potion  0.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
compile.c
Go to the documentation of this file.
1 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <math.h>
16 #include <ctype.h>
17 #include "potion.h"
18 #include "internal.h"
19 #include "ast.h"
20 #include "opcodes.h"
21 #include "asm.h"
22 #ifdef WITH_EXTERN
23 #include <dlfcn.h>
24 #endif
25 
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)
28 
29 const struct {
30  const char *name;
31  const u8 args;
32 } potion_ops[] = {
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}
43 };
44 
48 PN potion_proto_tree(Potion *P, PN cl, PN self) {
49  return PN_PROTO(self)->tree;
50 }
51 
56  return potion_vm(P, self, P->lobby, args, 0, NULL);
57 }
58 
61  PN out = potion_byte_str(P, "");
62  if (PN_IS_TUPLE(sig)) {
63  int nextdef = 0;
64  struct PNTuple * volatile t = ((struct PNTuple *)potion_fwd(sig));
65  if (t->len != 0) {
66  PN_SIZE i, comma=0;
67  for (i = 0; i < t->len; i++) {
68  PN v = (PN)t->set[i];
69  if (PN_IS_INT(v)) {
70  // currently types are still encoded as NUM, TODO: support VTABLE also
71  int c = PN_INT(v); comma=0;
72  if (c == '.') // is end
73  pn_printf(P, out, ".");
74  else if (c == '|') // is optional
75  pn_printf(P, out, "|");
76  else if (c == ':') { nextdef = 1;
77  pn_printf(P, out, ":"); // is default
78  }
79  else {
80  if (comma++) pn_printf(P, out, ",");
81  if (nextdef) { nextdef = 0;
82  pn_printf(P, out, "=");
83  potion_bytes_obj_string(P, out, v);
84  } else
85  pn_printf(P, out, "=%c", c);
86  }
87  } else {
88  if (comma++) pn_printf(P, out, ",");
89  if (nextdef)
90  { nextdef = 0; pn_printf(P, out, "="); }
91  potion_bytes_obj_string(P, out, v);
92  }}}}
93  return PN_STR_B(out);
94 }
95 
99  vPN(Proto) t = (struct PNProto *)self;
100  int x = 0;
101  PN_SIZE num = 1;
102  PN_SIZE numcols;
103  PN out = potion_byte_str(P, "; function definition");
104  #ifdef JIT_DEBUG
105  pn_printf(P, out, ": %p; %u bytes\n", t, PN_FLEX_SIZE(t->asmb));
106  #else
107  pn_printf(P, out, ": %u bytes\n", PN_FLEX_SIZE(t->asmb));
108  #endif
109  if (t->name)
110  pn_printf(P, out, "; %s(", PN_STR_PTR(t->name));
111  else
112  pn_printf(P, out, "; (");
113  potion_bytes_obj_string(P, out, potion_sig_string(P, cl, t->sig));
114  pn_printf(P, out, ") %ld registers\n", PN_INT(t->stack));
115  PN_TUPLE_EACH(t->paths, i, v, {
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);
120  });
121  PN_TUPLE_EACH(t->locals, i, v, {
122  pn_printf(P, out, ".local ");
123  potion_bytes_obj_string(P, out, v);
124  pn_printf(P, out, " ; %u\n", i);
125  });
126  PN_TUPLE_EACH(t->upvals, i, v, {
127  pn_printf(P, out, ".upval ");
128  potion_bytes_obj_string(P, out, v);
129  pn_printf(P, out, " ; %u\n", i);
130  });
131  PN_TUPLE_EACH(t->values, i, v, {
132  pn_printf(P, out, ".value ");
133  potion_bytes_obj_string(P, out, v);
134  pn_printf(P, out, " ; %u\n", i);
135  });
136  PN_TUPLE_EACH(t->protos, i, v, {
137  potion_bytes_obj_string(P, out, v);
138  });
139  numcols = (int)ceil(log10(PN_FLEX_SIZE(t->asmb) / sizeof(PN_OP)));
140  for (x = 0; x < PN_FLEX_SIZE(t->asmb) / sizeof(PN_OP); x++) {
141  const int commentoffset = 20;
142  int width = pn_printf(P, out, "[%*u] %-8s %d",
143  numcols, num, potion_ops[PN_OP_AT(t->asmb, x).code].name, PN_OP_AT(t->asmb, x).a);
144 
145  if (potion_ops[PN_OP_AT(t->asmb, x).code].args > 1)
146  width += pn_printf(P, out, " %d", PN_OP_AT(t->asmb, x).b);
147 
148  if (width < commentoffset)
149  pn_printf(P, out, "%*s", commentoffset - width, "");
150  else
151  pn_printf(P, out, " ");
152 
153  // TODO: Byte code listing: instead of using tabs, pad with spaces to make everything line up
154  switch (PN_OP_AT(t->asmb, x).code) {
155  case OP_JMP:
156  pn_printf(P, out, "; to %d", num + PN_OP_AT(t->asmb, x).a + 1);
157  break;
158  case OP_NOTJMP:
159  case OP_TESTJMP:
160  pn_printf(P, out, "; to %d", num + PN_OP_AT(t->asmb, x).b + 1);
161  break;
162  case OP_LOADPN:
163  pn_printf(P, out, "; ");
164  potion_bytes_obj_string(P, out, PN_OP_AT(t->asmb, x).b);
165  break;
166  case OP_LOADK:
167  pn_printf(P, out, "; ");
168  potion_bytes_obj_string(P, out, PN_TUPLE_AT(t->values, PN_OP_AT(t->asmb, x).b));
169  break;
170  case OP_SETLOCAL:
171  case OP_GETLOCAL:
172  pn_printf(P, out, "; ");
173  potion_bytes_obj_string(P, out, PN_TUPLE_AT(t->locals, PN_OP_AT(t->asmb, x).b));
174  break;
175  }
176  pn_printf(P, out, "\n");
177  num++;
178  }
179  //pn_printf(P, out, "\n");
180  pn_printf(P, out, "; function end\n");
181  return PN_STR_B(out);
182 }
183 
184 #define PN_REG(f, reg) \
185  if (reg >= PN_INT(f->stack)) \
186  f->stack = PN_NUM(reg + 1)
187 #define PN_ARG(n, reg) \
188  if (PN_PART(t->a[n]) == AST_EXPR && PN_PART(PN_TUPLE_AT(PN_S(t->a[n],0), 0)) == AST_LIST) { \
189  PN test = PN_S(PN_TUPLE_AT(PN_S(t->a[n],0), 0), 0); \
190  if (!PN_IS_NIL(test)) { \
191  DBG_c("expr (list %s) => %s\n", AS_STR(test), AS_STR(test)); \
192  PN_TUPLE_EACH(test, i, v, { \
193  potion_source_asmb(P, f, loop, 0, PN_SRC(v), reg); }); \
194  } \
195  } else { \
196  potion_source_asmb(P, f, loop, 0, t->a[n], reg); \
197  }
198 #define PN_BLOCK(reg, blk, sig) ({ \
199  PN block = potion_send(blk, PN_compile, (PN)f, sig); \
200  PN_SIZE num = PN_PUT(f->protos, block); \
201  DBG_c("protos => %u\n", num); \
202  PN_ASM2(OP_PROTO, reg, num); \
203  PN_TUPLE_EACH(((struct PNProto *)block)->upvals, i, v, { \
204  PN_SIZE numup = PN_GET(f->upvals, v); \
205  DBG_c("upvals %s <= %d\n", AS_STR(v), (int)numup); \
206  if (numup != PN_NONE) PN_ASM2(OP_GETUPVAL, reg, numup); \
207  else PN_ASM2(OP_GETLOCAL, reg, PN_GET(f->locals, v)); \
208  }); \
209 })
210 #define PN_UPVAL(name) ({ \
211  PN_SIZE numl = PN_GET(f->locals, name); \
212  DBG_c("locals %s <= %d\n", AS_STR(name), (int)numl); \
213  PN_SIZE numup = PN_NONE; \
214  if (numl == PN_NONE) { \
215  numup = PN_GET(f->upvals, name); \
216  if (numup == PN_NONE) { \
217  DBG_c("upvals %s <= -1\n", AS_STR(name)); \
218  vPN(Proto) up = f; \
219  int depth = 1; \
220  while (PN_IS_PROTO(up->source)) { \
221  up = (struct PNProto *)up->source; \
222  if (PN_NONE != (numup = PN_GET(up->locals, name))) break; \
223  depth++; \
224  } \
225  DBG_c("locals %s <= %d\n", AS_STR(name), (int)numup); \
226  if (numup != PN_NONE) { \
227  up = f; \
228  while (depth--) { \
229  up->upvals = PN_PUSH(up->upvals, name); \
230  DBG_c("upvals %s =>\n", AS_STR(name)); \
231  up = (struct PNProto *)up->source; \
232  } \
233  } \
234  numup = PN_GET(f->upvals, name); \
235  DBG_c("upvals %s <= %d\n", AS_STR(name), (int)numup); \
236  } \
237  } \
238  numup; \
239 })
240 #define PN_ARG_TABLE(args, reg, inc) potion_arg_asmb(P, f, loop, args, &reg, inc)
241 #define SRC_TUPLE_AT(src,i) PN_SRC(PN_TUPLE_AT(PN_S(src,0), i))
242 #define PN_ASM_DEBUG(REG, T) REG = potion_source_debug(P, f, T, REG)
243 
245 u8 potion_source_debug(Potion *P, struct PNProto * volatile f, struct PNSource * volatile t, u8 reg) {
246  static PNType lineno = 0;
247  if ((P->flags & EXEC_DEBUG) && t && t->loc.lineno != lineno && t->loc.lineno > 0) {
248  PN_SIZE num = PN_PUT(f->debugs, (PN)t);
249  PN_ASM2(OP_DEBUG, reg, num);
250  lineno = t->loc.lineno;
251  DBG_c("debug %s :%d\n", PN_STR_PTR(potion_send(t, PN_name)), lineno);
252  }
253  return reg;
254 }
255 
256 #define MAX_JUMPS 1024
257 struct PNLoop {
262 
263  int bjmpc;
264  int cjmpc;
265 };
266 
267 void potion_source_asmb(Potion *, struct PNProto * volatile, struct PNLoop *, PN_SIZE, struct PNSource * volatile, u8);
268 
269 void potion_arg_asmb(Potion *P, struct PNProto * volatile f, struct PNLoop *loop, PN args, u8 *reg, int inc) {
270  if (args != PN_NIL) {
271  if (PN_PART(args) == AST_LIST) {
272  args = PN_S(args,0);
273  if (!PN_IS_NIL(args)) {
274  u8 freg = *reg, sreg = *reg + PN_TUPLE_LEN(args) + 1;
275  DBG_c("ARGLIST %d %d\n", freg, sreg);
276  PN_TUPLE_EACH(args, i, v, {
277  if (inc) {
278  (*reg)++;
279  if (PN_PART(v) == AST_ASSIGN) {
280  vPN(Source) lhs = PN_SRC(PN_S(v,0));
281  potion_source_asmb(P, f, loop, 0, PN_SRC(v)->a[1], sreg + 1);
282  if (lhs->part == AST_EXPR && PN_TUPLE_LEN(PN_S(lhs,0)) == 1)
283  {
284  lhs = SRC_TUPLE_AT(lhs, 0);
285  PN_ASM_DEBUG(sreg, lhs);
286  if (lhs->part == AST_MSG || lhs->part == AST_VALUE) {
287  PN_OP op; op.a = PN_S(lhs,0); //12 bit!
288  if (!PN_IS_PTR(PN_S(lhs,0)) && PN_S(lhs,0) == op.a) {
289  PN_ASM2(OP_LOADPN, sreg, PN_S(lhs,0));
290  } else {
291  PN_SIZE num = PN_PUT(f->values, PN_S(lhs,0));
292  DBG_c("values %d %s => %d\n", sreg, AS_STR(lhs->a[0]), (int)num);
293  PN_ASM2(OP_LOADK, sreg, num);
294  }
295  lhs = NULL;
296  }
297  }
298 
299  if (lhs != NULL)
300  potion_source_asmb(P, f, loop, 0, lhs, sreg);
301 
302  PN_ASM2(OP_NAMED, freg - 1, sreg + 1);
303  PN_REG(f, sreg + 1);
304  } else
305  potion_source_asmb(P, f, loop, 0, PN_SRC(v), *reg);
306  } else
307  potion_source_asmb(P, f, loop, 0, PN_SRC(v), *reg);
308  });
309  }
310  } else {
311  if (inc) (*reg)++;
312  potion_source_asmb(P, f, loop, 0, PN_SRC(args), *reg);
313  }
314  } else {
315  if (inc) (*reg)++;
316  PN_ASM_DEBUG(*reg, PN_SRC(args));
317  PN_ASM2(OP_LOADPN, *reg, args);
318  }
319 }
320 
321 void potion_source_asmb(Potion *P, struct PNProto * volatile f, struct PNLoop *loop, PN_SIZE count,
322  struct PNSource * volatile t, u8 reg) {
323  //PN fname = 0;
324  PN_REG(f, reg);
325  PN_ASM_DEBUG(reg, t);
326  switch (t->part) {
327  case AST_CODE:
328  case AST_BLOCK:
329  if (PN_S(t,0) != PN_NIL) {
330  DBG_c("%s %u %s\n", t->part == AST_CODE?"code":"block", reg,
331  t->part == AST_CODE?"":AS_STR(PN_S(t,0)));
332  PN_TUPLE_EACH(PN_S(t,0), i, v, {
333  potion_source_asmb(P, f, loop, 0, PN_SRC(v), reg);
334  });
335  }
336  break;
337 
338  case AST_EXPR:
339  if (PN_S(t,0) != PN_NIL) {
340  PN e = PN_S(t,0);
341  DBG_c("expr %u %s\n", reg, AS_STR(e));
342  PN_TUPLE_EACH(e, i, v, {
343  potion_source_asmb(P, f, loop, i, PN_SRC(v), reg);
344  });
345  }
346  break;
347 
348  case AST_PROTO:
349  PN_BLOCK(reg, PN_S(t,1), PN_S(t,0));
350  break;
351 
352  case AST_VALUE: {
353  vPN(Source) a = PN_S_(t,0);
354  PN_OP op; op.a = PN_S(t,0); // but 12bit only
355  if (!PN_IS_PTR(a) && (PN)a == (PN)op.a) {
356  PN_ASM2(OP_LOADPN, reg, PN_S(t,0));
357  } else if (a != PN_NIL && PN_IS_PTR(a)
358  && PN_PART(a) == AST_LICK && PN_PART(a->a[0]) == AST_MSG) {
359  vPN(Source) msg = a->a[0];
360  PN tpl = PN_S(msg, 0);
361  // locals or upvals. locals alone broke nbody
362  PN_SIZE num = PN_UPVAL(tpl);
363  u8 opcode = OP_GETUPVAL;
364  PN key = PN_S(PN_TUPLE_AT(a->a[1]->a[0], 0), 0);
365  if (num == PN_NONE) {
366  num = PN_PUT(f->locals, tpl);
367  DBG_c("locals %s => %d\n", AS_STR(tpl), (int)num);
368  opcode = OP_GETLOCAL;
369  }
370  PN_ASM2(opcode, reg, num);
371  if (PN_VTYPE(key) == PN_TSTRING) { // a[k] a variable
372  num = PN_PUT(f->locals, key);
373  DBG_c("locals %s => %d\n", PN_STR_PTR(key), (int)num);
374  PN_ASM2(OP_GETLOCAL, reg+1, num);
375  num = reg+1;
376  DBG_c("gettuple %d %d %s[%s]\n", reg, num, PN_STR_PTR(tpl), PN_STR_PTR(key));
377  PN_ASM2(OP_GETTUPLE, reg, num | ASM_TPL_IMM);
378  PN_REG(f, reg + 1);
379  } else { // a[0] constant, could to be optimized in jit
380  assert(PN_VTYPE(key) == PN_TSOURCE && PN_PART(key) == AST_VALUE);
381  PN k = PN_S(key, 0);
382  if (PN_IS_INT(k)) {
383  if (PN_INT(k) >= ASM_TPL_IMM || PN_INT(k) < 0) {
384  num = PN_PUT(f->values, k);
385  PN_ASM2(OP_LOADK, reg+1, num);
386  DBG_c("values %ld => %d\n", PN_INT(k), (int)num);
387  num = reg + 1;
388  PN_REG(f, reg + 1);
389  } else {
390  num = PN_INT(k);
391  }
392  DBG_c("gettuple %d %d %s[%ld]\n", reg, num, PN_STR_PTR(tpl), PN_INT(k));
393  PN_ASM2(OP_GETTUPLE, reg, num);
394  } else {
395  num = PN_PUT(f->values, k); // op.b has 12 bits
396  PN_ASM2(OP_LOADK, reg+1, num);
397  DBG_c("values \"%s\" => %d\n", PN_STR_PTR(k), (int)num);
398  num = reg+1;
399  DBG_c("gettable %d %d %s[\"%s\"]\n", reg, num, PN_STR_PTR(tpl), PN_STR_PTR(k));
400  PN_ASM2(OP_GETTABLE, reg, num);
401  PN_REG(f, reg + 1);
402  }
403  }
404  } else {
405  PN_SIZE num = PN_PUT(f->values, (PN)a);
406  DBG_c("values %d %s => %d\n", reg, AS_STR(a), (int)num);
407  PN_ASM2(OP_LOADK, reg, num);
408  }
409  if (PN_S(t,1) != PN_NIL && a->part != AST_LICK) {
410  u8 breg = reg;
411  PN_ASM1(OP_SELF, ++breg);
412  PN_ARG_TABLE(PN_S(t,1), breg, 1);
413  if (PN_S(t,2) != PN_NIL) {
414  breg++;
415  PN_BLOCK(breg, PN_S(t,2), PN_NIL);
416  }
417  DBG_c("; call %d %d VALUE\n", reg, breg);
418  PN_ASM2(OP_CALL, reg, breg);
419  }
420  }
421  break;
422 
423  case AST_ASSIGN: {
424  vPN(Source) lhs = t->a[0];
425  PN_SIZE num = PN_NONE, c = count;
426  u8 opcode = OP_GETUPVAL, breg = reg;
427 
428  if (lhs->part == AST_EXPR) {
429  unsigned long i = 0;
430  c = PN_TUPLE_LEN(PN_S(lhs,0)) - 1;
431  DBG_c("assign expr [%lu]\n", (_PN)c);
432  for (i = 0; i < c; i++) {
433  potion_source_asmb(P, f, loop, i, SRC_TUPLE_AT(lhs, i), reg);
434  };
435  lhs = SRC_TUPLE_AT(lhs, c);
436  PN_ASM_DEBUG(reg, lhs);
437  }
438 
439  if (lhs->part == AST_MSG || lhs->part == AST_QUERY) {
440  char first_letter = PN_STR_PTR(PN_S(lhs,0))[0];
441  DBG_c("assign %s '%s'\n", lhs->part == AST_MSG?"msg":"query",
442  AS_STR(PN_S(lhs,0)));
443  if ((first_letter & 0x80) == 0 && isupper((unsigned char)first_letter)) {
444  num = PN_PUT(f->values, PN_S(lhs,0));
445  DBG_c("values %d %s => %d\n", breg, AS_STR(lhs->a[0]), (int)num);
446  PN_ASM2(OP_LOADK, breg, num);
447  opcode = OP_GLOBAL;
448  num = ++breg;
449  } else if (c == 0) {
450  num = PN_UPVAL(PN_S(lhs,0));
451  if (num == PN_NONE) {
452  num = PN_PUT(f->locals, PN_S(lhs,0));
453  DBG_c("locals %s => %d\n", AS_STR(lhs->a[0]), (int)num);
454  opcode = OP_GETLOCAL;
455 #if 0 // store func names
456  if (lhs->part == AST_MSG) {
457  PN rhs = PN_TUPLE_AT(f->locals, num);
458  PN fname = PN_S(lhs,0);
459  DBG_c("getlocal %s %ld = %s\n",
460  PN_STR_PTR(fname), PN_INT(num), AS_STR(rhs));
461  }
462 #endif
463  }
464  } else {
465  num = PN_PUT(f->values, PN_S(lhs,0));
466  DBG_c("values %d %s => %d\n", breg+1, AS_STR(lhs->a[0]), (int)num);
467  PN_ASM2(OP_LOADK, ++breg, num);
468  opcode = OP_DEF;
469  num = ++breg;
470  }
471  } else if (lhs->part == AST_PATH || lhs->part == AST_PATHQ) {
472  DBG_c("assign %s\n", lhs->part == AST_PATH?"path":"pathq");
473  num = PN_PUT(f->values, PN_S(lhs,0));
474  DBG_c("values %d %s => %d\n", breg+1, AS_STR(lhs->a[0]), (int)num);
475  if (c == 0) {
476  PN_PUT(f->paths, PN_NUM(num));
477  DBG_c("paths %d\n", (int)num);
478  PN_ASM1(OP_SELF, reg);
479  }
480  PN_ASM2(OP_LOADK, ++breg, num);
481  opcode = OP_GETPATH;
482  num = ++breg;
483  }
484 
485  if (num == PN_NONE)
486  potion_syntax_error(P, t, "Assignment to illegal variable");
487  else if (lhs->a[1] != PN_NIL) {
488  breg = reg;
489  PN_ASM2(opcode, ++breg, num);
490  DBG_c("; callset %d %d ASSIGN\n", reg, breg);
491  PN_ASM2(OP_CALLSET, reg, breg);
492  PN_ARG_TABLE(PN_S(lhs,1), breg, 1);
493  // TODO: no block allowed here?
494  potion_source_asmb(P, f, loop, 0, t->a[1], ++breg);
495  DBG_c("; call %d %d ASSIGN\n", reg, breg);
496  PN_ASM2(OP_CALL, reg, breg);
497  } else {
498  potion_source_asmb(P, f, loop, 0, t->a[1], breg);
499  if (opcode == OP_GETUPVAL) {
500  if (lhs->part == AST_QUERY) {
501  PN_ASM2(OP_GETUPVAL, breg, num);
502  PN_ASM2(OP_TESTJMP, breg, 1);
503  }
504  PN_ASM2(OP_SETUPVAL, reg, num);
505  } else if (opcode == OP_GETLOCAL) {
506  if (lhs->part == AST_QUERY) {
507  PN_ASM2(OP_GETLOCAL, breg, num);
508  PN_ASM2(OP_TESTJMP, breg, 1);
509  } else {
510  DBG_c("setlocal %d %d\n", reg, (int)num);
511  PN_ASM2(OP_SETLOCAL, reg, num);
512  }
513  } else if (opcode == OP_GETPATH) {
514  if (lhs->part == AST_PATHQ) {
515  PN_ASM2(OP_GETPATH, reg, num);
516  PN_ASM2(OP_TESTJMP, reg, 1);
517  }
518  PN_ASM2(OP_SETPATH, reg, num);
519  } else {
520  PN_ASM2(opcode, reg, num);
521  }
522  }
523  PN_REG(f, breg);
524  }
525  break;
526 
527  case AST_INC: {
528  u8 breg = reg;
529  vPN(Source) lhs = t->a[0];
530  PN_SIZE num = PN_UPVAL(PN_S(lhs,0));
531  u8 opcode = OP_SETUPVAL;
532  if (num == PN_NONE) {
533  num = PN_PUT(f->locals, PN_S(lhs,0));
534  DBG_c("locals %s => %d\n", AS_STR(lhs->a[0]), (int)num);
535  opcode = OP_SETLOCAL;
536  }
537 
538  if (opcode == OP_SETUPVAL)
539  PN_ASM2(OP_GETUPVAL, reg, num);
540  else if (opcode == OP_SETLOCAL)
541  PN_ASM2(OP_GETLOCAL, reg, num);
542  if (PN_IS_INT(PN_S(t,1))) {
543  breg++;
544  PN_ASM2(OP_MOVE, breg, reg);
545  }
546  PN_ASM2(OP_LOADPN, breg + 1, (PN_S(t,1) | PN_FINTEGER));
547  PN_ASM2(OP_ADD, breg, breg + 1);
548  PN_ASM2(opcode, breg, num);
549  PN_REG(f, breg + 1);
550  }
551  break;
552 
553  case AST_CMP: case AST_EQ: case AST_NEQ:
554  case AST_GT: case AST_GTE: case AST_LT: case AST_LTE:
555  case AST_PLUS: case AST_MINUS: case AST_TIMES: case AST_DIV:
556  case AST_REM: case AST_POW: case AST_BITL: case AST_BITR: {
557  PN_ARG(0, reg);
558  PN_ARG(1, reg + 1);
559  switch (t->part) {
560  case AST_CMP: PN_ASM2(OP_CMP, reg, reg + 1); break;
561  case AST_EQ: PN_ASM2(OP_EQ, reg, reg + 1); break;
562  case AST_NEQ: PN_ASM2(OP_NEQ, reg, reg + 1); break;
563  case AST_GTE: PN_ASM2(OP_GTE, reg, reg + 1); break;
564  case AST_GT: PN_ASM2(OP_GT, reg, reg + 1); break;
565  case AST_LT: PN_ASM2(OP_LT, reg, reg + 1); break;
566  case AST_LTE: PN_ASM2(OP_LTE, reg, reg + 1); break;
567  case AST_PLUS: PN_ASM2(OP_ADD, reg, reg + 1); break;
568  case AST_MINUS: PN_ASM2(OP_SUB, reg, reg + 1); break;
569  case AST_TIMES: PN_ASM2(OP_MULT, reg, reg + 1); break;
570  case AST_DIV: PN_ASM2(OP_DIV, reg, reg + 1); break;
571  case AST_REM: PN_ASM2(OP_REM, reg, reg + 1); break;
572  case AST_POW: PN_ASM2(OP_POW, reg, reg + 1); break;
573  case AST_BITL: PN_ASM2(OP_BITL, reg, reg + 1); break;
574  case AST_BITR: PN_ASM2(OP_BITR, reg, reg + 1); break;
575  }
576  }
577  break;
578 
579  case AST_NOT: case AST_WAVY:
580  PN_ARG(0, reg);
581  PN_ASM2(t->part == AST_WAVY ? OP_BITN : OP_NOT, reg, reg);
582  break;
583 
584  case AST_AND: case AST_OR: {
585  int jmp;
586  PN_ARG(0, reg);
587  jmp = PN_OP_LEN(f->asmb);
588  PN_ASM2(t->part == AST_AND ? OP_NOTJMP : OP_TESTJMP, reg, 0);
589  PN_ARG(1, reg);
590  PN_OP_AT(f->asmb, jmp).b = (PN_OP_LEN(f->asmb) - jmp) - 1;
591  }
592  break;
593 
594  // TODO: this stuff is ugly and repetitive. replace by compiler macros for control structures
595  case AST_MSG:
596  case AST_QUERY: {
597  u8 breg = reg;
598  int arg = (PN_S(t,1) != PN_NIL);
599  int call = (PN_S(t,2) != PN_NIL || arg);
600  if (t->part == AST_MSG && PN_S(t,0) == PN_if) {
601  int jmp; breg++;
602  if (!t->a[1])
603  return potion_syntax_error(P, t, "Missing if clause");
604  PN_ARG_TABLE(PN_S(t,1), breg, 0);
605  jmp = PN_OP_LEN(f->asmb);
606  PN_ASM2(OP_NOTJMP, breg, 0);
607  if (!t->a[2])
608  return potion_syntax_error(P, t, "Missing if body");
609  potion_source_asmb(P, f, loop, 0, t->a[2], reg);
610  PN_OP_AT(f->asmb, jmp).b = (PN_OP_LEN(f->asmb) - jmp) - 1;
611  } else if (t->part == AST_MSG && PN_S(t,0) == PN_elsif) {
612  int jmp1 = PN_OP_LEN(f->asmb), jmp2; breg++;
613  PN_ASM2(OP_TESTJMP, breg, 0);
614  if (!t->a[1])
615  return potion_syntax_error(P, t, "Missing elsif clause");
616  PN_ARG_TABLE(PN_S(t,1), breg, 0);
617  jmp2 = PN_OP_LEN(f->asmb);
618  PN_ASM2(OP_NOTJMP, breg, 0);
619  if (!t->a[2])
620  return potion_syntax_error(P, t, "Missing elsif body");
621  potion_source_asmb(P, f, loop, 0, t->a[2], reg);
622  PN_OP_AT(f->asmb, jmp1).b = (PN_OP_LEN(f->asmb) - jmp1) - 1;
623  PN_OP_AT(f->asmb, jmp2).b = (PN_OP_LEN(f->asmb) - jmp2) - 1;
624  } else if (t->part == AST_MSG && PN_S(t,0) == PN_else) {
625  int jmp = PN_OP_LEN(f->asmb); breg++;
626  PN_ASM2(OP_TESTJMP, breg, 0);
627  if (!t->a[2])
628  potion_syntax_error(P, t, "Missing else body");
629  potion_source_asmb(P, f, loop, 0, t->a[2], reg);
630  PN_OP_AT(f->asmb, jmp).b = (PN_OP_LEN(f->asmb) - jmp) - 1;
631  } else if (t->part == AST_MSG && PN_S(t,0) == PN_class) {
632  u8 breg = reg;
633  if (count == 0)
634  PN_ASM1(OP_SELF, reg);
635  if (PN_S(t,2) != PN_NIL) {
636  vPN(Source) blk = PN_S_(t,2);
637  // TODO: a hack to make sure constructors always return self
638  if (PN_S(blk, 0) == PN_NIL)
639  blk->a[0] = PN_SRC(PN_AST(CODE, PN_NIL, blk->loc.lineno, blk->line));
640  PN ctor = PN_S(blk, 0);
641  PN_PUSH(ctor, PN_AST(EXPR, PN_TUP(PN_AST(MSG,
642  PN_STRN("self", 4), blk->loc.lineno, 0)),
643  blk->loc.lineno, blk->line));
644  breg++;
645  PN_BLOCK(breg, (PN)blk, PN_S(t,1));
646  }
647  PN_ASM2(OP_CLASS, reg, breg);
648 #ifdef WITH_EXTERN
649  } else if (t->part == AST_MSG && PN_S(t,0) == PN_extern) { // ffi
650  //u8 breg = reg;
651  int i, arity;
652  PN msg = PN_S(t,1);
653  char *name = PN_STR_PTR(PN_S(PN_TUPLE_AT(msg,0),0));
654  //defer dlsym to run-time to see load, or require load at BEGIN time?
655  //PN_ASM2(OP_LOADPN, breg++, name);
656  PN_F sym = (PN_F)dlsym(RTLD_DEFAULT, name);
657  DBG_c("extern %s => dlsym %p\n", name, sym);
658  if (!sym) {
659  fprintf(stderr, "* extern %s not found. You may need to load a library first\n",
660  name);
661  PN_ASM2(OP_LOADPN, reg, PN_NIL);
662  } else {
663  // TODO: create a ffi wrapper to translate the args and return value
664  struct PNProto* cl = PN_CALLOC_N(PN_TPROTO, struct PNProto, 0);
665  cl->source = PN_NIL;
666  cl->stack = PN_NUM(1);
667  cl->protos = cl->paths = cl->locals = cl->upvals = cl->values = PN_TUP0();
668  cl->tree = (PN)t;
669  cl->asmb = (PN)potion_asm_new(P);
670  cl->name = PN_S(PN_TUPLE_AT(msg,0),0);
671  cl->jit = (PN_F)sym;
672  PN sig = PN_TUPLE_LEN(msg) ? PN_TUPLE_AT(msg, 1) : PN_TUP0();
673  cl->sig = sig;
674  arity = cl->arity = potion_sig_arity(P, sig);
675  for (i=0; i < arity; i++) {
676  if (PN_TUPLE_LEN(msg) > 1) {
677  // TODO set argtype translators
678  PN arg = PN_TUPLE_AT(sig, i);
679  if (arg == PN_STR("N") || arg == PN_STR("int") || arg == PN_STR("long")) {
680  DBG_c("extern %s %d-th arg => PN_INT(N)\n", name, i);
681  //insert PN_INT >>1 at runtime
682  //PN_ASM2(OP_LOADPN, breg++, arg);
683  } else if (arg == PN_STR("S") || arg == PN_STR("char*")) {
684  DBG_c("extern %s %d-th arg => PN_STR_PTR(S)\n", name, i);
685  // insert call to potion_str_ptr at runtime
686  //PN_ASM2(OP_LOADPN, breg++, arg);
687  } else {
688  fprintf(stderr, "* unknown extern %s argument type qualifier\n",
689  PN_STR_PTR(arg));
690  }
691  }
692  // maybe add code to check and fill in defaults?
693  }
694  // TODO insert code to transform return values
695  cl->asmb = (PN)potion_asm_op(P, (PNAsm *)cl->asmb, OP_RETURN, reg, 0);
696  PN_ASM2(OP_PROTO, reg, PN_PUT(f->protos, (PN)cl));
697  //PN_ASM2(OP_EXTERN, reg, breg);
698  }
699 #endif
700  } else if (t->part == AST_MSG && (PN_S(t,0) == PN_while || PN_S(t,0) == PN_loop)) {
701  int jmp1 = 0, jmp2 = PN_OP_LEN(f->asmb); breg++;
702  struct PNLoop l; l.bjmpc = 0; l.cjmpc = 0;
703  int i;
704  if (PN_S(t,0) == PN_while) {
705  PN_ARG_TABLE(PN_S(t,1), breg, 0);
706  jmp1 = PN_OP_LEN(f->asmb);
707  PN_ASM2(OP_NOTJMP, breg, 0);
708  } else if (PN_S(t,1) || !t->a[2]) {
709  //warn or skip to allow a method named loop? for aio we want loop methods
710  //fprintf(stderr, "* loop takes no args, just a block");
711  goto loopfunc;
712  }
713  if (!t->a[2]) {
714  if (PN_S(t,0) == PN_while)
715  return potion_syntax_error(P, t, "Missing while body");
716  else
717  return potion_syntax_error(P, t, "Missing loop body");
718  }
719  potion_source_asmb(P, f, &l, 0, t->a[2], reg);
720  PN_ASM1(OP_JMP, (jmp2 - PN_OP_LEN(f->asmb)) - 1);
721  if (PN_S(t,0) == PN_while) {
722  PN_OP_AT(f->asmb, jmp1).b = (PN_OP_LEN(f->asmb) - jmp1) - 1;
723  }
724  for (i = 0; i < l.bjmpc; i++) {
725  PN_OP_AT(f->asmb, l.bjmps[i]).a = (PN_OP_LEN(f->asmb) - l.bjmps[i]) - 1;
726  }
727  for (i = 0; i < l.cjmpc; i++) {
728  PN_OP_AT(f->asmb, l.cjmps[i]).a = (jmp2 - l.cjmps[i]) - 1;
729  }
730  } else if (t->part == AST_MSG && PN_S(t,0) == PN_return) {
731  //if (!t->a[1])
732  // return potion_syntax_error(P, t, "Missing return value");
733  PN_ARG_TABLE(PN_S(t,1), reg, 0);
734  PN_ASM1(OP_RETURN, reg);
735  } else if (t->part == AST_MSG && PN_S(t,0) == PN_break) {
736  if (loop != NULL) {
737  loop->bjmps[loop->bjmpc++] = PN_OP_LEN(f->asmb);
738  PN_ASM1(OP_JMP, 0);
739  } else {
740  potion_syntax_error(P, t, "'break' outside of loop");
741  }
742  } else if (t->part == AST_MSG && PN_S(t,0) == PN_continue) {
743  if (loop != NULL) {
744  loop->cjmps[loop->cjmpc++] = PN_OP_LEN(f->asmb);
745  PN_ASM1(OP_JMP, 0);
746  } else {
747  potion_syntax_error(P, t, "'continue' outside of loop");
748  }
749  } else if (t->part == AST_MSG && PN_S(t,0) == PN_self) {
750  PN_ASM1(OP_SELF, reg);
751  } else {
752  // TODO lookup if macro
753  loopfunc: ;
754  u8 opcode = OP_GETUPVAL;
755  PN_SIZE num = PN_NONE;
756  PN v = PN_S(t,0);
757  if (count == 0 && t->part == AST_MSG) {
758  num = PN_UPVAL(v);
759  if (num == PN_NONE) {
760  num = PN_GET(f->locals, v);
761  DBG_c("locals %s <= %d\n", AS_STR(v), (int)num);
762  opcode = OP_GETLOCAL;
763  }
764  }
765 
766  if (num == PN_NONE && PN_S(t,0) != PN_NIL) {
767  u8 oreg = ++breg;
768  int jmp = 0;
769  num = PN_PUT(f->values, PN_S(t,0));
770  DBG_c("values %d %s => %d\n", reg, AS_STR(t->a[0]), (int)num);
771  if (count == 0) {
772  PN_ASM1(OP_SELF, oreg);
773  } else {
774  PN_ASM2(OP_MOVE, oreg, reg);
775  }
776  PN_ASM2(OP_LOADK, reg, num);
777  if (PN_S(t,2) != PN_NIL && (PN_PART(PN_S(t,2)) == AST_MSG)) {
778  vPN(Source) t2 = PN_S_(t,2); //typed message (MSG LIST|NIL TYPE)
779  DBG_c("typed %s %s\n", AS_STR(t->a[0]), AS_STR(t2));
780  //TODO type should already exist at compile-time. check native or user type
781  num = PN_PUT(f->values, PN_S(t2,0));
782  PN_ASM2(OP_LOADK, reg, num);
783  PN_ASM2(OP_BIND, reg, breg);
784  } else {
785  PN_ASM2(((PN_S(t,1) != PN_NIL || PN_S(t,2) != PN_NIL) ? OP_MSG : OP_BIND), reg, breg);
786  }
787  if (t->part == AST_QUERY && PN_S(t,1) != PN_NIL) {
788  jmp = PN_OP_LEN(f->asmb);
789  PN_ASM2(OP_NOTJMP, reg, 0);
790  }
791 #define LOAD_ARG() PN_ARG_TABLE(PN_S(t,1), breg, 1)
792  if (arg) {
793  u8 part1 = PN_PART(PN_S(t,1));
794  if (part1 == AST_VALUE || (part1 == AST_LIST && PN_S(t,2) == PN_NIL)) {
795  LOAD_ARG();
796  }
797  }
798  if (PN_S(t,2) != PN_NIL && (PN_PART(PN_S(t,2)) == AST_PROTO)) {
799  vPN(Source) t2 = PN_S_(t,2);
800  breg++;
801  PN_BLOCK(breg, PN_S(t2,1), PN_S(t2,0));
802  } else {
803  if (PN_S(t,1) == PN_NIL && PN_S(t,2) == PN_NIL)
804  LOAD_ARG();
805  if (PN_S(t,2) != PN_NIL && PN_PART(PN_S(t,2)) == AST_BLOCK) {
806  breg++;
807  PN_BLOCK(breg, PN_S(t,2), PN_S(t,1));
808  }
809  }
810 #undef LOAD_ARG
811  if (t->part == AST_MSG) {
812  DBG_c("; call %d %d MSG\n", reg, breg);
813  PN_ASM2(OP_CALL, reg, breg);
814  } else {
815  if (PN_S(t,1) != PN_NIL) {
816  DBG_c("; call %d %d !MSG\n", reg, breg);
817  PN_ASM2(OP_CALL, reg, breg);
818  PN_OP_AT(f->asmb, jmp).b = (PN_OP_LEN(f->asmb) - jmp) - 1;
819  } else {
820  PN_ASM2(OP_TEST, reg, breg);
821  }
822  }
823  } else {
824  if (num != PN_NONE)
825  PN_ASM2(opcode, reg, num);
826  if (call) {
827  PN_ASM1(OP_SELF, ++breg);
828  PN_ARG_TABLE(PN_S(t,1), breg, 1);
829  if (PN_S(t,2) != PN_NIL) {
830  breg++;
831  PN_BLOCK(breg, PN_S(t,2), PN_NIL);
832  }
833  DBG_c("; call %d %d\n", reg, breg);
834  PN_ASM2(OP_CALL, reg, breg);
835  }
836  }
837  }
838  PN_REG(f, breg);
839  }
840  break;
841 
842  case AST_PATH:
843  case AST_PATHQ: {
844  PN_SIZE num = PN_PUT(f->values, PN_S(t,0));
845  DBG_c("values %d %s => %d\n", reg, AS_STR(t->a[0]), (int)num);
846  if (count == 0) {
847  PN_PUT(f->paths, PN_NUM(num));
848  DBG_c("paths %d\n", (int)num);
849  PN_ASM1(OP_SELF, reg);
850  }
851  PN_ASM2(OP_LOADK, reg + 1, num);
852  PN_ASM2(OP_GETPATH, reg, reg + 1);
853  if (t->part == AST_PATHQ)
854  PN_ASM2(OP_TEST, reg, reg);
855  PN_REG(f, reg + 1);
856  }
857  break;
858 
859  case AST_LICK: {
860  u8 breg = reg;
861  PN_SIZE num = PN_PUT(f->values, PN_S(t,0));
862  DBG_c("values %d %s => %d\n", reg, AS_STR(t->a[0]), (int)num);
863  PN_ASM2(OP_LOADK, reg, num);
864  if (PN_S(t,1) != PN_NIL)
865  potion_source_asmb(P, f, loop, 0, t->a[1], ++breg);
866  else if (PN_S(t,2) != PN_NIL)
867  PN_ASM2(OP_LOADPN, ++breg, PN_NIL);
868  if (PN_S(t,2) != PN_NIL)
869  potion_source_asmb(P, f, loop, 0, t->a[2], ++breg);
870  PN_ASM2(OP_NEWLICK, reg, breg);
871  PN_REG(f, breg);
872  }
873  break;
874 
875  case AST_LIST:
876  PN_ASM1(OP_NEWTUPLE, reg);
877  if (PN_S(t,0) != PN_NIL) {
878  PN_TUPLE_EACH(PN_S(t,0), i, v, {
879  PN_ASM_DEBUG(reg, PN_SRC(v));
880  if (PN_PART(v) == AST_ASSIGN) { //potion only: (k=v, ...)
881  vPN(Source) lhs = PN_SRC(PN_S(v,0));
882  if (lhs->part == AST_EXPR && PN_TUPLE_LEN(PN_S(lhs,0)) == 1)
883  {
884  lhs = SRC_TUPLE_AT(lhs, 0);
885  if (lhs->part == AST_MSG) {
886  PN_ASM_DEBUG(reg, lhs);
887  PN_SIZE num = PN_PUT(f->values, PN_S(lhs,0));
888  DBG_c("values %d %s => %d\n", reg+1, AS_STR(lhs->a[0]), (int)num);
889  PN_ASM2(OP_LOADK, reg + 1, num);
890  lhs = NULL;
891  }
892  }
893 
894  if (lhs != NULL)
895  potion_source_asmb(P, f, loop, 0, lhs, reg + 1);
896 
897  potion_source_asmb(P, f, loop, 0, PN_SRC(v)->a[1], reg + 2);
898  PN_ASM2(OP_SETTABLE, reg, reg + 2);
899  PN_REG(f, reg + 2);
900  } else {
901  potion_source_asmb(P, f, loop, 0, PN_SRC(v), reg + 1);
902  PN_ASM2(OP_SETTUPLE, reg, reg + 1);
903  PN_REG(f, reg + 1);
904  }
905  });
906  }
907  break;
908  }
909 }
910 
911 #define SIG_EXPR_MSG(name,expr) \
912  if (expr->part == AST_EXPR) { \
913  vPN(Source) t = SRC_TUPLE_AT(expr, 0); \
914  if (t->part == AST_MSG) { \
915  name = PN_S(t,0); \
916  PN_PUT(f->locals, name); \
917  DBG_c("locals %s\n", PN_STR_PTR(name)); \
918  sig = PN_PUSH(sig, name); \
919  } \
920  } else { name = PN_NIL; }
921 
942 PN potion_sig_compile(Potion *P, vPN(Proto) f, PN src) {
943  PN sig = PN_TUP0();
944  vPN(Source) t = PN_SRC(src);
945  if (t->part == AST_LIST && PN_S(t,0) != PN_NIL) {
946  //PN_TUPLE_EACH(PN_S(t,0), i, v, {
947  ({ struct PNTuple * volatile __tv = ((struct PNTuple *)potion_fwd(PN_S(t,0)));
948  if (__tv->len != 0) {
949  DBG_c("--- sig compile ---\n");
950  PN_SIZE i;
951  for (i = 0; i < __tv->len; i++) {
952  struct PNSource *v = PN_SRC(__tv->set[i]);
953  {
954  vPN(Source) expr = PN_SRC(v);
955  PN name = 0;
956  SIG_EXPR_MSG(name, expr)
957  if (expr->part == AST_VALUE) {
958  vPN(Source) lhs = expr->a[0];
959  PN v = PN_S(lhs,0);
960  if (PN_IS_STR(v)) {
961  DBG_c("sig: lhs value, computed name %s\n", AS_STR(v));
962  PN_PUT(f->locals, v);
963  DBG_c("locals %s\n", PN_STR_PTR(v));
964  sig = PN_PUSH(sig, v);
965  } else {
966  potion_syntax_error(P, t, "in signature: value %s as argument name", AS_STR(v));
967  }
968  } else if (expr->part == AST_PIPE) { //x|y => (pipe (expm x) (expm y))
969  vPN(Source) lhs = expr->a[0];
970  vPN(Source) rhs = expr->a[1];
971  PN name2 = 0;
972  SIG_EXPR_MSG(name, lhs);
973  sig = PN_PUSH(sig, PN_NUM('|'));
974  SIG_EXPR_MSG(name2, rhs);
975  DBG_c("; (%s | %s)\n", AS_STR(name), AS_STR(name2));
976  } else if (expr->part == AST_ASSIGN) { //x=o => (assign (expm x) (expm o))
977  vPN(Source) lhs = expr->a[0];
978  vPN(Source) rhs = expr->a[1];
979  if (lhs->part == AST_EXPR && PN_TUPLE_LEN(PN_S(lhs,0)) == 1) {
980  SIG_EXPR_MSG(name, lhs);
981  lhs = SRC_TUPLE_AT(lhs, 0);
982  DBG_c("; (%s ", AS_STR(name));
983  }
984  else if (lhs->part == AST_PIPE) {
985  //x|y=o => (assign (pipe (expm x) (expm y)) (expm o))
986  SIG_EXPR_MSG(name, lhs->a[0]);
987  sig = PN_PUSH(sig, PN_NUM('|'));
988  rhs = lhs->a[1];
989  DBG_c("; (%s | ", AS_STR(name));
990  } else {
991  potion_syntax_error(P, t, "in signature: unexpected AST %s", AS_STR(lhs));
992  }
993  if (rhs->part == AST_EXPR && PN_TUPLE_LEN(rhs->a[0]) == 1) {
994  rhs = SRC_TUPLE_AT(rhs, 0);
995  if (rhs->part == AST_MSG) {
996  PN v = PN_NUM(PN_STR_PTR(PN_S(rhs,0))[0]); // = type. TODO: one-char => VTABLE
997  DBG_c("%s)\n", AS_STR(v));
998  sig = PN_PUSH(sig, v);
999  }
1000  } else if (rhs->part == AST_ASSIGN && rhs->a[0]->part == AST_PIPE) {
1001  //x=N|y=o => (assign (pipe (expm x) (expm y)) (expm o))
1002  lhs = PN_S_(PN_S_(rhs, 0), 0);
1003  if (lhs->part == AST_EXPR && SRC_TUPLE_AT(lhs,0)->part == AST_MSG) {
1004  PN v = PN_NUM(PN_STR_PTR((PN)SRC_TUPLE_AT(lhs,0)->a[0])[0]); // = type. TODO: one-char => VTABLE
1005  DBG_c("%s)\n", AS_STR(v));
1006  sig = PN_PUSH(sig, v);
1007  }
1008  sig = PN_PUSH(sig, PN_NUM('|'));
1009  SIG_EXPR_MSG(name, rhs->a[0]->a[1]);
1010  rhs = rhs->a[1];
1011  if (rhs->part == AST_EXPR && SRC_TUPLE_AT(rhs,0)->part == AST_MSG) {
1012  PN v = PN_S(SRC_TUPLE_AT(rhs,0),0);
1013  v = PN_NUM(PN_STR_PTR(v)[0]); // = type. TODO: one-char => VTABLE
1014  DBG_c("%s)\n", AS_STR(v));
1015  sig = PN_PUSH(sig, v);
1016  }
1017  } else if (rhs->part == AST_VALUE) { // :=default
1018  PN v = PN_S(rhs,0);
1019  DBG_c(": %s)\n", AS_STR(v));
1020  sig = PN_PUSH(PN_PUSH(sig, PN_NUM(':')), v);
1021  } else {
1022  potion_syntax_error(P, t, "in signature: unexpected AST %s", AS_STR(expr));
1023  }
1024  }
1025  }}}
1026  });
1027  }
1028  return sig;
1029 }
1030 #undef SRC_TUPLE_AT
1031 #undef SIG_EXPR_MSG
1032 
1039 PN potion_source_compile(Potion *P, PN cl, PN self, PN source, PN sig) {
1040  vPN(Proto) f;
1041  vPN(Source) t = (struct PNSource *)self;
1042 
1043  switch (t->part) {
1044  case AST_CODE:
1045  case AST_BLOCK: break;
1046  default: return PN_NIL; // TODO: error
1047  }
1048  f = PN_ALLOC(PN_TPROTO, struct PNProto);
1049  f->source = source;
1050  f->stack = PN_NUM(1);
1051  f->protos = PN_TUP0();
1052  f->paths = PN_TUP0();
1053  f->locals = PN_TUP0();
1054  f->upvals = PN_TUP0();
1055  f->values = PN_TUP0();
1056  f->debugs = PN_TUP0();
1057  f->tree = self;
1058  DBG_c("-- compile --\n");
1059  f->sig = (sig == PN_NIL ? PN_TUP0() : potion_sig_compile(P, f, sig));
1060  f->asmb = (PN)potion_asm_new(P);
1061  f->name = PN_NIL;
1062 
1063  potion_source_asmb(P, f, NULL, 0, t, 0);
1064  PN_ASM1(OP_RETURN, 0);
1065 
1066  f->localsize = PN_TUPLE_LEN(f->locals);
1067  f->upvalsize = PN_TUPLE_LEN(f->upvals);
1068  f->pathsize = PN_TUPLE_LEN(f->paths);
1069  return (PN)f;
1070 }
1071 
1076  vPN(Proto) f = (struct PNProto *)self;
1077  vPN(Proto) n = PN_ALLOC(PN_TPROTO, struct PNProto);
1078  PN PN_clone = PN_STR("clone");
1079  PNAsm * volatile asmb;
1080  PN len;
1081 
1082  //TODO extern protos
1083  n->name = f->name;
1084  n->source = f->source;
1085  n->stack = f->stack;
1086  n->protos = potion_send(PN_clone, f->protos);
1087  n->paths = potion_send(PN_clone, f->paths);
1088  n->locals = potion_send(PN_clone, f->locals);
1089  n->upvals = potion_send(PN_clone, f->upvals);
1090  n->values = potion_send(PN_clone, f->values);
1091  n->debugs = potion_send(PN_clone, f->debugs);
1092  n->tree = f->tree;
1093  n->localsize = f->localsize;
1094  n->upvalsize = f->upvalsize;
1095  n->pathsize = f->pathsize;
1096  n->sig = PN_IS_TUPLE(f->sig) ? potion_send(PN_clone, f->sig) : f->sig;
1097 
1098  len = ((PNAsm *)f->asmb)->len;
1099  PN_FLEX_NEW(asmb, PN_TBYTES, PNAsm, len);
1100  PN_MEMCPY_N(asmb->ptr, ((PNAsm *)f->asmb)->ptr, u8, len);
1101  asmb->len = len;
1102  n->asmb = (PN)asmb;
1103 
1104  return (PN)n;
1105 }
1106 
1107 #define READ_U8(ptr) ({u8 rpu = *ptr; ptr += sizeof(u8); rpu;})
1108 #define READ_PN(pn, ptr) ({PN rpn = *(PN *)ptr; ptr += pn; rpn;})
1109 #define READ_CONST(pn, ptr) ({ \
1110  PN val = READ_PN(pn, ptr); \
1111  if (PN_IS_PTR(val)) { \
1112  if (val & 2) { \
1113  size_t len = ((val ^ 2) >> 4) - 1; \
1114  val = potion_strtod(P, (char *)ptr, len); \
1115  ptr += len; \
1116  } else { \
1117  size_t len = (val >> 4) - 1; \
1118  val = PN_STRN((char *)ptr, len); \
1119  ptr += len; \
1120  } \
1121  } \
1122  val; \
1123  })
1124 
1125 #define READ_TUPLE(ptr) \
1126  long i = 0, count = READ_U8(ptr); \
1127  PN tup = potion_tuple_with_size(P, (PN_SIZE)count); \
1128  for (; i < count; i++)
1129 #define READ_VALUES(pn, ptr) ({ \
1130  READ_TUPLE(ptr) PN_TUPLE_AT(tup, i) = READ_CONST(pn, ptr); \
1131  tup; \
1132  })
1133 #define READ_PROTOS(pn, ptr) ({ \
1134  READ_TUPLE(ptr) PN_TUPLE_AT(tup, i) = potion_proto_load(P, (PN)f, pn, &(ptr)); \
1135  tup; \
1136  })
1137 
1138 // TODO: this byte string is volatile, need to avoid using ptr
1139 PN potion_proto_load(Potion *P, PN up, u8 pn, u8 **ptr) {
1140  PN len = 0;
1141  PNAsm * volatile asmb = NULL;
1142  vPN(Proto) f = PN_ALLOC(PN_TPROTO, struct PNProto);
1143  // TODO extern protos
1144  f->name = READ_CONST(pn, *ptr);
1145  f->source = READ_CONST(pn, *ptr);
1146  if (f->source == PN_NIL) f->source = up;
1147  f->sig = READ_VALUES(pn, *ptr);
1148  f->stack = READ_CONST(pn, *ptr);
1149  f->values = READ_VALUES(pn, *ptr);
1150  f->paths = READ_VALUES(pn, *ptr);
1151  f->locals = READ_VALUES(pn, *ptr);
1152  f->upvals = READ_VALUES(pn, *ptr);
1153  f->protos = READ_PROTOS(pn, *ptr);
1154  f->debugs = PN_TUP0();
1155 
1156  len = READ_PN(pn, *ptr);
1157  PN_FLEX_NEW(asmb, PN_TBYTES, PNAsm, len);
1158  PN_MEMCPY_N(asmb->ptr, *ptr, u8, len);
1159  asmb->len = len;
1160 
1161  f->asmb = (PN)asmb;
1162  f->localsize = PN_TUPLE_LEN(f->locals);
1163  f->upvalsize = PN_TUPLE_LEN(f->upvals);
1164  f->pathsize = PN_TUPLE_LEN(f->paths);
1165  *ptr += len;
1166  return (PN)f;
1167 }
1168 
1170 // TODO: "load" from a stream
1172  u8 *ptr;
1173  vPN(BHeader) h = (struct PNBHeader *)PN_STR_PTR(buf);
1174  // check for compiled binary first
1175  if ((size_t)PN_STR_LEN(buf) <= sizeof(struct PNBHeader) ||
1176  strncmp((char *)h->sig, POTION_SIG, 4) != 0)
1177  return PN_NIL;
1178 
1179  ptr = h->proto;
1180  return potion_proto_load(P, PN_NIL, h->pn, &ptr);
1181 }
1182 
1183 // TODO: switch to dump methods
1184 #define WRITE_U8(un, ptr) ({*ptr = (u8)un; ptr += sizeof(u8);})
1185 #define WRITE_PN(pn, ptr) ({*(PN *)ptr = pn; ptr += sizeof(PN);})
1186 #define WRITE_CONST(val, ptr) ({ \
1187  if (PN_IS_STR(val)) { \
1188  PN count = (PN_STR_LEN(val)+1) << 4; \
1189  WRITE_PN(count, ptr); \
1190  PN_MEMCPY_N(ptr, PN_STR_PTR(val), char, PN_STR_LEN(val)); \
1191  ptr += PN_STR_LEN(val); \
1192  } else if (PN_IS_DBL(val)) { \
1193  PN str = potion_num_string(P, PN_NIL, val); \
1194  PN count = ((PN_STR_LEN(str)+1) << 4) | 2; \
1195  WRITE_PN(count, ptr); \
1196  PN_MEMCPY_N(ptr, PN_STR_PTR(str), char, PN_STR_LEN(str)); \
1197  ptr += PN_STR_LEN(str); \
1198  } else { \
1199  PN cval = (PN_IS_PTR(val) ? PN_NIL : val); \
1200  WRITE_PN(cval, ptr); \
1201  } \
1202  })
1203 #define WRITE_TUPLE(tup, ptr) \
1204  long i = 0, count = PN_TUPLE_LEN(tup); \
1205  WRITE_U8(count, ptr); \
1206  for (; i < count; i++)
1207 #define WRITE_VALUES(tup, ptr) ({ \
1208  WRITE_TUPLE(tup, ptr) WRITE_CONST(PN_TUPLE_AT(tup, i), ptr); \
1209  })
1210 #define WRITE_PROTOS(tup, ptr) ({ \
1211  WRITE_TUPLE(tup, ptr) ptr += potion_proto_dumpbc(P, PN_TUPLE_AT(tup, i), \
1212  out, (char *)ptr - PN_STR_PTR(out)); \
1213  })
1214 
1221 long potion_proto_dumpbc(Potion *P, PN proto, PN out, long pos) {
1222  vPN(Proto) f = (struct PNProto *)proto;
1223  char *start = PN_STR_PTR(out) + pos;
1224  u8 *ptr = (u8 *)start;
1225  //TODO extern (by name)
1226  WRITE_CONST(f->name, ptr);
1227  WRITE_CONST(f->source, ptr);
1228  WRITE_VALUES(f->sig, ptr);
1229  WRITE_CONST(f->stack, ptr);
1230  WRITE_VALUES(f->values, ptr);
1231  WRITE_VALUES(f->paths, ptr);
1232  WRITE_VALUES(f->locals, ptr);
1233  WRITE_VALUES(f->upvals, ptr);
1234  WRITE_PROTOS(f->protos, ptr);
1235  WRITE_PN(PN_FLEX_SIZE(f->asmb), ptr);
1236  PN_MEMCPY_N(ptr, ((PNFlex *)f->asmb)->ptr, u8, PN_FLEX_SIZE(f->asmb));
1237  ptr += PN_FLEX_SIZE(f->asmb);
1238  return (char *)ptr - start;
1239 }
1240 
1243 // Low TODO: dump to a stream (if we have not enough memory)
1244 PN potion_source_dumpbc(Potion *P, PN cl, PN proto, PN options) {
1245  PN pnb = potion_bytes(P, 8192);
1246  struct PNBHeader h;
1247  DBG_c("compile bc\n");
1248  PN_MEMCPY_N(h.sig, POTION_SIG, u8, 4);
1249  h.major = POTION_MAJOR;
1250  h.minor = POTION_MINOR;
1251  h.vmid = POTION_VMID;
1252  h.pn = (u8)sizeof(PN);
1253 
1254  PN_MEMCPY(PN_STR_PTR(pnb), &h, struct PNBHeader);
1255  PN_STR_LEN(pnb) = (long)sizeof(struct PNBHeader) +
1256  potion_proto_dumpbc(P, proto, pnb, sizeof(struct PNBHeader));
1257  return pnb;
1258 }
1259 
1265 PN potion_source_dump(Potion *P, PN cl, PN self, PN backend, PN options) {
1266  if (backend == PN_STRN("bc", 2))
1267  return potion_source_dumpbc(P, cl, self, options);
1268 #ifndef SANDBOX
1269  char *cb = PN_STR_PTR(backend);
1270  if (potion_load(P, P->lobby, self, potion_strcat(P, "compile/", cb))) {
1271  DBG_c("loaded compile/%s\n", cb);
1272  DBG_c("Source dump%s(%s)\n", cb, PN_IS_STR(options) ? PN_STR_PTR(options) : "");
1273  return potion_send(self, potion_strcat(P, "dump", cb), options);
1274  } else {
1275  fprintf(stderr, "** failed loading the compile/%s module\n", cb);
1276  return PN_NIL;
1277  }
1278 #else
1279  potion_fatal("external compilers disabled with SANDBOX");
1280 #endif
1281 }
1282 
1283 PN potion_run(Potion *P, PN code, int jit) {
1284 #ifndef POTION_JIT_TARGET
1285  if (jit) {
1286  fprintf(stderr, "** potion not compiled with JIT\n");
1287  jit = 0;
1288  }
1289 #endif
1290  if (jit) {
1291  PN cl = potion_closure_new(P, (PN_F)potion_jit_proto(P, code), PN_NIL, 1);
1292  PN_CLOSURE(cl)->data[0] = code;
1293  return PN_PROTO(code)->jit(P, cl, P->lobby);
1294  } else {
1295  return potion_vm(P, code, P->lobby, PN_NIL, 0, NULL);
1296  }
1297 }
1298 
1299 PN potion_eval(Potion *P, PN bytes) {
1300  PN code = (PN_TYPE(bytes) == PN_TSOURCE)
1301  ? bytes
1302  : potion_parse(P, bytes, "<eval>");
1303  if (PN_TYPE(code) != PN_TSOURCE) return code;
1304  code = potion_send(code, PN_compile, PN_NIL, PN_NIL);
1305  return potion_run(P, code, P->flags & EXEC_JIT);
1306 }
1307 
1309  PN pro_vt = PN_VTABLE(PN_TPROTO);
1310  PN src_vt = PN_VTABLE(PN_TSOURCE);
1311  potion_method(pro_vt, "call", potion_proto_call, "args=u");
1312  potion_method(pro_vt, "tree", potion_proto_tree, 0);
1313  potion_method(pro_vt, "string", potion_proto_string, 0);
1314  potion_method(pro_vt, "clone", potion_proto_clone, 0);
1315  potion_method(src_vt, "compile", potion_source_compile, "source=a,sig=u");
1316  potion_method(src_vt, "dump", potion_source_dump, "backend=S|options=S");
1317  potion_method(src_vt, "dumpbc", potion_source_dumpbc, "|options=S");
1318 }
#define PN_TUPLE_AT(t, n)
Definition: potion.h:269
PN PN_compile
Definition: internal.c:14
PN PN_loop
Definition: internal.c:14
PN potion_vm(Potion *, PN, PN, PN, PN_SIZE, PN *volatile)
the bytecode run-loop
Definition: vm.c:594
#define PN_IS_STR(v)
Definition: potion.h:166
PN asmb
assembled instructions
Definition: potion.h:458
#define PN_FLEX_NEW(N, V, T, S)
Definition: internal.h:35
PN potion_bytes(Potion *, size_t)
Definition: string.c:342
PN potion_closure_new(Potion *P, PN_F meth, PN sig, PN_SIZE extra)
Definition: objmodel.c:17
PN upvals
variables in upper scopes
Definition: potion.h:452
PN PN_extern
Definition: internal.c:19
PN_AST
An AST fragment, non-volatile.
Definition: potion.h:386
u8 proto[]
Definition: internal.h:76
PN values
numbers, strings, etc.
Definition: potion.h:453
PN PN_return
Definition: internal.c:14
Definition: opcodes.h:32
#define WRITE_PN(pn, ptr)
Definition: compile.c:1185
#define PN_S(S, N)
Definition: ast.h:33
#define vPN(t)
Definition: potion.h:132
#define PN_TSTRING
Definition: potion.h:112
PN_F potion_jit_proto(Potion *, PN)
a tuple is an array of PNs.
Definition: potion.h:468
PN potion_proto_load(Potion *P, PN up, u8 pn, u8 **ptr)
Definition: compile.c:1139
#define READ_PROTOS(pn, ptr)
Definition: compile.c:1133
#define PN_CLOSURE(x)
Definition: potion.h:216
Potion_Flags flags
vm flags: execution model and debug flags
Definition: potion.h:650
PN PN_elsif
Definition: internal.c:14
#define MAX_JUMPS
Definition: compile.c:256
unsigned long _PN
Definition: potion.h:78
Definition: opcodes.h:36
PN sig
argument signature
Definition: potion.h:448
PN_SIZE void potion_bytes_obj_string(Potion *, PN, PN)
Definition: string.c:384
u8 sig[4]
Definition: internal.h:71
#define PN_PUT(T, X)
Definition: potion.h:266
Definition: potion.h:396
PN PN potion_byte_str(Potion *, const char *)
Definition: string.c:331
PN potion_sig_string(Potion *P, PN cl, PN sig)
Definition: compile.c:60
PN potion_source_dumpbc(Potion *P, PN cl, PN proto, PN options)
Definition: compile.c:1244
#define potion_method(RCV, MSG, FN, SIG)
Definition: potion.h:780
#define PN_TUPLE_LEN(t)
Definition: potion.h:268
Definition: opcodes.h:34
#define AS_STR(x)
Definition: potion.h:240
#define PN_FINTEGER
Definition: potion.h:152
unsigned int PNType
Definition: potion.h:79
#define PN_PUSH(T, X)
Definition: potion.h:263
#define PN_STR_LEN(x)
Definition: potion.h:214
PN PN_break
Definition: internal.c:14
static PN potion_fwd(PN)
the potion type is the 't' in the vtable tuple (m,t)
Definition: potion.h:561
#define PN_ASM_DEBUG(REG, T)
Definition: compile.c:242
PN potion_sig_compile(Potion *P, vPN(Proto) f, PN src)
Converts a pre-compiled potion expr to a signature tuple.
Definition: compile.c:942
#define WRITE_CONST(val, ptr)
Definition: compile.c:1186
#define PN_ARG(n, reg)
Definition: compile.c:187
Definition: opcodes.h:48
const struct @0 potion_ops[]
PN potion_source_load(Potion *P, PN cl, PN buf)
Definition: compile.c:1171
Definition: potion.h:577
#define DBG_c(...)
Definition: potion.h:250
PN_F jit
jit function pointer
Definition: potion.h:459
PN potion_source_compile(Potion *P, PN cl, PN self, PN source, PN sig)
Definition: compile.c:1039
Definition: opcodes.h:37
the Potion VM instruction set (heavily based on Lua's)
#define PN_TBYTES
Definition: potion.h:121
#define PN_STR(x)
Definition: potion.h:210
the ast for Potion code in-memory
#define PN_SRC(S)
Definition: ast.h:30
#define PN_INT(x)
Definition: potion.h:205
Definition: opcodes.h:31
#define PN_NUM(i)
Definition: potion.h:204
PN potion_source_dump(Potion *P, PN cl, PN self, PN backend, PN options)
Definition: compile.c:1265
int cjmps[MAX_JUMPS]
Definition: compile.c:261
unsigned int PN_SIZE
Definition: potion.h:79
PN potion_load(Potion *P, PN cl, PN self, PN file)
Definition: load.c:155
int arity
cached sig arity (number of args)
Definition: potion.h:460
#define PN_STR_B(x)
Definition: potion.h:215
#define PN_IS_NIL(v)
Definition: potion.h:160
enum PN_AST part
AST type, avoid -Wswitch (aligned access: 4+4+8+4+24)
Definition: potion.h:426
#define PN_OP(T, A, B)
Warning: This might conflict with the typedef struct PN_OP.
Definition: ast.h:28
PN lobby
root namespace
Definition: potion.h:648
PN_SIZE len
Definition: potion.h:470
PN potion_proto_string(Potion *P, PN cl, PN self)
Definition: compile.c:98
#define POTION_MAJOR
Definition: config.h:2
#define PN_ARG_TABLE(args, reg, inc)
Definition: compile.c:240
#define PN_TSOURCE
Definition: potion.h:120
PN locals
local variables
Definition: potion.h:451
u8 vmid
Definition: internal.h:74
#define PN_FLEX_SIZE(N)
Definition: potion.h:231
PNAsm * potion_asm_op(Potion *P, PNAsm *volatile asmb, u8 ins, int _a, int _b)
Definition: asm.c:43
PN potion_run(Potion *P, PN code, int jit)
Definition: compile.c:1283
PN potion_proto_call(Potion *P, PN cl, PN self, PN args)
Definition: compile.c:55
PN paths
paths (instance variables)
Definition: potion.h:450
Definition: opcodes.h:38
void potion_syntax_error(Potion *P, struct PNSource *t, const char *fmt,...)
Definition: internal.c:289
PN potion_parse(Potion *, PN, char *)
#define READ_CONST(pn, ptr)
Definition: compile.c:1109
#define PN_NONE
Definition: potion.h:145
u8 major
Definition: internal.h:72
jump table for loops, for the 2 args b and c Note: only statically allocated (max 1024) ...
Definition: compile.c:259
unsigned char u8
Definition: internal.h:8
#define PN_VTYPE(x)
Definition: potion.h:134
#define PN_MEMCPY_N(X, Y, T, N)
Definition: internal.h:22
.pnb binary dump header
Definition: internal.h:70
PN potion_eval(Potion *P, PN bytes)
Definition: compile.c:1299
some assembler macros
int cjmpc
count of c jumps (abc regs)
Definition: compile.c:264
PNAsm * potion_asm_new(Potion *P)
Definition: asm.c:13
#define PN_BLOCK(reg, blk, sig)
Definition: compile.c:198
#define LOAD_ARG()
#define PN_PART(S)
Definition: ast.h:31
JIT if detected at config-time (x86, ppc)
Definition: potion.h:607
a prototype is compiled source code, a closure block (lambda) non-volatile.
Definition: potion.h:445
void potion_arg_asmb(Potion *P, struct PNProto *volatile f, struct PNLoop *loop, PN args, u8 *reg, int inc)
Definition: compile.c:269
non-API internal parts
PN PN_if
Definition: internal.c:14
#define SIG_EXPR_MSG(name, expr)
Definition: compile.c:911
PN protos
nested closures
Definition: potion.h:454
#define ASM_TPL_IMM
Definition: asm.h:17
#define PN_IS_PTR(v)
Definition: potion.h:159
Definition: opcodes.h:41
Definition: potion.h:398
#define PN_GET(T, X)
Definition: potion.h:265
#define PN_ASM2(ins, _a, _b)
Definition: compile.c:27
Definition: opcodes.h:45
#define PN_UPVAL(name)
Definition: compile.c:210
u8 potion_source_debug(Potion *P, struct PNProto *volatile f, struct PNSource *volatile t, u8 reg)
insert DEBUG ops for every new line
Definition: compile.c:245
Definition: potion.h:391
PN_SIZE len
Definition: potion.h:577
#define PN_OP_AT(asmb, n)
Definition: opcodes.h:82
Definition: potion.h:394
#define PN_OP_LEN(asmb)
Definition: opcodes.h:83
-d: instrumented bytecode (line stepping) or just slow runloop?
Definition: potion.h:608
Definition: opcodes.h:28
int a
< the op. See vm.c http://www.lua.org/doc/jucs05.pdf
Definition: opcodes.h:71
the global interpreter state P. currently singleton (not threads yet)
Definition: potion.h:644
#define PN_ALLOC(V, T)
Definition: internal.h:12
#define PN_ASM1(ins, _a)
Definition: compile.c:26
The potion API.
PN_SIZE pn_printf(Potion *, PN, const char *,...) __attribute__((format(printf
PN PN_while
Definition: internal.c:14
unsigned char ptr[]
Definition: potion.h:577
PN PN_class
Definition: internal.c:14
#define READ_VALUES(pn, ptr)
Definition: compile.c:1129
#define PN_TYPE(x)
Definition: potion.h:133
#define PN_TPROTO
Definition: potion.h:122
Definition: opcodes.h:29
Definition: opcodes.h:40
PN potion_strcat(Potion *P, char *str, char *str2)
Definition: string.c:64
Definition: opcodes.h:35
#define PN_IS_INT(v)
Definition: potion.h:162
#define PN_S_(S, N)
Definition: ast.h:32
PN debugs
tree parts
Definition: potion.h:455
struct PNSource *volatile a[3]
PNTuple of 1-3 kids,.
Definition: potion.h:427
_PN(* PN_F)(Potion *, PN, PN,...)
Definition: potion.h:207
void potion_compiler_init(Potion *P)
Definition: compile.c:1308
#define PN_REG(f, reg)
Definition: compile.c:184
int bjmpc
count of b jumps (abc regs)
Definition: compile.c:263
#define POTION_VMID
Definition: potion.h:43
#define SRC_TUPLE_AT(src, i)
Definition: compile.c:241
PN stack
size of the stack
Definition: potion.h:449
#define potion_send(RCV, MSG, ARGS...)
method caches (more great stuff from ian piumarta)
Definition: potion.h:772
long potion_proto_dumpbc(Potion *P, PN proto, PN out, long pos)
Definition: compile.c:1221
int potion_sig_arity(Potion *P, PN sig)
number of args of sig tuple, implements the potion_closure_arity method.
Definition: objmodel.c:82
#define PN_STRN(x, l)
Definition: potion.h:211
int bjmps[MAX_JUMPS]
Definition: compile.c:260
const char * name
Definition: compile.c:30
#define PN_MEMCPY(X, Y, T)
Definition: internal.h:21
#define POTION_SIG
Definition: potion.h:42
Definition: opcodes.h:47
PN tree
abstract syntax tree
Definition: potion.h:456
#define WRITE_PROTOS(tup, ptr)
Definition: compile.c:1210
volatile _PN PN
Definition: potion.h:81
PNType lineno
Definition: potion.h:435
void potion_source_asmb(Potion *, struct PNProto *volatile, struct PNLoop *, PN_SIZE, struct PNSource *volatile, u8)
Definition: compile.c:321
#define PN_NIL
Definition: potion.h:139
PN PN_name
Definition: internal.c:18
#define READ_PN(pn, ptr)
Definition: compile.c:1108
u8 minor
Definition: internal.h:73
#define PN_IS_TUPLE(v)
Definition: potion.h:165
#define PN_CALLOC_N(V, T, C)
Definition: internal.h:14
#define WRITE_VALUES(tup, ptr)
Definition: compile.c:1207
PN source
program name or enclosing scope
Definition: potion.h:447
PN potion_proto_clone(Potion *P, PN cl, PN self)
Definition: compile.c:1075
PN name
PNString.
Definition: potion.h:461
PN potion_proto_tree(Potion *P, PN cl, PN self)
Definition: compile.c:48
PN PN_else
Definition: internal.c:14
struct PNSource::@1 loc
bitfield of fileno and lineno
#define PN_TUPLE_EACH(T, I, V, B)
Definition: potion.h:279
PN PN_self
Definition: internal.c:14
#define PN_TUP(X)
Definition: potion.h:262
PN set[]
Definition: potion.h:472
void potion_fatal(char *message)
Definition: internal.c:282
const u8 args
Definition: compile.c:31
#define PN_STR_PTR(x)
Definition: potion.h:213
PN PN_continue
Definition: internal.c:14
#define PN_TUP0()
Definition: potion.h:261
#define PN_VTABLE(t)
Definition: potion.h:136
PN_OP - a compressed three-address op (as 32bit int bitfield) TODO: expand to 64bit, check jit then.
Definition: opcodes.h:70
Definition: opcodes.h:33
#define PN_PROTO(x)
Definition: potion.h:218
#define POTION_MINOR
Definition: config.h:3
Definition: opcodes.h:39