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.
@@ -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
@@ -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, Heredoc, IfNode,
6187
- IfOp, Lambda, MAssign, Next, OpAssign, RescueMod, ReturnNode,
6188
- Super, Undef, UnlessNode, UntilNode, VoidStmt, WhileNode,
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
@@ -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 (keyword = find_keyword(:case))
998
- tokens.delete(keyword)
999
-
1000
- Case.new(
1001
- keyword: keyword,
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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SyntaxTree
4
- VERSION = "5.0.0"
4
+ VERSION = "5.1.0"
5
5
  end
@@ -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