prism 1.9.0 → 2.0.0.rc1
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 +84 -0
- 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 +21 -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 +778 -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 +24 -0
- data/include/prism/compiler/align.h +36 -0
- data/include/prism/compiler/assume.h +25 -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 +91 -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 +984 -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/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 +336 -868
- 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 +63 -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 +252 -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 +20268 -7030
- 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 +453 -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 +3443 -535
- data/lib/prism/string_query.rb +16 -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 +122 -60
- 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 +13681 -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 +764 -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 +181 -0
- data/rbi/generated/prism/string_query.rbi +36 -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 +20160 -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 +859 -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 +195 -0
- data/sig/generated/prism/string_query.rbs +36 -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} +44 -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 +349 -0
- data/src/prettyprint.c +421 -354
- data/src/prism.c +8030 -6970
- data/src/regexp.c +961 -45
- data/src/serialize.c +459 -424
- data/src/source.c +518 -0
- data/src/static_literals.c +111 -43
- data/src/string_query.c +166 -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
- metadata +122 -61
- 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,46 @@ 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
|
+
[]
|
|
106
128
|
)
|
|
107
129
|
|
|
108
130
|
load_exported_functions_from(
|
|
109
|
-
"prism/
|
|
110
|
-
"
|
|
111
|
-
"pm_buffer_init",
|
|
131
|
+
"prism/buffer.h",
|
|
132
|
+
"pm_buffer_new",
|
|
112
133
|
"pm_buffer_value",
|
|
113
134
|
"pm_buffer_length",
|
|
114
135
|
"pm_buffer_free",
|
|
@@ -116,20 +137,19 @@ module Prism
|
|
|
116
137
|
)
|
|
117
138
|
|
|
118
139
|
load_exported_functions_from(
|
|
119
|
-
"prism/
|
|
120
|
-
"
|
|
121
|
-
"
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
"
|
|
125
|
-
|
|
140
|
+
"prism/source.h",
|
|
141
|
+
"pm_source_file_new",
|
|
142
|
+
"pm_source_mapped_new",
|
|
143
|
+
"pm_source_stream_new",
|
|
144
|
+
"pm_source_free",
|
|
145
|
+
"pm_source_source",
|
|
146
|
+
"pm_source_length",
|
|
147
|
+
[:pm_source_stream_fgets_t, :pm_source_stream_feof_t]
|
|
126
148
|
)
|
|
127
149
|
|
|
128
150
|
# This object represents a pm_buffer_t. We only use it as an opaque pointer,
|
|
129
151
|
# so it doesn't need to know the fields of pm_buffer_t.
|
|
130
152
|
class PrismBuffer # :nodoc:
|
|
131
|
-
SIZEOF = LibRubyParser.pm_buffer_sizeof
|
|
132
|
-
|
|
133
153
|
attr_reader :pointer
|
|
134
154
|
|
|
135
155
|
def initialize(pointer)
|
|
@@ -151,22 +171,22 @@ module Prism
|
|
|
151
171
|
# Initialize a new buffer and yield it to the block. The buffer will be
|
|
152
172
|
# automatically freed when the block returns.
|
|
153
173
|
def self.with
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
174
|
+
buffer = LibRubyParser.pm_buffer_new
|
|
175
|
+
raise unless buffer
|
|
176
|
+
|
|
177
|
+
begin
|
|
178
|
+
yield new(buffer)
|
|
157
179
|
ensure
|
|
158
|
-
LibRubyParser.pm_buffer_free(
|
|
180
|
+
LibRubyParser.pm_buffer_free(buffer)
|
|
159
181
|
end
|
|
160
182
|
end
|
|
161
183
|
end
|
|
162
184
|
|
|
163
|
-
# This object represents
|
|
164
|
-
#
|
|
165
|
-
class
|
|
166
|
-
SIZEOF = LibRubyParser.pm_string_sizeof
|
|
167
|
-
|
|
185
|
+
# This object represents source code to be parsed. For strings it wraps a
|
|
186
|
+
# pointer directly; for files it uses a pm_source_t under the hood.
|
|
187
|
+
class PrismSource # :nodoc:
|
|
168
188
|
PLATFORM_EXPECTS_UTF8 =
|
|
169
|
-
RbConfig::CONFIG["host_os"].match?(/
|
|
189
|
+
RbConfig::CONFIG["host_os"].match?(/cygwin|mingw|mswin|darwin/i)
|
|
170
190
|
|
|
171
191
|
attr_reader :pointer, :length
|
|
172
192
|
|
|
@@ -181,7 +201,7 @@ module Prism
|
|
|
181
201
|
@pointer.read_string(@length)
|
|
182
202
|
end
|
|
183
203
|
|
|
184
|
-
# Yields a
|
|
204
|
+
# Yields a PrismSource backed by the given string to the block.
|
|
185
205
|
def self.with_string(string)
|
|
186
206
|
raise TypeError unless string.is_a?(String)
|
|
187
207
|
|
|
@@ -195,32 +215,43 @@ module Prism
|
|
|
195
215
|
end
|
|
196
216
|
end
|
|
197
217
|
|
|
198
|
-
# Yields a
|
|
199
|
-
def self.with_file(filepath)
|
|
200
|
-
|
|
218
|
+
# Yields a PrismSource to the given block, backed by a pm_source_t.
|
|
219
|
+
def self.with_file(filepath, options)
|
|
220
|
+
# File.path applies the same coercion and validation as the C
|
|
221
|
+
# extension's rb_get_path: it accepts to_path/to_str objects and
|
|
222
|
+
# rejects paths containing a NUL byte, which would otherwise truncate
|
|
223
|
+
# the path when it is handed to C as a NUL-terminated string.
|
|
224
|
+
filepath = File.path(filepath)
|
|
225
|
+
options[:filepath] = filepath
|
|
201
226
|
|
|
202
227
|
# On Windows and Mac, it's expected that filepaths will be encoded in
|
|
203
228
|
# UTF-8. If they are not, we need to convert them to UTF-8 before
|
|
204
|
-
# passing them into
|
|
229
|
+
# passing them into pm_source_mapped_new.
|
|
205
230
|
if PLATFORM_EXPECTS_UTF8 && (encoding = filepath.encoding) != Encoding::ASCII_8BIT && encoding != Encoding::UTF_8
|
|
206
231
|
filepath = filepath.encode(Encoding::UTF_8)
|
|
207
232
|
end
|
|
208
233
|
|
|
209
|
-
FFI::MemoryPointer.new(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
234
|
+
FFI::MemoryPointer.new(:int) do |result_ptr|
|
|
235
|
+
pm_source = LibRubyParser.pm_source_mapped_new(filepath, 0, result_ptr)
|
|
236
|
+
|
|
237
|
+
case SOURCE_INIT_RESULT[result_ptr.read_int]
|
|
238
|
+
when :PM_SOURCE_INIT_SUCCESS
|
|
239
|
+
pointer = LibRubyParser.pm_source_source(pm_source)
|
|
240
|
+
length = LibRubyParser.pm_source_length(pm_source)
|
|
214
241
|
return yield new(pointer, length, false)
|
|
215
|
-
when :
|
|
242
|
+
when :PM_SOURCE_INIT_ERROR_GENERIC
|
|
216
243
|
raise SystemCallError.new(filepath, FFI.errno)
|
|
217
|
-
when :
|
|
244
|
+
when :PM_SOURCE_INIT_ERROR_DIRECTORY
|
|
218
245
|
raise Errno::EISDIR.new(filepath)
|
|
246
|
+
when :PM_SOURCE_INIT_ERROR_NON_REGULAR
|
|
247
|
+
# Fall back to reading the file through Ruby IO for non-regular
|
|
248
|
+
# files (pipes, character devices, etc.)
|
|
249
|
+
return with_string(File.read(filepath)) { |string| yield string }
|
|
219
250
|
else
|
|
220
|
-
raise "Unknown error initializing
|
|
251
|
+
raise "Unknown error initializing pm_source_t: #{result_ptr.read_int}"
|
|
221
252
|
end
|
|
222
253
|
ensure
|
|
223
|
-
LibRubyParser.
|
|
254
|
+
LibRubyParser.pm_source_free(pm_source) if pm_source && !pm_source.null?
|
|
224
255
|
end
|
|
225
256
|
end
|
|
226
257
|
end
|
|
@@ -236,47 +267,58 @@ module Prism
|
|
|
236
267
|
class << self
|
|
237
268
|
# Mirror the Prism.dump API by using the serialization API.
|
|
238
269
|
def dump(source, **options)
|
|
239
|
-
LibRubyParser::
|
|
270
|
+
LibRubyParser::PrismSource.with_string(source) { |string| dump_common(string, options) }
|
|
240
271
|
end
|
|
241
272
|
|
|
242
273
|
# Mirror the Prism.dump_file API by using the serialization API.
|
|
243
274
|
def dump_file(filepath, **options)
|
|
244
|
-
|
|
245
|
-
LibRubyParser::PrismString.with_file(filepath) { |string| dump_common(string, options) }
|
|
275
|
+
LibRubyParser::PrismSource.with_file(filepath, options) { |string| dump_common(string, options) }
|
|
246
276
|
end
|
|
247
277
|
|
|
248
278
|
# Mirror the Prism.lex API by using the serialization API.
|
|
249
279
|
def lex(code, **options)
|
|
250
|
-
LibRubyParser::
|
|
280
|
+
LibRubyParser::PrismSource.with_string(code) { |string| lex_common(string, code, options) }
|
|
251
281
|
end
|
|
252
282
|
|
|
253
283
|
# Mirror the Prism.lex_file API by using the serialization API.
|
|
254
284
|
def lex_file(filepath, **options)
|
|
255
|
-
|
|
256
|
-
LibRubyParser::PrismString.with_file(filepath) { |string| lex_common(string, string.read, options) }
|
|
285
|
+
LibRubyParser::PrismSource.with_file(filepath, options) { |string| lex_common(string, string.read, options) }
|
|
257
286
|
end
|
|
258
287
|
|
|
259
288
|
# Mirror the Prism.parse API by using the serialization API.
|
|
260
289
|
def parse(code, **options)
|
|
261
|
-
LibRubyParser::
|
|
290
|
+
LibRubyParser::PrismSource.with_string(code) { |string| parse_common(string, code, options) }
|
|
262
291
|
end
|
|
263
292
|
|
|
264
293
|
# Mirror the Prism.parse_file API by using the serialization API. This uses
|
|
265
294
|
# native strings instead of Ruby strings because it allows us to use mmap
|
|
266
295
|
# when it is available.
|
|
267
296
|
def parse_file(filepath, **options)
|
|
268
|
-
|
|
269
|
-
LibRubyParser::PrismString.with_file(filepath) { |string| parse_common(string, string.read, options) }
|
|
297
|
+
LibRubyParser::PrismSource.with_file(filepath, options) { |string| parse_common(string, string.read, options) }
|
|
270
298
|
end
|
|
271
299
|
|
|
272
300
|
# Mirror the Prism.parse_stream API by using the serialization API.
|
|
273
301
|
def parse_stream(stream, **options)
|
|
302
|
+
format_type = raise_error_format_type(options)
|
|
303
|
+
|
|
274
304
|
LibRubyParser::PrismBuffer.with do |buffer|
|
|
305
|
+
# The largest number of bytes a single character can occupy in any
|
|
306
|
+
# encoding Ruby supports. IO#gets(limit) may return up to
|
|
307
|
+
# (max_enc_len - 1) bytes more than requested to avoid splitting a
|
|
308
|
+
# multi-byte character, so we reserve that much headroom (plus the NUL
|
|
309
|
+
# terminator) to guarantee the result fits in the caller's buffer. This
|
|
310
|
+
# mirrors MAX_ENC_LEN in ext/prism/extension.c.
|
|
311
|
+
max_enc_len = 6
|
|
312
|
+
|
|
275
313
|
source = +""
|
|
276
314
|
callback = -> (string, size, _) {
|
|
277
|
-
raise "Expected size to be
|
|
315
|
+
raise "Expected size to be > #{max_enc_len}, got: #{size}" if size <= max_enc_len
|
|
278
316
|
|
|
279
|
-
|
|
317
|
+
line = String.try_convert(stream.gets(size - max_enc_len))
|
|
318
|
+
if !line.nil?
|
|
319
|
+
# A misbehaving `gets` may ignore the limit; never write past the
|
|
320
|
+
# buffer (one byte is reserved for the NUL terminator).
|
|
321
|
+
line = line.byteslice(0, size - 1) if line.bytesize > size - 1
|
|
280
322
|
source << line
|
|
281
323
|
string.write_string("#{line}\x00", line.bytesize + 1)
|
|
282
324
|
end
|
|
@@ -284,43 +326,49 @@ module Prism
|
|
|
284
326
|
|
|
285
327
|
eof_callback = -> (_) { stream.eof? }
|
|
286
328
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
329
|
+
pm_source = LibRubyParser.pm_source_stream_new(nil, callback, eof_callback)
|
|
330
|
+
begin
|
|
331
|
+
LibRubyParser.pm_serialize_parse_stream(buffer.pointer, pm_source, dump_options(options))
|
|
332
|
+
result = Prism.load(source, buffer.read, options.fetch(:freeze, false))
|
|
333
|
+
|
|
334
|
+
if format_type && result.failure?
|
|
335
|
+
LibRubyParser::PrismSource.with_string(source) do |string|
|
|
336
|
+
raise_error(string, options, format_type)
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
result
|
|
341
|
+
ensure
|
|
342
|
+
LibRubyParser.pm_source_free(pm_source) if pm_source && !pm_source.null?
|
|
343
|
+
end
|
|
294
344
|
end
|
|
295
345
|
end
|
|
296
346
|
|
|
297
347
|
# Mirror the Prism.parse_comments API by using the serialization API.
|
|
298
348
|
def parse_comments(code, **options)
|
|
299
|
-
LibRubyParser::
|
|
349
|
+
LibRubyParser::PrismSource.with_string(code) { |string| parse_comments_common(string, code, options) }
|
|
300
350
|
end
|
|
301
351
|
|
|
302
352
|
# Mirror the Prism.parse_file_comments API by using the serialization
|
|
303
353
|
# API. This uses native strings instead of Ruby strings because it allows us
|
|
304
354
|
# to use mmap when it is available.
|
|
305
355
|
def parse_file_comments(filepath, **options)
|
|
306
|
-
|
|
307
|
-
LibRubyParser::PrismString.with_file(filepath) { |string| parse_comments_common(string, string.read, options) }
|
|
356
|
+
LibRubyParser::PrismSource.with_file(filepath, options) { |string| parse_comments_common(string, string.read, options) }
|
|
308
357
|
end
|
|
309
358
|
|
|
310
359
|
# Mirror the Prism.parse_lex API by using the serialization API.
|
|
311
360
|
def parse_lex(code, **options)
|
|
312
|
-
LibRubyParser::
|
|
361
|
+
LibRubyParser::PrismSource.with_string(code) { |string| parse_lex_common(string, code, options) }
|
|
313
362
|
end
|
|
314
363
|
|
|
315
364
|
# Mirror the Prism.parse_lex_file API by using the serialization API.
|
|
316
365
|
def parse_lex_file(filepath, **options)
|
|
317
|
-
|
|
318
|
-
LibRubyParser::PrismString.with_file(filepath) { |string| parse_lex_common(string, string.read, options) }
|
|
366
|
+
LibRubyParser::PrismSource.with_file(filepath, options) { |string| parse_lex_common(string, string.read, options) }
|
|
319
367
|
end
|
|
320
368
|
|
|
321
369
|
# Mirror the Prism.parse_success? API by using the serialization API.
|
|
322
370
|
def parse_success?(code, **options)
|
|
323
|
-
LibRubyParser::
|
|
371
|
+
LibRubyParser::PrismSource.with_string(code) { |string| parse_file_success_common(string, options) }
|
|
324
372
|
end
|
|
325
373
|
|
|
326
374
|
# Mirror the Prism.parse_failure? API by using the serialization API.
|
|
@@ -330,8 +378,7 @@ module Prism
|
|
|
330
378
|
|
|
331
379
|
# Mirror the Prism.parse_file_success? API by using the serialization API.
|
|
332
380
|
def parse_file_success?(filepath, **options)
|
|
333
|
-
|
|
334
|
-
LibRubyParser::PrismString.with_file(filepath) { |string| parse_file_success_common(string, options) }
|
|
381
|
+
LibRubyParser::PrismSource.with_file(filepath, options) { |string| parse_file_success_common(string, options) }
|
|
335
382
|
end
|
|
336
383
|
|
|
337
384
|
# Mirror the Prism.parse_file_failure? API by using the serialization API.
|
|
@@ -341,7 +388,11 @@ module Prism
|
|
|
341
388
|
|
|
342
389
|
# Mirror the Prism.profile API by using the serialization API.
|
|
343
390
|
def profile(source, **options)
|
|
344
|
-
LibRubyParser::
|
|
391
|
+
LibRubyParser::PrismSource.with_string(source) do |string|
|
|
392
|
+
if (format_type = raise_error_format_type(options))
|
|
393
|
+
raise_error(string, options, format_type)
|
|
394
|
+
end
|
|
395
|
+
|
|
345
396
|
LibRubyParser::PrismBuffer.with do |buffer|
|
|
346
397
|
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
|
|
347
398
|
nil
|
|
@@ -351,9 +402,12 @@ module Prism
|
|
|
351
402
|
|
|
352
403
|
# Mirror the Prism.profile_file API by using the serialization API.
|
|
353
404
|
def profile_file(filepath, **options)
|
|
354
|
-
LibRubyParser::
|
|
405
|
+
LibRubyParser::PrismSource.with_file(filepath, options) do |string|
|
|
406
|
+
if (format_type = raise_error_format_type(options))
|
|
407
|
+
raise_error(string, options, format_type)
|
|
408
|
+
end
|
|
409
|
+
|
|
355
410
|
LibRubyParser::PrismBuffer.with do |buffer|
|
|
356
|
-
options[:filepath] = filepath
|
|
357
411
|
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
|
|
358
412
|
nil
|
|
359
413
|
end
|
|
@@ -363,6 +417,10 @@ module Prism
|
|
|
363
417
|
private
|
|
364
418
|
|
|
365
419
|
def dump_common(string, options) # :nodoc:
|
|
420
|
+
if (format_type = raise_error_format_type(options))
|
|
421
|
+
raise_error(string, options, format_type)
|
|
422
|
+
end
|
|
423
|
+
|
|
366
424
|
LibRubyParser::PrismBuffer.with do |buffer|
|
|
367
425
|
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
|
|
368
426
|
|
|
@@ -374,18 +432,31 @@ module Prism
|
|
|
374
432
|
end
|
|
375
433
|
|
|
376
434
|
def lex_common(string, code, options) # :nodoc:
|
|
435
|
+
format_type = raise_error_format_type(options)
|
|
436
|
+
|
|
377
437
|
LibRubyParser::PrismBuffer.with do |buffer|
|
|
378
438
|
LibRubyParser.pm_serialize_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
|
|
379
|
-
Serialize.load_lex(code, buffer.read, options.fetch(:freeze, false))
|
|
439
|
+
result = Serialize.load_lex(code, buffer.read, options.fetch(:freeze, false))
|
|
440
|
+
|
|
441
|
+
raise_error(string, options, format_type) if format_type && result.failure?
|
|
442
|
+
result
|
|
380
443
|
end
|
|
381
444
|
end
|
|
382
445
|
|
|
383
446
|
def parse_common(string, code, options) # :nodoc:
|
|
447
|
+
format_type = raise_error_format_type(options)
|
|
384
448
|
serialized = dump_common(string, options)
|
|
385
|
-
Serialize.load_parse(code, serialized, options.fetch(:freeze, false))
|
|
449
|
+
result = Serialize.load_parse(code, serialized, options.fetch(:freeze, false))
|
|
450
|
+
|
|
451
|
+
raise_error(string, options, format_type) if format_type && result.failure?
|
|
452
|
+
result
|
|
386
453
|
end
|
|
387
454
|
|
|
388
455
|
def parse_comments_common(string, code, options) # :nodoc:
|
|
456
|
+
if (format_type = raise_error_format_type(options))
|
|
457
|
+
raise_error(string, options, format_type)
|
|
458
|
+
end
|
|
459
|
+
|
|
389
460
|
LibRubyParser::PrismBuffer.with do |buffer|
|
|
390
461
|
LibRubyParser.pm_serialize_parse_comments(buffer.pointer, string.pointer, string.length, dump_options(options))
|
|
391
462
|
Serialize.load_parse_comments(code, buffer.read, options.fetch(:freeze, false))
|
|
@@ -393,14 +464,82 @@ module Prism
|
|
|
393
464
|
end
|
|
394
465
|
|
|
395
466
|
def parse_lex_common(string, code, options) # :nodoc:
|
|
467
|
+
format_type = raise_error_format_type(options)
|
|
468
|
+
|
|
396
469
|
LibRubyParser::PrismBuffer.with do |buffer|
|
|
397
470
|
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))
|
|
471
|
+
result = Serialize.load_parse_lex(code, buffer.read, options.fetch(:freeze, false))
|
|
472
|
+
|
|
473
|
+
raise_error(string, options, format_type) if format_type && result.failure?
|
|
474
|
+
result
|
|
399
475
|
end
|
|
400
476
|
end
|
|
401
477
|
|
|
402
478
|
def parse_file_success_common(string, options) # :nodoc:
|
|
403
|
-
|
|
479
|
+
format_type = raise_error_format_type(options)
|
|
480
|
+
success = LibRubyParser.pm_serialize_parse_success_p(string.pointer, string.length, dump_options(options))
|
|
481
|
+
|
|
482
|
+
raise_error(string, options, format_type) if format_type && !success
|
|
483
|
+
success
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
# Extract the raise_error option from the given options hash and convert
|
|
487
|
+
# it into the format type that should be used when formatting errors, or
|
|
488
|
+
# nil if raising is disabled.
|
|
489
|
+
def raise_error_format_type(options) # :nodoc:
|
|
490
|
+
case (value = options.delete(:raise_error))
|
|
491
|
+
when nil, false
|
|
492
|
+
nil
|
|
493
|
+
when true
|
|
494
|
+
# When given true, mirror the behavior of CRuby itself: color when
|
|
495
|
+
# $stderr is a terminal (unless NO_COLOR is set), bold styling when
|
|
496
|
+
# NO_COLOR is set, plain otherwise. This policy is duplicated in
|
|
497
|
+
# ext/prism/extension.c (build_options_i) and the two must stay in
|
|
498
|
+
# sync.
|
|
499
|
+
if $stderr.respond_to?(:tty?) && $stderr.tty?
|
|
500
|
+
no_color = ENV["NO_COLOR"]
|
|
501
|
+
(no_color.nil? || no_color.empty?) ? :PM_ERRORS_FORMAT_COLOR : :PM_ERRORS_FORMAT_STYLE
|
|
502
|
+
else
|
|
503
|
+
:PM_ERRORS_FORMAT_PLAIN
|
|
504
|
+
end
|
|
505
|
+
when :plain
|
|
506
|
+
:PM_ERRORS_FORMAT_PLAIN
|
|
507
|
+
when :style
|
|
508
|
+
:PM_ERRORS_FORMAT_STYLE
|
|
509
|
+
when :color
|
|
510
|
+
:PM_ERRORS_FORMAT_COLOR
|
|
511
|
+
when Symbol
|
|
512
|
+
raise ArgumentError, "invalid raise_error value: #{value}"
|
|
513
|
+
else
|
|
514
|
+
raise TypeError, "wrong argument type #{value.class} (expected Symbol)"
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
# Parse the given source and format any errors that are encountered into
|
|
519
|
+
# an appropriate exception, then raise it. If the source parses without
|
|
520
|
+
# any errors, then return nil.
|
|
521
|
+
def raise_error(string, options, format_type) # :nodoc:
|
|
522
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
|
523
|
+
level = LibRubyParser.pm_serialize_parse_errors_format(buffer.pointer, string.pointer, string.length, dump_options(options), format_type)
|
|
524
|
+
return if level == -1
|
|
525
|
+
|
|
526
|
+
encoding_name, _, message = buffer.read.partition("\0")
|
|
527
|
+
|
|
528
|
+
case level
|
|
529
|
+
when 0 # syntax
|
|
530
|
+
error = SyntaxError.new(message.force_encoding(encoding_name))
|
|
531
|
+
error.instance_variable_set(:@path, options.fetch(:filepath, ""))
|
|
532
|
+
raise error
|
|
533
|
+
when 1 # argument
|
|
534
|
+
raise ArgumentError, message.force_encoding(encoding_name)
|
|
535
|
+
when 2 # load
|
|
536
|
+
error = LoadError.new(message.force_encoding(Encoding.find("locale")))
|
|
537
|
+
error.instance_variable_set(:@path, nil)
|
|
538
|
+
raise error
|
|
539
|
+
else
|
|
540
|
+
raise "Unknown error level: #{level}"
|
|
541
|
+
end
|
|
542
|
+
end
|
|
404
543
|
end
|
|
405
544
|
|
|
406
545
|
# Return the value that should be dumped for the command_line option.
|
|
@@ -423,11 +562,28 @@ module Prism
|
|
|
423
562
|
|
|
424
563
|
# Return the value that should be dumped for the version option.
|
|
425
564
|
def dump_options_version(version)
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
when
|
|
565
|
+
case version
|
|
566
|
+
when "current"
|
|
567
|
+
version_string_to_number(RUBY_VERSION) || raise(CurrentVersionError, RUBY_VERSION)
|
|
568
|
+
when "latest"
|
|
430
569
|
0 # Handled in pm_parser_init
|
|
570
|
+
when "nearest", nil
|
|
571
|
+
dump = version_string_to_number(RUBY_VERSION)
|
|
572
|
+
return dump if dump
|
|
573
|
+
if RUBY_VERSION < "3.3"
|
|
574
|
+
version_string_to_number("3.3")
|
|
575
|
+
else
|
|
576
|
+
0 # Handled in pm_parser_init
|
|
577
|
+
end
|
|
578
|
+
else
|
|
579
|
+
version_string_to_number(version) || raise(ArgumentError, "invalid version: #{version}")
|
|
580
|
+
end
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
# Converts a version string like "4.0.0" or "4.0" into a number.
|
|
584
|
+
# Returns nil if the version is unknown.
|
|
585
|
+
def version_string_to_number(version)
|
|
586
|
+
case version
|
|
431
587
|
when /\A3\.3(\.\d+)?\z/
|
|
432
588
|
1
|
|
433
589
|
when /\A3\.4(\.\d+)?\z/
|
|
@@ -436,17 +592,20 @@ module Prism
|
|
|
436
592
|
3
|
|
437
593
|
when /\A4\.1(\.\d+)?\z/
|
|
438
594
|
4
|
|
439
|
-
else
|
|
440
|
-
if current
|
|
441
|
-
raise CurrentVersionError, RUBY_VERSION
|
|
442
|
-
else
|
|
443
|
-
raise ArgumentError, "invalid version: #{version}"
|
|
444
|
-
end
|
|
445
595
|
end
|
|
446
596
|
end
|
|
447
597
|
|
|
598
|
+
# The set of options that are understood by the parsing APIs. Note that
|
|
599
|
+
# raise_error is not listed here because it is deleted from the options
|
|
600
|
+
# hash by raise_error_format_type before the options are dumped.
|
|
601
|
+
DUMP_OPTIONS_KEYS = [:attach_comments, :command_line, :encoding, :filepath, :freeze, :frozen_string_literal, :line, :main_script, :partial_script, :scopes, :version].freeze
|
|
602
|
+
private_constant :DUMP_OPTIONS_KEYS
|
|
603
|
+
|
|
448
604
|
# Convert the given options into a serialized options string.
|
|
449
605
|
def dump_options(options)
|
|
606
|
+
unknown_keys = options.keys - DUMP_OPTIONS_KEYS
|
|
607
|
+
raise ArgumentError, "unknown keyword: #{unknown_keys.first}" unless unknown_keys.empty?
|
|
608
|
+
|
|
450
609
|
template = +""
|
|
451
610
|
values = []
|
|
452
611
|
|
|
@@ -491,6 +650,9 @@ module Prism
|
|
|
491
650
|
template << "C"
|
|
492
651
|
values << (options.fetch(:freeze, false) ? 1 : 0)
|
|
493
652
|
|
|
653
|
+
template << "C"
|
|
654
|
+
values << (options.fetch(:attach_comments, false) ? 1 : 0)
|
|
655
|
+
|
|
494
656
|
template << "L"
|
|
495
657
|
if (scopes = options[:scopes])
|
|
496
658
|
values << scopes.length
|
|
@@ -543,7 +705,7 @@ module Prism
|
|
|
543
705
|
|
|
544
706
|
# Here we are going to patch StringQuery to put in the class-level methods so
|
|
545
707
|
# that it can maintain a consistent interface
|
|
546
|
-
class StringQuery
|
|
708
|
+
class StringQuery # :nodoc:
|
|
547
709
|
class << self
|
|
548
710
|
# Mirrors the C extension's StringQuery::local? method.
|
|
549
711
|
def local?(string)
|