mvz-live_ast 1.1.1 → 1.1.2
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/CHANGES.rdoc +14 -0
- data/Rakefile +48 -9
- data/devel/levitate.rb +5 -674
- data/lib/live_ast/common.rb +22 -21
- data/lib/live_ast/error.rb +2 -2
- data/lib/live_ast/irb_spy.rb +4 -6
- data/lib/live_ast/linker.rb +7 -7
- data/lib/live_ast/loader.rb +6 -6
- data/lib/live_ast/reader.rb +2 -2
- data/lib/live_ast/replace_eval.rb +27 -31
- data/lib/live_ast/replace_load.rb +1 -1
- data/lib/live_ast/ruby_parser.rb +24 -22
- data/lib/live_ast/ruby_parser/test.rb +183 -179
- data/lib/live_ast/ruby_parser/unparser.rb +10 -6
- data/lib/live_ast/to_ast.rb +1 -1
- data/lib/live_ast/version.rb +1 -1
- data/test/ast_eval/ast_eval_test.rb +11 -0
- data/test/ast_load/ast_load_test.rb +45 -0
- data/test/backtrace_test.rb +29 -28
- data/test/{noninvasive_test.rb → base/noninvasive_test.rb} +7 -5
- data/test/base/reload_test.rb +41 -0
- data/test/covert_define_method_test.rb +1 -1
- data/test/define_method_test.rb +5 -5
- data/test/encoding_test.rb +5 -5
- data/test/error_test.rb +6 -6
- data/test/eval_test.rb +7 -7
- data/test/flush_cache_test.rb +6 -6
- data/test/full/ast_reload_test.rb +39 -0
- data/test/{replace_eval_test.rb → full/replace_eval_test.rb} +31 -12
- data/test/irb_test.rb +1 -1
- data/test/lambda_test.rb +7 -0
- data/test/load_path_test.rb +12 -12
- data/test/load_test.rb +35 -35
- data/test/main.rb +19 -27
- data/test/nested_test.rb +1 -1
- data/test/readme_test.rb +1 -3
- data/test/recursive_eval_test.rb +2 -3
- data/test/redefine_method_test.rb +2 -2
- data/test/rubygems_test.rb +1 -1
- data/test/rubyspec_test.rb +3 -3
- data/test/stdlib_test.rb +1 -1
- data/test/thread_test.rb +1 -2
- data/test/to_ast/to_ast_feature_test.rb +11 -0
- data/test/to_ruby/to_ruby_feature_test.rb +11 -0
- data/test/{to_ruby_test.rb → to_ruby/to_ruby_test.rb} +2 -2
- metadata +93 -91
- data/test/ast_eval_feature_test.rb +0 -11
- data/test/ast_load_feature_test.rb +0 -11
- data/test/reload_test.rb +0 -105
- data/test/to_ast_feature_test.rb +0 -15
- data/test/to_ruby_feature_test.rb +0 -15
data/lib/live_ast/common.rb
CHANGED
@@ -2,36 +2,37 @@
|
|
2
2
|
module LiveAST
|
3
3
|
module Common
|
4
4
|
module_function
|
5
|
-
|
5
|
+
|
6
6
|
def arg_to_str(arg)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
7
|
+
arg.to_str
|
8
|
+
rescue NameError
|
9
|
+
thing = arg.nil? ? nil : arg.class
|
10
|
+
|
11
|
+
message = if RUBY_VERSION < "2.0.0"
|
12
|
+
"can't convert #{thing.inspect} into String"
|
13
|
+
else
|
14
|
+
"no implicit conversion of #{thing.inspect} into String"
|
15
|
+
end
|
16
|
+
raise TypeError, message
|
17
17
|
end
|
18
18
|
|
19
19
|
def check_arity(args, range)
|
20
|
-
|
21
|
-
range = 0 if range == (0..0)
|
20
|
+
return if range.include? args.size
|
22
21
|
|
23
|
-
|
22
|
+
range = 0 if range == (0..0)
|
23
|
+
|
24
|
+
raise ArgumentError,
|
24
25
|
"wrong number of arguments (#{args.size} for #{range})"
|
25
|
-
end
|
26
26
|
end
|
27
27
|
|
28
28
|
def check_is_binding(obj)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
29
|
+
return if obj.is_a? Binding
|
30
|
+
message = if RUBY_VERSION < "2.1.0"
|
31
|
+
"wrong argument type #{obj.class} (expected Binding)"
|
32
|
+
else
|
33
|
+
"wrong argument type #{obj.class} (expected binding)"
|
34
|
+
end
|
35
|
+
raise TypeError, message
|
35
36
|
end
|
36
37
|
|
37
38
|
def location_for_eval(*args)
|
data/lib/live_ast/error.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module LiveAST
|
2
2
|
class MultipleDefinitionsOnSameLineError < ScriptError
|
3
3
|
def message
|
4
|
-
"AST requested for a method or block that shares a line "
|
5
|
-
|
4
|
+
"AST requested for a method or block that shares a line " \
|
5
|
+
"with another method or block."
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
data/lib/live_ast/irb_spy.rb
CHANGED
@@ -9,7 +9,7 @@ module LiveAST
|
|
9
9
|
def code_at(line)
|
10
10
|
unless @history
|
11
11
|
raise NotImplementedError,
|
12
|
-
|
12
|
+
"LiveAST cannot access history for this IRB input method"
|
13
13
|
end
|
14
14
|
grow = 0
|
15
15
|
begin
|
@@ -27,16 +27,14 @@ module LiveAST
|
|
27
27
|
end
|
28
28
|
|
29
29
|
[
|
30
|
-
|
31
|
-
|
30
|
+
defined?(IRB::StdioInputMethod) ? IRB::StdioInputMethod : nil,
|
31
|
+
defined?(IRB::ReadlineInputMethod) ? IRB::ReadlineInputMethod : nil,
|
32
32
|
].compact.each do |klass|
|
33
33
|
klass.module_eval do
|
34
34
|
alias_method :live_ast_original_gets, :gets
|
35
35
|
def gets
|
36
36
|
live_ast_original_gets.tap do
|
37
|
-
if defined?(@line)
|
38
|
-
LiveAST::IRBSpy.history = @line
|
39
|
-
end
|
37
|
+
LiveAST::IRBSpy.history = @line if defined?(@line)
|
40
38
|
end
|
41
39
|
end
|
42
40
|
end
|
data/lib/live_ast/linker.rb
CHANGED
@@ -15,31 +15,31 @@ module LiveAST
|
|
15
15
|
|
16
16
|
module Attacher
|
17
17
|
VAR_NAME = :@_live_ast
|
18
|
-
|
18
|
+
|
19
19
|
def attach_to_proc(obj, ast)
|
20
20
|
obj.instance_variable_set(VAR_NAME, ast)
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def fetch_proc_attachment(obj)
|
24
24
|
if obj.instance_variable_defined?(VAR_NAME)
|
25
25
|
obj.instance_variable_get(VAR_NAME)
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def attach_to_method(klass, method, ast)
|
30
30
|
unless klass.instance_variable_defined?(VAR_NAME)
|
31
31
|
klass.instance_variable_set(VAR_NAME, {})
|
32
32
|
end
|
33
33
|
klass.instance_variable_get(VAR_NAME)[method] = ast
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
def fetch_method_attachment(klass, method)
|
37
37
|
if klass.instance_variable_defined?(VAR_NAME)
|
38
38
|
klass.instance_variable_get(VAR_NAME)[method]
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
module Linker
|
44
44
|
REVISION_TOKEN = "|ast@"
|
45
45
|
|
@@ -80,9 +80,9 @@ module LiveAST
|
|
80
80
|
|
81
81
|
def fetch_from_cache(file, line)
|
82
82
|
cache = @caches[file]
|
83
|
-
if !cache
|
83
|
+
if !cache && !file.index(REVISION_TOKEN)
|
84
84
|
_, cache =
|
85
|
-
if defined?(IRB)
|
85
|
+
if defined?(IRB) && file == "(irb)"
|
86
86
|
new_cache(IRBSpy.code_at(line), file, line, false)
|
87
87
|
else
|
88
88
|
#
|
data/lib/live_ast/loader.rb
CHANGED
@@ -6,29 +6,29 @@ module LiveAST
|
|
6
6
|
|
7
7
|
# guards to protect toplevel locals
|
8
8
|
header, footer, warnings_ok = header_footer(wrap)
|
9
|
-
|
9
|
+
|
10
10
|
parser_src = Reader.read(file)
|
11
11
|
evaler_src = header << parser_src << footer
|
12
|
-
|
12
|
+
|
13
13
|
run = lambda do
|
14
14
|
Evaler.eval(parser_src, evaler_src, TOPLEVEL_BINDING, file, 1)
|
15
15
|
end
|
16
16
|
warnings_ok ? run.call : suppress_warnings(&run)
|
17
17
|
true
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def header_footer(wrap)
|
21
21
|
if wrap
|
22
22
|
return "class << Object.new;", ";end", true
|
23
23
|
else
|
24
24
|
locals = NATIVE_EVAL.call("local_variables", TOPLEVEL_BINDING)
|
25
|
-
|
25
|
+
|
26
26
|
params = locals.empty? ? "" : ("|;" + locals.join(",") + "|")
|
27
|
-
|
27
|
+
|
28
28
|
return "lambda do #{params}", ";end.call", locals.empty?
|
29
29
|
end
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
def suppress_warnings
|
33
33
|
previous = $VERBOSE
|
34
34
|
$VERBOSE = nil
|
data/lib/live_ast/reader.rb
CHANGED
@@ -5,8 +5,8 @@ module LiveAST
|
|
5
5
|
MAGIC_COMMENT = /\A(?:#!.*?\n)?\s*\#.*(?:en)?coding\s*[:=]\s*([^\s;]+)/
|
6
6
|
|
7
7
|
def self.read(file)
|
8
|
-
contents = File.read(file, :
|
9
|
-
|
8
|
+
contents = File.read(file, encoding: "BINARY")
|
9
|
+
|
10
10
|
utf8 = contents.sub!(UTF8_BOM, "") ? "UTF-8" : nil
|
11
11
|
|
12
12
|
# magic comment overrides BOM
|
@@ -29,51 +29,47 @@ module LiveAST
|
|
29
29
|
Thread.current[:_live_ast_arg_cache] ||= {}
|
30
30
|
end
|
31
31
|
|
32
|
+
private
|
33
|
+
|
32
34
|
def handle_args(args)
|
33
35
|
if RUBY_VERSION < '2.0.0'
|
34
|
-
|
35
|
-
|
36
|
-
|
36
|
+
handle_args_pre_20(args)
|
37
|
+
else
|
38
|
+
handle_args_20(args)
|
39
|
+
end
|
40
|
+
end
|
37
41
|
|
38
|
-
|
42
|
+
def handle_args_20(args)
|
43
|
+
LiveAST::Common.check_arity(args, 1..3)
|
44
|
+
args[0] = Common.arg_to_str(args[0])
|
45
|
+
args[1] = Common.arg_to_str(args[1]) if args.length > 1
|
46
|
+
end
|
39
47
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
48
|
+
def handle_args_pre_20(args)
|
49
|
+
raise ArgumentError, "block not supplied" if args.empty?
|
50
|
+
|
51
|
+
args[0] = Common.arg_to_str(args[0])
|
52
|
+
|
53
|
+
unless (1..3).include? args.size
|
54
|
+
raise ArgumentError,
|
55
|
+
"wrong number of arguments: instance_eval(src) or instance_eval{..}"
|
47
56
|
end
|
48
|
-
|
49
|
-
args[1] = Common.arg_to_str(args[1]) if args
|
57
|
+
|
58
|
+
args[1] = Common.arg_to_str(args[1]) if args.length > 1
|
50
59
|
end
|
51
60
|
end
|
52
61
|
end
|
53
|
-
|
62
|
+
|
54
63
|
# ensure the parser is loaded -- rubygems calls eval
|
55
64
|
parser
|
56
65
|
end
|
57
66
|
|
58
|
-
#
|
59
|
-
prev_verbose = $VERBOSE
|
60
|
-
$VERBOSE = nil
|
61
|
-
|
67
|
+
# Override for Kernel#eval and Kernel.eval
|
62
68
|
module Kernel
|
63
69
|
class << self
|
64
70
|
alias_method :live_ast_original_singleton_eval, :eval
|
65
|
-
|
66
|
-
def eval(*args)
|
67
|
-
LiveAST::Common.check_arity(args, 1..4)
|
68
|
-
LiveAST.eval(
|
69
|
-
"::Kernel.live_ast_original_instance_eval do;" << args[0] << ";end",
|
70
|
-
args[1] || binding.of_caller(1),
|
71
|
-
*LiveAST::Common.location_for_eval(*args[1..3]))
|
72
|
-
end
|
73
71
|
end
|
74
72
|
|
75
|
-
private
|
76
|
-
|
77
73
|
alias_method :live_ast_original_eval, :eval
|
78
74
|
|
79
75
|
def eval(*args)
|
@@ -85,6 +81,7 @@ module Kernel
|
|
85
81
|
end
|
86
82
|
end
|
87
83
|
|
84
|
+
# Override for Binding#eval
|
88
85
|
class Binding
|
89
86
|
alias_method :live_ast_original_binding_eval, :eval
|
90
87
|
|
@@ -93,6 +90,7 @@ class Binding
|
|
93
90
|
end
|
94
91
|
end
|
95
92
|
|
93
|
+
# Override for BasicObject#instance_eval
|
96
94
|
class BasicObject
|
97
95
|
alias_method :live_ast_original_instance_eval, :instance_eval
|
98
96
|
|
@@ -106,6 +104,7 @@ class BasicObject
|
|
106
104
|
end
|
107
105
|
end
|
108
106
|
|
107
|
+
# Overrides for Module#module_eval and Module#class_eval
|
109
108
|
class Module
|
110
109
|
alias_method :live_ast_original_module_eval, :module_eval
|
111
110
|
|
@@ -121,6 +120,3 @@ class Module
|
|
121
120
|
remove_method :class_eval
|
122
121
|
alias_method :class_eval, :module_eval
|
123
122
|
end
|
124
|
-
|
125
|
-
# unsquelch alias warnings
|
126
|
-
$VERBOSE = prev_verbose
|
data/lib/live_ast/ruby_parser.rb
CHANGED
@@ -1,32 +1,34 @@
|
|
1
1
|
require 'ruby_parser'
|
2
2
|
require 'live_ast/base'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
def process(sexp)
|
18
|
-
case sexp.first
|
19
|
-
when :defn, :defs, :iter
|
20
|
-
store_sexp(sexp, sexp.line)
|
4
|
+
module LiveAST
|
5
|
+
class RubyParser
|
6
|
+
#
|
7
|
+
# Returns a line-to-sexp hash where sexp corresponds to the method
|
8
|
+
# or block defined at the given line.
|
9
|
+
#
|
10
|
+
# This method is the only requirement of a LiveAST parser plugin.
|
11
|
+
#
|
12
|
+
def parse(source)
|
13
|
+
@defs = {}
|
14
|
+
process ::RubyParser.new.parse(source)
|
15
|
+
@defs
|
21
16
|
end
|
22
17
|
|
23
|
-
sexp
|
24
|
-
|
18
|
+
def process(sexp)
|
19
|
+
case sexp.first
|
20
|
+
when :defn, :defs, :iter
|
21
|
+
store_sexp(sexp, sexp.line)
|
22
|
+
end
|
23
|
+
|
24
|
+
sexp.each do |elem|
|
25
|
+
process(elem) if elem.is_a? Sexp
|
26
|
+
end
|
25
27
|
end
|
26
|
-
end
|
27
28
|
|
28
|
-
|
29
|
-
|
29
|
+
def store_sexp(sexp, line)
|
30
|
+
@defs[line] = @defs.key?(line) ? :multiple : sexp
|
31
|
+
end
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
@@ -2,196 +2,200 @@
|
|
2
2
|
#
|
3
3
|
# Used by the LiveAST test suite.
|
4
4
|
#
|
5
|
-
module LiveAST
|
6
|
-
class
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
module LiveAST
|
6
|
+
class RubyParser
|
7
|
+
module Test
|
8
|
+
class << self
|
9
|
+
#
|
10
|
+
# Whether this is Ryan Davis's unified sexp format.
|
11
|
+
#
|
12
|
+
def unified_sexp?
|
13
|
+
true
|
14
|
+
end
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
#
|
17
|
+
# Whether the unparser output matches that of ruby2ruby.
|
18
|
+
#
|
19
|
+
def unparser_matches_ruby2ruby?
|
20
|
+
true
|
21
|
+
end
|
22
|
+
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
24
|
+
#
|
25
|
+
# no_arg_def(:f, "A#f") returns the ast of
|
26
|
+
#
|
27
|
+
# def f
|
28
|
+
# "A#f"
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
def no_arg_def(name, ret)
|
32
|
+
s(:defn, name, s(:args), s(:str, ret))
|
33
|
+
end
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
35
|
+
#
|
36
|
+
# singleton_no_arg_def(:f, "foo") returns the ast of
|
37
|
+
#
|
38
|
+
# def self.f
|
39
|
+
# "foo"
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
def singleton_no_arg_def(name, ret)
|
43
|
+
s(:defs, s(:self), name, s(:args), s(:str, ret))
|
44
|
+
end
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
#
|
47
|
+
# no_arg_def_return(no_arg_def(:f, "A#f")) == "A#f"
|
48
|
+
#
|
49
|
+
def no_arg_def_return(ast)
|
50
|
+
ast[3][1]
|
51
|
+
end
|
50
52
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
53
|
+
#
|
54
|
+
# binop_def(:f, :+) returns the ast of
|
55
|
+
#
|
56
|
+
# def f(x, y)
|
57
|
+
# x + y
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
def binop_def(name, op)
|
61
|
+
s(:defn,
|
62
|
+
name,
|
63
|
+
s(:args, :x, :y),
|
64
|
+
s(:call, s(:lvar, :x), op, s(:lvar, :y)))
|
65
|
+
end
|
64
66
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
67
|
+
#
|
68
|
+
# singleton_binop_def(:A, :f, :+) returns the ast of
|
69
|
+
#
|
70
|
+
# def A.f(x, y)
|
71
|
+
# x + y
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
def singleton_binop_def(const, name, op)
|
75
|
+
s(:defs,
|
76
|
+
s(:const, const),
|
77
|
+
name,
|
78
|
+
s(:args, :x, :y),
|
79
|
+
s(:call, s(:lvar, :x), op, s(:lvar, :y)))
|
80
|
+
end
|
79
81
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
82
|
+
#
|
83
|
+
# binop_define_method(:f, :*) returns the ast of
|
84
|
+
#
|
85
|
+
# define_method :f do |x, y|
|
86
|
+
# x * y
|
87
|
+
# end
|
88
|
+
#
|
89
|
+
# binop_define_method(:f, :-, :my_def) returns the ast of
|
90
|
+
#
|
91
|
+
# my_def :f do |x, y|
|
92
|
+
# x - y
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
def binop_define_method(name, op, using = :define_method)
|
96
|
+
s(:iter,
|
97
|
+
s(:call, nil, using, s(:lit, name)),
|
98
|
+
s(:args, :x, :y),
|
99
|
+
s(:call, s(:lvar, :x), op, s(:lvar, :y)))
|
100
|
+
end
|
99
101
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
102
|
+
#
|
103
|
+
# binop_define_method_with_var(:method_name, :/) returns the ast of
|
104
|
+
#
|
105
|
+
# define_method method_name do |x, y|
|
106
|
+
# x / y
|
107
|
+
# end
|
108
|
+
#
|
109
|
+
def binop_define_method_with_var(var_name, op)
|
110
|
+
s(:iter,
|
111
|
+
s(:call, nil, :define_method, s(:lvar, var_name)),
|
112
|
+
s(:args, :x, :y),
|
113
|
+
s(:call, s(:lvar, :x), op, s(:lvar, :y)))
|
114
|
+
end
|
113
115
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
#
|
130
|
-
# no_arg_block(:foo, "bar") returns the ast of
|
131
|
-
#
|
132
|
-
# foo { "bar" }
|
133
|
-
#
|
134
|
-
def no_arg_block(name, ret)
|
135
|
-
s(:iter, s(:call, nil, name), s(:args), s(:str, ret))
|
136
|
-
end
|
137
|
-
|
138
|
-
#
|
139
|
-
# binop_block(:foo, :+) returns the ast of
|
140
|
-
#
|
141
|
-
# foo { |x, y| x + y }
|
142
|
-
#
|
143
|
-
def binop_block(name, op)
|
144
|
-
s(:iter,
|
145
|
-
s(:call, nil, name),
|
146
|
-
s(:args, :x, :y),
|
147
|
-
s(:call, s(:lvar, :x), op, s(:lvar, :y)))
|
148
|
-
end
|
116
|
+
#
|
117
|
+
# binop_define_singleton_method(:f, :+, :a) returns the ast of
|
118
|
+
#
|
119
|
+
# a.define_singleton_method :f do |x, y|
|
120
|
+
# x + y
|
121
|
+
# end
|
122
|
+
#
|
123
|
+
def binop_define_singleton_method(name, op, receiver)
|
124
|
+
s(:iter,
|
125
|
+
s(:call, s(:lvar, receiver), :define_singleton_method,
|
126
|
+
s(:lit, name)),
|
127
|
+
s(:args, :x, :y),
|
128
|
+
s(:call, s(:lvar, :x), op, s(:lvar, :y)))
|
129
|
+
end
|
149
130
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
s(:args, :x, :y),
|
159
|
-
s(:call, s(:lvar, :x), op, s(:lvar, :y)))
|
160
|
-
end
|
131
|
+
#
|
132
|
+
# no_arg_block(:foo, "bar") returns the ast of
|
133
|
+
#
|
134
|
+
# foo { "bar" }
|
135
|
+
#
|
136
|
+
def no_arg_block(name, ret)
|
137
|
+
s(:iter, s(:call, nil, name), s(:args), s(:str, ret))
|
138
|
+
end
|
161
139
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
140
|
+
#
|
141
|
+
# binop_block(:foo, :+) returns the ast of
|
142
|
+
#
|
143
|
+
# foo { |x, y| x + y }
|
144
|
+
#
|
145
|
+
def binop_block(name, op)
|
146
|
+
s(:iter,
|
147
|
+
s(:call, nil, name),
|
148
|
+
s(:args, :x, :y),
|
149
|
+
s(:call, s(:lvar, :x), op, s(:lvar, :y)))
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
# binop_proc_new(:*) returns the ast of
|
154
|
+
#
|
155
|
+
# Proc.new { |x, y| x * y }
|
156
|
+
#
|
157
|
+
def binop_proc_new(op)
|
158
|
+
s(:iter,
|
159
|
+
s(:call, s(:const, :Proc), :new),
|
160
|
+
s(:args, :x, :y),
|
161
|
+
s(:call, s(:lvar, :x), op, s(:lvar, :y)))
|
162
|
+
end
|
177
163
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
164
|
+
#
|
165
|
+
# nested_lambdas("foo") returns the ast of
|
166
|
+
#
|
167
|
+
# lambda {
|
168
|
+
# lambda {
|
169
|
+
# "foo"
|
170
|
+
# }
|
171
|
+
# }
|
172
|
+
#
|
173
|
+
def nested_lambdas(str)
|
174
|
+
s(:iter,
|
175
|
+
s(:call, nil, :lambda),
|
176
|
+
s(:args),
|
177
|
+
s(:iter, s(:call, nil, :lambda), s(:args), s(:str, str)))
|
178
|
+
end
|
179
|
+
|
180
|
+
# nested_defs(:f, :g, "foo") returns the ast of
|
181
|
+
#
|
182
|
+
# def f
|
183
|
+
# Class.new do
|
184
|
+
# def g
|
185
|
+
# "foo"
|
186
|
+
# end
|
187
|
+
# end
|
188
|
+
# end
|
189
|
+
#
|
190
|
+
def nested_defs(u, v, str)
|
191
|
+
s(:defn,
|
192
|
+
u,
|
193
|
+
s(:args),
|
194
|
+
s(:iter,
|
195
|
+
s(:call, s(:const, :Class), :new),
|
196
|
+
s(:args),
|
197
|
+
s(:defn, v, s(:args), s(:str, str))))
|
198
|
+
end
|
199
|
+
end
|
196
200
|
end
|
197
201
|
end
|