ruby_parser 2.0.5 → 3.0.0.a1
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/.autotest +4 -4
- data/.gemtest +0 -0
- data/History.txt +124 -0
- data/Manifest.txt +6 -1
- data/README.txt +7 -6
- data/Rakefile +74 -27
- data/bin/ruby_parse +9 -1
- data/bin/ruby_parse_extract_error +75 -0
- data/lib/ruby18_parser.rb +5737 -0
- data/lib/{ruby_parser.y → ruby18_parser.y} +197 -124
- data/lib/ruby19_parser.rb +6147 -0
- data/lib/ruby19_parser.y +2014 -0
- data/lib/ruby_lexer.rb +146 -47
- data/lib/ruby_parser.rb +3 -5544
- data/lib/ruby_parser_extras.rb +392 -244
- data/test/test_ruby_lexer.rb +99 -15
- data/test/test_ruby_parser.rb +395 -130
- data/test/test_ruby_parser_extras.rb +10 -6
- data.tar.gz.sig +0 -0
- metadata +45 -39
- metadata.gz.sig +3 -1
data/lib/ruby_lexer.rb
CHANGED
|
@@ -2,10 +2,17 @@ class RubyLexer
|
|
|
2
2
|
attr_accessor :command_start
|
|
3
3
|
attr_accessor :cmdarg
|
|
4
4
|
attr_accessor :cond
|
|
5
|
+
attr_accessor :tern
|
|
5
6
|
attr_accessor :nest
|
|
6
7
|
|
|
7
8
|
ESC_RE = /\\([0-7]{1,3}|x[0-9a-fA-F]{1,2}|M-[^\\]|(C-|c)[^\\]|[^0-7xMCc])/
|
|
8
9
|
|
|
10
|
+
##
|
|
11
|
+
# What version of ruby to parse. 18 and 19 are the only valid values
|
|
12
|
+
# currently supported.
|
|
13
|
+
|
|
14
|
+
attr_accessor :version
|
|
15
|
+
|
|
9
16
|
# Additional context surrounding tokens that both the lexer and
|
|
10
17
|
# grammar use.
|
|
11
18
|
attr_reader :lex_state
|
|
@@ -35,7 +42,7 @@ class RubyLexer
|
|
|
35
42
|
STR_FUNC_ESCAPE = 0x01 # TODO: remove and replace with REGEXP
|
|
36
43
|
STR_FUNC_EXPAND = 0x02
|
|
37
44
|
STR_FUNC_REGEXP = 0x04
|
|
38
|
-
|
|
45
|
+
STR_FUNC_QWORDS = 0x08
|
|
39
46
|
STR_FUNC_SYMBOL = 0x10
|
|
40
47
|
STR_FUNC_INDENT = 0x20 # <<-HEREDOC
|
|
41
48
|
|
|
@@ -58,6 +65,7 @@ class RubyLexer
|
|
|
58
65
|
"===" => :tEQQ,
|
|
59
66
|
"=>" => :tASSOC,
|
|
60
67
|
"=~" => :tMATCH,
|
|
68
|
+
"->" => :tLAMBDA,
|
|
61
69
|
}
|
|
62
70
|
|
|
63
71
|
# How the parser advances to the next token.
|
|
@@ -130,7 +138,7 @@ class RubyLexer
|
|
|
130
138
|
string_buffer << '#'
|
|
131
139
|
end
|
|
132
140
|
|
|
133
|
-
until src.
|
|
141
|
+
until src.check(eos_re) do
|
|
134
142
|
c = tokadd_string func, "\n", nil
|
|
135
143
|
|
|
136
144
|
rb_compile_error err_msg if
|
|
@@ -146,9 +154,6 @@ class RubyLexer
|
|
|
146
154
|
rb_compile_error err_msg if
|
|
147
155
|
src.eos?
|
|
148
156
|
end
|
|
149
|
-
|
|
150
|
-
# tack on a NL after the heredoc token - FIX NL should not be needed
|
|
151
|
-
src.unread_many(eos + "\n") # TODO: remove this... stupid stupid stupid
|
|
152
157
|
else
|
|
153
158
|
until src.check(eos_re) do
|
|
154
159
|
string_buffer << src.scan(/.*(\n|\z)/)
|
|
@@ -195,11 +200,10 @@ class RubyLexer
|
|
|
195
200
|
return nil
|
|
196
201
|
end
|
|
197
202
|
|
|
198
|
-
if src.
|
|
203
|
+
if src.scan(/.*\n/) then
|
|
199
204
|
# TODO: think about storing off the char range instead
|
|
200
|
-
line = src.
|
|
201
|
-
src.
|
|
202
|
-
src.pos += 1
|
|
205
|
+
line = src.matched
|
|
206
|
+
src.extra_lines_added += 1
|
|
203
207
|
else
|
|
204
208
|
line = nil
|
|
205
209
|
end
|
|
@@ -215,9 +219,11 @@ class RubyLexer
|
|
|
215
219
|
end
|
|
216
220
|
end
|
|
217
221
|
|
|
218
|
-
def initialize
|
|
219
|
-
self.
|
|
220
|
-
self.
|
|
222
|
+
def initialize v = 18
|
|
223
|
+
self.version = v
|
|
224
|
+
self.cond = RubyParser::StackState.new(:cond)
|
|
225
|
+
self.cmdarg = RubyParser::StackState.new(:cmdarg)
|
|
226
|
+
self.tern = RubyParser::StackState.new(:tern)
|
|
221
227
|
self.nest = 0
|
|
222
228
|
@comments = []
|
|
223
229
|
|
|
@@ -231,7 +237,7 @@ class RubyLexer
|
|
|
231
237
|
end
|
|
232
238
|
|
|
233
239
|
def lex_state= o
|
|
234
|
-
raise "wtf
|
|
240
|
+
raise "wtf\?" unless Symbol === o
|
|
235
241
|
@lex_state = o
|
|
236
242
|
end
|
|
237
243
|
|
|
@@ -308,10 +314,10 @@ class RubyLexer
|
|
|
308
314
|
[:tSTRING_BEG, STR_SQUOTE]
|
|
309
315
|
when 'W' then
|
|
310
316
|
src.scan(/\s*/)
|
|
311
|
-
[:tWORDS_BEG, STR_DQUOTE |
|
|
317
|
+
[:tWORDS_BEG, STR_DQUOTE | STR_FUNC_QWORDS]
|
|
312
318
|
when 'w' then
|
|
313
319
|
src.scan(/\s*/)
|
|
314
|
-
[:
|
|
320
|
+
[:tQWORDS_BEG, STR_SQUOTE | STR_FUNC_QWORDS]
|
|
315
321
|
when 'x' then
|
|
316
322
|
[:tXSTRING_BEG, STR_XQUOTE]
|
|
317
323
|
when 'r' then
|
|
@@ -337,7 +343,7 @@ class RubyLexer
|
|
|
337
343
|
paren = open
|
|
338
344
|
term_re = Regexp.escape term
|
|
339
345
|
|
|
340
|
-
|
|
346
|
+
qwords = (func & STR_FUNC_QWORDS) != 0
|
|
341
347
|
regexp = (func & STR_FUNC_REGEXP) != 0
|
|
342
348
|
expand = (func & STR_FUNC_EXPAND) != 0
|
|
343
349
|
|
|
@@ -346,10 +352,10 @@ class RubyLexer
|
|
|
346
352
|
return :tSTRING_END
|
|
347
353
|
end
|
|
348
354
|
|
|
349
|
-
space = true if
|
|
355
|
+
space = true if qwords and src.scan(/\s+/)
|
|
350
356
|
|
|
351
357
|
if self.nest == 0 && src.scan(/#{term_re}/) then
|
|
352
|
-
if
|
|
358
|
+
if qwords then
|
|
353
359
|
quote[1] = nil
|
|
354
360
|
return :tSPACE
|
|
355
361
|
elsif regexp then
|
|
@@ -386,7 +392,6 @@ class RubyLexer
|
|
|
386
392
|
|
|
387
393
|
self.yacc_value = string_buffer.join
|
|
388
394
|
|
|
389
|
-
|
|
390
395
|
return :tSTRING_CONTENT
|
|
391
396
|
end
|
|
392
397
|
|
|
@@ -473,6 +478,10 @@ class RubyLexer
|
|
|
473
478
|
@lex_state = nil
|
|
474
479
|
end
|
|
475
480
|
|
|
481
|
+
def ruby18
|
|
482
|
+
Ruby18Parser === parser
|
|
483
|
+
end
|
|
484
|
+
|
|
476
485
|
def src= src
|
|
477
486
|
raise "bad src: #{src.inspect}" unless String === src
|
|
478
487
|
@src = RPStringScanner.new(src)
|
|
@@ -499,7 +508,7 @@ class RubyLexer
|
|
|
499
508
|
end
|
|
500
509
|
|
|
501
510
|
def tokadd_string(func, term, paren) # 105 lines
|
|
502
|
-
|
|
511
|
+
qwords = (func & STR_FUNC_QWORDS) != 0
|
|
503
512
|
escape = (func & STR_FUNC_ESCAPE) != 0
|
|
504
513
|
expand = (func & STR_FUNC_EXPAND) != 0
|
|
505
514
|
regexp = (func & STR_FUNC_REGEXP) != 0
|
|
@@ -519,7 +528,7 @@ class RubyLexer
|
|
|
519
528
|
self.nest += 1
|
|
520
529
|
when src.scan(term_re) then
|
|
521
530
|
self.nest -= 1
|
|
522
|
-
when
|
|
531
|
+
when qwords && src.scan(/\s/) then
|
|
523
532
|
src.pos -= 1
|
|
524
533
|
break
|
|
525
534
|
when expand && src.scan(/#(?=[\$\@\{])/) then
|
|
@@ -529,10 +538,10 @@ class RubyLexer
|
|
|
529
538
|
# do nothing
|
|
530
539
|
when src.check(/\\/) then
|
|
531
540
|
case
|
|
532
|
-
when
|
|
541
|
+
when qwords && src.scan(/\\\n/) then
|
|
533
542
|
string_buffer << "\n"
|
|
534
543
|
next
|
|
535
|
-
when
|
|
544
|
+
when qwords && src.scan(/\\\s/) then
|
|
536
545
|
c = ' '
|
|
537
546
|
when expand && src.scan(/\\\n/) then
|
|
538
547
|
next
|
|
@@ -561,7 +570,7 @@ class RubyLexer
|
|
|
561
570
|
|
|
562
571
|
t = Regexp.escape term
|
|
563
572
|
x = Regexp.escape(paren) if paren && paren != "\000"
|
|
564
|
-
re = if
|
|
573
|
+
re = if qwords then
|
|
565
574
|
/[^#{t}#{x}\#\0\\\n\ ]+|./ # |. to pick up whatever
|
|
566
575
|
else
|
|
567
576
|
/[^#{t}#{x}\#\0\\]+|./
|
|
@@ -630,7 +639,6 @@ class RubyLexer
|
|
|
630
639
|
# @return Description of the Returned Value
|
|
631
640
|
|
|
632
641
|
def yylex # 826 lines
|
|
633
|
-
|
|
634
642
|
c = ''
|
|
635
643
|
space_seen = false
|
|
636
644
|
command_state = false
|
|
@@ -655,7 +663,7 @@ class RubyLexer
|
|
|
655
663
|
self.lineno = nil
|
|
656
664
|
c = src.matched
|
|
657
665
|
if c == '#' then
|
|
658
|
-
src.
|
|
666
|
+
src.pos -= 1
|
|
659
667
|
|
|
660
668
|
while src.scan(/\s*#.*(\n+|\z)/) do
|
|
661
669
|
@comments << src.matched.gsub(/^ +#/, '#').gsub(/^ +$/, '')
|
|
@@ -687,6 +695,7 @@ class RubyLexer
|
|
|
687
695
|
"]" => :tRBRACK,
|
|
688
696
|
"}" => :tRCURLY
|
|
689
697
|
}[src.matched]
|
|
698
|
+
self.tern.lexpop if [:tRBRACK, :tRCURLY].include?(result)
|
|
690
699
|
return result
|
|
691
700
|
elsif src.scan(/\.\.\.?|,|![=~]?/) then
|
|
692
701
|
self.lex_state = :expr_beg
|
|
@@ -701,19 +710,11 @@ class RubyLexer
|
|
|
701
710
|
return :tDOT
|
|
702
711
|
end
|
|
703
712
|
elsif src.scan(/\(/) then
|
|
704
|
-
result =
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
elsif space_seen then
|
|
710
|
-
if lex_state == :expr_cmdarg then
|
|
711
|
-
result = :tLPAREN_ARG
|
|
712
|
-
elsif lex_state == :expr_arg then
|
|
713
|
-
warning("don't put space before argument parentheses")
|
|
714
|
-
result = :tLPAREN2
|
|
715
|
-
end
|
|
716
|
-
end
|
|
713
|
+
result = if ruby18 then
|
|
714
|
+
yylex_paren18 space_seen
|
|
715
|
+
else
|
|
716
|
+
yylex_paren19 space_seen
|
|
717
|
+
end
|
|
717
718
|
|
|
718
719
|
self.expr_beg_push "("
|
|
719
720
|
|
|
@@ -723,11 +724,11 @@ class RubyLexer
|
|
|
723
724
|
self.fix_arg_lex_state
|
|
724
725
|
tok = self.yacc_value = src.matched
|
|
725
726
|
return TOKENS[tok]
|
|
726
|
-
elsif src.
|
|
727
|
+
elsif src.scan(/\=begin(?=\s)/) then
|
|
727
728
|
# @comments << '=' << src.matched
|
|
728
729
|
@comments << src.matched
|
|
729
730
|
|
|
730
|
-
unless src.scan(/.*?\n=end
|
|
731
|
+
unless src.scan(/.*?\n=end( |\t|\f)*[^\n]*(\n|\z)/m) then
|
|
731
732
|
@comments.clear
|
|
732
733
|
rb_compile_error("embedded document meets end of file")
|
|
733
734
|
end
|
|
@@ -807,9 +808,13 @@ class RubyLexer
|
|
|
807
808
|
rb_compile_error "unexpected '['"
|
|
808
809
|
end
|
|
809
810
|
elsif lex_state == :expr_beg || lex_state == :expr_mid then
|
|
811
|
+
self.tern.push false
|
|
810
812
|
result = :tLBRACK
|
|
811
813
|
elsif lex_state.is_argument && space_seen then
|
|
814
|
+
self.tern.push false
|
|
812
815
|
result = :tLBRACK
|
|
816
|
+
else
|
|
817
|
+
result = :tLBRACK2
|
|
813
818
|
end
|
|
814
819
|
|
|
815
820
|
self.expr_beg_push "["
|
|
@@ -838,17 +843,29 @@ class RubyLexer
|
|
|
838
843
|
return :tPIPE
|
|
839
844
|
end
|
|
840
845
|
elsif src.scan(/\{/) then
|
|
846
|
+
if defined?(@hack_expects_lambda) && @hack_expects_lambda
|
|
847
|
+
@hack_expects_lambda = false
|
|
848
|
+
self.lex_state = :expr_beg
|
|
849
|
+
return :tLAMBEG
|
|
850
|
+
end
|
|
851
|
+
|
|
841
852
|
result = if lex_state.is_argument || lex_state == :expr_end then
|
|
842
853
|
:tLCURLY # block (primary)
|
|
843
854
|
elsif lex_state == :expr_endarg then
|
|
844
855
|
:tLBRACE_ARG # block (expr)
|
|
845
856
|
else
|
|
857
|
+
self.tern.push false
|
|
846
858
|
:tLBRACE # hash
|
|
847
859
|
end
|
|
848
860
|
|
|
849
861
|
self.expr_beg_push "{"
|
|
862
|
+
self.command_start = true unless result == :tLBRACE
|
|
850
863
|
|
|
851
864
|
return result
|
|
865
|
+
elsif src.scan(/->/) then
|
|
866
|
+
@hack_expects_lambda = true
|
|
867
|
+
self.lex_state = :expr_arg
|
|
868
|
+
return :tLAMBDA
|
|
852
869
|
elsif src.scan(/[+-]/) then
|
|
853
870
|
sign = src.matched
|
|
854
871
|
utype, type = if sign == "+" then
|
|
@@ -994,6 +1011,7 @@ class RubyLexer
|
|
|
994
1011
|
elsif src.scan(/\?/) then
|
|
995
1012
|
if lex_state == :expr_end || lex_state == :expr_endarg then
|
|
996
1013
|
self.lex_state = :expr_beg
|
|
1014
|
+
self.tern.push true
|
|
997
1015
|
self.yacc_value = "?"
|
|
998
1016
|
return :tEH
|
|
999
1017
|
end
|
|
@@ -1018,10 +1036,12 @@ class RubyLexer
|
|
|
1018
1036
|
|
|
1019
1037
|
# ternary
|
|
1020
1038
|
self.lex_state = :expr_beg
|
|
1039
|
+
self.tern.push true
|
|
1021
1040
|
self.yacc_value = "?"
|
|
1022
1041
|
return :tEH
|
|
1023
1042
|
elsif src.check(/\w(?=\w)/) then # ternary, also
|
|
1024
1043
|
self.lex_state = :expr_beg
|
|
1044
|
+
self.tern.push true
|
|
1025
1045
|
self.yacc_value = "?"
|
|
1026
1046
|
return :tEH
|
|
1027
1047
|
end
|
|
@@ -1032,8 +1052,14 @@ class RubyLexer
|
|
|
1032
1052
|
src.getch
|
|
1033
1053
|
end
|
|
1034
1054
|
self.lex_state = :expr_end
|
|
1035
|
-
|
|
1036
|
-
|
|
1055
|
+
|
|
1056
|
+
if version == 18 then
|
|
1057
|
+
self.yacc_value = c[0].ord & 0xff
|
|
1058
|
+
return :tINTEGER
|
|
1059
|
+
else
|
|
1060
|
+
self.yacc_value = c
|
|
1061
|
+
return :tSTRING
|
|
1062
|
+
end
|
|
1037
1063
|
elsif src.check(/\&/) then
|
|
1038
1064
|
if src.scan(/\&\&\=/) then
|
|
1039
1065
|
self.yacc_value = "&&"
|
|
@@ -1207,6 +1233,53 @@ class RubyLexer
|
|
|
1207
1233
|
end
|
|
1208
1234
|
end
|
|
1209
1235
|
|
|
1236
|
+
def yylex_paren18 space_seen
|
|
1237
|
+
self.command_start = true
|
|
1238
|
+
result = :tLPAREN2
|
|
1239
|
+
|
|
1240
|
+
if lex_state == :expr_beg || lex_state == :expr_mid then
|
|
1241
|
+
result = :tLPAREN
|
|
1242
|
+
elsif space_seen then
|
|
1243
|
+
if lex_state == :expr_cmdarg then
|
|
1244
|
+
result = :tLPAREN_ARG
|
|
1245
|
+
elsif lex_state == :expr_arg then
|
|
1246
|
+
self.tern.push false
|
|
1247
|
+
warning "don't put space before argument parentheses"
|
|
1248
|
+
end
|
|
1249
|
+
else
|
|
1250
|
+
self.tern.push false
|
|
1251
|
+
end
|
|
1252
|
+
|
|
1253
|
+
result
|
|
1254
|
+
end
|
|
1255
|
+
|
|
1256
|
+
def yylex_paren19 space_seen
|
|
1257
|
+
if (lex_state == :expr_beg || lex_state == :expr_mid ||
|
|
1258
|
+
lex_state == :expr_value || lex_state == :expr_class) then
|
|
1259
|
+
result = :tLPAREN
|
|
1260
|
+
elsif ((lex_state == :expr_arg || lex_state == :expr_cmdarg) and
|
|
1261
|
+
space_seen) then
|
|
1262
|
+
result = :tLPAREN_ARG
|
|
1263
|
+
else
|
|
1264
|
+
self.tern.push false
|
|
1265
|
+
result = :tLPAREN2
|
|
1266
|
+
end
|
|
1267
|
+
# HACK paren_nest++;
|
|
1268
|
+
|
|
1269
|
+
# HACK: this is a mess, but it makes the tests pass, so suck it
|
|
1270
|
+
# (stolen from the 1.8 side)
|
|
1271
|
+
if lex_state == :expr_beg || lex_state == :expr_mid then
|
|
1272
|
+
# do nothing
|
|
1273
|
+
elsif space_seen then
|
|
1274
|
+
if lex_state == :expr_arg then
|
|
1275
|
+
self.tern.push false
|
|
1276
|
+
end
|
|
1277
|
+
else
|
|
1278
|
+
self.tern.push false
|
|
1279
|
+
end
|
|
1280
|
+
result
|
|
1281
|
+
end
|
|
1282
|
+
|
|
1210
1283
|
def process_token(command_state)
|
|
1211
1284
|
|
|
1212
1285
|
token << src.matched if token =~ /^\w/ && src.scan(/[\!\?](?!=)/)
|
|
@@ -1214,7 +1287,6 @@ class RubyLexer
|
|
|
1214
1287
|
result = nil
|
|
1215
1288
|
last_state = lex_state
|
|
1216
1289
|
|
|
1217
|
-
|
|
1218
1290
|
case token
|
|
1219
1291
|
when /^\$/ then
|
|
1220
1292
|
self.lex_state, result = :expr_end, :tGVAR
|
|
@@ -1242,24 +1314,51 @@ class RubyLexer
|
|
|
1242
1314
|
end
|
|
1243
1315
|
end
|
|
1244
1316
|
|
|
1317
|
+
unless self.tern.is_in_state
|
|
1318
|
+
if (lex_state == :expr_beg && (ruby18 || !command_state)) ||
|
|
1319
|
+
lex_state == :expr_arg ||
|
|
1320
|
+
lex_state == :expr_cmdarg then
|
|
1321
|
+
colon = src.scan(/:/)
|
|
1322
|
+
|
|
1323
|
+
if colon && src.peek(1) != ":"
|
|
1324
|
+
src.unscan
|
|
1325
|
+
self.lex_state = :expr_beg
|
|
1326
|
+
src.scan(/:/)
|
|
1327
|
+
self.yacc_value = [token, src.lineno]
|
|
1328
|
+
return :tLABEL
|
|
1329
|
+
end
|
|
1330
|
+
|
|
1331
|
+
src.unscan if colon
|
|
1332
|
+
end
|
|
1333
|
+
end unless ruby18
|
|
1334
|
+
|
|
1245
1335
|
unless lex_state == :expr_dot then
|
|
1246
1336
|
# See if it is a reserved word.
|
|
1247
|
-
keyword = Keyword.keyword token
|
|
1337
|
+
keyword = RubyParser::Keyword.keyword token
|
|
1248
1338
|
|
|
1249
1339
|
if keyword then
|
|
1250
1340
|
state = lex_state
|
|
1251
1341
|
self.lex_state = keyword.state
|
|
1252
|
-
self.yacc_value = token
|
|
1342
|
+
self.yacc_value = [token, src.lineno]
|
|
1343
|
+
|
|
1344
|
+
if state == :expr_fname then
|
|
1345
|
+
self.yacc_value = keyword.name
|
|
1346
|
+
return keyword.id0
|
|
1347
|
+
end
|
|
1253
1348
|
|
|
1254
1349
|
if keyword.id0 == :kDO then
|
|
1255
1350
|
self.command_start = true
|
|
1256
1351
|
return :kDO_COND if cond.is_in_state
|
|
1257
1352
|
return :kDO_BLOCK if cmdarg.is_in_state && state != :expr_cmdarg
|
|
1258
1353
|
return :kDO_BLOCK if state == :expr_endarg
|
|
1354
|
+
if defined?(@hack_expects_lambda) && @hack_expects_lambda
|
|
1355
|
+
@hack_expects_lambda = false
|
|
1356
|
+
return :kDO_LAMBDA
|
|
1357
|
+
end
|
|
1259
1358
|
return :kDO
|
|
1260
1359
|
end
|
|
1261
1360
|
|
|
1262
|
-
return keyword.id0 if state == :expr_beg
|
|
1361
|
+
return keyword.id0 if state == :expr_beg or state == :expr_value
|
|
1263
1362
|
|
|
1264
1363
|
self.lex_state = :expr_beg if keyword.id0 != keyword.id1
|
|
1265
1364
|
|