Include the first constant name into `Ractor::IsolationError` message
[ruby.git] / test / ruby / test_parse.rb
blobb6d306352ce276d46a15442277e72061e6270599
1 # coding: US-ASCII
2 # frozen_string_literal: false
3 require 'test/unit'
4 require 'stringio'
6 class TestParse < Test::Unit::TestCase
7   def setup
8     @verbose = $VERBOSE
9   end
11   def teardown
12     $VERBOSE = @verbose
13   end
15   def test_error_line
16     assert_syntax_error('------,,', /\n\z/, 'Message to pipe should end with a newline')
17     assert_syntax_error("{hello\n  world}", /hello/)
18   end
20   def test_else_without_rescue
21     assert_syntax_error(<<-END, %r":#{__LINE__+2}: else without rescue"o, [__FILE__, __LINE__+1])
22       begin
23       else
24         42
25       end
26     END
27   end
29   def test_alias_backref
30     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /can't make alias/) do
31       begin;
32         alias $foo $1
33       end;
34     end
35   end
37   def test_command_call
38     t = Object.new
39     def t.foo(x); x; end
41     a = false
42     b = c = d = true
43     assert_nothing_raised do
44       eval <<-END, nil, __FILE__, __LINE__+1
45         a &&= t.foo 42
46         b &&= t.foo 42
47         c &&= t.foo nil
48         d &&= t.foo false
49       END
50     end
51     assert_equal([false, 42, nil, false], [a, b, c, d])
53     a = 3
54     assert_nothing_raised { eval("a &= t.foo 5") }
55     assert_equal(1, a)
57     a = [nil, nil, true, true]
58     assert_nothing_raised do
59       eval <<-END, nil, __FILE__, __LINE__+1
60         a[0] ||= t.foo 42
61         a[1] &&= t.foo 42
62         a[2] ||= t.foo 42
63         a[3] &&= t.foo 42
64       END
65     end
66     assert_equal([42, nil, true, 42], a)
68     o = Object.new
69     class << o
70       attr_accessor :foo, :bar, :Foo, :Bar, :baz, :qux
71     end
72     o.foo = o.Foo = o::baz = nil
73     o.bar = o.Bar = o::qux = 1
74     assert_nothing_raised do
75       eval <<-END, nil, __FILE__, __LINE__+1
76         o.foo ||= t.foo 42
77         o.bar &&= t.foo 42
78         o.Foo ||= t.foo 42
79         o.Bar &&= t.foo 42
80         o::baz ||= t.foo 42
81         o::qux &&= t.foo 42
82       END
83     end
84     assert_equal([42, 42], [o.foo, o.bar])
85     assert_equal([42, 42], [o.Foo, o.Bar])
86     assert_equal([42, 42], [o::baz, o::qux])
88     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /Can't set variable/) do
89       begin;
90         $1 ||= t.foo 42
91       end;
92     end
94     def t.bar(x); x + yield; end
96     a = b = nil
97     assert_nothing_raised do
98       eval <<-END, nil, __FILE__, __LINE__+1
99         a = t.bar "foo" do
100           "bar"
101         end.gsub "ob", "OB"
102         b = t.bar "foo" do
103           "bar"
104         end::gsub "ob", "OB"
105       END
106     end
107     assert_equal("foOBar", a)
108     assert_equal("foOBar", b)
110     a = nil
111     assert_nothing_raised do
112       t.instance_eval <<-END, __FILE__, __LINE__+1
113         a = bar "foo" do "bar" end
114       END
115     end
116     assert_equal("foobar", a)
118     a = nil
119     assert_nothing_raised do
120       eval <<-END, nil, __FILE__, __LINE__+1
121         a = t::bar "foo" do "bar" end
122       END
123     end
124     assert_equal("foobar", a)
126     def t.baz(*r)
127       @baz = r + (block_given? ? [yield] : [])
128     end
130     assert_nothing_raised do
131       t.instance_eval "baz (1), 2"
132     end
133     assert_equal([1, 2], t.instance_eval { @baz })
134   end
136   def test_mlhs_node
137     c = Class.new
138     class << c
139       attr_accessor :foo, :bar, :Foo, :Bar
140       FOO = BAR = nil
141     end
143     assert_nothing_raised do
144       eval <<-END, nil, __FILE__, __LINE__+1
145         c::foo, c::bar = 1, 2
146         c.Foo, c.Bar = 1, 2
147         c::FOO, c::BAR = 1, 2
148       END
149     end
150     assert_equal([1, 2], [c::foo, c::bar])
151     assert_equal([1, 2], [c.Foo, c.Bar])
152     assert_equal([1, 2], [c::FOO, c::BAR])
153   end
155   def test_dynamic_constant_assignment
156     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /dynamic constant/) do
157       begin;
158         def foo
159           self::FOO, self::BAR = 1, 2
160           ::FOO, ::BAR = 1, 2
161         end
162       end;
163     end
165     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /Can't set variable/) do
166       begin;
167         $1, $2 = 1, 2
168       end;
169     end
171     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /dynamic constant/) do
172       begin;
173         def foo
174           ::FOO = 1
175         end
176       end;
177     end
179     c = Class.new
180     c.freeze
181     assert_valid_syntax("#{<<~"begin;"}\n#{<<~'end;'}") do
182       begin;
183         c::FOO &= 1
184         ::FOO &= 1
185       end;
186     end
188     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /Can't set variable/) do
189       begin;
190         $1 &= 1
191       end;
192     end
193   end
195   def test_class_module
196     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /must be CONSTANT/) do
197       begin;
198         class foo; end
199       end;
200     end
202     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /in method body/) do
203       begin;
204         def foo
205           class Foo; end
206           module Bar; end
207         end
208       end;
209     end
211     assert_valid_syntax("#{<<~"begin;"}\n#{<<~'end;'}") do
212       begin;
213         class Foo 1; end
214       end;
215     end
216   end
218   def test_op_name
219     o = Object.new
220     def o.>(x); x; end
221     def o./(x); x; end
223     assert_nothing_raised do
224       o.instance_eval <<-END, __FILE__, __LINE__+1
225         undef >, /
226       END
227     end
228   end
230   def test_arg
231     o = Object.new
232     class << o
233       attr_accessor :foo, :bar, :Foo, :Bar, :baz, :qux
234     end
235     o.foo = o.Foo = o::baz = nil
236     o.bar = o.Bar = o::qux = 1
237     assert_nothing_raised do
238       eval <<-END, nil, __FILE__, __LINE__+1
239         o.foo ||= 42
240         o.bar &&= 42
241         o.Foo ||= 42
242         o.Bar &&= 42
243         o::baz ||= 42
244         o::qux &&= 42
245       END
246     end
247     assert_equal([42, 42], [o.foo, o.bar])
248     assert_equal([42, 42], [o.Foo, o.Bar])
249     assert_equal([42, 42], [o::baz, o::qux])
251     a = nil
252     assert_nothing_raised do
253       eval <<-END, nil, __FILE__, __LINE__+1
254         a = -2.0 ** 2
255       END
256     end
257     assert_equal(-4.0, a)
258   end
260   def test_block_variable
261     o = Object.new
262     def o.foo(*r); yield(*r); end
264     a = nil
265     assert_nothing_raised do
266       eval <<-END, nil, __FILE__, __LINE__+1
267         o.foo 1 do|; a| a = 42 end
268       END
269     end
270     assert_nil(a)
271   end
273   def test_bad_arg
274     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /cannot be a constant/) do
275       begin;
276         def foo(FOO); end
277       end;
278     end
280     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /cannot be an instance variable/) do
281       begin;
282         def foo(@foo); end
283       end;
284     end
286     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /cannot be a global variable/) do
287       begin;
288         def foo($foo); end
289       end;
290     end
292     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /cannot be a class variable/) do
293       begin;
294         def foo(@@foo); end
295       end;
296     end
298     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /cannot be an instance variable/) do
299       begin;
300         o.foo {|; @a| @a = 42 }
301       end;
302     end
303   end
305   def test_do_lambda
306     a = b = nil
307     assert_nothing_raised do
308       eval <<-END, nil, __FILE__, __LINE__+1
309         a = -> do
310           b = 42
311         end
312       END
313     end
314     a.call
315     assert_equal(42, b)
316   end
318   def test_block_call_colon2
319     o = Object.new
320     def o.foo(x); x + yield; end
322     a = b = nil
323     assert_nothing_raised do
324       o.instance_eval <<-END, __FILE__, __LINE__+1
325         a = foo 1 do 42 end.to_s
326         b = foo 1 do 42 end::to_s
327       END
328     end
329     assert_equal("43", a)
330     assert_equal("43", b)
331   end
333   def test_call_method
334     a = b = nil
335     assert_nothing_raised do
336       eval <<-END, nil, __FILE__, __LINE__+1
337         a = proc {|x| x + "bar" }.("foo")
338         b = proc {|x| x + "bar" }::("foo")
339       END
340     end
341     assert_equal("foobar", a)
342     assert_equal("foobar", b)
343   end
345   def test_xstring
346     assert_raise(Errno::ENOENT) do
347       eval("``")
348     end
349   end
351   def test_words
352     assert_equal([], %W( ))
353     assert_syntax_error('%w[abc', /unterminated list/)
354   end
356   def test_dstr
357     @@foo = 1
358     assert_equal("foo 1 bar", "foo #@@foo bar")
359     "1" =~ /(.)/
360     assert_equal("foo 1 bar", "foo #$1 bar")
361     assert_equal('foo #@1 bar', eval('"foo #@1 bar"'))
362   end
364   def test_dstr_disallowed_variable
365     bug8375 = '[ruby-core:54885] [Bug #8375]'
366     %w[@ @. @@ @@1 @@. $ $%].each do |src|
367       src = '#'+src+' '
368       str = assert_nothing_raised(SyntaxError, "#{bug8375} #{src.dump}") do
369         break eval('"'+src+'"')
370       end
371       assert_equal(src, str, bug8375)
372     end
373   end
375   def test_dsym
376     assert_nothing_raised { eval(':""') }
377   end
379   def assert_disallowed_variable(type, noname, invalid)
380     noname.each do |name|
381       assert_syntax_error("proc{a = #{name} }", "`#{noname[0]}' without identifiers is not allowed as #{type} variable name")
382     end
383     invalid.each do |name|
384       assert_syntax_error("proc {a = #{name} }", "`#{name}' is not allowed as #{type} variable name")
385     end
386   end
388   def test_disallowed_instance_variable
389     assert_disallowed_variable("an instance", %w[@ @.], %w[])
390   end
392   def test_disallowed_class_variable
393     assert_disallowed_variable("a class", %w[@@ @@.], %w[@@1])
394   end
396   def test_disallowed_gloal_variable
397     assert_disallowed_variable("a global", %w[$], %w[$%])
398   end
400   def test_arg2
401     o = Object.new
402     assert_nothing_raised do
403       eval <<-END, nil, __FILE__, __LINE__+1
404         def o.foo(a=42,*r,z,&b); b.call(r.inject(a*1000+z*100, :+)); end
405       END
406     end
407     assert_equal(-1405, o.foo(1,2,3,4) {|x| -x })
408     assert_equal(-1302, o.foo(1,2,3) {|x| -x })
409     assert_equal(-1200, o.foo(1,2) {|x| -x })
410     assert_equal(-42100, o.foo(1) {|x| -x })
411     assert_raise(ArgumentError) { o.foo() }
413     o = Object.new
414     assert_nothing_raised do
415       eval <<-END, nil, __FILE__, __LINE__+1
416         def o.foo(a=42,z,&b); b.call(a*1000+z*100); end
417       END
418     end
419     assert_equal(-1200, o.foo(1,2) {|x| -x } )
420     assert_equal(-42100, o.foo(1) {|x| -x } )
421     assert_raise(ArgumentError) { o.foo() }
423     o = Object.new
424     assert_nothing_raised do
425       eval <<-END, nil, __FILE__, __LINE__+1
426         def o.foo(*r,z,&b); b.call(r.inject(z*100, :+)); end
427       END
428     end
429     assert_equal(-303, o.foo(1,2,3) {|x| -x } )
430     assert_equal(-201, o.foo(1,2) {|x| -x } )
431     assert_equal(-100, o.foo(1) {|x| -x } )
432     assert_raise(ArgumentError) { o.foo() }
433   end
435   def test_duplicate_argument
436     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", '') do
437       begin;
438         1.times {|&b?| }
439       end;
440     end
442     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /duplicated argument/) do
443       begin;
444         1.times {|a, a|}
445       end;
446     end
448     assert_syntax_error("#{<<~"begin;"}\n#{<<~'end;'}", /duplicated argument/) do
449       begin;
450         def foo(a, a); end
451       end;
452     end
453   end
455   def test_define_singleton_error
456     msg = /singleton method for literals/
457     assert_parse_error(%q[def ("foo").foo; end], msg)
458     assert_parse_error(%q[def (1).foo; end], msg)
459     assert_parse_error(%q[def ((1;1)).foo; end], msg)
460     assert_parse_error(%q[def ((;1)).foo; end], msg)
461     assert_parse_error(%q[def ((1+1;1)).foo; end], msg)
462     assert_parse_error(%q[def ((%s();1)).foo; end], msg)
463     assert_parse_error(%q[def ((%w();1)).foo; end], msg)
464     assert_parse_error(%q[def ("#{42}").foo; end], msg)
465     assert_parse_error(%q[def (:"#{42}").foo; end], msg)
466   end
468   def test_flip_flop
469     all_assertions_foreach(nil,
470       ['(cond1..cond2)', true],
471       ['((cond1..cond2))', true],
473       # '(;;;cond1..cond2)', # don't care
475       '(1; cond1..cond2)',
476       '(%s(); cond1..cond2)',
477       '(%w(); cond1..cond2)',
478       '(1; (2; (3; 4; cond1..cond2)))',
479       '(1+1; cond1..cond2)',
480     ) do |code, pass|
481       code = code.sub("cond1", "n==4").sub("cond2", "n==5")
482       if pass
483         assert_equal([4,5], eval("(1..9).select {|n| true if #{code}}"))
484       else
485         assert_raise_with_message(ArgumentError, /bad value for range/, code) {
486           verbose_bak, $VERBOSE = $VERBOSE, nil # disable "warning: possibly useless use of a literal in void context"
487           begin
488             eval("[4].each {|n| true if #{code}}")
489           ensure
490             $VERBOSE = verbose_bak
491           end
492         }
493       end
494     end
495   end
497   def test_op_asgn1_with_block
498     t = Object.new
499     a = []
500     blk = proc {|x| a << x }
501     def t.[](_)
502       yield(:aref)
503       nil
504     end
505     def t.[]=(_, _)
506       yield(:aset)
507     end
508     def t.dummy(_)
509     end
510     eval <<-END, nil, __FILE__, __LINE__+1
511       t[42, &blk] ||= 42
512     END
513     assert_equal([:aref, :aset], a)
514     a.clear
515     eval <<-END, nil, __FILE__, __LINE__+1
516     t[42, &blk] ||= t.dummy 42 # command_asgn test
517     END
518     assert_equal([:aref, :aset], a)
519     blk
520   end
522   def test_backquote
523     t = Object.new
525     assert_nothing_raised do
526       eval <<-END, nil, __FILE__, __LINE__+1
527         def t.`(x); "foo" + x + "bar"; end
528       END
529     end
530     a = b = c = nil
531     assert_nothing_raised do
532       eval <<-END, nil, __FILE__, __LINE__+1
533         a = t.` "zzz"
534         1.times {|;z| t.` ("zzz") }
535       END
536       t.instance_eval <<-END, __FILE__, __LINE__+1
537         b = `zzz`
538         c = %x(ccc)
539       END
540     end
541     assert_equal("foozzzbar", a)
542     assert_equal("foozzzbar", b)
543     assert_equal("foocccbar", c)
544   end
546   def test_carrige_return
547     assert_equal(2, eval("1 +\r\n1"))
548   end
550   def test_string
551     mesg = 'from the backslash through the invalid char'
553     e = assert_syntax_error('"\xg1"', /hex escape/)
554     assert_equal(' ^~'"\n", e.message.lines.last, mesg)
556     e = assert_syntax_error('"\u{1234"', 'unterminated Unicode escape')
557     assert_equal('        ^'"\n", e.message.lines.last, mesg)
559     e = assert_syntax_error('"\u{xxxx}"', 'invalid Unicode escape')
560     assert_equal('    ^'"\n", e.message.lines.last, mesg)
562     e = assert_syntax_error('"\u{xxxx', 'Unicode escape')
563     assert_pattern_list([
564                           /.*: invalid Unicode escape\n.*\n/,
565                           /    \^/,
566                           /\n/,
567                           /.*: unterminated Unicode escape\n.*\n/,
568                           /    \^/,
569                           /\n/,
570                           /.*: unterminated string.*\n.*\n/,
571                           /        \^\n/,
572                         ], e.message)
574     e = assert_syntax_error('"\M1"', /escape character syntax/)
575     assert_equal(' ^~~'"\n", e.message.lines.last, mesg)
577     e = assert_syntax_error('"\C1"', /escape character syntax/)
578     assert_equal(' ^~~'"\n", e.message.lines.last, mesg)
580     src = '"\xD0\u{90'"\n""000000000000000000000000"
581     assert_syntax_error(src, /:#{__LINE__}: unterminated/o)
583     assert_syntax_error('"\u{100000000}"', /invalid Unicode escape/)
584     assert_equal("", eval('"\u{}"'))
585     assert_equal("", eval('"\u{ }"'))
587     assert_equal("\x81", eval('"\C-\M-a"'))
588     assert_equal("\177", eval('"\c?"'))
590     assert_warning(/use \\C-\\s/) {assert_equal("\x00", eval('"\C- "'))}
591     assert_warning(/use \\M-\\s/) {assert_equal("\xa0", eval('"\M- "'))}
592     assert_warning(/use \\M-\\C-\\s/) {assert_equal("\x80", eval('"\M-\C- "'))}
593     assert_warning(/use \\C-\\M-\\s/) {assert_equal("\x80", eval('"\C-\M- "'))}
594     assert_warning(/use \\t/) {assert_equal("\x09", eval("\"\\C-\t\""))}
595     assert_warning(/use \\M-\\t/) {assert_equal("\x89", eval("\"\\M-\t\""))}
596     assert_warning(/use \\M-\\t/) {assert_equal("\x89", eval("\"\\M-\\C-\t\""))}
597     assert_warning(/use \\M-\\t/) {assert_equal("\x89", eval("\"\\C-\\M-\t\""))}
598     assert_syntax_error("\"\\C-\x01\"", 'Invalid escape character syntax')
599     assert_syntax_error("\"\\M-\x01\"", 'Invalid escape character syntax')
600     assert_syntax_error("\"\\M-\\C-\x01\"", 'Invalid escape character syntax')
601     assert_syntax_error("\"\\C-\\M-\x01\"", 'Invalid escape character syntax')
603     e = assert_syntax_error('"\c\u0000"', 'Invalid escape character syntax')
604     assert_equal(' ^~~~'"\n", e.message.lines.last)
605     e = assert_syntax_error('"\c\U0000"', 'Invalid escape character syntax')
606     assert_equal(' ^~~~'"\n", e.message.lines.last)
608     e = assert_syntax_error('"\C-\u0000"', 'Invalid escape character syntax')
609     assert_equal(' ^~~~~'"\n", e.message.lines.last)
610     e = assert_syntax_error('"\C-\U0000"', 'Invalid escape character syntax')
611     assert_equal(' ^~~~~'"\n", e.message.lines.last)
613     e = assert_syntax_error('"\M-\u0000"', 'Invalid escape character syntax')
614     assert_equal(' ^~~~~'"\n", e.message.lines.last)
615     e = assert_syntax_error('"\M-\U0000"', 'Invalid escape character syntax')
616     assert_equal(' ^~~~~'"\n", e.message.lines.last)
618     e = assert_syntax_error(%["\\C-\u3042"], 'Invalid escape character syntax')
619     assert_match(/^\s \^(?# \\ ) ~(?# C ) ~(?# - ) ~+(?# U+3042 )$/x, e.message.lines.last)
620     assert_not_include(e.message, "invalid multibyte char")
621   end
623   def test_question
624     assert_syntax_error('?', /incomplete/)
625     assert_syntax_error('? ', /unexpected/)
626     assert_syntax_error("?\n", /unexpected/)
627     assert_syntax_error("?\t", /unexpected/)
628     assert_syntax_error("?\v", /unexpected/)
629     assert_syntax_error("?\r", /unexpected/)
630     assert_syntax_error("?\f", /unexpected/)
631     assert_syntax_error(" ?a\x8a".force_encoding("utf-8"), /invalid multibyte/)
632     assert_equal("\u{1234}", eval("?\u{1234}"))
633     assert_equal("\u{1234}", eval('?\u{1234}'))
634     assert_equal("\u{1234}", eval('?\u1234'))
635     assert_syntax_error('?\u{41 42}', 'Multiple codepoints at single character literal')
636     e = assert_syntax_error('"#{?\u123}"', 'invalid Unicode escape')
637     assert_not_match(/end-of-input/, e.message)
639     assert_warning(/use ?\\C-\\s/) {assert_equal("\x00", eval('?\C- '))}
640     assert_warning(/use ?\\M-\\s/) {assert_equal("\xa0", eval('?\M- '))}
641     assert_warning(/use ?\\M-\\C-\\s/) {assert_equal("\x80", eval('?\M-\C- '))}
642     assert_warning(/use ?\\C-\\M-\\s/) {assert_equal("\x80", eval('?\C-\M- '))}
643     assert_warning(/use ?\\t/) {assert_equal("\x09", eval("?\\C-\t"))}
644     assert_warning(/use ?\\M-\\t/) {assert_equal("\x89", eval("?\\M-\t"))}
645     assert_warning(/use ?\\M-\\t/) {assert_equal("\x89", eval("?\\M-\\C-\t"))}
646     assert_warning(/use ?\\M-\\t/) {assert_equal("\x89", eval("?\\C-\\M-\t"))}
647     assert_syntax_error("?\\C-\x01", 'Invalid escape character syntax')
648     assert_syntax_error("?\\M-\x01", 'Invalid escape character syntax')
649     assert_syntax_error("?\\M-\\C-\x01", 'Invalid escape character syntax')
650     assert_syntax_error("?\\C-\\M-\x01", 'Invalid escape character syntax')
652     assert_equal("\xff", eval("# encoding: ascii-8bit\n""?\\\xFF"))
653   end
655   def test_percent
656     assert_equal(:foo, eval('%s(foo)'))
657     assert_syntax_error('%s', /unterminated quoted string/)
658     assert_syntax_error('%ss', /unknown type/)
659     assert_syntax_error('%z()', /unknown type/)
660     assert_syntax_error("%\u3042", /unknown type/)
661     assert_syntax_error("%q\u3042", /unknown type/)
662     assert_syntax_error("%", /unterminated quoted string/)
663   end
665   def test_symbol
666     bug = '[ruby-dev:41447]'
667     sym = "foo\0bar".to_sym
668     assert_nothing_raised(SyntaxError, bug) do
669       assert_equal(sym, eval(":'foo\0bar'"))
670     end
671     assert_nothing_raised(SyntaxError, bug) do
672       assert_equal(sym, eval(':"foo\u0000bar"'))
673     end
674     assert_nothing_raised(SyntaxError, bug) do
675       assert_equal(sym, eval(':"foo\u{0}bar"'))
676     end
677     assert_nothing_raised(SyntaxError) do
678       assert_equal(:foobar, eval(':"foo\u{}bar"'))
679       assert_equal(:foobar, eval(':"foo\u{ }bar"'))
680     end
682     assert_syntax_error(':@@', /is not allowed/)
683     assert_syntax_error(':@@1', /is not allowed/)
684     assert_syntax_error(':@', /is not allowed/)
685     assert_syntax_error(':@1', /is not allowed/)
686     assert_syntax_error(':$01234', /is not allowed/)
687   end
689   def test_parse_string
690     assert_syntax_error("/\n", /unterminated/)
691   end
693   def test_here_document
694     x = nil
696     assert_syntax_error("<\<FOO\n", /can't find string "FOO"/)
698     assert_nothing_raised(SyntaxError) do
699       x = eval %q(
700 <<FOO
703       )
704     end
705     assert_equal "\#$\n", x
707     assert_syntax_error("<\<\"\n", /unterminated here document identifier/)
709     assert_syntax_error("<<``\n", /can't find string ""/)
711     assert_syntax_error("<<--\n", /unexpected <</)
713     assert_nothing_raised(SyntaxError) do
714       x = eval %q(
715 <<FOO
719       )
720     end
721     assert_equal "\#$\nfoo\n", x
723     assert_nothing_raised do
724       eval "x = <<""FOO\r\n1\r\nFOO"
725     end
726     assert_equal("1\n", x)
728     assert_nothing_raised do
729       x = eval "<<' FOO'\n""[Bug #19539]\n"" FOO\n"
730     end
731     assert_equal("[Bug #19539]\n", x)
733     assert_nothing_raised do
734       x = eval "<<-' FOO'\n""[Bug #19539]\n"" FOO\n"
735     end
736     assert_equal("[Bug #19539]\n", x)
737   end
739   def test_magic_comment
740     x = nil
742     assert_nothing_raised do
743       eval <<-END, nil, __FILE__, __LINE__+1
744 # coding: utf-8
745 x = __ENCODING__
746       END
747     end
748     assert_equal(Encoding.find("UTF-8"), x)
750     assert_nothing_raised do
751       eval <<-END, nil, __FILE__, __LINE__+1
752 # coding = utf-8
753 x = __ENCODING__
754       END
755     end
756     assert_equal(Encoding.find("UTF-8"), x)
758     assert_raise(ArgumentError) do
759       eval <<-END, nil, __FILE__, __LINE__+1
760 # coding = foobarbazquxquux_dummy_enconding
761 x = __ENCODING__
762       END
763     end
765     assert_nothing_raised do
766       eval <<-END, nil, __FILE__, __LINE__+1
767 # xxxx : coding sjis
768 x = __ENCODING__
769       END
770     end
771     assert_equal(__ENCODING__, x)
773     assert_raise(ArgumentError) do
774       EnvUtil.with_default_external(Encoding::US_ASCII) {eval <<-END, nil, __FILE__, __LINE__+1}
775 # coding = external
776 x = __ENCODING__
777       END
778     end
780     assert_raise(ArgumentError) do
781       EnvUtil.with_default_internal(Encoding::US_ASCII) {eval <<-END, nil, __FILE__, __LINE__+1}
782 # coding = internal
783 x = __ENCODING__
784       END
785     end
787     assert_raise(ArgumentError) do
788       eval <<-END, nil, __FILE__, __LINE__+1
789 # coding = filesystem
790 x = __ENCODING__
791       END
792     end
794     assert_raise(ArgumentError) do
795       eval <<-END, nil, __FILE__, __LINE__+1
796 # coding = locale
797 x = __ENCODING__
798       END
799     end
800   end
802   def test_utf8_bom
803     x = nil
804     assert_nothing_raised do
805       eval "\xef\xbb\xbf x = __ENCODING__"
806     end
807     assert_equal(Encoding.find("UTF-8"), x)
808     assert_raise(NameError) { eval "\xef" }
809   end
811   def test_dot_in_next_line
812     x = nil
813     assert_nothing_raised do
814       eval <<-END, nil, __FILE__, __LINE__+1
815         x = 1
816         .to_s
817       END
818     end
819     assert_equal("1", x)
820   end
822   def test_pow_asgn
823     x = 3
824     assert_nothing_raised { eval("x **= 2") }
825     assert_equal(9, x)
826   end
828   def test_embedded_rd
829     assert_valid_syntax("=begin\n""=end")
830     assert_valid_syntax("=begin\n""=end\0")
831     assert_valid_syntax("=begin\n""=end\C-d")
832     assert_valid_syntax("=begin\n""=end\C-z")
833   end
835   def test_embedded_rd_error
836     error = 'embedded document meets end of file'
837     assert_syntax_error("=begin\n", error)
838     assert_syntax_error("=begin", error)
839   end
841   def test_float
842     assert_predicate(assert_warning(/out of range/) {eval("1e10000")}, :infinite?)
843     assert_syntax_error('1_E', /trailing `_'/)
844     assert_syntax_error('1E1E1', /unexpected constant/)
845   end
847   def test_global_variable
848     assert_equal(nil, assert_warning(/not initialized/) {eval('$-x')})
849     assert_equal(nil, eval('alias $preserve_last_match $&'))
850     assert_equal(nil, eval('alias $& $test_parse_foobarbazqux'))
851     $test_parse_foobarbazqux = nil
852     assert_equal(nil, $&)
853     assert_equal(nil, eval('alias $& $preserve_last_match'))
854     assert_syntax_error('a = $#', /as a global variable name\na = \$\#\n    \^~$/)
855   end
857   def test_invalid_instance_variable
858     pattern = /without identifiers is not allowed as an instance variable name/
859     assert_syntax_error('@%', pattern)
860     assert_syntax_error('@', pattern)
861   end
863   def test_invalid_class_variable
864     pattern = /without identifiers is not allowed as a class variable name/
865     assert_syntax_error('@@%', pattern)
866     assert_syntax_error('@@', pattern)
867   end
869   def test_invalid_char
870     bug10117 = '[ruby-core:64243] [Bug #10117]'
871     invalid_char = /Invalid char `\\x01'/
872     x = 1
873     assert_in_out_err(%W"-e \x01x", "", [], invalid_char, bug10117)
874     assert_syntax_error("\x01x", invalid_char, bug10117)
875     assert_equal(nil, eval("\x04x"))
876     assert_equal 1, x
877   end
879   def test_literal_concat
880     x = "baz"
881     assert_equal("foobarbaz", eval('"foo" "bar#{x}"'))
882     assert_equal("baz", x)
883   end
885   def test_unassignable
886     assert_syntax_error(%q(self = 1), /Can't change the value of self/)
887     assert_syntax_error(%q(nil = 1), /Can't assign to nil/)
888     assert_syntax_error(%q(true = 1), /Can't assign to true/)
889     assert_syntax_error(%q(false = 1), /Can't assign to false/)
890     assert_syntax_error(%q(__FILE__ = 1), /Can't assign to __FILE__/)
891     assert_syntax_error(%q(__LINE__ = 1), /Can't assign to __LINE__/)
892     assert_syntax_error(%q(__ENCODING__ = 1), /Can't assign to __ENCODING__/)
893     assert_syntax_error("def foo; FOO = 1; end", /dynamic constant assignment/)
894     assert_syntax_error("x, true", /Can't assign to true/)
895   end
897   def test_block_dup
898     assert_syntax_error("foo(&proc{}) {}", /both block arg and actual block/)
899   end
901   def test_set_backref
902     assert_syntax_error("$& = 1", /Can't set variable/)
903   end
905   def test_arg_concat
906     o = Object.new
907     class << o; self; end.instance_eval do
908       define_method(:[]=) {|*r, &b| b.call(r) }
909     end
910     r = nil
911     assert_nothing_raised do
912       eval <<-END, nil, __FILE__, __LINE__+1
913         o[&proc{|x| r = x }] = 1
914       END
915     end
916     assert_equal([1], r)
917   end
919   def test_void_expr_stmts_value
920     x = 1
921     useless_use = /useless use/
922     assert_nil assert_warning(useless_use) {eval("x; nil")}
923     assert_nil assert_warning(useless_use) {eval("1+1; nil")}
924     assert_nil assert_warning('') {eval("1.+(1); nil")}
925     assert_nil assert_warning(useless_use) {eval("TestParse; nil")}
926     assert_nil assert_warning(useless_use) {eval("::TestParse; nil")}
927     assert_nil assert_warning(useless_use) {eval("x..x; nil")}
928     assert_nil assert_warning(useless_use) {eval("x...x; nil")}
929     assert_nil assert_warning(useless_use) {eval("self; nil")}
930     assert_nil assert_warning(useless_use) {eval("nil; nil")}
931     assert_nil assert_warning(useless_use) {eval("true; nil")}
932     assert_nil assert_warning(useless_use) {eval("false; nil")}
933     assert_nil assert_warning(useless_use) {eval("defined?(1); nil")}
934     assert_equal 1, x
936     assert_syntax_error("1; next; 2", /Invalid next/)
937   end
939   def test_assign_in_conditional
940     # multiple assignment
941     assert_warning(/`= literal' in conditional/) do
942       eval <<-END, nil, __FILE__, __LINE__+1
943         (x, y = 1, 2) ? 1 : 2
944       END
945     end
947     # instance variable assignment
948     assert_warning(/`= literal' in conditional/) do
949       eval <<-END, nil, __FILE__, __LINE__+1
950         if @x = true
951           1
952         else
953           2
954         end
955       END
956     end
958     # local variable assignment
959     assert_warning(/`= literal' in conditional/) do
960       eval <<-END, nil, __FILE__, __LINE__+1
961         def m
962           if x = true
963             1
964           else
965             2
966           end
967         end
968       END
969     end
971     # global variable assignment
972     assert_separately([], <<-RUBY)
973       assert_warning(/`= literal' in conditional/) do
974         eval <<-END, nil, __FILE__, __LINE__+1
975           if $x = true
976             1
977           else
978             2
979           end
980         END
981       end
982     RUBY
984     # dynamic variable assignment
985     assert_warning(/`= literal' in conditional/) do
986       eval <<-END, nil, __FILE__, __LINE__+1
987         y = 1
989         1.times do
990           if y = true
991             1
992           else
993             2
994           end
995         end
996       END
997     end
999     # class variable assignment
1000     assert_warning(/`= literal' in conditional/) do
1001       eval <<-END, nil, __FILE__, __LINE__+1
1002         c = Class.new
1003         class << c
1004           if @@a = 1
1005           end
1006         end
1007       END
1008     end
1010     # constant declaration
1011     assert_separately([], <<-RUBY)
1012       assert_warning(/`= literal' in conditional/) do
1013         eval <<-END, nil, __FILE__, __LINE__+1
1014           if Const = true
1015             1
1016           else
1017             2
1018           end
1019         END
1020       end
1021     RUBY
1022   end
1024   def test_literal_in_conditional
1025     assert_warning(/string literal in condition/) do
1026       eval <<-END, nil, __FILE__, __LINE__+1
1027         "foo" ? 1 : 2
1028       END
1029     end
1031     assert_warning(/regex literal in condition/) do
1032       x = "bar"
1033       eval <<-END, nil, __FILE__, __LINE__+1
1034         /foo#{x}baz/ ? 1 : 2
1035       END
1036     end
1038     assert_nothing_raised do
1039       eval <<-END, nil, __FILE__, __LINE__+1
1040         (true..false) ? 1 : 2
1041       END
1042     end
1044     assert_warning(/string literal in flip-flop/) do
1045       eval <<-END, nil, __FILE__, __LINE__+1
1046         ("foo".."bar") ? 1 : 2
1047       END
1048     end
1050     assert_warning(/literal in condition/) do
1051       x = "bar"
1052       eval <<-END, nil, __FILE__, __LINE__+1
1053         :"foo#{"x"}baz" ? 1 : 2
1054       END
1055       assert_equal "bar", x
1056     end
1057   end
1059   def test_no_blockarg
1060     assert_syntax_error("yield(&:+)", /block argument should not be given/)
1061   end
1063   def test_method_block_location
1064     bug5614 = '[ruby-core:40936]'
1065     expected = nil
1066     e = assert_raise(NoMethodError) do
1067       1.times do
1068         expected = __LINE__+1
1069       end.print do
1070         #
1071       end
1072     end
1073     actual = e.backtrace.first[/\A#{Regexp.quote(__FILE__)}:(\d+):/o, 1].to_i
1074     assert_equal(expected, actual, bug5614)
1075   end
1077   def test_no_shadowing_variable_warning
1078     assert_no_warning(/shadowing outer local variable/) {eval("a=1; tap {|a|}")}
1079   end
1081   def test_shadowing_private_local_variable
1082     assert_equal 1, eval("_ = 1; [[2]].each{ |(_)| }; _")
1083   end
1085   def test_unused_variable
1086     o = Object.new
1087     assert_warning(/assigned but unused variable/) {o.instance_eval("def foo; a=1; nil; end")}
1088     assert_warning(/assigned but unused variable/) {o.instance_eval("def bar; a=1; a(); end")}
1089     a = "\u{3042}"
1090     assert_warning(/#{a}/) {o.instance_eval("def foo0; #{a}=1; nil; end")}
1091     assert_warning(/assigned but unused variable/) {o.instance_eval("def foo1; tap {a=1; a()}; end")}
1092     assert_warning('') {o.instance_eval("def bar1; a=a=1; nil; end")}
1093     assert_warning(/assigned but unused variable/) {o.instance_eval("def bar2; a, = 1, 2; end")}
1094     assert_warning('') {o.instance_eval("def marg1(a); nil; end")}
1095     assert_warning('') {o.instance_eval("def marg2((a)); nil; end")}
1096   end
1098   def test_named_capture_conflict
1099     a = 1
1100     assert_warning('') {eval("a = 1; /(?<a>)/ =~ ''")}
1101     a = "\u{3042}"
1102     assert_warning('') {eval("#{a} = 1; /(?<#{a}>)/ =~ ''")}
1103   end
1105   def test_named_capture_in_block
1106     all_assertions_foreach(nil,
1107       '(/(?<a>.*)/)',
1108       '(;/(?<a>.*)/)',
1109       '(%s();/(?<a>.*)/)',
1110       '(%w();/(?<a>.*)/)',
1111       '(1; (2; 3; (4; /(?<a>.*)/)))',
1112       '(1+1; /(?<a>.*)/)',
1113       '/#{""}(?<a>.*)/',
1114     ) do |code, pass|
1115       token = Random.bytes(4).unpack1("H*")
1116       if pass
1117         assert_equal(token, eval("#{code} =~ #{token.dump}; a"))
1118       else
1119         verbose_bak, $VERBOSE = $VERBOSE, nil # disable "warning: possibly useless use of a literal in void context"
1120         begin
1121           assert_nil(eval("#{code} =~ #{token.dump}; defined?(a)"), code)
1122         ensure
1123           $VERBOSE = verbose_bak
1124         end
1125       end
1126     end
1127   end
1129   def test_rescue_in_command_assignment
1130     bug = '[ruby-core:75621] [Bug #12402]'
1131     all_assertions(bug) do |a|
1132       a.for("lhs = arg") do
1133         v = bug
1134         v = raise(bug) rescue "ok"
1135         assert_equal("ok", v)
1136       end
1137       a.for("lhs op_asgn arg") do
1138         v = 0
1139         v += raise(bug) rescue 1
1140         assert_equal(1, v)
1141       end
1142       a.for("lhs[] op_asgn arg") do
1143         v = [0]
1144         v[0] += raise(bug) rescue 1
1145         assert_equal([1], v)
1146       end
1147       a.for("lhs.m op_asgn arg") do
1148         k = Struct.new(:m)
1149         v = k.new(0)
1150         v.m += raise(bug) rescue 1
1151         assert_equal(k.new(1), v)
1152       end
1153       a.for("lhs::m op_asgn arg") do
1154         k = Struct.new(:m)
1155         v = k.new(0)
1156         v::m += raise(bug) rescue 1
1157         assert_equal(k.new(1), v)
1158       end
1159       a.for("lhs.C op_asgn arg") do
1160         k = Struct.new(:C)
1161         v = k.new(0)
1162         v.C += raise(bug) rescue 1
1163         assert_equal(k.new(1), v)
1164       end
1165       a.for("lhs::C op_asgn arg") do
1166         v = Class.new
1167         v::C ||= raise(bug) rescue 1
1168         assert_equal(1, v::C)
1169       end
1170       a.for("lhs = command") do
1171         v = bug
1172         v = raise bug rescue "ok"
1173         assert_equal("ok", v)
1174       end
1175       a.for("lhs op_asgn command") do
1176         v = 0
1177         v += raise bug rescue 1
1178         assert_equal(1, v)
1179       end
1180       a.for("lhs[] op_asgn command") do
1181         v = [0]
1182         v[0] += raise bug rescue 1
1183         assert_equal([1], v)
1184       end
1185       a.for("lhs.m op_asgn command") do
1186         k = Struct.new(:m)
1187         v = k.new(0)
1188         v.m += raise bug rescue 1
1189         assert_equal(k.new(1), v)
1190       end
1191       a.for("lhs::m op_asgn command") do
1192         k = Struct.new(:m)
1193         v = k.new(0)
1194         v::m += raise bug rescue 1
1195         assert_equal(k.new(1), v)
1196       end
1197       a.for("lhs.C op_asgn command") do
1198         k = Struct.new(:C)
1199         v = k.new(0)
1200         v.C += raise bug rescue 1
1201         assert_equal(k.new(1), v)
1202       end
1203       a.for("lhs::C op_asgn command") do
1204         v = Class.new
1205         v::C ||= raise bug rescue 1
1206         assert_equal(1, v::C)
1207       end
1208     end
1209   end
1211   def test_yyerror_at_eol
1212     assert_syntax_error("    0b", /\^/)
1213     assert_syntax_error("    0b\n", /\^/)
1214   end
1216   def test_unclosed_unicode_escape_at_eol_bug_19750
1217     assert_separately([], "#{<<-"begin;"}\n#{<<~'end;'}")
1218     begin;
1219       assert_syntax_error("/\\u", /too short escape sequence/)
1220       assert_syntax_error("/\\u{", /unterminated regexp meets end of file/)
1221       assert_syntax_error("/\\u{\\n", /invalid Unicode list/)
1222       assert_syntax_error("/a#\\u{\\n/", /invalid Unicode list/)
1223       re = eval("/a#\\u{\n$/x")
1224       assert_match(re, 'a')
1225       assert_not_match(re, 'a#')
1226       re = eval("/a#\\u\n$/x")
1227       assert_match(re, 'a')
1228       assert_not_match(re, 'a#')
1229     end;
1230   end
1232   def test_error_def_in_argument
1233     assert_separately([], "#{<<-"begin;"}\n#{<<~"end;"}")
1234     begin;
1235       assert_syntax_error("def f r:def d; def f 0end", /unexpected/)
1236     end;
1238     assert_syntax_error("def\nf(000)end", /^  \^~~/)
1239     assert_syntax_error("def\nf(&0)end", /^   \^/)
1240   end
1242   def test_method_location_in_rescue
1243     bug = '[ruby-core:79388] [Bug #13181]'
1244     obj, line = Object.new, __LINE__+1
1245     def obj.location
1246       #
1247       raise
1248     rescue
1249       caller_locations(1, 1)[0]
1250     end
1252     assert_equal(line, obj.location.lineno, bug)
1253   end
1255   def test_negative_line_number
1256     bug = '[ruby-core:80920] [Bug #13523]'
1257     obj = Object.new
1258     obj.instance_eval("def t(e = false);raise if e; __LINE__;end", "test", -100)
1259     assert_equal(-100, obj.t, bug)
1260     assert_equal(-100, obj.method(:t).source_location[1], bug)
1261     e = assert_raise(RuntimeError) {obj.t(true)}
1262     assert_equal(-100, e.backtrace_locations.first.lineno, bug)
1263   end
1265   def test_file_in_indented_heredoc
1266     name = '[ruby-core:80987] [Bug #13540]' # long enough to be shared
1267     assert_equal(name+"\n", eval("#{<<-"begin;"}\n#{<<-'end;'}", nil, name))
1268     begin;
1269       <<~HEREDOC
1270         #{__FILE__}
1271       HEREDOC
1272     end;
1273   end
1275   def test_heredoc_interpolation
1276     var = 1
1278     v1 = <<~HEREDOC
1279       something
1280       #{"/#{var}"}
1281     HEREDOC
1283     v2 = <<~HEREDOC
1284       something
1285       #{_other = "/#{var}"}
1286     HEREDOC
1288     v3 = <<~HEREDOC
1289       something
1290       #{("/#{var}")}
1291     HEREDOC
1293     assert_equal "something\n/1\n", v1
1294     assert_equal "something\n/1\n", v2
1295     assert_equal "something\n/1\n", v3
1296     assert_equal v1, v2
1297     assert_equal v2, v3
1298     assert_equal v1, v3
1299   end
1301   def test_heredoc_unterminated_interpolation
1302     code = <<~'HEREDOC'
1303     <<A+1
1304     #{
1305     HEREDOC
1307     assert_syntax_error(code, /can't find string "A"/)
1308   end
1310   def test_unexpected_token_error
1311     assert_syntax_error('"x"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', /unexpected/)
1312   end
1314   def test_unexpected_token_after_numeric
1315     assert_syntax_error('0000xyz', /^    \^~~\Z/)
1316     assert_syntax_error('1.2i1.1', /^    \^~~\Z/)
1317     assert_syntax_error('1.2.3', /^   \^~\Z/)
1318     assert_syntax_error('1.', /unexpected end-of-input/)
1319     assert_syntax_error('1e', /expecting end-of-input/)
1320   end
1322   def test_truncated_source_line
1323     e = assert_syntax_error("'0123456789012345678901234567890123456789' abcdefghijklmnopqrstuvwxyz0123456789 0123456789012345678901234567890123456789",
1324                             /unexpected local variable or method/)
1325     line = e.message.lines[1]
1326     assert_operator(line, :start_with?, "...")
1327     assert_operator(line, :end_with?, "...\n")
1328   end
1330   def test_unterminated_regexp_error
1331     e = assert_syntax_error("/x", /unterminated regexp meets end of file/)
1332     assert_not_match(/unexpected tSTRING_END/, e.message)
1333   end
1335   def test_lparenarg
1336     o = Struct.new(:x).new
1337     def o.i(x)
1338       self.x = x
1339     end
1340     o.instance_eval {i (-1.3).abs}
1341     assert_equal(1.3, o.x)
1342     o.i(nil)
1343     o.instance_eval {i = 0; i (-1.3).abs; i}
1344     assert_equal(1.3, o.x)
1345   end
1347   def test_serial_comparison
1348     assert_warning(/comparison '<' after/) do
1349       $VERBOSE = true
1350       x = 1
1351       eval("if false; 0 < x < 2; end")
1352       x
1353     end
1354   end
1356   def test_eof
1357     assert_equal(42, eval("42\0""end"))
1358     assert_equal(42, eval("42\C-d""end"))
1359     assert_equal(42, eval("42\C-z""end"))
1360   end
1362   def test_eof_in_def
1363     assert_syntax_error("def m\n\0""end", /unexpected/)
1364     assert_syntax_error("def m\n\C-d""end", /unexpected/)
1365     assert_syntax_error("def m\n\C-z""end", /unexpected/)
1366   end
1368   def test_unexpected_eof
1369     assert_syntax_error('unless', /^      \^\Z/)
1370   end
1372   def test_location_of_invalid_token
1373     assert_syntax_error('class xxx end', /^      \^~~\Z/)
1374   end
1376   def test_whitespace_warning
1377     assert_syntax_error("\\foo", /backslash/)
1378     assert_syntax_error("\\ ", /escaped space/)
1379     assert_syntax_error("\\\t", /escaped horizontal tab/)
1380     assert_syntax_error("\\\f", /escaped form feed/)
1381     assert_syntax_error("\\\r", /escaped carriage return/)
1382     assert_warn(/middle of line/) {eval(" \r ")}
1383     assert_syntax_error("\\\v", /escaped vertical tab/)
1384   end
1386   def test_command_def_cmdarg
1387     assert_valid_syntax("\n#{<<~"begin;"}\n#{<<~'end;'}")
1388     begin;
1389       m def x(); end
1390       1.tap do end
1391     end;
1392   end
1394   NONASCII_CONSTANTS = [
1395     *%W"\u{00de} \u{00C0}".flat_map {|c| [c, c.encode("iso-8859-15")]},
1396     "\u{1c4}", "\u{1f2}", "\u{1f88}", "\u{370}",
1397     *%W"\u{391} \u{ff21}".flat_map {|c| [c, c.encode("cp932"), c.encode("euc-jp")]},
1398   ]
1400   def assert_nonascii_const
1401     assert_all_assertions_foreach("NONASCII_CONSTANTS", *NONASCII_CONSTANTS) do |n|
1402       m = Module.new
1403       assert_not_operator(m, :const_defined?, n)
1404       assert_raise_with_message(NameError, /uninitialized/) do
1405         m.const_get(n)
1406       end
1407       assert_nil(eval("defined?(m::#{n})"))
1409       v = yield m, n
1411       assert_operator(m, :const_defined?, n)
1412       assert_equal("constant", eval("defined?(m::#{n})"))
1413       assert_same(v, m.const_get(n))
1415       m.__send__(:remove_const, n)
1416       assert_not_operator(m, :const_defined?, n)
1417       assert_nil(eval("defined?(m::#{n})"))
1418     end
1419   end
1421   def test_nonascii_const_set
1422     assert_nonascii_const do |m, n|
1423       m.const_set(n, 42)
1424     end
1425   end
1427   def test_nonascii_constant
1428     assert_nonascii_const do |m, n|
1429       m.module_eval("class #{n}; self; end")
1430     end
1431   end
1433   def test_cdmarg_after_command_args_and_tlbrace_arg
1434     assert_valid_syntax('let () { m(a) do; end }')
1435   end
1437   def test_void_value_in_rhs
1438     w = "void value expression"
1439     [
1440       "x = return 1", "x = return, 1", "x = 1, return", "x, y = return",
1441       "x = begin return ensure end",
1442       "x = begin ensure return end",
1443       "x = begin return ensure return end",
1444       "x = begin return; rescue; return end",
1445       "x = begin return; rescue; return; else return end",
1446     ].each do |code|
1447       ex = assert_syntax_error(code, w)
1448       assert_equal(1, ex.message.scan(w).size, ->{"same #{w.inspect} warning should be just once\n#{w.message}"})
1449     end
1450     [
1451       "x = begin return; rescue; end",
1452       "x = begin return; rescue; return; else end",
1453     ].each do |code|
1454       assert_valid_syntax(code)
1455     end
1456   end
1458   def eval_separately(code)
1459     Class.new.class_eval(code)
1460   end
1462   def assert_raise_separately(error, message, code)
1463     assert_raise_with_message(error, message) do
1464       eval_separately(code)
1465     end
1466   end
1468   def assert_ractor_shareable(obj)
1469     assert Ractor.shareable?(obj), ->{"Expected #{mu_pp(obj)} to be ractor shareable"}
1470   end
1472   def assert_not_ractor_shareable(obj)
1473     assert !Ractor.shareable?(obj), ->{"Expected #{mu_pp(obj)} not to be ractor shareable"}
1474   end
1476   def test_shareable_constant_value_invalid
1477     assert_warning(/invalid value/) do
1478       assert_valid_syntax("# shareable_constant_value: invalid-option", verbose: true)
1479     end
1480   end
1482   def test_shareable_constant_value_ignored
1483     assert_warning(/ignored/) do
1484       assert_valid_syntax("nil # shareable_constant_value: true", verbose: true)
1485     end
1486   end
1488   def test_shareable_constant_value_simple
1489     obj = [['unsharable_value']]
1490     a, b, c = eval_separately("#{<<~"begin;"}\n#{<<~'end;'}")
1491     begin;
1492       # shareable_constant_value: experimental_everything
1493       A = [[1]]
1494       # shareable_constant_value: none
1495       B = [[2]]
1496       # shareable_constant_value: literal
1497       C = [["shareable", "constant#{nil}"]]
1498       D = A
1500       [A, B, C]
1501     end;
1502     assert_ractor_shareable(a)
1503     assert_not_ractor_shareable(b)
1504     assert_ractor_shareable(c)
1505     assert_equal([1], a[0])
1506     assert_ractor_shareable(a[0])
1508     a, obj = eval_separately(<<~'end;')
1509       # shareable_constant_value: experimental_copy
1510       obj = [["unshareable"]]
1511       A = obj
1512       [A, obj]
1513     end;
1515     assert_ractor_shareable(a)
1516     assert_not_ractor_shareable(obj)
1517     assert_equal obj, a
1518     assert !obj.equal?(a)
1519   end
1521   def test_shareable_constant_value_nested
1522     a, b = eval_separately("#{<<~"begin;"}\n#{<<~'end;'}")
1523     begin;
1524       # shareable_constant_value: none
1525       class X
1526         # shareable_constant_value: experimental_everything
1527         var = [[1]]
1528         A = var
1529       end
1530       B = []
1531       [X::A, B]
1532     end;
1533     assert_ractor_shareable(a)
1534     assert_not_ractor_shareable(b)
1535     assert_equal([1], a[0])
1536     assert_ractor_shareable(a[0])
1537   end
1539   def test_shareable_constant_value_unshareable_literal
1540     assert_raise_separately(Ractor::IsolationError, /unshareable object to C/,
1541                             "#{<<~"begin;"}\n#{<<~'end;'}")
1542     begin;
1543       # shareable_constant_value: literal
1544       C = ["Not " + "shareable"]
1545     end;
1547     assert_raise_separately(Ractor::IsolationError, /unshareable object to B::C/,
1548                             "#{<<~"begin;"}\n#{<<~'end;'}")
1549     begin;
1550       # shareable_constant_value: literal
1551       B = Class.new
1552       B::C = ["Not " + "shareable"]
1553     end;
1555     assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
1556     begin;
1557       assert_raise_with_message(Ractor::IsolationError, /unshareable object to ::C/) do
1558         # shareable_constant_value: literal
1559         ::C = ["Not " + "shareable"]
1560       end
1561     end;
1563     assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
1564     begin;
1565       assert_raise_with_message(Ractor::IsolationError, /unshareable object to ::B::C/) do
1566         # shareable_constant_value: literal
1567         ::B = Class.new
1568         ::B::C = ["Not " + "shareable"]
1569       end
1570     end;
1571   end
1573   def test_shareable_constant_value_nonliteral
1574     assert_raise_separately(Ractor::IsolationError, /unshareable/, "#{<<~"begin;"}\n#{<<~'end;'}")
1575     begin;
1576       # shareable_constant_value: literal
1577       var = [:not_frozen]
1578       C = var
1579     end;
1581     assert_raise_separately(Ractor::IsolationError, /unshareable/, "#{<<~"begin;"}\n#{<<~'end;'}")
1582     begin;
1583       # shareable_constant_value: literal
1584       D = begin [] end
1585     end;
1586   end
1588   def test_shareable_constant_value_unfrozen
1589     assert_raise_separately(Ractor::Error, /does not freeze object correctly/,
1590                             "#{<<~"begin;"}\n#{<<~'end;'}")
1591     begin;
1592       # shareable_constant_value: experimental_everything
1593       o = Object.new
1594       def o.freeze; self; end
1595       C = [o]
1596     end;
1597   end
1599   def test_if_after_class
1600     assert_valid_syntax('module if true; Object end::Kernel; end')
1601     assert_valid_syntax('module while true; break Object end::Kernel; end')
1602     assert_valid_syntax('class if true; Object end::Kernel; end')
1603     assert_valid_syntax('class while true; break Object end::Kernel; end')
1604   end
1606   def test_escaped_space
1607     assert_syntax_error('x = \ 42', /escaped space/)
1608   end
1610   def test_label
1611     expected = {:foo => 1}
1613     code = '{"foo": 1}'
1614     assert_valid_syntax(code)
1615     assert_equal(expected, eval(code))
1617     code = '{foo: 1}'
1618     assert_valid_syntax(code)
1619     assert_equal(expected, eval(code))
1621     class << (obj = Object.new)
1622       attr_reader :arg
1623       def set(arg)
1624         @arg = arg
1625       end
1626     end
1628     assert_valid_syntax(code = "#{<<~"do;"}\n#{<<~'end;'}")
1629     do;
1630       obj.set foo:
1631                 1
1632     end;
1633     assert_equal(expected, eval(code))
1634     assert_equal(expected, obj.arg)
1636     assert_valid_syntax(code = "#{<<~"do;"}\n#{<<~'end;'}")
1637     do;
1638       obj.set "foo":
1639                   1
1640     end;
1641     assert_equal(expected, eval(code))
1642     assert_equal(expected, obj.arg)
1643   end
1645   def test_ungettable_gvar
1646     assert_syntax_error('$01234', /not allowed/)
1647     assert_syntax_error('"#$01234"', /not allowed/)
1648   end
1650 =begin
1651   def test_past_scope_variable
1652     assert_warning(/past scope/) {catch {|tag| eval("BEGIN{throw tag}; tap {a = 1}; a")}}
1653   end
1654 =end
1656   def assert_parse(code)
1657     assert_kind_of(RubyVM::AbstractSyntaxTree::Node, RubyVM::AbstractSyntaxTree.parse(code))
1658   end
1660   def assert_parse_error(code, message)
1661     assert_raise_with_message(SyntaxError, message) do
1662       $VERBOSE, verbose_bak = nil, $VERBOSE
1663       begin
1664         RubyVM::AbstractSyntaxTree.parse(code)
1665       ensure
1666         $VERBOSE = verbose_bak
1667       end
1668     end
1669   end