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