prism 0.29.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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