]> git.mxchange.org Git - simgear.git/blobdiff - simgear/nasal/codegen.c
Fix crash in code generator for some bad lvalue expressions
[simgear.git] / simgear / nasal / codegen.c
index f481e4190e9affe0866ba5316237bd72a78fdebe..15276e8c96ec4f59c68278c49eb1a45749371e76 100644 (file)
@@ -1,6 +1,8 @@
 #include "parse.h"
 #include "code.h"
 
+#define MAX_FUNARGS 32
+
 // These are more sensical predicate names in most contexts in this file
 #define LEFT(tok)   ((tok)->children)
 #define RIGHT(tok)  ((tok)->lastChild)
 // Forward references for recursion
 static void genExpr(struct Parser* p, struct Token* t);
 static void genExprList(struct Parser* p, struct Token* t);
+static naRef newLambda(struct Parser* p, struct Token* t);
 
-static void emit(struct Parser* p, int byte)
+static void emit(struct Parser* p, int val)
 {
-    if(p->cg->nBytes >= p->cg->codeAlloced) {
+    if(p->cg->codesz >= p->cg->codeAlloced) {
         int i, sz = p->cg->codeAlloced * 2;
-        unsigned char* buf = naParseAlloc(p, sz);
+        unsigned short* buf = naParseAlloc(p, sz*sizeof(unsigned short));
         for(i=0; i<p->cg->codeAlloced; i++) buf[i] = p->cg->byteCode[i];
         p->cg->byteCode = buf;
         p->cg->codeAlloced = sz;
     }
-    p->cg->byteCode[p->cg->nBytes++] = (unsigned char)byte;
+    p->cg->byteCode[p->cg->codesz++] = (unsigned short)val;
 }
 
-static void emitImmediate(struct Parser* p, int byte, int arg)
+static void emitImmediate(struct Parser* p, int val, int arg)
 {
-    emit(p, byte);
-    emit(p, arg >> 8);
-    emit(p, arg & 0xff);
+    emit(p, val);
+    emit(p, arg);
 }
 
 static void genBinOp(int op, struct Parser* p, struct Token* t)
@@ -55,87 +57,178 @@ static naRef getConstant(struct Parser* p, int idx)
 // Interns a scalar (!) constant and returns its index
 static int internConstant(struct Parser* p, naRef c)
 {
-    int i, j, n = naVec_size(p->cg->consts);
+    int i, n = naVec_size(p->cg->consts);
+    if(IS_CODE(c)) return newConstant(p, c);
     for(i=0; i<n; i++) {
         naRef b = naVec_get(p->cg->consts, i);
-        if(IS_NUM(b) && IS_NUM(c) && b.num == c.num)
-            return i;
-        if(IS_STR(b) && IS_STR(c)) {
-            int len = naStr_len(c);
-            char* cs = naStr_data(c);
-            char* bs = naStr_data(b);
-            if(naStr_len(b) != len)
-                continue;
-            for(j=0; j<len; j++)
-                if(cs[j] != bs[j])
-                    continue;
-        }
-        if(IS_REF(b) && IS_REF(c))
-            if(b.ref.ptr.obj->type == c.ref.ptr.obj->type)
-                if(naEqual(b, c))
-                    return i;
+        if(IS_NUM(b) && IS_NUM(c) && b.num == c.num) return i;
+        else if(IS_NIL(b) && IS_NIL(c)) return i;
+        else if(naStrEqual(b, c)) return i;
     }
     return newConstant(p, c);
 }
 
-static void genScalarConstant(struct Parser* p, struct Token* t)
+naRef naInternSymbol(naRef sym)
+{
+    naRef result;
+    if(naHash_get(globals->symbols, sym, &result))
+        return result;
+    naHash_set(globals->symbols, sym, sym);
+    return sym;
+}
+
+static int findConstantIndex(struct Parser* p, struct Token* t)
 {
-    naRef c = (t->str
-               ? naStr_fromdata(naNewString(p->context), t->str, t->strlen)
-               : naNum(t->num));
-    int idx = internConstant(p, c);
-    emitImmediate(p, OP_PUSHCONST, idx);
+    naRef c, dummy;
+    if(t->type == TOK_NIL) c = naNil();
+    else if(t->str) {
+        c = naStr_fromdata(naNewString(p->context), t->str, t->strlen);
+        naHash_get(globals->symbols, c, &dummy); // noop, make c immutable
+        if(t->type == TOK_SYMBOL) c = naInternSymbol(c);
+    } else if(t->type == TOK_FUNC) c = newLambda(p, t);
+    else if(t->type == TOK_LITERAL) c = naNum(t->num);
+    else naParseError(p, "invalid/non-constant constant", t->line);
+    return internConstant(p, c);
 }
 
-static int genLValue(struct Parser* p, struct Token* t)
+static int genScalarConstant(struct Parser* p, struct Token* t)
 {
-    if(t->type == TOK_LPAR) {
-        return genLValue(p, LEFT(t)); // Handle stuff like "(a) = 1"
+    // These opcodes are for special-case use in other constructs, but
+    // we might as well use them here to save a few bytes in the
+    // instruction stream.
+    if(t->str == 0 && t->num == 1) {
+        emit(p, OP_PUSHONE);
+    } else if(t->str == 0 && t->num == 0) {
+        emit(p, OP_PUSHZERO);
+    } else {
+        int idx = findConstantIndex(p, t);
+        emitImmediate(p, OP_PUSHCONST, idx);
+        return idx;
+    }
+    return 0;
+}
+
+static int genLValue(struct Parser* p, struct Token* t, int* cidx)
+{
+    if(!t) naParseError(p, "bad lvalue", -1);
+    if(t->type == TOK_LPAR && t->rule != PREC_SUFFIX) {
+        return genLValue(p, LEFT(t), cidx); // Handle stuff like "(a) = 1"
     } else if(t->type == TOK_SYMBOL) {
-        genScalarConstant(p, t);
-        return OP_SETLOCAL;
+        *cidx = genScalarConstant(p, t);
+        return OP_SETSYM;
     } else if(t->type == TOK_DOT && RIGHT(t) && RIGHT(t)->type == TOK_SYMBOL) {
         genExpr(p, LEFT(t));
-        genScalarConstant(p, RIGHT(t));
+        *cidx = genScalarConstant(p, RIGHT(t));
         return OP_SETMEMBER;
     } else if(t->type == TOK_LBRA) {
         genExpr(p, LEFT(t));
         genExpr(p, RIGHT(t));
         return OP_INSERT;
+    } else if(t->type == TOK_VAR && RIGHT(t) && RIGHT(t)->type == TOK_SYMBOL) {
+        *cidx = genScalarConstant(p, RIGHT(t));
+        return OP_SETLOCAL;
     } else {
         naParseError(p, "bad lvalue", t->line);
         return -1;
     }
 }
 
-static void genLambda(struct Parser* p, struct Token* t)
+static void genEqOp(int op, struct Parser* p, struct Token* t)
+{
+    int cidx, setop = genLValue(p, LEFT(t), &cidx);
+    if(setop == OP_SETMEMBER) {
+        emit(p, OP_DUP2);
+        emit(p, OP_POP);
+        emitImmediate(p, OP_MEMBER, cidx);
+    } else if(setop == OP_INSERT) {
+        emit(p, OP_DUP2);
+        emit(p, OP_EXTRACT);
+    } else // OP_SETSYM, OP_SETLOCAL
+        emitImmediate(p, OP_LOCAL, cidx);
+    genExpr(p, RIGHT(t));
+    emit(p, op);
+    emit(p, setop);
+}
+
+static int defArg(struct Parser* p, struct Token* t)
+{
+    if(t->type == TOK_LPAR) return defArg(p, RIGHT(t));
+    if(t->type == TOK_MINUS && RIGHT(t) && 
+       RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str)
+    {
+        /* default arguments are constants, but "-1" parses as two
+         * tokens, so we have to subset the expression generator for that
+         * case */
+        RIGHT(t)->num *= -1;
+        return defArg(p, RIGHT(t));
+    }
+    return findConstantIndex(p, t);
+}
+
+static void genArgList(struct Parser* p, struct naCode* c, struct Token* t)
+{
+    naRef sym;
+    if(t->type == TOK_EMPTY) return;
+    if(!IDENTICAL(c->restArgSym, globals->argRef))
+            naParseError(p, "remainder must be last", t->line);
+    if(t->type == TOK_ELLIPSIS) {
+        if(LEFT(t)->type != TOK_SYMBOL)
+            naParseError(p, "bad function argument expression", t->line);
+        sym = naStr_fromdata(naNewString(p->context),
+                             LEFT(t)->str, LEFT(t)->strlen);
+        c->restArgSym = naInternSymbol(sym);
+        c->needArgVector = 1;
+    } else if(t->type == TOK_ASSIGN) {
+        if(LEFT(t)->type != TOK_SYMBOL)
+            naParseError(p, "bad function argument expression", t->line);
+        c->optArgSyms[c->nOptArgs] = findConstantIndex(p, LEFT(t));
+        c->optArgVals[c->nOptArgs++] = defArg(p, RIGHT(t));
+    } else if(t->type == TOK_SYMBOL) {
+        if(c->nOptArgs)
+            naParseError(p, "optional arguments must be last", t->line);
+        if(c->nArgs >= MAX_FUNARGS)
+            naParseError(p, "too many named function arguments", t->line);
+        c->argSyms[c->nArgs++] = findConstantIndex(p, t);
+    } else if(t->type == TOK_COMMA) {
+        genArgList(p, c, LEFT(t));
+        genArgList(p, c, RIGHT(t));
+    } else
+        naParseError(p, "bad function argument expression", t->line);
+}
+
+static naRef newLambda(struct Parser* p, struct Token* t)
 {
-    int idx;
     struct CodeGenerator* cgSave;
     naRef codeObj;
-    if(LEFT(t)->type != TOK_LCURL)
+    struct Token* arglist;
+    if(RIGHT(t)->type != TOK_LCURL)
         naParseError(p, "bad function definition", t->line);
 
     // Save off the generator state while we do the new one
     cgSave = p->cg;
-    codeObj = naCodeGen(p, LEFT(LEFT(t)));
+    arglist = LEFT(t)->type == TOK_LPAR ? LEFT(LEFT(t)) : 0;
+    codeObj = naCodeGen(p, LEFT(RIGHT(t)), arglist);
     p->cg = cgSave;
+    return codeObj;
+}
 
-    idx = newConstant(p, codeObj);
-    emitImmediate(p, OP_PUSHCONST, idx);
+static void genLambda(struct Parser* p, struct Token* t)
+{
+    emitImmediate(p, OP_PUSHCONST, newConstant(p, newLambda(p, t)));
 }
 
-static void genList(struct Parser* p, struct Token* t)
+static int genList(struct Parser* p, struct Token* t, int doAppend)
 {
     if(t->type == TOK_COMMA) {
         genExpr(p, LEFT(t));
-        emit(p, OP_VAPPEND);
-        genList(p, RIGHT(t));
+        if(doAppend) emit(p, OP_VAPPEND);
+        return 1 + genList(p, RIGHT(t), doAppend);
     } else if(t->type == TOK_EMPTY) {
-        return;
+        return 0;
     } else {
         genExpr(p, t);
-        emit(p, OP_VAPPEND);
+        if(doAppend) emit(p, OP_VAPPEND);
+        return 1;
     }
 }
 
@@ -165,18 +258,17 @@ static void genHash(struct Parser* p, struct Token* t)
 static void genFuncall(struct Parser* p, struct Token* t)
 {
     int op = OP_FCALL;
+    int nargs = 0;
     if(LEFT(t)->type == TOK_DOT) {
         genExpr(p, LEFT(LEFT(t)));
         emit(p, OP_DUP);
-        genScalarConstant(p, RIGHT(LEFT(t)));
-        emit(p, OP_MEMBER);
+        emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(LEFT(t))));
         op = OP_MCALL;
     } else {
         genExpr(p, LEFT(t));
     }
-    emit(p, OP_NEWVEC);
-    if(RIGHT(t)) genList(p, RIGHT(t));
-    emit(p, op);
+    if(RIGHT(t)) nargs = genList(p, RIGHT(t), 0);
+    emitImmediate(p, op, nargs);
 }
 
 static void pushLoop(struct Parser* p, struct Token* label)
@@ -202,30 +294,25 @@ static int emitJump(struct Parser* p, int op)
 {
     int ip;
     emit(p, op);
-    ip = p->cg->nBytes;
-    emit(p, 0xff); // dummy address
-    emit(p, 0xff);
+    ip = p->cg->codesz;
+    emit(p, 0xffff); // dummy address
     return ip;
 }
 
 // Points a previous jump instruction at the current "end-of-bytecode"
 static void fixJumpTarget(struct Parser* p, int spot)
 {
-    p->cg->byteCode[spot]   = p->cg->nBytes >> 8;
-    p->cg->byteCode[spot+1] = p->cg->nBytes & 0xff;
+    p->cg->byteCode[spot] = p->cg->codesz;
 }
 
 static void genShortCircuit(struct Parser* p, struct Token* t)
 {
-    int jumpNext, jumpEnd, isAnd = (t->type == TOK_AND);
+    int end;
     genExpr(p, LEFT(t));
-    if(isAnd) emit(p, OP_NOT);
-    jumpNext = emitJump(p, OP_JIFNOT);
-    emit(p, isAnd ? OP_PUSHNIL : OP_PUSHONE);
-    jumpEnd = emitJump(p, OP_JMP);
-    fixJumpTarget(p, jumpNext);
+    end = emitJump(p, t->type == TOK_AND ? OP_JIFNOT : OP_JIFTRUE);
+    emit(p, OP_POP);
     genExpr(p, RIGHT(t));
-    fixJumpTarget(p, jumpEnd);
+    fixJumpTarget(p, end);
 }
 
 
@@ -233,7 +320,7 @@ static void genIf(struct Parser* p, struct Token* tif, struct Token* telse)
 {
     int jumpNext, jumpEnd;
     genExpr(p, tif->children); // the test
-    jumpNext = emitJump(p, OP_JIFNOT);
+    jumpNext = emitJump(p, OP_JIFNOTPOP);
     genExprList(p, tif->children->next->children); // the body
     jumpEnd = emitJump(p, OP_JMP);
     fixJumpTarget(p, jumpNext);
@@ -251,6 +338,20 @@ static void genIfElse(struct Parser* p, struct Token* t)
     genIf(p, t, t->children->next->next);
 }
 
+static void genQuestion(struct Parser* p, struct Token* t)
+{
+    int jumpNext, jumpEnd;
+    if(!RIGHT(t) || RIGHT(t)->type != TOK_COLON)
+        naParseError(p, "invalid ?: expression", t->line);
+    genExpr(p, LEFT(t)); // the test
+    jumpNext = emitJump(p, OP_JIFNOTPOP);
+    genExpr(p, LEFT(RIGHT(t))); // the "if true" expr
+    jumpEnd = emitJump(p, OP_JMP);
+    fixJumpTarget(p, jumpNext);
+    genExpr(p, RIGHT(RIGHT(t))); // the "else" expr
+    fixJumpTarget(p, jumpEnd);
+}
+
 static int countSemis(struct Token* t)
 {
     if(!t || t->type != TOK_SEMI) return 0;
@@ -266,7 +367,7 @@ static void genLoop(struct Parser* p, struct Token* body,
     p->cg->loops[p->cg->loopTop-1].breakIP = jumpEnd-1;
 
     jumpOverContinue = emitJump(p, OP_JMP);
-    p->cg->loops[p->cg->loopTop-1].contIP = p->cg->nBytes;
+    p->cg->loops[p->cg->loopTop-1].contIP = p->cg->codesz;
     cont = emitJump(p, OP_JMP);
     fixJumpTarget(p, jumpOverContinue);
 
@@ -274,7 +375,7 @@ static void genLoop(struct Parser* p, struct Token* body,
     emit(p, OP_POP);
     fixJumpTarget(p, cont);
     if(update) { genExpr(p, update); emit(p, OP_POP); }
-    emitImmediate(p, OP_JMP, loopTop);
+    emitImmediate(p, OP_JMPLOOP, loopTop);
     fixJumpTarget(p, jumpEnd);
     popLoop(p);
     emit(p, OP_PUSHNIL); // Leave something on the stack
@@ -287,9 +388,9 @@ static void genForWhile(struct Parser* p, struct Token* init,
     int loopTop, jumpEnd;
     if(init) { genExpr(p, init); emit(p, OP_POP); }
     pushLoop(p, label);
-    loopTop = p->cg->nBytes;
+    loopTop = p->cg->codesz;
     genExpr(p, test);
-    jumpEnd = emitJump(p, OP_JIFNOT);
+    jumpEnd = emitJump(p, OP_JIFNOTPOP);
     genLoop(p, body, update, label, loopTop, jumpEnd);
 }
 
@@ -333,7 +434,7 @@ static void genFor(struct Parser* p, struct Token* t)
 
 static void genForEach(struct Parser* p, struct Token* t)
 {
-    int loopTop, jumpEnd, assignOp;
+    int loopTop, jumpEnd, assignOp, dummy;
     struct Token *elem, *body, *vec, *label=0;
     struct Token *h = LEFT(LEFT(t));
     int semis = countSemis(h);
@@ -349,17 +450,19 @@ static void genForEach(struct Parser* p, struct Token* t)
     vec = RIGHT(h);
     body = RIGHT(t)->children;
 
-    pushLoop(p, label);
     genExpr(p, vec);
     emit(p, OP_PUSHZERO);
-    loopTop = p->cg->nBytes;
-    emit(p, OP_EACH);
-    jumpEnd = emitJump(p, OP_JIFNIL);
-    assignOp = genLValue(p, elem);
+    pushLoop(p, label);
+    loopTop = p->cg->codesz;
+    emit(p, t->type == TOK_FOREACH ? OP_EACH : OP_INDEX);
+    jumpEnd = emitJump(p, OP_JIFEND);
+    assignOp = genLValue(p, elem, &dummy);
     emit(p, OP_XCHG);
     emit(p, assignOp);
     emit(p, OP_POP);
     genLoop(p, body, 0, label, loopTop, jumpEnd);
+    emit(p, OP_POP); // Pull off the vector and index
+    emit(p, OP_POP);
 }
 
 static int tokMatch(struct Token* a, struct Token* b)
@@ -387,24 +490,42 @@ static void genBreakContinue(struct Parser* p, struct Token* t)
     bp = p->cg->loops[p->cg->loopTop - levels].breakIP;
     cp = p->cg->loops[p->cg->loopTop - levels].contIP;
     for(i=0; i<levels; i++)
-        emit(p, OP_BREAK);
+        emit(p, (i<levels-1) ? OP_BREAK2 : OP_BREAK);
     if(t->type == TOK_BREAK)
-        emit(p, OP_PUSHNIL); // breakIP is always a JIFNOT/JIFNIL!
+        emit(p, OP_PUSHEND); // breakIP is always a JIFNOTPOP/JIFEND!
     emitImmediate(p, OP_JMP, t->type == TOK_BREAK ? bp : cp);
 }
 
-static void genExpr(struct Parser* p, struct Token* t)
+static void newLineEntry(struct Parser* p, int line)
 {
     int i;
-    if(t == 0)
-        naParseError(p, "BUG: null subexpression", -1);
+    if(p->cg->nextLineIp >= p->cg->nLineIps) {
+        int nsz = p->cg->nLineIps*2 + 1;
+        unsigned short* n = naParseAlloc(p, sizeof(unsigned short)*2*nsz);
+        for(i=0; i<(p->cg->nextLineIp*2); i++)
+            n[i] = p->cg->lineIps[i];
+        p->cg->lineIps = n;
+        p->cg->nLineIps = nsz;
+    }
+    p->cg->lineIps[p->cg->nextLineIp++] = (unsigned short) p->cg->codesz;
+    p->cg->lineIps[p->cg->nextLineIp++] = (unsigned short) line;
+}
+
+static void genExpr(struct Parser* p, struct Token* t)
+{
+    int i, dummy;
+    if(!t) naParseError(p, "parse error", -1); // throw line -1...
+    p->errLine = t->line;                      // ...to use this one instead
     if(t->line != p->cg->lastLine)
-        emitImmediate(p, OP_LINE, t->line);
+        newLineEntry(p, t->line);
     p->cg->lastLine = t->line;
     switch(t->type) {
     case TOK_IF:
         genIfElse(p, t);
         break;
+    case TOK_QUESTION:
+        genQuestion(p, t);
+        break;
     case TOK_WHILE:
         genWhile(p, t);
         break;
@@ -412,6 +533,7 @@ static void genExpr(struct Parser* p, struct Token* t)
         genFor(p, t);
         break;
     case TOK_FOREACH:
+    case TOK_FORINDEX:
         genForEach(p, t);
         break;
     case TOK_BREAK: case TOK_CONTINUE:
@@ -432,7 +554,7 @@ static void genExpr(struct Parser* p, struct Token* t)
             genBinOp(OP_EXTRACT, p, t); // a[i]
         } else {
             emit(p, OP_NEWVEC);
-            genList(p, LEFT(t));
+            genList(p, LEFT(t), 1);
         }
         break;
     case TOK_LCURL:
@@ -440,13 +562,14 @@ static void genExpr(struct Parser* p, struct Token* t)
         genHash(p, LEFT(t));
         break;
     case TOK_ASSIGN:
-        i = genLValue(p, LEFT(t));
+        i = genLValue(p, LEFT(t), &dummy);
         genExpr(p, RIGHT(t));
         emit(p, i); // use the op appropriate to the lvalue
         break;
     case TOK_RETURN:
         if(RIGHT(t)) genExpr(p, RIGHT(t));
         else emit(p, OP_PUSHNIL);
+        for(i=0; i<p->cg->loopTop; i++) emit(p, OP_UNMARK);
         emit(p, OP_RETURN);
         break;
     case TOK_NOT:
@@ -454,8 +577,7 @@ static void genExpr(struct Parser* p, struct Token* t)
         emit(p, OP_NOT);
         break;
     case TOK_SYMBOL:
-        genScalarConstant(p, t);
-        emit(p, OP_LOCAL);
+        emitImmediate(p, OP_LOCAL, findConstantIndex(p, t));
         break;
     case TOK_LITERAL:
         genScalarConstant(p, t);
@@ -463,7 +585,7 @@ static void genExpr(struct Parser* p, struct Token* t)
     case TOK_MINUS:
         if(BINARY(t)) {
             genBinOp(OP_MINUS,  p, t);  // binary subtraction
-        } else if(RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) {
+        } else if(RIGHT(t) && RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) {
             RIGHT(t)->num *= -1;        // Pre-negate constants
             genScalarConstant(p, RIGHT(t));
         } else {
@@ -477,10 +599,9 @@ static void genExpr(struct Parser* p, struct Token* t)
         break;
     case TOK_DOT:
         genExpr(p, LEFT(t));
-        if(RIGHT(t)->type != TOK_SYMBOL)
+        if(!RIGHT(t) || RIGHT(t)->type != TOK_SYMBOL)
             naParseError(p, "object field not symbol", RIGHT(t)->line);
-        genScalarConstant(p, RIGHT(t));
-        emit(p, OP_MEMBER);
+        emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(t)));
         break;
     case TOK_EMPTY: case TOK_NIL:
         emit(p, OP_PUSHNIL); break; // *NOT* a noop!
@@ -497,6 +618,11 @@ static void genExpr(struct Parser* p, struct Token* t)
     case TOK_NEQ:   genBinOp(OP_NEQ,    p, t); break;
     case TOK_GT:    genBinOp(OP_GT,     p, t); break;
     case TOK_GTE:   genBinOp(OP_GTE,    p, t); break;
+    case TOK_PLUSEQ:  genEqOp(OP_PLUS, p, t);  break;
+    case TOK_MINUSEQ: genEqOp(OP_MINUS, p, t); break;
+    case TOK_MULEQ:   genEqOp(OP_MUL, p, t);   break;
+    case TOK_DIVEQ:   genEqOp(OP_DIV, p, t);   break;
+    case TOK_CATEQ:   genEqOp(OP_CAT, p, t);   break;
     default:
         naParseError(p, "parse error", t->line);
     };
@@ -504,7 +630,7 @@ static void genExpr(struct Parser* p, struct Token* t)
 
 static void genExprList(struct Parser* p, struct Token* t)
 {
-    if(t->type == TOK_SEMI) {
+    if(t && t->type == TOK_SEMI) {
         genExpr(p, LEFT(t));
         if(RIGHT(t) && RIGHT(t)->type != TOK_EMPTY) {
             emit(p, OP_POP);
@@ -515,7 +641,7 @@ static void genExprList(struct Parser* p, struct Token* t)
     }
 }
 
-naRef naCodeGen(struct Parser* p, struct Token* t)
+naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist)
 {
     int i;
     naRef codeObj;
@@ -524,26 +650,62 @@ naRef naCodeGen(struct Parser* p, struct Token* t)
 
     cg.lastLine = 0;
     cg.codeAlloced = 1024; // Start fairly big, this is a cheap allocation
-    cg.byteCode = naParseAlloc(p, cg.codeAlloced);
-    cg.nBytes = 0;
+    cg.byteCode = naParseAlloc(p, cg.codeAlloced *sizeof(unsigned short));
+    cg.codesz = 0;
     cg.consts = naNewVector(p->context);
     cg.loopTop = 0;
+    cg.lineIps = 0;
+    cg.nLineIps = 0;
+    cg.nextLineIp = 0;
     p->cg = &cg;
 
-    genExprList(p, t);
+    genExprList(p, block);
+    emit(p, OP_RETURN);
 
     // Now make a code object
     codeObj = naNewCode(p->context);
-    code = codeObj.ref.ptr.code;
-    code->nBytes = cg.nBytes;
-    code->byteCode = naAlloc(cg.nBytes);
-    for(i=0; i < cg.nBytes; i++)
+    code = PTR(codeObj).code;
+
+    // Parse the argument list, if any
+    code->restArgSym = globals->argRef;
+    code->nArgs = code->nOptArgs = 0;
+    code->argSyms = code->optArgSyms = code->optArgVals = 0;
+    code->needArgVector = 1;
+    if(arglist) {
+        code->argSyms    = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
+        code->optArgSyms = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
+        code->optArgVals = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
+        code->needArgVector = 0;
+        genArgList(p, code, arglist);
+        if(code->nArgs) {
+            int i, *nsyms;
+            nsyms = naAlloc(sizeof(int) * code->nArgs);
+            for(i=0; i<code->nArgs; i++) nsyms[i] = code->argSyms[i];
+            code->argSyms = nsyms;
+        } else code->argSyms = 0;
+        if(code->nOptArgs) {
+            int i, *nsyms, *nvals;
+            nsyms = naAlloc(sizeof(int) * code->nOptArgs);
+            nvals = naAlloc(sizeof(int) * code->nOptArgs);
+            for(i=0; i<code->nOptArgs; i++) nsyms[i] = code->optArgSyms[i];
+            for(i=0; i<code->nOptArgs; i++) nvals[i] = code->optArgVals[i];
+            code->optArgSyms = nsyms;
+            code->optArgVals = nvals;
+        } else code->optArgSyms = code->optArgVals = 0;
+    }
+
+    code->codesz = cg.codesz;
+    code->byteCode = naAlloc(cg.codesz * sizeof(unsigned short));
+    for(i=0; i < cg.codesz; i++)
         code->byteCode[i] = cg.byteCode[i];
     code->nConstants = naVec_size(cg.consts);
     code->constants = naAlloc(code->nConstants * sizeof(naRef));
     code->srcFile = p->srcFile;
     for(i=0; i<code->nConstants; i++)
         code->constants[i] = getConstant(p, i);
-
+    code->nLines = p->cg->nextLineIp;
+    code->lineIps = naAlloc(sizeof(unsigned short)*p->cg->nLineIps*2);
+    for(i=0; i<p->cg->nLineIps*2; i++)
+        code->lineIps[i] = p->cg->lineIps[i];
     return codeObj;
 }