void potion_test_proto(CuTest *T) { // test compiler transformation potion_sig_compile, not just yy_sig PN p2; vPN(Closure) f2; vPN(Closure) f1 = PN_CLOSURE(potion_eval(P, potion_str(P, "(x,y):x+y."))); CuAssertIntEquals(T, "arity f1", 2, potion_sig_arity(P, f1->sig)); CuAssertStrEquals(T, "x,y", PN_STR_PTR(potion_sig_string(P,0,f1->sig))); p2 = PN_FUNC(PN_CLOSURE_F(f1), "x=N,y=N"); f2 = PN_CLOSURE(p2); CuAssertIntEquals(T, "sig arity f2", 2, potion_sig_arity(P, f2->sig)); CuAssertStrEquals(T, "x=N,y=N", PN_STR_PTR(potion_sig_string(P,0,f2->sig))); CuAssertIntEquals(T, "cl arity f2", 2, PN_INT(potion_closure_arity(P,0,p2))); }
PN potion_call(Potion *P, PN cl, PN_SIZE argc, PN * volatile argv) { vPN(Closure) c = PN_CLOSURE(cl); switch (argc) { case 0: return c->method(P, cl, cl); case 1: return c->method(P, cl, argv[0]); case 2: return c->method(P, cl, argv[0], argv[1]); case 3: return c->method(P, cl, argv[0], argv[1], argv[2]); case 4: return c->method(P, cl, argv[0], argv[1], argv[2], argv[3]); case 5: return c->method(P, cl, argv[0], argv[1], argv[2], argv[3], argv[4]); case 6: return c->method(P, cl, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); case 7: return c->method(P, cl, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); case 8: return c->method(P, cl, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]); case 9: return c->method(P, cl, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]); case 10: return c->method(P, cl, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]); case 11: return c->method(P, cl, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]); case 12: return c->method(P, cl, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]); case 13: return c->method(P, cl, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]); case 14: return c->method(P, cl, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]); case 15: return c->method(P, cl, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]); } return PN_NIL; // TODO: error "too many arguments" }
static int potion_database_callback(void *callback, int argc, char **argv, char **azColName) { struct PNCallback * cbp = (struct PNCallback *)callback; if (cbp != NULL) { vPN(Closure) cb = PN_IS_CLOSURE(cbp->cb) ? PN_CLOSURE(cbp->cb) : NULL; if (cb) { Potion *P = cbp->P; PN table = potion_table_empty(P); int i; for (i = 0; i < argc; i++) { potion_table_put(P, PN_NIL, table, PN_STR(azColName[i]), argv[i] ? PN_STR(argv[i]) : PN_NIL); } // Now call the callback with the table cb->method(P, (PN)cb, (PN)cb, (PN)table); } } return 0; }
PN_SIZE potion_type_size(Potion *P, const struct PNObject *ptr) { int sz = 0; switch (((struct PNFwd *)ptr)->fwd) { case POTION_COPIED: case POTION_FWD: sz = ((struct PNFwd *)ptr)->siz; goto done; } if (ptr->vt > PN_TUSER) { sz = sizeof(struct PNObject) + (((struct PNVtable *)PN_VTABLE(ptr->vt))->ivlen * sizeof(PN)); goto done; } switch (ptr->vt) { case PN_TNUMBER: sz = sizeof(struct PNDecimal); break; case PN_TSTRING: sz = sizeof(struct PNString) + PN_STR_LEN(ptr) + 1; break; case PN_TCLOSURE: sz = sizeof(struct PNClosure) + (PN_CLOSURE(ptr)->extra * sizeof(PN)); break; case PN_TTUPLE: sz = sizeof(struct PNTuple) + (sizeof(PN) * ((struct PNTuple *)ptr)->len); break; case PN_TSTATE: sz = sizeof(Potion); break; case PN_TFILE: sz = sizeof(struct PNFile); break; case PN_TVTABLE: sz = sizeof(struct PNVtable); break; case PN_TSOURCE: // TODO: look up ast size (see core/ast.c) sz = sizeof(struct PNSource) + (3 * sizeof(PN)); break; case PN_TBYTES: sz = sizeof(struct PNBytes) + ((struct PNBytes *)ptr)->siz; break; case PN_TPROTO: sz = sizeof(struct PNProto); break; case PN_TTABLE: sz = sizeof(struct PNTable) + kh_mem(PN, ptr); break; case PN_TSTRINGS: sz = sizeof(struct PNTable) + kh_mem(str, ptr); break; case PN_TFLEX: sz = sizeof(PNFlex) + ((PNFlex *)ptr)->siz; break; case PN_TCONT: sz = sizeof(struct PNCont) + (((struct PNCont *)ptr)->len * sizeof(PN)); break; case PN_TUSER: sz = sizeof(struct PNData) + ((struct PNData *)ptr)->siz; break; } done: if (sz < sizeof(struct PNFwd)) sz = sizeof(struct PNFwd); return PN_ALIGN(sz, 8); // force 64-bit alignment }
static void potion_cmd_compile ( char *filename, int exec, int verbose, void *sp ) { PN buf, code; int fd = -1; struct stat stats; Potion *P = potion_create(sp); if (stat(filename, &stats) == -1) { potion_warn("** %s does not exist.\n", filename); goto done; } fd = open(filename, O_RDONLY | O_BINARY); if (fd == -1) { potion_warn("** could not open %s. check permissions.\n", filename); goto done; } buf = potion_bytes(P, stats.st_size); if (read(fd, PN_STR_PTR(buf), stats.st_size) == stats.st_size) { PN_STR_PTR(buf)[stats.st_size] = '\0'; code = potion_source_load(P, PN_NIL, buf); if (PN_IS_PROTO(code)) { if (verbose > 1) printf("\n\n-- loaded --\n"); } else { code = potion_parse(P, buf); if (PN_TYPE(code) == PN_TERROR) { potion_send(potion_send(code, PN_string), PN_print); goto done; } if (verbose > 1) { printf("\n-- parsed --\n"); potion_send(potion_send(code, PN_string), PN_print); printf("\n"); } code = potion_send(code, PN_compile, potion_str(P, filename), PN_NIL); if (verbose > 1) printf("\n-- compiled --\n"); } if (verbose > 1) { potion_send(potion_send(code, PN_string), PN_print); printf("\n"); } if (exec == 1) { code = potion_vm(P, code, P->lobby, PN_NIL, 0, NULL ); if (verbose > 1) printf( "\n-- vm returned %p (fixed=%ld, actual=%ld, reserved=%ld) --\n", (void *) code, PN_INT(potion_gc_fixed(P, 0, 0)), PN_INT(potion_gc_actual(P, 0, 0)), PN_INT(potion_gc_reserved(P, 0, 0))); if (verbose) { potion_send(potion_send(code, PN_string), PN_print); printf("\n"); } } else if (exec == 2) { #if POTION_JIT == 1 PN val; PN cl = potion_closure_new(P, (PN_F)potion_jit_proto(P, code, POTION_JIT_TARGET), PN_NIL, 1); PN_CLOSURE(cl)->data[0] = code; val = PN_PROTO(code)->jit(P, cl, P->lobby); if (verbose > 1) printf("\n-- jit returned %p (fixed=%ld, actual=%ld, reserved=%ld) --\n", PN_PROTO(code)->jit, PN_INT(potion_gc_fixed(P, 0, 0)), PN_INT(potion_gc_actual(P, 0, 0)), PN_INT(potion_gc_reserved(P, 0, 0))); if (verbose) { potion_send(potion_send(val, PN_string), PN_print); printf("\n"); } #else potion_warn("** potion built without JIT support\n"); #endif } else { char pnbpath[255]; FILE *pnb; sprintf(pnbpath, "%sb", filename); pnb = fopen(pnbpath, "wb"); if (!pnb) { potion_warn("** could not open %s for writing. check permissions.\n",pnbpath); goto done; } code = potion_source_dump(P, PN_NIL, code); if (fwrite(PN_STR_PTR(code), 1, PN_STR_LEN(code), pnb) == PN_STR_LEN(code)) { potion_notice("** compiled code saved to %s\n", pnbpath); potion_notice("** run it with: potion %s\n", pnbpath); fclose(pnb); } else { potion_warn("** could not write all bytecode.\n"); } } #if 0 void *scanptr = (void *)((char *)P->mem->old_lo + (sizeof(PN) * 2)); while ((PN)scanptr < (PN)P->mem->old_cur) { printf("%p.vt = %lx (%u)\n", scanptr, ((struct PNObject *)scanptr)->vt, potion_type_size(P, scanptr)); if (((struct PNFwd *)scanptr)->fwd != POTION_FWD && ((struct PNFwd *)scanptr)->fwd != POTION_COPIED) { if (((struct PNObject *)scanptr)->vt < 0 || ((struct PNObject *)scanptr)->vt > PN_TUSER) { printf("wrong type for allocated object: %p.vt = %lx\n", scanptr, ((struct PNObject *)scanptr)->vt); break; } } scanptr = (void *)((char *)scanptr + potion_type_size(P, scanptr)); if ((PN)scanptr > (PN)P->mem->old_cur) { printf("allocated object goes beyond GC pointer\n"); break; } } #endif } else { potion_warn("** could not read entire file."); } done: if (fd != -1) close(fd); if (P != NULL ) potion_destroy(P); }
PN_SIZE potion_type_size(Potion *P, const struct PNObject *ptr) { int sz = 0; switch (((struct PNFwd *)ptr)->fwd) { case POTION_COPIED: case POTION_FWD: sz = ((struct PNFwd *)ptr)->siz; goto done; } if (ptr->vt < PN_TNIL) goto err; if (ptr->vt > PN_TUSER) { if (P->vts && ptr->vt < P->vts->len && PN_VTABLE(ptr->vt) && PN_TYPECHECK(ptr->vt)) { sz = sizeof(struct PNObject) + (((struct PNVtable *)PN_VTABLE(ptr->vt))->ivlen * sizeof(PN)); //sz = potion_send((PN)ptr, PN_size); //cannot use bind with POTION_COPIED objs during GC! } else { err: if (P->flags & (DEBUG_VERBOSE #ifdef DEBUG |DEBUG_GC #endif )) fprintf(stderr, "** Invalid User Object 0x%lx vt: 0x%lx\n", (unsigned long)ptr, (unsigned long)ptr->vt); return 0; } goto done; } switch (ptr->vt) { case PN_TNUMBER: sz = sizeof(struct PNDecimal); break; case PN_TSTRING: sz = sizeof(struct PNString) + PN_STR_LEN(ptr) + 1; break; case PN_TCLOSURE: sz = sizeof(struct PNClosure) + (PN_CLOSURE(ptr)->extra * sizeof(PN)); break; case PN_TTUPLE: sz = sizeof(struct PNTuple) + (sizeof(PN) * ((struct PNTuple *)ptr)->alloc); break; case PN_TSTATE: sz = sizeof(Potion); break; case PN_TFILE: sz = sizeof(struct PNFile); break; case PN_TVTABLE: sz = sizeof(struct PNVtable); break; case PN_TSOURCE: sz = sizeof(struct PNSource); break; case PN_TBYTES: sz = sizeof(struct PNBytes) + ((struct PNBytes *)ptr)->siz; break; case PN_TPROTO: sz = sizeof(struct PNProto); break; case PN_TTABLE: sz = sizeof(struct PNTable) + kh_mem(PN, ptr); break; case PN_TLICK: sz = sizeof(struct PNLick); break; case PN_TSTRINGS: sz = sizeof(struct PNTable) + kh_mem(str, ptr); break; case PN_TFLEX: sz = sizeof(PNFlex) + ((PNFlex *)ptr)->siz; break; case PN_TCONT: sz = sizeof(struct PNCont) + (((struct PNCont *)ptr)->len * sizeof(PN)); break; case PN_TUSER: sz = sizeof(struct PNData) + ((struct PNData *)ptr)->siz; break; } done: if (sz < sizeof(struct PNFwd)) sz = sizeof(struct PNFwd); return PN_ALIGN(sz, 8); // force 64-bit alignment }