]> git.mxchange.org Git - simgear.git/blobdiff - simgear/nasal/code.c
Improve (mostly Canvas event related) documentation.
[simgear.git] / simgear / nasal / code.c
index e58f7ecb96cc101ebef61d1e621a437e17e851bc..2bf46451d8501223ed99e2ea97aa1ceb4786b09c 100644 (file)
@@ -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; i<nargs; i++)
             PTR(argv).vec->rec->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; 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;
@@ -424,23 +431,40 @@ 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_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;
@@ -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;
+}