prism 0.19.0 → 0.24.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +102 -1
- data/Makefile +5 -0
- data/README.md +9 -6
- data/config.yml +236 -38
- data/docs/build_system.md +19 -2
- data/docs/cruby_compilation.md +27 -0
- data/docs/parser_translation.md +34 -0
- data/docs/parsing_rules.md +19 -0
- data/docs/releasing.md +84 -16
- data/docs/ruby_api.md +1 -1
- data/docs/ruby_parser_translation.md +19 -0
- data/docs/serialization.md +19 -5
- data/ext/prism/api_node.c +1989 -1525
- data/ext/prism/extension.c +130 -30
- data/ext/prism/extension.h +2 -2
- data/include/prism/ast.h +1700 -505
- data/include/prism/defines.h +8 -0
- data/include/prism/diagnostic.h +49 -7
- data/include/prism/encoding.h +17 -0
- data/include/prism/options.h +40 -14
- data/include/prism/parser.h +34 -18
- data/include/prism/util/pm_buffer.h +9 -0
- data/include/prism/util/pm_constant_pool.h +18 -0
- data/include/prism/util/pm_newline_list.h +4 -14
- data/include/prism/util/pm_strpbrk.h +4 -1
- data/include/prism/version.h +2 -2
- data/include/prism.h +19 -2
- data/lib/prism/debug.rb +11 -5
- data/lib/prism/desugar_compiler.rb +225 -80
- data/lib/prism/dot_visitor.rb +36 -14
- data/lib/prism/dsl.rb +302 -299
- data/lib/prism/ffi.rb +107 -76
- data/lib/prism/lex_compat.rb +17 -1
- data/lib/prism/node.rb +4580 -2607
- data/lib/prism/node_ext.rb +27 -4
- data/lib/prism/parse_result.rb +75 -29
- data/lib/prism/serialize.rb +633 -305
- data/lib/prism/translation/parser/compiler.rb +1838 -0
- data/lib/prism/translation/parser/lexer.rb +335 -0
- data/lib/prism/translation/parser/rubocop.rb +45 -0
- data/lib/prism/translation/parser.rb +190 -0
- data/lib/prism/translation/parser33.rb +12 -0
- data/lib/prism/translation/parser34.rb +12 -0
- data/lib/prism/translation/ripper.rb +696 -0
- data/lib/prism/translation/ruby_parser.rb +1521 -0
- data/lib/prism/translation.rb +11 -0
- data/lib/prism.rb +1 -1
- data/prism.gemspec +18 -7
- data/rbi/prism.rbi +150 -88
- data/rbi/prism_static.rbi +15 -3
- data/sig/prism.rbs +996 -961
- data/sig/prism_static.rbs +123 -46
- data/src/diagnostic.c +264 -219
- data/src/encoding.c +21 -26
- data/src/node.c +2 -6
- data/src/options.c +29 -5
- data/src/prettyprint.c +176 -44
- data/src/prism.c +1499 -564
- data/src/serialize.c +35 -21
- data/src/token_type.c +353 -4
- data/src/util/pm_buffer.c +11 -0
- data/src/util/pm_constant_pool.c +37 -11
- data/src/util/pm_newline_list.c +6 -15
- data/src/util/pm_string.c +0 -7
- data/src/util/pm_strpbrk.c +122 -14
- metadata +16 -5
- data/docs/building.md +0 -29
- data/lib/prism/ripper_compat.rb +0 -207
data/lib/prism/node_ext.rb
CHANGED
@@ -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.
|
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
|
-
|
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
|
-
|
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
|
data/lib/prism/parse_result.rb
CHANGED
@@ -9,18 +9,16 @@ module Prism
|
|
9
9
|
attr_reader :source
|
10
10
|
|
11
11
|
# The line number where this source starts.
|
12
|
-
|
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
|
18
|
-
|
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
|
-
|
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
|
373
|
-
#
|
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
|