mvz-live_ast 1.1.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|