lib/raap/symbolic_caller.rb in raap-0.3.0 vs lib/raap/symbolic_caller.rb in raap-0.4.0
- old
+ new
@@ -16,10 +16,11 @@
# c = C.new(a: a, b: b)
# c.run() { }
class SymbolicCaller
class Var
attr_reader :name
+
def initialize(name)
@name = name
end
def +(other)
@@ -44,54 +45,70 @@
eval_one(symbolic_call)
end
end
def call_str
- symbolic_call => [:call, receiver, Symbol => method_name, Array => args, Hash => kwargs, b]
+ symbolic_call => [:call, receiver, Symbol => method_name, Array => args, Hash => kwargs, block]
receiver = try_eval(receiver)
args, kwargs, block = try_eval([args, kwargs, block])
a = []
- a << args.map(&:inspect).join(', ') if !args.empty?
- a << kwargs.map { |k ,v| "#{k}: #{BindCall.inspect(v)}" }.join(', ') if !kwargs.empty?
+ a << args.map(&BindCall.method(:inspect)).join(', ') if !args.empty?
+ a << kwargs.map { |k, v| "#{k}: #{BindCall.inspect(v)}" }.join(', ') if !kwargs.empty?
argument_str = a.join(', ')
block_str = block ? "{ }" : nil
"#{BindCall.inspect(receiver)}.#{method_name}(#{argument_str})#{block_str}"
end
def to_lines
[].tap do |lines|
- walk do |symbolic_call|
+ walk do |symbolic_call, is_last|
symbolic_call => [:call, receiver_value, method_name, args, kwargs, block]
is_mod = receiver_value.is_a?(Module)
case
when receiver_value == Kernel
var = Var.new(method_name.to_s.downcase)
var_eq = "#{var} = "
receiver = ''
when BindCall.instance_of?(receiver_value, Var)
- var_eq = ""
+ var_eq = "#{receiver_value} = "
var = Var.new(receiver_value.name)
receiver = var + '.'
when is_mod
var = Var.new(var_name(receiver_value))
var_eq = "#{var} = "
receiver = receiver_value.name + '.'
else
- var_eq = ""
+ var_eq = ''
receiver = Var.new(printable(receiver_value)) + '.'
end
+ var_eq = '' if is_last
+
arguments = []
- arguments << args.map { |a| printable(a) } if !args.empty?
- arguments << kwargs.map{|k,v| "#{k}: #{printable(v)}" }.join(', ') if !kwargs.empty?
+ if !args.empty?
+ # The reproduction code is kept short and executable.
+ if [Value::Interface, Value::Intersection].include?(receiver_value)
+ if args.all? { |a| a.respond_to?(:free_variables) } && !args.all? { |a| a.free_variables.empty? }
+ # FIXME: Type arguments are not yet supported.
+ args.each do |a|
+ lines << "# Free variables: #{a.free_variables.to_a.join(', ')}"
+ end
+ end
+ arguments << args.map { |a| printable(a.to_s) }
+ else
+ arguments << args.map { |a| printable(a) }
+ end
+ end
+ arguments << kwargs.map { |k, v| "#{k}: #{printable(v)}" }.join(', ') if !kwargs.empty?
block_str = block ? " { }" : ""
- lines << "#{var_eq}#{receiver}#{method_name}(#{arguments.join(', ')})#{block_str}"
+ line = "#{var_eq}#{receiver}#{method_name}(#{arguments.join(', ')})#{block_str}"
+ lines << line
var
end
end
end
@@ -103,29 +120,28 @@
rescue RuntimeError, NotImplementedError
symbolic_call
end
def walk(&)
- _walk(@symbolic_call, &)
+ _walk(@symbolic_call, true, &)
end
- def _walk(symbolic_call, &block)
+ def _walk(symbolic_call, is_last, &block)
return symbolic_call if BindCall::instance_of?(symbolic_call, BasicObject)
return symbolic_call if !BindCall.respond_to?(symbolic_call, :deconstruct) && !BindCall.respond_to?(symbolic_call, :deconstruct_keys)
case symbolic_call
in [:call, receiver, Symbol => method_name, Array => args, Hash => kwargs, b]
- receiver = _walk(receiver, &block)
- args = _walk(args, &block) if !args.empty?
- kwargs = _walk(kwargs, &block) if !kwargs.empty?
- block.call [:call, receiver, method_name, args, kwargs, b]
- in Var
- symbolic_call.name
+ receiver = _walk(receiver, false, &block)
+ args = _walk(args, false, &block) if !args.empty?
+ kwargs = _walk(kwargs, false, &block) if !kwargs.empty?
+ block.call [:call, receiver, method_name, args, kwargs, b], is_last
in Array
- symbolic_call.map { |sc| _walk(sc, &block) }
+ symbolic_call.map { |sc| _walk(sc, false, &block) }
in Hash
- symbolic_call.transform_values { |sc| _walk(sc, &block) }
+ symbolic_call.transform_keys { |k| _walk(k, false, &block) }
+ .transform_values! { |v| _walk(v, false, &block) }
else
symbolic_call
end
end
@@ -141,19 +157,15 @@
def var_name(mod)
printable(mod).gsub('::', '_').downcase
end
def printable(obj)
- if obj in [:call, _, Symbol, Array, Hash, _]
- return _walk(obj)
- end
-
case obj
when Var
obj.name
# Object from which it can get strings that can be eval with `#inspect`
- when Symbol, Integer, Float, Regexp, nil, true, false
+ when Symbol, Integer, Float, Regexp, Range, nil, true, false
obj.inspect
when String
obj.inspect.gsub('"', "'") or raise
when Hash
hash_body = obj.map do |k, v|
@@ -163,12 +175,12 @@
end
"{#{hash_body.join(', ')}}"
when Array
"[#{obj.map { |o| printable(o) }.join(', ')}]"
when Module
- BindCall.name(obj) or raise
+ BindCall.name(obj) or raise "`#class` method returns nil"
else
- var_name(obj.class)
+ var_name(BindCall.class(obj))
end
end
end
end