00001 #include <math.h>
00002 #include <stdio.h>
00003 #include <stdlib.h>
00004 #include <stdarg.h>
00005 #include <string.h>
00006
00007 #ifdef _MSC_VER // sigh...
00008 #define snprintf _snprintf
00009 #define vsnprintf _vsnprintf
00010 #endif
00011
00012 #include "nasal.h"
00013 #include "code.h"
00014
00015 #define NEWSTR(c, s, l) naStr_fromdata(naNewString(c), s, l)
00016 #define NEWCSTR(c, s) NEWSTR(c, s, strlen(s))
00017
00018
00019
00020 #define ARGERR() \
00021 naRuntimeError(c, "bad/missing argument to %s()", (__FUNCTION__ + 2))
00022
00023 static naRef f_size(naContext c, naRef me, int argc, naRef* args)
00024 {
00025 if(argc == 0) ARGERR();
00026 if(naIsString(args[0])) return naNum(naStr_len(args[0]));
00027 if(naIsVector(args[0])) return naNum(naVec_size(args[0]));
00028 if(naIsHash(args[0])) return naNum(naHash_size(args[0]));
00029 naRuntimeError(c, "object has no size()");
00030 return naNil();
00031 }
00032
00033 static naRef f_keys(naContext c, naRef me, int argc, naRef* args)
00034 {
00035 naRef v, h = argc > 0 ? args[0] : naNil();
00036 if(!naIsHash(h)) ARGERR();
00037 v = naNewVector(c);
00038 naHash_keys(v, h);
00039 return v;
00040 }
00041
00042 static naRef f_append(naContext c, naRef me, int argc, naRef* args)
00043 {
00044 int i;
00045 if(argc < 2 || !naIsVector(args[0])) ARGERR();
00046 for(i=1; i<argc; i++) naVec_append(args[0], args[i]);
00047 return args[0];
00048 }
00049
00050 static naRef f_pop(naContext c, naRef me, int argc, naRef* args)
00051 {
00052 if(argc < 1 || !naIsVector(args[0])) ARGERR();
00053 return naVec_removelast(args[0]);
00054 }
00055
00056 static naRef f_setsize(naContext c, naRef me, int argc, naRef* args)
00057 {
00058 if(argc < 2 || !naIsVector(args[0])) ARGERR();
00059 naVec_setsize(args[0], (int)naNumValue(args[1]).num);
00060 return args[0];
00061 }
00062
00063 static naRef f_subvec(naContext c, naRef me, int argc, naRef* args)
00064 {
00065 int i;
00066 naRef nlen, result, v = args[0];
00067 int len = 0, start = (int)naNumValue(args[1]).num;
00068 if(argc < 2) return naNil();
00069 nlen = argc > 2 ? naNumValue(args[2]) : naNil();
00070 if(!naIsNil(nlen))
00071 len = (int)nlen.num;
00072 if(!naIsVector(v) || start < 0 || start > naVec_size(v) || len < 0)
00073 ARGERR();
00074 if(naIsNil(nlen) || len > naVec_size(v) - start)
00075 len = naVec_size(v) - start;
00076 result = naNewVector(c);
00077 naVec_setsize(result, len);
00078 for(i=0; i<len; i++)
00079 naVec_set(result, i, naVec_get(v, start + i));
00080 return result;
00081 }
00082
00083 static naRef f_delete(naContext c, naRef me, int argc, naRef* args)
00084 {
00085 if(argc < 2 || !naIsHash(args[0])) ARGERR();
00086 naHash_delete(args[0], args[1]);
00087 return args[0];
00088 }
00089
00090 static naRef f_int(naContext c, naRef me, int argc, naRef* args)
00091 {
00092 if(argc > 0) {
00093 naRef n = naNumValue(args[0]);
00094 if(naIsNil(n)) return n;
00095 if(n.num < 0) n.num = -floor(-n.num);
00096 else n.num = floor(n.num);
00097 return n;
00098 } else ARGERR();
00099 return naNil();
00100 }
00101
00102 static naRef f_num(naContext c, naRef me, int argc, naRef* args)
00103 {
00104 return argc > 0 ? naNumValue(args[0]) : naNil();
00105 }
00106
00107 static naRef f_streq(naContext c, naRef me, int argc, naRef* args)
00108 {
00109 return argc > 1 ? naNum(naStrEqual(args[0], args[1])) : naNil();
00110 }
00111
00112 static naRef f_cmp(naContext c, naRef me, int argc, naRef* args)
00113 {
00114 char *a, *b;
00115 int i, alen, blen;
00116 if(argc < 2 || !naIsString(args[0]) || !naIsString(args[1]))
00117 ARGERR();
00118 a = naStr_data(args[0]);
00119 alen = naStr_len(args[0]);
00120 b = naStr_data(args[1]);
00121 blen = naStr_len(args[1]);
00122 for(i=0; i<alen && i<blen; i++) {
00123 int diff = a[i] - b[i];
00124 if(diff) return naNum(diff < 0 ? -1 : 1);
00125 }
00126 return naNum(alen == blen ? 0 : (alen < blen ? -1 : 1));
00127 }
00128
00129 static naRef f_substr(naContext c, naRef me, int argc, naRef* args)
00130 {
00131 int start, len, srclen;
00132 naRef src = argc > 0 ? args[0] : naNil();
00133 naRef startr = argc > 1 ? naNumValue(args[1]) : naNil();
00134 naRef lenr = argc > 2 ? naNumValue(args[2]) : naNil();
00135 if(!naIsString(src)) ARGERR();
00136 if(naIsNil(startr) || !naIsNum(startr)) ARGERR();
00137 if(!naIsNil(lenr) && !naIsNum(lenr)) ARGERR();
00138 srclen = naStr_len(src);
00139 start = (int)startr.num;
00140 len = naIsNum(lenr) ? (int)lenr.num : (srclen - start);
00141 if(start < 0) start += srclen;
00142 if(start < 0) start = len = 0;
00143 if(start >= srclen) start = len = 0;
00144 if(len < 0) len = 0;
00145 if(len > srclen - start) len = srclen - start;
00146 return naStr_substr(naNewString(c), src, start, len);
00147 }
00148
00149 static naRef f_chr(naContext c, naRef me, int argc, naRef* args)
00150 {
00151 char chr[1];
00152 naRef cr = argc > 0 ? naNumValue(args[0]) : naNil();
00153 if(IS_NIL(cr)) ARGERR();
00154 chr[0] = (char)cr.num;
00155 return NEWSTR(c, chr, 1);
00156 }
00157
00158 static naRef f_contains(naContext c, naRef me, int argc, naRef* args)
00159 {
00160 naRef hash = argc > 0 ? args[0] : naNil();
00161 naRef key = argc > 1 ? args[1] : naNil();
00162 if(naIsNil(hash) || naIsNil(key)) ARGERR();
00163 if(!naIsHash(hash)) return naNil();
00164 return naHash_get(hash, key, &key) ? naNum(1) : naNum(0);
00165 }
00166
00167 static naRef f_typeof(naContext c, naRef me, int argc, naRef* args)
00168 {
00169 naRef r = argc > 0 ? args[0] : naNil();
00170 char* t = "unknown";
00171 if(naIsNil(r)) t = "nil";
00172 else if(naIsNum(r)) t = "scalar";
00173 else if(naIsString(r)) t = "scalar";
00174 else if(naIsVector(r)) t = "vector";
00175 else if(naIsHash(r)) t = "hash";
00176 else if(naIsFunc(r)) t = "func";
00177 else if(naIsGhost(r)) t = "ghost";
00178 return NEWCSTR(c, t);
00179 }
00180
00181 static naRef f_ghosttype(naContext c, naRef me, int argc, naRef* args)
00182 {
00183 naRef g = argc > 0 ? args[0] : naNil();
00184 if(!naIsGhost(g)) return naNil();
00185 if(naGhost_type(g)->name) {
00186 return NEWCSTR(c, (char*)naGhost_type(g)->name);
00187 } else {
00188 char buf[32];
00189 sprintf(buf, "%p", naGhost_type(g));
00190 return NEWCSTR(c, buf);
00191 }
00192 }
00193
00194 static naRef f_compile(naContext c, naRef me, int argc, naRef* args)
00195 {
00196 int errLine;
00197 naRef script, code, fname;
00198 script = argc > 0 ? args[0] : naNil();
00199 fname = argc > 1 ? args[1] : NEWCSTR(c, "<compile>");
00200 if(!naIsString(script) || !naIsString(fname)) return naNil();
00201 code = naParseCode(c, fname, 1,
00202 naStr_data(script), naStr_len(script), &errLine);
00203 if(naIsNil(code)) {
00204 char buf[256];
00205 snprintf(buf, sizeof(buf), "Parse error: %s at line %d",
00206 naGetError(c), errLine);
00207 c->dieArg = NEWCSTR(c, buf);
00208 naRuntimeError(c, "__die__");
00209 }
00210 return naBindToContext(c, code);
00211 }
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 static naRef f_call(naContext c, naRef me, int argc, naRef* args)
00222 {
00223 naContext subc;
00224 naRef callargs, callme, callns, result;
00225 struct VecRec* vr;
00226 callargs = argc > 1 ? args[1] : naNil();
00227 callme = argc > 2 ? args[2] : naNil();
00228 callns = argc > 3 ? args[3] : naNil();
00229 if(!IS_HASH(callme)) callme = naNil();
00230 if(!IS_HASH(callns)) callns = naNil();
00231 if(argc==0 || !IS_FUNC(args[0]) || (!IS_NIL(callargs) && !IS_VEC(callargs)))
00232 ARGERR();
00233
00234 subc = naSubContext(c);
00235 vr = IS_NIL(callargs) ? 0 : PTR(callargs).vec->rec;
00236 result = naCall(subc, args[0], vr ? vr->size : 0, vr ? vr->array : 0,
00237 callme, callns);
00238 if(!naGetError(subc)) {
00239 naFreeContext(subc);
00240 return result;
00241 }
00242
00243
00244
00245
00246 if(argc <= 2 || !IS_VEC(args[argc-1])) {
00247 naRethrowError(subc);
00248 } else {
00249 int i, sd;
00250 naRef errv = args[argc-1];
00251 if(!IS_NIL(subc->dieArg)) naVec_append(errv, subc->dieArg);
00252 else naVec_append(errv, NEWCSTR(subc, naGetError(subc)));
00253 sd = naStackDepth(subc);
00254 for(i=0; i<sd; i++) {
00255 naVec_append(errv, naGetSourceFile(subc, i));
00256 naVec_append(errv, naNum(naGetLine(subc, i)));
00257 }
00258 }
00259 return naNil();
00260 }
00261
00262 static naRef f_die(naContext c, naRef me, int argc, naRef* args)
00263 {
00264 naRef darg = argc > 0 ? args[0] : naNil();
00265 if(!naIsNil(darg) && c->callChild && IDENTICAL(c->callChild->dieArg, darg))
00266 naRethrowError(c->callChild);
00267 c->dieArg = darg;
00268 naRuntimeError(c, "__die__");
00269 return naNil();
00270 }
00271
00272
00273
00274 static char* dosprintf(char* f, ...)
00275 {
00276 char* buf;
00277 va_list va;
00278 int olen, len = 16;
00279 while(1) {
00280 buf = naAlloc(len);
00281 va_start(va, f);
00282 olen = vsnprintf(buf, len, f, va);
00283 if(olen >= 0 && olen < len) {
00284 va_end(va);
00285 return buf;
00286 }
00287 va_end(va);
00288 naFree(buf);
00289 len *= 2;
00290 }
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
00300 static char* nextFormat(naContext c, char* f, char** out, int* len, char* type)
00301 {
00302
00303 while(*f && *f != '%') f++;
00304 if(!*f) return 0;
00305 *out = f++;
00306
00307 while(*f && (*f=='-' || *f=='+' || *f==' ' || *f=='0' || *f=='#')) f++;
00308
00309
00310
00311 { char *p1, *p2;
00312 for(p1 = *out + 1; p1 < f; p1++)
00313 for(p2 = p1+1; p2 < f; p2++)
00314 if(*p1 == *p2)
00315 naRuntimeError(c, "duplicate flag in format string"); }
00316
00317 while(*f && *f >= '0' && *f <= '9') f++;
00318 if(*f && *f == '.') f++;
00319 while(*f && *f >= '0' && *f <= '9') f++;
00320 if(!*f) naRuntimeError(c, "invalid format string");
00321
00322 *type = *f++;
00323 *len = f - *out;
00324 return f;
00325 }
00326
00327 #define ERR(m) naRuntimeError(c, m)
00328 #define APPEND(r) result = naStr_concat(naNewString(c), result, r)
00329 static naRef f_sprintf(naContext c, naRef me, int argc, naRef* args)
00330 {
00331 char t, nultmp, *fstr, *next, *fout=0, *s;
00332 int flen, argn=1;
00333 naRef format, arg, result = naNewString(c);
00334
00335 if(argc < 1) ERR("not enough arguments to sprintf()");
00336 format = naStringValue(c, argc > 0 ? args[0] : naNil());
00337 if(naIsNil(format)) ERR("bad format string in sprintf()");
00338 s = naStr_data(format);
00339
00340 while((next = nextFormat(c, s, &fstr, &flen, &t))) {
00341 APPEND(NEWSTR(c, s, fstr-s));
00342 if(flen == 2 && fstr[1] == '%') {
00343 APPEND(NEWSTR(c, "%", 1));
00344 s = next;
00345 continue;
00346 }
00347 if(argn >= argc) ERR("not enough arguments to sprintf()");
00348 arg = args[argn++];
00349 nultmp = fstr[flen];
00350 fstr[flen] = 0;
00351 if(t == 's') {
00352 arg = naStringValue(c, arg);
00353 if(naIsNil(arg)) fout = dosprintf(fstr, "nil");
00354 else fout = dosprintf(fstr, naStr_data(arg));
00355 } else {
00356 arg = naNumValue(arg);
00357 if(naIsNil(arg))
00358 fout = dosprintf(fstr, "nil");
00359 else if(t=='d' || t=='i' || t=='c')
00360 fout = dosprintf(fstr, (int)naNumValue(arg).num);
00361 else if(t=='o' || t=='u' || t=='x' || t=='X')
00362 fout = dosprintf(fstr, (unsigned int)naNumValue(arg).num);
00363 else if(t=='e' || t=='E' || t=='f' || t=='F' || t=='g' || t=='G')
00364 fout = dosprintf(fstr, naNumValue(arg).num);
00365 else
00366 ERR("invalid sprintf format type");
00367 }
00368 fstr[flen] = nultmp;
00369 APPEND(NEWSTR(c, fout, strlen(fout)));
00370 naFree(fout);
00371 s = next;
00372 }
00373 APPEND(NEWSTR(c, s, strlen(s)));
00374 return result;
00375 }
00376
00377
00378 static naRef f_caller(naContext c, naRef me, int argc, naRef* args)
00379 {
00380 int fidx;
00381 struct Frame* frame;
00382 naRef result, fr = argc ? naNumValue(args[0]) : naNum(1);
00383 if(IS_NIL(fr)) ARGERR();
00384 fidx = (int)fr.num;
00385 if(fidx > c->fTop - 1) return naNil();
00386 frame = &c->fStack[c->fTop - 1 - fidx];
00387 result = naNewVector(c);
00388 naVec_append(result, frame->locals);
00389 naVec_append(result, frame->func);
00390 naVec_append(result, PTR(PTR(frame->func).func->code).code->srcFile);
00391 naVec_append(result, naNum(naGetLine(c, fidx)));
00392 return result;
00393 }
00394
00395 static naRef f_closure(naContext c, naRef me, int argc, naRef* args)
00396 {
00397 int i;
00398 struct naFunc* f;
00399 naRef func = argc > 0 ? args[0] : naNil();
00400 naRef idx = argc > 1 ? naNumValue(args[1]) : naNum(0);
00401 if(!IS_FUNC(func) || IS_NIL(idx)) ARGERR();
00402 i = (int)idx.num;
00403 f = PTR(func).func;
00404 while(i > 0 && f) { i--; f = PTR(f->next).func; }
00405 if(!f) return naNil();
00406 return f->namespace;
00407 }
00408
00409 static int match(unsigned char* a, unsigned char* b, int l)
00410 {
00411 int i;
00412 for(i=0; i<l; i++) if(a[i] != b[i]) return 0;
00413 return 1;
00414 }
00415
00416 static int find(unsigned char* a, int al, unsigned char* s, int sl, int start)
00417 {
00418 int i;
00419 if(al == 0) return 0;
00420 for(i=start; i<sl-al+1; i++) if(match(a, s+i, al)) return i;
00421 return -1;
00422 }
00423
00424 static naRef f_find(naContext c, naRef me, int argc, naRef* args)
00425 {
00426 int start = 0;
00427 if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) ARGERR();
00428 if(argc > 2) start = (int)(naNumValue(args[2]).num);
00429 return naNum(find((void*)naStr_data(args[0]), naStr_len(args[0]),
00430 (void*)naStr_data(args[1]), naStr_len(args[1]),
00431 start));
00432 }
00433
00434 static naRef f_split(naContext c, naRef me, int argc, naRef* args)
00435 {
00436 int sl, dl, i;
00437 char *s, *d, *s0;
00438 naRef result;
00439 if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) ARGERR();
00440 d = naStr_data(args[0]); dl = naStr_len(args[0]);
00441 s = naStr_data(args[1]); sl = naStr_len(args[1]);
00442 result = naNewVector(c);
00443 if(dl == 0) {
00444 for(i=0; i<sl; i++) naVec_append(result, NEWSTR(c, s+i, 1));
00445 return result;
00446 }
00447 s0 = s;
00448 for(i=0; i <= sl-dl; i++) {
00449 if(match((unsigned char*)(s+i), (unsigned char*)d, dl)) {
00450 naVec_append(result, NEWSTR(c, s0, s+i-s0));
00451 s0 = s + i + dl;
00452 i += dl - 1;
00453 }
00454 }
00455 if(s0 - s <= sl) naVec_append(result, NEWSTR(c, s0, s+sl-s0));
00456 return result;
00457 }
00458
00459
00460
00461
00462
00463 static naRef f_rand(naContext c, naRef me, int argc, naRef* args)
00464 {
00465 int i;
00466 double r = 0;
00467 if(argc) {
00468 if(!IS_NUM(args[0])) naRuntimeError(c, "rand() seed not number");
00469 srand((unsigned int)args[0].num);
00470 return naNil();
00471 }
00472 for(i=0; i<5; i++) r = (r + rand()) * (1.0/(RAND_MAX+1.0));
00473 return naNum(r);
00474 }
00475
00476 static naRef f_bind(naContext c, naRef me, int argc, naRef* args)
00477 {
00478 naRef func = argc > 0 ? args[0] : naNil();
00479 naRef hash = argc > 1 ? args[1] : naNewHash(c);
00480 naRef next = argc > 2 ? args[2] : naNil();
00481 if(!IS_FUNC(func) || (!IS_NIL(next) && !IS_FUNC(next)) || !IS_HASH(hash))
00482 ARGERR();
00483 func = naNewFunc(c, PTR(func).func->code);
00484 PTR(func).func->namespace = hash;
00485 PTR(func).func->next = next;
00486 return func;
00487 }
00488
00489
00490
00491
00492
00493
00494
00495 struct SortData { naContext ctx, subc; struct SortRec* recs;
00496 naRef* elems; int n; naRef fn; };
00497 struct SortRec { struct SortData* sd; int i; };
00498
00499 static int sortcmp(struct SortRec* a, struct SortRec* b)
00500 {
00501 struct SortData* sd = a->sd;
00502 naRef args[2], d;
00503 args[0] = sd->elems[a->i];
00504 args[1] = sd->elems[b->i];
00505 d = naCall(sd->subc, sd->fn, 2, args, naNil(), naNil());
00506 if(naGetError(sd->subc)) {
00507 naFree(sd->recs);
00508 naRethrowError(sd->subc);
00509 } else if(!naIsNum(d = naNumValue(d))) {
00510 naFree(sd->recs);
00511 naRuntimeError(sd->ctx, "sort() comparison returned non-number");
00512 }
00513 return (d.num > 0) ? 1 : ((d.num < 0) ? -1 : (a->i - b->i));
00514 }
00515
00516 static naRef f_sort(naContext c, naRef me, int argc, naRef* args)
00517 {
00518 int i;
00519 struct SortData sd;
00520 naRef out;
00521 if(argc != 2 || !naIsVector(args[0]) || !naIsFunc(args[1]))
00522 naRuntimeError(c, "bad/missing argument to sort()");
00523 sd.subc = naSubContext(c);
00524 if(!PTR(args[0]).vec->rec) return naNewVector(c);
00525 sd.elems = PTR(args[0]).vec->rec->array;
00526 sd.n = PTR(args[0]).vec->rec->size;
00527 sd.fn = args[1];
00528 sd.recs = naAlloc(sizeof(struct SortRec) * sd.n);
00529 for(i=0; i<sd.n; i++) {
00530 sd.recs[i].sd = &sd;
00531 sd.recs[i].i = i;
00532 }
00533 qsort(sd.recs, sd.n, sizeof(sd.recs[0]),
00534 (int(*)(const void*,const void*))sortcmp);
00535 out = naNewVector(c);
00536 naVec_setsize(out, sd.n);
00537 for(i=0; i<sd.n; i++)
00538 PTR(out).vec->rec->array[i] = sd.elems[sd.recs[i].i];
00539 naFree(sd.recs);
00540 naFreeContext(sd.subc);
00541 return out;
00542 }
00543
00544 static naRef f_id(naContext c, naRef me, int argc, naRef* args)
00545 {
00546 char *t = "unk", buf[64];
00547 if(argc != 1 || !IS_REF(args[0]))
00548 naRuntimeError(c, "bad/missing argument to id()");
00549 if (IS_STR(args[0])) t = "str";
00550 else if(IS_VEC(args[0])) t = "vec";
00551 else if(IS_HASH(args[0])) t = "hash";
00552 else if(IS_CODE(args[0])) t = "code";
00553 else if(IS_FUNC(args[0])) t = "func";
00554 else if(IS_CCODE(args[0])) t = "ccode";
00555 else if(IS_GHOST(args[0])) {
00556 naGhostType *gt = PTR(args[0]).ghost->gtype;
00557 t = gt->name ? (char*)gt->name : "ghost";
00558 }
00559 sprintf(buf, "%s:%p", (char*)t, (void*)PTR(args[0]).obj);
00560 return NEWCSTR(c, buf);
00561 }
00562
00563 static naCFuncItem funcs[] = {
00564 { "size", f_size },
00565 { "keys", f_keys },
00566 { "append", f_append },
00567 { "pop", f_pop },
00568 { "setsize", f_setsize },
00569 { "subvec", f_subvec },
00570 { "delete", f_delete },
00571 { "int", f_int },
00572 { "num", f_num },
00573 { "streq", f_streq },
00574 { "cmp", f_cmp },
00575 { "substr", f_substr },
00576 { "chr", f_chr },
00577 { "contains", f_contains },
00578 { "typeof", f_typeof },
00579 { "ghosttype", f_ghosttype },
00580 { "compile", f_compile },
00581 { "call", f_call },
00582 { "die", f_die },
00583 { "sprintf", f_sprintf },
00584 { "caller", f_caller },
00585 { "closure", f_closure },
00586 { "find", f_find },
00587 { "split", f_split },
00588 { "rand", f_rand },
00589 { "bind", f_bind },
00590 { "sort", f_sort },
00591 { "id", f_id },
00592 { 0 }
00593 };
00594
00595 naRef naInit_std(naContext c)
00596 {
00597 return naGenLib(c, funcs);
00598 }