ruby-next-parser 3.0.0.3 → 3.1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -519,7 +519,8 @@ class Next
519
519
  c_nl_zlen = c_nl | zlen;
520
520
  c_line = any - c_nl_zlen;
521
521
 
522
- c_unicode = c_any - 0x00..0x7f;
522
+ c_ascii = 0x00..0x7f;
523
+ c_unicode = c_any - c_ascii;
523
524
  c_upper = [A-Z];
524
525
  c_lower = [a-z_] | c_unicode;
525
526
  c_alpha = c_lower | c_upper;
@@ -706,6 +707,11 @@ class Next
706
707
 
707
708
  action unescape_char {
708
709
  codepoint = @source_pts[p - 1]
710
+
711
+ if @version >= 30 && (codepoint == 117 || codepoint == 85) # 'u' or 'U'
712
+ diagnostic :fatal, :invalid_escape
713
+ end
714
+
709
715
  if (@escape = ESCAPES[codepoint]).nil?
710
716
  @escape = encode_escape(@source_buffer.slice(p - 1))
711
717
  end
@@ -733,12 +739,14 @@ class Next
733
739
 
734
740
  maybe_escaped_char = (
735
741
  '\\' c_any %unescape_char
742
+ | '\\x' xdigit{1,2} % { @escape = encode_escape(tok(p - 2, p).to_i(16)) } %slash_c_char
736
743
  | ( c_any - [\\] ) %read_post_meta_or_ctrl_char
737
744
  );
738
745
 
739
746
  maybe_escaped_ctrl_char = ( # why?!
740
747
  '\\' c_any %unescape_char %slash_c_char
741
748
  | '?' % { @escape = "\x7f" }
749
+ | '\\x' xdigit{1,2} % { @escape = encode_escape(tok(p - 2, p).to_i(16)) } %slash_c_char
742
750
  | ( c_any - [\\?] ) %read_post_meta_or_ctrl_char %slash_c_char
743
751
  );
744
752
 
@@ -930,6 +938,10 @@ class Next
930
938
  # b"
931
939
  # must be parsed as "ab"
932
940
  current_literal.extend_string(tok.gsub("\\\n".freeze, ''.freeze), @ts, @te)
941
+ elsif current_literal.regexp? && @version >= 31 && %w[c C m M].include?(escaped_char)
942
+ # Ruby >= 3.1 escapes \c- and \m chars, that's the only escape sequence
943
+ # supported by regexes so far, so it needs a separate branch.
944
+ current_literal.extend_string(@escape, @ts, @te)
933
945
  elsif current_literal.regexp?
934
946
  # Regular expressions should include escape sequences in their
935
947
  # escaped form. On the other hand, escaped newlines are removed (in cases like "\\C-\\\n\\M-x")
@@ -1402,7 +1414,7 @@ class Next
1402
1414
  ':'
1403
1415
  => { fhold; fgoto expr_beg; };
1404
1416
 
1405
- '%s' c_any
1417
+ '%s' (c_ascii - [A-Za-z0-9])
1406
1418
  => {
1407
1419
  if version?(23)
1408
1420
  type, delimiter = tok[0..-2], tok[-1].chr
@@ -1431,6 +1443,18 @@ class Next
1431
1443
  => { emit(:tLABEL, tok(@ts, @te - 2), @ts, @te - 1)
1432
1444
  fhold; fnext expr_labelarg; fbreak; };
1433
1445
 
1446
+ '...' c_nl
1447
+ => {
1448
+ if @version >= 31
1449
+ emit(:tBDOT3, '...'.freeze, @ts, @te - 1)
1450
+ emit(:tNL, "\n".freeze, @te - 1, @te)
1451
+ fnext expr_end; fbreak;
1452
+ else
1453
+ p -= 4;
1454
+ fhold; fgoto expr_end;
1455
+ end
1456
+ };
1457
+
1434
1458
  w_space_comment;
1435
1459
 
1436
1460
  c_any
@@ -1754,14 +1778,14 @@ class Next
1754
1778
  };
1755
1779
 
1756
1780
  # %<string>
1757
- '%' ( any - [A-Za-z] )
1781
+ '%' ( c_ascii - [A-Za-z0-9] )
1758
1782
  => {
1759
1783
  type, delimiter = @source_buffer.slice(@ts).chr, tok[-1].chr
1760
1784
  fgoto *push_literal(type, delimiter, @ts);
1761
1785
  };
1762
1786
 
1763
1787
  # %w(we are the people)
1764
- '%' [A-Za-z]+ c_any
1788
+ '%' [A-Za-z] (c_ascii - [A-Za-z0-9])
1765
1789
  => {
1766
1790
  type, delimiter = tok[0..-2], tok[-1].chr
1767
1791
  fgoto *push_literal(type, delimiter, @ts);
@@ -2035,19 +2059,38 @@ class Next
2035
2059
  fnext expr_beg; fbreak;
2036
2060
  };
2037
2061
 
2038
- '...'
2062
+ '...' c_nl?
2039
2063
  => {
2064
+ # Here we scan and conditionally emit "\n":
2065
+ # + if it's there
2066
+ # + and emitted we do nothing
2067
+ # + and not emitted we return `p` to "\n" to process it on the next scan
2068
+ # + if it's not there we do nothing
2069
+ followed_by_nl = @te - 1 == @newline_s
2070
+ nl_emitted = false
2071
+ dots_te = followed_by_nl ? @te - 1 : @te
2072
+
2040
2073
  if @version >= 30
2041
2074
  if @lambda_stack.any? && @lambda_stack.last + 1 == @paren_nest
2042
2075
  # To reject `->(...)` like `->...`
2043
- emit(:tDOT3)
2076
+ emit(:tDOT3, '...'.freeze, @ts, dots_te)
2044
2077
  else
2045
- emit(:tBDOT3)
2078
+ emit(:tBDOT3, '...'.freeze, @ts, dots_te)
2079
+
2080
+ if @version >= 31 && followed_by_nl && @context.in_def_open_args?
2081
+ emit(:tNL, @te - 1, @te)
2082
+ nl_emitted = true
2083
+ end
2046
2084
  end
2047
2085
  elsif @version >= 27
2048
- emit(:tBDOT3)
2086
+ emit(:tBDOT3, '...'.freeze, @ts, dots_te)
2049
2087
  else
2050
- emit(:tDOT3)
2088
+ emit(:tDOT3, '...'.freeze, @ts, dots_te)
2089
+ end
2090
+
2091
+ if followed_by_nl && !nl_emitted
2092
+ # return "\n" to process it on the next scan
2093
+ fhold;
2051
2094
  end
2052
2095
 
2053
2096
  fnext expr_beg; fbreak;
@@ -2526,6 +2569,28 @@ class Next
2526
2569
  end
2527
2570
  };
2528
2571
 
2572
+ c_space* '..'
2573
+ => {
2574
+ emit(:tNL, nil, @newline_s, @newline_s + 1)
2575
+ if @version < 27
2576
+ fhold; fnext line_begin; fbreak;
2577
+ else
2578
+ emit(:tBDOT2)
2579
+ fnext expr_beg; fbreak;
2580
+ end
2581
+ };
2582
+
2583
+ c_space* '...'
2584
+ => {
2585
+ emit(:tNL, nil, @newline_s, @newline_s + 1)
2586
+ if @version < 27
2587
+ fhold; fnext line_begin; fbreak;
2588
+ else
2589
+ emit(:tBDOT3)
2590
+ fnext expr_beg; fbreak;
2591
+ end
2592
+ };
2593
+
2529
2594
  c_space* %{ tm = p } ('.' | '&.')
2530
2595
  => { p = tm - 1; fgoto expr_end; };
2531
2596
 
@@ -5,7 +5,7 @@ require "parser/meta"
5
5
  module Parser
6
6
  # Parser metadata
7
7
  module Meta
8
- NEXT_NODE_TYPES = (NODE_TYPES + %i[meth_ref ipair]).to_set.freeze
8
+ NEXT_NODE_TYPES = (NODE_TYPES + %i[meth_ref]).to_set.freeze
9
9
 
10
10
  remove_const(:NODE_TYPES)
11
11
  const_set(:NODE_TYPES, NEXT_NODE_TYPES)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parser
4
- NEXT_VERSION = "3.0.0.3"
4
+ NEXT_VERSION = "3.1.1.0"
5
5
  end