├── .gitignore ├── LICENSE ├── README.md ├── ada_lua.gpr ├── alire.toml ├── examples ├── example1 │ ├── example1.gpr │ ├── example1.lua │ └── src │ │ └── main.adb └── example2 │ ├── example2.gpr │ ├── example2.lua │ └── src │ └── main.adb └── src ├── lua-ada_limited_types.adb ├── lua-ada_limited_types.ads ├── lua-ada_types.adb ├── lua-ada_types.ads ├── lua-utils.adb ├── lua-utils.ads ├── lua.adb └── lua.ads /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.bexch 3 | *.ali 4 | 5 | lib/* 6 | obj/* 7 | examples/*/obj 8 | alire/ 9 | alire.lock 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023 Nicolas Roche 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ada-lua 2 | ======= 3 | 4 | An Ada binding for lua 5 | 6 | Example 7 | ------- 8 | 9 | This Ada program shows how to execute a Lua script from Ada 10 | 11 | ~~~ada 12 | -- The example show how to create a new lua state and launch a lua script 13 | 14 | with Lua; use Lua; 15 | with Ada.Text_IO; use Ada.Text_IO; 16 | with Ada.Exceptions; use Ada.Exceptions; 17 | 18 | function Main return Integer is 19 | S : constant Lua_State := New_State; 20 | -- Here we create a new state using New_State function 21 | 22 | Status : Lua_Return_Code; 23 | 24 | begin 25 | Open_Libs (S); 26 | -- Load the lua "standard" libraries 27 | 28 | Ada.Text_IO.Put_Line ("Load script"); 29 | Load_File (S, "../example1.lua"); 30 | -- Load a script. Note that loading a script does not execute it. This 31 | -- includes toplevel code. 32 | 33 | Ada.Text_IO.Put_Line ("Execute script"); 34 | Status := Lua.PCall (S); 35 | 36 | if Status /= LUA_OK then 37 | -- An error occurs during the execution 38 | Put_Line (Status'Img); 39 | Put_Line (To_Ada (S, -1)); 40 | return 1; 41 | end if; 42 | 43 | return 0; 44 | exception 45 | when E : Lua_Error => 46 | Put_Line (Exception_Message (E)); 47 | return 1; 48 | end Main; 49 | ~~~ 50 | -------------------------------------------------------------------------------- /ada_lua.gpr: -------------------------------------------------------------------------------- 1 | project Ada_Lua is 2 | 3 | for Library_Name use "Ada_Lua"; 4 | for Library_Version use "0.1.0"; 5 | 6 | for Source_Dirs use ("src"); 7 | for Object_Dir use "obj"; 8 | for Create_Missing_Dirs use "True"; 9 | for Library_Dir use "lib"; 10 | 11 | type Library_Type_Type is ("relocatable", "static", "static-pic"); 12 | Library_Type : Library_Type_Type := 13 | external ("ADA_LUA_LIBRARY_TYPE", external ("LIBRARY_TYPE", "static")); 14 | for Library_Kind use Library_Type; 15 | 16 | type Enabled_Kind is ("enabled", "disabled"); 17 | Compile_Checks : Enabled_Kind := External ("ADA_LUA_COMPILE_CHECKS", "disabled"); 18 | Runtime_Checks : Enabled_Kind := External ("ADA_LUA_RUNTIME_CHECKS", "disabled"); 19 | Style_Checks : Enabled_Kind := External ("ADA_LUA_STYLE_CHECKS", "disabled"); 20 | Contracts_Checks : Enabled_Kind := External ("ADA_LUA_CONTRACTS", "disabled"); 21 | 22 | type Build_Kind is ("debug", "optimize"); 23 | Build_Mode : Build_Kind := External ("ADA_LUA_BUILD_MODE", "debug"); 24 | 25 | Compile_Checks_Switches := (); 26 | case Compile_Checks is 27 | when "enabled" => 28 | Compile_Checks_Switches := 29 | ("-gnatwa", -- All warnings 30 | "-gnatVa", -- All validity checks 31 | "-gnatwe"); -- Warnings as errors 32 | when others => null; 33 | end case; 34 | 35 | Runtime_Checks_Switches := (); 36 | case Runtime_Checks is 37 | when "enabled" => null; 38 | when others => 39 | Runtime_Checks_Switches := 40 | ("-gnatp"); -- Supress checks 41 | end case; 42 | 43 | Style_Checks_Switches := (); 44 | case Style_Checks is 45 | when "enabled" => null; 46 | Style_Checks_Switches := 47 | ("-gnatyg", -- GNAT Style checks 48 | "-gnaty-d", -- Disable no DOS line terminators 49 | "-gnatyM80", -- Maximum line length 50 | "-gnatyO"); -- Overriding subprograms explicitly marked as such 51 | when others => null; 52 | end case; 53 | 54 | Contracts_Switches := (); 55 | case Contracts_Checks is 56 | when "enabled" => null; 57 | Contracts_Switches := 58 | ("-gnata"); -- Enable assertions and contracts 59 | when others => 60 | end case; 61 | 62 | Build_Switches := (); 63 | case Build_Mode is 64 | when "optimize" => 65 | Build_Switches := ("-O2", -- Optimization 66 | "-gnatn"); -- Enable inlining 67 | when "debug" => 68 | Build_Switches := ("-g", -- Debug info 69 | "-Og"); -- No optimization 70 | end case; 71 | 72 | package Compiler is 73 | for Default_Switches ("Ada") use 74 | Compile_Checks_Switches & 75 | Build_Switches & 76 | Runtime_Checks_Switches & 77 | Style_Checks_Switches & 78 | Contracts_Switches & 79 | ("-gnatQ"); -- Don't quit. Generate ALI and tree files even if illegalities 80 | end Compiler; 81 | 82 | package Binder is 83 | for Switches ("Ada") use ("-Es"); -- Symbolic traceback 84 | end Binder; 85 | 86 | end Ada_Lua; 87 | -------------------------------------------------------------------------------- /alire.toml: -------------------------------------------------------------------------------- 1 | name = "ada_lua" 2 | description = "An Ada binding for lua" 3 | version = "0.1.0" 4 | authors = ["Nicolas Roche "] 5 | maintainers = ["Nicolas Roche "] 6 | maintainers-logins = ["Nikokrock", "Fabien-Chouteau"] 7 | website = "https://github.com/adacore/ada-lua" 8 | licenses = ["GMGPL 3.0"] 9 | tags = ["lua", "binding", "script"] 10 | 11 | [[depends-on]] 12 | liblua = "~5.3" 13 | -------------------------------------------------------------------------------- /examples/example1/example1.gpr: -------------------------------------------------------------------------------- 1 | with "Lua"; 2 | 3 | project Example1 is 4 | 5 | for Languages use ("ada"); 6 | 7 | for Source_Dirs use ("src"); 8 | for Object_Dir use "obj"; 9 | for Main use ("main.adb"); 10 | 11 | package Compiler is 12 | for Default_Switches("ada") use ("-O2", 13 | "-gnat12", 14 | "-gnatwa", 15 | "-gnatyg"); 16 | end Compiler; 17 | 18 | package Linker is 19 | for Default_Switches("ada") use ("-L../..", "-llua"); 20 | end Linker; 21 | 22 | end Example1; 23 | -------------------------------------------------------------------------------- /examples/example1/example1.lua: -------------------------------------------------------------------------------- 1 | print("Hello from Lua") 2 | -------------------------------------------------------------------------------- /examples/example1/src/main.adb: -------------------------------------------------------------------------------- 1 | -- The example show how to create a new lua state and launch a lua script 2 | 3 | with Lua; use Lua; 4 | with Ada.Text_IO; use Ada.Text_IO; 5 | with Ada.Exceptions; use Ada.Exceptions; 6 | 7 | function Main return Integer is 8 | S : constant Lua_State := New_State; 9 | -- Here we create a new state using New_State function 10 | 11 | Status : Lua_Return_Code; 12 | 13 | begin 14 | Open_Libs (S); 15 | -- Load the lua "standard" libraries 16 | 17 | Ada.Text_IO.Put_Line ("Load script"); 18 | Load_File (S, "../example1.lua"); 19 | -- Load a script. Note that loading a script does not execute it. This 20 | -- includes toplevel code. 21 | 22 | Ada.Text_IO.Put_Line ("Execute script"); 23 | Status := Lua.PCall (S); 24 | 25 | if Status /= LUA_OK then 26 | -- An error occurs during the execution 27 | Put_Line (Status'Img); 28 | Put_Line (To_Ada (S, -1)); 29 | return 1; 30 | end if; 31 | 32 | return 0; 33 | exception 34 | when E : Lua_Error => 35 | Put_Line (Exception_Message (E)); 36 | return 1; 37 | end Main; 38 | -------------------------------------------------------------------------------- /examples/example2/example2.gpr: -------------------------------------------------------------------------------- 1 | with "Lua"; 2 | 3 | project Example2 is 4 | 5 | for Languages use ("ada"); 6 | 7 | for Source_Dirs use ("src"); 8 | for Object_Dir use "obj"; 9 | for Main use ("main.adb"); 10 | 11 | package Compiler is 12 | for Default_Switches("ada") use ("-O2", 13 | "-gnat12", 14 | "-gnatwa", 15 | "-gnatyg"); 16 | end Compiler; 17 | 18 | package Linker is 19 | for Default_Switches("ada") use ("-L../..", "-llua"); 20 | end Linker; 21 | 22 | end Example2; 23 | -------------------------------------------------------------------------------- /examples/example2/example2.lua: -------------------------------------------------------------------------------- 1 | print("Hello from Lua") 2 | 3 | function example2_fun () 4 | return "Hello from Lua function" 5 | end 6 | -------------------------------------------------------------------------------- /examples/example2/src/main.adb: -------------------------------------------------------------------------------- 1 | -- The example show how to create a new lua state and launch a lua script 2 | 3 | with Lua; use Lua; 4 | with Lua.Utils; use Lua.Utils; 5 | with Ada.Text_IO; use Ada.Text_IO; 6 | with Ada.Exceptions; use Ada.Exceptions; 7 | 8 | function Main return Integer is 9 | S : constant Lua_State := New_State; 10 | -- Here we create a new state using New_State function 11 | 12 | begin 13 | Open_Libs (S); 14 | -- Load the lua "standard" libraries 15 | 16 | Put_Line ("Load script"); 17 | Load_File (S, "../example2.lua"); 18 | -- Load a script. Note that loading a script does not execute it. This 19 | -- includes toplevel code. 20 | 21 | Put_Line ("Execute script"); 22 | PCall (S); 23 | -- A first execution is needed (kind of elaboration) 24 | 25 | -- Call a function declared in the script that return a string 26 | Put_Line (Call_Function (S, "example2_fun")); 27 | return 0; 28 | 29 | exception 30 | when E : Lua_Error => 31 | Put_Line ("exception: " & Exception_Message (E)); 32 | return 1; 33 | end Main; 34 | -------------------------------------------------------------------------------- /src/lua-ada_limited_types.adb: -------------------------------------------------------------------------------- 1 | with System.Address_To_Access_Conversions; 2 | 3 | package body Lua.Ada_Limited_Types is 4 | 5 | package Conv is new System.Address_To_Access_Conversions (Ada_Type); 6 | 7 | ------------------ 8 | -- New_Instance -- 9 | ------------------ 10 | 11 | function New_Instance (State : Lua_State) return Integer is 12 | Arg_Num : constant Lua_Index := Get_Top (State); 13 | Result : constant access Ada_Type := new Ada_Type; 14 | begin 15 | if Arg_Num /= 0 then 16 | Push (State, "no argument expected"); 17 | return Error (State); 18 | end if; 19 | 20 | Push (State, Result); 21 | return 1; 22 | end New_Instance; 23 | 24 | ---------- 25 | -- Push -- 26 | ---------- 27 | 28 | procedure Push (State : Lua_State; Data : access Ada_Type) is 29 | begin 30 | Push (State, Lua_Light_User_Data (Data.all'Address)); 31 | end Push; 32 | 33 | ------------ 34 | -- To_Ada -- 35 | ------------ 36 | 37 | function To_Ada 38 | (State : Lua_State; 39 | Index : Lua_Index) 40 | return access Ada_Type 41 | is 42 | User_Data : constant Lua_User_Data := To_Ada (State, Index); 43 | Result : constant access Ada_Type := 44 | Conv.To_Pointer (System.Address (User_Data)); 45 | 46 | begin 47 | return Result; 48 | end To_Ada; 49 | 50 | end Lua.Ada_Limited_Types; 51 | -------------------------------------------------------------------------------- /src/lua-ada_limited_types.ads: -------------------------------------------------------------------------------- 1 | -- Generic package that ease export and import to Lua of Ada limited types. 2 | -- Note that because of limitation of limited types, the To_Ada function 3 | -- returns an access to the value instead of the value itself. 4 | -- 5 | -- One approach to import a value from Lua is to do the following 6 | -- 7 | -- declare 8 | -- Var : Ada_Type renames To_Ada (State, -1); 9 | -- begin 10 | -- 11 | -- Note also that internally we are using light user data. In that case no 12 | -- user data can be associated with the Lua object, so we cannot perform any 13 | -- type checks when importing from Lua. 14 | 15 | generic 16 | type Ada_Type is limited private; 17 | package Lua.Ada_Limited_Types is 18 | 19 | procedure Push (State : Lua_State; Data : access Ada_Type); 20 | -- Push an Ada_Type value as a LightUserData Lua Type. 21 | 22 | function To_Ada 23 | (State : Lua_State; 24 | Index : Lua_Index) 25 | return access Ada_Type; 26 | -- Get an Ada_Type value from the stack at position Index. No type check 27 | -- is performed. 28 | 29 | function New_Instance (State : Lua_State) return Integer; 30 | -- Function that can be registered in Lua to create new instance of 31 | -- Ada_Type 32 | pragma Convention (C, New_Instance); 33 | 34 | end Lua.Ada_Limited_Types; 35 | -------------------------------------------------------------------------------- /src/lua-ada_types.adb: -------------------------------------------------------------------------------- 1 | with Ada.Unchecked_Conversion; 2 | 3 | package body Lua.Ada_Types is 4 | 5 | function Img2Addr is new Ada.Unchecked_Conversion 6 | (Image_Function, System.Address); 7 | function Addr2Img is new Ada.Unchecked_Conversion 8 | (System.Address, Image_Function); 9 | 10 | function Image_Lua_Wrapper (State : Lua_State) return Integer; 11 | pragma Convention (C, Image_Lua_Wrapper); 12 | -- Lua function registered as __tostring metamethod. The function is used 13 | -- to implement Register_Image_Function 14 | 15 | function Equal_To (State : Lua_State) return Integer; 16 | pragma Convention (C, Equal_To); 17 | -- Lua function used to implement the __eq metamethod 18 | 19 | procedure Create_Metatable (State : Lua_State); 20 | -- Initialize the metatable associated with Ada_Type object in Lua 21 | 22 | ---------------------- 23 | -- Create_Metatable -- 24 | ---------------------- 25 | 26 | procedure Create_Metatable (State : Lua_State) is 27 | begin 28 | -- We assume that the metatable is the top of the stack at the beginning 29 | -- of the procedure. 30 | Push (State, "__eq"); 31 | Push_Closure (State, Equal_To'Unrestricted_Access); 32 | Set_Table (State, -3); 33 | end Create_Metatable; 34 | 35 | -------------- 36 | -- Equal_To -- 37 | -------------- 38 | 39 | function Equal_To (State : Lua_State) return Integer is 40 | Left : constant Ada_Type := To_Ada (State, 1); 41 | Right : constant Ada_Type := To_Ada (State, 2); 42 | 43 | begin 44 | Push (State, Left = Right); 45 | return 1; 46 | end Equal_To; 47 | 48 | ----------------------- 49 | -- Image_Lua_Wrapper -- 50 | ----------------------- 51 | 52 | function Image_Lua_Wrapper (State : Lua_State) return Integer is 53 | -- Get the argument 54 | Arg : constant Ada_Type := To_Ada (State, 1); 55 | User_Data : constant Lua_User_Data := To_Ada (State, Upvalue_Index (1)); 56 | Fun : Image_Function; 57 | begin 58 | -- The Ada image function is an upvalue in the closure of our wrapper. 59 | Fun := Addr2Img (System.Address (User_Data)); 60 | Push (State, Fun (Arg)); 61 | return 1; 62 | end Image_Lua_Wrapper; 63 | 64 | ---------- 65 | -- Push -- 66 | ---------- 67 | 68 | procedure Push (State : Lua_State; Data : Ada_Type) 69 | is 70 | Result_Addr : constant System.Address := 71 | New_User_Data (State, Data'Size); 72 | Result : Ada_Type; 73 | pragma Import (C, Result); 74 | for Result'Address use Result_Addr; 75 | Ada_Type_Exists : constant Boolean := New_Metatable (State, Name); 76 | begin 77 | if not Ada_Type_Exists then 78 | Create_Metatable (State); 79 | end if; 80 | Result := Data; 81 | Set_Metatable (State, -2); 82 | end Push; 83 | 84 | -------------------- 85 | -- Register_Image -- 86 | -------------------- 87 | 88 | procedure Register_Image (State : Lua_State; Fun : Image_Function) is 89 | Ada_Type_Exists : constant Boolean := New_Metatable (State, Name); 90 | begin 91 | if not Ada_Type_Exists then 92 | Create_Metatable (State); 93 | end if; 94 | Push (State, "__tostring"); 95 | Push (State, Lua_Light_User_Data (Img2Addr (Fun))); 96 | Push_Closure (State, Image_Lua_Wrapper'Unrestricted_Access, 1); 97 | Set_Table (State, -3); 98 | Pop (State); 99 | end Register_Image; 100 | 101 | --------------------- 102 | -- Register_Object -- 103 | --------------------- 104 | 105 | procedure Register_Object 106 | (State : Lua_State; Name : String; Obj : Ada_Type) 107 | is 108 | begin 109 | Push (State, Obj); 110 | Register_Object (State, Name); 111 | end Register_Object; 112 | 113 | ------------ 114 | -- To_Ada -- 115 | ------------ 116 | 117 | function To_Ada 118 | (State : Lua_State; Index : Lua_Index) 119 | return Ada_Type 120 | is 121 | User_Data : constant Lua_User_Data := 122 | Test_User_Data (State, Index, Name); 123 | 124 | begin 125 | if User_Data = Lua_User_Data (System.Null_Address) then 126 | raise Lua_Type_Error 127 | with "expect type " & Name; 128 | end if; 129 | 130 | declare 131 | Result : Ada_Type; 132 | for Result'Address use System.Address (User_Data); 133 | pragma Import (C, Result); 134 | begin 135 | return Result; 136 | end; 137 | end To_Ada; 138 | 139 | end Lua.Ada_Types; 140 | -------------------------------------------------------------------------------- /src/lua-ada_types.ads: -------------------------------------------------------------------------------- 1 | generic 2 | Name : String; 3 | type Ada_Type is private; 4 | 5 | package Lua.Ada_Types is 6 | 7 | procedure Push (State : Lua_State; Data : Ada_Type); 8 | -- Push an Ada_Type value as a UserData Lua Type. Note that the type name 9 | -- is saved as a user data value in order to be able to perform type check 10 | -- when reimporting to ada. 11 | 12 | function To_Ada (State : Lua_State; Index : Lua_Index) return Ada_Type; 13 | -- Get an Ada_Type value from the stack. In case of type error 14 | -- Lua_Type_Error is raised 15 | 16 | procedure Register_Object 17 | (State : Lua_State; Name : String; Obj : Ada_Type); 18 | -- Register an Ada_Type object in the global environment. See 19 | -- Lua.Register_Object for more details. 20 | 21 | type Image_Function is access function (Data : Ada_Type) return String; 22 | 23 | procedure Register_Image (State : Lua_State; Fun : Image_Function); 24 | -- Register a function to be used for the __tostring metamethod. 25 | 26 | end Lua.Ada_Types; 27 | -------------------------------------------------------------------------------- /src/lua-utils.adb: -------------------------------------------------------------------------------- 1 | package body Lua.Utils is 2 | 3 | ------------------- 4 | -- Call_Function -- 5 | ------------------- 6 | 7 | function Call_Function (State : Lua_State; Name : String) return String 8 | is 9 | begin 10 | Get_Global (State, Name); 11 | PCall (State, 0, 1); 12 | 13 | declare 14 | Result : constant String := To_Ada (State, -1); 15 | begin 16 | Pop (State); 17 | return Result; 18 | end; 19 | end Call_Function; 20 | 21 | function Call_Function 22 | (State : Lua_State; 23 | Name : String; 24 | Arg : String) 25 | return String 26 | is 27 | begin 28 | Get_Global (State, Name); 29 | Push (State, Arg); 30 | PCall (State, 1, 1); 31 | 32 | declare 33 | Result : constant String := To_Ada (State, -1); 34 | begin 35 | Pop (State); 36 | return Result; 37 | end; 38 | end Call_Function; 39 | 40 | end Lua.Utils; 41 | -------------------------------------------------------------------------------- /src/lua-utils.ads: -------------------------------------------------------------------------------- 1 | package Lua.Utils is 2 | 3 | function Call_Function (State : Lua_State; Name : String) return String; 4 | -- call a lua function that takes no parameter and return a string 5 | 6 | function Call_Function 7 | (State : Lua_State; 8 | Name : String; 9 | Arg : String) 10 | return String; 11 | -- call a lua function that takes a string as parameter and return a 12 | -- string 13 | end Lua.Utils; 14 | -------------------------------------------------------------------------------- /src/lua.adb: -------------------------------------------------------------------------------- 1 | with Interfaces.C.Strings; use Interfaces.C.Strings; 2 | 3 | package body Lua is 4 | 5 | LUAI_MAXSTACK : constant Lua_Index := 1000000; 6 | LUAI_FIRSTPSEUDOIDX : constant Lua_Index := -LUAI_MAXSTACK - 1000; 7 | LUA_REGISTRYINDEX : constant Lua_Index := LUAI_FIRSTPSEUDOIDX; 8 | 9 | ----------------- 10 | -- Check_Stack -- 11 | ----------------- 12 | 13 | function Check_Stack (State : Lua_State; N : Integer) return Boolean 14 | is 15 | function Internal (State : Lua_State; N : Integer) return Integer; 16 | pragma Import (C, Internal, "lua_checkstack"); 17 | begin 18 | if Internal (State, N) = 0 then 19 | return False; 20 | else 21 | return True; 22 | end if; 23 | end Check_Stack; 24 | 25 | --------------------- 26 | -- Check_User_Data -- 27 | --------------------- 28 | 29 | function Check_User_Data 30 | (State : Lua_State; 31 | Index : Lua_Index; 32 | Name : String) 33 | return Lua_User_Data 34 | is 35 | function Internal 36 | (State : Lua_State; 37 | Index : Lua_Index; 38 | Str : chars_ptr) 39 | return Lua_User_Data; 40 | pragma Import (C, Internal, "luaL_checkudata"); 41 | 42 | Str_Ptr : chars_ptr := New_String (Name); 43 | Result : constant Lua_User_Data := Internal (State, Index, Str_Ptr); 44 | begin 45 | Free (Str_Ptr); 46 | return Result; 47 | end Check_User_Data; 48 | 49 | ------------- 50 | -- Compare -- 51 | ------------- 52 | 53 | function Compare 54 | (State : Lua_State; 55 | Index1 : Lua_Index; 56 | Index2 : Lua_Index; 57 | Operator : Lua_Compare_Op) 58 | return Boolean 59 | is 60 | function Internal 61 | (State : Lua_State; 62 | Index1 : Lua_Index; 63 | Index2 : Lua_Index; 64 | Operator : Lua_Compare_Op) 65 | return Integer; 66 | pragma Import (C, Internal, "lua_compare"); 67 | begin 68 | if Internal (State, Index1, Index2, Operator) = 0 then 69 | return False; 70 | else 71 | return True; 72 | end if; 73 | end Compare; 74 | 75 | --------------- 76 | -- Get_Field -- 77 | --------------- 78 | 79 | procedure Get_Field 80 | (State : Lua_State; 81 | Index : Lua_Index; 82 | Name : String) 83 | is 84 | 85 | procedure Internal 86 | (State : Lua_State; 87 | Index : Lua_Index; 88 | Name : chars_ptr); 89 | pragma Import (C, Internal, "lua_getfield"); 90 | 91 | Result : chars_ptr := New_String (Name); 92 | 93 | begin 94 | 95 | Internal (State, Index, Result); 96 | Free (Result); 97 | end Get_Field; 98 | 99 | ---------------- 100 | -- Get_Global -- 101 | ---------------- 102 | 103 | procedure Get_Global 104 | (State : Lua_State; 105 | Name : String) 106 | is 107 | procedure Internal 108 | (State : Lua_State; 109 | Name : chars_ptr); 110 | pragma Import (C, Internal, "lua_getglobal"); 111 | 112 | Name_Ptr : chars_ptr := New_String (Name); 113 | begin 114 | Internal (State, Name_Ptr); 115 | Free (Name_Ptr); 116 | end Get_Global; 117 | 118 | ------------------- 119 | -- Get_Metatable -- 120 | ------------------- 121 | 122 | procedure Get_Metatable 123 | (State : Lua_State; 124 | Name : String) 125 | is 126 | begin 127 | Get_Field (State, LUA_REGISTRYINDEX, Name); 128 | end Get_Metatable; 129 | 130 | ----------------- 131 | -- Is_Function -- 132 | ----------------- 133 | 134 | function Is_Function 135 | (State : Lua_State; 136 | Index : Lua_Index) 137 | return Boolean 138 | is 139 | 140 | function Internal 141 | (State : Lua_State; 142 | Index : Lua_Index) 143 | return Integer; 144 | pragma Import (C, Internal, "lua_iscfunction"); 145 | 146 | Result : constant Integer := Internal (State, Index); 147 | begin 148 | if Result = 1 then 149 | return True; 150 | else 151 | return False; 152 | end if; 153 | end Is_Function; 154 | 155 | --------------- 156 | -- Is_Number -- 157 | --------------- 158 | 159 | function Is_Number (State : Lua_State; Index : Lua_Index) return Boolean is 160 | 161 | function Internal 162 | (State : Lua_State; 163 | Index : Lua_Index) 164 | return Integer; 165 | pragma Import (C, Internal, "lua_isnumber"); 166 | 167 | Result : constant Integer := Internal (State, Index); 168 | begin 169 | if Result = 1 then 170 | return True; 171 | else 172 | return False; 173 | end if; 174 | end Is_Number; 175 | 176 | --------------- 177 | -- Is_String -- 178 | --------------- 179 | 180 | function Is_String (State : Lua_State; Index : Lua_Index) return Boolean is 181 | 182 | function Internal 183 | (State : Lua_State; 184 | Index : Lua_Index) 185 | return Integer; 186 | pragma Import (C, Internal, "lua_isstring"); 187 | 188 | Result : constant Integer := Internal (State, Index); 189 | begin 190 | if Result = 1 then 191 | return True; 192 | else 193 | return False; 194 | end if; 195 | end Is_String; 196 | 197 | ------------------ 198 | -- Is_User_Data -- 199 | ------------------ 200 | 201 | function Is_User_Data 202 | (State : Lua_State; 203 | Index : Lua_Index) 204 | return Boolean 205 | is 206 | 207 | function Internal 208 | (State : Lua_State; 209 | Index : Lua_Index) 210 | return Integer; 211 | pragma Import (C, Internal, "lua_isuserdata"); 212 | 213 | Result : constant Integer := Internal (State, Index); 214 | begin 215 | if Result = 1 then 216 | return True; 217 | else 218 | return False; 219 | end if; 220 | end Is_User_Data; 221 | 222 | --------------- 223 | -- Load_File -- 224 | --------------- 225 | 226 | function Load_File 227 | (State : Lua_State; 228 | Filename : String; 229 | Mode : String := "") 230 | return Lua_Return_Code 231 | is 232 | function Internal 233 | (State : Lua_State; 234 | Filename : chars_ptr; 235 | Mode : chars_ptr) 236 | return Lua_Return_Code; 237 | pragma Import (C, Internal, "luaL_loadfilex"); 238 | 239 | Filename_Ptr : chars_ptr := New_String (Filename); 240 | Mode_Ptr : chars_ptr := Null_Ptr; 241 | Result : Lua_Return_Code; 242 | begin 243 | if Mode /= "" then 244 | Mode_Ptr := New_String (Mode); 245 | end if; 246 | 247 | Result := Internal (State, Filename_Ptr, Mode_Ptr); 248 | 249 | if Mode_Ptr /= Null_Ptr then 250 | Free (Mode_Ptr); 251 | end if; 252 | 253 | Free (Filename_Ptr); 254 | 255 | return Result; 256 | end Load_File; 257 | 258 | --------------- 259 | -- Load_File -- 260 | --------------- 261 | 262 | procedure Load_File 263 | (State : Lua_State; 264 | Filename : String; 265 | Mode : String := "") 266 | is 267 | Result : constant Lua_Return_Code := Load_File (State, Filename, Mode); 268 | 269 | begin 270 | if Result /= LUA_OK then 271 | declare 272 | Error_Msg : constant String := To_Ada (State, -1); 273 | begin 274 | Pop (State); 275 | raise Lua_Error with Result'Img & ": " & Error_Msg; 276 | end; 277 | end if; 278 | end Load_File; 279 | 280 | ----------------- 281 | -- Load_String -- 282 | ----------------- 283 | 284 | procedure Load_String 285 | (State : Lua_State; 286 | Str : String) 287 | is 288 | function Internal 289 | (State : Lua_State; 290 | Str : chars_ptr) 291 | return Lua_Return_Code; 292 | pragma Import (C, Internal, "luaL_loadstring"); 293 | 294 | Str_Ptr : chars_ptr := New_String (Str); 295 | Result : constant Lua_Return_Code := Internal (State, Str_Ptr); 296 | begin 297 | Free (Str_Ptr); 298 | 299 | if Result /= LUA_OK then 300 | declare 301 | Error_Msg : constant String := To_Ada (State, -1); 302 | begin 303 | Pop (State); 304 | raise Lua_Error with Result'Img & ": " & Error_Msg; 305 | end; 306 | end if; 307 | end Load_String; 308 | 309 | ------------------- 310 | -- New_Metatable -- 311 | ------------------- 312 | 313 | function New_Metatable (State : Lua_State; Name : String) return Boolean 314 | is 315 | function Internal 316 | (State : Lua_State; 317 | Str : chars_ptr) 318 | return Integer; 319 | pragma Import (C, Internal, "luaL_newmetatable"); 320 | 321 | Str_Ptr : chars_ptr := New_String (Name); 322 | Result : constant Integer := Internal (State, Str_Ptr); 323 | begin 324 | Free (Str_Ptr); 325 | if Result = 0 then 326 | return False; 327 | else 328 | return True; 329 | end if; 330 | end New_Metatable; 331 | 332 | procedure New_Metatable (State : Lua_State; Name : String) is 333 | Status : constant Boolean := New_Metatable (State, Name); 334 | pragma Unreferenced (Status); 335 | begin 336 | null; 337 | end New_Metatable; 338 | 339 | ---------- 340 | -- Next -- 341 | ---------- 342 | 343 | function Next (State : Lua_State; Index : Lua_Index) return Boolean 344 | is 345 | function Internal (State : Lua_State; Index : Lua_Index) return Integer; 346 | pragma Import (C, Internal, "lua_next"); 347 | 348 | Result : constant Integer := Internal (State, Index); 349 | begin 350 | if Result = 0 then 351 | return False; 352 | else 353 | return True; 354 | end if; 355 | end Next; 356 | 357 | ----------- 358 | -- PCall -- 359 | ----------- 360 | 361 | procedure PCall 362 | (State : Lua_State; 363 | Nargs : Integer := 0; 364 | NResults : Integer := 0; 365 | Err_Fun : Integer := 0; 366 | Context : Integer := 0; 367 | Cont_Fun : Lua_Function := null) 368 | is 369 | Result : constant Lua_Return_Code := PCall 370 | (State, Nargs, NResults, Err_Fun, Context, Cont_Fun); 371 | 372 | begin 373 | if Result /= LUA_OK then 374 | declare 375 | Error_Msg : constant String := To_Ada (State, -1); 376 | begin 377 | Pop (State); 378 | raise Lua_Error with Result'Img & ": " & Error_Msg; 379 | end; 380 | end if; 381 | end PCall; 382 | 383 | ------------ 384 | -- Insert -- 385 | ------------ 386 | procedure Insert (State : Lua_State; Index : Lua_Index) 387 | is 388 | begin 389 | -- lua.h definition 390 | -- #define lua_insert(L,idx) lua_rotate(L, (idx), 1) 391 | Rotate (State, From => Index, To => 1); 392 | end Insert; 393 | 394 | ------------ 395 | -- Remove -- 396 | ------------ 397 | procedure Remove (State : Lua_State; Index : Lua_Index) 398 | is 399 | begin 400 | -- lua.h definition 401 | -- #define lua_remove(L,idx) (lua_rotate(L,(idx),-1), lua_pop(L,1)) 402 | Rotate (State, From => Index, To => -1); 403 | Pop (State); 404 | end Remove; 405 | 406 | ------------- 407 | -- Replace -- 408 | ------------- 409 | procedure Replace (State : Lua_State; Index : Lua_Index) 410 | is 411 | begin 412 | -- lua.h definition 413 | -- #define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1)) 414 | Copy (State, From => -1, To => Index); 415 | Pop (State); 416 | end Replace; 417 | 418 | --------- 419 | -- Pop -- 420 | --------- 421 | 422 | procedure Pop 423 | (State : Lua_State; 424 | N : Integer := 1) 425 | is 426 | begin 427 | Set_Top (State, -N - 1); 428 | end Pop; 429 | 430 | ---------- 431 | -- Push -- 432 | ---------- 433 | 434 | procedure Push (State : Lua_State) is 435 | procedure Internal (State : Lua_State); 436 | pragma Import (C, Internal, "lua_pushnil"); 437 | 438 | begin 439 | Internal (State); 440 | end Push; 441 | 442 | ---------- 443 | -- Push -- 444 | ---------- 445 | 446 | procedure Push (State : Lua_State; Data : Lua_Float) is 447 | 448 | procedure Internal (State : Lua_State; Data : Lua_Float); 449 | pragma Import (C, Internal, "lua_pushnumber"); 450 | begin 451 | Internal (State, Data); 452 | end Push; 453 | 454 | ---------- 455 | -- Push -- 456 | ---------- 457 | 458 | procedure Push (State : Lua_State; Data : Lua_Integer) is 459 | 460 | procedure Internal (State : Lua_State; Data : Lua_Integer); 461 | pragma Import (C, Internal, "lua_pushinteger"); 462 | begin 463 | Internal (State, Data); 464 | end Push; 465 | 466 | ---------- 467 | -- Push -- 468 | ---------- 469 | 470 | procedure Push (State : Lua_State; Data : Lua_Unsigned) is 471 | Signed_Data : constant Lua_Integer := Lua_Integer (Data); 472 | 473 | begin 474 | Push (State, Signed_Data); 475 | end Push; 476 | 477 | ---------- 478 | -- Push -- 479 | ---------- 480 | 481 | procedure Push (State : Lua_State; Data : Lua_Light_User_Data) 482 | is 483 | procedure Internal (State : Lua_State; Data : Lua_Light_User_Data); 484 | pragma Import (C, Internal, "lua_pushlightuserdata"); 485 | begin 486 | Internal (State, Data); 487 | end Push; 488 | 489 | ---------- 490 | -- Push -- 491 | ---------- 492 | 493 | procedure Push (State : Lua_State; Data : Boolean) is 494 | procedure Internal (State : Lua_State; Data : Integer); 495 | pragma Import (C, Internal, "lua_pushboolean"); 496 | begin 497 | if Data then 498 | Internal (State, 1); 499 | else 500 | Internal (State, 0); 501 | end if; 502 | end Push; 503 | 504 | ---------- 505 | -- Push -- 506 | ---------- 507 | 508 | procedure Push (State : Lua_State; Data : String) is 509 | function Internal 510 | (State : Lua_State; 511 | Str_Addr : System.Address; 512 | Str_Size : size_t) 513 | return Interfaces.C.Strings.chars_ptr; 514 | pragma Import (C, Internal, "lua_pushlstring"); 515 | 516 | Result : chars_ptr; 517 | pragma Unreferenced (Result); 518 | begin 519 | Result := Internal (State, Data'Address, Data'Length); 520 | end Push; 521 | 522 | ----------------------- 523 | -- Register_Function -- 524 | ----------------------- 525 | 526 | procedure Register_Function 527 | (State : Lua_State; 528 | Name : String; 529 | Fun : Lua_Function) 530 | is 531 | begin 532 | Push_Closure (State, Fun); 533 | Register_Object (State, Name); 534 | end Register_Function; 535 | 536 | --------------------- 537 | -- Register_Object -- 538 | --------------------- 539 | 540 | procedure Register_Object 541 | (State : Lua_State; 542 | Name : String) 543 | is 544 | Start : Integer := Name'First; 545 | Is_First : Boolean := True; 546 | Need_Global : Boolean := False; 547 | Pop_Times : Integer := 0; 548 | Set_Table_Times : Integer := 0; 549 | Global_First, Global_Last : Integer := 0; 550 | Obj_Index : constant Lua_Index := 551 | Absolute_Index (State, -1); 552 | begin 553 | -- check that name does not start or ends with . and cannot be empty 554 | -- ??? 555 | 556 | for Index in Name'Range loop 557 | if Name (Index) = '.' then 558 | 559 | declare 560 | Name_Comp : constant String := Name (Start .. Index - 1); 561 | Comp_Type : Lua_Type; 562 | begin 563 | 564 | if Is_First then 565 | Get_Global (State, Name_Comp); 566 | Comp_Type := Get_Type (State, -1); 567 | Global_First := Start; 568 | Global_Last := Index - 1; 569 | else 570 | Get_Field (State, -1, Name_Comp); 571 | Comp_Type := Get_Type (State, -1); 572 | end if; 573 | 574 | if Comp_Type = LUA_TNIL then 575 | -- Create the table 576 | Pop (State); 577 | if not Is_First then 578 | Push (State, Name_Comp); 579 | Set_Table_Times := Set_Table_Times + 1; 580 | else 581 | 582 | Need_Global := True; 583 | end if; 584 | 585 | Create_Table (State); 586 | 587 | elsif Comp_Type /= LUA_TTABLE then 588 | raise Lua_Type_Error with "expecting table"; 589 | else 590 | Pop_Times := Pop_Times + 1; 591 | end if; 592 | 593 | Is_First := False; 594 | end; 595 | Start := Index + 1; 596 | end if; 597 | end loop; 598 | 599 | if Start = Name'First then 600 | Set_Global (State, Name); 601 | else 602 | Push_Value (State, Obj_Index); 603 | -- At least one dot has been found so create a hierarchy 604 | Set_Field (State, -2, Name (Start .. Name'Last), 605 | Override => False); 606 | 607 | for J in 1 .. Set_Table_Times loop 608 | Set_Table (State, -3); 609 | end loop; 610 | 611 | if Pop_Times > 0 then 612 | Pop (State, Pop_Times); 613 | end if; 614 | 615 | if Need_Global then 616 | Set_Global (State, Name (Global_First .. Global_Last)); 617 | end if; 618 | 619 | -- Remove the object from the stack 620 | Pop (State); 621 | end if; 622 | end Register_Object; 623 | 624 | --------------- 625 | -- Set_Field -- 626 | --------------- 627 | 628 | procedure Set_Field 629 | (State : Lua_State; 630 | Index : Lua_Index; 631 | Name : String; 632 | Override : Boolean := True) 633 | is 634 | 635 | procedure Internal 636 | (State : Lua_State; 637 | Index : Lua_Index; 638 | Name : chars_ptr); 639 | pragma Import (C, Internal, "lua_setfield"); 640 | 641 | Result : chars_ptr := New_String (Name); 642 | begin 643 | if not Override then 644 | Get_Field (State, Index, Name); 645 | if Get_Type (State, -1) /= LUA_TNIL then 646 | Pop (State); 647 | Free (Result); 648 | raise Lua_Override_Error with "element already set"; 649 | end if; 650 | Pop (State); 651 | end if; 652 | Internal (State, Index, Result); 653 | Free (Result); 654 | end Set_Field; 655 | 656 | --------------- 657 | -- Set_Field -- 658 | --------------- 659 | 660 | procedure Set_Field 661 | (State : Lua_State; 662 | Index : Lua_Index; 663 | Name : String; 664 | Fun : Lua_Function; 665 | Override : Boolean := True) 666 | is 667 | Table_Index : constant Lua_Index := Absolute_Index (State, Index); 668 | begin 669 | Push_Closure (State, Fun); 670 | begin 671 | Set_Field (State, Table_Index, Name, Override); 672 | exception 673 | when Lua_Override_Error => 674 | Pop (State); 675 | raise; 676 | end; 677 | end Set_Field; 678 | 679 | ---------------- 680 | -- Set_Global -- 681 | ---------------- 682 | 683 | procedure Set_Global 684 | (State : Lua_State; 685 | Name : String) 686 | is 687 | 688 | procedure Internal 689 | (State : Lua_State; 690 | Name : chars_ptr); 691 | pragma Import (C, Internal, "lua_setglobal"); 692 | 693 | Name_Ptr : chars_ptr := New_String (Name); 694 | begin 695 | Internal (State, Name_Ptr); 696 | Free (Name_Ptr); 697 | end Set_Global; 698 | 699 | ------------------- 700 | -- Set_Metatable -- 701 | ------------------- 702 | 703 | procedure Set_Metatable 704 | (State : Lua_State; 705 | Name : String) 706 | is 707 | procedure Internal 708 | (State : Lua_State; 709 | Str : chars_ptr); 710 | pragma Import (C, Internal, "luaL_setmetatable"); 711 | 712 | Str_Ptr : chars_ptr := New_String (Name); 713 | begin 714 | Internal (State, Str_Ptr); 715 | Free (Str_Ptr); 716 | end Set_Metatable; 717 | 718 | -------------------- 719 | -- Test_User_Data -- 720 | -------------------- 721 | 722 | function Test_User_Data 723 | (State : Lua_State; 724 | Index : Lua_Index; 725 | Name : String) 726 | return Lua_User_Data 727 | is 728 | function Internal 729 | (State : Lua_State; 730 | Index : Lua_Index; 731 | Str : chars_ptr) 732 | return Lua_User_Data; 733 | pragma Import (C, Internal, "luaL_testudata"); 734 | 735 | Str_Ptr : chars_ptr := New_String (Name); 736 | Result : constant Lua_User_Data := Internal (State, Index, Str_Ptr); 737 | begin 738 | Free (Str_Ptr); 739 | return Result; 740 | end Test_User_Data; 741 | 742 | ------------ 743 | -- To_Ada -- 744 | ------------ 745 | 746 | function To_Ada 747 | (State : Lua_State; 748 | Index : Lua_Index) 749 | return Lua_Function 750 | is 751 | 752 | function Internal 753 | (State : Lua_State; 754 | Index : Lua_Index) 755 | return Lua_Function; 756 | pragma Import (C, Internal, "lua_tocfunction"); 757 | begin 758 | return Internal (State, Index); 759 | end To_Ada; 760 | 761 | ------------ 762 | -- To_Ada -- 763 | ------------ 764 | 765 | function To_Ada 766 | (State : Lua_State; 767 | Index : Lua_Index) 768 | return Lua_User_Data 769 | is 770 | function Internal 771 | (State : Lua_State; 772 | Index : Lua_Index) 773 | return System.Address; 774 | pragma Import (C, Internal, "lua_touserdata"); 775 | 776 | begin 777 | return Lua_User_Data (Internal (State, Index)); 778 | end To_Ada; 779 | 780 | ------------ 781 | -- To_Ada -- 782 | ------------ 783 | 784 | function To_Ada 785 | (State : Lua_State; 786 | Index : Lua_Index) 787 | return Lua_State 788 | is 789 | function Internal 790 | (State : Lua_State; Index : Lua_Index) return Lua_State; 791 | pragma Import (C, Internal, "lua_tothread"); 792 | begin 793 | return Internal (State, Index); 794 | end To_Ada; 795 | 796 | ------------ 797 | -- To_Ada -- 798 | ------------ 799 | 800 | function To_Ada 801 | (State : Lua_State; 802 | Index : Lua_Index) 803 | return Lua_Float 804 | is 805 | function Internal 806 | (State : Lua_State; 807 | Index : Lua_Index; 808 | Success : in out Integer) 809 | return Lua_Float; 810 | pragma Import (C, Internal, "lua_tonumberx"); 811 | 812 | Success : Integer := 0; 813 | Result : constant Lua_Float := Internal (State, Index, Success); 814 | begin 815 | if Success = 0 then 816 | raise Lua_Type_Error with "an float was expected"; 817 | end if; 818 | 819 | return Result; 820 | end To_Ada; 821 | 822 | ------------ 823 | -- To_Ada -- 824 | ------------ 825 | 826 | function To_Ada 827 | (State : Lua_State; 828 | Index : Lua_Index) 829 | return Lua_Integer 830 | is 831 | function Internal 832 | (State : Lua_State; 833 | Index : Lua_Index; 834 | Success : in out Integer) 835 | return Lua_Integer; 836 | pragma Import (C, Internal, "lua_tointegerx"); 837 | 838 | Success : Integer := 0; 839 | Result : constant Lua_Integer := Internal (State, Index, Success); 840 | begin 841 | if Success = 0 then 842 | raise Lua_Type_Error with "an integer was expected"; 843 | end if; 844 | 845 | return Result; 846 | end To_Ada; 847 | 848 | ------------ 849 | -- To_Ada -- 850 | ------------ 851 | 852 | function To_Ada 853 | (State : Lua_State; 854 | Index : Lua_Index) 855 | return Lua_Unsigned 856 | is 857 | Result_Signed : constant Lua_Integer := To_Ada (State, Index); 858 | Result : Lua_Unsigned; 859 | begin 860 | Result := Lua_Unsigned (Result_Signed); 861 | return Result; 862 | exception 863 | when Constraint_Error => 864 | raise Lua_Type_Error with "an unsigned integer was expected"; 865 | end To_Ada; 866 | 867 | ------------ 868 | -- To_Ada -- 869 | ------------ 870 | 871 | function To_Ada 872 | (State : Lua_State; 873 | Index : Lua_Index) 874 | return Boolean 875 | is 876 | function Internal 877 | (State : Lua_State; 878 | Index : Lua_Index) 879 | return Integer; 880 | pragma Import (C, Internal, "lua_toboolean"); 881 | begin 882 | if Internal (State, Index) = 0 then 883 | return False; 884 | else 885 | return True; 886 | end if; 887 | end To_Ada; 888 | 889 | ------------ 890 | -- To_Ada -- 891 | ------------ 892 | 893 | function To_Ada 894 | (State : Lua_State; 895 | Index : Lua_Index) 896 | return String 897 | is 898 | function Internal 899 | (State : Lua_State; 900 | Index : Integer; 901 | Length : out size_t) 902 | return chars_ptr; 903 | pragma Import (C, Internal, "lua_tolstring"); 904 | 905 | Length : size_t; 906 | begin 907 | return Value (Internal (State, Index, Length)); 908 | end To_Ada; 909 | 910 | --------------- 911 | -- Type_Name -- 912 | --------------- 913 | 914 | function Type_Name 915 | (State : Lua_State; 916 | Index : Lua_Index) 917 | return String 918 | is 919 | 920 | function Internal 921 | (State : Lua_State; Index : Lua_Index) 922 | return chars_ptr; 923 | pragma Import (C, Internal, "lua_typename"); 924 | 925 | Result : constant chars_ptr := Internal (State, Index); 926 | begin 927 | return Value (Result); 928 | end Type_Name; 929 | 930 | function Upvalue_Index (N : Positive) return Lua_Index is 931 | begin 932 | return LUA_REGISTRYINDEX - N; 933 | end Upvalue_Index; 934 | end Lua; 935 | -------------------------------------------------------------------------------- /src/lua.ads: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nikokrock/ada-lua/7c5c03413a35a3b0e57903a633b0b5243e0d5e7f/src/lua.ads --------------------------------------------------------------------------------