ruby_parser 3.0.0.a2 → 3.0.0.a3
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.
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
|