syntax_tree 5.0.0 → 5.1.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 +51 -0
- data/CHANGELOG.md +24 -1
- data/Gemfile.lock +9 -9
- data/README.md +5 -5
- data/lib/syntax_tree/cli.rb +8 -6
- data/lib/syntax_tree/dsl.rb +1004 -0
- data/lib/syntax_tree/formatter.rb +2 -2
- data/lib/syntax_tree/language_server.rb +2 -0
- data/lib/syntax_tree/node.rb +7 -7
- data/lib/syntax_tree/parser.rb +20 -21
- data/lib/syntax_tree/version.rb +1 -1
- data/lib/syntax_tree/yarv/assembler.rb +459 -0
- data/lib/syntax_tree/yarv/bf.rb +179 -0
- data/lib/syntax_tree/yarv/compiler.rb +2287 -0
- data/lib/syntax_tree/yarv/decompiler.rb +254 -0
- data/lib/syntax_tree/yarv/disassembler.rb +211 -0
- data/lib/syntax_tree/yarv/instruction_sequence.rb +1171 -0
- data/lib/syntax_tree/yarv/instructions.rb +5203 -0
- data/lib/syntax_tree/yarv/legacy.rb +192 -0
- data/lib/syntax_tree/yarv/local_table.rb +89 -0
- data/lib/syntax_tree/yarv.rb +287 -0
- data/lib/syntax_tree.rb +23 -1
- data/syntax_tree.gemspec +1 -1
- metadata +15 -4
@@ -84,10 +84,10 @@ module SyntaxTree
|
|
84
84
|
@target_ruby_version = options.target_ruby_version
|
85
85
|
end
|
86
86
|
|
87
|
-
def self.format(source, node)
|
87
|
+
def self.format(source, node, base_indentation = 0)
|
88
88
|
q = new(source, [])
|
89
89
|
q.format(node)
|
90
|
-
q.flush
|
90
|
+
q.flush(base_indentation)
|
91
91
|
q.output.join
|
92
92
|
end
|
93
93
|
|
@@ -111,6 +111,8 @@ module SyntaxTree
|
|
111
111
|
write(id: request[:id], result: PP.pp(SyntaxTree.parse(store[uri]), +""))
|
112
112
|
when Request[method: %r{\$/.+}]
|
113
113
|
# ignored
|
114
|
+
when Request[method: "textDocument/documentColor", params: { textDocument: { uri: :any } }]
|
115
|
+
# ignored
|
114
116
|
else
|
115
117
|
raise ArgumentError, "Unhandled: #{request}"
|
116
118
|
end
|
data/lib/syntax_tree/node.rb
CHANGED
@@ -1604,7 +1604,7 @@ module SyntaxTree
|
|
1604
1604
|
# { **pairs }
|
1605
1605
|
#
|
1606
1606
|
class AssocSplat < Node
|
1607
|
-
# [untyped] the expression that is being splatted
|
1607
|
+
# [nil | untyped] the expression that is being splatted
|
1608
1608
|
attr_reader :value
|
1609
1609
|
|
1610
1610
|
# [Array[ Comment | EmbDoc ]] the comments attached to this node
|
@@ -1643,7 +1643,7 @@ module SyntaxTree
|
|
1643
1643
|
|
1644
1644
|
def format(q)
|
1645
1645
|
q.text("**")
|
1646
|
-
q.format(value)
|
1646
|
+
q.format(value) if value
|
1647
1647
|
end
|
1648
1648
|
|
1649
1649
|
def ===(other)
|
@@ -6160,7 +6160,7 @@ module SyntaxTree
|
|
6160
6160
|
# want to force it to not be a ternary, like if the predicate is an
|
6161
6161
|
# assignment because it's hard to read.
|
6162
6162
|
case node.predicate
|
6163
|
-
when Assign, Command, CommandCall, MAssign, OpAssign
|
6163
|
+
when Assign, Binary, Command, CommandCall, MAssign, OpAssign
|
6164
6164
|
return false
|
6165
6165
|
when Not
|
6166
6166
|
return false unless node.predicate.parentheses?
|
@@ -6183,10 +6183,10 @@ module SyntaxTree
|
|
6183
6183
|
# and default instead to breaking them into multiple lines.
|
6184
6184
|
def ternaryable?(statement)
|
6185
6185
|
case statement
|
6186
|
-
when AliasNode, Assign, Break, Command, CommandCall,
|
6187
|
-
IfOp, Lambda, MAssign, Next, OpAssign, RescueMod,
|
6188
|
-
Super, Undef, UnlessNode, UntilNode, VoidStmt,
|
6189
|
-
YieldNode, ZSuper
|
6186
|
+
when AliasNode, Assign, Break, Command, CommandCall, Defined, Heredoc,
|
6187
|
+
IfNode, IfOp, Lambda, MAssign, Next, OpAssign, RescueMod,
|
6188
|
+
ReturnNode, Super, Undef, UnlessNode, UntilNode, VoidStmt,
|
6189
|
+
WhileNode, YieldNode, ZSuper
|
6190
6190
|
# This is a list of nodes that should not be allowed to be a part of a
|
6191
6191
|
# ternary clause.
|
6192
6192
|
false
|
data/lib/syntax_tree/parser.rb
CHANGED
@@ -744,7 +744,7 @@ module SyntaxTree
|
|
744
744
|
|
745
745
|
AssocSplat.new(
|
746
746
|
value: value,
|
747
|
-
location: operator.location.to(value.location)
|
747
|
+
location: operator.location.to((value || operator).location)
|
748
748
|
)
|
749
749
|
end
|
750
750
|
|
@@ -820,13 +820,13 @@ module SyntaxTree
|
|
820
820
|
end
|
821
821
|
|
822
822
|
bodystmt.bind(
|
823
|
-
keyword.location.end_char,
|
823
|
+
find_next_statement_start(keyword.location.end_char),
|
824
824
|
keyword.location.end_column,
|
825
825
|
end_location.end_char,
|
826
826
|
end_location.end_column
|
827
827
|
)
|
828
|
-
location = keyword.location.to(bodystmt.location)
|
829
828
|
|
829
|
+
location = keyword.location.to(end_location)
|
830
830
|
Begin.new(bodystmt: bodystmt, location: location)
|
831
831
|
end
|
832
832
|
end
|
@@ -905,14 +905,15 @@ module SyntaxTree
|
|
905
905
|
# (nil | Ensure) ensure_clause
|
906
906
|
# ) -> BodyStmt
|
907
907
|
def on_bodystmt(statements, rescue_clause, else_clause, ensure_clause)
|
908
|
+
parts = [statements, rescue_clause, else_clause, ensure_clause].compact
|
909
|
+
|
908
910
|
BodyStmt.new(
|
909
911
|
statements: statements,
|
910
912
|
rescue_clause: rescue_clause,
|
911
913
|
else_keyword: else_clause && consume_keyword(:else),
|
912
914
|
else_clause: else_clause,
|
913
915
|
ensure_clause: ensure_clause,
|
914
|
-
location:
|
915
|
-
Location.fixed(line: lineno, char: char_pos, column: current_column)
|
916
|
+
location: parts.first.location.to(parts.last.location)
|
916
917
|
)
|
917
918
|
end
|
918
919
|
|
@@ -994,22 +995,11 @@ module SyntaxTree
|
|
994
995
|
# :call-seq:
|
995
996
|
# on_case: (untyped value, untyped consequent) -> Case | RAssign
|
996
997
|
def on_case(value, consequent)
|
997
|
-
if (
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
value: value,
|
1003
|
-
consequent: consequent,
|
1004
|
-
location: keyword.location.to(consequent.location)
|
1005
|
-
)
|
1006
|
-
else
|
1007
|
-
operator =
|
1008
|
-
if (keyword = find_keyword(:in))
|
1009
|
-
tokens.delete(keyword)
|
1010
|
-
else
|
1011
|
-
consume_operator(:"=>")
|
1012
|
-
end
|
998
|
+
if value && (operator = find_keyword(:in) || find_operator(:"=>")) &&
|
999
|
+
(value.location.end_char...consequent.location.start_char).cover?(
|
1000
|
+
operator.location.start_char
|
1001
|
+
)
|
1002
|
+
tokens.delete(operator)
|
1013
1003
|
|
1014
1004
|
node =
|
1015
1005
|
RAssign.new(
|
@@ -1021,6 +1011,15 @@ module SyntaxTree
|
|
1021
1011
|
|
1022
1012
|
PinVisitor.visit(node, tokens)
|
1023
1013
|
node
|
1014
|
+
else
|
1015
|
+
keyword = consume_keyword(:case)
|
1016
|
+
|
1017
|
+
Case.new(
|
1018
|
+
keyword: keyword,
|
1019
|
+
value: value,
|
1020
|
+
consequent: consequent,
|
1021
|
+
location: keyword.location.to(consequent.location)
|
1022
|
+
)
|
1024
1023
|
end
|
1025
1024
|
end
|
1026
1025
|
|
data/lib/syntax_tree/version.rb
CHANGED
@@ -0,0 +1,459 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SyntaxTree
|
4
|
+
module YARV
|
5
|
+
class Assembler
|
6
|
+
class ObjectVisitor < Compiler::RubyVisitor
|
7
|
+
def visit_dyna_symbol(node)
|
8
|
+
if node.parts.empty?
|
9
|
+
:""
|
10
|
+
else
|
11
|
+
raise CompilationError
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def visit_string_literal(node)
|
16
|
+
case node.parts.length
|
17
|
+
when 0
|
18
|
+
""
|
19
|
+
when 1
|
20
|
+
raise CompilationError unless node.parts.first.is_a?(TStringContent)
|
21
|
+
node.parts.first.value
|
22
|
+
else
|
23
|
+
raise CompilationError
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
CALLDATA_FLAGS = {
|
29
|
+
"ARGS_SPLAT" => CallData::CALL_ARGS_SPLAT,
|
30
|
+
"ARGS_BLOCKARG" => CallData::CALL_ARGS_BLOCKARG,
|
31
|
+
"FCALL" => CallData::CALL_FCALL,
|
32
|
+
"VCALL" => CallData::CALL_VCALL,
|
33
|
+
"ARGS_SIMPLE" => CallData::CALL_ARGS_SIMPLE,
|
34
|
+
"BLOCKISEQ" => CallData::CALL_BLOCKISEQ,
|
35
|
+
"KWARG" => CallData::CALL_KWARG,
|
36
|
+
"KW_SPLAT" => CallData::CALL_KW_SPLAT,
|
37
|
+
"TAILCALL" => CallData::CALL_TAILCALL,
|
38
|
+
"SUPER" => CallData::CALL_SUPER,
|
39
|
+
"ZSUPER" => CallData::CALL_ZSUPER,
|
40
|
+
"OPT_SEND" => CallData::CALL_OPT_SEND,
|
41
|
+
"KW_SPLAT_MUT" => CallData::CALL_KW_SPLAT_MUT
|
42
|
+
}.freeze
|
43
|
+
|
44
|
+
DEFINED_TYPES = [
|
45
|
+
nil,
|
46
|
+
"nil",
|
47
|
+
"instance-variable",
|
48
|
+
"local-variable",
|
49
|
+
"global-variable",
|
50
|
+
"class variable",
|
51
|
+
"constant",
|
52
|
+
"method",
|
53
|
+
"yield",
|
54
|
+
"super",
|
55
|
+
"self",
|
56
|
+
"true",
|
57
|
+
"false",
|
58
|
+
"assignment",
|
59
|
+
"expression",
|
60
|
+
"ref",
|
61
|
+
"func",
|
62
|
+
"constant-from"
|
63
|
+
].freeze
|
64
|
+
|
65
|
+
attr_reader :filepath
|
66
|
+
|
67
|
+
def initialize(filepath)
|
68
|
+
@filepath = filepath
|
69
|
+
end
|
70
|
+
|
71
|
+
def assemble
|
72
|
+
iseq = InstructionSequence.new(:top, "<main>", nil, Location.default)
|
73
|
+
assemble_iseq(iseq, File.readlines(filepath, chomp: true))
|
74
|
+
|
75
|
+
iseq.compile!
|
76
|
+
iseq
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.assemble(filepath)
|
80
|
+
new(filepath).assemble
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def assemble_iseq(iseq, lines)
|
86
|
+
labels = Hash.new { |hash, name| hash[name] = iseq.label }
|
87
|
+
line_index = 0
|
88
|
+
|
89
|
+
while line_index < lines.length
|
90
|
+
line = lines[line_index]
|
91
|
+
line_index += 1
|
92
|
+
|
93
|
+
case line.strip
|
94
|
+
when "", /^;/
|
95
|
+
# skip over blank lines and comments
|
96
|
+
next
|
97
|
+
when /^(\w+):$/
|
98
|
+
# create labels
|
99
|
+
iseq.push(labels[$1])
|
100
|
+
next
|
101
|
+
when /^__END__/
|
102
|
+
# skip over the rest of the file when we hit __END__
|
103
|
+
return
|
104
|
+
end
|
105
|
+
|
106
|
+
insn, operands = line.split(" ", 2)
|
107
|
+
|
108
|
+
case insn
|
109
|
+
when "adjuststack"
|
110
|
+
iseq.adjuststack(parse_number(operands))
|
111
|
+
when "anytostring"
|
112
|
+
iseq.anytostring
|
113
|
+
when "branchif"
|
114
|
+
iseq.branchif(labels[operands])
|
115
|
+
when "branchnil"
|
116
|
+
iseq.branchnil(labels[operands])
|
117
|
+
when "branchunless"
|
118
|
+
iseq.branchunless(labels[operands])
|
119
|
+
when "checkkeyword"
|
120
|
+
kwbits_index, keyword_index = operands.split(/,\s*/)
|
121
|
+
iseq.checkkeyword(
|
122
|
+
parse_number(kwbits_index),
|
123
|
+
parse_number(keyword_index)
|
124
|
+
)
|
125
|
+
when "checkmatch"
|
126
|
+
iseq.checkmatch(parse_number(operands))
|
127
|
+
when "checktype"
|
128
|
+
iseq.checktype(parse_number(operands))
|
129
|
+
when "concatarray"
|
130
|
+
iseq.concatarray
|
131
|
+
when "concatstrings"
|
132
|
+
iseq.concatstrings(parse_number(operands))
|
133
|
+
when "defineclass"
|
134
|
+
body = parse_nested(lines[line_index..])
|
135
|
+
line_index += body.length
|
136
|
+
|
137
|
+
name_value, flags_value = operands.split(/,\s*/)
|
138
|
+
name = parse_symbol(name_value)
|
139
|
+
flags = parse_number(flags_value)
|
140
|
+
|
141
|
+
class_iseq = iseq.class_child_iseq(name.to_s, Location.default)
|
142
|
+
assemble_iseq(class_iseq, body)
|
143
|
+
iseq.defineclass(name, class_iseq, flags)
|
144
|
+
when "defined"
|
145
|
+
type, object, message = operands.split(/,\s*/)
|
146
|
+
iseq.defined(
|
147
|
+
DEFINED_TYPES.index(type),
|
148
|
+
parse_symbol(object),
|
149
|
+
parse_string(message)
|
150
|
+
)
|
151
|
+
when "definemethod"
|
152
|
+
body = parse_nested(lines[line_index..])
|
153
|
+
line_index += body.length
|
154
|
+
|
155
|
+
name = parse_symbol(operands)
|
156
|
+
method_iseq = iseq.method_child_iseq(name.to_s, Location.default)
|
157
|
+
assemble_iseq(method_iseq, body)
|
158
|
+
|
159
|
+
iseq.definemethod(name, method_iseq)
|
160
|
+
when "definesmethod"
|
161
|
+
body = parse_nested(lines[line_index..])
|
162
|
+
line_index += body.length
|
163
|
+
|
164
|
+
name = parse_symbol(operands)
|
165
|
+
method_iseq = iseq.method_child_iseq(name.to_s, Location.default)
|
166
|
+
|
167
|
+
assemble_iseq(method_iseq, body)
|
168
|
+
iseq.definesmethod(name, method_iseq)
|
169
|
+
when "dup"
|
170
|
+
iseq.dup
|
171
|
+
when "dupn"
|
172
|
+
iseq.dupn(parse_number(operands))
|
173
|
+
when "duparray"
|
174
|
+
iseq.duparray(parse_type(operands, Array))
|
175
|
+
when "duphash"
|
176
|
+
iseq.duphash(parse_type(operands, Hash))
|
177
|
+
when "expandarray"
|
178
|
+
number, flags = operands.split(/,\s*/)
|
179
|
+
iseq.expandarray(parse_number(number), parse_number(flags))
|
180
|
+
when "getblockparam"
|
181
|
+
lookup = find_local(iseq, operands)
|
182
|
+
iseq.getblockparam(lookup.index, lookup.level)
|
183
|
+
when "getblockparamproxy"
|
184
|
+
lookup = find_local(iseq, operands)
|
185
|
+
iseq.getblockparamproxy(lookup.index, lookup.level)
|
186
|
+
when "getclassvariable"
|
187
|
+
iseq.getclassvariable(parse_symbol(operands))
|
188
|
+
when "getconstant"
|
189
|
+
iseq.getconstant(parse_symbol(operands))
|
190
|
+
when "getglobal"
|
191
|
+
iseq.getglobal(parse_symbol(operands))
|
192
|
+
when "getinstancevariable"
|
193
|
+
iseq.getinstancevariable(parse_symbol(operands))
|
194
|
+
when "getlocal"
|
195
|
+
lookup = find_local(iseq, operands)
|
196
|
+
iseq.getlocal(lookup.index, lookup.level)
|
197
|
+
when "getspecial"
|
198
|
+
key, type = operands.split(/,\s*/)
|
199
|
+
iseq.getspecial(parse_number(key), parse_number(type))
|
200
|
+
when "intern"
|
201
|
+
iseq.intern
|
202
|
+
when "invokeblock"
|
203
|
+
iseq.invokeblock(
|
204
|
+
operands ? parse_calldata(operands) : YARV.calldata(nil, 0)
|
205
|
+
)
|
206
|
+
when "invokesuper"
|
207
|
+
calldata =
|
208
|
+
if operands
|
209
|
+
parse_calldata(operands)
|
210
|
+
else
|
211
|
+
YARV.calldata(
|
212
|
+
nil,
|
213
|
+
0,
|
214
|
+
CallData::CALL_FCALL | CallData::CALL_ARGS_SIMPLE |
|
215
|
+
CallData::CALL_SUPER
|
216
|
+
)
|
217
|
+
end
|
218
|
+
|
219
|
+
block_iseq =
|
220
|
+
if lines[line_index].start_with?(" ")
|
221
|
+
body = parse_nested(lines[line_index..])
|
222
|
+
line_index += body.length
|
223
|
+
|
224
|
+
block_iseq = iseq.block_child_iseq(Location.default)
|
225
|
+
assemble_iseq(block_iseq, body)
|
226
|
+
block_iseq
|
227
|
+
end
|
228
|
+
|
229
|
+
iseq.invokesuper(calldata, block_iseq)
|
230
|
+
when "jump"
|
231
|
+
iseq.jump(labels[operands])
|
232
|
+
when "leave"
|
233
|
+
iseq.leave
|
234
|
+
when "newarray"
|
235
|
+
iseq.newarray(parse_number(operands))
|
236
|
+
when "newarraykwsplat"
|
237
|
+
iseq.newarraykwsplat(parse_number(operands))
|
238
|
+
when "newhash"
|
239
|
+
iseq.newhash(parse_number(operands))
|
240
|
+
when "newrange"
|
241
|
+
iseq.newrange(parse_options(operands, [0, 1]))
|
242
|
+
when "nop"
|
243
|
+
iseq.nop
|
244
|
+
when "objtostring"
|
245
|
+
iseq.objtostring(YARV.calldata(:to_s))
|
246
|
+
when "once"
|
247
|
+
block_iseq =
|
248
|
+
if lines[line_index].start_with?(" ")
|
249
|
+
body = parse_nested(lines[line_index..])
|
250
|
+
line_index += body.length
|
251
|
+
|
252
|
+
block_iseq = iseq.block_child_iseq(Location.default)
|
253
|
+
assemble_iseq(block_iseq, body)
|
254
|
+
block_iseq
|
255
|
+
end
|
256
|
+
|
257
|
+
iseq.once(block_iseq, iseq.inline_storage)
|
258
|
+
when "opt_and"
|
259
|
+
iseq.send(YARV.calldata(:&, 1))
|
260
|
+
when "opt_aref"
|
261
|
+
iseq.send(YARV.calldata(:[], 1))
|
262
|
+
when "opt_aref_with"
|
263
|
+
iseq.opt_aref_with(parse_string(operands), YARV.calldata(:[], 1))
|
264
|
+
when "opt_aset"
|
265
|
+
iseq.send(YARV.calldata(:[]=, 2))
|
266
|
+
when "opt_aset_with"
|
267
|
+
iseq.opt_aset_with(parse_string(operands), YARV.calldata(:[]=, 2))
|
268
|
+
when "opt_case_dispatch"
|
269
|
+
cdhash_value, else_label_value = operands.split(/\s*\},\s*/)
|
270
|
+
cdhash_value.sub!(/\A\{/, "")
|
271
|
+
|
272
|
+
pairs =
|
273
|
+
cdhash_value
|
274
|
+
.split(/\s*,\s*/)
|
275
|
+
.map! { |pair| pair.split(/\s*=>\s*/) }
|
276
|
+
|
277
|
+
cdhash = pairs.to_h { |value, nm| [parse(value), labels[nm]] }
|
278
|
+
else_label = labels[else_label_value]
|
279
|
+
|
280
|
+
iseq.opt_case_dispatch(cdhash, else_label)
|
281
|
+
when "opt_div"
|
282
|
+
iseq.send(YARV.calldata(:/, 1))
|
283
|
+
when "opt_empty_p"
|
284
|
+
iseq.send(YARV.calldata(:empty?))
|
285
|
+
when "opt_eq"
|
286
|
+
iseq.send(YARV.calldata(:==, 1))
|
287
|
+
when "opt_ge"
|
288
|
+
iseq.send(YARV.calldata(:>=, 1))
|
289
|
+
when "opt_gt"
|
290
|
+
iseq.send(YARV.calldata(:>, 1))
|
291
|
+
when "opt_getconstant_path"
|
292
|
+
iseq.opt_getconstant_path(parse_type(operands, Array))
|
293
|
+
when "opt_le"
|
294
|
+
iseq.send(YARV.calldata(:<=, 1))
|
295
|
+
when "opt_length"
|
296
|
+
iseq.send(YARV.calldata(:length))
|
297
|
+
when "opt_lt"
|
298
|
+
iseq.send(YARV.calldata(:<, 1))
|
299
|
+
when "opt_ltlt"
|
300
|
+
iseq.send(YARV.calldata(:<<, 1))
|
301
|
+
when "opt_minus"
|
302
|
+
iseq.send(YARV.calldata(:-, 1))
|
303
|
+
when "opt_mod"
|
304
|
+
iseq.send(YARV.calldata(:%, 1))
|
305
|
+
when "opt_mult"
|
306
|
+
iseq.send(YARV.calldata(:*, 1))
|
307
|
+
when "opt_neq"
|
308
|
+
iseq.send(YARV.calldata(:!=, 1))
|
309
|
+
when "opt_newarray_max"
|
310
|
+
iseq.newarray(parse_number(operands))
|
311
|
+
iseq.send(YARV.calldata(:max))
|
312
|
+
when "opt_newarray_min"
|
313
|
+
iseq.newarray(parse_number(operands))
|
314
|
+
iseq.send(YARV.calldata(:min))
|
315
|
+
when "opt_nil_p"
|
316
|
+
iseq.send(YARV.calldata(:nil?))
|
317
|
+
when "opt_not"
|
318
|
+
iseq.send(YARV.calldata(:!))
|
319
|
+
when "opt_or"
|
320
|
+
iseq.send(YARV.calldata(:|, 1))
|
321
|
+
when "opt_plus"
|
322
|
+
iseq.send(YARV.calldata(:+, 1))
|
323
|
+
when "opt_regexpmatch2"
|
324
|
+
iseq.send(YARV.calldata(:=~, 1))
|
325
|
+
when "opt_reverse"
|
326
|
+
iseq.send(YARV.calldata(:reverse))
|
327
|
+
when "opt_send_without_block"
|
328
|
+
iseq.send(parse_calldata(operands))
|
329
|
+
when "opt_size"
|
330
|
+
iseq.send(YARV.calldata(:size))
|
331
|
+
when "opt_str_freeze"
|
332
|
+
iseq.putstring(parse_string(operands))
|
333
|
+
iseq.send(YARV.calldata(:freeze))
|
334
|
+
when "opt_str_uminus"
|
335
|
+
iseq.putstring(parse_string(operands))
|
336
|
+
iseq.send(YARV.calldata(:-@))
|
337
|
+
when "opt_succ"
|
338
|
+
iseq.send(YARV.calldata(:succ))
|
339
|
+
when "pop"
|
340
|
+
iseq.pop
|
341
|
+
when "putnil"
|
342
|
+
iseq.putnil
|
343
|
+
when "putobject"
|
344
|
+
iseq.putobject(parse(operands))
|
345
|
+
when "putself"
|
346
|
+
iseq.putself
|
347
|
+
when "putspecialobject"
|
348
|
+
iseq.putspecialobject(parse_options(operands, [1, 2, 3]))
|
349
|
+
when "putstring"
|
350
|
+
iseq.putstring(parse_string(operands))
|
351
|
+
when "send"
|
352
|
+
block_iseq =
|
353
|
+
if lines[line_index].start_with?(" ")
|
354
|
+
body = parse_nested(lines[line_index..])
|
355
|
+
line_index += body.length
|
356
|
+
|
357
|
+
block_iseq = iseq.block_child_iseq(Location.default)
|
358
|
+
assemble_iseq(block_iseq, body)
|
359
|
+
block_iseq
|
360
|
+
end
|
361
|
+
|
362
|
+
iseq.send(parse_calldata(operands), block_iseq)
|
363
|
+
when "setblockparam"
|
364
|
+
lookup = find_local(iseq, operands)
|
365
|
+
iseq.setblockparam(lookup.index, lookup.level)
|
366
|
+
when "setconstant"
|
367
|
+
iseq.setconstant(parse_symbol(operands))
|
368
|
+
when "setglobal"
|
369
|
+
iseq.setglobal(parse_symbol(operands))
|
370
|
+
when "setlocal"
|
371
|
+
lookup = find_local(iseq, operands)
|
372
|
+
iseq.setlocal(lookup.index, lookup.level)
|
373
|
+
when "setn"
|
374
|
+
iseq.setn(parse_number(operands))
|
375
|
+
when "setclassvariable"
|
376
|
+
iseq.setclassvariable(parse_symbol(operands))
|
377
|
+
when "setinstancevariable"
|
378
|
+
iseq.setinstancevariable(parse_symbol(operands))
|
379
|
+
when "setspecial"
|
380
|
+
iseq.setspecial(parse_number(operands))
|
381
|
+
when "splatarray"
|
382
|
+
iseq.splatarray(parse_options(operands, [true, false]))
|
383
|
+
when "swap"
|
384
|
+
iseq.swap
|
385
|
+
when "throw"
|
386
|
+
iseq.throw(parse_number(operands))
|
387
|
+
when "topn"
|
388
|
+
iseq.topn(parse_number(operands))
|
389
|
+
when "toregexp"
|
390
|
+
options, length = operands.split(", ")
|
391
|
+
iseq.toregexp(parse_number(options), parse_number(length))
|
392
|
+
when "ARG_REQ"
|
393
|
+
iseq.argument_size += 1
|
394
|
+
iseq.local_table.plain(operands.to_sym)
|
395
|
+
when "ARG_BLOCK"
|
396
|
+
iseq.argument_options[:block_start] = iseq.argument_size
|
397
|
+
iseq.local_table.block(operands.to_sym)
|
398
|
+
iseq.argument_size += 1
|
399
|
+
else
|
400
|
+
raise "Could not understand: #{line}"
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
def find_local(iseq, operands)
|
406
|
+
name_string, level_string = operands.split(/,\s*/)
|
407
|
+
name = name_string.to_sym
|
408
|
+
level = level_string&.to_i || 0
|
409
|
+
|
410
|
+
iseq.local_table.plain(name)
|
411
|
+
iseq.local_table.find(name, level)
|
412
|
+
end
|
413
|
+
|
414
|
+
def parse(value)
|
415
|
+
program = SyntaxTree.parse(value)
|
416
|
+
raise if program.statements.body.length != 1
|
417
|
+
|
418
|
+
program.statements.body.first.accept(ObjectVisitor.new)
|
419
|
+
end
|
420
|
+
|
421
|
+
def parse_options(value, options)
|
422
|
+
parse(value).tap { raise unless options.include?(_1) }
|
423
|
+
end
|
424
|
+
|
425
|
+
def parse_type(value, type)
|
426
|
+
parse(value).tap { raise unless _1.is_a?(type) }
|
427
|
+
end
|
428
|
+
|
429
|
+
def parse_number(value)
|
430
|
+
parse_type(value, Integer)
|
431
|
+
end
|
432
|
+
|
433
|
+
def parse_string(value)
|
434
|
+
parse_type(value, String)
|
435
|
+
end
|
436
|
+
|
437
|
+
def parse_symbol(value)
|
438
|
+
parse_type(value, Symbol)
|
439
|
+
end
|
440
|
+
|
441
|
+
def parse_nested(lines)
|
442
|
+
body = lines.take_while { |line| line.match?(/^($|;| )/) }
|
443
|
+
body.map! { |line| line.delete_prefix!(" ") || +"" }
|
444
|
+
end
|
445
|
+
|
446
|
+
def parse_calldata(value)
|
447
|
+
message, argc_value, flags_value = value.split
|
448
|
+
flags =
|
449
|
+
if flags_value
|
450
|
+
flags_value.split("|").map(&CALLDATA_FLAGS).inject(:|)
|
451
|
+
else
|
452
|
+
CallData::CALL_ARGS_SIMPLE
|
453
|
+
end
|
454
|
+
|
455
|
+
YARV.calldata(message.to_sym, argc_value&.to_i || 0, flags)
|
456
|
+
end
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end
|