prism 1.4.0 → 1.7.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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +73 -1
  3. data/Makefile +7 -5
  4. data/README.md +3 -1
  5. data/config.yml +294 -41
  6. data/docs/build_system.md +2 -2
  7. data/docs/cruby_compilation.md +1 -1
  8. data/docs/design.md +2 -2
  9. data/docs/parser_translation.md +8 -23
  10. data/docs/releasing.md +6 -25
  11. data/docs/ripper_translation.md +1 -1
  12. data/ext/prism/api_node.c +9 -3
  13. data/ext/prism/extconf.rb +1 -1
  14. data/ext/prism/extension.c +24 -3
  15. data/ext/prism/extension.h +1 -1
  16. data/include/prism/ast.h +360 -70
  17. data/include/prism/diagnostic.h +7 -0
  18. data/include/prism/options.h +49 -3
  19. data/include/prism/parser.h +3 -0
  20. data/include/prism/regexp.h +2 -2
  21. data/include/prism/util/pm_buffer.h +8 -0
  22. data/include/prism/util/pm_integer.h +4 -0
  23. data/include/prism/util/pm_list.h +6 -0
  24. data/include/prism/util/pm_string.h +12 -2
  25. data/include/prism/version.h +2 -2
  26. data/include/prism.h +40 -15
  27. data/lib/prism/compiler.rb +456 -151
  28. data/lib/prism/desugar_compiler.rb +1 -0
  29. data/lib/prism/dispatcher.rb +16 -0
  30. data/lib/prism/dot_visitor.rb +10 -1
  31. data/lib/prism/dsl.rb +5 -2
  32. data/lib/prism/ffi.rb +28 -10
  33. data/lib/prism/inspect_visitor.rb +4 -0
  34. data/lib/prism/lex_compat.rb +1 -0
  35. data/lib/prism/mutation_compiler.rb +3 -0
  36. data/lib/prism/node.rb +559 -349
  37. data/lib/prism/node_ext.rb +4 -1
  38. data/lib/prism/pack.rb +2 -0
  39. data/lib/prism/parse_result/comments.rb +1 -0
  40. data/lib/prism/parse_result/errors.rb +1 -0
  41. data/lib/prism/parse_result/newlines.rb +1 -0
  42. data/lib/prism/parse_result.rb +3 -15
  43. data/lib/prism/pattern.rb +1 -0
  44. data/lib/prism/polyfill/scan_byte.rb +14 -0
  45. data/lib/prism/polyfill/warn.rb +36 -0
  46. data/lib/prism/reflection.rb +4 -1
  47. data/lib/prism/relocation.rb +1 -0
  48. data/lib/prism/serialize.rb +30 -22
  49. data/lib/prism/string_query.rb +1 -0
  50. data/lib/prism/translation/parser/builder.rb +1 -0
  51. data/lib/prism/translation/parser/compiler.rb +63 -41
  52. data/lib/prism/translation/parser/lexer.rb +29 -21
  53. data/lib/prism/translation/parser.rb +25 -4
  54. data/lib/prism/translation/parser33.rb +1 -0
  55. data/lib/prism/translation/parser34.rb +1 -0
  56. data/lib/prism/translation/parser35.rb +2 -6
  57. data/lib/prism/translation/parser40.rb +13 -0
  58. data/lib/prism/translation/parser41.rb +13 -0
  59. data/lib/prism/translation/parser_current.rb +26 -0
  60. data/lib/prism/translation/ripper/sexp.rb +1 -0
  61. data/lib/prism/translation/ripper.rb +19 -3
  62. data/lib/prism/translation/ruby_parser.rb +340 -22
  63. data/lib/prism/translation.rb +4 -0
  64. data/lib/prism/visitor.rb +457 -152
  65. data/lib/prism.rb +22 -0
  66. data/prism.gemspec +9 -1
  67. data/rbi/prism/dsl.rbi +6 -6
  68. data/rbi/prism/node.rbi +42 -17
  69. data/rbi/prism/translation/parser35.rbi +0 -2
  70. data/rbi/prism/translation/parser40.rbi +6 -0
  71. data/rbi/prism/translation/parser41.rbi +6 -0
  72. data/sig/prism/dispatcher.rbs +3 -0
  73. data/sig/prism/dsl.rbs +5 -5
  74. data/sig/prism/node.rbs +462 -38
  75. data/sig/prism/node_ext.rbs +84 -17
  76. data/sig/prism/parse_result/comments.rbs +38 -0
  77. data/sig/prism/parse_result.rbs +4 -0
  78. data/sig/prism/reflection.rbs +1 -1
  79. data/sig/prism.rbs +4 -0
  80. data/src/diagnostic.c +13 -1
  81. data/src/encoding.c +172 -67
  82. data/src/node.c +11 -0
  83. data/src/options.c +17 -7
  84. data/src/prettyprint.c +18 -0
  85. data/src/prism.c +1495 -2021
  86. data/src/serialize.c +9 -1
  87. data/src/token_type.c +38 -36
  88. data/src/util/pm_constant_pool.c +1 -1
  89. data/src/util/pm_string.c +6 -8
  90. metadata +11 -3
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
+ # :markup: markdown
2
3
 
4
+ #--
3
5
  # Here we are reopening the prism module to provide methods on nodes that aren't
4
6
  # templated and are meant as convenience methods.
7
+ #++
5
8
  module Prism
6
9
  class Node
7
10
  def deprecated(*replacements) # :nodoc:
@@ -9,7 +12,7 @@ module Prism
9
12
  location = location[0].label if location
10
13
  suggest = replacements.map { |replacement| "#{self.class}##{replacement}" }
11
14
 
12
- warn(<<~MSG, category: :deprecated)
15
+ warn(<<~MSG, uplevel: 1, category: :deprecated)
13
16
  [deprecation]: #{self.class}##{location} is deprecated and will be \
14
17
  removed in the next major version. Use #{suggest.join("/")} instead.
15
18
  #{(caller(1, 3) || []).join("\n")}
data/lib/prism/pack.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
+ # :markup: markdown
2
3
  # typed: ignore
3
4
 
5
+ #
4
6
  module Prism
5
7
  # A parser for the pack template language.
6
8
  module Pack
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # :markup: markdown
2
3
 
3
4
  module Prism
4
5
  class ParseResult < Result
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # :markup: markdown
2
3
 
3
4
  require "stringio"
4
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # :markup: markdown
2
3
 
3
4
  module Prism
4
5
  class ParseResult < Result
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # :markup: markdown
2
3
 
3
4
  module Prism
4
5
  # This represents a source of Ruby code that has been parsed. It is used in
@@ -154,21 +155,8 @@ module Prism
154
155
  # Binary search through the offsets to find the line number for the given
155
156
  # byte offset.
156
157
  def find_line(byte_offset)
157
- left = 0
158
- right = offsets.length - 1
159
-
160
- while left <= right
161
- mid = left + (right - left) / 2
162
- return mid if (offset = offsets[mid]) == byte_offset
163
-
164
- if offset < byte_offset
165
- left = mid + 1
166
- else
167
- right = mid - 1
168
- end
169
- end
170
-
171
- left - 1
158
+ index = offsets.bsearch_index { |offset| offset > byte_offset } || offsets.length
159
+ index - 1
172
160
  end
173
161
  end
174
162
 
data/lib/prism/pattern.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # :markup: markdown
2
3
 
3
4
  module Prism
4
5
  # A pattern is an object that wraps a Ruby pattern matching expression. The
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "strscan"
4
+
5
+ # Polyfill for StringScanner#scan_byte, which didn't exist until Ruby 3.4.
6
+ if !(StringScanner.method_defined?(:scan_byte))
7
+ StringScanner.include(
8
+ Module.new {
9
+ def scan_byte # :nodoc:
10
+ get_byte&.b&.ord
11
+ end
12
+ }
13
+ )
14
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Polyfill for Kernel#warn with the category parameter. Not all Ruby engines
4
+ # have Method#parameters implemented, so we check the arity instead if
5
+ # necessary.
6
+ if (method = Kernel.instance_method(:warn)).respond_to?(:parameters) ? method.parameters.none? { |_, name| name == :category } : (method.arity == -1)
7
+ Kernel.prepend(
8
+ Module.new {
9
+ def warn(*msgs, uplevel: nil, category: nil) # :nodoc:
10
+ case uplevel
11
+ when nil
12
+ super(*msgs)
13
+ when Integer
14
+ super(*msgs, uplevel: uplevel + 1)
15
+ else
16
+ super(*msgs, uplevel: uplevel.to_int + 1)
17
+ end
18
+ end
19
+ }
20
+ )
21
+
22
+ Object.prepend(
23
+ Module.new {
24
+ def warn(*msgs, uplevel: nil, category: nil) # :nodoc:
25
+ case uplevel
26
+ when nil
27
+ super(*msgs)
28
+ when Integer
29
+ super(*msgs, uplevel: uplevel + 1)
30
+ else
31
+ super(*msgs, uplevel: uplevel.to_int + 1)
32
+ end
33
+ end
34
+ }
35
+ )
36
+ end
@@ -1,9 +1,12 @@
1
1
  # frozen_string_literal: true
2
+ # :markup: markdown
2
3
 
3
4
  =begin
5
+ --
4
6
  This file is generated by the templates/template.rb script and should not be
5
7
  modified manually. See templates/lib/prism/reflection.rb.erb
6
8
  if you are looking to modify the template
9
+ ++
7
10
  =end
8
11
 
9
12
  module Prism
@@ -140,7 +143,7 @@ module Prism
140
143
  when :call_and_write_node
141
144
  [FlagsField.new(:flags, [:safe_navigation?, :variable_call?, :attribute_write?, :ignore_visibility?]), OptionalNodeField.new(:receiver), OptionalLocationField.new(:call_operator_loc), OptionalLocationField.new(:message_loc), ConstantField.new(:read_name), ConstantField.new(:write_name), LocationField.new(:operator_loc), NodeField.new(:value)]
142
145
  when :call_node
143
- [FlagsField.new(:flags, [:safe_navigation?, :variable_call?, :attribute_write?, :ignore_visibility?]), OptionalNodeField.new(:receiver), OptionalLocationField.new(:call_operator_loc), ConstantField.new(:name), OptionalLocationField.new(:message_loc), OptionalLocationField.new(:opening_loc), OptionalNodeField.new(:arguments), OptionalLocationField.new(:closing_loc), OptionalNodeField.new(:block)]
146
+ [FlagsField.new(:flags, [:safe_navigation?, :variable_call?, :attribute_write?, :ignore_visibility?]), OptionalNodeField.new(:receiver), OptionalLocationField.new(:call_operator_loc), ConstantField.new(:name), OptionalLocationField.new(:message_loc), OptionalLocationField.new(:opening_loc), OptionalNodeField.new(:arguments), OptionalLocationField.new(:closing_loc), OptionalLocationField.new(:equal_loc), OptionalNodeField.new(:block)]
144
147
  when :call_operator_write_node
145
148
  [FlagsField.new(:flags, [:safe_navigation?, :variable_call?, :attribute_write?, :ignore_visibility?]), OptionalNodeField.new(:receiver), OptionalLocationField.new(:call_operator_loc), OptionalLocationField.new(:message_loc), ConstantField.new(:read_name), ConstantField.new(:write_name), ConstantField.new(:binary_operator), LocationField.new(:binary_operator_loc), NodeField.new(:value)]
146
149
  when :call_or_write_node
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # :markup: markdown
2
3
 
3
4
  module Prism
4
5
  # Prism parses deterministically for the same input. This provides a nice
@@ -1,9 +1,12 @@
1
1
  # frozen_string_literal: true
2
+ # :markup: markdown
2
3
 
3
4
  =begin
5
+ --
4
6
  This file is generated by the templates/template.rb script and should not be
5
7
  modified manually. See templates/lib/prism/serialize.rb.erb
6
8
  if you are looking to modify the template
9
+ ++
7
10
  =end
8
11
 
9
12
  require "stringio"
@@ -18,7 +21,7 @@ module Prism
18
21
 
19
22
  # The minor version of prism that we are expecting to find in the serialized
20
23
  # strings.
21
- MINOR_VERSION = 4
24
+ MINOR_VERSION = 7
22
25
 
23
26
  # The patch version of prism that we are expecting to find in the serialized
24
27
  # strings.
@@ -394,6 +397,7 @@ module Prism
394
397
  :conditional_while_predicate,
395
398
  :constant_path_colon_colon_constant,
396
399
  :def_endless,
400
+ :def_endless_parameters,
397
401
  :def_endless_setter,
398
402
  :def_name,
399
403
  :def_params_term,
@@ -435,6 +439,8 @@ module Prism
435
439
  :expect_for_delimiter,
436
440
  :expect_ident_req_parameter,
437
441
  :expect_in_delimiter,
442
+ :expect_lparen_after_not_lparen,
443
+ :expect_lparen_after_not_other,
438
444
  :expect_lparen_req_parameter,
439
445
  :expect_message,
440
446
  :expect_rbracket,
@@ -550,6 +556,7 @@ module Prism
550
556
  :parameter_wild_loose_comma,
551
557
  :pattern_array_multiple_rests,
552
558
  :pattern_capture_duplicate,
559
+ :pattern_capture_in_alternative,
553
560
  :pattern_expression_after_bracket,
554
561
  :pattern_expression_after_comma,
555
562
  :pattern_expression_after_hrocket,
@@ -611,6 +618,7 @@ module Prism
611
618
  :unexpected_index_keywords,
612
619
  :unexpected_label,
613
620
  :unexpected_multi_write,
621
+ :unexpected_parameter_default_value,
614
622
  :unexpected_range_operator,
615
623
  :unexpected_safe_navigation,
616
624
  :unexpected_token_close_context,
@@ -873,7 +881,7 @@ module Prism
873
881
  when 18 then
874
882
  CallAndWriteNode.new(source, node_id, location, load_varuint, load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_optional_location(freeze), load_constant(constant_pool, encoding), load_constant(constant_pool, encoding), load_location(freeze), load_node(constant_pool, encoding, freeze))
875
883
  when 19 then
876
- CallNode.new(source, node_id, location, load_varuint, load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_constant(constant_pool, encoding), load_optional_location(freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze))
884
+ CallNode.new(source, node_id, location, load_varuint, load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_constant(constant_pool, encoding), load_optional_location(freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze))
877
885
  when 20 then
878
886
  CallOperatorWriteNode.new(source, node_id, location, load_varuint, load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_optional_location(freeze), load_constant(constant_pool, encoding), load_constant(constant_pool, encoding), load_constant(constant_pool, encoding), load_location(freeze), load_node(constant_pool, encoding, freeze))
879
887
  when 21 then
@@ -1281,7 +1289,7 @@ module Prism
1281
1289
  -> (constant_pool, encoding, freeze) {
1282
1290
  node_id = load_varuint
1283
1291
  location = load_location(freeze)
1284
- value = CallNode.new(source, node_id, location, load_varuint, load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_constant(constant_pool, encoding), load_optional_location(freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze))
1292
+ value = CallNode.new(source, node_id, location, load_varuint, load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_constant(constant_pool, encoding), load_optional_location(freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze), load_optional_location(freeze), load_optional_location(freeze), load_optional_node(constant_pool, encoding, freeze))
1285
1293
  value.freeze if freeze
1286
1294
  value
1287
1295
  },
@@ -2219,8 +2227,22 @@ module Prism
2219
2227
  TOKEN_TYPES = [
2220
2228
  nil,
2221
2229
  :EOF,
2222
- :MISSING,
2223
- :NOT_PROVIDED,
2230
+ :BRACE_RIGHT,
2231
+ :COMMA,
2232
+ :EMBEXPR_END,
2233
+ :KEYWORD_DO,
2234
+ :KEYWORD_ELSE,
2235
+ :KEYWORD_ELSIF,
2236
+ :KEYWORD_END,
2237
+ :KEYWORD_ENSURE,
2238
+ :KEYWORD_IN,
2239
+ :KEYWORD_RESCUE,
2240
+ :KEYWORD_THEN,
2241
+ :KEYWORD_WHEN,
2242
+ :NEWLINE,
2243
+ :PARENTHESIS_RIGHT,
2244
+ :PIPE,
2245
+ :SEMICOLON,
2224
2246
  :AMPERSAND,
2225
2247
  :AMPERSAND_AMPERSAND,
2226
2248
  :AMPERSAND_AMPERSAND_EQUAL,
@@ -2232,7 +2254,6 @@ module Prism
2232
2254
  :BANG_EQUAL,
2233
2255
  :BANG_TILDE,
2234
2256
  :BRACE_LEFT,
2235
- :BRACE_RIGHT,
2236
2257
  :BRACKET_LEFT,
2237
2258
  :BRACKET_LEFT_ARRAY,
2238
2259
  :BRACKET_LEFT_RIGHT,
@@ -2244,7 +2265,6 @@ module Prism
2244
2265
  :CLASS_VARIABLE,
2245
2266
  :COLON,
2246
2267
  :COLON_COLON,
2247
- :COMMA,
2248
2268
  :COMMENT,
2249
2269
  :CONSTANT,
2250
2270
  :DOT,
@@ -2254,7 +2274,6 @@ module Prism
2254
2274
  :EMBDOC_END,
2255
2275
  :EMBDOC_LINE,
2256
2276
  :EMBEXPR_BEGIN,
2257
- :EMBEXPR_END,
2258
2277
  :EMBVAR,
2259
2278
  :EQUAL,
2260
2279
  :EQUAL_EQUAL,
@@ -2288,38 +2307,29 @@ module Prism
2288
2307
  :KEYWORD_CLASS,
2289
2308
  :KEYWORD_DEF,
2290
2309
  :KEYWORD_DEFINED,
2291
- :KEYWORD_DO,
2292
2310
  :KEYWORD_DO_LOOP,
2293
- :KEYWORD_ELSE,
2294
- :KEYWORD_ELSIF,
2295
- :KEYWORD_END,
2296
2311
  :KEYWORD_END_UPCASE,
2297
- :KEYWORD_ENSURE,
2298
2312
  :KEYWORD_FALSE,
2299
2313
  :KEYWORD_FOR,
2300
2314
  :KEYWORD_IF,
2301
2315
  :KEYWORD_IF_MODIFIER,
2302
- :KEYWORD_IN,
2303
2316
  :KEYWORD_MODULE,
2304
2317
  :KEYWORD_NEXT,
2305
2318
  :KEYWORD_NIL,
2306
2319
  :KEYWORD_NOT,
2307
2320
  :KEYWORD_OR,
2308
2321
  :KEYWORD_REDO,
2309
- :KEYWORD_RESCUE,
2310
2322
  :KEYWORD_RESCUE_MODIFIER,
2311
2323
  :KEYWORD_RETRY,
2312
2324
  :KEYWORD_RETURN,
2313
2325
  :KEYWORD_SELF,
2314
2326
  :KEYWORD_SUPER,
2315
- :KEYWORD_THEN,
2316
2327
  :KEYWORD_TRUE,
2317
2328
  :KEYWORD_UNDEF,
2318
2329
  :KEYWORD_UNLESS,
2319
2330
  :KEYWORD_UNLESS_MODIFIER,
2320
2331
  :KEYWORD_UNTIL,
2321
2332
  :KEYWORD_UNTIL_MODIFIER,
2322
- :KEYWORD_WHEN,
2323
2333
  :KEYWORD_WHILE,
2324
2334
  :KEYWORD_WHILE_MODIFIER,
2325
2335
  :KEYWORD_YIELD,
@@ -2338,11 +2348,9 @@ module Prism
2338
2348
  :MINUS,
2339
2349
  :MINUS_EQUAL,
2340
2350
  :MINUS_GREATER,
2341
- :NEWLINE,
2342
2351
  :NUMBERED_REFERENCE,
2343
2352
  :PARENTHESIS_LEFT,
2344
2353
  :PARENTHESIS_LEFT_PARENTHESES,
2345
- :PARENTHESIS_RIGHT,
2346
2354
  :PERCENT,
2347
2355
  :PERCENT_EQUAL,
2348
2356
  :PERCENT_LOWER_I,
@@ -2350,7 +2358,6 @@ module Prism
2350
2358
  :PERCENT_LOWER_X,
2351
2359
  :PERCENT_UPPER_I,
2352
2360
  :PERCENT_UPPER_W,
2353
- :PIPE,
2354
2361
  :PIPE_EQUAL,
2355
2362
  :PIPE_PIPE,
2356
2363
  :PIPE_PIPE_EQUAL,
@@ -2359,7 +2366,6 @@ module Prism
2359
2366
  :QUESTION_MARK,
2360
2367
  :REGEXP_BEGIN,
2361
2368
  :REGEXP_END,
2362
- :SEMICOLON,
2363
2369
  :SLASH,
2364
2370
  :SLASH_EQUAL,
2365
2371
  :STAR,
@@ -2382,7 +2388,9 @@ module Prism
2382
2388
  :USTAR_STAR,
2383
2389
  :WORDS_SEP,
2384
2390
  :__END__,
2385
- ]
2391
+ :MISSING,
2392
+ :NOT_PROVIDED,
2393
+ ].freeze
2386
2394
 
2387
2395
  private_constant :MAJOR_VERSION, :MINOR_VERSION, :PATCH_VERSION
2388
2396
  private_constant :ConstantPool, :FastStringIO, :Loader, :TOKEN_TYPES
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # :markup: markdown
2
3
 
3
4
  module Prism
4
5
  # Query methods that allow categorizing strings based on their context for
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # :markup: markdown
2
3
 
3
4
  module Prism
4
5
  module Translation
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # :markup: markdown
2
3
 
3
4
  module Prism
4
5
  module Translation
@@ -133,8 +134,8 @@ module Prism
133
134
  def visit_assoc_node(node)
134
135
  key = node.key
135
136
 
136
- if in_pattern
137
- if node.value.is_a?(ImplicitNode)
137
+ if node.value.is_a?(ImplicitNode)
138
+ if in_pattern
138
139
  if key.is_a?(SymbolNode)
139
140
  if key.opening.nil?
140
141
  builder.match_hash_var([key.unescaped, srange(key.location)])
@@ -144,23 +145,19 @@ module Prism
144
145
  else
145
146
  builder.match_hash_var_from_str(token(key.opening_loc), visit_all(key.parts), token(key.closing_loc))
146
147
  end
147
- elsif key.opening.nil?
148
- builder.pair_keyword([key.unescaped, srange(key.location)], visit(node.value))
149
148
  else
150
- builder.pair_quoted(token(key.opening_loc), [builder.string_internal([key.unescaped, srange(key.value_loc)])], token(key.closing_loc), visit(node.value))
151
- end
152
- elsif node.value.is_a?(ImplicitNode)
153
- value = node.value.value
149
+ value = node.value.value
154
150
 
155
- implicit_value = if value.is_a?(CallNode)
156
- builder.call_method(nil, nil, [value.name, srange(value.message_loc)])
157
- elsif value.is_a?(ConstantReadNode)
158
- builder.const([value.name, srange(key.value_loc)])
159
- else
160
- builder.ident([value.name, srange(key.value_loc)]).updated(:lvar)
161
- end
151
+ implicit_value = if value.is_a?(CallNode)
152
+ builder.call_method(nil, nil, [value.name, srange(value.message_loc)])
153
+ elsif value.is_a?(ConstantReadNode)
154
+ builder.const([value.name, srange(key.value_loc)])
155
+ else
156
+ builder.ident([value.name, srange(key.value_loc)]).updated(:lvar)
157
+ end
162
158
 
163
- builder.pair_keyword([key.unescaped, srange(key)], implicit_value)
159
+ builder.pair_keyword([key.unescaped, srange(key)], implicit_value)
160
+ end
164
161
  elsif node.operator_loc
165
162
  builder.pair(visit(key), token(node.operator_loc), visit(node.value))
166
163
  elsif key.is_a?(SymbolNode) && key.opening_loc.nil?
@@ -220,7 +217,7 @@ module Prism
220
217
  rescue_clause.exceptions.any? ? builder.array(nil, visit_all(rescue_clause.exceptions), nil) : nil,
221
218
  token(rescue_clause.operator_loc),
222
219
  visit(rescue_clause.reference),
223
- srange_find(find_start_offset, find_end_offset, ";"),
220
+ srange_semicolon(find_start_offset, find_end_offset),
224
221
  visit(rescue_clause.statements)
225
222
  )
226
223
  end until (rescue_clause = rescue_clause.subsequent).nil?
@@ -326,7 +323,7 @@ module Prism
326
323
  visit_all(arguments),
327
324
  token(node.closing_loc),
328
325
  ),
329
- srange_find(node.message_loc.end_offset, node.arguments.arguments.last.location.start_offset, "="),
326
+ token(node.equal_loc),
330
327
  visit(node.arguments.arguments.last)
331
328
  ),
332
329
  block
@@ -343,7 +340,7 @@ module Prism
343
340
  if name.end_with?("=") && !message_loc.slice.end_with?("=") && node.arguments && block.nil?
344
341
  builder.assign(
345
342
  builder.attr_asgn(visit(node.receiver), call_operator, token(message_loc)),
346
- srange_find(message_loc.end_offset, node.arguments.location.start_offset, "="),
343
+ token(node.equal_loc),
347
344
  visit(node.arguments.arguments.last)
348
345
  )
349
346
  else
@@ -696,13 +693,37 @@ module Prism
696
693
  # defined?(a)
697
694
  # ^^^^^^^^^^^
698
695
  def visit_defined_node(node)
699
- builder.keyword_cmd(
700
- :defined?,
701
- token(node.keyword_loc),
702
- token(node.lparen_loc),
703
- [visit(node.value)],
704
- token(node.rparen_loc)
705
- )
696
+ # Very weird circumstances here where something like:
697
+ #
698
+ # defined?
699
+ # (1)
700
+ #
701
+ # gets parsed in Ruby as having only the `1` expression but in parser
702
+ # it gets parsed as having a begin. In this case we need to synthesize
703
+ # that begin to match parser's behavior.
704
+ if node.lparen_loc && node.keyword_loc.join(node.lparen_loc).slice.include?("\n")
705
+ builder.keyword_cmd(
706
+ :defined?,
707
+ token(node.keyword_loc),
708
+ nil,
709
+ [
710
+ builder.begin(
711
+ token(node.lparen_loc),
712
+ visit(node.value),
713
+ token(node.rparen_loc)
714
+ )
715
+ ],
716
+ nil
717
+ )
718
+ else
719
+ builder.keyword_cmd(
720
+ :defined?,
721
+ token(node.keyword_loc),
722
+ token(node.lparen_loc),
723
+ [visit(node.value)],
724
+ token(node.rparen_loc)
725
+ )
726
+ end
706
727
  end
707
728
 
708
729
  # if foo then bar else baz end
@@ -768,7 +789,7 @@ module Prism
768
789
  if (do_keyword_loc = node.do_keyword_loc)
769
790
  token(do_keyword_loc)
770
791
  else
771
- srange_find(node.collection.location.end_offset, (node.statements&.location || node.end_keyword_loc).start_offset, ";")
792
+ srange_semicolon(node.collection.location.end_offset, (node.statements&.location || node.end_keyword_loc).start_offset)
772
793
  end,
773
794
  visit(node.statements),
774
795
  token(node.end_keyword_loc)
@@ -900,7 +921,7 @@ module Prism
900
921
  if (then_keyword_loc = node.then_keyword_loc)
901
922
  token(then_keyword_loc)
902
923
  else
903
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.subsequent&.location || node.end_keyword_loc).start_offset, ";")
924
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.subsequent&.location || node.end_keyword_loc).start_offset)
904
925
  end,
905
926
  visit(node.statements),
906
927
  case node.subsequent
@@ -966,7 +987,7 @@ module Prism
966
987
  if (then_loc = node.then_loc)
967
988
  token(then_loc)
968
989
  else
969
- srange_find(node.pattern.location.end_offset, node.statements&.location&.start_offset, ";")
990
+ srange_semicolon(node.pattern.location.end_offset, node.statements&.location&.start_offset)
970
991
  end,
971
992
  visit(node.statements)
972
993
  )
@@ -1032,7 +1053,7 @@ module Prism
1032
1053
  builder.index_asgn(
1033
1054
  visit(node.receiver),
1034
1055
  token(node.opening_loc),
1035
- visit_all(node.arguments.arguments),
1056
+ visit_all(node.arguments&.arguments || []),
1036
1057
  token(node.closing_loc),
1037
1058
  )
1038
1059
  end
@@ -1461,7 +1482,8 @@ module Prism
1461
1482
  # foo => ^(bar)
1462
1483
  # ^^^^^^
1463
1484
  def visit_pinned_expression_node(node)
1464
- expression = builder.begin(token(node.lparen_loc), visit(node.expression), token(node.rparen_loc))
1485
+ parts = node.expression.accept(copy_compiler(in_pattern: false)) # Don't treat * and similar as match_rest
1486
+ expression = builder.begin(token(node.lparen_loc), parts, token(node.rparen_loc))
1465
1487
  builder.pin(token(node.operator_loc), expression)
1466
1488
  end
1467
1489
 
@@ -1786,7 +1808,7 @@ module Prism
1786
1808
  if (then_keyword_loc = node.then_keyword_loc)
1787
1809
  token(then_keyword_loc)
1788
1810
  else
1789
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.else_clause&.location || node.end_keyword_loc).start_offset, ";")
1811
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.else_clause&.location || node.end_keyword_loc).start_offset)
1790
1812
  end,
1791
1813
  visit(node.else_clause),
1792
1814
  token(node.else_clause&.else_keyword_loc),
@@ -1817,7 +1839,7 @@ module Prism
1817
1839
  if (do_keyword_loc = node.do_keyword_loc)
1818
1840
  token(do_keyword_loc)
1819
1841
  else
1820
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset, ";")
1842
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset)
1821
1843
  end,
1822
1844
  visit(node.statements),
1823
1845
  token(node.closing_loc)
@@ -1841,7 +1863,7 @@ module Prism
1841
1863
  if (then_keyword_loc = node.then_keyword_loc)
1842
1864
  token(then_keyword_loc)
1843
1865
  else
1844
- srange_find(node.conditions.last.location.end_offset, node.statements&.location&.start_offset, ";")
1866
+ srange_semicolon(node.conditions.last.location.end_offset, node.statements&.location&.start_offset)
1845
1867
  end,
1846
1868
  visit(node.statements)
1847
1869
  )
@@ -1861,7 +1883,7 @@ module Prism
1861
1883
  if (do_keyword_loc = node.do_keyword_loc)
1862
1884
  token(do_keyword_loc)
1863
1885
  else
1864
- srange_find(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset, ";")
1886
+ srange_semicolon(node.predicate.location.end_offset, (node.statements&.location || node.closing_loc).start_offset)
1865
1887
  end,
1866
1888
  visit(node.statements),
1867
1889
  token(node.closing_loc)
@@ -1990,16 +2012,16 @@ module Prism
1990
2012
  Range.new(source_buffer, offset_cache[start_offset], offset_cache[end_offset])
1991
2013
  end
1992
2014
 
1993
- # Constructs a new source range by finding the given character between
1994
- # the given start offset and end offset. If the needle is not found, it
1995
- # returns nil. Importantly it does not search past newlines or comments.
2015
+ # Constructs a new source range by finding a semicolon between the given
2016
+ # start offset and end offset. If the semicolon is not found, it returns
2017
+ # nil. Importantly it does not search past newlines or comments.
1996
2018
  #
1997
2019
  # Note that end_offset is allowed to be nil, in which case this will
1998
2020
  # search until the end of the string.
1999
- def srange_find(start_offset, end_offset, character)
2000
- if (match = source_buffer.source.byteslice(start_offset...end_offset)[/\A\s*#{character}/])
2021
+ def srange_semicolon(start_offset, end_offset)
2022
+ if (match = source_buffer.source.byteslice(start_offset...end_offset)[/\A\s*;/])
2001
2023
  final_offset = start_offset + match.bytesize
2002
- [character, Range.new(source_buffer, offset_cache[final_offset - character.bytesize], offset_cache[final_offset])]
2024
+ [";", Range.new(source_buffer, offset_cache[final_offset - 1], offset_cache[final_offset])]
2003
2025
  end
2004
2026
  end
2005
2027