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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/.autotest +36 -19
- data/History.rdoc +1297 -0
- data/Manifest.txt +35 -7
- data/{README.txt → README.rdoc} +44 -14
- data/Rakefile +308 -110
- data/bin/ruby_parse +3 -1
- data/bin/ruby_parse_extract_error +36 -16
- data/compare/normalize.rb +218 -0
- data/debugging.md +190 -0
- data/gauntlet.md +107 -0
- data/lib/.document +1 -0
- data/lib/rp_extensions.rb +53 -0
- data/lib/rp_stringscanner.rb +33 -0
- data/lib/ruby20_parser.rb +10973 -0
- data/lib/ruby20_parser.y +2683 -0
- data/lib/ruby21_parser.rb +10980 -0
- data/lib/ruby21_parser.y +2700 -0
- data/lib/ruby22_parser.rb +11123 -0
- data/lib/ruby22_parser.y +2711 -0
- data/lib/ruby23_parser.rb +11132 -0
- data/lib/ruby23_parser.y +2713 -0
- data/lib/ruby24_parser.rb +11231 -0
- data/lib/ruby24_parser.y +2721 -0
- data/lib/ruby25_parser.rb +11231 -0
- data/lib/ruby25_parser.y +2721 -0
- data/lib/ruby26_parser.rb +11253 -0
- data/lib/ruby26_parser.y +2736 -0
- data/lib/ruby27_parser.rb +12980 -0
- data/lib/ruby27_parser.y +3324 -0
- data/lib/ruby30_parser.rb +13242 -0
- data/lib/ruby30_parser.y +3447 -0
- data/lib/ruby31_parser.rb +13622 -0
- data/lib/ruby31_parser.y +3481 -0
- data/lib/ruby3_parser.yy +3536 -0
- data/lib/ruby_lexer.rb +933 -1232
- data/lib/ruby_lexer.rex +185 -0
- data/lib/ruby_lexer.rex.rb +399 -0
- data/lib/ruby_lexer_strings.rb +638 -0
- data/lib/ruby_parser.rb +97 -3
- data/lib/ruby_parser.yy +3465 -0
- data/lib/ruby_parser_extras.rb +1216 -687
- data/test/test_ruby_lexer.rb +2249 -1092
- data/test/test_ruby_parser.rb +5156 -975
- data/test/test_ruby_parser_extras.rb +47 -77
- data/tools/munge.rb +250 -0
- data/tools/ripper.rb +44 -0
- data.tar.gz.sig +1 -1
- metadata +200 -155
- metadata.gz.sig +0 -0
- data/.gemtest +0 -0
- data/History.txt +0 -482
- data/lib/gauntlet_rubyparser.rb +0 -120
- data/lib/ruby18_parser.rb +0 -5747
- data/lib/ruby18_parser.y +0 -1873
- data/lib/ruby19_parser.rb +0 -6110
- data/lib/ruby19_parser.y +0 -2078
data/lib/ruby_lexer.rex
ADDED
@@ -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
|