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 static naRef f_call(naContext c, naRef me, int argc, naRef* args)
00218 {
00219 naContext subc;
00220 naRef callargs, callme, callns, result;
00221 struct VecRec* vr;
00222 callargs = argc > 1 ? args[1] : naNil();
00223 callme = argc > 2 ? args[2] : naNil();
00224 callns = argc > 3 ? args[3] : naNil();
00225 if(!IS_HASH(callme)) callme = naNil();
00226 if(!IS_HASH(callns)) callns = naNil();
00227 if(argc==0 || !IS_FUNC(args[0]) || (!IS_NIL(callargs) && !IS_VEC(callargs)))
00228 ARGERR();
00229
00230 subc = naSubContext(c);
00231 vr = IS_NIL(callargs) ? 0 : PTR(callargs).vec->rec;
00232 result = naCall(subc, args[0], vr ? vr->size : 0, vr ? vr->array : 0,
00233 callme, callns);
00234 if(!naGetError(subc)) {
00235 naFreeContext(subc);
00236 return result;
00237 }
00238
00239
00240
00241
00242 if(argc <= 2 || !IS_VEC(args[argc-1])) {
00243 naRethrowError(subc);
00244 } else {
00245 int i, sd;
00246 naRef errv = args[argc-1];
00247 if(!IS_NIL(subc->dieArg)) naVec_append(errv, subc->dieArg);
00248 else naVec_append(errv, NEWCSTR(subc, naGetError(subc)));
00249 sd = naStackDepth(subc);
00250 for(i=0; i<sd; i++) {
00251 naVec_append(errv, naGetSourceFile(subc, i));
00252 naVec_append(errv, naNum(naGetLine(subc, i)));
00253 }
00254 }
00255 return naNil();
00256 }
00257
00258 static naRef f_die(naContext c, naRef me, int argc, naRef* args)
00259 {
00260 naRef darg = argc > 0 ? args[0] : naNil();
00261 if(!naIsNil(darg) && c->callChild && IDENTICAL(c->callChild->dieArg, darg))
00262 naRethrowError(c->callChild);
00263 c->dieArg = darg;
00264 naRuntimeError(c, "__die__");
00265 return naNil();
00266 }
00267
00268
00269
00270 static char* dosprintf(char* f, ...)
00271 {
00272 char* buf;
00273 va_list va;
00274 int olen, len = 16;
00275 while(1) {
00276 buf = naAlloc(len);
00277 va_start(va, f);
00278 olen = vsnprintf(buf, len, f, va);
00279 if(olen >= 0 && olen < len) {
00280 va_end(va);
00281 return buf;
00282 }
00283 va_end(va);
00284 naFree(buf);
00285 len *= 2;
00286 }
00287 }
00288
00289
00290
00291
00292
00293
00294
00295
00296 static char* nextFormat(naContext c, char* f, char** out, int* len, char* type)
00297 {
00298
00299 while(*f && *f != '%') f++;
00300 if(!*f) return 0;
00301 *out = f++;
00302
00303 while(*f && (*f=='-' || *f=='+' || *f==' ' || *f=='0' || *f=='#')) f++;
00304
00305
00306
00307 { char *p1, *p2;
00308 for(p1 = *out + 1; p1 < f; p1++)
00309 for(p2 = p1+1; p2 < f; p2++)
00310 if(*p1 == *p2)
00311 naRuntimeError(c, "duplicate flag in format string"); }
00312
00313 while(*f && *f >= '0' && *f <= '9') f++;
00314 if(*f && *f == '.') f++;
00315 while(*f && *f >= '0' && *f <= '9') f++;
00316 if(!*f) naRuntimeError(c, "invalid format string");
00317
00318 *type = *f++;
00319 *len = f - *out;
00320 return f;
00321 }
00322
00323 #define ERR(m) naRuntimeError(c, m)
00324 #define APPEND(r) result = naStr_concat(naNewString(c), result, r)
00325 static naRef f_sprintf(naContext c, naRef me, int argc, naRef* args)
00326 {
00327 char t, nultmp, *fstr, *next, *fout=0, *s;
00328 int flen, argn=1;
00329 naRef format, arg, result = naNewString(c);
00330
00331 if(argc < 1) ERR("not enough arguments to sprintf()");
00332 format = naStringValue(c, argc > 0 ? args[0] : naNil());
00333 if(naIsNil(format)) ERR("bad format string in sprintf()");
00334 s = naStr_data(format);
00335
00336 while((next = nextFormat(c, s, &fstr, &flen, &t))) {
00337 APPEND(NEWSTR(c, s, fstr-s));
00338 if(flen == 2 && fstr[1] == '%') {
00339 APPEND(NEWSTR(c, "%", 1));
00340 s = next;
00341 continue;
00342 }
00343 if(argn >= argc) ERR("not enough arguments to sprintf()");
00344 arg = args[argn++];
00345 nultmp = fstr[flen];
00346 fstr[flen] = 0;
00347 if(t == 's') {
00348 arg = naStringValue(c, arg);
00349 if(naIsNil(arg)) fout = dosprintf(fstr, "nil");
00350 else fout = dosprintf(fstr, naStr_data(arg));
00351 } else {
00352 arg = naNumValue(arg);
00353 if(naIsNil(arg))
00354 fout = dosprintf(fstr, "nil");
00355 else if(t=='d' || t=='i' || t=='c')
00356 fout = dosprintf(fstr, (int)naNumValue(arg).num);
00357 else if(t=='o' || t=='u' || t=='x' || t=='X')
00358 fout = dosprintf(fstr, (unsigned int)naNumValue(arg).num);
00359 else if(t=='e' || t=='E' || t=='f' || t=='F' || t=='g' || t=='G')
00360 fout = dosprintf(fstr, naNumValue(arg).num);
00361 else
00362 ERR("invalid sprintf format type");
00363 }
00364 fstr[flen] = nultmp;
00365 APPEND(NEWSTR(c, fout, strlen(fout)));
00366 naFree(fout);
00367 s = next;
00368 }
00369 APPEND(NEWSTR(c, s, strlen(s)));
00370 return result;
00371 }
00372
00373
00374 static naRef f_caller(naContext c, naRef me, int argc, naRef* args)
00375 {
00376 int fidx;
00377 struct Frame* frame;
00378 naRef result, fr = argc ? naNumValue(args[0]) : naNum(1);
00379 if(IS_NIL(fr)) ARGERR();
00380 fidx = (int)fr.num;
00381 if(fidx > c->fTop - 1) return naNil();
00382 frame = &c->fStack[c->fTop - 1 - fidx];
00383 result = naNewVector(c);
00384 naVec_append(result, frame->locals);
00385 naVec_append(result, frame->func);
00386 naVec_append(result, PTR(PTR(frame->func).func->code).code->srcFile);
00387 naVec_append(result, naNum(naGetLine(c, fidx)));
00388 return result;
00389 }
00390
00391 static naRef f_closure(naContext c, naRef me, int argc, naRef* args)
00392 {
00393 int i;
00394 struct naFunc* f;
00395 naRef func = argc > 0 ? args[0] : naNil();
00396 naRef idx = argc > 1 ? naNumValue(args[1]) : naNum(0);
00397 if(!IS_FUNC(func) || IS_NIL(idx)) ARGERR();
00398 i = (int)idx.num;
00399 f = PTR(func).func;
00400 while(i > 0 && f) { i--; f = PTR(f->next).func; }
00401 if(!f) return naNil();
00402 return f->namespace;
00403 }
00404
00405 static int match(unsigned char* a, unsigned char* b, int l)
00406 {
00407 int i;
00408 for(i=0; i<l; i++) if(a[i] != b[i]) return 0;
00409 return 1;
00410 }
00411
00412 static int find(unsigned char* a, int al, unsigned char* s, int sl, int start)
00413 {
00414 int i;
00415 if(al == 0) return 0;
00416 for(i=start; i<sl-al+1; i++) if(match(a, s+i, al)) return i;
00417 return -1;
00418 }
00419
00420 static naRef f_find(naContext c, naRef me, int argc, naRef* args)
00421 {
00422 int start = 0;
00423 if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) ARGERR();
00424 if(argc > 2) start = (int)(naNumValue(args[2]).num);
00425 return naNum(find(PTR(args[0]).str->data, PTR(args[0]).str->len,
00426 PTR(args[1]).str->data, PTR(args[1]).str->len,
00427 start));
00428 }
00429
00430 static naRef f_split(naContext c, naRef me, int argc, naRef* args)
00431 {
00432 int sl, dl, i;
00433 char *s, *d, *s0;
00434 naRef result;
00435 if(argc < 2 || !IS_STR(args[0]) || !IS_STR(args[1])) ARGERR();
00436 d = naStr_data(args[0]); dl = naStr_len(args[0]);
00437 s = naStr_data(args[1]); sl = naStr_len(args[1]);
00438 result = naNewVector(c);
00439 if(dl == 0) {
00440 for(i=0; i<sl; i++) naVec_append(result, NEWSTR(c, s+i, 1));
00441 return result;
00442 }
00443 s0 = s;
00444 for(i=0; i <= sl-dl; i++) {
00445 if(match((unsigned char*)(s+i), (unsigned char*)d, dl)) {
00446 naVec_append(result, NEWSTR(c, s0, s+i-s0));
00447 s0 = s + i + dl;
00448 i += dl - 1;
00449 }
00450 }
00451 if(s0 - s <= sl) naVec_append(result, NEWSTR(c, s0, s+sl-s0));
00452 return result;
00453 }
00454
00455
00456
00457
00458
00459 static naRef f_rand(naContext c, naRef me, int argc, naRef* args)
00460 {
00461 int i;
00462 double r = 0;
00463 if(argc) {
00464 if(!IS_NUM(args[0])) naRuntimeError(c, "rand() seed not number");
00465 srand((unsigned int)args[0].num);
00466 return naNil();
00467 }
00468 for(i=0; i<5; i++) r = (r + rand()) * (1.0/(RAND_MAX+1.0));
00469 return naNum(r);
00470 }
00471
00472 static naRef f_bind(naContext c, naRef me, int argc, naRef* args)
00473 {
00474 naRef func = argc > 0 ? args[0] : naNil();
00475 naRef hash = argc > 1 ? args[1] : naNewHash(c);
00476 naRef next = argc > 2 ? args[2] : naNil();
00477 if(!IS_FUNC(func) || (!IS_NIL(next) && !IS_FUNC(next)) || !IS_HASH(hash))
00478 ARGERR();
00479 func = naNewFunc(c, PTR(func).func->code);
00480 PTR(func).func->namespace = hash;
00481 PTR(func).func->next = next;
00482 return func;
00483 }
00484
00485
00486
00487
00488
00489
00490
00491 struct SortData { naContext ctx, subc; struct SortRec* recs;
00492 naRef* elems; int n; naRef fn; };
00493 struct SortRec { struct SortData* sd; int i; };
00494
00495 static int sortcmp(struct SortRec* a, struct SortRec* b)
00496 {
00497 struct SortData* sd = a->sd;
00498 naRef args[2], d;
00499 args[0] = sd->elems[a->i];
00500 args[1] = sd->elems[b->i];
00501 d = naCall(sd->subc, sd->fn, 2, args, naNil(), naNil());
00502 if(naGetError(sd->subc)) {
00503 naFree(sd->recs);
00504 naRethrowError(sd->subc);
00505 } else if(!naIsNum(d = naNumValue(d))) {
00506 naFree(sd->recs);
00507 naRuntimeError(sd->ctx, "sort() comparison returned non-number");
00508 }
00509 return (d.num > 0) ? 1 : ((d.num < 0) ? -1 : (a->i - b->i));
00510 }
00511
00512 static naRef f_sort(naContext c, naRef me, int argc, naRef* args)
00513 {
00514 int i;
00515 struct SortData sd;
00516 naRef out;
00517 if(argc != 2 || !naIsVector(args[0]) || !naIsFunc(args[1]))
00518 naRuntimeError(c, "bad/missing argument to sort()");
00519 sd.subc = naSubContext(c);
00520 if(!PTR(args[0]).vec->rec) return naNewVector(c);
00521 sd.elems = PTR(args[0]).vec->rec->array;
00522 sd.n = PTR(args[0]).vec->rec->size;
00523 sd.fn = args[1];
00524 sd.recs = naAlloc(sizeof(struct SortRec) * sd.n);
00525 for(i=0; i<sd.n; i++) {
00526 sd.recs[i].sd = &sd;
00527 sd.recs[i].i = i;
00528 }
00529 qsort(sd.recs, sd.n, sizeof(sd.recs[0]),
00530 (int(*)(const void*,const void*))sortcmp);
00531 out = naNewVector(c);
00532 naVec_setsize(out, sd.n);
00533 for(i=0; i<sd.n; i++)
00534 PTR(out).vec->rec->array[i] = sd.elems[sd.recs[i].i];
00535 naFree(sd.recs);
00536 naFreeContext(sd.subc);
00537 return out;
00538 }
00539
00540 static naCFuncItem funcs[] = {
00541 { "size", f_size },
00542 { "keys", f_keys },
00543 { "append", f_append },
00544 { "pop", f_pop },
00545 { "setsize", f_setsize },
00546 { "subvec", f_subvec },
00547 { "delete", f_delete },
00548 { "int", f_int },
00549 { "num", f_num },
00550 { "streq", f_streq },
00551 { "cmp", f_cmp },
00552 { "substr", f_substr },
00553 { "chr", f_chr },
00554 { "contains", f_contains },
00555 { "typeof", f_typeof },
00556 { "ghosttype", f_ghosttype },
00557 { "compile", f_compile },
00558 { "call", f_call },
00559 { "die", f_die },
00560 { "sprintf", f_sprintf },
00561 { "caller", f_caller },
00562 { "closure", f_closure },
00563 { "find", f_find },
00564 { "split", f_split },
00565 { "rand", f_rand },
00566 { "bind", f_bind },
00567 { "sort", f_sort },
00568 { 0 }
00569 };
00570
00571 naRef naInit_std(naContext c)
00572 {
00573 return naGenLib(c, funcs);
00574 }