prism 1.9.0 → 2.0.0.rc2
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 +88 -0
- data/CODE_OF_CONDUCT.md +1 -1
- data/LICENSE.md +1 -1
- data/Makefile +41 -12
- data/README.md +35 -97
- data/config.yml +174 -161
- data/docs/build_system.md +2 -2
- data/docs/configuration.md +5 -4
- data/docs/encoding.md +2 -2
- data/docs/fuzzing.md +4 -11
- data/docs/javascript.md +19 -4
- data/docs/mapping.md +1 -1
- data/docs/releasing.md +77 -5
- data/docs/relocation.md +2 -4
- data/docs/serialization.md +22 -24
- data/docs/testing.md +46 -29
- data/ext/prism/api_node.c +1461 -1401
- data/ext/prism/extconf.rb +3 -4
- data/ext/prism/extension.c +796 -422
- data/ext/prism/extension.h +3 -3
- data/include/prism/arena.h +37 -0
- data/include/prism/ast.h +2727 -610
- data/include/prism/buffer.h +52 -0
- data/include/prism/comments.h +55 -0
- data/include/prism/compiler/accel.h +26 -0
- data/include/prism/compiler/align.h +36 -0
- data/include/prism/compiler/assume.h +25 -0
- data/include/prism/compiler/bswap.h +46 -0
- data/include/prism/compiler/endianness.h +34 -0
- data/include/prism/compiler/exported.h +24 -0
- data/include/prism/compiler/fallthrough.h +22 -0
- data/include/prism/compiler/filesystem.h +32 -0
- data/include/prism/compiler/flex_array.h +19 -0
- data/include/prism/compiler/force_inline.h +21 -0
- data/include/prism/compiler/format.h +25 -0
- data/include/prism/compiler/inline.h +17 -0
- data/include/prism/compiler/nodiscard.h +22 -0
- data/include/prism/compiler/nonnull.h +18 -0
- data/include/prism/compiler/unused.h +18 -0
- data/include/prism/constant_pool.h +81 -0
- data/include/prism/diagnostic.h +38 -403
- data/include/prism/errors_format.h +53 -0
- data/include/prism/excludes.h +29 -0
- data/include/prism/integer.h +41 -0
- data/include/prism/internal/allocator.h +68 -0
- data/include/prism/internal/allocator_debug.h +88 -0
- data/include/prism/internal/arena.h +108 -0
- data/include/prism/internal/bit.h +42 -0
- data/include/prism/internal/buffer.h +94 -0
- data/include/prism/internal/char.h +145 -0
- data/include/prism/internal/comments.h +53 -0
- data/include/prism/internal/constant_pool.h +152 -0
- data/include/prism/internal/diagnostic.h +389 -0
- data/include/prism/{encoding.h → internal/encoding.h} +27 -68
- data/include/prism/internal/integer.h +68 -0
- data/include/prism/internal/isinf.h +16 -0
- data/include/prism/internal/line_offset_list.h +34 -0
- data/include/prism/{util/pm_list.h → internal/list.h} +11 -52
- data/include/prism/internal/magic_comments.h +23 -0
- data/include/prism/internal/memchr.h +15 -0
- data/include/prism/internal/node.h +38 -0
- data/include/prism/internal/options.h +232 -0
- data/include/prism/internal/parser.h +1004 -0
- data/include/prism/internal/regexp.h +26 -0
- data/include/prism/internal/serialize.h +39 -0
- data/include/prism/internal/source.h +72 -0
- data/include/prism/{static_literals.h → internal/static_literals.h} +26 -47
- data/include/prism/internal/stringy.h +35 -0
- data/include/prism/{util/pm_strncasecmp.h → internal/strncasecmp.h} +3 -17
- data/include/prism/{util/pm_strpbrk.h → internal/strpbrk.h} +7 -20
- data/include/prism/internal/tokens.h +11 -0
- data/include/prism/internal/xxh3.h +16 -0
- data/include/prism/json.h +32 -0
- data/include/prism/line_offset_list.h +61 -0
- data/include/prism/magic_comments.h +35 -0
- data/include/prism/node.h +18 -53
- data/include/prism/options.h +146 -280
- data/include/prism/parser.h +356 -867
- data/include/prism/prettyprint.h +6 -9
- data/include/prism/serialize.h +115 -0
- data/include/prism/source.h +155 -0
- data/include/prism/stream.h +28 -0
- data/include/prism/string_query.h +74 -0
- data/include/prism/stringy.h +72 -0
- data/include/prism/version.h +12 -3
- data/include/prism.h +43 -320
- data/lib/prism/compiler.rb +319 -305
- data/lib/prism/desugar_compiler.rb +105 -34
- data/lib/prism/dispatcher.rb +646 -473
- data/lib/prism/dot_visitor.rb +592 -511
- data/lib/prism/dsl.rb +391 -25
- data/lib/prism/ffi.rb +258 -90
- data/lib/prism/inspect_visitor.rb +357 -325
- data/lib/prism/lex_compat.rb +254 -212
- data/lib/prism/mutation_compiler.rb +313 -305
- data/lib/prism/node.rb +20966 -6992
- data/lib/prism/node_ext.rb +180 -187
- data/lib/prism/node_find.rb +215 -0
- data/lib/prism/parse_result/errors.rb +7 -1
- data/lib/prism/parse_result/newlines.rb +276 -8
- data/lib/prism/parse_result.rb +468 -139
- data/lib/prism/pattern.rb +65 -20
- data/lib/prism/reflection.rb +23 -12
- data/lib/prism/relocation.rb +149 -87
- data/lib/prism/serialize.rb +3460 -539
- data/lib/prism/string_query.rb +24 -1
- data/lib/prism/translation/parser/builder.rb +10 -2
- data/lib/prism/translation/parser/compiler.rb +44 -52
- data/lib/prism/translation/parser/lexer.rb +41 -92
- data/lib/prism/translation/parser.rb +1 -1
- data/lib/prism/translation/parser_current.rb +1 -1
- data/lib/prism/translation/ripper/lexer.rb +8 -10
- data/lib/prism/translation/ripper/sexp.rb +2 -10
- data/lib/prism/translation/ripper/shim.rb +2 -0
- data/lib/prism/translation/ripper.rb +967 -209
- data/lib/prism/translation/ruby_parser.rb +73 -316
- data/lib/prism/translation.rb +2 -0
- data/lib/prism/visitor.rb +632 -5
- data/lib/prism.rb +79 -9
- data/prism.gemspec +128 -62
- data/rbi/generated/prism/compiler.rbi +489 -0
- data/rbi/generated/prism/desugar_compiler.rbi +306 -0
- data/rbi/generated/prism/dispatcher.rbi +1138 -0
- data/rbi/generated/prism/dot_visitor.rbi +618 -0
- data/rbi/generated/prism/dsl.rbi +751 -0
- data/rbi/generated/prism/inspect_visitor.rbi +503 -0
- data/rbi/generated/prism/lex_compat.rbi +162 -0
- data/rbi/generated/prism/mutation_compiler.rbi +464 -0
- data/rbi/generated/prism/node.rbi +14407 -0
- data/rbi/generated/prism/node_ext.rbi +259 -0
- data/rbi/generated/prism/node_find.rbi +79 -0
- data/rbi/generated/prism/parse_result/errors.rbi +21 -0
- data/rbi/generated/prism/parse_result/newlines.rbi +208 -0
- data/rbi/generated/prism/parse_result.rbi +776 -0
- data/rbi/generated/prism/pattern.rbi +134 -0
- data/rbi/generated/prism/reflection.rbi +89 -0
- data/rbi/generated/prism/relocation.rbi +329 -0
- data/rbi/generated/prism/serialize.rbi +184 -0
- data/rbi/generated/prism/string_query.rbi +43 -0
- data/rbi/generated/prism/translation.rbi +7 -0
- data/rbi/generated/prism/visitor.rbi +650 -0
- data/rbi/generated/prism.rbi +86 -0
- data/rbi/prism/translation/parser_versions.rbi +5 -0
- data/rbi/rubyvm/node_find.rbi +14 -0
- data/sig/generated/prism/compiler.rbs +492 -0
- data/sig/generated/prism/desugar_compiler.rbs +305 -0
- data/sig/generated/prism/dispatcher.rbs +1292 -0
- data/sig/generated/prism/dot_visitor.rbs +635 -0
- data/sig/generated/prism/dsl.rbs +928 -0
- data/sig/generated/prism/inspect_visitor.rbs +509 -0
- data/sig/generated/prism/lex_compat.rbs +166 -0
- data/sig/{prism → generated/prism}/mutation_compiler.rbs +309 -4
- data/sig/generated/prism/node.rbs +20896 -0
- data/sig/generated/prism/node_ext.rbs +290 -0
- data/sig/generated/prism/node_find.rbs +90 -0
- data/sig/generated/prism/parse_result/errors.rbs +22 -0
- data/sig/generated/prism/parse_result/newlines.rbs +223 -0
- data/sig/generated/prism/parse_result.rbs +871 -0
- data/sig/generated/prism/pattern.rbs +156 -0
- data/sig/generated/prism/reflection.rbs +101 -0
- data/sig/generated/prism/relocation.rbs +428 -0
- data/sig/generated/prism/serialize.rbs +198 -0
- data/sig/generated/prism/string_query.rbs +43 -0
- data/sig/generated/prism/translation.rbs +8 -0
- data/sig/generated/prism/visitor.rbs +1111 -0
- data/sig/generated/prism.rbs +84 -0
- data/sig/manifest.yaml +2 -0
- data/src/arena.c +117 -0
- data/src/{util/pm_buffer.c → buffer.c} +53 -21
- data/src/{util/pm_char.c → char.c} +28 -57
- data/src/comments.c +454 -0
- data/src/constant_pool.c +406 -0
- data/src/diagnostic.c +97 -65
- data/src/encoding.c +8 -3
- data/src/errors_format.c +519 -0
- data/src/{util/pm_integer.c → integer.c} +33 -22
- data/src/json.c +5733 -0
- data/src/line_offset_list.c +100 -0
- data/src/list.c +24 -0
- data/src/{util/pm_memchr.c → memchr.c} +8 -6
- data/src/node.c +3504 -7674
- data/src/options.c +162 -49
- data/src/parser.c +367 -0
- data/src/prettyprint.c +421 -354
- data/src/prism.c +8402 -7161
- data/src/regexp.c +961 -45
- data/src/serialize.c +460 -424
- data/src/source.c +518 -0
- data/src/static_literals.c +111 -43
- data/src/string_query.c +180 -0
- data/src/stringy.c +91 -0
- data/src/{util/pm_strncasecmp.c → strncasecmp.c} +5 -4
- data/src/strpbrk.c +447 -0
- data/src/{token_type.c → tokens.c} +39 -18
- data/src/xxh3.c +292 -0
- metadata +128 -63
- data/ext/prism/api_pack.c +0 -276
- data/include/prism/defines.h +0 -260
- data/include/prism/pack.h +0 -163
- data/include/prism/regexp.h +0 -43
- data/include/prism/util/pm_buffer.h +0 -236
- data/include/prism/util/pm_char.h +0 -204
- data/include/prism/util/pm_constant_pool.h +0 -218
- data/include/prism/util/pm_integer.h +0 -130
- data/include/prism/util/pm_memchr.h +0 -29
- data/include/prism/util/pm_newline_list.h +0 -113
- data/include/prism/util/pm_string.h +0 -200
- data/lib/prism/pack.rb +0 -230
- data/lib/prism/parse_result/comments.rb +0 -188
- data/rbi/prism/compiler.rbi +0 -12
- data/rbi/prism/dsl.rbi +0 -524
- data/rbi/prism/inspect_visitor.rbi +0 -12
- data/rbi/prism/node.rbi +0 -8750
- data/rbi/prism/node_ext.rbi +0 -107
- data/rbi/prism/parse_result.rbi +0 -404
- data/rbi/prism/reflection.rbi +0 -58
- data/rbi/prism/string_query.rbi +0 -12
- data/rbi/prism/visitor.rbi +0 -473
- data/rbi/prism.rbi +0 -63
- data/sig/prism/compiler.rbs +0 -9
- data/sig/prism/dispatcher.rbs +0 -19
- data/sig/prism/dot_visitor.rbs +0 -6
- data/sig/prism/dsl.rbs +0 -351
- data/sig/prism/inspect_visitor.rbs +0 -22
- data/sig/prism/lex_compat.rbs +0 -10
- data/sig/prism/node.rbs +0 -4042
- data/sig/prism/node_ext.rbs +0 -149
- data/sig/prism/pack.rbs +0 -43
- data/sig/prism/parse_result/comments.rbs +0 -38
- data/sig/prism/parse_result.rbs +0 -197
- data/sig/prism/pattern.rbs +0 -13
- data/sig/prism/reflection.rbs +0 -50
- data/sig/prism/relocation.rbs +0 -185
- data/sig/prism/serialize.rbs +0 -8
- data/sig/prism/string_query.rbs +0 -11
- data/sig/prism/visitor.rbs +0 -169
- data/sig/prism.rbs +0 -272
- data/src/pack.c +0 -509
- data/src/util/pm_constant_pool.c +0 -342
- data/src/util/pm_list.c +0 -49
- data/src/util/pm_newline_list.c +0 -125
- data/src/util/pm_string.c +0 -381
- data/src/util/pm_strpbrk.c +0 -206
data/lib/prism/ffi.rb
CHANGED
|
@@ -12,7 +12,7 @@ require "ffi"
|
|
|
12
12
|
# autoloaded from within a non-main Ractor.
|
|
13
13
|
require "prism/serialize" if defined?(Ractor)
|
|
14
14
|
|
|
15
|
-
module Prism
|
|
15
|
+
module Prism # :nodoc:
|
|
16
16
|
module LibRubyParser # :nodoc:
|
|
17
17
|
extend FFI::Library
|
|
18
18
|
|
|
@@ -54,13 +54,18 @@ module Prism
|
|
|
54
54
|
def self.load_exported_functions_from(header, *functions, callbacks)
|
|
55
55
|
File.foreach("#{INCLUDE_DIR}/#{header}") do |line|
|
|
56
56
|
# We only want to attempt to load exported functions.
|
|
57
|
-
next unless line.
|
|
57
|
+
next unless line.include?("PRISM_EXPORTED_FUNCTION ")
|
|
58
58
|
|
|
59
59
|
# We only want to load the functions that we are interested in.
|
|
60
60
|
next unless functions.any? { |function| line.include?(function) }
|
|
61
61
|
|
|
62
|
+
# Strip leading attributes (PRISM_EXPORTED_FUNCTION, PRISM_NODISCARD, etc.)
|
|
63
|
+
line = line.sub(/\A(PRISM_\w+(?:\([^)]*\))?)+/, "")
|
|
64
|
+
# Strip trailing attributes (PRISM_NODISCARD, PRISM_NONNULL(...), etc.)
|
|
65
|
+
line = line.sub(/\)(\s+PRISM_\w+(?:\([^)]*\))?)+\s*;/, ");")
|
|
66
|
+
|
|
62
67
|
# Parse the function declaration.
|
|
63
|
-
unless /^
|
|
68
|
+
unless /^(?<return_type>.+) (?<name>\w+)\((?<arg_types>.+)\);$/ =~ line
|
|
64
69
|
raise "Could not parse #{line}"
|
|
65
70
|
end
|
|
66
71
|
|
|
@@ -85,30 +90,47 @@ module Prism
|
|
|
85
90
|
raise "Could not find functions #{functions.inspect}" unless functions.empty?
|
|
86
91
|
end
|
|
87
92
|
|
|
88
|
-
callback :
|
|
89
|
-
callback :
|
|
90
|
-
|
|
93
|
+
callback :pm_source_stream_fgets_t, [:pointer, :int, :pointer], :pointer
|
|
94
|
+
callback :pm_source_stream_feof_t, [:pointer], :int
|
|
95
|
+
pm_source_init_result_values = %i[PM_SOURCE_INIT_SUCCESS PM_SOURCE_INIT_ERROR_GENERIC PM_SOURCE_INIT_ERROR_DIRECTORY PM_SOURCE_INIT_ERROR_NON_REGULAR]
|
|
96
|
+
enum :pm_source_init_result_t, pm_source_init_result_values
|
|
91
97
|
enum :pm_string_query_t, [:PM_STRING_QUERY_ERROR, -1, :PM_STRING_QUERY_FALSE, :PM_STRING_QUERY_TRUE]
|
|
98
|
+
enum :pm_errors_format_type_t, [:PM_ERRORS_FORMAT_PLAIN, 1, :PM_ERRORS_FORMAT_STYLE, :PM_ERRORS_FORMAT_COLOR]
|
|
99
|
+
|
|
100
|
+
# Ractor-safe lookup table for pm_source_init_result_t, since FFI's
|
|
101
|
+
# enum_type accesses module instance variables that are not shareable.
|
|
102
|
+
SOURCE_INIT_RESULT = pm_source_init_result_values.freeze
|
|
92
103
|
|
|
93
104
|
load_exported_functions_from(
|
|
94
|
-
"prism.h",
|
|
105
|
+
"prism/version.h",
|
|
95
106
|
"pm_version",
|
|
107
|
+
[]
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
load_exported_functions_from(
|
|
111
|
+
"prism/serialize.h",
|
|
96
112
|
"pm_serialize_parse",
|
|
97
113
|
"pm_serialize_parse_stream",
|
|
98
114
|
"pm_serialize_parse_comments",
|
|
99
115
|
"pm_serialize_lex",
|
|
100
116
|
"pm_serialize_parse_lex",
|
|
101
|
-
"
|
|
117
|
+
"pm_serialize_parse_success_p",
|
|
118
|
+
"pm_serialize_parse_errors_format",
|
|
119
|
+
[]
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
load_exported_functions_from(
|
|
123
|
+
"prism/string_query.h",
|
|
102
124
|
"pm_string_query_local",
|
|
103
125
|
"pm_string_query_constant",
|
|
104
126
|
"pm_string_query_method_name",
|
|
105
|
-
|
|
127
|
+
"pm_string_query_keyword",
|
|
128
|
+
[]
|
|
106
129
|
)
|
|
107
130
|
|
|
108
131
|
load_exported_functions_from(
|
|
109
|
-
"prism/
|
|
110
|
-
"
|
|
111
|
-
"pm_buffer_init",
|
|
132
|
+
"prism/buffer.h",
|
|
133
|
+
"pm_buffer_new",
|
|
112
134
|
"pm_buffer_value",
|
|
113
135
|
"pm_buffer_length",
|
|
114
136
|
"pm_buffer_free",
|
|
@@ -116,20 +138,19 @@ module Prism
|
|
|
116
138
|
)
|
|
117
139
|
|
|
118
140
|
load_exported_functions_from(
|
|
119
|
-
"prism/
|
|
120
|
-
"
|
|
121
|
-
"
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
"
|
|
125
|
-
|
|
141
|
+
"prism/source.h",
|
|
142
|
+
"pm_source_file_new",
|
|
143
|
+
"pm_source_mapped_new",
|
|
144
|
+
"pm_source_stream_new",
|
|
145
|
+
"pm_source_free",
|
|
146
|
+
"pm_source_source",
|
|
147
|
+
"pm_source_length",
|
|
148
|
+
[:pm_source_stream_fgets_t, :pm_source_stream_feof_t]
|
|
126
149
|
)
|
|
127
150
|
|
|
128
151
|
# This object represents a pm_buffer_t. We only use it as an opaque pointer,
|
|
129
152
|
# so it doesn't need to know the fields of pm_buffer_t.
|
|
130
153
|
class PrismBuffer # :nodoc:
|
|
131
|
-
SIZEOF = LibRubyParser.pm_buffer_sizeof
|
|
132
|
-
|
|
133
154
|
attr_reader :pointer
|
|
134
155
|
|
|
135
156
|
def initialize(pointer)
|
|
@@ -151,22 +172,22 @@ module Prism
|
|
|
151
172
|
# Initialize a new buffer and yield it to the block. The buffer will be
|
|
152
173
|
# automatically freed when the block returns.
|
|
153
174
|
def self.with
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
175
|
+
buffer = LibRubyParser.pm_buffer_new
|
|
176
|
+
raise unless buffer
|
|
177
|
+
|
|
178
|
+
begin
|
|
179
|
+
yield new(buffer)
|
|
157
180
|
ensure
|
|
158
|
-
LibRubyParser.pm_buffer_free(
|
|
181
|
+
LibRubyParser.pm_buffer_free(buffer)
|
|
159
182
|
end
|
|
160
183
|
end
|
|
161
184
|
end
|
|
162
185
|
|
|
163
|
-
# This object represents
|
|
164
|
-
#
|
|
165
|
-
class
|
|
166
|
-
SIZEOF = LibRubyParser.pm_string_sizeof
|
|
167
|
-
|
|
186
|
+
# This object represents source code to be parsed. For strings it wraps a
|
|
187
|
+
# pointer directly; for files it uses a pm_source_t under the hood.
|
|
188
|
+
class PrismSource # :nodoc:
|
|
168
189
|
PLATFORM_EXPECTS_UTF8 =
|
|
169
|
-
RbConfig::CONFIG["host_os"].match?(/
|
|
190
|
+
RbConfig::CONFIG["host_os"].match?(/cygwin|mingw|mswin|darwin/i)
|
|
170
191
|
|
|
171
192
|
attr_reader :pointer, :length
|
|
172
193
|
|
|
@@ -181,7 +202,7 @@ module Prism
|
|
|
181
202
|
@pointer.read_string(@length)
|
|
182
203
|
end
|
|
183
204
|
|
|
184
|
-
# Yields a
|
|
205
|
+
# Yields a PrismSource backed by the given string to the block.
|
|
185
206
|
def self.with_string(string)
|
|
186
207
|
raise TypeError unless string.is_a?(String)
|
|
187
208
|
|
|
@@ -195,32 +216,43 @@ module Prism
|
|
|
195
216
|
end
|
|
196
217
|
end
|
|
197
218
|
|
|
198
|
-
# Yields a
|
|
199
|
-
def self.with_file(filepath)
|
|
200
|
-
|
|
219
|
+
# Yields a PrismSource to the given block, backed by a pm_source_t.
|
|
220
|
+
def self.with_file(filepath, options)
|
|
221
|
+
# File.path applies the same coercion and validation as the C
|
|
222
|
+
# extension's rb_get_path: it accepts to_path/to_str objects and
|
|
223
|
+
# rejects paths containing a NUL byte, which would otherwise truncate
|
|
224
|
+
# the path when it is handed to C as a NUL-terminated string.
|
|
225
|
+
filepath = File.path(filepath)
|
|
226
|
+
options[:filepath] = filepath
|
|
201
227
|
|
|
202
228
|
# On Windows and Mac, it's expected that filepaths will be encoded in
|
|
203
229
|
# UTF-8. If they are not, we need to convert them to UTF-8 before
|
|
204
|
-
# passing them into
|
|
230
|
+
# passing them into pm_source_mapped_new.
|
|
205
231
|
if PLATFORM_EXPECTS_UTF8 && (encoding = filepath.encoding) != Encoding::ASCII_8BIT && encoding != Encoding::UTF_8
|
|
206
232
|
filepath = filepath.encode(Encoding::UTF_8)
|
|
207
233
|
end
|
|
208
234
|
|
|
209
|
-
FFI::MemoryPointer.new(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
235
|
+
FFI::MemoryPointer.new(:int) do |result_ptr|
|
|
236
|
+
pm_source = LibRubyParser.pm_source_mapped_new(filepath, 0, result_ptr)
|
|
237
|
+
|
|
238
|
+
case SOURCE_INIT_RESULT[result_ptr.read_int]
|
|
239
|
+
when :PM_SOURCE_INIT_SUCCESS
|
|
240
|
+
pointer = LibRubyParser.pm_source_source(pm_source)
|
|
241
|
+
length = LibRubyParser.pm_source_length(pm_source)
|
|
214
242
|
return yield new(pointer, length, false)
|
|
215
|
-
when :
|
|
243
|
+
when :PM_SOURCE_INIT_ERROR_GENERIC
|
|
216
244
|
raise SystemCallError.new(filepath, FFI.errno)
|
|
217
|
-
when :
|
|
245
|
+
when :PM_SOURCE_INIT_ERROR_DIRECTORY
|
|
218
246
|
raise Errno::EISDIR.new(filepath)
|
|
247
|
+
when :PM_SOURCE_INIT_ERROR_NON_REGULAR
|
|
248
|
+
# Fall back to reading the file through Ruby IO for non-regular
|
|
249
|
+
# files (pipes, character devices, etc.)
|
|
250
|
+
return with_string(File.read(filepath)) { |string| yield string }
|
|
219
251
|
else
|
|
220
|
-
raise "Unknown error initializing
|
|
252
|
+
raise "Unknown error initializing pm_source_t: #{result_ptr.read_int}"
|
|
221
253
|
end
|
|
222
254
|
ensure
|
|
223
|
-
LibRubyParser.
|
|
255
|
+
LibRubyParser.pm_source_free(pm_source) if pm_source && !pm_source.null?
|
|
224
256
|
end
|
|
225
257
|
end
|
|
226
258
|
end
|
|
@@ -236,47 +268,58 @@ module Prism
|
|
|
236
268
|
class << self
|
|
237
269
|
# Mirror the Prism.dump API by using the serialization API.
|
|
238
270
|
def dump(source, **options)
|
|
239
|
-
LibRubyParser::
|
|
271
|
+
LibRubyParser::PrismSource.with_string(source) { |string| dump_common(string, options) }
|
|
240
272
|
end
|
|
241
273
|
|
|
242
274
|
# Mirror the Prism.dump_file API by using the serialization API.
|
|
243
275
|
def dump_file(filepath, **options)
|
|
244
|
-
|
|
245
|
-
LibRubyParser::PrismString.with_file(filepath) { |string| dump_common(string, options) }
|
|
276
|
+
LibRubyParser::PrismSource.with_file(filepath, options) { |string| dump_common(string, options) }
|
|
246
277
|
end
|
|
247
278
|
|
|
248
279
|
# Mirror the Prism.lex API by using the serialization API.
|
|
249
280
|
def lex(code, **options)
|
|
250
|
-
LibRubyParser::
|
|
281
|
+
LibRubyParser::PrismSource.with_string(code) { |string| lex_common(string, code, options) }
|
|
251
282
|
end
|
|
252
283
|
|
|
253
284
|
# Mirror the Prism.lex_file API by using the serialization API.
|
|
254
285
|
def lex_file(filepath, **options)
|
|
255
|
-
|
|
256
|
-
LibRubyParser::PrismString.with_file(filepath) { |string| lex_common(string, string.read, options) }
|
|
286
|
+
LibRubyParser::PrismSource.with_file(filepath, options) { |string| lex_common(string, string.read, options) }
|
|
257
287
|
end
|
|
258
288
|
|
|
259
289
|
# Mirror the Prism.parse API by using the serialization API.
|
|
260
290
|
def parse(code, **options)
|
|
261
|
-
LibRubyParser::
|
|
291
|
+
LibRubyParser::PrismSource.with_string(code) { |string| parse_common(string, code, options) }
|
|
262
292
|
end
|
|
263
293
|
|
|
264
294
|
# Mirror the Prism.parse_file API by using the serialization API. This uses
|
|
265
295
|
# native strings instead of Ruby strings because it allows us to use mmap
|
|
266
296
|
# when it is available.
|
|
267
297
|
def parse_file(filepath, **options)
|
|
268
|
-
|
|
269
|
-
LibRubyParser::PrismString.with_file(filepath) { |string| parse_common(string, string.read, options) }
|
|
298
|
+
LibRubyParser::PrismSource.with_file(filepath, options) { |string| parse_common(string, string.read, options) }
|
|
270
299
|
end
|
|
271
300
|
|
|
272
301
|
# Mirror the Prism.parse_stream API by using the serialization API.
|
|
273
302
|
def parse_stream(stream, **options)
|
|
303
|
+
format_type = raise_error_format_type(options)
|
|
304
|
+
|
|
274
305
|
LibRubyParser::PrismBuffer.with do |buffer|
|
|
306
|
+
# The largest number of bytes a single character can occupy in any
|
|
307
|
+
# encoding Ruby supports. IO#gets(limit) may return up to
|
|
308
|
+
# (max_enc_len - 1) bytes more than requested to avoid splitting a
|
|
309
|
+
# multi-byte character, so we reserve that much headroom (plus the NUL
|
|
310
|
+
# terminator) to guarantee the result fits in the caller's buffer. This
|
|
311
|
+
# mirrors MAX_ENC_LEN in ext/prism/extension.c.
|
|
312
|
+
max_enc_len = 6
|
|
313
|
+
|
|
275
314
|
source = +""
|
|
276
315
|
callback = -> (string, size, _) {
|
|
277
|
-
raise "Expected size to be
|
|
316
|
+
raise "Expected size to be > #{max_enc_len}, got: #{size}" if size <= max_enc_len
|
|
278
317
|
|
|
279
|
-
|
|
318
|
+
line = String.try_convert(stream.gets(size - max_enc_len))
|
|
319
|
+
if !line.nil?
|
|
320
|
+
# A misbehaving `gets` may ignore the limit; never write past the
|
|
321
|
+
# buffer (one byte is reserved for the NUL terminator).
|
|
322
|
+
line = line.byteslice(0, size - 1) if line.bytesize > size - 1
|
|
280
323
|
source << line
|
|
281
324
|
string.write_string("#{line}\x00", line.bytesize + 1)
|
|
282
325
|
end
|
|
@@ -284,43 +327,49 @@ module Prism
|
|
|
284
327
|
|
|
285
328
|
eof_callback = -> (_) { stream.eof? }
|
|
286
329
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
330
|
+
pm_source = LibRubyParser.pm_source_stream_new(nil, callback, eof_callback)
|
|
331
|
+
begin
|
|
332
|
+
LibRubyParser.pm_serialize_parse_stream(buffer.pointer, pm_source, dump_options(options))
|
|
333
|
+
result = Prism.load(source, buffer.read, options.fetch(:freeze, false))
|
|
334
|
+
|
|
335
|
+
if format_type && result.failure?
|
|
336
|
+
LibRubyParser::PrismSource.with_string(source) do |string|
|
|
337
|
+
raise_error(string, options, format_type)
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
result
|
|
342
|
+
ensure
|
|
343
|
+
LibRubyParser.pm_source_free(pm_source) if pm_source && !pm_source.null?
|
|
344
|
+
end
|
|
294
345
|
end
|
|
295
346
|
end
|
|
296
347
|
|
|
297
348
|
# Mirror the Prism.parse_comments API by using the serialization API.
|
|
298
349
|
def parse_comments(code, **options)
|
|
299
|
-
LibRubyParser::
|
|
350
|
+
LibRubyParser::PrismSource.with_string(code) { |string| parse_comments_common(string, code, options) }
|
|
300
351
|
end
|
|
301
352
|
|
|
302
353
|
# Mirror the Prism.parse_file_comments API by using the serialization
|
|
303
354
|
# API. This uses native strings instead of Ruby strings because it allows us
|
|
304
355
|
# to use mmap when it is available.
|
|
305
356
|
def parse_file_comments(filepath, **options)
|
|
306
|
-
|
|
307
|
-
LibRubyParser::PrismString.with_file(filepath) { |string| parse_comments_common(string, string.read, options) }
|
|
357
|
+
LibRubyParser::PrismSource.with_file(filepath, options) { |string| parse_comments_common(string, string.read, options) }
|
|
308
358
|
end
|
|
309
359
|
|
|
310
360
|
# Mirror the Prism.parse_lex API by using the serialization API.
|
|
311
361
|
def parse_lex(code, **options)
|
|
312
|
-
LibRubyParser::
|
|
362
|
+
LibRubyParser::PrismSource.with_string(code) { |string| parse_lex_common(string, code, options) }
|
|
313
363
|
end
|
|
314
364
|
|
|
315
365
|
# Mirror the Prism.parse_lex_file API by using the serialization API.
|
|
316
366
|
def parse_lex_file(filepath, **options)
|
|
317
|
-
|
|
318
|
-
LibRubyParser::PrismString.with_file(filepath) { |string| parse_lex_common(string, string.read, options) }
|
|
367
|
+
LibRubyParser::PrismSource.with_file(filepath, options) { |string| parse_lex_common(string, string.read, options) }
|
|
319
368
|
end
|
|
320
369
|
|
|
321
370
|
# Mirror the Prism.parse_success? API by using the serialization API.
|
|
322
371
|
def parse_success?(code, **options)
|
|
323
|
-
LibRubyParser::
|
|
372
|
+
LibRubyParser::PrismSource.with_string(code) { |string| parse_file_success_common(string, options) }
|
|
324
373
|
end
|
|
325
374
|
|
|
326
375
|
# Mirror the Prism.parse_failure? API by using the serialization API.
|
|
@@ -330,8 +379,7 @@ module Prism
|
|
|
330
379
|
|
|
331
380
|
# Mirror the Prism.parse_file_success? API by using the serialization API.
|
|
332
381
|
def parse_file_success?(filepath, **options)
|
|
333
|
-
|
|
334
|
-
LibRubyParser::PrismString.with_file(filepath) { |string| parse_file_success_common(string, options) }
|
|
382
|
+
LibRubyParser::PrismSource.with_file(filepath, options) { |string| parse_file_success_common(string, options) }
|
|
335
383
|
end
|
|
336
384
|
|
|
337
385
|
# Mirror the Prism.parse_file_failure? API by using the serialization API.
|
|
@@ -341,7 +389,11 @@ module Prism
|
|
|
341
389
|
|
|
342
390
|
# Mirror the Prism.profile API by using the serialization API.
|
|
343
391
|
def profile(source, **options)
|
|
344
|
-
LibRubyParser::
|
|
392
|
+
LibRubyParser::PrismSource.with_string(source) do |string|
|
|
393
|
+
if (format_type = raise_error_format_type(options))
|
|
394
|
+
raise_error(string, options, format_type)
|
|
395
|
+
end
|
|
396
|
+
|
|
345
397
|
LibRubyParser::PrismBuffer.with do |buffer|
|
|
346
398
|
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
|
|
347
399
|
nil
|
|
@@ -351,9 +403,12 @@ module Prism
|
|
|
351
403
|
|
|
352
404
|
# Mirror the Prism.profile_file API by using the serialization API.
|
|
353
405
|
def profile_file(filepath, **options)
|
|
354
|
-
LibRubyParser::
|
|
406
|
+
LibRubyParser::PrismSource.with_file(filepath, options) do |string|
|
|
407
|
+
if (format_type = raise_error_format_type(options))
|
|
408
|
+
raise_error(string, options, format_type)
|
|
409
|
+
end
|
|
410
|
+
|
|
355
411
|
LibRubyParser::PrismBuffer.with do |buffer|
|
|
356
|
-
options[:filepath] = filepath
|
|
357
412
|
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
|
|
358
413
|
nil
|
|
359
414
|
end
|
|
@@ -363,6 +418,10 @@ module Prism
|
|
|
363
418
|
private
|
|
364
419
|
|
|
365
420
|
def dump_common(string, options) # :nodoc:
|
|
421
|
+
if (format_type = raise_error_format_type(options))
|
|
422
|
+
raise_error(string, options, format_type)
|
|
423
|
+
end
|
|
424
|
+
|
|
366
425
|
LibRubyParser::PrismBuffer.with do |buffer|
|
|
367
426
|
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
|
|
368
427
|
|
|
@@ -374,18 +433,31 @@ module Prism
|
|
|
374
433
|
end
|
|
375
434
|
|
|
376
435
|
def lex_common(string, code, options) # :nodoc:
|
|
436
|
+
format_type = raise_error_format_type(options)
|
|
437
|
+
|
|
377
438
|
LibRubyParser::PrismBuffer.with do |buffer|
|
|
378
439
|
LibRubyParser.pm_serialize_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
|
|
379
|
-
Serialize.load_lex(code, buffer.read, options.fetch(:freeze, false))
|
|
440
|
+
result = Serialize.load_lex(code, buffer.read, options.fetch(:freeze, false))
|
|
441
|
+
|
|
442
|
+
raise_error(string, options, format_type) if format_type && result.failure?
|
|
443
|
+
result
|
|
380
444
|
end
|
|
381
445
|
end
|
|
382
446
|
|
|
383
447
|
def parse_common(string, code, options) # :nodoc:
|
|
448
|
+
format_type = raise_error_format_type(options)
|
|
384
449
|
serialized = dump_common(string, options)
|
|
385
|
-
Serialize.load_parse(code, serialized, options.fetch(:freeze, false))
|
|
450
|
+
result = Serialize.load_parse(code, serialized, options.fetch(:freeze, false))
|
|
451
|
+
|
|
452
|
+
raise_error(string, options, format_type) if format_type && result.failure?
|
|
453
|
+
result
|
|
386
454
|
end
|
|
387
455
|
|
|
388
456
|
def parse_comments_common(string, code, options) # :nodoc:
|
|
457
|
+
if (format_type = raise_error_format_type(options))
|
|
458
|
+
raise_error(string, options, format_type)
|
|
459
|
+
end
|
|
460
|
+
|
|
389
461
|
LibRubyParser::PrismBuffer.with do |buffer|
|
|
390
462
|
LibRubyParser.pm_serialize_parse_comments(buffer.pointer, string.pointer, string.length, dump_options(options))
|
|
391
463
|
Serialize.load_parse_comments(code, buffer.read, options.fetch(:freeze, false))
|
|
@@ -393,14 +465,82 @@ module Prism
|
|
|
393
465
|
end
|
|
394
466
|
|
|
395
467
|
def parse_lex_common(string, code, options) # :nodoc:
|
|
468
|
+
format_type = raise_error_format_type(options)
|
|
469
|
+
|
|
396
470
|
LibRubyParser::PrismBuffer.with do |buffer|
|
|
397
471
|
LibRubyParser.pm_serialize_parse_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
|
|
398
|
-
Serialize.load_parse_lex(code, buffer.read, options.fetch(:freeze, false))
|
|
472
|
+
result = Serialize.load_parse_lex(code, buffer.read, options.fetch(:freeze, false))
|
|
473
|
+
|
|
474
|
+
raise_error(string, options, format_type) if format_type && result.failure?
|
|
475
|
+
result
|
|
399
476
|
end
|
|
400
477
|
end
|
|
401
478
|
|
|
402
479
|
def parse_file_success_common(string, options) # :nodoc:
|
|
403
|
-
|
|
480
|
+
format_type = raise_error_format_type(options)
|
|
481
|
+
success = LibRubyParser.pm_serialize_parse_success_p(string.pointer, string.length, dump_options(options))
|
|
482
|
+
|
|
483
|
+
raise_error(string, options, format_type) if format_type && !success
|
|
484
|
+
success
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
# Extract the raise_error option from the given options hash and convert
|
|
488
|
+
# it into the format type that should be used when formatting errors, or
|
|
489
|
+
# nil if raising is disabled.
|
|
490
|
+
def raise_error_format_type(options) # :nodoc:
|
|
491
|
+
case (value = options.delete(:raise_error))
|
|
492
|
+
when nil, false
|
|
493
|
+
nil
|
|
494
|
+
when true
|
|
495
|
+
# When given true, mirror the behavior of CRuby itself: color when
|
|
496
|
+
# $stderr is a terminal (unless NO_COLOR is set), bold styling when
|
|
497
|
+
# NO_COLOR is set, plain otherwise. This policy is duplicated in
|
|
498
|
+
# ext/prism/extension.c (build_options_i) and the two must stay in
|
|
499
|
+
# sync.
|
|
500
|
+
if $stderr.respond_to?(:tty?) && $stderr.tty?
|
|
501
|
+
no_color = ENV["NO_COLOR"]
|
|
502
|
+
(no_color.nil? || no_color.empty?) ? :PM_ERRORS_FORMAT_COLOR : :PM_ERRORS_FORMAT_STYLE
|
|
503
|
+
else
|
|
504
|
+
:PM_ERRORS_FORMAT_PLAIN
|
|
505
|
+
end
|
|
506
|
+
when :plain
|
|
507
|
+
:PM_ERRORS_FORMAT_PLAIN
|
|
508
|
+
when :style
|
|
509
|
+
:PM_ERRORS_FORMAT_STYLE
|
|
510
|
+
when :color
|
|
511
|
+
:PM_ERRORS_FORMAT_COLOR
|
|
512
|
+
when Symbol
|
|
513
|
+
raise ArgumentError, "invalid raise_error value: #{value}"
|
|
514
|
+
else
|
|
515
|
+
raise TypeError, "wrong argument type #{value.class} (expected Symbol)"
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
# Parse the given source and format any errors that are encountered into
|
|
520
|
+
# an appropriate exception, then raise it. If the source parses without
|
|
521
|
+
# any errors, then return nil.
|
|
522
|
+
def raise_error(string, options, format_type) # :nodoc:
|
|
523
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
|
524
|
+
level = LibRubyParser.pm_serialize_parse_errors_format(buffer.pointer, string.pointer, string.length, dump_options(options), format_type)
|
|
525
|
+
return if level == -1
|
|
526
|
+
|
|
527
|
+
encoding_name, _, message = buffer.read.partition("\0")
|
|
528
|
+
|
|
529
|
+
case level
|
|
530
|
+
when 0 # syntax
|
|
531
|
+
error = SyntaxError.new(message.force_encoding(encoding_name))
|
|
532
|
+
error.instance_variable_set(:@path, options.fetch(:filepath, ""))
|
|
533
|
+
raise error
|
|
534
|
+
when 1 # argument
|
|
535
|
+
raise ArgumentError, message.force_encoding(encoding_name)
|
|
536
|
+
when 2 # load
|
|
537
|
+
error = LoadError.new(message.force_encoding(Encoding.find("locale")))
|
|
538
|
+
error.instance_variable_set(:@path, nil)
|
|
539
|
+
raise error
|
|
540
|
+
else
|
|
541
|
+
raise "Unknown error level: #{level}"
|
|
542
|
+
end
|
|
543
|
+
end
|
|
404
544
|
end
|
|
405
545
|
|
|
406
546
|
# Return the value that should be dumped for the command_line option.
|
|
@@ -423,11 +563,28 @@ module Prism
|
|
|
423
563
|
|
|
424
564
|
# Return the value that should be dumped for the version option.
|
|
425
565
|
def dump_options_version(version)
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
when
|
|
566
|
+
case version
|
|
567
|
+
when "current"
|
|
568
|
+
version_string_to_number(RUBY_VERSION) || raise(CurrentVersionError, RUBY_VERSION)
|
|
569
|
+
when "latest"
|
|
430
570
|
0 # Handled in pm_parser_init
|
|
571
|
+
when "nearest", nil
|
|
572
|
+
dump = version_string_to_number(RUBY_VERSION)
|
|
573
|
+
return dump if dump
|
|
574
|
+
if RUBY_VERSION < "3.3"
|
|
575
|
+
version_string_to_number("3.3")
|
|
576
|
+
else
|
|
577
|
+
0 # Handled in pm_parser_init
|
|
578
|
+
end
|
|
579
|
+
else
|
|
580
|
+
version_string_to_number(version) || raise(ArgumentError, "invalid version: #{version}")
|
|
581
|
+
end
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
# Converts a version string like "4.0.0" or "4.0" into a number.
|
|
585
|
+
# Returns nil if the version is unknown.
|
|
586
|
+
def version_string_to_number(version)
|
|
587
|
+
case version
|
|
431
588
|
when /\A3\.3(\.\d+)?\z/
|
|
432
589
|
1
|
|
433
590
|
when /\A3\.4(\.\d+)?\z/
|
|
@@ -436,17 +593,20 @@ module Prism
|
|
|
436
593
|
3
|
|
437
594
|
when /\A4\.1(\.\d+)?\z/
|
|
438
595
|
4
|
|
439
|
-
else
|
|
440
|
-
if current
|
|
441
|
-
raise CurrentVersionError, RUBY_VERSION
|
|
442
|
-
else
|
|
443
|
-
raise ArgumentError, "invalid version: #{version}"
|
|
444
|
-
end
|
|
445
596
|
end
|
|
446
597
|
end
|
|
447
598
|
|
|
599
|
+
# The set of options that are understood by the parsing APIs. Note that
|
|
600
|
+
# raise_error is not listed here because it is deleted from the options
|
|
601
|
+
# hash by raise_error_format_type before the options are dumped.
|
|
602
|
+
DUMP_OPTIONS_KEYS = [:attach_comments, :command_line, :encoding, :filepath, :freeze, :frozen_string_literal, :line, :main_script, :partial_script, :scopes, :version].freeze
|
|
603
|
+
private_constant :DUMP_OPTIONS_KEYS
|
|
604
|
+
|
|
448
605
|
# Convert the given options into a serialized options string.
|
|
449
606
|
def dump_options(options)
|
|
607
|
+
unknown_keys = options.keys - DUMP_OPTIONS_KEYS
|
|
608
|
+
raise ArgumentError, "unknown keyword: #{unknown_keys.first}" unless unknown_keys.empty?
|
|
609
|
+
|
|
450
610
|
template = +""
|
|
451
611
|
values = []
|
|
452
612
|
|
|
@@ -491,6 +651,9 @@ module Prism
|
|
|
491
651
|
template << "C"
|
|
492
652
|
values << (options.fetch(:freeze, false) ? 1 : 0)
|
|
493
653
|
|
|
654
|
+
template << "C"
|
|
655
|
+
values << (options.fetch(:attach_comments, false) ? 1 : 0)
|
|
656
|
+
|
|
494
657
|
template << "L"
|
|
495
658
|
if (scopes = options[:scopes])
|
|
496
659
|
values << scopes.length
|
|
@@ -543,7 +706,7 @@ module Prism
|
|
|
543
706
|
|
|
544
707
|
# Here we are going to patch StringQuery to put in the class-level methods so
|
|
545
708
|
# that it can maintain a consistent interface
|
|
546
|
-
class StringQuery
|
|
709
|
+
class StringQuery # :nodoc:
|
|
547
710
|
class << self
|
|
548
711
|
# Mirrors the C extension's StringQuery::local? method.
|
|
549
712
|
def local?(string)
|
|
@@ -560,6 +723,11 @@ module Prism
|
|
|
560
723
|
query(LibRubyParser.pm_string_query_method_name(string, string.bytesize, string.encoding.name))
|
|
561
724
|
end
|
|
562
725
|
|
|
726
|
+
# Mirrors the C extension's StringQuery::keyword? method.
|
|
727
|
+
def keyword?(string)
|
|
728
|
+
query(LibRubyParser.pm_string_query_keyword(string, string.bytesize, string.encoding.name))
|
|
729
|
+
end
|
|
730
|
+
|
|
563
731
|
private
|
|
564
732
|
|
|
565
733
|
# Parse the enum result and return an appropriate boolean.
|