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);
	}

	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 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, " Tru ye: [ e@ 42 ] . Tru no: [ e@ 13 ] . e");
		assertEquals(42.0, e.eval(f).asNum().num);
	}
	public void testYesNoToFalse() {
		Expr e = Parser.parse(t, " Fal ye: [ a@ 42 ] . Fal no: [ a@ 13 ] . a");
		assertEquals(13.0, e.eval(f).asNum().num);
	}
	public void testDefiningUsrSubclass() {
		Expr e = Parser.parse(t, " Usr defineSubclass: 'Foo' . Foo new cls nam");
		assertEquals("Foo", e.eval(f).asStr().str);
	}
	public void testDefiningUsrMethod() {
		Expr e = Parser.parse(t, " Usr defsub 'Foo' . Foo defmet: 'xyz' ab: '' ds: '' co: '888' . Foo new xyz ");
		assertEquals(888.0, e.eval(f).asNum().num);
	}
	public void testInstVar() {
		Expr e = Parser.parse(t, "Usr defSub: 'Foo' . Foo defineMethod: 'stor:' abbrev: '' docStr: 'Store in x.' code: '/x@ a' . Foo defmet: 'rcl' ab: nil ds: '' co: '/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 setLen: 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 testEq() {
		Expr e = Parser.parse(t, " 5 eq: 2 ");
		assertEquals(t.instFalse, e.eval(f));
	}
	public void testNe() {
		Expr e = Parser.parse(t, " 5 ne: 2 ");
		assertEquals(t.instTrue, e.eval(f));
	}
	public void testLt() {
		Expr e = Parser.parse(t, " 5 lt: 2 ");
		assertEquals(t.instFalse, e.eval(f));
	}
	public void testLe() {
		Expr e = Parser.parse(t, " 5 le: 5 ");
		assertEquals(t.instTrue, e.eval(f));
	}
	public void testGt() {
		Expr e = Parser.parse(t, " 5 gt: 2 ");
		assertEquals(t.instTrue, e.eval(f));
	}
	public void testGe() {
		Expr e = Parser.parse(t, " 5 ge: 6 ");
		assertEquals(t.instFalse, e.eval(f));
	}
	public void testStrEq() {
		Expr e = Parser.parse(t, " 'a' eq: 'x' ");
		assertEquals(t.instFalse, e.eval(f));
	}
	public void testStrNe() {
		Expr e = Parser.parse(t, " 'x' ne: 'xx' ");
		assertEquals(t.instTrue, e.eval(f));
	}
	public void testStrLt() {
		Expr e = Parser.parse(t, " 'xxx' lt: 'xxx' ");
		assertEquals(t.instFalse, e.eval(f));
	}
	public void testStrLe() {
		Expr e = Parser.parse(t, " 'xx' le: 'xxx' ");
		assertEquals(t.instTrue, e.eval(f));
	}
	public void testStrGt() {
		Expr e = Parser.parse(t, " '5' gt: '20' ");
		assertEquals(t.instTrue, e.eval(f));
	}
	public void testStrGe() {
		Expr e = Parser.parse(t, " '' ge: '!' ");
		assertEquals(t.instFalse, e.eval(f));
	}
	public void testDoForRange() {
		Expr e = Parser.parse(t, " s@ 0 . 5 do: [ i . s@ s pl i ] . s ");
		assertEquals(10.0, e.eval(f).asNum().num);
	}
	public void testDoForVec() {
		Expr e = Parser.parse(t, " s@ 0 . v@ Vec ap: 3 . v do: [ i . s@ s pl i ] . s ");
		assertEquals(3.0, e.eval(f).asNum().num);
	}
	public void testStrSplit() {
		Expr e = Parser.parse(t, " 'one/more/time' spli: '/' , at: 2 ");
		assertEquals("time", e.eval(f).asStr().str);
	}
	public void testBuf() {
		Expr e = Parser.parse(t, " Buf ap: 'one/' , ap: 'more/' , ap: 'time' , str");
		assertEquals("one/more/time", e.eval(f).asStr().str);
	}
	public void testBlkToVec() {
		Expr e = Parser.parse(t, " [ 1 pl 1 . 2 pl 2 . 3 pl 3 . 4 pl 4 . ] vec at: 2 ");
		assertEquals(6.0, e.eval(f).asNum().num);
	}
	public void testBlkToMap() {
		Expr e = Parser.parse(t, " [ 1 pl 1 . 2 pl 2 . 3 pl 3 . 4 pl 4 . ] map at: 2 ");
		assertEquals(4.0, e.eval(f).asNum().num);
	}
	public void testTriangleNumber() {
		Expr e = Parser.parse(t, "USR DefSub: 'Foo' . Foo trac: Tru . "
				+ " Foo defmet: 'trIaNgle:' ab: '' ds: '' co:  ' "
				+ "   g@ 0 . "
				+ "   [ a gt: 0 ] run ye: [ g@   / triangle [ a mi: 1 ] run , pl: a  ] . "
				+ "   g' . " 
		        + "   Foo new TRIANGLE: 6  ");
		assertEquals(21.0, e.eval(f).asNum().num);
	}
}
