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