]> git.mxchange.org Git - simgear.git/commitdiff
Nasal Ghosts can optionally specify member get/set functions.
authorJames Turner <zakalawe@mac.com>
Sat, 28 Apr 2012 21:25:57 +0000 (22:25 +0100)
committerJames Turner <zakalawe@mac.com>
Sat, 28 Apr 2012 21:25:57 +0000 (22:25 +0100)
simgear/nasal/code.c
simgear/nasal/misc.c
simgear/nasal/nasal.h

index 782509da1d268c038da9ca60899cc8e96dc65bfa..08d710f81f6014edce893b2d13b8a3fce9f85ff3 100644 (file)
@@ -424,23 +424,37 @@ static void setSymbol(struct Frame* f, naRef sym, naRef val)
             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;
@@ -449,14 +463,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];
 }
 
@@ -619,9 +648,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));
index 8640aea09769c2b90bc5c17f796cb8d7a7a5058f..1c3a6195564d50eafd86c5ce5df49173123846bc 100644 (file)
@@ -121,12 +121,24 @@ naRef naNewFunc(struct Context* c, naRef code)
 
 naRef naNewGhost(naContext c, naGhostType* type, void* ptr)
 {
+    // ensure 'simple' ghost users don't see garbage for these fields
+    type->get_member = 0;
+    type->set_member = 0;
+    
     naRef ghost = naNew(c, T_GHOST);
     PTR(ghost).ghost->gtype = type;
     PTR(ghost).ghost->ptr = ptr;
     return ghost;
 }
 
+naRef naNewGhost2(naContext c, naGhostType* t, void* ptr)
+{
+    naRef ghost = naNew(c, T_GHOST);
+    PTR(ghost).ghost->gtype = t;
+    PTR(ghost).ghost->ptr = ptr;
+    return ghost;
+}
+
 naGhostType* naGhost_type(naRef ghost)
 {
     if(!IS_GHOST(ghost)) return 0;
index 6857013a07b3f0519028fc0967e4617aa5f2df90..3c5140e0d20896022286ef0e87cadb64862a1b7a 100644 (file)
@@ -99,8 +99,8 @@ void naRethrowError(naContext subc);
 // 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
@@ -181,8 +181,12 @@ void naHash_keys(naRef dst, naRef hash);
 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);