ruby_parser 3.0.0.a2 → 3.0.0.a3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ruby_parser might be problematic. Click here for more details.
- data.tar.gz.sig +0 -0
- data/.autotest +2 -2
- data/History.txt +33 -0
- data/Rakefile +1 -1
- data/bin/ruby_parse_extract_error +2 -2
- data/lib/ruby18_parser.rb +2 -2
- data/lib/ruby18_parser.y +2 -2
- data/lib/ruby19_parser.rb +3436 -3514
- data/lib/ruby19_parser.y +298 -277
- data/lib/ruby_lexer.rb +45 -19
- data/lib/ruby_parser_extras.rb +89 -13
- data/test/test_ruby_parser.rb +281 -46
- data/test/test_ruby_parser_extras.rb +2 -2
- metadata +4 -4
- metadata.gz.sig +0 -0
data/lib/ruby_lexer.rb
CHANGED
@@ -35,6 +35,8 @@ class RubyLexer
|
|
35
35
|
# What handles warnings
|
36
36
|
attr_accessor :warnings
|
37
37
|
|
38
|
+
attr_accessor :space_seen
|
39
|
+
|
38
40
|
EOF = :eof_haha!
|
39
41
|
|
40
42
|
# ruby constants for strings (should this be moved somewhere else?)
|
@@ -221,9 +223,9 @@ class RubyLexer
|
|
221
223
|
|
222
224
|
def initialize v = 18
|
223
225
|
self.version = v
|
224
|
-
self.cond =
|
225
|
-
self.cmdarg =
|
226
|
-
self.tern =
|
226
|
+
self.cond = RubyParserStuff::StackState.new(:cond)
|
227
|
+
self.cmdarg = RubyParserStuff::StackState.new(:cmdarg)
|
228
|
+
self.tern = RubyParserStuff::StackState.new(:tern)
|
227
229
|
self.nest = 0
|
228
230
|
@comments = []
|
229
231
|
|
@@ -237,6 +239,7 @@ class RubyLexer
|
|
237
239
|
end
|
238
240
|
|
239
241
|
def lex_state= o
|
242
|
+
# warn "wtf lex_state = #{o.inspect}"
|
240
243
|
raise "wtf\?" unless Symbol === o
|
241
244
|
@lex_state = o
|
242
245
|
end
|
@@ -640,7 +643,7 @@ class RubyLexer
|
|
640
643
|
|
641
644
|
def yylex # 826 lines
|
642
645
|
c = ''
|
643
|
-
space_seen = false
|
646
|
+
self.space_seen = false
|
644
647
|
command_state = false
|
645
648
|
src = self.src
|
646
649
|
|
@@ -656,7 +659,7 @@ class RubyLexer
|
|
656
659
|
|
657
660
|
loop do # START OF CASE
|
658
661
|
if src.scan(/[\ \t\r\f\v]/) then # \s - \n + \v
|
659
|
-
space_seen = true
|
662
|
+
self.space_seen = true
|
660
663
|
next
|
661
664
|
elsif src.check(/[^a-zA-Z]/) then
|
662
665
|
if src.scan(/\n|#/) then
|
@@ -711,9 +714,9 @@ class RubyLexer
|
|
711
714
|
end
|
712
715
|
elsif src.scan(/\(/) then
|
713
716
|
result = if ruby18 then
|
714
|
-
yylex_paren18
|
717
|
+
yylex_paren18
|
715
718
|
else
|
716
|
-
yylex_paren19
|
719
|
+
yylex_paren19
|
717
720
|
end
|
718
721
|
|
719
722
|
self.expr_beg_push "("
|
@@ -755,10 +758,7 @@ class RubyLexer
|
|
755
758
|
|
756
759
|
return process_token(command_state)
|
757
760
|
elsif src.scan(/\:\:/) then
|
758
|
-
if
|
759
|
-
lex_state == :expr_mid ||
|
760
|
-
lex_state == :expr_class ||
|
761
|
-
(lex_state.is_argument && space_seen)) then
|
761
|
+
if is_beg? || lex_state == :expr_class || is_space_arg? then
|
762
762
|
self.lex_state = :expr_beg
|
763
763
|
self.yacc_value = "::"
|
764
764
|
return :tCOLON3
|
@@ -1139,7 +1139,7 @@ class RubyLexer
|
|
1139
1139
|
elsif src.scan(/\\/) then
|
1140
1140
|
if src.scan(/\n/) then
|
1141
1141
|
self.lineno = nil
|
1142
|
-
space_seen = true
|
1142
|
+
self.space_seen = true
|
1143
1143
|
next
|
1144
1144
|
end
|
1145
1145
|
rb_compile_error "bare backslash only allowed before newline"
|
@@ -1233,7 +1233,7 @@ class RubyLexer
|
|
1233
1233
|
end
|
1234
1234
|
end
|
1235
1235
|
|
1236
|
-
def yylex_paren18
|
1236
|
+
def yylex_paren18
|
1237
1237
|
self.command_start = true
|
1238
1238
|
result = :tLPAREN2
|
1239
1239
|
|
@@ -1253,17 +1253,39 @@ class RubyLexer
|
|
1253
1253
|
result
|
1254
1254
|
end
|
1255
1255
|
|
1256
|
-
def
|
1257
|
-
|
1258
|
-
|
1256
|
+
def is_end?
|
1257
|
+
(lex_state == :expr_end ||
|
1258
|
+
lex_state == :expr_endarg ||
|
1259
|
+
lex_state == :expr_endfn)
|
1260
|
+
end
|
1261
|
+
|
1262
|
+
def is_arg?
|
1263
|
+
lex_state == :expr_arg || lex_state == :expr_cmdarg
|
1264
|
+
end
|
1265
|
+
|
1266
|
+
def is_beg?
|
1267
|
+
(lex_state == :expr_beg ||
|
1268
|
+
lex_state == :expr_mid ||
|
1269
|
+
lex_state == :expr_value ||
|
1270
|
+
lex_state == :expr_class)
|
1271
|
+
end
|
1272
|
+
|
1273
|
+
def is_space_arg? c = "x"
|
1274
|
+
is_arg? and space_seen and c !~ /\s/
|
1275
|
+
end
|
1276
|
+
|
1277
|
+
def yylex_paren19
|
1278
|
+
if is_beg? then
|
1259
1279
|
result = :tLPAREN
|
1260
|
-
elsif
|
1261
|
-
space_seen) then
|
1280
|
+
elsif is_space_arg? then
|
1262
1281
|
result = :tLPAREN_ARG
|
1263
1282
|
else
|
1264
1283
|
self.tern.push false
|
1265
1284
|
result = :tLPAREN2
|
1266
1285
|
end
|
1286
|
+
|
1287
|
+
# p :wtf_paren => [lex_state, space_seen, result]
|
1288
|
+
|
1267
1289
|
# HACK paren_nest++;
|
1268
1290
|
|
1269
1291
|
# HACK: this is a mess, but it makes the tests pass, so suck it
|
@@ -1334,7 +1356,11 @@ class RubyLexer
|
|
1334
1356
|
|
1335
1357
|
unless lex_state == :expr_dot then
|
1336
1358
|
# See if it is a reserved word.
|
1337
|
-
keyword =
|
1359
|
+
keyword = if ruby18 then # REFACTOR need 18/19 lexer subclasses
|
1360
|
+
RubyParserStuff::Keyword.keyword18 token
|
1361
|
+
else
|
1362
|
+
RubyParserStuff::Keyword.keyword19 token
|
1363
|
+
end
|
1338
1364
|
|
1339
1365
|
if keyword then
|
1340
1366
|
state = lex_state
|
data/lib/ruby_parser_extras.rb
CHANGED
@@ -2,6 +2,7 @@ require 'stringio'
|
|
2
2
|
require 'racc/parser'
|
3
3
|
require 'sexp'
|
4
4
|
require 'strscan'
|
5
|
+
require 'ruby_lexer'
|
5
6
|
|
6
7
|
def d o
|
7
8
|
$stderr.puts o.inspect
|
@@ -115,7 +116,7 @@ class RPStringScanner < StringScanner
|
|
115
116
|
end
|
116
117
|
|
117
118
|
module RubyParserStuff
|
118
|
-
VERSION = '3.0.0.
|
119
|
+
VERSION = '3.0.0.a3' unless constants.include? "VERSION" # SIGH
|
119
120
|
|
120
121
|
attr_accessor :lexer, :in_def, :in_single, :file
|
121
122
|
attr_reader :env, :comments
|
@@ -223,6 +224,57 @@ module RubyParserStuff
|
|
223
224
|
result
|
224
225
|
end
|
225
226
|
|
227
|
+
def block_args19 val, id
|
228
|
+
# HACK OMG THIS CODE IS SOOO UGLY! CLEAN ME
|
229
|
+
untested = %w[1 2 3 4 7 9 10 11 12 14]
|
230
|
+
raise "no block_args19 #{id}" if untested.include? id
|
231
|
+
|
232
|
+
r = s(:array)
|
233
|
+
|
234
|
+
val.compact.each do |v|
|
235
|
+
next if %w[,].include? v
|
236
|
+
case v
|
237
|
+
when Sexp then
|
238
|
+
case v.first
|
239
|
+
when :args then
|
240
|
+
r.concat v[1..-1].map { |s| s(:lasgn, s) }
|
241
|
+
when :block_arg then
|
242
|
+
r << s(:lasgn, :"&#{v.last}")
|
243
|
+
else
|
244
|
+
raise "block_args19 #{id} unhandled sexp type:: #{v.inspect}"
|
245
|
+
end
|
246
|
+
when Symbol
|
247
|
+
case v.to_s
|
248
|
+
when /^\*(.+)/ then
|
249
|
+
r << s(:splat, s(:lasgn, $1.to_sym))
|
250
|
+
when /^\*/ then
|
251
|
+
r << s(:splat)
|
252
|
+
else
|
253
|
+
raise "block_args19 #{id} unhandled symbol type:: #{v.inspect}"
|
254
|
+
end
|
255
|
+
else
|
256
|
+
raise "block_args19 #{id} unhandled type:: #{v.inspect}"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
if r.size > 2 then
|
261
|
+
r = s(:masgn, r)
|
262
|
+
elsif r.size == 2 then
|
263
|
+
case r.last.first
|
264
|
+
when :splat then
|
265
|
+
r = s(:masgn, r)
|
266
|
+
when :lasgn then
|
267
|
+
r = r.last
|
268
|
+
else
|
269
|
+
raise "oh noes!: #{r.inspect}"
|
270
|
+
end
|
271
|
+
else
|
272
|
+
raise "fuck no #{r.inspect}"
|
273
|
+
end
|
274
|
+
|
275
|
+
r
|
276
|
+
end
|
277
|
+
|
226
278
|
def aryset receiver, index
|
227
279
|
s(:attrasgn, receiver, :"[]=", *index[1..-1])
|
228
280
|
end
|
@@ -389,7 +441,7 @@ module RubyParserStuff
|
|
389
441
|
v = self.class.name[/1[89]/]
|
390
442
|
self.lexer = RubyLexer.new v && v.to_i
|
391
443
|
self.lexer.parser = self
|
392
|
-
@env = Environment.new
|
444
|
+
@env = RubyParserStuff::Environment.new
|
393
445
|
@comments = []
|
394
446
|
|
395
447
|
@canonicalize_conditions = true
|
@@ -583,7 +635,7 @@ module RubyParserStuff
|
|
583
635
|
end
|
584
636
|
|
585
637
|
def new_compstmt val
|
586
|
-
result = void_stmts(val[0])
|
638
|
+
result = void_stmts(val.grep(Sexp)[0])
|
587
639
|
result = remove_begin(result) if result
|
588
640
|
result
|
589
641
|
end
|
@@ -1011,15 +1063,29 @@ module RubyParserStuff
|
|
1011
1063
|
["BEGIN", [:klBEGIN, :klBEGIN ], :expr_end ],
|
1012
1064
|
["while", [:kWHILE, :kWHILE_MOD ], :expr_beg ],
|
1013
1065
|
["alias", [:kALIAS, :kALIAS ], :expr_fname ],
|
1066
|
+
["__ENCODING__", [:k__ENCODING__, :k__ENCODING__], :expr_end],
|
1014
1067
|
].map { |args| KWtable.new(*args) }
|
1015
1068
|
|
1016
1069
|
# :startdoc:
|
1017
1070
|
|
1018
|
-
|
1019
|
-
|
1071
|
+
WORDLIST18 = Hash[*wordlist.map { |o| [o.name, o] }.flatten]
|
1072
|
+
WORDLIST19 = Hash[*wordlist.map { |o| [o.name, o] }.flatten]
|
1073
|
+
|
1074
|
+
%w[and case elsif for if in module or unless until when while].each do |k|
|
1075
|
+
WORDLIST19[k] = WORDLIST19[k].dup
|
1076
|
+
WORDLIST19[k].state = :expr_value
|
1077
|
+
end
|
1078
|
+
%w[not].each do |k|
|
1079
|
+
WORDLIST19[k] = WORDLIST19[k].dup
|
1080
|
+
WORDLIST19[k].state = :expr_arg
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
def self.keyword18 str # REFACTOR
|
1084
|
+
WORDLIST18[str]
|
1085
|
+
end
|
1020
1086
|
|
1021
|
-
def self.
|
1022
|
-
|
1087
|
+
def self.keyword19 str
|
1088
|
+
WORDLIST19[str]
|
1023
1089
|
end
|
1024
1090
|
end
|
1025
1091
|
|
@@ -1138,11 +1204,21 @@ class Ruby18Parser < Racc::Parser
|
|
1138
1204
|
include RubyParserStuff
|
1139
1205
|
end
|
1140
1206
|
|
1141
|
-
|
1207
|
+
##
|
1208
|
+
# RubyParser is a compound parser that first attempts to parse using
|
1209
|
+
# the 1.9 syntax parser and falls back to the 1.8 syntax parser on a
|
1210
|
+
# parse error.
|
1211
|
+
|
1212
|
+
class RubyParser
|
1142
1213
|
def initialize
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1214
|
+
@p18 = Ruby18Parser.new
|
1215
|
+
@p19 = Ruby19Parser.new
|
1216
|
+
end
|
1217
|
+
|
1218
|
+
def parse s
|
1219
|
+
@p19.parse s
|
1220
|
+
rescue Racc::ParseError
|
1221
|
+
@p18.parse s
|
1146
1222
|
end
|
1147
1223
|
end
|
1148
1224
|
|
@@ -1172,11 +1248,11 @@ class Sexp
|
|
1172
1248
|
end
|
1173
1249
|
|
1174
1250
|
def add x
|
1175
|
-
|
1251
|
+
concat x
|
1176
1252
|
end
|
1177
1253
|
|
1178
1254
|
def add_all x
|
1179
|
-
raise "no" # TODO: need a test to trigger this
|
1255
|
+
raise "no: #{self.inspect}.add_all #{x.inspect}" # TODO: need a test to trigger this
|
1180
1256
|
end
|
1181
1257
|
|
1182
1258
|
alias :node_type :sexp_type
|
data/test/test_ruby_parser.rb
CHANGED
@@ -1,28 +1,16 @@
|
|
1
1
|
#!/usr/local/bin/ruby
|
2
2
|
|
3
|
-
ENV['VERBOSE'] = "1"
|
3
|
+
# ENV['VERBOSE'] = "1"
|
4
4
|
|
5
5
|
require 'rubygems'
|
6
6
|
gem "minitest"
|
7
7
|
require 'minitest/autorun'
|
8
8
|
require 'ruby_parser'
|
9
9
|
|
10
|
-
$: << File.expand_path('~/Work/p4/zss/src/
|
10
|
+
$: << File.expand_path('~/Work/p4/zss/src/sexp_processor/dev/lib')
|
11
11
|
|
12
12
|
require 'pt_testcase'
|
13
13
|
|
14
|
-
class Ruby18Parser # FIX
|
15
|
-
def process input
|
16
|
-
parse input
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class Ruby19Parser
|
21
|
-
def process input
|
22
|
-
parse input
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
14
|
class RubyParserTestCase < ParseTreeTestCase
|
27
15
|
attr_accessor :result, :processor
|
28
16
|
|
@@ -44,13 +32,21 @@ class RubyParserTestCase < ParseTreeTestCase
|
|
44
32
|
assert_equal pt, result
|
45
33
|
end
|
46
34
|
|
35
|
+
def assert_parse_error rb, emsg
|
36
|
+
e = assert_raises Racc::ParseError do
|
37
|
+
processor.parse rb
|
38
|
+
end
|
39
|
+
|
40
|
+
assert_equal emsg, e.message.strip # TODO: why strip?
|
41
|
+
end
|
42
|
+
|
47
43
|
def assert_parse_line rb, pt, line
|
48
44
|
assert_parse rb, pt
|
49
45
|
assert_equal line, result.line, "call should have line number"
|
50
46
|
end
|
51
47
|
end
|
52
48
|
|
53
|
-
module
|
49
|
+
module TestRubyParserShared
|
54
50
|
def test_attrasgn_array_lhs
|
55
51
|
rb = '[1, 2, 3, 4][from .. to] = ["a", "b", "c"]'
|
56
52
|
pt = s(:attrasgn,
|
@@ -617,6 +613,103 @@ module TestRubyParser
|
|
617
613
|
assert_equal 3, result.if.return.line
|
618
614
|
assert_equal 3, result.if.return.lit.line
|
619
615
|
end
|
616
|
+
end
|
617
|
+
|
618
|
+
class TestRubyParser < MiniTest::Unit::TestCase
|
619
|
+
def test_parse
|
620
|
+
processor = RubyParser.new
|
621
|
+
|
622
|
+
# 1.8 only syntax
|
623
|
+
rb = "while false : 42 end"
|
624
|
+
pt = s(:while, s(:false), s(:lit, 42), true)
|
625
|
+
|
626
|
+
assert_equal pt, processor.parse(rb)
|
627
|
+
|
628
|
+
# 1.9 only syntax
|
629
|
+
rb = "a.()"
|
630
|
+
pt = s(:call, s(:call, nil, :a), :call)
|
631
|
+
|
632
|
+
assert_equal pt, processor.parse(rb)
|
633
|
+
|
634
|
+
# bad syntax
|
635
|
+
e = assert_raises Racc::ParseError do
|
636
|
+
processor.parse "a.("
|
637
|
+
end
|
638
|
+
|
639
|
+
msg = "parse error on value \"(\" (tLPAREN2)"
|
640
|
+
assert_equal msg, e.message.strip
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
644
|
+
class TestRuby18Parser < RubyParserTestCase
|
645
|
+
include TestRubyParserShared
|
646
|
+
|
647
|
+
def setup
|
648
|
+
super
|
649
|
+
|
650
|
+
self.processor = Ruby18Parser.new
|
651
|
+
end
|
652
|
+
|
653
|
+
def test_flip2_env_lvar
|
654
|
+
rb = "if a..b then end"
|
655
|
+
pt = s(:if, s(:flip2, s(:call, nil, :a), s(:call, nil, :b)), nil, nil)
|
656
|
+
|
657
|
+
assert_parse rb, pt
|
658
|
+
|
659
|
+
top_env = processor.env.env.first
|
660
|
+
|
661
|
+
assert_kind_of Hash, top_env
|
662
|
+
|
663
|
+
flip = top_env.find { |k,v| k =~ /^flip/ }
|
664
|
+
|
665
|
+
assert flip
|
666
|
+
assert_equal :lvar, flip.last
|
667
|
+
end
|
668
|
+
|
669
|
+
def test_assoc_list_18
|
670
|
+
rb = "{1, 2, 3, 4}"
|
671
|
+
pt = s(:hash, s(:lit, 1), s(:lit, 2), s(:lit, 3), s(:lit, 4))
|
672
|
+
|
673
|
+
assert_parse rb, pt
|
674
|
+
end
|
675
|
+
|
676
|
+
def test_case_then_colon_18
|
677
|
+
rb = "case x; when Fixnum: 42; end"
|
678
|
+
pt = s(:case,
|
679
|
+
s(:call, nil, :x),
|
680
|
+
s(:when, s(:array, s(:const, :Fixnum)), s(:lit, 42)),
|
681
|
+
nil)
|
682
|
+
|
683
|
+
assert_parse rb, pt
|
684
|
+
end
|
685
|
+
|
686
|
+
def test_do_colon_18
|
687
|
+
rb = "while false : 42 end"
|
688
|
+
pt = s(:while, s(:false), s(:lit, 42), true)
|
689
|
+
|
690
|
+
assert_parse rb, pt
|
691
|
+
end
|
692
|
+
|
693
|
+
def test_parse_until_not_canonical
|
694
|
+
rb = "until not var.nil?\n 'foo'\nend"
|
695
|
+
|
696
|
+
pt = s(:while,
|
697
|
+
s(:call, s(:call, nil, :var), :nil?),
|
698
|
+
s(:str, "foo"), true)
|
699
|
+
|
700
|
+
assert_parse rb, pt
|
701
|
+
end
|
702
|
+
|
703
|
+
def test_parse_until_not_noncanonical
|
704
|
+
rb = "until not var.nil?\n 'foo'\nend"
|
705
|
+
pt = s(:until,
|
706
|
+
s(:not, s(:call, s(:call, nil, :var), :nil?)),
|
707
|
+
s(:str, "foo"), true)
|
708
|
+
|
709
|
+
processor.canonicalize_conditions = false
|
710
|
+
|
711
|
+
assert_parse rb, pt
|
712
|
+
end
|
620
713
|
|
621
714
|
def test_parse_if_not_canonical
|
622
715
|
rb = "if not var.nil? then 'foo' else 'bar'\nend"
|
@@ -631,8 +724,7 @@ module TestRubyParser
|
|
631
724
|
def test_parse_if_not_noncanonical
|
632
725
|
rb = "if not var.nil? then 'foo' else 'bar'\nend"
|
633
726
|
pt = s(:if,
|
634
|
-
s(:not,
|
635
|
-
s(:call, s(:call, nil, :var), :nil?)),
|
727
|
+
s(:not, s(:call, s(:call, nil, :var), :nil?)),
|
636
728
|
s(:str, "foo"),
|
637
729
|
s(:str, "bar"))
|
638
730
|
|
@@ -653,20 +745,151 @@ module TestRubyParser
|
|
653
745
|
def test_parse_while_not_noncanonical
|
654
746
|
rb = "while not var.nil?\n 'foo'\nend"
|
655
747
|
pt = s(:while,
|
656
|
-
s(:not,
|
657
|
-
s(:call, s(:call, nil, :var), :nil?)),
|
748
|
+
s(:not, s(:call, s(:call, nil, :var), :nil?)),
|
658
749
|
s(:str, "foo"), true)
|
659
750
|
|
660
751
|
processor.canonicalize_conditions = false
|
661
752
|
|
662
753
|
assert_parse rb, pt
|
663
754
|
end
|
755
|
+
end
|
756
|
+
|
757
|
+
class TestRuby19Parser < RubyParserTestCase
|
758
|
+
include TestRubyParserShared
|
759
|
+
|
760
|
+
def setup
|
761
|
+
super
|
762
|
+
|
763
|
+
self.processor = Ruby19Parser.new
|
764
|
+
end
|
765
|
+
|
766
|
+
def test_mlhs_back_splat
|
767
|
+
rb = "a, b, c, *s = f"
|
768
|
+
pt = s(:masgn,
|
769
|
+
s(:array,
|
770
|
+
s(:lasgn, :a), s(:lasgn, :b), s(:lasgn, :c),
|
771
|
+
s(:splat, s(:lasgn, :s))),
|
772
|
+
s(:to_ary, s(:call, nil, :f)))
|
773
|
+
|
774
|
+
assert_parse rb, pt
|
775
|
+
end
|
776
|
+
|
777
|
+
def test_mlhs_back_anonsplat
|
778
|
+
rb = "a, b, c, * = f"
|
779
|
+
pt = s(:masgn,
|
780
|
+
s(:array,
|
781
|
+
s(:lasgn, :a), s(:lasgn, :b), s(:lasgn, :c),
|
782
|
+
s(:splat)),
|
783
|
+
s(:to_ary, s(:call, nil, :f)))
|
784
|
+
|
785
|
+
assert_parse rb, pt
|
786
|
+
end
|
787
|
+
|
788
|
+
def test_mlhs_mid_splat
|
789
|
+
rb = "a, b, c, *s, x, y, z = f"
|
790
|
+
pt = s(:masgn,
|
791
|
+
s(:array,
|
792
|
+
s(:lasgn, :a), s(:lasgn, :b), s(:lasgn, :c),
|
793
|
+
s(:splat, s(:lasgn, :s)),
|
794
|
+
s(:lasgn, :x), s(:lasgn, :y), s(:lasgn, :z)),
|
795
|
+
s(:to_ary, s(:call, nil, :f)))
|
796
|
+
|
797
|
+
assert_parse rb, pt
|
798
|
+
end
|
799
|
+
|
800
|
+
def test_mlhs_mid_anonsplat
|
801
|
+
rb = "a, b, c, *, x, y, z = f"
|
802
|
+
pt = s(:masgn,
|
803
|
+
s(:array, s(:lasgn, :a), s(:splat), s(:lasgn, :z)),
|
804
|
+
s(:to_ary, s(:call, nil, :f)))
|
805
|
+
pt = s(:masgn,
|
806
|
+
s(:array,
|
807
|
+
s(:lasgn, :a), s(:lasgn, :b), s(:lasgn, :c),
|
808
|
+
s(:splat),
|
809
|
+
s(:lasgn, :x), s(:lasgn, :y), s(:lasgn, :z)),
|
810
|
+
s(:to_ary, s(:call, nil, :f)))
|
811
|
+
|
812
|
+
assert_parse rb, pt
|
813
|
+
end
|
814
|
+
|
815
|
+
def test_mlhs_front_splat
|
816
|
+
rb = "*s, x, y, z = f"
|
817
|
+
pt = s(:masgn,
|
818
|
+
s(:array, s(:splat, s(:lasgn, :s)), s(:lasgn, :z)),
|
819
|
+
s(:to_ary, s(:call, nil, :f)))
|
820
|
+
pt = s(:masgn,
|
821
|
+
s(:array,
|
822
|
+
s(:splat, s(:lasgn, :s)),
|
823
|
+
s(:lasgn, :x), s(:lasgn, :y), s(:lasgn, :z)),
|
824
|
+
s(:to_ary, s(:call, nil, :f)))
|
825
|
+
|
826
|
+
assert_parse rb, pt
|
827
|
+
end
|
828
|
+
|
829
|
+
def test_mlhs_front_anonsplat
|
830
|
+
rb = "*, x, y, z = f"
|
831
|
+
pt = s(:masgn,
|
832
|
+
s(:array,
|
833
|
+
s(:splat),
|
834
|
+
s(:lasgn, :x), s(:lasgn, :y), s(:lasgn, :z)),
|
835
|
+
s(:to_ary, s(:call, nil, :f)))
|
836
|
+
|
837
|
+
assert_parse rb, pt
|
838
|
+
end
|
839
|
+
|
840
|
+
def test_expr_not_bang
|
841
|
+
rb = "! a b"
|
842
|
+
pt = s(:call, s(:call, nil, :a, s(:call, nil, :b)), :"!")
|
843
|
+
|
844
|
+
assert_parse rb, pt
|
845
|
+
end
|
846
|
+
|
847
|
+
def test_encoding
|
848
|
+
rb = '__ENCODING__'
|
849
|
+
pt = s(:str, "Unsupported!")
|
850
|
+
|
851
|
+
assert_parse rb, pt
|
852
|
+
end
|
853
|
+
|
854
|
+
def test_do_colon_19
|
855
|
+
rb = "while false : 42 end"
|
856
|
+
|
857
|
+
assert_parse_error rb, "parse error on value \":\" (tCOLON)"
|
858
|
+
end
|
859
|
+
|
860
|
+
def test_assoc_list_19
|
861
|
+
rb = "{1, 2, 3, 4}"
|
862
|
+
|
863
|
+
assert_parse_error rb, "parse error on value \",\" (tCOMMA)"
|
864
|
+
end
|
865
|
+
|
866
|
+
def test_case_then_colon_19
|
867
|
+
rb = <<-EOM
|
868
|
+
case x
|
869
|
+
when Fixnum : # need the space to not hit new hash arg syntax
|
870
|
+
42
|
871
|
+
end
|
872
|
+
EOM
|
873
|
+
|
874
|
+
assert_parse_error rb, "parse error on value \":\" (tCOLON)"
|
875
|
+
end
|
876
|
+
|
877
|
+
def test_parse_def_xxx1
|
878
|
+
rb = 'def f(a, *b, c = nil) end'
|
879
|
+
|
880
|
+
assert_parse_error rb, 'parse error on value "=" (tEQL)'
|
881
|
+
end
|
882
|
+
|
883
|
+
def test_parse_def_xxx2
|
884
|
+
rb = 'def f(a = nil, *b, c = nil) end'
|
885
|
+
|
886
|
+
assert_parse_error rb, 'parse error on value "=" (tEQL)'
|
887
|
+
end
|
664
888
|
|
665
889
|
def test_parse_until_not_canonical
|
666
890
|
rb = "until not var.nil?\n 'foo'\nend"
|
667
|
-
|
668
|
-
|
669
|
-
s(:call, s(:call, nil, :var), :nil?),
|
891
|
+
pt = s(:until,
|
892
|
+
s(:call, s(:call, s(:call, nil, :var), :nil?), :"!"),
|
670
893
|
s(:str, "foo"), true)
|
671
894
|
|
672
895
|
assert_parse rb, pt
|
@@ -675,49 +898,61 @@ module TestRubyParser
|
|
675
898
|
def test_parse_until_not_noncanonical
|
676
899
|
rb = "until not var.nil?\n 'foo'\nend"
|
677
900
|
pt = s(:until,
|
678
|
-
s(:
|
679
|
-
s(:call, s(:call, nil, :var), :nil?)),
|
901
|
+
s(:call, s(:call, s(:call, nil, :var), :nil?), :"!"),
|
680
902
|
s(:str, "foo"), true)
|
681
903
|
|
682
904
|
processor.canonicalize_conditions = false
|
683
905
|
|
684
906
|
assert_parse rb, pt
|
685
907
|
end
|
686
|
-
end
|
687
908
|
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
909
|
+
def test_parse_if_not_canonical
|
910
|
+
rb = "if not var.nil? then 'foo' else 'bar'\nend"
|
911
|
+
pt = s(:if,
|
912
|
+
s(:call, s(:call, s(:call, nil, :var), :nil?), :"!"),
|
913
|
+
s(:str, "foo"),
|
914
|
+
s(:str, "bar"))
|
693
915
|
|
694
|
-
|
916
|
+
assert_parse rb, pt
|
695
917
|
end
|
696
918
|
|
697
|
-
def
|
698
|
-
rb = "if
|
699
|
-
pt = s(:if,
|
919
|
+
def test_parse_if_not_noncanonical
|
920
|
+
rb = "if not var.nil? then 'foo' else 'bar'\nend"
|
921
|
+
pt = s(:if,
|
922
|
+
s(:call, s(:call, s(:call, nil, :var), :nil?), :"!"),
|
923
|
+
s(:str, "foo"),
|
924
|
+
s(:str, "bar"))
|
925
|
+
|
926
|
+
processor.canonicalize_conditions = false
|
700
927
|
|
701
928
|
assert_parse rb, pt
|
929
|
+
end
|
702
930
|
|
703
|
-
|
931
|
+
def test_parse_while_not_canonical
|
932
|
+
rb = "while not var.nil?\n 'foo'\nend"
|
933
|
+
pt = s(:while,
|
934
|
+
s(:call, s(:call, s(:call, nil, :var), :nil?), :"!"),
|
935
|
+
s(:str, "foo"), true)
|
704
936
|
|
705
|
-
|
937
|
+
assert_parse rb, pt
|
938
|
+
end
|
706
939
|
|
707
|
-
|
940
|
+
def test_parse_while_not_noncanonical
|
941
|
+
rb = "while not var.nil?\n 'foo'\nend"
|
942
|
+
pt = s(:while,
|
943
|
+
s(:call, s(:call, s(:call, nil, :var), :nil?), :"!"),
|
944
|
+
s(:str, "foo"), true)
|
708
945
|
|
709
|
-
|
710
|
-
assert_equal :lvar, flip.last
|
711
|
-
end
|
712
|
-
end
|
946
|
+
processor.canonicalize_conditions = false
|
713
947
|
|
714
|
-
|
715
|
-
|
948
|
+
assert_parse rb, pt
|
949
|
+
end
|
716
950
|
|
717
|
-
def
|
718
|
-
|
951
|
+
def test_parse_opt_call_args_assocs_comma
|
952
|
+
rb = "1[2=>3,]"
|
953
|
+
pt = s(:call, s(:lit, 1), :[], s(:lit, 2), s(:lit, 3))
|
719
954
|
|
720
|
-
|
955
|
+
assert_parse rb, pt
|
721
956
|
end
|
722
957
|
|
723
958
|
# HACK: need to figure out the desired structure and get this working
|