prism 1.3.0 → 1.5.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 +46 -1
- data/Makefile +2 -1
- data/README.md +1 -0
- data/config.yml +273 -37
- data/docs/parser_translation.md +8 -23
- data/docs/releasing.md +1 -1
- data/docs/ripper_translation.md +1 -1
- data/docs/ruby_api.md +1 -1
- data/ext/prism/api_node.c +1816 -1303
- data/ext/prism/extension.c +244 -110
- data/ext/prism/extension.h +4 -4
- data/include/prism/ast.h +291 -49
- data/include/prism/defines.h +4 -1
- data/include/prism/diagnostic.h +4 -0
- data/include/prism/options.h +89 -3
- data/include/prism/regexp.h +2 -2
- data/include/prism/util/pm_buffer.h +18 -0
- data/include/prism/util/pm_integer.h +4 -0
- data/include/prism/util/pm_list.h +6 -0
- data/include/prism/util/pm_string.h +12 -2
- data/include/prism/version.h +2 -2
- data/include/prism.h +41 -16
- data/lib/prism/compiler.rb +456 -151
- data/lib/prism/desugar_compiler.rb +1 -0
- data/lib/prism/dispatcher.rb +16 -0
- data/lib/prism/dot_visitor.rb +21 -1
- data/lib/prism/dsl.rb +13 -2
- data/lib/prism/ffi.rb +62 -34
- data/lib/prism/inspect_visitor.rb +5 -1
- data/lib/prism/lex_compat.rb +1 -0
- data/lib/prism/mutation_compiler.rb +3 -0
- data/lib/prism/node.rb +554 -345
- data/lib/prism/node_ext.rb +4 -1
- data/lib/prism/pack.rb +2 -0
- data/lib/prism/parse_result/comments.rb +1 -0
- data/lib/prism/parse_result/errors.rb +1 -0
- data/lib/prism/parse_result/newlines.rb +2 -1
- data/lib/prism/parse_result.rb +53 -0
- data/lib/prism/pattern.rb +1 -0
- data/lib/prism/polyfill/append_as_bytes.rb +15 -0
- data/lib/prism/polyfill/scan_byte.rb +14 -0
- data/lib/prism/polyfill/warn.rb +42 -0
- data/lib/prism/reflection.rb +5 -2
- data/lib/prism/relocation.rb +1 -0
- data/lib/prism/serialize.rb +1275 -783
- data/lib/prism/string_query.rb +1 -0
- data/lib/prism/translation/parser/builder.rb +62 -0
- data/lib/prism/translation/parser/compiler.rb +230 -152
- data/lib/prism/translation/parser/lexer.rb +446 -64
- data/lib/prism/translation/parser.rb +64 -4
- data/lib/prism/translation/parser33.rb +1 -0
- data/lib/prism/translation/parser34.rb +1 -0
- data/lib/prism/translation/parser35.rb +13 -0
- data/lib/prism/translation/parser_current.rb +24 -0
- data/lib/prism/translation/ripper/sexp.rb +1 -0
- data/lib/prism/translation/ripper.rb +30 -4
- data/lib/prism/translation/ruby_parser.rb +291 -7
- data/lib/prism/translation.rb +3 -0
- data/lib/prism/visitor.rb +457 -152
- data/lib/prism.rb +5 -3
- data/prism.gemspec +9 -1
- data/rbi/prism/dsl.rbi +9 -6
- data/rbi/prism/node.rbi +43 -16
- data/rbi/prism/parse_result.rbi +17 -0
- data/rbi/prism/translation/parser35.rbi +6 -0
- data/rbi/prism.rbi +39 -36
- data/sig/prism/dispatcher.rbs +3 -0
- data/sig/prism/dsl.rbs +7 -5
- data/sig/prism/node.rbs +461 -37
- data/sig/prism/node_ext.rbs +84 -17
- data/sig/prism/parse_result/comments.rbs +38 -0
- data/sig/prism/parse_result.rbs +14 -0
- data/sig/prism/reflection.rbs +1 -1
- data/sig/prism/serialize.rbs +4 -2
- data/sig/prism.rbs +22 -1
- data/src/diagnostic.c +9 -3
- data/src/node.c +23 -0
- data/src/options.c +33 -2
- data/src/prettyprint.c +32 -0
- data/src/prism.c +620 -242
- data/src/serialize.c +8 -0
- data/src/token_type.c +36 -34
- data/src/util/pm_buffer.c +40 -0
- data/src/util/pm_constant_pool.c +6 -2
- data/src/util/pm_strncasecmp.c +13 -1
- metadata +11 -7
data/lib/prism/dispatcher.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
# :markup: markdown
|
2
3
|
|
3
4
|
=begin
|
5
|
+
--
|
4
6
|
This file is generated by the templates/template.rb script and should not be
|
5
7
|
modified manually. See templates/lib/prism/dispatcher.rb.erb
|
6
8
|
if you are looking to modify the template
|
9
|
+
++
|
7
10
|
=end
|
8
11
|
|
9
12
|
module Prism
|
@@ -52,6 +55,19 @@ module Prism
|
|
52
55
|
#
|
53
56
|
# def register: (Listener, *Symbol) -> void
|
54
57
|
def register(listener, *events)
|
58
|
+
register_events(listener, events)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Register all public methods of a listener that match the pattern
|
62
|
+
# `on_<node_name>_(enter|leave)`.
|
63
|
+
#
|
64
|
+
# def register_public_methods: (Listener) -> void
|
65
|
+
def register_public_methods(listener)
|
66
|
+
register_events(listener, listener.public_methods(false).grep(/\Aon_.+_(?:enter|leave)\z/))
|
67
|
+
end
|
68
|
+
|
69
|
+
# Register a listener for the given events.
|
70
|
+
private def register_events(listener, events)
|
55
71
|
events.each { |event| (listeners[event] ||= []) << listener }
|
56
72
|
end
|
57
73
|
|
data/lib/prism/dot_visitor.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
# :markup: markdown
|
2
3
|
|
3
4
|
=begin
|
5
|
+
--
|
4
6
|
This file is generated by the templates/template.rb script and should not be
|
5
7
|
modified manually. See templates/lib/prism/dot_visitor.rb.erb
|
6
8
|
if you are looking to modify the template
|
9
|
+
++
|
7
10
|
=end
|
8
11
|
|
9
|
-
require "cgi"
|
12
|
+
require "cgi/escape"
|
13
|
+
require "cgi/util" unless defined?(CGI::EscapeExt)
|
10
14
|
|
11
15
|
module Prism
|
12
16
|
# This visitor provides the ability to call Node#to_dot, which converts a
|
@@ -3608,6 +3612,9 @@ module Prism
|
|
3608
3612
|
table = Table.new("ParenthesesNode")
|
3609
3613
|
id = node_id(node)
|
3610
3614
|
|
3615
|
+
# flags
|
3616
|
+
table.field("flags", parentheses_node_flags_inspect(node))
|
3617
|
+
|
3611
3618
|
# body
|
3612
3619
|
unless (body = node.body).nil?
|
3613
3620
|
table.field("body", port: true)
|
@@ -3954,6 +3961,11 @@ module Prism
|
|
3954
3961
|
digraph.edge("#{id}:reference -> #{node_id(reference)};")
|
3955
3962
|
end
|
3956
3963
|
|
3964
|
+
# then_keyword_loc
|
3965
|
+
unless (then_keyword_loc = node.then_keyword_loc).nil?
|
3966
|
+
table.field("then_keyword_loc", location_inspect(then_keyword_loc))
|
3967
|
+
end
|
3968
|
+
|
3957
3969
|
# statements
|
3958
3970
|
unless (statements = node.statements).nil?
|
3959
3971
|
table.field("statements", port: true)
|
@@ -4682,6 +4694,14 @@ module Prism
|
|
4682
4694
|
flags.join(", ")
|
4683
4695
|
end
|
4684
4696
|
|
4697
|
+
# Inspect a node that has parentheses_node_flags flags to display the flags as a
|
4698
|
+
# comma-separated list.
|
4699
|
+
def parentheses_node_flags_inspect(node)
|
4700
|
+
flags = [] #: Array[String]
|
4701
|
+
flags << "multiple_statements" if node.multiple_statements?
|
4702
|
+
flags.join(", ")
|
4703
|
+
end
|
4704
|
+
|
4685
4705
|
# Inspect a node that has range_flags flags to display the flags as a
|
4686
4706
|
# comma-separated list.
|
4687
4707
|
def range_flags_inspect(node)
|
data/lib/prism/dsl.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
# :markup: markdown
|
2
3
|
|
3
4
|
=begin
|
5
|
+
--
|
4
6
|
This file is generated by the templates/template.rb script and should not be
|
5
7
|
modified manually. See templates/lib/prism/dsl.rb.erb
|
6
8
|
if you are looking to modify the template
|
9
|
+
++
|
7
10
|
=end
|
8
11
|
|
9
12
|
module Prism
|
@@ -714,8 +717,8 @@ module Prism
|
|
714
717
|
end
|
715
718
|
|
716
719
|
# Create a new RescueNode node.
|
717
|
-
def rescue_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, exceptions: [], operator_loc: nil, reference: nil, statements: nil, subsequent: nil)
|
718
|
-
RescueNode.new(source, node_id, location, flags, keyword_loc, exceptions, operator_loc, reference, statements, subsequent)
|
720
|
+
def rescue_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, exceptions: [], operator_loc: nil, reference: nil, then_keyword_loc: nil, statements: nil, subsequent: nil)
|
721
|
+
RescueNode.new(source, node_id, location, flags, keyword_loc, exceptions, operator_loc, reference, then_keyword_loc, statements, subsequent)
|
719
722
|
end
|
720
723
|
|
721
724
|
# Create a new RestParameterNode node.
|
@@ -912,6 +915,14 @@ module Prism
|
|
912
915
|
end
|
913
916
|
end
|
914
917
|
|
918
|
+
# Retrieve the value of one of the ParenthesesNodeFlags flags.
|
919
|
+
def parentheses_node_flag(name)
|
920
|
+
case name
|
921
|
+
when :multiple_statements then ParenthesesNodeFlags::MULTIPLE_STATEMENTS
|
922
|
+
else Kernel.raise ArgumentError, "invalid ParenthesesNodeFlags flag: #{name.inspect}"
|
923
|
+
end
|
924
|
+
end
|
925
|
+
|
915
926
|
# Retrieve the value of one of the RangeFlags flags.
|
916
927
|
def range_flag(name)
|
917
928
|
case name
|
data/lib/prism/ffi.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
# :markup: markdown
|
2
3
|
# typed: ignore
|
3
4
|
|
4
5
|
# This file is responsible for mirroring the API provided by the C extension by
|
@@ -7,6 +8,10 @@
|
|
7
8
|
require "rbconfig"
|
8
9
|
require "ffi"
|
9
10
|
|
11
|
+
# We want to eagerly load this file if there are Ractors so that it does not get
|
12
|
+
# autoloaded from within a non-main Ractor.
|
13
|
+
require "prism/serialize" if defined?(Ractor)
|
14
|
+
|
10
15
|
module Prism
|
11
16
|
module LibRubyParser # :nodoc:
|
12
17
|
extend FFI::Library
|
@@ -15,7 +20,8 @@ module Prism
|
|
15
20
|
# must align with the build shared library from make/rake.
|
16
21
|
libprism_in_build = File.expand_path("../../build/libprism.#{RbConfig::CONFIG["SOEXT"]}", __dir__)
|
17
22
|
libprism_in_libdir = "#{RbConfig::CONFIG["libdir"]}/prism/libprism.#{RbConfig::CONFIG["SOEXT"]}"
|
18
|
-
|
23
|
+
|
24
|
+
if File.exist?(libprism_in_build)
|
19
25
|
INCLUDE_DIR = File.expand_path("../../include", __dir__)
|
20
26
|
ffi_lib libprism_in_build
|
21
27
|
else
|
@@ -80,6 +86,7 @@ module Prism
|
|
80
86
|
end
|
81
87
|
|
82
88
|
callback :pm_parse_stream_fgets_t, [:pointer, :int, :pointer], :pointer
|
89
|
+
callback :pm_parse_stream_feof_t, [:pointer], :int
|
83
90
|
enum :pm_string_init_result_t, %i[PM_STRING_INIT_SUCCESS PM_STRING_INIT_ERROR_GENERIC PM_STRING_INIT_ERROR_DIRECTORY]
|
84
91
|
enum :pm_string_query_t, [:PM_STRING_QUERY_ERROR, -1, :PM_STRING_QUERY_FALSE, :PM_STRING_QUERY_TRUE]
|
85
92
|
|
@@ -95,7 +102,7 @@ module Prism
|
|
95
102
|
"pm_string_query_local",
|
96
103
|
"pm_string_query_constant",
|
97
104
|
"pm_string_query_method_name",
|
98
|
-
[:pm_parse_stream_fgets_t]
|
105
|
+
[:pm_parse_stream_fgets_t, :pm_parse_stream_feof_t]
|
99
106
|
)
|
100
107
|
|
101
108
|
load_exported_functions_from(
|
@@ -158,6 +165,9 @@ module Prism
|
|
158
165
|
class PrismString # :nodoc:
|
159
166
|
SIZEOF = LibRubyParser.pm_string_sizeof
|
160
167
|
|
168
|
+
PLATFORM_EXPECTS_UTF8 =
|
169
|
+
RbConfig::CONFIG["host_os"].match?(/bccwin|cygwin|djgpp|mingw|mswin|wince|darwin/i)
|
170
|
+
|
161
171
|
attr_reader :pointer, :length
|
162
172
|
|
163
173
|
def initialize(pointer, length, from_string)
|
@@ -192,8 +202,7 @@ module Prism
|
|
192
202
|
# On Windows and Mac, it's expected that filepaths will be encoded in
|
193
203
|
# UTF-8. If they are not, we need to convert them to UTF-8 before
|
194
204
|
# passing them into pm_string_mapped_init.
|
195
|
-
if
|
196
|
-
(encoding = filepath.encoding) != Encoding::ASCII_8BIT && encoding != Encoding::UTF_8
|
205
|
+
if PLATFORM_EXPECTS_UTF8 && (encoding = filepath.encoding) != Encoding::ASCII_8BIT && encoding != Encoding::UTF_8
|
197
206
|
filepath = filepath.encode(Encoding::UTF_8)
|
198
207
|
end
|
199
208
|
|
@@ -222,7 +231,7 @@ module Prism
|
|
222
231
|
private_constant :LibRubyParser
|
223
232
|
|
224
233
|
# The version constant is set by reading the result of calling pm_version.
|
225
|
-
VERSION = LibRubyParser.pm_version.read_string
|
234
|
+
VERSION = LibRubyParser.pm_version.read_string.freeze
|
226
235
|
|
227
236
|
class << self
|
228
237
|
# Mirror the Prism.dump API by using the serialization API.
|
@@ -273,13 +282,15 @@ module Prism
|
|
273
282
|
end
|
274
283
|
}
|
275
284
|
|
285
|
+
eof_callback = -> (_) { stream.eof? }
|
286
|
+
|
276
287
|
# In the pm_serialize_parse_stream function it accepts a pointer to the
|
277
288
|
# IO object as a void* and then passes it through to the callback as the
|
278
289
|
# third argument, but it never touches it itself. As such, since we have
|
279
290
|
# access to the IO object already through the closure of the lambda, we
|
280
291
|
# can pass a null pointer here and not worry.
|
281
|
-
LibRubyParser.pm_serialize_parse_stream(buffer.pointer, nil, callback, dump_options(options))
|
282
|
-
Prism.load(source, buffer.read)
|
292
|
+
LibRubyParser.pm_serialize_parse_stream(buffer.pointer, nil, callback, eof_callback, dump_options(options))
|
293
|
+
Prism.load(source, buffer.read, options.fetch(:freeze, false))
|
283
294
|
end
|
284
295
|
end
|
285
296
|
|
@@ -354,50 +365,37 @@ module Prism
|
|
354
365
|
def dump_common(string, options) # :nodoc:
|
355
366
|
LibRubyParser::PrismBuffer.with do |buffer|
|
356
367
|
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
|
357
|
-
|
368
|
+
|
369
|
+
dumped = buffer.read
|
370
|
+
dumped.freeze if options.fetch(:freeze, false)
|
371
|
+
|
372
|
+
dumped
|
358
373
|
end
|
359
374
|
end
|
360
375
|
|
361
376
|
def lex_common(string, code, options) # :nodoc:
|
362
|
-
|
377
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
363
378
|
LibRubyParser.pm_serialize_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
|
364
|
-
buffer.read
|
379
|
+
Serialize.load_lex(code, buffer.read, options.fetch(:freeze, false))
|
365
380
|
end
|
366
|
-
|
367
|
-
Serialize.load_tokens(Source.for(code), serialized)
|
368
381
|
end
|
369
382
|
|
370
383
|
def parse_common(string, code, options) # :nodoc:
|
371
384
|
serialized = dump_common(string, options)
|
372
|
-
|
385
|
+
Serialize.load_parse(code, serialized, options.fetch(:freeze, false))
|
373
386
|
end
|
374
387
|
|
375
388
|
def parse_comments_common(string, code, options) # :nodoc:
|
376
389
|
LibRubyParser::PrismBuffer.with do |buffer|
|
377
390
|
LibRubyParser.pm_serialize_parse_comments(buffer.pointer, string.pointer, string.length, dump_options(options))
|
378
|
-
|
379
|
-
source = Source.for(code)
|
380
|
-
loader = Serialize::Loader.new(source, buffer.read)
|
381
|
-
|
382
|
-
loader.load_header
|
383
|
-
loader.load_encoding
|
384
|
-
loader.load_start_line
|
385
|
-
loader.load_comments
|
391
|
+
Serialize.load_parse_comments(code, buffer.read, options.fetch(:freeze, false))
|
386
392
|
end
|
387
393
|
end
|
388
394
|
|
389
395
|
def parse_lex_common(string, code, options) # :nodoc:
|
390
396
|
LibRubyParser::PrismBuffer.with do |buffer|
|
391
397
|
LibRubyParser.pm_serialize_parse_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
|
392
|
-
|
393
|
-
source = Source.for(code)
|
394
|
-
loader = Serialize::Loader.new(source, buffer.read)
|
395
|
-
|
396
|
-
tokens = loader.load_tokens
|
397
|
-
node, comments, magic_comments, data_loc, errors, warnings = loader.load_nodes
|
398
|
-
tokens.each { |token,| token.value.force_encoding(loader.encoding) }
|
399
|
-
|
400
|
-
ParseLexResult.new([node, tokens], comments, magic_comments, data_loc, errors, warnings, source)
|
398
|
+
Serialize.load_parse_lex(code, buffer.read, options.fetch(:freeze, false))
|
401
399
|
end
|
402
400
|
end
|
403
401
|
|
@@ -427,11 +425,13 @@ module Prism
|
|
427
425
|
def dump_options_version(version)
|
428
426
|
case version
|
429
427
|
when nil, "latest"
|
430
|
-
0
|
428
|
+
0 # Handled in pm_parser_init
|
431
429
|
when /\A3\.3(\.\d+)?\z/
|
432
430
|
1
|
433
431
|
when /\A3\.4(\.\d+)?\z/
|
434
|
-
|
432
|
+
2
|
433
|
+
when /\A3\.5(\.\d+)?\z/
|
434
|
+
3
|
435
435
|
else
|
436
436
|
raise ArgumentError, "invalid version: #{version}"
|
437
437
|
end
|
@@ -480,15 +480,43 @@ module Prism
|
|
480
480
|
template << "C"
|
481
481
|
values << (options.fetch(:partial_script, false) ? 1 : 0)
|
482
482
|
|
483
|
+
template << "C"
|
484
|
+
values << (options.fetch(:freeze, false) ? 1 : 0)
|
485
|
+
|
483
486
|
template << "L"
|
484
487
|
if (scopes = options[:scopes])
|
485
488
|
values << scopes.length
|
486
489
|
|
487
490
|
scopes.each do |scope|
|
491
|
+
locals = nil
|
492
|
+
forwarding = 0
|
493
|
+
|
494
|
+
case scope
|
495
|
+
when Array
|
496
|
+
locals = scope
|
497
|
+
when Scope
|
498
|
+
locals = scope.locals
|
499
|
+
|
500
|
+
scope.forwarding.each do |forward|
|
501
|
+
case forward
|
502
|
+
when :* then forwarding |= 0x1
|
503
|
+
when :** then forwarding |= 0x2
|
504
|
+
when :& then forwarding |= 0x4
|
505
|
+
when :"..." then forwarding |= 0x8
|
506
|
+
else raise ArgumentError, "invalid forwarding value: #{forward}"
|
507
|
+
end
|
508
|
+
end
|
509
|
+
else
|
510
|
+
raise TypeError, "wrong argument type #{scope.class.inspect} (expected Array or Prism::Scope)"
|
511
|
+
end
|
512
|
+
|
488
513
|
template << "L"
|
489
|
-
values <<
|
514
|
+
values << locals.length
|
515
|
+
|
516
|
+
template << "C"
|
517
|
+
values << forwarding
|
490
518
|
|
491
|
-
|
519
|
+
locals.each do |local|
|
492
520
|
name = local.name
|
493
521
|
template << "L"
|
494
522
|
values << name.bytesize
|
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
# :markup: markdown
|
2
3
|
|
3
4
|
=begin
|
5
|
+
--
|
4
6
|
This file is generated by the templates/template.rb script and should not be
|
5
7
|
modified manually. See templates/lib/prism/inspect_visitor.rb.erb
|
6
8
|
if you are looking to modify the template
|
9
|
+
++
|
7
10
|
=end
|
8
11
|
|
9
12
|
module Prism
|
@@ -1879,7 +1882,7 @@ module Prism
|
|
1879
1882
|
# Inspect a ParenthesesNode node.
|
1880
1883
|
def visit_parentheses_node(node)
|
1881
1884
|
commands << [inspect_node("ParenthesesNode", node), indent]
|
1882
|
-
flags = [("newline" if node.newline?), ("static_literal" if node.static_literal?), ].compact
|
1885
|
+
flags = [("newline" if node.newline?), ("static_literal" if node.static_literal?), ("multiple_statements" if node.multiple_statements?)].compact
|
1883
1886
|
commands << ["├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n", indent]
|
1884
1887
|
if (body = node.body).nil?
|
1885
1888
|
commands << ["├── body: ∅\n", indent]
|
@@ -2053,6 +2056,7 @@ module Prism
|
|
2053
2056
|
commands << ["├── reference:\n", indent]
|
2054
2057
|
commands << [reference, "#{indent}│ "]
|
2055
2058
|
end
|
2059
|
+
commands << ["├── then_keyword_loc: #{inspect_location(node.then_keyword_loc)}\n", indent]
|
2056
2060
|
if (statements = node.statements).nil?
|
2057
2061
|
commands << ["├── statements: ∅\n", indent]
|
2058
2062
|
else
|
data/lib/prism/lex_compat.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
# :markup: markdown
|
2
3
|
|
3
4
|
=begin
|
5
|
+
--
|
4
6
|
This file is generated by the templates/template.rb script and should not be
|
5
7
|
modified manually. See templates/lib/prism/mutation_compiler.rb.erb
|
6
8
|
if you are looking to modify the template
|
9
|
+
++
|
7
10
|
=end
|
8
11
|
|
9
12
|
module Prism
|