#define T lua_gettop(L)
…
int t = T;
…
assert(T == t + expected_inc);
…
lua_pushvalue(L, -2); // note: this is b
lua_remove(L, -3); // old b
// eventual realization that
// -index is fragile
// and rewrite to
int start = T;
int a = ++start;
int b = ++start;
luaL_checkstack(L, 10, "…");
…
lua_pushvalue(L, b);
lua_remove(L, b);
lua_call(L, …);
luaL_ref(L, …);
…
lua_settop(L, t - 1);
If you have ever done this, idk how that feels flexibility. I’d rather get handles to a and b and directly call a function with them as like:
LFN *func = LGETFN(L, LARG(1));
LTAB *retvs = LCHKTAB(
LCALL(L, func, 3,
LGET(L, LARG(2)),
LGET(L, LARG(3)),
LGET(L, LUPV(1))
)
);
me.retvs = LREF(L, retvs);
// everything but ref’d
// things disappears here:
return;
And avoid all this stack-in-your-mind and stack-in-your-int nonsense, which is completely unnecessary in C and I fail to see where exactly it is flexible, compared to the short snippet above. Stack is just how vm sees it, it is not any special “for you” thing, it’s literally implementation shining through.
I’d like to see a specific example (low-key, I left Lua) on how its stack provides more flexibility or anything, because in my humble experience it does not, absolutely, do anything like it. It just makes you play these off-by-one games all day for no good reason.