]> git.mxchange.org Git - simgear.git/blob - simgear/nasal/codegen.c
cppbind::Ghost: improve compiler error message for wrong usage.
[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     return findConstantIndex(p, t);
170 }
171
172 static void genArgList(struct Parser* p, struct naCode* c, struct Token* t)
173 {
174     naRef sym;
175     if(t->type == TOK_EMPTY) return;
176     if(!IDENTICAL(p->cg->restArgSym, globals->argRef))
177         naParseError(p, "remainder must be last", t->line);
178     if(t->type == TOK_ELLIPSIS) {
179         if(LEFT(t)->type != TOK_SYMBOL)
180             naParseError(p, "bad function argument expression", t->line);
181         sym = naStr_fromdata(naNewString(p->context),
182                              LEFT(t)->str, LEFT(t)->strlen);
183         p->cg->restArgSym = naInternSymbol(sym);
184         c->needArgVector = 1;
185     } else if(t->type == TOK_ASSIGN) {
186         if(LEFT(t)->type != TOK_SYMBOL)
187             naParseError(p, "bad function argument expression", t->line);
188         p->cg->optArgSyms[c->nOptArgs] = findConstantIndex(p, LEFT(t));
189         p->cg->optArgVals[c->nOptArgs++] = defArg(p, RIGHT(t));
190     } else if(t->type == TOK_SYMBOL) {
191         if(c->nOptArgs)
192             naParseError(p, "optional arguments must be last", t->line);
193         if(c->nArgs >= MAX_FUNARGS)
194             naParseError(p, "too many named function arguments", t->line);
195         p->cg->argSyms[c->nArgs++] = findConstantIndex(p, t);
196     } else if(t->type == TOK_COMMA) {
197         if(!LEFT(t) || !RIGHT(t))
198             naParseError(p, "empty function argument", t->line);
199         genArgList(p, c, LEFT(t));
200         genArgList(p, c, RIGHT(t));
201     } else
202         naParseError(p, "bad function argument expression", t->line);
203 }
204
205 static naRef newLambda(struct Parser* p, struct Token* t)
206 {
207     struct CodeGenerator* cgSave;
208     naRef codeObj;
209     struct Token* arglist;
210     if(RIGHT(t)->type != TOK_LCURL)
211         naParseError(p, "bad function definition", t->line);
212
213     // Save off the generator state while we do the new one
214     cgSave = p->cg;
215     arglist = LEFT(t)->type == TOK_LPAR ? LEFT(LEFT(t)) : 0;
216     codeObj = naCodeGen(p, LEFT(RIGHT(t)), arglist);
217     p->cg = cgSave;
218     return codeObj;
219 }
220
221 static void genLambda(struct Parser* p, struct Token* t)
222 {
223     emitImmediate(p, OP_PUSHCONST, newConstant(p, newLambda(p, t)));
224 }
225
226 static int genList(struct Parser* p, struct Token* t, int doAppend)
227 {
228     if(!t || t->type == TOK_EMPTY) {
229         return 0;
230     } else if(t->type == TOK_COMMA) {
231         genExpr(p, LEFT(t));
232         if(doAppend) emit(p, OP_VAPPEND);
233         return 1 + genList(p, RIGHT(t), doAppend);
234     } else {
235         genExpr(p, t);
236         if(doAppend) emit(p, OP_VAPPEND);
237         return 1;
238     }
239 }
240
241 static void genHashElem(struct Parser* p, struct Token* t)
242 {
243     if(!t || t->type == TOK_EMPTY)
244         return;
245     if(t->type != TOK_COLON || !LEFT(t))
246         naParseError(p, "bad hash/object initializer", t->line);
247     if(LEFT(t)->type == TOK_SYMBOL) genScalarConstant(p, LEFT(t));
248     else if(LEFT(t)->type == TOK_LITERAL) genExpr(p, LEFT(t));
249     else naParseError(p, "bad hash/object initializer", t->line);
250     genExpr(p, RIGHT(t));
251     emit(p, OP_HAPPEND);
252 }
253
254 static void genHash(struct Parser* p, struct Token* t)
255 {
256     if(t && t->type == TOK_COMMA) {
257         genHashElem(p, LEFT(t));
258         genHash(p, RIGHT(t));
259     } else if(t && t->type != TOK_EMPTY) {
260         genHashElem(p, t);
261     }
262 }
263
264 static int isHashcall(struct Parser* p, struct Token* t)
265 {
266     if(t) {
267         int sep = LEFT(t) && t->type == TOK_COMMA ? t->children->type : t->type;
268         return sep == TOK_COLON;
269     }
270     return 0;
271 }
272
273 static void genFuncall(struct Parser* p, struct Token* t)
274 {
275     int method = 0;
276     if(LEFT(t)->type == TOK_DOT) {
277         method = 1;
278         genExpr(p, LEFT(LEFT(t)));
279         emit(p, OP_DUP);
280         emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(LEFT(t))));
281     } else {
282         genExpr(p, LEFT(t));
283     }
284     if(isHashcall(p, RIGHT(t))) {
285         emit(p, OP_NEWHASH);
286         genHash(p, RIGHT(t));
287         emit(p, method ? OP_MCALLH : OP_FCALLH);
288     } else {
289         int nargs = genList(p, RIGHT(t), 0);
290         emitImmediate(p, method ? OP_MCALL : OP_FCALL, nargs);
291     }
292 }
293
294 static int startLoop(struct Parser* p, struct Token* label)
295 {
296     int i = p->cg->loopTop;
297     p->cg->loops[i].breakIP = 0xffffff;
298     p->cg->loops[i].contIP = 0xffffff;
299     p->cg->loops[i].label = label;
300     p->cg->loopTop++;
301     emit(p, OP_MARK);
302     return p->cg->codesz;
303 }
304
305 // Emit a jump operation, and return the location of the address in
306 // the bytecode for future fixup in fixJumpTarget
307 static int emitJump(struct Parser* p, int op)
308 {
309     int ip;
310     emit(p, op);
311     ip = p->cg->codesz;
312     emit(p, 0xffff); // dummy address
313     return ip;
314 }
315
316 // Points a previous jump instruction at the current "end-of-bytecode"
317 static void fixJumpTarget(struct Parser* p, int spot)
318 {
319     p->cg->byteCode[spot] = p->cg->codesz;
320 }
321
322 static void genShortCircuit(struct Parser* p, struct Token* t)
323 {
324     int end;
325     genExpr(p, LEFT(t));
326     end = emitJump(p, t->type == TOK_AND ? OP_JIFNOT : OP_JIFTRUE);
327     emit(p, OP_POP);
328     genExpr(p, RIGHT(t));
329     fixJumpTarget(p, end);
330 }
331
332
333 static void genIf(struct Parser* p, struct Token* tif, struct Token* telse)
334 {
335     int jumpNext, jumpEnd;
336     genExpr(p, tif->children); // the test
337     jumpNext = emitJump(p, OP_JIFNOTPOP);
338     genExprList(p, tif->children->next->children); // the body
339     jumpEnd = emitJump(p, OP_JMP);
340     fixJumpTarget(p, jumpNext);
341     if(telse) {
342         if(telse->type == TOK_ELSIF) genIf(p, telse, telse->next);
343         else genExprList(p, telse->children->children);
344     } else {
345         emit(p, OP_PUSHNIL);
346     }
347     fixJumpTarget(p, jumpEnd);
348 }
349
350 static void genIfElse(struct Parser* p, struct Token* t)
351 {
352     genIf(p, t, t->children->next->next);
353 }
354
355 static void genQuestion(struct Parser* p, struct Token* t)
356 {
357     int jumpNext, jumpEnd;
358     if(!RIGHT(t) || RIGHT(t)->type != TOK_COLON)
359         naParseError(p, "invalid ?: expression", t->line);
360     genExpr(p, LEFT(t)); // the test
361     jumpNext = emitJump(p, OP_JIFNOTPOP);
362     genExpr(p, LEFT(RIGHT(t))); // the "if true" expr
363     jumpEnd = emitJump(p, OP_JMP);
364     fixJumpTarget(p, jumpNext);
365     genExpr(p, RIGHT(RIGHT(t))); // the "else" expr
366     fixJumpTarget(p, jumpEnd);
367 }
368
369 static int countList(struct Token* t, int type)
370 {
371     int n;
372     for(n = 1; t && t->type == type; t = RIGHT(t)) n++;
373     return n;
374 }
375
376 static void genLoop(struct Parser* p, struct Token* body,
377                     struct Token* update, struct Token* label,
378                     int loopTop, int jumpEnd)
379 {
380     int cont, jumpOverContinue;
381     
382     p->cg->loops[p->cg->loopTop-1].breakIP = jumpEnd-1;
383
384     jumpOverContinue = emitJump(p, OP_JMP);
385     p->cg->loops[p->cg->loopTop-1].contIP = p->cg->codesz;
386     cont = emitJump(p, OP_JMP);
387     fixJumpTarget(p, jumpOverContinue);
388
389     genExprList(p, body);
390     emit(p, OP_POP);
391     fixJumpTarget(p, cont);
392     if(update) { genExpr(p, update); emit(p, OP_POP); }
393     emitImmediate(p, OP_JMPLOOP, loopTop);
394     fixJumpTarget(p, jumpEnd);
395     p->cg->loopTop--;
396     emit(p, OP_UNMARK);
397     emit(p, OP_PUSHNIL); // Leave something on the stack
398 }
399
400 static void genForWhile(struct Parser* p, struct Token* init,
401                         struct Token* test, struct Token* update,
402                         struct Token* body, struct Token* label)
403 {
404     int loopTop, jumpEnd;
405     if(init) { genExpr(p, init); emit(p, OP_POP); }
406     loopTop = startLoop(p, label);
407     genExpr(p, test);
408     jumpEnd = emitJump(p, OP_JIFNOTPOP);
409     genLoop(p, body, update, label, loopTop, jumpEnd);
410 }
411
412 static void genWhile(struct Parser* p, struct Token* t)
413 {
414     struct Token *test=LEFT(t)->children, *body, *label=0;
415     int len = countList(test, TOK_SEMI);
416     if(len == 2) {
417         label = LEFT(test);
418         if(!label || label->type != TOK_SYMBOL)
419             naParseError(p, "bad loop label", t->line);
420         test = RIGHT(test);
421     } else if(len != 1)
422         naParseError(p, "too many semicolons in while test", t->line);
423     body = LEFT(RIGHT(t));
424     genForWhile(p, 0, test, 0, body, label);
425 }
426
427 static void genFor(struct Parser* p, struct Token* t)
428 {
429     struct Token *init, *test, *body, *update, *label=0;
430     struct Token *h = LEFT(t)->children;
431     int len = countList(h, TOK_SEMI);
432     if(len == 4) {
433         if(!LEFT(h) || LEFT(h)->type != TOK_SYMBOL)
434             naParseError(p, "bad loop label", h->line);
435         label = LEFT(h);
436         h=RIGHT(h);
437     } else if(len != 3)
438         naParseError(p, "wrong number of terms in for header", t->line);
439     init = LEFT(h);
440     test = LEFT(RIGHT(h));
441     update = RIGHT(RIGHT(h));
442     body = RIGHT(t)->children;
443     genForWhile(p, init, test, update, body, label);
444 }
445
446 static void genForEach(struct Parser* p, struct Token* t)
447 {
448     int loopTop, jumpEnd, assignOp, dummy;
449     struct Token *elem, *body, *vec, *label=0;
450     struct Token *h = LEFT(LEFT(t));
451     int len = countList(h, TOK_SEMI);
452     if(len == 3) {
453         if(!LEFT(h) || LEFT(h)->type != TOK_SYMBOL)
454             naParseError(p, "bad loop label", h->line);
455         label = LEFT(h);
456         h = RIGHT(h);
457     } else if (len != 2) {
458         naParseError(p, "wrong number of terms in foreach header", t->line);
459     }
460     elem = LEFT(h);
461     vec = RIGHT(h);
462     body = RIGHT(t)->children;
463
464     genExpr(p, vec);
465     emit(p, OP_PUSHZERO);
466     loopTop = startLoop(p, label);
467     emit(p, t->type == TOK_FOREACH ? OP_EACH : OP_INDEX);
468     jumpEnd = emitJump(p, OP_JIFEND);
469     assignOp = genLValue(p, elem, &dummy);
470     emit(p, assignOp);
471     emit(p, OP_POP);
472     genLoop(p, body, 0, label, loopTop, jumpEnd);
473     emit(p, OP_POP); // Pull off the vector and index
474     emit(p, OP_POP);
475 }
476
477 static int tokMatch(struct Token* a, struct Token* b)
478 {
479     int i, l = a->strlen;
480     if(!a || !b) return 0;
481     if(l != b->strlen) return 0;
482     for(i=0; i<l; i++) if(a->str[i] != b->str[i]) return 0;
483     return 1;
484 }
485
486 static void genBreakContinue(struct Parser* p, struct Token* t)
487 {
488     int levels = 1, loop = -1, bp, cp, i;
489     // http://code.google.com/p/flightgear-bugs/issues/detail?id=587
490     // Make sure we are inside of a loop
491     if(p->cg->loopTop <= 0)
492         naParseError(p, "break/continue outside of a valid loop", t->line);
493     
494     if(RIGHT(t)) {
495         if(RIGHT(t)->type != TOK_SYMBOL)
496             naParseError(p, "bad break/continue label", t->line);
497         for(i=0; i<p->cg->loopTop; i++)
498             if(tokMatch(RIGHT(t), p->cg->loops[i].label))
499                 loop = i;
500         if(loop == -1)
501             naParseError(p, "no match for break/continue label", t->line);
502         levels = p->cg->loopTop - loop;
503     }
504     bp = p->cg->loops[p->cg->loopTop - levels].breakIP;
505     cp = p->cg->loops[p->cg->loopTop - levels].contIP;
506     for(i=0; i<levels; i++)
507         emit(p, (i<levels-1) ? OP_BREAK2 : OP_BREAK);
508     if(t->type == TOK_BREAK)
509         emit(p, OP_PUSHEND); // breakIP is always a JIFNOTPOP/JIFEND!
510     emitImmediate(p, OP_JMP, t->type == TOK_BREAK ? bp : cp);
511 }
512
513 static void newLineEntry(struct Parser* p, int line)
514 {
515     int i;
516     if(p->cg->nextLineIp >= p->cg->nLineIps) {
517         int nsz = p->cg->nLineIps*2 + 1;
518         unsigned short* n = naParseAlloc(p, sizeof(unsigned short)*2*nsz);
519         for(i=0; i<(p->cg->nextLineIp*2); i++)
520             n[i] = p->cg->lineIps[i];
521         p->cg->lineIps = n;
522         p->cg->nLineIps = nsz;
523     }
524     p->cg->lineIps[p->cg->nextLineIp++] = (unsigned short) p->cg->codesz;
525     p->cg->lineIps[p->cg->nextLineIp++] = (unsigned short) line;
526 }
527
528 static int parListLen(struct Token* t)
529 {
530     if(t->type != TOK_LPAR || !LEFT(t) || LEFT(t)->type != TOK_COMMA) return 0;
531     return countList(LEFT(t), TOK_COMMA);
532 }
533
534 static void genCommaList(struct Parser* p, struct Token* t)
535 {
536     if(t->type != TOK_COMMA) { genExpr(p, t); return; }
537     genCommaList(p, RIGHT(t));
538     genExpr(p, LEFT(t));
539 }
540
541 static void genMultiLV(struct Parser* p, struct Token* t, int var)
542 {
543     if(!var) { emit(p, genLValue(p, t, &var)); return; }
544     if(t->type != TOK_SYMBOL) naParseError(p, "bad lvalue", t->line);
545     genScalarConstant(p, t);
546     emit(p, OP_SETLOCAL);
547 }
548
549 static void genAssign(struct Parser* p, struct Token* t)
550 {
551     struct Token *lv = LEFT(t), *rv = RIGHT(t);
552     int len, dummy, var=0;
553     if (!lv)
554         naParseError(p, "bad assignment, missing variable", t->line);
555     else
556     if(parListLen(lv) || (lv->type == TOK_VAR && parListLen(RIGHT(lv)))) {
557         if(lv->type == TOK_VAR) { lv = RIGHT(lv); var = 1; }
558         len = parListLen(lv);
559         // http://code.google.com/p/flightgear-bugs/issues/detail?id=585
560         // TOK_LPAR can mean multi-value assignment or function call,
561         // disambigaute by checking the rule of the token
562         if(rv->type == TOK_LPAR && rv->rule != PREC_SUFFIX) {
563             if(len != parListLen(rv))
564                 naParseError(p, "bad assignment count", rv->line);
565             genCommaList(p, LEFT(rv));
566         } else {
567             genExpr(p, rv);
568             emitImmediate(p, OP_UNPACK, len);
569         }
570         for(t = LEFT(lv); t && t->type == TOK_COMMA; t = RIGHT(t)) {
571             genMultiLV(p, LEFT(t), var);
572             emit(p, OP_POP);
573         }
574         genMultiLV(p, t, var);
575     } else {
576         genExpr(p, rv);
577         emit(p, genLValue(p, lv, &dummy));
578     }
579 }
580
581 static void genSlice(struct Parser* p, struct Token* t)
582 {
583     if(!t || t->type==TOK_EMPTY) naParseError(p, "empty slice expression", -1);
584     if(t->type == TOK_COLON) {
585         if(LEFT(t))  genExpr(p, LEFT(t));  else emit(p, OP_PUSHNIL);
586         if(RIGHT(t)) genExpr(p, RIGHT(t)); else emit(p, OP_PUSHNIL);
587         emit(p, OP_SLICE2);
588     } else {
589         genExpr(p, t);
590         emit(p, OP_SLICE);
591     }
592 }
593
594 static void genExtract(struct Parser* p, struct Token* t)
595 {
596     genExpr(p, LEFT(t));
597     if(countList(RIGHT(t), TOK_COMMA) == 1 && RIGHT(t)->type != TOK_COLON) {
598         genExpr(p, RIGHT(t));
599         emit(p, OP_EXTRACT);
600     } else {
601         emit(p, OP_NEWVEC);
602         for(t = RIGHT(t); t->type == TOK_COMMA; t = RIGHT(t))
603             genSlice(p, LEFT(t));
604         genSlice(p, t);
605         emit(p, OP_XCHG);
606         emit(p, OP_POP);
607     }
608 }
609
610 static void genExpr(struct Parser* p, struct Token* t)
611 {
612     int i;
613     if(!t) naParseError(p, "parse error", -1); // throw line -1...
614     p->errLine = t->line;                      // ...to use this one instead
615     if(t->line != p->cg->lastLine)
616         newLineEntry(p, t->line);
617     p->cg->lastLine = t->line;
618     switch(t->type) {
619     case TOK_TOP:      genExprList(p, LEFT(t)); break;
620     case TOK_IF:       genIfElse(p, t);   break;
621     case TOK_QUESTION: genQuestion(p, t); break;
622     case TOK_WHILE:    genWhile(p, t);    break;
623     case TOK_FOR:      genFor(p, t);      break;
624     case TOK_FUNC:     genLambda(p, t);   break;
625     case TOK_ASSIGN:   genAssign(p, t);   break;
626     case TOK_LITERAL:  genScalarConstant(p, t); break;
627     case TOK_FOREACH: case TOK_FORINDEX:
628         genForEach(p, t);
629         break;
630     case TOK_BREAK: case TOK_CONTINUE:
631         genBreakContinue(p, t);
632         break;
633     case TOK_LPAR:
634         if(BINARY(t) || !RIGHT(t)) genFuncall(p, t);
635         else genExpr(p, LEFT(t));
636         break;
637     case TOK_LBRA:
638         if(UNARY(t)) {
639             emit(p, OP_NEWVEC);
640             genList(p, LEFT(t), 1);
641         }
642         else if(BINARY(t)) {
643             genExtract(p, t);
644         } else {
645             // forbid usage as 'vec[]'
646             naParseError(p, "missing index or slice expression(s)", t->line);
647         }
648         break;
649     case TOK_LCURL:
650         emit(p, OP_NEWHASH);
651         genHash(p, LEFT(t));
652         break;
653     case TOK_RETURN:
654         if(RIGHT(t)) genExpr(p, RIGHT(t));
655         else emit(p, OP_PUSHNIL);
656         for(i=0; i<p->cg->loopTop; i++) emit(p, OP_UNMARK);
657         emit(p, OP_RETURN);
658         break;
659     case TOK_NOT:
660         genExpr(p, RIGHT(t));
661         emit(p, OP_NOT);
662         break;
663     case TOK_SYMBOL:
664         emitImmediate(p, OP_LOCAL, findConstantIndex(p, t));
665         break;
666     case TOK_MINUS:
667         if(BINARY(t)) {
668             genBinOp(OP_MINUS,  p, t);  // binary subtraction
669         } else if(RIGHT(t) && RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) {
670             RIGHT(t)->num *= -1;        // Pre-negate constants
671             genScalarConstant(p, RIGHT(t));
672         } else {
673             genExpr(p, RIGHT(t));       // unary negation
674             emit(p, OP_NEG);
675         }
676         break;
677     case TOK_NEG:
678         genExpr(p, RIGHT(t)); // unary negation (see also TOK_MINUS!)
679         emit(p, OP_NEG);
680         break;
681     case TOK_DOT:
682         genExpr(p, LEFT(t));
683         if(!RIGHT(t) || RIGHT(t)->type != TOK_SYMBOL)
684             naParseError(p, "object field not symbol", RIGHT(t)->line);
685         emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(t)));
686         break;
687     case TOK_EMPTY: case TOK_NIL:
688         emit(p, OP_PUSHNIL);
689         break;
690     case TOK_AND: case TOK_OR:
691         genShortCircuit(p, t);
692         break;
693     case TOK_MUL:   genBinOp(OP_MUL,    p, t); break;
694     case TOK_PLUS:  genBinOp(OP_PLUS,   p, t); break;
695     case TOK_DIV:   genBinOp(OP_DIV,    p, t); break;
696     case TOK_CAT:   genBinOp(OP_CAT,    p, t); break;
697     case TOK_LT:    genBinOp(OP_LT,     p, t); break;
698     case TOK_LTE:   genBinOp(OP_LTE,    p, t); break;
699     case TOK_EQ:    genBinOp(OP_EQ,     p, t); break;
700     case TOK_NEQ:   genBinOp(OP_NEQ,    p, t); break;
701     case TOK_GT:    genBinOp(OP_GT,     p, t); break;
702     case TOK_GTE:   genBinOp(OP_GTE,    p, t); break;
703     case TOK_PLUSEQ:  genEqOp(OP_PLUS, p, t);  break;
704     case TOK_MINUSEQ: genEqOp(OP_MINUS, p, t); break;
705     case TOK_MULEQ:   genEqOp(OP_MUL, p, t);   break;
706     case TOK_DIVEQ:   genEqOp(OP_DIV, p, t);   break;
707     case TOK_CATEQ:   genEqOp(OP_CAT, p, t);   break;
708     default:
709         naParseError(p, "parse error", t->line);
710     };
711 }
712
713 static void genExprList(struct Parser* p, struct Token* t)
714 {
715     if(t && t->type == TOK_SEMI) {
716         genExpr(p, LEFT(t));
717         if(RIGHT(t) && RIGHT(t)->type != TOK_EMPTY) {
718             emit(p, OP_POP);
719             genExprList(p, RIGHT(t));
720         }
721     } else {
722         genExpr(p, t);
723     }
724 }
725
726 naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist)
727 {
728     int i;
729     naRef codeObj;
730     struct naCode* code;
731     struct CodeGenerator cg;
732
733     cg.lastLine = 0;
734     cg.codeAlloced = 1024; // Start fairly big, this is a cheap allocation
735     cg.byteCode = naParseAlloc(p, cg.codeAlloced *sizeof(unsigned short));
736     cg.codesz = 0;
737     cg.consts = naNewVector(p->context);
738     cg.loopTop = 0;
739     cg.lineIps = 0;
740     cg.nLineIps = 0;
741     cg.nextLineIp = 0;
742     p->cg = &cg;
743
744     genExprList(p, block);
745     emit(p, OP_RETURN);
746     
747     // Now make a code object
748     codeObj = naNewCode(p->context);
749     code = PTR(codeObj).code;
750     
751     // Parse the argument list, if any
752     p->cg->restArgSym = globals->argRef;
753     code->nArgs = code->nOptArgs = 0;
754     p->cg->argSyms = p->cg->optArgSyms = p->cg->optArgVals = 0;
755     code->needArgVector = 1;
756     if(arglist) {
757         p->cg->argSyms    = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
758         p->cg->optArgSyms = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
759         p->cg->optArgVals = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
760         code->needArgVector = 0;
761         genArgList(p, code, arglist);
762     }
763
764     code->restArgSym = internConstant(p, p->cg->restArgSym);
765
766     /* Set the size fields and allocate the combined array buffer.
767      * Note cute trick with null pointer to get the array size. */
768     code->nConstants = naVec_size(cg.consts);
769     code->codesz = cg.codesz;
770     code->nLines = cg.nextLineIp;
771     code->srcFile = p->srcFile;
772     code->constants = 0;
773     code->constants = naAlloc((int)(size_t)(LINEIPS(code)+code->nLines));
774     for(i=0; i<code->nConstants; i++)
775         code->constants[i] = naVec_get(p->cg->consts, i);
776
777     for(i=0; i<code->nArgs; i++) ARGSYMS(code)[i] = cg.argSyms[i];
778     for(i=0; i<code->nOptArgs; i++) OPTARGSYMS(code)[i] = cg.optArgSyms[i];
779     for(i=0; i<code->nOptArgs; i++) OPTARGVALS(code)[i] = cg.optArgVals[i];
780     for(i=0; i<code->codesz; i++) BYTECODE(code)[i] = cg.byteCode[i];
781     for(i=0; i<code->nLines; i++) LINEIPS(code)[i] = cg.lineIps[i];
782
783     return codeObj;
784 }