package net.yak.stalk;

import net.yak.stalk.Talk.Terp;
import net.yak.stalk.Talk.Terp.Frame;
import junit.framework.TestCase;

public class ExprTest extends TestCase {
	Terp t;
	Frame f;

	protected void setUp() throws Exception {
		super.setUp();
		t = new Terp();
		f = t.newFrame(null, null, null);
	}

	public void testLit888() {
		Expr e = Parser.parse(t, " 888 ");
		Pro obj = e.eval(f);
		assertEquals(888.0, obj.asNum().num);
	}
	public void testLitString() {
		Expr e = Parser.parse(t, " 'foo''bar' ");
		Pro obj = e.eval(f);
		assertEquals("foo'bar", obj.asStr().str);
	}
	public void testTwoStmts() {
		Expr e = Parser.parse(t, " . 23 . 42 . . . ");
		assertEquals(42.0, e.eval(f).asNum().num);
	}
	public void testUnaryNeg() {
		Expr e = Parser.parse(t, " . 23 . 42 neg . . . ");
		assertEquals(-42.0, e.eval(f).asNum().num);
	}
	public void testUnaryNegSgn() {
		Expr e = Parser.parse(t, " . 23 . 42 neg sgn ");
		assertEquals(-1.0, e.eval(f).asNum().num);
	}
	public void testPlusTwoNums() {
		Expr e = Parser.parse(t, " 23 pl: 42  ");
		assertEquals(65.0, e.eval(f).asNum().num);
	}
	public void testPlusTwoNumsWithNeg() {
		Expr e = Parser.parse(t, " 23 pl: 42 neg  ");
		assertEquals(-19.0, e.eval(f).asNum().num);
	}
	public void testPlusTwoNumsWithOtherNeg() {
		Expr e = Parser.parse(t, " 23 neg pl: 42  ");
		assertEquals(19.0, e.eval(f).asNum().num);
	}
	public void testStoreAndFetch() {
		Expr e = Parser.parse(t, " n/ 23 pl: 42 . 13 . n  ");
		assertEquals(65.0, e.eval(f).asNum().num);
	}
	public void testStoreAndFetchWithGlobalAndLocal() {
		Expr e = Parser.parse(t, " /X/ 4 pl: 4 . j/ 5 pl: 5 . /X pl: j ");
		assertEquals(18.0, e.eval(f).asNum().num);
	}
	public void testBlock() {
		Expr e = Parser.parse(t, " [ 23 pl: 42 . ] run  ");
		assertEquals(65.0, e.eval(f).asNum().num);
	}
	public void testYesNoToTrue() {
		Expr e = Parser.parse(t, " /t ye: [ e/ 42 ] . /t no: [ e/ 13 ] . e");
		assertEquals(42.0, e.eval(f).asNum().num);
	}
	public void testYesNoToFalse() {
		Expr e = Parser.parse(t, " /f ye: [ a/ 42 ] . /f no: [ a/ 13 ] . a");
		assertEquals(13.0, e.eval(f).asNum().num);
	}
	public void testDefiningUsrSubclass() {
		Expr e = Parser.parse(t, " /Usr subc: 'Foo' . /Foo new cls nam");
		assertEquals("Foo", e.eval(f).asStr().str);
	}
	public void testDefiningUsrMethod() {
		Expr e = Parser.parse(t, " /Usr subc: 'Foo' . /Foo meth: 'xyz' as: '888' . /Foo new xyz ");
		assertEquals(888.0, e.eval(f).asNum().num);
	}
	public void testInstVar() {
		Expr e = Parser.parse(t, "/Usr subc: 'Foo' . /Foo meth: 'stor:' as: 'x/ a' . /Foo meth: 'rcl' as: 'x' . h/ /Foo new . h stor: 56 . h rcl ");
		assertEquals(56.0, e.eval(f).asNum().num);
	}
	public void testVec() {
		Expr e = Parser.parse(t, "a/ /Vec new . a setn: 10 . a at: 3 pu: 33 . a at: 3 ");
		assertEquals(33.0, e.eval(f).asNum().num);
	}
	public void testMap() {
		Expr e = Parser.parse(t, "a/ /Map new . a at: 'foo' pu: 333 . a at: 'foo' ");
		assertEquals(333.0, e.eval(f).asNum().num);
	}
	public void testGt() {
		Expr e = Parser.parse(t, " 5 gt: 2 ");
		assertEquals(t.instTrue, e.eval(f));
	}
	public void testEq() {
		Expr e = Parser.parse(t, " 5 eq: 2 ");
		assertEquals(t.instFalse, e.eval(f));
	}
	public void testTriangleNumber() {
		Expr e = Parser.parse(t, "/Usr subc: 'Foo' . "
				+ " /Foo meth: 'tria:' as: ' "
				+ "   g/ 0 . "
				+ "   [ a gt: 0 ] run ye: [ g/  self tria: [ a mi: 1 ] run  ] . "
				+ "   g' . " 
		        + "   /Foo new tria: 4  ");
		assertEquals(56.0, e.eval(f).asNum().num);
	}
}
