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;
}
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));
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; i<nargs; i++)
PTR(argv).vec->rec->array[i] = *args++;
naiHash_newsym(PTR(f->locals).hash, &c->constants[c->restArgSym], &argv);
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);
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; i<ls; i+=1) naVec_set(v, i, naVec_get(l, i));
for(i=0; i<rs; i+=1) naVec_set(v, i+ls, naVec_get(r, i));
return v;
naHash_set(f->locals, 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 && i<pv->size; 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;
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];
}
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:
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;
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));
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;
}
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;
}
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;
+}