prism 0.29.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +115 -1
- data/CONTRIBUTING.md +0 -4
- data/Makefile +1 -1
- data/README.md +4 -0
- data/config.yml +920 -148
- data/docs/build_system.md +8 -11
- data/docs/fuzzing.md +1 -1
- data/docs/parsing_rules.md +4 -1
- data/docs/relocation.md +34 -0
- data/docs/ripper_translation.md +22 -0
- data/docs/serialization.md +3 -0
- data/ext/prism/api_node.c +2863 -2079
- data/ext/prism/extconf.rb +14 -37
- data/ext/prism/extension.c +241 -391
- data/ext/prism/extension.h +2 -2
- data/include/prism/ast.h +2156 -453
- data/include/prism/defines.h +58 -7
- data/include/prism/diagnostic.h +24 -6
- data/include/prism/node.h +0 -21
- data/include/prism/options.h +94 -3
- data/include/prism/parser.h +82 -40
- data/include/prism/regexp.h +18 -8
- data/include/prism/static_literals.h +3 -2
- data/include/prism/util/pm_char.h +1 -2
- data/include/prism/util/pm_constant_pool.h +0 -8
- data/include/prism/util/pm_integer.h +22 -15
- data/include/prism/util/pm_newline_list.h +11 -0
- data/include/prism/util/pm_string.h +28 -12
- data/include/prism/version.h +3 -3
- data/include/prism.h +47 -11
- data/lib/prism/compiler.rb +3 -0
- data/lib/prism/desugar_compiler.rb +111 -74
- data/lib/prism/dispatcher.rb +16 -1
- data/lib/prism/dot_visitor.rb +55 -34
- data/lib/prism/dsl.rb +660 -468
- data/lib/prism/ffi.rb +113 -8
- data/lib/prism/inspect_visitor.rb +296 -64
- data/lib/prism/lex_compat.rb +1 -1
- data/lib/prism/mutation_compiler.rb +11 -6
- data/lib/prism/node.rb +4262 -5023
- data/lib/prism/node_ext.rb +91 -14
- data/lib/prism/parse_result/comments.rb +0 -7
- data/lib/prism/parse_result/errors.rb +65 -0
- data/lib/prism/parse_result/newlines.rb +101 -11
- data/lib/prism/parse_result.rb +183 -6
- data/lib/prism/reflection.rb +12 -10
- data/lib/prism/relocation.rb +504 -0
- data/lib/prism/serialize.rb +496 -609
- data/lib/prism/string_query.rb +30 -0
- data/lib/prism/translation/parser/compiler.rb +185 -155
- data/lib/prism/translation/parser/lexer.rb +26 -4
- data/lib/prism/translation/parser.rb +9 -4
- data/lib/prism/translation/ripper.rb +23 -25
- data/lib/prism/translation/ruby_parser.rb +86 -17
- data/lib/prism/visitor.rb +3 -0
- data/lib/prism.rb +6 -8
- data/prism.gemspec +9 -5
- data/rbi/prism/dsl.rbi +521 -0
- data/rbi/prism/node.rbi +1115 -1120
- data/rbi/prism/parse_result.rbi +29 -0
- data/rbi/prism/string_query.rbi +12 -0
- data/rbi/prism/visitor.rbi +3 -0
- data/rbi/prism.rbi +36 -30
- data/sig/prism/dsl.rbs +190 -303
- data/sig/prism/mutation_compiler.rbs +1 -0
- data/sig/prism/node.rbs +678 -632
- data/sig/prism/parse_result.rbs +22 -0
- data/sig/prism/relocation.rbs +185 -0
- data/sig/prism/string_query.rbs +11 -0
- data/sig/prism/visitor.rbs +1 -0
- data/sig/prism.rbs +103 -64
- data/src/diagnostic.c +64 -28
- data/src/node.c +502 -1739
- data/src/options.c +76 -27
- data/src/prettyprint.c +188 -112
- data/src/prism.c +3376 -2293
- data/src/regexp.c +208 -71
- data/src/serialize.c +182 -50
- data/src/static_literals.c +64 -85
- data/src/token_type.c +4 -4
- data/src/util/pm_char.c +1 -1
- data/src/util/pm_constant_pool.c +0 -8
- data/src/util/pm_integer.c +53 -25
- data/src/util/pm_newline_list.c +29 -0
- data/src/util/pm_string.c +131 -80
- data/src/util/pm_strpbrk.c +32 -6
- metadata +11 -7
- data/include/prism/util/pm_string_list.h +0 -44
- data/lib/prism/debug.rb +0 -249
- data/lib/prism/translation/parser/rubocop.rb +0 -73
- data/src/util/pm_string_list.c +0 -28
data/lib/prism/ffi.rb
CHANGED
@@ -13,7 +13,15 @@ module Prism
|
|
13
13
|
|
14
14
|
# Define the library that we will be pulling functions from. Note that this
|
15
15
|
# must align with the build shared library from make/rake.
|
16
|
-
|
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
|
+
if File.exist? libprism_in_build
|
19
|
+
INCLUDE_DIR = File.expand_path("../../include", __dir__)
|
20
|
+
ffi_lib libprism_in_build
|
21
|
+
else
|
22
|
+
INCLUDE_DIR = "#{RbConfig::CONFIG["libdir"]}/prism/include"
|
23
|
+
ffi_lib libprism_in_libdir
|
24
|
+
end
|
17
25
|
|
18
26
|
# Convert a native C type declaration into a symbol that FFI understands.
|
19
27
|
# For example:
|
@@ -38,7 +46,7 @@ module Prism
|
|
38
46
|
# given functions. For each one, define a function with the same name and
|
39
47
|
# signature as the C function.
|
40
48
|
def self.load_exported_functions_from(header, *functions, callbacks)
|
41
|
-
File.foreach(
|
49
|
+
File.foreach("#{INCLUDE_DIR}/#{header}") do |line|
|
42
50
|
# We only want to attempt to load exported functions.
|
43
51
|
next unless line.start_with?("PRISM_EXPORTED_FUNCTION ")
|
44
52
|
|
@@ -72,6 +80,8 @@ module Prism
|
|
72
80
|
end
|
73
81
|
|
74
82
|
callback :pm_parse_stream_fgets_t, [:pointer, :int, :pointer], :pointer
|
83
|
+
enum :pm_string_init_result_t, %i[PM_STRING_INIT_SUCCESS PM_STRING_INIT_ERROR_GENERIC PM_STRING_INIT_ERROR_DIRECTORY]
|
84
|
+
enum :pm_string_query_t, [:PM_STRING_QUERY_ERROR, -1, :PM_STRING_QUERY_FALSE, :PM_STRING_QUERY_TRUE]
|
75
85
|
|
76
86
|
load_exported_functions_from(
|
77
87
|
"prism.h",
|
@@ -82,6 +92,9 @@ module Prism
|
|
82
92
|
"pm_serialize_lex",
|
83
93
|
"pm_serialize_parse_lex",
|
84
94
|
"pm_parse_success_p",
|
95
|
+
"pm_string_query_local",
|
96
|
+
"pm_string_query_constant",
|
97
|
+
"pm_string_query_method_name",
|
85
98
|
[:pm_parse_stream_fgets_t]
|
86
99
|
)
|
87
100
|
|
@@ -176,13 +189,26 @@ module Prism
|
|
176
189
|
def self.with_file(filepath)
|
177
190
|
raise TypeError unless filepath.is_a?(String)
|
178
191
|
|
192
|
+
# On Windows and Mac, it's expected that filepaths will be encoded in
|
193
|
+
# UTF-8. If they are not, we need to convert them to UTF-8 before
|
194
|
+
# passing them into pm_string_mapped_init.
|
195
|
+
if RbConfig::CONFIG["host_os"].match?(/bccwin|cygwin|djgpp|mingw|mswin|wince|darwin/i) &&
|
196
|
+
(encoding = filepath.encoding) != Encoding::ASCII_8BIT && encoding != Encoding::UTF_8
|
197
|
+
filepath = filepath.encode(Encoding::UTF_8)
|
198
|
+
end
|
199
|
+
|
179
200
|
FFI::MemoryPointer.new(SIZEOF) do |pm_string|
|
180
|
-
|
201
|
+
case (result = LibRubyParser.pm_string_mapped_init(pm_string, filepath))
|
202
|
+
when :PM_STRING_INIT_SUCCESS
|
181
203
|
pointer = LibRubyParser.pm_string_source(pm_string)
|
182
204
|
length = LibRubyParser.pm_string_length(pm_string)
|
183
205
|
return yield new(pointer, length, false)
|
184
|
-
|
206
|
+
when :PM_STRING_INIT_ERROR_GENERIC
|
185
207
|
raise SystemCallError.new(filepath, FFI.errno)
|
208
|
+
when :PM_STRING_INIT_ERROR_DIRECTORY
|
209
|
+
raise Errno::EISDIR.new(filepath)
|
210
|
+
else
|
211
|
+
raise "Unknown error initializing pm_string_t: #{result.inspect}"
|
186
212
|
end
|
187
213
|
ensure
|
188
214
|
LibRubyParser.pm_string_free(pm_string)
|
@@ -200,8 +226,8 @@ module Prism
|
|
200
226
|
|
201
227
|
class << self
|
202
228
|
# Mirror the Prism.dump API by using the serialization API.
|
203
|
-
def dump(
|
204
|
-
LibRubyParser::PrismString.with_string(
|
229
|
+
def dump(source, **options)
|
230
|
+
LibRubyParser::PrismString.with_string(source) { |string| dump_common(string, options) }
|
205
231
|
end
|
206
232
|
|
207
233
|
# Mirror the Prism.dump_file API by using the serialization API.
|
@@ -302,6 +328,27 @@ module Prism
|
|
302
328
|
!parse_file_success?(filepath, **options)
|
303
329
|
end
|
304
330
|
|
331
|
+
# Mirror the Prism.profile API by using the serialization API.
|
332
|
+
def profile(source, **options)
|
333
|
+
LibRubyParser::PrismString.with_string(source) do |string|
|
334
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
335
|
+
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
|
336
|
+
nil
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
# Mirror the Prism.profile_file API by using the serialization API.
|
342
|
+
def profile_file(filepath, **options)
|
343
|
+
LibRubyParser::PrismString.with_file(filepath) do |string|
|
344
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
345
|
+
options[:filepath] = filepath
|
346
|
+
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
|
347
|
+
nil
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
305
352
|
private
|
306
353
|
|
307
354
|
def dump_common(string, options) # :nodoc:
|
@@ -376,6 +423,20 @@ module Prism
|
|
376
423
|
end
|
377
424
|
end
|
378
425
|
|
426
|
+
# Return the value that should be dumped for the version option.
|
427
|
+
def dump_options_version(version)
|
428
|
+
case version
|
429
|
+
when nil, "latest"
|
430
|
+
0
|
431
|
+
when /\A3\.3(\.\d+)?\z/
|
432
|
+
1
|
433
|
+
when /\A3\.4(\.\d+)?\z/
|
434
|
+
0
|
435
|
+
else
|
436
|
+
raise ArgumentError, "invalid version: #{version}"
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
379
440
|
# Convert the given options into a serialized options string.
|
380
441
|
def dump_options(options)
|
381
442
|
template = +""
|
@@ -394,7 +455,7 @@ module Prism
|
|
394
455
|
|
395
456
|
template << "L"
|
396
457
|
if (encoding = options[:encoding])
|
397
|
-
name = encoding.name
|
458
|
+
name = encoding.is_a?(Encoding) ? encoding.name : encoding
|
398
459
|
values.push(name.bytesize, name.b)
|
399
460
|
template << "A*"
|
400
461
|
else
|
@@ -408,7 +469,16 @@ module Prism
|
|
408
469
|
values << dump_options_command_line(options)
|
409
470
|
|
410
471
|
template << "C"
|
411
|
-
values <<
|
472
|
+
values << dump_options_version(options[:version])
|
473
|
+
|
474
|
+
template << "C"
|
475
|
+
values << (options[:encoding] == false ? 1 : 0)
|
476
|
+
|
477
|
+
template << "C"
|
478
|
+
values << (options.fetch(:main_script, false) ? 1 : 0)
|
479
|
+
|
480
|
+
template << "C"
|
481
|
+
values << (options.fetch(:partial_script, false) ? 1 : 0)
|
412
482
|
|
413
483
|
template << "L"
|
414
484
|
if (scopes = options[:scopes])
|
@@ -434,4 +504,39 @@ module Prism
|
|
434
504
|
values.pack(template)
|
435
505
|
end
|
436
506
|
end
|
507
|
+
|
508
|
+
# Here we are going to patch StringQuery to put in the class-level methods so
|
509
|
+
# that it can maintain a consistent interface
|
510
|
+
class StringQuery
|
511
|
+
class << self
|
512
|
+
# Mirrors the C extension's StringQuery::local? method.
|
513
|
+
def local?(string)
|
514
|
+
query(LibRubyParser.pm_string_query_local(string, string.bytesize, string.encoding.name))
|
515
|
+
end
|
516
|
+
|
517
|
+
# Mirrors the C extension's StringQuery::constant? method.
|
518
|
+
def constant?(string)
|
519
|
+
query(LibRubyParser.pm_string_query_constant(string, string.bytesize, string.encoding.name))
|
520
|
+
end
|
521
|
+
|
522
|
+
# Mirrors the C extension's StringQuery::method_name? method.
|
523
|
+
def method_name?(string)
|
524
|
+
query(LibRubyParser.pm_string_query_method_name(string, string.bytesize, string.encoding.name))
|
525
|
+
end
|
526
|
+
|
527
|
+
private
|
528
|
+
|
529
|
+
# Parse the enum result and return an appropriate boolean.
|
530
|
+
def query(result)
|
531
|
+
case result
|
532
|
+
when :PM_STRING_QUERY_ERROR
|
533
|
+
raise ArgumentError, "Invalid or non ascii-compatible encoding"
|
534
|
+
when :PM_STRING_QUERY_FALSE
|
535
|
+
false
|
536
|
+
when :PM_STRING_QUERY_TRUE
|
537
|
+
true
|
538
|
+
end
|
539
|
+
end
|
540
|
+
end
|
541
|
+
end
|
437
542
|
end
|