syntax_tree 4.2.0 → 5.0.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.
@@ -75,98 +75,213 @@ module SyntaxTree
75
75
 
76
76
  private
77
77
 
78
+ # Shortcut for combining two procs into one that returns true if both return
79
+ # true.
78
80
  def combine_and(left, right)
79
- ->(node) { left.call(node) && right.call(node) }
81
+ ->(other) { left.call(other) && right.call(other) }
80
82
  end
81
83
 
84
+ # Shortcut for combining two procs into one that returns true if either
85
+ # returns true.
82
86
  def combine_or(left, right)
83
- ->(node) { left.call(node) || right.call(node) }
87
+ ->(other) { left.call(other) || right.call(other) }
84
88
  end
85
89
 
86
- def compile_node(root)
87
- case root
88
- in AryPtn[constant:, requireds:, rest: nil, posts: []]
89
- compiled_constant = compile_node(constant) if constant
90
+ # Raise an error because the given node is not supported.
91
+ def compile_error(node)
92
+ raise CompilationError, PP.pp(node, +"").chomp
93
+ end
94
+
95
+ # There are a couple of nodes (string literals, dynamic symbols, and regexp)
96
+ # that contain list of parts. This can include plain string content,
97
+ # interpolated expressions, and interpolated variables. We only support
98
+ # plain string content, so this method will extract out the plain string
99
+ # content if it is the only element in the list.
100
+ def extract_string(node)
101
+ parts = node.parts
90
102
 
91
- preprocessed = requireds.map { |required| compile_node(required) }
103
+ if parts.length == 1 && (part = parts.first) && part.is_a?(TStringContent)
104
+ part.value
105
+ end
106
+ end
92
107
 
93
- compiled_requireds = ->(node) do
94
- deconstructed = node.deconstruct
108
+ # in [foo, bar, baz]
109
+ def compile_aryptn(node)
110
+ compile_error(node) if !node.rest.nil? || node.posts.any?
95
111
 
96
- deconstructed.length == preprocessed.length &&
97
- preprocessed
98
- .zip(deconstructed)
99
- .all? { |(matcher, value)| matcher.call(value) }
100
- end
112
+ constant = node.constant
113
+ compiled_constant = compile_node(constant) if constant
101
114
 
102
- if compiled_constant
103
- combine_and(compiled_constant, compiled_requireds)
104
- else
105
- compiled_requireds
106
- end
107
- in Binary[left:, operator: :|, right:]
108
- combine_or(compile_node(left), compile_node(right))
109
- in Const[value:] if SyntaxTree.const_defined?(value)
115
+ preprocessed = node.requireds.map { |required| compile_node(required) }
116
+
117
+ compiled_requireds = ->(other) do
118
+ deconstructed = other.deconstruct
119
+
120
+ deconstructed.length == preprocessed.length &&
121
+ preprocessed
122
+ .zip(deconstructed)
123
+ .all? { |(matcher, value)| matcher.call(value) }
124
+ end
125
+
126
+ if compiled_constant
127
+ combine_and(compiled_constant, compiled_requireds)
128
+ else
129
+ compiled_requireds
130
+ end
131
+ end
132
+
133
+ # in foo | bar
134
+ def compile_binary(node)
135
+ compile_error(node) if node.operator != :|
136
+
137
+ combine_or(compile_node(node.left), compile_node(node.right))
138
+ end
139
+
140
+ # in Ident
141
+ # in String
142
+ def compile_const(node)
143
+ value = node.value
144
+
145
+ if SyntaxTree.const_defined?(value, false)
110
146
  clazz = SyntaxTree.const_get(value)
111
147
 
112
- ->(node) { node.is_a?(clazz) }
113
- in Const[value:] if Object.const_defined?(value)
148
+ ->(other) { clazz === other }
149
+ elsif Object.const_defined?(value, false)
114
150
  clazz = Object.const_get(value)
115
151
 
116
- ->(node) { node.is_a?(clazz) }
117
- in ConstPathRef[
118
- parent: VarRef[value: Const[value: "SyntaxTree"]], constant:
119
- ]
120
- compile_node(constant)
121
- in DynaSymbol[parts: []]
152
+ ->(other) { clazz === other }
153
+ else
154
+ compile_error(node)
155
+ end
156
+ end
157
+
158
+ # in SyntaxTree::Ident
159
+ def compile_const_path_ref(node)
160
+ parent = node.parent
161
+ compile_error(node) if !parent.is_a?(VarRef) || !parent.value.is_a?(Const)
162
+
163
+ if parent.value.value == "SyntaxTree"
164
+ compile_node(node.constant)
165
+ else
166
+ compile_error(node)
167
+ end
168
+ end
169
+
170
+ # in :""
171
+ # in :"foo"
172
+ def compile_dyna_symbol(node)
173
+ if node.parts.empty?
122
174
  symbol = :""
123
175
 
124
- ->(node) { node == symbol }
125
- in DynaSymbol[parts: [TStringContent[value:]]]
176
+ ->(other) { symbol === other }
177
+ elsif (value = extract_string(node))
126
178
  symbol = value.to_sym
127
179
 
128
- ->(attribute) { attribute == value }
129
- in HshPtn[constant:, keywords:, keyword_rest: nil]
130
- compiled_constant = compile_node(constant)
131
-
132
- preprocessed =
133
- keywords.to_h do |keyword, value|
134
- raise NoMatchingPatternError unless keyword.is_a?(Label)
135
- [keyword.value.chomp(":").to_sym, compile_node(value)]
136
- end
180
+ ->(other) { symbol === other }
181
+ else
182
+ compile_error(node)
183
+ end
184
+ end
137
185
 
138
- compiled_keywords = ->(node) do
139
- deconstructed = node.deconstruct_keys(preprocessed.keys)
186
+ # in Ident[value: String]
187
+ # in { value: String }
188
+ def compile_hshptn(node)
189
+ compile_error(node) unless node.keyword_rest.nil?
190
+ compiled_constant = compile_node(node.constant) if node.constant
140
191
 
141
- preprocessed.all? do |keyword, matcher|
142
- matcher.call(deconstructed[keyword])
143
- end
192
+ preprocessed =
193
+ node.keywords.to_h do |keyword, value|
194
+ compile_error(node) unless keyword.is_a?(Label)
195
+ [keyword.value.chomp(":").to_sym, compile_node(value)]
144
196
  end
145
197
 
146
- if compiled_constant
147
- combine_and(compiled_constant, compiled_keywords)
148
- else
149
- compiled_keywords
198
+ compiled_keywords = ->(other) do
199
+ deconstructed = other.deconstruct_keys(preprocessed.keys)
200
+
201
+ preprocessed.all? do |keyword, matcher|
202
+ matcher.call(deconstructed[keyword])
150
203
  end
151
- in RegexpLiteral[parts: [TStringContent[value:]]]
204
+ end
205
+
206
+ if compiled_constant
207
+ combine_and(compiled_constant, compiled_keywords)
208
+ else
209
+ compiled_keywords
210
+ end
211
+ end
212
+
213
+ # in /foo/
214
+ def compile_regexp_literal(node)
215
+ if (value = extract_string(node))
152
216
  regexp = /#{value}/
153
217
 
154
- ->(attribute) { regexp.match?(attribute) }
155
- in StringLiteral[parts: []]
156
- ->(attribute) { attribute == "" }
157
- in StringLiteral[parts: [TStringContent[value:]]]
158
- ->(attribute) { attribute == value }
159
- in SymbolLiteral[value:]
160
- symbol = value.value.to_sym
218
+ ->(attribute) { regexp === attribute }
219
+ else
220
+ compile_error(node)
221
+ end
222
+ end
223
+
224
+ # in ""
225
+ # in "foo"
226
+ def compile_string_literal(node)
227
+ if node.parts.empty?
228
+ ->(attribute) { "" === attribute }
229
+ elsif (value = extract_string(node))
230
+ ->(attribute) { value === attribute }
231
+ else
232
+ compile_error(node)
233
+ end
234
+ end
235
+
236
+ # in :+
237
+ # in :foo
238
+ def compile_symbol_literal(node)
239
+ symbol = node.value.value.to_sym
161
240
 
162
- ->(attribute) { attribute == symbol }
163
- in VarRef[value: Const => value]
241
+ ->(attribute) { symbol === attribute }
242
+ end
243
+
244
+ # in Foo
245
+ # in nil
246
+ def compile_var_ref(node)
247
+ value = node.value
248
+
249
+ if value.is_a?(Const)
164
250
  compile_node(value)
165
- in VarRef[value: Kw[value: "nil"]]
166
- ->(attribute) { attribute.nil? }
251
+ elsif value.is_a?(Kw) && value.value.nil?
252
+ ->(attribute) { nil === attribute }
253
+ else
254
+ compile_error(node)
255
+ end
256
+ end
257
+
258
+ # Compile any kind of node. Dispatch out to the individual compilation
259
+ # methods based on the type of node.
260
+ def compile_node(node)
261
+ case node
262
+ when AryPtn
263
+ compile_aryptn(node)
264
+ when Binary
265
+ compile_binary(node)
266
+ when Const
267
+ compile_const(node)
268
+ when ConstPathRef
269
+ compile_const_path_ref(node)
270
+ when DynaSymbol
271
+ compile_dyna_symbol(node)
272
+ when HshPtn
273
+ compile_hshptn(node)
274
+ when RegexpLiteral
275
+ compile_regexp_literal(node)
276
+ when StringLiteral
277
+ compile_string_literal(node)
278
+ when SymbolLiteral
279
+ compile_symbol_literal(node)
280
+ when VarRef
281
+ compile_var_ref(node)
282
+ else
283
+ compile_error(node)
167
284
  end
168
- rescue NoMatchingPatternError
169
- raise CompilationError, PP.pp(root, +"").chomp
170
285
  end
171
286
  end
172
287
  end
@@ -1,3 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- SyntaxTree::Formatter::OPTIONS[:quote] = "'"
3
+ module SyntaxTree
4
+ class Formatter
5
+ SINGLE_QUOTES = true
6
+ end
7
+ end
@@ -1,3 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- SyntaxTree::Formatter::OPTIONS[:trailing_comma] = true
3
+ module SyntaxTree
4
+ class Formatter
5
+ TRAILING_COMMA = true
6
+ end
7
+ end
@@ -78,7 +78,7 @@ module SyntaxTree
78
78
 
79
79
  arguments << "--ignore-files=#{ignore_files}" if ignore_files != ""
80
80
 
81
- SyntaxTree::CLI.run(arguments + Array(source_files))
81
+ abort if SyntaxTree::CLI.run(arguments + Array(source_files)) != 0
82
82
  end
83
83
  end
84
84
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SyntaxTree
4
- VERSION = "4.2.0"
4
+ VERSION = "5.0.0"
5
5
  end
@@ -4,10 +4,6 @@ module SyntaxTree
4
4
  # The environment class is used to keep track of local variables and arguments
5
5
  # inside a particular scope
6
6
  class Environment
7
- # [Array[Local]] The local variables and arguments defined in this
8
- # environment
9
- attr_reader :locals
10
-
11
7
  # This class tracks the occurrences of a local variable or argument
12
8
  class Local
13
9
  # [Symbol] The type of the local (e.g. :argument, :variable)
@@ -38,6 +34,13 @@ module SyntaxTree
38
34
  end
39
35
  end
40
36
 
37
+ # [Array[Local]] The local variables and arguments defined in this
38
+ # environment
39
+ attr_reader :locals
40
+
41
+ # [Environment | nil] The parent environment
42
+ attr_reader :parent
43
+
41
44
  # initialize: (Environment | nil parent) -> void
42
45
  def initialize(parent = nil)
43
46
  @locals = {}
@@ -103,7 +103,7 @@ module SyntaxTree
103
103
  end
104
104
 
105
105
  def visit_args_forward(node)
106
- visit_token(node, "args_forward")
106
+ node(node, "args_forward") { comments(node) }
107
107
  end
108
108
 
109
109
  def visit_array(node)
@@ -184,6 +184,14 @@ module SyntaxTree
184
184
  end
185
185
  end
186
186
 
187
+ def visit_block(node)
188
+ node(node, "block") do
189
+ field("block_var", node.block_var) if node.block_var
190
+ field("bodystmt", node.bodystmt)
191
+ comments(node)
192
+ end
193
+ end
194
+
187
195
  def visit_blockarg(node)
188
196
  node(node, "blockarg") do
189
197
  field("name", node.name) if node.name
@@ -209,14 +217,6 @@ module SyntaxTree
209
217
  end
210
218
  end
211
219
 
212
- def visit_brace_block(node)
213
- node(node, "brace_block") do
214
- field("block_var", node.block_var) if node.block_var
215
- field("statements", node.statements)
216
- comments(node)
217
- end
218
- end
219
-
220
220
  def visit_break(node)
221
221
  node(node, "break") do
222
222
  field("arguments", node.arguments)
@@ -315,6 +315,8 @@ module SyntaxTree
315
315
 
316
316
  def visit_def(node)
317
317
  node(node, "def") do
318
+ field("target", node.target)
319
+ field("operator", node.operator)
318
320
  field("name", node.name)
319
321
  field("params", node.params)
320
322
  field("bodystmt", node.bodystmt)
@@ -322,20 +324,6 @@ module SyntaxTree
322
324
  end
323
325
  end
324
326
 
325
- def visit_def_endless(node)
326
- node(node, "def_endless") do
327
- if node.target
328
- field("target", node.target)
329
- field("operator", node.operator)
330
- end
331
-
332
- field("name", node.name)
333
- field("paren", node.paren) if node.paren
334
- field("statement", node.statement)
335
- comments(node)
336
- end
337
- end
338
-
339
327
  def visit_defined(node)
340
328
  node(node, "defined") do
341
329
  field("value", node.value)
@@ -343,41 +331,6 @@ module SyntaxTree
343
331
  end
344
332
  end
345
333
 
346
- def visit_defs(node)
347
- node(node, "defs") do
348
- field("target", node.target)
349
- field("operator", node.operator)
350
- field("name", node.name)
351
- field("params", node.params)
352
- field("bodystmt", node.bodystmt)
353
- comments(node)
354
- end
355
- end
356
-
357
- def visit_do_block(node)
358
- node(node, "do_block") do
359
- field("block_var", node.block_var) if node.block_var
360
- field("bodystmt", node.bodystmt)
361
- comments(node)
362
- end
363
- end
364
-
365
- def visit_dot2(node)
366
- node(node, "dot2") do
367
- field("left", node.left) if node.left
368
- field("right", node.right) if node.right
369
- comments(node)
370
- end
371
- end
372
-
373
- def visit_dot3(node)
374
- node(node, "dot3") do
375
- field("left", node.left) if node.left
376
- field("right", node.right) if node.right
377
- comments(node)
378
- end
379
- end
380
-
381
334
  def visit_dyna_symbol(node)
382
335
  node(node, "dyna_symbol") do
383
336
  list("parts", node.parts)
@@ -435,14 +388,6 @@ module SyntaxTree
435
388
  visit_token(node, "excessed_comma")
436
389
  end
437
390
 
438
- def visit_fcall(node)
439
- node(node, "fcall") do
440
- field("value", node.value)
441
- field("arguments", node.arguments) if node.arguments
442
- comments(node)
443
- end
444
- end
445
-
446
391
  def visit_field(node)
447
392
  node(node, "field") do
448
393
  field("parent", node.parent)
@@ -523,14 +468,6 @@ module SyntaxTree
523
468
  end
524
469
  end
525
470
 
526
- def visit_if_mod(node)
527
- node(node, "if_mod") do
528
- field("statement", node.statement)
529
- field("predicate", node.predicate)
530
- comments(node)
531
- end
532
- end
533
-
534
471
  def visit_if_op(node)
535
472
  node(node, "if_op") do
536
473
  field("predicate", node.predicate)
@@ -747,6 +684,15 @@ module SyntaxTree
747
684
  node(node, "qwords_beg") { field("value", node.value) }
748
685
  end
749
686
 
687
+ def visit_range(node)
688
+ node(node, "range") do
689
+ field("left", node.left) if node.left
690
+ field("operator", node.operator)
691
+ field("right", node.right) if node.right
692
+ comments(node)
693
+ end
694
+ end
695
+
750
696
  def visit_rassign(node)
751
697
  node(node, "rassign") do
752
698
  field("value", node.value)
@@ -769,7 +715,7 @@ module SyntaxTree
769
715
  end
770
716
 
771
717
  def visit_redo(node)
772
- visit_token(node, "redo")
718
+ node(node, "redo") { comments(node) }
773
719
  end
774
720
 
775
721
  def visit_regexp_beg(node)
@@ -825,7 +771,7 @@ module SyntaxTree
825
771
  end
826
772
 
827
773
  def visit_retry(node)
828
- visit_token(node, "retry")
774
+ node(node, "retry") { comments(node) }
829
775
  end
830
776
 
831
777
  def visit_return(node)
@@ -835,10 +781,6 @@ module SyntaxTree
835
781
  end
836
782
  end
837
783
 
838
- def visit_return0(node)
839
- visit_token(node, "return0")
840
- end
841
-
842
784
  def visit_rparen(node)
843
785
  node(node, "rparen") { field("value", node.value) }
844
786
  end
@@ -982,14 +924,6 @@ module SyntaxTree
982
924
  end
983
925
  end
984
926
 
985
- def visit_unless_mod(node)
986
- node(node, "unless_mod") do
987
- field("statement", node.statement)
988
- field("predicate", node.predicate)
989
- comments(node)
990
- end
991
- end
992
-
993
927
  def visit_until(node)
994
928
  node(node, "until") do
995
929
  field("predicate", node.predicate)
@@ -998,22 +932,6 @@ module SyntaxTree
998
932
  end
999
933
  end
1000
934
 
1001
- def visit_until_mod(node)
1002
- node(node, "until_mod") do
1003
- field("statement", node.statement)
1004
- field("predicate", node.predicate)
1005
- comments(node)
1006
- end
1007
- end
1008
-
1009
- def visit_var_alias(node)
1010
- node(node, "var_alias") do
1011
- field("left", node.left)
1012
- field("right", node.right)
1013
- comments(node)
1014
- end
1015
- end
1016
-
1017
935
  def visit_var_field(node)
1018
936
  node(node, "var_field") do
1019
937
  field("value", node.value)
@@ -1056,14 +974,6 @@ module SyntaxTree
1056
974
  end
1057
975
  end
1058
976
 
1059
- def visit_while_mod(node)
1060
- node(node, "while_mod") do
1061
- field("statement", node.statement)
1062
- field("predicate", node.predicate)
1063
- comments(node)
1064
- end
1065
- end
1066
-
1067
977
  def visit_word(node)
1068
978
  node(node, "word") do
1069
979
  list("parts", node.parts)
@@ -1100,12 +1010,8 @@ module SyntaxTree
1100
1010
  end
1101
1011
  end
1102
1012
 
1103
- def visit_yield0(node)
1104
- visit_token(node, "yield0")
1105
- end
1106
-
1107
1013
  def visit_zsuper(node)
1108
- visit_token(node, "zsuper")
1014
+ node(node, "zsuper") { comments(node) }
1109
1015
  end
1110
1016
 
1111
1017
  def visit___end__(node)