const TObject *luaH_get (lua_State *L, const Hash *t, const TObject *key) { switch (ttype(key)) { case LUA_TNUMBER: return luaH_getnum(t, nvalue(key)); case LUA_TSTRING: return luaH_getstr(t, tsvalue(key)); default: return luaH_getany(L, t, key); } }
LUA_API void lua_rawgeti (lua_State *L, int idx, int n) { StkId o; lua_lock(L); o = luaA_index(L, idx); api_check(L, ttistable(o)); setobj2s(L->top, luaH_getnum(hvalue(o), n)); api_incr_top(L); lua_unlock(L); }
/* ** try to remove a key without value from a table. To avoid problems with ** hash, change `key' for a number with the same hash. */ void luaH_remove (Hash *t, TObject *key) { if (ttype(key) == LUA_TNUMBER || (ttype(key) == LUA_TSTRING && tsvalue(key)->len <= 30)) return; /* do not remove numbers nor small strings */ else { /* try to find a number `n' with the same hash as `key' */ Node *mp = luaH_mainposition(t, key); int n = mp - &t->node[0]; /* make sure `n' is not in `t' */ while (luaH_getnum(t, n) != &luaO_nilobject) { if (n >= MAX_INT - t->size) return; /* give up; (to avoid overflow) */ n += t->size; } ttype(key) = LUA_TNUMBER; nvalue(key) = n; LUA_ASSERT(luaH_mainposition(t, key) == mp, "cannot change hash"); } }
TObject *negindex (lua_State *L, int idx) { if (idx > LUA_REGISTRYINDEX) { api_check(L, idx != 0 && -idx <= L->top - L->base); return L->top+idx; } else if (idx < -40000) { return (TObject*)luaH_getnum(hvalue(registry(L)), -idx - 40000); } else switch (idx) { /* pseudo-indices */ case LUA_REGISTRYINDEX: return registry(L); case LUA_GLOBALSINDEX: return gt(L); default: { TObject *func = (L->base - 1); idx = LUA_GLOBALSINDEX - idx; lua_assert(iscfunction(func)); return (idx <= clvalue(func)->c.nupvalues) ? &clvalue(func)->c.upvalue[idx-1] : NULL; } } }
LUA_API void lua_rawgeti (lua_State *L, int index, int n) { StkId o = Index(L, index); LUA_ASSERT(ttype(o) == LUA_TTABLE, "table expected"); *L->top = *luaH_getnum(hvalue(o), n); api_incr_top(L); }
/* ** Executes the given Lua function. Parameters are between [base,top). ** Returns n such that the the results are between [n,top). */ StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) { const Proto *const tf = cl->f.l; StkId top; /* keep top local, for performance */ const Instruction *pc = tf->code; TString **const kstr = tf->kstr; const lua_Hook linehook = L->linehook; infovalue(base-1)->pc = &pc; luaD_checkstack(L, tf->maxstacksize+EXTRA_STACK); if (tf->is_vararg) /* varargs? */ adjust_varargs(L, base, tf->numparams); else luaD_adjusttop(L, base, tf->numparams); top = L->top; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; if (linehook) traceexec(L, base, top, linehook); switch (GET_OPCODE(i)) { case OP_END: { L->top = top; return top; } case OP_RETURN: { L->top = top; return base+GETARG_U(i); } case OP_CALL: { int nres = GETARG_B(i); if (nres == MULT_RET) nres = LUA_MULTRET; L->top = top; luaD_call(L, base+GETARG_A(i), nres); top = L->top; break; } case OP_TAILCALL: { L->top = top; luaD_call(L, base+GETARG_A(i), LUA_MULTRET); return base+GETARG_B(i); } case OP_PUSHNIL: { int n = GETARG_U(i); LUA_ASSERT(n>0, "invalid argument"); do { ttype(top++) = LUA_TNIL; } while (--n > 0); break; } case OP_POP: { top -= GETARG_U(i); break; } case OP_PUSHINT: { ttype(top) = LUA_TNUMBER; nvalue(top) = (Number)GETARG_S(i); top++; break; } case OP_PUSHSTRING: { ttype(top) = LUA_TSTRING; tsvalue(top) = kstr[GETARG_U(i)]; top++; break; } case OP_PUSHNUM: { ttype(top) = LUA_TNUMBER; nvalue(top) = tf->knum[GETARG_U(i)]; top++; break; } case OP_PUSHNEGNUM: { ttype(top) = LUA_TNUMBER; nvalue(top) = -tf->knum[GETARG_U(i)]; top++; break; } case OP_PUSHUPVALUE: { *top++ = cl->upvalue[GETARG_U(i)]; break; } case OP_GETLOCAL: { *top++ = *(base+GETARG_U(i)); break; } case OP_GETGLOBAL: { L->top = top; *top = *luaV_getglobal(L, kstr[GETARG_U(i)]); top++; break; } case OP_GETTABLE: { L->top = top; top--; *(top-1) = *luaV_gettable(L, top-1); break; } case OP_GETDOTTED: { ttype(top) = LUA_TSTRING; tsvalue(top) = kstr[GETARG_U(i)]; L->top = top+1; *(top-1) = *luaV_gettable(L, top-1); break; } case OP_GETINDEXED: { *top = *(base+GETARG_U(i)); L->top = top+1; *(top-1) = *luaV_gettable(L, top-1); break; } case OP_PUSHSELF: { TObject receiver; receiver = *(top-1); ttype(top) = LUA_TSTRING; tsvalue(top++) = kstr[GETARG_U(i)]; L->top = top; *(top-2) = *luaV_gettable(L, top-2); *(top-1) = receiver; break; } case OP_CREATETABLE: { L->top = top; luaC_checkGC(L); hvalue(top) = luaH_new(L, GETARG_U(i)); ttype(top) = LUA_TTABLE; top++; break; } case OP_SETLOCAL: { *(base+GETARG_U(i)) = *(--top); break; } case OP_SETGLOBAL: { L->top = top; luaV_setglobal(L, kstr[GETARG_U(i)]); top--; break; } case OP_SETTABLE: { StkId t = top-GETARG_A(i); L->top = top; luaV_settable(L, t, t+1); top -= GETARG_B(i); /* pop values */ break; } case OP_SETLIST: { int aux = GETARG_A(i) * LFIELDS_PER_FLUSH; int n = GETARG_B(i); Hash *arr = hvalue(top-n-1); L->top = top-n; /* final value of `top' (in case of errors) */ for (; n; n--) *luaH_setint(L, arr, n+aux) = *(--top); break; } case OP_SETMAP: { int n = GETARG_U(i); StkId finaltop = top-2*n; Hash *arr = hvalue(finaltop-1); L->top = finaltop; /* final value of `top' (in case of errors) */ for (; n; n--) { top-=2; *luaH_set(L, arr, top) = *(top+1); } break; } case OP_ADD: { if (tonumber(top-2) || tonumber(top-1)) call_arith(L, top, TM_ADD); else nvalue(top-2) += nvalue(top-1); top--; break; } case OP_ADDI: { if (tonumber(top-1)) { ttype(top) = LUA_TNUMBER; nvalue(top) = (Number)GETARG_S(i); call_arith(L, top+1, TM_ADD); } else nvalue(top-1) += (Number)GETARG_S(i); break; } case OP_SUB: { if (tonumber(top-2) || tonumber(top-1)) call_arith(L, top, TM_SUB); else nvalue(top-2) -= nvalue(top-1); top--; break; } case OP_MULT: { if (tonumber(top-2) || tonumber(top-1)) call_arith(L, top, TM_MUL); else nvalue(top-2) *= nvalue(top-1); top--; break; } case OP_DIV: { if (tonumber(top-2) || tonumber(top-1)) call_arith(L, top, TM_DIV); else nvalue(top-2) /= nvalue(top-1); top--; break; } case OP_POW: { if (!call_binTM(L, top, TM_POW)) lua_error(L, "undefined operation"); top--; break; } /* DG -- Add binary operations */ case OP_BAND: { if (tonumber(top-2) || tonumber(top-1)) call_arith(L, top, TM_BAND); else nvalue(top-2) &= nvalue(top-1); top--; break; } case OP_BOR: { if (tonumber(top-2) || tonumber(top-1)) call_arith(L, top, TM_BOR); else nvalue(top-2) |= nvalue(top-1); top--; break; } case OP_BXOR: { if (tonumber(top-2) || tonumber(top-1)) call_arith(L, top, TM_BXOR); else nvalue(top-2) ^= nvalue(top-1); top--; break; } case OP_BNOT: { if (tonumber(top-1)) { ttype(top) = LUA_TNIL; call_arith(L, top+1, TM_BNOT); } else nvalue(top-1) = ~ nvalue(top-1); break; } case OP_CONCAT: { int n = GETARG_U(i); luaV_strconc(L, n, top); top -= n-1; L->top = top; luaC_checkGC(L); break; } case OP_MINUS: { if (tonumber(top-1)) { ttype(top) = LUA_TNIL; call_arith(L, top+1, TM_UNM); } else nvalue(top-1) = -nvalue(top-1); break; } case OP_NOT: { ttype(top-1) = (ttype(top-1) == LUA_TNIL) ? LUA_TNUMBER : LUA_TNIL; nvalue(top-1) = 1; break; } case OP_JMPNE: { top -= 2; if (!luaO_equalObj(top, top+1)) dojump(pc, i); break; } case OP_JMPEQ: { top -= 2; if (luaO_equalObj(top, top+1)) dojump(pc, i); break; } case OP_JMPLT: { top -= 2; if (luaV_lessthan(L, top, top+1, top+2)) dojump(pc, i); break; } case OP_JMPLE: { /* a <= b === !(b<a) */ top -= 2; if (!luaV_lessthan(L, top+1, top, top+2)) dojump(pc, i); break; } case OP_JMPGT: { /* a > b === (b<a) */ top -= 2; if (luaV_lessthan(L, top+1, top, top+2)) dojump(pc, i); break; } case OP_JMPGE: { /* a >= b === !(a<b) */ top -= 2; if (!luaV_lessthan(L, top, top+1, top+2)) dojump(pc, i); break; } case OP_JMPT: { if (ttype(--top) != LUA_TNIL) dojump(pc, i); break; } case OP_JMPF: { if (ttype(--top) == LUA_TNIL) dojump(pc, i); break; } case OP_JMPONT: { if (ttype(top-1) == LUA_TNIL) top--; else dojump(pc, i); break; } case OP_JMPONF: { if (ttype(top-1) != LUA_TNIL) top--; else dojump(pc, i); break; } case OP_JMP: { dojump(pc, i); break; } case OP_PUSHNILJMP: { ttype(top++) = LUA_TNIL; pc++; break; } case OP_FORPREP: { if (tonumber(top-1)) lua_error(L, "`for' step must be a number"); if (tonumber(top-2)) lua_error(L, "`for' limit must be a number"); if (tonumber(top-3)) lua_error(L, "`for' initial value must be a number"); if (nvalue(top-1) > 0 ? nvalue(top-3) > nvalue(top-2) : nvalue(top-3) < nvalue(top-2)) { /* `empty' loop? */ top -= 3; /* remove control variables */ dojump(pc, i); /* jump to loop end */ } break; } case OP_FORLOOP: { LUA_ASSERT(ttype(top-1) == LUA_TNUMBER, "invalid step"); LUA_ASSERT(ttype(top-2) == LUA_TNUMBER, "invalid limit"); if (ttype(top-3) != LUA_TNUMBER) lua_error(L, "`for' index must be a number"); nvalue(top-3) += nvalue(top-1); /* increment index */ if (nvalue(top-1) > 0 ? nvalue(top-3) > nvalue(top-2) : nvalue(top-3) < nvalue(top-2)) top -= 3; /* end loop: remove control variables */ else dojump(pc, i); /* repeat loop */ break; } case OP_LFORPREP: { Node *node; if (ttype(top-1) != LUA_TTABLE) lua_error(L, "`for' table must be a table"); node = luaH_next(L, hvalue(top-1), &luaO_nilobject); if (node == NULL) { /* `empty' loop? */ top--; /* remove table */ dojump(pc, i); /* jump to loop end */ } else { top += 2; /* index,value */ *(top-2) = *key(node); *(top-1) = *val(node); } break; } case OP_LFORLOOP: { Node *node; LUA_ASSERT(ttype(top-3) == LUA_TTABLE, "invalid table"); node = luaH_next(L, hvalue(top-3), top-2); if (node == NULL) /* end loop? */ top -= 3; /* remove table, key, and value */ else { *(top-2) = *key(node); *(top-1) = *val(node); dojump(pc, i); /* repeat loop */ } break; } case OP_CLOSURE: { L->top = top; luaV_Lclosure(L, tf->kproto[GETARG_A(i)], GETARG_B(i)); top = L->top; luaC_checkGC(L); break; } case OP_LISTFORPREP: { const Hash *h = hvalue(top-1); int n; if (ttype(top-1) != LUA_TTABLE) lua_error(L, "`for' table must be a table"); /* find n (copied from lua_getn, should factor this out) */ { const TObject *value = luaH_getstr(h, luaS_new(L, "n")); if (ttype(value) == LUA_TNUMBER) n = nvalue(value); else { Number max = 0; int i = h->size; Node *node = h->node; while (i--) { if (ttype(key(node)) == LUA_TNUMBER && ttype(val(node)) != LUA_TNIL && nvalue(key(node)) > max) max = nvalue(key(node)); node++; } n = (int)max; } } if (n < 1) { /* `empty' loop? */ top--; /* remove table */ dojump(pc, i); /* jump to loop end */ } else { top += 3; /* n, index, value */ ttype(top-3) = LUA_TNUMBER; nvalue(top-3) = n; ttype(top-2) = LUA_TNUMBER; nvalue(top-2) = 1; *(top-1) = *luaH_getnum(h, 1); } break; } case OP_LISTFORLOOP: { LUA_ASSERT(ttype(top-4) == LUA_TTABLE, "invalid table"); LUA_ASSERT(ttype(top-3) == LUA_TNUMBER, "invalid n"); LUA_ASSERT(ttype(top-2) == LUA_TNUMBER, "invalid index"); if (++nvalue(top-2) > nvalue(top-3)) /* end loop? */ top -= 4; /* remove table, n, index, and value */ else { *(top-1) = *luaH_getnum(hvalue(top-4), nvalue(top-2)); dojump(pc, i); /* repeat loop */ } break; } } } }