prism 0.29.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +115 -1
  3. data/CONTRIBUTING.md +0 -4
  4. data/Makefile +1 -1
  5. data/README.md +4 -0
  6. data/config.yml +920 -148
  7. data/docs/build_system.md +8 -11
  8. data/docs/fuzzing.md +1 -1
  9. data/docs/parsing_rules.md +4 -1
  10. data/docs/relocation.md +34 -0
  11. data/docs/ripper_translation.md +22 -0
  12. data/docs/serialization.md +3 -0
  13. data/ext/prism/api_node.c +2863 -2079
  14. data/ext/prism/extconf.rb +14 -37
  15. data/ext/prism/extension.c +241 -391
  16. data/ext/prism/extension.h +2 -2
  17. data/include/prism/ast.h +2156 -453
  18. data/include/prism/defines.h +58 -7
  19. data/include/prism/diagnostic.h +24 -6
  20. data/include/prism/node.h +0 -21
  21. data/include/prism/options.h +94 -3
  22. data/include/prism/parser.h +82 -40
  23. data/include/prism/regexp.h +18 -8
  24. data/include/prism/static_literals.h +3 -2
  25. data/include/prism/util/pm_char.h +1 -2
  26. data/include/prism/util/pm_constant_pool.h +0 -8
  27. data/include/prism/util/pm_integer.h +22 -15
  28. data/include/prism/util/pm_newline_list.h +11 -0
  29. data/include/prism/util/pm_string.h +28 -12
  30. data/include/prism/version.h +3 -3
  31. data/include/prism.h +47 -11
  32. data/lib/prism/compiler.rb +3 -0
  33. data/lib/prism/desugar_compiler.rb +111 -74
  34. data/lib/prism/dispatcher.rb +16 -1
  35. data/lib/prism/dot_visitor.rb +55 -34
  36. data/lib/prism/dsl.rb +660 -468
  37. data/lib/prism/ffi.rb +113 -8
  38. data/lib/prism/inspect_visitor.rb +296 -64
  39. data/lib/prism/lex_compat.rb +1 -1
  40. data/lib/prism/mutation_compiler.rb +11 -6
  41. data/lib/prism/node.rb +4262 -5023
  42. data/lib/prism/node_ext.rb +91 -14
  43. data/lib/prism/parse_result/comments.rb +0 -7
  44. data/lib/prism/parse_result/errors.rb +65 -0
  45. data/lib/prism/parse_result/newlines.rb +101 -11
  46. data/lib/prism/parse_result.rb +183 -6
  47. data/lib/prism/reflection.rb +12 -10
  48. data/lib/prism/relocation.rb +504 -0
  49. data/lib/prism/serialize.rb +496 -609
  50. data/lib/prism/string_query.rb +30 -0
  51. data/lib/prism/translation/parser/compiler.rb +185 -155
  52. data/lib/prism/translation/parser/lexer.rb +26 -4
  53. data/lib/prism/translation/parser.rb +9 -4
  54. data/lib/prism/translation/ripper.rb +23 -25
  55. data/lib/prism/translation/ruby_parser.rb +86 -17
  56. data/lib/prism/visitor.rb +3 -0
  57. data/lib/prism.rb +6 -8
  58. data/prism.gemspec +9 -5
  59. data/rbi/prism/dsl.rbi +521 -0
  60. data/rbi/prism/node.rbi +1115 -1120
  61. data/rbi/prism/parse_result.rbi +29 -0
  62. data/rbi/prism/string_query.rbi +12 -0
  63. data/rbi/prism/visitor.rbi +3 -0
  64. data/rbi/prism.rbi +36 -30
  65. data/sig/prism/dsl.rbs +190 -303
  66. data/sig/prism/mutation_compiler.rbs +1 -0
  67. data/sig/prism/node.rbs +678 -632
  68. data/sig/prism/parse_result.rbs +22 -0
  69. data/sig/prism/relocation.rbs +185 -0
  70. data/sig/prism/string_query.rbs +11 -0
  71. data/sig/prism/visitor.rbs +1 -0
  72. data/sig/prism.rbs +103 -64
  73. data/src/diagnostic.c +64 -28
  74. data/src/node.c +502 -1739
  75. data/src/options.c +76 -27
  76. data/src/prettyprint.c +188 -112
  77. data/src/prism.c +3376 -2293
  78. data/src/regexp.c +208 -71
  79. data/src/serialize.c +182 -50
  80. data/src/static_literals.c +64 -85
  81. data/src/token_type.c +4 -4
  82. data/src/util/pm_char.c +1 -1
  83. data/src/util/pm_constant_pool.c +0 -8
  84. data/src/util/pm_integer.c +53 -25
  85. data/src/util/pm_newline_list.c +29 -0
  86. data/src/util/pm_string.c +131 -80
  87. data/src/util/pm_strpbrk.c +32 -6
  88. metadata +11 -7
  89. data/include/prism/util/pm_string_list.h +0 -44
  90. data/lib/prism/debug.rb +0 -249
  91. data/lib/prism/translation/parser/rubocop.rb +0 -73
  92. 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
- ffi_lib File.expand_path("../../build/libprism.#{RbConfig::CONFIG["SOEXT"]}", __dir__)
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(File.expand_path("../../include/#{header}", __dir__)) do |line|
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
- if LibRubyParser.pm_string_mapped_init(pm_string, filepath)
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
- else
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(code, **options)
204
- LibRubyParser::PrismString.with_string(code) { |string| dump_common(string, options) }
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 << { nil => 0, "3.3.0" => 1, "3.3.1" => 1, "3.4.0" => 0, "latest" => 0 }.fetch(options[:version])
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