summaryrefslogtreecommitdiff
path: root/yarvtest
diff options
context:
space:
mode:
Diffstat (limited to 'yarvtest')
-rw-r--r--yarvtest/runner.rb10
-rw-r--r--yarvtest/test_bin.rb585
-rw-r--r--yarvtest/test_block.rb429
-rw-r--r--yarvtest/test_class.rb753
-rw-r--r--yarvtest/test_eval.rb213
-rw-r--r--yarvtest/test_exception.rb408
-rw-r--r--yarvtest/test_flow.rb591
-rw-r--r--yarvtest/test_jump.rb296
-rw-r--r--yarvtest/test_massign.rb417
-rw-r--r--yarvtest/test_method.rb539
-rw-r--r--yarvtest/test_opts.rb118
-rw-r--r--yarvtest/test_proc.rb293
-rw-r--r--yarvtest/test_syntax.rb594
-rw-r--r--yarvtest/test_test.rb8
-rw-r--r--yarvtest/test_thread.rb209
-rw-r--r--yarvtest/test_yield.rb207
-rw-r--r--yarvtest/yarvtest.rb136
17 files changed, 5806 insertions, 0 deletions
diff --git a/yarvtest/runner.rb b/yarvtest/runner.rb
new file mode 100644
index 0000000000..25b813e99c
--- /dev/null
+++ b/yarvtest/runner.rb
@@ -0,0 +1,10 @@
+require 'test/unit'
+
+if $0 == __FILE__
+ # exit Test::Unit::AutoRunner.run(false, File.dirname($0))
+ Dir.glob(File.dirname($0) + '/test_*'){|file|
+ p file
+ require file
+ }
+end
+
diff --git a/yarvtest/test_bin.rb b/yarvtest/test_bin.rb
new file mode 100644
index 0000000000..5f587b5a8c
--- /dev/null
+++ b/yarvtest/test_bin.rb
@@ -0,0 +1,585 @@
+require 'yarvtest/yarvtest'
+
+# test of basic instruction
+class TestBIN < YarvTestBase
+
+ def test_literal
+ ae %q(true)
+ ae %q(false)
+ ae %q(nil)
+ ae %q(1234)
+ ae %q(:sym)
+ ae %q(123456789012345678901234567890)
+ ae %q(1.234)
+ ae %q(0x12)
+ ae %q(0b0101001)
+ ae %q(1_2_3) # 123
+ end
+
+ def test_self
+ ae %q(self)
+ end
+
+ def test_string
+ ae %q('str')
+ end
+
+ def test_dstring
+ ae %q(
+ "1+1 = #{1+1}"
+ )
+ ae %q{
+ i = 10
+ "#{i} ** #{i} = #{i ** i}"
+ }
+ ae %q{
+ s = "str"
+ s.__id__ == "#{s}".__id__
+ }
+ end
+
+ def test_dsym
+ ae %q{
+ :"a#{1+2}c"
+ }
+ end
+
+ def test_xstr
+ ae %q(`echo hoge`)
+ ae %q(hoge = 'huga'; `echo #{hoge}`)
+ end
+
+ def test_regexp
+ ae %q{
+ /test/ =~ 'test'
+ }
+ ae %q{
+ /test/ =~ 'tes'
+ }
+ ae %q{
+ r = /test/; l = 'test'
+ r =~ l
+ }
+ ae %q{
+ r = /testx/; l = 'test'
+ r =~ l
+ }
+ ae %q{
+ i = 10
+ /test#{i}/ =~ 'test10'
+ }
+ ae %q{
+ i = 10
+ /test#{i}/ =~ 'test20'
+ }
+ ae %q{
+ :sym =~ /sym/
+ }
+ ae %q{
+ sym = :sym
+ sym =~ /sym/
+ }
+ ae %q{
+ reg = /sym/
+ :sym =~ reg
+ }
+ end
+
+ def test_array
+ ae %q([])
+ ae %q([1,2,3])
+ ae %q([1+1,2+2,3+3])
+ ae %q([0][0]+=3)
+ ae %q([0][0]-=3)
+ end
+
+ def test_array_access
+ ae %q(ary = [1,2,3]; ary[1])
+ ae %q(ary = [1,2,3]; ary[1] = 10)
+ ae %q(ary = Array.new(10, 100); ary[3])
+ end
+
+ def test_hash
+ ae %q({})
+ ae %q({1 => 2})
+ ae %q({"str" => "val", "str2" => "valval"})
+ ae %q({1 => 2, 1=>3})
+ end
+
+ def test_range
+ ae %q((1..2))
+ ae %q((1...2))
+ ae %q(((1+1)..(2+2)))
+ ae %q(((1+1)...(2+2)))
+ end
+
+ def test_not
+ ae %q(!true)
+ ae %q(!nil)
+ ae %q(!false)
+ ae %q(!(1+1))
+ ae %q(!!nil)
+ ae %q(!!1)
+ end
+
+ # var
+ def test_local
+ ae %q(a = 1)
+ ae %q(a = 1; b = 2; a)
+ ae %q(a = b = 3)
+ ae %q(a = b = 3; a)
+ ae %q(a = b = c = 4)
+ ae %q(a = b = c = 4; c)
+ end
+
+ def test_constant
+ ae %q(C = 1; C)
+ ae %q(C = 1; $a = []; 2.times{$a << ::C}; $a)
+ ae %q(
+ class A
+ class B
+ class C
+ Const = 1
+ end
+ end
+ end
+ (1..2).map{
+ A::B::C::Const
+ }
+ ) do
+ remove_const :A
+ end
+
+ ae %q(
+ class A
+ class B
+ Const = 1
+ class C
+ (1..2).map{
+ Const
+ }
+ end
+ end
+ end
+ ) do
+ remove_const :A
+ end
+
+ ae %q(
+ class A
+ Const = 1
+ class B
+ class C
+ (1..2).map{
+ Const
+ }
+ end
+ end
+ end
+ ) do
+ remove_const :A
+ end
+
+ ae %q(
+ Const = 1
+ class A
+ class B
+ class C
+ (1..2).map{
+ Const
+ }
+ end
+ end
+ end
+ ) do
+ remove_const :A
+ remove_const :Const
+ end
+
+ ae %q{
+ C = 1
+ begin
+ C::D
+ rescue TypeError
+ :ok
+ else
+ :ng
+ end
+ }
+ end
+
+ def test_constant2
+ ae %q{
+ class A
+ class B
+ C = 10
+ end
+ end
+ i = 0
+ while i<3
+ i+=1
+ r = A::B::C
+ end
+ r
+ } do
+ remove_const :A
+ end
+
+ ae %q{
+ class A
+ class B
+ C = 10
+ end
+ end
+ i = 0
+ while i<3
+ i+=1
+ r = A::B::C
+ class A::B
+ remove_const :C
+ end
+ A::B::C = i**i
+ end
+ r
+ } do
+ remove_const :A
+ end
+
+ ae %q{
+ class C
+ Const = 1
+ (1..3).map{
+ self::Const
+ }
+ end
+ }
+ ae %q{
+ class C
+ Const = 1
+ (1..3).map{
+ eval('self')::Const
+ }
+ end
+ }
+ ae %q{
+ class C
+ Const = 0
+ def self.foo()
+ self::Const
+ end
+ end
+
+ class D < C
+ Const = 1
+ end
+
+ class E < C
+ Const = 2
+ end
+
+ [C.foo, D.foo, E.foo]
+ }
+ end
+
+ def test_gvar
+ ae %q(
+ $g1 = 1
+ )
+
+ ae %q(
+ $g2 = 2
+ $g2
+ )
+ end
+
+ def test_cvar
+ ae %q{
+ class C
+ @@c = 1
+ def m
+ @@c += 1
+ end
+ end
+
+ C.new.m
+ } do
+ remove_const :C
+ end
+ end
+
+ def test_cvar_from_singleton
+ ae %q{
+ class C
+ @@c=1
+ class << self
+ def m
+ @@c += 1
+ end
+ end
+ end
+ C.m
+ } do
+ remove_const :C
+ end
+ end
+
+ def test_cvar_from_singleton2
+ ae %q{
+ class C
+ @@c = 1
+ def self.m
+ @@c += 1
+ end
+ end
+ C.m
+ } do
+ remove_const :C
+ end
+ end
+
+ def test_op_asgin2
+ ae %q{
+ class C
+ attr_accessor :a
+ end
+ r = []
+ o = C.new
+ o.a &&= 1
+ r << o.a
+ o.a ||= 2
+ r << o.a
+ o.a &&= 3
+ r << o.a
+ r
+ } do
+ remove_const :C
+ end
+ ae %q{
+ @@x ||= 1
+ }
+ ae %q{
+ @@x = 0
+ @@x ||= 1
+ }
+ end
+
+ def test_op_assgin_and_or
+ ae %q{
+ r = []
+ a = 1 ; a ||= 2; r << a
+ a = nil; a ||= 2; r << a
+ a = 1 ; a &&= 2; r << a
+ a = nil; a &&= 2; r << a
+ r
+ }
+ ae %q{
+ a = {}
+ a[0] ||= 1
+ }
+ ae %q{
+ a = {}
+ a[0] &&= 1
+ }
+ ae %q{
+ a = {0 => 10}
+ a[0] ||= 1
+ }
+ ae %q{
+ a = {0 => 10}
+ a[0] &&= 1
+ }
+ end
+
+ def test_backref
+ ae %q{
+ /a(b)(c)d/ =~ 'xyzabcdefgabcdefg'
+ [$1, $2, $3, $~.class, $&, $`, $', $+]
+ }
+
+ ae %q{
+ def m
+ /a(b)(c)d/ =~ 'xyzabcdefgabcdefg'
+ [$1, $2, $3, $~.class, $&, $`, $', $+]
+ end
+ m
+ }
+ end
+
+ def test_fact
+ ae %q{
+ def fact(n)
+ if(n > 1)
+ n * fact(n-1)
+ else
+ 1
+ end
+ end
+ fact(300)
+ }
+ end
+
+ def test_mul
+ ae %q{
+ 2*0
+ }
+ ae %q{
+ 0*2
+ }
+ ae %q{
+ 2*2
+ }
+ end
+
+ def test_div
+ ae %q{
+ 3/2
+ }
+ ae %q{
+ 3.0/2.0
+ }
+ ae %q{
+ class C
+ def /(a)
+ a * 100
+ end
+ end
+ C.new/3
+ } do
+ remove_const :C
+ end
+ end
+
+ def test_length
+ ae %q{
+ [].length
+ }
+ ae %q{
+ [1, 2].length
+ }
+ ae %q{
+ {}.length
+ }
+ ae %q{
+ {:a => 1, :b => 2}.length
+ }
+ ae %q{
+ class C
+ def length
+ 'hoge'
+ end
+ end
+ C.new.length
+ } do
+ remove_const :C
+ end
+ end
+
+ def test_mod
+ ae %q{
+ 3%2
+ }
+ ae %q{
+ 3.0%2.0
+ }
+ ae %q{
+ class C
+ def % (a)
+ a * 100
+ end
+ end
+ C.new%3
+ } do
+ remove_const :C
+ end
+ end
+
+ def test_attr_set
+ ae %q{
+ o = Object.new
+ def o.[]=(*args)
+ args
+ end
+ [o[]=:x, o[0]=:x, o[0, 1]=:x, o[0, 1, 2]=:x]
+ }
+ ae %q{
+ o = Object.new
+ def o.foo=(*args)
+ args
+ end
+ o.foo = :x
+ }
+ ae %q{
+ $r = []
+ class C
+ def [](*args)
+ $r << [:ref, args]
+ args.size
+ end
+
+ def []=(*args)
+ $r << [:set, args]
+ args.size
+ end
+ end
+
+ o = C.new
+ ary = [:x, :y]
+ o[1] = 2
+ o[1, 2] = 3
+ o[1, 2, *ary] = 3
+ o[1, 2, *ary, 3] = 4
+ $r
+ }
+ end
+
+ def test_aref_aset
+ ae %q{
+ a = []
+ a << 0
+ a[1] = 1
+ a[2] = 2
+ a[3] = a[1] + a[2]
+ }
+ ae %q{
+ a = {}
+ a[1] = 1
+ a[2] = 2
+ a[3] = a[1] + a[2]
+ a.sort
+ }
+ ae %q{
+ class C
+ attr_reader :a, :b
+ def [](a)
+ @a = a
+ end
+
+ def []=(a, b)
+ @b = [a, b]
+ end
+ end
+ c = C.new
+ c[3]
+ c[4] = 5
+ [c.a, c.b]
+ } do
+ remove_const :C
+ end
+ end
+
+ def test_array_concat
+ ae %q{
+ ary = []
+ [:x, *ary]
+ }
+ #ae %q{
+ # ary = 1
+ # [:x, *ary]
+ #}
+ ae %q{
+ ary = [1, 2]
+ [:x, *ary]
+ }
+ end
+end
+
diff --git a/yarvtest/test_block.rb b/yarvtest/test_block.rb
new file mode 100644
index 0000000000..87800da5f6
--- /dev/null
+++ b/yarvtest/test_block.rb
@@ -0,0 +1,429 @@
+require 'yarvtest/yarvtest'
+
+class TestBlock < YarvTestBase
+ def test_simple
+ ae %q(
+ def m
+ yield
+ end
+ m{
+ 1
+ }
+ )
+ end
+
+ def test_param
+ ae %q(
+ def m
+ yield 1
+ end
+ m{|ib|
+ ib*2
+ }
+ )
+
+ ae %q(
+ def m
+ yield 12345, 67890
+ end
+ m{|ib,jb|
+ ib*2+jb
+ }
+ )
+ end
+
+ def test_param2
+ ae %q{
+ def iter
+ yield 10
+ end
+
+ a = nil
+ [iter{|a|
+ a
+ }, a]
+ }
+ ae %q{
+ def iter
+ yield 10
+ end
+
+ iter{|a|
+ iter{|a|
+ a + 1
+ } + a
+ }
+ }
+ ae %q{
+ def iter
+ yield 10, 20, 30, 40
+ end
+
+ a = b = c = d = nil
+ iter{|a, b, c, d|
+ [a, b, c, d]
+ } + [a, b, c, d]
+ }
+ ae %q{
+ def iter
+ yield 10, 20, 30, 40
+ end
+
+ a = b = nil
+ iter{|a, b, c, d|
+ [a, b, c, d]
+ } + [a, b]
+ }
+ ae %q{
+ def iter
+ yield 10, 20, 30, 40
+ end
+
+ a = nil
+ iter{|a, $b, @c, d|
+ [a, $b]
+ } + [a, $b, @c]
+ } if false # 1.9 doesn't support expr block parameters
+ end
+
+ def test_param3
+ if false
+ # TODO: Ruby 1.9 doesn't support expr block parameter
+ ae %q{
+ h = {}
+ [1].each{|h[:foo]|}
+ h
+ }
+ ae %q{
+ obj = Object.new
+ def obj.x=(y)
+ $ans = y
+ end
+ [1].each{|obj.x|}
+ $ans
+ }
+ end
+ end
+
+ def test_blocklocal
+ ae %q{
+ 1.times{
+ begin
+ a = 1
+ ensure
+ foo = nil
+ end
+ }
+ }
+ end
+
+ def test_simplenest
+ ae %q(
+ def m
+ yield 123
+ end
+ m{|ib|
+ m{|jb|
+ ib*jb
+ }
+ }
+ )
+ end
+
+ def test_simplenest2
+ ae %q(
+ def m a
+ yield a
+ end
+ m(1){|ib|
+ m(2){|jb|
+ ib*jb
+ }
+ }
+ )
+ end
+
+ def test_nest2
+ ae %q(
+ def m
+ yield
+ end
+ def n
+ yield
+ end
+
+ m{
+ n{
+ 100
+ }
+ }
+ )
+
+ ae %q(
+ def m
+ yield 1
+ end
+
+ m{|ib|
+ m{|jb|
+ i = 20
+ }
+ }
+ )
+
+ ae %q(
+ def m
+ yield 1
+ end
+
+ m{|ib|
+ m{|jb|
+ ib = 20
+ kb = 2
+ }
+ }
+ )
+
+ ae %q(
+ def iter1
+ iter2{
+ yield
+ }
+ end
+
+ def iter2
+ yield
+ end
+
+ iter1{
+ jb = 2
+ iter1{
+ jb = 3
+ }
+ jb
+ }
+ )
+
+ ae %q(
+ def iter1
+ iter2{
+ yield
+ }
+ end
+
+ def iter2
+ yield
+ end
+
+ iter1{
+ jb = 2
+ iter1{
+ jb
+ }
+ jb
+ }
+ )
+ end
+
+ def test_ifunc
+ ae %q{
+ (1..3).to_a
+ }
+
+ ae %q{
+ (1..3).map{|e|
+ e * 4
+ }
+ }
+
+ ae %q{
+ class C
+ include Enumerable
+ def each
+ [1,2,3].each{|e|
+ yield e
+ }
+ end
+ end
+
+ C.new.to_a
+ }
+
+ ae %q{
+ class C
+ include Enumerable
+ def each
+ [1,2,3].each{|e|
+ yield e
+ }
+ end
+ end
+
+ C.new.map{|e|
+ e + 3
+ }
+ }
+ end
+
+ def test_times
+ ae %q{
+ sum = 0
+ 3.times{|ib|
+ 2.times{|jb|
+ sum += ib + jb
+ }}
+ sum
+ }
+ ae %q{
+ 3.times{|bl|
+ break 10
+ }
+ }
+ end
+
+ def test_for
+ ae %q{
+ sum = 0
+ for x in [1, 2, 3]
+ sum += x
+ end
+ sum
+ }
+ ae %q{
+ sum = 0
+ for x in (1..5)
+ sum += x
+ end
+ sum
+ }
+ ae %q{
+ sum = 0
+ for x in []
+ sum += x
+ end
+ sum
+ }
+ ae %q{
+ ans = []
+ 1.times{
+ for n in 1..3
+ a = n
+ ans << a
+ end
+ }
+ }
+ ae %q{
+ ans = []
+ for m in 1..3
+ for n in 1..3
+ a = [m, n]
+ ans << a
+ end
+ end
+ }
+ end
+
+ def test_unmatched_params
+ ae %q{
+ def iter
+ yield 1,2,3
+ end
+
+ iter{|i, j|
+ [i, j]
+ }
+ }
+ ae %q{
+ def iter
+ yield 1
+ end
+
+ iter{|i, j|
+ [i, j]
+ }
+ }
+ end
+
+ def test_rest
+ # TODO: known bug
+ #ae %q{
+ # def iter
+ # yield 1, 2
+ # end
+ #
+ # iter{|a, |
+ # [a]
+ # }
+ #}
+ ae %q{
+ def iter
+ yield 1, 2
+ end
+
+ iter{|a, *b|
+ [a, b]
+ }
+ }
+ ae %q{
+ def iter
+ yield 1, 2
+ end
+
+ iter{|*a|
+ [a]
+ }
+ }
+ ae %q{
+ def iter
+ yield 1, 2
+ end
+
+ iter{|a, b, *c|
+ [a, b, c]
+ }
+ }
+ ae %q{
+ def iter
+ yield 1, 2
+ end
+
+ iter{|a, b, c, *d|
+ [a, b, c, d]
+ }
+ }
+ end
+
+ def test_param_and_locals
+ ae %q{
+ $a = []
+
+ def iter
+ yield 1
+ end
+
+ def m
+ x = iter{|x|
+ $a << x
+ y = 0
+ }
+ end
+ m
+ $a
+ }
+ end
+
+ def test_c_break
+ ae %q{
+ [1,2,3].find{|x| x == 2}
+ }
+ ae %q{
+ class E
+ include Enumerable
+ def each(&block)
+ [1, 2, 3].each(&block)
+ end
+ end
+ E.new.find {|x| x == 2 }
+ }
+ end
+end
diff --git a/yarvtest/test_class.rb b/yarvtest/test_class.rb
new file mode 100644
index 0000000000..1eab39f0d5
--- /dev/null
+++ b/yarvtest/test_class.rb
@@ -0,0 +1,753 @@
+require 'yarvtest/yarvtest'
+
+class TestClass < YarvTestBase
+
+ def test_simple
+ ae %q(
+ class C
+ def m(a,b)
+ a+b
+ end
+ end
+ C.new.m(1,2)
+ ) do
+ remove_const(:C)
+ end
+
+ ae %q(
+ class A
+ end
+ class A::B
+ def m
+ A::B.name
+ end
+ end
+ A::B.new.m
+ ) do
+ remove_const(:A)
+ end
+
+ #ae %q(
+ # class (class C;self; end)::D < C
+ # self.name
+ # end
+ #) do
+ # remove_const(:C)
+ #end
+
+ end
+
+ def test_sub
+ ae %q(
+ class A
+ def m
+ 123
+ end
+ end
+
+ class B < A
+ end
+
+ B.new.m
+ ) do
+ remove_const(:A)
+ remove_const(:B)
+ end
+
+ ae %q(
+ class A
+ class B
+ class C
+ def m
+ 456
+ end
+ end
+ end
+ end
+
+ class A::BB < A::B::C
+ end
+
+ A::BB.new.m
+ ) do
+ remove_const(:A)
+ end
+ end
+
+ def test_attr
+ ae %q(
+ class C
+ def set
+ @a = 1
+ end
+ def get
+ @a
+ end
+ end
+ c = C.new
+ c.set
+ c.get
+ ) do
+ remove_const(:C)
+ end
+ end
+
+ def test_initialize
+ ae %q{
+ class C
+ def initialize
+ @a = :C
+ end
+ def a
+ @a
+ end
+ end
+
+ C.new.a
+ } do
+ remove_const(:C)
+ end
+ end
+
+ def test_to_s
+ ae %q{
+ class C
+ def to_s
+ "hoge"
+ end
+ end
+
+ "ab#{C.new}cd"
+ } do
+ remove_const(:C)
+ end
+
+ end
+
+ def test_attr_accessor
+ ae %q{
+ class C
+ attr_accessor :a
+ attr_reader :b
+ attr_writer :c
+ def b_write
+ @b = 'huga'
+ end
+ def m a
+ 'test_attr_accessor' + @b + @c
+ end
+ end
+
+ c = C.new
+ c.a = true
+ c.c = 'hoge'
+ c.b_write
+ c.m(c.b)
+ } do
+ remove_const(:C)
+ end
+ end
+
+ def test_super
+ ae %q{
+ class C
+ def m1
+ 100
+ end
+
+ def m2 a
+ a + 100
+ end
+ end
+
+ class CC < C
+ def m1
+ super() * 100
+ end
+
+ def m2
+ super(200) * 100
+ end
+ end
+
+ a = CC.new
+ a.m1 + a.m2
+ } do
+ remove_const(:C)
+ remove_const(:CC)
+ end
+ end
+
+ def test_super2
+ ae %q{
+ class C
+ def m(a, b)
+ a+b
+ end
+ end
+
+ class D < C
+ def m arg
+ super(*arg) + super(1, arg.shift)
+ end
+ end
+
+ D.new.m([1, 2])
+ }
+
+ ae %q{
+ class C
+ def m
+ yield
+ end
+ end
+
+ class D < C
+ def m
+ super(){
+ :D
+ }
+ end
+ end
+
+ D.new.m{
+ :top
+ }
+ }
+ ae %q{
+ class C0
+ def m a, &b
+ [a, b]
+ end
+ end
+
+ class C1 < C0
+ def m a, &b
+ super a, &b
+ end
+ end
+
+ C1.new.m(10)
+ }
+ end
+
+ def test_zsuper_from_define_method
+ ae %q{
+ class C
+ def a
+ "C#a"
+ end
+ def m
+ "C#m"
+ end
+ end
+ class D < C
+ define_method(:m){
+ super
+ }
+ define_method(:a){
+ r = nil
+ 1.times{
+ r = super
+ }
+ r
+ }
+ end
+ D.new.m + D.new.a
+ }
+ ae %q{
+ class X
+ def a
+ "X#a"
+ end
+ def b
+ class << self
+ define_method(:a) {
+ super
+ }
+ end
+ end
+ end
+
+ x = X.new
+ x.b
+ x.a
+ }
+ ae %q{
+ class C
+ def m arg
+ "C#m(#{arg})"
+ end
+ def b
+ class << self
+ define_method(:m){|a|
+ super
+ }
+ end
+ self
+ end
+ end
+ C.new.b.m(:ok)
+ }
+ ae %q{
+ class C
+ def m *args
+ "C#m(#{args.join(', ')})"
+ end
+ def b
+ class << self
+ define_method(:m){|a, b|
+ r = nil
+ 1.times{
+ r = super
+ }
+ r
+ }
+ end
+ self
+ end
+ end
+ C.new.b.m(:ok1, :ok2)
+ } if false # ruby 1.9 dumped core
+ ae %q{ # [yarv-dev:859]
+ $ans = []
+ class A
+ def m_a
+ $ans << "m_a"
+ end
+ def def_m_a
+ $ans << "def_m_a"
+ end
+ end
+ class B < A
+ def def_m_a
+ B.class_eval{
+ super
+ define_method(:m_a) do
+ super
+ end
+ }
+ super
+ end
+ end
+ b = B.new
+ b.def_m_a
+ b.m_a
+ $ans
+ }
+ ae %q{
+ class A
+ def hoge
+ :hoge
+ end
+ def foo
+ :foo
+ end
+ end
+ class B < A
+ def memoize(name)
+ B.instance_eval do
+ define_method(name) do
+ [name, super]
+ end
+ end
+ end
+ end
+ b = B.new
+ b.memoize(:hoge)
+ b.memoize(:foo)
+ [b.foo, b.hoge]
+ }
+ end
+
+ def test_zsuper
+ ae %q{
+ class C
+ def m1
+ 100
+ end
+
+ def m2 a
+ a + 100
+ end
+
+ def m3 a
+ a + 200
+ end
+ end
+
+ class CC < C
+ def m1
+ super * 100
+ end
+
+ def m2 a
+ super * 100
+ end
+
+ def m3 a
+ a = 400
+ super * 100
+ end
+ end
+
+ a = CC.new
+ a.m1 + a.m2(200) + a.m3(300)
+ } do
+ remove_const(:C)
+ remove_const(:CC)
+ end
+ end
+
+ def test_zsuper2
+ ae %q{
+ class C1
+ def m
+ 10
+ end
+ end
+
+ class C2 < C1
+ def m
+ 20 + super
+ end
+ end
+
+ class C3 < C2
+ def m
+ 30 + super
+ end
+ end
+
+ C3.new.m
+ } do
+ remove_const(:C1)
+ remove_const(:C2)
+ remove_const(:C3)
+ end
+
+ ae %q{
+ class C
+ def m
+ yield
+ end
+ end
+
+ class D < C
+ def m
+ super{
+ :D
+ }
+ end
+ end
+
+ D.new.m{
+ :top
+ }
+ }
+ ae %q{
+ class C
+ def m(a, b, c, d)
+ a+b+c+d
+ end
+ end
+
+ class D < C
+ def m(a, b=1, c=2, *d)
+ d[0] ||= 0.1
+ [super,
+ begin
+ a *= 2
+ b *= 3
+ c *= 4
+ d[0] *= 5
+ super
+ end
+ ]
+ end
+ end
+ ary = []
+ ary << D.new.m(10, 20, 30, 40)
+ if false # On current ruby, these programs don't work
+ ary << D.new.m(10, 20, 30)
+ ary << D.new.m(10, 20)
+ ary << D.new.m(10)
+ end
+ ary
+ }
+ ae %q{
+ class C
+ def m(a, b, c, d)
+ a+b+c+d
+ end
+ end
+
+ class D < C
+ def m(a, b=1, c=2, d=3)
+ [super,
+ begin
+ a *= 2
+ b *= 3
+ c *= 4
+ d *= 5
+ super
+ end
+ ]
+ end
+ end
+ ary = []
+ ary << D.new.m(10, 20, 30, 40)
+ ary << D.new.m(10, 20, 30)
+ ary << D.new.m(10, 20)
+ ary << D.new.m(10)
+ ary
+ }
+ ae %q{
+ class C
+ def m(a, b, c, d, &e)
+ a+b+c+d+e.call
+ end
+ def n(a, b, c, d, &e)
+ a+b+c+d+e.call
+ end
+ end
+
+ class D < C
+ def m(a, b=1, c=2, *d, &e)
+ super
+ end
+ def n(a, b=1, c=2, d=3, &e)
+ super
+ end
+ end
+ ary = []
+ ary << D.new.m(1, 2, 3, 4){
+ 5
+ }
+ ary << D.new.m(1, 2, 3, 4, &lambda{
+ 5
+ })
+ ary << D.new.n(1, 2, 3){
+ 5
+ }
+ ary << D.new.n(1, 2){
+ 5
+ }
+ ary << D.new.n(1){
+ 5
+ }
+ ary
+ }
+ end
+
+ def test_super_with_private
+ ae %q{
+ class C
+ private
+ def m1
+ :OK
+ end
+ protected
+ def m2
+ end
+ end
+ class D < C
+ def m1
+ [super, super()]
+ end
+ def m2
+ [super, super()]
+ end
+ end
+ D.new.m1 + D.new.m2
+ }
+ end
+
+ def test_const_in_other_scope
+ ae %q{
+ class C
+ Const = :ok
+ def m
+ 1.times{
+ Const
+ }
+ end
+ end
+ C.new.m
+ } do
+ remove_const(:C)
+ end
+
+ ae %q{
+ class C
+ Const = 1
+ def m
+ begin
+ raise
+ rescue
+ Const
+ end
+ end
+ end
+ C.new.m
+ } do
+ remove_const(:C)
+ end
+ end
+
+ def test_reopen_not_class
+ ae %q{ # [yarv-dev:782]
+ begin
+ B = 1
+ class B
+ p B
+ end
+ rescue TypeError => e
+ e.message
+ end
+ }
+ ae %q{ # [yarv-dev:800]
+ begin
+ B = 1
+ module B
+ p B
+ end
+ rescue TypeError => e
+ e.message
+ end
+ }
+ end
+
+ def test_set_const_not_class
+ ae %q{
+ begin
+ 1::A = 1
+ rescue TypeError => e
+ e.message
+ end
+ }
+ end
+
+ def test_singletonclass
+ ae %q{
+ obj = ''
+ class << obj
+ def m
+ :OK
+ end
+ end
+ obj.m
+ }
+ ae %q{
+ obj = ''
+ Const = :NG
+ class << obj
+ Const = :OK
+ def m
+ Const
+ end
+ end
+ obj.m
+ }
+ ae %q{
+ obj = ''
+ class C
+ def m
+ :NG
+ end
+ end
+ class << obj
+ class C
+ def m
+ :OK
+ end
+ end
+ def m
+ C.new.m
+ end
+ end
+ obj.m
+ }
+ ae %q{ # [yarv-dev:818]
+ class A
+ end
+ class << A
+ C = "OK"
+ def m
+ class << Object
+ $a = C
+ end
+ end
+ end
+ A.m
+ $a
+ }
+ end
+
+ def test_include
+ ae %q{
+ module M
+ class A
+ def hoge
+ "hoge"
+ end
+ end
+ end
+
+ class A
+ include M
+ def m
+ [Module.nesting, A.new.hoge, instance_eval("A.new.hoge")]
+ end
+ end
+ A.new.m
+ }
+ end
+
+ def test_colon3
+ ae %q{
+ class A
+ ::B = :OK
+ end
+ B
+ }
+ ae %q{
+ class A
+ class ::C
+ end
+ end
+ C
+ }
+ end
+
+ def test_undef
+ # [yarv-dev:999]
+ ae %q{
+ class Parent
+ def foo
+ end
+ end
+ class Child < Parent
+ def bar
+ end
+
+ undef foo, bar
+ end
+
+ c = Child.new
+ [c.methods.include?('foo'), c.methods.include?('bar')]
+ }
+ end
+
+ def test_dup
+ ae %q{
+ ObjectSpace.each_object{|obj|
+ if Module === obj && (obj.respond_to? :dup)
+ obj.dup
+ end
+ }
+ :ok
+ }
+ end
+end
+
diff --git a/yarvtest/test_eval.rb b/yarvtest/test_eval.rb
new file mode 100644
index 0000000000..fc4ac0372d
--- /dev/null
+++ b/yarvtest/test_eval.rb
@@ -0,0 +1,213 @@
+require 'yarvtest/yarvtest'
+
+class TestEval < YarvTestBase
+ def test_eval
+ ae %q{
+ eval('1')
+ }
+ ae %q{
+ eval('a=1; a')
+ }
+ ae %q{
+ a = 1
+ eval('a')
+ }
+ end
+
+ def test_eval_with_send
+ ae %q{
+ __send! :eval, %{
+ :ok
+ }
+ }
+ ae %q{
+ 1.__send! :instance_eval, %{
+ :ok
+ }
+ }
+ end
+
+ def test_module_eval
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ end
+ C.module_eval{
+ Const
+ }
+ }
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ end
+ C.module_eval %{
+ Const
+ }
+ } if false # TODO: Ruby 1.9 error
+
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ end
+ C.class_eval %{
+ def m
+ Const
+ end
+ }
+ C.new.m
+ }
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ end
+ C.class_eval{
+ def m
+ Const
+ end
+ }
+ C.new.m
+ }
+ end
+
+ def test_instance_eval
+ ae %q{
+ 1.instance_eval{
+ self
+ }
+ }
+ ae %q{
+ 'foo'.instance_eval{
+ self
+ }
+ }
+ ae %q{
+ class Fixnum
+ Const = 1
+ end
+ 1.instance_eval %{
+ Const
+ }
+ }
+ end
+
+ def test_nest_eval
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ end
+ $nest = false
+ $ans = []
+ def m
+ $ans << Const
+ C.module_eval %{
+ $ans << Const
+ Boo = false unless defined? Boo
+ unless $nest
+ $nest = true
+ m
+ end
+ }
+ end
+ m
+ $ans
+ }
+ ae %q{
+ $nested = false
+ $ans = []
+ $pr = proc{
+ $ans << self
+ unless $nested
+ $nested = true
+ $pr.call
+ end
+ }
+ class C
+ def initialize &b
+ 10.instance_eval(&b)
+ end
+ end
+ C.new(&$pr)
+ $ans
+ }
+ end
+
+ def test_binding
+ ae %q{
+ def m
+ a = :ok
+ $b = binding
+ end
+ m
+ eval('a', $b)
+ }
+ ae %q{
+ def m
+ a = :ok
+ $b = binding
+ end
+ m
+ eval('b = :ok2', $b)
+ eval('[a, b]', $b)
+ }
+ ae %q{
+ $ans = []
+ def m
+ $b = binding
+ end
+ m
+ $ans << eval(%q{
+ $ans << eval(%q{
+ a
+ }, $b)
+ a = 1
+ }, $b)
+ $ans
+ }
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ def m
+ binding
+ end
+ end
+ eval('Const', C.new.m)
+ }
+ ae %q{
+ Const = :top
+ a = 1
+ class C
+ Const = :C
+ def m
+ eval('Const', TOPLEVEL_BINDING)
+ end
+ end
+ C.new.m
+ }
+ ae %q{
+ class C
+ $b = binding
+ end
+ eval %q{
+ def m
+ :ok
+ end
+ }, $b
+ p C.new.m
+ }
+ ae %q{
+ b = proc{
+ a = :ok
+ binding
+ }.call
+ a = :ng
+ eval("a", b)
+ }
+ end
+end
+
diff --git a/yarvtest/test_exception.rb b/yarvtest/test_exception.rb
new file mode 100644
index 0000000000..3b0bd10cd6
--- /dev/null
+++ b/yarvtest/test_exception.rb
@@ -0,0 +1,408 @@
+require 'yarvtest/yarvtest'
+
+class TestException < YarvTestBase
+
+ def test_rescue
+ ae %q{
+ begin
+ 1
+ rescue
+ 2
+ end
+ }
+
+ ae %q{
+ begin
+ 1
+ begin
+ 2
+ rescue
+ 3
+ end
+ 4
+ rescue
+ 5
+ end
+ }
+
+ ae %q{
+ begin
+ 1
+ rescue
+ 2
+ else
+ 3
+ end
+ }
+ end
+
+ def test_ensure
+ ae %q{
+ begin
+ 1+1
+ ensure
+ 2+2
+ end
+ }
+ ae %q{
+ begin
+ 1+1
+ begin
+ 2+2
+ ensure
+ 3+3
+ end
+ ensure
+ 4+4
+ end
+ }
+ ae %q{
+ begin
+ 1+1
+ begin
+ 2+2
+ ensure
+ 3+3
+ end
+ ensure
+ 4+4
+ begin
+ 5+5
+ ensure
+ 6+6
+ end
+ end
+ }
+ end
+
+ def test_rescue_ensure
+ ae %q{
+ begin
+ 1+1
+ rescue
+ 2+2
+ ensure
+ 3+3
+ end
+ }
+ ae %q{
+ begin
+ 1+1
+ rescue
+ 2+2
+ ensure
+ 3+3
+ end
+ }
+ ae %q{
+ begin
+ 1+1
+ rescue
+ 2+2
+ else
+ 3+3
+ ensure
+ 4+4
+ end
+ }
+ ae %q{
+ begin
+ 1+1
+ begin
+ 2+2
+ rescue
+ 3+3
+ else
+ 4+4
+ end
+ rescue
+ 5+5
+ else
+ 6+6
+ ensure
+ 7+7
+ end
+ }
+
+ end
+
+ def test_raise
+ ae %q{
+ begin
+ raise
+ rescue
+ :ok
+ end
+ }
+ ae %q{
+ begin
+ raise
+ rescue
+ :ok
+ ensure
+ :ng
+ end
+ }
+ ae %q{
+ begin
+ raise
+ rescue => e
+ e.class
+ end
+ }
+ ae %q{
+ begin
+ raise
+ rescue StandardError
+ :ng
+ rescue Exception
+ :ok
+ end
+ }
+ ae %q{
+ begin
+ begin
+ raise "a"
+ rescue
+ raise "b"
+ ensure
+ raise "c"
+ end
+ rescue => e
+ e.message
+ end
+ }
+ end
+
+ def test_error_variable
+ ae %q{
+ a = nil
+ 1.times{|e|
+ begin
+ rescue => err
+ end
+ a = err.class
+ }
+ }
+ ae %q{
+ a = nil
+ 1.times{|e|
+ begin
+ raise
+ rescue => err
+ end
+ a = err.class
+ }
+ a
+ }
+ end
+
+ def test_raise_in_other_scope
+ ae %q{
+ class E1 < Exception
+ end
+
+ def m
+ yield
+ end
+
+ begin
+ begin
+ begin
+ m{
+ raise
+ }
+ rescue E1
+ :ok2
+ ensure
+ end
+ rescue
+ :ok3
+ ensure
+ end
+ rescue E1
+ :ok
+ ensure
+ end
+ } do
+ remove_const :E1
+ end
+
+ ae %q{
+ $i = 0
+ def m
+ iter{
+ begin
+ $i += 1
+ begin
+ $i += 2
+ break
+ ensure
+
+ end
+ ensure
+ $i += 4
+ end
+ $i = 0
+ }
+ end
+
+ def iter
+ yield
+ end
+ m
+ $i
+ }
+
+ ae %q{
+ $i = 0
+ def m
+ begin
+ $i += 1
+ begin
+ $i += 2
+ return
+ ensure
+ $i += 3
+ end
+ ensure
+ $i += 4
+ end
+ p :end
+ end
+ m
+ $i
+ }
+ end
+
+ def test_raise_in_cont_sp
+ ae %q{
+ def m a, b
+ a + b
+ end
+ m(1, begin
+ raise
+ rescue
+ 2
+ end) +
+ m(10, begin
+ raise
+ rescue
+ 20
+ ensure
+ 30
+ end)
+ }
+ ae %q{
+ def m a, b
+ a + b
+ end
+ m(begin
+ raise
+ rescue
+ 1
+ end,
+ begin
+ raise
+ rescue
+ 2
+ end)
+ }
+ end
+
+ def test_geterror
+ ae %q{
+ $!
+ }
+ ae %q{
+ begin
+ raise "FOO"
+ rescue
+ $!
+ end
+ }
+ ae %q{
+ def m
+ $!
+ end
+ begin
+ raise "FOO"
+ rescue
+ m()
+ end
+ }
+ ae %q{
+ $ans = []
+ def m
+ $!
+ end
+ begin
+ raise "FOO"
+ rescue
+ begin
+ raise "BAR"
+ rescue
+ $ans << m()
+ end
+ $ans << m()
+ end
+ $ans
+ }
+ ae %q{
+ $ans = []
+ def m
+ $!
+ end
+
+ begin
+ begin
+ raise "FOO"
+ ensure
+ $ans << m()
+ end
+ rescue
+ $ans << m()
+ end
+ }
+ ae %q{
+ $ans = []
+ def m
+ $!
+ end
+ def m2
+ 1.times{
+ begin
+ return
+ ensure
+ $ans << m
+ end
+ }
+ end
+ m2
+ $ans
+ }
+ end
+
+ def test_stack_consistency
+ ae %q{ #
+ proc{
+ begin
+ raise
+ break
+ rescue
+ :ok
+ end
+ }.call
+ }
+ ae %q{
+ proc do
+ begin
+ raise StandardError
+ redo
+ rescue StandardError
+ end
+ end.call
+ }
+ end
+end
+
diff --git a/yarvtest/test_flow.rb b/yarvtest/test_flow.rb
new file mode 100644
index 0000000000..fa7224b987
--- /dev/null
+++ b/yarvtest/test_flow.rb
@@ -0,0 +1,591 @@
+#
+# This test program is contributed by George Marrows
+# Re: [Yarv-devel] Some tests for test_jump.rb
+#
+
+require 'yarvtest/yarvtest'
+
+class TestFlow < YarvTestBase
+ def ae_flow(src, for_value=true)
+ # Tracks flow through the code
+ # A test like
+ # begin
+ # ensure
+ # end
+ # gets transformed into
+ # a = []
+ # begin
+ # begin; a << 1
+ # ensure; a << 2
+ # end; a << 3
+ # rescue Exception
+ # a << 99
+ # end
+ # a
+ # before being run. This tracks control flow through the code.
+
+ cnt = 0
+ src = src.gsub(/(\n|$)/) { "; $a << #{cnt+=1}\n" }
+ src = "$a = []; begin; #{src}; rescue Exception; $a << 99; end; $a"
+
+ if false#||true
+ STDERR.puts
+ STDERR.puts '#----'
+ STDERR.puts src
+ STDERR.puts '#----'
+ end
+
+ ae(src)
+ end
+
+ def test_while_with_ensure
+ ae %q{
+ a = []
+ i = 0
+ begin
+ while i < 1
+ i+=1
+ begin
+ begin
+ next
+ ensure
+ a << :ok
+ end
+ ensure
+ a << :ok2
+ end
+ end
+ ensure
+ a << :last
+ end
+ }
+ ae %q{
+ a = []
+ i = 0
+ begin
+ while i < 1
+ i+=1
+ begin
+ begin
+ break
+ ensure
+ a << :ok
+ end
+ ensure
+ a << :ok2
+ end
+ end
+ ensure
+ a << :last
+ end
+ }
+ ae %q{
+ a = []
+ i = 0
+ begin
+ while i < 1
+ if i>0
+ break
+ end
+ i+=1
+ begin
+ begin
+ redo
+ ensure
+ a << :ok
+ end
+ ensure
+ a << :ok2
+ end
+ end
+ ensure
+ a << :last
+ end
+ }
+ end
+
+ def test_ensure_normal_flow
+ ae_flow %{
+ begin
+ ensure
+ end }
+ end
+
+ def test_ensure_exception
+ ae_flow %{
+ begin
+ raise StandardError
+ ensure
+ end
+ }
+ end
+
+ def test_break_in_block_runs_ensure
+ ae_flow %{
+ [1,2].each do
+ begin
+ break
+ ensure
+ end
+ end
+ }
+ end
+
+ def test_next_in_block_runs_ensure
+ ae_flow %{
+ [1,2].each do
+ begin
+ next
+ ensure
+ end
+ end
+ }
+ end
+ def test_return_from_method_runs_ensure
+ ae_flow %{
+ o = "test"
+ def o.test(a)
+ return a
+ ensure
+ end
+ o.test(123)
+ }
+ end
+
+ def test_break_from_ifunc
+ ae %q{
+ ["a"].inject("ng"){|x,y|
+ break :ok
+ }
+ }
+ ae %q{
+ unless ''.respond_to? :lines
+ class String
+ def lines
+ self
+ end
+ end
+ end
+
+ ('a').lines.map{|e|
+ break :ok
+ }
+ }
+ ae_flow %q{
+ ["a"].inject("ng"){|x,y|
+ break :ok
+ }
+ }
+ ae_flow %q{
+ ('a'..'b').map{|e|
+ break :ok
+ }
+ }
+ end
+
+ def test_break_ensure_interaction1
+ # make sure that any 'break state' set up in the VM is c
+ # the time of the ensure
+ ae_flow %{
+ [1,2].each{
+ break
+ }
+ begin
+ ensure
+ end
+ }
+ end
+
+ def test_break_ensure_interaction2
+ # ditto, different arrangement
+ ae_flow %{
+ begin
+ [1,2].each do
+ break
+ end
+ ensure
+ end
+ }
+ end
+
+ def test_break_through_2_ensures
+ ae_flow %{
+ [1,2].each do
+ begin
+ begin
+ break
+ ensure
+ end
+ ensure
+ end
+ end
+ }
+ end
+
+ def test_ensure_break_ensure
+ # break through an ensure; run 2nd normally
+ ae_flow %{
+ begin
+ [1,2].each do
+ begin
+ break
+ ensure
+ end
+ end
+ ensure
+ end
+ }
+ end
+
+ def test_exception_overrides_break
+ ae_flow %{
+ [1,2].each do
+ begin
+ break
+ ensure
+ raise StandardError
+ end
+ end
+ }
+ end
+
+ def test_break_overrides_exception
+ ae_flow %{
+ [1,2].each do
+ begin
+ raise StandardError
+ ensure
+ break
+ end
+ end
+ }
+ ae_flow %{
+ [1,2].each do
+ begin
+ raise StandardError
+ rescue
+ break
+ end
+ end
+ }
+ end
+
+ def test_break_in_exception
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ begin
+ ensure
+ break
+ end
+ end
+ }
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ begin
+ raise
+ ensure
+ break
+ end
+ end
+ }
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ begin
+ raise
+ rescue
+ break
+ end
+ end
+ }
+ end
+
+ def test_next_in_exception
+ return
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ begin
+ ensure
+ next
+ end
+ end
+ }
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ begin
+ raise
+ ensure
+ next
+ end
+ end
+ }
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ begin
+ raise
+ rescue
+ next
+ end
+ end
+ }
+ end
+
+ def test_complex_break
+ ae_flow %q{
+ i = 0
+ while i<3
+ i+=1
+ j = 0
+ while j<3
+ j+=1
+ begin
+ raise
+ rescue
+ break
+ end
+ end
+ end
+ }
+ ae_flow %q{
+ i = 0
+ while i<3
+ i+=1
+ j = 0
+ while j<3
+ j+=1
+ 1.times{
+ begin
+ raise
+ rescue
+ break
+ end
+ }
+ end
+ end
+ }
+ ae_flow %q{
+ i = 0
+ while i<3
+ i+=1
+ j = 0
+ while j<3
+ j+=1
+ begin
+ raise
+ ensure
+ break
+ end
+ end
+ end
+ }
+ ae_flow %q{
+ i = 0
+ while i<3
+ i+=1
+ j = 0
+ while j<3
+ j+=1
+ 1.times{
+ begin
+ raise
+ ensure
+ break
+ end
+ }
+ end
+ end
+ }
+ ae_flow %q{
+ while true
+ begin
+ break
+ ensure
+ break
+ end
+ end
+ }
+ ae_flow %q{
+ while true
+ begin
+ break
+ ensure
+ raise
+ end
+ end
+ }
+ end
+
+ def test_jump_from_class
+ ae_flow %q{
+ 3.times{
+ class C
+ break
+ end
+ }
+ }
+ ae_flow %q{
+ 3.times{
+ class A
+ class B
+ break
+ end
+ end
+ }
+ }
+ ae_flow %q{
+ 3.times{
+ class C
+ next
+ end
+ }
+ }
+ ae_flow %q{
+ 3.times{
+ class C
+ class D
+ next
+ end
+ end
+ }
+ }
+ ae_flow %q{
+ while true
+ class C
+ break
+ end
+ end
+ }
+ ae_flow %q{
+ while true
+ class C
+ class D
+ break
+ end
+ end
+ end
+ }
+ ae_flow %q{
+ i=0
+ while i<3
+ i+=1
+ class C
+ next 10
+ end
+ end
+ }
+ ae %q{
+ 1.times{
+ while true
+ class C
+ begin
+ break
+ ensure
+ break
+ end
+ end
+ end
+ }
+ }
+ end
+
+ def test_flow_with_cont_sp
+ ae %q{
+ def m a, b
+ a + b
+ end
+ m(1,
+ while true
+ break 2
+ end
+ )
+ }
+ ae %q{
+ def m a, b
+ a + b
+ end
+ m(1,
+ (i=0; while i<2
+ i+=1
+ class C
+ next 2
+ end
+ end; 3)
+ )
+ }
+ ae %q{
+ def m a, b
+ a+b
+ end
+ m(1, 1.times{break 3}) +
+ m(10, (1.times{next 3}; 20))
+ }
+ end
+
+ def test_return_in_deep_stack
+ ae_flow %q{
+ def m1 *args
+
+ end
+ def m2
+ m1(:a, :b, (return 1; :c))
+ end
+ m2
+ }
+ end
+
+ def test_return_in_ensure
+ ae_flow %q{
+ def m()
+ begin
+ 2
+ ensure
+ return 3
+ end
+ end
+ m
+ }
+ ae_flow %q{
+ def m2
+ end
+ def m()
+ m2(begin
+ 2
+ ensure
+ return 3
+ end)
+ 4
+ end
+ m()
+ }
+ ae_flow %q{
+ def m
+ 1
+ 1.times{
+ 2
+ begin
+ 3
+ return
+ 4
+ ensure
+ 5
+ end
+ 6
+ }
+ 7
+ end
+ m()
+ }
+ end
+end
+
diff --git a/yarvtest/test_jump.rb b/yarvtest/test_jump.rb
new file mode 100644
index 0000000000..e7c2cc37a6
--- /dev/null
+++ b/yarvtest/test_jump.rb
@@ -0,0 +1,296 @@
+require 'yarvtest/yarvtest'
+
+class TestJump < YarvTestBase
+
+ def test_redo
+ ae %q{
+ def m
+ yield + 10
+ end
+ i=0
+ m{
+ if i>10
+ i*i
+ else
+ i+=1
+ redo
+ end
+ }
+ }
+ end
+
+ def test_next
+ ae %q{
+ def m
+ yield
+ :ok
+ end
+ i=0
+ m{
+ if i>10
+ i*i
+ else
+ i+=1
+ next
+ end
+ }
+ }
+ end
+
+ def test_next_with_val
+ ae %q{
+ def m
+ yield
+ end
+
+ m{
+ next :ok
+ }
+ }
+ end
+
+ def test_return
+ ae %q{
+ def m
+ return 3
+ end
+ m
+ }
+
+ ae %q{
+ def m
+ :ng1
+ mm{
+ return :ok
+ }
+ :ng2
+ end
+
+ def mm
+ :ng3
+ yield
+ :ng4
+ end
+ m
+ }
+ end
+
+ def test_return2
+ ae %q{
+ $i = 0
+ def m
+ begin
+ iter{
+ return
+ }
+ ensure
+ $i = 100
+ end
+ end
+
+ def iter
+ yield
+ end
+ m
+ $i
+ }
+ end
+
+ def test_return3
+ ae %q{
+ def m
+ begin
+ raise
+ rescue
+ return :ok
+ end
+ :ng
+ end
+ m
+ }
+ end
+
+ def test_break
+ ae %q{
+ def m
+ :ng1
+ mm{
+ yield
+ }
+ :ng2
+ end
+
+ def mm
+ :ng3
+ yield
+ :ng4
+ end
+
+ m{
+ break :ok
+ }
+ }
+ end
+
+ def test_exception_and_break
+ ae %q{
+ def m
+ yield
+ end
+
+ m{
+ begin
+ ensure
+ break :ok
+ end
+ }
+ }
+ end
+
+ def test_retry
+ # this test can't run on ruby 1.9(yarv can do)
+ %q{
+ def m a
+ mm{
+ yield
+ }
+ end
+
+ def mm
+ yield
+ end
+
+ i=0
+ m(i+=1){
+ retry if i<10
+ :ok
+ }
+ }
+
+ ae %q{
+ def m a
+ yield
+ end
+
+ i=0
+ m(i+=1){
+ retry if i<10
+ :ok
+ }
+ }
+ end
+
+ def test_complex_jump
+ ae %q{
+ module Enumerable
+ def all_?
+ self.each{|e|
+ unless yield(e)
+ return false
+ end
+ }
+ true
+ end
+ end
+
+ xxx = 0
+ [1,2].each{|bi|
+ [3,4].each{|bj|
+ [true, nil, true].all_?{|be| be}
+ break
+ }
+ xxx += 1
+ }
+ xxx
+ }
+ end
+
+ def test_return_from
+ ae %q{
+ def m
+ begin
+ raise
+ rescue
+ return 1
+ end
+ end
+
+ m
+ }
+ ae %q{
+ def m
+ begin
+ #
+ ensure
+ return 1
+ end
+ end
+
+ m
+ }
+ end
+
+ def test_break_from_times
+ ae %q{
+ 3.times{
+ break :ok
+ }
+ }
+ end
+
+ def test_catch_and_throw
+ ae %q{
+ catch(:foo){
+ throw :foo
+ }
+ }
+ ae %q{
+ catch(:foo){
+ throw :foo, false
+ }
+ }
+ ae %q{
+ catch(:foo){
+ throw :foo, nil
+ }
+ }
+ ae %q{
+ catch(:foo){
+ throw :foo, :ok
+ }
+ }
+ ae %q{
+ catch(:foo){
+ 1.times{
+ throw :foo
+ }
+ }
+ }
+ ae %q{
+ catch(:foo){
+ 1.times{
+ throw :foo, :ok
+ }
+ }
+ }
+ ae %q{
+ catch(:foo){
+ catch(:bar){
+ throw :foo, :ok
+ }
+ :ng
+ }
+ }
+ ae %q{
+ catch(:foo){
+ catch(:bar){
+ 1.times{
+ throw :foo, :ok
+ }
+ }
+ :ng
+ }
+ }
+ end
+end
+
diff --git a/yarvtest/test_massign.rb b/yarvtest/test_massign.rb
new file mode 100644
index 0000000000..bb42c7e180
--- /dev/null
+++ b/yarvtest/test_massign.rb
@@ -0,0 +1,417 @@
+require 'yarvtest/yarvtest'
+
+# test of syntax
+class TestMassign < YarvTestBase
+ def test_simle
+ ae %q{
+ a = :a; b = :b; c = :c
+ x, y = a, b
+ [x, y]
+ }
+ ae %q{
+ a = :a; b = :b; c = :c
+ x, y, z = a, b, c
+ [x, y, z]
+ }
+ end
+
+ def test_diff_elems
+ ae %q{
+ a = :a ; b = :b ; c = :c
+ x, y, z = a, b
+ [x, y, z]
+ }
+ ae %q{
+ a = :a; b = :b; c = :c
+ x, y = a, b, c
+ [x, y]
+ }
+ end
+
+ def test_single_l
+ ae %q{
+ a = :a; b = :b
+ x = a, b
+ x
+ }
+ ae %q{
+ a = [1, 2]; b = [3, 4]
+ x = a, b
+ x
+ }
+ end
+
+ def test_single_r
+ ae %q{
+ a = :a
+ x, y = a
+ [x, y]
+ }
+ ae %q{
+ a = [1, 2]
+ x, y = a
+ [x, y]
+ }
+ ae %q{
+ a = [1, 2, 3]
+ x, y = a
+ [x, y]
+ }
+ end
+
+ def test_splat_l
+ ae %q{
+ a = :a; b = :b; c = :c
+ *x = a, b
+ [x]
+ }
+ ae %q{
+ a = :a; b = :b; c = :c
+ *x = a, b
+ [x]
+ }
+ ae %q{
+ a = :a; b = :b; c = :c
+ x, * = a, b
+ [x]
+ }
+ ae %q{
+ a = :a; b = :b; c = :c
+ x, *y = a, b
+ [x, y]
+ }
+ ae %q{
+ a = :a; b = :b; c = :c
+ x, y, *z = a, b
+ [x, y]
+ }
+ ae %q{ # only one item on rhs
+ *x = :x
+ x
+ }
+ ae %q{ # nil on rhs
+ *x = nil
+ x
+ }
+ end
+
+ def test_splat_r
+ if false
+ ae %q{
+ a = :a; b = :b; c = :c
+ x, y = *a
+ [x, y]
+ }
+ ae %q{
+ a = :a; b = :b; c = :c
+ x, y = a, *b
+ [x, y]
+ }
+ ae %q{
+ a = :a; b = :b; c = :c
+ x, y = a, b, *c
+ [x, y]
+ }
+ ae %q{
+ x=*nil
+ x
+ }
+ end
+
+ ae %q{
+ a = [:a, :a2]; b = [:b, :b2]; c = [:c, :c2]
+ x, y = *a
+ [x, y]
+ }
+ ae %q{
+ a = [:a, :a2]; b = [:b, :b2]; c = [:c, :c2]
+ x, y = a, *b
+ [x, y]
+ }
+ ae %q{
+ a = [:a, :a2]; b = [:b, :b2]; c = [:c, :c2]
+ x, y = a, b, *c
+ [x, y]
+ }
+ end
+
+ def test_splat_b1
+ if false
+ # error
+ ae %q{
+ a = :a; b = :b; c = :c
+ x, *y = *a
+ [x, y]
+ }
+ ae %q{
+ a = :a; b = :b; c = :c
+ x, *y = a, *b
+ [x, y]
+ }
+ ae %q{
+ a = :a; b = :b; c = :c
+ x, *y = a, b, *c
+ [x, y]
+ }
+ end
+
+ ae %q{
+ a = [:a, :a2]; b = [:b, :b2]; c = [:c, :c2]
+ x, *y = *a
+ [x, y]
+ }
+ ae %q{
+ a = [:a, :a2]; b = [:b, :b2]; c = [:c, :c2]
+ x, *y = a, *b
+ [x, y]
+ }
+ ae %q{
+ a = [:a, :a2]; b = [:b, :b2]; c = [:c, :c2]
+ x, *y = a, b, *c
+ [x, y]
+ }
+ end
+
+ def test_splat_b2
+ if false
+ # error
+ ae %q{
+ a = :a; b = :b; c = :c
+ *x = *a
+ x
+ }
+ ae %q{
+ a = :a; b = :b; c = :c
+ *x = a, *b
+ x
+ }
+ ae %q{
+ a = :a; b = :b; c = :c
+ *x = a, b, *c
+ x
+ }
+ end
+
+ ae %q{
+ a = [:a, :a2]; b = [:b, :b2]; c = [:c, :c2]
+ *x = *a
+ x
+ }
+ ae %q{
+ a = [:a, :a2]; b = [:b, :b2]; c = [:c, :c2]
+ *x = a, *b
+ x
+ }
+ ae %q{
+ a = [:a, :a2]; b = [:b, :b2]; c = [:c, :c2]
+ *x = a, b, *c
+ x
+ }
+ end
+
+ def test_toary
+ ae %q{
+ x, y = :a
+ [x, y]
+ }
+ ae %q{
+ x, y = [1, 2]
+ [x, y]
+ }
+ ae %q{
+ x, y = [1, 2, 3]
+ [x, y]
+ }
+ end
+
+ def test_swap
+ ae %q{
+ a = 1; b = 2
+ a, b = b, a
+ [a, b]
+ }
+ end
+
+ def test_mret
+ ae %q{
+ def m
+ return 1, 2
+ end
+
+ a, b = m
+ [a, b]
+ }
+ ae %q{
+ def m
+ return 1, 2
+ end
+
+ a = m
+ [a]
+ }
+ ae %q{
+ def m
+ return 1
+ end
+
+ a, b = m
+ [a, b]
+ }
+ end
+
+ def test_mret_splat
+ if false
+ ae %q{
+ def m
+ return *1
+ end
+ a, b = m
+ [a, b]
+ }
+ end
+
+ ae %q{
+ def m
+ return *[]
+ end
+ a, b = m
+ [a, b]
+ }
+ ae %q{
+ def m
+ return *[1]
+ end
+ a, b = m
+ [a, b]
+ }
+ ae %q{
+ def m
+ return *[1,2]
+ end
+ a, b = m
+ [a, b]
+ }
+ ae %q{
+ def m
+ return *[1,2,3]
+ end
+ a, b = m
+ [a, b]
+ }
+ ae %q{
+ def m
+ return *[1]
+ end
+ a = m
+ }
+ end
+
+ def test_mret_argscat
+ ae %q{
+ def m
+ return 1, *[]
+ end
+ a, b = m
+ [a, b]
+ }
+ ae %q{
+ def m
+ return 1, 2, *[1]
+ end
+ a, b = m
+ [a, b]
+ }
+ ae %q{
+ def m
+ return 1, 2, 3, *[1,2]
+ end
+ a, b = m
+ [a, b]
+ }
+ end
+
+ def test_nested_massign
+ ae %q{
+ (a, b), c = [[1, 2], 3]
+ [a, b, c]
+ }
+ ae %q{
+ a, (b, c) = [[1, 2], 3]
+ [a, b, c]
+ }
+ ae %q{
+ a, (b, c) = [1, [2, 3]]
+ [a, b, c]
+ }
+ ae %q{
+ (a, b), *c = [[1, 2], 3]
+ [a, b, c]
+ }
+ ae %q{
+ (a, b), c, (d, e) = [[1, 2], 3, [4, 5]]
+ [a, b, c, d, e]
+ }
+ ae %q{
+ (a, *b), c, (d, e, *) = [[1, 2], 3, [4, 5]]
+ [a, b, c, d, e]
+ }
+ ae %q{
+ (a, b), c, (d, *e) = [[1, 2, 3], 3, [4, 5, 6, 7]]
+ [a, b, c, d, e]
+ }
+ ae %q{
+ (a, (b1, b2)), c, (d, e) = [[1, 2], 3, [4, 5]]
+ [a, b1, b2, c, d, e]
+ }
+ ae %q{
+ (a, (b1, b2)), c, (d, e) = [[1, [21, 22]], 3, [4, 5]]
+ [a, b1, b2, c, d, e]
+ }
+ end
+
+ # ignore
+ def _test_massign_value
+ # Value of this massign statement should be [1, 2, 3]
+ ae %q{
+ a, b, c = [1, 2, 3]
+ }
+ end
+
+ def test_nested_splat
+ # Somewhat obscure nested splat
+ ae %q{
+ a = *[*[1]]
+ a
+ }
+ end
+
+ def test_calls_to_a
+ # Should be result of calling to_a on arg, ie [[1, 2], [3, 4]]
+ ae %q{
+ x=*{1=>2,3=>4}
+ x
+ }
+ end
+
+ def test_const_massign
+ ae %q{
+ class C
+ class D
+ end
+ end
+
+ X, Y = 1, 2
+ Z, C::Const, C::D::Const, ::C::Const2 = 3, 4, 5, 6
+ [X, Y, Z, C::Const, C::D::Const, ::C::Const2]
+ }
+ end
+
+ def test_massign_values
+ ae %q{
+ ary = [1, 2].partition {|n| n == 1 }
+ a, b = ary
+ [a, b]
+ }
+ end
+end
+
diff --git a/yarvtest/test_method.rb b/yarvtest/test_method.rb
new file mode 100644
index 0000000000..c2ef4c99de
--- /dev/null
+++ b/yarvtest/test_method.rb
@@ -0,0 +1,539 @@
+require 'yarvtest/yarvtest'
+class TestMethod < YarvTestBase
+
+ def test_simple_method
+ ae %q{
+ def m_simple_method
+ 1
+ end
+ m_simple_method()
+ }
+ end
+
+ def test_polymorphic
+ ae %q{
+ o1 = 'str'
+ o2 = 1
+ str = ''
+ i = 1
+ while i<10
+ i+=1
+ o = (i%2==0) ? o1 : o2
+ str += o.to_s
+ end
+ str
+ }
+ end
+
+ def test_arg
+ ae <<-'EOS'
+ def m_arg(a1, a2)
+ a1+a2
+ end
+ m_arg(1,2)
+ EOS
+ end
+
+ def test_rec
+ ae <<-'EOS'
+ def m_rec n
+ if n > 1
+ n + m_rec(n-1)
+ else
+ 1
+ end
+ end
+ m_rec(10)
+ EOS
+ end
+
+ def test_splat
+ ae %q{
+ def m a
+ a
+ end
+ begin
+ m(*1)
+ rescue TypeError
+ :ok
+ end
+ }
+ ae %q{
+ def m a, b
+ [a, b]
+ end
+ m(*[1,2])
+ }
+ ae %q{
+ def m a, b, c
+ [a, b, c]
+ end
+ m(1, *[2, 3])
+ }
+
+ ae %q{
+ def m a, b, c
+ [a, b, c]
+ end
+
+ m(1, 2, *[3])
+ }
+ end
+
+ def test_rest
+ ae %q{
+ def m *a
+ a
+ end
+
+ m
+ }
+
+ ae %q{
+ def m *a
+ a
+ end
+
+ m 1
+ }
+
+ ae %q{
+ def m *a
+ a
+ end
+
+ m 1, 2, 3
+ }
+
+ ae %q{
+ def m x, *a
+ [x, a]
+ end
+
+ m 1
+ }
+
+ ae %q{
+ def m x, *a
+ [x, a]
+ end
+
+ m 1, 2
+ }
+
+ ae %q{
+ def m x, *a
+ [x, a]
+ end
+
+ m 1, 2, 3, 4
+ }
+ end
+
+ def test_opt
+ ae %q{
+ def m a=1
+ a
+ end
+ m
+ }
+ ae %q{
+ def m a=1
+ a
+ end
+ m 2
+ }
+ ae %q{
+ def m a=1, b=2
+ [a, b]
+ end
+ m
+ }
+ ae %q{
+ def m a=1, b=2
+ [a, b]
+ end
+ m 10
+ }
+ ae %q{
+ def m a=1, b=2
+ [a, b]
+ end
+ m 10, 20
+ }
+ ae %q{
+ def m x, a=1, b=2
+ [x, a, b]
+ end
+ m 10
+ }
+ ae %q{
+ def m x, a=1, b=2
+ [x, a, b]
+ end
+ m 10, 20
+ }
+ ae %q{
+ def m x, a=1, b=2
+ [x, a, b]
+ end
+ m 10, 20, 30
+ }
+ ae %q{
+ def m x, y, a
+ [x, y, a]
+ end
+ m 10, 20, 30
+ }
+ end
+
+
+ def test_opt_rest
+ ae %q{
+ def m0 b = 0, c = 1, *d
+ [:sep, b, c, d]
+ end
+
+ def m1 a, b = 0, c = 1, *d
+ [:sep, a, b, c, d]
+ end
+
+ def m2 x, a, b = 0, c = 1, *d
+ [:sep, x, a, b, c, d]
+ end
+
+ def m3 x, y, a, b = 0, c = 1, *d
+ [:sep, x, y, a, b, c, d]
+ end
+
+ def s3 x, y, a, b = 0, c = 1
+ [:sep, x, y, a, b, c]
+ end
+
+ m0() +
+ m0(:a) +
+ m0(:a, :b) +
+ m0(:a, :b, :c) +
+ m0(:a, :b, :c, :d) +
+ m0(:a, :b, :c, :d, :e) +
+ m1(:a) +
+ m1(:a, :b) +
+ m1(:a, :b, :c) +
+ m1(:a, :b, :c, :d) +
+ m1(:a, :b, :c, :d, :e) +
+ m2(:a, :b) +
+ m2(:a, :b, :c) +
+ m2(:a, :b, :c, :d) +
+ m2(:a, :b, :c, :d, :e) +
+ m2(:a, :b, :c, :d, :e, :f) +
+ m3(:a, :b, :c) +
+ m3(:a, :b, :c, :d) +
+ m3(:a, :b, :c, :d, :e) +
+ m3(:a, :b, :c, :d, :e, :f) +
+ m3(:a, :b, :c, :d, :e, :f, :g)
+ }
+ end
+
+ def test_opt_rest_block
+ ae %q{
+ def m a, b = 0, c = 1, *d, &pr
+ [a, b, c, d, pr]
+ end
+ m(:a) +
+ m(:a, :b) +
+ m(:a, :b, :c) +
+ m(:a, :b, :c, :d) +
+ m(:a, :b, :c, :d, :e)
+ }
+ ae %q{
+ def m a, b = 0, c = 1, *d, &pr
+ [a, b, c, d, pr.call]
+ end
+
+ m(:a){1} +
+ m(:a, :b){2} +
+ m(:a, :b, :c){3} +
+ m(:a, :b, :c, :d){4} +
+ m(:a, :b, :c, :d, :e){5}
+ }
+ end
+
+ def test_singletonmethod
+ ae %q{
+ lobj = Object.new
+ def lobj.m
+ :singleton
+ end
+ lobj.m
+ }
+ ae %q{
+ class C
+ def m
+ :C_m
+ end
+ end
+ lobj = C.new
+ def lobj.m
+ :Singleton_m
+ end
+ lobj.m
+ }
+ end
+
+ def test_singletonmethod_with_const
+ ae %q{
+ class C
+ Const = :C
+ def self.m
+ 1.times{
+ Const
+ }
+ end
+ end
+ C.m
+ }
+ end
+
+ def test_alias
+ ae %q{
+ def m1
+ :ok
+ end
+ alias :m2 :m1
+ m1
+ }
+ ae %q{
+ def m1
+ :ok
+ end
+ alias m2 m1
+ m1
+ }
+ ae %q{
+ def m1
+ :ok
+ end
+ alias m2 :m1
+ m1
+ }
+ ae %q{
+ def m1
+ :ok
+ end
+ alias :m2 m1
+ m1
+ }
+ ae %q{
+ def m1
+ :ok
+ end
+ alias m2 m1
+ def m1
+ :ok2
+ end
+ [m1, m2]
+ }
+ end
+
+ def test_split
+ ae %q{
+ 'abc'.split(/b/)
+ }
+ ae %q{
+ 1.times{|bi|
+ 'abc'.split(/b/)
+ }
+ }
+ end
+
+ def test_block_pass
+ ae %q{
+ def getproc &b
+ b
+ end
+ def m
+ yield
+ end
+ m(&getproc{
+ "test"
+ })
+ }
+ ae %q{
+ def getproc &b
+ b
+ end
+ def m a
+ yield a
+ end
+ m(123, &getproc{|block_a|
+ block_a
+ })
+ }
+ ae %q{
+ def getproc &b
+ b
+ end
+ def m *a
+ yield a
+ end
+ m(123, 456, &getproc{|block_a|
+ block_a
+ })
+ }
+ ae %q{
+ def getproc &b
+ b
+ end
+ [1,2,3].map(&getproc{|block_e| block_e*block_e})
+ }
+ ae %q{
+ def m a, b, &c
+ c.call(a, b)
+ end
+ m(10, 20){|x, y|
+ [x+y, x*y]
+ }
+ }
+ ae %q{
+ def m &b
+ b
+ end
+ m(&nil)
+ }
+ ae %q{
+ def m a, &b
+ [a, b]
+ end
+ m(1, &nil)
+ }
+ ae %q{
+ def m a
+ [a, block_given?]
+ end
+ m(1, &nil)
+ }
+ end
+
+ def test_method_missing
+ ae %q{
+ class C
+ def method_missing id
+ id
+ end
+ end
+ C.new.hoge
+ } do
+ remove_const :C
+ end
+
+ ae %q{
+ class C
+ def method_missing *args, &b
+ b.call(args)
+ end
+ end
+ C.new.foo(1){|args|
+ args
+ }
+ C.new.foo(1){|args|
+ args
+ } +
+ C.new.foo(1, 2){|args|
+ args
+ }
+ }
+ end
+
+ def test_svar
+ ae %q{
+ 'abc'.match(/a(b)c/)
+ $1
+ }
+ end
+
+ def test_nested_method
+ ae %q{
+ class A
+ def m
+ def m2
+ p :m2
+ end
+ m2()
+ end
+ end
+ A.new.m
+ }
+ ae %q{
+ class A
+ def m
+ def m2
+ p :m2
+ end
+ m2()
+ end
+ end
+ instance_eval('A.new.m')
+ }
+ end
+
+ def test_private_class_method
+ ae %q{
+ class C
+ def self.m
+ :ok
+ end
+ def self.test
+ m
+ end
+ private_class_method :m
+ end
+ C.test
+ }
+ end
+
+ def test_alias_and_private
+ ae %q{ # [yarv-dev:899]
+ $ans = []
+ class C
+ def m
+ $ans << "OK"
+ end
+ end
+ C.new.m
+ class C
+ alias mm m
+ private :mm
+ end
+ C.new.m
+ begin
+ C.new.mm
+ rescue NoMethodError
+ $ans << "OK!"
+ end
+ $ans
+ }
+ end
+
+ def test_break_from_defined_method
+ ae %q{
+ class C
+ define_method(:foo){
+ break :ok
+ }
+ end
+ C.new.foo
+ }
+ end
+
+ def test_return_from_defined_method
+ ae %q{
+ class C
+ define_method(:m){
+ return :ok
+ }
+ end
+ C.new.m
+ }
+ end
+end
+
diff --git a/yarvtest/test_opts.rb b/yarvtest/test_opts.rb
new file mode 100644
index 0000000000..689257c78a
--- /dev/null
+++ b/yarvtest/test_opts.rb
@@ -0,0 +1,118 @@
+require 'yarvtest/yarvtest'
+
+class TestOpt < YarvTestBase
+ def test_plus
+ ae %q{
+ a, b = 1, 2
+ a+b
+ }
+ ae %q{
+ class Fixnum
+ def +(*o)
+ o
+ end
+ def -(*o)
+ o
+ end
+ end
+ [10+11, 100-101]
+ }
+ ae %q{
+ class Float
+ def +(o)
+ self * o
+ end
+ end
+
+ a, b = 1, 2
+ a+b
+ }
+ end
+
+ def test_opt_methdos
+ klasses = [[Fixnum, 2, 3], [Float, 1.1, 2.2],
+ [String, "abc", "def"], [Array, [1,2,3], [4, 5]],
+ [Hash, {:a=>1, :b=>2}, {:x=>"foo", :y=>"bar"}]]
+
+ bin_methods = [:+, :-, :*, :/, :%, ]
+ one_methods = [:length, :succ, ]
+ ary = []
+
+ bin_methods.each{|m|
+ klasses.each{|klass, obj, arg|
+ str = %{
+ ary = []
+ if (#{obj.inspect}).respond_to? #{m.inspect}
+ begin
+ ary << (#{obj.inspect}).#{m.to_s}(#{arg.inspect})
+ rescue Exception => e
+ ary << :error
+ end
+ end
+
+ class #{klass}
+ def #{m}(o)
+ [#{m.inspect}, :bin, #{klass}].inspect
+ end
+ end
+ ary << (#{obj.inspect}).#{m.to_s}(#{arg.inspect})
+ ary
+ }
+ ae str
+ }
+ }
+ one_methods.each{|m|
+ klasses.each{|klass, obj|
+ str = %{
+ ary = []
+ if (#{obj.inspect}).respond_to? #{m.inspect}
+ ary << (#{obj.inspect}).#{m.to_s}()
+ end
+
+ class #{klass}
+ def #{m}()
+ [#{m.inspect}, self, #{klass}].inspect
+ end
+ end
+ ary << (#{obj.inspect}).#{m.to_s}()
+ ary
+ }
+ ae str
+ }
+ }
+ end
+
+ def test_opt_plus
+ ae %q{
+ temp = 2**30 - 5
+ (1..5).map do
+ temp += 1
+ [temp, temp.class]
+ end
+ }
+ ae %q{
+ temp = -(2**30 - 5)
+ (1..10).map do
+ temp += 1
+ [temp, temp.class]
+ end
+ }
+ end
+
+ def test_eq
+ ae %q{
+ class Foo
+ def ==(other)
+ true
+ end
+ end
+ foo = Foo.new
+ [1.0 == foo,
+ 1 == foo,
+ "abc" == foo,
+ ]
+ }
+ end
+end
+
+
diff --git a/yarvtest/test_proc.rb b/yarvtest/test_proc.rb
new file mode 100644
index 0000000000..3f7fae09a0
--- /dev/null
+++ b/yarvtest/test_proc.rb
@@ -0,0 +1,293 @@
+require 'yarvtest/yarvtest'
+
+class TestProc < YarvTestBase
+ def test_simpleproc
+ ae %q{
+ def m(&b)
+ b
+ end
+ m{1}.call
+ }
+
+ ae %q{
+ def m(&b)
+ b
+ end
+
+ m{
+ a = 1
+ a + 2
+ }.call
+ }
+ end
+
+ def test_procarg
+ ae %q{
+ def m(&b)
+ b
+ end
+
+ m{|e_proctest| e_proctest}.call(1)
+ }
+
+ ae %q{
+ def m(&b)
+ b
+ end
+
+ m{|e_proctest1, e_proctest2|
+ a = e_proctest1 * e_proctest2 * 2
+ a * 3
+ }.call(1, 2)
+ }
+
+ ae %q{
+ [
+ Proc.new{|*args| args}.call(),
+ Proc.new{|*args| args}.call(1),
+ Proc.new{|*args| args}.call(1, 2),
+ Proc.new{|*args| args}.call(1, 2, 3),
+ ]
+ }
+ ae %q{
+ [
+ Proc.new{|a, *b| [a, b]}.call(),
+ Proc.new{|a, *b| [a, b]}.call(1),
+ Proc.new{|a, *b| [a, b]}.call(1, 2),
+ Proc.new{|a, *b| [a, b]}.call(1, 2, 3),
+ ]
+ }
+ end
+
+ def test_closure
+ ae %q{
+ def make_proc(&b)
+ b
+ end
+
+ def make_closure
+ a = 0
+ make_proc{
+ a+=1
+ }
+ end
+
+ cl = make_closure
+ cl.call + cl.call * cl.call
+ }
+ end
+
+ def test_nestproc2
+ ae %q{
+ def iter
+ yield
+ end
+
+ def getproc &b
+ b
+ end
+
+ iter{
+ bvar = 3
+ getproc{
+ bvar2 = 4
+ bvar * bvar2
+ }
+ }.call
+ }
+
+ ae %q{
+ def iter
+ yield
+ end
+
+ def getproc &b
+ b
+ end
+
+ loc1 = 0
+ pr1 = iter{
+ bl1 = 1
+ getproc{
+ loc1 += 1
+ bl1 += 1
+ loc1 + bl1
+ }
+ }
+
+ pr2 = iter{
+ bl1 = 1
+ getproc{
+ loc1 += 1
+ bl1 += 1
+ loc1 + bl1
+ }
+ }
+
+ pr1.call; pr2.call
+ pr1.call; pr2.call
+ pr1.call; pr2.call
+ (pr1.call + pr2.call) * loc1
+ }
+ end
+
+ def test_proc_with_cref
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ $pr = proc{
+ (1..2).map{
+ Const
+ }
+ }
+ end
+ $pr.call
+ }
+ ae %q{
+ Const = :top
+ class C
+ Const = :C
+ end
+ pr = proc{
+ Const
+ }
+ C.class_eval %q{
+ pr.call
+ }
+ }
+ end
+
+ def test_3nest
+ ae %q{
+ def getproc &b
+ b
+ end
+
+ def m
+ yield
+ end
+
+ m{
+ i = 1
+ m{
+ j = 2
+ m{
+ k = 3
+ getproc{
+ [i, j, k]
+ }
+ }
+ }
+ }.call
+ }
+ end
+
+ def test_nestproc1
+ ae %q{
+ def proc &b
+ b
+ end
+
+ pr = []
+ proc{|i_b|
+ p3 = proc{|j_b|
+ pr << proc{|k_b|
+ [i_b, j_b, k_b]
+ }
+ }
+ p3.call(1)
+ p3.call(2)
+ }.call(0)
+
+ pr[0].call(:last).concat pr[1].call(:last)
+ }
+ end
+
+ def test_proc_with_block
+ ae %q{
+ def proc(&pr)
+ pr
+ end
+
+ def m
+ a = 1
+ m2{
+ a
+ }
+ end
+
+ def m2
+ b = 2
+ proc{
+ [yield, b]
+ }
+ end
+
+ pr = m
+ x = ['a', 1,2,3,4,5,6,7,8,9,0,
+ 1,2,3,4,5,6,7,8,9,0,
+ 1,2,3,4,5,6,7,8,9,0,
+ 1,2,3,4,5,6,7,8,9,0,
+ 1,2,3,4,5,6,7,8,9,0,]
+ pr.call
+ }
+ ae %q{
+ def proc(&pr)
+ pr
+ end
+
+ def m
+ a = 1
+ m2{
+ a
+ }
+ end
+
+ def m2
+ b = 2
+ proc{
+ [yield, b]
+ }
+ 100000.times{|x|
+ "#{x}"
+ }
+ yield
+ end
+ m
+ }
+ end
+
+ def test_method_to_proc
+ ae %q{
+ class C
+ def foo
+ :ok
+ end
+ end
+
+ def block
+ C.method(:new).to_proc
+ end
+ b = block()
+ b.call.foo
+ }
+ end
+
+ def test_safe
+ ae %q{
+ pr = proc{
+ $SAFE
+ }
+ $SAFE = 1
+ pr.call
+ }
+ ae %q{
+ pr = proc{
+ $SAFE += 1
+ }
+ [pr.call, $SAFE]
+ }
+ end
+end
+
diff --git a/yarvtest/test_syntax.rb b/yarvtest/test_syntax.rb
new file mode 100644
index 0000000000..ce375328ac
--- /dev/null
+++ b/yarvtest/test_syntax.rb
@@ -0,0 +1,594 @@
+require 'yarvtest/yarvtest'
+
+# test of syntax
+class TestSYNTAX < YarvTestBase
+
+ def test_if_unless
+ ae %q(if true then 1 ; end)
+ ae %q(if false then 1 ; end)
+ ae %q(if true then 1 ; else; 2; end)
+ ae %q(if false then 1 ; else; 2; end)
+ ae %q(if true then ; elsif true then ; 1 ; end)
+ ae %q(if false then ; elsif true then ; 1 ; end)
+
+ ae %q(unless true then 1 ; end)
+ ae %q(unless false then 1 ; end)
+ ae %q(unless true then 1 ; else; 2; end)
+ ae %q(unless false then 1 ; else; 2; end)
+
+ ae %q(1 if true)
+ ae %q(1 if false)
+ ae %q(1 if nil)
+
+ ae %q(1 unless true)
+ ae %q(1 unless false)
+ ae %q(1 unless nil)
+ end
+
+ def test_while_until
+ ae %q(
+ i = 0
+ while i < 10
+ i+=1
+ end)
+
+ ae %q(
+ i = 0
+ while i < 10
+ i+=1
+ end; i)
+
+ ae %q(
+ i = 0
+ until i > 10
+ i+=1
+ end)
+
+ ae %q(
+ i = 0
+ until i > 10
+ i+=1
+ end; i)
+ #
+ ae %q{
+ i = 0
+ begin
+ i+=1
+ end while false
+ i
+ }
+ ae %q{
+ i = 0
+ begin
+ i+=1
+ end until true
+ i
+ }
+ end
+
+ def test_and
+ ae %q(1 && 2 && 3 && 4)
+ ae %q(1 && nil && 3 && 4)
+ ae %q(1 && 2 && 3 && nil)
+ ae %q(1 && 2 && 3 && false)
+
+ ae %q(1 and 2 and 3 and 4)
+ ae %q(1 and nil and 3 and 4)
+ ae %q(1 and 2 and 3 and nil)
+ ae %q(1 and 2 and 3 and false)
+ ae %q(nil && true)
+ ae %q(false && true)
+
+ end
+
+ def test_or
+ ae %q(1 || 2 || 3 || 4)
+ ae %q(1 || false || 3 || 4)
+ ae %q(nil || 2 || 3 || 4)
+ ae %q(false || 2 || 3 || 4)
+ ae %q(nil || false || nil || false)
+
+ ae %q(1 or 2 or 3 or 4)
+ ae %q(1 or false or 3 or 4)
+ ae %q(nil or 2 or 3 or 4)
+ ae %q(false or 2 or 3 or 4)
+ ae %q(nil or false or nil or false)
+ end
+
+ def test_case
+ ae %q(
+ case 1
+ when 2
+ :ng
+ end)
+
+ ae %q(
+ case 1
+ when 10,20,30
+ :ng1
+ when 1,2,3
+ :ok
+ when 100,200,300
+ :ng2
+ else
+ :elseng
+ end)
+ ae %q(
+ case 123
+ when 10,20,30
+ :ng1
+ when 1,2,3
+ :ng2
+ when 100,200,300
+ :ng3
+ else
+ :elseok
+ end
+ )
+ ae %q(
+ case 'test'
+ when /testx/
+ :ng1
+ when /test/
+ :ok
+ when /tetxx/
+ :ng2
+ else
+ :ng_else
+ end
+ )
+ ae %q(
+ case Object.new
+ when Object
+ :ok
+ end
+ )
+ ae %q(
+ case Object
+ when Object.new
+ :ng
+ else
+ :ok
+ end
+ )
+ ae %q{
+ case 'test'
+ when 'tes'
+ :ng
+ when 'te'
+ :ng
+ else
+ :ok
+ end
+ }
+ ae %q{
+ case 'test'
+ when 'tes'
+ :ng
+ when 'te'
+ :ng
+ when 'test'
+ :ok
+ end
+ }
+ ae %q{
+ case 'test'
+ when 'tes'
+ :ng
+ when /te/
+ :ng
+ else
+ :ok
+ end
+ }
+ ae %q{
+ case 'test'
+ when 'tes'
+ :ng
+ when /test/
+ :ok
+ else
+ :ng
+ end
+ }
+ ae %q{
+ def test(arg)
+ case 1
+ when 2
+ 3
+ end
+ return arg
+ end
+
+ test(100)
+ }
+ end
+
+ def test_case_splat
+ ae %q{
+ ary = [1, 2]
+ case 1
+ when *ary
+ :ok
+ else
+ :ng
+ end
+ }
+ ae %q{
+ ary = [1, 2]
+ case 3
+ when *ary
+ :ng
+ else
+ :ok
+ end
+ }
+ ae %q{
+ ary = [1, 2]
+ case 1
+ when :x, *ary
+ :ok
+ when :z
+ :ng1
+ else
+ :ng2
+ end
+ }
+ ae %q{
+ ary = [1, 2]
+ case 3
+ when :x, *ary
+ :ng1
+ when :z
+ :ng2
+ else
+ :ok
+ end
+ }
+ end
+
+ def test_when
+ ae %q(
+ case
+ when 1==2, 2==3
+ :ng1
+ when false, 4==5
+ :ok
+ when false
+ :ng2
+ else
+ :elseng
+ end
+ )
+
+ ae %q(
+ case
+ when nil, nil
+ :ng1
+ when 1,2,3
+ :ok
+ when false, false
+ :ng2
+ else
+ :elseng
+ end
+ )
+
+ ae %q(
+ case
+ when nil
+ :ng1
+ when false
+ :ng2
+ else
+ :elseok
+ end)
+
+ ae %q{
+ case
+ when 1
+ end
+ }
+
+ ae %q{
+ r = nil
+ ary = []
+ case
+ when false
+ r = :ng1
+ when false, false
+ r = :ng2
+ when *ary
+ r = :ng3
+ when false, *ary
+ r = :ng4
+ when true, *ary
+ r = :ok
+ end
+ r
+ }
+ end
+
+ def test_when_splat
+ ae %q{
+ ary = []
+ case
+ when false, *ary
+ :ng
+ else
+ :ok
+ end
+ }
+ ae %q{
+ ary = [false, nil]
+ case
+ when *ary
+ :ng
+ else
+ :ok
+ end
+ }
+ ae %q{
+ ary = [false, nil]
+ case
+ when *ary
+ :ng
+ when true
+ :ok
+ else
+ :ng2
+ end
+ }
+ ae %q{
+ ary = [false, nil]
+ case
+ when *ary
+ :ok
+ else
+ :ng
+ end
+ }
+ ae %q{
+ ary = [false, true]
+ case
+ when *ary
+ :ok
+ else
+ :ng
+ end
+ }
+ ae %q{
+ ary = [false, true]
+ case
+ when false, false
+ when false, *ary
+ :ok
+ else
+ :ng
+ end
+ }
+ end
+
+ def test_flipflop
+ ae %q{
+ sum = 0
+ 30.times{|ib|
+ if ib % 10 == 0 .. true
+ sum += ib
+ end
+ }
+ sum
+ }
+ ae %q{
+ sum = 0
+ 30.times{|ib|
+ if ib % 10 == 0 ... true
+ sum += ib
+ end
+ }
+ sum
+ }
+ ae %q{
+ t = nil
+ unless ''.respond_to? :lines
+ class String
+ def lines
+ self
+ end
+ end
+ end
+
+ "this must not print
+ Type: NUM
+ 123
+ 456
+ Type: ARP
+ aaa
+ bbb
+ \f
+ this must not print
+ hoge
+ Type: ARP
+ aaa
+ bbb
+ ".lines.each{|l|
+ if (t = l[/^Type: (.*)/, 1])..(/^\f/ =~ l)
+ p [t, l]
+ end
+ }
+ }
+ end
+
+ def test_defined_vars
+ ae %q{
+ defined?(nil) + defined?(self) +
+ defined?(true) + defined?(false)
+ }
+ #ae %q{
+ # a = 1
+ # defined?(a) # yarv returns "in block" in eval context
+ #}
+ ae %q{
+ defined?(@a)
+ }
+ ae %q{
+ @a = 1
+ defined?(@a)
+ }
+ ae %q{
+ defined?(@@a)
+ }
+ ae %q{
+ @@a = 1
+ defined?(@@a)
+ }
+ ae %q{
+ defined?($a)
+ }
+ ae %q{
+ $a = 1
+ defined?($a)
+ }
+ ae %q{
+ defined?(C_definedtest)
+ }
+ ae %q{
+ C_definedtest = 1
+ defined?(C_definedtest)
+ } do
+ remove_const :C_definedtest
+ end
+
+ ae %q{
+ defined?(::C_definedtest)
+ }
+ ae %q{
+ C_definedtest = 1
+ defined?(::C_definedtest)
+ } do
+ remove_const :C_definedtest
+ end
+
+ ae %q{
+ defined?(C_definedtestA::C_definedtestB::C_definedtestC)
+ }
+ ae %q{
+ class C_definedtestA
+ class C_definedtestB
+ C_definedtestC = 1
+ end
+ end
+ defined?(C_definedtestA::C_definedtestB::C_definedtestC)
+ } do
+ remove_const :C_definedtestA
+ end
+ end
+
+ def test_defined_method
+ ae %q{
+ defined?(m)
+ }
+ ae %q{
+ def m
+ end
+ defined?(m)
+ }
+
+ ae %q{
+ defined?(a.class)
+ }
+ ae %q{
+ a = 1
+ defined?(a.class)
+ }
+ ae %q{
+ class C
+ def test
+ [defined?(m1()), defined?(self.m1), defined?(C.new.m1),
+ defined?(m2()), defined?(self.m2), defined?(C.new.m2),
+ defined?(m3()), defined?(self.m3), defined?(C.new.m3)]
+ end
+ def m1
+ end
+ private
+ def m2
+ end
+ protected
+ def m3
+ end
+ end
+ C.new.test + [defined?(C.new.m3)]
+ }
+ ae %q{
+ $ans = [defined?($1), defined?($2), defined?($3), defined?($4)]
+ /(a)(b)/ =~ 'ab'
+ $ans + [defined?($1), defined?($2), defined?($3), defined?($4)]
+ }
+ end
+
+ def test_condition
+ ae %q{
+
+ def make_perm ary, num
+ if num == 1
+ ary.map{|e| [e]}
+ else
+ base = make_perm(ary, num-1)
+ res = []
+ base.each{|b|
+ ary.each{|e|
+ res << [e] + b
+ }
+ }
+ res
+ end
+ end
+
+ def each_test
+ conds = make_perm(['fv', 'tv'], 3)
+ bangs = make_perm(['', '!'], 3)
+ exprs = make_perm(['and', 'or'], 3)
+ ['if', 'unless'].each{|syn|
+ conds.each{|cs|
+ bangs.each{|bs|
+ exprs.each{|es|
+ yield(syn, cs, bs, es)
+ }
+ }
+ }
+ }
+ end
+
+ fv = false
+ tv = true
+
+ $ans = []
+ each_test{|syn, conds, bangs, exprs|
+ c1, c2, c3 = conds
+ bang1, bang2, bang3 = bangs
+ e1, e2 = exprs
+ eval %Q{
+ #{syn} #{bang1}#{c1} #{e1} #{bang2}#{c2} #{e2} #{bang3}#{c3}
+ $ans << :then
+ else
+ $ans << :false
+ end
+ }
+ }
+
+ each_test{|syn, conds, bangs, exprs|
+ c1, c2, c3 = conds
+ bang1, bang2, bang3 = bangs
+ e1, e2 = exprs
+ eval %Q{
+ #{syn} #{bang1}#{c1} #{e1} #{bang2}#{c2} #{e2} #{bang3}#{c3}
+ $ans << :then
+ end
+ $ans << :sep
+ }
+ }
+ $ans
+ }
+ end
+end
+
diff --git a/yarvtest/test_test.rb b/yarvtest/test_test.rb
new file mode 100644
index 0000000000..17a0e2363b
--- /dev/null
+++ b/yarvtest/test_test.rb
@@ -0,0 +1,8 @@
+require 'yarvtest/yarvtest'
+
+# test of syntax
+class TestTest < YarvTestBase
+ def test_1
+ ae '100'
+ end
+end
diff --git a/yarvtest/test_thread.rb b/yarvtest/test_thread.rb
new file mode 100644
index 0000000000..ba0c0838dd
--- /dev/null
+++ b/yarvtest/test_thread.rb
@@ -0,0 +1,209 @@
+
+require 'yarvtest/yarvtest'
+
+class TestThread < YarvTestBase
+ def test_create
+ ae %q{
+ Thread.new{
+ }.join
+ :ok
+ }
+ ae %q{
+ Thread.new{
+ :ok
+ }.value
+ }
+ end
+
+ def test_create_many_threads1
+ ae %q{
+ v = 0
+ (1..200).map{|i|
+ Thread.new{
+ i
+ }
+ }.each{|t|
+ v += t.value
+ }
+ v
+ }
+ end
+
+ def test_create_many_threads2
+ ae %q{
+ 5000.times{|e|
+ (1..2).map{
+ Thread.new{
+ }
+ }.each{|e|
+ e.join
+ }
+ }
+ }
+ end
+
+ def test_create_many_threads3
+ ae %q{
+ 5000.times{
+ t = Thread.new{}
+ while t.alive?
+ Thread.pass
+ end
+ }
+ }
+ end
+
+ def test_create_many_threads4
+ ae %q{
+ 100.times{
+ Thread.new{loop{Thread.pass}}
+ }
+ }
+ end
+
+ def test_raise
+ ae %q{
+ t = Thread.new{
+ sleep
+ }
+ sleep 0.1
+ t.raise
+ begin
+ t.join
+ :ng
+ rescue
+ :ok
+ end
+ }
+ ae %q{
+ t = Thread.new{
+ loop{}
+ }
+ Thread.pass
+ t.raise
+ begin
+ t.join
+ :ng
+ rescue
+ :ok
+ end
+ }
+ ae %q{
+ t = Thread.new{
+ }
+ Thread.pass
+ t.join
+ t.raise # raise to exited thread
+ begin
+ t.join
+ :ok
+ rescue
+ :ng
+ end
+ }
+ end
+
+ def test_status
+ ae %q{
+ t = Thread.new{
+ loop{}
+ }
+ st = t.status
+ t.kill
+ st
+ }
+ ae %q{
+ t = Thread.new{
+ sleep
+ }
+ sleep 0.1
+ st = t.status
+ t.kill
+ st
+ }
+ ae %q{
+ t = Thread.new{
+ }
+ t.kill
+ sleep 0.1
+ t.status
+ }
+ end
+
+ def test_tlv
+ ae %q{
+ Thread.current[:a] = 1
+ Thread.new{
+ Thread.current[:a] = 10
+ Thread.pass
+ Thread.current[:a]
+ }.value + Thread.current[:a]
+ }
+ end
+
+ def test_thread_group
+ ae %q{
+ ptg = Thread.current.group
+ Thread.new{
+ ctg = Thread.current.group
+ [ctg.class, ctg == ptg]
+ }.value
+ }
+ ae %q{
+ thg = ThreadGroup.new
+
+ t = Thread.new{
+ thg.add Thread.current
+ sleep
+ }
+ sleep 0.1
+ [thg.list.size, ThreadGroup::Default.list.size]
+ }
+ end
+
+ def test_thread_local_svar
+ ae %q{
+ /a/ =~ 'a'
+ $a = $~
+ Thread.new{
+ $b = $~
+ /a/ =~ 'a'
+ $c = $~
+ }
+ $d = $~
+ [$a == $d, $b, $c != $d]
+ }
+ end
+
+ def test_join
+ ae %q{
+ Thread.new{
+ :ok
+ }.join.value
+ }
+ ae %q{
+ begin
+ Thread.new{
+ raise "ok"
+ }.join
+ rescue => e
+ e
+ end
+ }
+ ae %q{
+ ans = nil
+ t = Thread.new{
+ begin
+ sleep 0.5
+ ensure
+ ans = :ok
+ end
+ }
+ Thread.pass
+ t.kill
+ t.join
+ ans
+ }
+ end
+end
+
diff --git a/yarvtest/test_yield.rb b/yarvtest/test_yield.rb
new file mode 100644
index 0000000000..72b2182099
--- /dev/null
+++ b/yarvtest/test_yield.rb
@@ -0,0 +1,207 @@
+require 'yarvtest/yarvtest'
+class TestYield < YarvTestBase
+ def test_simple
+ ae %q{
+ def iter
+ yield
+ end
+ iter{
+ 1
+ }
+ }
+ end
+
+ def test_hash_each
+ ae %q{
+ h = {:a => 1}
+ a = []
+ h.each{|k, v|
+ a << [k, v]
+ }
+ h.each{|kv|
+ a << kv
+ }
+ a
+ }
+ end
+
+ def test_ary_each
+ ae %q{
+ ans = []
+ ary = [1,2,3]
+ ary.each{|a, b, c, d|
+ ans << [a, b, c, d]
+ }
+ ary.each{|a, b, c|
+ ans << [a, b, c]
+ }
+ ary.each{|a, b|
+ ans << [a, b]
+ }
+ ary.each{|a|
+ ans << [a]
+ }
+ ans
+ }
+ end
+
+ def test_iter
+ ae %q{
+ def iter *args
+ yield *args
+ end
+
+ ans = []
+ ary = [1,2,3]
+ ary.each{|a, b, c, d|
+ ans << [a, b, c, d]
+ }
+ ary.each{|a, b, c|
+ ans << [a, b, c]
+ }
+ ary.each{|a, b|
+ ans << [a, b]
+ }
+ ary.each{|a|
+ ans << [a]
+ }
+ ans
+ }
+ end
+
+ def test_iter2
+ ae %q{
+ def iter args
+ yield *args
+ end
+ ans = []
+ iter([]){|a, b|
+ ans << [a, b]
+ }
+ iter([1]){|a, b|
+ ans << [a, b]
+ }
+ iter([1, 2]){|a, b|
+ ans << [a, b]
+ }
+ iter([1, 2, 3]){|a, b|
+ ans << [a, b]
+ }
+ ans
+ }
+ ae %q{
+ def iter args
+ yield *args
+ end
+ ans = []
+
+ iter([]){|a|
+ ans << a
+ }
+ iter([1]){|a|
+ ans << a
+ }
+ iter([1, 2]){|a|
+ ans << a
+ }
+ iter([1, 2, 3]){|a|
+ ans << a
+ }
+ ans
+ }
+ end
+
+ def test_1_ary_and_n_params
+ ae %q{
+ def iter args
+ yield args
+ end
+ ans = []
+ iter([]){|a, b|
+ ans << [a, b]
+ }
+ iter([1]){|a, b|
+ ans << [a, b]
+ }
+ iter([1, 2]){|a, b|
+ ans << [a, b]
+ }
+ iter([1, 2, 3]){|a, b|
+ ans << [a, b]
+ }
+ ans
+ }
+ end
+
+ def test_1_ary_and_1_params
+ ae %q{
+ def iter args
+ yield args
+ end
+ ans = []
+ iter([]){|a|
+ ans << a
+ }
+ iter([1]){|a|
+ ans << a
+ }
+ iter([1, 2]){|a|
+ ans << a
+ }
+ iter([1, 2, 3]){|a|
+ ans << a
+ }
+ ans
+ }
+ end
+
+ def test_argscat
+ ae %q{
+ def iter
+ yield 1, *[2, 3]
+ end
+
+ iter{|a, b, c|
+ [a, b, c]
+ }
+ }
+ ae %q{
+ def iter
+ yield 1, *[]
+ end
+
+ iter{|a, b, c|
+ [a, b, c]
+ }
+ }
+ if false
+ ae %q{
+ def iter
+ yield 1, *2
+ end
+
+ iter{|a, b, c|
+ [a, b, c]
+ }
+ }
+ end
+ end
+
+ def test_massgin
+ ae %q{
+ ans = []
+ [[1, [2, 3]], [4, [5, 6]]].each{|a, (b, c)|
+ ans << [a, b, c]
+ }
+ ans
+ }
+ ae %q{
+ ans = []
+ [[1, [2, 3]], [4, [5, 6]]].map{|a, (b, c)|
+ ans << [a, b, c]
+ } + ans
+ }
+ end
+end
+
+
diff --git a/yarvtest/yarvtest.rb b/yarvtest/yarvtest.rb
new file mode 100644
index 0000000000..906af727b4
--- /dev/null
+++ b/yarvtest/yarvtest.rb
@@ -0,0 +1,136 @@
+require 'test/unit'
+
+if defined? YARV_PATCHED
+require 'yarvutil'
+
+class YarvTestBase < Test::Unit::TestCase
+
+ def remove_const sym
+ Object.module_eval{
+ remove_const sym
+ }
+ end
+
+ def remove_method sym
+ Object.module_eval{
+ undef sym
+ }
+ end
+
+ def ae str
+ # puts str
+ # puts YARVUtil.parse(str, $0, 0).disasm
+
+ ruby = YARVUtil.eval_in_wrap(str)
+ yield if block_given?
+
+ yarv = YARVUtil.eval(str)
+ yield if block_given?
+
+ assert_equal(ruby, yarv)
+ end
+
+ def test_
+ end
+
+end
+
+else
+
+require 'rbconfig'
+class YarvTestBase < Test::Unit::TestCase
+ def initialize *args
+ super
+
+ if /mswin32/ !~ RUBY_PLATFORM
+ @yarv = './miniruby'
+ else
+ @yarv = 'miniruby'
+ end
+ @ruby = Config::CONFIG['ruby_install_name']
+ end
+
+ def remove_const sym
+ Object.module_eval{
+ remove_const sym
+ }
+ end
+
+ def remove_method sym
+ Object.module_eval{
+ undef sym
+ }
+ end
+
+ require 'tempfile'
+ def exec exec_file, program
+ dir = []
+ dir << ENV['RAMDISK'] if ENV['RAMDISK']
+ tmpf = Tempfile.new("yarvtest_#{Process.pid}_#{Time.now.to_i}", *dir)
+ tmpf.write program
+ tmpf.close
+ result = `#{exec_file} #{tmpf.path}`
+ tmpf.open
+ tmpf.close(true)
+ result
+ end
+
+ def dump_and_exec exec_file, str
+ asmstr = <<-EOASMSTR
+ iseq = YARVCore::InstructionSequence.compile(<<-'EOS__')
+ #{str}
+ EOS__
+ p YARVCore::InstructionSequence.load(iseq.to_a).eval
+ EOASMSTR
+
+ exec(exec_file, asmstr)
+ end
+
+ def exec_ exec_file, program
+ exec_file.tr!('\\', '/')
+ r = ''
+ IO.popen("#{exec_file}", 'r+'){|io|
+ #
+ io.write program
+ io.close_write
+ begin
+ while line = io.gets
+ r << line
+ # p line
+ end
+ rescue => e
+ # p e
+ end
+ }
+ r
+ end
+
+ def ae str
+ evalstr = %{
+ p eval(%q{
+ #{str}
+ })
+ }
+
+ ruby = exec(@ruby, evalstr)
+ yarv = exec(@yarv, evalstr)
+
+ if $DEBUG #|| true
+ puts "yarv (#@yarv): #{yarv}"
+ puts "ruby (#@ruby): #{ruby}"
+ end
+
+ assert_equal(ruby.gsub(/\r/, ''), yarv.gsub(/\r/, ''))
+
+ # store/load test
+ if false # || true
+ yarvasm = dump_and_exec(@yarv, str)
+ assert_equal(ruby.gsub(/\r/, ''), yarvasm.gsub(/\r/, ''))
+ end
+ end
+
+ def test_
+ end
+end
+
+end