prism 0.18.0 → 0.19.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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -1
  3. data/README.md +2 -1
  4. data/config.yml +188 -55
  5. data/docs/building.md +9 -2
  6. data/docs/configuration.md +10 -9
  7. data/docs/encoding.md +24 -56
  8. data/docs/local_variable_depth.md +229 -0
  9. data/docs/ruby_api.md +2 -0
  10. data/docs/serialization.md +18 -13
  11. data/ext/prism/api_node.c +337 -195
  12. data/ext/prism/extconf.rb +13 -7
  13. data/ext/prism/extension.c +96 -32
  14. data/ext/prism/extension.h +1 -1
  15. data/include/prism/ast.h +340 -137
  16. data/include/prism/defines.h +17 -0
  17. data/include/prism/diagnostic.h +11 -5
  18. data/include/prism/encoding.h +248 -0
  19. data/include/prism/options.h +2 -2
  20. data/include/prism/parser.h +62 -42
  21. data/include/prism/regexp.h +2 -2
  22. data/include/prism/util/pm_buffer.h +9 -1
  23. data/include/prism/util/pm_memchr.h +2 -2
  24. data/include/prism/util/pm_strpbrk.h +3 -3
  25. data/include/prism/version.h +2 -2
  26. data/include/prism.h +13 -15
  27. data/lib/prism/compiler.rb +12 -0
  28. data/lib/prism/debug.rb +9 -4
  29. data/lib/prism/desugar_compiler.rb +3 -3
  30. data/lib/prism/dispatcher.rb +56 -0
  31. data/lib/prism/dot_visitor.rb +476 -198
  32. data/lib/prism/dsl.rb +66 -46
  33. data/lib/prism/ffi.rb +16 -3
  34. data/lib/prism/lex_compat.rb +19 -9
  35. data/lib/prism/mutation_compiler.rb +20 -0
  36. data/lib/prism/node.rb +1173 -450
  37. data/lib/prism/node_ext.rb +41 -16
  38. data/lib/prism/parse_result.rb +12 -15
  39. data/lib/prism/ripper_compat.rb +49 -34
  40. data/lib/prism/serialize.rb +242 -212
  41. data/lib/prism/visitor.rb +12 -0
  42. data/lib/prism.rb +20 -4
  43. data/prism.gemspec +4 -10
  44. data/rbi/prism.rbi +605 -230
  45. data/rbi/prism_static.rbi +3 -0
  46. data/sig/prism.rbs +379 -124
  47. data/sig/prism_static.rbs +1 -0
  48. data/src/diagnostic.c +228 -222
  49. data/src/encoding.c +5137 -0
  50. data/src/node.c +66 -0
  51. data/src/options.c +21 -2
  52. data/src/prettyprint.c +806 -406
  53. data/src/prism.c +1092 -700
  54. data/src/regexp.c +3 -3
  55. data/src/serialize.c +227 -157
  56. data/src/util/pm_buffer.c +10 -1
  57. data/src/util/pm_memchr.c +1 -1
  58. data/src/util/pm_strpbrk.c +4 -4
  59. metadata +5 -11
  60. data/include/prism/enc/pm_encoding.h +0 -227
  61. data/src/enc/pm_big5.c +0 -116
  62. data/src/enc/pm_cp51932.c +0 -57
  63. data/src/enc/pm_euc_jp.c +0 -69
  64. data/src/enc/pm_gbk.c +0 -65
  65. data/src/enc/pm_shift_jis.c +0 -57
  66. data/src/enc/pm_tables.c +0 -2073
  67. data/src/enc/pm_unicode.c +0 -2369
  68. data/src/enc/pm_windows_31j.c +0 -57
@@ -14,8 +14,49 @@ module Prism
14
14
  end
15
15
  end
16
16
 
17
+ class InterpolatedMatchLastLineNode < Node
18
+ include RegularExpressionOptions
19
+ end
20
+
21
+ class InterpolatedRegularExpressionNode < Node
22
+ include RegularExpressionOptions
23
+ end
24
+
25
+ class MatchLastLineNode < Node
26
+ include RegularExpressionOptions
27
+ end
28
+
29
+ class RegularExpressionNode < Node
30
+ include RegularExpressionOptions
31
+ end
32
+
17
33
  private_constant :RegularExpressionOptions
18
34
 
35
+ module HeredocQuery # :nodoc:
36
+ # Returns true if this node was represented as a heredoc in the source code.
37
+ def heredoc?
38
+ opening&.start_with?("<<")
39
+ end
40
+ end
41
+
42
+ class InterpolatedStringNode < Node
43
+ include HeredocQuery
44
+ end
45
+
46
+ class InterpolatedXStringNode < Node
47
+ include HeredocQuery
48
+ end
49
+
50
+ class StringNode < Node
51
+ include HeredocQuery
52
+ end
53
+
54
+ class XStringNode < Node
55
+ include HeredocQuery
56
+ end
57
+
58
+ private_constant :HeredocQuery
59
+
19
60
  class FloatNode < Node
20
61
  # Returns the value of the node as a Ruby Float.
21
62
  def value
@@ -37,18 +78,6 @@ module Prism
37
78
  end
38
79
  end
39
80
 
40
- class InterpolatedMatchLastLineNode < Node
41
- include RegularExpressionOptions
42
- end
43
-
44
- class InterpolatedRegularExpressionNode < Node
45
- include RegularExpressionOptions
46
- end
47
-
48
- class MatchLastLineNode < Node
49
- include RegularExpressionOptions
50
- end
51
-
52
81
  class RationalNode < Node
53
82
  # Returns the value of the node as a Ruby Rational.
54
83
  def value
@@ -56,10 +85,6 @@ module Prism
56
85
  end
57
86
  end
58
87
 
59
- class RegularExpressionNode < Node
60
- include RegularExpressionOptions
61
- end
62
-
63
88
  class ConstantReadNode < Node
64
89
  # Returns the list of parts for the full name of this constant.
65
90
  # For example: [:Foo]
@@ -238,11 +238,6 @@ module Prism
238
238
  def deconstruct_keys(keys)
239
239
  { location: location }
240
240
  end
241
-
242
- # This can only be true for inline comments.
243
- def trailing?
244
- false
245
- end
246
241
  end
247
242
 
248
243
  # InlineComment objects are the most common. They correspond to comments in
@@ -263,18 +258,14 @@ module Prism
263
258
  # EmbDocComment objects correspond to comments that are surrounded by =begin
264
259
  # and =end.
265
260
  class EmbDocComment < Comment
266
- # Returns a string representation of this comment.
267
- def inspect
268
- "#<Prism::EmbDocComment @location=#{location.inspect}>"
261
+ # This can only be true for inline comments.
262
+ def trailing?
263
+ false
269
264
  end
270
- end
271
265
 
272
- # DATAComment objects correspond to comments that are after the __END__
273
- # keyword in a source file.
274
- class DATAComment < Comment
275
266
  # Returns a string representation of this comment.
276
267
  def inspect
277
- "#<Prism::DATAComment @location=#{location.inspect}>"
268
+ "#<Prism::EmbDocComment @location=#{location.inspect}>"
278
269
  end
279
270
  end
280
271
 
@@ -378,6 +369,11 @@ module Prism
378
369
  # The list of magic comments that were encountered during parsing.
379
370
  attr_reader :magic_comments
380
371
 
372
+ # An optional location that represents the location of the content after the
373
+ # __END__ marker. This content is loaded into the DATA constant when the
374
+ # file being parsed is the main file being executed.
375
+ attr_reader :data_loc
376
+
381
377
  # The list of errors that were generated during parsing.
382
378
  attr_reader :errors
383
379
 
@@ -388,10 +384,11 @@ module Prism
388
384
  attr_reader :source
389
385
 
390
386
  # Create a new parse result object with the given values.
391
- def initialize(value, comments, magic_comments, errors, warnings, source)
387
+ def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
392
388
  @value = value
393
389
  @comments = comments
394
390
  @magic_comments = magic_comments
391
+ @data_loc = data_loc
395
392
  @errors = errors
396
393
  @warnings = warnings
397
394
  @source = source
@@ -399,7 +396,7 @@ module Prism
399
396
 
400
397
  # Implement the hash pattern matching interface for ParseResult.
401
398
  def deconstruct_keys(keys)
402
- { value: value, comments: comments, magic_comments: magic_comments, errors: errors, warnings: warnings }
399
+ { value: value, comments: comments, magic_comments: magic_comments, data_loc: data_loc, errors: errors, warnings: warnings }
403
400
  end
404
401
 
405
402
  # Returns true if there were no errors during parsing and false if there
@@ -3,6 +3,10 @@
3
3
  require "ripper"
4
4
 
5
5
  module Prism
6
+ # Note: This integration is not finished, and therefore still has many
7
+ # inconsistencies with Ripper. If you'd like to help out, pull requests would
8
+ # be greatly appreciated!
9
+ #
6
10
  # This class is meant to provide a compatibility layer between prism and
7
11
  # Ripper. It functions by parsing the entire tree first and then walking it
8
12
  # and executing each of the Ripper callbacks as it goes.
@@ -10,7 +14,10 @@ module Prism
10
14
  # This class is going to necessarily be slower than the native Ripper API. It
11
15
  # is meant as a stopgap until developers migrate to using prism. It is also
12
16
  # meant as a test harness for the prism parser.
13
- class RipperCompat
17
+ #
18
+ # To use this class, you treat `Prism::RipperCompat` effectively as you would
19
+ # treat the `Ripper` class.
20
+ class RipperCompat < Visitor
14
21
  # This class mirrors the ::Ripper::SexpBuilder subclass of ::Ripper that
15
22
  # returns the arrays of [type, *children].
16
23
  class SexpBuilder < RipperCompat
@@ -77,43 +84,63 @@ module Prism
77
84
 
78
85
  # True if the parser encountered an error during parsing.
79
86
  def error?
80
- result.errors.any?
87
+ result.failure?
81
88
  end
82
89
 
83
90
  # Parse the source and return the result.
84
91
  def parse
85
- result.value.accept(self) unless error?
92
+ result.magic_comments.each do |magic_comment|
93
+ on_magic_comment(magic_comment.key, magic_comment.value)
94
+ end
95
+
96
+ if error?
97
+ result.errors.each do |error|
98
+ on_parse_error(error.message)
99
+ end
100
+ else
101
+ result.value.accept(self)
102
+ end
86
103
  end
87
104
 
88
105
  ############################################################################
89
106
  # Visitor methods
90
107
  ############################################################################
91
108
 
92
- # This method is responsible for dispatching to the correct visitor method
93
- # based on the type of the node.
94
- def visit(node)
95
- node&.accept(self)
96
- end
97
-
98
109
  # Visit a CallNode node.
99
110
  def visit_call_node(node)
100
- if !node.opening_loc && node.arguments.arguments.length == 1
101
- bounds(node.receiver.location)
111
+ if !node.message.match?(/^[[:alpha:]_]/) && node.opening_loc.nil? && node.arguments&.arguments&.length == 1
102
112
  left = visit(node.receiver)
103
-
104
- bounds(node.arguments.arguments.first.location)
105
113
  right = visit(node.arguments.arguments.first)
106
114
 
107
- on_binary(left, source[node.message_loc.start_offset...node.message_loc.end_offset].to_sym, right)
115
+ bounds(node.location)
116
+ on_binary(left, node.name, right)
108
117
  else
109
118
  raise NotImplementedError
110
119
  end
111
120
  end
112
121
 
122
+ # Visit a FloatNode node.
123
+ def visit_float_node(node)
124
+ bounds(node.location)
125
+ on_float(node.slice)
126
+ end
127
+
128
+ # Visit a ImaginaryNode node.
129
+ def visit_imaginary_node(node)
130
+ bounds(node.location)
131
+ on_imaginary(node.slice)
132
+ end
133
+
113
134
  # Visit an IntegerNode node.
114
135
  def visit_integer_node(node)
115
136
  bounds(node.location)
116
- on_int(source[node.location.start_offset...node.location.end_offset])
137
+ on_int(node.slice)
138
+ end
139
+
140
+ # Visit a RationalNode node.
141
+ def visit_rational_node(node)
142
+ bounds(node.location)
143
+ on_rational(node.slice)
117
144
  end
118
145
 
119
146
  # Visit a StatementsNode node.
@@ -124,24 +151,11 @@ module Prism
124
151
  end
125
152
  end
126
153
 
127
- # Visit a token found during parsing.
128
- def visit_token(node)
129
- bounds(node.location)
130
-
131
- case node.type
132
- when :MINUS
133
- on_op(node.value)
134
- when :PLUS
135
- on_op(node.value)
136
- else
137
- raise NotImplementedError, "Unknown token: #{node.type}"
138
- end
139
- end
140
-
141
154
  # Visit a ProgramNode node.
142
155
  def visit_program_node(node)
156
+ statements = visit(node.statements)
143
157
  bounds(node.location)
144
- on_program(visit(node.statements))
158
+ on_program(statements)
145
159
  end
146
160
 
147
161
  ############################################################################
@@ -166,10 +180,8 @@ module Prism
166
180
  # This method could be drastically improved with some caching on the start
167
181
  # of every line, but for now it's good enough.
168
182
  def bounds(location)
169
- start_offset = location.start_offset
170
-
171
- @lineno = source[0..start_offset].count("\n") + 1
172
- @column = start_offset - (source.rindex("\n", start_offset) || 0)
183
+ @lineno = location.start_line
184
+ @column = location.start_column
173
185
  end
174
186
 
175
187
  # Lazily initialize the parse result.
@@ -185,6 +197,9 @@ module Prism
185
197
  def _dispatch5(_, _, _, _, _); end # :nodoc:
186
198
  def _dispatch7(_, _, _, _, _, _, _); end # :nodoc:
187
199
 
200
+ alias_method :on_parse_error, :_dispatch1
201
+ alias_method :on_magic_comment, :_dispatch2
202
+
188
203
  (Ripper::SCANNER_EVENT_TABLE.merge(Ripper::PARSER_EVENT_TABLE)).each do |event, arity|
189
204
  alias_method :"on_#{event}", :"_dispatch#{arity}"
190
205
  end