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))
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);
18 static void emit(struct Parser* p, int val)
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;
27 p->cg->byteCode[p->cg->codesz++] = (unsigned short)val;
30 static void emitImmediate(struct Parser* p, int val, int arg)
36 static void genBinOp(int op, struct Parser* p, struct Token* t)
38 if(!LEFT(t) || !RIGHT(t))
39 naParseError(p, "empty subexpression", t->line);
45 static int newConstant(struct Parser* p, naRef c)
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);
54 // Interns a scalar (!) constant and returns its index
55 static int internConstant(struct Parser* p, naRef c)
57 int i, n = naVec_size(p->cg->consts);
58 if(IS_CODE(c)) return newConstant(p, c);
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;
65 return newConstant(p, c);
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)
75 if(naHash_get(globals->symbols, sym, &result))
77 naHash_set(globals->symbols, sym, sym);
81 static int findConstantIndex(struct Parser* p, struct Token* t)
84 if(t->type == TOK_NIL) c = naNil();
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);
95 static int genScalarConstant(struct Parser* p, struct Token* t)
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));
104 static int genLValue(struct Parser* p, struct Token* t, int* cidx)
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);
112 } else if(t->type == TOK_DOT && RIGHT(t) && RIGHT(t)->type == TOK_SYMBOL) {
114 *cidx = genScalarConstant(p, RIGHT(t));
116 } else if(t->type == TOK_LBRA) {
118 genExpr(p, RIGHT(t));
120 } else if(t->type == TOK_VAR && RIGHT(t) && RIGHT(t)->type == TOK_SYMBOL) {
121 *cidx = genScalarConstant(p, RIGHT(t));
124 naParseError(p, "bad lvalue", t->line);
129 static void genEqOp(int op, struct Parser* p, struct Token* t)
131 int cidx, n = 2, setop = genLValue(p, LEFT(t), &cidx);
132 if(setop == OP_SETMEMBER) {
135 emitImmediate(p, OP_MEMBER, cidx);
136 } else if(setop == OP_INSERT) {
140 emitImmediate(p, OP_LOCAL, cidx);
143 genExpr(p, RIGHT(t));
145 emit(p, n == 1 ? OP_XCHG : OP_XCHG2);
149 static int defArg(struct Parser* p, struct Token* t)
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));
160 if(t->type == TOK_MINUS && RIGHT(t) &&
161 RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str)
163 /* default arguments are constants, but "-1" parses as two
164 * tokens, so we have to subset the expression generator for that
167 return defArg(p, RIGHT(t));
169 if(t->type == TOK_CAT && RIGHT(t) &&
170 RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str)
172 /* default arguments are constants, but "~1" parses as two
173 * tokens, so we have to subset the expression generator for that
175 RIGHT(t)->num = ~(int)RIGHT(t)->num;
176 return defArg(p, RIGHT(t));
178 return findConstantIndex(p, t);
181 static void genArgList(struct Parser* p, struct naCode* c, struct Token* t)
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) {
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));
211 naParseError(p, "bad function argument expression", t->line);
214 static naRef newLambda(struct Parser* p, struct Token* t)
216 struct CodeGenerator* cgSave;
218 struct Token* arglist;
219 if(RIGHT(t)->type != TOK_LCURL)
220 naParseError(p, "bad function definition", t->line);
222 // Save off the generator state while we do the new one
224 arglist = LEFT(t)->type == TOK_LPAR ? LEFT(LEFT(t)) : 0;
225 codeObj = naCodeGen(p, LEFT(RIGHT(t)), arglist);
230 static void genLambda(struct Parser* p, struct Token* t)
232 emitImmediate(p, OP_PUSHCONST, newConstant(p, newLambda(p, t)));
235 static int genList(struct Parser* p, struct Token* t, int doAppend)
237 if(!t || t->type == TOK_EMPTY) {
239 } else if(t->type == TOK_COMMA) {
241 if(doAppend) emit(p, OP_VAPPEND);
242 return 1 + genList(p, RIGHT(t), doAppend);
245 if(doAppend) emit(p, OP_VAPPEND);
250 static void genHashElem(struct Parser* p, struct Token* t)
252 if(!t || t->type == TOK_EMPTY)
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));
263 static void genHash(struct Parser* p, struct Token* t)
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) {
273 static int isHashcall(struct Parser* p, struct Token* t)
276 int sep = LEFT(t) && t->type == TOK_COMMA ? t->children->type : t->type;
277 return sep == TOK_COLON;
282 static void genFuncall(struct Parser* p, struct Token* t)
285 if(LEFT(t)->type == TOK_DOT) {
287 genExpr(p, LEFT(LEFT(t)));
289 emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(LEFT(t))));
293 if(isHashcall(p, RIGHT(t))) {
295 genHash(p, RIGHT(t));
296 emit(p, method ? OP_MCALLH : OP_FCALLH);
298 int nargs = genList(p, RIGHT(t), 0);
299 emitImmediate(p, method ? OP_MCALL : OP_FCALL, nargs);
303 static int startLoop(struct Parser* p, struct Token* label)
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;
311 return p->cg->codesz;
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)
321 emit(p, 0xffff); // dummy address
325 // Points a previous jump instruction at the current "end-of-bytecode"
326 static void fixJumpTarget(struct Parser* p, int spot)
328 p->cg->byteCode[spot] = p->cg->codesz;
331 static void genShortCircuit(struct Parser* p, struct Token* t)
335 end = emitJump(p, t->type == TOK_AND ? OP_JIFNOT : OP_JIFTRUE);
337 genExpr(p, RIGHT(t));
338 fixJumpTarget(p, end);
342 static void genIf(struct Parser* p, struct Token* tif, struct Token* telse)
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);
351 if(telse->type == TOK_ELSIF) genIf(p, telse, telse->next);
352 else genExprList(p, telse->children->children);
356 fixJumpTarget(p, jumpEnd);
359 static void genIfElse(struct Parser* p, struct Token* t)
361 genIf(p, t, t->children->next->next);
364 static void genQuestion(struct Parser* p, struct Token* t)
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);
378 static int countList(struct Token* t, int type)
381 for(n = 1; t && t->type == type; t = RIGHT(t)) n++;
385 static void genLoop(struct Parser* p, struct Token* body,
386 struct Token* update, struct Token* label,
387 int loopTop, int jumpEnd)
389 int cont, jumpOverContinue;
391 p->cg->loops[p->cg->loopTop-1].breakIP = jumpEnd-1;
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);
398 genExprList(p, body);
400 fixJumpTarget(p, cont);
401 if(update) { genExpr(p, update); emit(p, OP_POP); }
402 emitImmediate(p, OP_JMPLOOP, loopTop);
403 fixJumpTarget(p, jumpEnd);
406 emit(p, OP_PUSHNIL); // Leave something on the stack
409 static void genForWhile(struct Parser* p, struct Token* init,
410 struct Token* test, struct Token* update,
411 struct Token* body, struct Token* label)
413 int loopTop, jumpEnd;
414 if(init) { genExpr(p, init); emit(p, OP_POP); }
415 loopTop = startLoop(p, label);
417 jumpEnd = emitJump(p, OP_JIFNOTPOP);
418 genLoop(p, body, update, label, loopTop, jumpEnd);
421 static void genWhile(struct Parser* p, struct Token* t)
423 struct Token *test=LEFT(t)->children, *body, *label=0;
424 int len = countList(test, TOK_SEMI);
427 if(!label || label->type != TOK_SYMBOL)
428 naParseError(p, "bad loop label", t->line);
431 naParseError(p, "too many semicolons in while test", t->line);
432 body = LEFT(RIGHT(t));
433 genForWhile(p, 0, test, 0, body, label);
436 static void genFor(struct Parser* p, struct Token* t)
438 struct Token *init, *test, *body, *update, *label=0;
439 struct Token *h = LEFT(t)->children;
440 int len = countList(h, TOK_SEMI);
442 if(!LEFT(h) || LEFT(h)->type != TOK_SYMBOL)
443 naParseError(p, "bad loop label", h->line);
447 naParseError(p, "wrong number of terms in for header", t->line);
449 test = LEFT(RIGHT(h));
450 update = RIGHT(RIGHT(h));
451 body = RIGHT(t)->children;
452 genForWhile(p, init, test, update, body, label);
455 static void genForEach(struct Parser* p, struct Token* t)
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);
462 if(!LEFT(h) || LEFT(h)->type != TOK_SYMBOL)
463 naParseError(p, "bad loop label", h->line);
466 } else if (len != 2) {
467 naParseError(p, "wrong number of terms in foreach header", t->line);
471 body = RIGHT(t)->children;
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);
481 genLoop(p, body, 0, label, loopTop, jumpEnd);
482 emit(p, OP_POP); // Pull off the vector and index
486 static int tokMatch(struct Token* a, struct Token* b)
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;
495 static void genBreakContinue(struct Parser* p, struct Token* t)
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);
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))
510 naParseError(p, "no match for break/continue label", t->line);
511 levels = p->cg->loopTop - loop;
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);
522 static void newLineEntry(struct Parser* p, int line)
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];
531 p->cg->nLineIps = nsz;
533 p->cg->lineIps[p->cg->nextLineIp++] = (unsigned short) p->cg->codesz;
534 p->cg->lineIps[p->cg->nextLineIp++] = (unsigned short) line;
537 static int parListLen(struct Token* t)
539 if(t->type != TOK_LPAR || !LEFT(t) || LEFT(t)->type != TOK_COMMA) return 0;
540 return countList(LEFT(t), TOK_COMMA);
543 static void genCommaList(struct Parser* p, struct Token* t)
545 if(t->type != TOK_COMMA) { genExpr(p, t); return; }
546 genCommaList(p, RIGHT(t));
550 static void genMultiLV(struct Parser* p, struct Token* t, int var)
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);
558 static void genAssign(struct Parser* p, struct Token* t)
560 struct Token *lv = LEFT(t), *rv = RIGHT(t);
561 int len, dummy, var=0;
563 naParseError(p, "bad assignment, missing variable", t->line);
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));
577 emitImmediate(p, OP_UNPACK, len);
579 for(t = LEFT(lv); t && t->type == TOK_COMMA; t = RIGHT(t)) {
580 genMultiLV(p, LEFT(t), var);
583 genMultiLV(p, t, var);
586 emit(p, genLValue(p, lv, &dummy));
590 static void genSlice(struct Parser* p, struct Token* t)
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);
603 static void genExtract(struct Parser* p, struct Token* t)
606 if(countList(RIGHT(t), TOK_COMMA) == 1 && RIGHT(t)->type != TOK_COLON) {
607 genExpr(p, RIGHT(t));
611 for(t = RIGHT(t); t->type == TOK_COMMA; t = RIGHT(t))
612 genSlice(p, LEFT(t));
619 static void genExpr(struct Parser* p, struct Token* t)
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;
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:
639 case TOK_BREAK: case TOK_CONTINUE:
640 genBreakContinue(p, t);
643 if(BINARY(t) || !RIGHT(t)) genFuncall(p, t);
644 else genExpr(p, LEFT(t));
649 genList(p, LEFT(t), 1);
654 // forbid usage as 'vec[]'
655 naParseError(p, "missing index or slice expression(s)", t->line);
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);
669 genExpr(p, RIGHT(t));
673 emitImmediate(p, OP_LOCAL, findConstantIndex(p, 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));
682 genExpr(p, RIGHT(t)); // unary negation
687 genExpr(p, RIGHT(t)); // unary negation (see also TOK_MINUS!)
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));
697 genExpr(p, RIGHT(t)); // unary, bitwise negation
702 genExpr(p, RIGHT(t)); // unary, bitwise negation (see also TOK_CAT!)
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)));
711 case TOK_EMPTY: case TOK_NIL:
714 case TOK_AND: case TOK_OR:
715 genShortCircuit(p, t);
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;
738 naParseError(p, "parse error", t->line);
742 static void genExprList(struct Parser* p, struct Token* t)
744 if(t && t->type == TOK_SEMI) {
746 if(RIGHT(t) && RIGHT(t)->type != TOK_EMPTY) {
748 genExprList(p, RIGHT(t));
755 naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist)
760 struct CodeGenerator cg;
763 cg.codeAlloced = 1024; // Start fairly big, this is a cheap allocation
764 cg.byteCode = naParseAlloc(p, cg.codeAlloced *sizeof(unsigned short));
766 cg.consts = naNewVector(p->context);
773 genExprList(p, block);
776 // Now make a code object
777 codeObj = naNewCode(p->context);
778 code = PTR(codeObj).code;
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;
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);
793 code->restArgSym = internConstant(p, p->cg->restArgSym);
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;
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);
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];