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_HASH(obj) && !IS_GHOST(obj)) return "non-objects have no members";
+
+ if (IS_GHOST(obj)) {
+ if (ghostGetMember(ctx, obj, field, out)) return "";
+ if(!ghostGetMember(ctx, obj, globals->parentsRef, &p)) return 0;
+ } else {
+ if(naHash_get(obj, field, out)) return "";
+ if(!naHash_get(obj, globals->parentsRef, &p)) return 0;
+ }
+
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];
}
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));
// Retrieve the specified member from the object, respecting the
// "parents" array as for "object.field". Returns zero for missing
// fields.
-int naMember_get(naRef obj, naRef field, naRef* out);
-int naMember_cget(naRef obj, const char* field, naRef* out);
+int naMember_get(naContext c, naRef obj, naRef field, naRef* out);
+int naMember_cget(naContext c, naRef obj, const char* field, naRef* out);
// Returns a hash containing functions from the Nasal standard library
// Useful for passing as a namespace to an initial function call
typedef struct naGhostType {
void(*destroy)(void*);
const char* name;
+ const char*(*get_member)(naContext c, void*, naRef key, naRef* out);
+ void(*set_member)(naContext c, void*, naRef key, naRef val);
} naGhostType;
+
naRef naNewGhost(naContext c, naGhostType* t, void* ghost);
+naRef naNewGhost2(naContext c, naGhostType* t, void* ghost);
naGhostType* naGhost_type(naRef ghost);
void* naGhost_ptr(naRef ghost);
int naIsGhost(naRef r);