/* Browse a table pushed on top of the index, and put all its table and * sub-table ginto an array. * \param L The Lua VM state. * \param elems The elements array. * \return False if we encounter an elements already in list. */ static gboolean luaH_isloop_check(lua_State *L, GPtrArray *elems) { if(lua_istable(L, -1)) { gconstpointer object = lua_topointer(L, -1); /* Check that the object table is not already in the list */ for(guint i = 0; i < elems->len; i++) if(elems->pdata[i] == object) return FALSE; /* push the table in the elements list */ g_ptr_array_add(elems, (gpointer) object); /* look every object in the "table" */ lua_pushnil(L); while(luaH_next(L, -2)) { if(!luaH_isloop_check(L, elems)) { /* remove key and value */ lua_pop(L, 2); return FALSE; } /* remove value, keep key for next iteration */ lua_pop(L, 1); } } return TRUE; }
static void next() { lua_Object o = luaL_tablearg(1); lua_Object r = luaL_nonnullarg(2); Node *n = luaH_next(luaA_Address(o), luaA_Address(r)); if (n) { luaA_pushobject(&n->ref); luaA_pushobject(&n->val); } }
LUA_API int lua_next (lua_State *L, int index) { StkId t = luaA_index(L, index); Node *n; LUA_ASSERT(ttype(t) == LUA_TTABLE, "table expected"); n = luaH_next(L, hvalue(t), luaA_index(L, -1)); if (n) { *(L->top-1) = *key(n); *L->top = *val(n); api_incr_top(L); return 1; } else { /* no more elements */ L->top -= 1; /* remove key */ return 0; } }
static GSList* cookies_from_table(lua_State *L, gint idx) { GSList *cookies = NULL; SoupCookie *cookie; gchar *error; /* bring a copy of the table to the top of the stack */ lua_pushvalue(L, idx); /* push first index */ lua_pushnil(L); /* iterate over cookies table */ while(luaH_next(L, -2)) { /* create soup cookie from table */ if ((cookie = cookie_new_from_table(L, -1, &error))) cookies = g_slist_prepend(cookies, cookie); /* bad cookie, raise error */ else if (error) { /* free cookies */ for (GSList *p = cookies; p; p = g_slist_next(p)) soup_cookie_free(p->data); g_slist_free(cookies); /* push & raise error */ lua_pushfstring(L, "bad cookie in cookies table (%s)", error); g_free(error); lua_error(L); } /* remove cookie table */ lua_pop(L, 1); } /* remove copy of the table */ lua_pop(L, 1); return cookies; }
/* Look for an item: table, function, etc. * \param L The Lua VM state. * \param item The pointer item. */ gboolean luaH_hasitem(lua_State *L, gconstpointer item) { lua_pushnil(L); while(luaH_next(L, -2)) { if(lua_topointer(L, -1) == item) { /* remove value and key */ lua_pop(L, 2); return TRUE; } if(lua_istable(L, -1)) if(luaH_hasitem(L, item)) { /* remove key and value */ lua_pop(L, 2); return TRUE; } /* remove value */ lua_pop(L, 1); } return FALSE; }
/* ** 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; } 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; } } } }