ruby_parser 3.0.0 → 3.19.1

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 (58) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/.autotest +36 -19
  4. data/History.rdoc +1297 -0
  5. data/Manifest.txt +35 -7
  6. data/{README.txt → README.rdoc} +44 -14
  7. data/Rakefile +308 -110
  8. data/bin/ruby_parse +3 -1
  9. data/bin/ruby_parse_extract_error +36 -16
  10. data/compare/normalize.rb +218 -0
  11. data/debugging.md +190 -0
  12. data/gauntlet.md +107 -0
  13. data/lib/.document +1 -0
  14. data/lib/rp_extensions.rb +53 -0
  15. data/lib/rp_stringscanner.rb +33 -0
  16. data/lib/ruby20_parser.rb +10973 -0
  17. data/lib/ruby20_parser.y +2683 -0
  18. data/lib/ruby21_parser.rb +10980 -0
  19. data/lib/ruby21_parser.y +2700 -0
  20. data/lib/ruby22_parser.rb +11123 -0
  21. data/lib/ruby22_parser.y +2711 -0
  22. data/lib/ruby23_parser.rb +11132 -0
  23. data/lib/ruby23_parser.y +2713 -0
  24. data/lib/ruby24_parser.rb +11231 -0
  25. data/lib/ruby24_parser.y +2721 -0
  26. data/lib/ruby25_parser.rb +11231 -0
  27. data/lib/ruby25_parser.y +2721 -0
  28. data/lib/ruby26_parser.rb +11253 -0
  29. data/lib/ruby26_parser.y +2736 -0
  30. data/lib/ruby27_parser.rb +12980 -0
  31. data/lib/ruby27_parser.y +3324 -0
  32. data/lib/ruby30_parser.rb +13242 -0
  33. data/lib/ruby30_parser.y +3447 -0
  34. data/lib/ruby31_parser.rb +13622 -0
  35. data/lib/ruby31_parser.y +3481 -0
  36. data/lib/ruby3_parser.yy +3536 -0
  37. data/lib/ruby_lexer.rb +933 -1232
  38. data/lib/ruby_lexer.rex +185 -0
  39. data/lib/ruby_lexer.rex.rb +399 -0
  40. data/lib/ruby_lexer_strings.rb +638 -0
  41. data/lib/ruby_parser.rb +97 -3
  42. data/lib/ruby_parser.yy +3465 -0
  43. data/lib/ruby_parser_extras.rb +1216 -687
  44. data/test/test_ruby_lexer.rb +2249 -1092
  45. data/test/test_ruby_parser.rb +5156 -975
  46. data/test/test_ruby_parser_extras.rb +47 -77
  47. data/tools/munge.rb +250 -0
  48. data/tools/ripper.rb +44 -0
  49. data.tar.gz.sig +1 -1
  50. metadata +200 -155
  51. metadata.gz.sig +0 -0
  52. data/.gemtest +0 -0
  53. data/History.txt +0 -482
  54. data/lib/gauntlet_rubyparser.rb +0 -120
  55. data/lib/ruby18_parser.rb +0 -5747
  56. data/lib/ruby18_parser.y +0 -1873
  57. data/lib/ruby19_parser.rb +0 -6110
  58. data/lib/ruby19_parser.y +0 -2078
@@ -0,0 +1,185 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # lexical scanner definition for ruby
4
+
5
+ class RubyLexer
6
+
7
+ option
8
+
9
+ lineno
10
+ column
11
+
12
+ macro
13
+
14
+ IDENT_CHAR /[a-zA-Z0-9_[:^ascii:]]/
15
+
16
+ ESC /\\((?>[0-7]{1,3}|x\h{1,2}|M-[^\\]|(C-|c)[^\\]|u\h{1,4}|u\{\h+(?:\s+\h+)*\}|[^0-7xMCc]))/
17
+ SIMPLE_STRING /((#{ESC}|\#(#{ESC}|[^\{\#\@\$\"\\])|[^\"\\\#])*)/o
18
+ SSTRING /((\\.|[^\'])*)/
19
+
20
+ INT_DEC /[+]?(?:(?:[1-9][\d_]*|0)(?!\.\d)(ri|r|i)?\b|0d[0-9_]+)(ri|r|i)?/i
21
+ INT_HEX /[+]?0x[a-f0-9_]+(ri|r|i)?/i
22
+ INT_BIN /[+]?0b[01_]+(ri|r|i)?/i
23
+ INT_OCT /[+]?0o?[0-7_]+(ri|r|i)?|0o(ri|r|i)?/i
24
+ FLOAT /[+]?\d[\d_]*\.[\d_]+(e[+-]?[\d_]+)?(?:(ri|r|i)\b)?|[+]?[\d_]+e[+-]?[\d_]+(?:(ri|r|i)\b)?/i
25
+ INT_DEC2 /[+]?\d[0-9_]*(?![e])((ri|r|i)\b)?/i
26
+
27
+ NUM_BAD /[+]?0[xbd]\b/i
28
+ INT_OCT_BAD /[+]?0o?[0-7_]*[89]/i
29
+ FLOAT_BAD /[+]?\d[\d_]*_(e|\.)/i
30
+
31
+ start
32
+
33
+ maybe_pop_stack
34
+ return process_string_or_heredoc if lex_strterm
35
+
36
+ self.cmd_state = self.command_start
37
+ self.command_start = false
38
+ self.space_seen = false # TODO: rename token_seen?
39
+ self.last_state = lex_state
40
+
41
+ rule
42
+
43
+ # [:state] pattern [actions]
44
+
45
+ # \s - \n + \v
46
+ /[\ \t\r\f\v]+/ { self.space_seen = true; next }
47
+
48
+ /\n|\#/ process_newline_or_comment
49
+
50
+ /[\]\)\}]/ process_brace_close
51
+
52
+ : /\!/
53
+ | is_after_operator? /\!\@/ { result EXPR_ARG, TOKENS[text], text }
54
+ | /\![=~]?/ { result :arg_state, TOKENS[text], text }
55
+
56
+ : /\./
57
+ | /\.\.\.?/ process_dots
58
+ | /\.\d/ { rb_compile_error "no .<digit> floating literal anymore put 0 before dot" }
59
+ | /\./ { self.lex_state = EXPR_BEG; result EXPR_DOT, :tDOT, "." }
60
+
61
+ /\(/ process_paren
62
+
63
+ /\,/ { result EXPR_PAR, TOKENS[text], text }
64
+
65
+ : /=/
66
+ | /\=\=\=|\=\=|\=~|\=>|\=(?!begin\b)/ { result arg_state, TOKENS[text], text }
67
+ | bol? /\=begin(?=\s)/ process_begin
68
+ | /\=(?=begin\b)/ { result arg_state, TOKENS[text], text }
69
+
70
+ ruby22_label? /\"#{SIMPLE_STRING}\":/o process_label
71
+ /\"(#{SIMPLE_STRING})\"/o process_simple_string
72
+ /\"/ { string STR_DQUOTE, '"'; result nil, :tSTRING_BEG, text }
73
+
74
+ /\@\@?\d/ { rb_compile_error "`#{text}` is not allowed as a variable name" }
75
+ /\@\@?#{IDENT_CHAR}+/o process_ivar
76
+
77
+ : /:/
78
+ | not_end? /:([a-zA-Z_]#{IDENT_CHAR}*(?:[?]|[!](?!=)|=(?==>)|=(?![=>]))?)/o process_symbol
79
+ | not_end? /\:\"(#{SIMPLE_STRING})\"/o process_symbol
80
+ | not_end? /\:\'(#{SSTRING})\'/o process_symbol
81
+ | /\:\:/ process_colon2
82
+ | /\:/ process_colon1
83
+
84
+ /->/ { result EXPR_ENDFN, :tLAMBDA, text }
85
+
86
+ /[+-]/ process_plus_minus
87
+
88
+ : /[+\d]/
89
+ | /#{NUM_BAD}/o { rb_compile_error "Invalid numeric format" }
90
+ | /#{INT_DEC}/o { int_with_base 10 }
91
+ | /#{INT_HEX}/o { int_with_base 16 }
92
+ | /#{INT_BIN}/o { int_with_base 2 }
93
+ | /#{INT_OCT_BAD}/o { rb_compile_error "Illegal octal digit." }
94
+ | /#{INT_OCT}/o { int_with_base 8 }
95
+ | /#{FLOAT_BAD}/o { rb_compile_error "Trailing '_' in number." }
96
+ | /#{FLOAT}/o process_float
97
+ | /#{INT_DEC2}/o { int_with_base 10 }
98
+ | /[0-9]/ { rb_compile_error "Bad number format" }
99
+
100
+ /\[/ process_square_bracket
101
+
102
+ was_label? /\'#{SSTRING}\':?/o process_label_or_string
103
+ /\'/ { string STR_SQUOTE, "'"; result nil, :tSTRING_BEG, text }
104
+
105
+ : /\|/
106
+ | /\|\|\=/ { result EXPR_BEG, :tOP_ASGN, "||" }
107
+ | /\|\|/ { result EXPR_BEG, :tOROP, "||" }
108
+ | /\|\=/ { result EXPR_BEG, :tOP_ASGN, "|" }
109
+ | /\|/ { state = is_after_operator? ? EXPR_ARG : EXPR_PAR; result state, :tPIPE, "|" }
110
+
111
+ /\{/ process_brace_open
112
+
113
+ : /\*/
114
+ | /\*\*=/ { result EXPR_BEG, :tOP_ASGN, "**" }
115
+ | /\*\*/ { result :arg_state, space_vs_beginning(:tDSTAR, :tDSTAR, :tPOW), "**" }
116
+ | /\*\=/ { result EXPR_BEG, :tOP_ASGN, "*" }
117
+ | /\*/ { result :arg_state, space_vs_beginning(:tSTAR, :tSTAR, :tSTAR2), "*" }
118
+
119
+ # TODO: fix result+process_lchevron to set command_start = true
120
+ : /</
121
+ | /\<\=\>/ { result :arg_state, :tCMP, "<=>" }
122
+ | /\<\=/ { result :arg_state, :tLEQ, "<=" }
123
+ | /\<\<\=/ { result EXPR_BEG, :tOP_ASGN, "<<" }
124
+ | /\<\</ process_lchevron
125
+ | /\</ { result :arg_state, :tLT, "<" }
126
+
127
+ : />/
128
+ | /\>\=/ { result :arg_state, :tGEQ, ">=" }
129
+ | /\>\>=/ { result EXPR_BEG, :tOP_ASGN, ">>" }
130
+ | /\>\>/ { result :arg_state, :tRSHFT, ">>" }
131
+ | /\>/ { result :arg_state, :tGT, ">" }
132
+
133
+ : /\`/
134
+ | expr_fname? /\`/ { result EXPR_END, :tBACK_REF2, "`" }
135
+ | expr_dot? /\`/ { result((cmd_state ? EXPR_CMDARG : EXPR_ARG), :tBACK_REF2, "`") }
136
+ | /\`/ { string STR_XQUOTE, '`'; result nil, :tXSTRING_BEG, "`" }
137
+
138
+ /\?/ process_questionmark
139
+
140
+ : /&/
141
+ | /\&\&\=/ { result EXPR_BEG, :tOP_ASGN, "&&" }
142
+ | /\&\&/ { result EXPR_BEG, :tANDOP, "&&" }
143
+ | /\&\=/ { result EXPR_BEG, :tOP_ASGN, "&" }
144
+ | /\&\./ { result EXPR_DOT, :tLONELY, "&." }
145
+ | /\&/ process_amper
146
+
147
+ /\// process_slash
148
+
149
+ : /\^/
150
+ | /\^=/ { result EXPR_BEG, :tOP_ASGN, "^" }
151
+ | /\^/ { result :arg_state, :tCARET, "^" }
152
+
153
+ /\;/ { self.command_start = true; result EXPR_BEG, :tSEMI, ";" }
154
+
155
+ : /~/
156
+ | is_after_operator? /\~@/ { result :arg_state, :tTILDE, "~" }
157
+ | /\~/ { result :arg_state, :tTILDE, "~" }
158
+
159
+ : /\\/
160
+ | /\\\r?\n/ { self.lineno += 1; self.space_seen = true; next }
161
+ | /\\/ { rb_compile_error "bare backslash only allowed before newline" }
162
+
163
+ /\%/ process_percent
164
+
165
+ : /\$/
166
+ | /\$_\w+/ process_gvar
167
+ | /\$_/ process_gvar
168
+ | /\$[~*$?!@\/\\;,.=:<>\"]|\$-\w?/ process_gvar
169
+ | in_fname? /\$([\&\`\'\+])/ process_gvar
170
+ | /\$([\&\`\'\+])/ process_backref
171
+ | in_fname? /\$([1-9]\d*)/ process_gvar
172
+ | /\$([1-9]\d*)/ process_nthref
173
+ | /\$0/ process_gvar
174
+ | /\$#{IDENT_CHAR}+/ process_gvar
175
+ | /\$\W/ process_gvar_oddity
176
+
177
+ /\_/ process_underscore
178
+
179
+ /#{IDENT_CHAR}+/o process_token
180
+
181
+ /\004|\032|\000|\Z/ { [RubyLexer::EOF, RubyLexer::EOF] }
182
+
183
+ /./ { rb_compile_error "Invalid char #{text.inspect} in expression" }
184
+
185
+ end
@@ -0,0 +1,399 @@
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+ #--
4
+ # This file is automatically generated. Do not modify it.
5
+ # Generated by: oedipus_lex version 2.6.0.
6
+ # Source: lib/ruby_lexer.rex
7
+ #++
8
+
9
+ #
10
+ # lexical scanner definition for ruby
11
+
12
+
13
+ ##
14
+ # The generated lexer RubyLexer
15
+
16
+ class RubyLexer
17
+ require 'strscan'
18
+
19
+ # :stopdoc:
20
+ IDENT_CHAR = /[a-zA-Z0-9_[:^ascii:]]/
21
+ ESC = /\\((?>[0-7]{1,3}|x\h{1,2}|M-[^\\]|(C-|c)[^\\]|u\h{1,4}|u\{\h+(?:\s+\h+)*\}|[^0-7xMCc]))/
22
+ SIMPLE_STRING = /((#{ESC}|\#(#{ESC}|[^\{\#\@\$\"\\])|[^\"\\\#])*)/o
23
+ SSTRING = /((\\.|[^\'])*)/
24
+ INT_DEC = /[+]?(?:(?:[1-9][\d_]*|0)(?!\.\d)(ri|r|i)?\b|0d[0-9_]+)(ri|r|i)?/i
25
+ INT_HEX = /[+]?0x[a-f0-9_]+(ri|r|i)?/i
26
+ INT_BIN = /[+]?0b[01_]+(ri|r|i)?/i
27
+ INT_OCT = /[+]?0o?[0-7_]+(ri|r|i)?|0o(ri|r|i)?/i
28
+ FLOAT = /[+]?\d[\d_]*\.[\d_]+(e[+-]?[\d_]+)?(?:(ri|r|i)\b)?|[+]?[\d_]+e[+-]?[\d_]+(?:(ri|r|i)\b)?/i
29
+ INT_DEC2 = /[+]?\d[0-9_]*(?![e])((ri|r|i)\b)?/i
30
+ NUM_BAD = /[+]?0[xbd]\b/i
31
+ INT_OCT_BAD = /[+]?0o?[0-7_]*[89]/i
32
+ FLOAT_BAD = /[+]?\d[\d_]*_(e|\.)/i
33
+ # :startdoc:
34
+ # :stopdoc:
35
+ class LexerError < StandardError ; end
36
+ class ScanError < LexerError ; end
37
+ # :startdoc:
38
+
39
+ ##
40
+ # The current line number.
41
+
42
+ attr_accessor :lineno
43
+ ##
44
+ # The file name / path
45
+
46
+ attr_accessor :filename
47
+
48
+ ##
49
+ # The StringScanner for this lexer.
50
+
51
+ attr_accessor :ss
52
+
53
+ ##
54
+ # The current lexical state.
55
+
56
+ attr_accessor :state
57
+
58
+ alias :match :ss
59
+
60
+ ##
61
+ # The match groups for the current scan.
62
+
63
+ def matches
64
+ m = (1..9).map { |i| ss[i] }
65
+ m.pop until m[-1] or m.empty?
66
+ m
67
+ end
68
+
69
+ ##
70
+ # Yields on the current action.
71
+
72
+ def action
73
+ yield
74
+ end
75
+
76
+ ##
77
+ # The previous position. Only available if the :column option is on.
78
+
79
+ attr_accessor :old_pos
80
+
81
+ ##
82
+ # The position of the start of the current line. Only available if the
83
+ # :column option is on.
84
+
85
+ attr_accessor :start_of_current_line_pos
86
+
87
+ ##
88
+ # The current column, starting at 0. Only available if the
89
+ # :column option is on.
90
+ def column
91
+ old_pos - start_of_current_line_pos
92
+ end
93
+
94
+
95
+ ##
96
+ # The current scanner class. Must be overridden in subclasses.
97
+
98
+ def scanner_class
99
+ StringScanner
100
+ end unless instance_methods(false).map(&:to_s).include?("scanner_class")
101
+
102
+ ##
103
+ # Parse the given string.
104
+
105
+ def parse str
106
+ self.ss = scanner_class.new str
107
+ self.lineno = 1
108
+ self.start_of_current_line_pos = 0
109
+ self.state ||= nil
110
+
111
+ do_parse
112
+ end
113
+
114
+ ##
115
+ # Read in and parse the file at +path+.
116
+
117
+ def parse_file path
118
+ self.filename = path
119
+ open path do |f|
120
+ parse f.read
121
+ end
122
+ end
123
+
124
+ ##
125
+ # The current location in the parse.
126
+
127
+ def location
128
+ [
129
+ (filename || "<input>"),
130
+ lineno,
131
+ column,
132
+ ].compact.join(":")
133
+ end
134
+
135
+ ##
136
+ # Lex the next token.
137
+
138
+ def next_token
139
+ maybe_pop_stack
140
+ return process_string_or_heredoc if lex_strterm
141
+ self.cmd_state = self.command_start
142
+ self.command_start = false
143
+ self.space_seen = false # TODO: rename token_seen?
144
+ self.last_state = lex_state
145
+
146
+ token = nil
147
+
148
+ until ss.eos? or token do
149
+ if ss.check(/\n/) then
150
+ self.lineno += 1
151
+ # line starts 1 position after the newline
152
+ self.start_of_current_line_pos = ss.pos + 1
153
+ end
154
+ self.old_pos = ss.pos
155
+ token =
156
+ case state
157
+ when nil then
158
+ case
159
+ when ss.skip(/[\ \t\r\f\v]+/) then
160
+ action { self.space_seen = true; next }
161
+ when text = ss.scan(/\n|\#/) then
162
+ process_newline_or_comment text
163
+ when text = ss.scan(/[\]\)\}]/) then
164
+ process_brace_close text
165
+ when ss.match?(/\!/) then
166
+ case
167
+ when is_after_operator? && (text = ss.scan(/\!\@/)) then
168
+ action { result EXPR_ARG, TOKENS[text], text }
169
+ when text = ss.scan(/\![=~]?/) then
170
+ action { result :arg_state, TOKENS[text], text }
171
+ end # group /\!/
172
+ when ss.match?(/\./) then
173
+ case
174
+ when text = ss.scan(/\.\.\.?/) then
175
+ process_dots text
176
+ when ss.skip(/\.\d/) then
177
+ action { rb_compile_error "no .<digit> floating literal anymore put 0 before dot" }
178
+ when ss.skip(/\./) then
179
+ action { self.lex_state = EXPR_BEG; result EXPR_DOT, :tDOT, "." }
180
+ end # group /\./
181
+ when text = ss.scan(/\(/) then
182
+ process_paren text
183
+ when text = ss.scan(/\,/) then
184
+ action { result EXPR_PAR, TOKENS[text], text }
185
+ when ss.match?(/=/) then
186
+ case
187
+ when text = ss.scan(/\=\=\=|\=\=|\=~|\=>|\=(?!begin\b)/) then
188
+ action { result arg_state, TOKENS[text], text }
189
+ when bol? && (text = ss.scan(/\=begin(?=\s)/)) then
190
+ process_begin text
191
+ when text = ss.scan(/\=(?=begin\b)/) then
192
+ action { result arg_state, TOKENS[text], text }
193
+ end # group /=/
194
+ when ruby22_label? && (text = ss.scan(/\"#{SIMPLE_STRING}\":/o)) then
195
+ process_label text
196
+ when text = ss.scan(/\"(#{SIMPLE_STRING})\"/o) then
197
+ process_simple_string text
198
+ when text = ss.scan(/\"/) then
199
+ action { string STR_DQUOTE, '"'; result nil, :tSTRING_BEG, text }
200
+ when text = ss.scan(/\@\@?\d/) then
201
+ action { rb_compile_error "`#{text}` is not allowed as a variable name" }
202
+ when text = ss.scan(/\@\@?#{IDENT_CHAR}+/o) then
203
+ process_ivar text
204
+ when ss.match?(/:/) then
205
+ case
206
+ when not_end? && (text = ss.scan(/:([a-zA-Z_]#{IDENT_CHAR}*(?:[?]|[!](?!=)|=(?==>)|=(?![=>]))?)/o)) then
207
+ process_symbol text
208
+ when not_end? && (text = ss.scan(/\:\"(#{SIMPLE_STRING})\"/o)) then
209
+ process_symbol text
210
+ when not_end? && (text = ss.scan(/\:\'(#{SSTRING})\'/o)) then
211
+ process_symbol text
212
+ when text = ss.scan(/\:\:/) then
213
+ process_colon2 text
214
+ when text = ss.scan(/\:/) then
215
+ process_colon1 text
216
+ end # group /:/
217
+ when text = ss.scan(/->/) then
218
+ action { result EXPR_ENDFN, :tLAMBDA, text }
219
+ when text = ss.scan(/[+-]/) then
220
+ process_plus_minus text
221
+ when ss.match?(/[+\d]/) then
222
+ case
223
+ when ss.skip(/#{NUM_BAD}/o) then
224
+ action { rb_compile_error "Invalid numeric format" }
225
+ when ss.skip(/#{INT_DEC}/o) then
226
+ action { int_with_base 10 }
227
+ when ss.skip(/#{INT_HEX}/o) then
228
+ action { int_with_base 16 }
229
+ when ss.skip(/#{INT_BIN}/o) then
230
+ action { int_with_base 2 }
231
+ when ss.skip(/#{INT_OCT_BAD}/o) then
232
+ action { rb_compile_error "Illegal octal digit." }
233
+ when ss.skip(/#{INT_OCT}/o) then
234
+ action { int_with_base 8 }
235
+ when ss.skip(/#{FLOAT_BAD}/o) then
236
+ action { rb_compile_error "Trailing '_' in number." }
237
+ when text = ss.scan(/#{FLOAT}/o) then
238
+ process_float text
239
+ when ss.skip(/#{INT_DEC2}/o) then
240
+ action { int_with_base 10 }
241
+ when ss.skip(/[0-9]/) then
242
+ action { rb_compile_error "Bad number format" }
243
+ end # group /[+\d]/
244
+ when text = ss.scan(/\[/) then
245
+ process_square_bracket text
246
+ when was_label? && (text = ss.scan(/\'#{SSTRING}\':?/o)) then
247
+ process_label_or_string text
248
+ when text = ss.scan(/\'/) then
249
+ action { string STR_SQUOTE, "'"; result nil, :tSTRING_BEG, text }
250
+ when ss.match?(/\|/) then
251
+ case
252
+ when ss.skip(/\|\|\=/) then
253
+ action { result EXPR_BEG, :tOP_ASGN, "||" }
254
+ when ss.skip(/\|\|/) then
255
+ action { result EXPR_BEG, :tOROP, "||" }
256
+ when ss.skip(/\|\=/) then
257
+ action { result EXPR_BEG, :tOP_ASGN, "|" }
258
+ when ss.skip(/\|/) then
259
+ action { state = is_after_operator? ? EXPR_ARG : EXPR_PAR; result state, :tPIPE, "|" }
260
+ end # group /\|/
261
+ when text = ss.scan(/\{/) then
262
+ process_brace_open text
263
+ when ss.match?(/\*/) then
264
+ case
265
+ when ss.skip(/\*\*=/) then
266
+ action { result EXPR_BEG, :tOP_ASGN, "**" }
267
+ when ss.skip(/\*\*/) then
268
+ action { result :arg_state, space_vs_beginning(:tDSTAR, :tDSTAR, :tPOW), "**" }
269
+ when ss.skip(/\*\=/) then
270
+ action { result EXPR_BEG, :tOP_ASGN, "*" }
271
+ when ss.skip(/\*/) then
272
+ action { result :arg_state, space_vs_beginning(:tSTAR, :tSTAR, :tSTAR2), "*" }
273
+ end # group /\*/
274
+ when ss.match?(/</) then
275
+ case
276
+ when ss.skip(/\<\=\>/) then
277
+ action { result :arg_state, :tCMP, "<=>" }
278
+ when ss.skip(/\<\=/) then
279
+ action { result :arg_state, :tLEQ, "<=" }
280
+ when ss.skip(/\<\<\=/) then
281
+ action { result EXPR_BEG, :tOP_ASGN, "<<" }
282
+ when text = ss.scan(/\<\</) then
283
+ process_lchevron text
284
+ when ss.skip(/\</) then
285
+ action { result :arg_state, :tLT, "<" }
286
+ end # group /</
287
+ when ss.match?(/>/) then
288
+ case
289
+ when ss.skip(/\>\=/) then
290
+ action { result :arg_state, :tGEQ, ">=" }
291
+ when ss.skip(/\>\>=/) then
292
+ action { result EXPR_BEG, :tOP_ASGN, ">>" }
293
+ when ss.skip(/\>\>/) then
294
+ action { result :arg_state, :tRSHFT, ">>" }
295
+ when ss.skip(/\>/) then
296
+ action { result :arg_state, :tGT, ">" }
297
+ end # group />/
298
+ when ss.match?(/\`/) then
299
+ case
300
+ when expr_fname? && (ss.skip(/\`/)) then
301
+ action { result EXPR_END, :tBACK_REF2, "`" }
302
+ when expr_dot? && (ss.skip(/\`/)) then
303
+ action { result((cmd_state ? EXPR_CMDARG : EXPR_ARG), :tBACK_REF2, "`") }
304
+ when ss.skip(/\`/) then
305
+ action { string STR_XQUOTE, '`'; result nil, :tXSTRING_BEG, "`" }
306
+ end # group /\`/
307
+ when text = ss.scan(/\?/) then
308
+ process_questionmark text
309
+ when ss.match?(/&/) then
310
+ case
311
+ when ss.skip(/\&\&\=/) then
312
+ action { result EXPR_BEG, :tOP_ASGN, "&&" }
313
+ when ss.skip(/\&\&/) then
314
+ action { result EXPR_BEG, :tANDOP, "&&" }
315
+ when ss.skip(/\&\=/) then
316
+ action { result EXPR_BEG, :tOP_ASGN, "&" }
317
+ when ss.skip(/\&\./) then
318
+ action { result EXPR_DOT, :tLONELY, "&." }
319
+ when text = ss.scan(/\&/) then
320
+ process_amper text
321
+ end # group /&/
322
+ when text = ss.scan(/\//) then
323
+ process_slash text
324
+ when ss.match?(/\^/) then
325
+ case
326
+ when ss.skip(/\^=/) then
327
+ action { result EXPR_BEG, :tOP_ASGN, "^" }
328
+ when ss.skip(/\^/) then
329
+ action { result :arg_state, :tCARET, "^" }
330
+ end # group /\^/
331
+ when ss.skip(/\;/) then
332
+ action { self.command_start = true; result EXPR_BEG, :tSEMI, ";" }
333
+ when ss.match?(/~/) then
334
+ case
335
+ when is_after_operator? && (ss.skip(/\~@/)) then
336
+ action { result :arg_state, :tTILDE, "~" }
337
+ when ss.skip(/\~/) then
338
+ action { result :arg_state, :tTILDE, "~" }
339
+ end # group /~/
340
+ when ss.match?(/\\/) then
341
+ case
342
+ when ss.skip(/\\\r?\n/) then
343
+ action { self.lineno += 1; self.space_seen = true; next }
344
+ when ss.skip(/\\/) then
345
+ action { rb_compile_error "bare backslash only allowed before newline" }
346
+ end # group /\\/
347
+ when text = ss.scan(/\%/) then
348
+ process_percent text
349
+ when ss.match?(/\$/) then
350
+ case
351
+ when text = ss.scan(/\$_\w+/) then
352
+ process_gvar text
353
+ when text = ss.scan(/\$_/) then
354
+ process_gvar text
355
+ when text = ss.scan(/\$[~*$?!@\/\\;,.=:<>\"]|\$-\w?/) then
356
+ process_gvar text
357
+ when in_fname? && (text = ss.scan(/\$([\&\`\'\+])/)) then
358
+ process_gvar text
359
+ when text = ss.scan(/\$([\&\`\'\+])/) then
360
+ process_backref text
361
+ when in_fname? && (text = ss.scan(/\$([1-9]\d*)/)) then
362
+ process_gvar text
363
+ when text = ss.scan(/\$([1-9]\d*)/) then
364
+ process_nthref text
365
+ when text = ss.scan(/\$0/) then
366
+ process_gvar text
367
+ when text = ss.scan(/\$#{IDENT_CHAR}+/) then
368
+ process_gvar text
369
+ when text = ss.scan(/\$\W/) then
370
+ process_gvar_oddity text
371
+ end # group /\$/
372
+ when text = ss.scan(/\_/) then
373
+ process_underscore text
374
+ when text = ss.scan(/#{IDENT_CHAR}+/o) then
375
+ process_token text
376
+ when ss.skip(/\004|\032|\000|\Z/) then
377
+ action { [RubyLexer::EOF, RubyLexer::EOF] }
378
+ when text = ss.scan(/./) then
379
+ action { rb_compile_error "Invalid char #{text.inspect} in expression" }
380
+ else
381
+ text = ss.string[ss.pos .. -1]
382
+ raise ScanError, "can not match (#{state.inspect}) at #{location}: '#{text}'"
383
+ end
384
+ else
385
+ raise ScanError, "undefined state at #{location}: '#{state}'"
386
+ end # token = case state
387
+
388
+ next unless token # allow functions to trigger redo w/ nil
389
+ end # while
390
+
391
+ raise LexerError, "bad lexical result at #{location}: #{token.inspect}" unless
392
+ token.nil? || (Array === token && token.size >= 2)
393
+
394
+ # auto-switch state
395
+ self.state = token.last if token && token.first == :state
396
+
397
+ token
398
+ end # def next_token
399
+ end # class