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.
data/lib/ruby_lexer.rb CHANGED
@@ -25,11 +25,10 @@ class RubyLexer
25
25
 
26
26
  HAS_ENC = "".respond_to? :encoding
27
27
 
28
- IDENT_CHAR = if HAS_ENC then
29
- /[\w\u0080-\u{10ffff}]/u
30
- else
31
- /[\w\x80-\xFF]/n
32
- end
28
+ BTOKENS = {
29
+ ".." => :tBDOT2,
30
+ "..." => :tBDOT3,
31
+ }
33
32
 
34
33
  TOKENS = {
35
34
  "!" => :tBANG,
@@ -137,6 +136,10 @@ class RubyLexer
137
136
  ss.eos?
138
137
  end
139
138
 
139
+ def expr_beg?
140
+ lex_state =~ EXPR_BEG
141
+ end
142
+
140
143
  def expr_dot?
141
144
  lex_state =~ EXPR_DOT
142
145
  end
@@ -162,7 +165,7 @@ class RubyLexer
162
165
  indent = func =~ STR_FUNC_INDENT ? "[ \t]*" : nil
163
166
  expand = func =~ STR_FUNC_EXPAND
164
167
  eol = last_line && last_line.end_with?("\r\n") ? "\r\n" : "\n"
165
- eos_re = /#{indent}#{Regexp.escape eos}(#{eol}|\z)/
168
+ eos_re = /#{indent}#{Regexp.escape eos}(\r*\n|\z)/
166
169
  err_msg = "can't match #{eos_re.inspect} anywhere in "
167
170
 
168
171
  rb_compile_error err_msg if end_of_stream?
@@ -177,10 +180,15 @@ class RubyLexer
177
180
 
178
181
  if expand then
179
182
  case
180
- when scan(/#[$@]/) then
181
- ss.pos -= 1 # FIX omg stupid
183
+ when scan(/#(?=\$(-.|[a-zA-Z_0-9~\*\$\?!@\/\\;,\.=:<>\"\&\`\'+]))/) then
184
+ # TODO: !ISASCII
185
+ # ?! see parser_peek_variable_name
186
+ return :tSTRING_DVAR, matched
187
+ when scan(/#(?=\@\@?[a-zA-Z_])/) then
188
+ # TODO: !ISASCII
182
189
  return :tSTRING_DVAR, matched
183
190
  when scan(/#[{]/) then
191
+ self.command_start = true
184
192
  return :tSTRING_DBEG, matched
185
193
  when scan(/#/) then
186
194
  string_buffer << "#"
@@ -320,6 +328,11 @@ class RubyLexer
320
328
  lpar_beg && lpar_beg == paren_nest
321
329
  end
322
330
 
331
+ def is_local_id id
332
+ # maybe just make this false for now
333
+ self.parser.env[id.to_sym] == :lvar # HACK: this isn't remotely right
334
+ end
335
+
323
336
  def lvar_defined? id
324
337
  # TODO: (dyna_in_block? && dvar_defined?(id)) || local_id?(id)
325
338
  self.parser.env[id.to_sym] == :lvar
@@ -338,9 +351,9 @@ class RubyLexer
338
351
 
339
352
  if scan(/[a-z0-9]{1,2}/i) then # Long-hand (e.g. %Q{}).
340
353
  rb_compile_error "unknown type of %string" if ss.matched_size == 2
341
- c, beg, short_hand = matched, ss.getch, false
354
+ c, beg, short_hand = matched, getch, false
342
355
  else # Short-hand (e.g. %{, %., %!, etc)
343
- c, beg, short_hand = "Q", ss.getch, true
356
+ c, beg, short_hand = "Q", getch, true
344
357
  end
345
358
 
346
359
  if end_of_stream? or c == RubyLexer::EOF or beg == RubyLexer::EOF then
@@ -457,7 +470,7 @@ class RubyLexer
457
470
  if text =~ check then
458
471
  content.gsub(ESC) { unescape $1 }
459
472
  else
460
- content.gsub(/\\\\/, "\\").gsub(/\\'/, "'")
473
+ content.gsub(/\\\\/, "\\").gsub(/\\\'/, "'")
461
474
  end
462
475
  end
463
476
 
@@ -495,16 +508,19 @@ class RubyLexer
495
508
  end
496
509
 
497
510
  def process_brace_close text
498
- # matching compare/parse23.y:8561
499
- cond.lexpop
500
- cmdarg.lexpop
501
-
502
511
  case matched
503
512
  when "}" then
504
513
  self.brace_nest -= 1
505
- self.lex_state = ruby24minus? ? EXPR_ENDARG : EXPR_END
506
-
507
514
  return :tSTRING_DEND, matched if brace_nest < 0
515
+ end
516
+
517
+ # matching compare/parse26.y:8099
518
+ cond.pop
519
+ cmdarg.pop
520
+
521
+ case matched
522
+ when "}" then
523
+ self.lex_state = ruby24minus? ? EXPR_ENDARG : EXPR_END
508
524
  return :tRCURLY, matched
509
525
  when "]" then
510
526
  self.paren_nest -= 1
@@ -573,6 +589,12 @@ class RubyLexer
573
589
  end
574
590
  end
575
591
 
592
+ def process_dots text
593
+ tokens = ruby27plus? && expr_beg? ? BTOKENS : TOKENS
594
+
595
+ result EXPR_BEG, tokens[text], text
596
+ end
597
+
576
598
  def process_float text
577
599
  rb_compile_error "Invalid numeric format" if text =~ /__/
578
600
 
@@ -605,7 +627,7 @@ class RubyLexer
605
627
  end
606
628
 
607
629
  def process_label text
608
- symbol = possibly_escape_string text, /^"/
630
+ symbol = possibly_escape_string text, /^\"/
609
631
 
610
632
  result EXPR_LAB, :tLABEL, [symbol, self.lineno]
611
633
  end
@@ -619,7 +641,7 @@ class RubyLexer
619
641
  text = text[0..-2]
620
642
  end
621
643
 
622
- result EXPR_END, :tSTRING, text[1..-2].gsub(/\\\\/, "\\").gsub(/\\'/, "'")
644
+ result EXPR_END, :tSTRING, text[1..-2].gsub(/\\\\/, "\\").gsub(/\\\'/, "\'")
623
645
  end
624
646
 
625
647
  def process_lchevron text
@@ -791,12 +813,22 @@ class RubyLexer
791
813
  c = if scan(/\\/) then
792
814
  self.read_escape
793
815
  else
794
- ss.getch
816
+ getch
795
817
  end
796
818
 
797
819
  result EXPR_END, :tSTRING, c
798
820
  end
799
821
 
822
+ def process_simple_string text
823
+ replacement = text[1..-2].gsub(ESC) {
824
+ unescape($1).b.force_encoding Encoding::UTF_8
825
+ }
826
+
827
+ replacement = replacement.b unless replacement.valid_encoding?
828
+
829
+ result EXPR_END, :tSTRING, replacement
830
+ end
831
+
800
832
  def process_slash text
801
833
  if is_beg? then
802
834
  string STR_REGEXP
@@ -870,16 +902,16 @@ class RubyLexer
870
902
 
871
903
  if [:tSTRING_END, :tREGEXP_END, :tLABEL_END].include? token_type then
872
904
  self.lex_strterm = nil
873
- self.lex_state = (token_type == :tLABEL_END) ? EXPR_PAR : EXPR_END|EXPR_ENDARG
905
+ self.lex_state = (token_type == :tLABEL_END) ? EXPR_PAR : EXPR_LIT
874
906
  end
875
907
 
876
908
  return token
877
909
  end
878
910
 
879
911
  def process_symbol text
880
- symbol = possibly_escape_string text, /^:"/
912
+ symbol = possibly_escape_string text, /^:\"/ # stupid emacs
881
913
 
882
- result EXPR_END|EXPR_ENDARG, :tSYMBOL, symbol
914
+ result EXPR_LIT, :tSYMBOL, symbol
883
915
  end
884
916
 
885
917
  def process_token text
@@ -928,6 +960,8 @@ class RubyLexer
928
960
  EXPR_END
929
961
  end
930
962
 
963
+ tok_id = :tIDENTIFIER if tok_id == :tCONSTANT && is_local_id(token)
964
+
931
965
  if last_state !~ EXPR_DOT|EXPR_FNAME and
932
966
  (tok_id == :tIDENTIFIER) and # not EXPR_FNAME, not attrasgn
933
967
  lvar_defined?(token) then
@@ -951,18 +985,16 @@ class RubyLexer
951
985
  self.command_start = true if lex_state =~ EXPR_BEG
952
986
 
953
987
  case
954
- when keyword.id0 == :kDO then
988
+ when keyword.id0 == :kDO then # parse26.y line 7591
955
989
  case
956
990
  when lambda_beginning? then
957
991
  self.lpar_beg = nil # lambda_beginning? == FALSE in the body of "-> do ... end"
958
- self.paren_nest -= 1
992
+ self.paren_nest -= 1 # TODO: question this?
959
993
  result lex_state, :kDO_LAMBDA, value
960
994
  when cond.is_in_state then
961
995
  result lex_state, :kDO_COND, value
962
996
  when cmdarg.is_in_state && state != EXPR_CMDARG then
963
997
  result lex_state, :kDO_BLOCK, value
964
- when state =~ EXPR_BEG|EXPR_ENDARG then
965
- result lex_state, :kDO_BLOCK, value
966
998
  else
967
999
  result lex_state, :kDO, value
968
1000
  end
@@ -979,9 +1011,9 @@ class RubyLexer
979
1011
  ss.unscan # put back "_"
980
1012
 
981
1013
  if beginning_of_line? && scan(/\__END__(\r?\n|\Z)/) then
982
- return [RubyLexer::EOF, RubyLexer::EOF]
983
- elsif scan(/\_\w*/) then
984
- return process_token matched
1014
+ [RubyLexer::EOF, RubyLexer::EOF]
1015
+ elsif scan(/#{IDENT_CHAR}+/) then
1016
+ process_token matched
985
1017
  end
986
1018
  end
987
1019
 
@@ -1018,7 +1050,7 @@ class RubyLexer
1018
1050
  when scan(/x([0-9a-fA-F]{1,2})/) then # hex constant
1019
1051
  # TODO: force encode everything to UTF-8?
1020
1052
  ss[1].to_i(16).chr.force_encoding Encoding::UTF_8
1021
- when check(/M-\\[\\MCc]/) then
1053
+ when check(/M-\\./) then
1022
1054
  scan(/M-\\/) # eat it
1023
1055
  c = self.read_escape
1024
1056
  c[0] = (c[0].ord | 0x80).chr
@@ -1032,6 +1064,11 @@ class RubyLexer
1032
1064
  c = self.read_escape
1033
1065
  c[0] = (c[0].ord & 0x9f).chr
1034
1066
  c
1067
+ when check(/(C-|c)\\(?!u|\\)/) then
1068
+ scan(/(C-|c)\\/) # eat it
1069
+ c = read_escape
1070
+ c[0] = (c[0].ord & 0x9f).chr
1071
+ c
1035
1072
  when scan(/C-\?|c\?/) then
1036
1073
  127.chr
1037
1074
  when scan(/(C-|c)(.)/) then
@@ -1040,17 +1077,25 @@ class RubyLexer
1040
1077
  c
1041
1078
  when scan(/^[89]/i) then # bad octal or hex... MRI ignores them :(
1042
1079
  matched
1043
- when scan(/u([0-9a-fA-F]{4}|\{[0-9a-fA-F]{2,6}\})/) then
1044
- [ss[1].delete("{}").to_i(16)].pack("U")
1045
- when scan(/u([0-9a-fA-F]{1,3})/) then
1080
+ when scan(/u(\h{4})/) then
1081
+ [ss[1].to_i(16)].pack("U")
1082
+ when scan(/u(\h{1,3})/) then
1046
1083
  rb_compile_error "Invalid escape character syntax"
1084
+ when scan(/u\{(\h+(?:\s+\h+)*)\}/) then
1085
+ ss[1].split.map { |s| s.to_i(16) }.pack("U*")
1047
1086
  when scan(/[McCx0-9]/) || end_of_stream? then
1048
1087
  rb_compile_error("Invalid escape character syntax")
1049
1088
  else
1050
- ss.getch
1089
+ getch
1051
1090
  end.dup
1052
1091
  end
1053
1092
 
1093
+ def getch
1094
+ c = ss.getch
1095
+ c = ss.getch if c == "\r" && ss.peek(1) == "\n"
1096
+ c
1097
+ end
1098
+
1054
1099
  def regx_options # TODO: rewrite / remove
1055
1100
  good, bad = [], []
1056
1101
 
@@ -1106,6 +1151,10 @@ class RubyLexer
1106
1151
  parser.class.version <= 24
1107
1152
  end
1108
1153
 
1154
+ def ruby27plus?
1155
+ parser.class.version >= 27
1156
+ end
1157
+
1109
1158
  def scan re
1110
1159
  ss.scan re
1111
1160
  end
@@ -1274,10 +1323,12 @@ class RubyLexer
1274
1323
  s
1275
1324
  when /^[McCx0-9]/ then
1276
1325
  rb_compile_error("Invalid escape character syntax")
1277
- when /u([0-9a-fA-F]{4}|\{[0-9a-fA-F]{2,6}\})/ then
1326
+ when /u(\h{4})/ then
1278
1327
  [$1.delete("{}").to_i(16)].pack("U")
1279
- when /u([0-9a-fA-F]{1,3})/ then
1328
+ when /u(\h{1,3})/ then
1280
1329
  rb_compile_error("Invalid escape character syntax")
1330
+ when /u\{(\h+(?:\s+\h+)*)\}/ then
1331
+ $1.split.map { |s| s.to_i(16) }.pack("U*")
1281
1332
  else
1282
1333
  s
1283
1334
  end
@@ -1355,11 +1406,11 @@ class RubyLexer
1355
1406
  # extra fake lex_state names to make things a bit cleaner
1356
1407
 
1357
1408
  EXPR_LAB = EXPR_ARG|EXPR_LABELED
1358
- EXPR_NUM = EXPR_END|EXPR_ENDARG
1409
+ EXPR_LIT = EXPR_END|EXPR_ENDARG
1359
1410
  EXPR_PAR = EXPR_BEG|EXPR_LABEL
1360
1411
  EXPR_PAD = EXPR_BEG|EXPR_LABELED
1361
1412
 
1362
- EXPR_LIT = EXPR_NUM # TODO: migrate to EXPR_LIT
1413
+ EXPR_NUM = EXPR_LIT
1363
1414
 
1364
1415
  expr_names.merge!(EXPR_NONE => "EXPR_NONE",
1365
1416
  EXPR_BEG => "EXPR_BEG",
data/lib/ruby_lexer.rex CHANGED
@@ -6,9 +6,9 @@ class RubyLexer
6
6
 
7
7
  macro
8
8
 
9
- IDENT /^#{IDENT_CHAR}+/o
9
+ IDENT_CHAR /[a-zA-Z0-9_[:^ascii:]]/
10
10
 
11
- ESC /\\((?>[0-7]{1,3}|x[0-9a-fA-F]{1,2}|M-[^\\]|(C-|c)[^\\]|u[0-9a-fA-F]{1,4}|u\{[0-9a-fA-F]+\}|[^0-7xMCc]))/
11
+ ESC /\\((?>[0-7]{1,3}|x\h{1,2}|M-[^\\]|(C-|c)[^\\]|u\h{1,4}|u\{\h+(?:\s+\h+)*\}|[^0-7xMCc]))/
12
12
  SIMPLE_STRING /((#{ESC}|\#(#{ESC}|[^\{\#\@\$\"\\])|[^\"\\\#])*)/o
13
13
  SSTRING /((\\.|[^\'])*)/
14
14
 
@@ -48,7 +48,7 @@ rule
48
48
  | /\![=~]?/ { result :arg_state, TOKENS[text], text }
49
49
 
50
50
  : /\./
51
- | /\.\.\.?/ { result EXPR_BEG, TOKENS[text], text }
51
+ | /\.\.\.?/ process_dots
52
52
  | /\.\d/ { rb_compile_error "no .<digit> floating literal anymore put 0 before dot" }
53
53
  | /\./ { self.lex_state = EXPR_BEG; result EXPR_DOT, :tDOT, "." }
54
54
 
@@ -62,7 +62,7 @@ rule
62
62
  | /\=(?=begin\b)/ { result arg_state, TOKENS[text], text }
63
63
 
64
64
  ruby22_label? /\"#{SIMPLE_STRING}\":/o process_label
65
- /\"(#{SIMPLE_STRING})\"/o { result EXPR_END, :tSTRING, text[1..-2].gsub(ESC) { unescape $1 } }
65
+ /\"(#{SIMPLE_STRING})\"/o process_simple_string
66
66
  /\"/ { string STR_DQUOTE; result nil, :tSTRING_BEG, text }
67
67
 
68
68
  /\@\@?\d/ { rb_compile_error "`#{text}` is not allowed as a variable name" }
@@ -164,13 +164,12 @@ was_label? /\'#{SSTRING}\':?/o process_label_or_string
164
164
  | in_fname? /\$([1-9]\d*)/ process_gvar
165
165
  | /\$([1-9]\d*)/ process_nthref
166
166
  | /\$0/ process_gvar
167
- | /\$[^[:ascii:]]+/ process_gvar
167
+ | /\$#{IDENT_CHAR}+/ process_gvar
168
168
  | /\$\W|\$\z/ process_gvar_oddity
169
- | /\$\w+/ process_gvar
170
169
 
171
170
  /\_/ process_underscore
172
171
 
173
- /#{IDENT}/o process_token
172
+ /#{IDENT_CHAR}+/o process_token
174
173
 
175
174
  /\004|\032|\000|\Z/ { [RubyLexer::EOF, RubyLexer::EOF] }
176
175
 
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
  #--
3
3
  # This file is automatically generated. Do not modify it.
4
- # Generated by: oedipus_lex version 2.5.1.
4
+ # Generated by: oedipus_lex version 2.5.3.
5
5
  # Source: lib/ruby_lexer.rex
6
6
  #++
7
7
 
@@ -16,8 +16,8 @@ class RubyLexer
16
16
  require 'strscan'
17
17
 
18
18
  # :stopdoc:
19
- IDENT = /^#{IDENT_CHAR}+/o
20
- ESC = /\\((?>[0-7]{1,3}|x[0-9a-fA-F]{1,2}|M-[^\\]|(C-|c)[^\\]|u[0-9a-fA-F]{1,4}|u\{[0-9a-fA-F]+\}|[^0-7xMCc]))/
19
+ IDENT_CHAR = /[a-zA-Z0-9_[:^ascii:]]/
20
+ ESC = /\\((?>[0-7]{1,3}|x\h{1,2}|M-[^\\]|(C-|c)[^\\]|u\h{1,4}|u\{\h+(?:\s+\h+)*\}|[^0-7xMCc]))/
21
21
  SIMPLE_STRING = /((#{ESC}|\#(#{ESC}|[^\{\#\@\$\"\\])|[^\"\\\#])*)/o
22
22
  SSTRING = /((\\.|[^\'])*)/
23
23
  INT_DEC = /[+]?(?:(?:[1-9][\d_]*|0)(?!\.\d)(ri|r|i)?\b|0d[0-9_]+)(ri|r|i)?/i
@@ -138,7 +138,7 @@ class RubyLexer
138
138
  when ss.match?(/\./) then
139
139
  case
140
140
  when text = ss.scan(/\.\.\.?/) then
141
- action { result EXPR_BEG, TOKENS[text], text }
141
+ process_dots text
142
142
  when ss.skip(/\.\d/) then
143
143
  action { rb_compile_error "no .<digit> floating literal anymore put 0 before dot" }
144
144
  when ss.skip(/\./) then
@@ -160,7 +160,7 @@ class RubyLexer
160
160
  when ruby22_label? && (text = ss.scan(/\"#{SIMPLE_STRING}\":/o)) then
161
161
  process_label text
162
162
  when text = ss.scan(/\"(#{SIMPLE_STRING})\"/o) then
163
- action { result EXPR_END, :tSTRING, text[1..-2].gsub(ESC) { unescape $1 } }
163
+ process_simple_string text
164
164
  when text = ss.scan(/\"/) then
165
165
  action { string STR_DQUOTE; result nil, :tSTRING_BEG, text }
166
166
  when text = ss.scan(/\@\@?\d/) then
@@ -328,16 +328,14 @@ class RubyLexer
328
328
  process_nthref text
329
329
  when text = ss.scan(/\$0/) then
330
330
  process_gvar text
331
- when text = ss.scan(/\$[^[:ascii:]]+/) then
331
+ when text = ss.scan(/\$#{IDENT_CHAR}+/) then
332
332
  process_gvar text
333
333
  when text = ss.scan(/\$\W|\$\z/) then
334
334
  process_gvar_oddity text
335
- when text = ss.scan(/\$\w+/) then
336
- process_gvar text
337
335
  end # group /\$/
338
336
  when text = ss.scan(/\_/) then
339
337
  process_underscore text
340
- when text = ss.scan(/#{IDENT}/o) then
338
+ when text = ss.scan(/#{IDENT_CHAR}+/o) then
341
339
  process_token text
342
340
  when ss.skip(/\004|\032|\000|\Z/) then
343
341
  action { [RubyLexer::EOF, RubyLexer::EOF] }
data/lib/ruby_parser.rb CHANGED
@@ -78,10 +78,14 @@ require "ruby23_parser"
78
78
  require "ruby24_parser"
79
79
  require "ruby25_parser"
80
80
  require "ruby26_parser"
81
+ require "ruby27_parser"
82
+ require "ruby30_parser"
81
83
 
82
84
  class RubyParser # HACK
83
85
  VERSIONS.clear # also a HACK caused by racc namespace issues
84
86
 
87
+ class V30 < ::Ruby30Parser; end
88
+ class V27 < ::Ruby27Parser; end
85
89
  class V26 < ::Ruby26Parser; end
86
90
  class V25 < ::Ruby25Parser; end
87
91
  class V24 < ::Ruby24Parser; end
data/lib/ruby_parser.yy CHANGED
@@ -14,6 +14,10 @@ class Ruby24Parser
14
14
  class Ruby25Parser
15
15
  #elif V == 26
16
16
  class Ruby26Parser
17
+ #elif V == 27
18
+ class Ruby27Parser
19
+ #elif V == 30
20
+ class Ruby30Parser
17
21
  #else
18
22
  fail "version not specified or supported on code generation"
19
23
  #endif
@@ -44,6 +48,9 @@ token kCLASS kMODULE kDEF kUNDEF kBEGIN kRESCUE kENSURE kEND kIF kUNLESS
44
48
  #if V >= 23
45
49
  tLONELY
46
50
  #endif
51
+ #if V >= 26
52
+ tBDOT2 tBDOT3
53
+ #endif
47
54
 
48
55
  preclow
49
56
  nonassoc tLOWEST
@@ -55,7 +62,7 @@ preclow
55
62
  right tEQL tOP_ASGN
56
63
  left kRESCUE_MOD
57
64
  right tEH tCOLON
58
- nonassoc tDOT2 tDOT3
65
+ nonassoc tDOT2 tDOT3 tBDOT2 tBDOT3
59
66
  left tOROP
60
67
  left tANDOP
61
68
  nonassoc tCMP tEQ tEQQ tNEQ tMATCH tNMATCH
@@ -78,6 +85,9 @@ rule
78
85
  top_compstmt
79
86
  {
80
87
  result = new_compstmt val
88
+
89
+ lexer.cond.pop # local_pop
90
+ lexer.cmdarg.pop
81
91
  }
82
92
 
83
93
  top_compstmt: top_stmts opt_terms
@@ -286,13 +296,15 @@ rule
286
296
  }
287
297
  | primary_value tCOLON2 tCONSTANT tOP_ASGN command_rhs
288
298
  {
289
- result = s(:op_asgn, val[0], val[4], val[2], val[3])
290
- debug20 4, val, result
299
+ lhs1, _, lhs2, op, rhs = val
300
+
301
+ result = s(:op_asgn, lhs1, rhs, lhs2.to_sym, op.to_sym)
291
302
  }
292
303
  | primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_rhs
293
304
  {
294
- result = s(:op_asgn, val[0], val[4], val[2], val[3])
295
- debug20 5, val, result
305
+ lhs1, _, lhs2, op, rhs = val
306
+
307
+ result = s(:op_asgn, lhs1, rhs, lhs2.to_sym, op.to_sym)
296
308
  }
297
309
  | backref tOP_ASGN command_rhs
298
310
  {
@@ -852,6 +864,24 @@ rule
852
864
  result = s(:dot3, v1, v2).line v1.line
853
865
  }
854
866
  #endif
867
+
868
+ #if V >= 27
869
+ | tBDOT2 arg
870
+ {
871
+ _, v2, = val
872
+ v1 = nil
873
+
874
+ result = s(:dot2, v1, v2).line v2.line
875
+ }
876
+ | tBDOT3 arg
877
+ {
878
+ _, v2 = val
879
+ v1 = nil
880
+
881
+ result = s(:dot3, v1, v2).line v2.line
882
+ }
883
+ #endif
884
+
855
885
  | arg tPLUS arg
856
886
  {
857
887
  result = new_call val[0], :+, argl(val[2])
@@ -1036,6 +1066,26 @@ rule
1036
1066
  _, args, _ = val
1037
1067
  result = args
1038
1068
  }
1069
+ #if V >= 27
1070
+ | tLPAREN2 args tCOMMA args_forward rparen
1071
+ {
1072
+ yyerror "Unexpected ..." unless
1073
+ self.lexer.is_local_id(:"*") &&
1074
+ self.lexer.is_local_id(:"**") &&
1075
+ self.lexer.is_local_id(:"&")
1076
+
1077
+ result = call_args val
1078
+ }
1079
+ | tLPAREN2 args_forward rparen
1080
+ {
1081
+ yyerror "Unexpected ..." unless
1082
+ self.lexer.is_local_id(:"*") &&
1083
+ self.lexer.is_local_id(:"**") &&
1084
+ self.lexer.is_local_id(:"&")
1085
+
1086
+ result = call_args val
1087
+ }
1088
+ #endif
1039
1089
 
1040
1090
  opt_paren_args: none
1041
1091
  | paren_args
@@ -1078,12 +1128,39 @@ rule
1078
1128
  }
1079
1129
 
1080
1130
  command_args: {
1081
- result = lexer.cmdarg.store true
1131
+ # parse26.y line 2200
1132
+
1133
+ # If call_args starts with a open paren '(' or
1134
+ # '[', look-ahead reading of the letters calls
1135
+ # CMDARG_PUSH(0), but the push must be done
1136
+ # after CMDARG_PUSH(1). So this code makes them
1137
+ # consistent by first cancelling the premature
1138
+ # CMDARG_PUSH(0), doing CMDARG_PUSH(1), and
1139
+ # finally redoing CMDARG_PUSH(0).
1140
+
1141
+ result = yychar = self.last_token_type.first
1142
+ lookahead = [:tLPAREN, :tLPAREN_ARG, :tLPAREN2, :tLBRACK, :tLBRACK2].include?(yychar)
1143
+ lexer.cmdarg.pop if lookahead
1144
+ lexer.cmdarg.push true
1145
+ lexer.cmdarg.push false if lookahead
1082
1146
  }
1083
1147
  call_args
1084
1148
  {
1085
- lexer.cmdarg.restore val[0]
1086
- result = val[1]
1149
+ yychar, args = val
1150
+
1151
+ # call_args can be followed by tLBRACE_ARG (that
1152
+ # does CMDARG_PUSH(0) in the lexer) but the push
1153
+ # must be done after CMDARG_POP() in the parser.
1154
+ # So this code does CMDARG_POP() to pop 0 pushed
1155
+ # by tLBRACE_ARG, CMDARG_POP() to pop 1 pushed
1156
+ # by command_args, and CMDARG_PUSH(0) to restore
1157
+ # back the flag set by tLBRACE_ARG.
1158
+
1159
+ lookahead = [:tLBRACE_ARG].include?(yychar)
1160
+ lexer.cmdarg.pop if lookahead
1161
+ lexer.cmdarg.pop
1162
+ lexer.cmdarg.push false if lookahead
1163
+ result = args
1087
1164
  }
1088
1165
 
1089
1166
  block_arg: tAMPER arg_value
@@ -1101,8 +1178,9 @@ rule
1101
1178
  args: arg_value
1102
1179
  {
1103
1180
  arg, = val
1181
+ lineno = arg.line || lexer.lineno # HACK
1104
1182
 
1105
- result = s(:array, arg).line arg.line
1183
+ result = s(:array, arg).line lineno
1106
1184
  }
1107
1185
  | tSTAR arg_value
1108
1186
  {
@@ -1114,9 +1192,11 @@ rule
1114
1192
  args, _, id = val
1115
1193
  result = self.list_append args, id
1116
1194
  }
1117
- | args tCOMMA tSTAR { result = lexer.lineno } arg_value
1195
+ | args tCOMMA tSTAR arg_value
1118
1196
  {
1119
- args, _, _, line, id = val
1197
+ # TODO: the line number from tSTAR has been dropped
1198
+ args, _, _, id = val
1199
+ line = lexer.lineno
1120
1200
  result = self.list_append args, s(:splat, id).line(line)
1121
1201
  }
1122
1202
 
@@ -1137,7 +1217,6 @@ rule
1137
1217
  }
1138
1218
  | args tCOMMA tSTAR arg_value
1139
1219
  {
1140
- # FIX: bad shift/reduce conflict with rhs' comma star prod
1141
1220
  # TODO: make all tXXXX terminals include lexer.lineno
1142
1221
  arg, _, _, splat = val
1143
1222
  result = self.arg_concat arg, splat
@@ -1165,21 +1244,13 @@ rule
1165
1244
  }
1166
1245
  | k_begin
1167
1246
  {
1247
+ lexer.cmdarg.push false
1168
1248
  result = self.lexer.lineno
1169
- # TODO:
1170
- # $<val>1 = cmdarg_stack;
1171
- # CMDARG_SET(0);
1172
1249
  }
1173
1250
  bodystmt k_end
1174
1251
  {
1175
- # TODO: CMDARG_SET($<val>1);
1176
- unless val[2] then
1177
- result = s(:nil)
1178
- else
1179
- result = s(:begin, val[2])
1180
- end
1181
-
1182
- result.line = val[1]
1252
+ lexer.cmdarg.pop
1253
+ result = new_begin val
1183
1254
  }
1184
1255
  | tLPAREN_ARG
1185
1256
  {
@@ -1192,18 +1263,14 @@ rule
1192
1263
  result = s(:begin).line line
1193
1264
  }
1194
1265
  | tLPAREN_ARG
1195
- {
1196
- result = lexer.cmdarg.store false
1197
- }
1198
1266
  stmt
1199
1267
  {
1200
1268
  lexer.lex_state = EXPR_ENDARG
1201
1269
  }
1202
1270
  rparen
1203
1271
  {
1204
- _, cmdarg, stmt, _, _, = val
1205
- warning "(...) interpreted as grouped expression"
1206
- lexer.cmdarg.restore cmdarg
1272
+ _, stmt, _, _, = val
1273
+ # warning "(...) interpreted as grouped expression"
1207
1274
  result = stmt
1208
1275
  }
1209
1276
  | tLPAREN compstmt tRPAREN
@@ -1386,48 +1453,61 @@ rule
1386
1453
  }
1387
1454
  | k_def fname
1388
1455
  {
1389
- result = [self.in_def, self.lexer.cmdarg.stack.dup]
1456
+ result = self.in_def
1390
1457
 
1391
- self.comments.push self.lexer.comments
1392
- self.in_def = true
1458
+ self.in_def = true # group = local_push
1393
1459
  self.env.extend
1394
- # TODO: local->cmdargs = cmdarg_stack;
1395
- # TODO: port local_push_gen and local_pop_gen
1396
- lexer.cmdarg.stack.replace [false]
1460
+ lexer.cmdarg.push false
1461
+ lexer.cond.push false
1462
+
1463
+ self.comments.push self.lexer.comments
1397
1464
  }
1398
1465
  f_arglist bodystmt { result = lexer.lineno } k_end
1399
1466
  {
1400
- in_def, cmdarg = val[2]
1467
+ in_def = val[2]
1401
1468
 
1402
1469
  result = new_defn val
1403
1470
 
1404
- lexer.cmdarg.stack.replace cmdarg
1471
+ lexer.cond.pop # group = local_pop
1472
+ lexer.cmdarg.pop
1405
1473
  self.env.unextend
1406
1474
  self.in_def = in_def
1475
+
1407
1476
  self.lexer.comments # we don't care about comments in the body
1408
1477
  }
1409
1478
  | k_def singleton dot_or_colon
1410
1479
  {
1411
- self.comments.push self.lexer.comments
1412
1480
  lexer.lex_state = EXPR_FNAME
1413
1481
  }
1414
1482
  fname
1415
1483
  {
1416
- self.in_single += 1
1484
+ result = [self.in_def, lexer.lineno]
1485
+
1486
+ self.in_single += 1 # TODO: remove?
1487
+
1488
+ self.in_def = true # local_push
1417
1489
  self.env.extend
1418
- lexer.lex_state = EXPR_ENDFN # force for args
1419
- result = [lexer.lineno, self.lexer.cmdarg.stack.dup]
1420
- lexer.cmdarg.stack.replace [false]
1490
+ lexer.cmdarg.push false
1491
+ lexer.cond.push false
1492
+
1493
+ lexer.lex_state = EXPR_ENDFN|EXPR_LABEL
1494
+ self.comments.push self.lexer.comments
1421
1495
  }
1422
1496
  f_arglist bodystmt k_end
1423
1497
  {
1424
- _, cmdarg = val[5]
1425
- result = new_defs val
1498
+ _, _recv, _, _, _name, (in_def, _lineno), _args, _body, _ = val
1426
1499
 
1427
- lexer.cmdarg.stack.replace cmdarg
1500
+ result = new_defs val
1428
1501
 
1502
+ lexer.cond.pop # group = local_pop
1503
+ lexer.cmdarg.pop
1429
1504
  self.env.unextend
1505
+ self.in_def = in_def
1506
+
1430
1507
  self.in_single -= 1
1508
+
1509
+ # TODO: restore cur_arg ? what's cur_arg?
1510
+
1431
1511
  self.lexer.comments # we don't care about comments in the body
1432
1512
  }
1433
1513
  | kBREAK
@@ -1712,20 +1792,19 @@ opt_block_args_tail: tCOMMA block_args_tail
1712
1792
  }
1713
1793
  f_larglist
1714
1794
  {
1715
- result = lexer.cmdarg.store(false)
1795
+ lexer.cmdarg.push false
1716
1796
  }
1717
1797
  lambda_body
1718
1798
  {
1719
- (line, lpar), args, cmdarg, body = val
1799
+ (line, lpar), args, _cmdarg, body = val
1720
1800
  lexer.lpar_beg = lpar
1721
1801
 
1722
- lexer.cmdarg.restore cmdarg
1723
- lexer.cmdarg.lexpop
1802
+ lexer.cmdarg.pop
1724
1803
 
1725
1804
  call = s(:lambda).line line
1726
1805
  result = new_iter call, args, body
1727
1806
  result.line = line
1728
- self.env.unextend
1807
+ self.env.unextend # TODO: dynapush & dynapop
1729
1808
  }
1730
1809
 
1731
1810
  f_larglist: tLPAREN2 f_args opt_bv_decl rparen
@@ -1878,7 +1957,7 @@ opt_block_args_tail: tCOMMA block_args_tail
1878
1957
  }
1879
1958
 
1880
1959
  do_body: { self.env.extend :dynamic; result = self.lexer.lineno }
1881
- { result = lexer.cmdarg.store(false) }
1960
+ { lexer.cmdarg.push false }
1882
1961
  opt_block_param
1883
1962
  #if V >= 25
1884
1963
  bodystmt
@@ -1886,11 +1965,11 @@ opt_block_args_tail: tCOMMA block_args_tail
1886
1965
  compstmt
1887
1966
  #endif
1888
1967
  {
1889
- line, cmdarg, param, cmpstmt = val
1968
+ line, _cmdarg, param, cmpstmt = val
1890
1969
 
1891
1970
  result = new_do_body param, cmpstmt, line
1971
+ lexer.cmdarg.pop
1892
1972
  self.env.unextend
1893
- lexer.cmdarg.restore cmdarg
1894
1973
  }
1895
1974
 
1896
1975
  case_body: k_when
@@ -1990,7 +2069,7 @@ opt_block_args_tail: tCOMMA block_args_tail
1990
2069
 
1991
2070
  xstring: tXSTRING_BEG xstring_contents tSTRING_END
1992
2071
  {
1993
- result = new_xstring val[1]
2072
+ result = new_xstring val
1994
2073
  # TODO: dedent?!?! SERIOUSLY?!?
1995
2074
  }
1996
2075
 
@@ -2132,12 +2211,13 @@ regexp_contents: none
2132
2211
  result = [lexer.lex_strterm,
2133
2212
  lexer.brace_nest,
2134
2213
  lexer.string_nest, # TODO: remove
2135
- lexer.cond.store,
2136
- lexer.cmdarg.store,
2137
2214
  lexer.lex_state,
2138
2215
  lexer.lineno,
2139
2216
  ]
2140
2217
 
2218
+ lexer.cmdarg.push false
2219
+ lexer.cond.push false
2220
+
2141
2221
  lexer.lex_strterm = nil
2142
2222
  lexer.brace_nest = 0
2143
2223
  lexer.string_nest = 0
@@ -2149,14 +2229,15 @@ regexp_contents: none
2149
2229
  {
2150
2230
  _, memo, stmt, _ = val
2151
2231
 
2152
- lex_strterm, brace_nest, string_nest, oldcond, oldcmdarg, oldlex_state, line = memo
2232
+ lex_strterm, brace_nest, string_nest, oldlex_state, line = memo
2233
+ # TODO: heredoc_indent
2153
2234
 
2154
2235
  lexer.lex_strterm = lex_strterm
2155
2236
  lexer.brace_nest = brace_nest
2156
2237
  lexer.string_nest = string_nest
2157
2238
 
2158
- lexer.cond.restore oldcond
2159
- lexer.cmdarg.restore oldcmdarg
2239
+ lexer.cmdarg.pop
2240
+ lexer.cond.pop
2160
2241
 
2161
2242
  lexer.lex_state = oldlex_state
2162
2243
 
@@ -2305,6 +2386,22 @@ keyword_variable: kNIL { result = s(:nil).line lexer.lineno }
2305
2386
  self.lexer.lex_state = EXPR_BEG
2306
2387
  self.lexer.command_start = true
2307
2388
  }
2389
+ #if V >= 27
2390
+ | tLPAREN2 f_arg tCOMMA args_forward rparen
2391
+ {
2392
+ result = args val
2393
+
2394
+ self.lexer.lex_state = EXPR_BEG
2395
+ self.lexer.command_start = true
2396
+ }
2397
+ | tLPAREN2 args_forward rparen
2398
+ {
2399
+ result = args val
2400
+
2401
+ self.lexer.lex_state = EXPR_BEG
2402
+ self.lexer.command_start = true
2403
+ }
2404
+ #endif
2308
2405
  | {
2309
2406
  result = self.in_kwarg
2310
2407
  self.in_kwarg = true
@@ -2404,6 +2501,13 @@ keyword_variable: kNIL { result = s(:nil).line lexer.lineno }
2404
2501
  result = args val
2405
2502
  }
2406
2503
 
2504
+ #if V >= 27
2505
+ args_forward: tBDOT3
2506
+ {
2507
+ result = s(:forward_args).line lexer.lineno
2508
+ }
2509
+ #endif
2510
+
2407
2511
  f_bad_arg: tCONSTANT
2408
2512
  {
2409
2513
  yyerror "formal argument cannot be a constant"
@@ -2552,6 +2656,7 @@ keyword_variable: kNIL { result = s(:nil).line lexer.lineno }
2552
2656
  | kwrest_mark
2553
2657
  {
2554
2658
  result = :"**"
2659
+ self.env[result] = :lvar
2555
2660
  }
2556
2661
 
2557
2662
  #if V == 20