One Level Up
Top Level
userspace/kp_parse.c - ktap
Global variables defined
Data types defined
Functions defined
Macros defined
Source code
- #include "../include/ktap_types.h"
- #include "../include/ktap_err.h"
- #include "kp_util.h"
- #include "kp_lex.h"
- #define VARNAMEDEF(_) \
- _(FOR_IDX, "(for index)") \
- _(FOR_STOP, "(for limit)") \
- _(FOR_STEP, "(for step)") \
- _(FOR_GEN, "(for generator)") \
- _(FOR_STATE, "(for state)") \
- _(FOR_CTL, "(for control)")
- enum {
- VARNAME_END,
- #define VARNAMEENUM(name, str) VARNAME_##name,
- VARNAMEDEF(VARNAMEENUM)
- #undef VARNAMEENUM
- VARNAME__MAX
- };
- typedef enum {
-
- VKNIL,
- VKFALSE,
- VKTRUE,
- VKSTR,
- VKNUM,
- VKLAST = VKNUM,
- VKCDATA,
-
- VLOCAL,
- VUPVAL,
- VGLOBAL,
- VINDEXED,
- VJMP,
- VRELOCABLE,
- VNONRELOC,
- VCALL,
- VVOID,
- VARGN,
- VARGSTR,
- VARGNAME,
- VPID,
- VTID,
- VUID,
- VCPU,
- VEXECNAME,
- VMAX
- } ExpKind;
- typedef struct ExpDesc {
- union {
- struct {
- uint32_t info;
- uint32_t aux;
- } s;
- ktap_val_t nval;
- ktap_str_t *sval;
- } u;
- ExpKind k;
- BCPos t;
- BCPos f;
- } ExpDesc;
- #define expr_hasjump(e) ((e)->t != (e)->f)
- #define expr_isk(e) ((e)->k <= VKLAST)
- #define expr_isk_nojump(e) (expr_isk(e) && !expr_hasjump(e))
- #define expr_isnumk(e) ((e)->k == VKNUM)
- #define expr_isnumk_nojump(e) (expr_isnumk(e) && !expr_hasjump(e))
- #define expr_isstrk(e) ((e)->k == VKSTR)
- #define expr_numtv(e) (&(e)->u.nval)
- #define expr_numberV(e) nvalue(expr_numtv((e)))
- static inline void expr_init(ExpDesc *e, ExpKind k, uint32_t info)
- {
- e->k = k;
- e->u.s.info = info;
- e->f = e->t = NO_JMP;
- }
- static int expr_numiszero(ExpDesc *e)
- {
- ktap_val_t *o = expr_numtv(e);
- return (nvalue(o) == 0);
- }
- typedef struct FuncScope {
- struct FuncScope *prev;
- int vstart;
- uint8_t nactvar;
- uint8_t flags;
- } FuncScope;
- #define FSCOPE_LOOP 0x01
- #define FSCOPE_BREAK 0x02
- #define FSCOPE_GOLA 0x04
- #define FSCOPE_UPVAL 0x08
- #define FSCOPE_NOCLOSE 0x10
- #define NAME_BREAK ((ktap_str_t *)(uintptr_t)1)
- typedef uint16_t VarIndex;
- #define KP_MAX_VSTACK (65536 - KP_MAX_UPVAL)
- #define VSTACK_VAR_RW 0x01
- #define VSTACK_GOTO 0x02
- #define VSTACK_LABEL 0x04
- typedef struct FuncState {
- ktap_tab_t *kt;
- LexState *ls;
- FuncScope *bl;
- struct FuncState *prev;
- BCPos pc;
- BCPos lasttarget;
- BCPos jpc;
- BCReg freereg;
- BCReg nactvar;
- BCReg nkn, nkgc;
- BCLine linedefined;
- BCInsLine *bcbase;
- BCPos bclim;
- int vbase;
- uint8_t flags;
- uint8_t numparams;
- uint8_t framesize;
- uint8_t nuv;
- VarIndex varmap[KP_MAX_LOCVAR];
- VarIndex uvmap[KP_MAX_UPVAL];
- VarIndex uvtmp[KP_MAX_UPVAL];
- } FuncState;
- typedef enum BinOpr {
- OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW,
- OPR_CONCAT,
- OPR_NE, OPR_EQ,
- OPR_LT, OPR_GE, OPR_LE, OPR_GT,
- OPR_AND, OPR_OR,
- OPR_NOBINOPR
- } BinOpr;
- KP_STATIC_ASSERT((int)BC_ISGE-(int)BC_ISLT == (int)OPR_GE-(int)OPR_LT);
- KP_STATIC_ASSERT((int)BC_ISLE-(int)BC_ISLT == (int)OPR_LE-(int)OPR_LT);
- KP_STATIC_ASSERT((int)BC_ISGT-(int)BC_ISLT == (int)OPR_GT-(int)OPR_LT);
- KP_STATIC_ASSERT((int)BC_SUBVV-(int)BC_ADDVV == (int)OPR_SUB-(int)OPR_ADD);
- KP_STATIC_ASSERT((int)BC_MULVV-(int)BC_ADDVV == (int)OPR_MUL-(int)OPR_ADD);
- KP_STATIC_ASSERT((int)BC_DIVVV-(int)BC_ADDVV == (int)OPR_DIV-(int)OPR_ADD);
- KP_STATIC_ASSERT((int)BC_MODVV-(int)BC_ADDVV == (int)OPR_MOD-(int)OPR_ADD);
- static void err_syntax(LexState *ls, ErrMsg em)
- {
- kp_lex_error(ls, ls->tok, em);
- }
- static void err_token(LexState *ls, LexToken tok)
- {
- kp_lex_error(ls, ls->tok, KP_ERR_XTOKEN, kp_lex_token2str(ls, tok));
- }
- static void err_limit(FuncState *fs, uint32_t limit, const char *what)
- {
- if (fs->linedefined == 0)
- kp_lex_error(fs->ls, 0, KP_ERR_XLIMM, limit, what);
- else
- kp_lex_error(fs->ls, 0, KP_ERR_XLIMF, fs->linedefined,
- limit, what);
- }
- #define checklimit(fs, v, l, m) if ((v) >= (l)) err_limit(fs, l, m)
- #define checklimitgt(fs, v, l, m) if ((v) > (l)) err_limit(fs, l, m)
- #define checkcond(ls, c, em) { if (!(c)) err_syntax(ls, em); }
- #define const_pri(e) ((e)->k)
- #define tvhaskslot(o) (is_number(o))
- #define tvkslot(o) (nvalue(o))
- static BCReg const_num(FuncState *fs, ExpDesc *e)
- {
- ktap_val_t *o;
- kp_assert(expr_isnumk(e));
- o = kp_tab_set(fs->kt, &e->u.nval);
- if (tvhaskslot(o))
- return tvkslot(o);
- set_number(o, fs->nkn);
- return fs->nkn++;
- }
- static BCReg const_gc(FuncState *fs, ktap_obj_t *gc, uint32_t itype)
- {
- ktap_val_t key, *o;
- setitype(&key, itype);
- key.val.gc = gc;
- o = kp_tab_set(fs->kt, &key);
- if (tvhaskslot(o))
- return tvkslot(o);
- set_number(o, fs->nkgc);
- return fs->nkgc++;
- }
- static BCReg const_str(FuncState *fs, ExpDesc *e)
- {
- kp_assert(expr_isstrk(e) || e->k == VGLOBAL);
- return const_gc(fs, obj2gco(e->u.sval), KTAP_TSTR);
- }
- ktap_str_t *kp_parse_keepstr(LexState *ls, const char *str, size_t len)
- {
- ktap_val_t v;
- ktap_str_t *s = kp_str_new(str, len);
- set_string(&v, s);
- ktap_val_t *tv = kp_tab_set(ls->fs->kt, &v);
- if (is_nil(tv))
- set_bool(tv, 1);
- return s;
- }
- static BCPos jmp_next(FuncState *fs, BCPos pc)
- {
- ptrdiff_t delta = bc_j(fs->bcbase[pc].ins);
- if ((BCPos)delta == NO_JMP)
- return NO_JMP;
- else
- return (BCPos)(((ptrdiff_t)pc+1)+delta);
- }
- static int jmp_novalue(FuncState *fs, BCPos list)
- {
- for (; list != NO_JMP; list = jmp_next(fs, list)) {
- BCIns p = fs->bcbase[list >= 1 ? list-1 : list].ins;
- if (!(bc_op(p) == BC_ISTC || bc_op(p) == BC_ISFC ||
- bc_a(p) == NO_REG))
- return 1;
- }
- return 0;
- }
- static int jmp_patchtestreg(FuncState *fs, BCPos pc, BCReg reg)
- {
- BCInsLine *ilp = &fs->bcbase[pc >= 1 ? pc-1 : pc];
- BCOp op = bc_op(ilp->ins);
- if (op == BC_ISTC || op == BC_ISFC) {
- if (reg != NO_REG && reg != bc_d(ilp->ins)) {
- setbc_a(&ilp->ins, reg);
- } else {
- setbc_op(&ilp->ins, op+(BC_IST-BC_ISTC));
- setbc_a(&ilp->ins, 0);
- }
- } else if (bc_a(ilp->ins) == NO_REG) {
- if (reg == NO_REG) {
- ilp->ins =
- BCINS_AJ(BC_JMP, bc_a(fs->bcbase[pc].ins), 0);
- } else {
- setbc_a(&ilp->ins, reg);
- if (reg >= bc_a(ilp[1].ins))
- setbc_a(&ilp[1].ins, reg+1);
- }
- } else {
- return 0;
- }
- return 1;
- }
- static void jmp_dropval(FuncState *fs, BCPos list)
- {
- for (; list != NO_JMP; list = jmp_next(fs, list))
- jmp_patchtestreg(fs, list, NO_REG);
- }
- static void jmp_patchins(FuncState *fs, BCPos pc, BCPos dest)
- {
- BCIns *jmp = &fs->bcbase[pc].ins;
- BCPos offset = dest-(pc+1)+BCBIAS_J;
- kp_assert(dest != NO_JMP);
- if (offset > BCMAX_D)
- err_syntax(fs->ls, KP_ERR_XJUMP);
- setbc_d(jmp, offset);
- }
- static void jmp_append(FuncState *fs, BCPos *l1, BCPos l2)
- {
- if (l2 == NO_JMP) {
- return;
- } else if (*l1 == NO_JMP) {
- *l1 = l2;
- } else {
- BCPos list = *l1;
- BCPos next;
-
- while ((next = jmp_next(fs, list)) != NO_JMP)
- list = next;
- jmp_patchins(fs, list, l2);
- }
- }
- static void jmp_patchval(FuncState *fs, BCPos list, BCPos vtarget,
- BCReg reg, BCPos dtarget)
- {
- while (list != NO_JMP) {
- BCPos next = jmp_next(fs, list);
- if (jmp_patchtestreg(fs, list, reg)) {
-
- jmp_patchins(fs, list, vtarget);
- } else {
-
- jmp_patchins(fs, list, dtarget);
- }
- list = next;
- }
- }
- static void jmp_tohere(FuncState *fs, BCPos list)
- {
- fs->lasttarget = fs->pc;
- jmp_append(fs, &fs->jpc, list);
- }
- static void jmp_patch(FuncState *fs, BCPos list, BCPos target)
- {
- if (target == fs->pc) {
- jmp_tohere(fs, list);
- } else {
- kp_assert(target < fs->pc);
- jmp_patchval(fs, list, target, NO_REG, target);
- }
- }
- static void bcreg_bump(FuncState *fs, BCReg n)
- {
- BCReg sz = fs->freereg + n;
- if (sz > fs->framesize) {
- if (sz >= KP_MAX_SLOTS)
- err_syntax(fs->ls, KP_ERR_XSLOTS);
- fs->framesize = (uint8_t)sz;
- }
- }
- static void bcreg_reserve(FuncState *fs, BCReg n)
- {
- bcreg_bump(fs, n);
- fs->freereg += n;
- }
- static void bcreg_free(FuncState *fs, BCReg reg)
- {
- if (reg >= fs->nactvar) {
- fs->freereg--;
- kp_assert(reg == fs->freereg);
- }
- }
- static void expr_free(FuncState *fs, ExpDesc *e)
- {
- if (e->k == VNONRELOC)
- bcreg_free(fs, e->u.s.info);
- }
- static BCPos bcemit_INS(FuncState *fs, BCIns ins)
- {
- BCPos pc = fs->pc;
- LexState *ls = fs->ls;
- jmp_patchval(fs, fs->jpc, pc, NO_REG, pc);
- fs->jpc = NO_JMP;
- if (pc >= fs->bclim) {
- ptrdiff_t base = fs->bcbase - ls->bcstack;
- checklimit(fs, ls->sizebcstack, KP_MAX_BCINS,
- "bytecode instructions");
- if (!ls->bcstack) {
- ls->bcstack = malloc(sizeof(BCInsLine) * 20);
- ls->sizebcstack = 20;
- } else {
- ls->bcstack = realloc(ls->bcstack,
- ls->sizebcstack * sizeof(BCInsLine) * 2);
- ls->sizebcstack = ls->sizebcstack * 2;
- }
- fs->bclim = (BCPos)(ls->sizebcstack - base);
- fs->bcbase = ls->bcstack + base;
- }
- fs->bcbase[pc].ins = ins;
- fs->bcbase[pc].line = ls->lastline;
- fs->pc = pc+1;
- return pc;
- }
- #define bcemit_ABC(fs, o, a, b, c) bcemit_INS(fs, BCINS_ABC(o, a, b, c))
- #define bcemit_AD(fs, o, a, d) bcemit_INS(fs, BCINS_AD(o, a, d))
- #define bcemit_AJ(fs, o, a, j) bcemit_INS(fs, BCINS_AJ(o, a, j))
- #define bcptr(fs, e) (&(fs)->bcbase[(e)->u.s.info].ins)
- static void expr_discharge(FuncState *fs, ExpDesc *e)
- {
- BCIns ins;
- if (e->k == VUPVAL) {
- ins = BCINS_AD(BC_UGET, 0, e->u.s.info);
- } else if (e->k == VGLOBAL) {
- ins = BCINS_AD(BC_GGET, 0, const_str(fs, e));
- } else if (e->k == VINDEXED) {
- BCReg rc = e->u.s.aux;
- if ((int32_t)rc < 0) {
- ins = BCINS_ABC(BC_TGETS, 0, e->u.s.info, ~rc);
- } else if (rc > BCMAX_C) {
- ins = BCINS_ABC(BC_TGETB, 0, e->u.s.info,
- rc-(BCMAX_C+1));
- } else {
- bcreg_free(fs, rc);
- ins = BCINS_ABC(BC_TGETV, 0, e->u.s.info, rc);
- }
- bcreg_free(fs, e->u.s.info);
- } else if (e->k == VCALL) {
- e->u.s.info = e->u.s.aux;
- e->k = VNONRELOC;
- return;
- } else if (e->k == VLOCAL) {
- e->k = VNONRELOC;
- return;
- } else {
- return;
- }
- e->u.s.info = bcemit_INS(fs, ins);
- e->k = VRELOCABLE;
- }
- static void bcemit_nil(FuncState *fs, BCReg from, BCReg n)
- {
- if (fs->pc > fs->lasttarget) {
- BCIns *ip = &fs->bcbase[fs->pc-1].ins;
- BCReg pto, pfrom = bc_a(*ip);
-
- switch (bc_op(*ip)) {
- case BC_KPRI:
- if (bc_d(*ip) != ~KTAP_TNIL) break;
- if (from == pfrom) {
- if (n == 1)
- return;
- } else if (from == pfrom+1) {
- from = pfrom;
- n++;
- } else {
- break;
- }
-
- *ip = BCINS_AD(BC_KNIL, from, from+n-1);
- return;
- case BC_KNIL:
- pto = bc_d(*ip);
-
- if (pfrom <= from && from <= pto+1) {
- if (from+n-1 > pto) {
-
- setbc_d(ip, from+n-1);
- }
- return;
- }
- break;
- default:
- break;
- }
- }
-
- bcemit_INS(fs, n == 1 ? BCINS_AD(BC_KPRI, from, VKNIL) :
- BCINS_AD(BC_KNIL, from, from+n-1));
- }
- static void expr_toreg_nobranch(FuncState *fs, ExpDesc *e, BCReg reg)
- {
- BCIns ins;
- expr_discharge(fs, e);
- if (e->k == VKSTR) {
- ins = BCINS_AD(BC_KSTR, reg, const_str(fs, e));
- } else if (e->k == VKNUM) {
- ktap_number n = expr_numberV(e);
- if (n >= 0 && n <= 0xffff) {
- ins = BCINS_AD(BC_KSHORT, reg, (BCReg)(uint16_t)n);
- } else
- ins = BCINS_AD(BC_KNUM, reg, const_num(fs, e));
- } else if (e->k == VRELOCABLE) {
- setbc_a(bcptr(fs, e), reg);
- goto noins;
- } else if (e->k == VNONRELOC) {
- if (reg == e->u.s.info)
- goto noins;
- ins = BCINS_AD(BC_MOV, reg, e->u.s.info);
- } else if (e->k == VKNIL) {
- bcemit_nil(fs, reg, 1);
- goto noins;
- } else if (e->k <= VKTRUE) {
- ins = BCINS_AD(BC_KPRI, reg, const_pri(e));
- } else if (e->k == VARGN) {
- ins = BCINS_AD(BC_VARGN, reg, e->u.s.info);
- } else if (e->k > VARGN && e->k < VMAX) {
- ins = BCINS_AD(e->k - VARGN + BC_VARGN, reg, 0);
- } else {
- kp_assert(e->k == VVOID || e->k == VJMP);
- return;
- }
- bcemit_INS(fs, ins);
- noins:
- e->u.s.info = reg;
- e->k = VNONRELOC;
- }
- static BCPos bcemit_jmp(FuncState *fs);
- static void expr_toreg(FuncState *fs, ExpDesc *e, BCReg reg)
- {
- expr_toreg_nobranch(fs, e, reg);
- if (e->k == VJMP) {
-
- jmp_append(fs, &e->t, e->u.s.info);
- }
- if (expr_hasjump(e)) {
- BCPos jend, jfalse = NO_JMP, jtrue = NO_JMP;
- if (jmp_novalue(fs, e->t) || jmp_novalue(fs, e->f)) {
- BCPos jval = (e->k == VJMP) ? NO_JMP : bcemit_jmp(fs);
- jfalse = bcemit_AD(fs, BC_KPRI, reg, VKFALSE);
- bcemit_AJ(fs, BC_JMP, fs->freereg, 1);
- jtrue = bcemit_AD(fs, BC_KPRI, reg, VKTRUE);
- jmp_tohere(fs, jval);
- }
- jend = fs->pc;
- fs->lasttarget = jend;
- jmp_patchval(fs, e->f, jend, reg, jfalse);
- jmp_patchval(fs, e->t, jend, reg, jtrue);
- }
- e->f = e->t = NO_JMP;
- e->u.s.info = reg;
- e->k = VNONRELOC;
- }
- static void expr_tonextreg(FuncState *fs, ExpDesc *e)
- {
- expr_discharge(fs, e);
- expr_free(fs, e);
- bcreg_reserve(fs, 1);
- expr_toreg(fs, e, fs->freereg - 1);
- }
- static BCReg expr_toanyreg(FuncState *fs, ExpDesc *e)
- {
- expr_discharge(fs, e);
- if (e->k == VNONRELOC) {
- if (!expr_hasjump(e))
- return e->u.s.info;
- if (e->u.s.info >= fs->nactvar) {
-
- expr_toreg(fs, e, e->u.s.info);
- return e->u.s.info;
- }
- }
- expr_tonextreg(fs, e);
- return e->u.s.info;
- }
- static void expr_toval(FuncState *fs, ExpDesc *e)
- {
- if (expr_hasjump(e))
- expr_toanyreg(fs, e);
- else
- expr_discharge(fs, e);
- }
- static void bcemit_store(FuncState *fs, ExpDesc *var, ExpDesc *e)
- {
- BCIns ins;
- if (var->k == VLOCAL) {
- fs->ls->vstack[var->u.s.aux].info |= VSTACK_VAR_RW;
- expr_free(fs, e);
- expr_toreg(fs, e, var->u.s.info);
- return;
- } else if (var->k == VUPVAL) {
- fs->ls->vstack[var->u.s.aux].info |= VSTACK_VAR_RW;
- expr_toval(fs, e);
- if (e->k <= VKTRUE)
- ins = BCINS_AD(BC_USETP, var->u.s.info, const_pri(e));
- else if (e->k == VKSTR)
- ins = BCINS_AD(BC_USETS, var->u.s.info,
- const_str(fs, e));
- else if (e->k == VKNUM)
- ins = BCINS_AD(BC_USETN, var->u.s.info,
- const_num(fs, e));
- else
- ins = BCINS_AD(BC_USETV, var->u.s.info,
- expr_toanyreg(fs, e));
- } else if (var->k == VGLOBAL) {
- BCReg ra = expr_toanyreg(fs, e);
- ins = BCINS_AD(BC_GSET, ra, const_str(fs, var));
- } else {
- BCReg ra, rc;
- kp_assert(var->k == VINDEXED);
- ra = expr_toanyreg(fs, e);
- rc = var->u.s.aux;
- if ((int32_t)rc < 0) {
- ins = BCINS_ABC(BC_TSETS, ra, var->u.s.info, ~rc);
- } else if (rc > BCMAX_C) {
- ins = BCINS_ABC(BC_TSETB, ra, var->u.s.info,
- rc-(BCMAX_C+1));
- } else {
-
- kp_assert(e->k != VNONRELOC || ra < fs->nactvar ||
- rc < ra || (bcreg_free(fs, rc),1));
- ins = BCINS_ABC(BC_TSETV, ra, var->u.s.info, rc);
- }
- }
- bcemit_INS(fs, ins);
- expr_free(fs, e);
- }
- static void bcemit_store_incr(FuncState *fs, ExpDesc *var, ExpDesc *e)
- {
- BCIns ins;
- if (var->k == VLOCAL) {
-
- err_syntax(fs->ls, KP_ERR_XSYMBOL);
- return;
- } else if (var->k == VUPVAL) {
- fs->ls->vstack[var->u.s.aux].info |= VSTACK_VAR_RW;
- expr_toval(fs, e);
- if (e->k == VKNUM) {
- ins = BCINS_AD(BC_UINCN, var->u.s.info,
- const_num(fs, e));
- } else if (e->k <= VKTRUE || e->k == VKSTR) {
- err_syntax(fs->ls, KP_ERR_XSYMBOL);
- return;
- } else
- ins = BCINS_AD(BC_UINCV, var->u.s.info,
- expr_toanyreg(fs, e));
- } else if (var->k == VGLOBAL) {
- BCReg ra = expr_toanyreg(fs, e);
- ins = BCINS_AD(BC_GINC, ra, const_str(fs, var));
- } else {
- BCReg ra, rc;
- kp_assert(var->k == VINDEXED);
- ra = expr_toanyreg(fs, e);
- rc = var->u.s.aux;
- if ((int32_t)rc < 0) {
- ins = BCINS_ABC(BC_TINCS, ra, var->u.s.info, ~rc);
- } else if (rc > BCMAX_C) {
- ins = BCINS_ABC(BC_TINCB, ra, var->u.s.info,
- rc-(BCMAX_C+1));
- } else {
-
- kp_assert(e->k != VNONRELOC || ra < fs->nactvar ||
- rc < ra || (bcreg_free(fs, rc),1));
- ins = BCINS_ABC(BC_TINCV, ra, var->u.s.info, rc);
- }
- }
- bcemit_INS(fs, ins);
- expr_free(fs, e);
- }
- static void bcemit_method(FuncState *fs, ExpDesc *e, ExpDesc *key)
- {
- BCReg idx, func, obj = expr_toanyreg(fs, e);
- expr_free(fs, e);
- func = fs->freereg;
- bcemit_AD(fs, BC_MOV, func+1, obj);
- kp_assert(expr_isstrk(key));
- idx = const_str(fs, key);
- if (idx <= BCMAX_C) {
- bcreg_reserve(fs, 2);
- bcemit_ABC(fs, BC_TGETS, func, obj, idx);
- } else {
- bcreg_reserve(fs, 3);
- bcemit_AD(fs, BC_KSTR, func+2, idx);
- bcemit_ABC(fs, BC_TGETV, func, obj, func+2);
- fs->freereg--;
- }
- e->u.s.info = func;
- e->k = VNONRELOC;
- }
- static BCPos bcemit_jmp(FuncState *fs)
- {
- BCPos jpc = fs->jpc;
- BCPos j = fs->pc - 1;
- BCIns *ip = &fs->bcbase[j].ins;
- fs->jpc = NO_JMP;
- if ((int32_t)j >= (int32_t)fs->lasttarget && bc_op(*ip) == BC_UCLO)
- setbc_j(ip, NO_JMP);
- else
- j = bcemit_AJ(fs, BC_JMP, fs->freereg, NO_JMP);
- jmp_append(fs, &j, jpc);
- return j;
- }
- static void invertcond(FuncState *fs, ExpDesc *e)
- {
- BCIns *ip = &fs->bcbase[e->u.s.info - 1].ins;
- setbc_op(ip, bc_op(*ip)^1);
- }
- static BCPos bcemit_branch(FuncState *fs, ExpDesc *e, int cond)
- {
- BCPos pc;
- if (e->k == VRELOCABLE) {
- BCIns *ip = bcptr(fs, e);
- if (bc_op(*ip) == BC_NOT) {
- *ip = BCINS_AD(cond ? BC_ISF : BC_IST, 0, bc_d(*ip));
- return bcemit_jmp(fs);
- }
- }
- if (e->k != VNONRELOC) {
- bcreg_reserve(fs, 1);
- expr_toreg_nobranch(fs, e, fs->freereg-1);
- }
- bcemit_AD(fs, cond ? BC_ISTC : BC_ISFC, NO_REG, e->u.s.info);
- pc = bcemit_jmp(fs);
- expr_free(fs, e);
- return pc;
- }
- static void bcemit_branch_t(FuncState *fs, ExpDesc *e)
- {
- BCPos pc;
- expr_discharge(fs, e);
- if (e->k == VKSTR || e->k == VKNUM || e->k == VKTRUE)
- pc = NO_JMP;
- else if (e->k == VJMP)
- invertcond(fs, e), pc = e->u.s.info;
- else if (e->k == VKFALSE || e->k == VKNIL)
- expr_toreg_nobranch(fs, e, NO_REG), pc = bcemit_jmp(fs);
- else
- pc = bcemit_branch(fs, e, 0);
- jmp_append(fs, &e->f, pc);
- jmp_tohere(fs, e->t);
- e->t = NO_JMP;
- }
- static void bcemit_branch_f(FuncState *fs, ExpDesc *e)
- {
- BCPos pc;
- expr_discharge(fs, e);
- if (e->k == VKNIL || e->k == VKFALSE)
- pc = NO_JMP;
- else if (e->k == VJMP)
- pc = e->u.s.info;
- else if (e->k == VKSTR || e->k == VKNUM || e->k == VKTRUE)
- expr_toreg_nobranch(fs, e, NO_REG), pc = bcemit_jmp(fs);
- else
- pc = bcemit_branch(fs, e, 1);
- jmp_append(fs, &e->t, pc);
- jmp_tohere(fs, e->f);
- e->f = NO_JMP;
- }
- static ktap_number number_foldarith(ktap_number x, ktap_number y, int op)
- {
- switch (op) {
- case OPR_ADD - OPR_ADD: return x + y;
- case OPR_SUB - OPR_ADD: return x - y;
- case OPR_MUL - OPR_ADD: return x * y;
- case OPR_DIV - OPR_ADD: return x / y;
- default: return x;
- }
- }
- static int foldarith(BinOpr opr, ExpDesc *e1, ExpDesc *e2)
- {
- ktap_val_t o;
- ktap_number n;
- if (!expr_isnumk_nojump(e1) || !expr_isnumk_nojump(e2))
- return 0;
- if (opr == OPR_DIV && expr_numberV(e2) == 0)
- return 0;
- if (opr == OPR_MOD)
- return 0;
- n = number_foldarith(expr_numberV(e1), expr_numberV(e2),
- (int)opr-OPR_ADD);
- set_number(&o, n);
- set_number(&e1->u.nval, n);
- return 1;
- }
- static void bcemit_arith(FuncState *fs, BinOpr opr, ExpDesc *e1, ExpDesc *e2)
- {
- BCReg rb, rc, t;
- uint32_t op;
- if (foldarith(opr, e1, e2))
- return;
- if (opr == OPR_POW) {
- op = BC_POW;
- rc = expr_toanyreg(fs, e2);
- rb = expr_toanyreg(fs, e1);
- } else {
- op = opr-OPR_ADD+BC_ADDVV;
-
- expr_toval(fs, e2);
- if (expr_isnumk(e2) && (rc = const_num(fs, e2)) <= BCMAX_C)
- op -= BC_ADDVV-BC_ADDVN;
- else
- rc = expr_toanyreg(fs, e2);
-
- kp_assert(expr_isnumk(e1) || e1->k == VNONRELOC);
- expr_toval(fs, e1);
-
- if (expr_isnumk(e1) && !expr_isnumk(e2) &&
- (t = const_num(fs, e1)) <= BCMAX_B) {
- rb = rc; rc = t; op -= BC_ADDVV-BC_ADDNV;
- } else {
- rb = expr_toanyreg(fs, e1);
- }
- }
-
- if (e1->k == VNONRELOC && e1->u.s.info >= fs->nactvar)
- fs->freereg--;
- if (e2->k == VNONRELOC && e2->u.s.info >= fs->nactvar)
- fs->freereg--;
- e1->u.s.info = bcemit_ABC(fs, op, 0, rb, rc);
- e1->k = VRELOCABLE;
- }
- static void bcemit_comp(FuncState *fs, BinOpr opr, ExpDesc *e1, ExpDesc *e2)
- {
- ExpDesc *eret = e1;
- BCIns ins;
- expr_toval(fs, e1);
- if (opr == OPR_EQ || opr == OPR_NE) {
- BCOp op = opr == OPR_EQ ? BC_ISEQV : BC_ISNEV;
- BCReg ra;
- if (expr_isk(e1)) {
- e1 = e2;
- e2 = eret;
- }
- ra = expr_toanyreg(fs, e1);
- expr_toval(fs, e2);
- switch (e2->k) {
- case VKNIL: case VKFALSE: case VKTRUE:
- ins = BCINS_AD(op+(BC_ISEQP-BC_ISEQV), ra,
- const_pri(e2));
- break;
- case VKSTR:
- ins = BCINS_AD(op+(BC_ISEQS-BC_ISEQV), ra,
- const_str(fs, e2));
- break;
- case VKNUM:
- ins = BCINS_AD(op+(BC_ISEQN-BC_ISEQV), ra,
- const_num(fs, e2));
- break;
- default:
- ins = BCINS_AD(op, ra, expr_toanyreg(fs, e2));
- break;
- }
- } else {
- uint32_t op = opr-OPR_LT+BC_ISLT;
- BCReg ra, rd;
- if ((op-BC_ISLT) & 1) {
- e1 = e2; e2 = eret;
- op = ((op-BC_ISLT)^3)+BC_ISLT;
- expr_toval(fs, e1);
- }
- rd = expr_toanyreg(fs, e2);
- ra = expr_toanyreg(fs, e1);
- ins = BCINS_AD(op, ra, rd);
- }
-
- if (e1->k == VNONRELOC && e1->u.s.info >= fs->nactvar)
- fs->freereg--;
- if (e2->k == VNONRELOC && e2->u.s.info >= fs->nactvar)
- fs->freereg--;
- bcemit_INS(fs, ins);
- eret->u.s.info = bcemit_jmp(fs);
- eret->k = VJMP;
- }
- static void bcemit_binop_left(FuncState *fs, BinOpr op, ExpDesc *e)
- {
- if (op == OPR_AND) {
- bcemit_branch_t(fs, e);
- } else if (op == OPR_OR) {
- bcemit_branch_f(fs, e);
- } else if (op == OPR_CONCAT) {
- expr_tonextreg(fs, e);
- } else if (op == OPR_EQ || op == OPR_NE) {
- if (!expr_isk_nojump(e))
- expr_toanyreg(fs, e);
- } else {
- if (!expr_isnumk_nojump(e))
- expr_toanyreg(fs, e);
- }
- }
- static void bcemit_binop(FuncState *fs, BinOpr op, ExpDesc *e1, ExpDesc *e2)
- {
- if (op <= OPR_POW) {
- bcemit_arith(fs, op, e1, e2);
- } else if (op == OPR_AND) {
- kp_assert(e1->t == NO_JMP);
- expr_discharge(fs, e2);
- jmp_append(fs, &e2->f, e1->f);
- *e1 = *e2;
- } else if (op == OPR_OR) {
- kp_assert(e1->f == NO_JMP);
- expr_discharge(fs, e2);
- jmp_append(fs, &e2->t, e1->t);
- *e1 = *e2;
- } else if (op == OPR_CONCAT) {
- expr_toval(fs, e2);
- if (e2->k == VRELOCABLE && bc_op(*bcptr(fs, e2)) == BC_CAT) {
- kp_assert(e1->u.s.info == bc_b(*bcptr(fs, e2))-1);
- expr_free(fs, e1);
- setbc_b(bcptr(fs, e2), e1->u.s.info);
- e1->u.s.info = e2->u.s.info;
- } else {
- expr_tonextreg(fs, e2);
- expr_free(fs, e2);
- expr_free(fs, e1);
- e1->u.s.info = bcemit_ABC(fs, BC_CAT, 0, e1->u.s.info,
- e2->u.s.info);
- }
- e1->k = VRELOCABLE;
- } else {
- kp_assert(op == OPR_NE || op == OPR_EQ || op == OPR_LT ||
- op == OPR_GE || op == OPR_LE || op == OPR_GT);
- bcemit_comp(fs, op, e1, e2);
- }
- }
- static void bcemit_unop(FuncState *fs, BCOp op, ExpDesc *e)
- {
- if (op == BC_NOT) {
-
- { BCPos temp = e->f; e->f = e->t; e->t = temp; }
- jmp_dropval(fs, e->f);
- jmp_dropval(fs, e->t);
- expr_discharge(fs, e);
- if (e->k == VKNIL || e->k == VKFALSE) {
- e->k = VKTRUE;
- return;
- } else if (expr_isk(e)) {
- e->k = VKFALSE;
- return;
- } else if (e->k == VJMP) {
- invertcond(fs, e);
- return;
- } else if (e->k == VRELOCABLE) {
- bcreg_reserve(fs, 1);
- setbc_a(bcptr(fs, e), fs->freereg-1);
- e->u.s.info = fs->freereg-1;
- e->k = VNONRELOC;
- } else {
- kp_assert(e->k == VNONRELOC);
- }
- } else {
- kp_assert(op == BC_UNM || op == BC_LEN);
-
- if (op == BC_UNM && !expr_hasjump(e)) {
-
- if (expr_isnumk(e) && !expr_numiszero(e)) {
- ktap_val_t *o = expr_numtv(e);
- if (is_number(o))
- set_number(o, -nvalue(o));
- return;
- }
- }
- expr_toanyreg(fs, e);
- }
- expr_free(fs, e);
- e->u.s.info = bcemit_AD(fs, op, 0, e->u.s.info);
- e->k = VRELOCABLE;
- }
- static int lex_opt(LexState *ls, LexToken tok)
- {
- if (ls->tok == tok) {
- kp_lex_next(ls);
- return 1;
- }
- return 0;
- }
- static void lex_check(LexState *ls, LexToken tok)
- {
- if (ls->tok != tok)
- err_token(ls, tok);
- kp_lex_next(ls);
- }
- static void lex_match(LexState *ls, LexToken what, LexToken who, BCLine line)
- {
- if (!lex_opt(ls, what)) {
- if (line == ls->linenumber) {
- err_token(ls, what);
- } else {
- const char *swhat = kp_lex_token2str(ls, what);
- const char *swho = kp_lex_token2str(ls, who);
- kp_lex_error(ls, ls->tok, KP_ERR_XMATCH, swhat, swho,
- line);
- }
- }
- }
- static ktap_str_t *lex_str(LexState *ls)
- {
- ktap_str_t *s;
- if (ls->tok != TK_name)
- err_token(ls, TK_name);
- s = rawtsvalue(&ls->tokval);
- kp_lex_next(ls);
- return s;
- }
- #define var_get(ls, fs, i) ((ls)->vstack[(fs)->varmap[(i)]])
- static void var_new(LexState *ls, BCReg n, ktap_str_t *name)
- {
- FuncState *fs = ls->fs;
- int vtop = ls->vtop;
- checklimit(fs, fs->nactvar+n, KP_MAX_LOCVAR, "local variables");
- if (vtop >= ls->sizevstack) {
- if (ls->sizevstack >= KP_MAX_VSTACK)
- kp_lex_error(ls, 0, KP_ERR_XLIMC, KP_MAX_VSTACK);
- if (!ls->vstack) {
- ls->vstack = malloc(sizeof(VarInfo) * 20);
- ls->sizevstack = 20;
- } else {
- ls->vstack = realloc(ls->vstack,
- ls->sizevstack * sizeof(VarInfo) * 2);
- ls->sizevstack = ls->sizevstack * 2;
- }
- }
- kp_assert((uintptr_t)name < VARNAME__MAX ||
- kp_tab_getstr(fs->kt, name) != NULL);
- ls->vstack[vtop].name = name;
- fs->varmap[fs->nactvar+n] = (uint16_t)vtop;
- ls->vtop = vtop+1;
- }
- #define var_new_lit(ls, n, v) \
- var_new(ls, (n), kp_parse_keepstr(ls, "" v, sizeof(v)-1))
- #define var_new_fixed(ls, n, vn) \
- var_new(ls, (n), (ktap_str_t *)(uintptr_t)(vn))
- static void var_add(LexState *ls, BCReg nvars)
- {
- FuncState *fs = ls->fs;
- BCReg nactvar = fs->nactvar;
- while (nvars--) {
- VarInfo *v = &var_get(ls, fs, nactvar);
- v->startpc = fs->pc;
- v->slot = nactvar++;
- v->info = 0;
- }
- fs->nactvar = nactvar;
- }
- static void var_remove(LexState *ls, BCReg tolevel)
- {
- FuncState *fs = ls->fs;
- while (fs->nactvar > tolevel)
- var_get(ls, fs, --fs->nactvar).endpc = fs->pc;
- }
- static BCReg var_lookup_local(FuncState *fs, ktap_str_t *n)
- {
- int i;
- for (i = fs->nactvar-1; i >= 0; i--) {
- if (n == var_get(fs->ls, fs, i).name)
- return (BCReg)i;
- }
- return (BCReg)-1;
- }
- static int var_lookup_uv(FuncState *fs, int vidx, ExpDesc *e)
- {
- int i, n = fs->nuv;
- for (i = 0; i < n; i++)
- if (fs->uvmap[i] == vidx)
- return i;
-
- checklimit(fs, fs->nuv, KP_MAX_UPVAL, "upvalues");
- kp_assert(e->k == VLOCAL || e->k == VUPVAL);
- fs->uvmap[n] = (uint16_t)vidx;
- fs->uvtmp[n] = (uint16_t)(e->k == VLOCAL ? vidx :
- KP_MAX_VSTACK+e->u.s.info);
- fs->nuv = n+1;
- return n;
- }
- static void fscope_uvmark(FuncState *fs, BCReg level);
- static int var_lookup_(FuncState *fs, ktap_str_t *name, ExpDesc *e,
- int first)
- {
- if (fs) {
- BCReg reg = var_lookup_local(fs, name);
- if ((int32_t)reg >= 0) {
- expr_init(e, VLOCAL, reg);
- if (!first) {
-
- fscope_uvmark(fs, reg);
- }
- return (int)(e->u.s.aux = (uint32_t)fs->varmap[reg]);
- } else {
-
- int vidx = var_lookup_(fs->prev, name, e, 0);
- if ((int32_t)vidx >= 0) {
-
- e->u.s.info =
- (uint8_t)var_lookup_uv(fs, vidx, e);
- e->k = VUPVAL;
- return vidx;
- }
- }
- } else {
- expr_init(e, VGLOBAL, 0);
- e->u.sval = name;
- }
- return (int)-1;
- }
- #define var_lookup(ls, e) \
- var_lookup_((ls)->fs, lex_str(ls), (e), 1)
- static int gola_new(LexState *ls, ktap_str_t *name, uint8_t info, BCPos pc)
- {
- FuncState *fs = ls->fs;
- int vtop = ls->vtop;
- if (vtop >= ls->sizevstack) {
- if (ls->sizevstack >= KP_MAX_VSTACK)
- kp_lex_error(ls, 0, KP_ERR_XLIMC, KP_MAX_VSTACK);
- if (!ls->vstack) {
- ls->vstack = malloc(sizeof(VarInfo) * 20);
- ls->sizevstack = 20;
- } else {
- ls->vstack = realloc(ls->vstack,
- ls->sizevstack * sizeof(VarInfo) * 2);
- ls->sizevstack = ls->sizevstack * 2;
- }
- }
- kp_assert(name == NAME_BREAK ||
- kp_tab_getstr(fs->kt, name) != NULL);
- ls->vstack[vtop].name = name;
- ls->vstack[vtop].startpc = pc;
- ls->vstack[vtop].slot = (uint8_t)fs->nactvar;
- ls->vstack[vtop].info = info;
- ls->vtop = vtop+1;
- return vtop;
- }
- #define gola_isgoto(v) ((v)->info & VSTACK_GOTO)
- #define gola_islabel(v) ((v)->info & VSTACK_LABEL)
- #define gola_isgotolabel(v) ((v)->info & (VSTACK_GOTO|VSTACK_LABEL))
- static void gola_patch(LexState *ls, VarInfo *vg, VarInfo *vl)
- {
- FuncState *fs = ls->fs;
- BCPos pc = vg->startpc;
- vg->name = NULL;
- setbc_a(&fs->bcbase[pc].ins, vl->slot);
- jmp_patch(fs, pc, vl->startpc);
- }
- static void gola_close(LexState *ls, VarInfo *vg)
- {
- FuncState *fs = ls->fs;
- BCPos pc = vg->startpc;
- BCIns *ip = &fs->bcbase[pc].ins;
- kp_assert(gola_isgoto(vg));
- kp_assert(bc_op(*ip) == BC_JMP || bc_op(*ip) == BC_UCLO);
- setbc_a(ip, vg->slot);
- if (bc_op(*ip) == BC_JMP) {
- BCPos next = jmp_next(fs, pc);
- if (next != NO_JMP)
- jmp_patch(fs, next, pc);
- setbc_op(ip, BC_UCLO);
- setbc_j(ip, NO_JMP);
- }
- }
- static void gola_resolve(LexState *ls, FuncScope *bl, int idx)
- {
- VarInfo *vg = ls->vstack + bl->vstart;
- VarInfo *vl = ls->vstack + idx;
- for (; vg < vl; vg++)
- if (vg->name == vl->name && gola_isgoto(vg)) {
- if (vg->slot < vl->slot) {
- ktap_str_t *name =
- var_get(ls, ls->fs, vg->slot).name;
- kp_assert((uintptr_t)name >= VARNAME__MAX);
- ls->linenumber =
- ls->fs->bcbase[vg->startpc].line;
- kp_assert(vg->name != NAME_BREAK);
- kp_lex_error(ls, 0, KP_ERR_XGSCOPE,
- getstr(vg->name), getstr(name));
- }
- gola_patch(ls, vg, vl);
- }
- }
- static void gola_fixup(LexState *ls, FuncScope *bl)
- {
- VarInfo *v = ls->vstack + bl->vstart;
- VarInfo *ve = ls->vstack + ls->vtop;
- for (; v < ve; v++) {
- ktap_str_t *name = v->name;
-
- if (name != NULL) {
- if (gola_islabel(v)) {
- VarInfo *vg;
-
- v->name = NULL;
-
- for (vg = v+1; vg < ve; vg++)
- if (vg->name == name &&
- gola_isgoto(vg)) {
- if ((bl->flags&FSCOPE_UPVAL) &&
- vg->slot > v->slot)
- gola_close(ls, vg);
- gola_patch(ls, vg, v);
- }
- } else if (gola_isgoto(v)) {
-
- if (bl->prev) {
- bl->prev->flags |= name == NAME_BREAK ? FSCOPE_BREAK : FSCOPE_GOLA;
- v->slot = bl->nactvar;
- if ((bl->flags & FSCOPE_UPVAL))
- gola_close(ls, v);
- } else {
- ls->linenumber =
- ls->fs->bcbase[v->startpc].line;
- if (name == NAME_BREAK)
- kp_lex_error(ls, 0, KP_ERR_XBREAK);
- else
- kp_lex_error(ls, 0, KP_ERR_XLUNDEF, getstr(name));
- }
- }
- }
- }
- }
- static VarInfo *gola_findlabel(LexState *ls, ktap_str_t *name)
- {
- VarInfo *v = ls->vstack + ls->fs->bl->vstart;
- VarInfo *ve = ls->vstack + ls->vtop;
- for (; v < ve; v++)
- if (v->name == name && gola_islabel(v))
- return v;
- return NULL;
- }
- static void fscope_begin(FuncState *fs, FuncScope *bl, int flags)
- {
- bl->nactvar = (uint8_t)fs->nactvar;
- bl->flags = flags;
- bl->vstart = fs->ls->vtop;
- bl->prev = fs->bl;
- fs->bl = bl;
- kp_assert(fs->freereg == fs->nactvar);
- }
- static void fscope_end(FuncState *fs)
- {
- FuncScope *bl = fs->bl;
- LexState *ls = fs->ls;
- fs->bl = bl->prev;
- var_remove(ls, bl->nactvar);
- fs->freereg = fs->nactvar;
- kp_assert(bl->nactvar == fs->nactvar);
- if ((bl->flags & (FSCOPE_UPVAL|FSCOPE_NOCLOSE)) == FSCOPE_UPVAL)
- bcemit_AJ(fs, BC_UCLO, bl->nactvar, 0);
- if ((bl->flags & FSCOPE_BREAK)) {
- if ((bl->flags & FSCOPE_LOOP)) {
- int idx = gola_new(ls, NAME_BREAK, VSTACK_LABEL,
- fs->pc);
- ls->vtop = idx;
- gola_resolve(ls, bl, idx);
- return;
- }
- } else if (!(bl->flags & FSCOPE_GOLA)) {
- return;
- }
- gola_fixup(ls, bl);
- }
- static void fscope_uvmark(FuncState *fs, BCReg level)
- {
- FuncScope *bl;
- for (bl = fs->bl; bl && bl->nactvar > level; bl = bl->prev);
- if (bl)
- bl->flags |= FSCOPE_UPVAL;
- }
- static void fs_fixup_bc(FuncState *fs, ktap_proto_t *pt, BCIns *bc, int n)
- {
- BCInsLine *base = fs->bcbase;
- int i;
- pt->sizebc = n;
- bc[0] = BCINS_AD((fs->flags & PROTO_VARARG) ? BC_FUNCV : BC_FUNCF,
- fs->framesize, 0);
- for (i = 1; i < n; i++)
- bc[i] = base[i].ins;
- }
- static void fs_fixup_uv2(FuncState *fs, ktap_proto_t *pt)
- {
- VarInfo *vstack = fs->ls->vstack;
- uint16_t *uv = pt->uv;
- int i, n = pt->sizeuv;
- for (i = 0; i < n; i++) {
- VarIndex vidx = uv[i];
- if (vidx >= KP_MAX_VSTACK)
- uv[i] = vidx - KP_MAX_VSTACK;
- else if ((vstack[vidx].info & VSTACK_VAR_RW))
- uv[i] = vstack[vidx].slot | PROTO_UV_LOCAL;
- else
- uv[i] = vstack[vidx].slot | PROTO_UV_LOCAL |
- PROTO_UV_IMMUTABLE;
- }
- }
- static void fs_fixup_k(FuncState *fs, ktap_proto_t *pt, void *kptr)
- {
- ktap_tab_t *kt;
- ktap_node_t *node;
- int i, hmask;
- checklimitgt(fs, fs->nkn, BCMAX_D+1, "constants");
- checklimitgt(fs, fs->nkgc, BCMAX_D+1, "constants");
- pt->k = kptr;
- pt->sizekn = fs->nkn;
- pt->sizekgc = fs->nkgc;
- kt = fs->kt;
- node = kt->node;
- hmask = kt->hmask;
- for (i = 0; i <= hmask; i++) {
- ktap_node_t *n = &node[i];
- if (tvhaskslot(&n->val)) {
- ptrdiff_t kidx = (ptrdiff_t)tvkslot(&n->val);
- kp_assert(!is_number(&n->key));
- if (is_number(&n->key)) {
- ktap_val_t *tv = &((ktap_val_t *)kptr)[kidx];
- *tv = n->key;
- } else {
- ktap_obj_t *o = n->key.val.gc;
- ktap_obj_t **v = (ktap_obj_t **)kptr;
- v[~kidx] = o;
- if (is_proto(&n->key))
- fs_fixup_uv2(fs, (ktap_proto_t *)o);
- }
- }
- }
- }
- static void fs_fixup_uv1(FuncState *fs, ktap_proto_t *pt, uint16_t *uv)
- {
- pt->uv = uv;
- pt->sizeuv = fs->nuv;
- memcpy(uv, fs->uvtmp, fs->nuv*sizeof(VarIndex));
- }
- #ifndef KTAP_DISABLE_LINEINFO
- static size_t fs_prep_line(FuncState *fs, BCLine numline)
- {
- return (fs->pc-1) << (numline < 256 ? 0 : numline < 65536 ? 1 : 2);
- }
- static void fs_fixup_line(FuncState *fs, ktap_proto_t *pt,
- void *lineinfo, BCLine numline)
- {
- BCInsLine *base = fs->bcbase + 1;
- BCLine first = fs->linedefined;
- int i = 0, n = fs->pc-1;
- pt->firstline = fs->linedefined;
- pt->numline = numline;
- pt->lineinfo = lineinfo;
- if (numline < 256) {
- uint8_t *li = (uint8_t *)lineinfo;
- do {
- BCLine delta = base[i].line - first;
- kp_assert(delta >= 0 && delta < 256);
- li[i] = (uint8_t)delta;
- } while (++i < n);
- } else if (numline < 65536) {
- uint16_t *li = (uint16_t *)lineinfo;
- do {
- BCLine delta = base[i].line - first;
- kp_assert(delta >= 0 && delta < 65536);
- li[i] = (uint16_t)delta;
- } while (++i < n);
- } else {
- uint32_t *li = (uint32_t *)lineinfo;
- do {
- BCLine delta = base[i].line - first;
- kp_assert(delta >= 0);
- li[i] = (uint32_t)delta;
- } while (++i < n);
- }
- }
- static size_t fs_prep_var(LexState *ls, FuncState *fs, size_t *ofsvar)
- {
- VarInfo *vs =ls->vstack, *ve;
- int i, n;
- BCPos lastpc;
- kp_buf_reset(&ls->sb);
-
- for (i = 0, n = fs->nuv; i < n; i++) {
- ktap_str_t *s = vs[fs->uvmap[i]].name;
- int len = s->len+1;
- char *p = kp_buf_more(&ls->sb, len);
- p = kp_buf_wmem(p, getstr(s), len);
- setsbufP(&ls->sb, p);
- }
- *ofsvar = sbuflen(&ls->sb);
- lastpc = 0;
-
- for (ve = vs + ls->vtop, vs += fs->vbase; vs < ve; vs++) {
- if (!gola_isgotolabel(vs)) {
- ktap_str_t *s = vs->name;
- BCPos startpc;
- char *p;
- if ((uintptr_t)s < VARNAME__MAX) {
- p = kp_buf_more(&ls->sb, 1 + 2*5);
- *p++ = (char)(uintptr_t)s;
- } else {
- int len = s->len+1;
- p = kp_buf_more(&ls->sb, len + 2*5);
- p = kp_buf_wmem(p, getstr(s), len);
- }
- startpc = vs->startpc;
- p = strfmt_wuleb128(p, startpc-lastpc);
- p = strfmt_wuleb128(p, vs->endpc-startpc);
- setsbufP(&ls->sb, p);
- lastpc = startpc;
- }
- }
- kp_buf_putb(&ls->sb, '\0');
- return sbuflen(&ls->sb);
- }
- static void fs_fixup_var(LexState *ls, ktap_proto_t *pt, uint8_t *p,
- size_t ofsvar)
- {
- pt->uvinfo = p;
- pt->varinfo = (char *)p + ofsvar;
-
- memcpy(p, sbufB(&ls->sb), sbuflen(&ls->sb));
- }
- #else
- #define fs_prep_line(fs, numline) (UNUSED(numline), 0)
- #define fs_fixup_line(fs, pt, li, numline) \
- pt->firstline = pt->numline = 0, (pt)->lineinfo = NULL
- #define fs_prep_var(ls, fs, ofsvar) (UNUSED(ofsvar), 0)
- #define fs_fixup_var(ls, pt, p, ofsvar) \
- (pt)->uvinfo = NULL, (pt)->varinfo = NULL
- #endif
- static int bcopisret(BCOp op)
- {
- switch (op) {
- case BC_CALLMT: case BC_CALLT:
- case BC_RETM: case BC_RET: case BC_RET0: case BC_RET1:
- return 1;
- default:
- return 0;
- }
- }
- static void fs_fixup_ret(FuncState *fs)
- {
- BCPos lastpc = fs->pc;
- if (lastpc <= fs->lasttarget ||
- !bcopisret(bc_op(fs->bcbase[lastpc-1].ins))) {
- if ((fs->bl->flags & FSCOPE_UPVAL))
- bcemit_AJ(fs, BC_UCLO, 0, 0);
- bcemit_AD(fs, BC_RET0, 0, 1);
- }
- fs->bl->flags |= FSCOPE_NOCLOSE;
- fscope_end(fs);
- kp_assert(fs->bl == NULL);
-
- if (fs->flags & PROTO_FIXUP_RETURN) {
- BCPos pc;
- for (pc = 1; pc < lastpc; pc++) {
- BCIns ins = fs->bcbase[pc].ins;
- BCPos offset;
- switch (bc_op(ins)) {
- case BC_CALLMT: case BC_CALLT:
- case BC_RETM: case BC_RET: case BC_RET0: case BC_RET1:
-
- offset = bcemit_INS(fs, ins);
- fs->bcbase[offset].line = fs->bcbase[pc].line;
- offset = offset-(pc+1)+BCBIAS_J;
- if (offset > BCMAX_D)
- err_syntax(fs->ls, KP_ERR_XFIXUP);
-
- fs->bcbase[pc].ins = BCINS_AD(BC_UCLO, 0,
- offset);
- break;
- case BC_UCLO:
- return;
- default:
- break;
- }
- }
- }
- }
- static ktap_proto_t *fs_finish(LexState *ls, BCLine line)
- {
- FuncState *fs = ls->fs;
- BCLine numline = line - fs->linedefined;
- size_t sizept, ofsk, ofsuv, ofsli, ofsdbg, ofsvar;
- ktap_proto_t *pt;
-
- fs_fixup_ret(fs);
-
- sizept = sizeof(ktap_proto_t) + fs->pc*sizeof(BCIns) +
- fs->nkgc*sizeof(ktap_obj_t *);
- sizept = (sizept + sizeof(ktap_val_t)-1) & ~(sizeof(ktap_val_t)-1);
- ofsk = sizept; sizept += fs->nkn*sizeof(ktap_val_t);
- ofsuv = sizept; sizept += ((fs->nuv+1)&~1)*2;
- ofsli = sizept; sizept += fs_prep_line(fs, numline);
- ofsdbg = sizept; sizept += fs_prep_var(ls, fs, &ofsvar);
-
- pt = (ktap_proto_t *)malloc((int)sizept);
- pt->gct = ~KTAP_TPROTO;
- pt->sizept = (int)sizept;
- pt->flags =
- (uint8_t)(fs->flags & ~(PROTO_HAS_RETURN|PROTO_FIXUP_RETURN));
- pt->numparams = fs->numparams;
- pt->framesize = fs->framesize;
- pt->chunkname = ls->chunkname;
-
- *(uint32_t *)((char *)pt + ofsk - sizeof(ktap_obj_t *)*(fs->nkgc+1)) = 0;
- fs_fixup_bc(fs, pt, (BCIns *)((char *)pt + sizeof(ktap_proto_t)), fs->pc);
- fs_fixup_k(fs, pt, (void *)((char *)pt + ofsk));
- fs_fixup_uv1(fs, pt, (uint16_t *)((char *)pt + ofsuv));
- fs_fixup_line(fs, pt, (void *)((char *)pt + ofsli), numline);
- fs_fixup_var(ls, pt, (uint8_t *)((char *)pt + ofsdbg), ofsvar);
- ls->vtop = fs->vbase;
- ls->fs = fs->prev;
- kp_assert(ls->fs != NULL || ls->tok == TK_eof);
- return pt;
- }
- static void fs_init(LexState *ls, FuncState *fs)
- {
- fs->prev = ls->fs; ls->fs = fs;
- fs->ls = ls;
- fs->vbase = ls->vtop;
- fs->pc = 0;
- fs->lasttarget = 0;
- fs->jpc = NO_JMP;
- fs->freereg = 0;
- fs->nkgc = 0;
- fs->nkn = 0;
- fs->nactvar = 0;
- fs->nuv = 0;
- fs->bl = NULL;
- fs->flags = 0;
- fs->framesize = 1;
- fs->kt = kp_tab_new();
- }
- static void expr(LexState *ls, ExpDesc *v);
- static void expr_str(LexState *ls, ExpDesc *e)
- {
- expr_init(e, VKSTR, 0);
- e->u.sval = lex_str(ls);
- }
- #define checku8(x) ((x) == (int32_t)(uint8_t)(x))
- static void expr_index(FuncState *fs, ExpDesc *t, ExpDesc *e)
- {
-
- t->k = VINDEXED;
- if (expr_isnumk(e)) {
- ktap_number n = expr_numberV(e);
- int32_t k = (int)n;
- if (checku8(k) && n == (ktap_number)k) {
-
- t->u.s.aux = BCMAX_C+1+(uint32_t)k;
- return;
- }
- } else if (expr_isstrk(e)) {
- BCReg idx = const_str(fs, e);
- if (idx <= BCMAX_C) {
-
- t->u.s.aux = ~idx;
- return;
- }
- }
- t->u.s.aux = expr_toanyreg(fs, e);
- }
- static void expr_field(LexState *ls, ExpDesc *v)
- {
- FuncState *fs = ls->fs;
- ExpDesc key;
- expr_toanyreg(fs, v);
- kp_lex_next(ls);
- expr_str(ls, &key);
- expr_index(fs, v, &key);
- }
- static void expr_bracket(LexState *ls, ExpDesc *v)
- {
- kp_lex_next(ls);
- expr(ls, v);
- expr_toval(ls->fs, v);
- lex_check(ls, ']');
- }
- static void expr_kvalue(ktap_val_t *v, ExpDesc *e)
- {
- if (e->k <= VKTRUE) {
- setitype(v, ~(uint32_t)e->k);
- } else if (e->k == VKSTR) {
- set_string(v, e->u.sval);
- } else {
- kp_assert(tvisnumber(expr_numtv(e)));
- *v = *expr_numtv(e);
- }
- }
- #define FLS(x) ((uint32_t)(__builtin_clz(x)^31))
- #define hsize2hbits(s) ((s) ? ((s)==1 ? 1 : 1+FLS((uint32_t)((s)-1))) : 0)
- static void expr_table(LexState *ls, ExpDesc *e)
- {
- FuncState *fs = ls->fs;
- BCLine line = ls->linenumber;
- ktap_tab_t *t = NULL;
- int vcall = 0, needarr = 0, fixt = 0;
- uint32_t narr = 1;
- uint32_t nhash = 0;
- BCReg freg = fs->freereg;
- BCPos pc = bcemit_AD(fs, BC_TNEW, freg, 0);
- expr_init(e, VNONRELOC, freg);
- bcreg_reserve(fs, 1);
- freg++;
- lex_check(ls, '{');
- while (ls->tok != '}') {
- ExpDesc key, val;
- vcall = 0;
- if (ls->tok == '[') {
- expr_bracket(ls, &key);
- if (!expr_isk(&key))
- expr_index(fs, e, &key);
- if (expr_isnumk(&key) && expr_numiszero(&key))
- needarr = 1;
- else
- nhash++;
- lex_check(ls, '=');
- } else if ((ls->tok == TK_name) &&
- kp_lex_lookahead(ls) == '=') {
- expr_str(ls, &key);
- lex_check(ls, '=');
- nhash++;
- } else {
- expr_init(&key, VKNUM, 0);
- set_number(&key.u.nval, (int)narr);
- narr++;
- needarr = vcall = 1;
- }
- expr(ls, &val);
- if (expr_isk(&key) && key.k != VKNIL &&
- (key.k == VKSTR || expr_isk_nojump(&val))) {
- ktap_val_t k, *v;
- if (!t) {
- BCReg kidx;
- t = kp_tab_new();
- kidx = const_gc(fs, obj2gco(t), KTAP_TTAB);
- fs->bcbase[pc].ins = BCINS_AD(BC_TDUP, freg-1,
- kidx);
- }
- vcall = 0;
- expr_kvalue(&k, &key);
- v = kp_tab_set(t, &k);
-
- if (expr_isk_nojump(&val)) {
- expr_kvalue(v, &val);
- } else {
-
- set_table(v, t);
- fixt = 1;
- goto nonconst;
- }
- } else {
- nonconst:
- if (val.k != VCALL) {
- expr_toanyreg(fs, &val);
- vcall = 0;
- }
- if (expr_isk(&key))
- expr_index(fs, e, &key);
- bcemit_store(fs, e, &val);
- }
- fs->freereg = freg;
- if (!lex_opt(ls, ',') && !lex_opt(ls, ';'))
- break;
- }
- lex_match(ls, '}', '{', line);
- if (vcall) {
- BCInsLine *ilp = &fs->bcbase[fs->pc-1];
- ExpDesc en;
- kp_assert(bc_a(ilp->ins) == freg &&
- bc_op(ilp->ins) == (narr > 256 ? BC_TSETV : BC_TSETB));
- expr_init(&en, VKNUM, 0);
- set_number(&en.u.nval, narr - 1);
- if (narr > 256) { fs->pc--; ilp--; }
- ilp->ins = BCINS_AD(BC_TSETM, freg, const_num(fs, &en));
- setbc_b(&ilp[-1].ins, 0);
- }
- if (pc == fs->pc-1) {
- e->u.s.info = pc;
- fs->freereg--;
- e->k = VRELOCABLE;
- } else {
- e->k = VNONRELOC;
- }
- if (!t) {
- BCIns *ip = &fs->bcbase[pc].ins;
- if (!needarr) narr = 0;
- else if (narr < 3) narr = 3;
- else if (narr > 0x7ff) narr = 0x7ff;
- setbc_d(ip, narr|(hsize2hbits(nhash)<<11));
- } else {
- if (fixt) {
- ktap_node_t *node = t->node;
- uint32_t i, hmask = t->hmask;
- for (i = 0; i <= hmask; i++) {
- ktap_node_t *n = &node[i];
- if (is_table(&n->val)) {
- kp_assert(tabV(&n->val) == t);
-
- set_nil(&n->val);
- }
- }
- }
- }
- }
- static BCReg parse_params(LexState *ls, int needself)
- {
- FuncState *fs = ls->fs;
- BCReg nparams = 0;
- lex_check(ls, '(');
- if (needself)
- var_new_lit(ls, nparams++, "self");
- if (ls->tok != ')') {
- do {
- if (ls->tok == TK_name) {
- var_new(ls, nparams++, lex_str(ls));
- } else if (ls->tok == TK_dots) {
- kp_lex_next(ls);
- fs->flags |= PROTO_VARARG;
- break;
- } else {
- err_syntax(ls, KP_ERR_XPARAM);
- }
- } while (lex_opt(ls, ','));
- }
- var_add(ls, nparams);
- kp_assert(fs->nactvar == nparams);
- bcreg_reserve(fs, nparams);
- lex_check(ls, ')');
- return nparams;
- }
- static void parse_chunk(LexState *ls);
- static void parse_body(LexState *ls, ExpDesc *e, int needself, BCLine line)
- {
- FuncState fs, *pfs = ls->fs;
- FuncScope bl;
- ktap_proto_t *pt;
- ptrdiff_t oldbase = pfs->bcbase - ls->bcstack;
- fs_init(ls, &fs);
- fscope_begin(&fs, &bl, 0);
- fs.linedefined = line;
- fs.numparams = (uint8_t)parse_params(ls, needself);
- fs.bcbase = pfs->bcbase + pfs->pc;
- fs.bclim = pfs->bclim - pfs->pc;
- bcemit_AD(&fs, BC_FUNCF, 0, 0);
- lex_check(ls, '{');
- parse_chunk(ls);
- lex_check(ls, '}');
- pt = fs_finish(ls, (ls->lastline = ls->linenumber));
- pfs->bcbase = ls->bcstack + oldbase;
- pfs->bclim = (BCPos)(ls->sizebcstack - oldbase);
-
- expr_init(e, VRELOCABLE,
- bcemit_AD(pfs, BC_FNEW, 0,
- const_gc(pfs, (ktap_obj_t *)pt, KTAP_TPROTO)));
- if (!(pfs->flags & PROTO_CHILD)) {
- if (pfs->flags & PROTO_HAS_RETURN)
- pfs->flags |= PROTO_FIXUP_RETURN;
- pfs->flags |= PROTO_CHILD;
- }
-
- }
- static void parse_body_no_args(LexState *ls, ExpDesc *e, int needself,
- BCLine line)
- {
- FuncState fs, *pfs = ls->fs;
- FuncScope bl;
- ktap_proto_t *pt;
- ptrdiff_t oldbase = pfs->bcbase - ls->bcstack;
- fs_init(ls, &fs);
- fscope_begin(&fs, &bl, 0);
- fs.linedefined = line;
- fs.numparams = 0;
- fs.bcbase = pfs->bcbase + pfs->pc;
- fs.bclim = pfs->bclim - pfs->pc;
- bcemit_AD(&fs, BC_FUNCF, 0, 0);
- lex_check(ls, '{');
- parse_chunk(ls);
- lex_check(ls, '}');
- pt = fs_finish(ls, (ls->lastline = ls->linenumber));
- pfs->bcbase = ls->bcstack + oldbase;
- pfs->bclim = (BCPos)(ls->sizebcstack - oldbase);
-
- expr_init(e, VRELOCABLE,
- bcemit_AD(pfs, BC_FNEW, 0,
- const_gc(pfs, (ktap_obj_t *)pt, KTAP_TPROTO)));
- if (!(pfs->flags & PROTO_CHILD)) {
- if (pfs->flags & PROTO_HAS_RETURN)
- pfs->flags |= PROTO_FIXUP_RETURN;
- pfs->flags |= PROTO_CHILD;
- }
-
- }
- static BCReg expr_list(LexState *ls, ExpDesc *v)
- {
- BCReg n = 1;
- expr(ls, v);
- while (lex_opt(ls, ',')) {
- expr_tonextreg(ls->fs, v);
- expr(ls, v);
- n++;
- }
- return n;
- }
- static void parse_args(LexState *ls, ExpDesc *e)
- {
- FuncState *fs = ls->fs;
- ExpDesc args;
- BCIns ins;
- BCReg base;
- BCLine line = ls->linenumber;
- if (ls->tok == '(') {
- if (line != ls->lastline)
- err_syntax(ls, KP_ERR_XAMBIG);
- kp_lex_next(ls);
- if (ls->tok == ')') {
- args.k = VVOID;
- } else {
- expr_list(ls, &args);
-
- if (args.k == VCALL) {
-
- setbc_b(bcptr(fs, &args), 0);
- }
- }
- lex_match(ls, ')', '(', line);
- } else if (ls->tok == '{') {
- expr_table(ls, &args);
- } else if (ls->tok == TK_string) {
- expr_init(&args, VKSTR, 0);
- args.u.sval = rawtsvalue(&ls->tokval);
- kp_lex_next(ls);
- } else {
- err_syntax(ls, KP_ERR_XFUNARG);
- return;
- }
- kp_assert(e->k == VNONRELOC);
- base = e->u.s.info;
- if (args.k == VCALL) {
- ins = BCINS_ABC(BC_CALLM, base, 2, args.u.s.aux - base - 1);
- } else {
- if (args.k != VVOID)
- expr_tonextreg(fs, &args);
- ins = BCINS_ABC(BC_CALL, base, 2, fs->freereg - base);
- }
- expr_init(e, VCALL, bcemit_INS(fs, ins));
- e->u.s.aux = base;
- fs->bcbase[fs->pc - 1].line = line;
- fs->freereg = base+1;
- }
- static void expr_primary(LexState *ls, ExpDesc *v)
- {
- FuncState *fs = ls->fs;
-
- if (ls->tok == '(') {
- BCLine line = ls->linenumber;
- kp_lex_next(ls);
- expr(ls, v);
- lex_match(ls, ')', '(', line);
- expr_discharge(ls->fs, v);
- } else if (ls->tok == TK_name) {
- var_lookup(ls, v);
- } else {
- err_syntax(ls, KP_ERR_XSYMBOL);
- }
- for (;;) {
- if (ls->tok == '.') {
- expr_field(ls, v);
- } else if (ls->tok == '[') {
- ExpDesc key;
- expr_toanyreg(fs, v);
- expr_bracket(ls, &key);
- expr_index(fs, v, &key);
- } else if (ls->tok == ':') {
- ExpDesc key;
- kp_lex_next(ls);
- expr_str(ls, &key);
- bcemit_method(fs, v, &key);
- parse_args(ls, v);
- } else if (ls->tok == '(' || ls->tok == TK_string ||
- ls->tok == '{') {
- expr_tonextreg(fs, v);
- parse_args(ls, v);
- } else {
- break;
- }
- }
- }
- static void expr_simple(LexState *ls, ExpDesc *v)
- {
- switch (ls->tok) {
- case TK_number:
- expr_init(v, VKNUM, 0);
- set_obj(&v->u.nval, &ls->tokval);
- break;
- case TK_string:
- expr_init(v, VKSTR, 0);
- v->u.sval = rawtsvalue(&ls->tokval);
- break;
- case TK_nil:
- expr_init(v, VKNIL, 0);
- break;
- case TK_true:
- expr_init(v, VKTRUE, 0);
- break;
- case TK_false:
- expr_init(v, VKFALSE, 0);
- break;
- case TK_dots: {
- FuncState *fs = ls->fs;
- BCReg base;
- checkcond(ls, fs->flags & PROTO_VARARG, KP_ERR_XDOTS);
- bcreg_reserve(fs, 1);
- base = fs->freereg-1;
- expr_init(v, VCALL, bcemit_ABC(fs, BC_VARG, base, 2,
- fs->numparams));
- v->u.s.aux = base;
- break;
- }
- case '{':
- expr_table(ls, v);
- return;
- case TK_function:
- kp_lex_next(ls);
- parse_body(ls, v, 0, ls->linenumber);
- return;
- case TK_argstr:
- expr_init(v, VARGSTR, 0);
- break;
- case TK_probename:
- expr_init(v, VARGNAME, 0);
- break;
- case TK_arg0: case TK_arg1: case TK_arg2: case TK_arg3: case TK_arg4:
- case TK_arg5: case TK_arg6: case TK_arg7: case TK_arg8: case TK_arg9:
- expr_init(v, VARGN, ls->tok - TK_arg0);
- break;
- case TK_pid:
- expr_init(v, VPID, 0);
- break;
- case TK_tid:
- expr_init(v, VTID, 0);
- break;
- case TK_uid:
- expr_init(v, VUID, 0);
- break;
- case TK_cpu:
- expr_init(v, VCPU, 0);
- break;
- case TK_execname:
- expr_init(v, VEXECNAME, 0);
- break;
- default:
- expr_primary(ls, v);
- return;
- }
- kp_lex_next(ls);
- }
- static void synlevel_begin(LexState *ls)
- {
- if (++ls->level >= KP_MAX_XLEVEL)
- kp_lex_error(ls, 0, KP_ERR_XLEVELS);
- }
- #define synlevel_end(ls) ((ls)->level--)
- static BinOpr token2binop(LexToken tok)
- {
- switch (tok) {
- case '+': return OPR_ADD;
- case '-': return OPR_SUB;
- case '*': return OPR_MUL;
- case '/': return OPR_DIV;
- case '%': return OPR_MOD;
- case '^': return OPR_POW;
- case TK_concat: return OPR_CONCAT;
- case TK_ne: return OPR_NE;
- case TK_eq: return OPR_EQ;
- case '<': return OPR_LT;
- case TK_le: return OPR_LE;
- case '>': return OPR_GT;
- case TK_ge: return OPR_GE;
- case TK_and: return OPR_AND;
- case TK_or: return OPR_OR;
- default: return OPR_NOBINOPR;
- }
- }
- static const struct {
- uint8_t left;
- uint8_t right;
- } priority[] = {
- {6,6}, {6,6}, {7,7}, {7,7}, {7,7},
- {10,9}, {5,4},
- {3,3}, {3,3},
- {3,3}, {3,3}, {3,3}, {3,3},
- {2,2}, {1,1}
- };
- #define UNARY_PRIORITY 8
- static BinOpr expr_binop(LexState *ls, ExpDesc *v, uint32_t limit);
- static void expr_unop(LexState *ls, ExpDesc *v)
- {
- BCOp op;
- if (ls->tok == TK_not) {
- op = BC_NOT;
- } else if (ls->tok == '-') {
- op = BC_UNM;
- #if 0
- #endif
- } else {
- expr_simple(ls, v);
- return;
- }
- kp_lex_next(ls);
- expr_binop(ls, v, UNARY_PRIORITY);
- bcemit_unop(ls->fs, op, v);
- }
- static BinOpr expr_binop(LexState *ls, ExpDesc *v, uint32_t limit)
- {
- BinOpr op;
- synlevel_begin(ls);
- expr_unop(ls, v);
- op = token2binop(ls->tok);
- while (op != OPR_NOBINOPR && priority[op].left > limit) {
- ExpDesc v2;
- BinOpr nextop;
- kp_lex_next(ls);
- bcemit_binop_left(ls->fs, op, v);
-
- nextop = expr_binop(ls, &v2, priority[op].right);
- bcemit_binop(ls->fs, op, v, &v2);
- op = nextop;
- }
- synlevel_end(ls);
- return op;
- }
- static void expr(LexState *ls, ExpDesc *v)
- {
- expr_binop(ls, v, 0);
- }
- static void expr_next(LexState *ls)
- {
- ExpDesc e;
- expr(ls, &e);
- expr_tonextreg(ls->fs, &e);
- }
- static BCPos expr_cond(LexState *ls)
- {
- ExpDesc v;
- lex_check(ls, '(');
- expr(ls, &v);
- if (v.k == VKNIL)
- v.k = VKFALSE;
- bcemit_branch_t(ls->fs, &v);
- lex_check(ls, ')');
- return v.f;
- }
- typedef struct LHSVarList {
- ExpDesc v;
- struct LHSVarList *prev;
- } LHSVarList;
- static void assign_hazard(LexState *ls, LHSVarList *lh, const ExpDesc *v)
- {
- FuncState *fs = ls->fs;
- BCReg reg = v->u.s.info;
- BCReg tmp = fs->freereg;
- int hazard = 0;
- for (; lh; lh = lh->prev) {
- if (lh->v.k == VINDEXED) {
- if (lh->v.u.s.info == reg) {
- hazard = 1;
- lh->v.u.s.info = tmp;
- }
- if (lh->v.u.s.aux == reg) {
- hazard = 1;
- lh->v.u.s.aux = tmp;
- }
- }
- }
- if (hazard) {
-
- bcemit_AD(fs, BC_MOV, tmp, reg);
- bcreg_reserve(fs, 1);
- }
- }
- static void assign_adjust(LexState *ls, BCReg nvars, BCReg nexps, ExpDesc *e)
- {
- FuncState *fs = ls->fs;
- int32_t extra = (int32_t)nvars - (int32_t)nexps;
- if (e->k == VCALL) {
- extra++;
- if (extra < 0)
- extra = 0;
- setbc_b(bcptr(fs, e), extra+1);
- if (extra > 1)
- bcreg_reserve(fs, (BCReg)extra-1);
- } else {
- if (e->k != VVOID)
- expr_tonextreg(fs, e);
- if (extra > 0) {
- BCReg reg = fs->freereg;
- bcreg_reserve(fs, (BCReg)extra);
- bcemit_nil(fs, reg, (BCReg)extra);
- }
- }
- }
- static void parse_assignment(LexState *ls, LHSVarList *lh, BCReg nvars)
- {
- ExpDesc e;
- checkcond(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED,
- KP_ERR_XSYNTAX);
- if (lex_opt(ls, ',')) {
- LHSVarList vl;
- vl.prev = lh;
- expr_primary(ls, &vl.v);
- if (vl.v.k == VLOCAL)
- assign_hazard(ls, lh, &vl.v);
- checklimit(ls->fs, ls->level + nvars, KP_MAX_XLEVEL,
- "variable names");
- parse_assignment(ls, &vl, nvars+1);
- } else {
- BCReg nexps;
- int assign_incr = 1;
- if (lex_opt(ls, '='))
- assign_incr = 0;
- else if (lex_opt(ls, TK_incr))
- assign_incr = 1;
- else
- err_syntax(ls, KP_ERR_XSYMBOL);
- nexps = expr_list(ls, &e);
- if (nexps == nvars) {
- if (e.k == VCALL) {
-
- if (bc_op(*bcptr(ls->fs, &e)) == BC_VARG) {
- ls->fs->freereg--;
- e.k = VRELOCABLE;
- } else {
-
- e.u.s.info = e.u.s.aux;
- e.k = VNONRELOC;
- }
- }
- if (assign_incr == 0)
- bcemit_store(ls->fs, &lh->v, &e);
- else
- bcemit_store_incr(ls->fs, &lh->v, &e);
- return;
- }
- assign_adjust(ls, nvars, nexps, &e);
- if (nexps > nvars) {
-
- ls->fs->freereg -= nexps - nvars;
- }
- }
-
- expr_init(&e, VNONRELOC, ls->fs->freereg-1);
- bcemit_store(ls->fs, &lh->v, &e);
- }
- static void parse_call_assign(LexState *ls)
- {
- FuncState *fs = ls->fs;
- LHSVarList vl;
- expr_primary(ls, &vl.v);
- if (vl.v.k == VCALL) {
- setbc_b(bcptr(fs, &vl.v), 1);
- } else {
- vl.prev = NULL;
- parse_assignment(ls, &vl, 1);
- }
- }
- static void parse_local(LexState *ls)
- {
- if (lex_opt(ls, TK_function)) {
- ExpDesc v, b;
- FuncState *fs = ls->fs;
- var_new(ls, 0, lex_str(ls));
- expr_init(&v, VLOCAL, fs->freereg);
- v.u.s.aux = fs->varmap[fs->freereg];
- bcreg_reserve(fs, 1);
- var_add(ls, 1);
- parse_body(ls, &b, 0, ls->linenumber);
-
- expr_free(fs, &b);
- expr_toreg(fs, &b, v.u.s.info);
-
- var_get(ls, fs, fs->nactvar - 1).startpc = fs->pc;
- } else {
- ExpDesc e;
- BCReg nexps, nvars = 0;
- do {
- var_new(ls, nvars++, lex_str(ls));
- } while (lex_opt(ls, ','));
- if (lex_opt(ls, '=')) {
- nexps = expr_list(ls, &e);
- } else {
- e.k = VVOID;
- nexps = 0;
- }
- assign_adjust(ls, nvars, nexps, &e);
- var_add(ls, nvars);
- }
- }
- static void parse_func(LexState *ls, BCLine line)
- {
- FuncState *fs = ls->fs;
- ExpDesc v, b;
- kp_lex_next(ls);
-
- #if 1
- var_new(ls, 0, lex_str(ls));
- expr_init(&v, VLOCAL, fs->freereg);
- v.u.s.aux = fs->varmap[fs->freereg];
- bcreg_reserve(fs, 1);
- var_add(ls, 1);
- parse_body(ls, &b, 0, ls->linenumber);
-
- expr_free(fs, &b);
- expr_toreg(fs, &b, v.u.s.info);
-
- var_get(ls, fs, fs->nactvar - 1).startpc = fs->pc;
- #else
- #endif
- }
- static int parse_isend(LexToken tok)
- {
- switch (tok) {
- case TK_else: case TK_elseif: case TK_end: case TK_until: case TK_eof:
- case '}':
- return 1;
- default:
- return 0;
- }
- }
- static void parse_return(LexState *ls)
- {
- BCIns ins;
- FuncState *fs = ls->fs;
- kp_lex_next(ls);
- fs->flags |= PROTO_HAS_RETURN;
- if (parse_isend(ls->tok) || ls->tok == ';') {
- ins = BCINS_AD(BC_RET0, 0, 1);
- } else {
- ExpDesc e;
- BCReg nret = expr_list(ls, &e);
- if (nret == 1) {
- if (e.k == VCALL) {
- BCIns *ip = bcptr(fs, &e);
-
- if (bc_op(*ip) == BC_VARG)
- goto notailcall;
- fs->pc--;
- ins = BCINS_AD(bc_op(*ip)-BC_CALL+BC_CALLT,
- bc_a(*ip), bc_c(*ip));
- } else {
- ins = BCINS_AD(BC_RET1,
- expr_toanyreg(fs, &e), 2);
- }
- } else {
- if (e.k == VCALL) {
- notailcall:
- setbc_b(bcptr(fs, &e), 0);
- ins = BCINS_AD(BC_RETM, fs->nactvar,
- e.u.s.aux - fs->nactvar);
- } else {
-
- expr_tonextreg(fs, &e);
- ins = BCINS_AD(BC_RET, fs->nactvar, nret+1);
- }
- }
- }
- if (fs->flags & PROTO_CHILD) {
-
- bcemit_AJ(fs, BC_UCLO, 0, 0);
- }
- bcemit_INS(fs, ins);
- }
- static void parse_break(LexState *ls)
- {
- ls->fs->bl->flags |= FSCOPE_BREAK;
- gola_new(ls, NAME_BREAK, VSTACK_GOTO, bcemit_jmp(ls->fs));
- }
- static void parse_label(LexState *ls)
- {
- FuncState *fs = ls->fs;
- ktap_str_t *name;
- int idx;
- fs->lasttarget = fs->pc;
- fs->bl->flags |= FSCOPE_GOLA;
- kp_lex_next(ls);
- name = lex_str(ls);
- if (gola_findlabel(ls, name))
- kp_lex_error(ls, 0, KP_ERR_XLDUP, getstr(name));
- idx = gola_new(ls, name, VSTACK_LABEL, fs->pc);
- lex_check(ls, TK_label);
-
- for (;;) {
- if (ls->tok == TK_label) {
- synlevel_begin(ls);
- parse_label(ls);
- synlevel_end(ls);
- } else if (ls->tok == ';') {
- kp_lex_next(ls);
- } else {
- break;
- }
- }
-
- if (parse_isend(ls->tok) && ls->tok != TK_until)
- ls->vstack[idx].slot = fs->bl->nactvar;
- gola_resolve(ls, fs->bl, idx);
- }
- static void parse_block(LexState *ls)
- {
- FuncState *fs = ls->fs;
- FuncScope bl;
- fscope_begin(fs, &bl, 0);
- parse_chunk(ls);
- fscope_end(fs);
- }
- static void parse_while(LexState *ls, BCLine line)
- {
- FuncState *fs = ls->fs;
- BCPos start, loop, condexit;
- FuncScope bl;
- kp_lex_next(ls);
- start = fs->lasttarget = fs->pc;
- condexit = expr_cond(ls);
- fscope_begin(fs, &bl, FSCOPE_LOOP);
-
- lex_check(ls, '{');
- loop = bcemit_AD(fs, BC_LOOP, fs->nactvar, 0);
- parse_block(ls);
- jmp_patch(fs, bcemit_jmp(fs), start);
-
- lex_check(ls, '}');
- fscope_end(fs);
- jmp_tohere(fs, condexit);
- jmp_patchins(fs, loop, fs->pc);
- }
- static void parse_repeat(LexState *ls, BCLine line)
- {
- FuncState *fs = ls->fs;
- BCPos loop = fs->lasttarget = fs->pc;
- BCPos condexit;
- FuncScope bl1, bl2;
- fscope_begin(fs, &bl1, FSCOPE_LOOP);
- fscope_begin(fs, &bl2, 0);
- kp_lex_next(ls);
- bcemit_AD(fs, BC_LOOP, fs->nactvar, 0);
- parse_chunk(ls);
- lex_match(ls, TK_until, TK_repeat, line);
-
- condexit = expr_cond(ls);
-
- if (!(bl2.flags & FSCOPE_UPVAL)) {
- fscope_end(fs);
- } else {
-
- parse_break(ls);
- jmp_tohere(fs, condexit);
- fscope_end(fs);
- condexit = bcemit_jmp(fs);
- }
- jmp_patch(fs, condexit, loop);
- jmp_patchins(fs, loop, fs->pc);
- fscope_end(fs);
- }
- static void parse_for_num(LexState *ls, ktap_str_t *varname, BCLine line)
- {
- FuncState *fs = ls->fs;
- BCReg base = fs->freereg;
- FuncScope bl;
- BCPos loop, loopend;
-
- var_new_fixed(ls, FORL_IDX, VARNAME_FOR_IDX);
- var_new_fixed(ls, FORL_STOP, VARNAME_FOR_STOP);
- var_new_fixed(ls, FORL_STEP, VARNAME_FOR_STEP);
-
- var_new(ls, FORL_EXT, varname);
- lex_check(ls, '=');
- expr_next(ls);
- lex_check(ls, ',');
- expr_next(ls);
- if (lex_opt(ls, ',')) {
- expr_next(ls);
- } else {
-
- bcemit_AD(fs, BC_KSHORT, fs->freereg, 1);
- bcreg_reserve(fs, 1);
- }
- var_add(ls, 3);
-
- lex_check(ls, ')');
- lex_check(ls, '{');
- loop = bcemit_AJ(fs, BC_FORI, base, NO_JMP);
- fscope_begin(fs, &bl, 0);
- var_add(ls, 1);
- bcreg_reserve(fs, 1);
- parse_block(ls);
- fscope_end(fs);
-
- loopend = bcemit_AJ(fs, BC_FORL, base, NO_JMP);
- fs->bcbase[loopend].line = line;
- jmp_patchins(fs, loopend, loop+1);
- jmp_patchins(fs, loop, fs->pc);
- }
- static int predict_next(LexState *ls, FuncState *fs, BCPos pc)
- {
- BCIns ins = fs->bcbase[pc].ins;
- ktap_str_t *name;
- const ktap_val_t *o;
- switch (bc_op(ins)) {
- case BC_MOV:
- name = var_get(ls, fs, bc_d(ins)).name;
- break;
- case BC_UGET:
- name = ls->vstack[fs->uvmap[bc_d(ins)]].name;
- break;
- case BC_GGET:
-
- o = kp_tab_getstr(fs->kt, kp_str_newz("pairs"));
- if (o && tvhaskslot(o) && tvkslot(o) == bc_d(ins))
- return 1;
- o = kp_tab_getstr(fs->kt, kp_str_newz("next"));
- if (o && tvhaskslot(o) && tvkslot(o) == bc_d(ins))
- return 1;
- return 0;
- default:
- return 0;
- }
- return (name->len == 5 && !strcmp(getstr(name), "pairs")) ||
- (name->len == 4 && !strcmp(getstr(name), "next"));
- }
- static void parse_for_iter(LexState *ls, ktap_str_t *indexname)
- {
- FuncState *fs = ls->fs;
- ExpDesc e;
- BCReg nvars = 0;
- BCLine line;
- BCReg base = fs->freereg + 3;
- BCPos loop, loopend, exprpc = fs->pc;
- FuncScope bl;
- int isnext;
-
- var_new_fixed(ls, nvars++, VARNAME_FOR_GEN);
- var_new_fixed(ls, nvars++, VARNAME_FOR_STATE);
- var_new_fixed(ls, nvars++, VARNAME_FOR_CTL);
-
- var_new(ls, nvars++, indexname);
- while (lex_opt(ls, ','))
- var_new(ls, nvars++, lex_str(ls));
- lex_check(ls, TK_in);
- line = ls->linenumber;
- assign_adjust(ls, 3, expr_list(ls, &e), &e);
-
- bcreg_bump(fs, 3);
- isnext = (nvars <= 5 && predict_next(ls, fs, exprpc));
- var_add(ls, 3);
-
- lex_check(ls, ')');
- lex_check(ls, '{');
- loop = bcemit_AJ(fs, isnext ? BC_ISNEXT : BC_JMP, base, NO_JMP);
- fscope_begin(fs, &bl, 0);
- var_add(ls, nvars-3);
- bcreg_reserve(fs, nvars-3);
- parse_block(ls);
- fscope_end(fs);
-
- jmp_patchins(fs, loop, fs->pc);
- bcemit_ABC(fs, isnext ? BC_ITERN : BC_ITERC, base, nvars-3+1, 2+1);
- loopend = bcemit_AJ(fs, BC_ITERL, base, NO_JMP);
- fs->bcbase[loopend-1].line = line;
- fs->bcbase[loopend].line = line;
- jmp_patchins(fs, loopend, loop+1);
- }
- static void parse_for(LexState *ls, BCLine line)
- {
- FuncState *fs = ls->fs;
- ktap_str_t *varname;
- FuncScope bl;
- fscope_begin(fs, &bl, FSCOPE_LOOP);
- kp_lex_next(ls);
- lex_check(ls, '(');
- varname = lex_str(ls);
- if (ls->tok == '=')
- parse_for_num(ls, varname, line);
- else if (ls->tok == ',' || ls->tok == TK_in)
- parse_for_iter(ls, varname);
- else
- err_syntax(ls, KP_ERR_XFOR);
-
-
- lex_match(ls, '}', TK_for, line);
- fscope_end(fs);
- }
- static BCPos parse_then(LexState *ls)
- {
- BCPos condexit;
- kp_lex_next(ls);
- condexit = expr_cond(ls);
- lex_check(ls, '{');
- parse_block(ls);
- lex_check(ls, '}');
- return condexit;
- }
- static void parse_if(LexState *ls, BCLine line)
- {
- FuncState *fs = ls->fs;
- BCPos flist;
- BCPos escapelist = NO_JMP;
- flist = parse_then(ls);
- while (ls->tok == TK_elseif) {
- jmp_append(fs, &escapelist, bcemit_jmp(fs));
- jmp_tohere(fs, flist);
- flist = parse_then(ls);
- }
- if (ls->tok == TK_else) {
- jmp_append(fs, &escapelist, bcemit_jmp(fs));
- jmp_tohere(fs, flist);
- kp_lex_next(ls);
- lex_check(ls, '{');
- parse_block(ls);
- lex_check(ls, '}');
- } else {
- jmp_append(fs, &escapelist, flist);
- }
- jmp_tohere(fs, escapelist);
-
- }
- static void parse_trace(LexState *ls)
- {
- ExpDesc v, key, args;
- ktap_str_t *kdebug_str = kp_str_newz("kdebug");
- ktap_str_t *probe_str = kp_str_newz("trace_by_id");
- ktap_str_t *probe_end_str = kp_str_newz("trace_end");
- FuncState *fs = ls->fs;
- int token = ls->tok;
- BCIns ins;
- BCReg base;
- BCLine line = ls->linenumber;
- if (token == TK_trace)
- kp_lex_read_string_until(ls, '{');
- else
- kp_lex_next(ls);
-
- expr_init(&v, VGLOBAL, 0);
- v.u.sval = kdebug_str;
- expr_toanyreg(fs, &v);
-
- expr_init(&key, VKSTR, 0);
- key.u.sval = token == TK_trace ? probe_str : probe_end_str;
- expr_index(fs, &v, &key);
-
- expr_tonextreg(fs, &v);
- if (token == TK_trace) {
- ktap_eventdesc_t *evdef_info;
- const char *str;
-
- lex_check(ls, TK_string);
- str = svalue(&ls->tokval);
- evdef_info = kp_parse_events(str);
- if (!evdef_info)
- kp_lex_error(ls, 0, KP_ERR_XEVENTDEF, str);
-
- expr_init(&args, VKNUM, 0);
- set_number(&args.u.nval, (ktap_number)evdef_info);
- expr_tonextreg(fs, &args);
- }
-
- parse_body_no_args(ls, &args, 0, ls->linenumber);
- expr_tonextreg(fs, &args);
- base = v.u.s.info;
- ins = BCINS_ABC(BC_CALL, base, 2, fs->freereg - base);
- expr_init(&v, VCALL, bcemit_INS(fs, ins));
- v.u.s.aux = base;
- fs->bcbase[fs->pc - 1].line = line;
- fs->freereg = base+1;
- setbc_b(bcptr(fs, &v), 1);
- }
- static void parse_timer(LexState *ls)
- {
- FuncState *fs = ls->fs;
- ExpDesc v, key, args;
- ktap_str_t *token_str = rawtsvalue(&ls->tokval);
- ktap_str_t *interval_str;
- BCLine line = ls->linenumber;
- BCIns ins;
- BCReg base;
- kp_lex_next(ls);
- kp_lex_read_string_until(ls, '{');
- interval_str = rawtsvalue(&ls->tokval);
- lex_check(ls, TK_string);
-
- expr_init(&v, VGLOBAL, 0);
- v.u.sval = kp_str_newz("timer");
- expr_toanyreg(fs, &v);
-
- expr_init(&key, VKSTR, 0);
- key.u.sval = token_str;
- expr_index(fs, &v, &key);
-
- expr_tonextreg(fs, &v);
-
- expr_init(&args, VKSTR, 0);
- args.u.sval = interval_str;
- expr_tonextreg(fs, &args);
-
- parse_body_no_args(ls, &args, 0, ls->linenumber);
- expr_tonextreg(fs, &args);
- base = v.u.s.info;
- ins = BCINS_ABC(BC_CALL, base, 2, fs->freereg - base);
- expr_init(&v, VCALL, bcemit_INS(fs, ins));
- v.u.s.aux = base;
- fs->bcbase[fs->pc - 1].line = line;
- fs->freereg = base+1;
- setbc_b(bcptr(fs, &v), 1);
- }
- static int parse_stmt(LexState *ls)
- {
- BCLine line = ls->linenumber;
- switch (ls->tok) {
- case TK_if:
- parse_if(ls, line);
- break;
- case TK_while:
- parse_while(ls, line);
- break;
- case TK_do:
- kp_lex_next(ls);
- parse_block(ls);
- lex_match(ls, TK_end, TK_do, line);
- break;
- case TK_for:
- parse_for(ls, line);
- break;
- case TK_repeat:
- parse_repeat(ls, line);
- break;
- case TK_function:
- parse_func(ls, line);
- break;
- case TK_local:
- kp_lex_next(ls);
- parse_local(ls);
- break;
- case TK_return:
- parse_return(ls);
- return 1;
- case TK_break:
- kp_lex_next(ls);
- parse_break(ls);
- return 0;
- case ';':
- kp_lex_next(ls);
- break;
- case TK_label:
- parse_label(ls);
- break;
- case TK_trace:
- case TK_trace_end:
- parse_trace(ls);
- break;
- case TK_profile:
- case TK_tick:
- parse_timer(ls);
- break;
- default:
- parse_call_assign(ls);
- break;
- }
- return 0;
- }
- static void parse_chunk(LexState *ls)
- {
- int islast = 0;
- synlevel_begin(ls);
- while (!islast && !parse_isend(ls->tok)) {
- islast = parse_stmt(ls);
- lex_opt(ls, ';');
- kp_assert(ls->fs->framesize >= ls->fs->freereg &&
- ls->fs->freereg >= ls->fs->nactvar);
-
- ls->fs->freereg = ls->fs->nactvar;
- }
- synlevel_end(ls);
- }
- ktap_proto_t *kp_parse(LexState *ls)
- {
- FuncState fs;
- FuncScope bl;
- ktap_proto_t *pt;
- ls->chunkname = kp_str_newz(ls->chunkarg);
- ls->level = 0;
- fs_init(ls, &fs);
- fs.linedefined = 0;
- fs.numparams = 0;
- fs.bcbase = NULL;
- fs.bclim = 0;
- fs.flags |= PROTO_VARARG;
- fscope_begin(&fs, &bl, 0);
- bcemit_AD(&fs, BC_FUNCV, 0, 0);
- kp_lex_next(ls);
- parse_chunk(ls);
- if (ls->tok != TK_eof)
- err_token(ls, TK_eof);
- pt = fs_finish(ls, ls->linenumber);
- kp_assert(fs.prev == NULL);
- kp_assert(ls->fs == NULL);
- kp_assert(pt->sizeuv == 0);
- return pt;
- }
One Level Up
Top Level