我仍然对将 Delphi 用户数据注册到 Lua 感到困惑。为了教我原理,我尝试实现 Date(Time) 类型。
一开始这种类型应该有三个 Lua 可以访问的函数:
new
创建此类型变量的函数。- 一个
getdate
函数。 - 和一个
setdate
功能。
最后这个小 Lua 脚本应该可以工作:
DT = DateTime.new()
DT:setdate(1, 1, 2011)
day, month, year = DT:getdate()
print("Day: " .. day .. " Month: " .. month .." Year: " .. year)
我试图自己实现它(使用Lua 中的编程一书),但我收到一条错误消息:_attempt to index global 'DT' (a userdata value)_
在第 2 行。我可能在用户数据注册方面做错了,但我无法找到错误。
我希望你能帮我找到它,这是我已经得到的:
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, month, year : lua_Integer;
Begin
Result := 0;
DT := luaL_checkudata(aState, 1, MetaPosDateTime);
luaL_argcheck(aState, DT <> Nil, 1, 'DataTime expected');
ParamType := lua_type(aState, 2);
If (ParamType = LUA_TTABLE) Then
Begin
{ GetData from Table }
End
Else
Begin // param order must be: day, month, year
day := luaL_checkinteger(aState, 2);
month := luaL_checkinteger(aState, 3);
year := luaL_checkinteger(aState, 4);
End;
DT^:= EncodeDate(year, month, day);
End;
Function getdate(aState : pLua_State) : longint; cdecl;
Var
DT : pLuaDateTime;
Day, Month, Year : Word;
Begin
DT := luaL_checkudata(aState, 1, MetaPosDateTime);
luaL_argcheck(aState, DT <> Nil, 1, 'DataTime expected');
DecodeDate(DT^, Year, Month, Day);
lua_pushinteger(aState, 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”中设置断点来确保这一点。这两个函数都按此顺序调用。所以我的错误必须在这两个函数之一中。我'我几乎可以肯定这是一件简单的事情,但我看不到它。:(