加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

如何从Delphi中注册Lua userdata?

发布时间:2020-12-15 04:05:19 所属栏目:大数据 来源:网络整理
导读:我仍然对将Delphi userdata注册到Lua感到困惑.教我学习实现日期(时间)类型的原则. 在开始时,这种类型应该具有Lua可访问的三个函数: 创建此类变量的新函数. 一个getdate函数. 和一个setdate函数. 最后这个小Lua脚本应该工作: DT = DateTime.new()DT:setdate
我仍然对将Delphi userdata注册到Lua感到困惑.教我学习实现日期(时间)类型的原则.

在开始时,这种类型应该具有Lua可访问的三个函数:

>创建此类变量的新函数.
>一个getdate函数.
>和一个setdate函数.

最后这个小Lua脚本应该工作:

DT = DateTime.new()
DT:setdate(1,1,2011)
day,month,year = DT:getdate()
print("Day: " .. day .. " Month: " .. month .." Year: " .. year)

我试图自己实现它(使用Programming in Lua书)但我收到一个错误说:_尝试在第2行索引全局’DT'(用户数据值)_我可能在用户数据注册时出错了但是我是无法找到错误.

我希望你能帮助我找到它,这是我已经得到的:

Const
  MetaPosDateTime = 'DateTime';

Type
  tLuaDateTime = tDateTime;
  pLuaDateTime = ^tLuaDateTime;

  Function newdatetime(aState : pLua_State) : longint; cdecl;
  Var
    NewData : pLuaDateTime;
  Begin
    Result := 0;
    NewData := lua_newuserdata(aState,SizeOf(tLuaDateTime)); 
    NewData^ := now; 
    luaL_newmetatable(aState,MetaPosDateTime);
    lua_setmetatable(aState,-2);    
    Result := 1;
  End;

  Function setdate(aState : pLua_State) : longint; cdecl;
  Var
    DT : pLuaDateTime;
    ParamType : integer;
    day,year : lua_Integer;
  Begin
    Result := 0;
    DT := luaL_checkudata(aState,MetaPosDateTime);
    luaL_argcheck(aState,DT <> Nil,'DataTime expected');
    ParamType := lua_type(aState,2); 
    If (ParamType = LUA_TTABLE) Then 
      Begin
        { GetData from Table }
      End
    Else
      Begin // param order must be: day,year
        day := luaL_checkinteger(aState,2);
        month := luaL_checkinteger(aState,3);
        year := luaL_checkinteger(aState,4);
      End;
    DT^:= EncodeDate(year,day);
  End;

  Function getdate(aState : pLua_State) : longint; cdecl;
  Var
    DT : pLuaDateTime;
    Day,Month,Year : Word;
  Begin
    DT := luaL_checkudata(aState,'DataTime expected');
    DecodeDate(DT^,Year,Day);
    lua_pushinteger(aState,Month);
    lua_pushinteger(aState,Year);
  End;

Procedure RegisterDateTime(aState : pLua_State; aName: string);
Var
  Funcs : packed Array[0..3] of luaL_reg;
Begin
  Funcs[0].name := 'new';
  Funcs[0].func := newdatetime;
  Funcs[1].name := 'setdate';
  Funcs[1].func := setdate;
  Funcs[2].name := 'getdate';
  Funcs[2].func := getdate;
  Funcs[3].name := Nil;
  Funcs[3].func := Nil;
  luaL_register(aState,PAnsiChar(aName),Funcs[0]);
End;

因为我不确定luaL_register函数(它只能通过创建一个必须用require调用的库来工作吗?)我还试图用这个替换RegisterDateTime函数:

Type
  tLuaFuncDef = Record
    FuncName : string;
    Func : Lua_CFunction;
  End;

tLuaFuncList = Array of tLuaFuncDef;

Procedure RegisterLuaObject(aState : pLua_State; aObjectName: string; aFuncList: tLuaFuncList);
Var
  i : Integer;
Begin
  If (aObjectName = '') Or (High(aFuncList) < 0) Then
    Exit;

  lua_newtable(aState); 
  For i := Low(aFuncList) To High(aFuncList) Do 
    If Assigned(aFuncList[i].Func) And Not (aFuncList[i].FuncName = '') Then
      Begin
        lua_pushcfunction(aState,aFuncList[i].Func);
        lua_setfield(aState,-2,pAnsiChar(aFuncList[i].FuncName));
      End;
  lua_SetGlobal(aState,pAnsiChar(aObjectName));
End;

Procedure RegisterDateTime(aState : pLua_State,aName: string);
Var
  FuncList : tLuaFuncList;
Begin
  SetLength(FuncList,3);
  FuncList[0].FuncName := 'new';
  FuncList[0].Func := newdatetime;
  FuncList[1].FuncName := 'setdate';
  FuncList[1].Func := setdate;
  FuncList[2].FuncName := 'getdate';
  FuncList[2].Func := getdate;
  RegisterLuaObject(aState,aName,FuncList);
End;

不幸的是,两个版本的RegisterDateTime的效果(errormessage;))是相同的.在脚本启动之前,我们在Delphi程序中直接调用它们(我通过在“RegisterDateTime”和“newdatetime”中设置断点来确保这一点.这两个函数都按此顺序调用.所以我的错误必须是这两个函数中的一个.I我几乎可以肯定这是一件简单的事情,但我会盲目地看到它.:(

解决方法

今天我推动了这个项目的大重置按钮,并完全重新启动了我的LuaDateTime-Type的实现,这一天我做对了.现在我想发布我的解决方案作为其他有相同问题的人的例子.

昨天我最大的错误就是忘记设置myatable的__index字段. Lua userdata的Delphi实现如下所示:

implementation
Uses
  LuaLib,LauXLib,SysUtils;

Type
  tLuaDateTime = tDateTime;
  pLuaDateTime = ^tLuaDateTime;

Const
  PosMetaTaleLuaDateTime = 'metatables.LuaDateTime';
  PosLuaDateTime = 'datetime';    

Function checkLuaDateTime(L : Plua_State) : pLuaDateTime; // raises error if first (self) parameter is not of type metatables.LuaDateTime
Begin
  Result := luaL_checkudata(L,PosMetaTaleLuaDateTime);
End;

Function newLuaDateTime(L : pLua_State) : LongInt; cdecl;
Var
  a : pLuaDateTime;
Begin
  a := lua_newuserdata(L,SizeOf(tLuaDateTime)); // Get Mem of Usertype
  a^ := now; // Init Value
  lua_getfield(L,LUA_REGISTRYINDEX,PosMetaTaleLuaDateTime); 
  lua_setmetatable(L,-2);

  Result := 1;
End;

Function setLuaDateTime(L : pLua_State) : LongInt; cdecl;
Var
  a : pLuaDateTime;
  day,year : Integer;
Begin
  a := checkLuaDateTime(L);
  // get params day,month and year
  day := luaL_checkint(L,2);
  month := luaL_checkint(L,3);
  year := luaL_checkint(L,4);

  // check Param Values
  luaL_argcheck(L,(day >= 1) and (day < 32),2,'day out of range');
  luaL_argcheck(L,(month >= 1) and (month < 13),3,'month out of range');

  a^ := EncodeDate(year,day);

  Result := 0;
End;

Function getLuaDateTime(L : pLua_State) : LongInt; cdecl;
Var
  a : pLuaDateTime;
  day,year : Word;
Begin
  a := checkLuaDateTime(L);
  DecodeDate(a^,year,day);

  // push 3 results of function
  lua_pushinteger(L,day);
  lua_pushinteger(L,month);
  lua_pushinteger(L,year);

  Result := 3;
End;

Function LuaDateTime2string(L : pLua_State) : LongInt; cdecl;
Var
  a : pLuaDateTime;
Begin
  a := checkLuaDateTime(L);
  lua_pushstring(L,pAnsiChar(FormatDateTime('c',a^)));
  Result := 1;
End;

Const
  LuaDateTimeLib_f : packed Array[0..1] of luaL_reg = // Normal functions (no self)
    (
      (name: 'new'; func: newLuaDateTime),(name: Nil; func: Nil)
    );

  LuaDateTimeLib_m : packed Array[0..3] of luaL_reg = // methods of class (need self)
    (
      (name: '__tostring'; func: LuaDateTime2string),(name: 'set'; func: setLuaDateTime),(name: 'get'; func: getLuaDateTime),(name: Nil; func: Nil)
    );

Function luaopen_LuaDateTime(L : pLua_State) : LongInt; cdecl;
Begin
  luaL_newmetatable(L,PosMetaTaleLuaDateTime);
  // Metatable.__index = Metatable
  lua_pushvalue(L,-1);
  lua_setfield(L,'__index');
  luaL_register(L,Nil,LuaDateTimeLib_m[0]);

  luaL_register(L,PosLuaDateTime,LuaDateTimeLib_f[0]);
  Result := 1;
End;

你必须从Delphi调用luaopen_LuaDateTime来注册Lua-State中的类型.完成后,您可以像这样运行Lua脚本:

dt = datetime.new()
 day,year = dt:get()
 print ("Day: " .. day .. " Month: " .. month .. " Year: " .. year)
 dt:set(1,1903)
 day,year = dt:get()
 print ("Day: " .. day .. " Month: " .. month .. " Year: " .. year)

我希望这对其他人有帮助.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读