質問

Delphi userdataをLuaに登録することについて、私はまだ混乱しています。原則を教えるために、日付(時刻)タイプを実装しようとしました。

最初に、このタイプには、LUAがアクセスできる3つの関数が必要です。

  1. a new このタイプの変数を作成する機能。
  2. a getdate 関数。
  3. そしてa setdate 関数。

最後に、この小さなlua-scriptは機能するはずです。

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

私は自分でそれを実装しようとしました(を使用して ルアでのプログラミング 本)しかし、私は次のように言っているエラーを受け取ります _attempt to index global 'DT' (a userdata value)_ 2行目。私はおそらくuserData登録に何か問題を抱えていましたが、エラーを見つけるのに苦労しています。

私はあなたが私がそれを見つけるのを手伝ってくれることを願っています、ここに私がすでに得たものがあります:

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」でブレークポイントを設定することでこれを保証しました。どちらの関数もこの順序で呼び出されます。 'Mはほぼ簡単なことだと確信していますが、私はそれを見るために盲目です。:(

役に立ちましたか?

解決

今日、私はこのプロジェクトの大きなリセットボタンを押し、LuadateTimeタイプの実装を完全に再開しましたが、今日はそれを正しくしました。今、私は同じ問題を抱えている他の人の例として私の解決策を投稿したいと思います。

昨日の私の最大の間違いは、設定を忘れることでした __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, 1, 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, month, 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, month, day);

  Result := 0;
End;

Function getLuaDateTime(L : pLua_State) : LongInt; cdecl;
Var
  a : pLuaDateTime;
  day, month, year : Word;
Begin
  a := checkLuaDateTime(L);
  DecodeDate(a^, year, month, 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, -2, '__index');
  luaL_register(L, Nil, LuaDateTimeLib_m[0]);

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

あなたは電話しなければなりません luaopen_LuaDateTime DelphiからLua-Stateのタイプを登録します。それをした後、あなたはこのようなlua-scriptを実行することができます:

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

これが他の誰かに役立つことを願っています。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top