static void retstat (LexState *ls) { /* stat -> RETURN explist */ FuncState *fs = ls->fs; expdesc e; int first, nret; /* registers with returned values */ luaX_next(ls); /* skip RETURN */ if (block_follow(ls->t.token) || ls->t.token == ';') first = nret = 0; /* return no values */ else { nret = explist1(ls, &e); /* optional return values */ if (hasmultret(e.k)) { luaK_setmultret(fs, &e); if (e.k == VCALL && nret == 1) { /* tail call? */ SET_OPCODE(getcode(fs,&e), OP_TAILCALL); lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); } first = fs->nactvar; nret = LUA_MULTRET; /* return all values */ } else { if (nret == 1) /* only one single value? */ first = luaK_exp2anyreg(fs, &e); else { luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ first = fs->nactvar; /* return all `active' values */ lua_assert(nret == fs->freereg - first); } } } luaK_ret(fs, first, nret); }
static void adjust_assign(LexState *ls, int nvars, int nexps, expdesc *e) { FuncState *fs = ls->fs; int extra = nvars - nexps; if (hasmultret(e->k)) { extra++; /* includes call itself */ if (extra < 0) extra = 0; luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ if (extra > 1) luaK_reserveregs(fs, extra - 1); } else { if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ if (extra > 0) { int reg = fs->freereg; luaK_reserveregs(fs, extra); luaK_nil(fs, reg, extra); } } }
static void funcargs(LexState* ls, expdesc* f) { FuncState* fs = ls->fs; expdesc args; int base, nparams; int line = ls->linenumber; switch (ls->t.token) { case '(': /* funcargs -> `(' [ explist1 ] `)' */ { if (line != ls->lastline) luaX_syntaxerror(ls, "ambiguous syntax (function call x new statement)"); luaX_next(ls); if (ls->t.token == ')') /* arg list is empty? */ args.k = VVOID; else { explist1(ls, &args); luaK_setmultret(fs, &args); } check_match(ls, ')', '(', line); break; } case '{': /* funcargs -> constructor */ { constructor(ls, &args); break; } case TK_STRING: /* funcargs -> STRING */ { codestring(ls, &args, ls->t.seminfo.ts); luaX_next(ls); /* must use `seminfo' before `next' */ break; } default: { luaX_syntaxerror(ls, "function arguments expected"); return; } } lua_assert(f->k == VNONRELOC); base = f->u.s.info; /* base register for call */ if (hasmultret(args.k)) nparams = LUA_MULTRET; /* open call */ else { if (args.k != VVOID) luaK_exp2nextreg(fs, &args); /* close last argument */ nparams = fs->freereg - (base + 1); } init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams + 1, 2)); luaK_fixline(fs, line); fs->freereg = base + 1; /* call remove function and arguments and leaves (unless changed) one result */ }
static void lastlistfield (FuncState *fs, struct ConsControl *cc) { if (cc->tostore == 0) return; if (hasmultret(cc->v.k)) { luaK_setmultret(fs, &cc->v); luaK_setlist(fs, cc->t->u.s.info, cc->na, LUA_MULTRET); cc->na--; /* do not count last expression (unknown number of elements) */ } else { if (cc->v.k != VVOID) luaK_exp2nextreg(fs, &cc->v); luaK_setlist(fs, cc->t->u.s.info, cc->na, cc->tostore); } }
Statement *TypeCompiler::visit(ReturnStatement *statement) { FuncState *fs = cs->fs; int first, nret; /* registers with returned values */ if (!statement->result) { first = nret = 0; /* return no values */ } else { ExpDesc e; nret = expList(&e, statement->result); if (hasmultret(e.k)) { BC::setMultRet(fs, &e); // LOOM: No tail calls as they screw up profiling/debugging /* * if (e.k == VCALL && nret == 1) { // tail call? * SET_OPCODE(getcode(fs,&e), OP_TAILCALL); * lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); * } */ first = fs->nactvar; nret = LUA_MULTRET; /* return all values */ } else { if (nret == 1) /* only one single value? */ { first = BC::expToAnyReg(fs, &e); } else { BC::expToNextReg(fs, &e); /* values must go to the `stack' */ first = fs->nactvar; /* return all `active' values */ lua_assert(nret == fs->freereg - first); } } } BC::ret(fs, first, nret); return statement; }
void TypeCompiler::generateCall(ExpDesc *call, utArray<Expression *> *arguments, MethodBase *methodBase) { FuncState *fs = cs->fs; int line = lineNumber; ParameterInfo *vararg = NULL; if (methodBase) { vararg = methodBase->getVarArgParameter(); } BC::expToNextReg(fs, call); ExpDesc args; args.k = VVOID; int nparams = 0; if ((arguments && arguments->size()) || vararg) { nparams = expList(&args, arguments, methodBase); BC::setMultRet(fs, &args); } lua_assert(call->k == VNONRELOC); int base = call->u.s.info; /* base register for call */ if (hasmultret(args.k)) { nparams = LUA_MULTRET; /* open call */ } else { if (args.k != VVOID) { BC::expToNextReg(fs, &args); /* close last argument */ } nparams = fs->freereg - (base + 1); } BC::initExpDesc(call, VCALL, BC::codeABC(fs, OP_CALL, base, nparams + 1, 2)); BC::fixLine(fs, line); fs->freereg = base + 1; }
static void retstat (LexState *ls) { /* stat -> RETURN explist */ FuncState *fs = ls->fs; BlockCnt *bl = fs->bl; expdesc e; int first, nret; /* registers with returned values */ int ret_in_try = 0; luaX_next(ls); /* skip RETURN */ if (block_follow(ls->t.token) || ls->t.token == ';') first = nret = 0; /* return no values */ else { nret = explist1(ls, &e); /* optional return values */ if (hasmultret(e.k)) { luaK_setmultret(fs, &e); if (e.k == VCALL && nret == 1) { /* tail call? */ SET_OPCODE(getcode(fs,&e), OP_TAILCALL); lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); } first = fs->nactvar; nret = LUA_MULTRET; /* return all values */ } else { if (nret == 1) /* only one single value? */ first = luaK_exp2anyreg(fs, &e); else { luaK_exp2nextreg(fs, &e); /* values must go to the `stack' */ first = fs->nactvar; /* return all `active' values */ lua_assert(nret == fs->freereg - first); } } } /* before return, we should exit all try-catch blocks */ while (bl) { if (bl->isbreakable == 2) { if (ret_in_try) luaK_codeABC(fs, OP_EXITTRY, 0, 0, 0); else { ret_in_try = 1; luaK_codeABC(fs, OP_EXITTRY, first, nret+1, 1); /* here we will save all return values */ } } else if (bl->isbreakable == 3) luaX_syntaxerror(ls, "can't return in _finally_ clause"); bl = bl->previous; } luaK_codeABC(fs, OP_RETURN, first, nret+1, ret_in_try); }
/*static*/ void LexState::adjust_assign (/*LexState *ls,*/ int nvars, int nexps, expdesc *e) { //FuncState *fs = fs; int extra = nvars - nexps; if (hasmultret(e->k)) { extra++; /* includes call itself */ if (extra < 0) extra = 0; fs->luaK_setreturns(e, extra); /* last exp. provides the difference */ if (extra > 1) fs->luaK_reserveregs(extra-1); } else { if (e->k != VVOID) fs->luaK_exp2nextreg(e); /* close last expression */ if (extra > 0) { int reg = fs->free_reg; fs->luaK_reserveregs(extra); fs->luaK_nil(reg, extra); } } }
Statement *TypeCompiler::visit(ForInStatement *statement) { FuncState *fs = cs->fs; int nvars = 0; int line; char forIteratorName[256]; // save off the previous iterator const char *prevForInIteratorName = currentForInIteratorName; // initially null, unless we need to use it due to // iterating with a variable external to block currentForInIteratorName = NULL; forIteratorName[0] = 0; const char *vname = NULL; ExpDesc v; ExpDesc fv; if (statement->variable->astType == AST_VARDECL) { VariableDeclaration *vd = (VariableDeclaration *)statement->variable; vname = vd->identifier->string.c_str(); } else if (statement->variable->astType == AST_IDENTIFIER) { vname = ((Identifier *)statement->variable)->string.c_str(); // a little sanity lmAssert(strlen(vname) < 240, "For..In variable name > 240 characters"); // we are using an external variable as the iterator for the loop // this means that we'll have to do a quick store to it when exiting the // loop (also via break) sprintf(forIteratorName, "__ls_%s", vname); currentForInIteratorName = forIteratorName; BC::newLocalVar(cs, forIteratorName, 0); BC::reserveRegs(fs, 1); BC::adjustLocalVars(cs, 1); } else { lmAssert(0, "Unknown variable statement in for..in initializer"); } BlockCnt forbl; enterBlock(fs, &forbl, 1); /* scope for loop and control variables */ int base = fs->freereg; /* create control variables */ BC::newLocalVar(cs, "(for generator)", nvars++); BC::newLocalVar(cs, "(for state)", nvars++); BC::newLocalVar(cs, "(for control)", nvars++); //TODO: It would be nice to have a way to iterate pairs if (statement->foreach) { BC::newLocalVar(cs, "__ls_key", nvars++); } /* create declared variables */ BC::newLocalVar(cs, vname, nvars++); line = lineNumber; bool isVector = false; if (statement->expression->type->getFullName() == "system.Vector") { isVector = true; } ExpDesc pairs; if (isVector) { BC::singleVar(cs, &pairs, "__lua_ipairs"); } else { BC::singleVar(cs, &pairs, "__lua_pairs"); } BC::expToNextReg(fs, &pairs); ExpDesc arg; int cbase = pairs.u.s.info; /* base register for call */ statement->expression->visitExpression(this); arg = statement->expression->e; ExpDesc right; if (isVector) { // we pass the instance itself } else { BC::initExpDesc(&right, VKNUM, 0); right.u.nval = LSINDEXDICTPAIRS; BC::expToNextReg(fs, &arg); BC::expToNextReg(fs, &right); BC::expToVal(fs, &right); BC::indexed(fs, &arg, &right); } BC::setMultRet(fs, &arg); int nparams = 0; if (hasmultret(arg.k)) { nparams = LUA_MULTRET; /* open call */ } else { if (arg.k != VVOID) { BC::expToNextReg(fs, &arg); /* close last argument */ } nparams = fs->freereg - (cbase + 1); } BC::initExpDesc(&pairs, VCALL, BC::codeABC(fs, OP_CALL, cbase, nparams + 1, 2 /* returns 1 values */)); fs->freereg = cbase + 1; /* call remove function and arguments and leaves*/ BC::adjustAssign(cs, 3, 1, &pairs); BC::checkStack(fs, 3); /* extra space to call generator */ /* forbody -> DO block */ BlockCnt bl; int prep, endfor; BC::adjustLocalVars(cs, 3); /* control variables */ prep = BC::jump(fs); enterBlock(fs, &bl, 0); /* scope for declared variables */ BC::adjustLocalVars(cs, nvars - 3); BC::reserveRegs(fs, nvars - 3); block(cs, statement->statement); if (forIteratorName[0]) { // we need to store BC::singleVar(cs, &v, vname); BC::singleVar(cs, &fv, forIteratorName); BC::storeVar(fs, &fv, &v); } leaveBlock(fs); /* end of scope for declared variables */ BC::patchToHere(fs, prep); BC::patchToHere(fs, forbl.continuelist); /* patch in continue list for for .. in/ for .. each */ endfor = BC::codeABC(fs, OP_TFORLOOP, base, 0, nvars - 3); BC::fixLine(fs, line); /* pretend that `OP_FOR' starts the loop */ BC::patchList(fs, BC::jump(fs), prep + 1); leaveBlock(fs); if (forIteratorName[0]) { // we need to store to this block's var BC::singleVar(cs, &v, vname); BC::singleVar(cs, &fv, forIteratorName); BC::storeVar(fs, &v, &fv); } currentForInIteratorName = prevForInIteratorName; return statement; }