X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fnasal%2Flib.c;h=796c3ca3c7008e2e9cc03f583328c87eb94e68f2;hb=289777bd99877d8d1ab439744bff5865e426cab4;hp=fd8451be7b264b9e8bce13e14be1782866c01bd6;hpb=7a680fb9f26af64738bddfca741dc48fd0be0bc3;p=simgear.git diff --git a/simgear/nasal/lib.c b/simgear/nasal/lib.c index fd8451be..796c3ca3 100644 --- a/simgear/nasal/lib.c +++ b/simgear/nasal/lib.c @@ -56,7 +56,7 @@ static naRef f_pop(naContext c, naRef me, int argc, naRef* args) static naRef f_setsize(naContext c, naRef me, int argc, naRef* args) { if(argc < 2 || !naIsVector(args[0])) ARGERR(); - naVec_setsize(args[0], (int)naNumValue(args[1]).num); + naVec_setsize(c, args[0], (int)naNumValue(args[1]).num); return args[0]; } @@ -74,7 +74,7 @@ static naRef f_subvec(naContext c, naRef me, int argc, naRef* args) if(naIsNil(nlen) || len > naVec_size(v) - start) len = naVec_size(v) - start; result = naNewVector(c); - naVec_setsize(result, len); + naVec_setsize(c, result, len); for(i=0; i 1 ? args[0] : naNil(); - naRef startR = argc > 1 ? naNumValue(args[1]) : naNil(); - naRef lenR = argc > 2 ? naNumValue(args[2]) : naNil(); - int start, len; - if(!naIsString(src) || naIsNil(startR)) ARGERR(); - start = (int)startR.num; - len = naIsNil(lenR) ? (naStr_len(src) - start) : (int)lenR.num; - if(len < 0) ARGERR(); + int start, len, srclen; + naRef src = argc > 0 ? args[0] : naNil(); + naRef startr = argc > 1 ? naNumValue(args[1]) : naNil(); + naRef lenr = argc > 2 ? naNumValue(args[2]) : naNil(); + if(!naIsString(src)) ARGERR(); + if(naIsNil(startr) || !naIsNum(startr)) ARGERR(); + if(!naIsNil(lenr) && !naIsNum(lenr)) ARGERR(); + srclen = naStr_len(src); + start = (int)startr.num; + len = naIsNum(lenr) ? (int)lenr.num : (srclen - start); + if(start < 0) start += srclen; + if(start < 0) start = len = 0; + if(start >= srclen) start = len = 0; + if(len < 0) len = 0; + if(len > srclen - start) len = srclen - start; return naStr_substr(naNewString(c), src, start, len); } +static naRef f_left(naContext c, naRef me, int argc, naRef* args) +{ + int len; + naRef src = argc > 0 ? args[0] : naNil(); + naRef lenr = argc > 1 ? naNumValue(args[1]) : naNil(); + if(!naIsString(src)) ARGERR(); + if(!naIsNum(lenr)) ARGERR(); + len = (int)lenr.num; + if(len < 0) len = 0; + return naStr_substr(naNewString(c), src, 0, len); +} + +static naRef f_right(naContext c, naRef me, int argc, naRef* args) +{ + int len, srclen; + naRef src = argc > 0 ? args[0] : naNil(); + naRef lenr = argc > 1 ? naNumValue(args[1]) : naNil(); + if(!naIsString(src)) ARGERR(); + if(!naIsNum(lenr)) ARGERR(); + srclen = naStr_len(src); + len = (int)lenr.num; + if (len > srclen) len = srclen; + if(len < 0) len = 0; + return naStr_substr(naNewString(c), src, srclen - len, len); +} + static naRef f_chr(naContext c, naRef me, int argc, naRef* args) { char chr[1]; @@ -207,6 +240,10 @@ static naRef f_compile(naContext c, naRef me, int argc, naRef* args) // that it can be reset if we get a die()/naRethrowError() situation // later. Right now, the IP on the stack trace is the line of the // die() call, when it should be this one... +// +// FIXME: don't use naCall at all here, we don't need it. Fix up the +// context stack to tail call the function directly. There's no need +// for f_call() to live on the C stack at all. static naRef f_call(naContext c, naRef me, int argc, naRef* args) { naContext subc; @@ -215,34 +252,37 @@ static naRef f_call(naContext c, naRef me, int argc, naRef* args) callargs = argc > 1 ? args[1] : naNil(); callme = argc > 2 ? args[2] : naNil(); // Might be nil, that's OK callns = argc > 3 ? args[3] : naNil(); // ditto - if(!IS_HASH(callme)) callme = naNil(); + if(!IS_HASH(callme) && !IS_GHOST(callme)) callme = naNil(); if(!IS_HASH(callns)) callns = naNil(); - if(!IS_FUNC(args[0]) || (!IS_NIL(callargs) && !IS_VEC(callargs))) + if(argc==0 || !IS_FUNC(args[0]) || (!IS_NIL(callargs) && !IS_VEC(callargs))) ARGERR(); - // Note that we don't free the subcontext, in case the user - // re-throws the same error. That happens at the next OP_RETURN - // or naSubContext(). subc = naSubContext(c); vr = IS_NIL(callargs) ? 0 : PTR(callargs).vec->rec; result = naCall(subc, args[0], vr ? vr->size : 0, vr ? vr->array : 0, callme, callns); - if(naGetError(subc)) { - if(argc <= 2 || !IS_VEC(args[argc-1])) { - naRethrowError(subc); - } else { - int i, sd; - naRef errv = args[argc-1]; - if(!IS_NIL(subc->dieArg)) naVec_append(errv, subc->dieArg); - else naVec_append(errv, NEWCSTR(subc, naGetError(subc))); - sd = naStackDepth(subc); - for(i=0; idieArg)) naVec_append(errv, subc->dieArg); + else naVec_append(errv, NEWCSTR(subc, naGetError(subc))); + sd = naStackDepth(subc); + for(i=0; i 2) start = (int)(naNumValue(args[2]).num); - return naNum(find(PTR(args[0]).str->data, PTR(args[0]).str->len, - PTR(args[1]).str->data, PTR(args[1]).str->len, + return naNum(find((void*)naStr_data(args[0]), naStr_len(args[0]), + (void*)naStr_data(args[1]), naStr_len(args[1]), start)); } @@ -472,6 +512,80 @@ static naRef f_bind(naContext c, naRef me, int argc, naRef* args) return func; } +/* We use the "SortRec" gadget for two reasons: first, because ANSI + * qsort() doesn't give us a mechanism for passing a "context" pointer + * to the comparison routine we have to store one in every sorted + * record. Second, using an index into the original vector here + * allows us to make the sort stable in the event of a zero returned + * from the Nasal comparison function. */ +struct SortData { naContext ctx, subc; struct SortRec* recs; + naRef* elems; int n; naRef fn; }; +struct SortRec { struct SortData* sd; int i; }; + +static int sortcmp(struct SortRec* a, struct SortRec* b) +{ + struct SortData* sd = a->sd; + naRef args[2], d; + args[0] = sd->elems[a->i]; + args[1] = sd->elems[b->i]; + d = naCall(sd->subc, sd->fn, 2, args, naNil(), naNil()); + if(naGetError(sd->subc)) { + naFree(sd->recs); + naRethrowError(sd->subc); + } else if(!naIsNum(d = naNumValue(d))) { + naFree(sd->recs); + naRuntimeError(sd->ctx, "sort() comparison returned non-number"); + } + return (d.num > 0) ? 1 : ((d.num < 0) ? -1 : (a->i - b->i)); +} + +static naRef f_sort(naContext c, naRef me, int argc, naRef* args) +{ + int i; + struct SortData sd; + naRef out; + if(argc != 2 || !naIsVector(args[0]) || !naIsFunc(args[1])) + naRuntimeError(c, "bad/missing argument to sort()"); + sd.subc = naSubContext(c); + if(!PTR(args[0]).vec->rec) return naNewVector(c); + sd.elems = PTR(args[0]).vec->rec->array; + sd.n = PTR(args[0]).vec->rec->size; + sd.fn = args[1]; + sd.recs = naAlloc(sizeof(struct SortRec) * sd.n); + for(i=0; irec->array[i] = sd.elems[sd.recs[i].i]; + naFree(sd.recs); + naFreeContext(sd.subc); + return out; +} + +static naRef f_id(naContext c, naRef me, int argc, naRef* args) +{ + char *t = "unk", buf[64]; + if(argc != 1 || !IS_REF(args[0])) + naRuntimeError(c, "bad/missing argument to id()"); + if (IS_STR(args[0])) t = "str"; + else if(IS_VEC(args[0])) t = "vec"; + else if(IS_HASH(args[0])) t = "hash"; + else if(IS_CODE(args[0])) t = "code"; + else if(IS_FUNC(args[0])) t = "func"; + else if(IS_CCODE(args[0])) t = "ccode"; + else if(IS_GHOST(args[0])) { + naGhostType *gt = PTR(args[0]).ghost->gtype; + t = gt->name ? (char*)gt->name : "ghost"; + } + sprintf(buf, "%s:%p", (char*)t, (void*)PTR(args[0]).obj); + return NEWCSTR(c, buf); +} + static naCFuncItem funcs[] = { { "size", f_size }, { "keys", f_keys }, @@ -485,6 +599,8 @@ static naCFuncItem funcs[] = { { "streq", f_streq }, { "cmp", f_cmp }, { "substr", f_substr }, + { "left", f_left }, + { "right", f_right }, { "chr", f_chr }, { "contains", f_contains }, { "typeof", f_typeof }, @@ -499,6 +615,8 @@ static naCFuncItem funcs[] = { { "split", f_split }, { "rand", f_rand }, { "bind", f_bind }, + { "sort", f_sort }, + { "id", f_id }, { 0 } };