summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--com.c13
-rwxr-xr-xrun_tests.sh53
-rw-r--r--tests/flet.bth7
-rw-r--r--tests/flet.out2
-rw-r--r--tests/iflet.bth8
-rw-r--r--tests/iflet.out1
-rw-r--r--tests/letstar.bth4
-rw-r--r--tests/sumrec.bth7
-rw-r--r--tests/sumrec.out2
-rw-r--r--tests/whilelet.bth11
-rw-r--r--tests/whilelet.out2
-rw-r--r--vm.c7
12 files changed, 94 insertions, 23 deletions
diff --git a/com.c b/com.c
index 695802a..2465777 100644
--- a/com.c
+++ b/com.c
@@ -180,18 +180,30 @@ void if_form(Compiler *C, AstVec l, Op _) {
// skip ->B
// A: if-false
// B:
+
+ int orig_stack_cur = C->stack_cur;
+
compile_node(C, l.vals[1]);
compile_opcode(C, OP_0BRANCH);
size_t ph_a = placeholder(C);
compile_node(C, l.vals[2]);
compile_opcode(C, OP_SKIP);
+
size_t ph_b = placeholder(C);
size_t dest_a = BYTECODE(C).len;
+ int stack_cur_a = C->stack_cur;
+ C->stack_cur = orig_stack_cur;
+
compile_node(C, l.vals[3]);
size_t dest_b = BYTECODE(C).len;
+ int stack_cur_b = C->stack_cur;
+
patch(C, ph_a, dest_a - ph_a - 2);
patch(C, ph_b, dest_b - ph_b - 2);
+
+ CHECK(stack_cur_a == stack_cur_b, "this should never happen");
+ CHECK(stack_cur_a == orig_stack_cur + 1, "this should never happen");
}
void while_form(Compiler *C, AstVec l, Op _) {
@@ -520,6 +532,7 @@ int main(int argc, char **argv) {
}
+
compile_opcode(&com, OP_HALT);
Thread th = thread_new(S);
diff --git a/run_tests.sh b/run_tests.sh
index 63b85aa..18885da 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -2,34 +2,47 @@
pass=0
fail=0
+skip=0
for testfile in tests/*.bth; do
outfile=${testfile%.bth}.out
- output="$(./bth $testfile 2>&1)"
- run_res=$?
- echo "$output" | diff $outfile - >/dev/null
- diff_res=$?
testname=${testfile#tests/}
testname=${testname%.bth}
- case $diff_res in
- 0) printf '\033[32m\033[1mPASS\033[0m %s\n' "$testname"
- pass=$((pass + 1)) ;;
- 1) printf '\033[31m\033[1mFAIL\033[0m %s\n' "$testname"
- printf "\tgot output: %s\n" "$(echo "$output" | head -n4)"
- printf "\texpected: "
- cat $outfile
- fail=$((fail + 1)) ;;
- esac
+ if [ ! -f "$outfile" ]; then
+ printf '\033[33mSKIP\033[0m %s (no output file)\n' "$testname"
+ skip=$((skip + 1))
+ else
+ output="$(./bth $testfile 2>&1)"
+ run_res=$?
+ echo "$output" | diff $outfile - >/dev/null
+ diff_res=$?
+ case $diff_res in
+ 0) printf '\033[32m\033[1mPASS\033[0m %s\n' "$testname"
+ pass=$((pass + 1)) ;;
+ 1) printf '\033[31m\033[1mFAIL\033[0m %s\n' "$testname"
+ printf "\tgot output: %s\n" "$(echo "$output" | head -n4)"
+ printf "\texpected: "
+ cat $outfile
+ fail=$((fail + 1)) ;;
+ esac
+ fi
done
echo
-printf "\033[32m%s\033[0m passed; " $pass
-if [ $fail -eq 0 ]; then
- printf "0 failed; "
-else
- printf "\033[31m%s\033[0m failed; " $fail
-fi
-printf "%s total\n" $((pass + fail))
+
+pnum () {
+ if [ $1 -eq 0 ]; then
+ printf "0 %s; " "$2"
+ else
+ printf "\033[3%dm%d\033[0m %s; " $3 $1 "$2"
+ fi
+}
+
+pnum $pass passed 2
+pnum $fail failed 1
+pnum $skip skipped 3
+
+printf "%s total\n" $((pass + fail + skip))
if [ $fail -eq 0 ]; then
exit 0
diff --git a/tests/flet.bth b/tests/flet.bth
new file mode 100644
index 0000000..102fc34
--- /dev/null
+++ b/tests/flet.bth
@@ -0,0 +1,7 @@
+(set f1 (fn (a b c) (say (* a (+ b c)))))
+(set f2 (fn (a) (say (* a a))))
+(if true
+ (f1 6 2 4)
+ (f2 7))
+(let (a 100 b 200 c 300)
+ (say b))
diff --git a/tests/flet.out b/tests/flet.out
new file mode 100644
index 0000000..7ba6bc8
--- /dev/null
+++ b/tests/flet.out
@@ -0,0 +1,2 @@
+36
+200
diff --git a/tests/iflet.bth b/tests/iflet.bth
new file mode 100644
index 0000000..b461a5f
--- /dev/null
+++ b/tests/iflet.bth
@@ -0,0 +1,8 @@
+(do
+ (if (< 2 3)
+ "yes"
+ "no")
+ (let (a 100
+ b 200
+ c 300)
+ (say b)))
diff --git a/tests/iflet.out b/tests/iflet.out
new file mode 100644
index 0000000..08839f6
--- /dev/null
+++ b/tests/iflet.out
@@ -0,0 +1 @@
+200
diff --git a/tests/letstar.bth b/tests/letstar.bth
new file mode 100644
index 0000000..03d4305
--- /dev/null
+++ b/tests/letstar.bth
@@ -0,0 +1,4 @@
+(say (let (a 100)
+ (let (a 200
+ b (/ a 10))
+ (+ a b))))
diff --git a/tests/sumrec.bth b/tests/sumrec.bth
new file mode 100644
index 0000000..8c8804a
--- /dev/null
+++ b/tests/sumrec.bth
@@ -0,0 +1,7 @@
+(set f' (fn (x acc)
+ (if (< x 1)
+ acc
+ (f' (- x 1) (+ acc x)))))
+(set f (fn (x) (f' x 0)))
+(say (f 10))
+(say (f 100))
diff --git a/tests/sumrec.out b/tests/sumrec.out
new file mode 100644
index 0000000..e613215
--- /dev/null
+++ b/tests/sumrec.out
@@ -0,0 +1,2 @@
+55
+5050
diff --git a/tests/whilelet.bth b/tests/whilelet.bth
new file mode 100644
index 0000000..ce8a482
--- /dev/null
+++ b/tests/whilelet.bth
@@ -0,0 +1,11 @@
+(do
+ (let (i 0
+ a [])
+ (while (< i 10)
+ (append a i)
+ (set i (+ i 1)))
+ (let (x 100
+ y 200
+ z 300)
+ (say y))
+ (say a)))
diff --git a/tests/whilelet.out b/tests/whilelet.out
new file mode 100644
index 0000000..013e367
--- /dev/null
+++ b/tests/whilelet.out
@@ -0,0 +1,2 @@
+200
+[ 0 1 2 3 4 5 6 7 8 9 ]
diff --git a/vm.c b/vm.c
index 023d2c3..500b4bf 100644
--- a/vm.c
+++ b/vm.c
@@ -177,12 +177,14 @@ int runvm(State *S) {
case OP_CALL: {
// nargs + 1 = function and args
uint8_t len = RBYTE();
-
+ uint8_t nargs = len - 1;
Val callee = PEEKN(len);
if (IS_FUNC(callee)) {
ObjFunc *func = AS_FUNC(callee);
+ CHECK(nargs == func->arity, "func needs exactly %d args, but got %d",func->arity,nargs);
+ CHECK(th->rsp < MAXDEPTH, "rstack overflow");
StackFrame *sf = &th->rstack[th->rsp++];
sf->ip = th->ip;
sf->ch = th->ch;
@@ -192,9 +194,8 @@ int runvm(State *S) {
th->ch = &func->ch;
th->fp = th->sp - len;
} else if (IS_CFUNC(callee)) {
- int nargs = len - 1;
Val *firstarg = &th->stack[th->sp - nargs];
- Val res = AS_CFUNC(callee)(S, len - 1, firstarg);
+ Val res = AS_CFUNC(callee)(S, nargs, firstarg);
th->sp -= len;
PUSH(res);
} else if (IS_ARR(callee)) {