]> git.mxchange.org Git - simgear.git/blob - simgear/nasal/codegen.c
cppbind.Ghost: register _get called on retrieving unset member.
[simgear.git] / simgear / nasal / codegen.c
1 #include <string.h>
2 #include "parse.h"
3 #include "code.h"
4
5 #define MAX_FUNARGS 32
6
7 // These are more sensical predicate names in most contexts in this file
8 #define LEFT(tok)   ((tok)->children)
9 #define RIGHT(tok)  ((tok)->lastChild)
10 #define BINARY(tok) (LEFT(tok) && RIGHT(tok) && LEFT(tok)->next == RIGHT(tok))
11
12 // Forward references for recursion
13 static void genExpr(struct Parser* p, struct Token* t);
14 static void genExprList(struct Parser* p, struct Token* t);
15 static naRef newLambda(struct Parser* p, struct Token* t);
16
17 static void emit(struct Parser* p, int val)
18 {
19     if(p->cg->codesz >= p->cg->codeAlloced) {
20         int i, sz = p->cg->codeAlloced * 2;
21         unsigned short* buf = naParseAlloc(p, sz*sizeof(unsigned short));
22         for(i=0; i<p->cg->codeAlloced; i++) buf[i] = p->cg->byteCode[i];
23         p->cg->byteCode = buf;
24         p->cg->codeAlloced = sz;
25     }
26     p->cg->byteCode[p->cg->codesz++] = (unsigned short)val;
27 }
28
29 static void emitImmediate(struct Parser* p, int val, int arg)
30 {
31     emit(p, val);
32     emit(p, arg);
33 }
34
35 static void genBinOp(int op, struct Parser* p, struct Token* t)
36 {
37     if(!LEFT(t) || !RIGHT(t))
38         naParseError(p, "empty subexpression", t->line);
39     genExpr(p, LEFT(t));
40     genExpr(p, RIGHT(t));
41     emit(p, op);
42 }
43
44 static int newConstant(struct Parser* p, naRef c)
45 {
46     int i;
47     naVec_append(p->cg->consts, c);
48     i = naVec_size(p->cg->consts) - 1;
49     if(i > 0xffff) naParseError(p, "too many constants in code block", 0);
50    return i;
51 }
52
53 // Interns a scalar (!) constant and returns its index
54 static int internConstant(struct Parser* p, naRef c)
55 {
56     int i, n = naVec_size(p->cg->consts);
57     if(IS_CODE(c)) return newConstant(p, c);
58     for(i=0; i<n; i++) {
59         naRef b = naVec_get(p->cg->consts, i);
60         if(IS_NUM(b) && IS_NUM(c) && b.num == c.num) return i;
61         else if(IS_NIL(b) && IS_NIL(c)) return i;
62         else if(naStrEqual(b, c)) return i;
63     }
64     return newConstant(p, c);
65 }
66
67 /* FIXME: this API is fundamentally a resource leak, because symbols
68  * can't be deregistered.  The "proper" way to do this would be to
69  * keep a reference count for each symbol, and decrement it when a
70  * code object referencing it is deleted. */
71 naRef naInternSymbol(naRef sym)
72 {
73     naRef result;
74     if(naHash_get(globals->symbols, sym, &result))
75         return result;
76     naHash_set(globals->symbols, sym, sym);
77     return sym;
78 }
79
80 static int findConstantIndex(struct Parser* p, struct Token* t)
81 {
82     naRef c, dummy;
83     if(t->type == TOK_NIL) c = naNil();
84     else if(t->str) {
85         c = naStr_fromdata(naNewString(p->context), t->str, t->strlen);
86         naHash_get(globals->symbols, c, &dummy); // noop, make c immutable
87         if(t->type == TOK_SYMBOL) c = naInternSymbol(c);
88     } else if(t->type == TOK_FUNC) c = newLambda(p, t);
89     else if(t->type == TOK_LITERAL) c = naNum(t->num);
90     else naParseError(p, "invalid/non-constant constant", t->line);
91     return internConstant(p, c);
92 }
93
94 static int genScalarConstant(struct Parser* p, struct Token* t)
95 {
96     int idx;
97     if(t->str == 0 && t->num == 1) { emit(p, OP_PUSHONE); return 0; }
98     if(t->str == 0 && t->num == 0) { emit(p, OP_PUSHZERO); return 0; }
99     emitImmediate(p, OP_PUSHCONST, idx = findConstantIndex(p, t));
100     return idx;
101 }
102
103 static int genLValue(struct Parser* p, struct Token* t, int* cidx)
104 {
105     if(!t) naParseError(p, "bad lvalue", -1);
106     if(t->type == TOK_LPAR && t->rule != PREC_SUFFIX) {
107         return genLValue(p, LEFT(t), cidx); // Handle stuff like "(a) = 1"
108     } else if(t->type == TOK_SYMBOL) {
109         *cidx = genScalarConstant(p, t);
110         return OP_SETSYM;
111     } else if(t->type == TOK_DOT && RIGHT(t) && RIGHT(t)->type == TOK_SYMBOL) {
112         genExpr(p, LEFT(t));
113         *cidx = genScalarConstant(p, RIGHT(t));
114         return OP_SETMEMBER;
115     } else if(t->type == TOK_LBRA) {
116         genExpr(p, LEFT(t));
117         genExpr(p, RIGHT(t));
118         return OP_INSERT;
119     } else if(t->type == TOK_VAR && RIGHT(t) && RIGHT(t)->type == TOK_SYMBOL) {
120         *cidx = genScalarConstant(p, RIGHT(t));
121         return OP_SETLOCAL;
122     } else {
123         naParseError(p, "bad lvalue", t->line);
124         return -1;
125     }
126 }
127
128 static void genEqOp(int op, struct Parser* p, struct Token* t)
129 {
130     int cidx, n = 2, setop = genLValue(p, LEFT(t), &cidx);
131     if(setop == OP_SETMEMBER) {
132         emit(p, OP_DUP2);
133         emit(p, OP_POP);
134         emitImmediate(p, OP_MEMBER, cidx);
135     } else if(setop == OP_INSERT) {
136         emit(p, OP_DUP2);
137         emit(p, OP_EXTRACT);
138     } else {
139         emitImmediate(p, OP_LOCAL, cidx);
140         n = 1;
141     }
142     genExpr(p, RIGHT(t));
143     emit(p, op);
144     emit(p, n == 1 ? OP_XCHG : OP_XCHG2);
145     emit(p, setop);
146 }
147
148 static int defArg(struct Parser* p, struct Token* t)
149 {
150     if(t->type == TOK_LPAR) {
151         // http://code.google.com/p/flightgear-bugs/issues/detail?id=737
152         // TOK_LPAR can mean multi-value assignment or function call,
153         // disambigaute by checking the rule of the token
154         if (t->rule == PREC_SUFFIX)
155             naParseError(p, "default arguments cannot be function calls", t->line);
156         return defArg(p, RIGHT(t));
157     }
158     
159     if(t->type == TOK_MINUS && RIGHT(t) && 
160        RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str)
161     {
162         /* default arguments are constants, but "-1" parses as two
163          * tokens, so we have to subset the expression generator for that
164          * case */
165         RIGHT(t)->num *= -1;
166         return defArg(p, RIGHT(t));
167     }
168     return findConstantIndex(p, t);
169 }
170
171 static void genArgList(struct Parser* p, struct naCode* c, struct Token* t)
172 {
173     naRef sym;
174     if(t->type == TOK_EMPTY) return;
175     if(!IDENTICAL(p->cg->restArgSym, globals->argRef))
176         naParseError(p, "remainder must be last", t->line);
177     if(t->type == TOK_ELLIPSIS) {
178         if(LEFT(t)->type != TOK_SYMBOL)
179             naParseError(p, "bad function argument expression", t->line);
180         sym = naStr_fromdata(naNewString(p->context),
181                              LEFT(t)->str, LEFT(t)->strlen);
182         p->cg->restArgSym = naInternSymbol(sym);
183         c->needArgVector = 1;
184     } else if(t->type == TOK_ASSIGN) {
185         if(LEFT(t)->type != TOK_SYMBOL)
186             naParseError(p, "bad function argument expression", t->line);
187         p->cg->optArgSyms[c->nOptArgs] = findConstantIndex(p, LEFT(t));
188         p->cg->optArgVals[c->nOptArgs++] = defArg(p, RIGHT(t));
189     } else if(t->type == TOK_SYMBOL) {
190         if(c->nOptArgs)
191             naParseError(p, "optional arguments must be last", t->line);
192         if(c->nArgs >= MAX_FUNARGS)
193             naParseError(p, "too many named function arguments", t->line);
194         p->cg->argSyms[c->nArgs++] = findConstantIndex(p, t);
195     } else if(t->type == TOK_COMMA) {
196         if(!LEFT(t) || !RIGHT(t))
197             naParseError(p, "empty function argument", t->line);
198         genArgList(p, c, LEFT(t));
199         genArgList(p, c, RIGHT(t));
200     } else
201         naParseError(p, "bad function argument expression", t->line);
202 }
203
204 static naRef newLambda(struct Parser* p, struct Token* t)
205 {
206     struct CodeGenerator* cgSave;
207     naRef codeObj;
208     struct Token* arglist;
209     if(RIGHT(t)->type != TOK_LCURL)
210         naParseError(p, "bad function definition", t->line);
211
212     // Save off the generator state while we do the new one
213     cgSave = p->cg;
214     arglist = LEFT(t)->type == TOK_LPAR ? LEFT(LEFT(t)) : 0;
215     codeObj = naCodeGen(p, LEFT(RIGHT(t)), arglist);
216     p->cg = cgSave;
217     return codeObj;
218 }
219
220 static void genLambda(struct Parser* p, struct Token* t)
221 {
222     emitImmediate(p, OP_PUSHCONST, newConstant(p, newLambda(p, t)));
223 }
224
225 static int genList(struct Parser* p, struct Token* t, int doAppend)
226 {
227     if(!t || t->type == TOK_EMPTY) {
228         return 0;
229     } else if(t->type == TOK_COMMA) {
230         genExpr(p, LEFT(t));
231         if(doAppend) emit(p, OP_VAPPEND);
232         return 1 + genList(p, RIGHT(t), doAppend);
233     } else {
234         genExpr(p, t);
235         if(doAppend) emit(p, OP_VAPPEND);
236         return 1;
237     }
238 }
239
240 static void genHashElem(struct Parser* p, struct Token* t)
241 {
242     if(!t || t->type == TOK_EMPTY)
243         return;
244     if(t->type != TOK_COLON || !LEFT(t))
245         naParseError(p, "bad hash/object initializer", t->line);
246     if(LEFT(t)->type == TOK_SYMBOL) genScalarConstant(p, LEFT(t));
247     else if(LEFT(t)->type == TOK_LITERAL) genExpr(p, LEFT(t));
248     else naParseError(p, "bad hash/object initializer", t->line);
249     genExpr(p, RIGHT(t));
250     emit(p, OP_HAPPEND);
251 }
252
253 static void genHash(struct Parser* p, struct Token* t)
254 {
255     if(t && t->type == TOK_COMMA) {
256         genHashElem(p, LEFT(t));
257         genHash(p, RIGHT(t));
258     } else if(t && t->type != TOK_EMPTY) {
259         genHashElem(p, t);
260     }
261 }
262
263 static int isHashcall(struct Parser* p, struct Token* t)
264 {
265     if(t) {
266         int sep = LEFT(t) && t->type == TOK_COMMA ? t->children->type : t->type;
267         return sep == TOK_COLON;
268     }
269     return 0;
270 }
271
272 static void genFuncall(struct Parser* p, struct Token* t)
273 {
274     int method = 0;
275     if(LEFT(t)->type == TOK_DOT) {
276         method = 1;
277         genExpr(p, LEFT(LEFT(t)));
278         emit(p, OP_DUP);
279         emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(LEFT(t))));
280     } else {
281         genExpr(p, LEFT(t));
282     }
283     if(isHashcall(p, RIGHT(t))) {
284         emit(p, OP_NEWHASH);
285         genHash(p, RIGHT(t));
286         emit(p, method ? OP_MCALLH : OP_FCALLH);
287     } else {
288         int nargs = genList(p, RIGHT(t), 0);
289         emitImmediate(p, method ? OP_MCALL : OP_FCALL, nargs);
290     }
291 }
292
293 static int startLoop(struct Parser* p, struct Token* label)
294 {
295     int i = p->cg->loopTop;
296     p->cg->loops[i].breakIP = 0xffffff;
297     p->cg->loops[i].contIP = 0xffffff;
298     p->cg->loops[i].label = label;
299     p->cg->loopTop++;
300     emit(p, OP_MARK);
301     return p->cg->codesz;
302 }
303
304 // Emit a jump operation, and return the location of the address in
305 // the bytecode for future fixup in fixJumpTarget
306 static int emitJump(struct Parser* p, int op)
307 {
308     int ip;
309     emit(p, op);
310     ip = p->cg->codesz;
311     emit(p, 0xffff); // dummy address
312     return ip;
313 }
314
315 // Points a previous jump instruction at the current "end-of-bytecode"
316 static void fixJumpTarget(struct Parser* p, int spot)
317 {
318     p->cg->byteCode[spot] = p->cg->codesz;
319 }
320
321 static void genShortCircuit(struct Parser* p, struct Token* t)
322 {
323     int end;
324     genExpr(p, LEFT(t));
325     end = emitJump(p, t->type == TOK_AND ? OP_JIFNOT : OP_JIFTRUE);
326     emit(p, OP_POP);
327     genExpr(p, RIGHT(t));
328     fixJumpTarget(p, end);
329 }
330
331
332 static void genIf(struct Parser* p, struct Token* tif, struct Token* telse)
333 {
334     int jumpNext, jumpEnd;
335     genExpr(p, tif->children); // the test
336     jumpNext = emitJump(p, OP_JIFNOTPOP);
337     genExprList(p, tif->children->next->children); // the body
338     jumpEnd = emitJump(p, OP_JMP);
339     fixJumpTarget(p, jumpNext);
340     if(telse) {
341         if(telse->type == TOK_ELSIF) genIf(p, telse, telse->next);
342         else genExprList(p, telse->children->children);
343     } else {
344         emit(p, OP_PUSHNIL);
345     }
346     fixJumpTarget(p, jumpEnd);
347 }
348
349 static void genIfElse(struct Parser* p, struct Token* t)
350 {
351     genIf(p, t, t->children->next->next);
352 }
353
354 static void genQuestion(struct Parser* p, struct Token* t)
355 {
356     int jumpNext, jumpEnd;
357     if(!RIGHT(t) || RIGHT(t)->type != TOK_COLON)
358         naParseError(p, "invalid ?: expression", t->line);
359     genExpr(p, LEFT(t)); // the test
360     jumpNext = emitJump(p, OP_JIFNOTPOP);
361     genExpr(p, LEFT(RIGHT(t))); // the "if true" expr
362     jumpEnd = emitJump(p, OP_JMP);
363     fixJumpTarget(p, jumpNext);
364     genExpr(p, RIGHT(RIGHT(t))); // the "else" expr
365     fixJumpTarget(p, jumpEnd);
366 }
367
368 static int countList(struct Token* t, int type)
369 {
370     int n;
371     for(n = 1; t && t->type == type; t = RIGHT(t)) n++;
372     return n;
373 }
374
375 static void genLoop(struct Parser* p, struct Token* body,
376                     struct Token* update, struct Token* label,
377                     int loopTop, int jumpEnd)
378 {
379     int cont, jumpOverContinue;
380     
381     p->cg->loops[p->cg->loopTop-1].breakIP = jumpEnd-1;
382
383     jumpOverContinue = emitJump(p, OP_JMP);
384     p->cg->loops[p->cg->loopTop-1].contIP = p->cg->codesz;
385     cont = emitJump(p, OP_JMP);
386     fixJumpTarget(p, jumpOverContinue);
387
388     genExprList(p, body);
389     emit(p, OP_POP);
390     fixJumpTarget(p, cont);
391     if(update) { genExpr(p, update); emit(p, OP_POP); }
392     emitImmediate(p, OP_JMPLOOP, loopTop);
393     fixJumpTarget(p, jumpEnd);
394     p->cg->loopTop--;
395     emit(p, OP_UNMARK);
396     emit(p, OP_PUSHNIL); // Leave something on the stack
397 }
398
399 static void genForWhile(struct Parser* p, struct Token* init,
400                         struct Token* test, struct Token* update,
401                         struct Token* body, struct Token* label)
402 {
403     int loopTop, jumpEnd;
404     if(init) { genExpr(p, init); emit(p, OP_POP); }
405     loopTop = startLoop(p, label);
406     genExpr(p, test);
407     jumpEnd = emitJump(p, OP_JIFNOTPOP);
408     genLoop(p, body, update, label, loopTop, jumpEnd);
409 }
410
411 static void genWhile(struct Parser* p, struct Token* t)
412 {
413     struct Token *test=LEFT(t)->children, *body, *label=0;
414     int len = countList(test, TOK_SEMI);
415     if(len == 2) {
416         label = LEFT(test);
417         if(!label || label->type != TOK_SYMBOL)
418             naParseError(p, "bad loop label", t->line);
419         test = RIGHT(test);
420     } else if(len != 1)
421         naParseError(p, "too many semicolons in while test", t->line);
422     body = LEFT(RIGHT(t));
423     genForWhile(p, 0, test, 0, body, label);
424 }
425
426 static void genFor(struct Parser* p, struct Token* t)
427 {
428     struct Token *init, *test, *body, *update, *label=0;
429     struct Token *h = LEFT(t)->children;
430     int len = countList(h, TOK_SEMI);
431     if(len == 4) {
432         if(!LEFT(h) || LEFT(h)->type != TOK_SYMBOL)
433             naParseError(p, "bad loop label", h->line);
434         label = LEFT(h);
435         h=RIGHT(h);
436     } else if(len != 3)
437         naParseError(p, "wrong number of terms in for header", t->line);
438     init = LEFT(h);
439     test = LEFT(RIGHT(h));
440     update = RIGHT(RIGHT(h));
441     body = RIGHT(t)->children;
442     genForWhile(p, init, test, update, body, label);
443 }
444
445 static void genForEach(struct Parser* p, struct Token* t)
446 {
447     int loopTop, jumpEnd, assignOp, dummy;
448     struct Token *elem, *body, *vec, *label=0;
449     struct Token *h = LEFT(LEFT(t));
450     int len = countList(h, TOK_SEMI);
451     if(len == 3) {
452         if(!LEFT(h) || LEFT(h)->type != TOK_SYMBOL)
453             naParseError(p, "bad loop label", h->line);
454         label = LEFT(h);
455         h = RIGHT(h);
456     } else if (len != 2) {
457         naParseError(p, "wrong number of terms in foreach header", t->line);
458     }
459     elem = LEFT(h);
460     vec = RIGHT(h);
461     body = RIGHT(t)->children;
462
463     genExpr(p, vec);
464     emit(p, OP_PUSHZERO);
465     loopTop = startLoop(p, label);
466     emit(p, t->type == TOK_FOREACH ? OP_EACH : OP_INDEX);
467     jumpEnd = emitJump(p, OP_JIFEND);
468     assignOp = genLValue(p, elem, &dummy);
469     emit(p, assignOp);
470     emit(p, OP_POP);
471     genLoop(p, body, 0, label, loopTop, jumpEnd);
472     emit(p, OP_POP); // Pull off the vector and index
473     emit(p, OP_POP);
474 }
475
476 static int tokMatch(struct Token* a, struct Token* b)
477 {
478     int i, l = a->strlen;
479     if(!a || !b) return 0;
480     if(l != b->strlen) return 0;
481     for(i=0; i<l; i++) if(a->str[i] != b->str[i]) return 0;
482     return 1;
483 }
484
485 static void genBreakContinue(struct Parser* p, struct Token* t)
486 {
487     int levels = 1, loop = -1, bp, cp, i;
488     // http://code.google.com/p/flightgear-bugs/issues/detail?id=587
489     // Make sure we are inside of a loop
490     if(p->cg->loopTop <= 0)
491         naParseError(p, "break/continue outside of a valid loop", t->line);
492     
493     if(RIGHT(t)) {
494         if(RIGHT(t)->type != TOK_SYMBOL)
495             naParseError(p, "bad break/continue label", t->line);
496         for(i=0; i<p->cg->loopTop; i++)
497             if(tokMatch(RIGHT(t), p->cg->loops[i].label))
498                 loop = i;
499         if(loop == -1)
500             naParseError(p, "no match for break/continue label", t->line);
501         levels = p->cg->loopTop - loop;
502     }
503     bp = p->cg->loops[p->cg->loopTop - levels].breakIP;
504     cp = p->cg->loops[p->cg->loopTop - levels].contIP;
505     for(i=0; i<levels; i++)
506         emit(p, (i<levels-1) ? OP_BREAK2 : OP_BREAK);
507     if(t->type == TOK_BREAK)
508         emit(p, OP_PUSHEND); // breakIP is always a JIFNOTPOP/JIFEND!
509     emitImmediate(p, OP_JMP, t->type == TOK_BREAK ? bp : cp);
510 }
511
512 static void newLineEntry(struct Parser* p, int line)
513 {
514     int i;
515     if(p->cg->nextLineIp >= p->cg->nLineIps) {
516         int nsz = p->cg->nLineIps*2 + 1;
517         unsigned short* n = naParseAlloc(p, sizeof(unsigned short)*2*nsz);
518         for(i=0; i<(p->cg->nextLineIp*2); i++)
519             n[i] = p->cg->lineIps[i];
520         p->cg->lineIps = n;
521         p->cg->nLineIps = nsz;
522     }
523     p->cg->lineIps[p->cg->nextLineIp++] = (unsigned short) p->cg->codesz;
524     p->cg->lineIps[p->cg->nextLineIp++] = (unsigned short) line;
525 }
526
527 static int parListLen(struct Token* t)
528 {
529     if(t->type != TOK_LPAR || !LEFT(t) || LEFT(t)->type != TOK_COMMA) return 0;
530     return countList(LEFT(t), TOK_COMMA);
531 }
532
533 static void genCommaList(struct Parser* p, struct Token* t)
534 {
535     if(t->type != TOK_COMMA) { genExpr(p, t); return; }
536     genCommaList(p, RIGHT(t));
537     genExpr(p, LEFT(t));
538 }
539
540 static void genMultiLV(struct Parser* p, struct Token* t, int var)
541 {
542     if(!var) { emit(p, genLValue(p, t, &var)); return; }
543     if(t->type != TOK_SYMBOL) naParseError(p, "bad lvalue", t->line);
544     genScalarConstant(p, t);
545     emit(p, OP_SETLOCAL);
546 }
547
548 static void genAssign(struct Parser* p, struct Token* t)
549 {
550     struct Token *lv = LEFT(t), *rv = RIGHT(t);
551     int len, dummy, var=0;
552     if (!lv)
553         naParseError(p, "bad assignment, missing variable", t->line);
554     else
555     if(parListLen(lv) || (lv->type == TOK_VAR && parListLen(RIGHT(lv)))) {
556         if(lv->type == TOK_VAR) { lv = RIGHT(lv); var = 1; }
557         len = parListLen(lv);
558         // http://code.google.com/p/flightgear-bugs/issues/detail?id=585
559         // TOK_LPAR can mean multi-value assignment or function call,
560         // disambigaute by checking the rule of the token
561         if(rv->type == TOK_LPAR && rv->rule != PREC_SUFFIX) {
562             if(len != parListLen(rv))
563                 naParseError(p, "bad assignment count", rv->line);
564             genCommaList(p, LEFT(rv));
565         } else {
566             genExpr(p, rv);
567             emitImmediate(p, OP_UNPACK, len);
568         }
569         for(t = LEFT(lv); t && t->type == TOK_COMMA; t = RIGHT(t)) {
570             genMultiLV(p, LEFT(t), var);
571             emit(p, OP_POP);
572         }
573         genMultiLV(p, t, var);
574     } else {
575         genExpr(p, rv);
576         emit(p, genLValue(p, lv, &dummy));
577     }
578 }
579
580 static void genSlice(struct Parser* p, struct Token* t)
581 {
582     if(!t || t->type==TOK_EMPTY) naParseError(p, "empty slice expression", -1);
583     if(t->type == TOK_COLON) {
584         if(LEFT(t))  genExpr(p, LEFT(t));  else emit(p, OP_PUSHNIL);
585         if(RIGHT(t)) genExpr(p, RIGHT(t)); else emit(p, OP_PUSHNIL);
586         emit(p, OP_SLICE2);
587     } else {
588         genExpr(p, t);
589         emit(p, OP_SLICE);
590     }
591 }
592
593 static void genExtract(struct Parser* p, struct Token* t)
594 {
595     genExpr(p, LEFT(t));
596     if(countList(RIGHT(t), TOK_COMMA) == 1 && RIGHT(t)->type != TOK_COLON) {
597         genExpr(p, RIGHT(t));
598         emit(p, OP_EXTRACT);
599     } else {
600         emit(p, OP_NEWVEC);
601         for(t = RIGHT(t); t->type == TOK_COMMA; t = RIGHT(t))
602             genSlice(p, LEFT(t));
603         genSlice(p, t);
604         emit(p, OP_XCHG);
605         emit(p, OP_POP);
606     }
607 }
608
609 static void genExpr(struct Parser* p, struct Token* t)
610 {
611     int i;
612     if(!t) naParseError(p, "parse error", -1); // throw line -1...
613     p->errLine = t->line;                      // ...to use this one instead
614     if(t->line != p->cg->lastLine)
615         newLineEntry(p, t->line);
616     p->cg->lastLine = t->line;
617     switch(t->type) {
618     case TOK_TOP:      genExprList(p, LEFT(t)); break;
619     case TOK_IF:       genIfElse(p, t);   break;
620     case TOK_QUESTION: genQuestion(p, t); break;
621     case TOK_WHILE:    genWhile(p, t);    break;
622     case TOK_FOR:      genFor(p, t);      break;
623     case TOK_FUNC:     genLambda(p, t);   break;
624     case TOK_ASSIGN:   genAssign(p, t);   break;
625     case TOK_LITERAL:  genScalarConstant(p, t); break;
626     case TOK_FOREACH: case TOK_FORINDEX:
627         genForEach(p, t);
628         break;
629     case TOK_BREAK: case TOK_CONTINUE:
630         genBreakContinue(p, t);
631         break;
632     case TOK_LPAR:
633         if(BINARY(t) || !RIGHT(t)) genFuncall(p, t);
634         else genExpr(p, LEFT(t));
635         break;
636     case TOK_LBRA:
637         if(BINARY(t)) {
638             genExtract(p, t);
639         } else {
640             emit(p, OP_NEWVEC);
641             genList(p, LEFT(t), 1);
642         }
643         break;
644     case TOK_LCURL:
645         emit(p, OP_NEWHASH);
646         genHash(p, LEFT(t));
647         break;
648     case TOK_RETURN:
649         if(RIGHT(t)) genExpr(p, RIGHT(t));
650         else emit(p, OP_PUSHNIL);
651         for(i=0; i<p->cg->loopTop; i++) emit(p, OP_UNMARK);
652         emit(p, OP_RETURN);
653         break;
654     case TOK_NOT:
655         genExpr(p, RIGHT(t));
656         emit(p, OP_NOT);
657         break;
658     case TOK_SYMBOL:
659         emitImmediate(p, OP_LOCAL, findConstantIndex(p, t));
660         break;
661     case TOK_MINUS:
662         if(BINARY(t)) {
663             genBinOp(OP_MINUS,  p, t);  // binary subtraction
664         } else if(RIGHT(t) && RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) {
665             RIGHT(t)->num *= -1;        // Pre-negate constants
666             genScalarConstant(p, RIGHT(t));
667         } else {
668             genExpr(p, RIGHT(t));       // unary negation
669             emit(p, OP_NEG);
670         }
671         break;
672     case TOK_NEG:
673         genExpr(p, RIGHT(t)); // unary negation (see also TOK_MINUS!)
674         emit(p, OP_NEG);
675         break;
676     case TOK_DOT:
677         genExpr(p, LEFT(t));
678         if(!RIGHT(t) || RIGHT(t)->type != TOK_SYMBOL)
679             naParseError(p, "object field not symbol", RIGHT(t)->line);
680         emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(t)));
681         break;
682     case TOK_EMPTY: case TOK_NIL:
683         emit(p, OP_PUSHNIL);
684         break;
685     case TOK_AND: case TOK_OR:
686         genShortCircuit(p, t);
687         break;
688     case TOK_MUL:   genBinOp(OP_MUL,    p, t); break;
689     case TOK_PLUS:  genBinOp(OP_PLUS,   p, t); break;
690     case TOK_DIV:   genBinOp(OP_DIV,    p, t); break;
691     case TOK_CAT:   genBinOp(OP_CAT,    p, t); break;
692     case TOK_LT:    genBinOp(OP_LT,     p, t); break;
693     case TOK_LTE:   genBinOp(OP_LTE,    p, t); break;
694     case TOK_EQ:    genBinOp(OP_EQ,     p, t); break;
695     case TOK_NEQ:   genBinOp(OP_NEQ,    p, t); break;
696     case TOK_GT:    genBinOp(OP_GT,     p, t); break;
697     case TOK_GTE:   genBinOp(OP_GTE,    p, t); break;
698     case TOK_PLUSEQ:  genEqOp(OP_PLUS, p, t);  break;
699     case TOK_MINUSEQ: genEqOp(OP_MINUS, p, t); break;
700     case TOK_MULEQ:   genEqOp(OP_MUL, p, t);   break;
701     case TOK_DIVEQ:   genEqOp(OP_DIV, p, t);   break;
702     case TOK_CATEQ:   genEqOp(OP_CAT, p, t);   break;
703     default:
704         naParseError(p, "parse error", t->line);
705     };
706 }
707
708 static void genExprList(struct Parser* p, struct Token* t)
709 {
710     if(t && t->type == TOK_SEMI) {
711         genExpr(p, LEFT(t));
712         if(RIGHT(t) && RIGHT(t)->type != TOK_EMPTY) {
713             emit(p, OP_POP);
714             genExprList(p, RIGHT(t));
715         }
716     } else {
717         genExpr(p, t);
718     }
719 }
720
721 naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist)
722 {
723     int i;
724     naRef codeObj;
725     struct naCode* code;
726     struct CodeGenerator cg;
727
728     cg.lastLine = 0;
729     cg.codeAlloced = 1024; // Start fairly big, this is a cheap allocation
730     cg.byteCode = naParseAlloc(p, cg.codeAlloced *sizeof(unsigned short));
731     cg.codesz = 0;
732     cg.consts = naNewVector(p->context);
733     cg.loopTop = 0;
734     cg.lineIps = 0;
735     cg.nLineIps = 0;
736     cg.nextLineIp = 0;
737     p->cg = &cg;
738
739     genExprList(p, block);
740     emit(p, OP_RETURN);
741     
742     // Now make a code object
743     codeObj = naNewCode(p->context);
744     code = PTR(codeObj).code;
745     
746     // Parse the argument list, if any
747     p->cg->restArgSym = globals->argRef;
748     code->nArgs = code->nOptArgs = 0;
749     p->cg->argSyms = p->cg->optArgSyms = p->cg->optArgVals = 0;
750     code->needArgVector = 1;
751     if(arglist) {
752         p->cg->argSyms    = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
753         p->cg->optArgSyms = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
754         p->cg->optArgVals = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
755         code->needArgVector = 0;
756         genArgList(p, code, arglist);
757     }
758
759     code->restArgSym = internConstant(p, p->cg->restArgSym);
760
761     /* Set the size fields and allocate the combined array buffer.
762      * Note cute trick with null pointer to get the array size. */
763     code->nConstants = naVec_size(cg.consts);
764     code->codesz = cg.codesz;
765     code->nLines = cg.nextLineIp;
766     code->srcFile = p->srcFile;
767     code->constants = 0;
768     code->constants = naAlloc((int)(size_t)(LINEIPS(code)+code->nLines));
769     for(i=0; i<code->nConstants; i++)
770         code->constants[i] = naVec_get(p->cg->consts, i);
771
772     for(i=0; i<code->nArgs; i++) ARGSYMS(code)[i] = cg.argSyms[i];
773     for(i=0; i<code->nOptArgs; i++) OPTARGSYMS(code)[i] = cg.optArgSyms[i];
774     for(i=0; i<code->nOptArgs; i++) OPTARGVALS(code)[i] = cg.optArgVals[i];
775     for(i=0; i<code->codesz; i++) BYTECODE(code)[i] = cg.byteCode[i];
776     for(i=0; i<code->nLines; i++) LINEIPS(code)[i] = cg.lineIps[i];
777
778     return codeObj;
779 }