diff --git a/simgear/nasal/code.c b/simgear/nasal/code.c index d24dcc47..9333c88f 100644 --- a/simgear/nasal/code.c +++ b/simgear/nasal/code.c @@ -358,8 +358,12 @@ static void run1(struct Context* ctx, struct Frame* f, naRef code) PUSH(ctx, evalAndOr(ctx, op, a, b)); break; case OP_CAT: - a = stringify(ctx, POP(ctx)); b = stringify(ctx, POP(ctx)); + // stringify can call the GC, so don't take stuff of the stack! + if(ctx->opTop <= 1) ERR(ctx, "BUG: stack underflow"); + a = stringify(ctx, ctx->opStack[ctx->opTop-1]); + b = stringify(ctx, ctx->opStack[ctx->opTop-2]); c = naStr_concat(naNewString(ctx), b, a); + ctx->opTop -= 2; PUSH(ctx, c); break; case OP_NEG: @@ -531,6 +535,7 @@ static naRef run(naContext ctx) { // Return early if an error occurred. It will be visible to the // caller via naGetError(). + ctx->error = 0; if(setjmp(ctx->jumpHandle)) return naNil(); diff --git a/simgear/nasal/data.h b/simgear/nasal/data.h index c350b657..4ed0f07c 100644 --- a/simgear/nasal/data.h +++ b/simgear/nasal/data.h @@ -7,7 +7,7 @@ // What actually gets executed at runtime is a bound FUNC object, // which combines the raw code with a pointer to a CLOSURE chain of // namespaces. -enum { T_STR, T_VEC, T_HASH, T_CODE, T_CLOSURE, T_FUNC, T_CCODE, +enum { T_STR, T_VEC, T_HASH, T_CODE, T_CLOSURE, T_FUNC, T_CCODE, T_GHOST, NUM_NASAL_TYPES }; // V. important that this come last! #define IS_REF(r) ((r).ref.reftag == NASAL_REFTAG) @@ -21,6 +21,7 @@ enum { T_STR, T_VEC, T_HASH, T_CODE, T_CLOSURE, T_FUNC, T_CCODE, #define IS_FUNC(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_FUNC) #define IS_CLOSURE(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_CLOSURE) #define IS_CCODE(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_CCODE) +#define IS_GHOST(r) (IS_OBJ((r)) && (r).ref.ptr.obj->type == T_GHOST) #define IS_CONTAINER(r) (IS_VEC(r)||IS_HASH(r)) #define IS_SCALAR(r) (IS_NUM((r)) || IS_STR((r))) @@ -90,6 +91,12 @@ struct naCCode { naCFunction fptr; }; +struct naGhost { + GC_HEADER; + naGhostType* gtype; + void* ptr; +}; + struct naPool { int type; int elemsz; diff --git a/simgear/nasal/gc.c b/simgear/nasal/gc.c index 8fa2b9c5..60f6c422 100644 --- a/simgear/nasal/gc.c +++ b/simgear/nasal/gc.c @@ -41,6 +41,12 @@ static void naCode_gcclean(struct naCode* o) naFree(o->constants); o->constants = 0; } +static void naGhost_gcclean(struct naGhost* g) +{ + if(g->ptr) g->gtype->destroy(g->ptr); + g->ptr = 0; +} + static void freeelem(struct naPool* p, struct naObj* o) { // Mark the object as "freed" for debugging purposes @@ -61,6 +67,9 @@ static void freeelem(struct naPool* p, struct naObj* o) case T_CODE: naCode_gcclean((struct naCode*)o); break; + case T_GHOST: + naGhost_gcclean((struct naGhost*)o); + break; } // And add it to the free list diff --git a/simgear/nasal/hash.c b/simgear/nasal/hash.c index 966cd957..8c8e537d 100644 --- a/simgear/nasal/hash.c +++ b/simgear/nasal/hash.c @@ -196,7 +196,7 @@ void naHash_keys(naRef dst, naRef hash) { struct naHash* h = hash.ref.ptr.hash; int i; - if(!IS_HASH(hash)) return; + if(!IS_HASH(hash) || !h->table) return; for(i=0; i<(1<lgalloced); i++) { struct HashNode* hn = h->table[i]; while(hn) { diff --git a/simgear/nasal/lex.c b/simgear/nasal/lex.c index 86f1442e..adc08e17 100644 --- a/simgear/nasal/lex.c +++ b/simgear/nasal/lex.c @@ -132,7 +132,7 @@ static void newToken(struct Parser* p, int pos, int type, static int hexc(char c, struct Parser* p, int index) { if(c >= '0' && c <= '9') return c - '0'; - if(c >= 'A' && c <= 'F') return c - 'a' + 10; + if(c >= 'A' && c <= 'F') return c - 'A' + 10; if(c >= 'a' && c <= 'f') return c - 'a' + 10; error(p, "bad hex constant", index); return 0; @@ -170,6 +170,7 @@ static void dqEscape(char* buf, int len, int index, struct Parser* p, if(len < 4) error(p, "unterminated string", index); *cOut = (char)((hexc(buf[2], p, index)<<4) | hexc(buf[3], p, index)); *eatenOut = 4; + break; default: // Unhandled, put the backslash back *cOut = '\\'; @@ -235,7 +236,8 @@ static int trySymbol(struct Parser* p, int start) { int i = start; while((i < p->len) && - ((p->buf[i] >= 'A' && p->buf[i] <= 'Z') || + ((p->buf[i] == '_') || + (p->buf[i] >= 'A' && p->buf[i] <= 'Z') || (p->buf[i] >= 'a' && p->buf[i] <= 'z') || (p->buf[i] >= '0' && p->buf[i] <= '9'))) { i++; } @@ -316,7 +318,7 @@ void naLex(struct Parser* p) if(!handled) { int symlen=0, lexlen=0, lexeme; lexlen = tryLexemes(p, i, &lexeme); - if((c>='A' && c<='Z') || (c>='a' && c<='z')) + if((c>='A' && c<='Z') || (c>='a' && c<='z') || (c=='_')) symlen = trySymbol(p, i); if(lexlen && lexlen >= symlen) { newToken(p, i, LEXEMES[lexeme].tok, 0, 0, 0); diff --git a/simgear/nasal/lib.c b/simgear/nasal/lib.c index 1ed3837b..b050aa70 100644 --- a/simgear/nasal/lib.c +++ b/simgear/nasal/lib.c @@ -118,6 +118,7 @@ static naRef typeOf(naContext c, naRef args) else if(naIsVector(r)) t = "vector"; else if(naIsHash(r)) t = "hash"; else if(naIsFunc(r)) t = "func"; + else if(naIsGhost(r)) t = "ghost"; r = naStr_fromdata(naNewString(c), t, strlen(t)); return r; } diff --git a/simgear/nasal/misc.c b/simgear/nasal/misc.c index 54190032..73bd19d2 100644 --- a/simgear/nasal/misc.c +++ b/simgear/nasal/misc.c @@ -104,6 +104,26 @@ naRef naNewClosure(struct Context* c, naRef namespace, naRef next) return closure; } +naRef naNewGhost(naContext c, naGhostType* type, void* ptr) +{ + naRef ghost = naNew(c, T_GHOST); + ghost.ref.ptr.ghost->gtype = type; + ghost.ref.ptr.ghost->ptr = ptr; + return ghost; +} + +naGhostType* naGhost_type(naRef ghost) +{ + if(!IS_GHOST(ghost)) return 0; + return ghost.ref.ptr.ghost->gtype; +} + +void* naGhost_ptr(naRef ghost) +{ + if(!IS_GHOST(ghost)) return 0; + return ghost.ref.ptr.ghost->ptr; +} + naRef naNil() { naRef r; @@ -151,6 +171,7 @@ int naTypeSize(int type) case T_FUNC: return sizeof(struct naFunc); case T_CLOSURE: return sizeof(struct naClosure); case T_CCODE: return sizeof(struct naCCode); + case T_GHOST: return sizeof(struct naGhost); }; return 0x7fffffff; // Make sure the answer is nonsense :) } @@ -200,3 +221,7 @@ int naIsCCode(naRef r) return IS_CCODE(r); } +int naIsGhost(naRef r) +{ + return IS_GHOST(r); +} diff --git a/simgear/nasal/nasal.h b/simgear/nasal/nasal.h index 417ca67d..57b0372d 100644 --- a/simgear/nasal/nasal.h +++ b/simgear/nasal/nasal.h @@ -31,6 +31,7 @@ typedef union { struct naFunc* func; struct naClosure* closure; struct naCCode* ccode; + struct naGhost* ghost; } ptr; #ifndef NASAL_BIG_ENDIAN_32_BIT int reftag; // Little-endian and 64 bit systems need this here! @@ -139,6 +140,15 @@ void naHash_cset(naRef hash, char* key, naRef val); void naHash_delete(naRef hash, naRef key); void naHash_keys(naRef dst, naRef hash); +// Ghost utilities: +typedef struct naGhostType { + void (*destroy)(void* ghost); +} naGhostType; +naRef naNewGhost(naContext c, naGhostType* t, void* ghost); +naGhostType* naGhost_type(naRef ghost); +void* naGhost_ptr(naRef ghost); +int naIsGhost(naRef r); + #ifdef __cplusplus } // extern "C" #endif