lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


#include <stdio.h>
#include <math.h>

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "luaconf.h"

const char *const code = "              \
local t = setmetatable({}, {            \
    __le = function(...)                \
        print(...)                      \
        return true                     \
    end                                 \
})                                      \
co = coroutine.create(function(...)     \
    print(\"le:\", 2 <= t)              \
end)                                    \
return co";

static void hook(lua_State *L, lua_Debug *ar)
{
    lua_yield(L, 0);
}

int main(int argc, const char * argv[]) {
    
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);
    luaL_dostring(L, code);
    lua_State* co = lua_tothread(L, -1);
    lua_sethook(co, hook, LUA_MASKLINE, 0);
    
    for (;;) {
        if (lua_resume(co, L, 0) != LUA_YIELD) break;
    }
    
    return 0;
}

OUTPUT:
    2   table: 0x10010a010
    le: false

-------------------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <math.h>

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "luaconf.h"

const char *const code = "              \
local t = setmetatable({}, {            \
    __le = function(...)                \
        print(...)                      \
        return true                     \
    end                                 \
})                                      \
co = coroutine.create(function(...)     \
    print(\"le:\", 2 <= t)              \
end)                                    \
return co";

static void hook(lua_State *L, lua_Debug *ar)
{
    //lua_yield(L, 0);
}

int main(int argc, const char * argv[]) {
    
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);
    luaL_dostring(L, code);
    lua_State* co = lua_tothread(L, -1);
    lua_sethook(co, hook, LUA_MASKLINE, 0);
    
    for (;;) {
        if (lua_resume(co, L, 0) != LUA_YIELD) break;
    }
    
    return 0;
}

OUTPUT:
    2   table: 0x10010a010
    le: true

-------------------------------------------------------------------------------------------------------------

it has different result when call or not call 'lua_yield' in 'hook' fun, i think there is a bug in when finish execution of an opcode(OP_LE) 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_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;
    }
......

in func luaV_finishOp, i think it is necessary to invert result when both R(B) and R(C) has no meta method 'TM_LE':
if (op == OP_LE &&  /* "<=" using "<" instead? */
          ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE)) &&
          ttisnil(luaT_gettmbyobj(L, base + GETARG_C(inst), TM_LE)))
        res = !res;  /* invert result */