/*
TestForthCompBootstrapF99b.java
(c) 2010-2014 Edward Swartz
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
*/
package v9t9.tools.forthcomp.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import v9t9.machine.f99b.asm.InstF99b;
import v9t9.tools.forthcomp.DictEntry;
import v9t9.tools.forthcomp.ITargetWord;
/**
* @author ejs
*
*/
public class TestForthCompBootstrapF99b extends BaseF99bTest {
@Test
public void testInvokeSimple1() throws Exception {
parseString(
": num 1 ;\n"+
"num");
assertEquals(1, hostCtx.popData());
}
@Test
public void testInvokeSimple2() throws Exception {
hostCtx.pushData(1);
parseString(
": num 2 + ;\n"+
"num");
assertEquals(3, hostCtx.popData());
}
@Test
public void testInvokeCalls1() throws Exception {
hostCtx.pushData(1);
parseString(
": inner 10 * ;\n"+
": num inner 2 + ;\n"+
"num");
assertEquals(12, hostCtx.popData());
}
@Test
public void testVariables1() throws Exception {
hostCtx.pushData(1);
parseString(
"Variable x\n"+
"10 x !\n"+
": inner x @ * ;\n"+
": num inner 2 + ;\n"+
"num");
assertEquals(12, hostCtx.popData());
}
@Test
public void testValues1() throws Exception {
hostCtx.pushData(1);
parseString(
"0 Value x\n"+
": inner x * ;\n"+
": num inner 2 + ;\n"+
"10 to x\n"+
"num");
assertEquals(12, hostCtx.popData());
}
@Test
public void testConditionsIf() throws Exception {
hostCtx.pushData(1);
parseString(
": num dup 0 < if negate else 5 * then ;\n"+
"-11 num");
assertEquals(11, hostCtx.popData());
assertEquals(1, hostCtx.popData());
parseString("10 num");
assertEquals(50, hostCtx.popData());
}
@Test
public void testDictChange() throws Exception {
parseString(
stockDictDefs +
": num dup , $f and c, ;\n"+
"here\n"+
"31 num 13 num\n"+
"here\n");
int outHere = hostCtx.popData();
assertEquals(outHere, targCtx.getDP());
int origHere = hostCtx.popData();
assertEquals(2 * (targCtx.getCellSize() + 1), outHere - origHere);
dumpDict();
assertEquals(31, targCtx.readCell(origHere));
assertEquals(15, targCtx.readChar(origHere + 2));
assertEquals(13, targCtx.readCell(origHere + 3));
assertEquals(13, targCtx.readChar(origHere + 5));
}
@Test
public void testImmed1() throws Exception {
parseString(
"Variable foo\n"+
": doit 123 Foo ! ; immediate\n"+
": push 11 Foo ! doit ;\n");
ITargetWord var = targCtx.require("Foo");
assertEquals(123, targCtx.readCell(var.getEntry().getParamAddr()));
parseString("push");
assertEquals(11, targCtx.readCell(var.getEntry().getParamAddr()));
}
@Test
public void testImmed2() throws Exception {
parseString(
"Variable foo\n"+
": doit 123 Foo ! ; immediate\n"+
": push 11 Foo ! postpone doit ;\n");
dumpDict();
ITargetWord var = targCtx.require("Foo");
assertEquals(0, targCtx.readCell(var.getEntry().getParamAddr()));
parseString("push");
assertEquals(123, targCtx.readCell(var.getEntry().getParamAddr()));
}
@Test
public void testDictCompileLiteral() throws Exception {
// TRICKY! We provide a way to both interpret (colon-def-wise) and
// show a mirror high-level variant, to ensure we match the behavior
parseString(
stockDictDefs +
compileLiteral +
compileMeta +
": literal ( n -- ) dup -8 >= over 8 < and if\n" +
" $f and $20 or c, else\n" +
"dup -128 >= over 128 < and if\n" +
" $78 c, c,\n" +
"else\n" +
" $79 c, ,\n" +
"then then\n"+
"; immediate host( 1 ) literal \n"+
": pushNum postpone literal ; immediate\n"+
": push [ 10 ] pushNum [ -3 ] pushNum [ $1234 ] pushNum ;\n"+
"push\n");
dumpDict();
assertEquals(0x1234, hostCtx.popData());
assertEquals(-3, hostCtx.popData());
assertEquals(10, hostCtx.popData());
int dp = (targCtx.require("push")).getEntry().getContentAddr();
assertEquals(InstF99b.IlitB, targCtx.readChar(dp++));
assertEquals(10, targCtx.readChar(dp++));
assertEquals(InstF99b.IlitX | (-3 & 0xf), targCtx.readChar(dp++));
assertEquals(InstF99b.IlitW, targCtx.readChar(dp++));
assertEquals(0x12, targCtx.readChar(dp++));
assertEquals(0x34, targCtx.readChar(dp++));
assertEquals(InstF99b.Iexit, targCtx.readChar(dp++));
}
@Test
public void testDictCompileWord() throws Exception {
hostCtx.pushData(99);
// Provide enough target defs to convince the compiler
// to allow emulating.
// Of course, /interpreting/ make-adder: would lead to BIG TROUBLE!
parseString(
stockDictDefs +
compileLiteral +
compileMeta +
": make-adder: ( n -- ) : postpone literal postpone + 0 postpone ; drop ;\n "+
"here swap\n"+
"100 make-adder: 100+\n"+
"100+");
dumpDict();
assertEquals(199, hostCtx.popData());
int dphere = hostCtx.popData();
DictEntry newEntry = (targCtx.require("100+")).getEntry();
int dp = newEntry.getContentAddr();
assertEquals(dp+"|"+dphere, dp, dphere + newEntry.getHeaderSize());
assertEquals(InstF99b.IlitB, targCtx.readChar(dp++));
assertEquals(100, targCtx.readChar(dp++));
assertEquals(InstF99b.Iadd, targCtx.readChar(dp++));
assertEquals(InstF99b.Iexit, targCtx.readChar(dp++));
}
@Test
public void testDictCreateDoes() throws Exception {
hostCtx.pushData(99);
// Provide enough target defs to convince the compiler
// to allow emulating.
// Of course, /interpreting/ make-adder: would lead to BIG TROUBLE!
parseString(
stockDictDefs +
compileLiteral +
compileMeta+
": xt! ( xt addr -- ) $7B ( BRANCHW ) over c! 1+ ! ; \n"+ // BOGUS
//": ] true state ! ; immediate host( 0 ) ] \n"+
": (does>) r> latest xt! ; \n"+
": does> postpone (does>) postpone rdrop ; immediate target-only\n"+
": make-adder: ( n -- ) create , does> @ + ;\n "+
"here swap\n"+
"100 make-adder: 100+\n");
dumpDict();
exportBinary();
parseString("100+");
assertEquals(199, hostCtx.popData());
// make sure CREATE , DOES> has expected code in it
DictEntry creatorEntry = (targCtx.require("make-adder:")).getEntry();
int dp = creatorEntry.getContentAddr();
// PUNT
assertTrue((targCtx.readCell(dp) & 0xffff) >= 0x8000); dp+=2;
assertTrue((targCtx.readCell(dp) & 0xffff) >= 0x8000); dp+=2;
// @ + bit
int doesDp = dp;
assertTrue(""+dp, (dp & 1) == 0); // calls, so must align
assertEquals(InstF99b.IRfrom, targCtx.readChar(dp++)); // get address
assertEquals(InstF99b.Iload, targCtx.readChar(dp++)); // user-specified code
assertEquals(InstF99b.Iadd, targCtx.readChar(dp++));
assertEquals(InstF99b.Iexit, targCtx.readChar(dp++));
/// now make sure the created word is sensible
int dphere = hostCtx.popData();
DictEntry newEntry = (targCtx.require("100+")).getEntry();
dp = newEntry.getContentAddr();
assertEquals(dp+"|"+dphere, ((dphere + newEntry.getHeaderSize()+1)&~1), dp);
/*
// first, normal DOVAR (PC@ 2+)
assertEquals(InstF99b.IcontextFrom, targCtx.readChar(dp++));
assertEquals(InstF99b.CTX_PC, targCtx.readChar(dp++));
assertEquals(InstF99b.I2plus, targCtx.readChar(dp++));
// then, instead of exit, go to a jump
assertEquals(InstF99b.IbranchX | 2, targCtx.readChar(dp++));
// then the data
assertEquals(100, targCtx.readCell(dp)); dp+=2;
// and the DOES> redirect
assertEquals(InstF99b.IbranchW, targCtx.readChar(dp++));
assertEquals(doesDp, targCtx.findReloc(dp)); dp+=2;
*/
// the DOES> redirect
assertEquals(doesDp, targCtx.findReloc(dp)); dp+=2;
// then the data
assertEquals(100, targCtx.readCell(dp)); dp+=2;
// should be nothing weird after this
assertEquals(targCtx.getDP(), dp);
}
@Test
public void testStringLits() throws Exception {
startDP = 0x400;
parseString(
stockDictDefs+
compileLiteral+
compileMeta+
": s\" postpone (s\") ; immediate target-only\n"+
": lala s\" hi there\" ;\n"
);
dumpDict();
exportBinary();
parseString("lala");
DictEntry entry = (targCtx.require("lala")).getEntry();
int dp = entry.getContentAddr();
assertEquals(((ITargetWord)targCtx.require("(S\")")).getEntry().getContentAddr(), targCtx.findReloc(dp));
dp+=2;
/*
assertEquals(InstF99b.IcontextFrom, targCtx.readChar(dp++));
assertEquals(InstF99b.CTX_PC, targCtx.readChar(dp++));
assertEquals(InstF99b.IlitX | 5, targCtx.readChar(dp++));
assertEquals(InstF99b.Iadd, targCtx.readChar(dp++));
assertEquals(InstF99b.Idup, targCtx.readChar(dp++));
assertEquals(InstF99b.I1plus, targCtx.readChar(dp++));
assertEquals(InstF99b.Iswap, targCtx.readChar(dp++));
assertEquals(InstF99b.Icload, targCtx.readChar(dp++));
*/
assertEquals(8, targCtx.readChar(dp++));
assertEquals('h', targCtx.readChar(dp++));
assertEquals('i', targCtx.readChar(dp++));
assertEquals(' ', targCtx.readChar(dp++));
assertEquals('t', targCtx.readChar(dp++));
assertEquals('h', targCtx.readChar(dp++));
assertEquals('e', targCtx.readChar(dp++));
assertEquals('r', targCtx.readChar(dp++));
assertEquals('e', targCtx.readChar(dp++));
assertEquals(InstF99b.Iexit, targCtx.readChar(dp++));
}
}