jruby-prism-parser 0.23.0.pre.SNAPSHOT-java → 1.4.0-java
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/BSDmakefile +58 -0
- data/CHANGELOG.md +284 -1
- data/CONTRIBUTING.md +0 -4
- data/Makefile +25 -18
- data/README.md +57 -6
- data/config.yml +1724 -140
- data/docs/build_system.md +39 -11
- data/docs/configuration.md +4 -0
- data/docs/cruby_compilation.md +1 -1
- data/docs/fuzzing.md +1 -1
- data/docs/parser_translation.md +14 -9
- data/docs/parsing_rules.md +4 -1
- data/docs/releasing.md +9 -11
- data/docs/relocation.md +34 -0
- data/docs/ripper_translation.md +72 -0
- data/docs/ruby_api.md +2 -1
- data/docs/serialization.md +29 -5
- data/ext/prism/api_node.c +3841 -2000
- data/ext/prism/api_pack.c +9 -0
- data/ext/prism/extconf.rb +55 -34
- data/ext/prism/extension.c +597 -346
- data/ext/prism/extension.h +6 -5
- data/include/prism/ast.h +2612 -455
- data/include/prism/defines.h +160 -2
- data/include/prism/diagnostic.h +188 -76
- data/include/prism/encoding.h +22 -4
- data/include/prism/node.h +89 -17
- data/include/prism/options.h +224 -12
- data/include/prism/pack.h +11 -0
- data/include/prism/parser.h +267 -66
- data/include/prism/prettyprint.h +8 -0
- data/include/prism/regexp.h +18 -8
- data/include/prism/static_literals.h +121 -0
- data/include/prism/util/pm_buffer.h +75 -2
- data/include/prism/util/pm_char.h +1 -2
- data/include/prism/util/pm_constant_pool.h +18 -9
- data/include/prism/util/pm_integer.h +126 -0
- data/include/prism/util/pm_list.h +1 -1
- data/include/prism/util/pm_newline_list.h +23 -3
- data/include/prism/util/pm_string.h +48 -8
- data/include/prism/version.h +3 -3
- data/include/prism.h +99 -5
- data/jruby-prism.jar +0 -0
- data/lib/prism/compiler.rb +11 -1
- data/lib/prism/desugar_compiler.rb +264 -80
- data/lib/prism/dispatcher.rb +45 -1
- data/lib/prism/dot_visitor.rb +201 -77
- data/lib/prism/dsl.rb +672 -457
- data/lib/prism/ffi.rb +308 -94
- data/lib/prism/inspect_visitor.rb +2389 -0
- data/lib/prism/lex_compat.rb +35 -16
- data/lib/prism/mutation_compiler.rb +24 -8
- data/lib/prism/node.rb +9712 -8931
- data/lib/prism/node_ext.rb +328 -32
- data/lib/prism/pack.rb +4 -0
- data/lib/prism/parse_result/comments.rb +34 -24
- data/lib/prism/parse_result/errors.rb +65 -0
- data/lib/prism/parse_result/newlines.rb +102 -12
- data/lib/prism/parse_result.rb +458 -46
- data/lib/prism/pattern.rb +28 -10
- data/lib/prism/polyfill/append_as_bytes.rb +15 -0
- data/lib/prism/polyfill/byteindex.rb +13 -0
- data/lib/prism/polyfill/unpack1.rb +14 -0
- data/lib/prism/reflection.rb +413 -0
- data/lib/prism/relocation.rb +504 -0
- data/lib/prism/serialize.rb +1940 -902
- data/lib/prism/string_query.rb +30 -0
- data/lib/prism/translation/parser/builder.rb +61 -0
- data/lib/prism/translation/parser/compiler.rb +569 -195
- data/lib/prism/translation/parser/lexer.rb +516 -39
- data/lib/prism/translation/parser.rb +188 -11
- data/lib/prism/translation/parser33.rb +12 -0
- data/lib/prism/translation/parser34.rb +12 -0
- data/lib/prism/translation/parser35.rb +12 -0
- data/lib/prism/translation/ripper/sexp.rb +125 -0
- data/lib/prism/translation/ripper/shim.rb +5 -0
- data/lib/prism/translation/ripper.rb +3267 -386
- data/lib/prism/translation/ruby_parser.rb +194 -69
- data/lib/prism/translation.rb +4 -1
- data/lib/prism/version.rb +1 -1
- data/lib/prism/visitor.rb +13 -0
- data/lib/prism.rb +17 -27
- data/prism.gemspec +59 -17
- data/rbi/prism/compiler.rbi +12 -0
- data/rbi/prism/dsl.rbi +524 -0
- data/rbi/prism/inspect_visitor.rbi +12 -0
- data/rbi/prism/node.rbi +8722 -0
- data/rbi/prism/node_ext.rbi +107 -0
- data/rbi/prism/parse_result.rbi +404 -0
- data/rbi/prism/reflection.rbi +58 -0
- data/rbi/prism/string_query.rbi +12 -0
- data/rbi/prism/translation/parser.rbi +11 -0
- data/rbi/prism/translation/parser33.rbi +6 -0
- data/rbi/prism/translation/parser34.rbi +6 -0
- data/rbi/prism/translation/parser35.rbi +6 -0
- data/rbi/prism/translation/ripper.rbi +15 -0
- data/rbi/prism/visitor.rbi +473 -0
- data/rbi/prism.rbi +44 -7745
- data/sig/prism/compiler.rbs +9 -0
- data/sig/prism/dispatcher.rbs +16 -0
- data/sig/prism/dot_visitor.rbs +6 -0
- data/sig/prism/dsl.rbs +351 -0
- data/sig/prism/inspect_visitor.rbs +22 -0
- data/sig/prism/lex_compat.rbs +10 -0
- data/sig/prism/mutation_compiler.rbs +159 -0
- data/sig/prism/node.rbs +3614 -0
- data/sig/prism/node_ext.rbs +82 -0
- data/sig/prism/pack.rbs +43 -0
- data/sig/prism/parse_result.rbs +192 -0
- data/sig/prism/pattern.rbs +13 -0
- data/sig/prism/reflection.rbs +50 -0
- data/sig/prism/relocation.rbs +185 -0
- data/sig/prism/serialize.rbs +8 -0
- data/sig/prism/string_query.rbs +11 -0
- data/sig/prism/visitor.rbs +169 -0
- data/sig/prism.rbs +248 -4767
- data/src/diagnostic.c +672 -230
- data/src/encoding.c +211 -108
- data/src/node.c +7541 -1653
- data/src/options.c +135 -20
- data/src/pack.c +33 -17
- data/src/prettyprint.c +1546 -1488
- data/src/prism.c +7822 -3044
- data/src/regexp.c +225 -73
- data/src/serialize.c +101 -77
- data/src/static_literals.c +617 -0
- data/src/token_type.c +14 -13
- data/src/util/pm_buffer.c +187 -20
- data/src/util/pm_char.c +5 -5
- data/src/util/pm_constant_pool.c +39 -19
- data/src/util/pm_integer.c +670 -0
- data/src/util/pm_list.c +1 -1
- data/src/util/pm_newline_list.c +49 -8
- data/src/util/pm_string.c +213 -33
- data/src/util/pm_strncasecmp.c +13 -1
- data/src/util/pm_strpbrk.c +32 -6
- metadata +59 -21
- data/docs/ripper.md +0 -36
- data/include/prism/util/pm_state_stack.h +0 -42
- data/include/prism/util/pm_string_list.h +0 -44
- data/lib/prism/debug.rb +0 -206
- data/lib/prism/node_inspector.rb +0 -68
- data/lib/prism/translation/parser/rubocop.rb +0 -37
- data/rbi/prism_static.rbi +0 -207
- data/sig/prism_static.rbs +0 -201
- data/src/util/pm_state_stack.c +0 -25
- data/src/util/pm_string_list.c +0 -28
data/lib/prism/ffi.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
# typed: ignore
|
2
3
|
|
3
4
|
# This file is responsible for mirroring the API provided by the C extension by
|
4
5
|
# using FFI to call into the shared library.
|
@@ -7,14 +8,21 @@ require "rbconfig"
|
|
7
8
|
require "ffi"
|
8
9
|
|
9
10
|
module Prism
|
10
|
-
BACKEND = :FFI
|
11
|
-
|
12
11
|
module LibRubyParser # :nodoc:
|
13
12
|
extend FFI::Library
|
14
13
|
|
15
14
|
# Define the library that we will be pulling functions from. Note that this
|
16
15
|
# must align with the build shared library from make/rake.
|
17
|
-
|
16
|
+
libprism_in_build = File.expand_path("../../build/libprism.#{RbConfig::CONFIG["SOEXT"]}", __dir__)
|
17
|
+
libprism_in_libdir = "#{RbConfig::CONFIG["libdir"]}/prism/libprism.#{RbConfig::CONFIG["SOEXT"]}"
|
18
|
+
|
19
|
+
if File.exist?(libprism_in_build)
|
20
|
+
INCLUDE_DIR = File.expand_path("../../include", __dir__)
|
21
|
+
ffi_lib libprism_in_build
|
22
|
+
else
|
23
|
+
INCLUDE_DIR = "#{RbConfig::CONFIG["libdir"]}/prism/include"
|
24
|
+
ffi_lib libprism_in_libdir
|
25
|
+
end
|
18
26
|
|
19
27
|
# Convert a native C type declaration into a symbol that FFI understands.
|
20
28
|
# For example:
|
@@ -24,16 +32,22 @@ module Prism
|
|
24
32
|
# size_t -> :size_t
|
25
33
|
# void -> :void
|
26
34
|
#
|
27
|
-
def self.resolve_type(type)
|
35
|
+
def self.resolve_type(type, callbacks)
|
28
36
|
type = type.strip
|
29
|
-
|
37
|
+
|
38
|
+
if !type.end_with?("*")
|
39
|
+
type.delete_prefix("const ").to_sym
|
40
|
+
else
|
41
|
+
type = type.delete_suffix("*").rstrip
|
42
|
+
callbacks.include?(type.to_sym) ? type.to_sym : :pointer
|
43
|
+
end
|
30
44
|
end
|
31
45
|
|
32
46
|
# Read through the given header file and find the declaration of each of the
|
33
47
|
# given functions. For each one, define a function with the same name and
|
34
48
|
# signature as the C function.
|
35
|
-
def self.load_exported_functions_from(header, *functions)
|
36
|
-
File.foreach(
|
49
|
+
def self.load_exported_functions_from(header, *functions, callbacks)
|
50
|
+
File.foreach("#{INCLUDE_DIR}/#{header}") do |line|
|
37
51
|
# We only want to attempt to load exported functions.
|
38
52
|
next unless line.start_with?("PRISM_EXPORTED_FUNCTION ")
|
39
53
|
|
@@ -56,24 +70,33 @@ module Prism
|
|
56
70
|
|
57
71
|
# Resolve the type of the argument by dropping the name of the argument
|
58
72
|
# first if it is present.
|
59
|
-
arg_types.map! { |type| resolve_type(type.sub(/\w+$/, "")) }
|
73
|
+
arg_types.map! { |type| resolve_type(type.sub(/\w+$/, ""), callbacks) }
|
60
74
|
|
61
75
|
# Attach the function using the FFI library.
|
62
|
-
attach_function name, arg_types, resolve_type(return_type)
|
76
|
+
attach_function name, arg_types, resolve_type(return_type, [])
|
63
77
|
end
|
64
78
|
|
65
79
|
# If we didn't find all of the functions, raise an error.
|
66
80
|
raise "Could not find functions #{functions.inspect}" unless functions.empty?
|
67
81
|
end
|
68
82
|
|
83
|
+
callback :pm_parse_stream_fgets_t, [:pointer, :int, :pointer], :pointer
|
84
|
+
enum :pm_string_init_result_t, %i[PM_STRING_INIT_SUCCESS PM_STRING_INIT_ERROR_GENERIC PM_STRING_INIT_ERROR_DIRECTORY]
|
85
|
+
enum :pm_string_query_t, [:PM_STRING_QUERY_ERROR, -1, :PM_STRING_QUERY_FALSE, :PM_STRING_QUERY_TRUE]
|
86
|
+
|
69
87
|
load_exported_functions_from(
|
70
88
|
"prism.h",
|
71
89
|
"pm_version",
|
72
90
|
"pm_serialize_parse",
|
91
|
+
"pm_serialize_parse_stream",
|
73
92
|
"pm_serialize_parse_comments",
|
74
93
|
"pm_serialize_lex",
|
75
94
|
"pm_serialize_parse_lex",
|
76
|
-
"pm_parse_success_p"
|
95
|
+
"pm_parse_success_p",
|
96
|
+
"pm_string_query_local",
|
97
|
+
"pm_string_query_constant",
|
98
|
+
"pm_string_query_method_name",
|
99
|
+
[:pm_parse_stream_fgets_t]
|
77
100
|
)
|
78
101
|
|
79
102
|
load_exported_functions_from(
|
@@ -82,7 +105,8 @@ module Prism
|
|
82
105
|
"pm_buffer_init",
|
83
106
|
"pm_buffer_value",
|
84
107
|
"pm_buffer_length",
|
85
|
-
"pm_buffer_free"
|
108
|
+
"pm_buffer_free",
|
109
|
+
[]
|
86
110
|
)
|
87
111
|
|
88
112
|
load_exported_functions_from(
|
@@ -91,7 +115,8 @@ module Prism
|
|
91
115
|
"pm_string_free",
|
92
116
|
"pm_string_source",
|
93
117
|
"pm_string_length",
|
94
|
-
"pm_string_sizeof"
|
118
|
+
"pm_string_sizeof",
|
119
|
+
[]
|
95
120
|
)
|
96
121
|
|
97
122
|
# This object represents a pm_buffer_t. We only use it as an opaque pointer,
|
@@ -119,15 +144,12 @@ module Prism
|
|
119
144
|
|
120
145
|
# Initialize a new buffer and yield it to the block. The buffer will be
|
121
146
|
# automatically freed when the block returns.
|
122
|
-
def self.with
|
123
|
-
|
124
|
-
|
125
|
-
begin
|
147
|
+
def self.with
|
148
|
+
FFI::MemoryPointer.new(SIZEOF) do |pointer|
|
126
149
|
raise unless LibRubyParser.pm_buffer_init(pointer)
|
127
|
-
yield new(pointer)
|
150
|
+
return yield new(pointer)
|
128
151
|
ensure
|
129
152
|
LibRubyParser.pm_buffer_free(pointer)
|
130
|
-
pointer.free
|
131
153
|
end
|
132
154
|
end
|
133
155
|
end
|
@@ -137,39 +159,60 @@ module Prism
|
|
137
159
|
class PrismString # :nodoc:
|
138
160
|
SIZEOF = LibRubyParser.pm_string_sizeof
|
139
161
|
|
140
|
-
attr_reader :pointer
|
162
|
+
attr_reader :pointer, :length
|
141
163
|
|
142
|
-
def initialize(pointer)
|
164
|
+
def initialize(pointer, length, from_string)
|
143
165
|
@pointer = pointer
|
144
|
-
|
145
|
-
|
146
|
-
def source
|
147
|
-
LibRubyParser.pm_string_source(pointer)
|
148
|
-
end
|
149
|
-
|
150
|
-
def length
|
151
|
-
LibRubyParser.pm_string_length(pointer)
|
166
|
+
@length = length
|
167
|
+
@from_string = from_string
|
152
168
|
end
|
153
169
|
|
154
170
|
def read
|
155
|
-
|
171
|
+
raise "should use the original String instead" if @from_string
|
172
|
+
@pointer.read_string(@length)
|
156
173
|
end
|
157
174
|
|
158
175
|
# Yields a pm_string_t pointer to the given block.
|
159
|
-
def self.
|
160
|
-
|
176
|
+
def self.with_string(string)
|
177
|
+
raise TypeError unless string.is_a?(String)
|
178
|
+
|
179
|
+
length = string.bytesize
|
180
|
+
# + 1 to never get an address of 0, which pm_parser_init() asserts
|
181
|
+
FFI::MemoryPointer.new(:char, length + 1, false) do |pointer|
|
182
|
+
pointer.write_string(string)
|
183
|
+
# since we have the extra byte we might as well \0-terminate
|
184
|
+
pointer.put_char(length, 0)
|
185
|
+
return yield new(pointer, length, true)
|
186
|
+
end
|
187
|
+
end
|
161
188
|
|
162
|
-
|
163
|
-
|
189
|
+
# Yields a pm_string_t pointer to the given block.
|
190
|
+
def self.with_file(filepath)
|
191
|
+
raise TypeError unless filepath.is_a?(String)
|
192
|
+
|
193
|
+
# On Windows and Mac, it's expected that filepaths will be encoded in
|
194
|
+
# UTF-8. If they are not, we need to convert them to UTF-8 before
|
195
|
+
# passing them into pm_string_mapped_init.
|
196
|
+
if RbConfig::CONFIG["host_os"].match?(/bccwin|cygwin|djgpp|mingw|mswin|wince|darwin/i) &&
|
197
|
+
(encoding = filepath.encoding) != Encoding::ASCII_8BIT && encoding != Encoding::UTF_8
|
198
|
+
filepath = filepath.encode(Encoding::UTF_8)
|
199
|
+
end
|
164
200
|
|
165
|
-
|
166
|
-
|
167
|
-
|
201
|
+
FFI::MemoryPointer.new(SIZEOF) do |pm_string|
|
202
|
+
case (result = LibRubyParser.pm_string_mapped_init(pm_string, filepath))
|
203
|
+
when :PM_STRING_INIT_SUCCESS
|
204
|
+
pointer = LibRubyParser.pm_string_source(pm_string)
|
205
|
+
length = LibRubyParser.pm_string_length(pm_string)
|
206
|
+
return yield new(pointer, length, false)
|
207
|
+
when :PM_STRING_INIT_ERROR_GENERIC
|
168
208
|
raise SystemCallError.new(filepath, FFI.errno)
|
209
|
+
when :PM_STRING_INIT_ERROR_DIRECTORY
|
210
|
+
raise Errno::EISDIR.new(filepath)
|
211
|
+
else
|
212
|
+
raise "Unknown error initializing pm_string_t: #{result.inspect}"
|
169
213
|
end
|
170
214
|
ensure
|
171
|
-
LibRubyParser.pm_string_free(
|
172
|
-
pointer.free
|
215
|
+
LibRubyParser.pm_string_free(pm_string)
|
173
216
|
end
|
174
217
|
end
|
175
218
|
end
|
@@ -184,110 +227,206 @@ module Prism
|
|
184
227
|
|
185
228
|
class << self
|
186
229
|
# Mirror the Prism.dump API by using the serialization API.
|
187
|
-
def dump(
|
188
|
-
LibRubyParser::
|
189
|
-
LibRubyParser.pm_serialize_parse(buffer.pointer, code, code.bytesize, dump_options(options))
|
190
|
-
buffer.read
|
191
|
-
end
|
230
|
+
def dump(source, **options)
|
231
|
+
LibRubyParser::PrismString.with_string(source) { |string| dump_common(string, options) }
|
192
232
|
end
|
193
233
|
|
194
234
|
# Mirror the Prism.dump_file API by using the serialization API.
|
195
235
|
def dump_file(filepath, **options)
|
196
|
-
|
197
|
-
|
198
|
-
end
|
236
|
+
options[:filepath] = filepath
|
237
|
+
LibRubyParser::PrismString.with_file(filepath) { |string| dump_common(string, options) }
|
199
238
|
end
|
200
239
|
|
201
240
|
# Mirror the Prism.lex API by using the serialization API.
|
202
241
|
def lex(code, **options)
|
203
|
-
LibRubyParser::
|
204
|
-
LibRubyParser.pm_serialize_lex(buffer.pointer, code, code.bytesize, dump_options(options))
|
205
|
-
Serialize.load_tokens(Source.new(code), buffer.read)
|
206
|
-
end
|
242
|
+
LibRubyParser::PrismString.with_string(code) { |string| lex_common(string, code, options) }
|
207
243
|
end
|
208
244
|
|
209
245
|
# Mirror the Prism.lex_file API by using the serialization API.
|
210
246
|
def lex_file(filepath, **options)
|
211
|
-
|
212
|
-
|
213
|
-
end
|
247
|
+
options[:filepath] = filepath
|
248
|
+
LibRubyParser::PrismString.with_file(filepath) { |string| lex_common(string, string.read, options) }
|
214
249
|
end
|
215
250
|
|
216
251
|
# Mirror the Prism.parse API by using the serialization API.
|
217
252
|
def parse(code, **options)
|
218
|
-
|
253
|
+
LibRubyParser::PrismString.with_string(code) { |string| parse_common(string, code, options) }
|
219
254
|
end
|
220
255
|
|
221
256
|
# Mirror the Prism.parse_file API by using the serialization API. This uses
|
222
|
-
# native strings instead of Ruby strings because it allows us to use mmap
|
223
|
-
# it is available.
|
257
|
+
# native strings instead of Ruby strings because it allows us to use mmap
|
258
|
+
# when it is available.
|
224
259
|
def parse_file(filepath, **options)
|
225
|
-
|
226
|
-
|
227
|
-
end
|
260
|
+
options[:filepath] = filepath
|
261
|
+
LibRubyParser::PrismString.with_file(filepath) { |string| parse_common(string, string.read, options) }
|
228
262
|
end
|
229
263
|
|
230
|
-
# Mirror the Prism.
|
231
|
-
def
|
264
|
+
# Mirror the Prism.parse_stream API by using the serialization API.
|
265
|
+
def parse_stream(stream, **options)
|
232
266
|
LibRubyParser::PrismBuffer.with do |buffer|
|
233
|
-
|
267
|
+
source = +""
|
268
|
+
callback = -> (string, size, _) {
|
269
|
+
raise "Expected size to be >= 0, got: #{size}" if size <= 0
|
234
270
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
271
|
+
if !(line = stream.gets(size - 1)).nil?
|
272
|
+
source << line
|
273
|
+
string.write_string("#{line}\x00", line.bytesize + 1)
|
274
|
+
end
|
275
|
+
}
|
276
|
+
|
277
|
+
# In the pm_serialize_parse_stream function it accepts a pointer to the
|
278
|
+
# IO object as a void* and then passes it through to the callback as the
|
279
|
+
# third argument, but it never touches it itself. As such, since we have
|
280
|
+
# access to the IO object already through the closure of the lambda, we
|
281
|
+
# can pass a null pointer here and not worry.
|
282
|
+
LibRubyParser.pm_serialize_parse_stream(buffer.pointer, nil, callback, dump_options(options))
|
283
|
+
Prism.load(source, buffer.read, options.fetch(:freeze, false))
|
242
284
|
end
|
243
285
|
end
|
244
286
|
|
287
|
+
# Mirror the Prism.parse_comments API by using the serialization API.
|
288
|
+
def parse_comments(code, **options)
|
289
|
+
LibRubyParser::PrismString.with_string(code) { |string| parse_comments_common(string, code, options) }
|
290
|
+
end
|
291
|
+
|
245
292
|
# Mirror the Prism.parse_file_comments API by using the serialization
|
246
293
|
# API. This uses native strings instead of Ruby strings because it allows us
|
247
294
|
# to use mmap when it is available.
|
248
295
|
def parse_file_comments(filepath, **options)
|
249
|
-
|
250
|
-
|
251
|
-
end
|
296
|
+
options[:filepath] = filepath
|
297
|
+
LibRubyParser::PrismString.with_file(filepath) { |string| parse_comments_common(string, string.read, options) }
|
252
298
|
end
|
253
299
|
|
254
300
|
# Mirror the Prism.parse_lex API by using the serialization API.
|
255
301
|
def parse_lex(code, **options)
|
256
|
-
LibRubyParser::
|
257
|
-
LibRubyParser.pm_serialize_parse_lex(buffer.pointer, code, code.bytesize, dump_options(options))
|
258
|
-
|
259
|
-
source = Source.new(code)
|
260
|
-
loader = Serialize::Loader.new(source, buffer.read)
|
261
|
-
|
262
|
-
tokens = loader.load_tokens
|
263
|
-
node, comments, magic_comments, data_loc, errors, warnings = loader.load_nodes
|
264
|
-
tokens.each { |token,| token.value.force_encoding(loader.encoding) }
|
265
|
-
|
266
|
-
ParseResult.new([node, tokens], comments, magic_comments, data_loc, errors, warnings, source)
|
267
|
-
end
|
302
|
+
LibRubyParser::PrismString.with_string(code) { |string| parse_lex_common(string, code, options) }
|
268
303
|
end
|
269
304
|
|
270
305
|
# Mirror the Prism.parse_lex_file API by using the serialization API.
|
271
306
|
def parse_lex_file(filepath, **options)
|
272
|
-
|
273
|
-
|
274
|
-
end
|
307
|
+
options[:filepath] = filepath
|
308
|
+
LibRubyParser::PrismString.with_file(filepath) { |string| parse_lex_common(string, string.read, options) }
|
275
309
|
end
|
276
310
|
|
277
311
|
# Mirror the Prism.parse_success? API by using the serialization API.
|
278
312
|
def parse_success?(code, **options)
|
279
|
-
LibRubyParser.
|
313
|
+
LibRubyParser::PrismString.with_string(code) { |string| parse_file_success_common(string, options) }
|
314
|
+
end
|
315
|
+
|
316
|
+
# Mirror the Prism.parse_failure? API by using the serialization API.
|
317
|
+
def parse_failure?(code, **options)
|
318
|
+
!parse_success?(code, **options)
|
280
319
|
end
|
281
320
|
|
282
321
|
# Mirror the Prism.parse_file_success? API by using the serialization API.
|
283
322
|
def parse_file_success?(filepath, **options)
|
284
|
-
|
285
|
-
|
323
|
+
options[:filepath] = filepath
|
324
|
+
LibRubyParser::PrismString.with_file(filepath) { |string| parse_file_success_common(string, options) }
|
325
|
+
end
|
326
|
+
|
327
|
+
# Mirror the Prism.parse_file_failure? API by using the serialization API.
|
328
|
+
def parse_file_failure?(filepath, **options)
|
329
|
+
!parse_file_success?(filepath, **options)
|
330
|
+
end
|
331
|
+
|
332
|
+
# Mirror the Prism.profile API by using the serialization API.
|
333
|
+
def profile(source, **options)
|
334
|
+
LibRubyParser::PrismString.with_string(source) do |string|
|
335
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
336
|
+
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
|
337
|
+
nil
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
# Mirror the Prism.profile_file API by using the serialization API.
|
343
|
+
def profile_file(filepath, **options)
|
344
|
+
LibRubyParser::PrismString.with_file(filepath) do |string|
|
345
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
346
|
+
options[:filepath] = filepath
|
347
|
+
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
|
348
|
+
nil
|
349
|
+
end
|
286
350
|
end
|
287
351
|
end
|
288
352
|
|
289
353
|
private
|
290
354
|
|
355
|
+
def dump_common(string, options) # :nodoc:
|
356
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
357
|
+
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
|
358
|
+
|
359
|
+
dumped = buffer.read
|
360
|
+
dumped.freeze if options.fetch(:freeze, false)
|
361
|
+
|
362
|
+
dumped
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
def lex_common(string, code, options) # :nodoc:
|
367
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
368
|
+
LibRubyParser.pm_serialize_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
|
369
|
+
Serialize.load_lex(code, buffer.read, options.fetch(:freeze, false))
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
def parse_common(string, code, options) # :nodoc:
|
374
|
+
serialized = dump_common(string, options)
|
375
|
+
Serialize.load_parse(code, serialized, options.fetch(:freeze, false))
|
376
|
+
end
|
377
|
+
|
378
|
+
def parse_comments_common(string, code, options) # :nodoc:
|
379
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
380
|
+
LibRubyParser.pm_serialize_parse_comments(buffer.pointer, string.pointer, string.length, dump_options(options))
|
381
|
+
Serialize.load_parse_comments(code, buffer.read, options.fetch(:freeze, false))
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
def parse_lex_common(string, code, options) # :nodoc:
|
386
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
387
|
+
LibRubyParser.pm_serialize_parse_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
|
388
|
+
Serialize.load_parse_lex(code, buffer.read, options.fetch(:freeze, false))
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
def parse_file_success_common(string, options) # :nodoc:
|
393
|
+
LibRubyParser.pm_parse_success_p(string.pointer, string.length, dump_options(options))
|
394
|
+
end
|
395
|
+
|
396
|
+
# Return the value that should be dumped for the command_line option.
|
397
|
+
def dump_options_command_line(options)
|
398
|
+
command_line = options.fetch(:command_line, "")
|
399
|
+
raise ArgumentError, "command_line must be a string" unless command_line.is_a?(String)
|
400
|
+
|
401
|
+
command_line.each_char.inject(0) do |value, char|
|
402
|
+
case char
|
403
|
+
when "a" then value | 0b000001
|
404
|
+
when "e" then value | 0b000010
|
405
|
+
when "l" then value | 0b000100
|
406
|
+
when "n" then value | 0b001000
|
407
|
+
when "p" then value | 0b010000
|
408
|
+
when "x" then value | 0b100000
|
409
|
+
else raise ArgumentError, "invalid command_line option: #{char}"
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
# Return the value that should be dumped for the version option.
|
415
|
+
def dump_options_version(version)
|
416
|
+
case version
|
417
|
+
when nil, "latest"
|
418
|
+
0
|
419
|
+
when /\A3\.3(\.\d+)?\z/
|
420
|
+
1
|
421
|
+
when /\A3\.4(\.\d+)?\z/
|
422
|
+
2
|
423
|
+
when /\A3\.5(\.\d+)?\z/
|
424
|
+
0
|
425
|
+
else
|
426
|
+
raise ArgumentError, "invalid version: #{version}"
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
291
430
|
# Convert the given options into a serialized options string.
|
292
431
|
def dump_options(options)
|
293
432
|
template = +""
|
@@ -306,7 +445,7 @@ module Prism
|
|
306
445
|
|
307
446
|
template << "L"
|
308
447
|
if (encoding = options[:encoding])
|
309
|
-
name = encoding.name
|
448
|
+
name = encoding.is_a?(Encoding) ? encoding.name : encoding
|
310
449
|
values.push(name.bytesize, name.b)
|
311
450
|
template << "A*"
|
312
451
|
else
|
@@ -317,17 +456,57 @@ module Prism
|
|
317
456
|
values << (options.fetch(:frozen_string_literal, false) ? 1 : 0)
|
318
457
|
|
319
458
|
template << "C"
|
320
|
-
values <<
|
459
|
+
values << dump_options_command_line(options)
|
460
|
+
|
461
|
+
template << "C"
|
462
|
+
values << dump_options_version(options[:version])
|
463
|
+
|
464
|
+
template << "C"
|
465
|
+
values << (options[:encoding] == false ? 1 : 0)
|
466
|
+
|
467
|
+
template << "C"
|
468
|
+
values << (options.fetch(:main_script, false) ? 1 : 0)
|
469
|
+
|
470
|
+
template << "C"
|
471
|
+
values << (options.fetch(:partial_script, false) ? 1 : 0)
|
472
|
+
|
473
|
+
template << "C"
|
474
|
+
values << (options.fetch(:freeze, false) ? 1 : 0)
|
321
475
|
|
322
476
|
template << "L"
|
323
477
|
if (scopes = options[:scopes])
|
324
478
|
values << scopes.length
|
325
479
|
|
326
480
|
scopes.each do |scope|
|
481
|
+
locals = nil
|
482
|
+
forwarding = 0
|
483
|
+
|
484
|
+
case scope
|
485
|
+
when Array
|
486
|
+
locals = scope
|
487
|
+
when Scope
|
488
|
+
locals = scope.locals
|
489
|
+
|
490
|
+
scope.forwarding.each do |forward|
|
491
|
+
case forward
|
492
|
+
when :* then forwarding |= 0x1
|
493
|
+
when :** then forwarding |= 0x2
|
494
|
+
when :& then forwarding |= 0x4
|
495
|
+
when :"..." then forwarding |= 0x8
|
496
|
+
else raise ArgumentError, "invalid forwarding value: #{forward}"
|
497
|
+
end
|
498
|
+
end
|
499
|
+
else
|
500
|
+
raise TypeError, "wrong argument type #{scope.class.inspect} (expected Array or Prism::Scope)"
|
501
|
+
end
|
502
|
+
|
327
503
|
template << "L"
|
328
|
-
values <<
|
504
|
+
values << locals.length
|
505
|
+
|
506
|
+
template << "C"
|
507
|
+
values << forwarding
|
329
508
|
|
330
|
-
|
509
|
+
locals.each do |local|
|
331
510
|
name = local.name
|
332
511
|
template << "L"
|
333
512
|
values << name.bytesize
|
@@ -343,4 +522,39 @@ module Prism
|
|
343
522
|
values.pack(template)
|
344
523
|
end
|
345
524
|
end
|
525
|
+
|
526
|
+
# Here we are going to patch StringQuery to put in the class-level methods so
|
527
|
+
# that it can maintain a consistent interface
|
528
|
+
class StringQuery
|
529
|
+
class << self
|
530
|
+
# Mirrors the C extension's StringQuery::local? method.
|
531
|
+
def local?(string)
|
532
|
+
query(LibRubyParser.pm_string_query_local(string, string.bytesize, string.encoding.name))
|
533
|
+
end
|
534
|
+
|
535
|
+
# Mirrors the C extension's StringQuery::constant? method.
|
536
|
+
def constant?(string)
|
537
|
+
query(LibRubyParser.pm_string_query_constant(string, string.bytesize, string.encoding.name))
|
538
|
+
end
|
539
|
+
|
540
|
+
# Mirrors the C extension's StringQuery::method_name? method.
|
541
|
+
def method_name?(string)
|
542
|
+
query(LibRubyParser.pm_string_query_method_name(string, string.bytesize, string.encoding.name))
|
543
|
+
end
|
544
|
+
|
545
|
+
private
|
546
|
+
|
547
|
+
# Parse the enum result and return an appropriate boolean.
|
548
|
+
def query(result)
|
549
|
+
case result
|
550
|
+
when :PM_STRING_QUERY_ERROR
|
551
|
+
raise ArgumentError, "Invalid or non ascii-compatible encoding"
|
552
|
+
when :PM_STRING_QUERY_FALSE
|
553
|
+
false
|
554
|
+
when :PM_STRING_QUERY_TRUE
|
555
|
+
true
|
556
|
+
end
|
557
|
+
end
|
558
|
+
end
|
559
|
+
end
|
346
560
|
end
|