ruby_parser 3.0.0.a8 → 3.0.0.a9
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 +6 -0
- data/History.txt +40 -0
- data/README.txt +6 -11
- data/Rakefile +5 -0
- data/bin/ruby_parse_extract_error +23 -6
- data/lib/ruby18_parser.rb +18 -8
- data/lib/ruby18_parser.y +18 -8
- data/lib/ruby19_parser.rb +67 -35
- data/lib/ruby19_parser.y +62 -32
- data/lib/ruby_lexer.rb +84 -95
- data/lib/ruby_parser_extras.rb +140 -20
- data/test/test_ruby_lexer.rb +58 -3
- data/test/test_ruby_parser.rb +193 -2
- data/test/test_ruby_parser_extras.rb +109 -0
- metadata +17 -22
- metadata.gz.sig +5 -2
data/lib/ruby_parser_extras.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
1
3
|
require 'stringio'
|
2
4
|
require 'racc/parser'
|
3
5
|
require 'sexp'
|
@@ -54,7 +56,11 @@ class RPStringScanner < StringScanner
|
|
54
56
|
def unread_many str # TODO: remove this entirely - we should not need it
|
55
57
|
warn({:unread_many => caller[0]}.inspect) if ENV['TALLY']
|
56
58
|
self.extra_lines_added += str.count("\n")
|
57
|
-
|
59
|
+
begin
|
60
|
+
string[pos, 0] = str
|
61
|
+
rescue IndexError
|
62
|
+
# HACK -- this is a bandaid on a dirty rag on an open festering wound
|
63
|
+
end
|
58
64
|
end
|
59
65
|
|
60
66
|
if ENV['DEBUG'] then
|
@@ -79,11 +85,15 @@ class RPStringScanner < StringScanner
|
|
79
85
|
end
|
80
86
|
|
81
87
|
module RubyParserStuff
|
82
|
-
VERSION = '3.0.0.
|
88
|
+
VERSION = '3.0.0.a9' unless constants.include? "VERSION" # SIGH
|
83
89
|
|
84
90
|
attr_accessor :lexer, :in_def, :in_single, :file
|
85
91
|
attr_reader :env, :comments
|
86
92
|
|
93
|
+
def syntax_error msg
|
94
|
+
raise RubyParser::SyntaxError, msg
|
95
|
+
end
|
96
|
+
|
87
97
|
def arg_add(node1, node2) # TODO: nuke
|
88
98
|
return s(:arglist, node2) unless node1
|
89
99
|
|
@@ -192,7 +202,7 @@ module RubyParserStuff
|
|
192
202
|
def block_args19 val, id
|
193
203
|
# HACK OMG THIS CODE IS SOOO UGLY! CLEAN ME
|
194
204
|
untested = %w[1 2 3 4 7 9 10 12 14]
|
195
|
-
raise "no block_args19 #{id} #{val.inspect}" if untested.include? id
|
205
|
+
raise "no block_args19 #{id}\non: #{val.inspect}" if untested.include? id
|
196
206
|
|
197
207
|
r = s(:array)
|
198
208
|
|
@@ -247,7 +257,7 @@ module RubyParserStuff
|
|
247
257
|
raise "oh noes!: #{r.inspect}"
|
248
258
|
end
|
249
259
|
else
|
250
|
-
raise "
|
260
|
+
raise "totally borked: #{r.inspect}"
|
251
261
|
end
|
252
262
|
|
253
263
|
r
|
@@ -261,6 +271,8 @@ module RubyParserStuff
|
|
261
271
|
id = lhs.to_sym
|
262
272
|
id = id.to_sym if Sexp === id
|
263
273
|
|
274
|
+
raise "write a test 1" if id.to_s =~ /^(?:self|nil|true|false|__LINE__|__FILE__)$/
|
275
|
+
|
264
276
|
raise SyntaxError, "Can't change the value of #{id}" if
|
265
277
|
id.to_s =~ /^(?:self|nil|true|false|__LINE__|__FILE__)$/
|
266
278
|
|
@@ -547,8 +559,10 @@ module RubyParserStuff
|
|
547
559
|
# TODO: need a test for this... obviously
|
548
560
|
case ref.first
|
549
561
|
when :nth_ref then
|
562
|
+
raise "write a test 2"
|
550
563
|
raise SyntaxError, "Can't set variable %p" % ref.last
|
551
564
|
when :back_ref then
|
565
|
+
raise "write a test 3"
|
552
566
|
raise SyntaxError, "Can't set back reference %p" % ref.last
|
553
567
|
else
|
554
568
|
raise "Unknown backref type: #{ref.inspect}"
|
@@ -861,6 +875,7 @@ module RubyParserStuff
|
|
861
875
|
|
862
876
|
def new_yield args = nil
|
863
877
|
# TODO: raise args.inspect unless [:arglist].include? args.first # HACK
|
878
|
+
raise "write a test 4" if args && args.node_type == :block_pass
|
864
879
|
raise SyntaxError, "Block argument should not be given." if
|
865
880
|
args && args.node_type == :block_pass
|
866
881
|
|
@@ -902,6 +917,99 @@ module RubyParserStuff
|
|
902
917
|
lhs
|
903
918
|
end
|
904
919
|
|
920
|
+
##
|
921
|
+
# Returns a UTF-8 encoded string after processing BOMs and magic
|
922
|
+
# encoding comments.
|
923
|
+
#
|
924
|
+
# Holy crap... ok. Here goes:
|
925
|
+
#
|
926
|
+
# Ruby's file handling and encoding support is insane. We need to be
|
927
|
+
# able to lex a file. The lexer file is explicitly UTF-8 to make
|
928
|
+
# things cleaner. This allows us to deal with extended chars in
|
929
|
+
# class and method names. In order to do this, we need to encode all
|
930
|
+
# input source files as UTF-8. First, we look for a UTF-8 BOM by
|
931
|
+
# looking at the first line while forcing its encoding to
|
932
|
+
# ASCII-8BIT. If we find a BOM, we strip it and set the expected
|
933
|
+
# encoding to UTF-8. Then, we search for a magic encoding comment.
|
934
|
+
# If found, it overrides the BOM. Finally, we force the encoding of
|
935
|
+
# the input string to whatever was found, and then encode that to
|
936
|
+
# UTF-8 for compatibility with the lexer.
|
937
|
+
|
938
|
+
def handle_encoding str
|
939
|
+
str = str.dup
|
940
|
+
ruby19 = str.respond_to? :encoding
|
941
|
+
encoding = nil
|
942
|
+
|
943
|
+
header = str.lines.first(2)
|
944
|
+
header.map! { |s| s.force_encoding "ASCII-8BIT" } if ruby19
|
945
|
+
|
946
|
+
first = header.first || ""
|
947
|
+
encoding, str = "utf-8", str[3..-1] if first =~ /\A\xEF\xBB\xBF/
|
948
|
+
|
949
|
+
encoding = $1.strip if header.find { |s|
|
950
|
+
s[/^#.*?-\*-.*?coding:\s*([^ ;]+).*?-\*-/, 1] ||
|
951
|
+
s[/^#.*(?:en)?coding(?:\s*[:=])\s*([\w-]+)/, 1]
|
952
|
+
}
|
953
|
+
|
954
|
+
if encoding then
|
955
|
+
if ruby19 then
|
956
|
+
encoding.sub!(/utf-8-.+$/, 'utf-8') # HACK for stupid emacs formats
|
957
|
+
hack_encoding str, encoding
|
958
|
+
else
|
959
|
+
warn "Skipping magic encoding comment"
|
960
|
+
end
|
961
|
+
else
|
962
|
+
# nothing specified... ugh. try to encode as utf-8
|
963
|
+
if ruby19 then
|
964
|
+
begin
|
965
|
+
str.encode! "utf-8"
|
966
|
+
rescue Encoding::InvalidByteSequenceError, Encoding::UndefinedConversionError
|
967
|
+
# OK... You really suck. You have extended chars but didn't
|
968
|
+
# specify what they were. Now we try to force it and double
|
969
|
+
# check that it is valid.
|
970
|
+
|
971
|
+
hack_encoding str
|
972
|
+
end
|
973
|
+
end
|
974
|
+
end
|
975
|
+
|
976
|
+
str
|
977
|
+
end
|
978
|
+
|
979
|
+
def hack_encoding str, extra = nil
|
980
|
+
# this is in sorted order of occurrence according to
|
981
|
+
# charlock_holmes against 500k files
|
982
|
+
encodings = [
|
983
|
+
extra,
|
984
|
+
Encoding::ISO_8859_1,
|
985
|
+
Encoding::UTF_8,
|
986
|
+
Encoding::ISO_8859_2,
|
987
|
+
Encoding::ISO_8859_9,
|
988
|
+
Encoding::SHIFT_JIS,
|
989
|
+
Encoding::WINDOWS_1252,
|
990
|
+
Encoding::EUC_JP,
|
991
|
+
].compact
|
992
|
+
|
993
|
+
# terrible, horrible, no good, very bad, last ditch effort.
|
994
|
+
encodings.each do |enc|
|
995
|
+
begin
|
996
|
+
str.force_encoding enc
|
997
|
+
if str.valid_encoding? then
|
998
|
+
str.encode! Encoding::UTF_8
|
999
|
+
break
|
1000
|
+
end
|
1001
|
+
rescue Encoding::InvalidByteSequenceError
|
1002
|
+
# do nothing
|
1003
|
+
rescue Encoding::UndefinedConversionError
|
1004
|
+
# do nothing
|
1005
|
+
end
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
# no amount of pain is enough for you.
|
1009
|
+
raise "Bad encoding. Need a magic encoding comment." unless
|
1010
|
+
str.encoding.name == "UTF-8"
|
1011
|
+
end
|
1012
|
+
|
905
1013
|
##
|
906
1014
|
# Parse +str+ at path +file+ and return a sexp. Raises
|
907
1015
|
# Timeout::Error if it runs for more than +time+ seconds.
|
@@ -910,20 +1018,9 @@ module RubyParserStuff
|
|
910
1018
|
Timeout.timeout time do
|
911
1019
|
raise "bad val: #{str.inspect}" unless String === str
|
912
1020
|
|
913
|
-
str
|
914
|
-
encoding = $1
|
915
|
-
|
916
|
-
str = str.dup
|
917
|
-
|
918
|
-
if encoding then
|
919
|
-
if defined?(Encoding) then
|
920
|
-
str.force_encoding(encoding).encode! "utf-8"
|
921
|
-
else
|
922
|
-
warn "Skipping magic encoding comment"
|
923
|
-
end
|
924
|
-
end
|
1021
|
+
str = handle_encoding str
|
925
1022
|
|
926
|
-
self.file = file
|
1023
|
+
self.file = file.dup
|
927
1024
|
self.lexer.src = str
|
928
1025
|
|
929
1026
|
@yydebug = ENV.has_key? 'DEBUG'
|
@@ -951,8 +1048,15 @@ module RubyParserStuff
|
|
951
1048
|
self.comments.clear
|
952
1049
|
end
|
953
1050
|
|
1051
|
+
def block_dup_check call_or_args, block
|
1052
|
+
syntax_error "Both block arg and actual block given." if
|
1053
|
+
block and call_or_args.block_pass?
|
1054
|
+
end
|
1055
|
+
|
954
1056
|
def ret_args node
|
955
1057
|
if node then
|
1058
|
+
raise "write a test 5" if node[0] == :block_pass
|
1059
|
+
|
956
1060
|
raise SyntaxError, "block argument should not be given" if
|
957
1061
|
node[0] == :block_pass
|
958
1062
|
|
@@ -1169,11 +1273,14 @@ module RubyParserStuff
|
|
1169
1273
|
end
|
1170
1274
|
|
1171
1275
|
class StackState
|
1276
|
+
attr_reader :name
|
1172
1277
|
attr_reader :stack
|
1278
|
+
attr_accessor :debug
|
1173
1279
|
|
1174
1280
|
def initialize(name)
|
1175
1281
|
@name = name
|
1176
1282
|
@stack = [false]
|
1283
|
+
@debug = false
|
1177
1284
|
end
|
1178
1285
|
|
1179
1286
|
def inspect
|
@@ -1181,10 +1288,12 @@ module RubyParserStuff
|
|
1181
1288
|
end
|
1182
1289
|
|
1183
1290
|
def is_in_state
|
1291
|
+
p :stack_is_in_state => [name, @stack.last, caller.first] if debug
|
1184
1292
|
@stack.last
|
1185
1293
|
end
|
1186
1294
|
|
1187
1295
|
def lexpop
|
1296
|
+
p :stack_lexpop => caller.first if debug
|
1188
1297
|
raise if @stack.size == 0
|
1189
1298
|
a = @stack.pop
|
1190
1299
|
b = @stack.pop
|
@@ -1193,12 +1302,15 @@ module RubyParserStuff
|
|
1193
1302
|
|
1194
1303
|
def pop
|
1195
1304
|
r = @stack.pop
|
1305
|
+
p :stack_pop => [name, r, @stack, caller.first] if debug
|
1196
1306
|
@stack.push false if @stack.size == 0
|
1197
1307
|
r
|
1198
1308
|
end
|
1199
1309
|
|
1200
1310
|
def push val
|
1201
1311
|
@stack.push val
|
1312
|
+
p :stack_push => [name, @stack, caller.first] if debug
|
1313
|
+
nil
|
1202
1314
|
end
|
1203
1315
|
end
|
1204
1316
|
end
|
@@ -1217,6 +1329,8 @@ end
|
|
1217
1329
|
# parse error.
|
1218
1330
|
|
1219
1331
|
class RubyParser
|
1332
|
+
class SyntaxError < RuntimeError; end
|
1333
|
+
|
1220
1334
|
def initialize
|
1221
1335
|
@p18 = Ruby18Parser.new
|
1222
1336
|
@p19 = Ruby19Parser.new
|
@@ -1239,9 +1353,11 @@ end
|
|
1239
1353
|
############################################################
|
1240
1354
|
# HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK
|
1241
1355
|
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1356
|
+
unless "".respond_to?(:grep) then
|
1357
|
+
class String
|
1358
|
+
def grep re
|
1359
|
+
lines.grep re
|
1360
|
+
end
|
1245
1361
|
end
|
1246
1362
|
end
|
1247
1363
|
|
@@ -1270,6 +1386,10 @@ class Sexp
|
|
1270
1386
|
raise "no: #{self.inspect}.add_all #{x.inspect}" # TODO: need a test to trigger this
|
1271
1387
|
end
|
1272
1388
|
|
1389
|
+
def block_pass?
|
1390
|
+
any? { |s| Sexp === s && s[0] == :block_pass }
|
1391
|
+
end
|
1392
|
+
|
1273
1393
|
alias :node_type :sexp_type
|
1274
1394
|
alias :values :sexp_body # TODO: retire
|
1275
1395
|
end
|
data/test/test_ruby_lexer.rb
CHANGED
@@ -318,7 +318,7 @@ class TestRubyLexer < MiniTest::Unit::TestCase
|
|
318
318
|
end
|
319
319
|
|
320
320
|
def test_yylex_cvar_bad
|
321
|
-
assert_raises SyntaxError do
|
321
|
+
assert_raises RubyParser::SyntaxError do
|
322
322
|
util_lex_token "@@1"
|
323
323
|
end
|
324
324
|
end
|
@@ -744,6 +744,22 @@ class TestRubyLexer < MiniTest::Unit::TestCase
|
|
744
744
|
:tASSOC, "=>")
|
745
745
|
end
|
746
746
|
|
747
|
+
def test_yylex_identifier_equals3
|
748
|
+
# @lex.lex_state = :expr_fname
|
749
|
+
util_lex_token(":a===b",
|
750
|
+
:tSYMBOL, "a",
|
751
|
+
:tEQQ, "===",
|
752
|
+
:tIDENTIFIER, "b")
|
753
|
+
end
|
754
|
+
|
755
|
+
def test_yylex_identifier_equals_equals_arrow
|
756
|
+
# @lex.lex_state = :expr_fname
|
757
|
+
util_lex_token(":a==>b",
|
758
|
+
:tSYMBOL, "a=",
|
759
|
+
:tASSOC, "=>",
|
760
|
+
:tIDENTIFIER, "b")
|
761
|
+
end
|
762
|
+
|
747
763
|
def test_yylex_identifier_equals_caret
|
748
764
|
util_lex_fname "^", :tCARET
|
749
765
|
end
|
@@ -1136,6 +1152,45 @@ class TestRubyLexer < MiniTest::Unit::TestCase
|
|
1136
1152
|
util_lex_token "+@", :tUPLUS, "+@"
|
1137
1153
|
end
|
1138
1154
|
|
1155
|
+
def test_yylex_numbers
|
1156
|
+
util_lex_token "0b10", :tINTEGER, 2
|
1157
|
+
util_lex_token "0B10", :tINTEGER, 2
|
1158
|
+
|
1159
|
+
util_lex_token "0d10", :tINTEGER, 10
|
1160
|
+
util_lex_token "0D10", :tINTEGER, 10
|
1161
|
+
|
1162
|
+
util_lex_token "0x10", :tINTEGER, 16
|
1163
|
+
util_lex_token "0X10", :tINTEGER, 16
|
1164
|
+
|
1165
|
+
util_lex_token "0o10", :tINTEGER, 8
|
1166
|
+
util_lex_token "0O10", :tINTEGER, 8
|
1167
|
+
util_lex_token "0o", :tINTEGER, 0
|
1168
|
+
util_lex_token "0O", :tINTEGER, 0
|
1169
|
+
|
1170
|
+
util_lex_token "0o", :tINTEGER, 0
|
1171
|
+
util_lex_token "0O", :tINTEGER, 0
|
1172
|
+
|
1173
|
+
util_lex_token "0", :tINTEGER, 0
|
1174
|
+
|
1175
|
+
util_bad_token "0x"
|
1176
|
+
util_bad_token "0X"
|
1177
|
+
util_bad_token "0b"
|
1178
|
+
util_bad_token "0B"
|
1179
|
+
util_bad_token "0d"
|
1180
|
+
util_bad_token "0D"
|
1181
|
+
|
1182
|
+
util_bad_token "08"
|
1183
|
+
util_bad_token "09"
|
1184
|
+
util_bad_token "0o8"
|
1185
|
+
util_bad_token "0o9"
|
1186
|
+
util_bad_token "0O8"
|
1187
|
+
util_bad_token "0O9"
|
1188
|
+
|
1189
|
+
util_bad_token "1_e1"
|
1190
|
+
util_bad_token "1_.1"
|
1191
|
+
util_bad_token "1__1"
|
1192
|
+
end
|
1193
|
+
|
1139
1194
|
def test_yylex_plus_unary_number
|
1140
1195
|
util_lex_token("+42",
|
1141
1196
|
:tINTEGER, 42)
|
@@ -1867,7 +1922,7 @@ class TestRubyLexer < MiniTest::Unit::TestCase
|
|
1867
1922
|
############################################################
|
1868
1923
|
|
1869
1924
|
def util_bad_token s, *args
|
1870
|
-
assert_raises SyntaxError do
|
1925
|
+
assert_raises RubyParser::SyntaxError do
|
1871
1926
|
util_lex_token s, *args
|
1872
1927
|
end
|
1873
1928
|
end
|
@@ -1879,7 +1934,7 @@ class TestRubyLexer < MiniTest::Unit::TestCase
|
|
1879
1934
|
|
1880
1935
|
def util_escape_bad input
|
1881
1936
|
@lex.src = input
|
1882
|
-
assert_raises SyntaxError do
|
1937
|
+
assert_raises RubyParser::SyntaxError do
|
1883
1938
|
@lex.read_escape
|
1884
1939
|
end
|
1885
1940
|
end
|
data/test/test_ruby_parser.rb
CHANGED
@@ -33,6 +33,17 @@ class RubyParserTestCase < ParseTreeTestCase
|
|
33
33
|
assert_equal pt, result
|
34
34
|
end
|
35
35
|
|
36
|
+
def assert_syntax_error rb, emsg
|
37
|
+
e = nil
|
38
|
+
assert_silent do
|
39
|
+
e = assert_raises RubyParser::SyntaxError do
|
40
|
+
processor.parse rb
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
assert_equal emsg, e.message.strip # TODO: why strip?
|
45
|
+
end
|
46
|
+
|
36
47
|
def assert_parse_error rb, emsg
|
37
48
|
e = nil
|
38
49
|
out, err = capture_io do
|
@@ -59,6 +70,58 @@ module TestRubyParserShared
|
|
59
70
|
# p :test => [self.class, __name__]
|
60
71
|
end
|
61
72
|
|
73
|
+
BLOCK_DUP_MSG = "Both block arg and actual block given."
|
74
|
+
|
75
|
+
def test_double_block_error_01
|
76
|
+
assert_syntax_error "a(1, &b) { }", BLOCK_DUP_MSG
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_double_block_error_02
|
80
|
+
assert_syntax_error "a(1, &b) do end", BLOCK_DUP_MSG
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_double_block_error_03
|
84
|
+
assert_syntax_error "a 1, &b do end", BLOCK_DUP_MSG
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_double_block_error_04
|
88
|
+
assert_syntax_error "m.a(1, &b) { }", BLOCK_DUP_MSG
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_double_block_error_05
|
92
|
+
assert_syntax_error "m.a(1, &b) do end", BLOCK_DUP_MSG
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_double_block_error_06
|
96
|
+
assert_syntax_error "m.a 1, &b do end", BLOCK_DUP_MSG
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_double_block_error_07
|
100
|
+
assert_syntax_error "m::a(1, &b) { }", BLOCK_DUP_MSG
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_double_block_error_08
|
104
|
+
assert_syntax_error "m::a(1, &b) do end", BLOCK_DUP_MSG
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_double_block_error_09
|
108
|
+
assert_syntax_error "m::a 1, &b do end", BLOCK_DUP_MSG
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_wtf_7
|
112
|
+
assert_parse "a.b (1) {c}", s(:iter,
|
113
|
+
s(:call, s(:call, nil, :a), :b, s(:lit, 1)),
|
114
|
+
nil,
|
115
|
+
s(:call, nil, :c))
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_wtf_8
|
119
|
+
assert_parse "a::b (1) {c}", s(:iter,
|
120
|
+
s(:call, s(:call, nil, :a), :b, s(:lit, 1)),
|
121
|
+
nil,
|
122
|
+
s(:call, nil, :c))
|
123
|
+
end
|
124
|
+
|
62
125
|
def test_attrasgn_array_lhs
|
63
126
|
rb = '[1, 2, 3, 4][from .. to] = ["a", "b", "c"]'
|
64
127
|
pt = s(:attrasgn,
|
@@ -808,6 +871,8 @@ module TestRubyParserShared
|
|
808
871
|
end
|
809
872
|
EOM
|
810
873
|
|
874
|
+
rb.force_encoding "ASCII-8BIT" if rb.respond_to? :force_encoding
|
875
|
+
|
811
876
|
# TODO: class vars
|
812
877
|
# TODO: odd-ternary: a ?bb : c
|
813
878
|
# TODO: globals
|
@@ -968,6 +1033,34 @@ class TestRuby18Parser < RubyParserTestCase
|
|
968
1033
|
|
969
1034
|
assert_parse rb, pt
|
970
1035
|
end
|
1036
|
+
|
1037
|
+
def test_double_block_error_10
|
1038
|
+
assert_syntax_error "a.b (&b) {}", BLOCK_DUP_MSG
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
def test_double_block_error_11
|
1042
|
+
assert_syntax_error "a (1, &b) { }", BLOCK_DUP_MSG
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
def test_double_block_error_12
|
1046
|
+
assert_syntax_error "a (1, &b) do end", BLOCK_DUP_MSG
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
def test_double_block_error_13
|
1050
|
+
assert_syntax_error "m.a (1, &b) { }", BLOCK_DUP_MSG
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
def test_double_block_error_14
|
1054
|
+
assert_syntax_error "m.a (1, &b) do end", BLOCK_DUP_MSG
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
def test_double_block_error_15
|
1058
|
+
assert_syntax_error "m::a (1, &b) { }", BLOCK_DUP_MSG
|
1059
|
+
end
|
1060
|
+
|
1061
|
+
def test_double_block_error_16
|
1062
|
+
assert_syntax_error "m::a (1, &b) do end", BLOCK_DUP_MSG
|
1063
|
+
end
|
971
1064
|
end
|
972
1065
|
|
973
1066
|
class TestRuby19Parser < RubyParserTestCase
|
@@ -1193,7 +1286,7 @@ class TestRuby19Parser < RubyParserTestCase
|
|
1193
1286
|
rb = "a { |b = 1| }"
|
1194
1287
|
pt = s(:iter,
|
1195
1288
|
s(:call, nil, :a),
|
1196
|
-
s(:
|
1289
|
+
s(:args, :b, s(:block, s(:lasgn, :b, s(:lit, 1)))))
|
1197
1290
|
|
1198
1291
|
assert_parse rb, pt
|
1199
1292
|
end
|
@@ -1238,7 +1331,7 @@ class TestRuby19Parser < RubyParserTestCase
|
|
1238
1331
|
# pt = s(:iter,
|
1239
1332
|
# s(:call, nil, :lambda),
|
1240
1333
|
# s(:args, :a, :b,
|
1241
|
-
# s(:block, s(:lasgn, :b, s(nil)))),
|
1334
|
+
# s(:block, s(:lasgn, :b, s(:nil)))),
|
1242
1335
|
# s(:call, nil, :p, s(:array, s(:lvar, :a), s(:lvar, :b))))
|
1243
1336
|
#
|
1244
1337
|
# assert_parse rb, pt
|
@@ -1247,4 +1340,102 @@ class TestRuby19Parser < RubyParserTestCase
|
|
1247
1340
|
#
|
1248
1341
|
# assert_parse rb, pt
|
1249
1342
|
# end
|
1343
|
+
|
1344
|
+
def test_block_args_opt1
|
1345
|
+
rb = "f { |a, b = 42| [a, b] }"
|
1346
|
+
pt = s(:iter,
|
1347
|
+
s(:call, nil, :f),
|
1348
|
+
s(:args, :a, :b,
|
1349
|
+
s(:block, s(:lasgn, :b, s(:lit, 42)))),
|
1350
|
+
s(:array, s(:lvar, :a), s(:lvar, :b)))
|
1351
|
+
|
1352
|
+
assert_parse rb, pt
|
1353
|
+
end
|
1354
|
+
|
1355
|
+
def test_block_args_opt2
|
1356
|
+
rb = "f { |a, b = 42, c = 24| [a, b, c] }"
|
1357
|
+
pt = s(:iter,
|
1358
|
+
s(:call, nil, :f),
|
1359
|
+
s(:args, :a, :b, :c,
|
1360
|
+
s(:block, s(:lasgn, :b, s(:lit, 42)), s(:lasgn, :c, s(:lit, 24)))),
|
1361
|
+
s(:array, s(:lvar, :a), s(:lvar, :b), s(:lvar, :c)))
|
1362
|
+
|
1363
|
+
assert_parse rb, pt
|
1364
|
+
end
|
1365
|
+
|
1366
|
+
def test_block_args_opt3
|
1367
|
+
rb = "f { |a, b = 42, c = 24, &d| [a, b, c, d] }"
|
1368
|
+
pt = s(:iter,
|
1369
|
+
s(:call, nil, :f),
|
1370
|
+
s(:args, :a, :b, :c, :"&d",
|
1371
|
+
s(:block, s(:lasgn, :b, s(:lit, 42)), s(:lasgn, :c, s(:lit, 24)))),
|
1372
|
+
s(:array, s(:lvar, :a), s(:lvar, :b), s(:lvar, :c), s(:lvar, :d)))
|
1373
|
+
|
1374
|
+
assert_parse rb, pt
|
1375
|
+
end
|
1376
|
+
|
1377
|
+
def test_i_have_no_freakin_clue
|
1378
|
+
rb = "1 ? b('') : 2\na d: 3"
|
1379
|
+
pt = s(:block,
|
1380
|
+
s(:if, s(:lit, 1), s(:call, nil, :b, s(:str, "")), s(:lit, 2)),
|
1381
|
+
s(:call, nil, :a, s(:hash, s(:lit, :d), s(:lit, 3))))
|
1382
|
+
|
1383
|
+
assert_parse rb, pt
|
1384
|
+
end
|
1385
|
+
|
1386
|
+
def test_motherfuckin_leading_dots
|
1387
|
+
rb = "a\n.b"
|
1388
|
+
pt = s(:call, s(:call, nil, :a), :b)
|
1389
|
+
|
1390
|
+
assert_parse rb, pt
|
1391
|
+
end
|
1392
|
+
|
1393
|
+
def test_motherfuckin_leading_dots2
|
1394
|
+
rb = "a\n..b"
|
1395
|
+
|
1396
|
+
assert_parse_error rb, 'parse error on value ".." (tDOT2)'
|
1397
|
+
end
|
1398
|
+
|
1399
|
+
def test_kill_me
|
1400
|
+
rb = "f { |a, (b, *c)| }"
|
1401
|
+
pt = s(:iter,
|
1402
|
+
s(:call, nil, :f),
|
1403
|
+
s(:masgn,
|
1404
|
+
s(:array,
|
1405
|
+
s(:lasgn, :a),
|
1406
|
+
s(:masgn,
|
1407
|
+
s(:array,
|
1408
|
+
s(:lasgn, :b),
|
1409
|
+
s(:splat, :c)))))) # TODO: omg this is so horrible
|
1410
|
+
|
1411
|
+
assert_parse rb, pt
|
1412
|
+
end
|
1413
|
+
|
1414
|
+
def test_kill_me2
|
1415
|
+
rb = "f { |*a, b| }"
|
1416
|
+
pt = s(:iter, s(:call, nil, :f), s(:args, :"*a", :b))
|
1417
|
+
|
1418
|
+
assert_parse rb, pt
|
1419
|
+
end
|
1420
|
+
|
1421
|
+
def test_kill_me3
|
1422
|
+
rb = "f { |*a, b, &c| }"
|
1423
|
+
pt = s(:iter, s(:call, nil, :f), s(:args, :"*a", :b, :"&c"))
|
1424
|
+
|
1425
|
+
assert_parse rb, pt
|
1426
|
+
end
|
1427
|
+
|
1428
|
+
def test_kill_me4
|
1429
|
+
rb = "a=b ? true: false"
|
1430
|
+
pt = s(:lasgn, :a, s(:if, s(:call, nil, :b), s(:true), s(:false)))
|
1431
|
+
|
1432
|
+
assert_parse rb, pt
|
1433
|
+
end
|
1434
|
+
|
1435
|
+
# def test_kill_me5
|
1436
|
+
# rb = "f ->() { g do end }"
|
1437
|
+
# pt = 42
|
1438
|
+
#
|
1439
|
+
# assert_parse rb, pt
|
1440
|
+
# end
|
1250
1441
|
end
|