00001 #include <stdio.h>
00002 #include <stdarg.h>
00003 #include <string.h>
00004 #include "nasal.h"
00005 #include "code.h"
00006
00008
00010
00011 #if !defined(INTERPRETER_DUMP)
00012 # define DBG(expr)
00013 #else
00014 # define DBG(expr) expr
00015 # include <stdio.h>
00016 # include <stdlib.h>
00017 #endif
00018 char* opStringDEBUG(int op);
00019 void printOpDEBUG(int ip, int op);
00020 void printStackDEBUG(struct Context* ctx);
00022
00023 #ifdef _MSC_VER
00024 #define vsnprintf _vsnprintf
00025 #endif
00026
00027 struct Globals* globals = 0;
00028
00029 static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code);
00030
00031 #define ERR(c, msg) naRuntimeError((c),(msg))
00032 void naRuntimeError(struct Context* c, const char* fmt, ...)
00033 {
00034 va_list ap;
00035 va_start(ap, fmt);
00036 vsnprintf(c->error, sizeof(c->error), fmt, ap);
00037 va_end(ap);
00038 longjmp(c->jumpHandle, 1);
00039 }
00040
00041 void naRethrowError(naContext subc)
00042 {
00043 strncpy(subc->callParent->error, subc->error, sizeof(subc->error));
00044 subc->callParent->dieArg = subc->dieArg;
00045 longjmp(subc->callParent->jumpHandle, 1);
00046 }
00047
00048 #define END_PTR ((void*)1)
00049 #define IS_END(r) (IS_REF((r)) && PTR((r)).obj == END_PTR)
00050 static naRef endToken()
00051 {
00052 naRef r;
00053 SETPTR(r, END_PTR);
00054 return r;
00055 }
00056
00057 static int boolify(struct Context* ctx, naRef r)
00058 {
00059 if(IS_NUM(r)) return r.num != 0;
00060 if(IS_NIL(r) || IS_END(r)) return 0;
00061 if(IS_STR(r)) {
00062 double d;
00063 if(naStr_len(r) == 0) return 0;
00064 if(naStr_tonum(r, &d)) return d != 0;
00065 else return 1;
00066 }
00067 ERR(ctx, "non-scalar used in boolean context");
00068 return 0;
00069 }
00070
00071 static double numify(struct Context* ctx, naRef o)
00072 {
00073 double n;
00074 if(IS_NUM(o)) return o.num;
00075 else if(IS_NIL(o)) ERR(ctx, "nil used in numeric context");
00076 else if(!IS_STR(o)) ERR(ctx, "non-scalar in numeric context");
00077 else if(naStr_tonum(o, &n)) return n;
00078 else ERR(ctx, "non-numeric string in numeric context");
00079 return 0;
00080 }
00081
00082 static naRef stringify(struct Context* ctx, naRef r)
00083 {
00084 if(IS_STR(r)) return r;
00085 if(IS_NUM(r)) return naStr_fromnum(naNewString(ctx), r.num);
00086 ERR(ctx, "non-scalar in string context");
00087 return naNil();
00088 }
00089
00090 static int checkVec(struct Context* ctx, naRef vec, naRef idx)
00091 {
00092 int i = (int)numify(ctx, idx);
00093 if(i < 0) i += naVec_size(vec);
00094 if(i < 0 || i >= naVec_size(vec))
00095 naRuntimeError(ctx, "vector index %d out of bounds (size: %d)",
00096 i, naVec_size(vec));
00097 return i;
00098 }
00099
00100 static int checkStr(struct Context* ctx, naRef str, naRef idx)
00101 {
00102 int i = (int)numify(ctx, idx);
00103 if(i < 0) i += naStr_len(str);
00104 if(i < 0 || i >= naStr_len(str))
00105 naRuntimeError(ctx, "string index %d out of bounds (size: %d)",
00106 i, naStr_len(str));
00107 return i;
00108 }
00109
00110 static naRef containerGet(struct Context* ctx, naRef box, naRef key)
00111 {
00112 naRef result = naNil();
00113 if(!IS_SCALAR(key)) ERR(ctx, "container index not scalar");
00114 if(IS_HASH(box)) {
00115 naHash_get(box, key, &result);
00116 } else if(IS_VEC(box)) {
00117 result = naVec_get(box, checkVec(ctx, box, key));
00118 } else if(IS_STR(box)) {
00119 result = naNum((unsigned char)naStr_data(box)[checkStr(ctx, box, key)]);
00120 } else {
00121 ERR(ctx, "extract from non-container");
00122 }
00123 return result;
00124 }
00125
00126 static void containerSet(struct Context* ctx, naRef box, naRef key, naRef val)
00127 {
00128 if(!IS_SCALAR(key)) ERR(ctx, "container index not scalar");
00129 else if(IS_HASH(box)) naHash_set(box, key, val);
00130 else if(IS_VEC(box)) naVec_set(box, checkVec(ctx, box, key), val);
00131 else if(IS_STR(box)) {
00132 if(PTR(box).str->hashcode)
00133 ERR(ctx, "cannot change immutable string");
00134 naStr_data(box)[checkStr(ctx, box, key)] = (char)numify(ctx, val);
00135 } else ERR(ctx, "insert into non-container");
00136 }
00137
00138 static void initTemps(struct Context* c)
00139 {
00140 c->tempsz = 4;
00141 c->temps = naAlloc(c->tempsz * sizeof(struct naObj*));
00142 c->ntemps = 0;
00143 }
00144
00145 static void initContext(struct Context* c)
00146 {
00147 int i;
00148 c->fTop = c->opTop = c->markTop = 0;
00149 for(i=0; i<NUM_NASAL_TYPES; i++)
00150 c->nfree[i] = 0;
00151
00152 if(c->tempsz > 32) {
00153 naFree(c->temps);
00154 initTemps(c);
00155 }
00156
00157 c->callParent = 0;
00158 c->callChild = 0;
00159 c->dieArg = naNil();
00160 c->error[0] = 0;
00161 c->userData = 0;
00162 }
00163
00164 static void initGlobals()
00165 {
00166 int i;
00167 struct Context* c;
00168 globals = (struct Globals*)naAlloc(sizeof(struct Globals));
00169 naBZero(globals, sizeof(struct Globals));
00170
00171 globals->sem = naNewSem();
00172 globals->lock = naNewLock();
00173
00174 globals->allocCount = 256;
00175 for(i=0; i<NUM_NASAL_TYPES; i++)
00176 naGC_init(&(globals->pools[i]), i);
00177 globals->deadsz = 256;
00178 globals->ndead = 0;
00179 globals->deadBlocks = naAlloc(sizeof(void*) * globals->deadsz);
00180
00181
00182 globals->freeContexts = 0;
00183 globals->allContexts = 0;
00184 c = naNewContext();
00185
00186 globals->symbols = naNewHash(c);
00187 globals->save = naNewVector(c);
00188
00189
00190 globals->meRef = naInternSymbol(naStr_fromdata(naNewString(c), "me", 2));
00191 globals->argRef = naInternSymbol(naStr_fromdata(naNewString(c), "arg", 3));
00192 globals->parentsRef = naInternSymbol(naStr_fromdata(naNewString(c), "parents", 7));
00193
00194 naFreeContext(c);
00195 }
00196
00197 struct Context* naNewContext()
00198 {
00199 struct Context* c;
00200 if(globals == 0)
00201 initGlobals();
00202
00203 LOCK();
00204 c = globals->freeContexts;
00205 if(c) {
00206 globals->freeContexts = c->nextFree;
00207 c->nextFree = 0;
00208 UNLOCK();
00209 initContext(c);
00210 } else {
00211 UNLOCK();
00212 c = (struct Context*)naAlloc(sizeof(struct Context));
00213 initTemps(c);
00214 initContext(c);
00215 LOCK();
00216 c->nextAll = globals->allContexts;
00217 c->nextFree = 0;
00218 globals->allContexts = c;
00219 UNLOCK();
00220 }
00221 return c;
00222 }
00223
00224 struct Context* naSubContext(struct Context* super)
00225 {
00226 struct Context* ctx = naNewContext();
00227 if(super->callChild) naFreeContext(super->callChild);
00228 ctx->callParent = super;
00229 super->callChild = ctx;
00230 return ctx;
00231 }
00232
00233 void naFreeContext(struct Context* c)
00234 {
00235 c->ntemps = 0;
00236 if(c->callChild) naFreeContext(c->callChild);
00237 if(c->callParent) c->callParent->callChild = 0;
00238 LOCK();
00239 c->nextFree = globals->freeContexts;
00240 globals->freeContexts = c;
00241 UNLOCK();
00242 }
00243
00244
00245
00246
00247 #define PUSH(r) do { \
00248 if(ctx->opTop >= MAX_STACK_DEPTH) ERR(ctx, "stack overflow"); \
00249 ctx->opStack[ctx->opTop] = r; \
00250 ctx->opTop++; \
00251 } while(0)
00252
00253 static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs)
00254 {
00255 int i;
00256 struct naCode* c = PTR(PTR(f->func).func->code).code;
00257
00258
00259 if(nargs < c->nArgs)
00260 naRuntimeError(ctx, "too few function args (have %d need %d)",
00261 nargs, c->nArgs);
00262 for(i=0; i<c->nArgs; i++)
00263 naHash_newsym(PTR(f->locals).hash,
00264 &c->constants[c->argSyms[i]], &args[i]);
00265 args += c->nArgs;
00266 nargs -= c->nArgs;
00267 for(i=0; i<c->nOptArgs; i++, nargs--) {
00268 naRef val = nargs > 0 ? args[i] : c->constants[c->optArgVals[i]];
00269 if(IS_CODE(val))
00270 val = bindFunction(ctx, &ctx->fStack[ctx->fTop-2], val);
00271 naHash_newsym(PTR(f->locals).hash, &c->constants[c->optArgSyms[i]],
00272 &val);
00273 }
00274 args += c->nOptArgs;
00275 if(c->needArgVector || nargs > 0) {
00276 naRef argsv = naNewVector(ctx);
00277 naVec_setsize(argsv, nargs > 0 ? nargs : 0);
00278 for(i=0; i<nargs; i++)
00279 PTR(argsv).vec->rec->array[i] = *args++;
00280 naHash_newsym(PTR(f->locals).hash, &c->restArgSym, &argsv);
00281 }
00282 }
00283
00284 static struct Frame* setupFuncall(struct Context* ctx, int nargs, int mcall)
00285 {
00286 naRef *frame;
00287 struct Frame* f;
00288
00289 DBG(printf("setupFuncall(nargs:%d, mcall:%d)\n", nargs, mcall);)
00290
00291 frame = &ctx->opStack[ctx->opTop - nargs - 1];
00292 if(!IS_FUNC(frame[0]))
00293 ERR(ctx, "function/method call invoked on uncallable object");
00294
00295 ctx->opFrame = ctx->opTop - (nargs + 1 + mcall);
00296
00297
00298 if(PTR(PTR(frame[0]).func->code).obj->type == T_CCODE) {
00299 naRef obj = mcall ? frame[-1] : naNil();
00300 naCFunction fp = PTR(PTR(frame[0]).func->code).ccode->fptr;
00301 naRef result = (*fp)(ctx, obj, nargs, frame + 1);
00302 ctx->opTop = ctx->opFrame;
00303 PUSH(result);
00304 return &(ctx->fStack[ctx->fTop-1]);
00305 }
00306
00307 if(ctx->fTop >= MAX_RECURSION) ERR(ctx, "call stack overflow");
00308
00309
00310
00311
00312 f = &(ctx->fStack[ctx->fTop++]);
00313 f->locals = f->func = naNil();
00314 f->locals = naNewHash(ctx);
00315 f->func = frame[0];
00316 f->ip = 0;
00317 f->bp = ctx->opFrame;
00318
00319 if(mcall)
00320 naHash_set(f->locals, globals->meRef, frame[-1]);
00321
00322 setupArgs(ctx, f, frame+1, nargs);
00323
00324 ctx->opTop = f->bp;
00325 DBG(printf("Entering frame %d with %d args\n", ctx->fTop-1, nargs);)
00326 return f;
00327 }
00328
00329 static naRef evalEquality(int op, naRef ra, naRef rb)
00330 {
00331 int result = naEqual(ra, rb);
00332 return naNum((op==OP_EQ) ? result : !result);
00333 }
00334
00335 static naRef evalCat(naContext ctx, naRef l, naRef r)
00336 {
00337 if(IS_VEC(l) && IS_VEC(r)) {
00338 int i, ls = naVec_size(l), rs = naVec_size(r);
00339 naRef v = naNewVector(ctx);
00340 naVec_setsize(v, ls + rs);
00341 for(i=0; i<ls; i+=1) naVec_set(v, i, naVec_get(l, i));
00342 for(i=0; i<rs; i+=1) naVec_set(v, i+ls, naVec_get(r, i));
00343 return v;
00344 } else {
00345 naRef a = stringify(ctx, l);
00346 naRef b = stringify(ctx, r);
00347 return naStr_concat(naNewString(ctx), a, b);
00348 }
00349 }
00350
00351
00352
00353 static naRef bindFunction(struct Context* ctx, struct Frame* f, naRef code)
00354 {
00355 naRef result = naNewFunc(ctx, code);
00356 PTR(result).func->namespace = f->locals;
00357 PTR(result).func->next = f->func;
00358 return result;
00359 }
00360
00361 static int getClosure(struct naFunc* c, naRef sym, naRef* result)
00362 {
00363 while(c) {
00364 if(naHash_get(c->namespace, sym, result)) return 1;
00365 c = PTR(c->next).func;
00366 }
00367 return 0;
00368 }
00369
00370 static naRef getLocal2(struct Context* ctx, struct Frame* f, naRef sym)
00371 {
00372 naRef result;
00373 if(!naHash_get(f->locals, sym, &result))
00374 if(!getClosure(PTR(f->func).func, sym, &result))
00375 naRuntimeError(ctx, "undefined symbol: %s", naStr_data(sym));
00376 return result;
00377 }
00378
00379 static void getLocal(struct Context* ctx, struct Frame* f,
00380 naRef* sym, naRef* out)
00381 {
00382 struct naFunc* func;
00383 struct naStr* str = PTR(*sym).str;
00384 if(naHash_sym(PTR(f->locals).hash, str, out))
00385 return;
00386 func = PTR(f->func).func;
00387 while(func && PTR(func->namespace).hash) {
00388 if(naHash_sym(PTR(func->namespace).hash, str, out))
00389 return;
00390 func = PTR(func->next).func;
00391 }
00392
00393
00394
00395
00396 *out = getLocal2(ctx, f, *sym);
00397 }
00398
00399 static int setClosure(naRef func, naRef sym, naRef val)
00400 {
00401 struct naFunc* c = PTR(func).func;
00402 if(c == 0) { return 0; }
00403 else if(naHash_tryset(c->namespace, sym, val)) { return 1; }
00404 else { return setClosure(c->next, sym, val); }
00405 }
00406
00407 static naRef setSymbol(struct Frame* f, naRef sym, naRef val)
00408 {
00409
00410
00411 if(!naHash_tryset(f->locals, sym, val))
00412 if(!setClosure(f->func, sym, val))
00413 naHash_set(f->locals, sym, val);
00414 return val;
00415 }
00416
00417
00418
00419
00420
00421 static const char* getMember_r(naRef obj, naRef field, naRef* out, int count)
00422 {
00423 int i;
00424 naRef p;
00425 struct VecRec* pv;
00426 if(--count < 0) return "too many parents";
00427 if(!IS_HASH(obj)) return 0;
00428 if(naHash_get(obj, field, out)) return "";
00429 if(!naHash_get(obj, globals->parentsRef, &p)) return 0;
00430 if(!IS_VEC(p)) return "object \"parents\" field not vector";
00431 pv = PTR(p).vec->rec;
00432 for(i=0; i<pv->size; i++) {
00433 const char* err = getMember_r(pv->array[i], field, out, count);
00434 if(err) return err;
00435 }
00436 return 0;
00437 }
00438
00439 static void getMember(struct Context* ctx, naRef obj, naRef fld,
00440 naRef* result, int count)
00441 {
00442 const char* err = getMember_r(obj, fld, result, count);
00443 if(!err) naRuntimeError(ctx, "No such member: %s", naStr_data(fld));
00444 if(err[0]) naRuntimeError(ctx, err);
00445 }
00446
00447 int naMember_get(naRef obj, naRef field, naRef* out)
00448 {
00449 const char* err = getMember_r(obj, field, out, 64);
00450 return err && !err[0];
00451 }
00452
00453
00454
00455
00456 static void evalEach(struct Context* ctx, int useIndex)
00457 {
00458 int idx = (int)(ctx->opStack[ctx->opTop-1].num);
00459 naRef vec = ctx->opStack[ctx->opTop-2];
00460 if(!IS_VEC(vec)) ERR(ctx, "foreach enumeration of non-vector");
00461 if(!PTR(vec).vec->rec || idx >= PTR(vec).vec->rec->size) {
00462 PUSH(endToken());
00463 return;
00464 }
00465 ctx->opStack[ctx->opTop-1].num = idx+1;
00466 PUSH(useIndex ? naNum(idx) : naVec_get(vec, idx));
00467 }
00468
00469 #define ARG() cd->byteCode[f->ip++]
00470 #define CONSTARG() cd->constants[ARG()]
00471 #define POP() ctx->opStack[--ctx->opTop]
00472 #define STK(n) (ctx->opStack[ctx->opTop-(n)])
00473 #define FIXFRAME() f = &(ctx->fStack[ctx->fTop-1]); \
00474 cd = PTR(PTR(f->func).func->code).code;
00475 static naRef run(struct Context* ctx)
00476 {
00477 struct Frame* f;
00478 struct naCode* cd;
00479 int op, arg;
00480 naRef a, b;
00481
00482 ctx->dieArg = naNil();
00483 ctx->error[0] = 0;
00484
00485 FIXFRAME();
00486
00487 while(1) {
00488 op = cd->byteCode[f->ip++];
00489 DBG(printf("Stack Depth: %d\n", ctx->opTop));
00490 DBG(printOpDEBUG(f->ip-1, op));
00491 switch(op) {
00492 case OP_POP:
00493 ctx->opTop--;
00494 break;
00495 case OP_DUP:
00496 PUSH(ctx->opStack[ctx->opTop-1]);
00497 break;
00498 case OP_DUP2:
00499 PUSH(ctx->opStack[ctx->opTop-2]);
00500 PUSH(ctx->opStack[ctx->opTop-2]);
00501 break;
00502 case OP_XCHG:
00503 a = STK(1); STK(1) = STK(2); STK(2) = a;
00504 break;
00505
00506 #define BINOP(expr) do { \
00507 double l = IS_NUM(STK(2)) ? STK(2).num : numify(ctx, STK(2)); \
00508 double r = IS_NUM(STK(1)) ? STK(1).num : numify(ctx, STK(1)); \
00509 SETNUM(STK(2), expr); \
00510 ctx->opTop--; } while(0)
00511
00512 case OP_PLUS: BINOP(l + r); break;
00513 case OP_MINUS: BINOP(l - r); break;
00514 case OP_MUL: BINOP(l * r); break;
00515 case OP_DIV: BINOP(l / r); break;
00516 case OP_LT: BINOP(l < r ? 1 : 0); break;
00517 case OP_LTE: BINOP(l <= r ? 1 : 0); break;
00518 case OP_GT: BINOP(l > r ? 1 : 0); break;
00519 case OP_GTE: BINOP(l >= r ? 1 : 0); break;
00520 #undef BINOP
00521
00522 case OP_EQ: case OP_NEQ:
00523 STK(2) = evalEquality(op, STK(2), STK(1));
00524 ctx->opTop--;
00525 break;
00526 case OP_CAT:
00527 STK(2) = evalCat(ctx, STK(2), STK(1));
00528 ctx->opTop -= 1;
00529 break;
00530 case OP_NEG:
00531 STK(1) = naNum(-numify(ctx, STK(1)));
00532 break;
00533 case OP_NOT:
00534 STK(1) = naNum(boolify(ctx, STK(1)) ? 0 : 1);
00535 break;
00536 case OP_PUSHCONST:
00537 a = CONSTARG();
00538 if(IS_CODE(a)) a = bindFunction(ctx, f, a);
00539 PUSH(a);
00540 break;
00541 case OP_PUSHONE:
00542 PUSH(naNum(1));
00543 break;
00544 case OP_PUSHZERO:
00545 PUSH(naNum(0));
00546 break;
00547 case OP_PUSHNIL:
00548 PUSH(naNil());
00549 break;
00550 case OP_PUSHEND:
00551 PUSH(endToken());
00552 break;
00553 case OP_NEWVEC:
00554 PUSH(naNewVector(ctx));
00555 break;
00556 case OP_VAPPEND:
00557 naVec_append(STK(2), STK(1));
00558 ctx->opTop--;
00559 break;
00560 case OP_NEWHASH:
00561 PUSH(naNewHash(ctx));
00562 break;
00563 case OP_HAPPEND:
00564 naHash_set(STK(3), STK(2), STK(1));
00565 ctx->opTop -= 2;
00566 break;
00567 case OP_LOCAL:
00568 a = CONSTARG();
00569 getLocal(ctx, f, &a, &b);
00570 PUSH(b);
00571 break;
00572 case OP_SETSYM:
00573 STK(2) = setSymbol(f, STK(2), STK(1));
00574 ctx->opTop--;
00575 break;
00576 case OP_SETLOCAL:
00577 naHash_set(f->locals, STK(2), STK(1));
00578 STK(2) = STK(1);
00579 ctx->opTop--;
00580 break;
00581 case OP_MEMBER:
00582 getMember(ctx, STK(1), CONSTARG(), &STK(1), 64);
00583 break;
00584 case OP_SETMEMBER:
00585 if(!IS_HASH(STK(3))) ERR(ctx, "non-objects have no members");
00586 naHash_set(STK(3), STK(2), STK(1));
00587 STK(3) = STK(1);
00588 ctx->opTop -= 2;
00589 break;
00590 case OP_INSERT:
00591 containerSet(ctx, STK(3), STK(2), STK(1));
00592 STK(3) = STK(1);
00593 ctx->opTop -= 2;
00594 break;
00595 case OP_EXTRACT:
00596 STK(2) = containerGet(ctx, STK(2), STK(1));
00597 ctx->opTop--;
00598 break;
00599 case OP_JMPLOOP:
00600
00601 naCheckBottleneck();
00602 f->ip = cd->byteCode[f->ip];
00603 DBG(printf(" [Jump to: %d]\n", f->ip);)
00604 break;
00605 case OP_JMP:
00606 f->ip = cd->byteCode[f->ip];
00607 DBG(printf(" [Jump to: %d]\n", f->ip);)
00608 break;
00609 case OP_JIFEND:
00610 arg = ARG();
00611 if(IS_END(STK(1))) {
00612 ctx->opTop--;
00613 f->ip = arg;
00614 DBG(printf(" [Jump to: %d]\n", f->ip);)
00615 }
00616 break;
00617 case OP_JIFTRUE:
00618 arg = ARG();
00619 if(boolify(ctx, STK(1))) {
00620 f->ip = arg;
00621 DBG(printf(" [Jump to: %d]\n", f->ip);)
00622 }
00623 break;
00624 case OP_JIFNOT:
00625 arg = ARG();
00626 if(!boolify(ctx, STK(1))) {
00627 f->ip = arg;
00628 DBG(printf(" [Jump to: %d]\n", f->ip);)
00629 }
00630 break;
00631 case OP_JIFNOTPOP:
00632 arg = ARG();
00633 if(!boolify(ctx, POP())) {
00634 f->ip = arg;
00635 DBG(printf(" [Jump to: %d]\n", f->ip);)
00636 }
00637 break;
00638 case OP_FCALL:
00639 f = setupFuncall(ctx, ARG(), 0);
00640 cd = PTR(PTR(f->func).func->code).code;
00641 break;
00642 case OP_MCALL:
00643 f = setupFuncall(ctx, ARG(), 1);
00644 cd = PTR(PTR(f->func).func->code).code;
00645 break;
00646 case OP_RETURN:
00647 a = STK(1);
00648 ctx->dieArg = naNil();
00649 if(ctx->callChild) naFreeContext(ctx->callChild);
00650 if(--ctx->fTop <= 0) return a;
00651 ctx->opTop = f->bp + 1;
00652 STK(1) = a;
00653 FIXFRAME();
00654 break;
00655 case OP_EACH:
00656 evalEach(ctx, 0);
00657 break;
00658 case OP_INDEX:
00659 evalEach(ctx, 1);
00660 break;
00661 case OP_MARK:
00662 if(ctx->markTop >= MAX_MARK_DEPTH)
00663 ERR(ctx, "mark stack overflow");
00664 ctx->markStack[ctx->markTop++] = ctx->opTop;
00665 break;
00666 case OP_UNMARK:
00667 ctx->markTop--;
00668 break;
00669 case OP_BREAK:
00670 ctx->opTop = ctx->markStack[ctx->markTop-1];
00671 break;
00672 case OP_BREAK2:
00673 ctx->opTop = ctx->markStack[--ctx->markTop];
00674 break;
00675 default:
00676 ERR(ctx, "BUG: bad opcode");
00677 }
00678 ctx->ntemps = 0;
00679 DBG(printStackDEBUG(ctx);)
00680 }
00681 return naNil();
00682 }
00683 #undef POP
00684 #undef CONSTARG
00685 #undef STK
00686 #undef FIXFRAME
00687
00688 void naSave(struct Context* ctx, naRef obj)
00689 {
00690 naVec_append(globals->save, obj);
00691 }
00692
00693 int naStackDepth(struct Context* ctx)
00694 {
00695 return ctx ? ctx->fTop + naStackDepth(ctx->callChild): 0;
00696 }
00697
00698 static int findFrame(naContext ctx, naContext* out, int fn)
00699 {
00700 int sd = naStackDepth(ctx->callChild);
00701 if(fn < sd) return findFrame(ctx->callChild, out, fn);
00702 *out = ctx;
00703 return ctx->fTop - 1 - (fn - sd);
00704 }
00705
00706 int naGetLine(struct Context* ctx, int frame)
00707 {
00708 struct Frame* f;
00709 frame = findFrame(ctx, &ctx, frame);
00710 f = &ctx->fStack[frame];
00711 if(IS_FUNC(f->func) && IS_CODE(PTR(f->func).func->code)) {
00712 struct naCode* c = PTR(PTR(f->func).func->code).code;
00713 unsigned short* p = c->lineIps + c->nLines - 2;
00714 while(p >= c->lineIps && p[0] > f->ip)
00715 p -= 2;
00716 return p[1];
00717 }
00718 return -1;
00719 }
00720
00721 naRef naGetSourceFile(struct Context* ctx, int frame)
00722 {
00723 naRef f;
00724 frame = findFrame(ctx, &ctx, frame);
00725 f = ctx->fStack[frame].func;
00726 f = PTR(f).func->code;
00727 return PTR(f).code->srcFile;
00728 }
00729
00730 char* naGetError(struct Context* ctx)
00731 {
00732 if(IS_STR(ctx->dieArg))
00733 return (char*)PTR(ctx->dieArg).str->data;
00734 return ctx->error[0] ? ctx->error : 0;
00735 }
00736
00737 naRef naBindFunction(naContext ctx, naRef code, naRef closure)
00738 {
00739 naRef func = naNewFunc(ctx, code);
00740 PTR(func).func->namespace = closure;
00741 PTR(func).func->next = naNil();
00742 return func;
00743 }
00744
00745 naRef naBindToContext(naContext ctx, naRef code)
00746 {
00747 naRef func = naNewFunc(ctx, code);
00748 struct Frame* f = &ctx->fStack[ctx->fTop-1];
00749 PTR(func).func->namespace = f->locals;
00750 PTR(func).func->next = f->func;
00751 return func;
00752 }
00753
00754 naRef naCall(naContext ctx, naRef func, int argc, naRef* args,
00755 naRef obj, naRef locals)
00756 {
00757 int i;
00758 naRef result;
00759 if(!ctx->callParent) naModLock();
00760
00761
00762
00763
00764 naTempSave(ctx, func);
00765 for(i=0; i<argc; i++)
00766 naTempSave(ctx, args[i]);
00767 naTempSave(ctx, obj);
00768 naTempSave(ctx, locals);
00769
00770
00771 if(setjmp(ctx->jumpHandle)) {
00772 if(!ctx->callParent) naModUnlock(ctx);
00773 return naNil();
00774 }
00775
00776 if(IS_CCODE(PTR(func).func->code)) {
00777 naCFunction fp = PTR(PTR(func).func->code).ccode->fptr;
00778 result = (*fp)(ctx, obj, argc, args);
00779 if(!ctx->callParent) naModUnlock();
00780 return result;
00781 }
00782
00783 if(IS_NIL(locals))
00784 locals = naNewHash(ctx);
00785 if(!IS_FUNC(func)) {
00786 func = naNewFunc(ctx, func);
00787 PTR(func).func->namespace = locals;
00788 }
00789 if(!IS_NIL(obj))
00790 naHash_set(locals, globals->meRef, obj);
00791
00792 ctx->opTop = ctx->markTop = 0;
00793 ctx->fTop = 1;
00794 ctx->fStack[0].func = func;
00795 ctx->fStack[0].locals = locals;
00796 ctx->fStack[0].ip = 0;
00797 ctx->fStack[0].bp = ctx->opTop;
00798
00799 if(args) setupArgs(ctx, ctx->fStack, args, argc);
00800
00801 result = run(ctx);
00802 if(!ctx->callParent) naModUnlock(ctx);
00803 return result;
00804 }
00805
00806 naRef naContinue(naContext ctx)
00807 {
00808 naRef result;
00809 if(!ctx->callParent) naModLock();
00810
00811 ctx->dieArg = naNil();
00812 ctx->error[0] = 0;
00813
00814 if(setjmp(ctx->jumpHandle)) {
00815 if(!ctx->callParent) naModUnlock(ctx);
00816 else naRethrowError(ctx);
00817 return naNil();
00818 }
00819
00820
00821
00822
00823
00824
00825 ctx->opTop = ctx->opFrame;
00826 PUSH(ctx->callChild ? naContinue(ctx->callChild) : naNil());
00827
00828
00829
00830
00831
00832 if(ctx->callChild) naFreeContext(ctx->callChild);
00833
00834 result = run(ctx);
00835 if(!ctx->callParent) naModUnlock();
00836 return result;
00837 }