ruby_parser 3.14.2 → 3.17.0

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