raap 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +31 -0
- data/README.md +32 -3
- data/Rakefile +10 -1
- data/exe/raap +4 -1
- data/lib/raap/bind_call.rb +21 -7
- data/lib/raap/cli.rb +211 -125
- data/lib/raap/function_type.rb +14 -10
- data/lib/raap/method_property.rb +60 -28
- data/lib/raap/method_type.rb +13 -6
- data/lib/raap/minitest.rb +9 -3
- data/lib/raap/rbs.rb +19 -0
- data/lib/raap/result.rb +84 -8
- data/lib/raap/sized.rb +2 -0
- data/lib/raap/symbolic_caller.rb +38 -26
- data/lib/raap/type.rb +111 -115
- data/lib/raap/type_substitution.rb +5 -1
- data/lib/raap/value/bottom.rb +2 -0
- data/lib/raap/value/interface.rb +61 -27
- data/lib/raap/value/intersection.rb +26 -21
- data/lib/raap/value/module.rb +50 -7
- data/lib/raap/value/top.rb +2 -0
- data/lib/raap/value/variable.rb +12 -1
- data/lib/raap/value/void.rb +2 -0
- data/lib/raap/version.rb +1 -1
- data/lib/raap.rb +3 -2
- data/public/jacket.webp +0 -0
- data/rbs_collection.lock.yaml +61 -1
- data/rbs_collection.yaml +0 -1
- data/sig/raap.rbs +63 -34
- data/sig/shims.rbs +4 -0
- metadata +10 -9
data/lib/raap/function_type.rb
CHANGED
@@ -6,35 +6,39 @@ module RaaP
|
|
6
6
|
@fun = fun
|
7
7
|
end
|
8
8
|
|
9
|
-
def pick_arguments(size: 10
|
10
|
-
|
11
|
-
|
9
|
+
def pick_arguments(size: 10)
|
10
|
+
SymbolicCaller.new(arguments_to_symbolic_call(size:)).eval
|
11
|
+
end
|
12
|
+
|
13
|
+
def arguments_to_symbolic_call(size: 10)
|
14
|
+
a = to_symbolic_call_recursive(build_args_type, size:)
|
15
|
+
k = to_symbolic_call_recursive(build_kwargs_type, size:)
|
12
16
|
|
13
17
|
[a, k]
|
14
18
|
end
|
15
19
|
|
16
20
|
private
|
17
21
|
|
18
|
-
def
|
22
|
+
def to_symbolic_call_recursive(type, size:)
|
19
23
|
case
|
20
24
|
when type.nil?
|
21
25
|
nil
|
22
26
|
when type.respond_to?(:each_pair)
|
23
|
-
type.each_pair.to_h { |k, v| [k,
|
27
|
+
type.each_pair.to_h { |k, v| [k, to_symbolic_call_recursive(v, size:)] }
|
24
28
|
when type.respond_to?(:each)
|
25
|
-
type.each.map { |v|
|
29
|
+
type.each.map { |v| to_symbolic_call_recursive(v, size:) }
|
26
30
|
else
|
27
|
-
type.
|
31
|
+
type.to_symbolic_call(size:)
|
28
32
|
end
|
29
33
|
end
|
30
34
|
|
31
35
|
def build_args_type
|
32
36
|
reqs = @fun.required_positionals.map { |param| Type.new(param.type) }
|
33
37
|
tras = @fun.trailing_positionals.map { |param| Type.new(param.type) }
|
34
|
-
sampled_optional_positionals = @fun.optional_positionals.
|
38
|
+
sampled_optional_positionals = @fun.optional_positionals.take(Random.rand(@fun.optional_positionals.length + 1))
|
35
39
|
opts = sampled_optional_positionals.map { |param| Type.new(param.type) }
|
36
40
|
rest = []
|
37
|
-
if param = @fun.rest_positionals
|
41
|
+
if (param = @fun.rest_positionals)
|
38
42
|
rest = Array.new(Random.rand(0..3)) { Type.new(param.type) }
|
39
43
|
end
|
40
44
|
[reqs, opts, rest, tras].flatten
|
@@ -45,7 +49,7 @@ module RaaP
|
|
45
49
|
rand = Random.rand(@fun.optional_keywords.length + 1)
|
46
50
|
opts = @fun.optional_keywords.to_a.sample(rand).to_h { |name, param| [name, Type.new(param.type)] }
|
47
51
|
kwargs = reqs.to_h.merge(opts)
|
48
|
-
if param = @fun.rest_keywords
|
52
|
+
if (param = @fun.rest_keywords)
|
49
53
|
keys = Array.new(Random.rand(0..3)) do
|
50
54
|
random_key = nil
|
51
55
|
loop do
|
data/lib/raap/method_property.rb
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module RaaP
|
4
4
|
class MethodProperty
|
5
|
-
class Stats < Struct.new(:success, :skip, :exception)
|
6
|
-
def initialize(success: 0, skip: 0, exception: 0)
|
5
|
+
class Stats < Struct.new(:success, :skip, :exception, :break)
|
6
|
+
def initialize(success: 0, skip: 0, exception: 0, break: false)
|
7
7
|
super
|
8
8
|
end
|
9
9
|
end
|
@@ -23,12 +23,26 @@ module RaaP
|
|
23
23
|
Timeout.timeout(@timeout) do
|
24
24
|
catch(:break) do
|
25
25
|
@size_step.each do |size|
|
26
|
-
|
26
|
+
call(size:, stats:).tap do |ret|
|
27
|
+
case ret
|
28
|
+
when Result::Success
|
29
|
+
stats.success += 1
|
30
|
+
when Result::Failure
|
31
|
+
# no count
|
32
|
+
when Result::Skip
|
33
|
+
stats.skip += 1
|
34
|
+
when Result::Exception
|
35
|
+
stats.exception += 1
|
36
|
+
end
|
37
|
+
|
38
|
+
yield ret
|
39
|
+
end
|
27
40
|
end
|
28
41
|
end
|
29
42
|
end
|
30
43
|
rescue Timeout::Error => exception
|
31
|
-
|
44
|
+
stats.break = true
|
45
|
+
RaaP.logger.info "Timeout: #{exception}"
|
32
46
|
end
|
33
47
|
stats
|
34
48
|
end
|
@@ -36,61 +50,75 @@ module RaaP
|
|
36
50
|
private
|
37
51
|
|
38
52
|
def call(size:, stats:)
|
39
|
-
|
40
|
-
|
53
|
+
if @method_type.rbs.type.each_type.find { |t| t.instance_of?(::RBS::Types::Bases::Any) }
|
54
|
+
RaaP.logger.info { "Skip type check since `#{@method_type.rbs}` includes `untyped`" }
|
55
|
+
stats.break = true
|
56
|
+
throw :break
|
57
|
+
end
|
58
|
+
receiver_value = @receiver_type.to_symbolic_call(size:)
|
59
|
+
args, kwargs, block = @method_type.arguments_to_symbolic_call(size:)
|
41
60
|
# @type var symbolic_call: symbolic_call
|
42
61
|
symbolic_call = [:call, receiver_value, @method_name, args, kwargs, block]
|
43
62
|
symbolic_caller = SymbolicCaller.new(symbolic_call, allow_private: @allow_private)
|
44
63
|
begin
|
45
64
|
# ensure symbolic_call
|
46
|
-
check =
|
65
|
+
check = [:failure]
|
47
66
|
if return_type.instance_of?(::RBS::Types::Bases::Bottom)
|
48
67
|
begin
|
49
68
|
return_value = symbolic_caller.eval
|
50
69
|
rescue StandardError, NotImplementedError
|
51
|
-
check =
|
70
|
+
check = [:success]
|
52
71
|
return_value = Value::Bottom.new
|
72
|
+
rescue Timeout::ExitException
|
73
|
+
raise
|
74
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
75
|
+
RaaP.logger.error("[#{e.class}] class is not supported to check `bot` type")
|
76
|
+
raise
|
53
77
|
end
|
54
78
|
else
|
55
79
|
return_value = symbolic_caller.eval
|
56
|
-
check = check_return(receiver_value:, return_value
|
80
|
+
check = check_return(receiver_value:, return_value:)
|
57
81
|
end
|
58
|
-
|
59
|
-
|
82
|
+
case check
|
83
|
+
in [:success]
|
60
84
|
Result::Success.new(symbolic_call:, return_value:)
|
61
|
-
|
85
|
+
in [:failure]
|
62
86
|
Result::Failure.new(symbolic_call:, return_value:)
|
87
|
+
in [:exception, exception]
|
88
|
+
Result::Exception.new(symbolic_call:, exception:)
|
63
89
|
end
|
64
90
|
rescue TypeError => exception
|
65
91
|
Result::Failure.new(symbolic_call:, return_value:, exception:)
|
66
92
|
end
|
67
93
|
|
68
94
|
# not ensure symbolic_call
|
69
|
-
rescue NoMethodError => exception
|
70
|
-
stats.skip += 1
|
95
|
+
rescue NoMethodError, NotImplementedError => exception
|
71
96
|
Result::Skip.new(symbolic_call:, exception:)
|
72
97
|
rescue NameError => e
|
98
|
+
RaaP.logger.error("[#{e.class}] #{e.detailed_message}")
|
73
99
|
msg = e.name.nil? ? '' : "for `#{BindCall.to_s(e.receiver)}::#{e.name}`"
|
74
|
-
RaaP.logger.
|
100
|
+
RaaP.logger.warn("Implementation is not found #{msg} maybe.")
|
101
|
+
RaaP.logger.debug(e.backtrace&.join("\n"))
|
102
|
+
stats.break = true
|
75
103
|
throw :break
|
76
|
-
rescue NotImplementedError => exception
|
77
|
-
stats.skip += 1
|
78
|
-
Result::Skip.new(symbolic_call:, exception:)
|
79
104
|
rescue SystemStackError => exception
|
80
|
-
|
81
|
-
RaaP.logger.warn "Found recursive type definition."
|
105
|
+
RaaP.logger.info "Found recursive type definition."
|
82
106
|
Result::Skip.new(symbolic_call:, exception:)
|
83
107
|
rescue => exception
|
84
|
-
stats.exception += 1
|
85
108
|
Result::Exception.new(symbolic_call:, exception:)
|
86
109
|
end
|
87
110
|
|
88
|
-
def check_return(receiver_value:, return_value
|
111
|
+
def check_return(receiver_value:, return_value:)
|
89
112
|
if BindCall.is_a?(receiver_value, Module)
|
90
113
|
if BindCall.is_a?(return_type, ::RBS::Types::ClassSingleton)
|
91
114
|
# ::RBS::Test::TypeCheck cannot support to check singleton class
|
92
|
-
|
115
|
+
if receiver_value == return_value
|
116
|
+
[:success]
|
117
|
+
else
|
118
|
+
[:failure]
|
119
|
+
end
|
93
120
|
end
|
121
|
+
|
94
122
|
self_class = receiver_value
|
95
123
|
instance_class = receiver_value
|
96
124
|
else
|
@@ -98,18 +126,22 @@ module RaaP
|
|
98
126
|
instance_class = BindCall.class(receiver_value)
|
99
127
|
end
|
100
128
|
type_check = ::RBS::Test::TypeCheck.new(
|
101
|
-
self_class
|
102
|
-
instance_class
|
129
|
+
self_class:,
|
130
|
+
instance_class:,
|
103
131
|
class_class: Module,
|
104
132
|
builder: RBS.builder,
|
105
133
|
sample_size: 100,
|
106
134
|
unchecked_classes: []
|
107
135
|
)
|
108
136
|
begin
|
109
|
-
type_check.value(return_value, return_type)
|
137
|
+
if type_check.value(return_value, return_type)
|
138
|
+
[:success]
|
139
|
+
else
|
140
|
+
[:failure]
|
141
|
+
end
|
110
142
|
rescue => e
|
111
|
-
|
112
|
-
|
143
|
+
RaaP.logger.debug("Type check fail by `(#{e.class}) #{e.message}`")
|
144
|
+
[:exception, e]
|
113
145
|
end
|
114
146
|
end
|
115
147
|
|
data/lib/raap/method_type.rb
CHANGED
@@ -16,25 +16,32 @@ module RaaP
|
|
16
16
|
else
|
17
17
|
raise "bad method #{method}"
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
|
+
params = (type_params_decl + rbs.type_params).uniq
|
21
|
+
ts = TypeSubstitution.new(params, type_args)
|
20
22
|
|
21
23
|
@rbs = ts.method_type_sub(rbs, self_type:, instance_type:, class_type:)
|
22
24
|
@fun_type = FunctionType.new(@rbs.type)
|
23
25
|
end
|
24
26
|
|
25
|
-
def pick_arguments(size: 10
|
26
|
-
|
27
|
-
|
27
|
+
def pick_arguments(size: 10)
|
28
|
+
SymbolicCaller.new(arguments_to_symbolic_call(size:)).eval
|
29
|
+
end
|
30
|
+
|
31
|
+
def arguments_to_symbolic_call(size: 10)
|
32
|
+
args, kwargs = @fun_type.arguments_to_symbolic_call(size:)
|
33
|
+
block = pick_block(size:)
|
28
34
|
|
29
35
|
[args, kwargs, block]
|
30
36
|
end
|
31
37
|
|
32
|
-
def pick_block(size: 10
|
38
|
+
def pick_block(size: 10)
|
33
39
|
block = @rbs.block
|
34
40
|
return nil if block.nil?
|
35
41
|
return nil if (block.required == false) && [true, false].sample
|
36
42
|
|
37
|
-
|
43
|
+
fixed_return_value = Type.new(block.type.return_type).pick(size:)
|
44
|
+
Proc.new { fixed_return_value }
|
38
45
|
end
|
39
46
|
|
40
47
|
def check_return(return_value)
|
data/lib/raap/minitest.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'minitest'
|
2
4
|
|
3
5
|
module RaaP
|
@@ -11,9 +13,13 @@ module RaaP
|
|
11
13
|
method_type = RaaP::MethodType.new(type)
|
12
14
|
size_step.each do |size|
|
13
15
|
# TODO assert_send_type
|
14
|
-
args, kwargs, _block = method_type.pick_arguments(size:
|
16
|
+
args, kwargs, _block = method_type.pick_arguments(size:)
|
15
17
|
return_value = yield(*args, **kwargs)
|
16
|
-
|
18
|
+
i = BindCall.inspect(return_value)
|
19
|
+
c = BindCall.class(return_value)
|
20
|
+
r = method_type.rbs.type.return_type
|
21
|
+
msg = "return value: #{i}[#{c}] is not match with `#{r}`"
|
22
|
+
assert method_type.check_return(return_value), msg
|
17
23
|
end
|
18
24
|
else
|
19
25
|
# forall("Integer", "String") { |int, str| Foo.new.int_str(int, str) }
|
@@ -24,7 +30,7 @@ module RaaP
|
|
24
30
|
end
|
25
31
|
end
|
26
32
|
size_step.each do |size|
|
27
|
-
values = types.map { |
|
33
|
+
values = types.map { |t| t.pick(size:) }
|
28
34
|
assert yield(*values)
|
29
35
|
end
|
30
36
|
end
|
data/lib/raap/rbs.rb
CHANGED
@@ -19,5 +19,24 @@ module RaaP
|
|
19
19
|
|
20
20
|
::RBS::Parser.parse_type(type, require_eof: true) or raise
|
21
21
|
end
|
22
|
+
|
23
|
+
def self.parse_method_type(method_type)
|
24
|
+
raise ArgumentError, "empty method type" if method_type == ""
|
25
|
+
|
26
|
+
::RBS::Parser.parse_method_type(method_type, require_eof: true) or raise
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.find_alias_decl(type_name, method_name)
|
30
|
+
env.class_decls[type_name].decls.each do |d|
|
31
|
+
d.decl.members.each do |member|
|
32
|
+
case member
|
33
|
+
when ::RBS::AST::Members::Alias
|
34
|
+
return member if member.new_name == method_name
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
nil
|
40
|
+
end
|
22
41
|
end
|
23
42
|
end
|
data/lib/raap/result.rb
CHANGED
@@ -2,22 +2,98 @@
|
|
2
2
|
|
3
3
|
module RaaP
|
4
4
|
module Result
|
5
|
-
module
|
5
|
+
module ReturnValueWithType
|
6
|
+
def return_value_with_type
|
7
|
+
return_type = return_value_to_type(return_value)
|
8
|
+
type = if return_type.empty? || return_type == 'nil'
|
9
|
+
''
|
10
|
+
else
|
11
|
+
"[#{return_type}]"
|
12
|
+
end
|
13
|
+
"#{BindCall.inspect(return_value)}#{type}"
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def return_value_to_type(val)
|
19
|
+
case val
|
20
|
+
when nil
|
21
|
+
'nil'
|
22
|
+
when true, false
|
23
|
+
"bool"
|
24
|
+
when Array
|
25
|
+
elem = if val.empty?
|
26
|
+
'untyped'
|
27
|
+
else
|
28
|
+
return_value_to_type(val.first)
|
29
|
+
end
|
30
|
+
"Array[#{elem}]"
|
31
|
+
when Hash
|
32
|
+
key = val.empty? ? 'untyped' : return_value_to_type(val.keys.first)
|
33
|
+
value = val.empty? ? 'untyped' : return_value_to_type(val.values.first)
|
34
|
+
"Hash[#{key}, #{value}]"
|
35
|
+
when Enumerator
|
36
|
+
elem =
|
37
|
+
begin
|
38
|
+
return_value_to_type(val.peek)
|
39
|
+
rescue StandardError
|
40
|
+
'untyped'
|
41
|
+
end
|
42
|
+
ret =
|
43
|
+
if val.size == Float::INFINITY
|
44
|
+
'bot'
|
45
|
+
else
|
46
|
+
begin
|
47
|
+
val.each {}
|
48
|
+
.tap { val.rewind }
|
49
|
+
.then { return_value_to_type(_1) }
|
50
|
+
rescue StandardError
|
51
|
+
'untyped'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
"Enumerator[#{elem}, #{ret}]"
|
55
|
+
else
|
56
|
+
"#{BindCall.class(val)}"
|
57
|
+
end
|
58
|
+
rescue StandardError => e
|
59
|
+
RaaP.logger.debug("[#{e.class}] #{e.exception.detailed_message}")
|
60
|
+
RaaP.logger.debug(e.exception.backtrace&.join("\n"))
|
61
|
+
"raised #{e.class} with check return_type"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Success < Data.define(:symbolic_call, :return_value)
|
66
|
+
include ReturnValueWithType
|
67
|
+
|
6
68
|
def called_str
|
7
69
|
scr = SymbolicCaller.new(symbolic_call)
|
8
|
-
"#{scr.call_str} -> #{
|
70
|
+
"#{scr.call_str} -> #{return_value_with_type}"
|
9
71
|
end
|
10
72
|
end
|
11
73
|
|
12
|
-
|
13
|
-
|
14
|
-
|
74
|
+
class Failure < Data.define(:symbolic_call, :return_value, :exception)
|
75
|
+
include ReturnValueWithType
|
76
|
+
|
15
77
|
def initialize(exception: nil, **)
|
16
78
|
super
|
17
79
|
end
|
80
|
+
|
81
|
+
def called_str
|
82
|
+
scr = SymbolicCaller.new(symbolic_call)
|
83
|
+
return_type =
|
84
|
+
if exception
|
85
|
+
"raised #{exception.class}"
|
86
|
+
else
|
87
|
+
return_value_with_type
|
88
|
+
end
|
89
|
+
"#{scr.call_str} -> #{return_type}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class Skip < Data.define(:symbolic_call, :exception)
|
94
|
+
end
|
95
|
+
|
96
|
+
class Exception < Data.define(:symbolic_call, :exception)
|
18
97
|
end
|
19
|
-
Failure.include CalledStr
|
20
|
-
Skip = Data.define(:symbolic_call, :exception)
|
21
|
-
Exception = Data.define(:symbolic_call, :exception)
|
22
98
|
end
|
23
99
|
end
|
data/lib/raap/sized.rb
CHANGED
@@ -4,6 +4,7 @@ module RaaP
|
|
4
4
|
class Sized
|
5
5
|
def initialize(&block)
|
6
6
|
raise LocalJumpError, "no block given" unless block
|
7
|
+
|
7
8
|
@block = block
|
8
9
|
@such_that = nil
|
9
10
|
end
|
@@ -28,6 +29,7 @@ module RaaP
|
|
28
29
|
picked = yield(skip)
|
29
30
|
such_that = @such_that
|
30
31
|
return picked if such_that.nil? || such_that.call(picked)
|
32
|
+
|
31
33
|
skip += 1
|
32
34
|
raise "too many skips" unless skip < 100
|
33
35
|
end
|
data/lib/raap/symbolic_caller.rb
CHANGED
@@ -18,6 +18,7 @@ module RaaP
|
|
18
18
|
class SymbolicCaller
|
19
19
|
class Var
|
20
20
|
attr_reader :name
|
21
|
+
|
21
22
|
def initialize(name)
|
22
23
|
@name = name
|
23
24
|
end
|
@@ -46,13 +47,13 @@ module RaaP
|
|
46
47
|
end
|
47
48
|
|
48
49
|
def call_str
|
49
|
-
symbolic_call => [:call, receiver, Symbol => method_name, Array => args, Hash => kwargs,
|
50
|
+
symbolic_call => [:call, receiver, Symbol => method_name, Array => args, Hash => kwargs, block]
|
50
51
|
receiver = try_eval(receiver)
|
51
52
|
args, kwargs, block = try_eval([args, kwargs, block])
|
52
53
|
|
53
54
|
a = []
|
54
|
-
a << args.map(
|
55
|
-
a << kwargs.map { |k
|
55
|
+
a << args.map(&BindCall.method(:inspect)).join(', ') if !args.empty?
|
56
|
+
a << kwargs.map { |k, v| "#{k}: #{BindCall.inspect(v)}" }.join(', ') if !kwargs.empty?
|
56
57
|
argument_str = a.join(', ')
|
57
58
|
block_str = block ? "{ }" : nil
|
58
59
|
|
@@ -61,7 +62,7 @@ module RaaP
|
|
61
62
|
|
62
63
|
def to_lines
|
63
64
|
[].tap do |lines|
|
64
|
-
walk do |symbolic_call|
|
65
|
+
walk do |symbolic_call, is_last|
|
65
66
|
symbolic_call => [:call, receiver_value, method_name, args, kwargs, block]
|
66
67
|
|
67
68
|
is_mod = receiver_value.is_a?(Module)
|
@@ -72,7 +73,7 @@ module RaaP
|
|
72
73
|
var_eq = "#{var} = "
|
73
74
|
receiver = ''
|
74
75
|
when BindCall.instance_of?(receiver_value, Var)
|
75
|
-
var_eq = ""
|
76
|
+
var_eq = "#{receiver_value} = "
|
76
77
|
var = Var.new(receiver_value.name)
|
77
78
|
receiver = var + '.'
|
78
79
|
when is_mod
|
@@ -80,16 +81,32 @@ module RaaP
|
|
80
81
|
var_eq = "#{var} = "
|
81
82
|
receiver = receiver_value.name + '.'
|
82
83
|
else
|
83
|
-
var_eq =
|
84
|
+
var_eq = ''
|
84
85
|
receiver = Var.new(printable(receiver_value)) + '.'
|
85
86
|
end
|
86
87
|
|
88
|
+
var_eq = '' if is_last
|
89
|
+
|
87
90
|
arguments = []
|
88
|
-
|
89
|
-
|
91
|
+
if !args.empty?
|
92
|
+
# The reproduction code is kept short and executable.
|
93
|
+
if [Value::Interface, Value::Intersection].include?(receiver_value)
|
94
|
+
if args.all? { |a| a.respond_to?(:free_variables) } && !args.all? { |a| a.free_variables.empty? }
|
95
|
+
# FIXME: Type arguments are not yet supported.
|
96
|
+
args.each do |a|
|
97
|
+
lines << "# Free variables: #{a.free_variables.to_a.join(', ')}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
arguments << args.map { |a| printable(a.to_s) }
|
101
|
+
else
|
102
|
+
arguments << args.map { |a| printable(a) }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
arguments << kwargs.map { |k, v| "#{k}: #{printable(v)}" }.join(', ') if !kwargs.empty?
|
90
106
|
block_str = block ? " { }" : ""
|
91
107
|
|
92
|
-
|
108
|
+
line = "#{var_eq}#{receiver}#{method_name}(#{arguments.join(', ')})#{block_str}"
|
109
|
+
lines << line
|
93
110
|
|
94
111
|
var
|
95
112
|
end
|
@@ -105,25 +122,24 @@ module RaaP
|
|
105
122
|
end
|
106
123
|
|
107
124
|
def walk(&)
|
108
|
-
_walk(@symbolic_call, &)
|
125
|
+
_walk(@symbolic_call, true, &)
|
109
126
|
end
|
110
127
|
|
111
|
-
def _walk(symbolic_call, &block)
|
128
|
+
def _walk(symbolic_call, is_last, &block)
|
112
129
|
return symbolic_call if BindCall::instance_of?(symbolic_call, BasicObject)
|
113
130
|
return symbolic_call if !BindCall.respond_to?(symbolic_call, :deconstruct) && !BindCall.respond_to?(symbolic_call, :deconstruct_keys)
|
114
131
|
|
115
132
|
case symbolic_call
|
116
133
|
in [:call, receiver, Symbol => method_name, Array => args, Hash => kwargs, b]
|
117
|
-
receiver = _walk(receiver, &block)
|
118
|
-
args = _walk(args, &block) if !args.empty?
|
119
|
-
kwargs = _walk(kwargs, &block) if !kwargs.empty?
|
120
|
-
block.call [:call, receiver, method_name, args, kwargs, b]
|
121
|
-
in Var
|
122
|
-
symbolic_call.name
|
134
|
+
receiver = _walk(receiver, false, &block)
|
135
|
+
args = _walk(args, false, &block) if !args.empty?
|
136
|
+
kwargs = _walk(kwargs, false, &block) if !kwargs.empty?
|
137
|
+
block.call [:call, receiver, method_name, args, kwargs, b], is_last
|
123
138
|
in Array
|
124
|
-
symbolic_call.map { |sc| _walk(sc, &block) }
|
139
|
+
symbolic_call.map { |sc| _walk(sc, false, &block) }
|
125
140
|
in Hash
|
126
|
-
symbolic_call.
|
141
|
+
symbolic_call.transform_keys { |k| _walk(k, false, &block) }
|
142
|
+
.transform_values! { |v| _walk(v, false, &block) }
|
127
143
|
else
|
128
144
|
symbolic_call
|
129
145
|
end
|
@@ -143,15 +159,11 @@ module RaaP
|
|
143
159
|
end
|
144
160
|
|
145
161
|
def printable(obj)
|
146
|
-
if obj in [:call, _, Symbol, Array, Hash, _]
|
147
|
-
return _walk(obj)
|
148
|
-
end
|
149
|
-
|
150
162
|
case obj
|
151
163
|
when Var
|
152
164
|
obj.name
|
153
165
|
# Object from which it can get strings that can be eval with `#inspect`
|
154
|
-
when Symbol, Integer, Float, Regexp, nil, true, false
|
166
|
+
when Symbol, Integer, Float, Regexp, Range, nil, true, false
|
155
167
|
obj.inspect
|
156
168
|
when String
|
157
169
|
obj.inspect.gsub('"', "'") or raise
|
@@ -165,9 +177,9 @@ module RaaP
|
|
165
177
|
when Array
|
166
178
|
"[#{obj.map { |o| printable(o) }.join(', ')}]"
|
167
179
|
when Module
|
168
|
-
BindCall.name(obj) or raise
|
180
|
+
BindCall.name(obj) or raise "`#class` method returns nil"
|
169
181
|
else
|
170
|
-
var_name(
|
182
|
+
var_name(BindCall.class(obj))
|
171
183
|
end
|
172
184
|
end
|
173
185
|
end
|