ruby_parser 3.14.2 → 3.17.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.
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # TODO: remove
2
3
 
3
4
  require "sexp"
4
5
  require "ruby_lexer"
@@ -28,7 +29,7 @@ class Sexp
28
29
  end
29
30
 
30
31
  module RubyParserStuff
31
- VERSION = "3.14.2"
32
+ VERSION = "3.16.0"
32
33
 
33
34
  attr_accessor :lexer, :in_def, :in_single, :file
34
35
  attr_accessor :in_kwarg
@@ -45,6 +46,11 @@ module RubyParserStuff
45
46
 
46
47
  attr_accessor :canonicalize_conditions
47
48
 
49
+ ##
50
+ # The last token type returned from #next_token
51
+
52
+ attr_accessor :last_token_type
53
+
48
54
  $good20 = []
49
55
 
50
56
  %w[
@@ -109,7 +115,7 @@ module RubyParserStuff
109
115
  def initialize(options = {})
110
116
  super()
111
117
 
112
- v = self.class.name[/2\d/]
118
+ v = self.class.name[/[23]\d/]
113
119
  raise "Bad Class name #{self.class}" unless v
114
120
 
115
121
  self.lexer = RubyLexer.new v && v.to_i
@@ -154,6 +160,12 @@ module RubyParserStuff
154
160
  case arg.sexp_type
155
161
  when :args, :block, :array, :call_args then # HACK call_args mismatch
156
162
  result.concat arg.sexp_body
163
+ when :forward_args then
164
+ self.env[:*] = :lvar # TODO: arg_var(p, idFWD_REST) ?
165
+ self.env[:**] = :lvar
166
+ self.env[:&] = :lvar
167
+
168
+ result << arg
157
169
  when :block_arg then
158
170
  result << :"&#{arg.last}"
159
171
  when :shadow then
@@ -305,7 +317,7 @@ module RubyParserStuff
305
317
  end
306
318
  when Symbol then
307
319
  result << arg
308
- when ",", nil then
320
+ when ",", nil, "(" then
309
321
  # ignore
310
322
  else
311
323
  raise "unhandled: #{arg.inspect} in #{args.inspect}"
@@ -493,6 +505,8 @@ module RubyParserStuff
493
505
  str.encode! Encoding::UTF_8
494
506
  break
495
507
  end
508
+ rescue ArgumentError # unknown encoding name
509
+ # do nothing
496
510
  rescue Encoding::InvalidByteSequenceError
497
511
  # do nothing
498
512
  rescue Encoding::UndefinedConversionError
@@ -532,7 +546,7 @@ module RubyParserStuff
532
546
  header.map! { |s| s.force_encoding "ASCII-8BIT" } if has_enc
533
547
 
534
548
  first = header.first || ""
535
- encoding, str = "utf-8", str[3..-1] if first =~ /\A\xEF\xBB\xBF/
549
+ encoding, str = "utf-8", str.b[3..-1] if first =~ /\A\xEF\xBB\xBF/
536
550
 
537
551
  encoding = $1.strip if header.find { |s|
538
552
  s[/^#.*?-\*-.*?coding:\s*([^ ;]+).*?-\*-/, 1] ||
@@ -592,7 +606,9 @@ module RubyParserStuff
592
606
  case ttype
593
607
  when :str then
594
608
  if htype == :str
595
- head.last << tail.last
609
+ a, b = head.last, tail.last
610
+ b = b.dup.force_encoding a.encoding unless Encoding.compatible?(a, b)
611
+ a << b
596
612
  elsif htype == :dstr and head.size == 2 then
597
613
  head.last << tail.last
598
614
  else
@@ -696,6 +712,15 @@ module RubyParserStuff
696
712
  result
697
713
  end
698
714
 
715
+ def new_begin val
716
+ _, lineno, body, _ = val
717
+
718
+ result = body ? s(:begin, body) : s(:nil)
719
+ result.line lineno
720
+
721
+ result
722
+ end
723
+
699
724
  def new_body val
700
725
  body, resbody, elsebody, ensurebody = val
701
726
 
@@ -723,7 +748,10 @@ module RubyParserStuff
723
748
  result = block_append(result, elsebody)
724
749
  end
725
750
 
726
- result = s(:ensure, result, ensurebody).compact.line result.line if ensurebody
751
+ if ensurebody
752
+ lineno = (result || ensurebody).line
753
+ result = s(:ensure, result, ensurebody).compact.line lineno
754
+ end
727
755
 
728
756
  result
729
757
  end
@@ -843,14 +871,17 @@ module RubyParserStuff
843
871
  end
844
872
 
845
873
  def new_defs val
846
- recv, (name, _line), args, body = val[1], val[4], val[6], val[7]
847
- line, _ = val[5]
874
+ _, recv, _, _, name, (_in_def, line), args, body, _ = val
875
+
848
876
  body ||= s(:nil).line line
849
877
 
850
878
  args.line line
851
879
 
852
880
  result = s(:defs, recv, name.to_sym, args)
853
881
 
882
+ # TODO: remove_begin
883
+ # TODO: reduce_nodes
884
+
854
885
  if body then
855
886
  if body.sexp_type == :block then
856
887
  result.push(*body.sexp_body)
@@ -875,7 +906,9 @@ module RubyParserStuff
875
906
  end
876
907
 
877
908
  def new_hash val
878
- s(:hash, *val[2].values).line(val[1])
909
+ _, line, assocs = val
910
+
911
+ s(:hash).line(line).concat assocs.values
879
912
  end
880
913
 
881
914
  def new_if c, t, f
@@ -1134,6 +1167,7 @@ module RubyParserStuff
1134
1167
  def new_string val
1135
1168
  str, = val
1136
1169
  str.force_encoding("UTF-8")
1170
+ # TODO: remove:
1137
1171
  str.force_encoding("ASCII-8BIT") unless str.valid_encoding?
1138
1172
  result = s(:str, str).line lexer.lineno
1139
1173
  self.lexer.fixup_lineno str.count("\n")
@@ -1228,20 +1262,23 @@ module RubyParserStuff
1228
1262
  result
1229
1263
  end
1230
1264
 
1231
- def new_xstring str
1232
- if str then
1233
- case str.sexp_type
1265
+ def new_xstring val
1266
+ _, node = val
1267
+
1268
+ node ||= s(:str, "").line lexer.lineno
1269
+
1270
+ if node then
1271
+ case node.sexp_type
1234
1272
  when :str
1235
- str.sexp_type = :xstr
1273
+ node.sexp_type = :xstr
1236
1274
  when :dstr
1237
- str.sexp_type = :dxstr
1275
+ node.sexp_type = :dxstr
1238
1276
  else
1239
- str = s(:dxstr, "", str).line str.line
1277
+ node = s(:dxstr, "", node).line node.line
1240
1278
  end
1241
- str
1242
- else
1243
- s(:xstr, "")
1244
1279
  end
1280
+
1281
+ node
1245
1282
  end
1246
1283
 
1247
1284
  def new_yield args = nil
@@ -1262,6 +1299,7 @@ module RubyParserStuff
1262
1299
  token = self.lexer.next_token
1263
1300
 
1264
1301
  if token and token.first != RubyLexer::EOF then
1302
+ self.last_token_type = token
1265
1303
  return token
1266
1304
  else
1267
1305
  return [false, false]
@@ -1320,6 +1358,7 @@ module RubyParserStuff
1320
1358
  self.in_single = 0
1321
1359
  self.env.reset
1322
1360
  self.comments.clear
1361
+ self.last_token_type = nil
1323
1362
  end
1324
1363
 
1325
1364
  def ret_args node
@@ -1,7 +1,3 @@
1
- # encoding: US-ASCII
2
-
3
- # TODO: work this out
4
-
5
1
  require "minitest/autorun"
6
2
  require "ruby_lexer"
7
3
  require "ruby_parser"
@@ -84,10 +80,12 @@ class TestRubyLexer < Minitest::Test
84
80
  assert_in_epsilon value, act_value, 0.001, msg
85
81
  when NilClass then
86
82
  assert_nil act_value, msg
83
+ when String then
84
+ assert_equal value, act_value.b.force_encoding(value.encoding), msg
87
85
  else
88
86
  assert_equal value, act_value, msg
89
87
  end
90
- assert_equal state, @lex.lex_state, msg if state
88
+ assert_match state, @lex.lex_state, msg if state
91
89
  assert_equal paren, @lex.paren_nest, msg if paren
92
90
  assert_equal brace, @lex.brace_nest, msg if brace
93
91
  end
@@ -98,7 +96,8 @@ class TestRubyLexer < Minitest::Test
98
96
 
99
97
  def assert_read_escape expected, input
100
98
  @lex.ss.string = input.dup
101
- assert_equal expected, @lex.read_escape.b, input
99
+ enc = expected.encoding
100
+ assert_equal expected, @lex.read_escape.b.force_encoding(enc), input
102
101
  end
103
102
 
104
103
  def assert_read_escape_bad input # TODO: rename refute_read_escape
@@ -146,7 +145,7 @@ class TestRubyLexer < Minitest::Test
146
145
  yield
147
146
 
148
147
  lexer.lex_state = EXPR_ENDARG
149
- assert_next_lexeme :tSTRING_DEND, "}", EXPR_END, 0
148
+ assert_next_lexeme :tSTRING_DEND, "}", EXPR_END|EXPR_ENDARG, 0
150
149
 
151
150
  lexer.lex_strterm = lex_strterm
152
151
  lexer.lex_state = EXPR_BEG
@@ -479,6 +478,22 @@ class TestRubyLexer < Minitest::Test
479
478
  assert_lex3("!~", nil, :tNMATCH, "!~", EXPR_BEG)
480
479
  end
481
480
 
481
+ def test_yylex_bdot2
482
+ assert_lex3("..42",
483
+ nil, # TODO: s(:dot2, nil, s(:lit, 42)),
484
+
485
+ :tBDOT2, "..", EXPR_BEG,
486
+ :tINTEGER, 42, EXPR_END|EXPR_ENDARG)
487
+ end
488
+
489
+ def test_yylex_bdot3
490
+ assert_lex3("...42",
491
+ nil, # TODO: s(:dot2, nil, s(:lit, 42)),
492
+
493
+ :tBDOT3, "...", EXPR_BEG,
494
+ :tINTEGER, 42, EXPR_END|EXPR_ENDARG)
495
+ end
496
+
482
497
  def test_yylex_block_bug_1
483
498
  assert_lex3("a do end",
484
499
  s(:iter, s(:call, nil, :a), 0),
@@ -720,7 +735,7 @@ class TestRubyLexer < Minitest::Test
720
735
 
721
736
  assert_lex3("do 42 end",
722
737
  nil,
723
- :kDO_BLOCK, "do", EXPR_BEG,
738
+ :kDO, "do", EXPR_BEG,
724
739
  :tINTEGER, 42, EXPR_NUM,
725
740
  :kEND, "end", EXPR_END)
726
741
  end
@@ -750,10 +765,26 @@ class TestRubyLexer < Minitest::Test
750
765
  end
751
766
 
752
767
  def test_yylex_dot2
768
+ assert_lex3("1..2",
769
+ s(:lit, 1..2),
770
+
771
+ :tINTEGER, 1, EXPR_END|EXPR_ENDARG,
772
+ :tDOT2, "..", EXPR_BEG,
773
+ :tINTEGER, 2, EXPR_END|EXPR_ENDARG)
774
+
775
+ self.lex_state = EXPR_END|EXPR_ENDARG
753
776
  assert_lex3("..", nil, :tDOT2, "..", EXPR_BEG)
754
777
  end
755
778
 
756
779
  def test_yylex_dot3
780
+ assert_lex3("1...2",
781
+ s(:lit, 1...2),
782
+
783
+ :tINTEGER, 1, EXPR_END|EXPR_ENDARG,
784
+ :tDOT3, "...", EXPR_BEG,
785
+ :tINTEGER, 2, EXPR_END|EXPR_ENDARG)
786
+
787
+ self.lex_state = EXPR_END|EXPR_ENDARG
757
788
  assert_lex3("...", nil, :tDOT3, "...", EXPR_BEG)
758
789
  end
759
790
 
@@ -926,6 +957,14 @@ class TestRubyLexer < Minitest::Test
926
957
  assert_lex3("$1234", nil, :tGVAR, "$1234", EXPR_END)
927
958
  end
928
959
 
960
+ def test_yylex_global_I_have_no_words
961
+ assert_lex3("$x\xE2\x80\x8B = 42", # zero width space?!?!?
962
+ nil,
963
+ :tGVAR, "$x\xE2\x80\x8B", EXPR_END,
964
+ :tEQL, "=", EXPR_BEG,
965
+ :tINTEGER, 42, EXPR_NUM)
966
+ end
967
+
929
968
  def test_yylex_global_other
930
969
  assert_lex3("[$~, $*, $$, $?, $!, $@, $/, $\\, $;, $,, $., $=, $:, $<, $>, $\"]",
931
970
  nil,
@@ -1109,11 +1148,11 @@ class TestRubyLexer < Minitest::Test
1109
1148
  :tEQL, "=", EXPR_BEG,
1110
1149
  :tSTRING_BEG, "\"", EXPR_BEG,
1111
1150
  :tSTRING_CONTENT, "#x a ", EXPR_BEG,
1112
- :tSTRING_DVAR, "\#@", EXPR_BEG,
1151
+ :tSTRING_DVAR, "#", EXPR_BEG,
1113
1152
  :tSTRING_CONTENT, "@a b ", EXPR_BEG, # HUH?
1114
- :tSTRING_DVAR, "\#$", EXPR_BEG,
1153
+ :tSTRING_DVAR, "#", EXPR_BEG,
1115
1154
  :tSTRING_CONTENT, "$b c ", EXPR_BEG, # HUH?
1116
- :tSTRING_DVAR, "\#@", EXPR_BEG,
1155
+ :tSTRING_DVAR, "#", EXPR_BEG,
1117
1156
  :tSTRING_CONTENT, "@@d ", EXPR_BEG, # HUH?
1118
1157
  :tSTRING_DBEG, "\#{", EXPR_BEG,
1119
1158
  :tSTRING_CONTENT, "3} \n", EXPR_BEG,
@@ -2099,6 +2138,10 @@ class TestRubyLexer < Minitest::Test
2099
2138
  assert_lex3("?\\M-\\C-a", nil, :tSTRING, "\M-\C-a", EXPR_END)
2100
2139
  end
2101
2140
 
2141
+ def test_yylex_question_control_escape
2142
+ assert_lex3('?\C-\]', nil, :tSTRING, ?\C-\], EXPR_END)
2143
+ end
2144
+
2102
2145
  def test_yylex_question_ws
2103
2146
  assert_lex3("? ", nil, :tEH, "?", EXPR_BEG)
2104
2147
  assert_lex3("?\n", nil, :tEH, "?", EXPR_BEG)
@@ -2549,11 +2592,7 @@ class TestRubyLexer < Minitest::Test
2549
2592
  end
2550
2593
 
2551
2594
  def test_yylex_string_double_escape_c_backslash
2552
- assert_lex3("\"\\c\\\"",
2553
- nil,
2554
- :tSTRING_BEG, "\"", EXPR_BEG,
2555
- :tSTRING_CONTENT, "\034", EXPR_BEG,
2556
- :tSTRING_END, "\"", EXPR_LIT)
2595
+ refute_lex("\"\\c\\\"", :tSTRING_BEG, '"')
2557
2596
  end
2558
2597
 
2559
2598
  def test_yylex_string_double_escape_c_escape
@@ -2847,6 +2886,15 @@ class TestRubyLexer < Minitest::Test
2847
2886
  :tSTRING_END, '"')
2848
2887
  end
2849
2888
 
2889
+ def test_yylex_string_utf8_bad_encoding_with_escapes
2890
+ str = "\"\\xBADπ\""
2891
+ exp = "\xBADπ".b
2892
+
2893
+ assert_lex(str,
2894
+ s(:str, exp),
2895
+ :tSTRING, exp, EXPR_END)
2896
+ end
2897
+
2850
2898
  def test_yylex_string_utf8_complex_trailing_hex
2851
2899
  chr = [0x3024].pack("U")
2852
2900
  str = "#{chr}abz"
@@ -185,6 +185,57 @@ module TestRubyParserShared
185
185
  assert_syntax_error rb, "else without rescue is useless"
186
186
  end
187
187
 
188
+ def test_begin_ensure_no_bodies
189
+ rb = "begin\nensure\nend"
190
+ pt = s(:ensure, s(:nil).line(2)).line(2)
191
+
192
+ assert_parse rb, pt
193
+ end
194
+
195
+ def test_begin_rescue_ensure_no_bodies
196
+ rb = "begin\nrescue\nensure\nend"
197
+ pt = s(:ensure,
198
+ s(:rescue,
199
+ s(:resbody, s(:array).line(2),
200
+ nil).line(2)
201
+ ).line(2),
202
+ s(:nil).line(3)
203
+ ).line(2)
204
+
205
+ assert_parse rb, pt
206
+ end
207
+
208
+ def test_begin_rescue_else_ensure_bodies
209
+ rb = "begin\n 1\nrescue\n 2\nelse\n 3\nensure\n 4\nend"
210
+ pt = s(:ensure,
211
+ s(:rescue,
212
+ s(:lit, 1).line(2),
213
+ s(:resbody, s(:array).line(3),
214
+ s(:lit, 2).line(4)).line(3),
215
+ s(:lit, 3).line(6)).line(2),
216
+ s(:lit, 4).line(8)).line(2)
217
+
218
+ s(:ensure, s(:rescue, s(:resbody, s(:array), nil)), s(:nil))
219
+
220
+ assert_parse rb, pt
221
+ end
222
+
223
+ def test_begin_rescue_else_ensure_no_bodies
224
+ rb = "begin\n\nrescue\n\nelse\n\nensure\n\nend"
225
+ pt = s(:ensure,
226
+ s(:rescue,
227
+ s(:resbody, s(:array).line(3),
228
+ # TODO: s(:nil)
229
+ nil
230
+ ).line(3),
231
+ ).line(3),
232
+ s(:nil).line(7)).line(3)
233
+
234
+ s(:ensure, s(:rescue, s(:resbody, s(:array), nil)), s(:nil))
235
+
236
+ assert_parse rb, pt
237
+ end
238
+
188
239
  def test_block_append
189
240
  head = s(:args).line 1
190
241
  tail = s(:zsuper).line 2
@@ -290,7 +341,7 @@ module TestRubyParserShared
290
341
  def test_bug190
291
342
  skip "not ready for this yet"
292
343
 
293
- rb = %{%r'\\''}
344
+ rb = %{%r'\\\''} # stupid emacs
294
345
 
295
346
  assert_parse rb, :FUCK
296
347
  assert_syntax_error rb, "FUCK"
@@ -872,6 +923,13 @@ module TestRubyParserShared
872
923
  assert_parse rb, pt
873
924
  end
874
925
 
926
+ def test_heredoc_with_extra_carriage_horrible_mix?
927
+ rb = "<<'eot'\r\nbody\r\neot\n"
928
+ pt = s(:str, "body\r\n")
929
+
930
+ assert_parse rb, pt
931
+ end
932
+
875
933
  def test_heredoc_with_interpolation_and_carriage_return_escapes
876
934
  rb = "<<EOS\nfoo\\r\#@bar\nEOS\n"
877
935
  pt = s(:dstr, "foo\r", s(:evstr, s(:ivar, :@bar)), s(:str, "\n"))
@@ -900,6 +958,13 @@ module TestRubyParserShared
900
958
  assert_parse rb, pt
901
959
  end
902
960
 
961
+ def test_heredoc_with_not_global_interpolation
962
+ rb = "<<-HEREDOC\n#${\nHEREDOC"
963
+ pt = s(:str, "\#${\n")
964
+
965
+ assert_parse rb, pt
966
+ end
967
+
903
968
  def test_i_fucking_hate_line_numbers
904
969
  rb = <<-END.gsub(/^ {6}/, "")
905
970
  if true
@@ -1252,6 +1317,20 @@ module TestRubyParserShared
1252
1317
  end
1253
1318
  end
1254
1319
 
1320
+ def test_magic_encoding_comment__bad
1321
+ rb = "#encoding: bunk\n0"
1322
+ pt = s(:lit, 0)
1323
+
1324
+ assert_parse rb, pt
1325
+ end
1326
+
1327
+ def test_utf8_bom
1328
+ rb = "\xEF\xBB\xBF#!/usr/bin/env ruby -w\np 0\n"
1329
+ pt = s(:call, nil, :p, s(:lit, 0))
1330
+
1331
+ assert_parse rb, pt
1332
+ end
1333
+
1255
1334
  def test_masgn_arg_colon_arg
1256
1335
  rb = "a, b::c = d"
1257
1336
  pt = s(:masgn,
@@ -1383,13 +1462,43 @@ module TestRubyParserShared
1383
1462
  assert_parse rb, pt
1384
1463
  end
1385
1464
 
1386
- def test_op_asgn_primary_colon_identifier
1465
+ def test_op_asgn_primary_colon_identifier1
1387
1466
  rb = "A::b += 1"
1388
1467
  pt = s(:op_asgn, s(:const, :A), s(:lit, 1), :b, :+) # TODO: check? looks wack
1389
1468
 
1390
1469
  assert_parse rb, pt
1391
1470
  end
1392
1471
 
1472
+ def test_lasgn_middle_splat
1473
+ rb = "a = b, *c, d"
1474
+ pt = s(:lasgn, :a,
1475
+ s(:svalue,
1476
+ s(:array,
1477
+ s(:call, nil, :b),
1478
+ s(:splat, s(:call, nil, :c)),
1479
+ s(:call, nil, :d))))
1480
+
1481
+ assert_parse rb, pt
1482
+ end
1483
+
1484
+ def test_op_asgn_primary_colon_const_command_call
1485
+ rb = "A::B *= c d"
1486
+ pt = s(:op_asgn, s(:const, :A),
1487
+ s(:call, nil, :c, s(:call, nil, :d)),
1488
+ :B, :*)
1489
+
1490
+ assert_parse rb, pt
1491
+ end
1492
+
1493
+ def test_op_asgn_primary_colon_identifier_command_call
1494
+ rb = "A::b *= c d"
1495
+ pt = s(:op_asgn, s(:const, :A),
1496
+ s(:call, nil, :c, s(:call, nil, :d)),
1497
+ :b, :*)
1498
+
1499
+ assert_parse rb, pt
1500
+ end
1501
+
1393
1502
  def test_op_asgn_val_dot_ident_command_call
1394
1503
  rb = "a.b ||= c 1"
1395
1504
  pt = s(:op_asgn, s(:call, nil, :a), s(:call, nil, :c, s(:lit, 1)), :b, :"||")
@@ -2971,6 +3080,8 @@ module TestRubyParserShared19Plus
2971
3080
  end
2972
3081
 
2973
3082
  def test_motherfuckin_leading_dots
3083
+ skip if processor.class.version >= 27
3084
+
2974
3085
  rb = "a\n.b"
2975
3086
  pt = s(:call, s(:call, nil, :a), :b)
2976
3087
 
@@ -2978,6 +3089,8 @@ module TestRubyParserShared19Plus
2978
3089
  end
2979
3090
 
2980
3091
  def test_motherfuckin_leading_dots2
3092
+ skip if processor.class.version >= 27
3093
+
2981
3094
  rb = "a\n..b"
2982
3095
 
2983
3096
  assert_parse_error rb, '(string):2 :: parse error on value ".." (tDOT2)'
@@ -3288,6 +3401,76 @@ module TestRubyParserShared20Plus
3288
3401
  assert_parse rb, pt
3289
3402
  end
3290
3403
 
3404
+ def test_call_array_block_call
3405
+ rb = "a [ nil, b do end ]"
3406
+ pt = s(:call, nil, :a,
3407
+ s(:array,
3408
+ s(:nil),
3409
+ s(:iter, s(:call, nil, :b), 0)))
3410
+
3411
+ assert_parse rb, pt
3412
+ end
3413
+
3414
+ def test_block_call_paren_call_block_call
3415
+ rb = "a (b)\nc.d do end"
3416
+ pt = s(:block,
3417
+ s(:call, nil, :a, s(:call, nil, :b)),
3418
+ s(:iter, s(:call, s(:call, nil, :c), :d), 0))
3419
+
3420
+
3421
+ assert_parse rb, pt
3422
+ end
3423
+
3424
+ def test_block_call_defn_call_block_call
3425
+ rb = "a def b(c)\n d\n end\n e.f do end"
3426
+ pt = s(:block,
3427
+ s(:call, nil, :a,
3428
+ s(:defn, :b, s(:args, :c), s(:call, nil, :d))),
3429
+ s(:iter, s(:call, s(:call, nil, :e), :f), 0))
3430
+
3431
+ assert_parse rb, pt
3432
+ end
3433
+
3434
+ def test_call_array_lambda_block_call
3435
+ rb = "a [->() {}] do\nend"
3436
+ pt = s(:iter,
3437
+ s(:call, nil, :a,
3438
+ s(:array, s(:iter, s(:lambda), s(:args)))),
3439
+ 0)
3440
+
3441
+ assert_parse rb, pt
3442
+ end
3443
+
3444
+ def test_call_begin_call_block_call
3445
+ rb = "a begin\nb.c do end\nend"
3446
+ pt = s(:call, nil, :a,
3447
+ s(:iter, s(:call, s(:call, nil, :b), :c), 0))
3448
+
3449
+ assert_parse rb, pt
3450
+ end
3451
+
3452
+ def test_messy_op_asgn_lineno
3453
+ rb = "a (B::C *= d e)"
3454
+ pt = s(:call, nil, :a,
3455
+ s(:op_asgn, s(:const, :B),
3456
+ s(:call, nil, :d, s(:call, nil, :e)),
3457
+ :C,
3458
+ :*)).line(1)
3459
+
3460
+ assert_parse rb, pt
3461
+ end
3462
+
3463
+ def test_str_lit_concat_bad_encodings
3464
+ rb = '"\xE3\xD3\x8B\xE3\x83\xBC\x83\xE3\x83\xE3\x82\xB3\xA3\x82\x99" \
3465
+ "\xE3\x83\xB3\xE3\x83\x8F\xE3\x82\x9A\xC3\xBD;foo@bar.com"'.b
3466
+ pt = s(:str, "\xE3\xD3\x8B\xE3\x83\xBC\x83\xE3\x83\xE3\x82\xB3\xA3\x82\x99\xE3\x83\xB3\xE3\x83\x8F\xE3\x82\x9A\xC3\xBD;foo@bar.com".b)
3467
+
3468
+ assert_parse rb, pt
3469
+
3470
+ sexp = processor.parse rb
3471
+ assert_equal Encoding::ASCII_8BIT, sexp.last.encoding
3472
+ end
3473
+
3291
3474
  def test_block_call_dot_op2_cmd_args_do_block
3292
3475
  rb = "a.b c() do d end.e f do |g| h end"
3293
3476
  pt = s(:iter,
@@ -3588,7 +3771,7 @@ module TestRubyParserShared21Plus
3588
3771
 
3589
3772
  def test_bug162__21plus
3590
3773
  rb = %q(<<E\nfoo\nE\rO)
3591
- emsg = "can't match /E(\n|\\z)/ anywhere in . near line 1: \"\""
3774
+ emsg = "can't match /E(\\r*\\n|\\z)/ anywhere in . near line 1: \"\""
3592
3775
 
3593
3776
  assert_syntax_error rb, emsg
3594
3777
  end
@@ -3738,6 +3921,13 @@ module TestRubyParserShared23Plus
3738
3921
  assert_parse rb, pt
3739
3922
  end
3740
3923
 
3924
+ def test_heredoc__backslash_dos_format
3925
+ rb = "str = <<-XXX\r\nbefore\\\r\nafter\r\nXXX\r\n"
3926
+ pt = s(:lasgn, :str, s(:str, "before\nafter\n"))
3927
+
3928
+ assert_parse rb, pt
3929
+ end
3930
+
3741
3931
  def test_heredoc_squiggly
3742
3932
  rb = "a = <<~\"EOF\"\n x\n y\n z\n EOF\n\n"
3743
3933
  pt = s(:lasgn, :a, s(:str, "x\ny\nz\n"))
@@ -3946,6 +4136,51 @@ module TestRubyParserShared26Plus
3946
4136
  end
3947
4137
  end
3948
4138
 
4139
+ module TestRubyParserShared27Plus
4140
+ include TestRubyParserShared26Plus
4141
+
4142
+ def test_defn_forward_args
4143
+ rb = "def a(...); b(...); end"
4144
+ pt = s(:defn, :a, s(:args, s(:forward_args)),
4145
+ s(:call, nil, :b, s(:forward_args)))
4146
+
4147
+ assert_parse_line rb, pt, 1
4148
+ end
4149
+
4150
+ def test_defn_arg_forward_args
4151
+ rb = "def a(x, ...); b(x, ...); end"
4152
+ pt = s(:defn, :a, s(:args, :x, s(:forward_args)),
4153
+ s(:call, nil, :b, s(:lvar, :x), s(:forward_args)))
4154
+
4155
+ assert_parse_line rb, pt, 1
4156
+ end
4157
+
4158
+ def test_defn_args_forward_args
4159
+ rb = "def a(x, y, z, ...); b(:get, z, ...); end"
4160
+ pt = s(:defn, :a, s(:args, :x, :y, :z, s(:forward_args)),
4161
+ s(:call, nil, :b, s(:lit, :get), s(:lvar, :z),
4162
+ s(:forward_args)))
4163
+
4164
+ assert_parse_line rb, pt, 1
4165
+ end
4166
+
4167
+ def test_call_forward_args_outside_method_definition
4168
+ rb = "b(...)"
4169
+
4170
+ assert_syntax_error rb, "Unexpected ..."
4171
+ end
4172
+
4173
+ def test_call_arg_forward_args_outside_method_definition
4174
+ rb = "b(x, ...)"
4175
+
4176
+ assert_syntax_error rb, "Unexpected ..."
4177
+ end
4178
+ end
4179
+
4180
+ module TestRubyParserShared30Plus
4181
+ include TestRubyParserShared27Plus
4182
+ end
4183
+
3949
4184
  class TestRubyParser < Minitest::Test
3950
4185
  def test_cls_version
3951
4186
  assert_equal 23, RubyParser::V23.version
@@ -4239,7 +4474,46 @@ class TestRubyParserV26 < RubyParserTestCase
4239
4474
 
4240
4475
  assert_parse_line rb, pt, 1
4241
4476
  end
4477
+ end
4478
+
4479
+ class TestRubyParserV27 < RubyParserTestCase
4480
+ include TestRubyParserShared27Plus
4242
4481
 
4482
+ def setup
4483
+ super
4484
+
4485
+ self.processor = RubyParser::V27.new
4486
+ end
4487
+
4488
+ def test_bdot2
4489
+ rb = "..10\n; ..a\n; c"
4490
+ pt = s(:block,
4491
+ s(:dot2, nil, s(:lit, 10).line(1)).line(1),
4492
+ s(:dot2, nil, s(:call, nil, :a).line(2)).line(2),
4493
+ s(:call, nil, :c).line(3)).line(1)
4494
+
4495
+ assert_parse_line rb, pt, 1
4496
+ end
4497
+
4498
+ def test_bdot3
4499
+ rb = "...10\n; ...a\n; c"
4500
+ pt = s(:block,
4501
+ s(:dot3, nil, s(:lit, 10).line(1)).line(1),
4502
+ s(:dot3, nil, s(:call, nil, :a).line(2)).line(2),
4503
+ s(:call, nil, :c).line(3)).line(1)
4504
+
4505
+ assert_parse_line rb, pt, 1
4506
+ end
4507
+ end
4508
+
4509
+ class TestRubyParserV30 < RubyParserTestCase
4510
+ include TestRubyParserShared30Plus
4511
+
4512
+ def setup
4513
+ super
4514
+
4515
+ self.processor = RubyParser::V30.new
4516
+ end
4243
4517
  end
4244
4518
 
4245
4519
  RubyParser::VERSIONS.each do |klass|