{$MODE FPC}
{$MODESWITCH RESULT}
unit lua;

interface

const
  LUA_LIB = 'lua53.dll';

  LUA_TNONE           = -1;
  LUA_TNIL            = 0;
  LUA_TBOOLEAN        = 1;
  LUA_TLIGHTUSERDATA  = 2;
  LUA_TNUMBER         = 3;
  LUA_TSTRING         = 4;
  LUA_TTABLE          = 5;
  LUA_TFUNCTION       = 6;
  LUA_TUSERDATA       = 7;
  LUA_TTHREAD         = 8;
  LUA_NUMTAGS         = 9;

  LUA_OK		      = 0;
  LUA_YIELD	      = 1;
  LUA_ERRRUN	    = 2;
  LUA_ERRSYNTAX	  = 3;
  LUA_ERRMEM	    = 4;
  LUA_ERRGCMM	    = 5;
  LUA_ERRERR	    = 6;

  LUA_MULTRET     = -1;

  LUAI_MAXSTACK   = 1000000;

  LUA_REGISTRYINDEX = -LUAI_MAXSTACK - 1000;

  LUA_NOREF       = -2;
  LUA_REFNIL      = -1;

const
  // Event codes
  LUA_HOOKCALL     = 0;
  LUA_HOOKRET      = 1;
  LUA_HOOKLINE     = 2;
  LUA_HOOKCOUNT    = 3;
  LUA_HOOKTAILCALL = 4;

  // Event masks
  LUA_MASKCALL  = 1 shl Ord(LUA_HOOKCALL);
  LUA_MASKRET   = 1 shl Ord(LUA_HOOKRET);
  LUA_MASKLINE  = 1 shl Ord(LUA_HOOKLINE);
  LUA_MASKCOUNT = 1 shl Ord(LUA_HOOKCOUNT);

  LUA_IDSIZE = 60;

type
  Plua_State = Pointer;

  lua_SystemInteger = LongInt;

  lua_Integer = LongInt;

  lua_TrueInteger = Int64;
  lua_TrueUnsigned = UInt64;

  lua_Number = Double;
  Plua_Number = ^lua_Number;

  lua_Reader = function(L: Plua_State; ud: Pointer; sz: PSizeUInt): PAnsiChar; cdecl;

  lua_KContext = Pointer;

  lua_CFunction = function(L: Plua_State): lua_Integer; cdecl;

  lua_KFunction = function(L: Plua_State; status: lua_Integer; ctx: lua_KContext): lua_Integer; cdecl;

     lua_Debug = packed record     (* activation record *)
      event: lua_Integer;
      name: PAnsiChar;           (* (n) *)
      namewhat: PAnsiChar;       (* (n) `global', `local', `field', `method' *)
      what: PAnsiChar;           (* (S) `Lua', `C', `main', `tail'*)
      source: PAnsiChar;         (* (S) *)
      currentline: lua_Integer;      (* (l) *)
      linedefined: lua_Integer;      (* (S) *)
      lastlinedefined: lua_Integer;  (* (S) *)
      nups: Byte;                (* (u) number of upvalues *)
      nparams: Byte;             (* (u) number of parameters *)
      isvararg: ByteBool;        (* (u) *)
      istailcall: ByteBool;      (* (t) *)
      short_src: packed array[0..LUA_IDSIZE - 1] of AnsiChar; (* (S) *)
      (* private part *)
      i_ci: Pointer;             (* active function *)  // ptr to struct CallInfo
   end;
   Plua_Debug = ^lua_Debug;

  lua_Hook = procedure(L: Plua_State; ar: Plua_Debug); cdecl;

  // Type for memory-allocation functions
  TLuaAlloc = function (Ud: Pointer; Ptr: Pointer; OSize, NSize: SizeUInt): Pointer; cdecl;

function luaL_newstate: Plua_State; cdecl; external LUA_LIB;
function lua_newstate(f: TLuaAlloc; Ud: Pointer): Plua_State; cdecl; external LUA_LIB;
procedure lua_close(L: Plua_State); cdecl; external LUA_LIB;
function lua_newthread(L: Plua_State): Plua_State; cdecl; external LUA_LIB;

function lua_version(L: Plua_State): Plua_Number; cdecl; external LUA_LIB;

function lua_load(L: Plua_State;
                  Reader: lua_Reader;
                  Dt: Pointer;
                  ChunkName: PAnsiChar;
                  Mode: PAnsiChar): lua_Integer; cdecl; external LUA_LIB;

function lua_pcallk(L: Plua_State;
                    nargs, nresults, errfunc: lua_Integer;
                    ctx: lua_KContext;
                    k: lua_KFunction): lua_Integer; cdecl; external LUA_LIB;
    // This function behaves exactly like lua_pcall, but allows the called
    // function to yield (see §4.7).
function lua_pcall(L: Plua_State;
                   nargs, nresults, errf: lua_Integer): lua_Integer; inline;
    //  Calls a function in protected mode.
    //
    //  Both nargs and nresults have the same meaning as in lua_call. If there
    //  are no errors during the call, lua_pcall behaves exactly like lua_call.
    //  However, if there is any error, lua_pcall catches it, pushes a single
    //  value on the stack (the error object), and returns an error code. Like
    //  lua_call, lua_pcall always removes the function and its arguments from
    //  the stack.
    //
    //  If msgh is 0, then the error object returned on the stack is exactly
    //  the original error object. Otherwise, msgh is the stack index of a
    //  message handler. (This index cannot be a pseudo-index.) In case of
    //  runtime errors, this function will be called with the error object and
    //  its return value will be the object returned on the stack by lua_pcall.
    //
    //  Typically, the message handler is used to add more debug information to
    //  the error object, such as a stack traceback. Such information cannot be
    //  gathered after the return of lua_pcall, since by then the stack has
    //  unwound.
    //
    //  The lua_pcall function returns one of the following constants (defined
    //  in lua.h):
    //
    //  * LUA_OK (0): success.
    //  * LUA_ERRRUN: a runtime error.
    //  * LUA_ERRMEM: memory allocation error. For such errors, Lua does not
    //    call the message handler.
    //  * LUA_ERRERR: error while running the message handler.
    //  * LUA_ERRGCMM: error while running a __gc metamethod. For such errors,
    //    Lua does not call the message handler (as this kind of error typically
    //    has no relation with the function being called).

function luaL_loadstring(L: Plua_State;
                         S: PAnsiChar): lua_Integer; cdecl; external LUA_LIB;

function lua_type(L: Plua_State; index: lua_Integer): lua_Integer; cdecl; external LUA_LIB;
function lua_tointegerx(L: Plua_State; index: lua_Integer; isnum: PLongBool): lua_TrueInteger; cdecl; external LUA_LIB;
function lua_tointeger(L: Plua_State; index: lua_Integer): lua_TrueInteger; inline;
function lua_tonumberx(L: Plua_State; index: lua_Integer; isnum: PLongBool): lua_Number; cdecl; external LUA_LIB;
    //  Converts the Lua value at the given index to the C type lua_Number (see
    //  lua_Number). The Lua value must be a number or a string convertible to
    //  a number (see §3.4.3); otherwise, lua_tonumberx returns 0.
    //
    //  If isnum is not NULL, its referent is assigned a boolean value that
    //  indicates whether the operation succeeded.
function lua_tonumber(L: Plua_State; index: lua_Integer): lua_Number; cdecl;
    //  Equivalent to lua_tonumberx with isnum equal to NULL.
function lua_tolstring(L: Plua_State; index: lua_Integer; len: PSizeInt): PAnsiChar; cdecl; external LUA_LIB;
    //  Converts the Lua value at the given index to a C string. If len is not
    //  NULL, it sets *len with the string length. The Lua value must be a
    //  string or a number; otherwise, the function returns NULL. If the value
    //  is a number, then lua_tolstring also changes the actual value in the
    //  stack to a string. (This change confuses lua_next when lua_tolstring is
    //  applied to keys during a table traversal.)
    //
    //  lua_tolstring returns a pointer to a string inside the Lua state. This
    //  string always has a zero ('\0') after its last character (as in C), but
    //  can contain other zeros in its body.
    //
    //  Because Lua has garbage collection, there is no guarantee that the
    //  pointer returned by lua_tolstring will be valid after the corresponding
    //  Lua value is removed from the stack.
function lua_tostring(L: Plua_State; index: lua_Integer): PAnsiChar;
    //  Equivalent to lua_tolstring with len equal to NULL.
function lua_isstring(L: Plua_State; idx: lua_Integer): LongBool; cdecl; external LUA_LIB;
function lua_isnumber(L: Plua_State; idx: lua_Integer): LongBool; cdecl; external LUA_LIB;
function lua_isfunction(L: Plua_State; idx: lua_Integer): LongBool; inline;
function lua_tocfunction(L: Plua_State; idx: lua_Integer): lua_CFunction; cdecl; external LUA_LIB;
function lua_topointer(L: Plua_State; idx: lua_Integer): Pointer; cdecl; external LUA_LIB;
function lua_touserdata(L: Plua_State; idx: lua_Integer): Pointer; cdecl; external LUA_LIB;
    //  If the value at the given index is a full userdata, returns its block
    //  address. If the value is a light userdata, returns its pointer.
    //  Otherwise, returns NULL.
function lua_toboolean(L: Plua_State; idx: lua_Integer): LongBool; cdecl; external LUA_LIB;

function lua_gettop(L: Plua_State): lua_Integer; cdecl; external LUA_LIB;
function lua_getglobal(L: Plua_State; name: PAnsiChar): lua_Integer; cdecl; external LUA_LIB;
    //  Pushes onto the stack the value of the global name. Returns the type of
    //  that value.
function lua_gettable(L: Plua_State; index: lua_Integer): lua_Integer; cdecl; external LUA_LIB;
    //  Pushes onto the stack the value t[k], where t is the value at the
    //  given index and k is the value at the top of the stack.
    //
    //  This function pops the key from the stack, pushing the resulting value
    //  in its place. As in Lua, this function may trigger a metamethod for the
    //  "index" event (see §2.4).
    //
    //  Returns the type of the pushed value.
function lua_getfield(L: Plua_state; idx: lua_Integer; k: PAnsiChar): lua_Integer; cdecl; external LUA_LIB;
    //  Pushes onto the stack the value t[k], where t is the value at the given
    //  index. As in Lua, this function may trigger a metamethod for the
    //  "index" event (see §2.4).
    //
    //  Returns the type of the pushed value.
function lua_rawget(L: Plua_State; idx: lua_Integer): lua_Integer; cdecl; external LUA_LIB;
    //  Similar to lua_gettable, but does a raw access (i.e., without
    //  metamethods).
function lua_rawgeti(L: Plua_State; index: lua_Integer; n: lua_TrueInteger): lua_Integer; cdecl; external LUA_LIB;
    //  Pushes onto the stack the value t[n], where t is the table at the given
    //  index. The access is raw, that is, it does not invoke the __index
    //  metamethod.
    //
    //  Returns the type of the pushed value.

procedure lua_setglobal(L: Plua_State; name: PAnsiChar); cdecl; external LUA_LIB;
procedure lua_pushvalue(L: Plua_State; index: lua_Integer); cdecl; external LUA_LIB;
    // Pushes a copy of the element at the given index onto the stack.
procedure lua_xmove(from, to_: Plua_State; n: lua_Integer); cdecl; external LUA_LIB;
procedure lua_pushnil(L: Plua_State); cdecl; external LUA_LIB;
procedure lua_pushinteger(L: Plua_State; n: lua_TrueInteger); cdecl; external LUA_LIB;
    // Pushes an integer with value n onto the stack.
procedure lua_pushnumber(L: Plua_State; n: lua_Number); cdecl; external LUA_LIB;
    //  Pushes a float with value n onto the stack.
procedure lua_pushcclosure(L: Plua_State; fn: lua_CFunction; n: lua_Integer); cdecl; external LUA_LIB;
procedure lua_pushcfunction(L: Plua_State; f: lua_CFunction); inline;
procedure lua_pushboolean(L: Plua_State; b: LongBool); cdecl; external LUA_LIB;
procedure lua_pushlightuserdata(L: Plua_State; p: Pointer); cdecl; external LUA_LIB;
procedure lua_pushstring(L: Plua_State; s: PAnsiChar); cdecl; external LUA_LIB;
procedure lua_pushlstring(L: Plua_State; s: PAnsiChar; len: SizeInt); cdecl; external LUA_LIB;
procedure lua_settop(L: Plua_State; idx: lua_Integer); cdecl; external LUA_LIB;
    // Accepts any index, or 0, and sets the stack top to this index. If the
    // new top is larger than the old one, then the new elements are filled
    // with nil. If index is 0, then all stack elements are removed.
procedure lua_pop(L: Plua_State; idx: lua_Integer); inline;
    //  Pops n elements from the stack.
procedure lua_rotate(L: Plua_State; idx, n: lua_Integer); cdecl; external LUA_LIB;
    //  Rotates the stack elements between the valid index idx and the top of
    //  the stack. The elements are rotated n positions in the direction of the
    //  top, for a positive n, or -n positions in the direction of the bottom,
    //  for a negative n. The absolute value of n must not be greater than the
    //  size of the slice being rotated. This function cannot be called with a
    //  pseudo-index, because a pseudo-index is not an actual stack position.
procedure lua_insert(L: Plua_State; idx: lua_Integer); inline;
    //  Moves the top element into the given valid index, shifting up the
    //  elements above this index to open space. Cannot be called with a
    //  pseudo-index, because a pseudo-index is not an actual stack position.
procedure lua_remove(L: Plua_State; idx: lua_Integer); inline;
    //  Removes the element at the given valid index, shifting down the
    //  elements above this index to fill the gap. This function cannot be
    //  called with a pseudo-index, because a pseudo-index is not an actual
    //  stack position.
procedure lua_register(L: Plua_State; n: PAnsiChar; f: lua_CFunction); inline;

//
// Metatables
//

function lua_setmetatable(L: Plua_State; objindex: lua_Integer): lua_Integer; cdecl; external LUA_LIB;
    // Pops a table from the stack and sets it as the new metatable for the
    // value at the given acceptable index.

procedure luaL_getmetatable(L: Plua_State; tname: PAnsiChar); cdecl; inline;
    // Pushes onto the stack the metatable associated with name tname in the
    // registry (see luaL_newmetatable) (nil if there is no metatable
    // associated with that name). Returns the type of the pushed value.

function luaL_newmetatable(L: Plua_State; tname: PAnsiChar): lua_Integer; cdecl; external LUA_LIB;
    //  If the registry already has the key tname, returns 0. Otherwise,
    //  creates a new table to be used as a metatable for userdata, adds to
    //  this new table the pair __name = tname, adds to the registry the pair
    //  [tname] = new table, and returns 1. (The entry __name is used by some
    //  error-reporting functions.)
    //
    //  In both cases pushes onto the stack the final value associated with
    //  tname in the registry.

function lua_getmetatable(L: Plua_State; index: lua_Integer): lua_Integer; cdecl; external LUA_LIB;
    //  If the value at the given index has a metatable, the function pushes
    //  that metatable onto the stack and returns 1. Otherwise, the function
    //  returns 0 and pushes nothing on the stack.

function luaL_checkudata(L: Plua_State; ud: lua_Integer; tname: PAnsiChar): Pointer; cdecl; external LUA_LIB;
    //  Checks whether the function argument arg is a userdata of the type
    //  tname (see luaL_newmetatable) and returns the userdata address (see
    //  lua_touserdata).

function lua_resume(L, from: Plua_State; narg: lua_Integer): lua_Integer; cdecl; external LUA_LIB;
function lua_status(L: Plua_State): lua_Integer; cdecl; external LUA_LIB;

function luaL_ref(L: Plua_State; t: lua_Integer): lua_Integer; cdecl; external LUA_LIB;
    //  Creates and returns a reference, in the table at index t, for the
    //  object at the top of the stack (and pops the object).
    //
    //  A reference is a unique integer key. As long as you do not manually add
    //  integer keys into table t, luaL_ref ensures the uniqueness of the key
    //  it returns. You can retrieve an object referred by reference r by
    //  calling lua_rawgeti(L, t, r). Function luaL_unref frees a reference and
    //  its associated object.
    //
    //  If the object at the top of the stack is nil, luaL_ref returns the
    //  constant LUA_REFNIL. The constant LUA_NOREF is guaranteed to be
    //  different from any reference returned by luaL_ref.
procedure luaL_unref(L: Plua_State; t, ref: lua_Integer); cdecl; external LUA_LIB;
    //  Releases reference ref from the table at index t (see luaL_ref). The
    //  entry is removed from the table, so that the referred object can be
    //  collected. The reference ref is also freed to be used again.
    //
    // If ref is LUA_NOREF or LUA_REFNIL, luaL_unref does nothing.

procedure lua_sethook(L: Plua_State; func: lua_Hook; mask: lua_Integer; count: lua_Integer); cdecl; external LUA_LIB;

function lua_upvalueindex(i: lua_Integer): lua_Integer; cdecl; inline;
function lua_setupvalue(L: Plua_State; funcindex, n: lua_Integer): PAnsiChar; cdecl; external LUA_LIB;
    //  Sets the value of a closure's upvalue. It assigns the value at the top
    //  of the stack to the upvalue and returns its name. It also pops the
    //  value from the stack.
    //
    // Returns NULL (and pops nothing) when the index n is greater than the
    // number of upvalues.
    //
    // Parameters funcindex and n are as in function lua_getupvalue.
function lua_getupvalue(L: Plua_State; funcindex, n: lua_Integer): PAnsiChar; cdecl; external LUA_LIB;

procedure lua_createtable(L: Plua_State; narr, nrec: lua_Integer); cdecl; external LUA_LIB;
procedure lua_setfield(L: Plua_State; idx: lua_Integer; k: PAnsiChar); cdecl; external LUA_LIB;
    //  Does the equivalent to t[k] = v, where t is the value at the given
    //  index and v is the value at the top of the stack.
    //
    //  This function pops the value from the stack. As in Lua, this function
    //  may trigger a metamethod for the "newindex" event (see §2.4).
function lua_newuserdata(L: Plua_State; sz: SizeInt): Pointer; cdecl; external LUA_LIB;

// libraries
function luaopen_base(L: Plua_State): lua_Integer; cdecl; external LUA_LIB;
function luaopen_coroutine(L: Plua_State): lua_Integer; cdecl; external LUA_LIB;
procedure luaL_openlibs(L: Plua_State); cdecl; external LUA_LIB;
function lua_tothread(L: Plua_State; idx: lua_Integer): Plua_State; cdecl; external LUA_LIB;

function lua_next(L: Plua_State; idx: lua_Integer): lua_Integer; cdecl; external LUA_LIB;
    //  Pops a key from the stack, and pushes a key-value pair from the table
    //  at the given index (the "next" pair after the given key). If there are
    //  no more elements in the table, then lua_next returns 0 (and pushes
    //  nothing).
    //
    //  While traversing a table, do not call lua_tolstring directly on a key,
    //  unless you know that the key is actually a string. Recall that
    //  lua_tolstring may change the value at the given index; this confuses
    //  the next call to lua_next.
    //
    //  See function next for the caveats of modifying the table during its
    //  traversal.

function luaL_error(L: Plua_State; fmt: PAnsiChar): lua_Integer; cdecl; varargs; external LUA_LIB;
    //  Raises an error. The error message format is given by fmt plus any
    //  extra arguments, following the same rules of lua_pushfstring. It also
    //  adds at the beginning of the message the file name and the line number
    //  where the error occurred, if this information is available.
    //
    //  This function never returns, but it is an idiom to use it in C
    //  functions as return luaL_error(args).

implementation

function lua_pcall(L: Plua_State; nargs, nresults, errf: lua_Integer): lua_Integer;
begin
  Result := lua_pcallk(L, nargs, nresults, errf, nil, nil);
end;

function lua_tointeger(L: Plua_State; index: lua_Integer): lua_TrueInteger;
begin
  Result := lua_tointegerx(L, index, nil);
end;

function lua_tonumber(L: Plua_State; index: lua_Integer): lua_Number; cdecl;
begin
  Result := lua_tonumberx(L, index, nil);
end;

function lua_tostring(L: Plua_State; index: lua_Integer): PAnsiChar;
begin
   Result := lua_tolstring(L, index, nil);
end;

procedure lua_pushcfunction(L: Plua_State; f: lua_CFunction);
begin
  lua_pushcclosure(L, f, 0);
end;

procedure lua_pop(L: Plua_State; idx: lua_Integer);
begin
  lua_settop(L, - idx - 1);
end;

procedure lua_insert(L: Plua_State; idx: lua_Integer);
begin
  lua_rotate(L, idx, 1);
end;

procedure lua_remove(L: Plua_State; idx: lua_Integer);
begin
  lua_rotate(L, idx, -1);
  lua_settop(L, -2);
end;

procedure lua_register(L: Plua_State; n: PAnsiChar; f: lua_CFunction);
begin
  lua_pushcfunction(L, f);
  lua_setglobal(L, n);
end;

function lua_isfunction(L: Plua_State; idx: lua_Integer): LongBool;
begin
  Result := lua_type(L, idx) = LUA_TFUNCTION;
end;

procedure luaL_getmetatable(L: Plua_State; tname: PAnsiChar); cdecl;
begin
  lua_getfield(L, LUA_REGISTRYINDEX, tname);
end;

function lua_upvalueindex(i: lua_Integer): lua_Integer; cdecl;
begin
   Result := LUA_REGISTRYINDEX - i;
end;

end.
