p2  0.0
 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 "p2.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 #ifdef P2XXX
188 // uses global PN_SRC(t)
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); }); \
196  } \
197  } else { \
198  potion_source_asmb(P, f, loop, 0, t->a[n], reg); \
199  }
200 #else
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); }); \
208  } \
209  } else { \
210  potion_source_asmb(P, f, loop, 0, t->a[n], reg); \
211  }
212 #endif
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)); \
223  }); \
224 })
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)); \
233  vPN(Proto) up = f; \
234  int depth = 1; \
235  while (PN_IS_PROTO(up->source)) { \
236  up = (struct PNProto *)up->source; \
237  if (PN_NONE != (numup = PN_GET(up->locals, name))) break; \
238  depth++; \
239  } \
240  DBG_c("locals %s <= %d\n", AS_STR(name), (int)numup); \
241  if (numup != PN_NONE) { \
242  up = f; \
243  while (depth--) { \
244  up->upvals = PN_PUSH(up->upvals, name); \
245  DBG_c("upvals %s =>\n", AS_STR(name)); \
246  up = (struct PNProto *)up->source; \
247  } \
248  } \
249  numup = PN_GET(f->upvals, name); \
250  DBG_c("upvals %s <= %d\n", AS_STR(name), (int)numup); \
251  } \
252  } \
253  numup; \
254 })
255 #define PN_ARG_TABLE(args, reg, inc) potion_arg_asmb(P, f, loop, args, &reg, 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)
258 
260 u8 potion_source_debug(Potion *P, struct PNProto * volatile f, struct PNSource * volatile t, u8 reg) {
261  static PNType lineno = 0;
262  if ((P->flags & EXEC_DEBUG) && t && t->loc.lineno != lineno && t->loc.lineno > 0) {
263  PN_SIZE num = PN_PUT(f->debugs, (PN)t);
264  PN_ASM2(OP_DEBUG, reg, num);
265  lineno = t->loc.lineno;
266  DBG_c("debug %s :%d\n", PN_STR_PTR(potion_send(t, PN_name)), lineno);
267  }
268  return reg;
269 }
270 
271 #define MAX_JUMPS 1024
272 struct PNLoop {
277 
278  int bjmpc;
279  int cjmpc;
280 };
281 
282 void potion_source_asmb(Potion *, struct PNProto * volatile, struct PNLoop *, PN_SIZE, struct PNSource * volatile, u8);
283 
284 void potion_arg_asmb(Potion *P, struct PNProto * volatile f, struct PNLoop *loop, PN args, u8 *reg, int inc) {
285  if (args != PN_NIL) {
286  if (PN_PART(args) == AST_LIST) {
287  args = PN_S(args,0);
288  if (!PN_IS_NIL(args)) {
289  u8 freg = *reg, sreg = *reg + PN_TUPLE_LEN(args) + 1;
290  DBG_c("ARGLIST %d %d\n", freg, sreg);
291  PN_TUPLE_EACH(args, i, v, {
292  if (inc) {
293  (*reg)++;
294  if (PN_PART(v) == AST_ASSIGN) {
295  vPN(Source) lhs = PN_SRC(PN_S(v,0));
296  potion_source_asmb(P, f, loop, 0, PN_SRC(v)->a[1], sreg + 1);
297  if (lhs->part == AST_EXPR && PN_TUPLE_LEN(PN_S(lhs,0)) == 1)
298  {
299  lhs = SRC_TUPLE_AT(lhs, 0);
300  PN_ASM_DEBUG(sreg, lhs);
301  if (lhs->part == AST_MSG || lhs->part == AST_VALUE) {
302  PN_OP op; op.a = PN_S(lhs,0); //12 bit!
303  if (!PN_IS_PTR(PN_S(lhs,0)) && PN_S(lhs,0) == op.a) {
304  PN_ASM2(OP_LOADPN, sreg, PN_S(lhs,0));
305  } else {
306  PN_SIZE num = PN_PUT(f->values, PN_S(lhs,0));
307  DBG_c("values %d %s => %d\n", sreg, AS_STR(lhs->a[0]), (int)num);
308  PN_ASM2(OP_LOADK, sreg, num);
309  }
310  lhs = NULL;
311  }
312  }
313 
314  if (lhs != NULL)
315  potion_source_asmb(P, f, loop, 0, lhs, sreg);
316 
317  PN_ASM2(OP_NAMED, freg - 1, sreg + 1);
318  PN_REG(f, sreg + 1);
319  } else
320  potion_source_asmb(P, f, loop, 0, PN_SRC(v), *reg);
321  } else
322  potion_source_asmb(P, f, loop, 0, PN_SRC(v), *reg);
323  });
324  }
325  } else {
326  if (inc) (*reg)++;
327  potion_source_asmb(P, f, loop, 0, PN_SRC(args), *reg);
328  }
329  } else {
330  if (inc) (*reg)++;
331  PN_ASM_DEBUG(*reg, PN_SRC(args));
332  PN_ASM2(OP_LOADPN, *reg, args);
333  }
334 }
335 
336 void potion_source_asmb(Potion *P, struct PNProto * volatile f, struct PNLoop *loop, PN_SIZE count,
337  struct PNSource * volatile t, u8 reg) {
338  //PN fname = 0;
339  PN_REG(f, reg);
340  PN_ASM_DEBUG(reg, t);
341  switch (t->part) {
342  case AST_CODE:
343  case AST_BLOCK:
344  if (PN_S(t,0) != PN_NIL) {
345  DBG_c("%s %u %s\n", t->part == AST_CODE?"code":"block", reg,
346  t->part == AST_CODE?"":AS_STR(PN_S(t,0)));
347  PN_TUPLE_EACH(PN_S(t,0), i, v, {
348  potion_source_asmb(P, f, loop, 0, PN_SRC(v), reg);
349  });
350  }
351  break;
352 
353  case AST_EXPR:
354  if (PN_S(t,0) != PN_NIL) {
355  PN e = PN_S(t,0);
356  DBG_c("expr %u %s\n", reg, AS_STR(e));
357  PN_TUPLE_EACH(e, i, v, {
358  potion_source_asmb(P, f, loop, i, PN_SRC(v), reg);
359  });
360  }
361  break;
362 
363  case AST_PROTO:
364  PN_BLOCK(reg, PN_S(t,1), PN_S(t,0));
365  break;
366 
367  case AST_VALUE: {
368  vPN(Source) a = PN_S_(t,0);
369  PN_OP op; op.a = PN_S(t,0); // but 12bit only
370  if (!PN_IS_PTR(a) && (PN)a == (PN)op.a) {
371  PN_ASM2(OP_LOADPN, reg, PN_S(t,0));
372  } else if (a != PN_NIL && PN_IS_PTR(a)
373  && PN_PART(a) == AST_LICK && PN_PART(a->a[0]) == AST_MSG) {
374  vPN(Source) msg = a->a[0];
375  PN tpl = PN_S(msg, 0);
376  // locals or upvals. locals alone broke nbody
377  PN_SIZE num = PN_UPVAL(tpl);
378  u8 opcode = OP_GETUPVAL;
379  PN key = PN_S(PN_TUPLE_AT(a->a[1]->a[0], 0), 0);
380  if (num == PN_NONE) {
381  num = PN_PUT(f->locals, tpl);
382  DBG_c("locals %s => %d\n", AS_STR(tpl), (int)num);
383  opcode = OP_GETLOCAL;
384  }
385  PN_ASM2(opcode, reg, num);
386  if (PN_VTYPE(key) == PN_TSTRING) { // a[k] a variable
387  num = PN_PUT(f->locals, key);
388  DBG_c("locals %s => %d\n", PN_STR_PTR(key), (int)num);
389  PN_ASM2(OP_GETLOCAL, reg+1, num);
390  num = reg+1;
391  DBG_c("gettuple %d %d %s[%s]\n", reg, num, PN_STR_PTR(tpl), PN_STR_PTR(key));
392  PN_ASM2(OP_GETTUPLE, reg, num | ASM_TPL_IMM);
393  PN_REG(f, reg + 1);
394  } else { // a[0] constant, could to be optimized in jit
395  assert(PN_VTYPE(key) == PN_TSOURCE && PN_PART(key) == AST_VALUE);
396  PN k = PN_S(key, 0);
397  if (PN_IS_INT(k)) {
398  if (PN_INT(k) >= ASM_TPL_IMM || PN_INT(k) < 0) {
399  num = PN_PUT(f->values, k);
400  PN_ASM2(OP_LOADK, reg+1, num);
401  DBG_c("values %ld => %d\n", PN_INT(k), (int)num);
402  num = reg + 1;
403  PN_REG(f, reg + 1);
404  } else {
405  num = PN_INT(k);
406  }
407  DBG_c("gettuple %d %d %s[%ld]\n", reg, num, PN_STR_PTR(tpl), PN_INT(k));
408  PN_ASM2(OP_GETTUPLE, reg, num);
409  } else {
410  num = PN_PUT(f->values, k); // op.b has 12 bits
411  PN_ASM2(OP_LOADK, reg+1, num);
412  DBG_c("values \"%s\" => %d\n", PN_STR_PTR(k), (int)num);
413  num = reg+1;
414  DBG_c("gettable %d %d %s[\"%s\"]\n", reg, num, PN_STR_PTR(tpl), PN_STR_PTR(k));
415  PN_ASM2(OP_GETTABLE, reg, num);
416  PN_REG(f, reg + 1);
417  }
418  }
419  } else {
420  PN_SIZE num = PN_PUT(f->values, (PN)a);
421  DBG_c("values %d %s => %d\n", reg, AS_STR(a), (int)num);
422  PN_ASM2(OP_LOADK, reg, num);
423  }
424  if (PN_S(t,1) != PN_NIL && a->part != AST_LICK) {
425  u8 breg = reg;
426  PN_ASM1(OP_SELF, ++breg);
427  PN_ARG_TABLE(PN_S(t,1), breg, 1);
428  if (PN_S(t,2) != PN_NIL) {
429  breg++;
430  PN_BLOCK(breg, PN_S(t,2), PN_NIL);
431  }
432  DBG_c("; call %d %d VALUE\n", reg, breg);
433  PN_ASM2(OP_CALL, reg, breg);
434  }
435  }
436  break;
437 
438  case AST_ASSIGN: {
439  vPN(Source) lhs = t->a[0];
440  PN_SIZE num = PN_NONE, c = count;
441  u8 opcode = OP_GETUPVAL, breg = reg;
442 
443  if (lhs->part == AST_EXPR) {
444  unsigned long i = 0;
445  c = PN_TUPLE_LEN(PN_S(lhs,0)) - 1;
446  DBG_c("assign expr [%lu]\n", (_PN)c);
447  for (i = 0; i < c; i++) {
448  potion_source_asmb(P, f, loop, i, SRC_TUPLE_AT(lhs, i), reg);
449  };
450  lhs = SRC_TUPLE_AT(lhs, c);
451  PN_ASM_DEBUG(reg, lhs);
452  }
453 
454  if (lhs->part == AST_MSG || lhs->part == AST_QUERY) {
455 #ifndef P2
456  char first_letter = PN_STR_PTR(PN_S(lhs,0))[0];
457 #endif
458  DBG_c("assign %s '%s'\n", lhs->part == AST_MSG?"msg":"query",
459  AS_STR(PN_S(lhs,0)));
460  /* globals are different in potion and p2 */
461 #ifndef P2
462  if ((first_letter & 0x80) == 0 && isupper((unsigned char)first_letter)) {
463  num = PN_PUT(f->values, PN_S(lhs,0));
464  DBG_c("values %d %s => %d\n", breg, AS_STR(lhs->a[0]), (int)num);
465  PN_ASM2(OP_LOADK, breg, num);
466  opcode = OP_GLOBAL;
467  num = ++breg;
468  } else
469 #endif
470  if (c == 0) {
471  num = PN_UPVAL(PN_S(lhs,0));
472  if (num == PN_NONE) {
473  num = PN_PUT(f->locals, PN_S(lhs,0));
474  DBG_c("locals %s => %d\n", AS_STR(lhs->a[0]), (int)num);
475  opcode = OP_GETLOCAL;
476 #if 0 // store func names
477  if (lhs->part == AST_MSG) {
478  PN rhs = PN_TUPLE_AT(f->locals, num);
479  PN fname = PN_S(lhs,0);
480  DBG_c("getlocal %s %ld = %s\n",
481  PN_STR_PTR(fname), PN_INT(num), AS_STR(rhs));
482  }
483 #endif
484  }
485  } else {
486  num = PN_PUT(f->values, PN_S(lhs,0));
487  DBG_c("values %d %s => %d\n", breg+1, AS_STR(lhs->a[0]), (int)num);
488  PN_ASM2(OP_LOADK, ++breg, num);
489  opcode = OP_DEF;
490  num = ++breg;
491  }
492  } else if (lhs->part == AST_PATH || lhs->part == AST_PATHQ) {
493  DBG_c("assign %s\n", lhs->part == AST_PATH?"path":"pathq");
494  num = PN_PUT(f->values, PN_S(lhs,0));
495  DBG_c("values %d %s => %d\n", breg+1, AS_STR(lhs->a[0]), (int)num);
496  if (c == 0) {
497  PN_PUT(f->paths, PN_NUM(num));
498  DBG_c("paths %d\n", (int)num);
499  PN_ASM1(OP_SELF, reg);
500  }
501  PN_ASM2(OP_LOADK, ++breg, num);
502  opcode = OP_GETPATH;
503  num = ++breg;
504  }
505 
506  if (num == PN_NONE)
507  potion_syntax_error(P, t, "Assignment to illegal variable");
508  else if (lhs->a[1] != PN_NIL) {
509  breg = reg;
510  PN_ASM2(opcode, ++breg, num);
511  DBG_c("; callset %d %d ASSIGN\n", reg, breg);
512  PN_ASM2(OP_CALLSET, reg, breg);
513  PN_ARG_TABLE(PN_S(lhs,1), breg, 1);
514  // TODO: no block allowed here?
515  potion_source_asmb(P, f, loop, 0, t->a[1], ++breg);
516  DBG_c("; call %d %d ASSIGN\n", reg, breg);
517  PN_ASM2(OP_CALL, reg, breg);
518  } else {
519  potion_source_asmb(P, f, loop, 0, t->a[1], breg);
520  if (opcode == OP_GETUPVAL) {
521  if (lhs->part == AST_QUERY) {
522  PN_ASM2(OP_GETUPVAL, breg, num);
523  PN_ASM2(OP_TESTJMP, breg, 1);
524  }
525  PN_ASM2(OP_SETUPVAL, reg, num);
526  } else if (opcode == OP_GETLOCAL) {
527  if (lhs->part == AST_QUERY) {
528  PN_ASM2(OP_GETLOCAL, breg, num);
529  PN_ASM2(OP_TESTJMP, breg, 1);
530  } else {
531  DBG_c("setlocal %d %d\n", reg, (int)num);
532  PN_ASM2(OP_SETLOCAL, reg, num);
533  }
534  } else if (opcode == OP_GETPATH) {
535  if (lhs->part == AST_PATHQ) {
536  PN_ASM2(OP_GETPATH, reg, num);
537  PN_ASM2(OP_TESTJMP, reg, 1);
538  }
539  PN_ASM2(OP_SETPATH, reg, num);
540  } else {
541  PN_ASM2(opcode, reg, num);
542  }
543  }
544  PN_REG(f, breg);
545  }
546  break;
547 
548  case AST_INC: {
549  u8 breg = reg;
550  vPN(Source) lhs = t->a[0];
551  PN_SIZE num = PN_UPVAL(PN_S(lhs,0));
552  u8 opcode = OP_SETUPVAL;
553  if (num == PN_NONE) {
554  num = PN_PUT(f->locals, PN_S(lhs,0));
555  DBG_c("locals %s => %d\n", AS_STR(lhs->a[0]), (int)num);
556  opcode = OP_SETLOCAL;
557  }
558 
559  if (opcode == OP_SETUPVAL)
560  PN_ASM2(OP_GETUPVAL, reg, num);
561  else if (opcode == OP_SETLOCAL)
562  PN_ASM2(OP_GETLOCAL, reg, num);
563  if (PN_IS_INT(PN_S(t,1))) {
564  breg++;
565  PN_ASM2(OP_MOVE, breg, reg);
566  }
567  PN_ASM2(OP_LOADPN, breg + 1, (PN_S(t,1) | PN_FINTEGER));
568  PN_ASM2(OP_ADD, breg, breg + 1);
569  PN_ASM2(opcode, breg, num);
570  PN_REG(f, breg + 1);
571  }
572  break;
573 
574  case AST_CMP: case AST_EQ: case AST_NEQ:
575  case AST_GT: case AST_GTE: case AST_LT: case AST_LTE:
576  case AST_PLUS: case AST_MINUS: case AST_TIMES: case AST_DIV:
577  case AST_REM: case AST_POW: case AST_BITL: case AST_BITR: {
578  PN_ARG(0, reg);
579  PN_ARG(1, reg + 1);
580  switch (t->part) {
581  case AST_CMP: PN_ASM2(OP_CMP, reg, reg + 1); break;
582  case AST_EQ: PN_ASM2(OP_EQ, reg, reg + 1); break;
583  case AST_NEQ: PN_ASM2(OP_NEQ, reg, reg + 1); break;
584  case AST_GTE: PN_ASM2(OP_GTE, reg, reg + 1); break;
585  case AST_GT: PN_ASM2(OP_GT, reg, reg + 1); break;
586  case AST_LT: PN_ASM2(OP_LT, reg, reg + 1); break;
587  case AST_LTE: PN_ASM2(OP_LTE, reg, reg + 1); break;
588  case AST_PLUS: PN_ASM2(OP_ADD, reg, reg + 1); break;
589  case AST_MINUS: PN_ASM2(OP_SUB, reg, reg + 1); break;
590  case AST_TIMES: PN_ASM2(OP_MULT, reg, reg + 1); break;
591  case AST_DIV: PN_ASM2(OP_DIV, reg, reg + 1); break;
592  case AST_REM: PN_ASM2(OP_REM, reg, reg + 1); break;
593  case AST_POW: PN_ASM2(OP_POW, reg, reg + 1); break;
594  case AST_BITL: PN_ASM2(OP_BITL, reg, reg + 1); break;
595  case AST_BITR: PN_ASM2(OP_BITR, reg, reg + 1); break;
596  }
597  }
598  break;
599 
600  case AST_NOT: case AST_WAVY:
601  PN_ARG(0, reg);
602  PN_ASM2(t->part == AST_WAVY ? OP_BITN : OP_NOT, reg, reg);
603  break;
604 
605  case AST_AND: case AST_OR: {
606  int jmp;
607  PN_ARG(0, reg);
608  jmp = PN_OP_LEN(f->asmb);
609  PN_ASM2(t->part == AST_AND ? OP_NOTJMP : OP_TESTJMP, reg, 0);
610  PN_ARG(1, reg);
611  PN_OP_AT(f->asmb, jmp).b = (PN_OP_LEN(f->asmb) - jmp) - 1;
612  }
613  break;
614 
615  // TODO: this stuff is ugly and repetitive. replace by compiler macros for control structures
616  case AST_MSG:
617  case AST_QUERY: {
618  u8 breg = reg;
619  int arg = (PN_S(t,1) != PN_NIL);
620  int call = (PN_S(t,2) != PN_NIL || arg);
621  PN ifconst = PN_NONE;
622 #ifdef P2
623  if (t->part == AST_MSG && PN_S(t,0) == PN_use) {
624 # if 0
625  PN use = PN_TUPLE_AT(PN_S(t,1), 0);
626  PN name = PN_TUPLE_AT(PN_S(t,1), 1);
627  PN list = potion_tuple_at(P,0,PN_S(t,1),2);
628  PN class = potion_require(P, name); //TODO name to file
629  if (use == PN_use) potion_send(class, PN_STR("import"), list);
630  else if (use == PN_no) potion_send(class, PN_STR("unimport"), list);
631  else potion_fatal("Internal error: use or no");
632 # endif
633  }
634  else
635 #endif
636  if (t->part == AST_MSG && PN_S(t,0) == PN_if) {
637  int jmp; breg++;
638 #ifdef P2
639  if (!t->a[2]) { // rhs ifexpr: missing block
640  DBG_c("expr (msg if, (cond)), block => expr (msg if, (cond), block)\n");
641  if (P->flags & MODE_P2) {
642  //TODO
643  breg++;
644  break;
645  } else {
646  potion_syntax_error(P, t,
647  "%s statement used as expr only valid with use p2;", "if");
648  }
649  }
650 #endif
651  if (t->a[1]->part == AST_VALUE && !t->a[1]->a[1]) {
652  ifconst = PN_S(t->a[1], 0);
653  if (PN_TEST1(ifconst)) {
654  DBG_c("if (true) {block} => block\n");
655  potion_source_asmb(P, f, loop, 0, t->a[2], reg);
656  } else {
657  DBG_c("if (false) {block} => \n");
658  }
659  } else {
660  ifconst = PN_NONE;
661  PN_ARG_TABLE(PN_S(t,1), breg, 0);
662  jmp = PN_OP_LEN(f->asmb);
663  PN_ASM2(OP_NOTJMP, breg, 0);
664  potion_source_asmb(P, f, loop, 0, t->a[2], reg);
665  PN_OP_AT(f->asmb, jmp).b = (PN_OP_LEN(f->asmb) - jmp) - 1;
666  }
667  } else if (t->part == AST_MSG && PN_S(t,0) == PN_elsif) {
668  int jmp1 = PN_OP_LEN(f->asmb), jmp2; breg++;
669  // true ifconst: ignore. use only 1st if
670 #ifdef P2
671  if (!t->a[2]) { // rhs ifexpr: missing block
672  DBG_c("expr (msg elsif, (cond)), block => expr (msg elsif, (cond), block)\n");
673  if (P->flags & MODE_P2) {
674  //TODO
675  breg++;
676  break;
677  } else {
678  potion_syntax_error(P, t,
679  "%s statement used as expr only valid with use p2;", "elsif");
680  }
681  }
682 #endif
683  if (ifconst != PN_NONE && PN_TEST1(ifconst)) {
684  DBG_c("elsif (...) {block} => [false]\n");
685  } else if (t->a[1]->part == AST_VALUE && !t->a[1]->a[1]) {
686  ifconst = PN_S(t->a[1], 0);
687  if (!PN_TEST1(ifconst)) {
688  DBG_c("elsif (true) {block} => block\n");
689  potion_source_asmb(P, f, loop, 0, t->a[2], reg);
690  } else {
691  DBG_c("elsif (false) {block} =>\n");
692  }
693  }
694  else {
695  PN_ASM2(OP_TESTJMP, breg, 0);
696  PN_ARG_TABLE(PN_S(t,1), breg, 0);
697  jmp2 = PN_OP_LEN(f->asmb);
698  PN_ASM2(OP_NOTJMP, breg, 0);
699  potion_source_asmb(P, f, loop, 0, t->a[2], reg);
700  PN_OP_AT(f->asmb, jmp1).b = (PN_OP_LEN(f->asmb) - jmp1) - 1;
701  PN_OP_AT(f->asmb, jmp2).b = (PN_OP_LEN(f->asmb) - jmp2) - 1;
702  }
703  } else if (t->part == AST_MSG && PN_S(t,0) == PN_else) {
704  int jmp = PN_OP_LEN(f->asmb); breg++;
705 #ifdef P2
706  if (!t->a[2]) { // rhs ifexpr: missing block
707  DBG_c("expr (msg else), block => expr (msg else, block)\n");
708  if (P->flags & MODE_P2) {
709  //TODO
710  break;
711  } else {
712  potion_syntax_error(P, t,
713  "%s statement used as expr only valid with use p2;", "else");
714  }
715  }
716 #endif
717  if (ifconst != PN_NONE) {
718  if (!PN_TEST1(ifconst)) {
719  DBG_c("else {block} => block [false]\n");
720  potion_source_asmb(P, f, loop, 0, t->a[2], reg);
721  } else {
722  DBG_c("else {block} => [true]\n");
723  }
724  }
725  else {
726  PN_ASM2(OP_TESTJMP, breg, 0);
727  potion_source_asmb(P, f, loop, 0, t->a[2], reg);
728  PN_OP_AT(f->asmb, jmp).b = (PN_OP_LEN(f->asmb) - jmp) - 1;
729  }
730  PN_ASM2(OP_TESTJMP, breg, 0);
731  potion_source_asmb(P, f, loop, 0, t->a[2], reg);
732  PN_OP_AT(f->asmb, jmp).b = (PN_OP_LEN(f->asmb) - jmp) - 1;
733  } else if (t->part == AST_MSG && PN_S(t,0) == PN_class) {
734  u8 breg = reg;
735  if (count == 0)
736  PN_ASM1(OP_SELF, reg);
737  if (PN_S(t,2) != PN_NIL) {
738  vPN(Source) blk = PN_S_(t,2);
739  // TODO: a hack to make sure constructors always return self
740  if (PN_S(blk, 0) == PN_NIL)
741  blk->a[0] = PN_SRC(PN_AST(CODE, PN_NIL, blk->loc.lineno, blk->line));
742  PN ctor = PN_S(blk, 0);
743  PN_PUSH(ctor, PN_AST(EXPR, PN_TUP(PN_AST(MSG,
744  PN_STRN("self", 4), blk->loc.lineno, 0)),
745  blk->loc.lineno, blk->line));
746  breg++;
747  PN_BLOCK(breg, (PN)blk, PN_S(t,1));
748  }
749  PN_ASM2(OP_CLASS, reg, breg);
750 #ifdef WITH_EXTERN
751  } else if (t->part == AST_MSG && PN_S(t,0) == PN_extern) { // ffi
752  //u8 breg = reg;
753  int i, arity;
754  PN msg = PN_S(t,1);
755  char *name = PN_STR_PTR(PN_S(PN_TUPLE_AT(msg,0),0));
756  //defer dlsym to run-time to see load, or require load at BEGIN time?
757  //PN_ASM2(OP_LOADPN, breg++, name);
758  PN_F sym = (PN_F)dlsym(RTLD_DEFAULT, name);
759  DBG_c("extern %s => dlsym %p\n", name, sym);
760  if (!sym) {
761  fprintf(stderr, "* extern %s not found. You may need to load a library first\n",
762  name);
763  PN_ASM2(OP_LOADPN, reg, PN_NIL);
764  } else {
765  // TODO: create a ffi wrapper to translate the args and return value
766  struct PNProto* cl = PN_CALLOC_N(PN_TPROTO, struct PNProto, 0);
767  cl->source = PN_NIL;
768  cl->stack = PN_NUM(1);
769  cl->protos = cl->paths = cl->locals = cl->upvals = cl->values = PN_TUP0();
770  cl->tree = (PN)t;
771  cl->asmb = (PN)potion_asm_new(P);
772  cl->name = PN_S(PN_TUPLE_AT(msg,0),0);
773  cl->jit = (PN_F)sym;
774  PN sig = PN_TUPLE_LEN(msg) ? PN_TUPLE_AT(msg, 1) : PN_TUP0();
775  cl->sig = sig;
776  arity = cl->arity = potion_sig_arity(P, sig);
777  for (i=0; i < arity; i++) {
778  if (PN_TUPLE_LEN(msg) > 1) {
779  // TODO set argtype translators
780  PN arg = PN_TUPLE_AT(sig, i);
781  if (arg == PN_STR("N") || arg == PN_STR("int") || arg == PN_STR("long")) {
782  DBG_c("extern %s %d-th arg => PN_INT(N)\n", name, i);
783  //insert PN_INT >>1 at runtime
784  //PN_ASM2(OP_LOADPN, breg++, arg);
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);
787  // insert call to potion_str_ptr at runtime
788  //PN_ASM2(OP_LOADPN, breg++, arg);
789  } else {
790  fprintf(stderr, "* unknown extern %s argument type qualifier\n",
791  PN_STR_PTR(arg));
792  }
793  }
794  // maybe add code to check and fill in defaults?
795  }
796  // TODO insert code to transform return values
797  cl->asmb = (PN)potion_asm_op(P, (PNAsm *)cl->asmb, OP_RETURN, reg, 0);
798  PN_ASM2(OP_PROTO, reg, PN_PUT(f->protos, (PN)cl));
799  //PN_ASM2(OP_EXTERN, reg, breg);
800  }
801 #endif
802  } else if (t->part == AST_MSG && (PN_S(t,0) == PN_while || PN_S(t,0) == PN_loop)) {
803  int jmp1 = 0, jmp2 = PN_OP_LEN(f->asmb); breg++;
804  struct PNLoop l; l.bjmpc = 0; l.cjmpc = 0;
805  int i;
806  if (PN_S(t,0) == PN_while) {
807  PN_ARG_TABLE(PN_S(t,1), breg, 0);
808  jmp1 = PN_OP_LEN(f->asmb);
809  PN_ASM2(OP_NOTJMP, breg, 0);
810  } else if (PN_S(t,1) || !t->a[2]) {
811  //warn or skip to allow a method named loop? for aio we want loop methods
812  //fprintf(stderr, "* loop takes no args, just a block");
813  goto loopfunc;
814  }
815  if (!t->a[2]) {
816  if (PN_S(t,0) == PN_while)
817  return potion_syntax_error(P, t, "Missing while body");
818  else
819  return potion_syntax_error(P, t, "Missing loop body");
820  }
821  potion_source_asmb(P, f, &l, 0, t->a[2], reg);
822  PN_ASM1(OP_JMP, (jmp2 - PN_OP_LEN(f->asmb)) - 1);
823  if (PN_S(t,0) == PN_while) {
824  PN_OP_AT(f->asmb, jmp1).b = (PN_OP_LEN(f->asmb) - jmp1) - 1;
825  }
826  for (i = 0; i < l.bjmpc; i++) {
827  PN_OP_AT(f->asmb, l.bjmps[i]).a = (PN_OP_LEN(f->asmb) - l.bjmps[i]) - 1;
828  }
829  for (i = 0; i < l.cjmpc; i++) {
830  PN_OP_AT(f->asmb, l.cjmps[i]).a = (jmp2 - l.cjmps[i]) - 1;
831  }
832  } else if (t->part == AST_MSG && PN_S(t,0) == PN_return) {
833  //if (!t->a[1])
834  // return potion_syntax_error(P, t, "Missing return value");
835  PN_ARG_TABLE(PN_S(t,1), reg, 0);
836  PN_ASM1(OP_RETURN, reg);
837  } else if (t->part == AST_MSG && PN_S(t,0) == PN_break) {
838  if (loop != NULL) {
839  loop->bjmps[loop->bjmpc++] = PN_OP_LEN(f->asmb);
840  PN_ASM1(OP_JMP, 0);
841  } else {
842  potion_syntax_error(P, t, "'break' outside of loop");
843  }
844  } else if (t->part == AST_MSG && PN_S(t,0) == PN_continue) {
845  if (loop != NULL) {
846  loop->cjmps[loop->cjmpc++] = PN_OP_LEN(f->asmb);
847  PN_ASM1(OP_JMP, 0);
848  } else {
849  potion_syntax_error(P, t, "'continue' outside of loop");
850  }
851  } else if (t->part == AST_MSG && PN_S(t,0) == PN_self) {
852  PN_ASM1(OP_SELF, reg);
853  } else {
854  // TODO lookup if macro
855  loopfunc: ;
856  u8 opcode = OP_GETUPVAL;
857  PN_SIZE num = PN_NONE;
858  PN v = PN_S(t,0);
859  if (count == 0 && t->part == AST_MSG) {
860  num = PN_UPVAL(v);
861  if (num == PN_NONE) {
862  num = PN_GET(f->locals, v);
863  DBG_c("locals %s <= %d\n", AS_STR(v), (int)num);
864  opcode = OP_GETLOCAL;
865  }
866  }
867 
868  if (num == PN_NONE && PN_S(t,0) != PN_NIL) {
869  u8 oreg = ++breg;
870  int jmp = 0;
871  num = PN_PUT(f->values, PN_S(t,0));
872  DBG_c("values %d %s => %d\n", reg, AS_STR(t->a[0]), (int)num);
873  if (count == 0) {
874  PN_ASM1(OP_SELF, oreg);
875  } else {
876  PN_ASM2(OP_MOVE, oreg, reg);
877  }
878  PN_ASM2(OP_LOADK, reg, num);
879  if (PN_S(t,2) != PN_NIL && (PN_PART(PN_S(t,2)) == AST_MSG)) {
880  vPN(Source) t2 = PN_S_(t,2); //typed message (MSG LIST|NIL TYPE)
881  DBG_c("typed %s %s\n", AS_STR(t->a[0]), AS_STR(t2));
882  //TODO type should already exist at compile-time. check native or user type
883  num = PN_PUT(f->values, PN_S(t2,0));
884  PN_ASM2(OP_LOADK, reg, num);
885  PN_ASM2(OP_BIND, reg, breg);
886  } else {
887  PN_ASM2(((PN_S(t,1) != PN_NIL || PN_S(t,2) != PN_NIL) ? OP_MSG : OP_BIND), reg, breg);
888  }
889  if (t->part == AST_QUERY && PN_S(t,1) != PN_NIL) {
890  jmp = PN_OP_LEN(f->asmb);
891  PN_ASM2(OP_NOTJMP, reg, 0);
892  }
893 #define LOAD_ARG() PN_ARG_TABLE(PN_S(t,1), breg, 1)
894  if (arg) {
895  u8 part1 = PN_PART(PN_S(t,1));
896  if (part1 == AST_VALUE || (part1 == AST_LIST && PN_S(t,2) == PN_NIL)) {
897  LOAD_ARG();
898  }
899  }
900  if (PN_S(t,2) != PN_NIL && (PN_PART(PN_S(t,2)) == AST_PROTO)) {
901  vPN(Source) t2 = PN_S_(t,2);
902  breg++;
903  PN_BLOCK(breg, PN_S(t2,1), PN_S(t2,0));
904  } else {
905  if (PN_S(t,1) == PN_NIL && PN_S(t,2) == PN_NIL)
906  LOAD_ARG();
907  if (PN_S(t,2) != PN_NIL && PN_PART(PN_S(t,2)) == AST_BLOCK) {
908  breg++;
909  PN_BLOCK(breg, PN_S(t,2), PN_S(t,1));
910  }
911  }
912 #undef LOAD_ARG
913  if (t->part == AST_MSG) {
914  DBG_c("; call %d %d MSG\n", reg, breg);
915  PN_ASM2(OP_CALL, reg, breg);
916  } else {
917  if (PN_S(t,1) != PN_NIL) {
918  DBG_c("; call %d %d !MSG\n", reg, breg);
919  PN_ASM2(OP_CALL, reg, breg);
920  PN_OP_AT(f->asmb, jmp).b = (PN_OP_LEN(f->asmb) - jmp) - 1;
921  } else {
922  PN_ASM2(OP_TEST, reg, breg);
923  }
924  }
925  } else {
926  if (num != PN_NONE)
927  PN_ASM2(opcode, reg, num);
928  if (call) {
929  PN_ASM1(OP_SELF, ++breg);
930  PN_ARG_TABLE(PN_S(t,1), breg, 1);
931  if (PN_S(t,2) != PN_NIL) {
932  breg++;
933  PN_BLOCK(breg, PN_S(t,2), PN_NIL);
934  }
935  DBG_c("; call %d %d\n", reg, breg);
936  PN_ASM2(OP_CALL, reg, breg);
937  }
938  }
939  }
940  PN_REG(f, breg);
941  }
942  break;
943 
944  case AST_PATH:
945  case AST_PATHQ: {
946  PN_SIZE num = PN_PUT(f->values, PN_S(t,0));
947  DBG_c("values %d %s => %d\n", reg, AS_STR(t->a[0]), (int)num);
948  if (count == 0) {
949  PN_PUT(f->paths, PN_NUM(num));
950  DBG_c("paths %d\n", (int)num);
951  PN_ASM1(OP_SELF, reg);
952  }
953  PN_ASM2(OP_LOADK, reg + 1, num);
954  PN_ASM2(OP_GETPATH, reg, reg + 1);
955  if (t->part == AST_PATHQ)
956  PN_ASM2(OP_TEST, reg, reg);
957  PN_REG(f, reg + 1);
958  }
959  break;
960 
961  case AST_LICK: {
962  u8 breg = reg;
963  PN_SIZE num = PN_PUT(f->values, PN_S(t,0));
964  DBG_c("values %d %s => %d\n", reg, AS_STR(t->a[0]), (int)num);
965  PN_ASM2(OP_LOADK, reg, num);
966  if (PN_S(t,1) != PN_NIL)
967  potion_source_asmb(P, f, loop, 0, t->a[1], ++breg);
968  else if (PN_S(t,2) != PN_NIL)
969  PN_ASM2(OP_LOADPN, ++breg, PN_NIL);
970  if (PN_S(t,2) != PN_NIL)
971  potion_source_asmb(P, f, loop, 0, t->a[2], ++breg);
972  PN_ASM2(OP_NEWLICK, reg, breg);
973  PN_REG(f, breg);
974  }
975  break;
976 
977  case AST_LIST:
978  PN_ASM1(OP_NEWTUPLE, reg);
979  if (PN_S(t,0) != PN_NIL) {
980  PN_TUPLE_EACH(PN_S(t,0), i, v, {
981  PN_ASM_DEBUG(reg, PN_SRC(v));
982  if (PN_PART(v) == AST_ASSIGN) { //potion only: (k=v, ...)
983  vPN(Source) lhs = PN_SRC(PN_S(v,0));
984  if (lhs->part == AST_EXPR && PN_TUPLE_LEN(PN_S(lhs,0)) == 1)
985  {
986  lhs = SRC_TUPLE_AT(lhs, 0);
987  if (lhs->part == AST_MSG) {
988  PN_ASM_DEBUG(reg, lhs);
989  PN_SIZE num = PN_PUT(f->values, PN_S(lhs,0));
990  DBG_c("values %d %s => %d\n", reg+1, AS_STR(lhs->a[0]), (int)num);
991  PN_ASM2(OP_LOADK, reg + 1, num);
992  lhs = NULL;
993  }
994  }
995 
996  if (lhs != NULL)
997  potion_source_asmb(P, f, loop, 0, lhs, reg + 1);
998 
999  potion_source_asmb(P, f, loop, 0, PN_SRC(v)->a[1], reg + 2);
1000  PN_ASM2(OP_SETTABLE, reg, reg + 2);
1001  PN_REG(f, reg + 2);
1002  } else {
1003  potion_source_asmb(P, f, loop, 0, PN_SRC(v), reg + 1);
1004  PN_ASM2(OP_SETTUPLE, reg, reg + 1);
1005  PN_REG(f, reg + 1);
1006  }
1007  });
1008  }
1009  break;
1010  }
1011 }
1012 
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) { \
1017  name = PN_S(t,0); \
1018  PN_PUT(f->locals, name); \
1019  DBG_c("locals %s\n", PN_STR_PTR(name)); \
1020  sig = PN_PUSH(sig, name); \
1021  } \
1022  } else { name = PN_NIL; }
1023 
1044 PN potion_sig_compile(Potion *P, vPN(Proto) f, PN src) {
1045  vPN(Source) t = PN_SRC(src);
1046 #ifdef P2
1047  // already parsed to tuple
1048  PN sig = PN_S(t,0);
1049  if (!sig)
1050  sig = PN_TUP0();
1051  else
1052  PN_TUPLE_EACH(sig, i, v, {
1053  if (PN_IS_STR(v)) { // assign string default to a local
1054  PN_PUT(f->locals, v);
1055  DBG_c("locals %s\n", PN_STR_PTR(v));
1056  }});
1057 #else
1058  PN sig = PN_TUP0();
1059  if (t->part == AST_LIST && PN_S(t,0) != PN_NIL) {
1060  //PN_TUPLE_EACH(PN_S(t,0), i, v, {
1061  ({ struct PNTuple * volatile __tv = ((struct PNTuple *)potion_fwd(PN_S(t,0)));
1062  if (__tv->len != 0) {
1063  DBG_c("--- sig compile ---\n");
1064  PN_SIZE i;
1065  for (i = 0; i < __tv->len; i++) {
1066  struct PNSource *v = PN_SRC(__tv->set[i]);
1067  {
1068  vPN(Source) expr = PN_SRC(v);
1069  PN name = 0;
1070  SIG_EXPR_MSG(name, expr)
1071  if (expr->part == AST_VALUE) {
1072  vPN(Source) lhs = expr->a[0];
1073  PN v = PN_S(lhs,0);
1074  if (PN_IS_STR(v)) {
1075  DBG_c("sig: lhs value, computed name %s\n", AS_STR(v));
1076  PN_PUT(f->locals, v);
1077  DBG_c("locals %s\n", PN_STR_PTR(v));
1078  sig = PN_PUSH(sig, v);
1079  } else {
1080  potion_syntax_error(P, t,
1081  "in signature: value %s as argument name", AS_STR(v));
1082  }
1083  } else if (expr->part == AST_PIPE) { //x|y => (pipe (expm x) (expm y))
1084  vPN(Source) lhs = expr->a[0];
1085  vPN(Source) rhs = expr->a[1];
1086  PN name2 = 0;
1087  SIG_EXPR_MSG(name, lhs);
1088  sig = PN_PUSH(sig, PN_NUM('|'));
1089  SIG_EXPR_MSG(name2, rhs);
1090  DBG_c("; (%s | %s)\n", AS_STR(name), AS_STR(name2));
1091  } else if (expr->part == AST_ASSIGN) { //x=o => (assign (expm x) (expm o))
1092  vPN(Source) lhs = expr->a[0];
1093  vPN(Source) rhs = expr->a[1];
1094  if (lhs->part == AST_EXPR && PN_TUPLE_LEN(PN_S(lhs,0)) == 1) {
1095  SIG_EXPR_MSG(name, lhs);
1096  lhs = SRC_TUPLE_AT(lhs, 0);
1097  DBG_c("; (%s ", AS_STR(name));
1098  }
1099  else if (lhs->part == AST_PIPE) {
1100  //x|y=o => (assign (pipe (expm x) (expm y)) (expm o))
1101  SIG_EXPR_MSG(name, lhs->a[0]);
1102  sig = PN_PUSH(sig, PN_NUM('|'));
1103  rhs = lhs->a[1];
1104  DBG_c("; (%s | ", AS_STR(name));
1105  } else {
1106  potion_syntax_error(P, t, "in signature: unexpected AST %s", AS_STR(lhs));
1107  }
1108  if (rhs->part == AST_EXPR && PN_TUPLE_LEN(rhs->a[0]) == 1) {
1109  rhs = SRC_TUPLE_AT(rhs, 0);
1110  if (rhs->part == AST_MSG) {
1111  PN v = PN_NUM(PN_STR_PTR(PN_S(rhs,0))[0]); // = type. TODO: one-char => VTABLE
1112  DBG_c("%s)\n", AS_STR(v));
1113  sig = PN_PUSH(sig, v);
1114  }
1115  } else if (rhs->part == AST_ASSIGN && rhs->a[0]->part == AST_PIPE) {
1116  //x=N|y=o => (assign (pipe (expm x) (expm y)) (expm o))
1117  lhs = PN_S_(PN_S_(rhs, 0), 0);
1118  if (lhs->part == AST_EXPR && SRC_TUPLE_AT(lhs,0)->part == AST_MSG) {
1119  PN v = PN_NUM(PN_STR_PTR((PN)SRC_TUPLE_AT(lhs,0)->a[0])[0]); // = type. TODO: one-char => VTABLE
1120  DBG_c("%s)\n", AS_STR(v));
1121  sig = PN_PUSH(sig, v);
1122  }
1123  sig = PN_PUSH(sig, PN_NUM('|'));
1124  SIG_EXPR_MSG(name, rhs->a[0]->a[1]);
1125  rhs = rhs->a[1];
1126  if (rhs->part == AST_EXPR && SRC_TUPLE_AT(rhs,0)->part == AST_MSG) {
1127  PN v = PN_S(SRC_TUPLE_AT(rhs,0),0);
1128  v = PN_NUM(PN_STR_PTR(v)[0]); // = type. TODO: one-char => VTABLE
1129  DBG_c("%s)\n", AS_STR(v));
1130  sig = PN_PUSH(sig, v);
1131  }
1132  } else if (rhs->part == AST_VALUE) { // :=default
1133  PN v = PN_S(rhs,0);
1134  DBG_c(": %s)\n", AS_STR(v));
1135  sig = PN_PUSH(PN_PUSH(sig, PN_NUM(':')), v);
1136  } else {
1137  potion_syntax_error(P, t, "in signature: unexpected AST %s", AS_STR(expr));
1138  }
1139  }
1140  }}}
1141  });
1142  }
1143 #endif
1144  return sig;
1145 }
1146 #undef SRC_TUPLE_AT
1147 #undef SIG_EXPR_MSG
1148 
1155 PN potion_source_compile(Potion *P, PN cl, PN self, PN source, PN sig) {
1156  vPN(Proto) f;
1157  vPN(Source) t = (struct PNSource *)self;
1158 
1159  switch (t->part) {
1160  case AST_CODE:
1161  case AST_BLOCK: break;
1162  default: return PN_NIL; // TODO: error
1163  }
1164  f = PN_ALLOC(PN_TPROTO, struct PNProto);
1165  f->source = source;
1166  f->stack = PN_NUM(1);
1167  f->protos = PN_TUP0();
1168  f->paths = PN_TUP0();
1169  f->locals = PN_TUP0();
1170  f->upvals = PN_TUP0();
1171  f->values = PN_TUP0();
1172  f->debugs = PN_TUP0();
1173  f->tree = self;
1174  DBG_c("-- compile --\n");
1175  f->sig = (sig == PN_NIL ? PN_TUP0() : potion_sig_compile(P, f, sig));
1176  f->asmb = (PN)potion_asm_new(P);
1177  f->name = PN_NIL;
1178 
1179  potion_source_asmb(P, f, NULL, 0, t, 0);
1180  PN_ASM1(OP_RETURN, 0);
1181 
1182  f->localsize = PN_TUPLE_LEN(f->locals);
1183  f->upvalsize = PN_TUPLE_LEN(f->upvals);
1184  f->pathsize = PN_TUPLE_LEN(f->paths);
1185  return (PN)f;
1186 }
1187 
1192  vPN(Proto) f = (struct PNProto *)self;
1193  vPN(Proto) n = PN_ALLOC(PN_TPROTO, struct PNProto);
1194  PN PN_clone = PN_STR("clone");
1195  PNAsm * volatile asmb;
1196  PN len;
1197 
1198  //TODO extern protos
1199  n->name = f->name;
1200  n->source = f->source;
1201  n->stack = f->stack;
1202  n->protos = potion_send(PN_clone, f->protos);
1203  n->paths = potion_send(PN_clone, f->paths);
1204  n->locals = potion_send(PN_clone, f->locals);
1205  n->upvals = potion_send(PN_clone, f->upvals);
1206  n->values = potion_send(PN_clone, f->values);
1207  n->debugs = potion_send(PN_clone, f->debugs);
1208  n->tree = f->tree;
1209  n->localsize = f->localsize;
1210  n->upvalsize = f->upvalsize;
1211  n->pathsize = f->pathsize;
1212  n->sig = PN_IS_TUPLE(f->sig) ? potion_send(PN_clone, f->sig) : f->sig;
1213 
1214  len = ((PNAsm *)f->asmb)->len;
1215  PN_FLEX_NEW(asmb, PN_TBYTES, PNAsm, len);
1216  PN_MEMCPY_N(asmb->ptr, ((PNAsm *)f->asmb)->ptr, u8, len);
1217  asmb->len = len;
1218  n->asmb = (PN)asmb;
1219 
1220  return (PN)n;
1221 }
1222 
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)) { \
1228  if (val & 2) { \
1229  size_t len = ((val ^ 2) >> 4) - 1; \
1230  val = potion_strtod(P, (char *)ptr, len); \
1231  ptr += len; \
1232  } else { \
1233  size_t len = (val >> 4) - 1; \
1234  val = PN_STRN((char *)ptr, len); \
1235  ptr += len; \
1236  } \
1237  } \
1238  val; \
1239  })
1240 
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); \
1247  tup; \
1248  })
1249 #define READ_PROTOS(pn, ptr) ({ \
1250  READ_TUPLE(ptr) PN_TUPLE_AT(tup, i) = potion_proto_load(P, (PN)f, pn, &(ptr)); \
1251  tup; \
1252  })
1253 
1254 // TODO: this byte string is volatile, need to avoid using ptr
1255 PN potion_proto_load(Potion *P, PN up, u8 pn, u8 **ptr) {
1256  PN len = 0;
1257  PNAsm * volatile asmb = NULL;
1258  vPN(Proto) f = PN_ALLOC(PN_TPROTO, struct PNProto);
1259  // TODO extern protos
1260  f->name = READ_CONST(pn, *ptr);
1261  f->source = READ_CONST(pn, *ptr);
1262  if (f->source == PN_NIL) f->source = up;
1263  f->sig = READ_VALUES(pn, *ptr);
1264  f->stack = READ_CONST(pn, *ptr);
1265  f->values = READ_VALUES(pn, *ptr);
1266  f->paths = READ_VALUES(pn, *ptr);
1267  f->locals = READ_VALUES(pn, *ptr);
1268  f->upvals = READ_VALUES(pn, *ptr);
1269  f->protos = READ_PROTOS(pn, *ptr);
1270  f->debugs = PN_TUP0();
1271 
1272  len = READ_PN(pn, *ptr);
1273  PN_FLEX_NEW(asmb, PN_TBYTES, PNAsm, len);
1274  PN_MEMCPY_N(asmb->ptr, *ptr, u8, len);
1275  asmb->len = len;
1276 
1277  f->asmb = (PN)asmb;
1278  f->localsize = PN_TUPLE_LEN(f->locals);
1279  f->upvalsize = PN_TUPLE_LEN(f->upvals);
1280  f->pathsize = PN_TUPLE_LEN(f->paths);
1281  *ptr += len;
1282  return (PN)f;
1283 }
1284 
1286 // TODO: "load" from a stream
1288  u8 *ptr;
1289  vPN(BHeader) h = (struct PNBHeader *)PN_STR_PTR(buf);
1290  // check for compiled binary first
1291  if ((size_t)PN_STR_LEN(buf) <= sizeof(struct PNBHeader) ||
1292  strncmp((char *)h->sig, POTION_SIG, 4) != 0)
1293  return PN_NIL;
1294 
1295  ptr = h->proto;
1296  return potion_proto_load(P, PN_NIL, h->pn, &ptr);
1297 }
1298 
1299 // TODO: switch to dump methods
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); \
1314  } else { \
1315  PN cval = (PN_IS_PTR(val) ? PN_NIL : val); \
1316  WRITE_PN(cval, ptr); \
1317  } \
1318  })
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); \
1325  })
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)); \
1329  })
1330 
1337 long potion_proto_dumpbc(Potion *P, PN proto, PN out, long pos) {
1338  vPN(Proto) f = (struct PNProto *)proto;
1339  char *start = PN_STR_PTR(out) + pos;
1340  u8 *ptr = (u8 *)start;
1341  //TODO extern (by name)
1342  WRITE_CONST(f->name, ptr);
1343  WRITE_CONST(f->source, ptr);
1344  WRITE_VALUES(f->sig, ptr);
1345  WRITE_CONST(f->stack, ptr);
1346  WRITE_VALUES(f->values, ptr);
1347  WRITE_VALUES(f->paths, ptr);
1348  WRITE_VALUES(f->locals, ptr);
1349  WRITE_VALUES(f->upvals, ptr);
1350  WRITE_PROTOS(f->protos, ptr);
1351  WRITE_PN(PN_FLEX_SIZE(f->asmb), ptr);
1352  PN_MEMCPY_N(ptr, ((PNFlex *)f->asmb)->ptr, u8, PN_FLEX_SIZE(f->asmb));
1353  ptr += PN_FLEX_SIZE(f->asmb);
1354  return (char *)ptr - start;
1355 }
1356 
1359 // Low TODO: dump to a stream (if we have not enough memory)
1360 PN potion_source_dumpbc(Potion *P, PN cl, PN proto, PN options) {
1361  PN pnb = potion_bytes(P, 8192);
1362  struct PNBHeader h;
1363  DBG_c("compile bc\n");
1364  PN_MEMCPY_N(h.sig, POTION_SIG, u8, 4);
1365  h.major = POTION_MAJOR;
1366  h.minor = POTION_MINOR;
1367  h.vmid = POTION_VMID;
1368  h.pn = (u8)sizeof(PN);
1369 
1370  PN_MEMCPY(PN_STR_PTR(pnb), &h, struct PNBHeader);
1371  PN_STR_LEN(pnb) = (long)sizeof(struct PNBHeader) +
1372  potion_proto_dumpbc(P, proto, pnb, sizeof(struct PNBHeader));
1373  return pnb;
1374 }
1375 
1381 PN potion_source_dump(Potion *P, PN cl, PN self, PN backend, PN options) {
1382  if (backend == PN_STRN("bc", 2))
1383  return potion_source_dumpbc(P, cl, self, options);
1384 #ifndef SANDBOX
1385  char *cb = PN_STR_PTR(backend);
1386  if (potion_load(P, P->lobby, self, potion_strcat(P, "compile/", cb))) {
1387  DBG_c("loaded compile/%s\n", cb);
1388  DBG_c("Source dump%s(%s)\n", cb, PN_IS_STR(options) ? PN_STR_PTR(options) : "");
1389  return potion_send(self, potion_strcat(P, "dump", cb), options);
1390  } else {
1391  fprintf(stderr, "** failed loading the compile/%s module\n", cb);
1392  return PN_NIL;
1393  }
1394 #else
1395  potion_fatal("external compilers disabled with SANDBOX");
1396 #endif
1397 }
1398 
1399 PN potion_run(Potion *P, PN code, int jit) {
1400 #ifndef POTION_JIT_TARGET
1401  if (jit) {
1402  fprintf(stderr, "** potion not compiled with JIT\n");
1403  jit = 0;
1404  }
1405 #endif
1406  if (jit) {
1407  PN cl = potion_closure_new(P, (PN_F)potion_jit_proto(P, code), PN_NIL, 1);
1408  PN_CLOSURE(cl)->data[0] = code;
1409  return PN_PROTO(code)->jit(P, cl, P->lobby);
1410  } else {
1411  return potion_vm(P, code, P->lobby, PN_NIL, 0, NULL);
1412  }
1413 }
1414 
1415 PN potion_eval(Potion *P, PN bytes) {
1416  PN code = (PN_TYPE(bytes) == PN_TSOURCE)
1417  ? bytes
1418  : potion_parse(P, bytes, "<eval>");
1419  if (PN_TYPE(code) != PN_TSOURCE) return code;
1420  code = potion_send(code, PN_compile, PN_NIL, PN_NIL);
1421  return potion_run(P, code, P->flags & EXEC_JIT);
1422 }
1423 
1425  PN pro_vt = PN_VTABLE(PN_TPROTO);
1426  PN src_vt = PN_VTABLE(PN_TSOURCE);
1427  potion_method(pro_vt, "call", potion_proto_call, "args=u");
1428  potion_method(pro_vt, "tree", potion_proto_tree, 0);
1429  potion_method(pro_vt, "string", potion_proto_string, 0);
1430  potion_method(pro_vt, "clone", potion_proto_clone, 0);
1431  potion_method(src_vt, "compile", potion_source_compile, "source=a,sig=u");
1432  potion_method(src_vt, "dump", potion_source_dump, "backend=S|options=S");
1433  potion_method(src_vt, "dumpbc", potion_source_dumpbc, "|options=S");
1434 }
#define PN_TUPLE_AT(t, n)
Definition: potion.h:278
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:175
PN asmb
assembled instructions
Definition: potion.h:467
#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:461
PN PN_extern
Definition: internal.c:19
PN_AST
An AST fragment, non-volatile.
Definition: potion.h:395
u8 proto[]
Definition: internal.h:76
PN values
numbers, strings, etc.
Definition: potion.h:462
PN PN_return
Definition: internal.c:14
Definition: opcodes.h:32
#define WRITE_PN(pn, ptr)
Definition: compile.c:1301
#define PN_S(S, N)
Definition: ast.h:33
#define PN_TSTRING
Definition: potion.h:112
PN_F potion_jit_proto(Potion *, PN)
Definition: vm.c:221
a tuple is an array of PNs.
Definition: potion.h:477
PN potion_proto_load(Potion *P, PN up, u8 pn, u8 **ptr)
Definition: compile.c:1255
#define READ_PROTOS(pn, ptr)
Definition: compile.c:1249
#define PN_CLOSURE(x)
Definition: potion.h:225
Potion_Flags flags
vm flags: execution model and debug flags
Definition: potion.h:659
PN PN_elsif
Definition: internal.c:14
#define MAX_JUMPS
Definition: compile.c:271
unsigned long _PN
Definition: potion.h:78
Definition: opcodes.h:36
PN sig
argument signature
Definition: potion.h:457
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:275
Definition: potion.h:405
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_tuple_at(Potion *P, PN cl, PN self, PN index)
Definition: table.c:309
PN potion_source_dumpbc(Potion *P, PN cl, PN proto, PN options)
Definition: compile.c:1360
#define potion_method(RCV, MSG, FN, SIG)
Definition: potion.h:789
#define PN_TUPLE_LEN(t)
Definition: potion.h:277
Definition: opcodes.h:34
#define AS_STR(x)
Definition: potion.h:249
#define PN_FINTEGER
Definition: potion.h:152
unsigned int PNType
Definition: potion.h:79
#define PN_PUSH(T, X)
Definition: potion.h:272
#define PN_STR_LEN(x)
Definition: potion.h:223
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:570
#define PN_ASM_DEBUG(REG, T)
Definition: compile.c:257
PN potion_sig_compile(Potion *P, vPN(Proto) f, PN src)
Converts a pre-compiled potion expr to a signature tuple.
Definition: compile.c:1044
#define WRITE_CONST(val, ptr)
Definition: compile.c:1302
#define PN_ARG(n, reg)
Definition: compile.c:201
Definition: opcodes.h:48
const struct @0 potion_ops[]
PN potion_source_load(Potion *P, PN cl, PN buf)
Definition: compile.c:1287
Definition: potion.h:586
#define DBG_c(...)
Definition: potion.h:266
PN_F jit
jit function pointer
Definition: potion.h:468
PN potion_source_compile(Potion *P, PN cl, PN self, PN source, PN sig)
Definition: compile.c:1155
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:219
the ast for Potion code in-memory
#define PN_SRC(S)
Definition: ast.h:30
#define PN_INT(x)
Definition: potion.h:214
Definition: opcodes.h:31
#define PN_NUM(i)
Definition: potion.h:213
PN potion_source_dump(Potion *P, PN cl, PN self, PN backend, PN options)
Definition: compile.c:1381
int cjmps[MAX_JUMPS]
Definition: compile.c:276
unsigned int PN_SIZE
Definition: potion.h:79
PN potion_load(Potion *P, PN cl, PN self, PN file)
Definition: load.c:163
int arity
cached sig arity (number of args)
Definition: potion.h:469
#define PN_STR_B(x)
Definition: potion.h:224
#define PN_IS_NIL(v)
Definition: potion.h:169
enum PN_AST part
AST type, avoid -Wswitch (aligned access: 4+4+8+4+24)
Definition: potion.h:435
#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:657
PN_SIZE len
Definition: potion.h:479
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:255
#define PN_TSOURCE
Definition: potion.h:120
PN locals
local variables
Definition: potion.h:460
u8 vmid
Definition: internal.h:74
#define PN_FLEX_SIZE(N)
Definition: potion.h:240
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:1399
PN potion_proto_call(Potion *P, PN cl, PN self, PN args)
Definition: compile.c:55
PN paths
paths (instance variables)
Definition: potion.h:459
Definition: opcodes.h:38
void potion_syntax_error(Potion *P, struct PNSource *t, const char *fmt,...)
Definition: internal.c:293
PN potion_parse(Potion *, PN, char *)
#define READ_CONST(pn, ptr)
Definition: compile.c:1225
#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:274
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:1415
some assembler macros
int cjmpc
count of c jumps (abc regs)
Definition: compile.c:279
PNAsm * potion_asm_new(Potion *P)
Definition: asm.c:13
#define PN_BLOCK(reg, blk, sig)
Definition: compile.c:213
#define LOAD_ARG()
#define PN_PART(S)
Definition: ast.h:31
JIT if detected at config-time (x86, ppc)
Definition: potion.h:616
a prototype is compiled source code, a closure block (lambda) non-volatile.
Definition: potion.h:454
void potion_arg_asmb(Potion *P, struct PNProto *volatile f, struct PNLoop *loop, PN args, u8 *reg, int inc)
Definition: compile.c:284
non-API internal parts
PN PN_if
Definition: internal.c:14
#define SIG_EXPR_MSG(name, expr)
Definition: compile.c:1013
#define PN_TEST1(v)
Definition: potion.h:163
PN protos
nested closures
Definition: potion.h:463
#define ASM_TPL_IMM
Definition: asm.h:17
#define PN_IS_PTR(v)
Definition: potion.h:168
Definition: opcodes.h:41
Definition: potion.h:407
#define PN_GET(T, X)
Definition: potion.h:274
#define PN_ASM2(ins, _a, _b)
Definition: compile.c:27
Definition: opcodes.h:45
#define PN_UPVAL(name)
Definition: compile.c:225
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:260
Definition: potion.h:400
PN_SIZE len
Definition: potion.h:586
#define PN_OP_AT(asmb, n)
Definition: opcodes.h:82
Definition: potion.h:403
#define PN_OP_LEN(asmb)
Definition: opcodes.h:83
-d: instrumented bytecode (line stepping) or just slow runloop?
Definition: potion.h:617
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:653
#define PN_ALLOC(V, T)
Definition: internal.h:12
#define PN_ASM1(ins, _a)
Definition: compile.c:26
PN_SIZE pn_printf(Potion *, PN, const char *,...) __attribute__((format(printf
PN PN_while
Definition: internal.c:14
unsigned char ptr[]
Definition: potion.h:586
PN PN_class
Definition: internal.c:14
#define READ_VALUES(pn, ptr)
Definition: compile.c:1245
#define PN_TYPE(x)
Definition: potion.h:133
#define PN_TPROTO
Definition: potion.h:122
The p2 API.
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:171
#define PN_S_(S, N)
Definition: ast.h:32
PN debugs
tree parts
Definition: potion.h:464
struct PNSource *volatile a[3]
PNTuple of 1-3 kids,.
Definition: potion.h:436
_PN(* PN_F)(Potion *, PN, PN,...)
Definition: potion.h:216
void potion_compiler_init(Potion *P)
Definition: compile.c:1424
#define PN_REG(f, reg)
Definition: compile.c:184
int bjmpc
count of b jumps (abc regs)
Definition: compile.c:278
#define POTION_VMID
Definition: potion.h:43
#define SRC_TUPLE_AT(src, i)
Definition: compile.c:256
PN stack
size of the stack
Definition: potion.h:458
#define potion_send(RCV, MSG, ARGS...)
method caches (more great stuff from ian piumarta)
Definition: potion.h:781
long potion_proto_dumpbc(Potion *P, PN proto, PN out, long pos)
Definition: compile.c:1337
int potion_sig_arity(Potion *P, PN sig)
number of args of sig tuple, implements the potion_closure_arity method.
Definition: objmodel.c:87
#define PN_STRN(x, l)
Definition: potion.h:220
int bjmps[MAX_JUMPS]
Definition: compile.c:275
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:465
#define WRITE_PROTOS(tup, ptr)
Definition: compile.c:1326
#define vPN(t)
Definition: buffile.c:34
volatile _PN PN
Definition: potion.h:81
PNType lineno
Definition: potion.h:444
void potion_source_asmb(Potion *, struct PNProto *volatile, struct PNLoop *, PN_SIZE, struct PNSource *volatile, u8)
Definition: compile.c:336
#define PN_NIL
Definition: potion.h:139
PN PN_name
Definition: internal.c:18
#define READ_PN(pn, ptr)
Definition: compile.c:1224
u8 minor
Definition: internal.h:73
#define PN_IS_TUPLE(v)
Definition: potion.h:174
#define PN_CALLOC_N(V, T, C)
Definition: internal.h:14
#define WRITE_VALUES(tup, ptr)
Definition: compile.c:1323
PN source
program name or enclosing scope
Definition: potion.h:456
PN potion_proto_clone(Potion *P, PN cl, PN self)
Definition: compile.c:1191
PN name
PNString.
Definition: potion.h:470
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:288
PN PN_self
Definition: internal.c:14
#define PN_TUP(X)
Definition: potion.h:271
PN set[]
Definition: potion.h:481
void potion_fatal(char *message)
Definition: internal.c:286
const u8 args
Definition: compile.c:31
#define PN_STR_PTR(x)
Definition: potion.h:222
PN PN_continue
Definition: internal.c:14
#define PN_TUP0()
Definition: potion.h:270
#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:227
#define POTION_MINOR
Definition: config.h:3
Definition: opcodes.h:39