require 'test/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)
  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}"
    }
  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'
    }
  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) do
      remove_const :C
    end

    ae %q(C = 1; ::C) do
      remove_const :C
    end
    
    ae %q(
      class A
        class B
          class C
            Const = 1
          end
        end
      end
      A::B::C::Const
    ) do
      remove_const :A
    end
    
    ae %q(
      class A
        class B
          Const = 1
          class C
            Const
          end
        end
      end
    ) do
      remove_const :A
    end
    
    ae %q(
      class A
        Const = 1
        class B
          class C
            Const
          end
        end
      end
    ) do
      remove_const :A
    end
    
    ae %q(
      Const = 1
      class A
        class B
          class C
            Const
          end
        end
      end
    ) do
      remove_const :A
      remove_const :Const
    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
  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_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
  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
  
end

