X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fnasal%2Fcode.c;h=2bf46451d8501223ed99e2ea97aa1ceb4786b09c;hb=f41b18f0649a50e179ba41383f4061e1878c4d4c;hp=e58f7ecb96cc101ebef61d1e621a437e17e851bc;hpb=f918602f58dea8846046b2b349f49bdc2682c3ff;p=simgear.git diff --git a/simgear/nasal/code.c b/simgear/nasal/code.c index e58f7ecb..2bf46451 100644 --- a/simgear/nasal/code.c +++ b/simgear/nasal/code.c @@ -71,7 +71,9 @@ static double numify(naContext ctx, naRef o) else if(IS_NIL(o)) ERR(ctx, "nil used in numeric context"); else if(!IS_STR(o)) ERR(ctx, "non-scalar in numeric context"); else if(naStr_tonum(o, &n)) return n; - else ERR(ctx, "non-numeric string in numeric context"); + else naRuntimeError( ctx, + "non-numeric string in numeric context: '%s'", + naStr_data(o) ); return 0; } @@ -180,6 +182,8 @@ static void initGlobals() globals->symbols = naNewHash(c); globals->save = naNewVector(c); + globals->save_hash = naNewHash(c); + globals->next_gc_key = 0; // Cache pre-calculated "me", "arg" and "parents" scalars globals->meRef = naInternSymbol(naStr_fromdata(naNewString(c), "me", 2)); @@ -269,7 +273,7 @@ static void setupArgs(naContext ctx, struct Frame* f, naRef* args, int nargs) args += c->nOptArgs; if(c->needArgVector || nargs > 0) { naRef argv = naNewVector(ctx); - naVec_setsize(argv, nargs > 0 ? nargs : 0); + naVec_setsize(ctx, argv, nargs > 0 ? nargs : 0); for(i=0; irec->array[i] = *args++; naiHash_newsym(PTR(f->locals).hash, &c->constants[c->restArgSym], &argv); @@ -313,7 +317,10 @@ static struct Frame* setupFuncall(naContext ctx, int nargs, int mcall, int named ctx->opFrame = opf; if(IS_CCODE(code)) { - naRef result = (*PTR(code).ccode->fptr)(ctx, obj, nargs, args); + struct naCCode *ccode = PTR(code).ccode; + naRef result = ccode->fptru + ? (*ccode->fptru)(ctx, obj, nargs, args, ccode->user_data) + : (*ccode->fptr)(ctx, obj, nargs, args); if(named) ERR(ctx, "native functions have no named arguments"); ctx->opTop = ctx->opFrame; PUSH(result); @@ -349,7 +356,7 @@ static naRef evalCat(naContext ctx, naRef l, naRef r) if(IS_VEC(l) && IS_VEC(r)) { int i, ls = naVec_size(l), rs = naVec_size(r); naRef v = naNewVector(ctx); - naVec_setsize(v, ls + rs); + naVec_setsize(ctx, v, ls + rs); for(i=0; ilocals, sym, val); } +static const char* ghostGetMember(naContext ctx, naRef obj, naRef field, naRef* out) +{ + naGhostType* gtype = PTR(obj).ghost->gtype; + if (!gtype->get_member) return "ghost does not support member access"; + return gtype->get_member(ctx, PTR(obj).ghost->ptr, field, out); +} + // Funky API: returns null to indicate no member, an empty string to // indicate success, or a non-empty error message. Works this way so // we can generate smart error messages without throwing them with a // longjmp -- this gets called under naMember_get() from C code. -static const char* getMember_r(naRef obj, naRef field, naRef* out, int count) +static const char* getMember_r(naContext ctx, naRef obj, naRef field, naRef* out, int count) { int i; naRef p; struct VecRec* pv; if(--count < 0) return "too many parents"; - if(!IS_HASH(obj)) return "non-objects have no members"; - if(naHash_get(obj, field, out)) return ""; - if(!naHash_get(obj, globals->parentsRef, &p)) return 0; + + if (IS_GHOST(obj)) { + if (ghostGetMember(ctx, obj, field, out)) return ""; + if(!ghostGetMember(ctx, obj, globals->parentsRef, &p)) return 0; + } else if (IS_HASH(obj)) { + if(naHash_get(obj, field, out)) return ""; + if(!naHash_get(obj, globals->parentsRef, &p)) return 0; + } else if (IS_STR(obj) ) { + return getMember_r(ctx, getStringMethods(ctx), field, out, count); + } else { + return "non-objects have no members"; + } + if(!IS_VEC(p)) return "object \"parents\" field not vector"; pv = PTR(p).vec->rec; for(i=0; pv && isize; i++) { - const char* err = getMember_r(pv->array[i], field, out, count); + const char* err = getMember_r(ctx, pv->array[i], field, out, count); if(err) return err; /* either an error or success */ } return 0; @@ -449,14 +473,29 @@ static const char* getMember_r(naRef obj, naRef field, naRef* out, int count) static void getMember(naContext ctx, naRef obj, naRef fld, naRef* result, int count) { - const char* err = getMember_r(obj, fld, result, count); + const char* err = getMember_r(ctx, obj, fld, result, count); if(!err) naRuntimeError(ctx, "No such member: %s", naStr_data(fld)); if(err[0]) naRuntimeError(ctx, err); } -int naMember_get(naRef obj, naRef field, naRef* out) +static void setMember(naContext ctx, naRef obj, naRef fld, naRef value) { - const char* err = getMember_r(obj, field, out, 64); + if (IS_GHOST(obj)) { + naGhostType* gtype = PTR(obj).ghost->gtype; + if (!gtype->set_member) ERR(ctx, "ghost does not support member access"); + gtype->set_member(ctx, PTR(obj).ghost->ptr, fld, value); + ctx->opTop -= 2; + return; + } + + if(!IS_HASH(obj)) ERR(ctx, "non-objects have no members"); + naHash_set(obj, fld, value); + ctx->opTop -= 2; +} + +int naMember_get(naContext ctx, naRef obj, naRef field, naRef* out) +{ + const char* err = getMember_r(ctx, obj, field, out, 64); return err && !err[0]; } @@ -555,6 +594,9 @@ static naRef run(naContext ctx) 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; + case OP_BIT_AND: BINOP((int)l & (int)r); break; + case OP_BIT_OR: BINOP((int)l | (int)r); break; + case OP_BIT_XOR: BINOP((int)l ^ (int)r); break; #undef BINOP case OP_EQ: case OP_NEQ: @@ -568,6 +610,9 @@ static naRef run(naContext ctx) case OP_NEG: STK(1) = naNum(-numify(ctx, STK(1))); break; + case OP_BIT_NEG: + STK(1) = naNum(~(int)numify(ctx, STK(1))); + break; case OP_NOT: STK(1) = naNum(boolify(ctx, STK(1)) ? 0 : 1); break; @@ -619,9 +664,7 @@ static naRef run(naContext ctx) 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; + setMember(ctx, STK(2), STK(1), STK(3)); break; case OP_INSERT: containerSet(ctx, STK(2), STK(1), STK(3)); @@ -732,6 +775,27 @@ void naSave(naContext ctx, naRef obj) naVec_append(globals->save, obj); } +int naGCSave(naRef obj) +{ + int key = globals->next_gc_key++; + naHash_set(globals->save_hash, naNum(key), obj); + return key; +} + +void naGCRelease(int key) +{ + naHash_delete(globals->save_hash, naNum(key)); +} + +void naClearSaved() +{ + naContext c; + c = naNewContext(); + globals->save = naNewVector(c); + globals->save_hash = naNewHash(c); + naFreeContext(c); +} + int naStackDepth(naContext ctx) { return ctx ? ctx->fTop + naStackDepth(ctx->callChild): 0; @@ -818,8 +882,10 @@ naRef naCall(naContext ctx, naRef func, int argc, naRef* args, } if(IS_CCODE(PTR(func).func->code)) { - naCFunction fp = PTR(PTR(func).func->code).ccode->fptr; - result = (*fp)(ctx, obj, argc, args); + struct naCCode *ccode = PTR(PTR(func).func->code).ccode; + result = ccode->fptru + ? (*ccode->fptru)(ctx, obj, argc, args, ccode->user_data) + : (*ccode->fptr) (ctx, obj, argc, args); if(!ctx->callParent) naModUnlock(); return result; } @@ -880,3 +946,52 @@ naRef naContinue(naContext ctx) if(!ctx->callParent) naModUnlock(); return result; } + +static void logError(naContext ctx) +{ + int i, stack_depth = naStackDepth(ctx); + printf("Nasal runtime error: %s\n", naGetError(ctx)); + if( stack_depth < 1 ) + return; + printf(" at %s\n", naStr_data(naGetSourceFile(ctx, 0))); + printf(", line %d\n", naGetLine(ctx, 0)); + for(i = 1; i < stack_depth; ++i ) + printf( " called from: %s, line %d", + naStr_data(naGetSourceFile(ctx, i)), + naGetLine(ctx, i)); +} + +static naErrorHandler error_handler = &logError; +naErrorHandler naSetErrorHandler(naErrorHandler cb) +{ + naErrorHandler old_handler = error_handler; + error_handler = cb; + return old_handler; +} + +static int call_count = 0; +naRef naCallMethodCtx( naContext ctx, + naRef code, + naRef self, + int argc, + naRef* args, + naRef locals ) +{ + naRef result; + if(call_count) naModUnlock(); + call_count++; + result = naCall(ctx, code, argc, args, self, locals); + if(naGetError(ctx) && error_handler) + error_handler(ctx); + call_count--; + if(call_count) naModLock(); + return result; +} + +naRef naCallMethod(naRef code, naRef self, int argc, naRef* args, naRef locals) +{ + naContext ctx = naNewContext(); + naRef result = naCallMethodCtx(ctx, code, self, argc, args, locals); + naFreeContext(ctx); + return result; +}