- op = cd->byteCode[f->ip++];
- DBG(printf("Stack Depth: %d\n", ctx->opTop));
- DBG(printOpDEBUG(f->ip-1, op));
- switch(op) {
- case OP_POP:
- POP(ctx);
- break;
- case OP_DUP:
- PUSH(ctx, ctx->opStack[ctx->opTop-1]);
- break;
- case OP_XCHG:
- a = POP(ctx); b = POP(ctx);
- PUSH(ctx, a); PUSH(ctx, b);
- break;
- case OP_PLUS: case OP_MUL: case OP_DIV: case OP_MINUS:
- case OP_LT: case OP_LTE: case OP_GT: case OP_GTE:
- a = POP(ctx); b = POP(ctx);
- PUSH(ctx, evalBinaryNumeric(ctx, op, b, a));
- break;
- case OP_EQ: case OP_NEQ:
- a = POP(ctx); b = POP(ctx);
- PUSH(ctx, evalEquality(op, b, a));
- break;
- case OP_AND: case OP_OR:
- a = POP(ctx); b = POP(ctx);
- PUSH(ctx, evalAndOr(ctx, op, a, b));
- break;
- case OP_CAT:
- a = stringify(ctx, POP(ctx)); b = stringify(ctx, POP(ctx));
- c = naStr_concat(naNewString(ctx), b, a);
- PUSH(ctx, c);
- break;
- case OP_NEG:
- a = POP(ctx);
- PUSH(ctx, naNum(-numify(ctx, a)));
- break;
- case OP_NOT:
- a = POP(ctx);
- PUSH(ctx, naNum(boolify(ctx, a) ? 0 : 1));
- break;
- case OP_PUSHCONST:
- a = cd->constants[ARG16(cd->byteCode, f)];
- if(IS_CODE(a)) a = bindFunction(ctx, f, a);
- PUSH(ctx, a);
- break;
- case OP_PUSHONE:
- PUSH(ctx, naNum(1));
- break;
- case OP_PUSHZERO:
- PUSH(ctx, naNum(0));
- break;
- case OP_PUSHNIL:
- PUSH(ctx, naNil());
- break;
- case OP_NEWVEC:
- PUSH(ctx, naNewVector(ctx));
- break;
- case OP_VAPPEND:
- b = POP(ctx); a = TOP(ctx);
- naVec_append(a, b);
- break;
- case OP_NEWHASH:
- PUSH(ctx, naNewHash(ctx));
- break;
- case OP_HAPPEND:
- c = POP(ctx); b = POP(ctx); a = TOP(ctx); // a,b,c: hash, key, val
- naHash_set(a, b, c);
- break;
- case OP_LOCAL:
- a = getLocal(ctx, f, POP(ctx));
- PUSH(ctx, a);
- break;
- case OP_SETLOCAL:
- a = POP(ctx); b = POP(ctx);
- PUSH(ctx, setLocal(f, b, a));
- break;
- case OP_MEMBER:
- a = POP(ctx); b = POP(ctx);
- if(!getMember(ctx, b, a, &c))
- ERR(ctx, "no such member");
- PUSH(ctx, c);
- break;
- case OP_SETMEMBER:
- c = POP(ctx); b = POP(ctx); a = POP(ctx); // a,b,c: hash, key, val
- if(!IS_HASH(a)) ERR(ctx, "non-objects have no members");
- naHash_set(a, b, c);
- PUSH(ctx, c);
- break;
- case OP_INSERT:
- c = POP(ctx); b = POP(ctx); a = POP(ctx); // a,b,c: box, key, val
- containerSet(ctx, a, b, c);
- PUSH(ctx, c);
- break;
- case OP_EXTRACT:
- b = POP(ctx); a = POP(ctx); // a,b: box, key
- PUSH(ctx, containerGet(ctx, a, b));
- break;
- case OP_JMP:
- f->ip = ARG16(cd->byteCode, f);
- DBG(printf(" [Jump to: %d]\n", f->ip);)
- break;
- case OP_JIFNIL:
- arg = ARG16(cd->byteCode, f);
- a = TOP(ctx);
- if(IS_NIL(a)) {
- POP(ctx); // Pops **ONLY** if it's nil!
- f->ip = arg;
- DBG(printf(" [Jump to: %d]\n", f->ip);)
- }
- break;
- case OP_JIFNOT:
- arg = ARG16(cd->byteCode, f);
- if(!boolify(ctx, POP(ctx))) {
- f->ip = arg;
- DBG(printf(" [Jump to: %d]\n", f->ip);)
+static void evalSlice(naContext ctx, naRef src, naRef dst, naRef idx)
+{
+ if(!IS_VEC(src)) ERR(ctx, "cannot slice non-vector");
+ naVec_append(dst, naVec_get(src, checkVec(ctx, src, idx)));
+}
+
+static void evalSlice2(naContext ctx, naRef src, naRef dst,
+ naRef start, naRef endr)
+{
+ int i, end;
+ if(!IS_VEC(src)) ERR(ctx, "cannot slice non-vector");
+ end = vbound(ctx, src, endr, 1);
+ for(i = vbound(ctx, src, start, 0); i<=end; i++)
+ naVec_append(dst, naVec_get(src, i));
+}
+
+#define ARG() BYTECODE(cd)[f->ip++]
+#define CONSTARG() cd->constants[ARG()]
+#define POP() ctx->opStack[--ctx->opTop]
+#define STK(n) (ctx->opStack[ctx->opTop-(n)])
+#define SETFRAME(F) f = (F); cd = PTR(PTR(f->func).func->code).code;
+#define FIXFRAME() SETFRAME(&(ctx->fStack[ctx->fTop-1]))
+static naRef run(naContext ctx)
+{
+ struct Frame* f;
+ struct naCode* cd;
+ int op, arg;
+ naRef a, b;
+
+ ctx->dieArg = naNil();
+ ctx->error[0] = 0;
+
+ FIXFRAME();
+
+ while(1) {
+ op = BYTECODE(cd)[f->ip++];
+ DBG(printf("Stack Depth: %d\n", ctx->opTop));
+ DBG(printOpDEBUG(f->ip-1, op));
+ switch(op) {
+ case OP_POP: ctx->opTop--; break;
+ case OP_DUP: PUSH(STK(1)); break;
+ case OP_DUP2: PUSH(STK(2)); PUSH(STK(2)); break;
+ case OP_XCHG: a=STK(1); STK(1)=STK(2); STK(2)=a; break;
+ case OP_XCHG2: a=STK(1); STK(1)=STK(2); STK(2)=STK(3); STK(3)=a; break;
+
+#define BINOP(expr) do { \
+ double l = IS_NUM(STK(2)) ? STK(2).num : numify(ctx, STK(2)); \
+ double r = IS_NUM(STK(1)) ? STK(1).num : numify(ctx, STK(1)); \
+ SETNUM(STK(2), expr); \
+ ctx->opTop--; } while(0)
+
+ case OP_PLUS: BINOP(l + r); break;
+ case OP_MINUS: BINOP(l - r); break;
+ case OP_MUL: BINOP(l * r); break;
+ case OP_DIV: BINOP(l / r); break;
+ case OP_LT: BINOP(l < r ? 1 : 0); break;
+ case OP_LTE: BINOP(l <= r ? 1 : 0); break;
+ case OP_GT: BINOP(l > r ? 1 : 0); break;
+ case OP_GTE: BINOP(l >= r ? 1 : 0); break;
+#undef BINOP
+
+ case OP_EQ: case OP_NEQ:
+ STK(2) = evalEquality(op, STK(2), STK(1));
+ ctx->opTop--;
+ break;
+ case OP_CAT:
+ STK(2) = evalCat(ctx, STK(2), STK(1));
+ ctx->opTop--;
+ break;
+ case OP_NEG:
+ STK(1) = naNum(-numify(ctx, STK(1)));
+ break;
+ case OP_NOT:
+ STK(1) = naNum(boolify(ctx, STK(1)) ? 0 : 1);
+ break;
+ case OP_PUSHCONST:
+ a = CONSTARG();
+ if(IS_CODE(a)) a = bindFunction(ctx, f, a);
+ PUSH(a);
+ break;
+ case OP_PUSHONE:
+ PUSH(naNum(1));
+ break;
+ case OP_PUSHZERO:
+ PUSH(naNum(0));
+ break;
+ case OP_PUSHNIL:
+ PUSH(naNil());
+ break;
+ case OP_PUSHEND:
+ PUSH(endToken());
+ break;
+ case OP_NEWVEC:
+ PUSH(naNewVector(ctx));
+ break;
+ case OP_VAPPEND:
+ naVec_append(STK(2), STK(1));
+ ctx->opTop--;
+ break;
+ case OP_NEWHASH:
+ PUSH(naNewHash(ctx));
+ break;
+ case OP_HAPPEND:
+ naHash_set(STK(3), STK(2), STK(1));
+ ctx->opTop -= 2;
+ break;
+ case OP_LOCAL:
+ a = CONSTARG();
+ getLocal(ctx, f, &a, &b);
+ PUSH(b);
+ break;
+ case OP_SETSYM:
+ setSymbol(f, STK(1), STK(2));
+ ctx->opTop--;
+ break;
+ case OP_SETLOCAL:
+ naHash_set(f->locals, STK(1), STK(2));
+ ctx->opTop--;
+ break;
+ case OP_MEMBER:
+ getMember(ctx, STK(1), CONSTARG(), &STK(1), 64);
+ break;
+ case OP_SETMEMBER:
+ if(!IS_HASH(STK(2))) ERR(ctx, "non-objects have no members");
+ naHash_set(STK(2), STK(1), STK(3));
+ ctx->opTop -= 2;
+ break;
+ case OP_INSERT:
+ containerSet(ctx, STK(2), STK(1), STK(3));
+ ctx->opTop -= 2;
+ break;
+ case OP_EXTRACT:
+ STK(2) = containerGet(ctx, STK(2), STK(1));
+ ctx->opTop--;
+ break;
+ case OP_SLICE:
+ evalSlice(ctx, STK(3), STK(2), STK(1));
+ ctx->opTop--;
+ break;
+ case OP_SLICE2:
+ evalSlice2(ctx, STK(4), STK(3), STK(2), STK(1));
+ ctx->opTop -= 2;
+ break;
+ case OP_JMPLOOP:
+ // Identical to JMP, except for locking
+ naCheckBottleneck();
+ f->ip = BYTECODE(cd)[f->ip];
+ DBG(printf(" [Jump to: %d]\n", f->ip));
+ break;
+ case OP_JMP:
+ f->ip = BYTECODE(cd)[f->ip];
+ DBG(printf(" [Jump to: %d]\n", f->ip));
+ break;
+ case OP_JIFEND:
+ arg = ARG();
+ if(IS_END(STK(1))) {
+ ctx->opTop--; // Pops **ONLY** if it's nil!
+ f->ip = arg;
+ DBG(printf(" [Jump to: %d]\n", f->ip));
+ }
+ break;
+ case OP_JIFTRUE:
+ arg = ARG();
+ if(boolify(ctx, STK(1))) {
+ f->ip = arg;
+ DBG(printf(" [Jump to: %d]\n", f->ip));
+ }
+ break;
+ case OP_JIFNOT:
+ arg = ARG();
+ if(!boolify(ctx, STK(1))) {
+ f->ip = arg;
+ DBG(printf(" [Jump to: %d]\n", f->ip));
+ }
+ break;
+ case OP_JIFNOTPOP:
+ arg = ARG();
+ if(!boolify(ctx, POP())) {
+ f->ip = arg;
+ DBG(printf(" [Jump to: %d]\n", f->ip));
+ }
+ break;
+ case OP_FCALL: SETFRAME(setupFuncall(ctx, ARG(), 0, 0)); break;
+ case OP_MCALL: SETFRAME(setupFuncall(ctx, ARG(), 1, 0)); break;
+ case OP_FCALLH: SETFRAME(setupFuncall(ctx, 1, 0, 1)); break;
+ case OP_MCALLH: SETFRAME(setupFuncall(ctx, 1, 1, 1)); break;
+ case OP_RETURN:
+ a = STK(1);
+ ctx->dieArg = naNil();
+ if(ctx->callChild) naFreeContext(ctx->callChild);
+ if(--ctx->fTop <= 0) return a;
+ ctx->opTop = f->bp + 1; // restore the correct opstack frame!
+ STK(1) = a;
+ FIXFRAME();
+ break;
+ case OP_EACH:
+ evalEach(ctx, 0);
+ break;
+ case OP_INDEX:
+ evalEach(ctx, 1);
+ break;
+ case OP_MARK: // save stack state (e.g. "setjmp")
+ if(ctx->markTop >= MAX_MARK_DEPTH)
+ ERR(ctx, "mark stack overflow");
+ ctx->markStack[ctx->markTop++] = ctx->opTop;
+ break;
+ case OP_UNMARK: // pop stack state set by mark
+ ctx->markTop--;
+ break;
+ case OP_BREAK: // restore stack state (FOLLOW WITH JMP!)
+ ctx->opTop = ctx->markStack[ctx->markTop-1];
+ break;
+ case OP_BREAK2: // same, but also pop the mark stack
+ ctx->opTop = ctx->markStack[--ctx->markTop];
+ break;
+ case OP_UNPACK:
+ evalUnpack(ctx, ARG());
+ break;
+ default:
+ ERR(ctx, "BUG: bad opcode");