UNLOCK();
}
-#if 0
-/*
- * This is the original code which might not work properly on all
- * platforms since it allows one to work on the same variable in one
- * statement without the prior knowledge how this will behave.
- *
- * e.g. ctx->opStack[ctx->opTop++] = ctx->opStack[ctx->opTop-1];
- * ^^^^^ ^^^^^
- */
-# define PUSH(r) do { \
+// Note that opTop is incremented separately, to avoid situations
+// where the "r" expression also references opTop. The SGI compiler
+// is known to have issues with such code.
+#define PUSH(r) do { \
if(ctx->opTop >= MAX_STACK_DEPTH) ERR(ctx, "stack overflow"); \
- ctx->opStack[ctx->opTop++] = r; \
+ ctx->opStack[ctx->opTop] = r; \
+ ctx->opTop++; \
} while(0)
-#else
-
-# define PUSH(r) _PUSH((ctx), (r))
-void _PUSH(struct Context* ctx, naRef r) {
- if(ctx->opTop >= MAX_STACK_DEPTH) ERR(ctx, "stack overflow");
- ctx->opStack[ctx->opTop++] = r;
-}
-#endif
-
static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
{
int i;
}
// OP_EACH works like a vector get, except that it leaves the vector
-// and index on the stack, increments the index after use, and pops
-// the arguments and pushes a nil if the index is beyond the end.
+// and index on the stack, increments the index after use, and
+// pushes a nil if the index is beyond the end.
static void evalEach(struct Context* ctx, int useIndex)
{
int idx = (int)(ctx->opStack[ctx->opTop-1].num);
naRef vec = ctx->opStack[ctx->opTop-2];
if(!IS_VEC(vec)) naRuntimeError(ctx, "foreach enumeration of non-vector");
if(!vec.ref.ptr.vec->rec || idx >= vec.ref.ptr.vec->rec->size) {
- ctx->opTop -= 2; // pop two values
PUSH(naNil());
return;
}
case OP_BREAK: // restore stack state (FOLLOW WITH JMP!)
ctx->opTop = ctx->markStack[--ctx->markTop];
break;
+ case OP_CONTINUE: // same, but don't modify markTop
+ ctx->opTop = ctx->markStack[ctx->markTop-1];
+ break;
default:
ERR(ctx, "BUG: bad opcode");
}
OP_DUP, OP_XCHG, OP_INSERT, OP_EXTRACT, OP_MEMBER, OP_SETMEMBER,
OP_LOCAL, OP_SETLOCAL, OP_NEWVEC, OP_VAPPEND, OP_NEWHASH, OP_HAPPEND,
OP_MARK, OP_UNMARK, OP_BREAK, OP_FTAIL, OP_MTAIL, OP_SETSYM, OP_DUP2,
- OP_INDEX
+ OP_INDEX, OP_CONTINUE
};
struct Frame {
vec = RIGHT(h);
body = RIGHT(t)->children;
- pushLoop(p, label);
genExpr(p, vec);
emit(p, OP_PUSHZERO);
+ pushLoop(p, label);
loopTop = p->cg->codesz;
emit(p, t->type == TOK_FOREACH ? OP_EACH : OP_INDEX);
jumpEnd = emitJump(p, OP_JIFNIL);
emit(p, assignOp);
emit(p, OP_POP);
genLoop(p, body, 0, label, loopTop, jumpEnd);
+ emit(p, OP_POP); // Pull off the vector and index
+ emit(p, OP_POP);
}
static int tokMatch(struct Token* a, struct Token* b)
bp = p->cg->loops[p->cg->loopTop - levels].breakIP;
cp = p->cg->loops[p->cg->loopTop - levels].contIP;
for(i=0; i<levels; i++)
- emit(p, OP_BREAK);
+ emit(p, (t->type == TOK_BREAK || i>0) ? OP_BREAK : OP_CONTINUE);
if(t->type == TOK_BREAK)
emit(p, OP_PUSHNIL); // breakIP is always a JIFNOT/JIFNIL!
emitImmediate(p, OP_JMP, t->type == TOK_BREAK ? bp : cp);
static void freeelem(struct naPool* p, struct naObj* o)
{
- // Free any intrinsic (i.e. non-garbage collected) storage the
- // object might have
+ // Clean up any intrinsic storage the object might have...
switch(p->type) {
- case T_STR:
- naStr_gcclean((struct naStr*)o);
- break;
- case T_VEC:
- naVec_gcclean((struct naVec*)o);
- break;
- case T_HASH:
- naHash_gcclean((struct naHash*)o);
- break;
- case T_CODE:
- naCode_gcclean((struct naCode*)o);
- break;
- case T_GHOST:
- naGhost_gcclean((struct naGhost*)o);
- break;
+ case T_STR: naStr_gcclean ((struct naStr*) o); break;
+ case T_VEC: naVec_gcclean ((struct naVec*) o); break;
+ case T_HASH: naHash_gcclean ((struct naHash*) o); break;
+ case T_CODE: naCode_gcclean ((struct naCode*) o); break;
+ case T_GHOST: naGhost_gcclean((struct naGhost*)o); break;
}
-
- // And add it to the free list
- p->free[p->nfree++] = o;
+ p->free[p->nfree++] = o; // ...and add it to the free list
}
static void newBlock(struct naPool* p, int need)
nlen = argc > 2 ? naNumValue(args[2]) : naNil();
if(!naIsNil(nlen))
len = (int)nlen.num;
- if(!naIsVector(v) || start < 0 || start >= naVec_size(v) || len < 0)
+ if(!naIsVector(v) || start < 0 || start > naVec_size(v) || len < 0)
return naNil();
if(naIsNil(nlen) || len > naVec_size(v) - start)
len = naVec_size(v) - start;
int errLine;
naRef script, code, fname;
script = argc > 0 ? args[0] : naNil();
- if(!naIsString(script)) return naNil();
- fname = NEWCSTR(c, "<compile>");
+ fname = argc > 1 ? args[1] : NEWCSTR(c, "<compile>");
+ if(!naIsString(script) || !naIsString(fname)) return naNil();
code = naParseCode(c, fname, 1,
naStr_data(script), naStr_len(script), &errLine);
if(!naIsCode(code)) return naNil(); // FIXME: export error to caller...
callme, callns);
c->callChild = 0;
if(argc > 2 && IS_VEC(args[argc-1])) {
- if(!IS_NIL(subc->dieArg)) naVec_append(args[argc-1], subc->dieArg);
+ naRef v = args[argc-1];
+ if(!IS_NIL(subc->dieArg)) naVec_append(v, subc->dieArg);
else if(naGetError(subc))
- naVec_append(args[argc-1], NEWCSTR(subc, naGetError(subc)));
+ naVec_append(v, NEWCSTR(subc, naGetError(subc)));
+ if(naVec_size(v)) {
+ int i, sd = naStackDepth(subc);
+ for(i=0; i<sd; i++) {
+ naVec_append(v, naGetSourceFile(subc, i));
+ naVec_append(v, naNum(naGetLine(subc, i)));
+ }
+ }
}
naFreeContext(subc);
return result;
static naRef f_closure(naContext ctx, naRef me, int argc, naRef* args)
{
int i;
- naRef func, idx;
struct naFunc* f;
- func = argc > 0 ? args[0] : naNil();
- idx = argc > 1 ? naNumValue(args[1]) : naNil();
+ naRef func = argc > 0 ? args[0] : naNil();
+ naRef idx = argc > 1 ? naNumValue(args[1]) : naNum(0);
if(!IS_FUNC(func) || IS_NIL(idx))
naRuntimeError(ctx, "bad arguments to closure()");
i = (int)idx.num;
return vr;
}
-static void vecrealloc(struct naVec* v)
+static void resize(struct naVec* v)
{
struct VecRec* vr = newvecrec(v->rec);
naGC_swapfree((void**)&(v->rec), vr);
if(IS_VEC(vec)) {
struct VecRec* r = vec.ref.ptr.vec->rec;
while(!r || r->size >= r->alloced) {
- vecrealloc(vec.ref.ptr.vec);
+ resize(vec.ref.ptr.vec);
r = vec.ref.ptr.vec->rec;
}
r->array[r->size] = o;
o = v->array[v->size - 1];
v->size--;
if(v->size < (v->alloced >> 1))
- vecrealloc(vec.ref.ptr.vec);
+ resize(vec.ref.ptr.vec);
return o;
}
return naNil();