static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, StkId res, TMS event) { const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (ttisnil(tm)) return 0; callTMres(L, res, tm, p1, p2); return 1; }
static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event) { const TValue *tm1 = luaT_gettmbyobj(L, p1, event); const TValue *tm2; if (ttisnil(tm1)) return -1; /* no metamethod? */ tm2 = luaT_gettmbyobj(L, p2, event); if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ return -1; callTMres(L, L->top, tm1, p1, p2); return !l_isfalse(L->top); }
static int call_binTM (lua_State *L, const TObject *p1, const TObject *p2, StkId res, TMS event) { ptrdiff_t result = savestack(L, res); const TObject *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (!ttisfunction(tm)) return 0; callTMres(L, tm, p1, p2); res = restorestack(L, result); /* previous call may change stack */ setobjs2s(res, L->top); return 1; }
/* ** Finish the table access 'val = t[key]'. ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to ** t[k] entry (which must be nil). */ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *slot) { int loop; /* counter to avoid infinite loops */ const TValue *tm; /* metamethod */ for (loop = 0; loop < MAXTAGLOOP; loop++) { if (slot == NULL) { /* 't' is not a table? */ lua_assert(!ttistable(t)); tm = luaT_gettmbyobj(L, t, TM_INDEX); if (ttisnil(tm)) luaG_typeerror(L, t, "index"); /* no metamethod */ /* else will try the metamethod */ } else { /* 't' is a table */ lua_assert(ttisnil(slot)); tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */ if (tm == NULL) { /* no metamethod? */ setnilvalue(val); /* result is nil */ return; } /* else will try the metamethod */ } if (ttisfunction(tm)) { /* is metamethod a function? */ luaT_callTM(L, tm, t, key, val, 1); /* call it */ return; } t = tm; /* else try to access 'tm[key]' */ if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */ setobj2s(L, val, slot); /* done */ return; } /* else repeat (tail call 'luaV_finishget') */ } luaG_runerror(L, "'__index' chain too long; possible loop"); }
/* * 获取哈希表 * L 虚拟机状态 * t 哈希表的指针 * key 哈希表的键 * val 哈希表的值在栈中的索引 */ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; /* 遍历 */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; /* 如果t是哈希表类型 */ if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); /* 获取哈希表值 */ /* 从键中取出值 */ const TValue *res = luaH_get(h, key); /* do a primitive get */ /* 如果不是空值或者其表的元运算为空 */ if (!ttisnil(res) || /* result is not nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ /* 设置哈希值到指定的栈索引位置 */ setobj2s(L, val, res); return; } /* else will try the tag method */ } /* 如果t不是哈希表则判断其元运算是否为空值 */ else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); /* 如果元运算是函数则进行调用 */ if (ttisfunction(tm)) { callTM(L, tm, t, key, val, 1); return; } t = tm; /* else repeat with 'tm' */ } luaG_runerror(L, "loop in gettable"); }
void luaV_settable (lua_State *L, TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ /* oldval is nil=> look for newindex, oldval is not nil => look for usedindex */ if (!((ttisnil(oldval) && ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) != NULL)) || ((!ttisnil(oldval)) && ((tm = fasttm(L, h->metatable, TM_USEDINDEX)) != NULL)))) { setobj2t(L, oldval, val); luaC_barriert(L, h, val); return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTM(L, tm, t, key, val); return; } t = tm; /* else repeat with `tm' */ } luaG_runerror(L, "loop in settable"); }
void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) /* `t' is a table? */ { Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) /* or no TM? */ { setobj2s(L, val, res); return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTMres(L, val, tm, t, key); return; } t = tm; /* else repeat with `tm' */ } luaG_runerror(L, "loop in gettable"); }
void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; TValue temp; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t) || ttisrotable(t)) { /* `t' is a table? */ void *h = ttistable(t) ? hvalue(t) : rvalue(t); const TValue *res = ttistable(t) ? luaH_get((Table*)h, key) : luaH_get_ro(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is no nil? */ (tm = fasttm(L, ttistable(t) ? ((Table*)h)->metatable : (Table*)luaR_getmeta(h), TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm) || ttislightfunction(tm)) { callTMres(L, val, tm, t, key); return; } /* else repeat with `tm' */ setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */ t = &temp; } luaG_runerror(L, "loop in gettable"); }
/* ** Main function for table assignment (invoking metamethods if needed). ** Compute 't[key] = val' */ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* 't' is a table? */ Table *h = hvalue(t); TValue *oldval = cast(TValue *, luaH_get(h, key)); /* if previous value is not nil, there must be a previous entry in the table; a metamethod has no relevance */ if (!ttisnil(oldval) || /* previous value is nil; must check the metamethod */ ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL && /* no metamethod; is there a previous entry in the table? */ (oldval != luaO_nilobject || /* no previous entry; must create one. (The next test is always true; we only need the assignment.) */ (oldval = luaH_newkey(L, h, key), 1)))) { /* no metamethod and (now) there is an entry with given key */ setobj2t(L, oldval, val); /* assign new value to that entry */ invalidateTMcache(h); luaC_barrierback(L, h, val); return; } /* else will try the metamethod */ } else /* not a table; check metamethod */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); /* try the metamethod */ if (ttisfunction(tm)) { luaT_callTM(L, tm, t, key, val, 0); return; } t = tm; /* else repeat assignment over 'tm' */ }
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t) || ttisrotable(t)) { /* `t' is a table? */ void *h = ttistable(t) ? hvalue(t) : rvalue(t); TValue *oldval = ttistable(t) ? luaH_set(L, (Table*)h, key) : NULL; /* do a primitive set */ if ((oldval && !ttisnil(oldval)) || /* result is no nil? */ (tm = fasttm(L, ttistable(t) ? ((Table*)h)->metatable : (Table*)luaR_getmeta(h), TM_NEWINDEX)) == NULL) { /* or no TM? */ if(oldval) { setobj2t(L, oldval, val); luaC_barriert(L, (Table*)h, val); } return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm) || ttislightfunction(tm)) { callTM(L, tm, t, key, val); return; } t = tm; /* else repeat with `tm' */ } luaG_runerror(L, "loop in settable"); }
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; TValue temp; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(L, oldval, val); luaC_barriert(L, h, val); return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTM(L, tm, t, key, val); return; } /* else repeat with `tm' */ setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */ t = &temp; } luaG_runerror(L, "loop in settable"); }
/* ** Main operation 'ra' = #rb'. */ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { const TValue *tm; switch (ttype(rb)) { case LUA_TTABLE: { Table *h = hvalue(rb); tm = fasttm(L, h->metatable, TM_LEN); if (tm) break; /* metamethod? break switch to call it */ setivalue(ra, luaH_getn(h)); /* else primitive len */ return; } case LUA_TSHRSTR: { setivalue(ra, tsvalue(rb)->shrlen); return; } case LUA_TLNGSTR: { setivalue(ra, tsvalue(rb)->u.lnglen); return; } default: { /* try metamethod */ tm = luaT_gettmbyobj(L, rb, TM_LEN); if (ttisnil(tm)) /* no metamethod? */ luaG_typeerror(L, rb, "get length of"); break; } } luaT_callTM(L, tm, rb, rb, ra, 1); }
static void GCTM (lua_State *L, int propagateerrors) { global_State *g = G(L); const TValue *tm; TValue v; setgcovalue(L, &v, udata2finalize(g)); tm = luaT_gettmbyobj(L, &v, TM_GC); if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */ int status; lu_byte oldah = L->allowhook; int running = g->gcrunning; L->allowhook = 0; /* stop debug hooks during GC metamethod */ g->gcrunning = 0; /* avoid GC steps */ setobj2s(L, L->top, tm); /* push finalizer... */ setobj2s(L, L->top + 1, &v); /* ... and its argument */ L->top += 2; /* and (next line) call the finalizer */ status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); L->allowhook = oldah; /* restore hooks */ g->gcrunning = running; /* restore state */ if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ if (status == LUA_ERRRUN) { /* is there an error object? */ const char *msg = (ttisstring(L->top - 1)) ? svalue(L->top - 1) : "no message"; luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); status = LUA_ERRGCMM; /* error in __gc metamethod */ } luaD_throw(L, status); /* re-throw error */ } } }
static const TObject *luaV_getnotable (lua_State *L, const TObject *t, TObject *key, int loop) { const TObject *tm = luaT_gettmbyobj(L, t, TM_INDEX); if (ttisnil(tm)) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTMres(L, tm, t, key); return L->top; } else return luaV_gettable(L, tm, key, loop); }
/* ** finish execution of an opcode interrupted by an yield */ void luaV_finishOp (lua_State *L) { CallInfo *ci = L->ci; StkId base = ci->u.l.base; Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ OpCode op = GET_OPCODE(inst); switch (op) { /* finish its execution */ case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: { setobjs2s(L, base + GETARG_A(inst), --L->top); break; } case OP_LE: case OP_LT: case OP_EQ: { int res = !l_isfalse(L->top - 1); L->top--; /* metamethod should not be called when operand is K */ lua_assert(!ISK(GETARG_B(inst))); if (op == OP_LE && /* "<=" using "<" instead? */ ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE))) res = !res; /* invert result */ lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); if (res != GETARG_A(inst)) /* condition failed? */ ci->u.l.savedpc++; /* skip jump instruction */ break; } case OP_CONCAT: { StkId top = L->top - 1; /* top when 'call_binTM' was called */ int b = GETARG_B(inst); /* first element to concatenate */ int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */ setobj2s(L, top - 2, top); /* put TM result in proper position */ if (total > 1) { /* are there elements to concat? */ L->top = top - 1; /* top is one after last element (at top-2) */ luaV_concat(L, total); /* concat them (may yield again) */ } /* move final result to final position */ setobj2s(L, ci->u.l.base + GETARG_A(inst), L->top - 1); L->top = ci->top; /* restore top */ break; } case OP_TFORCALL: { lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP); L->top = ci->top; /* correct top */ break; } case OP_CALL: { if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */ L->top = ci->top; /* adjust results */ break; } case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: break; default: lua_assert(0); } }
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { TValue tmp; int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(L, oldval, val); luaC_barriert(L, h, val); #if LUA_REFCOUNT if (ttisnil(val)) { Node* keyNode = luaH_getkey(h, key); if (keyNode) { luaH_removekey(L, h, keyNode); } } #endif /* LUA_REFCOUNT */ return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTM(L, tm, t, key, val); #if LUA_REFCOUNT { TValue *newval; if (ttistable(t)) { newval = luaH_set(L, hvalue(t), key); if (ttisnil(newval)) { Node* keyNode = luaH_getkey(hvalue(t), key); if (keyNode) luaH_removekey(L, hvalue(t), keyNode); } } } #endif /* LUA_REFCOUNT */ return; } setobj(L, &tmp, tm); t = &tmp; /* else repeat with copy of `tm' */ } luaG_runerror(L, "loop in settable"); }
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; TValue temp; setnilvalue(L->top); L->top++; fixedstack(L); for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t) || ttisrotable(t)) { /* `t' is a table? */ void *h = ttistable(t) ? hvalue(t) : rvalue(t); TValue *oldval = ttistable(t) ? luaH_set(L, (Table*)h, key) : NULL; /* do a primitive set */ if ((oldval && !ttisnil(oldval)) || /* result is no nil? */ (tm = fasttm(L, ttistable(t) ? ((Table*)h)->metatable : (Table*)luaR_getmeta(h), TM_NEWINDEX)) == NULL) { /* or no TM? */ if(oldval) { L->top--; unfixedstack(L); setobj2t(L, oldval, val); ((Table *)h)->flags = 0; luaC_barriert(L, (Table*)h, val); } return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm) || ttislightfunction(tm)) { L->top--; unfixedstack(L); callTM(L, tm, t, key, val); return; } /* else repeat with `tm' */ setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */ t = &temp; setobj2s(L, L->top-1, t); /* need to protect value from EGC. */ } luaG_runerror(L, "loop in settable"); }
/* ** Main function for table assignment (invoking metamethods if needed). ** Compute 't[key] = val' */ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *oldval) { int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (oldval != NULL) { Table *h = hvalue(t); /* save 't' table */ lua_assert(ttisnil(oldval)); /* must check the metamethod */ if ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL && /* no metamethod; is there a previous entry in the table? */ (oldval != luaO_nilobject || /* no previous entry; must create one. (The next test is always true; we only need the assignment.) */ (oldval = luaH_newkey(L, h, key), 1))) { /* no metamethod and (now) there is an entry with given key */ setobj2t(L, cast(TValue *, oldval), val); invalidateTMcache(h); luaC_barrierback(L, h, val); return; } /* else will try the metamethod */ } else { /* not a table; check metamethod */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); } /* try the metamethod */ if (ttisfunction(tm)) { luaT_callTM(L, tm, t, key, val, 0); return; } t = tm; /* else repeat assignment over 'tm' */ if (luaV_fastset(L, t, key, oldval, luaH_get, val)) return; /* done */ /* else loop */ } luaG_runerror(L, "settable chain too long; possible loop"); }
/* ** Complete a table access: if 't' is a table, 'tm' has its metamethod; ** otherwise, 'tm' is NULL. */ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *tm) { int loop; /* counter to avoid infinite loops */ lua_assert(tm != NULL || !ttistable(t)); for (loop = 0; loop < MAXTAGLOOP; loop++) { if (tm == NULL) { /* no metamethod (from a table)? */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); /* no metamethod */ } if (ttisfunction(tm)) { /* metamethod is a function */ luaT_callTM(L, tm, t, key, val, 1); /* call it */ return; } t = tm; /* else repeat access over 'tm' */ if (luaV_fastget(L,t,key,tm,luaH_get)) { /* try fast track */ setobj2s(L, val, tm); /* done */ return; } /* else repeat */ } luaG_runerror(L, "gettable chain too long; possible loop"); }
void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { const TValue *tm; switch (ttype(rb)) { case LUA_TTABLE: { Table *h = hvalue(rb); tm = fasttm(L, h->metatable, TM_LEN); if (tm) break; /* metamethod? break switch to call it */ setnvalue(ra, cast_num(luaH_getn(h))); /* else primitive len */ return; } case LUA_TSTRING: { setnvalue(ra, cast_num(tsvalue(rb)->len)); return; } default: { /* try metamethod */ tm = luaT_gettmbyobj(L, rb, TM_LEN); if (ttisnil(tm)) /* no metamethod? */ luaG_typeerror(L, rb, "get length of"); break; } } callTMres(L, ra, tm, rb, luaO_nilobject); }
/* ** Finish a table assignment 't[key] = val'. ** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points ** to the entry 't[key]', or to 'luaO_nilobject' if there is no such ** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset' ** would have done the job.) */ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *slot) { int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; /* '__newindex' metamethod */ if (slot != NULL) { /* is 't' a table? */ Table *h = hvalue(t); /* save 't' table */ lua_assert(ttisnil(slot)); /* old value must be nil */ tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ if (tm == NULL) { /* no metamethod? */ if (slot == luaO_nilobject) /* no previous entry? */ slot = luaH_newkey(L, h, key); /* create one */ /* no metamethod and (now) there is an entry with given key */ setobj2t(L, cast(TValue *, slot), val); /* set its new value */ invalidateTMcache(h); luaC_barrierback(L, h, val); return; } /* else will try the metamethod */ } else { /* not a table; check metamethod */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); } /* try the metamethod */ if (ttisfunction(tm)) { luaT_callTM(L, tm, t, key, val, 0); return; } t = tm; /* else repeat assignment over 'tm' */ if (luaV_fastset(L, t, key, slot, luaH_get, val)) return; /* done */ /* else loop */ } luaG_runerror(L, "'__newindex' chain too long; possible loop"); }
/* ** Receives table at `t', key at `key' and value at `val'. */ void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) { const TObject *tm; int loop = 0; do { if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TObject *oldval = luaH_set(L, h, key); /* do a primitive set */ if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(oldval, val); /* write barrier */ return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTM(L, tm, t, key, val); return; } t = tm; /* else repeat with `tm' */ } while (++loop <= MAXTAGLOOP); luaG_runerror(L, "loop in settable"); }
/* ** Main function for table access (invoking metamethods if needed). ** Compute 'val = t[key]' */ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* 't' is a table? */ Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is not nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); /* result is the raw get */ return; } /* else will try metamethod */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); /* no metamethod */ if (ttisfunction(tm)) { /* metamethod is a function */ luaT_callTM(L, tm, t, key, val, 1); return; } t = tm; /* else repeat access over 'tm' */ } luaG_runerror(L, "gettable chain too long; possible loop"); }
void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm = 0; /* LUA-VEC -- compiler gives a warning of uninitialized value on this so we set it to 0 */ if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); return; } /* else will try the tag method */ } else if (ttisvec(t)) { /* LUA-VEC -- vec[idx] operator */ /* issue: "index" may not be the correct arg for luaG_typeerror in here */ if (ttisnumber(key) && /* acessing vec by a number? */ (nvalue(key) >= 1 && nvalue(key) <= 4)) { /* index is between 1-4? */ TValue res; setnvalue(&res, vecvalue(t)[(int)nvalue(key)-1]); setobj2s(L, val, &res); return; } else if (ttisstring(key)) { /* acessing vec by a string? */ if (tsvalue(key)->len == 1) { /* accessing by a single component, such as vec.x */ TValue res; switch (*getstr(tsvalue(key))) { case 'x': setnvalue(&res, vecvalue(t)[0]); break; case 'y': setnvalue(&res, vecvalue(t)[1]); break; case 'z': setnvalue(&res, vecvalue(t)[2]); break; case 'w': setnvalue(&res, vecvalue(t)[3]); break; default: luaG_typeerror(L, t, "index"); } setobj2s(L, val, &res); return; } else if (tsvalue(key)->len <= 4) { /* accessing by swizzling, such as vec.xy, vec.xxyz etc. */ TValue res; float v[4] = {0.0f,0.0f,0.0f,0.0f}; int i; for (i = 0; i < (int)tsvalue(key)->len; ++i) { switch (getstr(tsvalue(key))[i]) { case 'x': v[i] = vecvalue(t)[0]; break; case 'y': v[i] = vecvalue(t)[1]; break; case 'z': v[i] = vecvalue(t)[2]; break; case 'w': v[i] = vecvalue(t)[3]; break; default: luaG_typeerror(L, t, "index"); } } setvecvalue(&res, v[0], v[1], v[2], v[3]); setobj2s(L, val, &res); return; } } luaG_typeerror(L, t, "index"); } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTMres(L, val, tm, t, key); return; } t = tm; /* else repeat with `tm' */ } luaG_runerror(L, "loop in gettable"); }