prism 0.19.0 → 0.24.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +102 -1
  3. data/Makefile +5 -0
  4. data/README.md +9 -6
  5. data/config.yml +236 -38
  6. data/docs/build_system.md +19 -2
  7. data/docs/cruby_compilation.md +27 -0
  8. data/docs/parser_translation.md +34 -0
  9. data/docs/parsing_rules.md +19 -0
  10. data/docs/releasing.md +84 -16
  11. data/docs/ruby_api.md +1 -1
  12. data/docs/ruby_parser_translation.md +19 -0
  13. data/docs/serialization.md +19 -5
  14. data/ext/prism/api_node.c +1989 -1525
  15. data/ext/prism/extension.c +130 -30
  16. data/ext/prism/extension.h +2 -2
  17. data/include/prism/ast.h +1700 -505
  18. data/include/prism/defines.h +8 -0
  19. data/include/prism/diagnostic.h +49 -7
  20. data/include/prism/encoding.h +17 -0
  21. data/include/prism/options.h +40 -14
  22. data/include/prism/parser.h +34 -18
  23. data/include/prism/util/pm_buffer.h +9 -0
  24. data/include/prism/util/pm_constant_pool.h +18 -0
  25. data/include/prism/util/pm_newline_list.h +4 -14
  26. data/include/prism/util/pm_strpbrk.h +4 -1
  27. data/include/prism/version.h +2 -2
  28. data/include/prism.h +19 -2
  29. data/lib/prism/debug.rb +11 -5
  30. data/lib/prism/desugar_compiler.rb +225 -80
  31. data/lib/prism/dot_visitor.rb +36 -14
  32. data/lib/prism/dsl.rb +302 -299
  33. data/lib/prism/ffi.rb +107 -76
  34. data/lib/prism/lex_compat.rb +17 -1
  35. data/lib/prism/node.rb +4580 -2607
  36. data/lib/prism/node_ext.rb +27 -4
  37. data/lib/prism/parse_result.rb +75 -29
  38. data/lib/prism/serialize.rb +633 -305
  39. data/lib/prism/translation/parser/compiler.rb +1838 -0
  40. data/lib/prism/translation/parser/lexer.rb +335 -0
  41. data/lib/prism/translation/parser/rubocop.rb +45 -0
  42. data/lib/prism/translation/parser.rb +190 -0
  43. data/lib/prism/translation/parser33.rb +12 -0
  44. data/lib/prism/translation/parser34.rb +12 -0
  45. data/lib/prism/translation/ripper.rb +696 -0
  46. data/lib/prism/translation/ruby_parser.rb +1521 -0
  47. data/lib/prism/translation.rb +11 -0
  48. data/lib/prism.rb +1 -1
  49. data/prism.gemspec +18 -7
  50. data/rbi/prism.rbi +150 -88
  51. data/rbi/prism_static.rbi +15 -3
  52. data/sig/prism.rbs +996 -961
  53. data/sig/prism_static.rbs +123 -46
  54. data/src/diagnostic.c +264 -219
  55. data/src/encoding.c +21 -26
  56. data/src/node.c +2 -6
  57. data/src/options.c +29 -5
  58. data/src/prettyprint.c +176 -44
  59. data/src/prism.c +1499 -564
  60. data/src/serialize.c +35 -21
  61. data/src/token_type.c +353 -4
  62. data/src/util/pm_buffer.c +11 -0
  63. data/src/util/pm_constant_pool.c +37 -11
  64. data/src/util/pm_newline_list.c +6 -15
  65. data/src/util/pm_string.c +0 -7
  66. data/src/util/pm_strpbrk.c +122 -14
  67. metadata +16 -5
  68. data/docs/building.md +0 -29
  69. data/lib/prism/ripper_compat.rb +0 -207
@@ -81,7 +81,7 @@ module Prism
81
81
  class RationalNode < Node
82
82
  # Returns the value of the node as a Ruby Rational.
83
83
  def value
84
- Rational(slice.chomp("r"))
84
+ Rational(numeric.is_a?(IntegerNode) ? numeric.value : slice.chomp("r"))
85
85
  end
86
86
  end
87
87
 
@@ -94,7 +94,7 @@ module Prism
94
94
 
95
95
  # Returns the full name of this constant. For example: "Foo"
96
96
  def full_name
97
- name.name
97
+ name.to_s
98
98
  end
99
99
  end
100
100
 
@@ -118,7 +118,7 @@ module Prism
118
118
  current = current.parent
119
119
  end
120
120
 
121
- unless current.is_a?(ConstantReadNode)
121
+ if !current.is_a?(ConstantReadNode) && !current.nil?
122
122
  raise DynamicPartsInConstantPathError, "Constant path contains dynamic parts. Cannot compute full name"
123
123
  end
124
124
 
@@ -135,7 +135,17 @@ module Prism
135
135
  # Returns the list of parts for the full name of this constant path.
136
136
  # For example: [:Foo, :Bar]
137
137
  def full_name_parts
138
- (parent&.full_name_parts || [:""]).push(child.name)
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"
146
+ end
147
+
148
+ parts.push(child.name)
139
149
  end
140
150
 
141
151
  # Returns the full name of this constant path. For example: "Foo::Bar"
@@ -144,6 +154,19 @@ module Prism
144
154
  end
145
155
  end
146
156
 
157
+ class ConstantTargetNode < Node
158
+ # Returns the list of parts for the full name of this constant.
159
+ # For example: [:Foo]
160
+ def full_name_parts
161
+ [name]
162
+ end
163
+
164
+ # Returns the full name of this constant. For example: "Foo"
165
+ def full_name
166
+ name.to_s
167
+ end
168
+ end
169
+
147
170
  class ParametersNode < Node
148
171
  # Mirrors the Method#parameters method.
149
172
  def signature
@@ -9,18 +9,16 @@ module Prism
9
9
  attr_reader :source
10
10
 
11
11
  # The line number where this source starts.
12
- attr_accessor :start_line
12
+ attr_reader :start_line
13
13
 
14
14
  # The list of newline byte offsets in the source code.
15
15
  attr_reader :offsets
16
16
 
17
- # Create a new source object with the given source code and newline byte
18
- # offsets. If no newline byte offsets are given, they will be computed from
19
- # the source code.
20
- def initialize(source, start_line = 1, offsets = compute_offsets(source))
17
+ # Create a new source object with the given source code.
18
+ def initialize(source, start_line = 1, offsets = [])
21
19
  @source = source
22
- @start_line = start_line
23
- @offsets = offsets
20
+ @start_line = start_line # set after parsing is done
21
+ @offsets = offsets # set after parsing is done
24
22
  end
25
23
 
26
24
  # Perform a byteslice on the source code using the given byte offset and
@@ -56,6 +54,23 @@ module Prism
56
54
  character_offset(byte_offset) - character_offset(line_start(byte_offset))
57
55
  end
58
56
 
57
+ # Returns the offset from the start of the file for the given byte offset
58
+ # counting in code units for the given encoding.
59
+ #
60
+ # This method is tested with UTF-8, UTF-16, and UTF-32. If there is the
61
+ # concept of code units that differs from the number of characters in other
62
+ # encodings, it is not captured here.
63
+ def code_units_offset(byte_offset, encoding)
64
+ byteslice = source.byteslice(0, byte_offset).encode(encoding)
65
+ (encoding == Encoding::UTF_16LE || encoding == Encoding::UTF_16BE) ? (byteslice.bytesize / 2) : byteslice.length
66
+ end
67
+
68
+ # Returns the column number in code units for the given encoding for the
69
+ # given byte offset.
70
+ def code_units_column(byte_offset, encoding)
71
+ code_units_offset(byte_offset, encoding) - code_units_offset(line_start(byte_offset), encoding)
72
+ end
73
+
59
74
  private
60
75
 
61
76
  # Binary search through the offsets to find the line number for the given
@@ -77,21 +92,14 @@ module Prism
77
92
 
78
93
  left - 1
79
94
  end
80
-
81
- # Find all of the newlines in the source code and return their byte offsets
82
- # from the start of the string an array.
83
- def compute_offsets(code)
84
- offsets = [0]
85
- code.b.scan("\n") { offsets << $~.end(0) }
86
- offsets
87
- end
88
95
  end
89
96
 
90
97
  # This represents a location in the source.
91
98
  class Location
92
99
  # A Source object that is used to determine more information from the given
93
100
  # offset and length.
94
- protected attr_reader :source
101
+ attr_reader :source
102
+ protected :source
95
103
 
96
104
  # The byte offset from the beginning of the source where this location
97
105
  # starts.
@@ -137,6 +145,11 @@ module Prism
137
145
  source.character_offset(start_offset)
138
146
  end
139
147
 
148
+ # The offset from the start of the file in code units of the given encoding.
149
+ def start_code_units_offset(encoding = Encoding::UTF_16LE)
150
+ source.code_units_offset(start_offset, encoding)
151
+ end
152
+
140
153
  # The byte offset from the beginning of the source where this location ends.
141
154
  def end_offset
142
155
  start_offset + length
@@ -148,6 +161,11 @@ module Prism
148
161
  source.character_offset(end_offset)
149
162
  end
150
163
 
164
+ # The offset from the start of the file in code units of the given encoding.
165
+ def end_code_units_offset(encoding = Encoding::UTF_16LE)
166
+ source.code_units_offset(end_offset, encoding)
167
+ end
168
+
151
169
  # The line number where this location starts.
152
170
  def start_line
153
171
  source.line(start_offset)
@@ -176,6 +194,12 @@ module Prism
176
194
  source.character_column(start_offset)
177
195
  end
178
196
 
197
+ # The column number in code units of the given encoding where this location
198
+ # starts from the start of the line.
199
+ def start_code_units_column(encoding = Encoding::UTF_16LE)
200
+ source.code_units_column(start_offset, encoding)
201
+ end
202
+
179
203
  # The column number in bytes where this location ends from the start of the
180
204
  # line.
181
205
  def end_column
@@ -188,6 +212,12 @@ module Prism
188
212
  source.character_column(end_offset)
189
213
  end
190
214
 
215
+ # The column number in code units of the given encoding where this location
216
+ # ends from the start of the line.
217
+ def end_code_units_column(encoding = Encoding::UTF_16LE)
218
+ source.code_units_column(end_offset, encoding)
219
+ end
220
+
191
221
  # Implement the hash pattern matching interface for Location.
192
222
  def deconstruct_keys(keys)
193
223
  { start_offset: start_offset, end_offset: end_offset }
@@ -312,20 +342,24 @@ module Prism
312
342
  # A Location object representing the location of this error in the source.
313
343
  attr_reader :location
314
344
 
345
+ # The level of this error.
346
+ attr_reader :level
347
+
315
348
  # Create a new error object with the given message and location.
316
- def initialize(message, location)
349
+ def initialize(message, location, level)
317
350
  @message = message
318
351
  @location = location
352
+ @level = level
319
353
  end
320
354
 
321
355
  # Implement the hash pattern matching interface for ParseError.
322
356
  def deconstruct_keys(keys)
323
- { message: message, location: location }
357
+ { message: message, location: location, level: level }
324
358
  end
325
359
 
326
360
  # Returns a string representation of this error.
327
361
  def inspect
328
- "#<Prism::ParseError @message=#{@message.inspect} @location=#{@location.inspect}>"
362
+ "#<Prism::ParseError @message=#{@message.inspect} @location=#{@location.inspect} @level=#{@level.inspect}>"
329
363
  end
330
364
  end
331
365
 
@@ -337,20 +371,24 @@ module Prism
337
371
  # A Location object representing the location of this warning in the source.
338
372
  attr_reader :location
339
373
 
374
+ # The level of this warning.
375
+ attr_reader :level
376
+
340
377
  # Create a new warning object with the given message and location.
341
- def initialize(message, location)
378
+ def initialize(message, location, level)
342
379
  @message = message
343
380
  @location = location
381
+ @level = level
344
382
  end
345
383
 
346
384
  # Implement the hash pattern matching interface for ParseWarning.
347
385
  def deconstruct_keys(keys)
348
- { message: message, location: location }
386
+ { message: message, location: location, level: level }
349
387
  end
350
388
 
351
389
  # Returns a string representation of this warning.
352
390
  def inspect
353
- "#<Prism::ParseWarning @message=#{@message.inspect} @location=#{@location.inspect}>"
391
+ "#<Prism::ParseWarning @message=#{@message.inspect} @location=#{@location.inspect} @level=#{@level.inspect}>"
354
392
  end
355
393
  end
356
394
 
@@ -369,9 +407,9 @@ module Prism
369
407
  # The list of magic comments that were encountered during parsing.
370
408
  attr_reader :magic_comments
371
409
 
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.
410
+ # An optional location that represents the location of the __END__ marker
411
+ # and the rest of the content of the file. This content is loaded into the
412
+ # DATA constant when the file being parsed is the main file being executed.
375
413
  attr_reader :data_loc
376
414
 
377
415
  # The list of errors that were generated during parsing.
@@ -414,17 +452,19 @@ module Prism
414
452
 
415
453
  # This represents a token from the Ruby source.
416
454
  class Token
455
+ # The Source object that represents the source this token came from.
456
+ attr_reader :source
457
+ private :source
458
+
417
459
  # The type of token that this token is.
418
460
  attr_reader :type
419
461
 
420
462
  # A byteslice of the source that this token represents.
421
463
  attr_reader :value
422
464
 
423
- # A Location object representing the location of this token in the source.
424
- attr_reader :location
425
-
426
465
  # Create a new token object with the given type, value, and location.
427
- def initialize(type, value, location)
466
+ def initialize(source, type, value, location)
467
+ @source = source
428
468
  @type = type
429
469
  @value = value
430
470
  @location = location
@@ -435,6 +475,12 @@ module Prism
435
475
  { type: type, value: value, location: location }
436
476
  end
437
477
 
478
+ # A Location object representing the location of this token in the source.
479
+ def location
480
+ return @location if @location.is_a?(Location)
481
+ @location = Location.new(source, @location >> 32, @location & 0xFFFFFFFF)
482
+ end
483
+
438
484
  # Implement the pretty print interface for Token.
439
485
  def pretty_print(q)
440
486
  q.group do