int codegen_codeABx(FuncState *fs, OpCode o, int a, unsigned int bc) { ktap_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); ktap_assert(getCMode(o) == OpArgN); ktap_assert(a <= MAXARG_A && bc <= MAXARG_Bx); return codegen_code(fs, CREATE_ABx(o, a, bc)); }
static void DumpConstants(const ktap_proto *f, DumpState *D) { int i, n = f->sizek; DumpInt(n, D); for (i = 0; i < n; i++) { const ktap_value* o=&f->k[i]; DumpChar(ttypenv(o), D); switch (ttypenv(o)) { case KTAP_TNIL: break; case KTAP_TBOOLEAN: DumpChar(bvalue(o), D); break; case KTAP_TNUMBER: DumpNumber(nvalue(o), D); break; case KTAP_TSTRING: DumpString(rawtsvalue(o), D); break; default: printf("ktap: DumpConstants with unknown vaule type %d\n", ttypenv(o)); ktap_assert(0); } } n = f->sizep; DumpInt(n, D); for (i = 0; i < n; i++) DumpFunction(f->p[i], D); }
static void leaveblock(ktap_funcstate *fs) { ktap_blockcnt *bl = fs->bl; ktap_lexstate *ls = fs->ls; if (bl->previous && bl->upval) { /* create a 'jump to here' to close upvalues */ int j = codegen_jump(fs); codegen_patchclose(fs, j, bl->nactvar); codegen_patchtohere(fs, j); } if (bl->isloop) breaklabel(ls); /* close pending breaks */ fs->bl = bl->previous; removevars(fs, bl->nactvar); ktap_assert(bl->nactvar == fs->nactvar); fs->freereg = fs->nactvar; /* free registers */ ls->dyd->label.n = bl->firstlabel; /* remove local labels */ if (bl->previous) /* inner block? */ movegotosout(fs, bl); /* update pending gotos to outer block */ else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ }
static ktap_locvar *getlocvar(ktap_funcstate *fs, int i) { int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; ktap_assert(idx < fs->nlocvars); return &fs->f->locvars[idx]; }
static void freereg(FuncState *fs, int reg) { if (!ISK(reg) && reg >= fs->nactvar) { fs->freereg--; ktap_assert(reg == fs->freereg); } }
int codegen_codeABC(FuncState *fs, OpCode o, int a, int b, int c) { ktap_assert(getOpMode(o) == iABC); //ktap_assert(getBMode(o) != OpArgN || b == 0); //ktap_assert(getCMode(o) != OpArgN || c == 0); //ktap_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C); return codegen_code(fs, CREATE_ABC(o, a, b, c)); }
static void anchor_token(ktap_lexstate *ls) { /* last token from outer function must be EOS */ ktap_assert((int)(ls->fs != NULL) || ls->t.token == TK_EOS); if (ls->t.token == TK_NAME || ls->t.token == TK_STRING) { ktap_string *ts = ls->t.seminfo.ts; lex_newstring(ls, getstr(ts), ts->tsv.len); } }
void codegen_patchlist(FuncState *fs, int list, int target) { if (target == fs->pc) codegen_patchtohere(fs, list); else { ktap_assert(target < fs->pc); patchlistaux(fs, list, target, NO_REG, target); } }
static void fixjump(FuncState *fs, int pc, int dest) { Instruction *jmp = &fs->f->code[pc]; int offset = dest-(pc+1); ktap_assert(dest != NO_JUMP); if (abs(offset) > MAXARG_sBx) lex_syntaxerror(fs->ls, "control structure too long"); SETARG_sBx(*jmp, offset); }
static void enterblock(ktap_funcstate *fs, ktap_blockcnt *bl, u8 isloop) { bl->isloop = isloop; bl->nactvar = fs->nactvar; bl->firstlabel = fs->ls->dyd->label.n; bl->firstgoto = fs->ls->dyd->gt.n; bl->upval = 0; bl->previous = fs->bl; fs->bl = bl; ktap_assert(fs->freereg == fs->nactvar); }
void codegen_patchclose(FuncState *fs, int list, int level) { level++; /* argument is +1 to reserve 0 as non-op */ while (list != NO_JUMP) { int next = getjump(fs, list); ktap_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && (GETARG_A(fs->f->code[list]) == 0 || GETARG_A(fs->f->code[list]) >= level)); SETARG_A(fs->f->code[list], level); list = next; } }
static void singlevar(ktap_lexstate *ls, ktap_expdesc *var) { ktap_string *varname = str_checkname(ls); ktap_funcstate *fs = ls->fs; if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */ ktap_expdesc key; singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ ktap_assert(var->k == VLOCAL || var->k == VUPVAL); codestring(ls, &key, varname); /* key is variable name */ codegen_indexed(fs, var, &key); /* env[varname] */ } }
ktap_number ktapc_arith(int op, ktap_number v1, ktap_number v2) { switch (op) { case KTAP_OPADD: return NUMADD(v1, v2); case KTAP_OPSUB: return NUMSUB(v1, v2); case KTAP_OPMUL: return NUMMUL(v1, v2); case KTAP_OPDIV: return NUMDIV(v1, v2); case KTAP_OPMOD: return NUMMOD(v1, v2); //case KTAP_OPPOW: return NUMPOW(v1, v2); case KTAP_OPUNM: return NUMUNM(v1); default: ktap_assert(0); return 0; } }
static void discharge2reg(ktap_funcstate *fs, ktap_expdesc *e, int reg) { codegen_dischargevars(fs, e); switch (e->k) { case VNIL: { codegen_nil(fs, reg, 1); break; } case VFALSE: case VTRUE: { codegen_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); break; } case VEVENT: codegen_codeABC(fs, OP_EVENT, reg, 0, 0); break; case VEVENTNAME: codegen_codeABC(fs, OP_EVENTNAME, reg, 0, 0); break; case VEVENTARG: codegen_codeABC(fs, OP_EVENTARG, reg, e->u.info, 0); break; case VK: { codegen_codek(fs, reg, e->u.info); break; } case VKNUM: { codegen_codek(fs, reg, codegen_numberK(fs, e->u.nval)); break; } case VRELOCABLE: { ktap_instruction *pc = &getcode(fs, e); SETARG_A(*pc, reg); break; } case VNONRELOC: { if (reg != e->u.info) codegen_codeABC(fs, OP_MOVE, reg, e->u.info, 0); break; } default: ktap_assert(e->k == VVOID || e->k == VJMP); return; /* nothing to do... */ } e->u.info = reg; e->k = VNONRELOC; }
static void closegoto(ktap_lexstate *ls, int g, ktap_labeldesc *label) { int i; ktap_funcstate *fs = ls->fs; ktap_labellist *gl = &ls->dyd->gt; ktap_labeldesc *gt = &gl->arr[g]; ktap_assert(ktapc_ts_eqstr(gt->name, label->name)); if (gt->nactvar < label->nactvar) { ktap_string *vname = getlocvar(fs, gt->nactvar)->varname; const char *msg = ktapc_sprintf( "<goto %s> at line %d jumps into the scope of local " KTAP_QS, getstr(gt->name), gt->line, getstr(vname)); semerror(ls, msg); } codegen_patchlist(fs, gt->pc, label->pc); /* remove goto from pending list */ for (i = g; i < gl->n - 1; i++) gl->arr[i] = gl->arr[i + 1]; gl->n--; }
static int codeextraarg(FuncState *fs, int a) { ktap_assert(a <= MAXARG_Ax); return codegen_code(fs, CREATE_Ax(OP_EXTRAARG, a)); }