jruby-prism-parser 0.23.0.pre.SNAPSHOT-java → 1.4.0-java

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.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/BSDmakefile +58 -0
  3. data/CHANGELOG.md +284 -1
  4. data/CONTRIBUTING.md +0 -4
  5. data/Makefile +25 -18
  6. data/README.md +57 -6
  7. data/config.yml +1724 -140
  8. data/docs/build_system.md +39 -11
  9. data/docs/configuration.md +4 -0
  10. data/docs/cruby_compilation.md +1 -1
  11. data/docs/fuzzing.md +1 -1
  12. data/docs/parser_translation.md +14 -9
  13. data/docs/parsing_rules.md +4 -1
  14. data/docs/releasing.md +9 -11
  15. data/docs/relocation.md +34 -0
  16. data/docs/ripper_translation.md +72 -0
  17. data/docs/ruby_api.md +2 -1
  18. data/docs/serialization.md +29 -5
  19. data/ext/prism/api_node.c +3841 -2000
  20. data/ext/prism/api_pack.c +9 -0
  21. data/ext/prism/extconf.rb +55 -34
  22. data/ext/prism/extension.c +597 -346
  23. data/ext/prism/extension.h +6 -5
  24. data/include/prism/ast.h +2612 -455
  25. data/include/prism/defines.h +160 -2
  26. data/include/prism/diagnostic.h +188 -76
  27. data/include/prism/encoding.h +22 -4
  28. data/include/prism/node.h +89 -17
  29. data/include/prism/options.h +224 -12
  30. data/include/prism/pack.h +11 -0
  31. data/include/prism/parser.h +267 -66
  32. data/include/prism/prettyprint.h +8 -0
  33. data/include/prism/regexp.h +18 -8
  34. data/include/prism/static_literals.h +121 -0
  35. data/include/prism/util/pm_buffer.h +75 -2
  36. data/include/prism/util/pm_char.h +1 -2
  37. data/include/prism/util/pm_constant_pool.h +18 -9
  38. data/include/prism/util/pm_integer.h +126 -0
  39. data/include/prism/util/pm_list.h +1 -1
  40. data/include/prism/util/pm_newline_list.h +23 -3
  41. data/include/prism/util/pm_string.h +48 -8
  42. data/include/prism/version.h +3 -3
  43. data/include/prism.h +99 -5
  44. data/jruby-prism.jar +0 -0
  45. data/lib/prism/compiler.rb +11 -1
  46. data/lib/prism/desugar_compiler.rb +264 -80
  47. data/lib/prism/dispatcher.rb +45 -1
  48. data/lib/prism/dot_visitor.rb +201 -77
  49. data/lib/prism/dsl.rb +672 -457
  50. data/lib/prism/ffi.rb +308 -94
  51. data/lib/prism/inspect_visitor.rb +2389 -0
  52. data/lib/prism/lex_compat.rb +35 -16
  53. data/lib/prism/mutation_compiler.rb +24 -8
  54. data/lib/prism/node.rb +9712 -8931
  55. data/lib/prism/node_ext.rb +328 -32
  56. data/lib/prism/pack.rb +4 -0
  57. data/lib/prism/parse_result/comments.rb +34 -24
  58. data/lib/prism/parse_result/errors.rb +65 -0
  59. data/lib/prism/parse_result/newlines.rb +102 -12
  60. data/lib/prism/parse_result.rb +458 -46
  61. data/lib/prism/pattern.rb +28 -10
  62. data/lib/prism/polyfill/append_as_bytes.rb +15 -0
  63. data/lib/prism/polyfill/byteindex.rb +13 -0
  64. data/lib/prism/polyfill/unpack1.rb +14 -0
  65. data/lib/prism/reflection.rb +413 -0
  66. data/lib/prism/relocation.rb +504 -0
  67. data/lib/prism/serialize.rb +1940 -902
  68. data/lib/prism/string_query.rb +30 -0
  69. data/lib/prism/translation/parser/builder.rb +61 -0
  70. data/lib/prism/translation/parser/compiler.rb +569 -195
  71. data/lib/prism/translation/parser/lexer.rb +516 -39
  72. data/lib/prism/translation/parser.rb +188 -11
  73. data/lib/prism/translation/parser33.rb +12 -0
  74. data/lib/prism/translation/parser34.rb +12 -0
  75. data/lib/prism/translation/parser35.rb +12 -0
  76. data/lib/prism/translation/ripper/sexp.rb +125 -0
  77. data/lib/prism/translation/ripper/shim.rb +5 -0
  78. data/lib/prism/translation/ripper.rb +3267 -386
  79. data/lib/prism/translation/ruby_parser.rb +194 -69
  80. data/lib/prism/translation.rb +4 -1
  81. data/lib/prism/version.rb +1 -1
  82. data/lib/prism/visitor.rb +13 -0
  83. data/lib/prism.rb +17 -27
  84. data/prism.gemspec +59 -17
  85. data/rbi/prism/compiler.rbi +12 -0
  86. data/rbi/prism/dsl.rbi +524 -0
  87. data/rbi/prism/inspect_visitor.rbi +12 -0
  88. data/rbi/prism/node.rbi +8722 -0
  89. data/rbi/prism/node_ext.rbi +107 -0
  90. data/rbi/prism/parse_result.rbi +404 -0
  91. data/rbi/prism/reflection.rbi +58 -0
  92. data/rbi/prism/string_query.rbi +12 -0
  93. data/rbi/prism/translation/parser.rbi +11 -0
  94. data/rbi/prism/translation/parser33.rbi +6 -0
  95. data/rbi/prism/translation/parser34.rbi +6 -0
  96. data/rbi/prism/translation/parser35.rbi +6 -0
  97. data/rbi/prism/translation/ripper.rbi +15 -0
  98. data/rbi/prism/visitor.rbi +473 -0
  99. data/rbi/prism.rbi +44 -7745
  100. data/sig/prism/compiler.rbs +9 -0
  101. data/sig/prism/dispatcher.rbs +16 -0
  102. data/sig/prism/dot_visitor.rbs +6 -0
  103. data/sig/prism/dsl.rbs +351 -0
  104. data/sig/prism/inspect_visitor.rbs +22 -0
  105. data/sig/prism/lex_compat.rbs +10 -0
  106. data/sig/prism/mutation_compiler.rbs +159 -0
  107. data/sig/prism/node.rbs +3614 -0
  108. data/sig/prism/node_ext.rbs +82 -0
  109. data/sig/prism/pack.rbs +43 -0
  110. data/sig/prism/parse_result.rbs +192 -0
  111. data/sig/prism/pattern.rbs +13 -0
  112. data/sig/prism/reflection.rbs +50 -0
  113. data/sig/prism/relocation.rbs +185 -0
  114. data/sig/prism/serialize.rbs +8 -0
  115. data/sig/prism/string_query.rbs +11 -0
  116. data/sig/prism/visitor.rbs +169 -0
  117. data/sig/prism.rbs +248 -4767
  118. data/src/diagnostic.c +672 -230
  119. data/src/encoding.c +211 -108
  120. data/src/node.c +7541 -1653
  121. data/src/options.c +135 -20
  122. data/src/pack.c +33 -17
  123. data/src/prettyprint.c +1546 -1488
  124. data/src/prism.c +7822 -3044
  125. data/src/regexp.c +225 -73
  126. data/src/serialize.c +101 -77
  127. data/src/static_literals.c +617 -0
  128. data/src/token_type.c +14 -13
  129. data/src/util/pm_buffer.c +187 -20
  130. data/src/util/pm_char.c +5 -5
  131. data/src/util/pm_constant_pool.c +39 -19
  132. data/src/util/pm_integer.c +670 -0
  133. data/src/util/pm_list.c +1 -1
  134. data/src/util/pm_newline_list.c +49 -8
  135. data/src/util/pm_string.c +213 -33
  136. data/src/util/pm_strncasecmp.c +13 -1
  137. data/src/util/pm_strpbrk.c +32 -6
  138. metadata +59 -21
  139. data/docs/ripper.md +0 -36
  140. data/include/prism/util/pm_state_stack.h +0 -42
  141. data/include/prism/util/pm_string_list.h +0 -44
  142. data/lib/prism/debug.rb +0 -206
  143. data/lib/prism/node_inspector.rb +0 -68
  144. data/lib/prism/translation/parser/rubocop.rb +0 -37
  145. data/rbi/prism_static.rbi +0 -207
  146. data/sig/prism_static.rbs +0 -201
  147. data/src/util/pm_state_stack.c +0 -25
  148. data/src/util/pm_string_list.c +0 -28
@@ -3,11 +3,28 @@
3
3
  # Here we are reopening the prism module to provide methods on nodes that aren't
4
4
  # templated and are meant as convenience methods.
5
5
  module Prism
6
+ class Node
7
+ def deprecated(*replacements) # :nodoc:
8
+ location = caller_locations(1, 1)
9
+ location = location[0].label if location
10
+ suggest = replacements.map { |replacement| "#{self.class}##{replacement}" }
11
+
12
+ warn(<<~MSG, category: :deprecated)
13
+ [deprecation]: #{self.class}##{location} is deprecated and will be \
14
+ removed in the next major version. Use #{suggest.join("/")} instead.
15
+ #{(caller(1, 3) || []).join("\n")}
16
+ MSG
17
+ end
18
+ end
19
+
6
20
  module RegularExpressionOptions # :nodoc:
7
21
  # Returns a numeric value that represents the flags that were used to create
8
22
  # the regular expression.
9
23
  def options
10
- o = flags & (RegularExpressionFlags::IGNORE_CASE | RegularExpressionFlags::EXTENDED | RegularExpressionFlags::MULTI_LINE)
24
+ o = 0
25
+ o |= Regexp::IGNORECASE if flags.anybits?(RegularExpressionFlags::IGNORE_CASE)
26
+ o |= Regexp::EXTENDED if flags.anybits?(RegularExpressionFlags::EXTENDED)
27
+ o |= Regexp::MULTILINE if flags.anybits?(RegularExpressionFlags::MULTI_LINE)
11
28
  o |= Regexp::FIXEDENCODING if flags.anybits?(RegularExpressionFlags::EUC_JP | RegularExpressionFlags::WINDOWS_31J | RegularExpressionFlags::UTF_8)
12
29
  o |= Regexp::NOENCODING if flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
13
30
  o
@@ -49,21 +66,42 @@ module Prism
49
66
 
50
67
  class StringNode < Node
51
68
  include HeredocQuery
69
+
70
+ # Occasionally it's helpful to treat a string as if it were interpolated so
71
+ # that there's a consistent interface for working with strings.
72
+ def to_interpolated
73
+ InterpolatedStringNode.new(
74
+ source,
75
+ -1,
76
+ location,
77
+ frozen? ? InterpolatedStringNodeFlags::FROZEN : 0,
78
+ opening_loc,
79
+ [copy(location: content_loc, opening_loc: nil, closing_loc: nil)],
80
+ closing_loc
81
+ )
82
+ end
52
83
  end
53
84
 
54
85
  class XStringNode < Node
55
86
  include HeredocQuery
56
- end
57
-
58
- private_constant :HeredocQuery
59
87
 
60
- class FloatNode < Node
61
- # Returns the value of the node as a Ruby Float.
62
- def value
63
- Float(slice)
88
+ # Occasionally it's helpful to treat a string as if it were interpolated so
89
+ # that there's a consistent interface for working with strings.
90
+ def to_interpolated
91
+ InterpolatedXStringNode.new(
92
+ source,
93
+ -1,
94
+ location,
95
+ flags,
96
+ opening_loc,
97
+ [StringNode.new(source, node_id, content_loc, 0, nil, content_loc, nil, unescaped)],
98
+ closing_loc
99
+ )
64
100
  end
65
101
  end
66
102
 
103
+ private_constant :HeredocQuery
104
+
67
105
  class ImaginaryNode < Node
68
106
  # Returns the value of the node as a Ruby Complex.
69
107
  def value
@@ -71,17 +109,22 @@ module Prism
71
109
  end
72
110
  end
73
111
 
74
- class IntegerNode < Node
75
- # Returns the value of the node as a Ruby Integer.
76
- def value
77
- Integer(slice)
78
- end
79
- end
80
-
81
112
  class RationalNode < Node
82
113
  # Returns the value of the node as a Ruby Rational.
83
114
  def value
84
- Rational(numeric.is_a?(IntegerNode) ? numeric.value : slice.chomp("r"))
115
+ Rational(numerator, denominator)
116
+ end
117
+
118
+ # Returns the value of the node as an IntegerNode or a FloatNode. This
119
+ # method is deprecated in favor of #value or #numerator/#denominator.
120
+ def numeric
121
+ deprecated("value", "numerator", "denominator")
122
+
123
+ if denominator == 1
124
+ IntegerNode.new(source, -1, location.chop, flags, numerator)
125
+ else
126
+ FloatNode.new(source, -1, location.chop, 0, numerator.to_f / denominator)
127
+ end
85
128
  end
86
129
  end
87
130
 
@@ -98,6 +141,19 @@ module Prism
98
141
  end
99
142
  end
100
143
 
144
+ class ConstantWriteNode < Node
145
+ # Returns the list of parts for the full name of this constant.
146
+ # For example: [:Foo]
147
+ def full_name_parts
148
+ [name]
149
+ end
150
+
151
+ # Returns the full name of this constant. For example: "Foo"
152
+ def full_name
153
+ name.to_s
154
+ end
155
+ end
156
+
101
157
  class ConstantPathNode < Node
102
158
  # An error class raised when dynamic parts are found while computing a
103
159
  # constant path's full name. For example:
@@ -107,14 +163,24 @@ module Prism
107
163
  # local variable
108
164
  class DynamicPartsInConstantPathError < StandardError; end
109
165
 
166
+ # An error class raised when missing nodes are found while computing a
167
+ # constant path's full name. For example:
168
+ # Foo:: -> raises because the constant path is missing the last part
169
+ class MissingNodesInConstantPathError < StandardError; end
170
+
110
171
  # Returns the list of parts for the full name of this constant path.
111
172
  # For example: [:Foo, :Bar]
112
173
  def full_name_parts
113
- parts = [child.name]
114
- current = parent
174
+ parts = [] #: Array[Symbol]
175
+ current = self #: node?
115
176
 
116
177
  while current.is_a?(ConstantPathNode)
117
- parts.unshift(current.child.name)
178
+ name = current.name
179
+ if name.nil?
180
+ raise MissingNodesInConstantPathError, "Constant path contains missing nodes. Cannot compute full name"
181
+ end
182
+
183
+ parts.unshift(name)
118
184
  current = current.parent
119
185
  end
120
186
 
@@ -129,29 +195,60 @@ module Prism
129
195
  def full_name
130
196
  full_name_parts.join("::")
131
197
  end
198
+
199
+ # Previously, we had a child node on this class that contained either a
200
+ # constant read or a missing node. To not cause a breaking change, we
201
+ # continue to supply that API.
202
+ def child
203
+ deprecated("name", "name_loc")
204
+
205
+ if name
206
+ ConstantReadNode.new(source, -1, name_loc, 0, name)
207
+ else
208
+ MissingNode.new(source, -1, location, 0)
209
+ end
210
+ end
132
211
  end
133
212
 
134
213
  class ConstantPathTargetNode < Node
135
214
  # Returns the list of parts for the full name of this constant path.
136
215
  # For example: [:Foo, :Bar]
137
216
  def full_name_parts
138
- parts = case parent
139
- when ConstantPathNode, ConstantReadNode
140
- parent.full_name_parts
141
- when nil
142
- [:""]
143
- else
144
- raise ConstantPathNode::DynamicPartsInConstantPathError,
145
- "Constant path target contains dynamic parts. Cannot compute full name"
217
+ parts =
218
+ case parent
219
+ when ConstantPathNode, ConstantReadNode
220
+ parent.full_name_parts
221
+ when nil
222
+ [:""]
223
+ else
224
+ # e.g. self::Foo, (var)::Bar = baz
225
+ raise ConstantPathNode::DynamicPartsInConstantPathError, "Constant target path contains dynamic parts. Cannot compute full name"
226
+ end
227
+
228
+ if name.nil?
229
+ raise ConstantPathNode::MissingNodesInConstantPathError, "Constant target path contains missing nodes. Cannot compute full name"
146
230
  end
147
231
 
148
- parts.push(child.name)
232
+ parts.push(name)
149
233
  end
150
234
 
151
235
  # Returns the full name of this constant path. For example: "Foo::Bar"
152
236
  def full_name
153
237
  full_name_parts.join("::")
154
238
  end
239
+
240
+ # Previously, we had a child node on this class that contained either a
241
+ # constant read or a missing node. To not cause a breaking change, we
242
+ # continue to supply that API.
243
+ def child
244
+ deprecated("name", "name_loc")
245
+
246
+ if name
247
+ ConstantReadNode.new(source, -1, name_loc, 0, name)
248
+ else
249
+ MissingNode.new(source, -1, location, 0)
250
+ end
251
+ end
155
252
  end
156
253
 
157
254
  class ConstantTargetNode < Node
@@ -170,22 +267,33 @@ module Prism
170
267
  class ParametersNode < Node
171
268
  # Mirrors the Method#parameters method.
172
269
  def signature
173
- names = []
270
+ names = [] #: Array[[Symbol, Symbol] | [Symbol]]
174
271
 
175
272
  requireds.each do |param|
176
273
  names << (param.is_a?(MultiTargetNode) ? [:req] : [:req, param.name])
177
274
  end
178
275
 
179
276
  optionals.each { |param| names << [:opt, param.name] }
180
- names << [:rest, rest.name || :*] if rest
277
+
278
+ if rest && rest.is_a?(RestParameterNode)
279
+ names << [:rest, rest.name || :*]
280
+ end
181
281
 
182
282
  posts.each do |param|
183
- names << (param.is_a?(MultiTargetNode) ? [:req] : [:req, param.name])
283
+ case param
284
+ when MultiTargetNode
285
+ names << [:req]
286
+ when NoKeywordsParameterNode, KeywordRestParameterNode, ForwardingParameterNode
287
+ # Invalid syntax, e.g. "def f(**nil, ...)" moves the NoKeywordsParameterNode to posts
288
+ raise "Invalid syntax"
289
+ else
290
+ names << [:req, param.name]
291
+ end
184
292
  end
185
293
 
186
294
  # Regardless of the order in which the keywords were defined, the required
187
295
  # keywords always come first followed by the optional keywords.
188
- keyopt = []
296
+ keyopt = [] #: Array[OptionalKeywordParameterNode]
189
297
  keywords.each do |param|
190
298
  if param.is_a?(OptionalKeywordParameterNode)
191
299
  keyopt << param
@@ -209,4 +317,192 @@ module Prism
209
317
  names
210
318
  end
211
319
  end
320
+
321
+ class CallNode < Node
322
+ # When a call node has the attribute_write flag set, it means that the call
323
+ # is using the attribute write syntax. This is either a method call to []=
324
+ # or a method call to a method that ends with =. Either way, the = sign is
325
+ # present in the source.
326
+ #
327
+ # Prism returns the message_loc _without_ the = sign attached, because there
328
+ # can be any amount of space between the message and the = sign. However,
329
+ # sometimes you want the location of the full message including the inner
330
+ # space and the = sign. This method provides that.
331
+ def full_message_loc
332
+ attribute_write? ? message_loc&.adjoin("=") : message_loc
333
+ end
334
+ end
335
+
336
+ class CallOperatorWriteNode < Node
337
+ # Returns the binary operator used to modify the receiver. This method is
338
+ # deprecated in favor of #binary_operator.
339
+ def operator
340
+ deprecated("binary_operator")
341
+ binary_operator
342
+ end
343
+
344
+ # Returns the location of the binary operator used to modify the receiver.
345
+ # This method is deprecated in favor of #binary_operator_loc.
346
+ def operator_loc
347
+ deprecated("binary_operator_loc")
348
+ binary_operator_loc
349
+ end
350
+ end
351
+
352
+ class ClassVariableOperatorWriteNode < Node
353
+ # Returns the binary operator used to modify the receiver. This method is
354
+ # deprecated in favor of #binary_operator.
355
+ def operator
356
+ deprecated("binary_operator")
357
+ binary_operator
358
+ end
359
+
360
+ # Returns the location of the binary operator used to modify the receiver.
361
+ # This method is deprecated in favor of #binary_operator_loc.
362
+ def operator_loc
363
+ deprecated("binary_operator_loc")
364
+ binary_operator_loc
365
+ end
366
+ end
367
+
368
+ class ConstantOperatorWriteNode < Node
369
+ # Returns the binary operator used to modify the receiver. This method is
370
+ # deprecated in favor of #binary_operator.
371
+ def operator
372
+ deprecated("binary_operator")
373
+ binary_operator
374
+ end
375
+
376
+ # Returns the location of the binary operator used to modify the receiver.
377
+ # This method is deprecated in favor of #binary_operator_loc.
378
+ def operator_loc
379
+ deprecated("binary_operator_loc")
380
+ binary_operator_loc
381
+ end
382
+ end
383
+
384
+ class ConstantPathOperatorWriteNode < Node
385
+ # Returns the binary operator used to modify the receiver. This method is
386
+ # deprecated in favor of #binary_operator.
387
+ def operator
388
+ deprecated("binary_operator")
389
+ binary_operator
390
+ end
391
+
392
+ # Returns the location of the binary operator used to modify the receiver.
393
+ # This method is deprecated in favor of #binary_operator_loc.
394
+ def operator_loc
395
+ deprecated("binary_operator_loc")
396
+ binary_operator_loc
397
+ end
398
+ end
399
+
400
+ class GlobalVariableOperatorWriteNode < Node
401
+ # Returns the binary operator used to modify the receiver. This method is
402
+ # deprecated in favor of #binary_operator.
403
+ def operator
404
+ deprecated("binary_operator")
405
+ binary_operator
406
+ end
407
+
408
+ # Returns the location of the binary operator used to modify the receiver.
409
+ # This method is deprecated in favor of #binary_operator_loc.
410
+ def operator_loc
411
+ deprecated("binary_operator_loc")
412
+ binary_operator_loc
413
+ end
414
+ end
415
+
416
+ class IndexOperatorWriteNode < Node
417
+ # Returns the binary operator used to modify the receiver. This method is
418
+ # deprecated in favor of #binary_operator.
419
+ def operator
420
+ deprecated("binary_operator")
421
+ binary_operator
422
+ end
423
+
424
+ # Returns the location of the binary operator used to modify the receiver.
425
+ # This method is deprecated in favor of #binary_operator_loc.
426
+ def operator_loc
427
+ deprecated("binary_operator_loc")
428
+ binary_operator_loc
429
+ end
430
+ end
431
+
432
+ class InstanceVariableOperatorWriteNode < Node
433
+ # Returns the binary operator used to modify the receiver. This method is
434
+ # deprecated in favor of #binary_operator.
435
+ def operator
436
+ deprecated("binary_operator")
437
+ binary_operator
438
+ end
439
+
440
+ # Returns the location of the binary operator used to modify the receiver.
441
+ # This method is deprecated in favor of #binary_operator_loc.
442
+ def operator_loc
443
+ deprecated("binary_operator_loc")
444
+ binary_operator_loc
445
+ end
446
+ end
447
+
448
+ class LocalVariableOperatorWriteNode < Node
449
+ # Returns the binary operator used to modify the receiver. This method is
450
+ # deprecated in favor of #binary_operator.
451
+ def operator
452
+ deprecated("binary_operator")
453
+ binary_operator
454
+ end
455
+
456
+ # Returns the location of the binary operator used to modify the receiver.
457
+ # This method is deprecated in favor of #binary_operator_loc.
458
+ def operator_loc
459
+ deprecated("binary_operator_loc")
460
+ binary_operator_loc
461
+ end
462
+ end
463
+
464
+ class CaseMatchNode < Node
465
+ # Returns the else clause of the case match node. This method is deprecated
466
+ # in favor of #else_clause.
467
+ def consequent
468
+ deprecated("else_clause")
469
+ else_clause
470
+ end
471
+ end
472
+
473
+ class CaseNode < Node
474
+ # Returns the else clause of the case node. This method is deprecated in
475
+ # favor of #else_clause.
476
+ def consequent
477
+ deprecated("else_clause")
478
+ else_clause
479
+ end
480
+ end
481
+
482
+ class IfNode < Node
483
+ # Returns the subsequent if/elsif/else clause of the if node. This method is
484
+ # deprecated in favor of #subsequent.
485
+ def consequent
486
+ deprecated("subsequent")
487
+ subsequent
488
+ end
489
+ end
490
+
491
+ class RescueNode < Node
492
+ # Returns the subsequent rescue clause of the rescue node. This method is
493
+ # deprecated in favor of #subsequent.
494
+ def consequent
495
+ deprecated("subsequent")
496
+ subsequent
497
+ end
498
+ end
499
+
500
+ class UnlessNode < Node
501
+ # Returns the else clause of the unless node. This method is deprecated in
502
+ # favor of #else_clause.
503
+ def consequent
504
+ deprecated("else_clause")
505
+ else_clause
506
+ end
507
+ end
212
508
  end
data/lib/prism/pack.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: ignore
2
3
 
3
4
  module Prism
4
5
  # A parser for the pack template language.
@@ -148,6 +149,8 @@ module Prism
148
149
  end
149
150
  when LENGTH_MAX
150
151
  base + ", as many as possible"
152
+ else
153
+ raise
151
154
  end
152
155
  when UTF8
153
156
  "UTF-8 character"
@@ -214,6 +217,7 @@ module Prism
214
217
  else
215
218
  source = directive.source
216
219
  end
220
+ # @type var source_width: Integer
217
221
  " #{source.ljust(source_width)} #{directive.describe}"
218
222
  end
219
223
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Prism
4
- class ParseResult
4
+ class ParseResult < Result
5
5
  # When we've parsed the source, we have both the syntax tree and the list of
6
6
  # comments that we found in the source. This class is responsible for
7
7
  # walking the tree and finding the nearest location to attach each comment.
@@ -27,11 +27,11 @@ module Prism
27
27
  end
28
28
 
29
29
  def start_offset
30
- node.location.start_offset
30
+ node.start_offset
31
31
  end
32
32
 
33
33
  def end_offset
34
- node.location.end_offset
34
+ node.end_offset
35
35
  end
36
36
 
37
37
  def encloses?(comment)
@@ -39,8 +39,12 @@ module Prism
39
39
  comment.location.end_offset <= end_offset
40
40
  end
41
41
 
42
- def <<(comment)
43
- node.location.comments << comment
42
+ def leading_comment(comment)
43
+ node.location.leading_comment(comment)
44
+ end
45
+
46
+ def trailing_comment(comment)
47
+ node.location.trailing_comment(comment)
44
48
  end
45
49
  end
46
50
 
@@ -65,8 +69,12 @@ module Prism
65
69
  false
66
70
  end
67
71
 
68
- def <<(comment)
69
- location.comments << comment
72
+ def leading_comment(comment)
73
+ location.leading_comment(comment)
74
+ end
75
+
76
+ def trailing_comment(comment)
77
+ location.trailing_comment(comment)
70
78
  end
71
79
  end
72
80
 
@@ -84,15 +92,23 @@ module Prism
84
92
  def attach!
85
93
  parse_result.comments.each do |comment|
86
94
  preceding, enclosing, following = nearest_targets(parse_result.value, comment)
87
- target =
88
- if comment.trailing?
89
- preceding || following || enclosing || NodeTarget.new(parse_result.value)
95
+
96
+ if comment.trailing?
97
+ if preceding
98
+ preceding.trailing_comment(comment)
90
99
  else
91
- # If a comment exists on its own line, prefer a leading comment.
92
- following || preceding || enclosing || NodeTarget.new(parse_result.value)
100
+ (following || enclosing || NodeTarget.new(parse_result.value)).leading_comment(comment)
93
101
  end
94
-
95
- target << comment
102
+ else
103
+ # If a comment exists on its own line, prefer a leading comment.
104
+ if following
105
+ following.leading_comment(comment)
106
+ elsif preceding
107
+ preceding.trailing_comment(comment)
108
+ else
109
+ (enclosing || NodeTarget.new(parse_result.value)).leading_comment(comment)
110
+ end
111
+ end
96
112
  end
97
113
  end
98
114
 
@@ -104,7 +120,7 @@ module Prism
104
120
  comment_start = comment.location.start_offset
105
121
  comment_end = comment.location.end_offset
106
122
 
107
- targets = []
123
+ targets = [] #: Array[_Target]
108
124
  node.comment_targets.map do |value|
109
125
  case value
110
126
  when StatementsNode
@@ -117,8 +133,8 @@ module Prism
117
133
  end
118
134
 
119
135
  targets.sort_by!(&:start_offset)
120
- preceding = nil
121
- following = nil
136
+ preceding = nil #: _Target?
137
+ following = nil #: _Target?
122
138
 
123
139
  left = 0
124
140
  right = targets.length
@@ -134,6 +150,7 @@ module Prism
134
150
  target_end = target.end_offset
135
151
 
136
152
  if target.encloses?(comment)
153
+ # @type var target: NodeTarget
137
154
  # The comment is completely contained by this target. Abandon the
138
155
  # binary search at this level.
139
156
  return nearest_targets(target.node, comment)
@@ -166,12 +183,5 @@ module Prism
166
183
  [preceding, NodeTarget.new(node), following]
167
184
  end
168
185
  end
169
-
170
- private_constant :Comments
171
-
172
- # Attach the list of comments to their respective locations in the tree.
173
- def attach_comments!
174
- Comments.new(self).attach!
175
- end
176
186
  end
177
187
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+
5
+ module Prism
6
+ class ParseResult < Result
7
+ # An object to represent the set of errors on a parse result. This object
8
+ # can be used to format the errors in a human-readable way.
9
+ class Errors
10
+ # The parse result that contains the errors.
11
+ attr_reader :parse_result
12
+
13
+ # Initialize a new set of errors from the given parse result.
14
+ def initialize(parse_result)
15
+ @parse_result = parse_result
16
+ end
17
+
18
+ # Formats the errors in a human-readable way and return them as a string.
19
+ def format
20
+ error_lines = {} #: Hash[Integer, Array[ParseError]]
21
+ parse_result.errors.each do |error|
22
+ location = error.location
23
+ (location.start_line..location.end_line).each do |line|
24
+ error_lines[line] ||= []
25
+ error_lines[line] << error
26
+ end
27
+ end
28
+
29
+ source_lines = parse_result.source.source.lines
30
+ source_lines << "" if error_lines.key?(source_lines.size + 1)
31
+
32
+ io = StringIO.new
33
+ source_lines.each.with_index(1) do |line, line_number|
34
+ io.puts(line)
35
+
36
+ (error_lines.delete(line_number) || []).each do |error|
37
+ location = error.location
38
+
39
+ case line_number
40
+ when location.start_line
41
+ io.print(" " * location.start_column + "^")
42
+
43
+ if location.start_line == location.end_line
44
+ if location.start_column != location.end_column
45
+ io.print("~" * (location.end_column - location.start_column - 1))
46
+ end
47
+
48
+ io.puts(" " + error.message)
49
+ else
50
+ io.puts("~" * (line.bytesize - location.start_column))
51
+ end
52
+ when location.end_line
53
+ io.puts("~" * location.end_column + " " + error.message)
54
+ else
55
+ io.puts("~" * line.bytesize)
56
+ end
57
+ end
58
+ end
59
+
60
+ io.puts
61
+ io.string
62
+ end
63
+ end
64
+ end
65
+ end