26 #define PN_ASM1(ins, _a) f->asmb = (PN)potion_asm_op(P, (PNAsm *)f->asmb, (u8)ins, (int)_a, 0)
27 #define PN_ASM2(ins, _a, _b) f->asmb = (PN)potion_asm_op(P, (PNAsm *)f->asmb, (u8)ins, (int)_a, (int)_b)
33 {
"noop", 0}, {
"move", 2}, {
"loadk", 2}, {
"loadpn", 2}, {
"self", 1},
34 {
"newtuple", 2}, {
"gettuple", 2}, {
"settuple", 2}, {
"getlocal", 2}, {
"setlocal", 2},
35 {
"getupval", 2}, {
"setupval", 2}, {
"global", 2}, {
"gettable", 2},
36 {
"settable", 2}, {
"newlick", 2}, {
"getpath", 2}, {
"setpath", 2},
37 {
"add", 2}, {
"sub", 2}, {
"mult", 2}, {
"div", 2}, {
"mod", 2}, {
"pow", 2},
38 {
"not", 1}, {
"cmp", 2}, {
"eq", 2}, {
"neq", 2}, {
"lt", 2}, {
"lte", 2},
39 {
"gt", 2}, {
"gte", 2}, {
"bitn", 2}, {
"bitl", 2}, {
"bitr", 2}, {
"def", 2},
40 {
"bind", 2}, {
"msg", 2}, {
"jump", 1}, {
"test", 2}, {
"testjmp", 2},
41 {
"notjmp", 2}, {
"named", 2}, {
"call", 2}, {
"callset", 2}, {
"tailcall", 2},
42 {
"return", 1}, {
"proto", 2}, {
"class", 2}, {
"debug", 2}
67 for (i = 0; i < t->
len; i++) {
71 int c =
PN_INT(v); comma=0;
76 else if (c ==
':') { nextdef = 1;
81 if (nextdef) { nextdef = 0;
116 pn_printf(P, out,
".path /");
117 v = PN_TUPLE_AT(t->values, PN_INT(v));
118 potion_bytes_obj_string(P, out, v);
119 pn_printf(P, out,
" ; %u\n", i);
122 pn_printf(P, out,
".local ");
123 potion_bytes_obj_string(P, out, v);
124 pn_printf(P, out,
" ; %u\n", i);
127 pn_printf(P, out,
".upval ");
128 potion_bytes_obj_string(P, out, v);
129 pn_printf(P, out,
" ; %u\n", i);
132 pn_printf(P, out,
".value ");
133 potion_bytes_obj_string(P, out, v);
134 pn_printf(P, out,
" ; %u\n", i);
137 potion_bytes_obj_string(P, out, v);
141 const int commentoffset = 20;
142 int width =
pn_printf(P, out,
"[%*u] %-8s %d",
148 if (width < commentoffset)
149 pn_printf(P, out,
"%*s", commentoffset - width,
"");
154 switch (
PN_OP_AT(t->asmb, x).code) {
184 #define PN_REG(f, reg) \
185 if (reg >= PN_INT(f->stack)) \
186 f->stack = PN_NUM(reg + 1)
189 #define PN_ARG(n, reg) \
190 if (PN_PART(t->a[n]) == AST_LIST && PN_PART(PN_TUPLE_AT(PN_S(t->a[n],0), 0)) == AST_EXPR) { \
191 PN test = PN_S(PN_TUPLE_AT(PN_S(t->a[n],0), 0), 0); \
192 if (!PN_IS_NIL(test)) { \
193 DBG_c("list (expr %s) => %s\n", AS_STR(test), AS_STR(test)); \
194 PN_TUPLE_EACH(test, i, v, { \
195 potion_source_asmb(P, f, loop, 0, PN_SRC(v), reg); }); \
198 potion_source_asmb(P, f, loop, 0, t->a[n], reg); \
201 #define PN_ARG(n, reg) \
202 if (PN_PART(t->a[n]) == AST_EXPR && PN_PART(PN_TUPLE_AT(PN_S(t->a[n],0), 0)) == AST_LIST) { \
203 PN test = PN_S(PN_TUPLE_AT(PN_S(t->a[n],0), 0), 0); \
204 if (!PN_IS_NIL(test)) { \
205 DBG_c("expr (list %s) => %s\n", AS_STR(test), AS_STR(test)); \
206 PN_TUPLE_EACH(test, i, v, { \
207 potion_source_asmb(P, f, loop, 0, PN_SRC(v), reg); }); \
210 potion_source_asmb(P, f, loop, 0, t->a[n], reg); \
213 #define PN_BLOCK(reg, blk, sig) ({ \
214 PN block = potion_send(blk, PN_compile, (PN)f, sig); \
215 PN_SIZE num = PN_PUT(f->protos, block); \
216 DBG_c("protos => %u\n", num); \
217 PN_ASM2(OP_PROTO, reg, num); \
218 PN_TUPLE_EACH(((struct PNProto *)block)->upvals, i, v, { \
219 PN_SIZE numup = PN_GET(f->upvals, v); \
220 DBG_c("upvals %s <= %d\n", AS_STR(v), (int)numup); \
221 if (numup != PN_NONE) PN_ASM2(OP_GETUPVAL, reg, numup); \
222 else PN_ASM2(OP_GETLOCAL, reg, PN_GET(f->locals, v)); \
225 #define PN_UPVAL(name) ({ \
226 PN_SIZE numl = PN_GET(f->locals, name); \
227 DBG_c("locals %s <= %d\n", AS_STR(name), (int)numl); \
228 PN_SIZE numup = PN_NONE; \
229 if (numl == PN_NONE) { \
230 numup = PN_GET(f->upvals, name); \
231 if (numup == PN_NONE) { \
232 DBG_c("upvals %s <= -1\n", AS_STR(name)); \
235 while (PN_IS_PROTO(up->source)) { \
236 up = (struct PNProto *)up->source; \
237 if (PN_NONE != (numup = PN_GET(up->locals, name))) break; \
240 DBG_c("locals %s <= %d\n", AS_STR(name), (int)numup); \
241 if (numup != PN_NONE) { \
244 up->upvals = PN_PUSH(up->upvals, name); \
245 DBG_c("upvals %s =>\n", AS_STR(name)); \
246 up = (struct PNProto *)up->source; \
249 numup = PN_GET(f->upvals, name); \
250 DBG_c("upvals %s <= %d\n", AS_STR(name), (int)numup); \
255 #define PN_ARG_TABLE(args, reg, inc) potion_arg_asmb(P, f, loop, args, ®, inc)
256 #define SRC_TUPLE_AT(src,i) PN_SRC(PN_TUPLE_AT(PN_S(src,0), i))
257 #define PN_ASM_DEBUG(REG, T) REG = potion_source_debug(P, f, T, REG)
265 lineno = t->loc.lineno;
271 #define MAX_JUMPS 1024
290 DBG_c(
"ARGLIST %d %d\n", freg, sreg);
307 DBG_c(
"values %d %s => %d\n", sreg,
AS_STR(lhs->a[0]), (
int)num);
374 vPN(Source) msg = a->a[0];
421 DBG_c(
"values %d %s => %d\n", reg,
AS_STR(a), (
int)num);
432 DBG_c(
"; call %d %d VALUE\n", reg, breg);
439 vPN(Source) lhs = t->
a[0];
446 DBG_c(
"assign expr [%lu]\n", (
_PN)c);
447 for (i = 0; i < c; i++) {
458 DBG_c(
"assign %s '%s'\n", lhs->part ==
AST_MSG?
"msg":
"query",
462 if ((first_letter & 0x80) == 0 && isupper((
unsigned char)first_letter)) {
464 DBG_c(
"values %d %s => %d\n", breg,
AS_STR(lhs->a[0]), (
int)num);
474 DBG_c(
"locals %s => %d\n",
AS_STR(lhs->a[0]), (
int)num);
476 #if 0 // store func names
480 DBG_c(
"getlocal %s %ld = %s\n",
487 DBG_c(
"values %d %s => %d\n", breg+1,
AS_STR(lhs->a[0]), (
int)num);
495 DBG_c(
"values %d %s => %d\n", breg+1,
AS_STR(lhs->a[0]), (
int)num);
498 DBG_c(
"paths %d\n", (
int)num);
508 else if (lhs->a[1] !=
PN_NIL) {
511 DBG_c(
"; callset %d %d ASSIGN\n", reg, breg);
516 DBG_c(
"; call %d %d ASSIGN\n", reg, breg);
531 DBG_c(
"setlocal %d %d\n", reg, (
int)num);
550 vPN(Source) lhs = t->
a[0];
555 DBG_c(
"locals %s => %d\n",
AS_STR(lhs->a[0]), (
int)num);
628 PN class = potion_require(P, name);
640 DBG_c(
"expr (msg if, (cond)), block => expr (msg if, (cond), block)\n");
641 if (P->
flags & MODE_P2) {
647 "%s statement used as expr only valid with use p2;",
"if");
652 ifconst =
PN_S(t->
a[1], 0);
654 DBG_c(
"if (true) {block} => block\n");
657 DBG_c(
"if (false) {block} => \n");
672 DBG_c(
"expr (msg elsif, (cond)), block => expr (msg elsif, (cond), block)\n");
673 if (P->
flags & MODE_P2) {
679 "%s statement used as expr only valid with use p2;",
"elsif");
684 DBG_c(
"elsif (...) {block} => [false]\n");
686 ifconst =
PN_S(t->
a[1], 0);
688 DBG_c(
"elsif (true) {block} => block\n");
691 DBG_c(
"elsif (false) {block} =>\n");
707 DBG_c(
"expr (msg else), block => expr (msg else, block)\n");
708 if (P->
flags & MODE_P2) {
713 "%s statement used as expr only valid with use p2;",
"else");
719 DBG_c(
"else {block} => block [false]\n");
722 DBG_c(
"else {block} => [true]\n");
744 PN_STRN(
"self", 4), blk->loc.lineno, 0)),
745 blk->loc.lineno, blk->line));
758 PN_F sym = (
PN_F)dlsym(RTLD_DEFAULT, name);
759 DBG_c(
"extern %s => dlsym %p\n", name, sym);
761 fprintf(stderr,
"* extern %s not found. You may need to load a library first\n",
777 for (i=0; i <
arity; i++) {
782 DBG_c(
"extern %s %d-th arg => PN_INT(N)\n", name, i);
785 }
else if (arg ==
PN_STR(
"S") || arg ==
PN_STR(
"char*")) {
786 DBG_c(
"extern %s %d-th arg => PN_STR_PTR(S)\n", name, i);
790 fprintf(stderr,
"* unknown extern %s argument type qualifier\n",
810 }
else if (
PN_S(t,1) || !t->
a[2]) {
826 for (i = 0; i < l.
bjmpc; i++) {
829 for (i = 0; i < l.
cjmpc; i++) {
872 DBG_c(
"values %d %s => %d\n", reg,
AS_STR(t->
a[0]), (
int)num);
893 #define LOAD_ARG() PN_ARG_TABLE(PN_S(t,1), breg, 1)
914 DBG_c(
"; call %d %d MSG\n", reg, breg);
918 DBG_c(
"; call %d %d !MSG\n", reg, breg);
935 DBG_c(
"; call %d %d\n", reg, breg);
947 DBG_c(
"values %d %s => %d\n", reg,
AS_STR(t->
a[0]), (
int)num);
950 DBG_c(
"paths %d\n", (
int)num);
964 DBG_c(
"values %d %s => %d\n", reg,
AS_STR(t->
a[0]), (
int)num);
990 DBG_c(
"values %d %s => %d\n", reg+1,
AS_STR(lhs->a[0]), (
int)num);
1013 #define SIG_EXPR_MSG(name,expr) \
1014 if (expr->part == AST_EXPR) { \
1015 vPN(Source) t = SRC_TUPLE_AT(expr, 0); \
1016 if (t->part == AST_MSG) { \
1018 PN_PUT(f->locals, name); \
1019 DBG_c("locals %s\n", PN_STR_PTR(name)); \
1020 sig = PN_PUSH(sig, name); \
1022 } else { name = PN_NIL; }
1062 if (__tv->
len != 0) {
1063 DBG_c(
"--- sig compile ---\n");
1065 for (i = 0; i < __tv->
len; i++) {
1072 vPN(Source) lhs = expr->a[0];
1075 DBG_c(
"sig: lhs value, computed name %s\n",
AS_STR(v));
1081 "in signature: value %s as argument name",
AS_STR(v));
1083 }
else if (expr->part ==
AST_PIPE) {
1084 vPN(Source) lhs = expr->a[0];
1085 vPN(Source) rhs = expr->a[1];
1092 vPN(Source) lhs = expr->a[0];
1093 vPN(Source) rhs = expr->a[1];
1174 DBG_c(
"-- compile --\n");
1200 n->source = f->source;
1201 n->stack = f->stack;
1209 n->localsize = f->localsize;
1210 n->upvalsize = f->upvalsize;
1211 n->pathsize = f->pathsize;
1214 len = ((
PNAsm *)f->asmb)->len;
1223 #define READ_U8(ptr) ({u8 rpu = *ptr; ptr += sizeof(u8); rpu;})
1224 #define READ_PN(pn, ptr) ({PN rpn = *(PN *)ptr; ptr += pn; rpn;})
1225 #define READ_CONST(pn, ptr) ({ \
1226 PN val = READ_PN(pn, ptr); \
1227 if (PN_IS_PTR(val)) { \
1229 size_t len = ((val ^ 2) >> 4) - 1; \
1230 val = potion_strtod(P, (char *)ptr, len); \
1233 size_t len = (val >> 4) - 1; \
1234 val = PN_STRN((char *)ptr, len); \
1241 #define READ_TUPLE(ptr) \
1242 long i = 0, count = READ_U8(ptr); \
1243 PN tup = potion_tuple_with_size(P, (PN_SIZE)count); \
1244 for (; i < count; i++)
1245 #define READ_VALUES(pn, ptr) ({ \
1246 READ_TUPLE(ptr) PN_TUPLE_AT(tup, i) = READ_CONST(pn, ptr); \
1249 #define READ_PROTOS(pn, ptr) ({ \
1250 READ_TUPLE(ptr) PN_TUPLE_AT(tup, i) = potion_proto_load(P, (PN)f, pn, &(ptr)); \
1262 if (f->source ==
PN_NIL) f->source = up;
1300 #define WRITE_U8(un, ptr) ({*ptr = (u8)un; ptr += sizeof(u8);})
1301 #define WRITE_PN(pn, ptr) ({*(PN *)ptr = pn; ptr += sizeof(PN);})
1302 #define WRITE_CONST(val, ptr) ({ \
1303 if (PN_IS_STR(val)) { \
1304 PN count = (PN_STR_LEN(val)+1) << 4; \
1305 WRITE_PN(count, ptr); \
1306 PN_MEMCPY_N(ptr, PN_STR_PTR(val), char, PN_STR_LEN(val)); \
1307 ptr += PN_STR_LEN(val); \
1308 } else if (PN_IS_DBL(val)) { \
1309 PN str = potion_num_string(P, PN_NIL, val); \
1310 PN count = ((PN_STR_LEN(str)+1) << 4) | 2; \
1311 WRITE_PN(count, ptr); \
1312 PN_MEMCPY_N(ptr, PN_STR_PTR(str), char, PN_STR_LEN(str)); \
1313 ptr += PN_STR_LEN(str); \
1315 PN cval = (PN_IS_PTR(val) ? PN_NIL : val); \
1316 WRITE_PN(cval, ptr); \
1319 #define WRITE_TUPLE(tup, ptr) \
1320 long i = 0, count = PN_TUPLE_LEN(tup); \
1321 WRITE_U8(count, ptr); \
1322 for (; i < count; i++)
1323 #define WRITE_VALUES(tup, ptr) ({ \
1324 WRITE_TUPLE(tup, ptr) WRITE_CONST(PN_TUPLE_AT(tup, i), ptr); \
1326 #define WRITE_PROTOS(tup, ptr) ({ \
1327 WRITE_TUPLE(tup, ptr) ptr += potion_proto_dumpbc(P, PN_TUPLE_AT(tup, i), \
1328 out, (char *)ptr - PN_STR_PTR(out)); \
1340 u8 *ptr = (
u8 *)start;
1354 return (
char *)ptr - start;
1363 DBG_c(
"compile bc\n");
1382 if (backend ==
PN_STRN(
"bc", 2))
1387 DBG_c(
"loaded compile/%s\n", cb);
1391 fprintf(stderr,
"** failed loading the compile/%s module\n", cb);
1395 potion_fatal(
"external compilers disabled with SANDBOX");
1400 #ifndef POTION_JIT_TARGET
1402 fprintf(stderr,
"** potion not compiled with JIT\n");
#define PN_TUPLE_AT(t, n)
PN potion_vm(Potion *, PN, PN, PN, PN_SIZE, PN *volatile)
the bytecode run-loop
PN asmb
assembled instructions
#define PN_FLEX_NEW(N, V, T, S)
PN potion_bytes(Potion *, size_t)
PN potion_closure_new(Potion *P, PN_F meth, PN sig, PN_SIZE extra)
PN upvals
variables in upper scopes
PN_AST
An AST fragment, non-volatile.
PN values
numbers, strings, etc.
#define WRITE_PN(pn, ptr)
PN_F potion_jit_proto(Potion *, PN)
a tuple is an array of PNs.
PN potion_proto_load(Potion *P, PN up, u8 pn, u8 **ptr)
#define READ_PROTOS(pn, ptr)
Potion_Flags flags
vm flags: execution model and debug flags
PN_SIZE void potion_bytes_obj_string(Potion *, PN, PN)
PN PN potion_byte_str(Potion *, const char *)
PN potion_sig_string(Potion *P, PN cl, PN sig)
PN potion_tuple_at(Potion *P, PN cl, PN self, PN index)
PN potion_source_dumpbc(Potion *P, PN cl, PN proto, PN options)
#define potion_method(RCV, MSG, FN, SIG)
static PN potion_fwd(PN)
the potion type is the 't' in the vtable tuple (m,t)
#define PN_ASM_DEBUG(REG, T)
PN potion_sig_compile(Potion *P, vPN(Proto) f, PN src)
Converts a pre-compiled potion expr to a signature tuple.
#define WRITE_CONST(val, ptr)
const struct @0 potion_ops[]
PN potion_source_load(Potion *P, PN cl, PN buf)
PN_F jit
jit function pointer
PN potion_source_compile(Potion *P, PN cl, PN self, PN source, PN sig)
the Potion VM instruction set (heavily based on Lua's)
the ast for Potion code in-memory
PN potion_source_dump(Potion *P, PN cl, PN self, PN backend, PN options)
PN potion_load(Potion *P, PN cl, PN self, PN file)
int arity
cached sig arity (number of args)
enum PN_AST part
AST type, avoid -Wswitch (aligned access: 4+4+8+4+24)
#define PN_OP(T, A, B)
Warning: This might conflict with the typedef struct PN_OP.
PN potion_proto_string(Potion *P, PN cl, PN self)
#define PN_ARG_TABLE(args, reg, inc)
PNAsm * potion_asm_op(Potion *P, PNAsm *volatile asmb, u8 ins, int _a, int _b)
PN potion_run(Potion *P, PN code, int jit)
PN potion_proto_call(Potion *P, PN cl, PN self, PN args)
PN paths
paths (instance variables)
void potion_syntax_error(Potion *P, struct PNSource *t, const char *fmt,...)
PN potion_parse(Potion *, PN, char *)
#define READ_CONST(pn, ptr)
jump table for loops, for the 2 args b and c Note: only statically allocated (max 1024) ...
#define PN_MEMCPY_N(X, Y, T, N)
PN potion_eval(Potion *P, PN bytes)
int cjmpc
count of c jumps (abc regs)
PNAsm * potion_asm_new(Potion *P)
#define PN_BLOCK(reg, blk, sig)
JIT if detected at config-time (x86, ppc)
a prototype is compiled source code, a closure block (lambda) non-volatile.
void potion_arg_asmb(Potion *P, struct PNProto *volatile f, struct PNLoop *loop, PN args, u8 *reg, int inc)
#define SIG_EXPR_MSG(name, expr)
#define PN_ASM2(ins, _a, _b)
u8 potion_source_debug(Potion *P, struct PNProto *volatile f, struct PNSource *volatile t, u8 reg)
insert DEBUG ops for every new line
#define PN_OP_AT(asmb, n)
-d: instrumented bytecode (line stepping) or just slow runloop?
int a
< the op. See vm.c http://www.lua.org/doc/jucs05.pdf
the global interpreter state P. currently singleton (not threads yet)
PN_SIZE pn_printf(Potion *, PN, const char *,...) __attribute__((format(printf
#define READ_VALUES(pn, ptr)
PN potion_strcat(Potion *P, char *str, char *str2)
struct PNSource *volatile a[3]
PNTuple of 1-3 kids,.
_PN(* PN_F)(Potion *, PN, PN,...)
void potion_compiler_init(Potion *P)
int bjmpc
count of b jumps (abc regs)
#define SRC_TUPLE_AT(src, i)
PN stack
size of the stack
#define potion_send(RCV, MSG, ARGS...)
method caches (more great stuff from ian piumarta)
long potion_proto_dumpbc(Potion *P, PN proto, PN out, long pos)
int potion_sig_arity(Potion *P, PN sig)
number of args of sig tuple, implements the potion_closure_arity method.
#define PN_MEMCPY(X, Y, T)
PN tree
abstract syntax tree
#define WRITE_PROTOS(tup, ptr)
void potion_source_asmb(Potion *, struct PNProto *volatile, struct PNLoop *, PN_SIZE, struct PNSource *volatile, u8)
#define PN_CALLOC_N(V, T, C)
#define WRITE_VALUES(tup, ptr)
PN source
program name or enclosing scope
PN potion_proto_clone(Potion *P, PN cl, PN self)
PN potion_proto_tree(Potion *P, PN cl, PN self)
struct PNSource::@1 loc
bitfield of fileno and lineno
#define PN_TUPLE_EACH(T, I, V, B)
void potion_fatal(char *message)
PN_OP - a compressed three-address op (as 32bit int bitfield) TODO: expand to 64bit, check jit then.