diff --git a/Applications/LuaRunner/LuaNetRunner.cs b/Applications/LuaRunner/LuaNetRunner.cs index 719c9b155bd09d2bbd3f047f9b5e6865b3cce130..8918af06fee637a7f6458d1cbb31fed96d401ac2 100644 --- a/Applications/LuaRunner/LuaNetRunner.cs +++ b/Applications/LuaRunner/LuaNetRunner.cs @@ -1,98 +1,98 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Threading; -using LuaInterface; - -/* - * Application to run Lua scripts that can use LuaInterface - * from the console - * - * Author: Fabio Mascarenhas - * Version: 1.0 - */ -namespace LuaRunner -{ - public class LuaNetRunner - { - /* - * Runs the Lua script passed as the first command-line argument. - * It passed all the command-line arguments to the script. - */ - [STAThread] // steffenj: testluaform.lua "Load" button complained with an exception that STAThread was missing - public static void Main(string[] args) - { - if(args.Length > 0) - { - // For attaching from the debugger - // Thread.Sleep(20000); - - using(Lua lua = new Lua()) - { - //lua.OpenLibs(); // steffenj: Lua 5.1.1 API change (all libs already opened in Lua constructor!) - lua.NewTable("arg"); - LuaTable argc = (LuaTable)lua["arg"]; - argc[-1] = "LuaRunner"; - argc[0] = args[0]; - - for(int i = 1; i < args.Length; i++) - argc[i] = args[i]; - - argc["n"] = args.Length - 1; - - try - { - //Console.WriteLine("DoFile(" + args[0] + ");"); - lua.DoFile(args[0]); - } - catch(Exception e) - { - // steffenj: BEGIN error message improved, output is now in decending order of importance (message, where, stacktrace) - // limit size of strack traceback message to roughly 1 console screen height - string trace = e.StackTrace; - - if(e.StackTrace.Length > 1300) - trace = e.StackTrace.Substring(0, 1300) + " [...] (traceback cut short)"; - - Console.WriteLine(); - Console.WriteLine(e.Message); - Console.WriteLine(e.Source + " raised a " + e.GetType().ToString()); - Console.WriteLine(trace); - - // wait for keypress if there is an error - Console.ReadKey(); - // steffenj: END error message improved - } - } - } - else - { - Console.WriteLine("LuaRunner -- runs Lua scripts with CLR access"); - Console.WriteLine("Usage: luarunner [{}]"); - } - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Threading; +using LuaInterface; + +/* + * Application to run Lua scripts that can use LuaInterface + * from the console + * + * Author: Fabio Mascarenhas + * Version: 1.0 + */ +namespace LuaRunner +{ + public class LuaNetRunner + { + /* + * Runs the Lua script passed as the first command-line argument. + * It passed all the command-line arguments to the script. + */ + [STAThread] // steffenj: testluaform.lua "Load" button complained with an exception that STAThread was missing + public static void Main(string[] args) + { + if(args.Length > 0) + { + // For attaching from the debugger + // Thread.Sleep(20000); + + using(Lua lua = new Lua()) + { + //lua.OpenLibs(); // steffenj: Lua 5.1.1 API change (all libs already opened in Lua constructor!) + lua.NewTable("arg"); + LuaTable argc = (LuaTable)lua["arg"]; + argc[-1] = "LuaRunner"; + argc[0] = args[0]; + + for(int i = 1; i < args.Length; i++) + argc[i] = args[i]; + + argc["n"] = args.Length - 1; + + try + { + //Console.WriteLine("DoFile(" + args[0] + ");"); + lua.DoFile(args[0]); + } + catch(Exception e) + { + // steffenj: BEGIN error message improved, output is now in decending order of importance (message, where, stacktrace) + // limit size of strack traceback message to roughly 1 console screen height + string trace = e.StackTrace; + + if(e.StackTrace.Length > 1300) + trace = e.StackTrace.Substring(0, 1300) + " [...] (traceback cut short)"; + + Console.WriteLine(); + Console.WriteLine(e.Message); + Console.WriteLine(e.Source + " raised a " + e.GetType().ToString()); + Console.WriteLine(trace); + + // wait for keypress if there is an error + Console.ReadKey(); + // steffenj: END error message improved + } + } + } + else + { + Console.WriteLine("LuaRunner -- runs Lua scripts with CLR access"); + Console.WriteLine("Usage: luarunner [{}]"); + } + } + } } \ No newline at end of file diff --git a/Applications/LuaRunner/LuaRunner.csproj b/Applications/LuaRunner/LuaRunner.csproj index 507166403866c5e2b30173c83eec95df51bf8166..1fa785b14734f8a403334954d7b701e90c405cfd 100644 --- a/Applications/LuaRunner/LuaRunner.csproj +++ b/Applications/LuaRunner/LuaRunner.csproj @@ -1,97 +1,97 @@ - - - - Debug - x86 - 9.0.21022 - 2.0 - {3CE4CCB6-3465-43E3-B5ED-5FB9B70D20E5} - Exe - Properties - LuaRunner - LuaRunner - 2.x - - - true - full - false - ..\..\Run\Debug - DEBUG - prompt - 4 - x86 - AllRules.ruleset - - - none - true - ..\..\Run\Release - RELEASE - prompt - 4 - x86 - AllRules.ruleset - - - true - full - false - ..\..\Run\Debug_x64 - DEBUG - prompt - 4 - x64 - AllRules.ruleset - - - none - true - ..\..\Run\Release_x64 - RELEASE - prompt - 4 - x64 - AllRules.ruleset - - - - - - - - - - - - - {F55CABBB-4108-4A39-94E1-581FD46DC021} - LuaInterface - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - + + + + Debug + x86 + 9.0.21022 + 2.0 + {3CE4CCB6-3465-43E3-B5ED-5FB9B70D20E5} + Exe + Properties + LuaRunner + LuaRunner + 2.x + + + true + full + false + ..\..\Run\Debug + DEBUG + prompt + 4 + x86 + AllRules.ruleset + + + none + true + ..\..\Run\Release + RELEASE + prompt + 4 + x86 + AllRules.ruleset + + + true + full + false + ..\..\Run\Debug_x64 + DEBUG + prompt + 4 + x64 + AllRules.ruleset + + + none + true + ..\..\Run\Release_x64 + RELEASE + prompt + 4 + x64 + AllRules.ruleset + + + + + + + + + + + + + {F55CABBB-4108-4A39-94E1-581FD46DC021} + LuaInterface + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + \ No newline at end of file diff --git a/Applications/LuaRunner/LuaRunner.make b/Applications/LuaRunner/LuaRunner.make new file mode 100644 index 0000000000000000000000000000000000000000..d284992c77bede6cc741b57d6d71b4a36876bd7d --- /dev/null +++ b/Applications/LuaRunner/LuaRunner.make @@ -0,0 +1,124 @@ + + +# Warning: This is an automatically generated file, do not edit! + +if ENABLE_DEBUG_X86 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize- -debug "-define:DEBUG" +ASSEMBLY = ../../Run/Debug/LuaRunner.exe +ASSEMBLY_MDB = $(ASSEMBLY).mdb +COMPILE_TARGET = exe +PROJECT_REFERENCES = \ + ../../Run/Debug/LuaInterface.dll +BUILD_DIR = ../../Run/Debug + +LUARUNNER_EXE_MDB_SOURCE=../../Run/Debug/LuaRunner.exe.mdb +LUARUNNER_EXE_MDB=$(BUILD_DIR)/LuaRunner.exe.mdb +LUAINTERFACE_DLL_SOURCE=../../Run/Debug/LuaInterface.dll +KOPILUA_DLL_SOURCE=../../Run/Debug/KopiLua.dll + +endif + +if ENABLE_RELEASE_X86 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize+ "-define:RELEASE" +ASSEMBLY = ../../Run/Release/LuaRunner.exe +ASSEMBLY_MDB = +COMPILE_TARGET = exe +PROJECT_REFERENCES = \ + ../../Run/Release/LuaInterface.dll +BUILD_DIR = ../../Run/Release + +LUARUNNER_EXE_MDB= +LUAINTERFACE_DLL_SOURCE=../../Run/Release/LuaInterface.dll +KOPILUA_DLL_SOURCE=../../Run/Release/KopiLua.dll + +endif + +if ENABLE_DEBUG_X64 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize- -debug "-define:DEBUG" +ASSEMBLY = ../../Run/Debug_x64/LuaRunner.exe +ASSEMBLY_MDB = $(ASSEMBLY).mdb +COMPILE_TARGET = exe +PROJECT_REFERENCES = \ + ../../Run/Debug_x64/LuaInterface.dll +BUILD_DIR = ../../Run/Debug_x64 + +LUARUNNER_EXE_MDB_SOURCE=../../Run/Debug_x64/LuaRunner.exe.mdb +LUARUNNER_EXE_MDB=$(BUILD_DIR)/LuaRunner.exe.mdb +LUAINTERFACE_DLL_SOURCE=../../Run/Debug_x64/LuaInterface.dll +KOPILUA_DLL_SOURCE=../../Run/Debug_x64/KopiLua.dll + +endif + +if ENABLE_RELEASE_X64 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize+ "-define:RELEASE" +ASSEMBLY = ../../Run/Release_x64/LuaRunner.exe +ASSEMBLY_MDB = +COMPILE_TARGET = exe +PROJECT_REFERENCES = \ + ../../Run/Release_x64/LuaInterface.dll +BUILD_DIR = ../../Run/Release_x64 + +LUARUNNER_EXE_MDB= +LUAINTERFACE_DLL_SOURCE=../../Run/Release_x64/LuaInterface.dll +KOPILUA_DLL_SOURCE=../../Run/Release_x64/KopiLua.dll + +endif + +AL=al +SATELLITE_ASSEMBLY_NAME=$(notdir $(basename $(ASSEMBLY))).resources.dll + +PROGRAMFILES = \ + $(LUARUNNER_EXE_MDB) \ + $(LUAINTERFACE_DLL) \ + $(KOPILUA_DLL) + +BINARIES = \ + $(LUARUNNER) + + +RESGEN=resgen2 + +all: $(ASSEMBLY) $(PROGRAMFILES) $(BINARIES) + +FILES = \ + LuaNetRunner.cs \ + Properties/AssemblyInfo.cs + +DATA_FILES = + +RESOURCES = + +EXTRAS = \ + luarunner.in + +REFERENCES = \ + System \ + System.Data \ + System.Xml + +DLL_REFERENCES = + +CLEANFILES = $(PROGRAMFILES) $(BINARIES) + +include $(top_srcdir)/Makefile.include + +LUAINTERFACE_DLL = $(BUILD_DIR)/LuaInterface.dll +KOPILUA_DLL = $(BUILD_DIR)/KopiLua.dll +LUARUNNER = $(BUILD_DIR)/luarunner + +$(eval $(call emit-deploy-wrapper,LUARUNNER,luarunner,x)) + + +$(eval $(call emit_resgen_targets)) +$(build_xamlg_list): %.xaml.g.cs: %.xaml + xamlg '$<' + +$(ASSEMBLY_MDB): $(ASSEMBLY) + +$(ASSEMBLY): $(build_sources) $(build_resources) $(build_datafiles) $(DLL_REFERENCES) $(PROJECT_REFERENCES) $(build_xamlg_list) $(build_satellite_assembly_list) + mkdir -p $(shell dirname $(ASSEMBLY)) + $(ASSEMBLY_COMPILER_COMMAND) $(ASSEMBLY_COMPILER_FLAGS) -out:$(ASSEMBLY) -target:$(COMPILE_TARGET) $(build_sources_embed) $(build_resources_embed) $(build_references_ref) diff --git a/Applications/LuaRunner/Makefile.am b/Applications/LuaRunner/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..455748ddedc8be878a3150058ba522b2c5a582a4 --- /dev/null +++ b/Applications/LuaRunner/Makefile.am @@ -0,0 +1,19 @@ + +EXTRA_DIST = + +#Warning: This is an automatically generated file, do not edit! +if ENABLE_DEBUG_X86 + SUBDIRS = . +endif +if ENABLE_RELEASE_X86 + SUBDIRS = . +endif +if ENABLE_DEBUG_X64 + SUBDIRS = . +endif +if ENABLE_RELEASE_X64 + SUBDIRS = . +endif + +# Projekt-specifikus makefile beszúrása +include LuaRunner.make \ No newline at end of file diff --git a/Applications/LuaRunner/Properties/AssemblyInfo.cs b/Applications/LuaRunner/Properties/AssemblyInfo.cs index fde026c0a2f40a27445419be18f51ac942e54d91..acc3f96e55bf57ea2ecbddb08f4573b64c43b126 100644 --- a/Applications/LuaRunner/Properties/AssemblyInfo.cs +++ b/Applications/LuaRunner/Properties/AssemblyInfo.cs @@ -1,59 +1,59 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using LuaInterface.Config; - -// Information about this assembly is defined by the following attributes. -// Change them to the values specific to your project. - -[assembly: AssemblyTitle("LuaRunner")] -[assembly: AssemblyDescription(Consts.LuaInterfaceDescription)] -[assembly: AssemblyConfiguration(Consts.LuaInterfaceConfiguration)] -[assembly: AssemblyCompany(Consts.LuaInterfaceCompany)] -[assembly: AssemblyProduct(Consts.LuaInterfaceProduct)] -[assembly: AssemblyCopyright(Consts.LuaInterfaceCopyright)] -[assembly: AssemblyTrademark(Consts.LuaInterfaceTrademark)] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.5.2")] +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using LuaInterface.Config; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("LuaRunner")] +[assembly: AssemblyDescription(Consts.LuaInterfaceDescription)] +[assembly: AssemblyConfiguration(Consts.LuaInterfaceConfiguration)] +[assembly: AssemblyCompany(Consts.LuaInterfaceCompany)] +[assembly: AssemblyProduct(Consts.LuaInterfaceProduct)] +[assembly: AssemblyCopyright(Consts.LuaInterfaceCopyright)] +[assembly: AssemblyTrademark(Consts.LuaInterfaceTrademark)] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.5.2")] [assembly: AssemblyFileVersion("1.5.2")] \ No newline at end of file diff --git a/Applications/LuaRunner/luarunner.in b/Applications/LuaRunner/luarunner.in new file mode 100644 index 0000000000000000000000000000000000000000..c2a177dc9ff989f3ce45f2c258ed1e021bd2aa89 --- /dev/null +++ b/Applications/LuaRunner/luarunner.in @@ -0,0 +1,3 @@ +#!/bin/sh + +exec mono "@expanded_libdir@/@PACKAGE@/LuaRunner.exe" "$@" diff --git a/COPYRIGHT b/COPYRIGHT index df96280e5514b089d75a3bf00fe3daec4fc5e20d..5a382c86e46a6cbbf6631f75ccc1e540e297cf36 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -1,76 +1,76 @@ -LuaInterface License --------------------- - -LuaInterface is licensed under the terms of the MIT license reproduced below. -This mean that LuaInterface is free software and can be used for both academic and -commercial purposes at absolutely no cost. - -=============================================================================== - -Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. -Copyright (C) 2012 Megax - -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: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -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. - -=============================================================================== - -Kopi Lua License ----------------- - -Kopi Lua is licensed under the terms of the MIT license. Both the MIT -license and the original Lua copyright notice are reproduced below. - -Please see http://www.ppl-pilot.com/KopiLua for details. - -=============================================================================== - -Lua License ------------ - -Lua is licensed under the terms of the MIT license reproduced below. -This means that Lua is free software and can be used for both academic -and commercial purposes at absolutely no cost. - -For details and rationale, see http://www.lua.org/license.html . - -=============================================================================== - -Copyright (C) 1994-2008 Lua.org, PUC-Rio. - -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: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -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. - -=============================================================================== - -(end of COPYRIGHT) +LuaInterface License +-------------------- + +LuaInterface is licensed under the terms of the MIT license reproduced below. +This mean that LuaInterface is free software and can be used for both academic and +commercial purposes at absolutely no cost. + +=============================================================================== + +Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. +Copyright (C) 2012 Megax + +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: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +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. + +=============================================================================== + +Kopi Lua License +---------------- + +Kopi Lua is licensed under the terms of the MIT license. Both the MIT +license and the original Lua copyright notice are reproduced below. + +Please see http://www.ppl-pilot.com/KopiLua for details. + +=============================================================================== + +Lua License +----------- + +Lua is licensed under the terms of the MIT license reproduced below. +This means that Lua is free software and can be used for both academic +and commercial purposes at absolutely no cost. + +For details and rationale, see http://www.lua.org/license.html . + +=============================================================================== + +Copyright (C) 1994-2008 Lua.org, PUC-Rio. + +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: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +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. + +=============================================================================== + +(end of COPYRIGHT) diff --git a/Core/KopiLua/KopiLua.csproj b/Core/KopiLua/KopiLua.csproj index 4aa15af11b12e66d9b163ab6b1bd8cdbd441d459..ed2dcdf186bbc17275609bfc5121eba47d53129e 100644 --- a/Core/KopiLua/KopiLua.csproj +++ b/Core/KopiLua/KopiLua.csproj @@ -1,126 +1,126 @@ - - - - Debug - x86 - 9.0.30729 - 2.0 - {E8DDBC21-EF74-4ABA-9C49-BFC702BE25D8} - Library - Properties - Lua - KopiLua - 2.x - - - true - full - false - ..\..\Run\Debug - TRACE;DEBUG;LUA_CORE;_WIN32;LUA_COMPAT_VARARG;LUA_COMPAT_MOD;LUA_COMPAT_GFIND;CATCH_EXCEPTIONS - prompt - 4 - x86 - AllRules.ruleset - - - none - true - ..\..\Run\Release - TRACE;RELEASE;LUA_CORE;_WIN32;LUA_COMPAT_VARARG;LUA_COMPAT_MOD;LUA_COMPAT_GFIND;CATCH_EXCEPTIONS - prompt - 4 - x86 - AllRules.ruleset - - - true - full - false - ..\..\Run\Debug_x64 - TRACE;DEBUG;LUA_CORE;_WIN32;LUA_COMPAT_VARARG;LUA_COMPAT_MOD;LUA_COMPAT_GFIND;CATCH_EXCEPTIONS - prompt - 4 - x64 - AllRules.ruleset - - - none - true - ..\..\Run\Release_x64 - TRACE;RELEASE;LUA_CORE;_WIN32;LUA_COMPAT_VARARG;LUA_COMPAT_MOD;LUA_COMPAT_GFIND;CATCH_EXCEPTIONS - prompt - 4 - x64 - AllRules.ruleset - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - Клиентский профиль .NET Framework 3.5 SP1 - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Установщик Windows 3.1 - true - - - - + + + + Debug + x86 + 9.0.30729 + 2.0 + {E8DDBC21-EF74-4ABA-9C49-BFC702BE25D8} + Library + Properties + Lua + KopiLua + 2.x + + + true + full + false + ..\..\Run\Debug + TRACE;DEBUG;LUA_CORE;_WIN32;LUA_COMPAT_VARARG;LUA_COMPAT_MOD;LUA_COMPAT_GFIND;CATCH_EXCEPTIONS + prompt + 4 + x86 + AllRules.ruleset + + + none + true + ..\..\Run\Release + TRACE;RELEASE;LUA_CORE;_WIN32;LUA_COMPAT_VARARG;LUA_COMPAT_MOD;LUA_COMPAT_GFIND;CATCH_EXCEPTIONS + prompt + 4 + x86 + AllRules.ruleset + + + true + full + false + ..\..\Run\Debug_x64 + TRACE;DEBUG;LUA_CORE;_WIN32;LUA_COMPAT_VARARG;LUA_COMPAT_MOD;LUA_COMPAT_GFIND;CATCH_EXCEPTIONS + prompt + 4 + x64 + AllRules.ruleset + + + none + true + ..\..\Run\Release_x64 + TRACE;RELEASE;LUA_CORE;_WIN32;LUA_COMPAT_VARARG;LUA_COMPAT_MOD;LUA_COMPAT_GFIND;CATCH_EXCEPTIONS + prompt + 4 + x64 + AllRules.ruleset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + Клиентский профиль .NET Framework 3.5 SP1 + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Установщик Windows 3.1 + true + + + + \ No newline at end of file diff --git a/Core/KopiLua/Makefile.am b/Core/KopiLua/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..331cf34d691a3bed2d2b4fe0dd9a5b7cce282ec0 --- /dev/null +++ b/Core/KopiLua/Makefile.am @@ -0,0 +1,144 @@ + +EXTRA_DIST = + +# Warning: This is an automatically generated file, do not edit! + +if ENABLE_DEBUG_X86 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize- -debug "-define:TRACE;DEBUG;LUA_CORE;_WIN32;LUA_COMPAT_VARARG;LUA_COMPAT_MOD;LUA_COMPAT_GFIND;CATCH_EXCEPTIONS" +ASSEMBLY = ../../Run/Debug/KopiLua.dll +ASSEMBLY_MDB = $(ASSEMBLY).mdb +COMPILE_TARGET = library +PROJECT_REFERENCES = +BUILD_DIR = ../../Run/Debug + +KOPILUA_DLL_MDB_SOURCE=../../Run/Debug/KopiLua.dll.mdb +KOPILUA_DLL_MDB=$(BUILD_DIR)/KopiLua.dll.mdb + +endif + +if ENABLE_RELEASE_X86 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize+ "-define:TRACE;RELEASE;LUA_CORE;_WIN32;LUA_COMPAT_VARARG;LUA_COMPAT_MOD;LUA_COMPAT_GFIND;CATCH_EXCEPTIONS" +ASSEMBLY = ../../Run/Release/KopiLua.dll +ASSEMBLY_MDB = +COMPILE_TARGET = library +PROJECT_REFERENCES = +BUILD_DIR = ../../Run/Release + +KOPILUA_DLL_MDB= + +endif + +if ENABLE_DEBUG_X64 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize- -debug "-define:TRACE;DEBUG;LUA_CORE;_WIN32;LUA_COMPAT_VARARG;LUA_COMPAT_MOD;LUA_COMPAT_GFIND;CATCH_EXCEPTIONS" +ASSEMBLY = ../../Run/Debug_x64/KopiLua.dll +ASSEMBLY_MDB = $(ASSEMBLY).mdb +COMPILE_TARGET = library +PROJECT_REFERENCES = +BUILD_DIR = ../../Run/Debug_x64 + +KOPILUA_DLL_MDB_SOURCE=../../Run/Debug_x64/KopiLua.dll.mdb +KOPILUA_DLL_MDB=$(BUILD_DIR)/KopiLua.dll.mdb + +endif + +if ENABLE_RELEASE_X64 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize+ "-define:TRACE;RELEASE;LUA_CORE;_WIN32;LUA_COMPAT_VARARG;LUA_COMPAT_MOD;LUA_COMPAT_GFIND;CATCH_EXCEPTIONS" +ASSEMBLY = ../../Run/Release_x64/KopiLua.dll +ASSEMBLY_MDB = +COMPILE_TARGET = library +PROJECT_REFERENCES = +BUILD_DIR = ../../Run/Release_x64 + +KOPILUA_DLL_MDB= + +endif + +AL=al +SATELLITE_ASSEMBLY_NAME=$(notdir $(basename $(ASSEMBLY))).resources.dll + +PROGRAMFILES = \ + $(KOPILUA_DLL_MDB) + +LINUX_PKGCONFIG = \ + $(KOPILUA_PC) + + +RESGEN=resgen2 + +all: $(ASSEMBLY) $(PROGRAMFILES) $(LINUX_PKGCONFIG) + +FILES = \ + lapi.cs \ + lauxlib.cs \ + lbaselib.cs \ + lcode.cs \ + ldblib.cs \ + ldebug.cs \ + ldo.cs \ + ldump.cs \ + lfunc.cs \ + lgc.cs \ + linit.cs \ + liolib.cs \ + llex.cs \ + llimits.cs \ + lmathlib.cs \ + lmem.cs \ + loadlib.cs \ + lobject.cs \ + lopcodes.cs \ + loslib.cs \ + lparser.cs \ + lstate.cs \ + lstring.cs \ + lstrlib.cs \ + ltable.cs \ + ltablib.cs \ + ltm.cs \ + lua.cs \ + luaconf.cs \ + lualib.cs \ + lundump.cs \ + lvm.cs \ + lzio.cs \ + print.cs \ + printf/Tools.cs \ + Properties/AssemblyInfo.cs + +DATA_FILES = + +RESOURCES = + +EXTRAS = \ + kopilua.pc.in + +REFERENCES = \ + System \ + System.Core \ + System.Data.DataSetExtensions \ + System.Data + +DLL_REFERENCES = + +CLEANFILES = $(PROGRAMFILES) $(LINUX_PKGCONFIG) + +include $(top_srcdir)/Makefile.include + +KOPILUA_PC = $(BUILD_DIR)/kopilua.pc + +$(eval $(call emit-deploy-wrapper,KOPILUA_PC,kopilua.pc)) + + +$(eval $(call emit_resgen_targets)) +$(build_xamlg_list): %.xaml.g.cs: %.xaml + xamlg '$<' + +$(ASSEMBLY_MDB): $(ASSEMBLY) + +$(ASSEMBLY): $(build_sources) $(build_resources) $(build_datafiles) $(DLL_REFERENCES) $(PROJECT_REFERENCES) $(build_xamlg_list) $(build_satellite_assembly_list) + mkdir -p $(shell dirname $(ASSEMBLY)) + $(ASSEMBLY_COMPILER_COMMAND) $(ASSEMBLY_COMPILER_FLAGS) -out:$(ASSEMBLY) -target:$(COMPILE_TARGET) $(build_sources_embed) $(build_resources_embed) $(build_references_ref) diff --git a/Core/KopiLua/Properties/AssemblyInfo.cs b/Core/KopiLua/Properties/AssemblyInfo.cs index 08fdbe92e3fd598e4519359dec10e941ea0be4fb..25bafc59640890b63c20de3288f695a29f08177b 100644 --- a/Core/KopiLua/Properties/AssemblyInfo.cs +++ b/Core/KopiLua/Properties/AssemblyInfo.cs @@ -1,39 +1,39 @@ -using System; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("KopiLua")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("KopiLua")] -[assembly: AssemblyCopyright("Copyright © 2009 Mark Feldman")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -[assembly: CLSCompliantAttribute(true)] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("1a9cd761-692f-40db-8566-c0217e5d3e0a")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("KopiLua")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("KopiLua")] +[assembly: AssemblyCopyright("Copyright © 2009 Mark Feldman")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: CLSCompliantAttribute(true)] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1a9cd761-692f-40db-8566-c0217e5d3e0a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/Core/KopiLua/Properties/AssemblyInfo_KopiLua_wp7.cs b/Core/KopiLua/Properties/AssemblyInfo_KopiLua_wp7.cs index 955140e2ea017dfef7a47f79b261b1f5a4ed4e10..c3e77652772370d922e5891fc802affa78265d16 100644 --- a/Core/KopiLua/Properties/AssemblyInfo_KopiLua_wp7.cs +++ b/Core/KopiLua/Properties/AssemblyInfo_KopiLua_wp7.cs @@ -1,37 +1,37 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Resources; - -// Управление общими сведениями о сборке осуществляется с помощью следующего -// набора атрибутов. Измените значения этих атрибутов для изменения -// сведений о сборке. -[assembly: AssemblyTitle("KopiLua_wp7")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("MICROSOFT")] -[assembly: AssemblyProduct("KopiLua_wp7")] -[assembly: AssemblyCopyright("Copyright © 2012 Gerasimov Sergey")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Если для ComVisible установить значение false, типы в этой сборке не будут поддерживаться -// COM-компонентами. При необходимости доступа к какому-либо типу в этой сборке -// из модели COM задайте для атрибута ComVisible этого типа значение true. -[assembly: ComVisible(false)] - -// Следующий GUID служит для идентификации библиотеки типов, если данный проект видим для COM -[assembly: Guid("63906a16-e4d0-4ad7-ba8f-cb4d6c29d2d5")] - -// Сведения о версии сборки состоят из следующих четырех значений: -// -// Основной номер версии -// Дополнительный номер версии -// Номер построения -// Редакция -// -// Можно указать все значения или задать для номеров редакции и построения значения по умолчанию -// с помощью символа '*', как показано ниже: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] -[assembly: NeutralResourcesLanguageAttribute("ru-RU")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Resources; + +// Управление общими сведениями о сборке осуществляется с помощью следующего +// набора атрибутов. Измените значения этих атрибутов для изменения +// сведений о сборке. +[assembly: AssemblyTitle("KopiLua_wp7")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("MICROSOFT")] +[assembly: AssemblyProduct("KopiLua_wp7")] +[assembly: AssemblyCopyright("Copyright © 2012 Gerasimov Sergey")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Если для ComVisible установить значение false, типы в этой сборке не будут поддерживаться +// COM-компонентами. При необходимости доступа к какому-либо типу в этой сборке +// из модели COM задайте для атрибута ComVisible этого типа значение true. +[assembly: ComVisible(false)] + +// Следующий GUID служит для идентификации библиотеки типов, если данный проект видим для COM +[assembly: Guid("63906a16-e4d0-4ad7-ba8f-cb4d6c29d2d5")] + +// Сведения о версии сборки состоят из следующих четырех значений: +// +// Основной номер версии +// Дополнительный номер версии +// Номер построения +// Редакция +// +// Можно указать все значения или задать для номеров редакции и построения значения по умолчанию +// с помощью символа '*', как показано ниже: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: NeutralResourcesLanguageAttribute("ru-RU")] diff --git a/Core/KopiLua/Properties/AssemblyInfo_Lua.cs b/Core/KopiLua/Properties/AssemblyInfo_Lua.cs index d0c0c035d6022a450848ef0e23c2b84539f53def..254a54aa673d311775facbff706633592a23a747 100644 --- a/Core/KopiLua/Properties/AssemblyInfo_Lua.cs +++ b/Core/KopiLua/Properties/AssemblyInfo_Lua.cs @@ -1,36 +1,36 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Lua")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Lua")] -[assembly: AssemblyCopyright("Copyright © Mark Feldman 2009")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("42f29687-47be-4860-a332-c7c4c75b7119")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Lua")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Lua")] +[assembly: AssemblyCopyright("Copyright © Mark Feldman 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("42f29687-47be-4860-a332-c7c4c75b7119")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Core/KopiLua/Properties/AssemblyInfo_Luac.cs b/Core/KopiLua/Properties/AssemblyInfo_Luac.cs index cfe14272c5d27f1b42e845c6cf1cbb95336274a8..5867632d8feda2dc625d32d5e8365d160ef08dc4 100644 --- a/Core/KopiLua/Properties/AssemblyInfo_Luac.cs +++ b/Core/KopiLua/Properties/AssemblyInfo_Luac.cs @@ -1,36 +1,36 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Luac")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Luac")] -[assembly: AssemblyCopyright("Copyright © Mark Feldman 2009")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("403d5192-280f-4171-98e6-c818dd6b9981")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Luac")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Luac")] +[assembly: AssemblyCopyright("Copyright © Mark Feldman 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("403d5192-280f-4171-98e6-c818dd6b9981")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Core/KopiLua/kopilua.pc.in b/Core/KopiLua/kopilua.pc.in new file mode 100644 index 0000000000000000000000000000000000000000..31cc01546a03e7c95ce7db76f6e4518c4b1c17de --- /dev/null +++ b/Core/KopiLua/kopilua.pc.in @@ -0,0 +1,6 @@ +Name: KopiLua +Description: KopiLua +Version: 2.x + +Requires: +Libs: -r:@expanded_libdir@/@PACKAGE@/KopiLua.dll diff --git a/Core/KopiLua/lapi.cs b/Core/KopiLua/lapi.cs index 68e1002a6904a4b16dbb56e281bf78bb221ecbf2..a2e4e1f2ec6d8404d92762f9fae018cd54e8dd81 100644 --- a/Core/KopiLua/lapi.cs +++ b/Core/KopiLua/lapi.cs @@ -1,1107 +1,1107 @@ -/* -** $Id: lapi.c,v 2.55.1.5 2008/07/04 18:41:18 roberto Exp $ -** Lua API -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -namespace KopiLua -{ - using lu_mem = System.UInt32; - using TValue = Lua.lua_TValue; - using StkId = Lua.lua_TValue; - using lua_Integer = System.Int32; - using lua_Number = System.Double; - using ptrdiff_t = System.Int32; - using ZIO = Lua.Zio; - - public partial class Lua - { - public const string lua_ident = - "$Lua: " + LUA_RELEASE + " " + LUA_COPYRIGHT + " $\n" + - "$Authors: " + LUA_AUTHORS + " $\n" + - "$URL: www.lua.org $\n"; - - public static void api_checknelems(lua_State L, int n) - { - api_check(L, n <= L.top - L.base_); - } - - public static void api_checkvalidindex(lua_State L, StkId i) - { - api_check(L, i != luaO_nilobject); - } - - public static void api_incr_top(lua_State L) - { - api_check(L, L.top < L.ci.top); - StkId.inc(ref L.top); - } - - - - static TValue index2adr (lua_State L, int idx) { - if (idx > 0) { - TValue o = L.base_ + (idx - 1); - api_check(L, idx <= L.ci.top - L.base_); - if (o >= L.top) return luaO_nilobject; - else return o; - } - else if (idx > LUA_REGISTRYINDEX) { - api_check(L, idx != 0 && -idx <= L.top - L.base_); - return L.top + idx; - } - else switch (idx) { /* pseudo-indices */ - case LUA_REGISTRYINDEX: return registry(L); - case LUA_ENVIRONINDEX: { - Closure func = curr_func(L); - sethvalue(L, L.env, func.c.env); - return L.env; - } - case LUA_GLOBALSINDEX: return gt(L); - default: { - Closure func = curr_func(L); - idx = LUA_GLOBALSINDEX - idx; - return (idx <= func.c.nupvalues) - ? func.c.upvalue[idx-1] - : (TValue)luaO_nilobject; - } - } - } - - - private static Table getcurrenv (lua_State L) { - if (L.ci == L.base_ci[0]) /* no enclosing function? */ - return hvalue(gt(L)); /* use global table as environment */ - else { - Closure func = curr_func(L); - return func.c.env; - } - } - - - public static void luaA_pushobject (lua_State L, TValue o) { - setobj2s(L, L.top, o); - api_incr_top(L); - } - - - public static int lua_checkstack (lua_State L, int size) { - int res = 1; - lua_lock(L); - if (size > LUAI_MAXCSTACK || (L.top - L.base_ + size) > LUAI_MAXCSTACK) - res = 0; /* stack overflow */ - else if (size > 0) { - luaD_checkstack(L, size); - if (L.ci.top < L.top + size) - L.ci.top = L.top + size; - } - lua_unlock(L); - return res; - } - - - public static void lua_xmove (lua_State from, lua_State to, int n) { - int i; - if (from == to) return; - lua_lock(to); - api_checknelems(from, n); - api_check(from, G(from) == G(to)); - api_check(from, to.ci.top - to.top >= n); - from.top -= n; - for (i = 0; i < n; i++) { - setobj2s(to, StkId.inc(ref to.top), from.top + i); - } - lua_unlock(to); - } - - - public static void lua_setlevel (lua_State from, lua_State to) { - to.nCcalls = from.nCcalls; - } - - - public static lua_CFunction lua_atpanic (lua_State L, lua_CFunction panicf) { - lua_CFunction old; - lua_lock(L); - old = G(L).panic; - G(L).panic = panicf; - lua_unlock(L); - return old; - } - - - public static lua_State lua_newthread (lua_State L) { - lua_State L1; - lua_lock(L); - luaC_checkGC(L); - L1 = luaE_newthread(L); - setthvalue(L, L.top, L1); - api_incr_top(L); - lua_unlock(L); - luai_userstatethread(L, L1); - return L1; - } - - - - /* - ** basic stack manipulation - */ - - - public static int lua_gettop (lua_State L) { - return cast_int(L.top - L.base_); - } - - - public static void lua_settop (lua_State L, int idx) { - lua_lock(L); - if (idx >= 0) { - api_check(L, idx <= L.stack_last - L.base_); - while (L.top < L.base_ + idx) - setnilvalue(StkId.inc(ref L.top)); - L.top = L.base_ + idx; - } - else { - api_check(L, -(idx+1) <= (L.top - L.base_)); - L.top += idx+1; /* `subtract' index (index is negative) */ - } - lua_unlock(L); - } - - - public static void lua_remove (lua_State L, int idx) { - StkId p; - lua_lock(L); - p = index2adr(L, idx); - api_checkvalidindex(L, p); - while ((p=p[1]) < L.top) setobjs2s(L, p-1, p); - StkId.dec(ref L.top); - lua_unlock(L); - } - - - public static void lua_insert (lua_State L, int idx) { - StkId p; - StkId q; - lua_lock(L); - p = index2adr(L, idx); - api_checkvalidindex(L, p); - for (q = L.top; q>p; StkId.dec(ref q)) setobjs2s(L, q, q-1); - setobjs2s(L, p, L.top); - lua_unlock(L); - } - - - public static void lua_replace (lua_State L, int idx) { - StkId o; - lua_lock(L); - /* explicit test for incompatible code */ - if (idx == LUA_ENVIRONINDEX && L.ci == L.base_ci[0]) - luaG_runerror(L, "no calling environment"); - api_checknelems(L, 1); - o = index2adr(L, idx); - api_checkvalidindex(L, o); - if (idx == LUA_ENVIRONINDEX) { - Closure func = curr_func(L); - api_check(L, ttistable(L.top - 1)); - func.c.env = hvalue(L.top - 1); - luaC_barrier(L, func, L.top - 1); - } - else { - setobj(L, o, L.top - 1); - if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ - luaC_barrier(L, curr_func(L), L.top - 1); - } - StkId.dec(ref L.top); - lua_unlock(L); - } - - - public static void lua_pushvalue (lua_State L, int idx) { - lua_lock(L); - setobj2s(L, L.top, index2adr(L, idx)); - api_incr_top(L); - lua_unlock(L); - } - - - - /* - ** access functions (stack . C) - */ - - - public static int lua_type (lua_State L, int idx) { - StkId o = index2adr(L, idx); - return (o == luaO_nilobject) ? LUA_TNONE : ttype(o); - } - - - public static CharPtr lua_typename (lua_State L, int t) { - //UNUSED(L); - return (t == LUA_TNONE) ? "no value" : luaT_typenames[t]; - } - - - public static bool lua_iscfunction (lua_State L, int idx) { - StkId o = index2adr(L, idx); - return iscfunction(o); - } - - - public static int lua_isnumber (lua_State L, int idx) { - TValue n = new TValue(); - TValue o = index2adr(L, idx); - return tonumber(ref o, n); - } - - - public static int lua_isstring (lua_State L, int idx) { - int t = lua_type(L, idx); - return (t == LUA_TSTRING || t == LUA_TNUMBER) ? 1 : 0; - } - - - public static int lua_isuserdata (lua_State L, int idx) { - TValue o = index2adr(L, idx); - return (ttisuserdata(o) || ttislightuserdata(o)) ? 1 : 0; - } - - - public static int lua_rawequal (lua_State L, int index1, int index2) { - StkId o1 = index2adr(L, index1); - StkId o2 = index2adr(L, index2); - return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 - : luaO_rawequalObj(o1, o2); - } - - - public static int lua_equal (lua_State L, int index1, int index2) { - StkId o1, o2; - int i; - lua_lock(L); /* may call tag method */ - o1 = index2adr(L, index1); - o2 = index2adr(L, index2); - i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2); - lua_unlock(L); - return i; - } - - - public static int lua_lessthan (lua_State L, int index1, int index2) { - StkId o1, o2; - int i; - lua_lock(L); /* may call tag method */ - o1 = index2adr(L, index1); - o2 = index2adr(L, index2); - i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 - : luaV_lessthan(L, o1, o2); - lua_unlock(L); - return i; - } - - - - public static lua_Number lua_tonumber (lua_State L, int idx) { - TValue n = new TValue(); - TValue o = index2adr(L, idx); - if (tonumber(ref o, n) != 0) - return nvalue(o); - else - return 0; - } - - - public static lua_Integer lua_tointeger (lua_State L, int idx) { - TValue n = new TValue(); - TValue o = index2adr(L, idx); - if (tonumber(ref o, n) != 0) { - lua_Integer res; - lua_Number num = nvalue(o); - lua_number2integer(out res, num); - return res; - } - else - return 0; - } - - - public static int lua_toboolean (lua_State L, int idx) { - TValue o = index2adr(L, idx); - return (l_isfalse(o) == 0) ? 1 : 0; - } - - [CLSCompliantAttribute(false)] - public static CharPtr lua_tolstring (lua_State L, int idx, out uint len) { - StkId o = index2adr(L, idx); - if (!ttisstring(o)) { - lua_lock(L); /* `luaV_tostring' may create a new string */ - if (luaV_tostring(L, o)==0) { /* conversion failed? */ - len = 0; - lua_unlock(L); - return null; - } - luaC_checkGC(L); - o = index2adr(L, idx); /* previous call may reallocate the stack */ - lua_unlock(L); - } - len = tsvalue(o).len; - return svalue(o); - } - - [CLSCompliantAttribute(false)] - public static uint lua_objlen (lua_State L, int idx) { - StkId o = index2adr(L, idx); - switch (ttype(o)) { - case LUA_TSTRING: return tsvalue(o).len; - case LUA_TUSERDATA: return uvalue(o).len; - case LUA_TTABLE: return (uint)luaH_getn(hvalue(o)); - case LUA_TNUMBER: { - uint l; - lua_lock(L); /* `luaV_tostring' may create a new string */ - l = (luaV_tostring(L, o) != 0 ? tsvalue(o).len : 0); - lua_unlock(L); - return l; - } - default: return 0; - } - } - - - public static lua_CFunction lua_tocfunction (lua_State L, int idx) { - StkId o = index2adr(L, idx); - return (!iscfunction(o)) ? null : clvalue(o).c.f; - } - - - public static object lua_touserdata (lua_State L, int idx) { - StkId o = index2adr(L, idx); - switch (ttype(o)) { - case LUA_TUSERDATA: return (rawuvalue(o).user_data); - case LUA_TLIGHTUSERDATA: return pvalue(o); - default: return null; - } - } - - public static lua_State lua_tothread (lua_State L, int idx) { - StkId o = index2adr(L, idx); - return (!ttisthread(o)) ? null : thvalue(o); - } - - - public static object lua_topointer (lua_State L, int idx) { - StkId o = index2adr(L, idx); - switch (ttype(o)) { - case LUA_TTABLE: return hvalue(o); - case LUA_TFUNCTION: return clvalue(o); - case LUA_TTHREAD: return thvalue(o); - case LUA_TUSERDATA: - case LUA_TLIGHTUSERDATA: - return lua_touserdata(L, idx); - default: return null; - } - } - - - - /* - ** push functions (C . stack) - */ - - - public static void lua_pushnil (lua_State L) { - lua_lock(L); - setnilvalue(L.top); - api_incr_top(L); - lua_unlock(L); - } - - - public static void lua_pushnumber (lua_State L, lua_Number n) { - lua_lock(L); - setnvalue(L.top, n); - api_incr_top(L); - lua_unlock(L); - } - - - public static void lua_pushinteger (lua_State L, lua_Integer n) { - lua_lock(L); - setnvalue(L.top, cast_num(n)); - api_incr_top(L); - lua_unlock(L); - } - - [CLSCompliantAttribute(false)] - public static void lua_pushlstring (lua_State L, CharPtr s, uint len) { - lua_lock(L); - luaC_checkGC(L); - setsvalue2s(L, L.top, luaS_newlstr(L, s, len)); - api_incr_top(L); - lua_unlock(L); - } - - - public static void lua_pushstring (lua_State L, CharPtr s) { - if (s == null) - lua_pushnil(L); - else - lua_pushlstring(L, s, (uint)strlen(s)); - } - - - public static CharPtr lua_pushvfstring (lua_State L, CharPtr fmt, - object[] argp) { - CharPtr ret; - lua_lock(L); - luaC_checkGC(L); - ret = luaO_pushvfstring(L, fmt, argp); - lua_unlock(L); - return ret; - } - - - public static CharPtr lua_pushfstring (lua_State L, CharPtr fmt) { - CharPtr ret; - lua_lock(L); - luaC_checkGC(L); - ret = luaO_pushvfstring(L, fmt, null); - lua_unlock(L); - return ret; - } - - public static CharPtr lua_pushfstring(lua_State L, CharPtr fmt, params object[] p) - { - CharPtr ret; - lua_lock(L); - luaC_checkGC(L); - ret = luaO_pushvfstring(L, fmt, p); - lua_unlock(L); - return ret; - } - - public static void lua_pushcclosure (lua_State L, lua_CFunction fn, int n) { - Closure cl; - lua_lock(L); - luaC_checkGC(L); - api_checknelems(L, n); - cl = luaF_newCclosure(L, n, getcurrenv(L)); - cl.c.f = fn; - L.top -= n; - while (n-- != 0) - setobj2n(L, cl.c.upvalue[n], L.top+n); - setclvalue(L, L.top, cl); - lua_assert(iswhite(obj2gco(cl))); - api_incr_top(L); - lua_unlock(L); - } - - - public static void lua_pushboolean (lua_State L, int b) { - lua_lock(L); - setbvalue(L.top, (b != 0) ? 1 : 0); /* ensure that true is 1 */ - api_incr_top(L); - lua_unlock(L); - } - - - public static void lua_pushlightuserdata (lua_State L, object p) { - lua_lock(L); - setpvalue(L.top, p); - api_incr_top(L); - lua_unlock(L); - } - - - public static int lua_pushthread (lua_State L) { - lua_lock(L); - setthvalue(L, L.top, L); - api_incr_top(L); - lua_unlock(L); - return (G(L).mainthread == L) ? 1 : 0; - } - - - - /* - ** get functions (Lua . stack) - */ - - - public static void lua_gettable (lua_State L, int idx) { - StkId t; - lua_lock(L); - t = index2adr(L, idx); - api_checkvalidindex(L, t); - luaV_gettable(L, t, L.top - 1, L.top - 1); - lua_unlock(L); - } - - public static void lua_getfield (lua_State L, int idx, CharPtr k) { - StkId t; - TValue key = new TValue(); - lua_lock(L); - t = index2adr(L, idx); - api_checkvalidindex(L, t); - setsvalue(L, key, luaS_new(L, k)); - luaV_gettable(L, t, key, L.top); - api_incr_top(L); - lua_unlock(L); - } - - - public static void lua_rawget (lua_State L, int idx) { - StkId t; - lua_lock(L); - t = index2adr(L, idx); - api_check(L, ttistable(t)); - setobj2s(L, L.top - 1, luaH_get(hvalue(t), L.top - 1)); - lua_unlock(L); - } - - - public static void lua_rawgeti (lua_State L, int idx, int n) { - StkId o; - lua_lock(L); - o = index2adr(L, idx); - api_check(L, ttistable(o)); - setobj2s(L, L.top, luaH_getnum(hvalue(o), n)); - api_incr_top(L); - lua_unlock(L); - } - - - public static void lua_createtable (lua_State L, int narray, int nrec) { - lua_lock(L); - luaC_checkGC(L); - sethvalue(L, L.top, luaH_new(L, narray, nrec)); - api_incr_top(L); - lua_unlock(L); - } - - - public static int lua_getmetatable (lua_State L, int objindex) { - TValue obj; - Table mt = null; - int res; - lua_lock(L); - obj = index2adr(L, objindex); - switch (ttype(obj)) { - case LUA_TTABLE: - mt = hvalue(obj).metatable; - break; - case LUA_TUSERDATA: - mt = uvalue(obj).metatable; - break; - default: - mt = G(L).mt[ttype(obj)]; - break; - } - if (mt == null) - res = 0; - else { - sethvalue(L, L.top, mt); - api_incr_top(L); - res = 1; - } - lua_unlock(L); - return res; - } - - - public static void lua_getfenv (lua_State L, int idx) { - StkId o; - lua_lock(L); - o = index2adr(L, idx); - api_checkvalidindex(L, o); - switch (ttype(o)) { - case LUA_TFUNCTION: - sethvalue(L, L.top, clvalue(o).c.env); - break; - case LUA_TUSERDATA: - sethvalue(L, L.top, uvalue(o).env); - break; - case LUA_TTHREAD: - setobj2s(L, L.top, gt(thvalue(o))); - break; - default: - setnilvalue(L.top); - break; - } - api_incr_top(L); - lua_unlock(L); - } - - - /* - ** set functions (stack . Lua) - */ - - - public static void lua_settable (lua_State L, int idx) { - StkId t; - lua_lock(L); - api_checknelems(L, 2); - t = index2adr(L, idx); - api_checkvalidindex(L, t); - luaV_settable(L, t, L.top - 2, L.top - 1); - L.top -= 2; /* pop index and value */ - lua_unlock(L); - } - - - public static void lua_setfield (lua_State L, int idx, CharPtr k) { - StkId t; - TValue key = new TValue(); - lua_lock(L); - api_checknelems(L, 1); - t = index2adr(L, idx); - api_checkvalidindex(L, t); - setsvalue(L, key, luaS_new(L, k)); - luaV_settable(L, t, key, L.top - 1); - StkId.dec(ref L.top); /* pop value */ - lua_unlock(L); - } - - - public static void lua_rawset (lua_State L, int idx) { - StkId t; - lua_lock(L); - api_checknelems(L, 2); - t = index2adr(L, idx); - api_check(L, ttistable(t)); - setobj2t(L, luaH_set(L, hvalue(t), L.top-2), L.top-1); - luaC_barriert(L, hvalue(t), L.top-1); - L.top -= 2; - lua_unlock(L); - } - - - public static void lua_rawseti (lua_State L, int idx, int n) { - StkId o; - lua_lock(L); - api_checknelems(L, 1); - o = index2adr(L, idx); - api_check(L, ttistable(o)); - setobj2t(L, luaH_setnum(L, hvalue(o), n), L.top-1); - luaC_barriert(L, hvalue(o), L.top-1); - StkId.dec(ref L.top); - lua_unlock(L); - } - - - public static int lua_setmetatable (lua_State L, int objindex) { - TValue obj; - Table mt; - lua_lock(L); - api_checknelems(L, 1); - obj = index2adr(L, objindex); - api_checkvalidindex(L, obj); - if (ttisnil(L.top - 1)) - mt = null; - else { - api_check(L, ttistable(L.top - 1)); - mt = hvalue(L.top - 1); - } - switch (ttype(obj)) { - case LUA_TTABLE: { - hvalue(obj).metatable = mt; - if (mt != null) - luaC_objbarriert(L, hvalue(obj), mt); - break; - } - case LUA_TUSERDATA: { - uvalue(obj).metatable = mt; - if (mt != null) - luaC_objbarrier(L, rawuvalue(obj), mt); - break; - } - default: { - G(L).mt[ttype(obj)] = mt; - break; - } - } - StkId.dec(ref L.top); - lua_unlock(L); - return 1; - } - - - public static int lua_setfenv (lua_State L, int idx) { - StkId o; - int res = 1; - lua_lock(L); - api_checknelems(L, 1); - o = index2adr(L, idx); - api_checkvalidindex(L, o); - api_check(L, ttistable(L.top - 1)); - switch (ttype(o)) { - case LUA_TFUNCTION: - clvalue(o).c.env = hvalue(L.top - 1); - break; - case LUA_TUSERDATA: - uvalue(o).env = hvalue(L.top - 1); - break; - case LUA_TTHREAD: - sethvalue(L, gt(thvalue(o)), hvalue(L.top - 1)); - break; - default: - res = 0; - break; - } - if (res != 0) luaC_objbarrier(L, gcvalue(o), hvalue(L.top - 1)); - StkId.dec(ref L.top); - lua_unlock(L); - return res; - } - - - /* - ** `load' and `call' functions (run Lua code) - */ - - - public static void adjustresults(lua_State L, int nres) { - if (nres == LUA_MULTRET && L.top >= L.ci.top) - L.ci.top = L.top; - } - - - public static void checkresults(lua_State L, int na, int nr) { - api_check(L, (nr) == LUA_MULTRET || (L.ci.top - L.top >= (nr) - (na))); - } - - - public static void lua_call (lua_State L, int nargs, int nresults) { - StkId func; - lua_lock(L); - api_checknelems(L, nargs+1); - checkresults(L, nargs, nresults); - func = L.top - (nargs+1); - luaD_call(L, func, nresults); - adjustresults(L, nresults); - lua_unlock(L); - } - - - - /* - ** Execute a protected call. - */ - public class CallS { /* data to `f_call' */ - public StkId func; - public int nresults; - }; - - - static void f_call (lua_State L, object ud) { - CallS c = ud as CallS; - luaD_call(L, c.func, c.nresults); - } - - - - public static int lua_pcall (lua_State L, int nargs, int nresults, int errfunc) { - CallS c = new CallS(); - int status; - ptrdiff_t func; - lua_lock(L); - api_checknelems(L, nargs+1); - checkresults(L, nargs, nresults); - if (errfunc == 0) - func = 0; - else { - StkId o = index2adr(L, errfunc); - api_checkvalidindex(L, o); - func = savestack(L, o); - } - c.func = L.top - (nargs+1); /* function to be called */ - c.nresults = nresults; - status = luaD_pcall(L, f_call, c, savestack(L, c.func), func); - adjustresults(L, nresults); - lua_unlock(L); - return status; - } - - - /* - ** Execute a protected C call. - */ - public class CCallS { /* data to `f_Ccall' */ - public lua_CFunction func; - public object ud; - }; - - - static void f_Ccall (lua_State L, object ud) { - CCallS c = ud as CCallS; - Closure cl; - cl = luaF_newCclosure(L, 0, getcurrenv(L)); - cl.c.f = c.func; - setclvalue(L, L.top, cl); /* push function */ - api_incr_top(L); - setpvalue(L.top, c.ud); /* push only argument */ - api_incr_top(L); - luaD_call(L, L.top - 2, 0); - } - - - public static int lua_cpcall (lua_State L, lua_CFunction func, object ud) { - CCallS c = new CCallS(); - int status; - lua_lock(L); - c.func = func; - c.ud = ud; - status = luaD_pcall(L, f_Ccall, c, savestack(L, L.top), 0); - lua_unlock(L); - return status; - } - - [CLSCompliantAttribute(false)] - public static int lua_load (lua_State L, lua_Reader reader, object data, - CharPtr chunkname) { - ZIO z = new ZIO(); - int status; - lua_lock(L); - if (chunkname == null) chunkname = "?"; - luaZ_init(L, z, reader, data); - status = luaD_protectedparser(L, z, chunkname); - lua_unlock(L); - return status; - } - - [CLSCompliantAttribute(false)] - public static int lua_dump (lua_State L, lua_Writer writer, object data) { - int status; - TValue o; - lua_lock(L); - api_checknelems(L, 1); - o = L.top - 1; - if (isLfunction(o)) - status = luaU_dump(L, clvalue(o).l.p, writer, data, 0); - else - status = 1; - lua_unlock(L); - return status; - } - - - public static int lua_status (lua_State L) { - return L.status; - } - - - /* - ** Garbage-collection function - */ - - public static int lua_gc (lua_State L, int what, int data) { - int res = 0; - global_State g; - lua_lock(L); - g = G(L); - switch (what) { - case LUA_GCSTOP: { - g.GCthreshold = MAX_LUMEM; - break; - } - case LUA_GCRESTART: { - g.GCthreshold = g.totalbytes; - break; - } - case LUA_GCCOLLECT: { - luaC_fullgc(L); - break; - } - case LUA_GCCOUNT: { - /* GC values are expressed in Kbytes: #bytes/2^10 */ - res = cast_int(g.totalbytes >> 10); - break; - } - case LUA_GCCOUNTB: { - res = cast_int(g.totalbytes & 0x3ff); - break; - } - case LUA_GCSTEP: { - lu_mem a = ((lu_mem)data << 10); - if (a <= g.totalbytes) - g.GCthreshold = (uint)(g.totalbytes - a); - else - g.GCthreshold = 0; - while (g.GCthreshold <= g.totalbytes) { - luaC_step(L); - if (g.gcstate == GCSpause) { /* end of cycle? */ - res = 1; /* signal it */ - break; - } - } - break; - } - case LUA_GCSETPAUSE: { - res = g.gcpause; - g.gcpause = data; - break; - } - case LUA_GCSETSTEPMUL: { - res = g.gcstepmul; - g.gcstepmul = data; - break; - } - default: - res = -1; /* invalid option */ - break; - } - lua_unlock(L); - return res; - } - - - - /* - ** miscellaneous functions - */ - - - public static int lua_error (lua_State L) { - lua_lock(L); - api_checknelems(L, 1); - luaG_errormsg(L); - lua_unlock(L); - return 0; /* to avoid warnings */ - } - - - public static int lua_next (lua_State L, int idx) { - StkId t; - int more; - lua_lock(L); - t = index2adr(L, idx); - api_check(L, ttistable(t)); - more = luaH_next(L, hvalue(t), L.top - 1); - if (more != 0) { - api_incr_top(L); - } - else /* no more elements */ - StkId.dec(ref L.top); /* remove key */ - lua_unlock(L); - return more; - } - - - public static void lua_concat (lua_State L, int n) { - lua_lock(L); - api_checknelems(L, n); - if (n >= 2) { - luaC_checkGC(L); - luaV_concat(L, n, cast_int(L.top - L.base_) - 1); - L.top -= (n-1); - } - else if (n == 0) { /* push empty string */ - setsvalue2s(L, L.top, luaS_newlstr(L, "", 0)); - api_incr_top(L); - } - /* else n == 1; nothing to do */ - lua_unlock(L); - } - - - public static lua_Alloc lua_getallocf (lua_State L, ref object ud) { - lua_Alloc f; - lua_lock(L); - if (ud != null) ud = G(L).ud; - f = G(L).frealloc; - lua_unlock(L); - return f; - } - - - public static void lua_setallocf (lua_State L, lua_Alloc f, object ud) { - lua_lock(L); - G(L).ud = ud; - G(L).frealloc = f; - lua_unlock(L); - } - - [CLSCompliantAttribute(false)] - public static object lua_newuserdata(lua_State L, uint size) - { - Udata u; - lua_lock(L); - luaC_checkGC(L); - u = luaS_newudata(L, size, getcurrenv(L)); - setuvalue(L, L.top, u); - api_incr_top(L); - lua_unlock(L); - return u.user_data; - } - - // this one is used internally only - internal static object lua_newuserdata(lua_State L, Type t) - { - Udata u; - lua_lock(L); - luaC_checkGC(L); - u = luaS_newudata(L, t, getcurrenv(L)); - setuvalue(L, L.top, u); - api_incr_top(L); - lua_unlock(L); - return u.user_data; - } - - static CharPtr aux_upvalue (StkId fi, int n, ref TValue val) { - Closure f; - if (!ttisfunction(fi)) return null; - f = clvalue(fi); - if (f.c.isC != 0) { - if (!(1 <= n && n <= f.c.nupvalues)) return null; - val = f.c.upvalue[n-1]; - return ""; - } - else { - Proto p = f.l.p; - if (!(1 <= n && n <= p.sizeupvalues)) return null; - val = f.l.upvals[n-1].v; - return getstr(p.upvalues[n-1]); - } - } - - - public static CharPtr lua_getupvalue (lua_State L, int funcindex, int n) { - CharPtr name; - TValue val = new TValue(); - lua_lock(L); - name = aux_upvalue(index2adr(L, funcindex), n, ref val); - if (name != null) { - setobj2s(L, L.top, val); - api_incr_top(L); - } - lua_unlock(L); - return name; - } - - - public static CharPtr lua_setupvalue (lua_State L, int funcindex, int n) { - CharPtr name; - TValue val = new TValue(); - StkId fi; - lua_lock(L); - fi = index2adr(L, funcindex); - api_checknelems(L, 1); - name = aux_upvalue(fi, n, ref val); - if (name != null) { - StkId.dec(ref L.top); - setobj(L, val, L.top); - luaC_barrier(L, clvalue(fi), L.top); - } - lua_unlock(L); - return name; - } - - } -} +/* +** $Id: lapi.c,v 2.55.1.5 2008/07/04 18:41:18 roberto Exp $ +** Lua API +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace KopiLua +{ + using lu_mem = System.UInt32; + using TValue = Lua.lua_TValue; + using StkId = Lua.lua_TValue; + using lua_Integer = System.Int32; + using lua_Number = System.Double; + using ptrdiff_t = System.Int32; + using ZIO = Lua.Zio; + + public partial class Lua + { + public const string lua_ident = + "$Lua: " + LUA_RELEASE + " " + LUA_COPYRIGHT + " $\n" + + "$Authors: " + LUA_AUTHORS + " $\n" + + "$URL: www.lua.org $\n"; + + public static void api_checknelems(lua_State L, int n) + { + api_check(L, n <= L.top - L.base_); + } + + public static void api_checkvalidindex(lua_State L, StkId i) + { + api_check(L, i != luaO_nilobject); + } + + public static void api_incr_top(lua_State L) + { + api_check(L, L.top < L.ci.top); + StkId.inc(ref L.top); + } + + + + static TValue index2adr (lua_State L, int idx) { + if (idx > 0) { + TValue o = L.base_ + (idx - 1); + api_check(L, idx <= L.ci.top - L.base_); + if (o >= L.top) return luaO_nilobject; + else return o; + } + else if (idx > LUA_REGISTRYINDEX) { + api_check(L, idx != 0 && -idx <= L.top - L.base_); + return L.top + idx; + } + else switch (idx) { /* pseudo-indices */ + case LUA_REGISTRYINDEX: return registry(L); + case LUA_ENVIRONINDEX: { + Closure func = curr_func(L); + sethvalue(L, L.env, func.c.env); + return L.env; + } + case LUA_GLOBALSINDEX: return gt(L); + default: { + Closure func = curr_func(L); + idx = LUA_GLOBALSINDEX - idx; + return (idx <= func.c.nupvalues) + ? func.c.upvalue[idx-1] + : (TValue)luaO_nilobject; + } + } + } + + + private static Table getcurrenv (lua_State L) { + if (L.ci == L.base_ci[0]) /* no enclosing function? */ + return hvalue(gt(L)); /* use global table as environment */ + else { + Closure func = curr_func(L); + return func.c.env; + } + } + + + public static void luaA_pushobject (lua_State L, TValue o) { + setobj2s(L, L.top, o); + api_incr_top(L); + } + + + public static int lua_checkstack (lua_State L, int size) { + int res = 1; + lua_lock(L); + if (size > LUAI_MAXCSTACK || (L.top - L.base_ + size) > LUAI_MAXCSTACK) + res = 0; /* stack overflow */ + else if (size > 0) { + luaD_checkstack(L, size); + if (L.ci.top < L.top + size) + L.ci.top = L.top + size; + } + lua_unlock(L); + return res; + } + + + public static void lua_xmove (lua_State from, lua_State to, int n) { + int i; + if (from == to) return; + lua_lock(to); + api_checknelems(from, n); + api_check(from, G(from) == G(to)); + api_check(from, to.ci.top - to.top >= n); + from.top -= n; + for (i = 0; i < n; i++) { + setobj2s(to, StkId.inc(ref to.top), from.top + i); + } + lua_unlock(to); + } + + + public static void lua_setlevel (lua_State from, lua_State to) { + to.nCcalls = from.nCcalls; + } + + + public static lua_CFunction lua_atpanic (lua_State L, lua_CFunction panicf) { + lua_CFunction old; + lua_lock(L); + old = G(L).panic; + G(L).panic = panicf; + lua_unlock(L); + return old; + } + + + public static lua_State lua_newthread (lua_State L) { + lua_State L1; + lua_lock(L); + luaC_checkGC(L); + L1 = luaE_newthread(L); + setthvalue(L, L.top, L1); + api_incr_top(L); + lua_unlock(L); + luai_userstatethread(L, L1); + return L1; + } + + + + /* + ** basic stack manipulation + */ + + + public static int lua_gettop (lua_State L) { + return cast_int(L.top - L.base_); + } + + + public static void lua_settop (lua_State L, int idx) { + lua_lock(L); + if (idx >= 0) { + api_check(L, idx <= L.stack_last - L.base_); + while (L.top < L.base_ + idx) + setnilvalue(StkId.inc(ref L.top)); + L.top = L.base_ + idx; + } + else { + api_check(L, -(idx+1) <= (L.top - L.base_)); + L.top += idx+1; /* `subtract' index (index is negative) */ + } + lua_unlock(L); + } + + + public static void lua_remove (lua_State L, int idx) { + StkId p; + lua_lock(L); + p = index2adr(L, idx); + api_checkvalidindex(L, p); + while ((p=p[1]) < L.top) setobjs2s(L, p-1, p); + StkId.dec(ref L.top); + lua_unlock(L); + } + + + public static void lua_insert (lua_State L, int idx) { + StkId p; + StkId q; + lua_lock(L); + p = index2adr(L, idx); + api_checkvalidindex(L, p); + for (q = L.top; q>p; StkId.dec(ref q)) setobjs2s(L, q, q-1); + setobjs2s(L, p, L.top); + lua_unlock(L); + } + + + public static void lua_replace (lua_State L, int idx) { + StkId o; + lua_lock(L); + /* explicit test for incompatible code */ + if (idx == LUA_ENVIRONINDEX && L.ci == L.base_ci[0]) + luaG_runerror(L, "no calling environment"); + api_checknelems(L, 1); + o = index2adr(L, idx); + api_checkvalidindex(L, o); + if (idx == LUA_ENVIRONINDEX) { + Closure func = curr_func(L); + api_check(L, ttistable(L.top - 1)); + func.c.env = hvalue(L.top - 1); + luaC_barrier(L, func, L.top - 1); + } + else { + setobj(L, o, L.top - 1); + if (idx < LUA_GLOBALSINDEX) /* function upvalue? */ + luaC_barrier(L, curr_func(L), L.top - 1); + } + StkId.dec(ref L.top); + lua_unlock(L); + } + + + public static void lua_pushvalue (lua_State L, int idx) { + lua_lock(L); + setobj2s(L, L.top, index2adr(L, idx)); + api_incr_top(L); + lua_unlock(L); + } + + + + /* + ** access functions (stack . C) + */ + + + public static int lua_type (lua_State L, int idx) { + StkId o = index2adr(L, idx); + return (o == luaO_nilobject) ? LUA_TNONE : ttype(o); + } + + + public static CharPtr lua_typename (lua_State L, int t) { + //UNUSED(L); + return (t == LUA_TNONE) ? "no value" : luaT_typenames[t]; + } + + + public static bool lua_iscfunction (lua_State L, int idx) { + StkId o = index2adr(L, idx); + return iscfunction(o); + } + + + public static int lua_isnumber (lua_State L, int idx) { + TValue n = new TValue(); + TValue o = index2adr(L, idx); + return tonumber(ref o, n); + } + + + public static int lua_isstring (lua_State L, int idx) { + int t = lua_type(L, idx); + return (t == LUA_TSTRING || t == LUA_TNUMBER) ? 1 : 0; + } + + + public static int lua_isuserdata (lua_State L, int idx) { + TValue o = index2adr(L, idx); + return (ttisuserdata(o) || ttislightuserdata(o)) ? 1 : 0; + } + + + public static int lua_rawequal (lua_State L, int index1, int index2) { + StkId o1 = index2adr(L, index1); + StkId o2 = index2adr(L, index2); + return (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 + : luaO_rawequalObj(o1, o2); + } + + + public static int lua_equal (lua_State L, int index1, int index2) { + StkId o1, o2; + int i; + lua_lock(L); /* may call tag method */ + o1 = index2adr(L, index1); + o2 = index2adr(L, index2); + i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 : equalobj(L, o1, o2); + lua_unlock(L); + return i; + } + + + public static int lua_lessthan (lua_State L, int index1, int index2) { + StkId o1, o2; + int i; + lua_lock(L); /* may call tag method */ + o1 = index2adr(L, index1); + o2 = index2adr(L, index2); + i = (o1 == luaO_nilobject || o2 == luaO_nilobject) ? 0 + : luaV_lessthan(L, o1, o2); + lua_unlock(L); + return i; + } + + + + public static lua_Number lua_tonumber (lua_State L, int idx) { + TValue n = new TValue(); + TValue o = index2adr(L, idx); + if (tonumber(ref o, n) != 0) + return nvalue(o); + else + return 0; + } + + + public static lua_Integer lua_tointeger (lua_State L, int idx) { + TValue n = new TValue(); + TValue o = index2adr(L, idx); + if (tonumber(ref o, n) != 0) { + lua_Integer res; + lua_Number num = nvalue(o); + lua_number2integer(out res, num); + return res; + } + else + return 0; + } + + + public static int lua_toboolean (lua_State L, int idx) { + TValue o = index2adr(L, idx); + return (l_isfalse(o) == 0) ? 1 : 0; + } + + [CLSCompliantAttribute(false)] + public static CharPtr lua_tolstring (lua_State L, int idx, out uint len) { + StkId o = index2adr(L, idx); + if (!ttisstring(o)) { + lua_lock(L); /* `luaV_tostring' may create a new string */ + if (luaV_tostring(L, o)==0) { /* conversion failed? */ + len = 0; + lua_unlock(L); + return null; + } + luaC_checkGC(L); + o = index2adr(L, idx); /* previous call may reallocate the stack */ + lua_unlock(L); + } + len = tsvalue(o).len; + return svalue(o); + } + + [CLSCompliantAttribute(false)] + public static uint lua_objlen (lua_State L, int idx) { + StkId o = index2adr(L, idx); + switch (ttype(o)) { + case LUA_TSTRING: return tsvalue(o).len; + case LUA_TUSERDATA: return uvalue(o).len; + case LUA_TTABLE: return (uint)luaH_getn(hvalue(o)); + case LUA_TNUMBER: { + uint l; + lua_lock(L); /* `luaV_tostring' may create a new string */ + l = (luaV_tostring(L, o) != 0 ? tsvalue(o).len : 0); + lua_unlock(L); + return l; + } + default: return 0; + } + } + + + public static lua_CFunction lua_tocfunction (lua_State L, int idx) { + StkId o = index2adr(L, idx); + return (!iscfunction(o)) ? null : clvalue(o).c.f; + } + + + public static object lua_touserdata (lua_State L, int idx) { + StkId o = index2adr(L, idx); + switch (ttype(o)) { + case LUA_TUSERDATA: return (rawuvalue(o).user_data); + case LUA_TLIGHTUSERDATA: return pvalue(o); + default: return null; + } + } + + public static lua_State lua_tothread (lua_State L, int idx) { + StkId o = index2adr(L, idx); + return (!ttisthread(o)) ? null : thvalue(o); + } + + + public static object lua_topointer (lua_State L, int idx) { + StkId o = index2adr(L, idx); + switch (ttype(o)) { + case LUA_TTABLE: return hvalue(o); + case LUA_TFUNCTION: return clvalue(o); + case LUA_TTHREAD: return thvalue(o); + case LUA_TUSERDATA: + case LUA_TLIGHTUSERDATA: + return lua_touserdata(L, idx); + default: return null; + } + } + + + + /* + ** push functions (C . stack) + */ + + + public static void lua_pushnil (lua_State L) { + lua_lock(L); + setnilvalue(L.top); + api_incr_top(L); + lua_unlock(L); + } + + + public static void lua_pushnumber (lua_State L, lua_Number n) { + lua_lock(L); + setnvalue(L.top, n); + api_incr_top(L); + lua_unlock(L); + } + + + public static void lua_pushinteger (lua_State L, lua_Integer n) { + lua_lock(L); + setnvalue(L.top, cast_num(n)); + api_incr_top(L); + lua_unlock(L); + } + + [CLSCompliantAttribute(false)] + public static void lua_pushlstring (lua_State L, CharPtr s, uint len) { + lua_lock(L); + luaC_checkGC(L); + setsvalue2s(L, L.top, luaS_newlstr(L, s, len)); + api_incr_top(L); + lua_unlock(L); + } + + + public static void lua_pushstring (lua_State L, CharPtr s) { + if (s == null) + lua_pushnil(L); + else + lua_pushlstring(L, s, (uint)strlen(s)); + } + + + public static CharPtr lua_pushvfstring (lua_State L, CharPtr fmt, + object[] argp) { + CharPtr ret; + lua_lock(L); + luaC_checkGC(L); + ret = luaO_pushvfstring(L, fmt, argp); + lua_unlock(L); + return ret; + } + + + public static CharPtr lua_pushfstring (lua_State L, CharPtr fmt) { + CharPtr ret; + lua_lock(L); + luaC_checkGC(L); + ret = luaO_pushvfstring(L, fmt, null); + lua_unlock(L); + return ret; + } + + public static CharPtr lua_pushfstring(lua_State L, CharPtr fmt, params object[] p) + { + CharPtr ret; + lua_lock(L); + luaC_checkGC(L); + ret = luaO_pushvfstring(L, fmt, p); + lua_unlock(L); + return ret; + } + + public static void lua_pushcclosure (lua_State L, lua_CFunction fn, int n) { + Closure cl; + lua_lock(L); + luaC_checkGC(L); + api_checknelems(L, n); + cl = luaF_newCclosure(L, n, getcurrenv(L)); + cl.c.f = fn; + L.top -= n; + while (n-- != 0) + setobj2n(L, cl.c.upvalue[n], L.top+n); + setclvalue(L, L.top, cl); + lua_assert(iswhite(obj2gco(cl))); + api_incr_top(L); + lua_unlock(L); + } + + + public static void lua_pushboolean (lua_State L, int b) { + lua_lock(L); + setbvalue(L.top, (b != 0) ? 1 : 0); /* ensure that true is 1 */ + api_incr_top(L); + lua_unlock(L); + } + + + public static void lua_pushlightuserdata (lua_State L, object p) { + lua_lock(L); + setpvalue(L.top, p); + api_incr_top(L); + lua_unlock(L); + } + + + public static int lua_pushthread (lua_State L) { + lua_lock(L); + setthvalue(L, L.top, L); + api_incr_top(L); + lua_unlock(L); + return (G(L).mainthread == L) ? 1 : 0; + } + + + + /* + ** get functions (Lua . stack) + */ + + + public static void lua_gettable (lua_State L, int idx) { + StkId t; + lua_lock(L); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + luaV_gettable(L, t, L.top - 1, L.top - 1); + lua_unlock(L); + } + + public static void lua_getfield (lua_State L, int idx, CharPtr k) { + StkId t; + TValue key = new TValue(); + lua_lock(L); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + setsvalue(L, key, luaS_new(L, k)); + luaV_gettable(L, t, key, L.top); + api_incr_top(L); + lua_unlock(L); + } + + + public static void lua_rawget (lua_State L, int idx) { + StkId t; + lua_lock(L); + t = index2adr(L, idx); + api_check(L, ttistable(t)); + setobj2s(L, L.top - 1, luaH_get(hvalue(t), L.top - 1)); + lua_unlock(L); + } + + + public static void lua_rawgeti (lua_State L, int idx, int n) { + StkId o; + lua_lock(L); + o = index2adr(L, idx); + api_check(L, ttistable(o)); + setobj2s(L, L.top, luaH_getnum(hvalue(o), n)); + api_incr_top(L); + lua_unlock(L); + } + + + public static void lua_createtable (lua_State L, int narray, int nrec) { + lua_lock(L); + luaC_checkGC(L); + sethvalue(L, L.top, luaH_new(L, narray, nrec)); + api_incr_top(L); + lua_unlock(L); + } + + + public static int lua_getmetatable (lua_State L, int objindex) { + TValue obj; + Table mt = null; + int res; + lua_lock(L); + obj = index2adr(L, objindex); + switch (ttype(obj)) { + case LUA_TTABLE: + mt = hvalue(obj).metatable; + break; + case LUA_TUSERDATA: + mt = uvalue(obj).metatable; + break; + default: + mt = G(L).mt[ttype(obj)]; + break; + } + if (mt == null) + res = 0; + else { + sethvalue(L, L.top, mt); + api_incr_top(L); + res = 1; + } + lua_unlock(L); + return res; + } + + + public static void lua_getfenv (lua_State L, int idx) { + StkId o; + lua_lock(L); + o = index2adr(L, idx); + api_checkvalidindex(L, o); + switch (ttype(o)) { + case LUA_TFUNCTION: + sethvalue(L, L.top, clvalue(o).c.env); + break; + case LUA_TUSERDATA: + sethvalue(L, L.top, uvalue(o).env); + break; + case LUA_TTHREAD: + setobj2s(L, L.top, gt(thvalue(o))); + break; + default: + setnilvalue(L.top); + break; + } + api_incr_top(L); + lua_unlock(L); + } + + + /* + ** set functions (stack . Lua) + */ + + + public static void lua_settable (lua_State L, int idx) { + StkId t; + lua_lock(L); + api_checknelems(L, 2); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + luaV_settable(L, t, L.top - 2, L.top - 1); + L.top -= 2; /* pop index and value */ + lua_unlock(L); + } + + + public static void lua_setfield (lua_State L, int idx, CharPtr k) { + StkId t; + TValue key = new TValue(); + lua_lock(L); + api_checknelems(L, 1); + t = index2adr(L, idx); + api_checkvalidindex(L, t); + setsvalue(L, key, luaS_new(L, k)); + luaV_settable(L, t, key, L.top - 1); + StkId.dec(ref L.top); /* pop value */ + lua_unlock(L); + } + + + public static void lua_rawset (lua_State L, int idx) { + StkId t; + lua_lock(L); + api_checknelems(L, 2); + t = index2adr(L, idx); + api_check(L, ttistable(t)); + setobj2t(L, luaH_set(L, hvalue(t), L.top-2), L.top-1); + luaC_barriert(L, hvalue(t), L.top-1); + L.top -= 2; + lua_unlock(L); + } + + + public static void lua_rawseti (lua_State L, int idx, int n) { + StkId o; + lua_lock(L); + api_checknelems(L, 1); + o = index2adr(L, idx); + api_check(L, ttistable(o)); + setobj2t(L, luaH_setnum(L, hvalue(o), n), L.top-1); + luaC_barriert(L, hvalue(o), L.top-1); + StkId.dec(ref L.top); + lua_unlock(L); + } + + + public static int lua_setmetatable (lua_State L, int objindex) { + TValue obj; + Table mt; + lua_lock(L); + api_checknelems(L, 1); + obj = index2adr(L, objindex); + api_checkvalidindex(L, obj); + if (ttisnil(L.top - 1)) + mt = null; + else { + api_check(L, ttistable(L.top - 1)); + mt = hvalue(L.top - 1); + } + switch (ttype(obj)) { + case LUA_TTABLE: { + hvalue(obj).metatable = mt; + if (mt != null) + luaC_objbarriert(L, hvalue(obj), mt); + break; + } + case LUA_TUSERDATA: { + uvalue(obj).metatable = mt; + if (mt != null) + luaC_objbarrier(L, rawuvalue(obj), mt); + break; + } + default: { + G(L).mt[ttype(obj)] = mt; + break; + } + } + StkId.dec(ref L.top); + lua_unlock(L); + return 1; + } + + + public static int lua_setfenv (lua_State L, int idx) { + StkId o; + int res = 1; + lua_lock(L); + api_checknelems(L, 1); + o = index2adr(L, idx); + api_checkvalidindex(L, o); + api_check(L, ttistable(L.top - 1)); + switch (ttype(o)) { + case LUA_TFUNCTION: + clvalue(o).c.env = hvalue(L.top - 1); + break; + case LUA_TUSERDATA: + uvalue(o).env = hvalue(L.top - 1); + break; + case LUA_TTHREAD: + sethvalue(L, gt(thvalue(o)), hvalue(L.top - 1)); + break; + default: + res = 0; + break; + } + if (res != 0) luaC_objbarrier(L, gcvalue(o), hvalue(L.top - 1)); + StkId.dec(ref L.top); + lua_unlock(L); + return res; + } + + + /* + ** `load' and `call' functions (run Lua code) + */ + + + public static void adjustresults(lua_State L, int nres) { + if (nres == LUA_MULTRET && L.top >= L.ci.top) + L.ci.top = L.top; + } + + + public static void checkresults(lua_State L, int na, int nr) { + api_check(L, (nr) == LUA_MULTRET || (L.ci.top - L.top >= (nr) - (na))); + } + + + public static void lua_call (lua_State L, int nargs, int nresults) { + StkId func; + lua_lock(L); + api_checknelems(L, nargs+1); + checkresults(L, nargs, nresults); + func = L.top - (nargs+1); + luaD_call(L, func, nresults); + adjustresults(L, nresults); + lua_unlock(L); + } + + + + /* + ** Execute a protected call. + */ + public class CallS { /* data to `f_call' */ + public StkId func; + public int nresults; + }; + + + static void f_call (lua_State L, object ud) { + CallS c = ud as CallS; + luaD_call(L, c.func, c.nresults); + } + + + + public static int lua_pcall (lua_State L, int nargs, int nresults, int errfunc) { + CallS c = new CallS(); + int status; + ptrdiff_t func; + lua_lock(L); + api_checknelems(L, nargs+1); + checkresults(L, nargs, nresults); + if (errfunc == 0) + func = 0; + else { + StkId o = index2adr(L, errfunc); + api_checkvalidindex(L, o); + func = savestack(L, o); + } + c.func = L.top - (nargs+1); /* function to be called */ + c.nresults = nresults; + status = luaD_pcall(L, f_call, c, savestack(L, c.func), func); + adjustresults(L, nresults); + lua_unlock(L); + return status; + } + + + /* + ** Execute a protected C call. + */ + public class CCallS { /* data to `f_Ccall' */ + public lua_CFunction func; + public object ud; + }; + + + static void f_Ccall (lua_State L, object ud) { + CCallS c = ud as CCallS; + Closure cl; + cl = luaF_newCclosure(L, 0, getcurrenv(L)); + cl.c.f = c.func; + setclvalue(L, L.top, cl); /* push function */ + api_incr_top(L); + setpvalue(L.top, c.ud); /* push only argument */ + api_incr_top(L); + luaD_call(L, L.top - 2, 0); + } + + + public static int lua_cpcall (lua_State L, lua_CFunction func, object ud) { + CCallS c = new CCallS(); + int status; + lua_lock(L); + c.func = func; + c.ud = ud; + status = luaD_pcall(L, f_Ccall, c, savestack(L, L.top), 0); + lua_unlock(L); + return status; + } + + [CLSCompliantAttribute(false)] + public static int lua_load (lua_State L, lua_Reader reader, object data, + CharPtr chunkname) { + ZIO z = new ZIO(); + int status; + lua_lock(L); + if (chunkname == null) chunkname = "?"; + luaZ_init(L, z, reader, data); + status = luaD_protectedparser(L, z, chunkname); + lua_unlock(L); + return status; + } + + [CLSCompliantAttribute(false)] + public static int lua_dump (lua_State L, lua_Writer writer, object data) { + int status; + TValue o; + lua_lock(L); + api_checknelems(L, 1); + o = L.top - 1; + if (isLfunction(o)) + status = luaU_dump(L, clvalue(o).l.p, writer, data, 0); + else + status = 1; + lua_unlock(L); + return status; + } + + + public static int lua_status (lua_State L) { + return L.status; + } + + + /* + ** Garbage-collection function + */ + + public static int lua_gc (lua_State L, int what, int data) { + int res = 0; + global_State g; + lua_lock(L); + g = G(L); + switch (what) { + case LUA_GCSTOP: { + g.GCthreshold = MAX_LUMEM; + break; + } + case LUA_GCRESTART: { + g.GCthreshold = g.totalbytes; + break; + } + case LUA_GCCOLLECT: { + luaC_fullgc(L); + break; + } + case LUA_GCCOUNT: { + /* GC values are expressed in Kbytes: #bytes/2^10 */ + res = cast_int(g.totalbytes >> 10); + break; + } + case LUA_GCCOUNTB: { + res = cast_int(g.totalbytes & 0x3ff); + break; + } + case LUA_GCSTEP: { + lu_mem a = ((lu_mem)data << 10); + if (a <= g.totalbytes) + g.GCthreshold = (uint)(g.totalbytes - a); + else + g.GCthreshold = 0; + while (g.GCthreshold <= g.totalbytes) { + luaC_step(L); + if (g.gcstate == GCSpause) { /* end of cycle? */ + res = 1; /* signal it */ + break; + } + } + break; + } + case LUA_GCSETPAUSE: { + res = g.gcpause; + g.gcpause = data; + break; + } + case LUA_GCSETSTEPMUL: { + res = g.gcstepmul; + g.gcstepmul = data; + break; + } + default: + res = -1; /* invalid option */ + break; + } + lua_unlock(L); + return res; + } + + + + /* + ** miscellaneous functions + */ + + + public static int lua_error (lua_State L) { + lua_lock(L); + api_checknelems(L, 1); + luaG_errormsg(L); + lua_unlock(L); + return 0; /* to avoid warnings */ + } + + + public static int lua_next (lua_State L, int idx) { + StkId t; + int more; + lua_lock(L); + t = index2adr(L, idx); + api_check(L, ttistable(t)); + more = luaH_next(L, hvalue(t), L.top - 1); + if (more != 0) { + api_incr_top(L); + } + else /* no more elements */ + StkId.dec(ref L.top); /* remove key */ + lua_unlock(L); + return more; + } + + + public static void lua_concat (lua_State L, int n) { + lua_lock(L); + api_checknelems(L, n); + if (n >= 2) { + luaC_checkGC(L); + luaV_concat(L, n, cast_int(L.top - L.base_) - 1); + L.top -= (n-1); + } + else if (n == 0) { /* push empty string */ + setsvalue2s(L, L.top, luaS_newlstr(L, "", 0)); + api_incr_top(L); + } + /* else n == 1; nothing to do */ + lua_unlock(L); + } + + + public static lua_Alloc lua_getallocf (lua_State L, ref object ud) { + lua_Alloc f; + lua_lock(L); + if (ud != null) ud = G(L).ud; + f = G(L).frealloc; + lua_unlock(L); + return f; + } + + + public static void lua_setallocf (lua_State L, lua_Alloc f, object ud) { + lua_lock(L); + G(L).ud = ud; + G(L).frealloc = f; + lua_unlock(L); + } + + [CLSCompliantAttribute(false)] + public static object lua_newuserdata(lua_State L, uint size) + { + Udata u; + lua_lock(L); + luaC_checkGC(L); + u = luaS_newudata(L, size, getcurrenv(L)); + setuvalue(L, L.top, u); + api_incr_top(L); + lua_unlock(L); + return u.user_data; + } + + // this one is used internally only + internal static object lua_newuserdata(lua_State L, Type t) + { + Udata u; + lua_lock(L); + luaC_checkGC(L); + u = luaS_newudata(L, t, getcurrenv(L)); + setuvalue(L, L.top, u); + api_incr_top(L); + lua_unlock(L); + return u.user_data; + } + + static CharPtr aux_upvalue (StkId fi, int n, ref TValue val) { + Closure f; + if (!ttisfunction(fi)) return null; + f = clvalue(fi); + if (f.c.isC != 0) { + if (!(1 <= n && n <= f.c.nupvalues)) return null; + val = f.c.upvalue[n-1]; + return ""; + } + else { + Proto p = f.l.p; + if (!(1 <= n && n <= p.sizeupvalues)) return null; + val = f.l.upvals[n-1].v; + return getstr(p.upvalues[n-1]); + } + } + + + public static CharPtr lua_getupvalue (lua_State L, int funcindex, int n) { + CharPtr name; + TValue val = new TValue(); + lua_lock(L); + name = aux_upvalue(index2adr(L, funcindex), n, ref val); + if (name != null) { + setobj2s(L, L.top, val); + api_incr_top(L); + } + lua_unlock(L); + return name; + } + + + public static CharPtr lua_setupvalue (lua_State L, int funcindex, int n) { + CharPtr name; + TValue val = new TValue(); + StkId fi; + lua_lock(L); + fi = index2adr(L, funcindex); + api_checknelems(L, 1); + name = aux_upvalue(fi, n, ref val); + if (name != null) { + StkId.dec(ref L.top); + setobj(L, val, L.top); + luaC_barrier(L, clvalue(fi), L.top); + } + lua_unlock(L); + return name; + } + + } +} diff --git a/Core/KopiLua/lauxlib.cs b/Core/KopiLua/lauxlib.cs index 031a769ed04a6d463ca2a9ac58c332405b9376ad..53a78692cab0fc919a0036d572b7b6138e6ef628 100644 --- a/Core/KopiLua/lauxlib.cs +++ b/Core/KopiLua/lauxlib.cs @@ -1,775 +1,775 @@ -/* -** $Id: lauxlib.c,v 1.159.1.3 2008/01/21 13:20:51 roberto Exp $ -** Auxiliary functions for building Lua libraries -** See Copyright Notice in lua.h -*/ - -#define lauxlib_c -#define LUA_LIB - -using System; -using System.IO; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace KopiLua -{ - using lua_Number = System.Double; - using lua_Integer = System.Int32; - - public partial class Lua - { - #if LUA_COMPAT_GETN - public static int luaL_getn(lua_State L, int t); - public static void luaL_setn(lua_State L, int t, int n); - #else - public static int luaL_getn(lua_State L, int i) {return (int)lua_objlen(L, i);} - public static void luaL_setn(lua_State L, int i, int j) {} /* no op! */ - #endif - - #if LUA_COMPAT_OPENLIB - //#define luaI_openlib luaL_openlib - #endif - - - /* extra error code for `luaL_load' */ - public const int LUA_ERRFILE = (LUA_ERRERR+1); - - - public class luaL_Reg { - public luaL_Reg(CharPtr name, lua_CFunction func) { - this.name = name; - this.func = func; - } - - public CharPtr name; - public lua_CFunction func; - }; - - - /* - ** =============================================================== - ** some useful macros - ** =============================================================== - */ - - public static void luaL_argcheck(lua_State L, bool cond, int numarg, string extramsg) { - if (!cond) - luaL_argerror(L, numarg, extramsg); - } - public static CharPtr luaL_checkstring(lua_State L, int n) { return luaL_checklstring(L, n); } - public static CharPtr luaL_optstring(lua_State L, int n, CharPtr d) { uint len; return luaL_optlstring(L, n, d, out len); } - public static int luaL_checkint(lua_State L, int n) {return (int)luaL_checkinteger(L, n);} - public static int luaL_optint(lua_State L, int n, lua_Integer d) {return (int)luaL_optinteger(L, n, d);} - public static long luaL_checklong(lua_State L, int n) {return luaL_checkinteger(L, n);} - public static long luaL_optlong(lua_State L, int n, lua_Integer d) {return luaL_optinteger(L, n, d);} - - public static CharPtr luaL_typename(lua_State L, int i) {return lua_typename(L, lua_type(L,i));} - - //#define luaL_dofile(L, fn) \ - // (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) - - //#define luaL_dostring(L, s) \ - // (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) - - public static void luaL_getmetatable(lua_State L, CharPtr n) { lua_getfield(L, LUA_REGISTRYINDEX, n); } - - public delegate lua_Number luaL_opt_delegate (lua_State L, int narg); - public static lua_Number luaL_opt(lua_State L, luaL_opt_delegate f, int n, lua_Number d) { - return lua_isnoneornil(L, (n != 0) ? d : f(L, n)) ? 1 : 0;} - - public delegate lua_Integer luaL_opt_delegate_integer(lua_State L, int narg); - public static lua_Integer luaL_opt_integer(lua_State L, luaL_opt_delegate_integer f, int n, lua_Number d) { - return (lua_Integer)(lua_isnoneornil(L, n) ? d : f(L, (n))); - } - - /* - ** {====================================================== - ** Generic Buffer manipulation - ** ======================================================= - */ - - - - public class luaL_Buffer { - public int p; /* current position in buffer */ - public int lvl; /* number of strings in the stack (level) */ - public lua_State L; - public CharPtr buffer = new char[LUAL_BUFFERSIZE]; - }; - - public static void luaL_addchar(luaL_Buffer B, char c) { - if (B.p >= LUAL_BUFFERSIZE) - luaL_prepbuffer(B); - B.buffer[B.p++] = c; - } - - ///* compatibility only */ - public static void luaL_putchar(luaL_Buffer B, char c) {luaL_addchar(B,c);} - - public static void luaL_addsize(luaL_Buffer B, int n) {B.p += n;} - - /* }====================================================== */ - - - /* compatibility with ref system */ - - /* pre-defined references */ - public const int LUA_NOREF = (-2); - public const int LUA_REFNIL = (-1); - - //#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \ - // (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0)) - - //#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref)) - - //#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref)) - - - //#define luaL_reg luaL_Reg - - - /* This file uses only the official API of Lua. - ** Any function declared here could be written as an application function. - */ - - //#define lauxlib_c - //#define LUA_LIB - - public const int FREELIST_REF = 0; /* free list of references */ - - - /* convert a stack index to positive */ - public static int abs_index(lua_State L, int i) - { - return ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1); - } - - - /* - ** {====================================================== - ** Error-report functions - ** ======================================================= - */ - - - public static int luaL_argerror (lua_State L, int narg, CharPtr extramsg) { - lua_Debug ar = new lua_Debug(); - if (lua_getstack(L, 0, ar)==0) /* no stack frame? */ - return luaL_error(L, "bad argument #%d (%s)", narg, extramsg); - lua_getinfo(L, "n", ar); - if (strcmp(ar.namewhat, "method") == 0) { - narg--; /* do not count `self' */ - if (narg == 0) /* error is in the self argument itself? */ - return luaL_error(L, "calling " + LUA_QS + " on bad self ({1})", - ar.name, extramsg); - } - if (ar.name == null) - ar.name = "?"; - return luaL_error(L, "bad argument #%d to " + LUA_QS + " (%s)", - narg, ar.name, extramsg); - } - - - public static int luaL_typerror (lua_State L, int narg, CharPtr tname) { - CharPtr msg = lua_pushfstring(L, "%s expected, got %s", - tname, luaL_typename(L, narg)); - return luaL_argerror(L, narg, msg); - } - - - private static void tag_error (lua_State L, int narg, int tag) { - luaL_typerror(L, narg, lua_typename(L, tag)); - } - - - public static void luaL_where (lua_State L, int level) { - lua_Debug ar = new lua_Debug(); - if (lua_getstack(L, level, ar) != 0) { /* check function at level */ - lua_getinfo(L, "Sl", ar); /* get info about it */ - if (ar.currentline > 0) { /* is there info? */ - lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); - return; - } - } - lua_pushliteral(L, ""); /* else, no information available... */ - } - - public static int luaL_error(lua_State L, CharPtr fmt, params object[] p) - { - luaL_where(L, 1); - lua_pushvfstring(L, fmt, p); - lua_concat(L, 2); - return lua_error(L); - } - - - /* }====================================================== */ - - - public static int luaL_checkoption (lua_State L, int narg, CharPtr def, - CharPtr [] lst) { - CharPtr name = (def != null) ? luaL_optstring(L, narg, def) : - luaL_checkstring(L, narg); - int i; - for (i=0; i= 0) { /* is there a numeric field `n'? */ - lua_pushliteral(L, "n"); /* use it */ - lua_pushinteger(L, n); - lua_rawset(L, t); - } - else { /* use `sizes' */ - getsizes(L); - lua_pushvalue(L, t); - lua_pushinteger(L, n); - lua_rawset(L, -3); /* sizes[t] = n */ - lua_pop(L, 1); /* remove `sizes' */ - } - } - - - public static int luaL_getn (lua_State L, int t) { - int n; - t = abs_index(L, t); - lua_pushliteral(L, "n"); /* try t.n */ - lua_rawget(L, t); - if ((n = checkint(L, 1)) >= 0) return n; - getsizes(L); /* else try sizes[t] */ - lua_pushvalue(L, t); - lua_rawget(L, -2); - if ((n = checkint(L, 2)) >= 0) return n; - return (int)lua_objlen(L, t); - } - - #endif - - /* }====================================================== */ - - - - public static CharPtr luaL_gsub (lua_State L, CharPtr s, CharPtr p, - CharPtr r) { - CharPtr wild; - uint l = (uint)strlen(p); - luaL_Buffer b = new luaL_Buffer(); - luaL_buffinit(L, b); - while ((wild = strstr(s, p)) != null) { - luaL_addlstring(b, s, (uint)(wild - s)); /* push prefix */ - luaL_addstring(b, r); /* push replacement in place of pattern */ - s = wild + l; /* continue after `p' */ - } - luaL_addstring(b, s); /* push last suffix */ - luaL_pushresult(b); - return lua_tostring(L, -1); - } - - - public static CharPtr luaL_findtable (lua_State L, int idx, - CharPtr fname, int szhint) { - CharPtr e; - lua_pushvalue(L, idx); - do { - e = strchr(fname, '.'); - if (e == null) e = fname + strlen(fname); - lua_pushlstring(L, fname, (uint)(e - fname)); - lua_rawget(L, -2); - if (lua_isnil(L, -1)) { /* no such field? */ - lua_pop(L, 1); /* remove this nil */ - lua_createtable(L, 0, (e == '.' ? 1 : szhint)); /* new table for field */ - lua_pushlstring(L, fname, (uint)(e - fname)); - lua_pushvalue(L, -2); - lua_settable(L, -4); /* set new table into field */ - } - else if (!lua_istable(L, -1)) { /* field has a non-table value? */ - lua_pop(L, 2); /* remove table and value */ - return fname; /* return problematic part of the name */ - } - lua_remove(L, -2); /* remove previous table */ - fname = e + 1; - } while (e == '.'); - return null; - } - - - - /* - ** {====================================================== - ** Generic Buffer manipulation - ** ======================================================= - */ - - - private static int bufflen(luaL_Buffer B) {return B.p;} - private static int bufffree(luaL_Buffer B) {return LUAL_BUFFERSIZE - bufflen(B);} - - public const int LIMIT = LUA_MINSTACK / 2; - - - private static int emptybuffer (luaL_Buffer B) { - uint l = (uint)bufflen(B); - if (l == 0) return 0; /* put nothing on stack */ - else { - lua_pushlstring(B.L, B.buffer, l); - B.p = 0; - B.lvl++; - return 1; - } - } - - - private static void adjuststack (luaL_Buffer B) { - if (B.lvl > 1) { - lua_State L = B.L; - int toget = 1; /* number of levels to concat */ - uint toplen = lua_strlen(L, -1); - do { - uint l = lua_strlen(L, -(toget+1)); - if (B.lvl - toget + 1 >= LIMIT || toplen > l) { - toplen += l; - toget++; - } - else break; - } while (toget < B.lvl); - lua_concat(L, toget); - B.lvl = B.lvl - toget + 1; - } - } - - - public static CharPtr luaL_prepbuffer (luaL_Buffer B) { - if (emptybuffer(B) != 0) - adjuststack(B); - return new CharPtr(B.buffer, B.p); - } - - [CLSCompliantAttribute(false)] - public static void luaL_addlstring (luaL_Buffer B, CharPtr s, uint l) { - while (l-- != 0) - { - char c = s[0]; - s = s.next(); - luaL_addchar(B, c); - } - } - - - public static void luaL_addstring (luaL_Buffer B, CharPtr s) { - luaL_addlstring(B, s, (uint)strlen(s)); - } - - - public static void luaL_pushresult (luaL_Buffer B) { - emptybuffer(B); - lua_concat(B.L, B.lvl); - B.lvl = 1; - } - - - public static void luaL_addvalue (luaL_Buffer B) { - lua_State L = B.L; - uint vl; - CharPtr s = lua_tolstring(L, -1, out vl); - if (vl <= bufffree(B)) { /* fit into buffer? */ - CharPtr dst = new CharPtr(B.buffer.chars, B.buffer.index + B.p); - CharPtr src = new CharPtr(s.chars, s.index); - for (uint i = 0; i < vl; i++) - dst[i] = src[i]; - B.p += (int)vl; - lua_pop(L, 1); /* remove from stack */ - } - else { - if (emptybuffer(B) != 0) - lua_insert(L, -2); /* put buffer before new value */ - B.lvl++; /* add new value into B stack */ - adjuststack(B); - } - } - - - public static void luaL_buffinit (lua_State L, luaL_Buffer B) { - B.L = L; - B.p = /*B.buffer*/ 0; - B.lvl = 0; - } - - /* }====================================================== */ - - - public static int luaL_ref (lua_State L, int t) { - int ref_; - t = abs_index(L, t); - if (lua_isnil(L, -1)) { - lua_pop(L, 1); /* remove from stack */ - return LUA_REFNIL; /* `nil' has a unique fixed reference */ - } - lua_rawgeti(L, t, FREELIST_REF); /* get first free element */ - ref_ = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */ - lua_pop(L, 1); /* remove it from stack */ - if (ref_ != 0) { /* any free element? */ - lua_rawgeti(L, t, ref_); /* remove it from list */ - lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ - } - else { /* no free elements */ - ref_ = (int)lua_objlen(L, t); - ref_++; /* create new reference */ - } - lua_rawseti(L, t, ref_); - return ref_; - } - - - public static void luaL_unref (lua_State L, int t, int ref_) { - if (ref_ >= 0) { - t = abs_index(L, t); - lua_rawgeti(L, t, FREELIST_REF); - lua_rawseti(L, t, ref_); /* t[ref] = t[FREELIST_REF] */ - lua_pushinteger(L, ref_); - lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */ - } - } - - - - /* - ** {====================================================== - ** Load functions - ** ======================================================= - */ - - public class LoadF { - public int extraline; - public Stream f; - public CharPtr buff = new char[LUAL_BUFFERSIZE]; - }; - - [CLSCompliantAttribute(false)] - public static CharPtr getF (lua_State L, object ud, out uint size) { - size = 0; - LoadF lf = (LoadF)ud; - //(void)L; - if (lf.extraline != 0) { - lf.extraline = 0; - size = 1; - return "\n"; - } - if (feof(lf.f) != 0) return null; - size = (uint)fread(lf.buff, 1, lf.buff.chars.Length, lf.f); - return (size > 0) ? new CharPtr(lf.buff) : null; - } - - - private static int errfile (lua_State L, CharPtr what, int fnameindex) { - CharPtr serr = strerror(errno()); - CharPtr filename = lua_tostring(L, fnameindex) + 1; - lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); - lua_remove(L, fnameindex); - return LUA_ERRFILE; - } - - - public static int luaL_loadfile (lua_State L, CharPtr filename) { - LoadF lf = new LoadF(); - int status, readstatus; - int c; - int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ - lf.extraline = 0; - if (filename == null) { - lua_pushliteral(L, "=stdin"); - lf.f = stdin; - } - else { - lua_pushfstring(L, "@%s", filename); - lf.f = fopen(filename, "r"); - if (lf.f == null) return errfile(L, "open", fnameindex); - } - c = getc(lf.f); - if (c == '#') { /* Unix exec. file? */ - lf.extraline = 1; - while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */ - if (c == '\n') c = getc(lf.f); - } - if (c == LUA_SIGNATURE[0] && (filename!=null)) { /* binary file? */ - lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ - if (lf.f == null) return errfile(L, "reopen", fnameindex); - /* skip eventual `#!...' */ - while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; - lf.extraline = 0; - } - ungetc(c, lf.f); - status = lua_load(L, getF, lf, lua_tostring(L, -1)); - readstatus = ferror(lf.f); - if (filename != null) fclose(lf.f); /* close file (even in case of errors) */ - if (readstatus != 0) { - lua_settop(L, fnameindex); /* ignore results from `lua_load' */ - return errfile(L, "read", fnameindex); - } - lua_remove(L, fnameindex); - return status; - } - - - public class LoadS { - public CharPtr s; - [CLSCompliantAttribute(false)] - public uint size; - }; - - - static CharPtr getS (lua_State L, object ud, out uint size) { - LoadS ls = (LoadS)ud; - //(void)L; - //if (ls.size == 0) return null; - size = ls.size; - ls.size = 0; - return ls.s; - } - - [CLSCompliantAttribute(false)] - public static int luaL_loadbuffer(lua_State L, CharPtr buff, uint size, - CharPtr name) { - LoadS ls = new LoadS(); - ls.s = new CharPtr(buff); - ls.size = size; - return lua_load(L, getS, ls, name); - } - - - public static int luaL_loadstring(lua_State L, CharPtr s) { - return luaL_loadbuffer(L, s, (uint)strlen(s), s); - } - - - - /* }====================================================== */ - - - private static object l_alloc (Type t) { - return System.Activator.CreateInstance(t); - } - - - private static int panic (lua_State L) { - //(void)L; /* to avoid warnings */ - fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", - lua_tostring(L, -1)); - return 0; - } - - - public static lua_State luaL_newstate() - { - lua_State L = lua_newstate(l_alloc, null); - if (L != null) lua_atpanic(L, panic); - return L; - } - - } -} +/* +** $Id: lauxlib.c,v 1.159.1.3 2008/01/21 13:20:51 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + +#define lauxlib_c +#define LUA_LIB + +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace KopiLua +{ + using lua_Number = System.Double; + using lua_Integer = System.Int32; + + public partial class Lua + { + #if LUA_COMPAT_GETN + public static int luaL_getn(lua_State L, int t); + public static void luaL_setn(lua_State L, int t, int n); + #else + public static int luaL_getn(lua_State L, int i) {return (int)lua_objlen(L, i);} + public static void luaL_setn(lua_State L, int i, int j) {} /* no op! */ + #endif + + #if LUA_COMPAT_OPENLIB + //#define luaI_openlib luaL_openlib + #endif + + + /* extra error code for `luaL_load' */ + public const int LUA_ERRFILE = (LUA_ERRERR+1); + + + public class luaL_Reg { + public luaL_Reg(CharPtr name, lua_CFunction func) { + this.name = name; + this.func = func; + } + + public CharPtr name; + public lua_CFunction func; + }; + + + /* + ** =============================================================== + ** some useful macros + ** =============================================================== + */ + + public static void luaL_argcheck(lua_State L, bool cond, int numarg, string extramsg) { + if (!cond) + luaL_argerror(L, numarg, extramsg); + } + public static CharPtr luaL_checkstring(lua_State L, int n) { return luaL_checklstring(L, n); } + public static CharPtr luaL_optstring(lua_State L, int n, CharPtr d) { uint len; return luaL_optlstring(L, n, d, out len); } + public static int luaL_checkint(lua_State L, int n) {return (int)luaL_checkinteger(L, n);} + public static int luaL_optint(lua_State L, int n, lua_Integer d) {return (int)luaL_optinteger(L, n, d);} + public static long luaL_checklong(lua_State L, int n) {return luaL_checkinteger(L, n);} + public static long luaL_optlong(lua_State L, int n, lua_Integer d) {return luaL_optinteger(L, n, d);} + + public static CharPtr luaL_typename(lua_State L, int i) {return lua_typename(L, lua_type(L,i));} + + //#define luaL_dofile(L, fn) \ + // (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) + + //#define luaL_dostring(L, s) \ + // (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) + + public static void luaL_getmetatable(lua_State L, CharPtr n) { lua_getfield(L, LUA_REGISTRYINDEX, n); } + + public delegate lua_Number luaL_opt_delegate (lua_State L, int narg); + public static lua_Number luaL_opt(lua_State L, luaL_opt_delegate f, int n, lua_Number d) { + return lua_isnoneornil(L, (n != 0) ? d : f(L, n)) ? 1 : 0;} + + public delegate lua_Integer luaL_opt_delegate_integer(lua_State L, int narg); + public static lua_Integer luaL_opt_integer(lua_State L, luaL_opt_delegate_integer f, int n, lua_Number d) { + return (lua_Integer)(lua_isnoneornil(L, n) ? d : f(L, (n))); + } + + /* + ** {====================================================== + ** Generic Buffer manipulation + ** ======================================================= + */ + + + + public class luaL_Buffer { + public int p; /* current position in buffer */ + public int lvl; /* number of strings in the stack (level) */ + public lua_State L; + public CharPtr buffer = new char[LUAL_BUFFERSIZE]; + }; + + public static void luaL_addchar(luaL_Buffer B, char c) { + if (B.p >= LUAL_BUFFERSIZE) + luaL_prepbuffer(B); + B.buffer[B.p++] = c; + } + + ///* compatibility only */ + public static void luaL_putchar(luaL_Buffer B, char c) {luaL_addchar(B,c);} + + public static void luaL_addsize(luaL_Buffer B, int n) {B.p += n;} + + /* }====================================================== */ + + + /* compatibility with ref system */ + + /* pre-defined references */ + public const int LUA_NOREF = (-2); + public const int LUA_REFNIL = (-1); + + //#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \ + // (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0)) + + //#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref)) + + //#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref)) + + + //#define luaL_reg luaL_Reg + + + /* This file uses only the official API of Lua. + ** Any function declared here could be written as an application function. + */ + + //#define lauxlib_c + //#define LUA_LIB + + public const int FREELIST_REF = 0; /* free list of references */ + + + /* convert a stack index to positive */ + public static int abs_index(lua_State L, int i) + { + return ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1); + } + + + /* + ** {====================================================== + ** Error-report functions + ** ======================================================= + */ + + + public static int luaL_argerror (lua_State L, int narg, CharPtr extramsg) { + lua_Debug ar = new lua_Debug(); + if (lua_getstack(L, 0, ar)==0) /* no stack frame? */ + return luaL_error(L, "bad argument #%d (%s)", narg, extramsg); + lua_getinfo(L, "n", ar); + if (strcmp(ar.namewhat, "method") == 0) { + narg--; /* do not count `self' */ + if (narg == 0) /* error is in the self argument itself? */ + return luaL_error(L, "calling " + LUA_QS + " on bad self ({1})", + ar.name, extramsg); + } + if (ar.name == null) + ar.name = "?"; + return luaL_error(L, "bad argument #%d to " + LUA_QS + " (%s)", + narg, ar.name, extramsg); + } + + + public static int luaL_typerror (lua_State L, int narg, CharPtr tname) { + CharPtr msg = lua_pushfstring(L, "%s expected, got %s", + tname, luaL_typename(L, narg)); + return luaL_argerror(L, narg, msg); + } + + + private static void tag_error (lua_State L, int narg, int tag) { + luaL_typerror(L, narg, lua_typename(L, tag)); + } + + + public static void luaL_where (lua_State L, int level) { + lua_Debug ar = new lua_Debug(); + if (lua_getstack(L, level, ar) != 0) { /* check function at level */ + lua_getinfo(L, "Sl", ar); /* get info about it */ + if (ar.currentline > 0) { /* is there info? */ + lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); + return; + } + } + lua_pushliteral(L, ""); /* else, no information available... */ + } + + public static int luaL_error(lua_State L, CharPtr fmt, params object[] p) + { + luaL_where(L, 1); + lua_pushvfstring(L, fmt, p); + lua_concat(L, 2); + return lua_error(L); + } + + + /* }====================================================== */ + + + public static int luaL_checkoption (lua_State L, int narg, CharPtr def, + CharPtr [] lst) { + CharPtr name = (def != null) ? luaL_optstring(L, narg, def) : + luaL_checkstring(L, narg); + int i; + for (i=0; i= 0) { /* is there a numeric field `n'? */ + lua_pushliteral(L, "n"); /* use it */ + lua_pushinteger(L, n); + lua_rawset(L, t); + } + else { /* use `sizes' */ + getsizes(L); + lua_pushvalue(L, t); + lua_pushinteger(L, n); + lua_rawset(L, -3); /* sizes[t] = n */ + lua_pop(L, 1); /* remove `sizes' */ + } + } + + + public static int luaL_getn (lua_State L, int t) { + int n; + t = abs_index(L, t); + lua_pushliteral(L, "n"); /* try t.n */ + lua_rawget(L, t); + if ((n = checkint(L, 1)) >= 0) return n; + getsizes(L); /* else try sizes[t] */ + lua_pushvalue(L, t); + lua_rawget(L, -2); + if ((n = checkint(L, 2)) >= 0) return n; + return (int)lua_objlen(L, t); + } + + #endif + + /* }====================================================== */ + + + + public static CharPtr luaL_gsub (lua_State L, CharPtr s, CharPtr p, + CharPtr r) { + CharPtr wild; + uint l = (uint)strlen(p); + luaL_Buffer b = new luaL_Buffer(); + luaL_buffinit(L, b); + while ((wild = strstr(s, p)) != null) { + luaL_addlstring(b, s, (uint)(wild - s)); /* push prefix */ + luaL_addstring(b, r); /* push replacement in place of pattern */ + s = wild + l; /* continue after `p' */ + } + luaL_addstring(b, s); /* push last suffix */ + luaL_pushresult(b); + return lua_tostring(L, -1); + } + + + public static CharPtr luaL_findtable (lua_State L, int idx, + CharPtr fname, int szhint) { + CharPtr e; + lua_pushvalue(L, idx); + do { + e = strchr(fname, '.'); + if (e == null) e = fname + strlen(fname); + lua_pushlstring(L, fname, (uint)(e - fname)); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { /* no such field? */ + lua_pop(L, 1); /* remove this nil */ + lua_createtable(L, 0, (e == '.' ? 1 : szhint)); /* new table for field */ + lua_pushlstring(L, fname, (uint)(e - fname)); + lua_pushvalue(L, -2); + lua_settable(L, -4); /* set new table into field */ + } + else if (!lua_istable(L, -1)) { /* field has a non-table value? */ + lua_pop(L, 2); /* remove table and value */ + return fname; /* return problematic part of the name */ + } + lua_remove(L, -2); /* remove previous table */ + fname = e + 1; + } while (e == '.'); + return null; + } + + + + /* + ** {====================================================== + ** Generic Buffer manipulation + ** ======================================================= + */ + + + private static int bufflen(luaL_Buffer B) {return B.p;} + private static int bufffree(luaL_Buffer B) {return LUAL_BUFFERSIZE - bufflen(B);} + + public const int LIMIT = LUA_MINSTACK / 2; + + + private static int emptybuffer (luaL_Buffer B) { + uint l = (uint)bufflen(B); + if (l == 0) return 0; /* put nothing on stack */ + else { + lua_pushlstring(B.L, B.buffer, l); + B.p = 0; + B.lvl++; + return 1; + } + } + + + private static void adjuststack (luaL_Buffer B) { + if (B.lvl > 1) { + lua_State L = B.L; + int toget = 1; /* number of levels to concat */ + uint toplen = lua_strlen(L, -1); + do { + uint l = lua_strlen(L, -(toget+1)); + if (B.lvl - toget + 1 >= LIMIT || toplen > l) { + toplen += l; + toget++; + } + else break; + } while (toget < B.lvl); + lua_concat(L, toget); + B.lvl = B.lvl - toget + 1; + } + } + + + public static CharPtr luaL_prepbuffer (luaL_Buffer B) { + if (emptybuffer(B) != 0) + adjuststack(B); + return new CharPtr(B.buffer, B.p); + } + + [CLSCompliantAttribute(false)] + public static void luaL_addlstring (luaL_Buffer B, CharPtr s, uint l) { + while (l-- != 0) + { + char c = s[0]; + s = s.next(); + luaL_addchar(B, c); + } + } + + + public static void luaL_addstring (luaL_Buffer B, CharPtr s) { + luaL_addlstring(B, s, (uint)strlen(s)); + } + + + public static void luaL_pushresult (luaL_Buffer B) { + emptybuffer(B); + lua_concat(B.L, B.lvl); + B.lvl = 1; + } + + + public static void luaL_addvalue (luaL_Buffer B) { + lua_State L = B.L; + uint vl; + CharPtr s = lua_tolstring(L, -1, out vl); + if (vl <= bufffree(B)) { /* fit into buffer? */ + CharPtr dst = new CharPtr(B.buffer.chars, B.buffer.index + B.p); + CharPtr src = new CharPtr(s.chars, s.index); + for (uint i = 0; i < vl; i++) + dst[i] = src[i]; + B.p += (int)vl; + lua_pop(L, 1); /* remove from stack */ + } + else { + if (emptybuffer(B) != 0) + lua_insert(L, -2); /* put buffer before new value */ + B.lvl++; /* add new value into B stack */ + adjuststack(B); + } + } + + + public static void luaL_buffinit (lua_State L, luaL_Buffer B) { + B.L = L; + B.p = /*B.buffer*/ 0; + B.lvl = 0; + } + + /* }====================================================== */ + + + public static int luaL_ref (lua_State L, int t) { + int ref_; + t = abs_index(L, t); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* remove from stack */ + return LUA_REFNIL; /* `nil' has a unique fixed reference */ + } + lua_rawgeti(L, t, FREELIST_REF); /* get first free element */ + ref_ = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */ + lua_pop(L, 1); /* remove it from stack */ + if (ref_ != 0) { /* any free element? */ + lua_rawgeti(L, t, ref_); /* remove it from list */ + lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */ + } + else { /* no free elements */ + ref_ = (int)lua_objlen(L, t); + ref_++; /* create new reference */ + } + lua_rawseti(L, t, ref_); + return ref_; + } + + + public static void luaL_unref (lua_State L, int t, int ref_) { + if (ref_ >= 0) { + t = abs_index(L, t); + lua_rawgeti(L, t, FREELIST_REF); + lua_rawseti(L, t, ref_); /* t[ref] = t[FREELIST_REF] */ + lua_pushinteger(L, ref_); + lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */ + } + } + + + + /* + ** {====================================================== + ** Load functions + ** ======================================================= + */ + + public class LoadF { + public int extraline; + public Stream f; + public CharPtr buff = new char[LUAL_BUFFERSIZE]; + }; + + [CLSCompliantAttribute(false)] + public static CharPtr getF (lua_State L, object ud, out uint size) { + size = 0; + LoadF lf = (LoadF)ud; + //(void)L; + if (lf.extraline != 0) { + lf.extraline = 0; + size = 1; + return "\n"; + } + if (feof(lf.f) != 0) return null; + size = (uint)fread(lf.buff, 1, lf.buff.chars.Length, lf.f); + return (size > 0) ? new CharPtr(lf.buff) : null; + } + + + private static int errfile (lua_State L, CharPtr what, int fnameindex) { + CharPtr serr = strerror(errno()); + CharPtr filename = lua_tostring(L, fnameindex) + 1; + lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); + lua_remove(L, fnameindex); + return LUA_ERRFILE; + } + + + public static int luaL_loadfile (lua_State L, CharPtr filename) { + LoadF lf = new LoadF(); + int status, readstatus; + int c; + int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ + lf.extraline = 0; + if (filename == null) { + lua_pushliteral(L, "=stdin"); + lf.f = stdin; + } + else { + lua_pushfstring(L, "@%s", filename); + lf.f = fopen(filename, "r"); + if (lf.f == null) return errfile(L, "open", fnameindex); + } + c = getc(lf.f); + if (c == '#') { /* Unix exec. file? */ + lf.extraline = 1; + while ((c = getc(lf.f)) != EOF && c != '\n') ; /* skip first line */ + if (c == '\n') c = getc(lf.f); + } + if (c == LUA_SIGNATURE[0] && (filename!=null)) { /* binary file? */ + lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ + if (lf.f == null) return errfile(L, "reopen", fnameindex); + /* skip eventual `#!...' */ + while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ; + lf.extraline = 0; + } + ungetc(c, lf.f); + status = lua_load(L, getF, lf, lua_tostring(L, -1)); + readstatus = ferror(lf.f); + if (filename != null) fclose(lf.f); /* close file (even in case of errors) */ + if (readstatus != 0) { + lua_settop(L, fnameindex); /* ignore results from `lua_load' */ + return errfile(L, "read", fnameindex); + } + lua_remove(L, fnameindex); + return status; + } + + + public class LoadS { + public CharPtr s; + [CLSCompliantAttribute(false)] + public uint size; + }; + + + static CharPtr getS (lua_State L, object ud, out uint size) { + LoadS ls = (LoadS)ud; + //(void)L; + //if (ls.size == 0) return null; + size = ls.size; + ls.size = 0; + return ls.s; + } + + [CLSCompliantAttribute(false)] + public static int luaL_loadbuffer(lua_State L, CharPtr buff, uint size, + CharPtr name) { + LoadS ls = new LoadS(); + ls.s = new CharPtr(buff); + ls.size = size; + return lua_load(L, getS, ls, name); + } + + + public static int luaL_loadstring(lua_State L, CharPtr s) { + return luaL_loadbuffer(L, s, (uint)strlen(s), s); + } + + + + /* }====================================================== */ + + + private static object l_alloc (Type t) { + return System.Activator.CreateInstance(t); + } + + + private static int panic (lua_State L) { + //(void)L; /* to avoid warnings */ + fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", + lua_tostring(L, -1)); + return 0; + } + + + public static lua_State luaL_newstate() + { + lua_State L = lua_newstate(l_alloc, null); + if (L != null) lua_atpanic(L, panic); + return L; + } + + } +} diff --git a/Core/KopiLua/lbaselib.cs b/Core/KopiLua/lbaselib.cs index 3316a9116ca9a56950e8ac665a6fe6d93106dc03..ffef0bd6e4d04292144db06f828c996a916a4738 100644 --- a/Core/KopiLua/lbaselib.cs +++ b/Core/KopiLua/lbaselib.cs @@ -1,652 +1,652 @@ -/* -** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 roberto Exp $ -** Basic library -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace KopiLua -{ - using lua_Number = System.Double; - - public partial class Lua - { - /* - ** If your system does not support `stdout', you can just remove this function. - ** If you need, you can define your own `print' function, following this - ** model but changing `fputs' to put the strings at a proper place - ** (a console window or a log file, for instance). - */ - private static int luaB_print (lua_State L) { - int n = lua_gettop(L); /* number of arguments */ - int i; - lua_getglobal(L, "tostring"); - for (i=1; i<=n; i++) { - CharPtr s; - lua_pushvalue(L, -1); /* function to be called */ - lua_pushvalue(L, i); /* value to print */ - lua_call(L, 1, 1); - s = lua_tostring(L, -1); /* get result */ - if (s == null) - return luaL_error(L, LUA_QL("tostring") + " must return a string to " + - LUA_QL("print")); - if (i > 1) fputs("\t", stdout); - fputs(s, stdout); - lua_pop(L, 1); /* pop result */ - } - Console.Write("\n", stdout); - return 0; - } - - - private static int luaB_tonumber (lua_State L) { - int base_ = luaL_optint(L, 2, 10); - if (base_ == 10) { /* standard conversion */ - luaL_checkany(L, 1); - if (lua_isnumber(L, 1) != 0) { - lua_pushnumber(L, lua_tonumber(L, 1)); - return 1; - } - } - else { - CharPtr s1 = luaL_checkstring(L, 1); - CharPtr s2; - ulong n; - luaL_argcheck(L, 2 <= base_ && base_ <= 36, 2, "base out of range"); - n = strtoul(s1, out s2, base_); - if (s1 != s2) { /* at least one valid digit? */ - while (isspace((byte)(s2[0]))) s2 = s2.next(); /* skip trailing spaces */ - if (s2[0] == '\0') { /* no invalid trailing characters? */ - lua_pushnumber(L, (lua_Number)n); - return 1; - } - } - } - lua_pushnil(L); /* else not a number */ - return 1; - } - - - private static int luaB_error (lua_State L) { - int level = luaL_optint(L, 2, 1); - lua_settop(L, 1); - if ((lua_isstring(L, 1)!=0) && (level > 0)) { /* add extra information? */ - luaL_where(L, level); - lua_pushvalue(L, 1); - lua_concat(L, 2); - } - return lua_error(L); - } - - - private static int luaB_getmetatable (lua_State L) { - luaL_checkany(L, 1); - if (lua_getmetatable(L, 1)==0) { - lua_pushnil(L); - return 1; /* no metatable */ - } - luaL_getmetafield(L, 1, "__metatable"); - return 1; /* returns either __metatable field (if present) or metatable */ - } - - - private static int luaB_setmetatable (lua_State L) { - int t = lua_type(L, 2); - luaL_checktype(L, 1, LUA_TTABLE); - luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, - "nil or table expected"); - if (luaL_getmetafield(L, 1, "__metatable") != 0) - luaL_error(L, "cannot change a protected metatable"); - lua_settop(L, 2); - lua_setmetatable(L, 1); - return 1; - } - - - private static void getfunc (lua_State L, int opt) { - if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); - else { - lua_Debug ar = new lua_Debug(); - int level = (opt != 0) ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1); - luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); - if (lua_getstack(L, level, ar) == 0) - luaL_argerror(L, 1, "invalid level"); - lua_getinfo(L, "f", ar); - if (lua_isnil(L, -1)) - luaL_error(L, "no function environment for tail call at level %d", - level); - } - } - - - private static int luaB_getfenv (lua_State L) { - getfunc(L, 1); - if (lua_iscfunction(L, -1)) /* is a C function? */ - lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */ - else - lua_getfenv(L, -1); - return 1; - } - - - private static int luaB_setfenv (lua_State L) { - luaL_checktype(L, 2, LUA_TTABLE); - getfunc(L, 0); - lua_pushvalue(L, 2); - if ((lua_isnumber(L, 1)!=0) && (lua_tonumber(L, 1) == 0)) { - /* change environment of current thread */ - lua_pushthread(L); - lua_insert(L, -2); - lua_setfenv(L, -2); - return 0; - } - else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) - luaL_error(L, - LUA_QL("setfenv") + " cannot change environment of given object"); - return 1; - } - - - private static int luaB_rawequal (lua_State L) { - luaL_checkany(L, 1); - luaL_checkany(L, 2); - lua_pushboolean(L, lua_rawequal(L, 1, 2)); - return 1; - } - - - private static int luaB_rawget (lua_State L) { - luaL_checktype(L, 1, LUA_TTABLE); - luaL_checkany(L, 2); - lua_settop(L, 2); - lua_rawget(L, 1); - return 1; - } - - private static int luaB_rawset (lua_State L) { - luaL_checktype(L, 1, LUA_TTABLE); - luaL_checkany(L, 2); - luaL_checkany(L, 3); - lua_settop(L, 3); - lua_rawset(L, 1); - return 1; - } - - - private static int luaB_gcinfo (lua_State L) { - lua_pushinteger(L, lua_getgccount(L)); - return 1; - } - - public static readonly CharPtr[] opts = {"stop", "restart", "collect", - "count", "step", "setpause", "setstepmul", null}; - public readonly static int[] optsnum = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, - LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; - - private static int luaB_collectgarbage (lua_State L) { - int o = luaL_checkoption(L, 1, "collect", opts); - int ex = luaL_optint(L, 2, 0); - int res = lua_gc(L, optsnum[o], ex); - switch (optsnum[o]) { - case LUA_GCCOUNT: { - int b = lua_gc(L, LUA_GCCOUNTB, 0); - lua_pushnumber(L, res + ((lua_Number)b/1024)); - return 1; - } - case LUA_GCSTEP: { - lua_pushboolean(L, res); - return 1; - } - default: { - lua_pushnumber(L, res); - return 1; - } - } - } - - - private static int luaB_type (lua_State L) { - luaL_checkany(L, 1); - lua_pushstring(L, luaL_typename(L, 1)); - return 1; - } - - - private static int luaB_next (lua_State L) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_settop(L, 2); /* create a 2nd argument if there isn't one */ - if (lua_next(L, 1) != 0) - return 2; - else { - lua_pushnil(L); - return 1; - } - } - - - private static int luaB_pairs (lua_State L) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ - lua_pushvalue(L, 1); /* state, */ - lua_pushnil(L); /* and initial value */ - return 3; - } - - - private static int ipairsaux (lua_State L) { - int i = luaL_checkint(L, 2); - luaL_checktype(L, 1, LUA_TTABLE); - i++; /* next value */ - lua_pushinteger(L, i); - lua_rawgeti(L, 1, i); - return (lua_isnil(L, -1)) ? 0 : 2; - } - - - private static int luaB_ipairs (lua_State L) { - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ - lua_pushvalue(L, 1); /* state, */ - lua_pushinteger(L, 0); /* and initial value */ - return 3; - } - - - private static int load_aux (lua_State L, int status) { - if (status == 0) /* OK? */ - return 1; - else { - lua_pushnil(L); - lua_insert(L, -2); /* put before error message */ - return 2; /* return nil plus error message */ - } - } - - - private static int luaB_loadstring (lua_State L) { - uint l; - CharPtr s = luaL_checklstring(L, 1, out l); - CharPtr chunkname = luaL_optstring(L, 2, s); - return load_aux(L, luaL_loadbuffer(L, s, l, chunkname)); - } - - - private static int luaB_loadfile (lua_State L) { - CharPtr fname = luaL_optstring(L, 1, null); - return load_aux(L, luaL_loadfile(L, fname)); - } - - - /* - ** Reader for generic `load' function: `lua_load' uses the - ** stack for internal stuff, so the reader cannot change the - ** stack top. Instead, it keeps its resulting string in a - ** reserved slot inside the stack. - */ - private static CharPtr generic_reader (lua_State L, object ud, out uint size) { - //(void)ud; /* to avoid warnings */ - luaL_checkstack(L, 2, "too many nested functions"); - lua_pushvalue(L, 1); /* get function */ - lua_call(L, 0, 1); /* call it */ - if (lua_isnil(L, -1)) { - size = 0; - return null; - } - else if (lua_isstring(L, -1) != 0) - { - lua_replace(L, 3); /* save string in a reserved stack slot */ - return lua_tolstring(L, 3, out size); - } - else - { - size = 0; - luaL_error(L, "reader function must return a string"); - } - return null; /* to avoid warnings */ - } - - - private static int luaB_load (lua_State L) { - int status; - CharPtr cname = luaL_optstring(L, 2, "=(load)"); - luaL_checktype(L, 1, LUA_TFUNCTION); - lua_settop(L, 3); /* function, eventual name, plus one reserved slot */ - status = lua_load(L, generic_reader, null, cname); - return load_aux(L, status); - } - - - private static int luaB_dofile (lua_State L) { - CharPtr fname = luaL_optstring(L, 1, null); - int n = lua_gettop(L); - if (luaL_loadfile(L, fname) != 0) lua_error(L); - lua_call(L, 0, LUA_MULTRET); - return lua_gettop(L) - n; - } - - - private static int luaB_assert (lua_State L) { - luaL_checkany(L, 1); - if (lua_toboolean(L, 1)==0) - return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); - return lua_gettop(L); - } - - - private static int luaB_unpack (lua_State L) { - int i, e, n; - luaL_checktype(L, 1, LUA_TTABLE); - i = luaL_optint(L, 2, 1); - e = luaL_opt_integer(L, luaL_checkint, 3, luaL_getn(L, 1)); - if (i > e) return 0; /* empty range */ - n = e - i + 1; /* number of elements */ - if (n <= 0 || (lua_checkstack(L, n)==0)) /* n <= 0 means arith. overflow */ - return luaL_error(L, "too many results to unpack"); - lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ - while (i++ < e) /* push arg[i + 1...e] */ - lua_rawgeti(L, 1, i); - return n; - } - - - private static int luaB_select (lua_State L) { - int n = lua_gettop(L); - if (lua_type(L, 1) == LUA_TSTRING && lua_tostring(L, 1)[0] == '#') { - lua_pushinteger(L, n-1); - return 1; - } - else { - int i = luaL_checkint(L, 1); - if (i < 0) i = n + i; - else if (i > n) i = n; - luaL_argcheck(L, 1 <= i, 1, "index out of range"); - return n - i; - } - } - - - private static int luaB_pcall (lua_State L) { - int status; - luaL_checkany(L, 1); - status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); - lua_pushboolean(L, (status == 0) ? 1 : 0); - lua_insert(L, 1); - return lua_gettop(L); /* return status + all results */ - } - - - private static int luaB_xpcall (lua_State L) { - int status; - luaL_checkany(L, 2); - lua_settop(L, 2); - lua_insert(L, 1); /* put error function under function to be called */ - status = lua_pcall(L, 0, LUA_MULTRET, 1); - lua_pushboolean(L, (status == 0) ? 1 : 0); - lua_replace(L, 1); - return lua_gettop(L); /* return status + all results */ - } - - - private static int luaB_tostring (lua_State L) { - luaL_checkany(L, 1); - if (luaL_callmeta(L, 1, "__tostring") != 0) /* is there a metafield? */ - return 1; /* use its value */ - switch (lua_type(L, 1)) { - case LUA_TNUMBER: - lua_pushstring(L, lua_tostring(L, 1)); - break; - case LUA_TSTRING: - lua_pushvalue(L, 1); - break; - case LUA_TBOOLEAN: - lua_pushstring(L, (lua_toboolean(L, 1) != 0 ? "true" : "false")); - break; - case LUA_TNIL: - lua_pushliteral(L, "nil"); - break; - default: - lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); - break; - } - return 1; - } - - - private static int luaB_newproxy (lua_State L) { - lua_settop(L, 1); - lua_newuserdata(L, 0); /* create proxy */ - if (lua_toboolean(L, 1) == 0) - return 1; /* no metatable */ - else if (lua_isboolean(L, 1)) { - lua_newtable(L); /* create a new metatable `m' ... */ - lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */ - lua_pushboolean(L, 1); - lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */ - } - else { - int validproxy = 0; /* to check if weaktable[metatable(u)] == true */ - if (lua_getmetatable(L, 1) != 0) { - lua_rawget(L, lua_upvalueindex(1)); - validproxy = lua_toboolean(L, -1); - lua_pop(L, 1); /* remove value */ - } - luaL_argcheck(L, validproxy!=0, 1, "boolean or proxy expected"); - lua_getmetatable(L, 1); /* metatable is valid; get it */ - } - lua_setmetatable(L, 2); - return 1; - } - - - private readonly static luaL_Reg[] base_funcs = { - new luaL_Reg("assert", luaB_assert), - new luaL_Reg("collectgarbage", luaB_collectgarbage), - new luaL_Reg("dofile", luaB_dofile), - new luaL_Reg("error", luaB_error), - new luaL_Reg("gcinfo", luaB_gcinfo), - new luaL_Reg("getfenv", luaB_getfenv), - new luaL_Reg("getmetatable", luaB_getmetatable), - new luaL_Reg("loadfile", luaB_loadfile), - new luaL_Reg("load", luaB_load), - new luaL_Reg("loadstring", luaB_loadstring), - new luaL_Reg("next", luaB_next), - new luaL_Reg("pcall", luaB_pcall), - new luaL_Reg("print", luaB_print), - new luaL_Reg("rawequal", luaB_rawequal), - new luaL_Reg("rawget", luaB_rawget), - new luaL_Reg("rawset", luaB_rawset), - new luaL_Reg("select", luaB_select), - new luaL_Reg("setfenv", luaB_setfenv), - new luaL_Reg("setmetatable", luaB_setmetatable), - new luaL_Reg("tonumber", luaB_tonumber), - new luaL_Reg("tostring", luaB_tostring), - new luaL_Reg("type", luaB_type), - new luaL_Reg("unpack", luaB_unpack), - new luaL_Reg("xpcall", luaB_xpcall), - new luaL_Reg(null, null) - }; - - - /* - ** {====================================================== - ** Coroutine library - ** ======================================================= - */ - - public const int CO_RUN = 0; /* running */ - public const int CO_SUS = 1; /* suspended */ - public const int CO_NOR = 2; /* 'normal' (it resumed another coroutine) */ - public const int CO_DEAD = 3; - - private static readonly string[] statnames = - {"running", "suspended", "normal", "dead"}; - - private static int costatus (lua_State L, lua_State co) { - if (L == co) return CO_RUN; - switch (lua_status(co)) { - case LUA_YIELD: - return CO_SUS; - case 0: { - lua_Debug ar = new lua_Debug(); - if (lua_getstack(co, 0, ar) > 0) /* does it have frames? */ - return CO_NOR; /* it is running */ - else if (lua_gettop(co) == 0) - return CO_DEAD; - else - return CO_SUS; /* initial state */ - } - default: /* some error occured */ - return CO_DEAD; - } - } - - - private static int luaB_costatus (lua_State L) { - lua_State co = lua_tothread(L, 1); - luaL_argcheck(L, co!=null, 1, "coroutine expected"); - lua_pushstring(L, statnames[costatus(L, co)]); - return 1; - } - - - private static int auxresume (lua_State L, lua_State co, int narg) { - int status = costatus(L, co); - if (lua_checkstack(co, narg)==0) - luaL_error(L, "too many arguments to resume"); - if (status != CO_SUS) { - lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]); - return -1; /* error flag */ - } - lua_xmove(L, co, narg); - lua_setlevel(L, co); - status = lua_resume(co, narg); - if (status == 0 || status == LUA_YIELD) { - int nres = lua_gettop(co); - if (lua_checkstack(L, nres + 1)==0) - luaL_error(L, "too many results to resume"); - lua_xmove(co, L, nres); /* move yielded values */ - return nres; - } - else { - lua_xmove(co, L, 1); /* move error message */ - return -1; /* error flag */ - } - } - - - private static int luaB_coresume (lua_State L) { - lua_State co = lua_tothread(L, 1); - int r; - luaL_argcheck(L, co!=null, 1, "coroutine expected"); - r = auxresume(L, co, lua_gettop(L) - 1); - if (r < 0) { - lua_pushboolean(L, 0); - lua_insert(L, -2); - return 2; /* return false + error message */ - } - else { - lua_pushboolean(L, 1); - lua_insert(L, -(r + 1)); - return r + 1; /* return true + `resume' returns */ - } - } - - - private static int luaB_auxwrap (lua_State L) { - lua_State co = lua_tothread(L, lua_upvalueindex(1)); - int r = auxresume(L, co, lua_gettop(L)); - if (r < 0) { - if (lua_isstring(L, -1) != 0) { /* error object is a string? */ - luaL_where(L, 1); /* add extra info */ - lua_insert(L, -2); - lua_concat(L, 2); - } - lua_error(L); /* propagate error */ - } - return r; - } - - - private static int luaB_cocreate (lua_State L) { - lua_State NL = lua_newthread(L); - luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, - "Lua function expected"); - lua_pushvalue(L, 1); /* move function to top */ - lua_xmove(L, NL, 1); /* move function from L to NL */ - return 1; - } - - - private static int luaB_cowrap (lua_State L) { - luaB_cocreate(L); - lua_pushcclosure(L, luaB_auxwrap, 1); - return 1; - } - - - private static int luaB_yield (lua_State L) { - return lua_yield(L, lua_gettop(L)); - } - - - private static int luaB_corunning (lua_State L) { - if (lua_pushthread(L) != 0) - lua_pushnil(L); /* main thread is not a coroutine */ - return 1; - } - - - private readonly static luaL_Reg[] co_funcs = { - new luaL_Reg("create", luaB_cocreate), - new luaL_Reg("resume", luaB_coresume), - new luaL_Reg("running", luaB_corunning), - new luaL_Reg("status", luaB_costatus), - new luaL_Reg("wrap", luaB_cowrap), - new luaL_Reg("yield", luaB_yield), - new luaL_Reg(null, null) - }; - - /* }====================================================== */ - - - private static void auxopen (lua_State L, CharPtr name, - lua_CFunction f, lua_CFunction u) { - lua_pushcfunction(L, u); - lua_pushcclosure(L, f, 1); - lua_setfield(L, -2, name); - } - - - private static void base_open (lua_State L) { - /* set global _G */ - lua_pushvalue(L, LUA_GLOBALSINDEX); - lua_setglobal(L, "_G"); - /* open lib into global table */ - luaL_register(L, "_G", base_funcs); - lua_pushliteral(L, LUA_VERSION); - lua_setglobal(L, "_VERSION"); /* set global _VERSION */ - /* `ipairs' and `pairs' need auxliliary functions as upvalues */ - auxopen(L, "ipairs", luaB_ipairs, ipairsaux); - auxopen(L, "pairs", luaB_pairs, luaB_next); - /* `newproxy' needs a weaktable as upvalue */ - lua_createtable(L, 0, 1); /* new table `w' */ - lua_pushvalue(L, -1); /* `w' will be its own metatable */ - lua_setmetatable(L, -2); - lua_pushliteral(L, "kv"); - lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ - lua_pushcclosure(L, luaB_newproxy, 1); - lua_setglobal(L, "newproxy"); /* set global `newproxy' */ - } - - - public static int luaopen_base (lua_State L) { - base_open(L); - luaL_register(L, LUA_COLIBNAME, co_funcs); - return 2; - } - - } -} +/* +** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 roberto Exp $ +** Basic library +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace KopiLua +{ + using lua_Number = System.Double; + + public partial class Lua + { + /* + ** If your system does not support `stdout', you can just remove this function. + ** If you need, you can define your own `print' function, following this + ** model but changing `fputs' to put the strings at a proper place + ** (a console window or a log file, for instance). + */ + private static int luaB_print (lua_State L) { + int n = lua_gettop(L); /* number of arguments */ + int i; + lua_getglobal(L, "tostring"); + for (i=1; i<=n; i++) { + CharPtr s; + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, i); /* value to print */ + lua_call(L, 1, 1); + s = lua_tostring(L, -1); /* get result */ + if (s == null) + return luaL_error(L, LUA_QL("tostring") + " must return a string to " + + LUA_QL("print")); + if (i > 1) fputs("\t", stdout); + fputs(s, stdout); + lua_pop(L, 1); /* pop result */ + } + Console.Write("\n", stdout); + return 0; + } + + + private static int luaB_tonumber (lua_State L) { + int base_ = luaL_optint(L, 2, 10); + if (base_ == 10) { /* standard conversion */ + luaL_checkany(L, 1); + if (lua_isnumber(L, 1) != 0) { + lua_pushnumber(L, lua_tonumber(L, 1)); + return 1; + } + } + else { + CharPtr s1 = luaL_checkstring(L, 1); + CharPtr s2; + ulong n; + luaL_argcheck(L, 2 <= base_ && base_ <= 36, 2, "base out of range"); + n = strtoul(s1, out s2, base_); + if (s1 != s2) { /* at least one valid digit? */ + while (isspace((byte)(s2[0]))) s2 = s2.next(); /* skip trailing spaces */ + if (s2[0] == '\0') { /* no invalid trailing characters? */ + lua_pushnumber(L, (lua_Number)n); + return 1; + } + } + } + lua_pushnil(L); /* else not a number */ + return 1; + } + + + private static int luaB_error (lua_State L) { + int level = luaL_optint(L, 2, 1); + lua_settop(L, 1); + if ((lua_isstring(L, 1)!=0) && (level > 0)) { /* add extra information? */ + luaL_where(L, level); + lua_pushvalue(L, 1); + lua_concat(L, 2); + } + return lua_error(L); + } + + + private static int luaB_getmetatable (lua_State L) { + luaL_checkany(L, 1); + if (lua_getmetatable(L, 1)==0) { + lua_pushnil(L); + return 1; /* no metatable */ + } + luaL_getmetafield(L, 1, "__metatable"); + return 1; /* returns either __metatable field (if present) or metatable */ + } + + + private static int luaB_setmetatable (lua_State L) { + int t = lua_type(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + if (luaL_getmetafield(L, 1, "__metatable") != 0) + luaL_error(L, "cannot change a protected metatable"); + lua_settop(L, 2); + lua_setmetatable(L, 1); + return 1; + } + + + private static void getfunc (lua_State L, int opt) { + if (lua_isfunction(L, 1)) lua_pushvalue(L, 1); + else { + lua_Debug ar = new lua_Debug(); + int level = (opt != 0) ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1); + luaL_argcheck(L, level >= 0, 1, "level must be non-negative"); + if (lua_getstack(L, level, ar) == 0) + luaL_argerror(L, 1, "invalid level"); + lua_getinfo(L, "f", ar); + if (lua_isnil(L, -1)) + luaL_error(L, "no function environment for tail call at level %d", + level); + } + } + + + private static int luaB_getfenv (lua_State L) { + getfunc(L, 1); + if (lua_iscfunction(L, -1)) /* is a C function? */ + lua_pushvalue(L, LUA_GLOBALSINDEX); /* return the thread's global env. */ + else + lua_getfenv(L, -1); + return 1; + } + + + private static int luaB_setfenv (lua_State L) { + luaL_checktype(L, 2, LUA_TTABLE); + getfunc(L, 0); + lua_pushvalue(L, 2); + if ((lua_isnumber(L, 1)!=0) && (lua_tonumber(L, 1) == 0)) { + /* change environment of current thread */ + lua_pushthread(L); + lua_insert(L, -2); + lua_setfenv(L, -2); + return 0; + } + else if (lua_iscfunction(L, -2) || lua_setfenv(L, -2) == 0) + luaL_error(L, + LUA_QL("setfenv") + " cannot change environment of given object"); + return 1; + } + + + private static int luaB_rawequal (lua_State L) { + luaL_checkany(L, 1); + luaL_checkany(L, 2); + lua_pushboolean(L, lua_rawequal(L, 1, 2)); + return 1; + } + + + private static int luaB_rawget (lua_State L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_rawget(L, 1); + return 1; + } + + private static int luaB_rawset (lua_State L) { + luaL_checktype(L, 1, LUA_TTABLE); + luaL_checkany(L, 2); + luaL_checkany(L, 3); + lua_settop(L, 3); + lua_rawset(L, 1); + return 1; + } + + + private static int luaB_gcinfo (lua_State L) { + lua_pushinteger(L, lua_getgccount(L)); + return 1; + } + + public static readonly CharPtr[] opts = {"stop", "restart", "collect", + "count", "step", "setpause", "setstepmul", null}; + public readonly static int[] optsnum = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, + LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL}; + + private static int luaB_collectgarbage (lua_State L) { + int o = luaL_checkoption(L, 1, "collect", opts); + int ex = luaL_optint(L, 2, 0); + int res = lua_gc(L, optsnum[o], ex); + switch (optsnum[o]) { + case LUA_GCCOUNT: { + int b = lua_gc(L, LUA_GCCOUNTB, 0); + lua_pushnumber(L, res + ((lua_Number)b/1024)); + return 1; + } + case LUA_GCSTEP: { + lua_pushboolean(L, res); + return 1; + } + default: { + lua_pushnumber(L, res); + return 1; + } + } + } + + + private static int luaB_type (lua_State L) { + luaL_checkany(L, 1); + lua_pushstring(L, luaL_typename(L, 1)); + return 1; + } + + + private static int luaB_next (lua_State L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 2); /* create a 2nd argument if there isn't one */ + if (lua_next(L, 1) != 0) + return 2; + else { + lua_pushnil(L); + return 1; + } + } + + + private static int luaB_pairs (lua_State L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushnil(L); /* and initial value */ + return 3; + } + + + private static int ipairsaux (lua_State L) { + int i = luaL_checkint(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + i++; /* next value */ + lua_pushinteger(L, i); + lua_rawgeti(L, 1, i); + return (lua_isnil(L, -1)) ? 0 : 2; + } + + + private static int luaB_ipairs (lua_State L) { + luaL_checktype(L, 1, LUA_TTABLE); + lua_pushvalue(L, lua_upvalueindex(1)); /* return generator, */ + lua_pushvalue(L, 1); /* state, */ + lua_pushinteger(L, 0); /* and initial value */ + return 3; + } + + + private static int load_aux (lua_State L, int status) { + if (status == 0) /* OK? */ + return 1; + else { + lua_pushnil(L); + lua_insert(L, -2); /* put before error message */ + return 2; /* return nil plus error message */ + } + } + + + private static int luaB_loadstring (lua_State L) { + uint l; + CharPtr s = luaL_checklstring(L, 1, out l); + CharPtr chunkname = luaL_optstring(L, 2, s); + return load_aux(L, luaL_loadbuffer(L, s, l, chunkname)); + } + + + private static int luaB_loadfile (lua_State L) { + CharPtr fname = luaL_optstring(L, 1, null); + return load_aux(L, luaL_loadfile(L, fname)); + } + + + /* + ** Reader for generic `load' function: `lua_load' uses the + ** stack for internal stuff, so the reader cannot change the + ** stack top. Instead, it keeps its resulting string in a + ** reserved slot inside the stack. + */ + private static CharPtr generic_reader (lua_State L, object ud, out uint size) { + //(void)ud; /* to avoid warnings */ + luaL_checkstack(L, 2, "too many nested functions"); + lua_pushvalue(L, 1); /* get function */ + lua_call(L, 0, 1); /* call it */ + if (lua_isnil(L, -1)) { + size = 0; + return null; + } + else if (lua_isstring(L, -1) != 0) + { + lua_replace(L, 3); /* save string in a reserved stack slot */ + return lua_tolstring(L, 3, out size); + } + else + { + size = 0; + luaL_error(L, "reader function must return a string"); + } + return null; /* to avoid warnings */ + } + + + private static int luaB_load (lua_State L) { + int status; + CharPtr cname = luaL_optstring(L, 2, "=(load)"); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_settop(L, 3); /* function, eventual name, plus one reserved slot */ + status = lua_load(L, generic_reader, null, cname); + return load_aux(L, status); + } + + + private static int luaB_dofile (lua_State L) { + CharPtr fname = luaL_optstring(L, 1, null); + int n = lua_gettop(L); + if (luaL_loadfile(L, fname) != 0) lua_error(L); + lua_call(L, 0, LUA_MULTRET); + return lua_gettop(L) - n; + } + + + private static int luaB_assert (lua_State L) { + luaL_checkany(L, 1); + if (lua_toboolean(L, 1)==0) + return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!")); + return lua_gettop(L); + } + + + private static int luaB_unpack (lua_State L) { + int i, e, n; + luaL_checktype(L, 1, LUA_TTABLE); + i = luaL_optint(L, 2, 1); + e = luaL_opt_integer(L, luaL_checkint, 3, luaL_getn(L, 1)); + if (i > e) return 0; /* empty range */ + n = e - i + 1; /* number of elements */ + if (n <= 0 || (lua_checkstack(L, n)==0)) /* n <= 0 means arith. overflow */ + return luaL_error(L, "too many results to unpack"); + lua_rawgeti(L, 1, i); /* push arg[i] (avoiding overflow problems) */ + while (i++ < e) /* push arg[i + 1...e] */ + lua_rawgeti(L, 1, i); + return n; + } + + + private static int luaB_select (lua_State L) { + int n = lua_gettop(L); + if (lua_type(L, 1) == LUA_TSTRING && lua_tostring(L, 1)[0] == '#') { + lua_pushinteger(L, n-1); + return 1; + } + else { + int i = luaL_checkint(L, 1); + if (i < 0) i = n + i; + else if (i > n) i = n; + luaL_argcheck(L, 1 <= i, 1, "index out of range"); + return n - i; + } + } + + + private static int luaB_pcall (lua_State L) { + int status; + luaL_checkany(L, 1); + status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); + lua_pushboolean(L, (status == 0) ? 1 : 0); + lua_insert(L, 1); + return lua_gettop(L); /* return status + all results */ + } + + + private static int luaB_xpcall (lua_State L) { + int status; + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_insert(L, 1); /* put error function under function to be called */ + status = lua_pcall(L, 0, LUA_MULTRET, 1); + lua_pushboolean(L, (status == 0) ? 1 : 0); + lua_replace(L, 1); + return lua_gettop(L); /* return status + all results */ + } + + + private static int luaB_tostring (lua_State L) { + luaL_checkany(L, 1); + if (luaL_callmeta(L, 1, "__tostring") != 0) /* is there a metafield? */ + return 1; /* use its value */ + switch (lua_type(L, 1)) { + case LUA_TNUMBER: + lua_pushstring(L, lua_tostring(L, 1)); + break; + case LUA_TSTRING: + lua_pushvalue(L, 1); + break; + case LUA_TBOOLEAN: + lua_pushstring(L, (lua_toboolean(L, 1) != 0 ? "true" : "false")); + break; + case LUA_TNIL: + lua_pushliteral(L, "nil"); + break; + default: + lua_pushfstring(L, "%s: %p", luaL_typename(L, 1), lua_topointer(L, 1)); + break; + } + return 1; + } + + + private static int luaB_newproxy (lua_State L) { + lua_settop(L, 1); + lua_newuserdata(L, 0); /* create proxy */ + if (lua_toboolean(L, 1) == 0) + return 1; /* no metatable */ + else if (lua_isboolean(L, 1)) { + lua_newtable(L); /* create a new metatable `m' ... */ + lua_pushvalue(L, -1); /* ... and mark `m' as a valid metatable */ + lua_pushboolean(L, 1); + lua_rawset(L, lua_upvalueindex(1)); /* weaktable[m] = true */ + } + else { + int validproxy = 0; /* to check if weaktable[metatable(u)] == true */ + if (lua_getmetatable(L, 1) != 0) { + lua_rawget(L, lua_upvalueindex(1)); + validproxy = lua_toboolean(L, -1); + lua_pop(L, 1); /* remove value */ + } + luaL_argcheck(L, validproxy!=0, 1, "boolean or proxy expected"); + lua_getmetatable(L, 1); /* metatable is valid; get it */ + } + lua_setmetatable(L, 2); + return 1; + } + + + private readonly static luaL_Reg[] base_funcs = { + new luaL_Reg("assert", luaB_assert), + new luaL_Reg("collectgarbage", luaB_collectgarbage), + new luaL_Reg("dofile", luaB_dofile), + new luaL_Reg("error", luaB_error), + new luaL_Reg("gcinfo", luaB_gcinfo), + new luaL_Reg("getfenv", luaB_getfenv), + new luaL_Reg("getmetatable", luaB_getmetatable), + new luaL_Reg("loadfile", luaB_loadfile), + new luaL_Reg("load", luaB_load), + new luaL_Reg("loadstring", luaB_loadstring), + new luaL_Reg("next", luaB_next), + new luaL_Reg("pcall", luaB_pcall), + new luaL_Reg("print", luaB_print), + new luaL_Reg("rawequal", luaB_rawequal), + new luaL_Reg("rawget", luaB_rawget), + new luaL_Reg("rawset", luaB_rawset), + new luaL_Reg("select", luaB_select), + new luaL_Reg("setfenv", luaB_setfenv), + new luaL_Reg("setmetatable", luaB_setmetatable), + new luaL_Reg("tonumber", luaB_tonumber), + new luaL_Reg("tostring", luaB_tostring), + new luaL_Reg("type", luaB_type), + new luaL_Reg("unpack", luaB_unpack), + new luaL_Reg("xpcall", luaB_xpcall), + new luaL_Reg(null, null) + }; + + + /* + ** {====================================================== + ** Coroutine library + ** ======================================================= + */ + + public const int CO_RUN = 0; /* running */ + public const int CO_SUS = 1; /* suspended */ + public const int CO_NOR = 2; /* 'normal' (it resumed another coroutine) */ + public const int CO_DEAD = 3; + + private static readonly string[] statnames = + {"running", "suspended", "normal", "dead"}; + + private static int costatus (lua_State L, lua_State co) { + if (L == co) return CO_RUN; + switch (lua_status(co)) { + case LUA_YIELD: + return CO_SUS; + case 0: { + lua_Debug ar = new lua_Debug(); + if (lua_getstack(co, 0, ar) > 0) /* does it have frames? */ + return CO_NOR; /* it is running */ + else if (lua_gettop(co) == 0) + return CO_DEAD; + else + return CO_SUS; /* initial state */ + } + default: /* some error occured */ + return CO_DEAD; + } + } + + + private static int luaB_costatus (lua_State L) { + lua_State co = lua_tothread(L, 1); + luaL_argcheck(L, co!=null, 1, "coroutine expected"); + lua_pushstring(L, statnames[costatus(L, co)]); + return 1; + } + + + private static int auxresume (lua_State L, lua_State co, int narg) { + int status = costatus(L, co); + if (lua_checkstack(co, narg)==0) + luaL_error(L, "too many arguments to resume"); + if (status != CO_SUS) { + lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]); + return -1; /* error flag */ + } + lua_xmove(L, co, narg); + lua_setlevel(L, co); + status = lua_resume(co, narg); + if (status == 0 || status == LUA_YIELD) { + int nres = lua_gettop(co); + if (lua_checkstack(L, nres + 1)==0) + luaL_error(L, "too many results to resume"); + lua_xmove(co, L, nres); /* move yielded values */ + return nres; + } + else { + lua_xmove(co, L, 1); /* move error message */ + return -1; /* error flag */ + } + } + + + private static int luaB_coresume (lua_State L) { + lua_State co = lua_tothread(L, 1); + int r; + luaL_argcheck(L, co!=null, 1, "coroutine expected"); + r = auxresume(L, co, lua_gettop(L) - 1); + if (r < 0) { + lua_pushboolean(L, 0); + lua_insert(L, -2); + return 2; /* return false + error message */ + } + else { + lua_pushboolean(L, 1); + lua_insert(L, -(r + 1)); + return r + 1; /* return true + `resume' returns */ + } + } + + + private static int luaB_auxwrap (lua_State L) { + lua_State co = lua_tothread(L, lua_upvalueindex(1)); + int r = auxresume(L, co, lua_gettop(L)); + if (r < 0) { + if (lua_isstring(L, -1) != 0) { /* error object is a string? */ + luaL_where(L, 1); /* add extra info */ + lua_insert(L, -2); + lua_concat(L, 2); + } + lua_error(L); /* propagate error */ + } + return r; + } + + + private static int luaB_cocreate (lua_State L) { + lua_State NL = lua_newthread(L); + luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, + "Lua function expected"); + lua_pushvalue(L, 1); /* move function to top */ + lua_xmove(L, NL, 1); /* move function from L to NL */ + return 1; + } + + + private static int luaB_cowrap (lua_State L) { + luaB_cocreate(L); + lua_pushcclosure(L, luaB_auxwrap, 1); + return 1; + } + + + private static int luaB_yield (lua_State L) { + return lua_yield(L, lua_gettop(L)); + } + + + private static int luaB_corunning (lua_State L) { + if (lua_pushthread(L) != 0) + lua_pushnil(L); /* main thread is not a coroutine */ + return 1; + } + + + private readonly static luaL_Reg[] co_funcs = { + new luaL_Reg("create", luaB_cocreate), + new luaL_Reg("resume", luaB_coresume), + new luaL_Reg("running", luaB_corunning), + new luaL_Reg("status", luaB_costatus), + new luaL_Reg("wrap", luaB_cowrap), + new luaL_Reg("yield", luaB_yield), + new luaL_Reg(null, null) + }; + + /* }====================================================== */ + + + private static void auxopen (lua_State L, CharPtr name, + lua_CFunction f, lua_CFunction u) { + lua_pushcfunction(L, u); + lua_pushcclosure(L, f, 1); + lua_setfield(L, -2, name); + } + + + private static void base_open (lua_State L) { + /* set global _G */ + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_setglobal(L, "_G"); + /* open lib into global table */ + luaL_register(L, "_G", base_funcs); + lua_pushliteral(L, LUA_VERSION); + lua_setglobal(L, "_VERSION"); /* set global _VERSION */ + /* `ipairs' and `pairs' need auxliliary functions as upvalues */ + auxopen(L, "ipairs", luaB_ipairs, ipairsaux); + auxopen(L, "pairs", luaB_pairs, luaB_next); + /* `newproxy' needs a weaktable as upvalue */ + lua_createtable(L, 0, 1); /* new table `w' */ + lua_pushvalue(L, -1); /* `w' will be its own metatable */ + lua_setmetatable(L, -2); + lua_pushliteral(L, "kv"); + lua_setfield(L, -2, "__mode"); /* metatable(w).__mode = "kv" */ + lua_pushcclosure(L, luaB_newproxy, 1); + lua_setglobal(L, "newproxy"); /* set global `newproxy' */ + } + + + public static int luaopen_base (lua_State L) { + base_open(L); + luaL_register(L, LUA_COLIBNAME, co_funcs); + return 2; + } + + } +} diff --git a/Core/KopiLua/lcode.cs b/Core/KopiLua/lcode.cs index a70991a834a5cdd333bc75abb1b16677b0d07c16..9c1ab0e56fe516b28684b20521f23b546658993f 100644 --- a/Core/KopiLua/lcode.cs +++ b/Core/KopiLua/lcode.cs @@ -1,917 +1,917 @@ -/* -** $Id: lcode.c,v 2.25.1.3 2007/12/28 15:32:23 roberto Exp $ -** Code generator for Lua -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -namespace KopiLua -{ - using TValue = Lua.lua_TValue; - using lua_Number = System.Double; - using Instruction = System.UInt32; - - public class InstructionPtr - { - [CLSCompliantAttribute(false)] - public Instruction[] codes; - public int pc; - - public InstructionPtr() { this.codes = null; ; this.pc = -1; } - [CLSCompliantAttribute(false)] - public InstructionPtr(Instruction[] codes, int pc) { - this.codes = codes; this.pc = pc; } - public static InstructionPtr Assign(InstructionPtr ptr) - { - if (ptr == null) return null; - return new InstructionPtr(ptr.codes, ptr.pc); - } - [CLSCompliantAttribute(false)] - public Instruction this[int index] - { - get { return this.codes[pc + index]; } - set { this.codes[pc + index] = value; } - } - public static InstructionPtr inc(ref InstructionPtr ptr) - { - InstructionPtr result = new InstructionPtr(ptr.codes, ptr.pc); - ptr.pc++; - return result; - } - public static InstructionPtr dec(ref InstructionPtr ptr) - { - InstructionPtr result = new InstructionPtr(ptr.codes, ptr.pc); - ptr.pc--; - return result; - } - public static bool operator <(InstructionPtr p1, InstructionPtr p2) - { - Debug.Assert(p1.codes == p2.codes); - return p1.pc < p2.pc; - } - public static bool operator >(InstructionPtr p1, InstructionPtr p2) - { - Debug.Assert(p1.codes == p2.codes); - return p1.pc > p2.pc; - } - public static bool operator <=(InstructionPtr p1, InstructionPtr p2) - { - Debug.Assert(p1.codes == p2.codes); - return p1.pc < p2.pc; - } - public static bool operator >=(InstructionPtr p1, InstructionPtr p2) - { - Debug.Assert(p1.codes == p2.codes); - return p1.pc > p2.pc; - } - }; - - public partial class Lua - { - /* - ** Marks the end of a patch list. It is an invalid value both as an absolute - ** address, and as a list link (would link an element to itself). - */ - public const int NO_JUMP = (-1); - - - /* - ** grep "ORDER OPR" if you change these enums - */ - public enum BinOpr { - OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, - OPR_CONCAT, - OPR_NE, OPR_EQ, - OPR_LT, OPR_LE, OPR_GT, OPR_GE, - OPR_AND, OPR_OR, - OPR_NOBINOPR - }; - - - public enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR }; - - - public static InstructionPtr getcode(FuncState fs, expdesc e) {return new InstructionPtr(fs.f.code, e.u.s.info);} - - public static int luaK_codeAsBx(FuncState fs, OpCode o, int A, int sBx) {return luaK_codeABx(fs,o,A,sBx+MAXARG_sBx);} - - public static void luaK_setmultret(FuncState fs, expdesc e) {luaK_setreturns(fs, e, LUA_MULTRET);} - - public static bool hasjumps(expdesc e) {return e.t != e.f;} - - - private static int isnumeral(expdesc e) { - return (e.k == expkind.VKNUM && e.t == NO_JUMP && e.f == NO_JUMP) ? 1 : 0; - } - - - public static void luaK_nil (FuncState fs, int from, int n) { - InstructionPtr previous; - if (fs.pc > fs.lasttarget) { /* no jumps to current position? */ - if (fs.pc == 0) { /* function start? */ - if (from >= fs.nactvar) - return; /* positions are already clean */ - } - else { - previous = new InstructionPtr(fs.f.code, fs.pc-1); - if (GET_OPCODE(previous) == OpCode.OP_LOADNIL) { - int pfrom = GETARG_A(previous); - int pto = GETARG_B(previous); - if (pfrom <= from && from <= pto+1) { /* can connect both? */ - if (from+n-1 > pto) - SETARG_B(previous, from+n-1); - return; - } - } - } - } - luaK_codeABC(fs, OpCode.OP_LOADNIL, from, from + n - 1, 0); /* else no optimization */ - } - - - public static int luaK_jump (FuncState fs) { - int jpc = fs.jpc; /* save list of jumps to here */ - int j; - fs.jpc = NO_JUMP; - j = luaK_codeAsBx(fs, OpCode.OP_JMP, 0, NO_JUMP); - luaK_concat(fs, ref j, jpc); /* keep them on hold */ - return j; - } - - - public static void luaK_ret (FuncState fs, int first, int nret) { - luaK_codeABC(fs, OpCode.OP_RETURN, first, nret + 1, 0); - } - - - private static int condjump (FuncState fs, OpCode op, int A, int B, int C) { - luaK_codeABC(fs, op, A, B, C); - return luaK_jump(fs); - } - - - private static void fixjump (FuncState fs, int pc, int dest) { - InstructionPtr jmp = new InstructionPtr(fs.f.code, pc); - int offset = dest-(pc+1); - lua_assert(dest != NO_JUMP); - if (Math.Abs(offset) > MAXARG_sBx) - luaX_syntaxerror(fs.ls, "control structure too long"); - SETARG_sBx(jmp, offset); - } - - - /* - ** returns current `pc' and marks it as a jump target (to avoid wrong - ** optimizations with consecutive instructions not in the same basic block). - */ - public static int luaK_getlabel (FuncState fs) { - fs.lasttarget = fs.pc; - return fs.pc; - } - - - private static int getjump (FuncState fs, int pc) { - int offset = GETARG_sBx(fs.f.code[pc]); - if (offset == NO_JUMP) /* point to itself represents end of list */ - return NO_JUMP; /* end of list */ - else - return (pc+1)+offset; /* turn offset into absolute position */ - } - - private static InstructionPtr getjumpcontrol (FuncState fs, int pc) { - InstructionPtr pi = new InstructionPtr(fs.f.code, pc); - if (pc >= 1 && (testTMode(GET_OPCODE(pi[-1]))!=0)) - return new InstructionPtr(pi.codes, pi.pc-1); - else - return new InstructionPtr(pi.codes, pi.pc); - } - - - /* - ** check whether list has any jump that do not produce a value - ** (or produce an inverted value) - */ - private static int need_value (FuncState fs, int list) { - for (; list != NO_JUMP; list = getjump(fs, list)) { - InstructionPtr i = getjumpcontrol(fs, list); - if (GET_OPCODE(i[0]) != OpCode.OP_TESTSET) return 1; - } - return 0; /* not found */ - } - - - private static int patchtestreg (FuncState fs, int node, int reg) { - InstructionPtr i = getjumpcontrol(fs, node); - if (GET_OPCODE(i[0]) != OpCode.OP_TESTSET) - return 0; /* cannot patch other instructions */ - if (reg != NO_REG && reg != GETARG_B(i[0])) - SETARG_A(i, reg); - else /* no register to put value or register already has the value */ - i[0] = (uint)CREATE_ABC(OpCode.OP_TEST, GETARG_B(i[0]), 0, GETARG_C(i[0])); - - return 1; - } - - - private static void removevalues (FuncState fs, int list) { - for (; list != NO_JUMP; list = getjump(fs, list)) - patchtestreg(fs, list, NO_REG); - } - - - private static void patchlistaux (FuncState fs, int list, int vtarget, int reg, - int dtarget) { - while (list != NO_JUMP) { - int next = getjump(fs, list); - if (patchtestreg(fs, list, reg) != 0) - fixjump(fs, list, vtarget); - else - fixjump(fs, list, dtarget); /* jump to default target */ - list = next; - } - } - - - private static void dischargejpc (FuncState fs) { - patchlistaux(fs, fs.jpc, fs.pc, NO_REG, fs.pc); - fs.jpc = NO_JUMP; - } - - - public static void luaK_patchlist (FuncState fs, int list, int target) { - if (target == fs.pc) - luaK_patchtohere(fs, list); - else { - lua_assert(target < fs.pc); - patchlistaux(fs, list, target, NO_REG, target); - } - } - - - public static void luaK_patchtohere (FuncState fs, int list) { - luaK_getlabel(fs); - luaK_concat(fs, ref fs.jpc, list); - } - - - public static void luaK_concat(FuncState fs, ref int l1, int l2) - { - if (l2 == NO_JUMP) return; - else if (l1 == NO_JUMP) - l1 = l2; - else { - int list = l1; - int next; - while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ - list = next; - fixjump(fs, list, l2); - } - } - - - public static void luaK_checkstack (FuncState fs, int n) { - int newstack = fs.freereg + n; - if (newstack > fs.f.maxstacksize) { - if (newstack >= MAXSTACK) - luaX_syntaxerror(fs.ls, "function or expression too complex"); - fs.f.maxstacksize = cast_byte(newstack); - } - } - - - public static void luaK_reserveregs (FuncState fs, int n) { - luaK_checkstack(fs, n); - fs.freereg += n; - } - - - private static void freereg (FuncState fs, int reg) { - if ((ISK(reg)==0) && reg >= fs.nactvar) { - fs.freereg--; - lua_assert(reg == fs.freereg); - } - } - - - private static void freeexp (FuncState fs, expdesc e) { - if (e.k == expkind.VNONRELOC) - freereg(fs, e.u.s.info); - } - - - private static int addk (FuncState fs, TValue k, TValue v) { - lua_State L = fs.L; - TValue idx = luaH_set(L, fs.h, k); - Proto f = fs.f; - int oldsize = f.sizek; - if (ttisnumber(idx)) { - lua_assert(luaO_rawequalObj(fs.f.k[cast_int(nvalue(idx))], v)); - return cast_int(nvalue(idx)); - } - else { /* constant not found; create a new entry */ - setnvalue(idx, cast_num(fs.nk)); - luaM_growvector(L, ref f.k, fs.nk, ref f.sizek, - MAXARG_Bx, "constant table overflow"); - while (oldsize < f.sizek) setnilvalue(f.k[oldsize++]); - setobj(L, f.k[fs.nk], v); - luaC_barrier(L, f, v); - return fs.nk++; - } - } - - - public static int luaK_stringK (FuncState fs, TString s) { - TValue o = new TValue(); - setsvalue(fs.L, o, s); - return addk(fs, o, o); - } - - - public static int luaK_numberK (FuncState fs, lua_Number r) { - TValue o = new TValue(); - setnvalue(o, r); - return addk(fs, o, o); - } - - - private static int boolK (FuncState fs, int b) { - TValue o = new TValue(); - setbvalue(o, b); - return addk(fs, o, o); - } - - - private static int nilK (FuncState fs) { - TValue k = new TValue(), v = new TValue(); - setnilvalue(v); - /* cannot use nil as key; instead use table itself to represent nil */ - sethvalue(fs.L, k, fs.h); - return addk(fs, k, v); - } - - - public static void luaK_setreturns (FuncState fs, expdesc e, int nresults) { - if (e.k == expkind.VCALL) { /* expression is an open function call? */ - SETARG_C(getcode(fs, e), nresults+1); - } - else if (e.k == expkind.VVARARG) { - SETARG_B(getcode(fs, e), nresults+1); - SETARG_A(getcode(fs, e), fs.freereg); - luaK_reserveregs(fs, 1); - } - } - - - public static void luaK_setoneret (FuncState fs, expdesc e) { - if (e.k == expkind.VCALL) { /* expression is an open function call? */ - e.k = expkind.VNONRELOC; - e.u.s.info = GETARG_A(getcode(fs, e)); - } - else if (e.k == expkind.VVARARG) { - SETARG_B(getcode(fs, e), 2); - e.k = expkind.VRELOCABLE; /* can relocate its simple result */ - } - } - - - public static void luaK_dischargevars (FuncState fs, expdesc e) { - switch (e.k) { - case expkind.VLOCAL: { - e.k = expkind.VNONRELOC; - break; - } - case expkind.VUPVAL: { - e.u.s.info = luaK_codeABC(fs, OpCode.OP_GETUPVAL, 0, e.u.s.info, 0); - e.k = expkind.VRELOCABLE; - break; - } - case expkind.VGLOBAL: { - e.u.s.info = luaK_codeABx(fs, OpCode.OP_GETGLOBAL, 0, e.u.s.info); - e.k = expkind.VRELOCABLE; - break; - } - case expkind.VINDEXED: { - freereg(fs, e.u.s.aux); - freereg(fs, e.u.s.info); - e.u.s.info = luaK_codeABC(fs, OpCode.OP_GETTABLE, 0, e.u.s.info, e.u.s.aux); - e.k = expkind.VRELOCABLE; - break; - } - case expkind.VVARARG: - case expkind.VCALL: { - luaK_setoneret(fs, e); - break; - } - default: break; /* there is one value available (somewhere) */ - } - } - - - private static int code_label (FuncState fs, int A, int b, int jump) { - luaK_getlabel(fs); /* those instructions may be jump targets */ - return luaK_codeABC(fs, OpCode.OP_LOADBOOL, A, b, jump); - } - - - private static void discharge2reg (FuncState fs, expdesc e, int reg) { - luaK_dischargevars(fs, e); - switch (e.k) { - case expkind.VNIL: { - luaK_nil(fs, reg, 1); - break; - } - case expkind.VFALSE: case expkind.VTRUE: { - luaK_codeABC(fs, OpCode.OP_LOADBOOL, reg, (e.k == expkind.VTRUE) ? 1 : 0, 0); - break; - } - case expkind.VK: { - luaK_codeABx(fs, OpCode.OP_LOADK, reg, e.u.s.info); - break; - } - case expkind.VKNUM: { - luaK_codeABx(fs, OpCode.OP_LOADK, reg, luaK_numberK(fs, e.u.nval)); - break; - } - case expkind.VRELOCABLE: { - InstructionPtr pc = getcode(fs, e); - SETARG_A(pc, reg); - break; - } - case expkind.VNONRELOC: { - if (reg != e.u.s.info) - luaK_codeABC(fs, OpCode.OP_MOVE, reg, e.u.s.info, 0); - break; - } - default: { - lua_assert(e.k == expkind.VVOID || e.k == expkind.VJMP); - return; /* nothing to do... */ - } - } - e.u.s.info = reg; - e.k = expkind.VNONRELOC; - } - - - private static void discharge2anyreg (FuncState fs, expdesc e) { - if (e.k != expkind.VNONRELOC) { - luaK_reserveregs(fs, 1); - discharge2reg(fs, e, fs.freereg-1); - } - } - - - private static void exp2reg (FuncState fs, expdesc e, int reg) { - discharge2reg(fs, e, reg); - if (e.k == expkind.VJMP) - luaK_concat(fs, ref e.t, e.u.s.info); /* put this jump in `t' list */ - if (hasjumps(e)) { - int final; /* position after whole expression */ - int p_f = NO_JUMP; /* position of an eventual LOAD false */ - int p_t = NO_JUMP; /* position of an eventual LOAD true */ - if (need_value(fs, e.t)!=0 || need_value(fs, e.f)!=0) { - int fj = (e.k == expkind.VJMP) ? NO_JUMP : luaK_jump(fs); - p_f = code_label(fs, reg, 0, 1); - p_t = code_label(fs, reg, 1, 0); - luaK_patchtohere(fs, fj); - } - final = luaK_getlabel(fs); - patchlistaux(fs, e.f, final, reg, p_f); - patchlistaux(fs, e.t, final, reg, p_t); - } - e.f = e.t = NO_JUMP; - e.u.s.info = reg; - e.k = expkind.VNONRELOC; - } - - - public static void luaK_exp2nextreg (FuncState fs, expdesc e) { - luaK_dischargevars(fs, e); - freeexp(fs, e); - luaK_reserveregs(fs, 1); - exp2reg(fs, e, fs.freereg - 1); - } - - - public static int luaK_exp2anyreg (FuncState fs, expdesc e) { - luaK_dischargevars(fs, e); - if (e.k == expkind.VNONRELOC) { - if (!hasjumps(e)) return e.u.s.info; /* exp is already in a register */ - if (e.u.s.info >= fs.nactvar) { /* reg. is not a local? */ - exp2reg(fs, e, e.u.s.info); /* put value on it */ - return e.u.s.info; - } - } - luaK_exp2nextreg(fs, e); /* default */ - return e.u.s.info; - } - - - public static void luaK_exp2val (FuncState fs, expdesc e) { - if (hasjumps(e)) - luaK_exp2anyreg(fs, e); - else - luaK_dischargevars(fs, e); - } - - - public static int luaK_exp2RK (FuncState fs, expdesc e) { - luaK_exp2val(fs, e); - switch (e.k) { - case expkind.VKNUM: - case expkind.VTRUE: - case expkind.VFALSE: - case expkind.VNIL: { - if (fs.nk <= MAXINDEXRK) { /* constant fit in RK operand? */ - e.u.s.info = (e.k == expkind.VNIL) ? nilK(fs) : - (e.k == expkind.VKNUM) ? luaK_numberK(fs, e.u.nval) : - boolK(fs, (e.k == expkind.VTRUE) ? 1 : 0); - e.k = expkind.VK; - return RKASK(e.u.s.info); - } - else break; - } - case expkind.VK: { - if (e.u.s.info <= MAXINDEXRK) /* constant fit in argC? */ - return RKASK(e.u.s.info); - else break; - } - default: break; - } - /* not a constant in the right range: put it in a register */ - return luaK_exp2anyreg(fs, e); - } - - - public static void luaK_storevar (FuncState fs, expdesc var, expdesc ex) { - switch (var.k) { - case expkind.VLOCAL: { - freeexp(fs, ex); - exp2reg(fs, ex, var.u.s.info); - return; - } - case expkind.VUPVAL: { - int e = luaK_exp2anyreg(fs, ex); - luaK_codeABC(fs, OpCode.OP_SETUPVAL, e, var.u.s.info, 0); - break; - } - case expkind.VGLOBAL: { - int e = luaK_exp2anyreg(fs, ex); - luaK_codeABx(fs, OpCode.OP_SETGLOBAL, e, var.u.s.info); - break; - } - case expkind.VINDEXED: { - int e = luaK_exp2RK(fs, ex); - luaK_codeABC(fs, OpCode.OP_SETTABLE, var.u.s.info, var.u.s.aux, e); - break; - } - default: { - lua_assert(0); /* invalid var kind to store */ - break; - } - } - freeexp(fs, ex); - } - - - public static void luaK_self (FuncState fs, expdesc e, expdesc key) { - int func; - luaK_exp2anyreg(fs, e); - freeexp(fs, e); - func = fs.freereg; - luaK_reserveregs(fs, 2); - luaK_codeABC(fs, OpCode.OP_SELF, func, e.u.s.info, luaK_exp2RK(fs, key)); - freeexp(fs, key); - e.u.s.info = func; - e.k = expkind.VNONRELOC; - } - - - private static void invertjump (FuncState fs, expdesc e) { - InstructionPtr pc = getjumpcontrol(fs, e.u.s.info); - lua_assert(testTMode(GET_OPCODE(pc[0])) != 0 && GET_OPCODE(pc[0]) != OpCode.OP_TESTSET && - GET_OPCODE(pc[0]) != OpCode.OP_TEST); - SETARG_A(pc, (GETARG_A(pc[0]) == 0) ? 1 : 0); - } - - - private static int jumponcond (FuncState fs, expdesc e, int cond) { - if (e.k == expkind.VRELOCABLE) { - InstructionPtr ie = getcode(fs, e); - if (GET_OPCODE(ie) == OpCode.OP_NOT) { - fs.pc--; /* remove previous OpCode.OP_NOT */ - return condjump(fs, OpCode.OP_TEST, GETARG_B(ie), 0, (cond==0) ? 1 : 0); - } - /* else go through */ - } - discharge2anyreg(fs, e); - freeexp(fs, e); - return condjump(fs, OpCode.OP_TESTSET, NO_REG, e.u.s.info, cond); - } - - - public static void luaK_goiftrue (FuncState fs, expdesc e) { - int pc; /* pc of last jump */ - luaK_dischargevars(fs, e); - switch (e.k) { - case expkind.VK: case expkind.VKNUM: case expkind.VTRUE: { - pc = NO_JUMP; /* always true; do nothing */ - break; - } - case expkind.VFALSE: { - pc = luaK_jump(fs); /* always jump */ - break; - } - case expkind.VJMP: { - invertjump(fs, e); - pc = e.u.s.info; - break; - } - default: { - pc = jumponcond(fs, e, 0); - break; - } - } - luaK_concat(fs, ref e.f, pc); /* insert last jump in `f' list */ - luaK_patchtohere(fs, e.t); - e.t = NO_JUMP; - } - - - private static void luaK_goiffalse (FuncState fs, expdesc e) { - int pc; /* pc of last jump */ - luaK_dischargevars(fs, e); - switch (e.k) { - case expkind.VNIL: case expkind.VFALSE: { - pc = NO_JUMP; /* always false; do nothing */ - break; - } - case expkind.VTRUE: { - pc = luaK_jump(fs); /* always jump */ - break; - } - case expkind.VJMP: { - pc = e.u.s.info; - break; - } - default: { - pc = jumponcond(fs, e, 1); - break; - } - } - luaK_concat(fs, ref e.t, pc); /* insert last jump in `t' list */ - luaK_patchtohere(fs, e.f); - e.f = NO_JUMP; - } - - - private static void codenot (FuncState fs, expdesc e) { - luaK_dischargevars(fs, e); - switch (e.k) { - case expkind.VNIL: case expkind.VFALSE: { - e.k = expkind.VTRUE; - break; - } - case expkind.VK: case expkind.VKNUM: case expkind.VTRUE: { - e.k = expkind.VFALSE; - break; - } - case expkind.VJMP: { - invertjump(fs, e); - break; - } - case expkind.VRELOCABLE: - case expkind.VNONRELOC: { - discharge2anyreg(fs, e); - freeexp(fs, e); - e.u.s.info = luaK_codeABC(fs, OpCode.OP_NOT, 0, e.u.s.info, 0); - e.k = expkind.VRELOCABLE; - break; - } - default: { - lua_assert(0); /* cannot happen */ - break; - } - } - /* interchange true and false lists */ - { int temp = e.f; e.f = e.t; e.t = temp; } - removevalues(fs, e.f); - removevalues(fs, e.t); - } - - - public static void luaK_indexed (FuncState fs, expdesc t, expdesc k) { - t.u.s.aux = luaK_exp2RK(fs, k); - t.k = expkind.VINDEXED; - } - - - private static int constfolding (OpCode op, expdesc e1, expdesc e2) { - lua_Number v1, v2, r; - if ((isnumeral(e1)==0) || (isnumeral(e2)==0)) return 0; - v1 = e1.u.nval; - v2 = e2.u.nval; - switch (op) { - case OpCode.OP_ADD: r = luai_numadd(v1, v2); break; - case OpCode.OP_SUB: r = luai_numsub(v1, v2); break; - case OpCode.OP_MUL: r = luai_nummul(v1, v2); break; - case OpCode.OP_DIV: - if (v2 == 0) return 0; /* do not attempt to divide by 0 */ - r = luai_numdiv(v1, v2); break; - case OpCode.OP_MOD: - if (v2 == 0) return 0; /* do not attempt to divide by 0 */ - r = luai_nummod(v1, v2); break; - case OpCode.OP_POW: r = luai_numpow(v1, v2); break; - case OpCode.OP_UNM: r = luai_numunm(v1); break; - case OpCode.OP_LEN: return 0; /* no constant folding for 'len' */ - default: lua_assert(0); r = 0; break; - } - if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */ - e1.u.nval = r; - return 1; - } - - - private static void codearith (FuncState fs, OpCode op, expdesc e1, expdesc e2) { - if (constfolding(op, e1, e2) != 0) - return; - else { - int o2 = (op != OpCode.OP_UNM && op != OpCode.OP_LEN) ? luaK_exp2RK(fs, e2) : 0; - int o1 = luaK_exp2RK(fs, e1); - if (o1 > o2) { - freeexp(fs, e1); - freeexp(fs, e2); - } - else { - freeexp(fs, e2); - freeexp(fs, e1); - } - e1.u.s.info = luaK_codeABC(fs, op, 0, o1, o2); - e1.k = expkind.VRELOCABLE; - } - } - - - private static void codecomp (FuncState fs, OpCode op, int cond, expdesc e1, - expdesc e2) { - int o1 = luaK_exp2RK(fs, e1); - int o2 = luaK_exp2RK(fs, e2); - freeexp(fs, e2); - freeexp(fs, e1); - if (cond == 0 && op != OpCode.OP_EQ) { - int temp; /* exchange args to replace by `<' or `<=' */ - temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ - cond = 1; - } - e1.u.s.info = condjump(fs, op, cond, o1, o2); - e1.k = expkind.VJMP; - } - - - public static void luaK_prefix (FuncState fs, UnOpr op, expdesc e) { - expdesc e2 = new expdesc(); - e2.t = e2.f = NO_JUMP; e2.k = expkind.VKNUM; e2.u.nval = 0; - switch (op) { - case UnOpr.OPR_MINUS: { - if (isnumeral(e)==0) - luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ - codearith(fs, OpCode.OP_UNM, e, e2); - break; - } - case UnOpr.OPR_NOT: codenot(fs, e); break; - case UnOpr.OPR_LEN: { - luaK_exp2anyreg(fs, e); /* cannot operate on constants */ - codearith(fs, OpCode.OP_LEN, e, e2); - break; - } - default: lua_assert(0); break; - } - } - - - public static void luaK_infix (FuncState fs, BinOpr op, expdesc v) { - switch (op) { - case BinOpr.OPR_AND: { - luaK_goiftrue(fs, v); - break; - } - case BinOpr.OPR_OR: { - luaK_goiffalse(fs, v); - break; - } - case BinOpr.OPR_CONCAT: { - luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ - break; - } - case BinOpr.OPR_ADD: case BinOpr.OPR_SUB: case BinOpr.OPR_MUL: case BinOpr.OPR_DIV: - case BinOpr.OPR_MOD: case BinOpr.OPR_POW: { - if ((isnumeral(v)==0)) luaK_exp2RK(fs, v); - break; - } - default: { - luaK_exp2RK(fs, v); - break; - } - } - } - - - public static void luaK_posfix (FuncState fs, BinOpr op, expdesc e1, expdesc e2) { - switch (op) { - case BinOpr.OPR_AND: { - lua_assert(e1.t == NO_JUMP); /* list must be closed */ - luaK_dischargevars(fs, e2); - luaK_concat(fs, ref e2.f, e1.f); - e1.Copy(e2); - break; - } - case BinOpr.OPR_OR: { - lua_assert(e1.f == NO_JUMP); /* list must be closed */ - luaK_dischargevars(fs, e2); - luaK_concat(fs, ref e2.t, e1.t); - e1.Copy(e2); - break; - } - case BinOpr.OPR_CONCAT: { - luaK_exp2val(fs, e2); - if (e2.k == expkind.VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OpCode.OP_CONCAT) { - lua_assert(e1.u.s.info == GETARG_B(getcode(fs, e2))-1); - freeexp(fs, e1); - SETARG_B(getcode(fs, e2), e1.u.s.info); - e1.k = expkind.VRELOCABLE; e1.u.s.info = e2.u.s.info; - } - else { - luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ - codearith(fs, OpCode.OP_CONCAT, e1, e2); - } - break; - } - case BinOpr.OPR_ADD: codearith(fs, OpCode.OP_ADD, e1, e2); break; - case BinOpr.OPR_SUB: codearith(fs, OpCode.OP_SUB, e1, e2); break; - case BinOpr.OPR_MUL: codearith(fs, OpCode.OP_MUL, e1, e2); break; - case BinOpr.OPR_DIV: codearith(fs, OpCode.OP_DIV, e1, e2); break; - case BinOpr.OPR_MOD: codearith(fs, OpCode.OP_MOD, e1, e2); break; - case BinOpr.OPR_POW: codearith(fs, OpCode.OP_POW, e1, e2); break; - case BinOpr.OPR_EQ: codecomp(fs, OpCode.OP_EQ, 1, e1, e2); break; - case BinOpr.OPR_NE: codecomp(fs, OpCode.OP_EQ, 0, e1, e2); break; - case BinOpr.OPR_LT: codecomp(fs, OpCode.OP_LT, 1, e1, e2); break; - case BinOpr.OPR_LE: codecomp(fs, OpCode.OP_LE, 1, e1, e2); break; - case BinOpr.OPR_GT: codecomp(fs, OpCode.OP_LT, 0, e1, e2); break; - case BinOpr.OPR_GE: codecomp(fs, OpCode.OP_LE, 0, e1, e2); break; - default: lua_assert(0); break; - } - } - - - public static void luaK_fixline (FuncState fs, int line) { - fs.f.lineinfo[fs.pc - 1] = line; - } - - - private static int luaK_code (FuncState fs, int i, int line) { - Proto f = fs.f; - dischargejpc(fs); /* `pc' will change */ - /* put new instruction in code array */ - luaM_growvector(fs.L, ref f.code, fs.pc, ref f.sizecode, - MAX_INT, "code size overflow"); - f.code[fs.pc] = (uint)i; - /* save corresponding line information */ - luaM_growvector(fs.L, ref f.lineinfo, fs.pc, ref f.sizelineinfo, - MAX_INT, "code size overflow"); - f.lineinfo[fs.pc] = line; - return fs.pc++; - } - - - public static int luaK_codeABC (FuncState fs, OpCode o, int a, int b, int c) { - lua_assert(getOpMode(o) == OpMode.iABC); - lua_assert(getBMode(o) != OpArgMask.OpArgN || b == 0); - lua_assert(getCMode(o) != OpArgMask.OpArgN || c == 0); - return luaK_code(fs, CREATE_ABC(o, a, b, c), fs.ls.lastline); - } - - - public static int luaK_codeABx (FuncState fs, OpCode o, int a, int bc) { - lua_assert(getOpMode(o) == OpMode.iABx || getOpMode(o) == OpMode.iAsBx); - lua_assert(getCMode(o) == OpArgMask.OpArgN); - return luaK_code(fs, CREATE_ABx(o, a, bc), fs.ls.lastline); - } - - public static void luaK_setlist (FuncState fs, int base_, int nelems, int tostore) { - int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; - int b = (tostore == LUA_MULTRET) ? 0 : tostore; - lua_assert(tostore != 0); - if (c <= MAXARG_C) - luaK_codeABC(fs, OpCode.OP_SETLIST, base_, b, c); - else { - luaK_codeABC(fs, OpCode.OP_SETLIST, base_, b, 0); - luaK_code(fs, c, fs.ls.lastline); - } - fs.freereg = base_ + 1; /* free registers with list values */ - } - - } -} +/* +** $Id: lcode.c,v 2.25.1.3 2007/12/28 15:32:23 roberto Exp $ +** Code generator for Lua +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace KopiLua +{ + using TValue = Lua.lua_TValue; + using lua_Number = System.Double; + using Instruction = System.UInt32; + + public class InstructionPtr + { + [CLSCompliantAttribute(false)] + public Instruction[] codes; + public int pc; + + public InstructionPtr() { this.codes = null; ; this.pc = -1; } + [CLSCompliantAttribute(false)] + public InstructionPtr(Instruction[] codes, int pc) { + this.codes = codes; this.pc = pc; } + public static InstructionPtr Assign(InstructionPtr ptr) + { + if (ptr == null) return null; + return new InstructionPtr(ptr.codes, ptr.pc); + } + [CLSCompliantAttribute(false)] + public Instruction this[int index] + { + get { return this.codes[pc + index]; } + set { this.codes[pc + index] = value; } + } + public static InstructionPtr inc(ref InstructionPtr ptr) + { + InstructionPtr result = new InstructionPtr(ptr.codes, ptr.pc); + ptr.pc++; + return result; + } + public static InstructionPtr dec(ref InstructionPtr ptr) + { + InstructionPtr result = new InstructionPtr(ptr.codes, ptr.pc); + ptr.pc--; + return result; + } + public static bool operator <(InstructionPtr p1, InstructionPtr p2) + { + Debug.Assert(p1.codes == p2.codes); + return p1.pc < p2.pc; + } + public static bool operator >(InstructionPtr p1, InstructionPtr p2) + { + Debug.Assert(p1.codes == p2.codes); + return p1.pc > p2.pc; + } + public static bool operator <=(InstructionPtr p1, InstructionPtr p2) + { + Debug.Assert(p1.codes == p2.codes); + return p1.pc < p2.pc; + } + public static bool operator >=(InstructionPtr p1, InstructionPtr p2) + { + Debug.Assert(p1.codes == p2.codes); + return p1.pc > p2.pc; + } + }; + + public partial class Lua + { + /* + ** Marks the end of a patch list. It is an invalid value both as an absolute + ** address, and as a list link (would link an element to itself). + */ + public const int NO_JUMP = (-1); + + + /* + ** grep "ORDER OPR" if you change these enums + */ + public enum BinOpr { + OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, + OPR_CONCAT, + OPR_NE, OPR_EQ, + OPR_LT, OPR_LE, OPR_GT, OPR_GE, + OPR_AND, OPR_OR, + OPR_NOBINOPR + }; + + + public enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR }; + + + public static InstructionPtr getcode(FuncState fs, expdesc e) {return new InstructionPtr(fs.f.code, e.u.s.info);} + + public static int luaK_codeAsBx(FuncState fs, OpCode o, int A, int sBx) {return luaK_codeABx(fs,o,A,sBx+MAXARG_sBx);} + + public static void luaK_setmultret(FuncState fs, expdesc e) {luaK_setreturns(fs, e, LUA_MULTRET);} + + public static bool hasjumps(expdesc e) {return e.t != e.f;} + + + private static int isnumeral(expdesc e) { + return (e.k == expkind.VKNUM && e.t == NO_JUMP && e.f == NO_JUMP) ? 1 : 0; + } + + + public static void luaK_nil (FuncState fs, int from, int n) { + InstructionPtr previous; + if (fs.pc > fs.lasttarget) { /* no jumps to current position? */ + if (fs.pc == 0) { /* function start? */ + if (from >= fs.nactvar) + return; /* positions are already clean */ + } + else { + previous = new InstructionPtr(fs.f.code, fs.pc-1); + if (GET_OPCODE(previous) == OpCode.OP_LOADNIL) { + int pfrom = GETARG_A(previous); + int pto = GETARG_B(previous); + if (pfrom <= from && from <= pto+1) { /* can connect both? */ + if (from+n-1 > pto) + SETARG_B(previous, from+n-1); + return; + } + } + } + } + luaK_codeABC(fs, OpCode.OP_LOADNIL, from, from + n - 1, 0); /* else no optimization */ + } + + + public static int luaK_jump (FuncState fs) { + int jpc = fs.jpc; /* save list of jumps to here */ + int j; + fs.jpc = NO_JUMP; + j = luaK_codeAsBx(fs, OpCode.OP_JMP, 0, NO_JUMP); + luaK_concat(fs, ref j, jpc); /* keep them on hold */ + return j; + } + + + public static void luaK_ret (FuncState fs, int first, int nret) { + luaK_codeABC(fs, OpCode.OP_RETURN, first, nret + 1, 0); + } + + + private static int condjump (FuncState fs, OpCode op, int A, int B, int C) { + luaK_codeABC(fs, op, A, B, C); + return luaK_jump(fs); + } + + + private static void fixjump (FuncState fs, int pc, int dest) { + InstructionPtr jmp = new InstructionPtr(fs.f.code, pc); + int offset = dest-(pc+1); + lua_assert(dest != NO_JUMP); + if (Math.Abs(offset) > MAXARG_sBx) + luaX_syntaxerror(fs.ls, "control structure too long"); + SETARG_sBx(jmp, offset); + } + + + /* + ** returns current `pc' and marks it as a jump target (to avoid wrong + ** optimizations with consecutive instructions not in the same basic block). + */ + public static int luaK_getlabel (FuncState fs) { + fs.lasttarget = fs.pc; + return fs.pc; + } + + + private static int getjump (FuncState fs, int pc) { + int offset = GETARG_sBx(fs.f.code[pc]); + if (offset == NO_JUMP) /* point to itself represents end of list */ + return NO_JUMP; /* end of list */ + else + return (pc+1)+offset; /* turn offset into absolute position */ + } + + private static InstructionPtr getjumpcontrol (FuncState fs, int pc) { + InstructionPtr pi = new InstructionPtr(fs.f.code, pc); + if (pc >= 1 && (testTMode(GET_OPCODE(pi[-1]))!=0)) + return new InstructionPtr(pi.codes, pi.pc-1); + else + return new InstructionPtr(pi.codes, pi.pc); + } + + + /* + ** check whether list has any jump that do not produce a value + ** (or produce an inverted value) + */ + private static int need_value (FuncState fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) { + InstructionPtr i = getjumpcontrol(fs, list); + if (GET_OPCODE(i[0]) != OpCode.OP_TESTSET) return 1; + } + return 0; /* not found */ + } + + + private static int patchtestreg (FuncState fs, int node, int reg) { + InstructionPtr i = getjumpcontrol(fs, node); + if (GET_OPCODE(i[0]) != OpCode.OP_TESTSET) + return 0; /* cannot patch other instructions */ + if (reg != NO_REG && reg != GETARG_B(i[0])) + SETARG_A(i, reg); + else /* no register to put value or register already has the value */ + i[0] = (uint)CREATE_ABC(OpCode.OP_TEST, GETARG_B(i[0]), 0, GETARG_C(i[0])); + + return 1; + } + + + private static void removevalues (FuncState fs, int list) { + for (; list != NO_JUMP; list = getjump(fs, list)) + patchtestreg(fs, list, NO_REG); + } + + + private static void patchlistaux (FuncState fs, int list, int vtarget, int reg, + int dtarget) { + while (list != NO_JUMP) { + int next = getjump(fs, list); + if (patchtestreg(fs, list, reg) != 0) + fixjump(fs, list, vtarget); + else + fixjump(fs, list, dtarget); /* jump to default target */ + list = next; + } + } + + + private static void dischargejpc (FuncState fs) { + patchlistaux(fs, fs.jpc, fs.pc, NO_REG, fs.pc); + fs.jpc = NO_JUMP; + } + + + public static void luaK_patchlist (FuncState fs, int list, int target) { + if (target == fs.pc) + luaK_patchtohere(fs, list); + else { + lua_assert(target < fs.pc); + patchlistaux(fs, list, target, NO_REG, target); + } + } + + + public static void luaK_patchtohere (FuncState fs, int list) { + luaK_getlabel(fs); + luaK_concat(fs, ref fs.jpc, list); + } + + + public static void luaK_concat(FuncState fs, ref int l1, int l2) + { + if (l2 == NO_JUMP) return; + else if (l1 == NO_JUMP) + l1 = l2; + else { + int list = l1; + int next; + while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ + list = next; + fixjump(fs, list, l2); + } + } + + + public static void luaK_checkstack (FuncState fs, int n) { + int newstack = fs.freereg + n; + if (newstack > fs.f.maxstacksize) { + if (newstack >= MAXSTACK) + luaX_syntaxerror(fs.ls, "function or expression too complex"); + fs.f.maxstacksize = cast_byte(newstack); + } + } + + + public static void luaK_reserveregs (FuncState fs, int n) { + luaK_checkstack(fs, n); + fs.freereg += n; + } + + + private static void freereg (FuncState fs, int reg) { + if ((ISK(reg)==0) && reg >= fs.nactvar) { + fs.freereg--; + lua_assert(reg == fs.freereg); + } + } + + + private static void freeexp (FuncState fs, expdesc e) { + if (e.k == expkind.VNONRELOC) + freereg(fs, e.u.s.info); + } + + + private static int addk (FuncState fs, TValue k, TValue v) { + lua_State L = fs.L; + TValue idx = luaH_set(L, fs.h, k); + Proto f = fs.f; + int oldsize = f.sizek; + if (ttisnumber(idx)) { + lua_assert(luaO_rawequalObj(fs.f.k[cast_int(nvalue(idx))], v)); + return cast_int(nvalue(idx)); + } + else { /* constant not found; create a new entry */ + setnvalue(idx, cast_num(fs.nk)); + luaM_growvector(L, ref f.k, fs.nk, ref f.sizek, + MAXARG_Bx, "constant table overflow"); + while (oldsize < f.sizek) setnilvalue(f.k[oldsize++]); + setobj(L, f.k[fs.nk], v); + luaC_barrier(L, f, v); + return fs.nk++; + } + } + + + public static int luaK_stringK (FuncState fs, TString s) { + TValue o = new TValue(); + setsvalue(fs.L, o, s); + return addk(fs, o, o); + } + + + public static int luaK_numberK (FuncState fs, lua_Number r) { + TValue o = new TValue(); + setnvalue(o, r); + return addk(fs, o, o); + } + + + private static int boolK (FuncState fs, int b) { + TValue o = new TValue(); + setbvalue(o, b); + return addk(fs, o, o); + } + + + private static int nilK (FuncState fs) { + TValue k = new TValue(), v = new TValue(); + setnilvalue(v); + /* cannot use nil as key; instead use table itself to represent nil */ + sethvalue(fs.L, k, fs.h); + return addk(fs, k, v); + } + + + public static void luaK_setreturns (FuncState fs, expdesc e, int nresults) { + if (e.k == expkind.VCALL) { /* expression is an open function call? */ + SETARG_C(getcode(fs, e), nresults+1); + } + else if (e.k == expkind.VVARARG) { + SETARG_B(getcode(fs, e), nresults+1); + SETARG_A(getcode(fs, e), fs.freereg); + luaK_reserveregs(fs, 1); + } + } + + + public static void luaK_setoneret (FuncState fs, expdesc e) { + if (e.k == expkind.VCALL) { /* expression is an open function call? */ + e.k = expkind.VNONRELOC; + e.u.s.info = GETARG_A(getcode(fs, e)); + } + else if (e.k == expkind.VVARARG) { + SETARG_B(getcode(fs, e), 2); + e.k = expkind.VRELOCABLE; /* can relocate its simple result */ + } + } + + + public static void luaK_dischargevars (FuncState fs, expdesc e) { + switch (e.k) { + case expkind.VLOCAL: { + e.k = expkind.VNONRELOC; + break; + } + case expkind.VUPVAL: { + e.u.s.info = luaK_codeABC(fs, OpCode.OP_GETUPVAL, 0, e.u.s.info, 0); + e.k = expkind.VRELOCABLE; + break; + } + case expkind.VGLOBAL: { + e.u.s.info = luaK_codeABx(fs, OpCode.OP_GETGLOBAL, 0, e.u.s.info); + e.k = expkind.VRELOCABLE; + break; + } + case expkind.VINDEXED: { + freereg(fs, e.u.s.aux); + freereg(fs, e.u.s.info); + e.u.s.info = luaK_codeABC(fs, OpCode.OP_GETTABLE, 0, e.u.s.info, e.u.s.aux); + e.k = expkind.VRELOCABLE; + break; + } + case expkind.VVARARG: + case expkind.VCALL: { + luaK_setoneret(fs, e); + break; + } + default: break; /* there is one value available (somewhere) */ + } + } + + + private static int code_label (FuncState fs, int A, int b, int jump) { + luaK_getlabel(fs); /* those instructions may be jump targets */ + return luaK_codeABC(fs, OpCode.OP_LOADBOOL, A, b, jump); + } + + + private static void discharge2reg (FuncState fs, expdesc e, int reg) { + luaK_dischargevars(fs, e); + switch (e.k) { + case expkind.VNIL: { + luaK_nil(fs, reg, 1); + break; + } + case expkind.VFALSE: case expkind.VTRUE: { + luaK_codeABC(fs, OpCode.OP_LOADBOOL, reg, (e.k == expkind.VTRUE) ? 1 : 0, 0); + break; + } + case expkind.VK: { + luaK_codeABx(fs, OpCode.OP_LOADK, reg, e.u.s.info); + break; + } + case expkind.VKNUM: { + luaK_codeABx(fs, OpCode.OP_LOADK, reg, luaK_numberK(fs, e.u.nval)); + break; + } + case expkind.VRELOCABLE: { + InstructionPtr pc = getcode(fs, e); + SETARG_A(pc, reg); + break; + } + case expkind.VNONRELOC: { + if (reg != e.u.s.info) + luaK_codeABC(fs, OpCode.OP_MOVE, reg, e.u.s.info, 0); + break; + } + default: { + lua_assert(e.k == expkind.VVOID || e.k == expkind.VJMP); + return; /* nothing to do... */ + } + } + e.u.s.info = reg; + e.k = expkind.VNONRELOC; + } + + + private static void discharge2anyreg (FuncState fs, expdesc e) { + if (e.k != expkind.VNONRELOC) { + luaK_reserveregs(fs, 1); + discharge2reg(fs, e, fs.freereg-1); + } + } + + + private static void exp2reg (FuncState fs, expdesc e, int reg) { + discharge2reg(fs, e, reg); + if (e.k == expkind.VJMP) + luaK_concat(fs, ref e.t, e.u.s.info); /* put this jump in `t' list */ + if (hasjumps(e)) { + int final; /* position after whole expression */ + int p_f = NO_JUMP; /* position of an eventual LOAD false */ + int p_t = NO_JUMP; /* position of an eventual LOAD true */ + if (need_value(fs, e.t)!=0 || need_value(fs, e.f)!=0) { + int fj = (e.k == expkind.VJMP) ? NO_JUMP : luaK_jump(fs); + p_f = code_label(fs, reg, 0, 1); + p_t = code_label(fs, reg, 1, 0); + luaK_patchtohere(fs, fj); + } + final = luaK_getlabel(fs); + patchlistaux(fs, e.f, final, reg, p_f); + patchlistaux(fs, e.t, final, reg, p_t); + } + e.f = e.t = NO_JUMP; + e.u.s.info = reg; + e.k = expkind.VNONRELOC; + } + + + public static void luaK_exp2nextreg (FuncState fs, expdesc e) { + luaK_dischargevars(fs, e); + freeexp(fs, e); + luaK_reserveregs(fs, 1); + exp2reg(fs, e, fs.freereg - 1); + } + + + public static int luaK_exp2anyreg (FuncState fs, expdesc e) { + luaK_dischargevars(fs, e); + if (e.k == expkind.VNONRELOC) { + if (!hasjumps(e)) return e.u.s.info; /* exp is already in a register */ + if (e.u.s.info >= fs.nactvar) { /* reg. is not a local? */ + exp2reg(fs, e, e.u.s.info); /* put value on it */ + return e.u.s.info; + } + } + luaK_exp2nextreg(fs, e); /* default */ + return e.u.s.info; + } + + + public static void luaK_exp2val (FuncState fs, expdesc e) { + if (hasjumps(e)) + luaK_exp2anyreg(fs, e); + else + luaK_dischargevars(fs, e); + } + + + public static int luaK_exp2RK (FuncState fs, expdesc e) { + luaK_exp2val(fs, e); + switch (e.k) { + case expkind.VKNUM: + case expkind.VTRUE: + case expkind.VFALSE: + case expkind.VNIL: { + if (fs.nk <= MAXINDEXRK) { /* constant fit in RK operand? */ + e.u.s.info = (e.k == expkind.VNIL) ? nilK(fs) : + (e.k == expkind.VKNUM) ? luaK_numberK(fs, e.u.nval) : + boolK(fs, (e.k == expkind.VTRUE) ? 1 : 0); + e.k = expkind.VK; + return RKASK(e.u.s.info); + } + else break; + } + case expkind.VK: { + if (e.u.s.info <= MAXINDEXRK) /* constant fit in argC? */ + return RKASK(e.u.s.info); + else break; + } + default: break; + } + /* not a constant in the right range: put it in a register */ + return luaK_exp2anyreg(fs, e); + } + + + public static void luaK_storevar (FuncState fs, expdesc var, expdesc ex) { + switch (var.k) { + case expkind.VLOCAL: { + freeexp(fs, ex); + exp2reg(fs, ex, var.u.s.info); + return; + } + case expkind.VUPVAL: { + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABC(fs, OpCode.OP_SETUPVAL, e, var.u.s.info, 0); + break; + } + case expkind.VGLOBAL: { + int e = luaK_exp2anyreg(fs, ex); + luaK_codeABx(fs, OpCode.OP_SETGLOBAL, e, var.u.s.info); + break; + } + case expkind.VINDEXED: { + int e = luaK_exp2RK(fs, ex); + luaK_codeABC(fs, OpCode.OP_SETTABLE, var.u.s.info, var.u.s.aux, e); + break; + } + default: { + lua_assert(0); /* invalid var kind to store */ + break; + } + } + freeexp(fs, ex); + } + + + public static void luaK_self (FuncState fs, expdesc e, expdesc key) { + int func; + luaK_exp2anyreg(fs, e); + freeexp(fs, e); + func = fs.freereg; + luaK_reserveregs(fs, 2); + luaK_codeABC(fs, OpCode.OP_SELF, func, e.u.s.info, luaK_exp2RK(fs, key)); + freeexp(fs, key); + e.u.s.info = func; + e.k = expkind.VNONRELOC; + } + + + private static void invertjump (FuncState fs, expdesc e) { + InstructionPtr pc = getjumpcontrol(fs, e.u.s.info); + lua_assert(testTMode(GET_OPCODE(pc[0])) != 0 && GET_OPCODE(pc[0]) != OpCode.OP_TESTSET && + GET_OPCODE(pc[0]) != OpCode.OP_TEST); + SETARG_A(pc, (GETARG_A(pc[0]) == 0) ? 1 : 0); + } + + + private static int jumponcond (FuncState fs, expdesc e, int cond) { + if (e.k == expkind.VRELOCABLE) { + InstructionPtr ie = getcode(fs, e); + if (GET_OPCODE(ie) == OpCode.OP_NOT) { + fs.pc--; /* remove previous OpCode.OP_NOT */ + return condjump(fs, OpCode.OP_TEST, GETARG_B(ie), 0, (cond==0) ? 1 : 0); + } + /* else go through */ + } + discharge2anyreg(fs, e); + freeexp(fs, e); + return condjump(fs, OpCode.OP_TESTSET, NO_REG, e.u.s.info, cond); + } + + + public static void luaK_goiftrue (FuncState fs, expdesc e) { + int pc; /* pc of last jump */ + luaK_dischargevars(fs, e); + switch (e.k) { + case expkind.VK: case expkind.VKNUM: case expkind.VTRUE: { + pc = NO_JUMP; /* always true; do nothing */ + break; + } + case expkind.VFALSE: { + pc = luaK_jump(fs); /* always jump */ + break; + } + case expkind.VJMP: { + invertjump(fs, e); + pc = e.u.s.info; + break; + } + default: { + pc = jumponcond(fs, e, 0); + break; + } + } + luaK_concat(fs, ref e.f, pc); /* insert last jump in `f' list */ + luaK_patchtohere(fs, e.t); + e.t = NO_JUMP; + } + + + private static void luaK_goiffalse (FuncState fs, expdesc e) { + int pc; /* pc of last jump */ + luaK_dischargevars(fs, e); + switch (e.k) { + case expkind.VNIL: case expkind.VFALSE: { + pc = NO_JUMP; /* always false; do nothing */ + break; + } + case expkind.VTRUE: { + pc = luaK_jump(fs); /* always jump */ + break; + } + case expkind.VJMP: { + pc = e.u.s.info; + break; + } + default: { + pc = jumponcond(fs, e, 1); + break; + } + } + luaK_concat(fs, ref e.t, pc); /* insert last jump in `t' list */ + luaK_patchtohere(fs, e.f); + e.f = NO_JUMP; + } + + + private static void codenot (FuncState fs, expdesc e) { + luaK_dischargevars(fs, e); + switch (e.k) { + case expkind.VNIL: case expkind.VFALSE: { + e.k = expkind.VTRUE; + break; + } + case expkind.VK: case expkind.VKNUM: case expkind.VTRUE: { + e.k = expkind.VFALSE; + break; + } + case expkind.VJMP: { + invertjump(fs, e); + break; + } + case expkind.VRELOCABLE: + case expkind.VNONRELOC: { + discharge2anyreg(fs, e); + freeexp(fs, e); + e.u.s.info = luaK_codeABC(fs, OpCode.OP_NOT, 0, e.u.s.info, 0); + e.k = expkind.VRELOCABLE; + break; + } + default: { + lua_assert(0); /* cannot happen */ + break; + } + } + /* interchange true and false lists */ + { int temp = e.f; e.f = e.t; e.t = temp; } + removevalues(fs, e.f); + removevalues(fs, e.t); + } + + + public static void luaK_indexed (FuncState fs, expdesc t, expdesc k) { + t.u.s.aux = luaK_exp2RK(fs, k); + t.k = expkind.VINDEXED; + } + + + private static int constfolding (OpCode op, expdesc e1, expdesc e2) { + lua_Number v1, v2, r; + if ((isnumeral(e1)==0) || (isnumeral(e2)==0)) return 0; + v1 = e1.u.nval; + v2 = e2.u.nval; + switch (op) { + case OpCode.OP_ADD: r = luai_numadd(v1, v2); break; + case OpCode.OP_SUB: r = luai_numsub(v1, v2); break; + case OpCode.OP_MUL: r = luai_nummul(v1, v2); break; + case OpCode.OP_DIV: + if (v2 == 0) return 0; /* do not attempt to divide by 0 */ + r = luai_numdiv(v1, v2); break; + case OpCode.OP_MOD: + if (v2 == 0) return 0; /* do not attempt to divide by 0 */ + r = luai_nummod(v1, v2); break; + case OpCode.OP_POW: r = luai_numpow(v1, v2); break; + case OpCode.OP_UNM: r = luai_numunm(v1); break; + case OpCode.OP_LEN: return 0; /* no constant folding for 'len' */ + default: lua_assert(0); r = 0; break; + } + if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */ + e1.u.nval = r; + return 1; + } + + + private static void codearith (FuncState fs, OpCode op, expdesc e1, expdesc e2) { + if (constfolding(op, e1, e2) != 0) + return; + else { + int o2 = (op != OpCode.OP_UNM && op != OpCode.OP_LEN) ? luaK_exp2RK(fs, e2) : 0; + int o1 = luaK_exp2RK(fs, e1); + if (o1 > o2) { + freeexp(fs, e1); + freeexp(fs, e2); + } + else { + freeexp(fs, e2); + freeexp(fs, e1); + } + e1.u.s.info = luaK_codeABC(fs, op, 0, o1, o2); + e1.k = expkind.VRELOCABLE; + } + } + + + private static void codecomp (FuncState fs, OpCode op, int cond, expdesc e1, + expdesc e2) { + int o1 = luaK_exp2RK(fs, e1); + int o2 = luaK_exp2RK(fs, e2); + freeexp(fs, e2); + freeexp(fs, e1); + if (cond == 0 && op != OpCode.OP_EQ) { + int temp; /* exchange args to replace by `<' or `<=' */ + temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ + cond = 1; + } + e1.u.s.info = condjump(fs, op, cond, o1, o2); + e1.k = expkind.VJMP; + } + + + public static void luaK_prefix (FuncState fs, UnOpr op, expdesc e) { + expdesc e2 = new expdesc(); + e2.t = e2.f = NO_JUMP; e2.k = expkind.VKNUM; e2.u.nval = 0; + switch (op) { + case UnOpr.OPR_MINUS: { + if (isnumeral(e)==0) + luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ + codearith(fs, OpCode.OP_UNM, e, e2); + break; + } + case UnOpr.OPR_NOT: codenot(fs, e); break; + case UnOpr.OPR_LEN: { + luaK_exp2anyreg(fs, e); /* cannot operate on constants */ + codearith(fs, OpCode.OP_LEN, e, e2); + break; + } + default: lua_assert(0); break; + } + } + + + public static void luaK_infix (FuncState fs, BinOpr op, expdesc v) { + switch (op) { + case BinOpr.OPR_AND: { + luaK_goiftrue(fs, v); + break; + } + case BinOpr.OPR_OR: { + luaK_goiffalse(fs, v); + break; + } + case BinOpr.OPR_CONCAT: { + luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ + break; + } + case BinOpr.OPR_ADD: case BinOpr.OPR_SUB: case BinOpr.OPR_MUL: case BinOpr.OPR_DIV: + case BinOpr.OPR_MOD: case BinOpr.OPR_POW: { + if ((isnumeral(v)==0)) luaK_exp2RK(fs, v); + break; + } + default: { + luaK_exp2RK(fs, v); + break; + } + } + } + + + public static void luaK_posfix (FuncState fs, BinOpr op, expdesc e1, expdesc e2) { + switch (op) { + case BinOpr.OPR_AND: { + lua_assert(e1.t == NO_JUMP); /* list must be closed */ + luaK_dischargevars(fs, e2); + luaK_concat(fs, ref e2.f, e1.f); + e1.Copy(e2); + break; + } + case BinOpr.OPR_OR: { + lua_assert(e1.f == NO_JUMP); /* list must be closed */ + luaK_dischargevars(fs, e2); + luaK_concat(fs, ref e2.t, e1.t); + e1.Copy(e2); + break; + } + case BinOpr.OPR_CONCAT: { + luaK_exp2val(fs, e2); + if (e2.k == expkind.VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OpCode.OP_CONCAT) { + lua_assert(e1.u.s.info == GETARG_B(getcode(fs, e2))-1); + freeexp(fs, e1); + SETARG_B(getcode(fs, e2), e1.u.s.info); + e1.k = expkind.VRELOCABLE; e1.u.s.info = e2.u.s.info; + } + else { + luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ + codearith(fs, OpCode.OP_CONCAT, e1, e2); + } + break; + } + case BinOpr.OPR_ADD: codearith(fs, OpCode.OP_ADD, e1, e2); break; + case BinOpr.OPR_SUB: codearith(fs, OpCode.OP_SUB, e1, e2); break; + case BinOpr.OPR_MUL: codearith(fs, OpCode.OP_MUL, e1, e2); break; + case BinOpr.OPR_DIV: codearith(fs, OpCode.OP_DIV, e1, e2); break; + case BinOpr.OPR_MOD: codearith(fs, OpCode.OP_MOD, e1, e2); break; + case BinOpr.OPR_POW: codearith(fs, OpCode.OP_POW, e1, e2); break; + case BinOpr.OPR_EQ: codecomp(fs, OpCode.OP_EQ, 1, e1, e2); break; + case BinOpr.OPR_NE: codecomp(fs, OpCode.OP_EQ, 0, e1, e2); break; + case BinOpr.OPR_LT: codecomp(fs, OpCode.OP_LT, 1, e1, e2); break; + case BinOpr.OPR_LE: codecomp(fs, OpCode.OP_LE, 1, e1, e2); break; + case BinOpr.OPR_GT: codecomp(fs, OpCode.OP_LT, 0, e1, e2); break; + case BinOpr.OPR_GE: codecomp(fs, OpCode.OP_LE, 0, e1, e2); break; + default: lua_assert(0); break; + } + } + + + public static void luaK_fixline (FuncState fs, int line) { + fs.f.lineinfo[fs.pc - 1] = line; + } + + + private static int luaK_code (FuncState fs, int i, int line) { + Proto f = fs.f; + dischargejpc(fs); /* `pc' will change */ + /* put new instruction in code array */ + luaM_growvector(fs.L, ref f.code, fs.pc, ref f.sizecode, + MAX_INT, "code size overflow"); + f.code[fs.pc] = (uint)i; + /* save corresponding line information */ + luaM_growvector(fs.L, ref f.lineinfo, fs.pc, ref f.sizelineinfo, + MAX_INT, "code size overflow"); + f.lineinfo[fs.pc] = line; + return fs.pc++; + } + + + public static int luaK_codeABC (FuncState fs, OpCode o, int a, int b, int c) { + lua_assert(getOpMode(o) == OpMode.iABC); + lua_assert(getBMode(o) != OpArgMask.OpArgN || b == 0); + lua_assert(getCMode(o) != OpArgMask.OpArgN || c == 0); + return luaK_code(fs, CREATE_ABC(o, a, b, c), fs.ls.lastline); + } + + + public static int luaK_codeABx (FuncState fs, OpCode o, int a, int bc) { + lua_assert(getOpMode(o) == OpMode.iABx || getOpMode(o) == OpMode.iAsBx); + lua_assert(getCMode(o) == OpArgMask.OpArgN); + return luaK_code(fs, CREATE_ABx(o, a, bc), fs.ls.lastline); + } + + public static void luaK_setlist (FuncState fs, int base_, int nelems, int tostore) { + int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; + int b = (tostore == LUA_MULTRET) ? 0 : tostore; + lua_assert(tostore != 0); + if (c <= MAXARG_C) + luaK_codeABC(fs, OpCode.OP_SETLIST, base_, b, c); + else { + luaK_codeABC(fs, OpCode.OP_SETLIST, base_, b, 0); + luaK_code(fs, c, fs.ls.lastline); + } + fs.freereg = base_ + 1; /* free registers with list values */ + } + + } +} diff --git a/Core/KopiLua/ldblib.cs b/Core/KopiLua/ldblib.cs index bcfa491d2faad220e5950b4565b0772a89f1b0f4..2c2bf01998af111f2229cab592d056cae7712967 100644 --- a/Core/KopiLua/ldblib.cs +++ b/Core/KopiLua/ldblib.cs @@ -1,393 +1,393 @@ -/* -** $Id: ldblib.c,v 1.104.1.3 2008/01/21 13:11:21 roberto Exp $ -** Interface from Lua to its debug API -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace KopiLua -{ - public partial class Lua - { - private static int db_getregistry (lua_State L) { - lua_pushvalue(L, LUA_REGISTRYINDEX); - return 1; - } - - - private static int db_getmetatable (lua_State L) { - luaL_checkany(L, 1); - if (lua_getmetatable(L, 1) == 0) { - lua_pushnil(L); /* no metatable */ - } - return 1; - } - - - private static int db_setmetatable (lua_State L) { - int t = lua_type(L, 2); - luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, - "nil or table expected"); - lua_settop(L, 2); - lua_pushboolean(L, lua_setmetatable(L, 1)); - return 1; - } - - - private static int db_getfenv (lua_State L) { - lua_getfenv(L, 1); - return 1; - } - - - private static int db_setfenv (lua_State L) { - luaL_checktype(L, 2, LUA_TTABLE); - lua_settop(L, 2); - if (lua_setfenv(L, 1) == 0) - luaL_error(L, LUA_QL("setfenv") + - " cannot change environment of given object"); - return 1; - } - - - private static void settabss (lua_State L, CharPtr i, CharPtr v) { - lua_pushstring(L, v); - lua_setfield(L, -2, i); - } - - - private static void settabsi (lua_State L, CharPtr i, int v) { - lua_pushinteger(L, v); - lua_setfield(L, -2, i); - } - - - private static lua_State getthread (lua_State L, out int arg) { - if (lua_isthread(L, 1)) { - arg = 1; - return lua_tothread(L, 1); - } - else { - arg = 0; - return L; - } - } - - - private static void treatstackoption (lua_State L, lua_State L1, CharPtr fname) { - if (L == L1) { - lua_pushvalue(L, -2); - lua_remove(L, -3); - } - else - lua_xmove(L1, L, 1); - lua_setfield(L, -2, fname); - } - - - private static int db_getinfo (lua_State L) { - lua_Debug ar = new lua_Debug(); - int arg; - lua_State L1 = getthread(L, out arg); - CharPtr options = luaL_optstring(L, arg+2, "flnSu"); - if (lua_isnumber(L, arg+1) != 0) { - if (lua_getstack(L1, (int)lua_tointeger(L, arg+1), ar)==0) { - lua_pushnil(L); /* level out of range */ - return 1; - } - } - else if (lua_isfunction(L, arg+1)) { - lua_pushfstring(L, ">%s", options); - options = lua_tostring(L, -1); - lua_pushvalue(L, arg+1); - lua_xmove(L, L1, 1); - } - else - return luaL_argerror(L, arg+1, "function or level expected"); - if (lua_getinfo(L1, options, ar)==0) - return luaL_argerror(L, arg+2, "invalid option"); - lua_createtable(L, 0, 2); - if (strchr(options, 'S') != null) { - settabss(L, "source", ar.source); - settabss(L, "short_src", ar.short_src); - settabsi(L, "linedefined", ar.linedefined); - settabsi(L, "lastlinedefined", ar.lastlinedefined); - settabss(L, "what", ar.what); - } - if (strchr(options, 'l') != null) - settabsi(L, "currentline", ar.currentline); - if (strchr(options, 'u') != null) - settabsi(L, "nups", ar.nups); - if (strchr(options, 'n') != null) { - settabss(L, "name", ar.name); - settabss(L, "namewhat", ar.namewhat); - } - if (strchr(options, 'L') != null) - treatstackoption(L, L1, "activelines"); - if (strchr(options, 'f') != null) - treatstackoption(L, L1, "func"); - return 1; /* return table */ - } - - - private static int db_getlocal (lua_State L) { - int arg; - lua_State L1 = getthread(L, out arg); - lua_Debug ar = new lua_Debug(); - CharPtr name; - if (lua_getstack(L1, luaL_checkint(L, arg+1), ar)==0) /* out of range? */ - return luaL_argerror(L, arg+1, "level out of range"); - name = lua_getlocal(L1, ar, luaL_checkint(L, arg+2)); - if (name != null) { - lua_xmove(L1, L, 1); - lua_pushstring(L, name); - lua_pushvalue(L, -2); - return 2; - } - else { - lua_pushnil(L); - return 1; - } - } - - - private static int db_setlocal (lua_State L) { - int arg; - lua_State L1 = getthread(L, out arg); - lua_Debug ar = new lua_Debug(); - if (lua_getstack(L1, luaL_checkint(L, arg+1), ar)==0) /* out of range? */ - return luaL_argerror(L, arg+1, "level out of range"); - luaL_checkany(L, arg+3); - lua_settop(L, arg+3); - lua_xmove(L, L1, 1); - lua_pushstring(L, lua_setlocal(L1, ar, luaL_checkint(L, arg+2))); - return 1; - } - - - private static int auxupvalue (lua_State L, int get) { - CharPtr name; - int n = luaL_checkint(L, 2); - luaL_checktype(L, 1, LUA_TFUNCTION); - if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */ - name = (get!=0) ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); - if (name == null) return 0; - lua_pushstring(L, name); - lua_insert(L, -(get+1)); - return get + 1; - } - - - private static int db_getupvalue (lua_State L) { - return auxupvalue(L, 1); - } - - - private static int db_setupvalue (lua_State L) { - luaL_checkany(L, 3); - return auxupvalue(L, 0); - } - - - - private const string KEY_HOOK = "h"; - - - private static readonly string[] hooknames = - {"call", "return", "line", "count", "tail return"}; - - private static void hookf (lua_State L, lua_Debug ar) { - lua_pushlightuserdata(L, KEY_HOOK); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_pushlightuserdata(L, L); - lua_rawget(L, -2); - if (lua_isfunction(L, -1)) { - lua_pushstring(L, hooknames[(int)ar.event_]); - if (ar.currentline >= 0) - lua_pushinteger(L, ar.currentline); - else lua_pushnil(L); - lua_assert(lua_getinfo(L, "lS", ar)); - lua_call(L, 2, 0); - } - } - - - private static int makemask (CharPtr smask, int count) { - int mask = 0; - if (strchr(smask, 'c') != null) mask |= LUA_MASKCALL; - if (strchr(smask, 'r') != null) mask |= LUA_MASKRET; - if (strchr(smask, 'l') != null) mask |= LUA_MASKLINE; - if (count > 0) mask |= LUA_MASKCOUNT; - return mask; - } - - - private static CharPtr unmakemask (int mask, CharPtr smask) { - int i = 0; - if ((mask & LUA_MASKCALL) != 0) smask[i++] = 'c'; - if ((mask & LUA_MASKRET) != 0) smask[i++] = 'r'; - if ((mask & LUA_MASKLINE) != 0) smask[i++] = 'l'; - smask[i] = '\0'; - return smask; - } - - - private static void gethooktable (lua_State L) { - lua_pushlightuserdata(L, KEY_HOOK); - lua_rawget(L, LUA_REGISTRYINDEX); - if (!lua_istable(L, -1)) { - lua_pop(L, 1); - lua_createtable(L, 0, 1); - lua_pushlightuserdata(L, KEY_HOOK); - lua_pushvalue(L, -2); - lua_rawset(L, LUA_REGISTRYINDEX); - } - } - - - private static int db_sethook (lua_State L) { - int arg, mask, count; - lua_Hook func; - lua_State L1 = getthread(L, out arg); - if (lua_isnoneornil(L, arg+1)) { - lua_settop(L, arg+1); - func = null; mask = 0; count = 0; /* turn off hooks */ - } - else { - CharPtr smask = luaL_checkstring(L, arg+2); - luaL_checktype(L, arg+1, LUA_TFUNCTION); - count = luaL_optint(L, arg+3, 0); - func = hookf; mask = makemask(smask, count); - } - gethooktable(L); - lua_pushlightuserdata(L, L1); - lua_pushvalue(L, arg+1); - lua_rawset(L, -3); /* set new hook */ - lua_pop(L, 1); /* remove hook table */ - lua_sethook(L1, func, mask, count); /* set hooks */ - return 0; - } - - - private static int db_gethook (lua_State L) { - int arg; - lua_State L1 = getthread(L, out arg); - CharPtr buff = new char[5]; - int mask = lua_gethookmask(L1); - lua_Hook hook = lua_gethook(L1); - if (hook != null && hook != hookf) /* external hook? */ - lua_pushliteral(L, "external hook"); - else { - gethooktable(L); - lua_pushlightuserdata(L, L1); - lua_rawget(L, -2); /* get hook */ - lua_remove(L, -2); /* remove hook table */ - } - lua_pushstring(L, unmakemask(mask, buff)); - lua_pushinteger(L, lua_gethookcount(L1)); - return 3; - } - - - private static int db_debug (lua_State L) { - for (;;) { - CharPtr buffer = new char[250]; - fputs("lua_debug> ", stderr); - if (fgets(buffer, stdin) == null || - strcmp(buffer, "cont\n") == 0) - return 0; - if (luaL_loadbuffer(L, buffer, (uint)strlen(buffer), "=(debug command)")!=0 || - lua_pcall(L, 0, 0, 0)!=0) { - fputs(lua_tostring(L, -1), stderr); - fputs("\n", stderr); - } - lua_settop(L, 0); /* remove eventual returns */ - } - } - - - public const int LEVELS1 = 12; /* size of the first part of the stack */ - public const int LEVELS2 = 10; /* size of the second part of the stack */ - - private static int db_errorfb (lua_State L) { - int level; - bool firstpart = true; /* still before eventual `...' */ - int arg; - lua_State L1 = getthread(L, out arg); - lua_Debug ar = new lua_Debug(); - if (lua_isnumber(L, arg+2) != 0) { - level = (int)lua_tointeger(L, arg+2); - lua_pop(L, 1); - } - else - level = (L == L1) ? 1 : 0; /* level 0 may be this own function */ - if (lua_gettop(L) == arg) - lua_pushliteral(L, ""); - else if (lua_isstring(L, arg+1)==0) return 1; /* message is not a string */ - else lua_pushliteral(L, "\n"); - lua_pushliteral(L, "stack traceback:"); - while (lua_getstack(L1, level++, ar) != 0) { - if (level > LEVELS1 && firstpart) { - /* no more than `LEVELS2' more levels? */ - if (lua_getstack(L1, level+LEVELS2, ar)==0) - level--; /* keep going */ - else { - lua_pushliteral(L, "\n\t..."); /* too many levels */ - while (lua_getstack(L1, level+LEVELS2, ar) != 0) /* find last levels */ - level++; - } - firstpart = false; - continue; - } - lua_pushliteral(L, "\n\t"); - lua_getinfo(L1, "Snl", ar); - lua_pushfstring(L, "%s:", ar.short_src); - if (ar.currentline > 0) - lua_pushfstring(L, "%d:", ar.currentline); - if (ar.namewhat != '\0') /* is there a name? */ - lua_pushfstring(L, " in function " + LUA_QS, ar.name); - else { - if (ar.what == 'm') /* main? */ - lua_pushfstring(L, " in main chunk"); - else if (ar.what == 'C' || ar.what == 't') - lua_pushliteral(L, " ?"); /* C function or tail call */ - else - lua_pushfstring(L, " in function <%s:%d>", - ar.short_src, ar.linedefined); - } - lua_concat(L, lua_gettop(L) - arg); - } - lua_concat(L, lua_gettop(L) - arg); - return 1; - } - - - private readonly static luaL_Reg[] dblib = { - new luaL_Reg("debug", db_debug), - new luaL_Reg("getfenv", db_getfenv), - new luaL_Reg("gethook", db_gethook), - new luaL_Reg("getinfo", db_getinfo), - new luaL_Reg("getlocal", db_getlocal), - new luaL_Reg("getregistry", db_getregistry), - new luaL_Reg("getmetatable", db_getmetatable), - new luaL_Reg("getupvalue", db_getupvalue), - new luaL_Reg("setfenv", db_setfenv), - new luaL_Reg("sethook", db_sethook), - new luaL_Reg("setlocal", db_setlocal), - new luaL_Reg("setmetatable", db_setmetatable), - new luaL_Reg("setupvalue", db_setupvalue), - new luaL_Reg("traceback", db_errorfb), - new luaL_Reg(null, null) - }; - - - public static int luaopen_debug (lua_State L) { - luaL_register(L, LUA_DBLIBNAME, dblib); - return 1; - } - - } -} +/* +** $Id: ldblib.c,v 1.104.1.3 2008/01/21 13:11:21 roberto Exp $ +** Interface from Lua to its debug API +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace KopiLua +{ + public partial class Lua + { + private static int db_getregistry (lua_State L) { + lua_pushvalue(L, LUA_REGISTRYINDEX); + return 1; + } + + + private static int db_getmetatable (lua_State L) { + luaL_checkany(L, 1); + if (lua_getmetatable(L, 1) == 0) { + lua_pushnil(L); /* no metatable */ + } + return 1; + } + + + private static int db_setmetatable (lua_State L) { + int t = lua_type(L, 2); + luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, + "nil or table expected"); + lua_settop(L, 2); + lua_pushboolean(L, lua_setmetatable(L, 1)); + return 1; + } + + + private static int db_getfenv (lua_State L) { + lua_getfenv(L, 1); + return 1; + } + + + private static int db_setfenv (lua_State L) { + luaL_checktype(L, 2, LUA_TTABLE); + lua_settop(L, 2); + if (lua_setfenv(L, 1) == 0) + luaL_error(L, LUA_QL("setfenv") + + " cannot change environment of given object"); + return 1; + } + + + private static void settabss (lua_State L, CharPtr i, CharPtr v) { + lua_pushstring(L, v); + lua_setfield(L, -2, i); + } + + + private static void settabsi (lua_State L, CharPtr i, int v) { + lua_pushinteger(L, v); + lua_setfield(L, -2, i); + } + + + private static lua_State getthread (lua_State L, out int arg) { + if (lua_isthread(L, 1)) { + arg = 1; + return lua_tothread(L, 1); + } + else { + arg = 0; + return L; + } + } + + + private static void treatstackoption (lua_State L, lua_State L1, CharPtr fname) { + if (L == L1) { + lua_pushvalue(L, -2); + lua_remove(L, -3); + } + else + lua_xmove(L1, L, 1); + lua_setfield(L, -2, fname); + } + + + private static int db_getinfo (lua_State L) { + lua_Debug ar = new lua_Debug(); + int arg; + lua_State L1 = getthread(L, out arg); + CharPtr options = luaL_optstring(L, arg+2, "flnSu"); + if (lua_isnumber(L, arg+1) != 0) { + if (lua_getstack(L1, (int)lua_tointeger(L, arg+1), ar)==0) { + lua_pushnil(L); /* level out of range */ + return 1; + } + } + else if (lua_isfunction(L, arg+1)) { + lua_pushfstring(L, ">%s", options); + options = lua_tostring(L, -1); + lua_pushvalue(L, arg+1); + lua_xmove(L, L1, 1); + } + else + return luaL_argerror(L, arg+1, "function or level expected"); + if (lua_getinfo(L1, options, ar)==0) + return luaL_argerror(L, arg+2, "invalid option"); + lua_createtable(L, 0, 2); + if (strchr(options, 'S') != null) { + settabss(L, "source", ar.source); + settabss(L, "short_src", ar.short_src); + settabsi(L, "linedefined", ar.linedefined); + settabsi(L, "lastlinedefined", ar.lastlinedefined); + settabss(L, "what", ar.what); + } + if (strchr(options, 'l') != null) + settabsi(L, "currentline", ar.currentline); + if (strchr(options, 'u') != null) + settabsi(L, "nups", ar.nups); + if (strchr(options, 'n') != null) { + settabss(L, "name", ar.name); + settabss(L, "namewhat", ar.namewhat); + } + if (strchr(options, 'L') != null) + treatstackoption(L, L1, "activelines"); + if (strchr(options, 'f') != null) + treatstackoption(L, L1, "func"); + return 1; /* return table */ + } + + + private static int db_getlocal (lua_State L) { + int arg; + lua_State L1 = getthread(L, out arg); + lua_Debug ar = new lua_Debug(); + CharPtr name; + if (lua_getstack(L1, luaL_checkint(L, arg+1), ar)==0) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + name = lua_getlocal(L1, ar, luaL_checkint(L, arg+2)); + if (name != null) { + lua_xmove(L1, L, 1); + lua_pushstring(L, name); + lua_pushvalue(L, -2); + return 2; + } + else { + lua_pushnil(L); + return 1; + } + } + + + private static int db_setlocal (lua_State L) { + int arg; + lua_State L1 = getthread(L, out arg); + lua_Debug ar = new lua_Debug(); + if (lua_getstack(L1, luaL_checkint(L, arg+1), ar)==0) /* out of range? */ + return luaL_argerror(L, arg+1, "level out of range"); + luaL_checkany(L, arg+3); + lua_settop(L, arg+3); + lua_xmove(L, L1, 1); + lua_pushstring(L, lua_setlocal(L1, ar, luaL_checkint(L, arg+2))); + return 1; + } + + + private static int auxupvalue (lua_State L, int get) { + CharPtr name; + int n = luaL_checkint(L, 2); + luaL_checktype(L, 1, LUA_TFUNCTION); + if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */ + name = (get!=0) ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); + if (name == null) return 0; + lua_pushstring(L, name); + lua_insert(L, -(get+1)); + return get + 1; + } + + + private static int db_getupvalue (lua_State L) { + return auxupvalue(L, 1); + } + + + private static int db_setupvalue (lua_State L) { + luaL_checkany(L, 3); + return auxupvalue(L, 0); + } + + + + private const string KEY_HOOK = "h"; + + + private static readonly string[] hooknames = + {"call", "return", "line", "count", "tail return"}; + + private static void hookf (lua_State L, lua_Debug ar) { + lua_pushlightuserdata(L, KEY_HOOK); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_pushlightuserdata(L, L); + lua_rawget(L, -2); + if (lua_isfunction(L, -1)) { + lua_pushstring(L, hooknames[(int)ar.event_]); + if (ar.currentline >= 0) + lua_pushinteger(L, ar.currentline); + else lua_pushnil(L); + lua_assert(lua_getinfo(L, "lS", ar)); + lua_call(L, 2, 0); + } + } + + + private static int makemask (CharPtr smask, int count) { + int mask = 0; + if (strchr(smask, 'c') != null) mask |= LUA_MASKCALL; + if (strchr(smask, 'r') != null) mask |= LUA_MASKRET; + if (strchr(smask, 'l') != null) mask |= LUA_MASKLINE; + if (count > 0) mask |= LUA_MASKCOUNT; + return mask; + } + + + private static CharPtr unmakemask (int mask, CharPtr smask) { + int i = 0; + if ((mask & LUA_MASKCALL) != 0) smask[i++] = 'c'; + if ((mask & LUA_MASKRET) != 0) smask[i++] = 'r'; + if ((mask & LUA_MASKLINE) != 0) smask[i++] = 'l'; + smask[i] = '\0'; + return smask; + } + + + private static void gethooktable (lua_State L) { + lua_pushlightuserdata(L, KEY_HOOK); + lua_rawget(L, LUA_REGISTRYINDEX); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + lua_createtable(L, 0, 1); + lua_pushlightuserdata(L, KEY_HOOK); + lua_pushvalue(L, -2); + lua_rawset(L, LUA_REGISTRYINDEX); + } + } + + + private static int db_sethook (lua_State L) { + int arg, mask, count; + lua_Hook func; + lua_State L1 = getthread(L, out arg); + if (lua_isnoneornil(L, arg+1)) { + lua_settop(L, arg+1); + func = null; mask = 0; count = 0; /* turn off hooks */ + } + else { + CharPtr smask = luaL_checkstring(L, arg+2); + luaL_checktype(L, arg+1, LUA_TFUNCTION); + count = luaL_optint(L, arg+3, 0); + func = hookf; mask = makemask(smask, count); + } + gethooktable(L); + lua_pushlightuserdata(L, L1); + lua_pushvalue(L, arg+1); + lua_rawset(L, -3); /* set new hook */ + lua_pop(L, 1); /* remove hook table */ + lua_sethook(L1, func, mask, count); /* set hooks */ + return 0; + } + + + private static int db_gethook (lua_State L) { + int arg; + lua_State L1 = getthread(L, out arg); + CharPtr buff = new char[5]; + int mask = lua_gethookmask(L1); + lua_Hook hook = lua_gethook(L1); + if (hook != null && hook != hookf) /* external hook? */ + lua_pushliteral(L, "external hook"); + else { + gethooktable(L); + lua_pushlightuserdata(L, L1); + lua_rawget(L, -2); /* get hook */ + lua_remove(L, -2); /* remove hook table */ + } + lua_pushstring(L, unmakemask(mask, buff)); + lua_pushinteger(L, lua_gethookcount(L1)); + return 3; + } + + + private static int db_debug (lua_State L) { + for (;;) { + CharPtr buffer = new char[250]; + fputs("lua_debug> ", stderr); + if (fgets(buffer, stdin) == null || + strcmp(buffer, "cont\n") == 0) + return 0; + if (luaL_loadbuffer(L, buffer, (uint)strlen(buffer), "=(debug command)")!=0 || + lua_pcall(L, 0, 0, 0)!=0) { + fputs(lua_tostring(L, -1), stderr); + fputs("\n", stderr); + } + lua_settop(L, 0); /* remove eventual returns */ + } + } + + + public const int LEVELS1 = 12; /* size of the first part of the stack */ + public const int LEVELS2 = 10; /* size of the second part of the stack */ + + private static int db_errorfb (lua_State L) { + int level; + bool firstpart = true; /* still before eventual `...' */ + int arg; + lua_State L1 = getthread(L, out arg); + lua_Debug ar = new lua_Debug(); + if (lua_isnumber(L, arg+2) != 0) { + level = (int)lua_tointeger(L, arg+2); + lua_pop(L, 1); + } + else + level = (L == L1) ? 1 : 0; /* level 0 may be this own function */ + if (lua_gettop(L) == arg) + lua_pushliteral(L, ""); + else if (lua_isstring(L, arg+1)==0) return 1; /* message is not a string */ + else lua_pushliteral(L, "\n"); + lua_pushliteral(L, "stack traceback:"); + while (lua_getstack(L1, level++, ar) != 0) { + if (level > LEVELS1 && firstpart) { + /* no more than `LEVELS2' more levels? */ + if (lua_getstack(L1, level+LEVELS2, ar)==0) + level--; /* keep going */ + else { + lua_pushliteral(L, "\n\t..."); /* too many levels */ + while (lua_getstack(L1, level+LEVELS2, ar) != 0) /* find last levels */ + level++; + } + firstpart = false; + continue; + } + lua_pushliteral(L, "\n\t"); + lua_getinfo(L1, "Snl", ar); + lua_pushfstring(L, "%s:", ar.short_src); + if (ar.currentline > 0) + lua_pushfstring(L, "%d:", ar.currentline); + if (ar.namewhat != '\0') /* is there a name? */ + lua_pushfstring(L, " in function " + LUA_QS, ar.name); + else { + if (ar.what == 'm') /* main? */ + lua_pushfstring(L, " in main chunk"); + else if (ar.what == 'C' || ar.what == 't') + lua_pushliteral(L, " ?"); /* C function or tail call */ + else + lua_pushfstring(L, " in function <%s:%d>", + ar.short_src, ar.linedefined); + } + lua_concat(L, lua_gettop(L) - arg); + } + lua_concat(L, lua_gettop(L) - arg); + return 1; + } + + + private readonly static luaL_Reg[] dblib = { + new luaL_Reg("debug", db_debug), + new luaL_Reg("getfenv", db_getfenv), + new luaL_Reg("gethook", db_gethook), + new luaL_Reg("getinfo", db_getinfo), + new luaL_Reg("getlocal", db_getlocal), + new luaL_Reg("getregistry", db_getregistry), + new luaL_Reg("getmetatable", db_getmetatable), + new luaL_Reg("getupvalue", db_getupvalue), + new luaL_Reg("setfenv", db_setfenv), + new luaL_Reg("sethook", db_sethook), + new luaL_Reg("setlocal", db_setlocal), + new luaL_Reg("setmetatable", db_setmetatable), + new luaL_Reg("setupvalue", db_setupvalue), + new luaL_Reg("traceback", db_errorfb), + new luaL_Reg(null, null) + }; + + + public static int luaopen_debug (lua_State L) { + luaL_register(L, LUA_DBLIBNAME, dblib); + return 1; + } + + } +} diff --git a/Core/KopiLua/ldebug.cs b/Core/KopiLua/ldebug.cs index 81b625c30c72a39148d14d5c17e98369c7857210..d34dedc5007ac775b0211f4af6fef72315b997f0 100644 --- a/Core/KopiLua/ldebug.cs +++ b/Core/KopiLua/ldebug.cs @@ -1,638 +1,638 @@ -/* -** $Id: ldebug.c,v 2.29.1.6 2008/05/08 16:56:26 roberto Exp $ -** Debug Interface -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -namespace KopiLua -{ - using TValue = Lua.lua_TValue; - using StkId = Lua.lua_TValue; - using Instruction = System.UInt32; - - public partial class Lua - { - - public static int pcRel(InstructionPtr pc, Proto p) - { - Debug.Assert(pc.codes == p.code); - return pc.pc - 1; - } - public static int getline(Proto f, int pc) { return (f.lineinfo != null) ? f.lineinfo[pc] : 0; } - public static void resethookcount(lua_State L) { L.hookcount = L.basehookcount; } - - - private static int currentpc (lua_State L, CallInfo ci) { - if (!isLua(ci)) return -1; /* function is not a Lua function? */ - if (ci == L.ci) - ci.savedpc = InstructionPtr.Assign(L.savedpc); - return pcRel(ci.savedpc, ci_func(ci).l.p); - } - - - private static int currentline (lua_State L, CallInfo ci) { - int pc = currentpc(L, ci); - if (pc < 0) - return -1; /* only active lua functions have current-line information */ - else - return getline(ci_func(ci).l.p, pc); - } - - - /* - ** this function can be called asynchronous (e.g. during a signal) - */ - public static int lua_sethook (lua_State L, lua_Hook func, int mask, int count) { - if (func == null || mask == 0) { /* turn off hooks? */ - mask = 0; - func = null; - } - L.hook = func; - L.basehookcount = count; - resethookcount(L); - L.hookmask = cast_byte(mask); - return 1; - } - - - public static lua_Hook lua_gethook (lua_State L) { - return L.hook; - } - - - public static int lua_gethookmask (lua_State L) { - return L.hookmask; - } - - - public static int lua_gethookcount (lua_State L) { - return L.basehookcount; - } - - - public static int lua_getstack (lua_State L, int level, lua_Debug ar) { - int status; - CallInfo ci; - lua_lock(L); - for (ci = L.ci; level > 0 && ci > L.base_ci[0]; CallInfo.dec(ref ci)) { - level--; - if (f_isLua(ci)) /* Lua function? */ - level -= ci.tailcalls; /* skip lost tail calls */ - } - if (level == 0 && ci > L.base_ci[0]) { /* level found? */ - status = 1; - ar.i_ci = ci - L.base_ci[0]; - } - else if (level < 0) { /* level is of a lost tail call? */ - status = 1; - ar.i_ci = 0; - } - else status = 0; /* no such level */ - lua_unlock(L); - return status; - } - - - private static Proto getluaproto (CallInfo ci) { - return (isLua(ci) ? ci_func(ci).l.p : null); - } - - - private static CharPtr findlocal (lua_State L, CallInfo ci, int n) { - CharPtr name; - Proto fp = getluaproto(ci); - if ((fp!=null) && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != null) - return name; /* is a local variable in a Lua function */ - else { - StkId limit = (ci == L.ci) ? L.top : (ci+1).func; - if (limit - ci.base_ >= n && n > 0) /* is 'n' inside 'ci' stack? */ - return "(*temporary)"; - else - return null; - } - } - - - public static CharPtr lua_getlocal (lua_State L, lua_Debug ar, int n) { - CallInfo ci = L.base_ci[ar.i_ci]; - CharPtr name = findlocal(L, ci, n); - lua_lock(L); - if (name != null) - luaA_pushobject(L, ci.base_[n - 1]); - lua_unlock(L); - return name; - } - - - public static CharPtr lua_setlocal (lua_State L, lua_Debug ar, int n) { - CallInfo ci = L.base_ci[ar.i_ci]; - CharPtr name = findlocal(L, ci, n); - lua_lock(L); - if (name != null) - setobjs2s(L, ci.base_[n - 1], L.top-1); - StkId.dec(ref L.top); /* pop value */ - lua_unlock(L); - return name; - } - - - private static void funcinfo (lua_Debug ar, Closure cl) { - if (cl.c.isC != 0) { - ar.source = "=[C]"; - ar.linedefined = -1; - ar.lastlinedefined = -1; - ar.what = "C"; - } - else { - ar.source = getstr(cl.l.p.source); - ar.linedefined = cl.l.p.linedefined; - ar.lastlinedefined = cl.l.p.lastlinedefined; - ar.what = (ar.linedefined == 0) ? "main" : "Lua"; - } - luaO_chunkid(ar.short_src, ar.source, LUA_IDSIZE); - } - - - private static void info_tailcall (lua_Debug ar) { - ar.name = ar.namewhat = ""; - ar.what = "tail"; - ar.lastlinedefined = ar.linedefined = ar.currentline = -1; - ar.source = "=(tail call)"; - luaO_chunkid(ar.short_src, ar.source, LUA_IDSIZE); - ar.nups = 0; - } - - - private static void collectvalidlines (lua_State L, Closure f) { - if (f == null || (f.c.isC!=0)) { - setnilvalue(L.top); - } - else { - Table t = luaH_new(L, 0, 0); - int[] lineinfo = f.l.p.lineinfo; - int i; - for (i=0; i') { - StkId func = L.top - 1; - luai_apicheck(L, ttisfunction(func)); - what = what.next(); /* skip the '>' */ - f = clvalue(func); - StkId.dec(ref L.top); /* pop function */ - } - else if (ar.i_ci != 0) { /* no tail call? */ - ci = L.base_ci[ar.i_ci]; - lua_assert(ttisfunction(ci.func)); - f = clvalue(ci.func); - } - status = auxgetinfo(L, what, ar, f, ci); - if (strchr(what, 'f') != null) { - if (f == null) setnilvalue(L.top); - else setclvalue(L, L.top, f); - incr_top(L); - } - if (strchr(what, 'L') != null) - collectvalidlines(L, f); - lua_unlock(L); - return status; - } - - - /* - ** {====================================================== - ** Symbolic Execution and code checker - ** ======================================================= - */ - - private static int checkjump(Proto pt, int pc) { if (!(0 <= pc && pc < pt.sizecode)) return 0; return 1; } - - private static int checkreg(Proto pt, int reg) { if (!((reg) < (pt).maxstacksize)) return 0; return 1; } - - - - private static int precheck (Proto pt) { - if (!(pt.maxstacksize <= MAXSTACK)) return 0; - if (!(pt.numparams+(pt.is_vararg & VARARG_HASARG) <= pt.maxstacksize)) return 0; - if (!(((pt.is_vararg & VARARG_NEEDSARG)==0) || - ((pt.is_vararg & VARARG_HASARG)!=0))) return 0; - if (!(pt.sizeupvalues <= pt.nups)) return 0; - if (!(pt.sizelineinfo == pt.sizecode || pt.sizelineinfo == 0)) return 0; - if (!(pt.sizecode > 0 && GET_OPCODE(pt.code[pt.sizecode - 1]) == OpCode.OP_RETURN)) return 0; - return 1; - } - - - public static int checkopenop(Proto pt, int pc) { return luaG_checkopenop(pt.code[pc + 1]); } - - [CLSCompliantAttribute(false)] - public static int luaG_checkopenop (Instruction i) { - switch (GET_OPCODE(i)) { - case OpCode.OP_CALL: - case OpCode.OP_TAILCALL: - case OpCode.OP_RETURN: - case OpCode.OP_SETLIST: { - if (!(GETARG_B(i) == 0)) return 0; - return 1; - } - default: return 0; /* invalid instruction after an open call */ - } - } - - - private static int checkArgMode (Proto pt, int r, OpArgMask mode) { - switch (mode) { - case OpArgMask.OpArgN: if (r!=0) return 0; break; - case OpArgMask.OpArgU: break; - case OpArgMask.OpArgR: checkreg(pt, r); break; - case OpArgMask.OpArgK: - if (!( (ISK(r) != 0) ? INDEXK(r) < pt.sizek : r < pt.maxstacksize)) return 0; - break; - } - return 1; - } - - - private static Instruction symbexec (Proto pt, int lastpc, int reg) { - int pc; - int last; /* stores position of last instruction that changed `reg' */ - int dest; - last = pt.sizecode-1; /* points to final return (a `neutral' instruction) */ - if (precheck(pt)==0) return 0; - for (pc = 0; pc < lastpc; pc++) { - Instruction i = pt.code[pc]; - OpCode op = GET_OPCODE(i); - int a = GETARG_A(i); - int b = 0; - int c = 0; - if (!((int)op < NUM_OPCODES)) return 0; - checkreg(pt, a); - switch (getOpMode(op)) { - case OpMode.iABC: { - b = GETARG_B(i); - c = GETARG_C(i); - if (checkArgMode(pt, b, getBMode(op))==0) return 0; - if (checkArgMode(pt, c, getCMode(op))==0) return 0; - break; - } - case OpMode.iABx: { - b = GETARG_Bx(i); - if (getBMode(op) == OpArgMask.OpArgK) if (!(b < pt.sizek)) return 0; - break; - } - case OpMode.iAsBx: { - b = GETARG_sBx(i); - if (getBMode(op) == OpArgMask.OpArgR) { - dest = pc+1+b; - if (!((0 <= dest && dest < pt.sizecode))) return 0; - if (dest > 0) { - int j; - /* check that it does not jump to a setlist count; this - is tricky, because the count from a previous setlist may - have the same value of an invalid setlist; so, we must - go all the way back to the first of them (if any) */ - for (j = 0; j < dest; j++) { - Instruction d = pt.code[dest-1-j]; - if (!(GET_OPCODE(d) == OpCode.OP_SETLIST && GETARG_C(d) == 0)) break; - } - /* if 'j' is even, previous value is not a setlist (even if - it looks like one) */ - if ((j&1)!=0) return 0; - } - } - break; - } - } - if (testAMode(op) != 0) { - if (a == reg) last = pc; /* change register `a' */ - } - if (testTMode(op) != 0) { - if (!(pc+2 < pt.sizecode)) return 0; /* check skip */ - if (!(GET_OPCODE(pt.code[pc + 1]) == OpCode.OP_JMP)) return 0; - } - switch (op) { - case OpCode.OP_LOADBOOL: { - if (c == 1) { /* does it jump? */ - if (!(pc+2 < pt.sizecode)) return 0; /* check its jump */ - if (!(GET_OPCODE(pt.code[pc + 1]) != OpCode.OP_SETLIST || - GETARG_C(pt.code[pc + 1]) != 0)) return 0; - } - break; - } - case OpCode.OP_LOADNIL: { - if (a <= reg && reg <= b) - last = pc; /* set registers from `a' to `b' */ - break; - } - case OpCode.OP_GETUPVAL: - case OpCode.OP_SETUPVAL: { - if (!(b < pt.nups)) return 0; - break; - } - case OpCode.OP_GETGLOBAL: - case OpCode.OP_SETGLOBAL: { - if (!(ttisstring(pt.k[b]))) return 0; - break; - } - case OpCode.OP_SELF: { - checkreg(pt, a+1); - if (reg == a+1) last = pc; - break; - } - case OpCode.OP_CONCAT: { - if (!(b < c)) return 0; /* at least two operands */ - break; - } - case OpCode.OP_TFORLOOP: { - if (!(c >= 1)) return 0; /* at least one result (control variable) */ - checkreg(pt, a+2+c); /* space for results */ - if (reg >= a+2) last = pc; /* affect all regs above its base */ - break; - } - case OpCode.OP_FORLOOP: - case OpCode.OP_FORPREP: - checkreg(pt, a+3); - /* go through ...no, on second thoughts don't, because this is C# */ - dest = pc + 1 + b; - /* not full check and jump is forward and do not skip `lastpc'? */ - if (reg != NO_REG && pc < dest && dest <= lastpc) - pc += b; /* do the jump */ - break; - - case OpCode.OP_JMP: { - dest = pc+1+b; - /* not full check and jump is forward and do not skip `lastpc'? */ - if (reg != NO_REG && pc < dest && dest <= lastpc) - pc += b; /* do the jump */ - break; - } - case OpCode.OP_CALL: - case OpCode.OP_TAILCALL: { - if (b != 0) { - checkreg(pt, a+b-1); - } - c--; /* c = num. returns */ - if (c == LUA_MULTRET) { - if (checkopenop(pt, pc)==0) return 0; - } - else if (c != 0) - checkreg(pt, a+c-1); - if (reg >= a) last = pc; /* affect all registers above base */ - break; - } - case OpCode.OP_RETURN: { - b--; /* b = num. returns */ - if (b > 0) checkreg(pt, a+b-1); - break; - } - case OpCode.OP_SETLIST: { - if (b > 0) checkreg(pt, a + b); - if (c == 0) { - pc++; - if (!(pc < pt.sizecode - 1)) return 0; - } - break; - } - case OpCode.OP_CLOSURE: { - int nup, j; - if (!(b < pt.sizep)) return 0; - nup = pt.p[b].nups; - if (!(pc + nup < pt.sizecode)) return 0; - for (j = 1; j <= nup; j++) { - OpCode op1 = GET_OPCODE(pt.code[pc + j]); - if (!(op1 == OpCode.OP_GETUPVAL || op1 == OpCode.OP_MOVE)) return 0; - } - if (reg != NO_REG) /* tracing? */ - pc += nup; /* do not 'execute' these pseudo-instructions */ - break; - } - case OpCode.OP_VARARG: { - if (!( (pt.is_vararg & VARARG_ISVARARG)!=0 && - (pt.is_vararg & VARARG_NEEDSARG)==0 )) return 0; - b--; - if (b == LUA_MULTRET) if (checkopenop(pt, pc)==0) return 0; - checkreg(pt, a+b-1); - break; - } - default: - break; - } - } - return pt.code[last]; - } - - //#undef check - //#undef checkjump - //#undef checkreg - - /* }====================================================== */ - - - public static int luaG_checkcode (Proto pt) { - return (symbexec(pt, pt.sizecode, NO_REG) != 0) ? 1 : 0; - } - - - private static CharPtr kname (Proto p, int c) { - if (ISK(c)!=0 && ttisstring(p.k[INDEXK(c)])) - return svalue(p.k[INDEXK(c)]); - else - return "?"; - } - - - private static CharPtr getobjname (lua_State L, CallInfo ci, int stackpos, - ref CharPtr name) { - if (isLua(ci)) { /* a Lua function? */ - Proto p = ci_func(ci).l.p; - int pc = currentpc(L, ci); - Instruction i; - name = luaF_getlocalname(p, stackpos+1, pc); - if (name!=null) /* is a local? */ - return "local"; - i = symbexec(p, pc, stackpos); /* try symbolic execution */ - lua_assert(pc != -1); - switch (GET_OPCODE(i)) { - case OpCode.OP_GETGLOBAL: { - int g = GETARG_Bx(i); /* global index */ - lua_assert(ttisstring(p.k[g])); - name = svalue(p.k[g]); - return "global"; - } - case OpCode.OP_MOVE: { - int a = GETARG_A(i); - int b = GETARG_B(i); /* move from `b' to `a' */ - if (b < a) - return getobjname(L, ci, b, ref name); /* get name for `b' */ - break; - } - case OpCode.OP_GETTABLE: { - int k = GETARG_C(i); /* key index */ - name = kname(p, k); - return "field"; - } - case OpCode.OP_GETUPVAL: { - int u = GETARG_B(i); /* upvalue index */ - name = (p.upvalues!=null) ? getstr(p.upvalues[u]) : "?"; - return "upvalue"; - } - case OpCode.OP_SELF: { - int k = GETARG_C(i); /* key index */ - name = kname(p, k); - return "method"; - } - default: break; - } - } - return null; /* no useful name found */ - } - - - private static CharPtr getfuncname (lua_State L, CallInfo ci, ref CharPtr name) { - Instruction i; - if ((isLua(ci) && ci.tailcalls > 0) || !isLua(ci - 1)) - return null; /* calling function is not Lua (or is unknown) */ - CallInfo.dec(ref ci); /* calling function */ - i = ci_func(ci).l.p.code[currentpc(L, ci)]; - if (GET_OPCODE(i) == OpCode.OP_CALL || GET_OPCODE(i) == OpCode.OP_TAILCALL || - GET_OPCODE(i) == OpCode.OP_TFORLOOP) - return getobjname(L, ci, GETARG_A(i), ref name); - else - return null; /* no useful name can be found */ - } - - - /* only ANSI way to check whether a pointer points to an array */ - private static int isinstack (CallInfo ci, TValue o) { - StkId p; - for (p = ci.base_; p < ci.top; StkId.inc(ref p)) - if (o == p) return 1; - return 0; - } - - - public static void luaG_typeerror (lua_State L, TValue o, CharPtr op) { - CharPtr name = null; - CharPtr t = luaT_typenames[ttype(o)]; - CharPtr kind = (isinstack(L.ci, o)) != 0 ? - getobjname(L, L.ci, cast_int(o - L.base_), ref name) : - null; - if (kind != null) - luaG_runerror(L, "attempt to %s %s " + LUA_QS + " (a %s value)", - op, kind, name, t); - else - luaG_runerror(L, "attempt to %s a %s value", op, t); - } - - - public static void luaG_concaterror (lua_State L, StkId p1, StkId p2) { - if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; - lua_assert(!ttisstring(p1) && !ttisnumber(p1)); - luaG_typeerror(L, p1, "concatenate"); - } - - - public static void luaG_aritherror (lua_State L, TValue p1, TValue p2) { - TValue temp = new TValue(); - if (luaV_tonumber(p1, temp) == null) - p2 = p1; /* first operand is wrong */ - luaG_typeerror(L, p2, "perform arithmetic on"); - } - - - public static int luaG_ordererror (lua_State L, TValue p1, TValue p2) { - CharPtr t1 = luaT_typenames[ttype(p1)]; - CharPtr t2 = luaT_typenames[ttype(p2)]; - if (t1[2] == t2[2]) - luaG_runerror(L, "attempt to compare two %s values", t1); - else - luaG_runerror(L, "attempt to compare %s with %s", t1, t2); - return 0; - } - - - private static void addinfo (lua_State L, CharPtr msg) { - CallInfo ci = L.ci; - if (isLua(ci)) { /* is Lua code? */ - CharPtr buff = new CharPtr(new char[LUA_IDSIZE]); /* add file:line information */ - int line = currentline(L, ci); - luaO_chunkid(buff, getstr(getluaproto(ci).source), LUA_IDSIZE); - luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); - } - } - - - public static void luaG_errormsg (lua_State L) { - if (L.errfunc != 0) { /* is there an error handling function? */ - StkId errfunc = restorestack(L, L.errfunc); - if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); - setobjs2s(L, L.top, L.top - 1); /* move argument */ - setobjs2s(L, L.top - 1, errfunc); /* push function */ - incr_top(L); - luaD_call(L, L.top - 2, 1); /* call it */ - } - luaD_throw(L, LUA_ERRRUN); - } - - public static void luaG_runerror(lua_State L, CharPtr fmt, params object[] argp) - { - addinfo(L, luaO_pushvfstring(L, fmt, argp)); - luaG_errormsg(L); - } - - } -} +/* +** $Id: ldebug.c,v 2.29.1.6 2008/05/08 16:56:26 roberto Exp $ +** Debug Interface +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace KopiLua +{ + using TValue = Lua.lua_TValue; + using StkId = Lua.lua_TValue; + using Instruction = System.UInt32; + + public partial class Lua + { + + public static int pcRel(InstructionPtr pc, Proto p) + { + Debug.Assert(pc.codes == p.code); + return pc.pc - 1; + } + public static int getline(Proto f, int pc) { return (f.lineinfo != null) ? f.lineinfo[pc] : 0; } + public static void resethookcount(lua_State L) { L.hookcount = L.basehookcount; } + + + private static int currentpc (lua_State L, CallInfo ci) { + if (!isLua(ci)) return -1; /* function is not a Lua function? */ + if (ci == L.ci) + ci.savedpc = InstructionPtr.Assign(L.savedpc); + return pcRel(ci.savedpc, ci_func(ci).l.p); + } + + + private static int currentline (lua_State L, CallInfo ci) { + int pc = currentpc(L, ci); + if (pc < 0) + return -1; /* only active lua functions have current-line information */ + else + return getline(ci_func(ci).l.p, pc); + } + + + /* + ** this function can be called asynchronous (e.g. during a signal) + */ + public static int lua_sethook (lua_State L, lua_Hook func, int mask, int count) { + if (func == null || mask == 0) { /* turn off hooks? */ + mask = 0; + func = null; + } + L.hook = func; + L.basehookcount = count; + resethookcount(L); + L.hookmask = cast_byte(mask); + return 1; + } + + + public static lua_Hook lua_gethook (lua_State L) { + return L.hook; + } + + + public static int lua_gethookmask (lua_State L) { + return L.hookmask; + } + + + public static int lua_gethookcount (lua_State L) { + return L.basehookcount; + } + + + public static int lua_getstack (lua_State L, int level, lua_Debug ar) { + int status; + CallInfo ci; + lua_lock(L); + for (ci = L.ci; level > 0 && ci > L.base_ci[0]; CallInfo.dec(ref ci)) { + level--; + if (f_isLua(ci)) /* Lua function? */ + level -= ci.tailcalls; /* skip lost tail calls */ + } + if (level == 0 && ci > L.base_ci[0]) { /* level found? */ + status = 1; + ar.i_ci = ci - L.base_ci[0]; + } + else if (level < 0) { /* level is of a lost tail call? */ + status = 1; + ar.i_ci = 0; + } + else status = 0; /* no such level */ + lua_unlock(L); + return status; + } + + + private static Proto getluaproto (CallInfo ci) { + return (isLua(ci) ? ci_func(ci).l.p : null); + } + + + private static CharPtr findlocal (lua_State L, CallInfo ci, int n) { + CharPtr name; + Proto fp = getluaproto(ci); + if ((fp!=null) && (name = luaF_getlocalname(fp, n, currentpc(L, ci))) != null) + return name; /* is a local variable in a Lua function */ + else { + StkId limit = (ci == L.ci) ? L.top : (ci+1).func; + if (limit - ci.base_ >= n && n > 0) /* is 'n' inside 'ci' stack? */ + return "(*temporary)"; + else + return null; + } + } + + + public static CharPtr lua_getlocal (lua_State L, lua_Debug ar, int n) { + CallInfo ci = L.base_ci[ar.i_ci]; + CharPtr name = findlocal(L, ci, n); + lua_lock(L); + if (name != null) + luaA_pushobject(L, ci.base_[n - 1]); + lua_unlock(L); + return name; + } + + + public static CharPtr lua_setlocal (lua_State L, lua_Debug ar, int n) { + CallInfo ci = L.base_ci[ar.i_ci]; + CharPtr name = findlocal(L, ci, n); + lua_lock(L); + if (name != null) + setobjs2s(L, ci.base_[n - 1], L.top-1); + StkId.dec(ref L.top); /* pop value */ + lua_unlock(L); + return name; + } + + + private static void funcinfo (lua_Debug ar, Closure cl) { + if (cl.c.isC != 0) { + ar.source = "=[C]"; + ar.linedefined = -1; + ar.lastlinedefined = -1; + ar.what = "C"; + } + else { + ar.source = getstr(cl.l.p.source); + ar.linedefined = cl.l.p.linedefined; + ar.lastlinedefined = cl.l.p.lastlinedefined; + ar.what = (ar.linedefined == 0) ? "main" : "Lua"; + } + luaO_chunkid(ar.short_src, ar.source, LUA_IDSIZE); + } + + + private static void info_tailcall (lua_Debug ar) { + ar.name = ar.namewhat = ""; + ar.what = "tail"; + ar.lastlinedefined = ar.linedefined = ar.currentline = -1; + ar.source = "=(tail call)"; + luaO_chunkid(ar.short_src, ar.source, LUA_IDSIZE); + ar.nups = 0; + } + + + private static void collectvalidlines (lua_State L, Closure f) { + if (f == null || (f.c.isC!=0)) { + setnilvalue(L.top); + } + else { + Table t = luaH_new(L, 0, 0); + int[] lineinfo = f.l.p.lineinfo; + int i; + for (i=0; i') { + StkId func = L.top - 1; + luai_apicheck(L, ttisfunction(func)); + what = what.next(); /* skip the '>' */ + f = clvalue(func); + StkId.dec(ref L.top); /* pop function */ + } + else if (ar.i_ci != 0) { /* no tail call? */ + ci = L.base_ci[ar.i_ci]; + lua_assert(ttisfunction(ci.func)); + f = clvalue(ci.func); + } + status = auxgetinfo(L, what, ar, f, ci); + if (strchr(what, 'f') != null) { + if (f == null) setnilvalue(L.top); + else setclvalue(L, L.top, f); + incr_top(L); + } + if (strchr(what, 'L') != null) + collectvalidlines(L, f); + lua_unlock(L); + return status; + } + + + /* + ** {====================================================== + ** Symbolic Execution and code checker + ** ======================================================= + */ + + private static int checkjump(Proto pt, int pc) { if (!(0 <= pc && pc < pt.sizecode)) return 0; return 1; } + + private static int checkreg(Proto pt, int reg) { if (!((reg) < (pt).maxstacksize)) return 0; return 1; } + + + + private static int precheck (Proto pt) { + if (!(pt.maxstacksize <= MAXSTACK)) return 0; + if (!(pt.numparams+(pt.is_vararg & VARARG_HASARG) <= pt.maxstacksize)) return 0; + if (!(((pt.is_vararg & VARARG_NEEDSARG)==0) || + ((pt.is_vararg & VARARG_HASARG)!=0))) return 0; + if (!(pt.sizeupvalues <= pt.nups)) return 0; + if (!(pt.sizelineinfo == pt.sizecode || pt.sizelineinfo == 0)) return 0; + if (!(pt.sizecode > 0 && GET_OPCODE(pt.code[pt.sizecode - 1]) == OpCode.OP_RETURN)) return 0; + return 1; + } + + + public static int checkopenop(Proto pt, int pc) { return luaG_checkopenop(pt.code[pc + 1]); } + + [CLSCompliantAttribute(false)] + public static int luaG_checkopenop (Instruction i) { + switch (GET_OPCODE(i)) { + case OpCode.OP_CALL: + case OpCode.OP_TAILCALL: + case OpCode.OP_RETURN: + case OpCode.OP_SETLIST: { + if (!(GETARG_B(i) == 0)) return 0; + return 1; + } + default: return 0; /* invalid instruction after an open call */ + } + } + + + private static int checkArgMode (Proto pt, int r, OpArgMask mode) { + switch (mode) { + case OpArgMask.OpArgN: if (r!=0) return 0; break; + case OpArgMask.OpArgU: break; + case OpArgMask.OpArgR: checkreg(pt, r); break; + case OpArgMask.OpArgK: + if (!( (ISK(r) != 0) ? INDEXK(r) < pt.sizek : r < pt.maxstacksize)) return 0; + break; + } + return 1; + } + + + private static Instruction symbexec (Proto pt, int lastpc, int reg) { + int pc; + int last; /* stores position of last instruction that changed `reg' */ + int dest; + last = pt.sizecode-1; /* points to final return (a `neutral' instruction) */ + if (precheck(pt)==0) return 0; + for (pc = 0; pc < lastpc; pc++) { + Instruction i = pt.code[pc]; + OpCode op = GET_OPCODE(i); + int a = GETARG_A(i); + int b = 0; + int c = 0; + if (!((int)op < NUM_OPCODES)) return 0; + checkreg(pt, a); + switch (getOpMode(op)) { + case OpMode.iABC: { + b = GETARG_B(i); + c = GETARG_C(i); + if (checkArgMode(pt, b, getBMode(op))==0) return 0; + if (checkArgMode(pt, c, getCMode(op))==0) return 0; + break; + } + case OpMode.iABx: { + b = GETARG_Bx(i); + if (getBMode(op) == OpArgMask.OpArgK) if (!(b < pt.sizek)) return 0; + break; + } + case OpMode.iAsBx: { + b = GETARG_sBx(i); + if (getBMode(op) == OpArgMask.OpArgR) { + dest = pc+1+b; + if (!((0 <= dest && dest < pt.sizecode))) return 0; + if (dest > 0) { + int j; + /* check that it does not jump to a setlist count; this + is tricky, because the count from a previous setlist may + have the same value of an invalid setlist; so, we must + go all the way back to the first of them (if any) */ + for (j = 0; j < dest; j++) { + Instruction d = pt.code[dest-1-j]; + if (!(GET_OPCODE(d) == OpCode.OP_SETLIST && GETARG_C(d) == 0)) break; + } + /* if 'j' is even, previous value is not a setlist (even if + it looks like one) */ + if ((j&1)!=0) return 0; + } + } + break; + } + } + if (testAMode(op) != 0) { + if (a == reg) last = pc; /* change register `a' */ + } + if (testTMode(op) != 0) { + if (!(pc+2 < pt.sizecode)) return 0; /* check skip */ + if (!(GET_OPCODE(pt.code[pc + 1]) == OpCode.OP_JMP)) return 0; + } + switch (op) { + case OpCode.OP_LOADBOOL: { + if (c == 1) { /* does it jump? */ + if (!(pc+2 < pt.sizecode)) return 0; /* check its jump */ + if (!(GET_OPCODE(pt.code[pc + 1]) != OpCode.OP_SETLIST || + GETARG_C(pt.code[pc + 1]) != 0)) return 0; + } + break; + } + case OpCode.OP_LOADNIL: { + if (a <= reg && reg <= b) + last = pc; /* set registers from `a' to `b' */ + break; + } + case OpCode.OP_GETUPVAL: + case OpCode.OP_SETUPVAL: { + if (!(b < pt.nups)) return 0; + break; + } + case OpCode.OP_GETGLOBAL: + case OpCode.OP_SETGLOBAL: { + if (!(ttisstring(pt.k[b]))) return 0; + break; + } + case OpCode.OP_SELF: { + checkreg(pt, a+1); + if (reg == a+1) last = pc; + break; + } + case OpCode.OP_CONCAT: { + if (!(b < c)) return 0; /* at least two operands */ + break; + } + case OpCode.OP_TFORLOOP: { + if (!(c >= 1)) return 0; /* at least one result (control variable) */ + checkreg(pt, a+2+c); /* space for results */ + if (reg >= a+2) last = pc; /* affect all regs above its base */ + break; + } + case OpCode.OP_FORLOOP: + case OpCode.OP_FORPREP: + checkreg(pt, a+3); + /* go through ...no, on second thoughts don't, because this is C# */ + dest = pc + 1 + b; + /* not full check and jump is forward and do not skip `lastpc'? */ + if (reg != NO_REG && pc < dest && dest <= lastpc) + pc += b; /* do the jump */ + break; + + case OpCode.OP_JMP: { + dest = pc+1+b; + /* not full check and jump is forward and do not skip `lastpc'? */ + if (reg != NO_REG && pc < dest && dest <= lastpc) + pc += b; /* do the jump */ + break; + } + case OpCode.OP_CALL: + case OpCode.OP_TAILCALL: { + if (b != 0) { + checkreg(pt, a+b-1); + } + c--; /* c = num. returns */ + if (c == LUA_MULTRET) { + if (checkopenop(pt, pc)==0) return 0; + } + else if (c != 0) + checkreg(pt, a+c-1); + if (reg >= a) last = pc; /* affect all registers above base */ + break; + } + case OpCode.OP_RETURN: { + b--; /* b = num. returns */ + if (b > 0) checkreg(pt, a+b-1); + break; + } + case OpCode.OP_SETLIST: { + if (b > 0) checkreg(pt, a + b); + if (c == 0) { + pc++; + if (!(pc < pt.sizecode - 1)) return 0; + } + break; + } + case OpCode.OP_CLOSURE: { + int nup, j; + if (!(b < pt.sizep)) return 0; + nup = pt.p[b].nups; + if (!(pc + nup < pt.sizecode)) return 0; + for (j = 1; j <= nup; j++) { + OpCode op1 = GET_OPCODE(pt.code[pc + j]); + if (!(op1 == OpCode.OP_GETUPVAL || op1 == OpCode.OP_MOVE)) return 0; + } + if (reg != NO_REG) /* tracing? */ + pc += nup; /* do not 'execute' these pseudo-instructions */ + break; + } + case OpCode.OP_VARARG: { + if (!( (pt.is_vararg & VARARG_ISVARARG)!=0 && + (pt.is_vararg & VARARG_NEEDSARG)==0 )) return 0; + b--; + if (b == LUA_MULTRET) if (checkopenop(pt, pc)==0) return 0; + checkreg(pt, a+b-1); + break; + } + default: + break; + } + } + return pt.code[last]; + } + + //#undef check + //#undef checkjump + //#undef checkreg + + /* }====================================================== */ + + + public static int luaG_checkcode (Proto pt) { + return (symbexec(pt, pt.sizecode, NO_REG) != 0) ? 1 : 0; + } + + + private static CharPtr kname (Proto p, int c) { + if (ISK(c)!=0 && ttisstring(p.k[INDEXK(c)])) + return svalue(p.k[INDEXK(c)]); + else + return "?"; + } + + + private static CharPtr getobjname (lua_State L, CallInfo ci, int stackpos, + ref CharPtr name) { + if (isLua(ci)) { /* a Lua function? */ + Proto p = ci_func(ci).l.p; + int pc = currentpc(L, ci); + Instruction i; + name = luaF_getlocalname(p, stackpos+1, pc); + if (name!=null) /* is a local? */ + return "local"; + i = symbexec(p, pc, stackpos); /* try symbolic execution */ + lua_assert(pc != -1); + switch (GET_OPCODE(i)) { + case OpCode.OP_GETGLOBAL: { + int g = GETARG_Bx(i); /* global index */ + lua_assert(ttisstring(p.k[g])); + name = svalue(p.k[g]); + return "global"; + } + case OpCode.OP_MOVE: { + int a = GETARG_A(i); + int b = GETARG_B(i); /* move from `b' to `a' */ + if (b < a) + return getobjname(L, ci, b, ref name); /* get name for `b' */ + break; + } + case OpCode.OP_GETTABLE: { + int k = GETARG_C(i); /* key index */ + name = kname(p, k); + return "field"; + } + case OpCode.OP_GETUPVAL: { + int u = GETARG_B(i); /* upvalue index */ + name = (p.upvalues!=null) ? getstr(p.upvalues[u]) : "?"; + return "upvalue"; + } + case OpCode.OP_SELF: { + int k = GETARG_C(i); /* key index */ + name = kname(p, k); + return "method"; + } + default: break; + } + } + return null; /* no useful name found */ + } + + + private static CharPtr getfuncname (lua_State L, CallInfo ci, ref CharPtr name) { + Instruction i; + if ((isLua(ci) && ci.tailcalls > 0) || !isLua(ci - 1)) + return null; /* calling function is not Lua (or is unknown) */ + CallInfo.dec(ref ci); /* calling function */ + i = ci_func(ci).l.p.code[currentpc(L, ci)]; + if (GET_OPCODE(i) == OpCode.OP_CALL || GET_OPCODE(i) == OpCode.OP_TAILCALL || + GET_OPCODE(i) == OpCode.OP_TFORLOOP) + return getobjname(L, ci, GETARG_A(i), ref name); + else + return null; /* no useful name can be found */ + } + + + /* only ANSI way to check whether a pointer points to an array */ + private static int isinstack (CallInfo ci, TValue o) { + StkId p; + for (p = ci.base_; p < ci.top; StkId.inc(ref p)) + if (o == p) return 1; + return 0; + } + + + public static void luaG_typeerror (lua_State L, TValue o, CharPtr op) { + CharPtr name = null; + CharPtr t = luaT_typenames[ttype(o)]; + CharPtr kind = (isinstack(L.ci, o)) != 0 ? + getobjname(L, L.ci, cast_int(o - L.base_), ref name) : + null; + if (kind != null) + luaG_runerror(L, "attempt to %s %s " + LUA_QS + " (a %s value)", + op, kind, name, t); + else + luaG_runerror(L, "attempt to %s a %s value", op, t); + } + + + public static void luaG_concaterror (lua_State L, StkId p1, StkId p2) { + if (ttisstring(p1) || ttisnumber(p1)) p1 = p2; + lua_assert(!ttisstring(p1) && !ttisnumber(p1)); + luaG_typeerror(L, p1, "concatenate"); + } + + + public static void luaG_aritherror (lua_State L, TValue p1, TValue p2) { + TValue temp = new TValue(); + if (luaV_tonumber(p1, temp) == null) + p2 = p1; /* first operand is wrong */ + luaG_typeerror(L, p2, "perform arithmetic on"); + } + + + public static int luaG_ordererror (lua_State L, TValue p1, TValue p2) { + CharPtr t1 = luaT_typenames[ttype(p1)]; + CharPtr t2 = luaT_typenames[ttype(p2)]; + if (t1[2] == t2[2]) + luaG_runerror(L, "attempt to compare two %s values", t1); + else + luaG_runerror(L, "attempt to compare %s with %s", t1, t2); + return 0; + } + + + private static void addinfo (lua_State L, CharPtr msg) { + CallInfo ci = L.ci; + if (isLua(ci)) { /* is Lua code? */ + CharPtr buff = new CharPtr(new char[LUA_IDSIZE]); /* add file:line information */ + int line = currentline(L, ci); + luaO_chunkid(buff, getstr(getluaproto(ci).source), LUA_IDSIZE); + luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); + } + } + + + public static void luaG_errormsg (lua_State L) { + if (L.errfunc != 0) { /* is there an error handling function? */ + StkId errfunc = restorestack(L, L.errfunc); + if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); + setobjs2s(L, L.top, L.top - 1); /* move argument */ + setobjs2s(L, L.top - 1, errfunc); /* push function */ + incr_top(L); + luaD_call(L, L.top - 2, 1); /* call it */ + } + luaD_throw(L, LUA_ERRRUN); + } + + public static void luaG_runerror(lua_State L, CharPtr fmt, params object[] argp) + { + addinfo(L, luaO_pushvfstring(L, fmt, argp)); + luaG_errormsg(L); + } + + } +} diff --git a/Core/KopiLua/ldo.cs b/Core/KopiLua/ldo.cs index 9d35b0edece514ae778fafef99d8836e0f8567d4..644c74b6d32a9736985df6aa44a4b5033ddefef1 100644 --- a/Core/KopiLua/ldo.cs +++ b/Core/KopiLua/ldo.cs @@ -1,593 +1,593 @@ -/* -** $Id: ldo.c,v 2.38.1.3 2008/01/18 22:31:22 roberto Exp $ -** Stack and Call structure of Lua -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; -using System.Threading; - -#if XBOX -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Audio; -using Microsoft.Xna.Framework.Content; -using Microsoft.Xna.Framework.GamerServices; -using Microsoft.Xna.Framework.Graphics; -using Microsoft.Xna.Framework.Input; -using Microsoft.Xna.Framework.Media; -using Microsoft.Xna.Framework.Net; -using Microsoft.Xna.Framework.Storage; -#endif - -namespace KopiLua -{ - using lua_Integer = System.Int32; - using ptrdiff_t = System.Int32; - using TValue = Lua.lua_TValue; - using StkId = Lua.lua_TValue; - using lu_byte = System.Byte; - using ZIO = Lua.Zio; - - public partial class Lua - { - public static void luaD_checkstack(lua_State L, int n) { - if ((L.stack_last - L.top) <= n) - luaD_growstack(L, n); - else - { - #if HARDSTACKTESTS - luaD_reallocstack(L, L.stacksize - EXTRA_STACK - 1); - #endif - } - } - - public static void incr_top(lua_State L) - { - luaD_checkstack(L, 1); - StkId.inc(ref L.top); - } - - // in the original C code these values save and restore the stack by number of bytes. marshalling sizeof - // isn't that straightforward in managed languages, so i implement these by index instead. - public static int savestack(lua_State L, StkId p) {return p;} - public static StkId restorestack(lua_State L, int n) {return L.stack[n];} - public static int saveci(lua_State L, CallInfo p) {return p - L.base_ci;} - public static CallInfo restoreci(lua_State L, int n) { return L.base_ci[n]; } - - - /* results from luaD_precall */ - public const int PCRLUA = 0; /* initiated a call to a Lua function */ - public const int PCRC = 1; /* did a call to a C function */ - public const int PCRYIELD = 2; /* C funtion yielded */ - - - /* type of protected functions, to be ran by `runprotected' */ - public delegate void Pfunc(lua_State L, object ud); - - - /* - ** {====================================================== - ** Error-recovery functions - ** ======================================================= - */ - - public delegate void luai_jmpbuf(lua_Integer b); - - /* chain list of long jump buffers */ - public class lua_longjmp { - public lua_longjmp previous; - public luai_jmpbuf b; - [CLSCompliantAttribute(false)] - public volatile int status; /* error code */ - }; - - - public static void luaD_seterrorobj (lua_State L, int errcode, StkId oldtop) { - switch (errcode) { - case LUA_ERRMEM: { - setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); - break; - } - case LUA_ERRERR: { - setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); - break; - } - case LUA_ERRSYNTAX: - case LUA_ERRRUN: { - setobjs2s(L, oldtop, L.top-1); /* error message on current top */ - break; - } - } - L.top = oldtop + 1; - } - - - private static void restore_stack_limit (lua_State L) { - lua_assert(L.stack_last == L.stacksize - EXTRA_STACK - 1); - if (L.size_ci > LUAI_MAXCALLS) { /* there was an overflow? */ - int inuse = L.ci - L.base_ci; - if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */ - luaD_reallocCI(L, LUAI_MAXCALLS); - } - } - - - private static void resetstack (lua_State L, int status) { - L.ci = L.base_ci[0]; - L.base_ = L.ci.base_; - luaF_close(L, L.base_); /* close eventual pending closures */ - luaD_seterrorobj(L, status, L.base_); - L.nCcalls = L.baseCcalls; - L.allowhook = 1; - restore_stack_limit(L); - L.errfunc = 0; - L.errorJmp = null; - } - - - public static void luaD_throw (lua_State L, int errcode) { - if (L.errorJmp != null) { - L.errorJmp.status = errcode; - LUAI_THROW(L, L.errorJmp); - } - else { - L.status = cast_byte(errcode); - if (G(L).panic != null) { - resetstack(L, errcode); - lua_unlock(L); - G(L).panic(L); - } -#if XBOX - throw new ApplicationException(); -#else -#if SILVERLIGHT - throw new SystemException(); -#else - Environment.Exit(EXIT_FAILURE); -#endif -#endif - - } - } - - - public static int luaD_rawrunprotected (lua_State L, Pfunc f, object ud) { - lua_longjmp lj = new lua_longjmp(); - lj.status = 0; - lj.previous = L.errorJmp; /* chain new error handler */ - L.errorJmp = lj; - /* - LUAI_TRY(L, lj, - f(L, ud) - ); - * */ -#if CATCH_EXCEPTIONS - try -#endif - { - f(L, ud); - } -#if CATCH_EXCEPTIONS - catch - { - if (lj.status == 0) - lj.status = -1; - } -#endif - L.errorJmp = lj.previous; /* restore old error handler */ - return lj.status; - } - - /* }====================================================== */ - - - private static void correctstack (lua_State L, TValue[] oldstack) { - /* don't need to do this - CallInfo ci; - GCObject up; - L.top = L.stack[L.top - oldstack]; - for (up = L.openupval; up != null; up = up.gch.next) - gco2uv(up).v = L.stack[gco2uv(up).v - oldstack]; - for (ci = L.base_ci[0]; ci <= L.ci; CallInfo.inc(ref ci)) { - ci.top = L.stack[ci.top - oldstack]; - ci.base_ = L.stack[ci.base_ - oldstack]; - ci.func = L.stack[ci.func - oldstack]; - } - L.base_ = L.stack[L.base_ - oldstack]; - * */ - } - - public static void luaD_reallocstack (lua_State L, int newsize) { - TValue[] oldstack = L.stack; - int realsize = newsize + 1 + EXTRA_STACK; - lua_assert(L.stack_last == L.stacksize - EXTRA_STACK - 1); - luaM_reallocvector(L, ref L.stack, L.stacksize, realsize/*, TValue*/); - L.stacksize = realsize; - L.stack_last = L.stack[newsize]; - correctstack(L, oldstack); - } - - public static void luaD_reallocCI (lua_State L, int newsize) { - CallInfo oldci = L.base_ci[0]; - luaM_reallocvector(L, ref L.base_ci, L.size_ci, newsize/*, CallInfo*/); - L.size_ci = newsize; - L.ci = L.base_ci[L.ci - oldci]; - L.end_ci = L.base_ci[L.size_ci - 1]; - } - - public static void luaD_growstack (lua_State L, int n) { - if (n <= L.stacksize) /* double size is enough? */ - luaD_reallocstack(L, 2*L.stacksize); - else - luaD_reallocstack(L, L.stacksize + n); - } - - private static CallInfo growCI (lua_State L) { - if (L.size_ci > LUAI_MAXCALLS) /* overflow while handling overflow? */ - luaD_throw(L, LUA_ERRERR); - else { - luaD_reallocCI(L, 2*L.size_ci); - if (L.size_ci > LUAI_MAXCALLS) - luaG_runerror(L, "stack overflow"); - } - CallInfo.inc(ref L.ci); - return L.ci; - } - - - public static void luaD_callhook (lua_State L, int event_, int line) { - lua_Hook hook = L.hook; - if ((hook!=null) && (L.allowhook!=0)) { - ptrdiff_t top = savestack(L, L.top); - ptrdiff_t ci_top = savestack(L, L.ci.top); - lua_Debug ar = new lua_Debug(); - ar.event_ = event_; - ar.currentline = line; - if (event_ == LUA_HOOKTAILRET) - ar.i_ci = 0; /* tail call; no debug information about it */ - else - ar.i_ci = L.ci - L.base_ci; - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - L.ci.top = L.top + LUA_MINSTACK; - lua_assert(L.ci.top <= L.stack_last); - L.allowhook = 0; /* cannot call hooks inside a hook */ - lua_unlock(L); - hook(L, ar); - lua_lock(L); - lua_assert(L.allowhook==0); - L.allowhook = 1; - L.ci.top = restorestack(L, ci_top); - L.top = restorestack(L, top); - } - } - - - private static StkId adjust_varargs (lua_State L, Proto p, int actual) { - int i; - int nfixargs = p.numparams; - Table htab = null; - StkId base_, fixed_; - for (; actual < nfixargs; ++actual) - setnilvalue(StkId.inc(ref L.top)); - #if LUA_COMPAT_VARARG - if ((p.is_vararg & VARARG_NEEDSARG) != 0) { /* compat. with old-style vararg? */ - int nvar = actual - nfixargs; /* number of extra arguments */ - lua_assert(p.is_vararg & VARARG_HASARG); - luaC_checkGC(L); - htab = luaH_new(L, nvar, 1); /* create `arg' table */ - for (i=0; i func; StkId.dec(ref p)) setobjs2s(L, p, p - 1); - incr_top(L); - func = restorestack(L, funcr); /* previous call may change stack */ - setobj2s(L, func, tm); /* tag method is the new function to be called */ - return func; - } - - - - public static CallInfo inc_ci(lua_State L) - { - if (L.ci == L.end_ci) return growCI(L); - // (condhardstacktests(luaD_reallocCI(L, L.size_ci)), ++L.ci)) - CallInfo.inc(ref L.ci); - return L.ci; - } - - - public static int luaD_precall (lua_State L, StkId func, int nresults) { - LClosure cl; - ptrdiff_t funcr; - if (!ttisfunction(func)) /* `func' is not a function? */ - func = tryfuncTM(L, func); /* check the `function' tag method */ - - funcr = savestack(L, func); - cl = clvalue(func).l; - L.ci.savedpc = InstructionPtr.Assign(L.savedpc); - - if (cl.isC==0) { /* Lua function? prepare its call */ - CallInfo ci; - StkId st, base_; - Proto p = cl.p; - luaD_checkstack(L, p.maxstacksize); - func = restorestack(L, funcr); - if (p.is_vararg == 0) { /* no varargs? */ - base_ = L.stack[func + 1]; - if (L.top > base_ + p.numparams) - L.top = base_ + p.numparams; - } - else { /* vararg function */ - int nargs = L.top - func - 1; - base_ = adjust_varargs(L, p, nargs); - func = restorestack(L, funcr); /* previous call may change the stack */ - } - ci = inc_ci(L); /* now `enter' new function */ - ci.func = func; - L.base_ = ci.base_ = base_; - ci.top = L.base_ + p.maxstacksize; - lua_assert(ci.top <= L.stack_last); - L.savedpc = new InstructionPtr(p.code, 0); /* starting point */ - ci.tailcalls = 0; - ci.nresults = nresults; - for (st = L.top; st < ci.top; StkId.inc(ref st)) - setnilvalue(st); - L.top = ci.top; - if ((L.hookmask & LUA_MASKCALL) != 0) { - InstructionPtr.inc(ref L.savedpc); /* hooks assume 'pc' is already incremented */ - luaD_callhook(L, LUA_HOOKCALL, -1); - InstructionPtr.dec(ref L.savedpc); /* correct 'pc' */ - } - return PCRLUA; - } - else { /* if is a C function, call it */ - CallInfo ci; - int n; - luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - ci = inc_ci(L); /* now `enter' new function */ - ci.func = restorestack(L, funcr); - L.base_ = ci.base_ = ci.func + 1; - ci.top = L.top + LUA_MINSTACK; - lua_assert(ci.top <= L.stack_last); - ci.nresults = nresults; - if ((L.hookmask & LUA_MASKCALL) != 0) - luaD_callhook(L, LUA_HOOKCALL, -1); - lua_unlock(L); - n = curr_func(L).c.f(L); /* do the actual call */ - lua_lock(L); - if (n < 0) /* yielding? */ - return PCRYIELD; - else { - luaD_poscall(L, L.top - n); - return PCRC; - } - } - } - - - private static StkId callrethooks (lua_State L, StkId firstResult) { - ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ - luaD_callhook(L, LUA_HOOKRET, -1); - if (f_isLua(L.ci)) { /* Lua function? */ - while ( ((L.hookmask & LUA_MASKRET)!=0) && (L.ci.tailcalls-- != 0)) /* tail calls */ - luaD_callhook(L, LUA_HOOKTAILRET, -1); - } - return restorestack(L, fr); - } - - - public static int luaD_poscall (lua_State L, StkId firstResult) { - StkId res; - int wanted, i; - CallInfo ci; - if ((L.hookmask & LUA_MASKRET) != 0) - firstResult = callrethooks(L, firstResult); - ci = CallInfo.dec(ref L.ci); - res = ci.func; /* res == final position of 1st result */ - wanted = ci.nresults; - L.base_ = (ci - 1).base_; /* restore base */ - L.savedpc = InstructionPtr.Assign((ci - 1).savedpc); /* restore savedpc */ - /* move results to correct place */ - for (i = wanted; i != 0 && firstResult < L.top; i--) - { - setobjs2s(L, res, firstResult); - res = res + 1; - firstResult = firstResult + 1; - } - while (i-- > 0) - setnilvalue(StkId.inc(ref res)); - L.top = res; - return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ - } - - - /* - ** Call a function (C or Lua). The function to be called is at *func. - ** The arguments are on the stack, right after the function. - ** When returns, all the results are on the stack, starting at the original - ** function position. - */ - private static void luaD_call (lua_State L, StkId func, int nResults) { - if (++L.nCcalls >= LUAI_MAXCCALLS) { - if (L.nCcalls == LUAI_MAXCCALLS) - luaG_runerror(L, "C stack overflow"); - else if (L.nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) - luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ - } - - if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ - luaV_execute(L, 1); /* call it */ - - L.nCcalls--; - luaC_checkGC(L); - } - - - private static void resume (lua_State L, object ud) { - StkId firstArg = (StkId)ud; - CallInfo ci = L.ci; - if (L.status == 0) { /* start coroutine? */ - lua_assert(ci == L.base_ci[0] && firstArg > L.base_); - if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) - return; - } - else { /* resuming from previous yield */ - lua_assert(L.status == LUA_YIELD); - L.status = 0; - if (!f_isLua(ci)) { /* `common' yield? */ - /* finish interrupted execution of `OP_CALL' */ - lua_assert(GET_OPCODE((ci-1).savedpc[-1]) == OpCode.OP_CALL || - GET_OPCODE((ci-1).savedpc[-1]) == OpCode.OP_TAILCALL); - if (luaD_poscall(L, firstArg) != 0) /* complete it... */ - L.top = L.ci.top; /* and correct top if not multiple results */ - } - else /* yielded inside a hook: just continue its execution */ - L.base_ = L.ci.base_; - } - luaV_execute(L, L.ci - L.base_ci); - } - - - private static int resume_error (lua_State L, CharPtr msg) { - L.top = L.ci.base_; - setsvalue2s(L, L.top, luaS_new(L, msg)); - incr_top(L); - lua_unlock(L); - return LUA_ERRRUN; - } - - - public static int lua_resume (lua_State L, int nargs) { - int status; - lua_lock(L); - if (L.status != LUA_YIELD && (L.status != 0 || (L.ci != L.base_ci[0]))) - return resume_error(L, "cannot resume non-suspended coroutine"); - if (L.nCcalls >= LUAI_MAXCCALLS) - return resume_error(L, "C stack overflow"); - luai_userstateresume(L, nargs); - lua_assert(L.errfunc == 0); - L.baseCcalls = ++L.nCcalls; - status = luaD_rawrunprotected(L, resume, L.top - nargs); - if (status != 0) { /* error? */ - L.status = cast_byte(status); /* mark thread as `dead' */ - luaD_seterrorobj(L, status, L.top); - L.ci.top = L.top; - } - else { - lua_assert(L.nCcalls == L.baseCcalls); - status = L.status; - } - --L.nCcalls; - lua_unlock(L); - return status; - } - - [CLSCompliantAttribute(false)] - public static int lua_yield (lua_State L, int nresults) { - luai_userstateyield(L, nresults); - lua_lock(L); - if (L.nCcalls > L.baseCcalls) - luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); - L.base_ = L.top - nresults; /* protect stack slots below */ - L.status = LUA_YIELD; - lua_unlock(L); - return -1; - } - - - public static int luaD_pcall (lua_State L, Pfunc func, object u, - ptrdiff_t old_top, ptrdiff_t ef) { - int status; - ushort oldnCcalls = L.nCcalls; - ptrdiff_t old_ci = saveci(L, L.ci); - lu_byte old_allowhooks = L.allowhook; - ptrdiff_t old_errfunc = L.errfunc; - L.errfunc = ef; - status = luaD_rawrunprotected(L, func, u); - if (status != 0) { /* an error occurred? */ - StkId oldtop = restorestack(L, old_top); - luaF_close(L, oldtop); /* close eventual pending closures */ - luaD_seterrorobj(L, status, oldtop); - L.nCcalls = oldnCcalls; - L.ci = restoreci(L, old_ci); - L.base_ = L.ci.base_; - L.savedpc = InstructionPtr.Assign(L.ci.savedpc); - L.allowhook = old_allowhooks; - restore_stack_limit(L); - } - L.errfunc = old_errfunc; - return status; - } - - - - /* - ** Execute a protected parser. - */ - public class SParser { /* data to `f_parser' */ - public ZIO z; - public Mbuffer buff = new Mbuffer(); /* buffer to be used by the scanner */ - public CharPtr name; - }; - - private static void f_parser (lua_State L, object ud) { - int i; - Proto tf; - Closure cl; - SParser p = (SParser)ud; - int c = luaZ_lookahead(p.z); - luaC_checkGC(L); - tf = (c == LUA_SIGNATURE[0]) ? - luaU_undump(L, p.z, p.buff, p.name) : - luaY_parser(L, p.z, p.buff, p.name); - cl = luaF_newLclosure(L, tf.nups, hvalue(gt(L))); - cl.l.p = tf; - for (i = 0; i < tf.nups; i++) /* initialize eventual upvalues */ - cl.l.upvals[i] = luaF_newupval(L); - setclvalue(L, L.top, cl); - incr_top(L); - } - - - public static int luaD_protectedparser (lua_State L, ZIO z, CharPtr name) { - SParser p = new SParser(); - int status; - p.z = z; p.name = new CharPtr(name); - luaZ_initbuffer(L, p.buff); - status = luaD_pcall(L, f_parser, p, savestack(L, L.top), L.errfunc); - luaZ_freebuffer(L, p.buff); - return status; - } - } -} +/* +** $Id: ldo.c,v 2.38.1.3 2008/01/18 22:31:22 roberto Exp $ +** Stack and Call structure of Lua +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; +using System.Threading; + +#if XBOX +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Audio; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.GamerServices; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using Microsoft.Xna.Framework.Media; +using Microsoft.Xna.Framework.Net; +using Microsoft.Xna.Framework.Storage; +#endif + +namespace KopiLua +{ + using lua_Integer = System.Int32; + using ptrdiff_t = System.Int32; + using TValue = Lua.lua_TValue; + using StkId = Lua.lua_TValue; + using lu_byte = System.Byte; + using ZIO = Lua.Zio; + + public partial class Lua + { + public static void luaD_checkstack(lua_State L, int n) { + if ((L.stack_last - L.top) <= n) + luaD_growstack(L, n); + else + { + #if HARDSTACKTESTS + luaD_reallocstack(L, L.stacksize - EXTRA_STACK - 1); + #endif + } + } + + public static void incr_top(lua_State L) + { + luaD_checkstack(L, 1); + StkId.inc(ref L.top); + } + + // in the original C code these values save and restore the stack by number of bytes. marshalling sizeof + // isn't that straightforward in managed languages, so i implement these by index instead. + public static int savestack(lua_State L, StkId p) {return p;} + public static StkId restorestack(lua_State L, int n) {return L.stack[n];} + public static int saveci(lua_State L, CallInfo p) {return p - L.base_ci;} + public static CallInfo restoreci(lua_State L, int n) { return L.base_ci[n]; } + + + /* results from luaD_precall */ + public const int PCRLUA = 0; /* initiated a call to a Lua function */ + public const int PCRC = 1; /* did a call to a C function */ + public const int PCRYIELD = 2; /* C funtion yielded */ + + + /* type of protected functions, to be ran by `runprotected' */ + public delegate void Pfunc(lua_State L, object ud); + + + /* + ** {====================================================== + ** Error-recovery functions + ** ======================================================= + */ + + public delegate void luai_jmpbuf(lua_Integer b); + + /* chain list of long jump buffers */ + public class lua_longjmp { + public lua_longjmp previous; + public luai_jmpbuf b; + [CLSCompliantAttribute(false)] + public volatile int status; /* error code */ + }; + + + public static void luaD_seterrorobj (lua_State L, int errcode, StkId oldtop) { + switch (errcode) { + case LUA_ERRMEM: { + setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); + break; + } + case LUA_ERRERR: { + setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); + break; + } + case LUA_ERRSYNTAX: + case LUA_ERRRUN: { + setobjs2s(L, oldtop, L.top-1); /* error message on current top */ + break; + } + } + L.top = oldtop + 1; + } + + + private static void restore_stack_limit (lua_State L) { + lua_assert(L.stack_last == L.stacksize - EXTRA_STACK - 1); + if (L.size_ci > LUAI_MAXCALLS) { /* there was an overflow? */ + int inuse = L.ci - L.base_ci; + if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */ + luaD_reallocCI(L, LUAI_MAXCALLS); + } + } + + + private static void resetstack (lua_State L, int status) { + L.ci = L.base_ci[0]; + L.base_ = L.ci.base_; + luaF_close(L, L.base_); /* close eventual pending closures */ + luaD_seterrorobj(L, status, L.base_); + L.nCcalls = L.baseCcalls; + L.allowhook = 1; + restore_stack_limit(L); + L.errfunc = 0; + L.errorJmp = null; + } + + + public static void luaD_throw (lua_State L, int errcode) { + if (L.errorJmp != null) { + L.errorJmp.status = errcode; + LUAI_THROW(L, L.errorJmp); + } + else { + L.status = cast_byte(errcode); + if (G(L).panic != null) { + resetstack(L, errcode); + lua_unlock(L); + G(L).panic(L); + } +#if XBOX + throw new ApplicationException(); +#else +#if SILVERLIGHT + throw new SystemException(); +#else + Environment.Exit(EXIT_FAILURE); +#endif +#endif + + } + } + + + public static int luaD_rawrunprotected (lua_State L, Pfunc f, object ud) { + lua_longjmp lj = new lua_longjmp(); + lj.status = 0; + lj.previous = L.errorJmp; /* chain new error handler */ + L.errorJmp = lj; + /* + LUAI_TRY(L, lj, + f(L, ud) + ); + * */ +#if CATCH_EXCEPTIONS + try +#endif + { + f(L, ud); + } +#if CATCH_EXCEPTIONS + catch + { + if (lj.status == 0) + lj.status = -1; + } +#endif + L.errorJmp = lj.previous; /* restore old error handler */ + return lj.status; + } + + /* }====================================================== */ + + + private static void correctstack (lua_State L, TValue[] oldstack) { + /* don't need to do this + CallInfo ci; + GCObject up; + L.top = L.stack[L.top - oldstack]; + for (up = L.openupval; up != null; up = up.gch.next) + gco2uv(up).v = L.stack[gco2uv(up).v - oldstack]; + for (ci = L.base_ci[0]; ci <= L.ci; CallInfo.inc(ref ci)) { + ci.top = L.stack[ci.top - oldstack]; + ci.base_ = L.stack[ci.base_ - oldstack]; + ci.func = L.stack[ci.func - oldstack]; + } + L.base_ = L.stack[L.base_ - oldstack]; + * */ + } + + public static void luaD_reallocstack (lua_State L, int newsize) { + TValue[] oldstack = L.stack; + int realsize = newsize + 1 + EXTRA_STACK; + lua_assert(L.stack_last == L.stacksize - EXTRA_STACK - 1); + luaM_reallocvector(L, ref L.stack, L.stacksize, realsize/*, TValue*/); + L.stacksize = realsize; + L.stack_last = L.stack[newsize]; + correctstack(L, oldstack); + } + + public static void luaD_reallocCI (lua_State L, int newsize) { + CallInfo oldci = L.base_ci[0]; + luaM_reallocvector(L, ref L.base_ci, L.size_ci, newsize/*, CallInfo*/); + L.size_ci = newsize; + L.ci = L.base_ci[L.ci - oldci]; + L.end_ci = L.base_ci[L.size_ci - 1]; + } + + public static void luaD_growstack (lua_State L, int n) { + if (n <= L.stacksize) /* double size is enough? */ + luaD_reallocstack(L, 2*L.stacksize); + else + luaD_reallocstack(L, L.stacksize + n); + } + + private static CallInfo growCI (lua_State L) { + if (L.size_ci > LUAI_MAXCALLS) /* overflow while handling overflow? */ + luaD_throw(L, LUA_ERRERR); + else { + luaD_reallocCI(L, 2*L.size_ci); + if (L.size_ci > LUAI_MAXCALLS) + luaG_runerror(L, "stack overflow"); + } + CallInfo.inc(ref L.ci); + return L.ci; + } + + + public static void luaD_callhook (lua_State L, int event_, int line) { + lua_Hook hook = L.hook; + if ((hook!=null) && (L.allowhook!=0)) { + ptrdiff_t top = savestack(L, L.top); + ptrdiff_t ci_top = savestack(L, L.ci.top); + lua_Debug ar = new lua_Debug(); + ar.event_ = event_; + ar.currentline = line; + if (event_ == LUA_HOOKTAILRET) + ar.i_ci = 0; /* tail call; no debug information about it */ + else + ar.i_ci = L.ci - L.base_ci; + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + L.ci.top = L.top + LUA_MINSTACK; + lua_assert(L.ci.top <= L.stack_last); + L.allowhook = 0; /* cannot call hooks inside a hook */ + lua_unlock(L); + hook(L, ar); + lua_lock(L); + lua_assert(L.allowhook==0); + L.allowhook = 1; + L.ci.top = restorestack(L, ci_top); + L.top = restorestack(L, top); + } + } + + + private static StkId adjust_varargs (lua_State L, Proto p, int actual) { + int i; + int nfixargs = p.numparams; + Table htab = null; + StkId base_, fixed_; + for (; actual < nfixargs; ++actual) + setnilvalue(StkId.inc(ref L.top)); + #if LUA_COMPAT_VARARG + if ((p.is_vararg & VARARG_NEEDSARG) != 0) { /* compat. with old-style vararg? */ + int nvar = actual - nfixargs; /* number of extra arguments */ + lua_assert(p.is_vararg & VARARG_HASARG); + luaC_checkGC(L); + htab = luaH_new(L, nvar, 1); /* create `arg' table */ + for (i=0; i func; StkId.dec(ref p)) setobjs2s(L, p, p - 1); + incr_top(L); + func = restorestack(L, funcr); /* previous call may change stack */ + setobj2s(L, func, tm); /* tag method is the new function to be called */ + return func; + } + + + + public static CallInfo inc_ci(lua_State L) + { + if (L.ci == L.end_ci) return growCI(L); + // (condhardstacktests(luaD_reallocCI(L, L.size_ci)), ++L.ci)) + CallInfo.inc(ref L.ci); + return L.ci; + } + + + public static int luaD_precall (lua_State L, StkId func, int nresults) { + LClosure cl; + ptrdiff_t funcr; + if (!ttisfunction(func)) /* `func' is not a function? */ + func = tryfuncTM(L, func); /* check the `function' tag method */ + + funcr = savestack(L, func); + cl = clvalue(func).l; + L.ci.savedpc = InstructionPtr.Assign(L.savedpc); + + if (cl.isC==0) { /* Lua function? prepare its call */ + CallInfo ci; + StkId st, base_; + Proto p = cl.p; + luaD_checkstack(L, p.maxstacksize); + func = restorestack(L, funcr); + if (p.is_vararg == 0) { /* no varargs? */ + base_ = L.stack[func + 1]; + if (L.top > base_ + p.numparams) + L.top = base_ + p.numparams; + } + else { /* vararg function */ + int nargs = L.top - func - 1; + base_ = adjust_varargs(L, p, nargs); + func = restorestack(L, funcr); /* previous call may change the stack */ + } + ci = inc_ci(L); /* now `enter' new function */ + ci.func = func; + L.base_ = ci.base_ = base_; + ci.top = L.base_ + p.maxstacksize; + lua_assert(ci.top <= L.stack_last); + L.savedpc = new InstructionPtr(p.code, 0); /* starting point */ + ci.tailcalls = 0; + ci.nresults = nresults; + for (st = L.top; st < ci.top; StkId.inc(ref st)) + setnilvalue(st); + L.top = ci.top; + if ((L.hookmask & LUA_MASKCALL) != 0) { + InstructionPtr.inc(ref L.savedpc); /* hooks assume 'pc' is already incremented */ + luaD_callhook(L, LUA_HOOKCALL, -1); + InstructionPtr.dec(ref L.savedpc); /* correct 'pc' */ + } + return PCRLUA; + } + else { /* if is a C function, call it */ + CallInfo ci; + int n; + luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ + ci = inc_ci(L); /* now `enter' new function */ + ci.func = restorestack(L, funcr); + L.base_ = ci.base_ = ci.func + 1; + ci.top = L.top + LUA_MINSTACK; + lua_assert(ci.top <= L.stack_last); + ci.nresults = nresults; + if ((L.hookmask & LUA_MASKCALL) != 0) + luaD_callhook(L, LUA_HOOKCALL, -1); + lua_unlock(L); + n = curr_func(L).c.f(L); /* do the actual call */ + lua_lock(L); + if (n < 0) /* yielding? */ + return PCRYIELD; + else { + luaD_poscall(L, L.top - n); + return PCRC; + } + } + } + + + private static StkId callrethooks (lua_State L, StkId firstResult) { + ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ + luaD_callhook(L, LUA_HOOKRET, -1); + if (f_isLua(L.ci)) { /* Lua function? */ + while ( ((L.hookmask & LUA_MASKRET)!=0) && (L.ci.tailcalls-- != 0)) /* tail calls */ + luaD_callhook(L, LUA_HOOKTAILRET, -1); + } + return restorestack(L, fr); + } + + + public static int luaD_poscall (lua_State L, StkId firstResult) { + StkId res; + int wanted, i; + CallInfo ci; + if ((L.hookmask & LUA_MASKRET) != 0) + firstResult = callrethooks(L, firstResult); + ci = CallInfo.dec(ref L.ci); + res = ci.func; /* res == final position of 1st result */ + wanted = ci.nresults; + L.base_ = (ci - 1).base_; /* restore base */ + L.savedpc = InstructionPtr.Assign((ci - 1).savedpc); /* restore savedpc */ + /* move results to correct place */ + for (i = wanted; i != 0 && firstResult < L.top; i--) + { + setobjs2s(L, res, firstResult); + res = res + 1; + firstResult = firstResult + 1; + } + while (i-- > 0) + setnilvalue(StkId.inc(ref res)); + L.top = res; + return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ + } + + + /* + ** Call a function (C or Lua). The function to be called is at *func. + ** The arguments are on the stack, right after the function. + ** When returns, all the results are on the stack, starting at the original + ** function position. + */ + private static void luaD_call (lua_State L, StkId func, int nResults) { + if (++L.nCcalls >= LUAI_MAXCCALLS) { + if (L.nCcalls == LUAI_MAXCCALLS) + luaG_runerror(L, "C stack overflow"); + else if (L.nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) + luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ + } + + if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ + luaV_execute(L, 1); /* call it */ + + L.nCcalls--; + luaC_checkGC(L); + } + + + private static void resume (lua_State L, object ud) { + StkId firstArg = (StkId)ud; + CallInfo ci = L.ci; + if (L.status == 0) { /* start coroutine? */ + lua_assert(ci == L.base_ci[0] && firstArg > L.base_); + if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) + return; + } + else { /* resuming from previous yield */ + lua_assert(L.status == LUA_YIELD); + L.status = 0; + if (!f_isLua(ci)) { /* `common' yield? */ + /* finish interrupted execution of `OP_CALL' */ + lua_assert(GET_OPCODE((ci-1).savedpc[-1]) == OpCode.OP_CALL || + GET_OPCODE((ci-1).savedpc[-1]) == OpCode.OP_TAILCALL); + if (luaD_poscall(L, firstArg) != 0) /* complete it... */ + L.top = L.ci.top; /* and correct top if not multiple results */ + } + else /* yielded inside a hook: just continue its execution */ + L.base_ = L.ci.base_; + } + luaV_execute(L, L.ci - L.base_ci); + } + + + private static int resume_error (lua_State L, CharPtr msg) { + L.top = L.ci.base_; + setsvalue2s(L, L.top, luaS_new(L, msg)); + incr_top(L); + lua_unlock(L); + return LUA_ERRRUN; + } + + + public static int lua_resume (lua_State L, int nargs) { + int status; + lua_lock(L); + if (L.status != LUA_YIELD && (L.status != 0 || (L.ci != L.base_ci[0]))) + return resume_error(L, "cannot resume non-suspended coroutine"); + if (L.nCcalls >= LUAI_MAXCCALLS) + return resume_error(L, "C stack overflow"); + luai_userstateresume(L, nargs); + lua_assert(L.errfunc == 0); + L.baseCcalls = ++L.nCcalls; + status = luaD_rawrunprotected(L, resume, L.top - nargs); + if (status != 0) { /* error? */ + L.status = cast_byte(status); /* mark thread as `dead' */ + luaD_seterrorobj(L, status, L.top); + L.ci.top = L.top; + } + else { + lua_assert(L.nCcalls == L.baseCcalls); + status = L.status; + } + --L.nCcalls; + lua_unlock(L); + return status; + } + + [CLSCompliantAttribute(false)] + public static int lua_yield (lua_State L, int nresults) { + luai_userstateyield(L, nresults); + lua_lock(L); + if (L.nCcalls > L.baseCcalls) + luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); + L.base_ = L.top - nresults; /* protect stack slots below */ + L.status = LUA_YIELD; + lua_unlock(L); + return -1; + } + + + public static int luaD_pcall (lua_State L, Pfunc func, object u, + ptrdiff_t old_top, ptrdiff_t ef) { + int status; + ushort oldnCcalls = L.nCcalls; + ptrdiff_t old_ci = saveci(L, L.ci); + lu_byte old_allowhooks = L.allowhook; + ptrdiff_t old_errfunc = L.errfunc; + L.errfunc = ef; + status = luaD_rawrunprotected(L, func, u); + if (status != 0) { /* an error occurred? */ + StkId oldtop = restorestack(L, old_top); + luaF_close(L, oldtop); /* close eventual pending closures */ + luaD_seterrorobj(L, status, oldtop); + L.nCcalls = oldnCcalls; + L.ci = restoreci(L, old_ci); + L.base_ = L.ci.base_; + L.savedpc = InstructionPtr.Assign(L.ci.savedpc); + L.allowhook = old_allowhooks; + restore_stack_limit(L); + } + L.errfunc = old_errfunc; + return status; + } + + + + /* + ** Execute a protected parser. + */ + public class SParser { /* data to `f_parser' */ + public ZIO z; + public Mbuffer buff = new Mbuffer(); /* buffer to be used by the scanner */ + public CharPtr name; + }; + + private static void f_parser (lua_State L, object ud) { + int i; + Proto tf; + Closure cl; + SParser p = (SParser)ud; + int c = luaZ_lookahead(p.z); + luaC_checkGC(L); + tf = (c == LUA_SIGNATURE[0]) ? + luaU_undump(L, p.z, p.buff, p.name) : + luaY_parser(L, p.z, p.buff, p.name); + cl = luaF_newLclosure(L, tf.nups, hvalue(gt(L))); + cl.l.p = tf; + for (i = 0; i < tf.nups; i++) /* initialize eventual upvalues */ + cl.l.upvals[i] = luaF_newupval(L); + setclvalue(L, L.top, cl); + incr_top(L); + } + + + public static int luaD_protectedparser (lua_State L, ZIO z, CharPtr name) { + SParser p = new SParser(); + int status; + p.z = z; p.name = new CharPtr(name); + luaZ_initbuffer(L, p.buff); + status = luaD_pcall(L, f_parser, p, savestack(L, L.top), L.errfunc); + luaZ_freebuffer(L, p.buff); + return status; + } + } +} diff --git a/Core/KopiLua/ldump.cs b/Core/KopiLua/ldump.cs index 0840c11d4446b34c92f05b13e2751084be2385d6..5bc7a017d0ae0a54120136d9516b7d6fe098bbf5 100644 --- a/Core/KopiLua/ldump.cs +++ b/Core/KopiLua/ldump.cs @@ -1,204 +1,204 @@ -/* -** $Id: ldump.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $ -** save precompiled Lua chunks -** See Copyright Notice in lua.h -*/ - -using System; -using System.IO; -using System.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; -using System.Diagnostics; -using System.Runtime.Serialization; - - -namespace KopiLua -{ - using lua_Number = System.Double; - using TValue = Lua.lua_TValue; - - public partial class Lua - { - public class DumpState { - public lua_State L; - [CLSCompliantAttribute(false)] - public lua_Writer writer; - public object data; - public int strip; - public int status; - }; - - public static void DumpMem(object b, DumpState D) - { -#if XBOX || SILVERLIGHT - // todo: implement this - mjf - Debug.Assert(false); -#else - int size = Marshal.SizeOf(b); - IntPtr ptr = Marshal.AllocHGlobal(size); - Marshal.StructureToPtr(b, ptr, false); - byte[] bytes = new byte[size]; - Marshal.Copy(ptr, bytes, 0, size); - char[] ch = new char[bytes.Length]; - for (int i = 0; i < bytes.Length; i++) - ch[i] = (char)bytes[i]; - CharPtr str = ch; - DumpBlock(str, (uint)str.chars.Length, D); - Marshal.Release(ptr); -#endif - } - - public static void DumpMem(object b, int n, DumpState D) - { - Array array = b as Array; - Debug.Assert(array.Length == n); - for (int i = 0; i < n; i++) - DumpMem(array.GetValue(i), D); - } - - public static void DumpVar(object x, DumpState D) - { - DumpMem(x, D); - } - - private static void DumpBlock(CharPtr b, uint size, DumpState D) - { - if (D.status==0) - { - lua_unlock(D.L); - D.status=D.writer(D.L,b,size,D.data); - lua_lock(D.L); - } - } - - private static void DumpChar(int y, DumpState D) - { - char x=(char)y; - DumpVar(x,D); - } - - private static void DumpInt(int x, DumpState D) - { - DumpVar(x,D); - } - - private static void DumpNumber(lua_Number x, DumpState D) - { - DumpVar(x,D); - } - - static void DumpVector(object b, int n, DumpState D) - { - DumpInt(n,D); - DumpMem(b, n, D); - } - - private static void DumpString(TString s, DumpState D) - { - if (s==null || getstr(s)==null) - { - uint size=0; - DumpVar(size,D); - } - else - { - uint size=s.tsv.len+1; /* include trailing '\0' */ - DumpVar(size,D); - DumpBlock(getstr(s),size,D); - } - } - - private static void DumpCode(Proto f,DumpState D) - { - DumpVector(f.code, f.sizecode, D); - } - - private static void DumpConstants(Proto f, DumpState D) - { - int i,n=f.sizek; - DumpInt(n,D); - for (i=0; i(L); - AddTotalBytes(L, sizeCclosure(nelems)); - luaC_link(L, obj2gco(c), LUA_TFUNCTION); - c.c.isC = 1; - c.c.env = e; - c.c.nupvalues = cast_byte(nelems); - c.c.upvalue = new TValue[nelems]; - for (int i = 0; i < nelems; i++) - c.c.upvalue[i] = new lua_TValue(); - return c; - } - - - public static Closure luaF_newLclosure (lua_State L, int nelems, Table e) { - //Closure c = (Closure)luaM_malloc(L, sizeLclosure(nelems)); - Closure c = luaM_new(L); - AddTotalBytes(L, sizeLclosure(nelems)); - luaC_link(L, obj2gco(c), LUA_TFUNCTION); - c.l.isC = 0; - c.l.env = e; - c.l.nupvalues = cast_byte(nelems); - c.l.upvals = new UpVal[nelems]; - for (int i = 0; i < nelems; i++) - c.l.upvals[i] = new UpVal(); - while (nelems-- > 0) c.l.upvals[nelems] = null; - return c; - } - - - public static UpVal luaF_newupval (lua_State L) { - UpVal uv = luaM_new(L); - luaC_link(L, obj2gco(uv), LUA_TUPVAL); - uv.v = uv.u.value; - setnilvalue(uv.v); - return uv; - } - - public static UpVal luaF_findupval (lua_State L, StkId level) { - global_State g = G(L); - GCObjectRef pp = new OpenValRef(L); - UpVal p; - UpVal uv; - while (pp.get() != null && (p = ngcotouv(pp.get())).v >= level) { - lua_assert(p.v != p.u.value); - if (p.v == level) { /* found a corresponding upvalue? */ - if (isdead(g, obj2gco(p))) /* is it dead? */ - changewhite(obj2gco(p)); /* ressurect it */ - return p; - } - pp = new NextRef(p); - } - uv = luaM_new(L); /* not found: create a new one */ - uv.tt = LUA_TUPVAL; - uv.marked = luaC_white(g); - uv.v = level; /* current value lives in the stack */ - uv.next = pp.get(); /* chain it in the proper position */ - pp.set( obj2gco(uv) ); - uv.u.l.prev = g.uvhead; /* double link it in `uvhead' list */ - uv.u.l.next = g.uvhead.u.l.next; - uv.u.l.next.u.l.prev = uv; - g.uvhead.u.l.next = uv; - lua_assert(uv.u.l.next.u.l.prev == uv && uv.u.l.prev.u.l.next == uv); - return uv; - } - - - private static void unlinkupval (UpVal uv) { - lua_assert(uv.u.l.next.u.l.prev == uv && uv.u.l.prev.u.l.next == uv); - uv.u.l.next.u.l.prev = uv.u.l.prev; /* remove from `uvhead' list */ - uv.u.l.prev.u.l.next = uv.u.l.next; - } - - - public static void luaF_freeupval (lua_State L, UpVal uv) { - if (uv.v != uv.u.value) /* is it open? */ - unlinkupval(uv); /* remove from open list */ - luaM_free(L, uv); /* free upvalue */ - } - - - public static void luaF_close (lua_State L, StkId level) { - UpVal uv; - global_State g = G(L); - while (L.openupval != null && (uv = ngcotouv(L.openupval)).v >= level) { - GCObject o = obj2gco(uv); - lua_assert(!isblack(o) && uv.v != uv.u.value); - L.openupval = uv.next; /* remove from `open' list */ - if (isdead(g, o)) - luaF_freeupval(L, uv); /* free upvalue */ - else { - unlinkupval(uv); - setobj(L, uv.u.value, uv.v); - uv.v = uv.u.value; /* now current value lives here */ - luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ - } - } - } - - - public static Proto luaF_newproto (lua_State L) { - Proto f = luaM_new(L); - luaC_link(L, obj2gco(f), LUA_TPROTO); - f.k = null; - f.sizek = 0; - f.p = null; - f.sizep = 0; - f.code = null; - f.sizecode = 0; - f.sizelineinfo = 0; - f.sizeupvalues = 0; - f.nups = 0; - f.upvalues = null; - f.numparams = 0; - f.is_vararg = 0; - f.maxstacksize = 0; - f.lineinfo = null; - f.sizelocvars = 0; - f.locvars = null; - f.linedefined = 0; - f.lastlinedefined = 0; - f.source = null; - return f; - } - - public static void luaF_freeproto (lua_State L, Proto f) { - luaM_freearray(L, f.code); - luaM_freearray(L, f.p); - luaM_freearray(L, f.k); - luaM_freearray(L, f.lineinfo); - luaM_freearray(L, f.locvars); - luaM_freearray(L, f.upvalues); - luaM_free(L, f); - } - - // we have a gc, so nothing to do - public static void luaF_freeclosure (lua_State L, Closure c) { - int size = (c.c.isC != 0) ? sizeCclosure(c.c.nupvalues) : - sizeLclosure(c.l.nupvalues); - //luaM_freemem(L, c, size); - SubtractTotalBytes(L, size); - } - - - /* - ** Look for n-th local variable at line `line' in function `func'. - ** Returns null if not found. - */ - public static CharPtr luaF_getlocalname (Proto f, int local_number, int pc) { - int i; - for (i = 0; i(L); + AddTotalBytes(L, sizeCclosure(nelems)); + luaC_link(L, obj2gco(c), LUA_TFUNCTION); + c.c.isC = 1; + c.c.env = e; + c.c.nupvalues = cast_byte(nelems); + c.c.upvalue = new TValue[nelems]; + for (int i = 0; i < nelems; i++) + c.c.upvalue[i] = new lua_TValue(); + return c; + } + + + public static Closure luaF_newLclosure (lua_State L, int nelems, Table e) { + //Closure c = (Closure)luaM_malloc(L, sizeLclosure(nelems)); + Closure c = luaM_new(L); + AddTotalBytes(L, sizeLclosure(nelems)); + luaC_link(L, obj2gco(c), LUA_TFUNCTION); + c.l.isC = 0; + c.l.env = e; + c.l.nupvalues = cast_byte(nelems); + c.l.upvals = new UpVal[nelems]; + for (int i = 0; i < nelems; i++) + c.l.upvals[i] = new UpVal(); + while (nelems-- > 0) c.l.upvals[nelems] = null; + return c; + } + + + public static UpVal luaF_newupval (lua_State L) { + UpVal uv = luaM_new(L); + luaC_link(L, obj2gco(uv), LUA_TUPVAL); + uv.v = uv.u.value; + setnilvalue(uv.v); + return uv; + } + + public static UpVal luaF_findupval (lua_State L, StkId level) { + global_State g = G(L); + GCObjectRef pp = new OpenValRef(L); + UpVal p; + UpVal uv; + while (pp.get() != null && (p = ngcotouv(pp.get())).v >= level) { + lua_assert(p.v != p.u.value); + if (p.v == level) { /* found a corresponding upvalue? */ + if (isdead(g, obj2gco(p))) /* is it dead? */ + changewhite(obj2gco(p)); /* ressurect it */ + return p; + } + pp = new NextRef(p); + } + uv = luaM_new(L); /* not found: create a new one */ + uv.tt = LUA_TUPVAL; + uv.marked = luaC_white(g); + uv.v = level; /* current value lives in the stack */ + uv.next = pp.get(); /* chain it in the proper position */ + pp.set( obj2gco(uv) ); + uv.u.l.prev = g.uvhead; /* double link it in `uvhead' list */ + uv.u.l.next = g.uvhead.u.l.next; + uv.u.l.next.u.l.prev = uv; + g.uvhead.u.l.next = uv; + lua_assert(uv.u.l.next.u.l.prev == uv && uv.u.l.prev.u.l.next == uv); + return uv; + } + + + private static void unlinkupval (UpVal uv) { + lua_assert(uv.u.l.next.u.l.prev == uv && uv.u.l.prev.u.l.next == uv); + uv.u.l.next.u.l.prev = uv.u.l.prev; /* remove from `uvhead' list */ + uv.u.l.prev.u.l.next = uv.u.l.next; + } + + + public static void luaF_freeupval (lua_State L, UpVal uv) { + if (uv.v != uv.u.value) /* is it open? */ + unlinkupval(uv); /* remove from open list */ + luaM_free(L, uv); /* free upvalue */ + } + + + public static void luaF_close (lua_State L, StkId level) { + UpVal uv; + global_State g = G(L); + while (L.openupval != null && (uv = ngcotouv(L.openupval)).v >= level) { + GCObject o = obj2gco(uv); + lua_assert(!isblack(o) && uv.v != uv.u.value); + L.openupval = uv.next; /* remove from `open' list */ + if (isdead(g, o)) + luaF_freeupval(L, uv); /* free upvalue */ + else { + unlinkupval(uv); + setobj(L, uv.u.value, uv.v); + uv.v = uv.u.value; /* now current value lives here */ + luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */ + } + } + } + + + public static Proto luaF_newproto (lua_State L) { + Proto f = luaM_new(L); + luaC_link(L, obj2gco(f), LUA_TPROTO); + f.k = null; + f.sizek = 0; + f.p = null; + f.sizep = 0; + f.code = null; + f.sizecode = 0; + f.sizelineinfo = 0; + f.sizeupvalues = 0; + f.nups = 0; + f.upvalues = null; + f.numparams = 0; + f.is_vararg = 0; + f.maxstacksize = 0; + f.lineinfo = null; + f.sizelocvars = 0; + f.locvars = null; + f.linedefined = 0; + f.lastlinedefined = 0; + f.source = null; + return f; + } + + public static void luaF_freeproto (lua_State L, Proto f) { + luaM_freearray(L, f.code); + luaM_freearray(L, f.p); + luaM_freearray(L, f.k); + luaM_freearray(L, f.lineinfo); + luaM_freearray(L, f.locvars); + luaM_freearray(L, f.upvalues); + luaM_free(L, f); + } + + // we have a gc, so nothing to do + public static void luaF_freeclosure (lua_State L, Closure c) { + int size = (c.c.isC != 0) ? sizeCclosure(c.c.nupvalues) : + sizeLclosure(c.l.nupvalues); + //luaM_freemem(L, c, size); + SubtractTotalBytes(L, size); + } + + + /* + ** Look for n-th local variable at line `line' in function `func'. + ** Returns null if not found. + */ + public static CharPtr luaF_getlocalname (Proto f, int local_number, int pc) { + int i; + for (i = 0; i= G(L).GCthreshold) - luaC_step(L); - } - - - public static void luaC_barrier(lua_State L, object p, TValue v) { if (valiswhite(v) && isblack(obj2gco(p))) - luaC_barrierf(L,obj2gco(p),gcvalue(v)); } - - public static void luaC_barriert(lua_State L, Table t, TValue v) { if (valiswhite(v) && isblack(obj2gco(t))) - luaC_barrierback(L,t); } - - public static void luaC_objbarrier(lua_State L, object p, object o) - { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) - luaC_barrierf(L,obj2gco(p),obj2gco(o)); } - - public static void luaC_objbarriert(lua_State L, Table t, object o) - { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } - - [CLSCompliantAttribute(false)] - public const uint GCSTEPSIZE = 1024; - public const int GCSWEEPMAX = 40; - public const int GCSWEEPCOST = 10; - public const int GCFINALIZECOST = 100; - - - public static byte maskmarks = (byte)(~(bitmask(BLACKBIT)|WHITEBITS)); - - public static void makewhite(global_State g, GCObject x) - { - x.gch.marked = (byte)(x.gch.marked & maskmarks | luaC_white(g)); - } - - public static void white2gray(GCObject x) { reset2bits(ref x.gch.marked, WHITE0BIT, WHITE1BIT); } - public static void black2gray(GCObject x) { resetbit(ref x.gch.marked, BLACKBIT); } - - public static void stringmark(TString s) {reset2bits(ref s.tsv.marked, WHITE0BIT, WHITE1BIT);} - - public static bool isfinalized(Udata_uv u) { return testbit(u.marked, FINALIZEDBIT); } - public static void markfinalized(Udata_uv u) - { - lu_byte marked = u.marked; // can't pass properties in as ref - l_setbit(ref marked, FINALIZEDBIT); - u.marked = marked; - } - - - public static int KEYWEAK = bitmask(KEYWEAKBIT); - public static int VALUEWEAK = bitmask(VALUEWEAKBIT); - - public static void markvalue(global_State g, TValue o) - { - checkconsistency(o); - if (iscollectable(o) && iswhite(gcvalue(o))) - reallymarkobject(g,gcvalue(o)); - } - - public static void markobject(global_State g, object t) - { - if (iswhite(obj2gco(t))) - reallymarkobject(g, obj2gco(t)); - } - - public static void setthreshold(global_State g) - { - g.GCthreshold = (uint)((g.estimate / 100) * g.gcpause); - } - - private static void removeentry (Node n) { - lua_assert(ttisnil(gval(n))); - if (iscollectable(gkey(n))) - setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ - } - - - private static void reallymarkobject (global_State g, GCObject o) { - lua_assert(iswhite(o) && !isdead(g, o)); - white2gray(o); - switch (o.gch.tt) { - case LUA_TSTRING: { - return; - } - case LUA_TUSERDATA: { - Table mt = gco2u(o).metatable; - gray2black(o); /* udata are never gray */ - if (mt != null) markobject(g, mt); - markobject(g, gco2u(o).env); - return; - } - case LUA_TUPVAL: { - UpVal uv = gco2uv(o); - markvalue(g, uv.v); - if (uv.v == uv.u.value) /* closed? */ - gray2black(o); /* open upvalues are never black */ - return; - } - case LUA_TFUNCTION: { - gco2cl(o).c.gclist = g.gray; - g.gray = o; - break; - } - case LUA_TTABLE: { - gco2h(o).gclist = g.gray; - g.gray = o; - break; - } - case LUA_TTHREAD: { - gco2th(o).gclist = g.gray; - g.gray = o; - break; - } - case LUA_TPROTO: { - gco2p(o).gclist = g.gray; - g.gray = o; - break; - } - default: lua_assert(0); break; - } - } - - - private static void marktmu (global_State g) { - GCObject u = g.tmudata; - if (u != null) { - do { - u = u.gch.next; - makewhite(g, u); /* may be marked, if left from previous GC */ - reallymarkobject(g, u); - } while (u != g.tmudata); - } - } - - - /* move `dead' udata that need finalization to list `tmudata' */ - [CLSCompliantAttribute(false)] - public static uint luaC_separateudata (lua_State L, int all) { - global_State g = G(L); - uint deadmem = 0; - GCObjectRef p = new NextRef(g.mainthread); - GCObject curr; - while ((curr = p.get()) != null) { - if (!(iswhite(curr) || (all!=0)) || isfinalized(gco2u(curr))) - p = new NextRef(curr.gch); /* don't bother with them */ - else if (fasttm(L, gco2u(curr).metatable, TMS.TM_GC) == null) { - markfinalized(gco2u(curr)); /* don't need finalization */ - p = new NextRef(curr.gch); - } - else { /* must call its gc method */ - deadmem += (uint)sizeudata(gco2u(curr)); - markfinalized(gco2u(curr)); - p.set( curr.gch.next ); - /* link `curr' at the end of `tmudata' list */ - if (g.tmudata == null) /* list is empty? */ - g.tmudata = curr.gch.next = curr; /* creates a circular list */ - else { - curr.gch.next = g.tmudata.gch.next; - g.tmudata.gch.next = curr; - g.tmudata = curr; - } - } - } - return deadmem; - } - - - private static int traversetable (global_State g, Table h) { - int i; - int weakkey = 0; - int weakvalue = 0; - /*const*/ TValue mode; - if (h.metatable != null) - markobject(g, h.metatable); - mode = gfasttm(g, h.metatable, TMS.TM_MODE); - if ((mode != null) && ttisstring(mode)) { /* is there a weak mode? */ - weakkey = (strchr(svalue(mode), 'k') != null) ? 1 : 0 ; - weakvalue = (strchr(svalue(mode), 'v') != null) ? 1 : 0; - if ((weakkey!=0) || (weakvalue!=0)) { /* is really weak? */ - h.marked &= (byte)~(KEYWEAK | VALUEWEAK); /* clear bits */ - h.marked |= cast_byte((weakkey << KEYWEAKBIT) | - (weakvalue << VALUEWEAKBIT)); - h.gclist = g.weak; /* must be cleared after GC, ... */ - g.weak = obj2gco(h); /* ... so put in the appropriate list */ - } - } - if ((weakkey!=0) && (weakvalue!=0)) return 1; - if (weakvalue==0) { - i = h.sizearray; - while ((i--) != 0) - markvalue(g, h.array[i]); - } - i = sizenode(h); - while ((i--) != 0) { - Node n = gnode(h, i); - lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); - if (ttisnil(gval(n))) - removeentry(n); /* remove empty entries */ - else { - lua_assert(!ttisnil(gkey(n))); - if (weakkey==0) markvalue(g, gkey(n)); - if (weakvalue==0) markvalue(g, gval(n)); - } - } - return ((weakkey != 0) || (weakvalue != 0)) ? 1 : 0; - } - - - /* - ** All marks are conditional because a GC may happen while the - ** prototype is still being created - */ - private static void traverseproto (global_State g, Proto f) { - int i; - if (f.source != null) stringmark(f.source); - for (i=0; i LUAI_MAXCALLS) /* handling overflow? */ - return; /* do not touch the stacks */ - if (4*ci_used < L.size_ci && 2*BASIC_CI_SIZE < L.size_ci) - luaD_reallocCI(L, L.size_ci/2); /* still big enough... */ - //condhardstacktests(luaD_reallocCI(L, ci_used + 1)); - if (4*s_used < L.stacksize && - 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L.stacksize) - luaD_reallocstack(L, L.stacksize/2); /* still big enough... */ - //condhardstacktests(luaD_reallocstack(L, s_used)); - } - - - private static void traversestack (global_State g, lua_State l) { - StkId o, lim; - CallInfo ci; - markvalue(g, gt(l)); - lim = l.top; - for (ci = l.base_ci[0]; ci <= l.ci; CallInfo.inc(ref ci)) { - lua_assert(ci.top <= l.stack_last); - if (lim < ci.top) lim = ci.top; - } - for (o = l.stack[0]; o < l.top; StkId.inc(ref o)) - markvalue(g, o); - for (; o <= lim; StkId.inc(ref o)) - setnilvalue(o); - checkstacksizes(l, lim); - } - - - /* - ** traverse one gray object, turning it to black. - ** Returns `quantity' traversed. - */ - private static l_mem propagatemark (global_State g) { - GCObject o = g.gray; - lua_assert(isgray(o)); - gray2black(o); - switch (o.gch.tt) { - case LUA_TTABLE: { - Table h = gco2h(o); - g.gray = h.gclist; - if (traversetable(g, h) != 0) /* table is weak? */ - black2gray(o); /* keep it gray */ - return GetUnmanagedSize(typeof(Table)) + - GetUnmanagedSize(typeof(TValue)) * h.sizearray + - GetUnmanagedSize(typeof(Node)) * sizenode(h); - } - case LUA_TFUNCTION: { - Closure cl = gco2cl(o); - g.gray = cl.c.gclist; - traverseclosure(g, cl); - return (cl.c.isC != 0) ? sizeCclosure(cl.c.nupvalues) : - sizeLclosure(cl.l.nupvalues); - } - case LUA_TTHREAD: { - lua_State th = gco2th(o); - g.gray = th.gclist; - th.gclist = g.grayagain; - g.grayagain = o; - black2gray(o); - traversestack(g, th); - return GetUnmanagedSize(typeof(lua_State)) + - GetUnmanagedSize(typeof(TValue)) * th.stacksize + - GetUnmanagedSize(typeof(CallInfo)) * th.size_ci; - } - case LUA_TPROTO: { - Proto p = gco2p(o); - g.gray = p.gclist; - traverseproto(g, p); - return GetUnmanagedSize(typeof(Proto)) + - GetUnmanagedSize(typeof(Instruction)) * p.sizecode + - GetUnmanagedSize(typeof(Proto)) * p.sizep + - GetUnmanagedSize(typeof(TValue)) * p.sizek + - GetUnmanagedSize(typeof(int)) * p.sizelineinfo + - GetUnmanagedSize(typeof(LocVar)) * p.sizelocvars + - GetUnmanagedSize(typeof(TString)) * p.sizeupvalues; - } - default: lua_assert(0); return 0; - } - } - - - private static uint propagateall (global_State g) { - uint m = 0; - while (g.gray != null) m += (uint)propagatemark(g); - return m; - } - - - /* - ** The next function tells whether a key or value can be cleared from - ** a weak table. Non-collectable objects are never removed from weak - ** tables. Strings behave as `values', so are never removed too. for - ** other objects: if really collected, cannot keep them; for userdata - ** being finalized, keep them in keys, but not in values - */ - private static bool iscleared (TValue o, bool iskey) { - if (!iscollectable(o)) return false; - if (ttisstring(o)) { - stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ - return false; - } - return iswhite(gcvalue(o)) || - (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); - } - - - /* - ** clear collected entries from weaktables - */ - private static void cleartable (GCObject l) { - while (l != null) { - Table h = gco2h(l); - int i = h.sizearray; - lua_assert(testbit(h.marked, VALUEWEAKBIT) || - testbit(h.marked, KEYWEAKBIT)); - if (testbit(h.marked, VALUEWEAKBIT)) { - while (i--!= 0) { - TValue o = h.array[i]; - if (iscleared(o, false)) /* value was collected? */ - setnilvalue(o); /* remove value */ - } - } - i = sizenode(h); - while (i-- != 0) { - Node n = gnode(h, i); - if (!ttisnil(gval(n)) && /* non-empty entry? */ - (iscleared(key2tval(n), true) || iscleared(gval(n), false))) { - setnilvalue(gval(n)); /* remove value ... */ - removeentry(n); /* remove entry from Table */ - } - } - l = h.gclist; - } - } - - - private static void freeobj (lua_State L, GCObject o) { - switch (o.gch.tt) { - case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; - case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; - case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; - case LUA_TTABLE: luaH_free(L, gco2h(o)); break; - case LUA_TTHREAD: { - lua_assert(gco2th(o) != L && gco2th(o) != G(L).mainthread); - luaE_freethread(L, gco2th(o)); - break; - } - case LUA_TSTRING: { - G(L).strt.nuse--; - SubtractTotalBytes(L, sizestring(gco2ts(o))); - luaM_freemem(L, gco2ts(o)); - break; - } - case LUA_TUSERDATA: { - SubtractTotalBytes(L, sizeudata(gco2u(o))); - luaM_freemem(L, gco2u(o)); - break; - } - default: lua_assert(0); break; - } - } - - - - public static void sweepwholelist(lua_State L, GCObjectRef p) { sweeplist(L, p, MAX_LUMEM); } - - - private static GCObjectRef sweeplist (lua_State L, GCObjectRef p, lu_mem count) { - GCObject curr; - global_State g = G(L); - int deadmask = otherwhite(g); - while ((curr = p.get()) != null && count-- > 0) { - if (curr.gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ - sweepwholelist(L, new OpenValRef( gco2th(curr) )); - if (((curr.gch.marked ^ WHITEBITS) & deadmask) != 0) { /* not dead? */ - lua_assert(!isdead(g, curr) || testbit(curr.gch.marked, FIXEDBIT)); - makewhite(g, curr); /* make it white (for next cycle) */ - p = new NextRef(curr.gch); - } - else { /* must erase `curr' */ - lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); - p.set( curr.gch.next ); - if (curr == g.rootgc) /* is the first element of the list? */ - g.rootgc = curr.gch.next; /* adjust first */ - freeobj(L, curr); - } - } - return p; - } - - - private static void checkSizes (lua_State L) { - global_State g = G(L); - /* check size of string hash */ - if (g.strt.nuse < (lu_int32)(g.strt.size/4) && - g.strt.size > MINSTRTABSIZE*2) - luaS_resize(L, g.strt.size/2); /* table is too big */ - /* check size of buffer */ - if (luaZ_sizebuffer(g.buff) > LUA_MINBUFFER*2) { /* buffer too big? */ - uint newsize = luaZ_sizebuffer(g.buff) / 2; - luaZ_resizebuffer(L, g.buff, (int)newsize); - } - } - - - private static void GCTM (lua_State L) { - global_State g = G(L); - GCObject o = g.tmudata.gch.next; /* get first element */ - Udata udata = rawgco2u(o); - TValue tm; - /* remove udata from `tmudata' */ - if (o == g.tmudata) /* last element? */ - g.tmudata = null; - else - g.tmudata.gch.next = udata.uv.next; - udata.uv.next = g.mainthread.next; /* return it to `root' list */ - g.mainthread.next = o; - makewhite(g, o); - tm = fasttm(L, udata.uv.metatable, TMS.TM_GC); - if (tm != null) { - lu_byte oldah = L.allowhook; - lu_mem oldt = (lu_mem)g.GCthreshold; - L.allowhook = 0; /* stop debug hooks during GC tag method */ - g.GCthreshold = 2*g.totalbytes; /* avoid GC steps */ - setobj2s(L, L.top, tm); - setuvalue(L, L.top+1, udata); - L.top += 2; - luaD_call(L, L.top - 2, 0); - L.allowhook = oldah; /* restore hooks */ - g.GCthreshold = (uint)oldt; /* restore threshold */ - } - } - - - /* - ** Call all GC tag methods - */ - public static void luaC_callGCTM (lua_State L) { - while (G(L).tmudata != null) - GCTM(L); - } - - - public static void luaC_freeall (lua_State L) { - global_State g = G(L); - int i; - g.currentwhite = (byte)(WHITEBITS | bitmask(SFIXEDBIT)); /* mask to collect all elements */ - sweepwholelist(L, new RootGCRef(g)); - for (i = 0; i < g.strt.size; i++) /* free all string lists */ - sweepwholelist(L, new ArrayRef(g.strt.hash, i)); - } - - - private static void markmt (global_State g) { - int i; - for (i=0; i= g.strt.size) /* nothing more to sweep? */ - g.gcstate = GCSsweep; /* end sweep-string phase */ - lua_assert(old >= g.totalbytes); - g.estimate -= (uint)(old - g.totalbytes); - return GCSWEEPCOST; - } - case GCSsweep: { - lu_mem old = (lu_mem)g.totalbytes; - g.sweepgc = sweeplist(L, g.sweepgc, GCSWEEPMAX); - if (g.sweepgc.get() == null) { /* nothing more to sweep? */ - checkSizes(L); - g.gcstate = GCSfinalize; /* end sweep phase */ - } - lua_assert(old >= g.totalbytes); - g.estimate -= (uint)(old - g.totalbytes); - return GCSWEEPMAX*GCSWEEPCOST; - } - case GCSfinalize: { - if (g.tmudata != null) { - GCTM(L); - if (g.estimate > GCFINALIZECOST) - g.estimate -= GCFINALIZECOST; - return GCFINALIZECOST; - } - else { - g.gcstate = GCSpause; /* end collection */ - g.gcdept = 0; - return 0; - } - } - default: lua_assert(0); return 0; - } - } - - public static void luaC_step (lua_State L) { - global_State g = G(L); - l_mem lim = (l_mem)((GCSTEPSIZE / 100) * g.gcstepmul); - if (lim == 0) - lim = (l_mem)((MAX_LUMEM-1)/2); /* no limit */ - g.gcdept += g.totalbytes - g.GCthreshold; - do { - lim -= singlestep(L); - if (g.gcstate == GCSpause) - break; - } while (lim > 0); - if (g.gcstate != GCSpause) { - if (g.gcdept < GCSTEPSIZE) - g.GCthreshold = g.totalbytes + GCSTEPSIZE; /* - lim/g.gcstepmul;*/ - else { - g.gcdept -= GCSTEPSIZE; - g.GCthreshold = g.totalbytes; - } - } - else { - lua_assert(g.totalbytes >= g.estimate); - setthreshold(g); - } - } - - - public static void luaC_fullgc (lua_State L) { - global_State g = G(L); - if (g.gcstate <= GCSpropagate) { - /* reset sweep marks to sweep all elements (returning them to white) */ - g.sweepstrgc = 0; - g.sweepgc = new RootGCRef(g); - /* reset other collector lists */ - g.gray = null; - g.grayagain = null; - g.weak = null; - g.gcstate = GCSsweepstring; - } - lua_assert(g.gcstate != GCSpause && g.gcstate != GCSpropagate); - /* finish any pending sweep phase */ - while (g.gcstate != GCSfinalize) { - lua_assert(g.gcstate == GCSsweepstring || g.gcstate == GCSsweep); - singlestep(L); - } - markroot(L); - while (g.gcstate != GCSpause) { - singlestep(L); - } - setthreshold(g); - } - - - public static void luaC_barrierf (lua_State L, GCObject o, GCObject v) { - global_State g = G(L); - lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(g.gcstate != GCSfinalize && g.gcstate != GCSpause); - lua_assert(ttype(o.gch) != LUA_TTABLE); - /* must keep invariant? */ - if (g.gcstate == GCSpropagate) - reallymarkobject(g, v); /* restore invariant */ - else /* don't mind */ - makewhite(g, o); /* mark as white just to avoid other barriers */ - } - - - public static void luaC_barrierback(lua_State L, Table t) - { - global_State g = G(L); - GCObject o = obj2gco(t); - lua_assert(isblack(o) && !isdead(g, o)); - lua_assert(g.gcstate != GCSfinalize && g.gcstate != GCSpause); - black2gray(o); /* make table gray (again) */ - t.gclist = g.grayagain; - g.grayagain = o; - } - - - public static void luaC_link (lua_State L, GCObject o, lu_byte tt) { - global_State g = G(L); - o.gch.next = g.rootgc; - g.rootgc = o; - o.gch.marked = luaC_white(g); - o.gch.tt = tt; - } - - - public static void luaC_linkupval (lua_State L, UpVal uv) { - global_State g = G(L); - GCObject o = obj2gco(uv); - o.gch.next = g.rootgc; /* link upvalue into `rootgc' list */ - g.rootgc = o; - if (isgray(o)) { - if (g.gcstate == GCSpropagate) { - gray2black(o); /* closed upvalues need barrier */ - luaC_barrier(L, uv, uv.v); - } - else { /* sweep phase: sweep it (turning it into white) */ - makewhite(g, o); - lua_assert(g.gcstate != GCSfinalize && g.gcstate != GCSpause); - } - } - } - - } -} +/* +** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp $ +** Garbage Collector +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Diagnostics; + +namespace KopiLua +{ + using lu_int32 = System.UInt32; + using l_mem = System.Int32; + using lu_mem = System.UInt32; + using TValue = Lua.lua_TValue; + using StkId = Lua.lua_TValue; + using lu_byte = System.Byte; + using Instruction = System.UInt32; + + public partial class Lua + { + /* + ** Possible states of the Garbage Collector + */ + public const int GCSpause = 0; + public const int GCSpropagate = 1; + public const int GCSsweepstring = 2; + public const int GCSsweep = 3; + public const int GCSfinalize = 4; + + + /* + ** some userful bit tricks + */ + public static int resetbits(ref lu_byte x, int m) { x &= (lu_byte)~m; return x; } + public static int setbits(ref lu_byte x, int m) { x |= (lu_byte)m; return x; } + public static bool testbits(lu_byte x, int m) { return (x & (lu_byte)m) != 0; } + public static int bitmask(int b) {return 1<= G(L).GCthreshold) + luaC_step(L); + } + + + public static void luaC_barrier(lua_State L, object p, TValue v) { if (valiswhite(v) && isblack(obj2gco(p))) + luaC_barrierf(L,obj2gco(p),gcvalue(v)); } + + public static void luaC_barriert(lua_State L, Table t, TValue v) { if (valiswhite(v) && isblack(obj2gco(t))) + luaC_barrierback(L,t); } + + public static void luaC_objbarrier(lua_State L, object p, object o) + { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) + luaC_barrierf(L,obj2gco(p),obj2gco(o)); } + + public static void luaC_objbarriert(lua_State L, Table t, object o) + { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } + + [CLSCompliantAttribute(false)] + public const uint GCSTEPSIZE = 1024; + public const int GCSWEEPMAX = 40; + public const int GCSWEEPCOST = 10; + public const int GCFINALIZECOST = 100; + + + public static byte maskmarks = (byte)(~(bitmask(BLACKBIT)|WHITEBITS)); + + public static void makewhite(global_State g, GCObject x) + { + x.gch.marked = (byte)(x.gch.marked & maskmarks | luaC_white(g)); + } + + public static void white2gray(GCObject x) { reset2bits(ref x.gch.marked, WHITE0BIT, WHITE1BIT); } + public static void black2gray(GCObject x) { resetbit(ref x.gch.marked, BLACKBIT); } + + public static void stringmark(TString s) {reset2bits(ref s.tsv.marked, WHITE0BIT, WHITE1BIT);} + + public static bool isfinalized(Udata_uv u) { return testbit(u.marked, FINALIZEDBIT); } + public static void markfinalized(Udata_uv u) + { + lu_byte marked = u.marked; // can't pass properties in as ref + l_setbit(ref marked, FINALIZEDBIT); + u.marked = marked; + } + + + public static int KEYWEAK = bitmask(KEYWEAKBIT); + public static int VALUEWEAK = bitmask(VALUEWEAKBIT); + + public static void markvalue(global_State g, TValue o) + { + checkconsistency(o); + if (iscollectable(o) && iswhite(gcvalue(o))) + reallymarkobject(g,gcvalue(o)); + } + + public static void markobject(global_State g, object t) + { + if (iswhite(obj2gco(t))) + reallymarkobject(g, obj2gco(t)); + } + + public static void setthreshold(global_State g) + { + g.GCthreshold = (uint)((g.estimate / 100) * g.gcpause); + } + + private static void removeentry (Node n) { + lua_assert(ttisnil(gval(n))); + if (iscollectable(gkey(n))) + setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ + } + + + private static void reallymarkobject (global_State g, GCObject o) { + lua_assert(iswhite(o) && !isdead(g, o)); + white2gray(o); + switch (o.gch.tt) { + case LUA_TSTRING: { + return; + } + case LUA_TUSERDATA: { + Table mt = gco2u(o).metatable; + gray2black(o); /* udata are never gray */ + if (mt != null) markobject(g, mt); + markobject(g, gco2u(o).env); + return; + } + case LUA_TUPVAL: { + UpVal uv = gco2uv(o); + markvalue(g, uv.v); + if (uv.v == uv.u.value) /* closed? */ + gray2black(o); /* open upvalues are never black */ + return; + } + case LUA_TFUNCTION: { + gco2cl(o).c.gclist = g.gray; + g.gray = o; + break; + } + case LUA_TTABLE: { + gco2h(o).gclist = g.gray; + g.gray = o; + break; + } + case LUA_TTHREAD: { + gco2th(o).gclist = g.gray; + g.gray = o; + break; + } + case LUA_TPROTO: { + gco2p(o).gclist = g.gray; + g.gray = o; + break; + } + default: lua_assert(0); break; + } + } + + + private static void marktmu (global_State g) { + GCObject u = g.tmudata; + if (u != null) { + do { + u = u.gch.next; + makewhite(g, u); /* may be marked, if left from previous GC */ + reallymarkobject(g, u); + } while (u != g.tmudata); + } + } + + + /* move `dead' udata that need finalization to list `tmudata' */ + [CLSCompliantAttribute(false)] + public static uint luaC_separateudata (lua_State L, int all) { + global_State g = G(L); + uint deadmem = 0; + GCObjectRef p = new NextRef(g.mainthread); + GCObject curr; + while ((curr = p.get()) != null) { + if (!(iswhite(curr) || (all!=0)) || isfinalized(gco2u(curr))) + p = new NextRef(curr.gch); /* don't bother with them */ + else if (fasttm(L, gco2u(curr).metatable, TMS.TM_GC) == null) { + markfinalized(gco2u(curr)); /* don't need finalization */ + p = new NextRef(curr.gch); + } + else { /* must call its gc method */ + deadmem += (uint)sizeudata(gco2u(curr)); + markfinalized(gco2u(curr)); + p.set( curr.gch.next ); + /* link `curr' at the end of `tmudata' list */ + if (g.tmudata == null) /* list is empty? */ + g.tmudata = curr.gch.next = curr; /* creates a circular list */ + else { + curr.gch.next = g.tmudata.gch.next; + g.tmudata.gch.next = curr; + g.tmudata = curr; + } + } + } + return deadmem; + } + + + private static int traversetable (global_State g, Table h) { + int i; + int weakkey = 0; + int weakvalue = 0; + /*const*/ TValue mode; + if (h.metatable != null) + markobject(g, h.metatable); + mode = gfasttm(g, h.metatable, TMS.TM_MODE); + if ((mode != null) && ttisstring(mode)) { /* is there a weak mode? */ + weakkey = (strchr(svalue(mode), 'k') != null) ? 1 : 0 ; + weakvalue = (strchr(svalue(mode), 'v') != null) ? 1 : 0; + if ((weakkey!=0) || (weakvalue!=0)) { /* is really weak? */ + h.marked &= (byte)~(KEYWEAK | VALUEWEAK); /* clear bits */ + h.marked |= cast_byte((weakkey << KEYWEAKBIT) | + (weakvalue << VALUEWEAKBIT)); + h.gclist = g.weak; /* must be cleared after GC, ... */ + g.weak = obj2gco(h); /* ... so put in the appropriate list */ + } + } + if ((weakkey!=0) && (weakvalue!=0)) return 1; + if (weakvalue==0) { + i = h.sizearray; + while ((i--) != 0) + markvalue(g, h.array[i]); + } + i = sizenode(h); + while ((i--) != 0) { + Node n = gnode(h, i); + lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); + if (ttisnil(gval(n))) + removeentry(n); /* remove empty entries */ + else { + lua_assert(!ttisnil(gkey(n))); + if (weakkey==0) markvalue(g, gkey(n)); + if (weakvalue==0) markvalue(g, gval(n)); + } + } + return ((weakkey != 0) || (weakvalue != 0)) ? 1 : 0; + } + + + /* + ** All marks are conditional because a GC may happen while the + ** prototype is still being created + */ + private static void traverseproto (global_State g, Proto f) { + int i; + if (f.source != null) stringmark(f.source); + for (i=0; i LUAI_MAXCALLS) /* handling overflow? */ + return; /* do not touch the stacks */ + if (4*ci_used < L.size_ci && 2*BASIC_CI_SIZE < L.size_ci) + luaD_reallocCI(L, L.size_ci/2); /* still big enough... */ + //condhardstacktests(luaD_reallocCI(L, ci_used + 1)); + if (4*s_used < L.stacksize && + 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L.stacksize) + luaD_reallocstack(L, L.stacksize/2); /* still big enough... */ + //condhardstacktests(luaD_reallocstack(L, s_used)); + } + + + private static void traversestack (global_State g, lua_State l) { + StkId o, lim; + CallInfo ci; + markvalue(g, gt(l)); + lim = l.top; + for (ci = l.base_ci[0]; ci <= l.ci; CallInfo.inc(ref ci)) { + lua_assert(ci.top <= l.stack_last); + if (lim < ci.top) lim = ci.top; + } + for (o = l.stack[0]; o < l.top; StkId.inc(ref o)) + markvalue(g, o); + for (; o <= lim; StkId.inc(ref o)) + setnilvalue(o); + checkstacksizes(l, lim); + } + + + /* + ** traverse one gray object, turning it to black. + ** Returns `quantity' traversed. + */ + private static l_mem propagatemark (global_State g) { + GCObject o = g.gray; + lua_assert(isgray(o)); + gray2black(o); + switch (o.gch.tt) { + case LUA_TTABLE: { + Table h = gco2h(o); + g.gray = h.gclist; + if (traversetable(g, h) != 0) /* table is weak? */ + black2gray(o); /* keep it gray */ + return GetUnmanagedSize(typeof(Table)) + + GetUnmanagedSize(typeof(TValue)) * h.sizearray + + GetUnmanagedSize(typeof(Node)) * sizenode(h); + } + case LUA_TFUNCTION: { + Closure cl = gco2cl(o); + g.gray = cl.c.gclist; + traverseclosure(g, cl); + return (cl.c.isC != 0) ? sizeCclosure(cl.c.nupvalues) : + sizeLclosure(cl.l.nupvalues); + } + case LUA_TTHREAD: { + lua_State th = gco2th(o); + g.gray = th.gclist; + th.gclist = g.grayagain; + g.grayagain = o; + black2gray(o); + traversestack(g, th); + return GetUnmanagedSize(typeof(lua_State)) + + GetUnmanagedSize(typeof(TValue)) * th.stacksize + + GetUnmanagedSize(typeof(CallInfo)) * th.size_ci; + } + case LUA_TPROTO: { + Proto p = gco2p(o); + g.gray = p.gclist; + traverseproto(g, p); + return GetUnmanagedSize(typeof(Proto)) + + GetUnmanagedSize(typeof(Instruction)) * p.sizecode + + GetUnmanagedSize(typeof(Proto)) * p.sizep + + GetUnmanagedSize(typeof(TValue)) * p.sizek + + GetUnmanagedSize(typeof(int)) * p.sizelineinfo + + GetUnmanagedSize(typeof(LocVar)) * p.sizelocvars + + GetUnmanagedSize(typeof(TString)) * p.sizeupvalues; + } + default: lua_assert(0); return 0; + } + } + + + private static uint propagateall (global_State g) { + uint m = 0; + while (g.gray != null) m += (uint)propagatemark(g); + return m; + } + + + /* + ** The next function tells whether a key or value can be cleared from + ** a weak table. Non-collectable objects are never removed from weak + ** tables. Strings behave as `values', so are never removed too. for + ** other objects: if really collected, cannot keep them; for userdata + ** being finalized, keep them in keys, but not in values + */ + private static bool iscleared (TValue o, bool iskey) { + if (!iscollectable(o)) return false; + if (ttisstring(o)) { + stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ + return false; + } + return iswhite(gcvalue(o)) || + (ttisuserdata(o) && (!iskey && isfinalized(uvalue(o)))); + } + + + /* + ** clear collected entries from weaktables + */ + private static void cleartable (GCObject l) { + while (l != null) { + Table h = gco2h(l); + int i = h.sizearray; + lua_assert(testbit(h.marked, VALUEWEAKBIT) || + testbit(h.marked, KEYWEAKBIT)); + if (testbit(h.marked, VALUEWEAKBIT)) { + while (i--!= 0) { + TValue o = h.array[i]; + if (iscleared(o, false)) /* value was collected? */ + setnilvalue(o); /* remove value */ + } + } + i = sizenode(h); + while (i-- != 0) { + Node n = gnode(h, i); + if (!ttisnil(gval(n)) && /* non-empty entry? */ + (iscleared(key2tval(n), true) || iscleared(gval(n), false))) { + setnilvalue(gval(n)); /* remove value ... */ + removeentry(n); /* remove entry from Table */ + } + } + l = h.gclist; + } + } + + + private static void freeobj (lua_State L, GCObject o) { + switch (o.gch.tt) { + case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; + case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; + case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; + case LUA_TTABLE: luaH_free(L, gco2h(o)); break; + case LUA_TTHREAD: { + lua_assert(gco2th(o) != L && gco2th(o) != G(L).mainthread); + luaE_freethread(L, gco2th(o)); + break; + } + case LUA_TSTRING: { + G(L).strt.nuse--; + SubtractTotalBytes(L, sizestring(gco2ts(o))); + luaM_freemem(L, gco2ts(o)); + break; + } + case LUA_TUSERDATA: { + SubtractTotalBytes(L, sizeudata(gco2u(o))); + luaM_freemem(L, gco2u(o)); + break; + } + default: lua_assert(0); break; + } + } + + + + public static void sweepwholelist(lua_State L, GCObjectRef p) { sweeplist(L, p, MAX_LUMEM); } + + + private static GCObjectRef sweeplist (lua_State L, GCObjectRef p, lu_mem count) { + GCObject curr; + global_State g = G(L); + int deadmask = otherwhite(g); + while ((curr = p.get()) != null && count-- > 0) { + if (curr.gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ + sweepwholelist(L, new OpenValRef( gco2th(curr) )); + if (((curr.gch.marked ^ WHITEBITS) & deadmask) != 0) { /* not dead? */ + lua_assert(!isdead(g, curr) || testbit(curr.gch.marked, FIXEDBIT)); + makewhite(g, curr); /* make it white (for next cycle) */ + p = new NextRef(curr.gch); + } + else { /* must erase `curr' */ + lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); + p.set( curr.gch.next ); + if (curr == g.rootgc) /* is the first element of the list? */ + g.rootgc = curr.gch.next; /* adjust first */ + freeobj(L, curr); + } + } + return p; + } + + + private static void checkSizes (lua_State L) { + global_State g = G(L); + /* check size of string hash */ + if (g.strt.nuse < (lu_int32)(g.strt.size/4) && + g.strt.size > MINSTRTABSIZE*2) + luaS_resize(L, g.strt.size/2); /* table is too big */ + /* check size of buffer */ + if (luaZ_sizebuffer(g.buff) > LUA_MINBUFFER*2) { /* buffer too big? */ + uint newsize = luaZ_sizebuffer(g.buff) / 2; + luaZ_resizebuffer(L, g.buff, (int)newsize); + } + } + + + private static void GCTM (lua_State L) { + global_State g = G(L); + GCObject o = g.tmudata.gch.next; /* get first element */ + Udata udata = rawgco2u(o); + TValue tm; + /* remove udata from `tmudata' */ + if (o == g.tmudata) /* last element? */ + g.tmudata = null; + else + g.tmudata.gch.next = udata.uv.next; + udata.uv.next = g.mainthread.next; /* return it to `root' list */ + g.mainthread.next = o; + makewhite(g, o); + tm = fasttm(L, udata.uv.metatable, TMS.TM_GC); + if (tm != null) { + lu_byte oldah = L.allowhook; + lu_mem oldt = (lu_mem)g.GCthreshold; + L.allowhook = 0; /* stop debug hooks during GC tag method */ + g.GCthreshold = 2*g.totalbytes; /* avoid GC steps */ + setobj2s(L, L.top, tm); + setuvalue(L, L.top+1, udata); + L.top += 2; + luaD_call(L, L.top - 2, 0); + L.allowhook = oldah; /* restore hooks */ + g.GCthreshold = (uint)oldt; /* restore threshold */ + } + } + + + /* + ** Call all GC tag methods + */ + public static void luaC_callGCTM (lua_State L) { + while (G(L).tmudata != null) + GCTM(L); + } + + + public static void luaC_freeall (lua_State L) { + global_State g = G(L); + int i; + g.currentwhite = (byte)(WHITEBITS | bitmask(SFIXEDBIT)); /* mask to collect all elements */ + sweepwholelist(L, new RootGCRef(g)); + for (i = 0; i < g.strt.size; i++) /* free all string lists */ + sweepwholelist(L, new ArrayRef(g.strt.hash, i)); + } + + + private static void markmt (global_State g) { + int i; + for (i=0; i= g.strt.size) /* nothing more to sweep? */ + g.gcstate = GCSsweep; /* end sweep-string phase */ + lua_assert(old >= g.totalbytes); + g.estimate -= (uint)(old - g.totalbytes); + return GCSWEEPCOST; + } + case GCSsweep: { + lu_mem old = (lu_mem)g.totalbytes; + g.sweepgc = sweeplist(L, g.sweepgc, GCSWEEPMAX); + if (g.sweepgc.get() == null) { /* nothing more to sweep? */ + checkSizes(L); + g.gcstate = GCSfinalize; /* end sweep phase */ + } + lua_assert(old >= g.totalbytes); + g.estimate -= (uint)(old - g.totalbytes); + return GCSWEEPMAX*GCSWEEPCOST; + } + case GCSfinalize: { + if (g.tmudata != null) { + GCTM(L); + if (g.estimate > GCFINALIZECOST) + g.estimate -= GCFINALIZECOST; + return GCFINALIZECOST; + } + else { + g.gcstate = GCSpause; /* end collection */ + g.gcdept = 0; + return 0; + } + } + default: lua_assert(0); return 0; + } + } + + public static void luaC_step (lua_State L) { + global_State g = G(L); + l_mem lim = (l_mem)((GCSTEPSIZE / 100) * g.gcstepmul); + if (lim == 0) + lim = (l_mem)((MAX_LUMEM-1)/2); /* no limit */ + g.gcdept += g.totalbytes - g.GCthreshold; + do { + lim -= singlestep(L); + if (g.gcstate == GCSpause) + break; + } while (lim > 0); + if (g.gcstate != GCSpause) { + if (g.gcdept < GCSTEPSIZE) + g.GCthreshold = g.totalbytes + GCSTEPSIZE; /* - lim/g.gcstepmul;*/ + else { + g.gcdept -= GCSTEPSIZE; + g.GCthreshold = g.totalbytes; + } + } + else { + lua_assert(g.totalbytes >= g.estimate); + setthreshold(g); + } + } + + + public static void luaC_fullgc (lua_State L) { + global_State g = G(L); + if (g.gcstate <= GCSpropagate) { + /* reset sweep marks to sweep all elements (returning them to white) */ + g.sweepstrgc = 0; + g.sweepgc = new RootGCRef(g); + /* reset other collector lists */ + g.gray = null; + g.grayagain = null; + g.weak = null; + g.gcstate = GCSsweepstring; + } + lua_assert(g.gcstate != GCSpause && g.gcstate != GCSpropagate); + /* finish any pending sweep phase */ + while (g.gcstate != GCSfinalize) { + lua_assert(g.gcstate == GCSsweepstring || g.gcstate == GCSsweep); + singlestep(L); + } + markroot(L); + while (g.gcstate != GCSpause) { + singlestep(L); + } + setthreshold(g); + } + + + public static void luaC_barrierf (lua_State L, GCObject o, GCObject v) { + global_State g = G(L); + lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); + lua_assert(g.gcstate != GCSfinalize && g.gcstate != GCSpause); + lua_assert(ttype(o.gch) != LUA_TTABLE); + /* must keep invariant? */ + if (g.gcstate == GCSpropagate) + reallymarkobject(g, v); /* restore invariant */ + else /* don't mind */ + makewhite(g, o); /* mark as white just to avoid other barriers */ + } + + + public static void luaC_barrierback(lua_State L, Table t) + { + global_State g = G(L); + GCObject o = obj2gco(t); + lua_assert(isblack(o) && !isdead(g, o)); + lua_assert(g.gcstate != GCSfinalize && g.gcstate != GCSpause); + black2gray(o); /* make table gray (again) */ + t.gclist = g.grayagain; + g.grayagain = o; + } + + + public static void luaC_link (lua_State L, GCObject o, lu_byte tt) { + global_State g = G(L); + o.gch.next = g.rootgc; + g.rootgc = o; + o.gch.marked = luaC_white(g); + o.gch.tt = tt; + } + + + public static void luaC_linkupval (lua_State L, UpVal uv) { + global_State g = G(L); + GCObject o = obj2gco(uv); + o.gch.next = g.rootgc; /* link upvalue into `rootgc' list */ + g.rootgc = o; + if (isgray(o)) { + if (g.gcstate == GCSpropagate) { + gray2black(o); /* closed upvalues need barrier */ + luaC_barrier(L, uv, uv.v); + } + else { /* sweep phase: sweep it (turning it into white) */ + makewhite(g, o); + lua_assert(g.gcstate != GCSfinalize && g.gcstate != GCSpause); + } + } + } + + } +} diff --git a/Core/KopiLua/linit.cs b/Core/KopiLua/linit.cs index b3c903337737e66878e793e9ff83f24cc20dacc6..fc7b3ab30a8ae964175671b383eaad62c284d97e 100644 --- a/Core/KopiLua/linit.cs +++ b/Core/KopiLua/linit.cs @@ -1,39 +1,39 @@ -/* -** $Id: linit.c,v 1.14.1.1 2007/12/27 13:02:25 roberto Exp $ -** Initialization of libraries for lua.c -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace KopiLua -{ - public partial class Lua - { - private readonly static luaL_Reg[] lualibs = { - new luaL_Reg("", luaopen_base), - new luaL_Reg(LUA_LOADLIBNAME, luaopen_package), - new luaL_Reg(LUA_TABLIBNAME, luaopen_table), - new luaL_Reg(LUA_IOLIBNAME, luaopen_io), - new luaL_Reg(LUA_OSLIBNAME, luaopen_os), - new luaL_Reg(LUA_STRLIBNAME, luaopen_string), - new luaL_Reg(LUA_MATHLIBNAME, luaopen_math), - new luaL_Reg(LUA_DBLIBNAME, luaopen_debug), - new luaL_Reg(null, null) - }; - - - public static void luaL_openlibs (lua_State L) { - for (int i=0; i 0) ? 1 : 0; /* check whether read something */ - } - l = (uint)strlen(p); - if (l == 0 || p[l-1] != '\n') - luaL_addsize(b, (int)l); - else { - luaL_addsize(b, (int)(l - 1)); /* do not include `eol' */ - luaL_pushresult(b); /* close buffer */ - return 1; /* read at least an `eol' */ - } - } - } - - - private static int read_chars (lua_State L, Stream f, uint n) { - uint rlen; /* how much to read */ - uint nr; /* number of chars actually read */ - luaL_Buffer b = new luaL_Buffer(); - luaL_buffinit(L, b); - rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ - do { - CharPtr p = luaL_prepbuffer(b); - if (rlen > n) rlen = n; /* cannot read more than asked */ - nr = (uint)fread(p, GetUnmanagedSize(typeof(char)), (int)rlen, f); - luaL_addsize(b, (int)nr); - n -= nr; /* still have to read `n' chars */ - } while (n > 0 && nr == rlen); /* until end of count or eof */ - luaL_pushresult(b); /* close buffer */ - return (n == 0 || lua_objlen(L, -1) > 0) ? 1 : 0; - } - - - private static int g_read (lua_State L, Stream f, int first) { - int nargs = lua_gettop(L) - 1; - int success; - int n; - clearerr(f); - if (nargs == 0) { /* no arguments? */ - success = read_line(L, f); - n = first+1; /* to return 1 result */ - } - else { /* ensure stack space for all results and for auxlib's buffer */ - luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); - success = 1; - for (n = first; (nargs-- != 0) && (success!=0); n++) { - if (lua_type(L, n) == LUA_TNUMBER) { - uint l = (uint)lua_tointeger(L, n); - success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); - } - else { - CharPtr p = lua_tostring(L, n); - luaL_argcheck(L, (p!=null) && (p[0] == '*'), n, "invalid option"); - switch (p[1]) { - case 'n': /* number */ - success = read_number(L, f); - break; - case 'l': /* line */ - success = read_line(L, f); - break; - case 'a': /* file */ - read_chars(L, f, ~((uint)0)); /* read MAX_uint chars */ - success = 1; /* always success */ - break; - default: - return luaL_argerror(L, n, "invalid format"); - } - } - } - } - if (ferror(f)!=0) - return pushresult(L, 0, null); - if (success==0) { - lua_pop(L, 1); /* remove last result */ - lua_pushnil(L); /* push nil instead */ - } - return n - first; - } - - - private static int io_read (lua_State L) { - return g_read(L, getiofile(L, IO_INPUT), 1); - } - - - private static int f_read (lua_State L) { - return g_read(L, tofile(L), 2); - } - - - private static int io_readline (lua_State L) { - Stream f = (lua_touserdata(L, lua_upvalueindex(1)) as FilePtr).file; - int sucess; - if (f == null) /* file is already closed? */ - luaL_error(L, "file is already closed"); - sucess = read_line(L, f); - if (ferror(f)!=0) - return luaL_error(L, "%s", strerror(errno())); - if (sucess != 0) return 1; - else { /* EOF */ - if (lua_toboolean(L, lua_upvalueindex(2)) != 0) { /* generator created file? */ - lua_settop(L, 0); - lua_pushvalue(L, lua_upvalueindex(1)); - aux_close(L); /* close it */ - } - return 0; - } - } - - /* }====================================================== */ - - - private static int g_write (lua_State L, Stream f, int arg) { - int nargs = lua_gettop(L) - 1; - int status = 1; - for (; (nargs--) != 0; arg++) { - if (lua_type(L, arg) == LUA_TNUMBER) { - /* optimization: could be done exactly as for strings */ - status = ((status!=0) && - (fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0)) ? 1 : 0; - } - else { - uint l; - CharPtr s = luaL_checklstring(L, arg, out l); - status = ((status!=0) && (fwrite(s, GetUnmanagedSize(typeof(char)), (int)l, f) == l)) ? 1 : 0; - } - } - return pushresult(L, status, null); - } - - - private static int io_write (lua_State L) { - return g_write(L, getiofile(L, IO_OUTPUT), 1); - } - - - private static int f_write (lua_State L) { - return g_write(L, tofile(L), 2); - } - - - - private static int f_seek (lua_State L) { - int[] mode = { SEEK_SET, SEEK_CUR, SEEK_END }; - CharPtr[] modenames = { "set", "cur", "end", null }; - Stream f = tofile(L); - int op = luaL_checkoption(L, 2, "cur", modenames); - long offset = luaL_optlong(L, 3, 0); - op = fseek(f, offset, mode[op]); - if (op != 0) - return pushresult(L, 0, null); /* error */ - else { - lua_pushinteger(L, ftell(f)); - return 1; - } - } - - private static int f_setvbuf (lua_State L) { - CharPtr[] modenames = { "no", "full", "line", null }; - int[] mode = { _IONBF, _IOFBF, _IOLBF }; - Stream f = tofile(L); - int op = luaL_checkoption(L, 2, null, modenames); - lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); - int res = setvbuf(f, null, mode[op], (uint)sz); - return pushresult(L, (res == 0) ? 1 : 0, null); - } - - - - private static int io_flush (lua_State L) { - int result = 1; - try {getiofile(L, IO_OUTPUT).Flush();} catch {result = 0;} - return pushresult(L, result, null); - } - - - private static int f_flush (lua_State L) { - int result = 1; - try {tofile(L).Flush();} catch {result = 0;} - return pushresult(L, result, null); - } - - - private readonly static luaL_Reg[] iolib = { - new luaL_Reg("close", io_close), - new luaL_Reg("flush", io_flush), - new luaL_Reg("input", io_input), - new luaL_Reg("lines", io_lines), - new luaL_Reg("open", io_open), - new luaL_Reg("output", io_output), - new luaL_Reg("popen", io_popen), - new luaL_Reg("read", io_read), - new luaL_Reg("tmpfile", io_tmpfile), - new luaL_Reg("type", io_type), - new luaL_Reg("write", io_write), - new luaL_Reg(null, null) - }; - - - private readonly static luaL_Reg[] flib = { - new luaL_Reg("close", io_close), - new luaL_Reg("flush", f_flush), - new luaL_Reg("lines", f_lines), - new luaL_Reg("read", f_read), - new luaL_Reg("seek", f_seek), - new luaL_Reg("setvbuf", f_setvbuf), - new luaL_Reg("write", f_write), - new luaL_Reg("__gc", io_gc), - new luaL_Reg("__tostring", io_tostring), - new luaL_Reg(null, null) - }; - - - private static void createmeta (lua_State L) { - luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file files */ - lua_pushvalue(L, -1); /* push metatable */ - lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ - luaL_register(L, null, flib); /* file methods */ - } - - - private static void createstdfile (lua_State L, Stream f, int k, CharPtr fname) { - newfile(L).file = f; - if (k > 0) { - lua_pushvalue(L, -1); - lua_rawseti(L, LUA_ENVIRONINDEX, k); - } - lua_pushvalue(L, -2); /* copy environment */ - lua_setfenv(L, -2); /* set it */ - lua_setfield(L, -3, fname); - } - - - private static void newfenv (lua_State L, lua_CFunction cls) { - lua_createtable(L, 0, 1); - lua_pushcfunction(L, cls); - lua_setfield(L, -2, "__close"); - } - - - public static int luaopen_io (lua_State L) { - createmeta(L); - /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ - newfenv(L, io_fclose); - lua_replace(L, LUA_ENVIRONINDEX); - /* open library */ - luaL_register(L, LUA_IOLIBNAME, iolib); - /* create (and set) default files */ - newfenv(L, io_noclose); /* close function for default files */ - createstdfile(L, stdin, IO_INPUT, "stdin"); - createstdfile(L, stdout, IO_OUTPUT, "stdout"); - createstdfile(L, stderr, 0, "stderr"); - lua_pop(L, 1); /* pop environment for default files */ - lua_getfield(L, -1, "popen"); - newfenv(L, io_pclose); /* create environment for 'popen' */ - lua_setfenv(L, -2); /* set fenv for 'popen' */ - lua_pop(L, 1); /* pop 'popen' */ - return 1; - } - - } -} +/* +** $Id: liolib.c,v 2.73.1.3 2008/01/18 17:47:43 roberto Exp $ +** Standard I/O (and system) library +** See Copyright Notice in lua.h +*/ + +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace KopiLua +{ + using lua_Number = System.Double; + using lua_Integer = System.Int32; + + public class FilePtr + { + public Stream file; + } + + public partial class Lua + { + public const int IO_INPUT = 1; + public const int IO_OUTPUT = 2; + + private static readonly string[] fnames = { "input", "output" }; + + + private static int pushresult (lua_State L, int i, CharPtr filename) { + int en = errno(); /* calls to Lua API may change this value */ + if (i != 0) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + if (filename != null) + lua_pushfstring(L, "%s: %s", filename, strerror(en)); + else + lua_pushfstring(L, "%s", strerror(en)); + lua_pushinteger(L, en); + return 3; + } + } + + + private static void fileerror (lua_State L, int arg, CharPtr filename) { + lua_pushfstring(L, "%s: %s", filename, strerror(errno())); + luaL_argerror(L, arg, lua_tostring(L, -1)); + } + + + public static FilePtr tofilep(lua_State L) { return (FilePtr)luaL_checkudata(L, 1, LUA_FILEHANDLE); } + + + private static int io_type (lua_State L) { + object ud; + luaL_checkany(L, 1); + ud = lua_touserdata(L, 1); + lua_getfield(L, LUA_REGISTRYINDEX, LUA_FILEHANDLE); + if (ud == null || (lua_getmetatable(L, 1)==0) || (lua_rawequal(L, -2, -1)==0)) + lua_pushnil(L); /* not a file */ + else if ( (ud as FilePtr).file == null) + lua_pushliteral(L, "closed file"); + else + lua_pushliteral(L, "file"); + return 1; + } + + + private static Stream tofile (lua_State L) { + FilePtr f = tofilep(L); + if (f.file == null) + luaL_error(L, "attempt to use a closed file"); + return f.file; + } + + + + /* + ** When creating file files, always creates a `closed' file file + ** before opening the actual file; so, if there is a memory error, the + ** file is not left opened. + */ + private static FilePtr newfile (lua_State L) { + + FilePtr pf = (FilePtr)lua_newuserdata(L, typeof(FilePtr)); + pf.file = null; /* file file is currently `closed' */ + luaL_getmetatable(L, LUA_FILEHANDLE); + lua_setmetatable(L, -2); + return pf; + } + + + /* + ** function to (not) close the standard files stdin, stdout, and stderr + */ + private static int io_noclose (lua_State L) { + lua_pushnil(L); + lua_pushliteral(L, "cannot close standard file"); + return 2; + } + + + /* + ** function to close 'popen' files + */ + private static int io_pclose (lua_State L) { + FilePtr p = tofilep(L); + int ok = (lua_pclose(L, p.file) == 0) ? 1 : 0; + p.file = null; + return pushresult(L, ok, null); + } + + + /* + ** function to close regular files + */ + private static int io_fclose (lua_State L) { + FilePtr p = tofilep(L); + int ok = (fclose(p.file) == 0) ? 1 : 0; + p.file = null; + return pushresult(L, ok, null); + } + + + private static int aux_close (lua_State L) { + lua_getfenv(L, 1); + lua_getfield(L, -1, "__close"); + return (lua_tocfunction(L, -1))(L); + } + + + private static int io_close (lua_State L) { + if (lua_isnone(L, 1)) + lua_rawgeti(L, LUA_ENVIRONINDEX, IO_OUTPUT); + tofile(L); /* make sure argument is a file */ + return aux_close(L); + } + + + private static int io_gc (lua_State L) { + Stream f = tofilep(L).file; + /* ignore closed files */ + if (f != null) + aux_close(L); + return 0; + } + + + private static int io_tostring (lua_State L) { + Stream f = tofilep(L).file; + if (f == null) + lua_pushliteral(L, "file (closed)"); + else + lua_pushfstring(L, "file (%p)", f); + return 1; + } + + + private static int io_open (lua_State L) { + CharPtr filename = luaL_checkstring(L, 1); + CharPtr mode = luaL_optstring(L, 2, "r"); + FilePtr pf = newfile(L); + pf.file = fopen(filename, mode); + return (pf.file == null) ? pushresult(L, 0, filename) : 1; + } + + + /* + ** this function has a separated environment, which defines the + ** correct __close for 'popen' files + */ + private static int io_popen (lua_State L) { + CharPtr filename = luaL_checkstring(L, 1); + CharPtr mode = luaL_optstring(L, 2, "r"); + FilePtr pf = newfile(L); + pf.file = lua_popen(L, filename, mode); + return (pf.file == null) ? pushresult(L, 0, filename) : 1; + } + + + private static int io_tmpfile (lua_State L) { + FilePtr pf = newfile(L); +#if XBOX + luaL_error(L, "io_tmpfile not supported on Xbox360"); +#else + pf.file = tmpfile(); +#endif + return (pf.file == null) ? pushresult(L, 0, null) : 1; + } + + + private static Stream getiofile (lua_State L, int findex) { + Stream f; + lua_rawgeti(L, LUA_ENVIRONINDEX, findex); + f = (lua_touserdata(L, -1) as FilePtr).file; + if (f == null) + luaL_error(L, "standard %s file is closed", fnames[findex - 1]); + return f; + } + + + private static int g_iofile (lua_State L, int f, CharPtr mode) { + if (!lua_isnoneornil(L, 1)) { + CharPtr filename = lua_tostring(L, 1); + if (filename != null) { + FilePtr pf = newfile(L); + pf.file = fopen(filename, mode); + if (pf.file == null) + fileerror(L, 1, filename); + } + else { + tofile(L); /* check that it's a valid file file */ + lua_pushvalue(L, 1); + } + lua_rawseti(L, LUA_ENVIRONINDEX, f); + } + /* return current value */ + lua_rawgeti(L, LUA_ENVIRONINDEX, f); + return 1; + } + + + private static int io_input (lua_State L) { + return g_iofile(L, IO_INPUT, "r"); + } + + + private static int io_output (lua_State L) { + return g_iofile(L, IO_OUTPUT, "w"); + } + + private static void aux_lines (lua_State L, int idx, int toclose) { + lua_pushvalue(L, idx); + lua_pushboolean(L, toclose); /* close/not close file when finished */ + lua_pushcclosure(L, io_readline, 2); + } + + + private static int f_lines (lua_State L) { + tofile(L); /* check that it's a valid file file */ + aux_lines(L, 1, 0); + return 1; + } + + + private static int io_lines (lua_State L) { + if (lua_isnoneornil(L, 1)) { /* no arguments? */ + /* will iterate over default input */ + lua_rawgeti(L, LUA_ENVIRONINDEX, IO_INPUT); + return f_lines(L); + } + else { + CharPtr filename = luaL_checkstring(L, 1); + FilePtr pf = newfile(L); + pf.file = fopen(filename, "r"); + if (pf.file == null) + fileerror(L, 1, filename); + aux_lines(L, lua_gettop(L), 1); + return 1; + } + } + + + /* + ** {====================================================== + ** READ + ** ======================================================= + */ + + + private static int read_number (lua_State L, Stream f) { + //lua_Number d; + object[] parms = { (object)(double)0.0 }; + if (fscanf(f, LUA_NUMBER_SCAN, parms) == 1) + { + lua_pushnumber(L, (double)parms[0]); + return 1; + } + else return 0; /* read fails */ + } + + + private static int test_eof (lua_State L, Stream f) { + int c = getc(f); + ungetc(c, f); + lua_pushlstring(L, null, 0); + return (c != EOF) ? 1 : 0; + } + + + private static int read_line (lua_State L, Stream f) { + luaL_Buffer b = new luaL_Buffer(); + luaL_buffinit(L, b); + for (;;) { + uint l; + CharPtr p = luaL_prepbuffer(b); + if (fgets(p, f) == null) { /* eof? */ + luaL_pushresult(b); /* close buffer */ + return (lua_objlen(L, -1) > 0) ? 1 : 0; /* check whether read something */ + } + l = (uint)strlen(p); + if (l == 0 || p[l-1] != '\n') + luaL_addsize(b, (int)l); + else { + luaL_addsize(b, (int)(l - 1)); /* do not include `eol' */ + luaL_pushresult(b); /* close buffer */ + return 1; /* read at least an `eol' */ + } + } + } + + + private static int read_chars (lua_State L, Stream f, uint n) { + uint rlen; /* how much to read */ + uint nr; /* number of chars actually read */ + luaL_Buffer b = new luaL_Buffer(); + luaL_buffinit(L, b); + rlen = LUAL_BUFFERSIZE; /* try to read that much each time */ + do { + CharPtr p = luaL_prepbuffer(b); + if (rlen > n) rlen = n; /* cannot read more than asked */ + nr = (uint)fread(p, GetUnmanagedSize(typeof(char)), (int)rlen, f); + luaL_addsize(b, (int)nr); + n -= nr; /* still have to read `n' chars */ + } while (n > 0 && nr == rlen); /* until end of count or eof */ + luaL_pushresult(b); /* close buffer */ + return (n == 0 || lua_objlen(L, -1) > 0) ? 1 : 0; + } + + + private static int g_read (lua_State L, Stream f, int first) { + int nargs = lua_gettop(L) - 1; + int success; + int n; + clearerr(f); + if (nargs == 0) { /* no arguments? */ + success = read_line(L, f); + n = first+1; /* to return 1 result */ + } + else { /* ensure stack space for all results and for auxlib's buffer */ + luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); + success = 1; + for (n = first; (nargs-- != 0) && (success!=0); n++) { + if (lua_type(L, n) == LUA_TNUMBER) { + uint l = (uint)lua_tointeger(L, n); + success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); + } + else { + CharPtr p = lua_tostring(L, n); + luaL_argcheck(L, (p!=null) && (p[0] == '*'), n, "invalid option"); + switch (p[1]) { + case 'n': /* number */ + success = read_number(L, f); + break; + case 'l': /* line */ + success = read_line(L, f); + break; + case 'a': /* file */ + read_chars(L, f, ~((uint)0)); /* read MAX_uint chars */ + success = 1; /* always success */ + break; + default: + return luaL_argerror(L, n, "invalid format"); + } + } + } + } + if (ferror(f)!=0) + return pushresult(L, 0, null); + if (success==0) { + lua_pop(L, 1); /* remove last result */ + lua_pushnil(L); /* push nil instead */ + } + return n - first; + } + + + private static int io_read (lua_State L) { + return g_read(L, getiofile(L, IO_INPUT), 1); + } + + + private static int f_read (lua_State L) { + return g_read(L, tofile(L), 2); + } + + + private static int io_readline (lua_State L) { + Stream f = (lua_touserdata(L, lua_upvalueindex(1)) as FilePtr).file; + int sucess; + if (f == null) /* file is already closed? */ + luaL_error(L, "file is already closed"); + sucess = read_line(L, f); + if (ferror(f)!=0) + return luaL_error(L, "%s", strerror(errno())); + if (sucess != 0) return 1; + else { /* EOF */ + if (lua_toboolean(L, lua_upvalueindex(2)) != 0) { /* generator created file? */ + lua_settop(L, 0); + lua_pushvalue(L, lua_upvalueindex(1)); + aux_close(L); /* close it */ + } + return 0; + } + } + + /* }====================================================== */ + + + private static int g_write (lua_State L, Stream f, int arg) { + int nargs = lua_gettop(L) - 1; + int status = 1; + for (; (nargs--) != 0; arg++) { + if (lua_type(L, arg) == LUA_TNUMBER) { + /* optimization: could be done exactly as for strings */ + status = ((status!=0) && + (fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0)) ? 1 : 0; + } + else { + uint l; + CharPtr s = luaL_checklstring(L, arg, out l); + status = ((status!=0) && (fwrite(s, GetUnmanagedSize(typeof(char)), (int)l, f) == l)) ? 1 : 0; + } + } + return pushresult(L, status, null); + } + + + private static int io_write (lua_State L) { + return g_write(L, getiofile(L, IO_OUTPUT), 1); + } + + + private static int f_write (lua_State L) { + return g_write(L, tofile(L), 2); + } + + + + private static int f_seek (lua_State L) { + int[] mode = { SEEK_SET, SEEK_CUR, SEEK_END }; + CharPtr[] modenames = { "set", "cur", "end", null }; + Stream f = tofile(L); + int op = luaL_checkoption(L, 2, "cur", modenames); + long offset = luaL_optlong(L, 3, 0); + op = fseek(f, offset, mode[op]); + if (op != 0) + return pushresult(L, 0, null); /* error */ + else { + lua_pushinteger(L, ftell(f)); + return 1; + } + } + + private static int f_setvbuf (lua_State L) { + CharPtr[] modenames = { "no", "full", "line", null }; + int[] mode = { _IONBF, _IOFBF, _IOLBF }; + Stream f = tofile(L); + int op = luaL_checkoption(L, 2, null, modenames); + lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); + int res = setvbuf(f, null, mode[op], (uint)sz); + return pushresult(L, (res == 0) ? 1 : 0, null); + } + + + + private static int io_flush (lua_State L) { + int result = 1; + try {getiofile(L, IO_OUTPUT).Flush();} catch {result = 0;} + return pushresult(L, result, null); + } + + + private static int f_flush (lua_State L) { + int result = 1; + try {tofile(L).Flush();} catch {result = 0;} + return pushresult(L, result, null); + } + + + private readonly static luaL_Reg[] iolib = { + new luaL_Reg("close", io_close), + new luaL_Reg("flush", io_flush), + new luaL_Reg("input", io_input), + new luaL_Reg("lines", io_lines), + new luaL_Reg("open", io_open), + new luaL_Reg("output", io_output), + new luaL_Reg("popen", io_popen), + new luaL_Reg("read", io_read), + new luaL_Reg("tmpfile", io_tmpfile), + new luaL_Reg("type", io_type), + new luaL_Reg("write", io_write), + new luaL_Reg(null, null) + }; + + + private readonly static luaL_Reg[] flib = { + new luaL_Reg("close", io_close), + new luaL_Reg("flush", f_flush), + new luaL_Reg("lines", f_lines), + new luaL_Reg("read", f_read), + new luaL_Reg("seek", f_seek), + new luaL_Reg("setvbuf", f_setvbuf), + new luaL_Reg("write", f_write), + new luaL_Reg("__gc", io_gc), + new luaL_Reg("__tostring", io_tostring), + new luaL_Reg(null, null) + }; + + + private static void createmeta (lua_State L) { + luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file files */ + lua_pushvalue(L, -1); /* push metatable */ + lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ + luaL_register(L, null, flib); /* file methods */ + } + + + private static void createstdfile (lua_State L, Stream f, int k, CharPtr fname) { + newfile(L).file = f; + if (k > 0) { + lua_pushvalue(L, -1); + lua_rawseti(L, LUA_ENVIRONINDEX, k); + } + lua_pushvalue(L, -2); /* copy environment */ + lua_setfenv(L, -2); /* set it */ + lua_setfield(L, -3, fname); + } + + + private static void newfenv (lua_State L, lua_CFunction cls) { + lua_createtable(L, 0, 1); + lua_pushcfunction(L, cls); + lua_setfield(L, -2, "__close"); + } + + + public static int luaopen_io (lua_State L) { + createmeta(L); + /* create (private) environment (with fields IO_INPUT, IO_OUTPUT, __close) */ + newfenv(L, io_fclose); + lua_replace(L, LUA_ENVIRONINDEX); + /* open library */ + luaL_register(L, LUA_IOLIBNAME, iolib); + /* create (and set) default files */ + newfenv(L, io_noclose); /* close function for default files */ + createstdfile(L, stdin, IO_INPUT, "stdin"); + createstdfile(L, stdout, IO_OUTPUT, "stdout"); + createstdfile(L, stderr, 0, "stderr"); + lua_pop(L, 1); /* pop environment for default files */ + lua_getfield(L, -1, "popen"); + newfenv(L, io_pclose); /* create environment for 'popen' */ + lua_setfenv(L, -2); /* set fenv for 'popen' */ + lua_pop(L, 1); /* pop 'popen' */ + return 1; + } + + } +} diff --git a/Core/KopiLua/llex.cs b/Core/KopiLua/llex.cs index 130780820c99f45f8b2e46660eb50206253051eb..5ace427e6b1397020ebca74b29413b1ee6eff843 100644 --- a/Core/KopiLua/llex.cs +++ b/Core/KopiLua/llex.cs @@ -1,519 +1,519 @@ -/* -** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $ -** Lexical Analyzer -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; -using System.Diagnostics; - -namespace KopiLua -{ - using TValue = Lua.lua_TValue; - using lua_Number = System.Double; - using ZIO = Lua.Zio; - - public partial class Lua - { - public const int FIRST_RESERVED = 257; - - /* maximum length of a reserved word */ - public const int TOKEN_LEN = 9; // "function" - - - /* - * WARNING: if you change the order of this enumeration, - * grep "ORDER RESERVED" - */ - public enum RESERVED { - /* terminal symbols denoted by reserved words */ - TK_AND = FIRST_RESERVED, TK_BREAK, - TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, - TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, - TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, - /* other terminal symbols */ - TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, - TK_NAME, TK_STRING, TK_EOS - }; - - /* number of reserved words */ - public const int NUM_RESERVED = (int)RESERVED.TK_WHILE - FIRST_RESERVED + 1; - - public class SemInfo { - public SemInfo() { } - public SemInfo(SemInfo copy) - { - this.r = copy.r; - this.ts = copy.ts; - } - public lua_Number r; - public TString ts; - } ; /* semantics information */ - - public class Token { - public Token() { } - public Token(Token copy) - { - this.token = copy.token; - this.seminfo = new SemInfo(copy.seminfo); - } - public int token; - public SemInfo seminfo = new SemInfo(); - }; - - - public class LexState { - public int current; /* current character (charint) */ - public int linenumber; /* input line counter */ - public int lastline; /* line of last token `consumed' */ - public Token t = new Token(); /* current token */ - public Token lookahead = new Token(); /* look ahead token */ - public FuncState fs; /* `FuncState' is private to the parser */ - public lua_State L; - public ZIO z; /* input stream */ - public Mbuffer buff; /* buffer for tokens */ - public TString source; /* current source name */ - public char decpoint; /* locale decimal point */ - }; - - - public static void next(LexState ls) { ls.current = zgetc(ls.z); } - - - public static bool currIsNewline(LexState ls) { return (ls.current == '\n' || ls.current == '\r'); } - - - /* ORDER RESERVED */ - public static readonly string[] luaX_tokens = { - "and", "break", "do", "else", "elseif", - "end", "false", "for", "function", "if", - "in", "local", "nil", "not", "or", "repeat", - "return", "then", "true", "until", "while", - "..", "...", "==", ">=", "<=", "~=", - "", "", "", "" - }; - - - public static void save_and_next(LexState ls) {save(ls, ls.current); next(ls);} - - private static void save (LexState ls, int c) { - Mbuffer b = ls.buff; - if (b.n + 1 > b.buffsize) { - uint newsize; - if (b.buffsize >= MAX_SIZET/2) - luaX_lexerror(ls, "lexical element too long", 0); - newsize = b.buffsize * 2; - luaZ_resizebuffer(ls.L, b, (int)newsize); - } - b.buffer[b.n++] = (char)c; - } - - - public static void luaX_init (lua_State L) { - int i; - for (i=0; i= MAX_INT) - luaX_syntaxerror(ls, "chunk has too many lines"); - } - - - public static void luaX_setinput (lua_State L, LexState ls, ZIO z, TString source) { - ls.decpoint = '.'; - ls.L = L; - ls.lookahead.token = (int)RESERVED.TK_EOS; /* no look-ahead token */ - ls.z = z; - ls.fs = null; - ls.linenumber = 1; - ls.lastline = 1; - ls.source = source; - luaZ_resizebuffer(ls.L, ls.buff, LUA_MINBUFFER); /* initialize buffer */ - next(ls); /* read first char */ - } - - - - /* - ** ======================================================= - ** LEXICAL ANALYZER - ** ======================================================= - */ - - - private static int check_next (LexState ls, CharPtr set) { - if (strchr(set, (char)ls.current) == null) - return 0; - save_and_next(ls); - return 1; - } - - - private static void buffreplace (LexState ls, char from, char to) { - uint n = luaZ_bufflen(ls.buff); - CharPtr p = luaZ_buffer(ls.buff); - while ((n--) != 0) - if (p[n] == from) p[n] = to; - } - - - private static void trydecpoint (LexState ls, SemInfo seminfo) { - /* format error: try to update decimal point separator */ - // todo: add proper support for localeconv - mjf - //lconv cv = localeconv(); - char old = ls.decpoint; - ls.decpoint = '.'; // (cv ? cv.decimal_point[0] : '.'); - buffreplace(ls, old, ls.decpoint); /* try updated decimal separator */ - if (luaO_str2d(luaZ_buffer(ls.buff), out seminfo.r) == 0) - { - /* format error with correct decimal point: no more options */ - buffreplace(ls, ls.decpoint, '.'); /* undo change (for error message) */ - luaX_lexerror(ls, "malformed number", (int)RESERVED.TK_NUMBER); - } - } - - - /* LUA_NUMBER */ - private static void read_numeral (LexState ls, SemInfo seminfo) { - lua_assert(isdigit(ls.current)); - do { - save_and_next(ls); - } while (isdigit(ls.current) || ls.current == '.'); - if (check_next(ls, "Ee") != 0) /* `E'? */ - check_next(ls, "+-"); /* optional exponent sign */ - while (isalnum(ls.current) || ls.current == '_') - save_and_next(ls); - save(ls, '\0'); - buffreplace(ls, '.', ls.decpoint); /* follow locale for decimal point */ - if (luaO_str2d(luaZ_buffer(ls.buff), out seminfo.r) == 0) /* format error? */ - trydecpoint(ls, seminfo); /* try to update decimal point separator */ - } - - - private static int skip_sep (LexState ls) { - int count = 0; - int s = ls.current; - lua_assert(s == '[' || s == ']'); - save_and_next(ls); - while (ls.current == '=') { - save_and_next(ls); - count++; - } - return (ls.current == s) ? count : (-count) - 1; - } - - - private static void read_long_string (LexState ls, SemInfo seminfo, int sep) { - //int cont = 0; - //(void)(cont); /* avoid warnings when `cont' is not used */ - save_and_next(ls); /* skip 2nd `[' */ - if (currIsNewline(ls)) /* string starts with a newline? */ - inclinenumber(ls); /* skip it */ - for (;;) { - switch (ls.current) { - case EOZ: - luaX_lexerror(ls, (seminfo != null) ? "unfinished long string" : - "unfinished long comment", (int)RESERVED.TK_EOS); - break; /* to avoid warnings */ - #if LUA_COMPAT_LSTR - case '[': { - if (skip_sep(ls) == sep) { - save_and_next(ls); /* skip 2nd `[' */ - cont++; - #if LUA_COMPAT_LSTR - if (sep == 0) - luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); - #endif - } - break; - } - #endif - case ']': - if (skip_sep(ls) == sep) - { - save_and_next(ls); /* skip 2nd `]' */ - //#if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 - // cont--; - // if (sep == 0 && cont >= 0) break; - //#endif - goto endloop; - } - break; - case '\n': - case '\r': - save(ls, '\n'); - inclinenumber(ls); - if (seminfo == null) luaZ_resetbuffer(ls.buff); /* avoid wasting space */ - break; - default: { - if (seminfo != null) save_and_next(ls); - else next(ls); - } - break; - } - } endloop: - if (seminfo != null) - { - seminfo.ts = luaX_newstring(ls, luaZ_buffer(ls.buff) + (2 + sep), - (uint)(luaZ_bufflen(ls.buff) - 2*(2 + sep))); - } - } - - - static void read_string (LexState ls, int del, SemInfo seminfo) { - save_and_next(ls); - while (ls.current != del) { - switch (ls.current) { - case EOZ: - luaX_lexerror(ls, "unfinished string", (int)RESERVED.TK_EOS); - continue; /* to avoid warnings */ - case '\n': - case '\r': - luaX_lexerror(ls, "unfinished string", (int)RESERVED.TK_STRING); - continue; /* to avoid warnings */ - case '\\': { - int c; - next(ls); /* do not save the `\' */ - switch (ls.current) { - case 'a': c = '\a'; break; - case 'b': c = '\b'; break; - case 'f': c = '\f'; break; - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - case 'v': c = '\v'; break; - case '\n': /* go through */ - case '\r': save(ls, '\n'); inclinenumber(ls); continue; - case EOZ: continue; /* will raise an error next loop */ - default: { - if (!isdigit(ls.current)) - save_and_next(ls); /* handles \\, \", \', and \? */ - else { /* \xxx */ - int i = 0; - c = 0; - do { - c = 10*c + (ls.current-'0'); - next(ls); - } while (++i<3 && isdigit(ls.current)); - if (c > System.Byte.MaxValue) - luaX_lexerror(ls, "escape sequence too large", (int)RESERVED.TK_STRING); - save(ls, c); - } - continue; - } - } - save(ls, c); - next(ls); - continue; - } - default: - save_and_next(ls); - break; - } - } - save_and_next(ls); /* skip delimiter */ - seminfo.ts = luaX_newstring(ls, luaZ_buffer(ls.buff) + 1, - luaZ_bufflen(ls.buff) - 2); - } - - - private static int llex (LexState ls, SemInfo seminfo) { - luaZ_resetbuffer(ls.buff); - for (;;) { - switch (ls.current) { - case '\n': - case '\r': { - inclinenumber(ls); - continue; - } - case '-': { - next(ls); - if (ls.current != '-') return '-'; - /* else is a comment */ - next(ls); - if (ls.current == '[') { - int sep = skip_sep(ls); - luaZ_resetbuffer(ls.buff); /* `skip_sep' may dirty the buffer */ - if (sep >= 0) { - read_long_string(ls, null, sep); /* long comment */ - luaZ_resetbuffer(ls.buff); - continue; - } - } - /* else short comment */ - while (!currIsNewline(ls) && ls.current != EOZ) - next(ls); - continue; - } - case '[': { - int sep = skip_sep(ls); - if (sep >= 0) { - read_long_string(ls, seminfo, sep); - return (int)RESERVED.TK_STRING; - } - else if (sep == -1) return '['; - else luaX_lexerror(ls, "invalid long string delimiter", (int)RESERVED.TK_STRING); - } - break; - case '=': { - next(ls); - if (ls.current != '=') return '='; - else { next(ls); return (int)RESERVED.TK_EQ; } - } - case '<': { - next(ls); - if (ls.current != '=') return '<'; - else { next(ls); return (int)RESERVED.TK_LE; } - } - case '>': { - next(ls); - if (ls.current != '=') return '>'; - else { next(ls); return (int)RESERVED.TK_GE; } - } - case '~': { - next(ls); - if (ls.current != '=') return '~'; - else { next(ls); return (int)RESERVED.TK_NE; } - } - case '"': - case '\'': { - read_string(ls, ls.current, seminfo); - return (int)RESERVED.TK_STRING; - } - case '.': { - save_and_next(ls); - if (check_next(ls, ".") != 0) { - if (check_next(ls, ".") != 0) - return (int)RESERVED.TK_DOTS; /* ... */ - else return (int)RESERVED.TK_CONCAT; /* .. */ - } - else if (!isdigit(ls.current)) return '.'; - else { - read_numeral(ls, seminfo); - return (int)RESERVED.TK_NUMBER; - } - } - case EOZ: { - return (int)RESERVED.TK_EOS; - } - default: { - if (isspace(ls.current)) { - lua_assert(!currIsNewline(ls)); - next(ls); - continue; - } - else if (isdigit(ls.current)) { - read_numeral(ls, seminfo); - return (int)RESERVED.TK_NUMBER; - } - else if (isalpha(ls.current) || ls.current == '_') { - /* identifier or reserved word */ - TString ts; - do { - save_and_next(ls); - } while (isalnum(ls.current) || ls.current == '_'); - ts = luaX_newstring(ls, luaZ_buffer(ls.buff), - luaZ_bufflen(ls.buff)); - if (ts.tsv.reserved > 0) /* reserved word? */ - return ts.tsv.reserved - 1 + FIRST_RESERVED; - else { - seminfo.ts = ts; - return (int)RESERVED.TK_NAME; - } - } - else { - int c = ls.current; - next(ls); - return c; /* single-char tokens (+ - / ...) */ - } - } - } - } - } - - - public static void luaX_next (LexState ls) { - ls.lastline = ls.linenumber; - if (ls.lookahead.token != (int)RESERVED.TK_EOS) - { /* is there a look-ahead token? */ - ls.t = new Token(ls.lookahead); /* use this one */ - ls.lookahead.token = (int)RESERVED.TK_EOS; /* and discharge it */ - } - else - ls.t.token = llex(ls, ls.t.seminfo); /* read next token */ - } - - - public static void luaX_lookahead (LexState ls) { - lua_assert(ls.lookahead.token == (int)RESERVED.TK_EOS); - ls.lookahead.token = llex(ls, ls.lookahead.seminfo); - } - - } -} +/* +** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $ +** Lexical Analyzer +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Diagnostics; + +namespace KopiLua +{ + using TValue = Lua.lua_TValue; + using lua_Number = System.Double; + using ZIO = Lua.Zio; + + public partial class Lua + { + public const int FIRST_RESERVED = 257; + + /* maximum length of a reserved word */ + public const int TOKEN_LEN = 9; // "function" + + + /* + * WARNING: if you change the order of this enumeration, + * grep "ORDER RESERVED" + */ + public enum RESERVED { + /* terminal symbols denoted by reserved words */ + TK_AND = FIRST_RESERVED, TK_BREAK, + TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, + TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, + TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, + /* other terminal symbols */ + TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_NUMBER, + TK_NAME, TK_STRING, TK_EOS + }; + + /* number of reserved words */ + public const int NUM_RESERVED = (int)RESERVED.TK_WHILE - FIRST_RESERVED + 1; + + public class SemInfo { + public SemInfo() { } + public SemInfo(SemInfo copy) + { + this.r = copy.r; + this.ts = copy.ts; + } + public lua_Number r; + public TString ts; + } ; /* semantics information */ + + public class Token { + public Token() { } + public Token(Token copy) + { + this.token = copy.token; + this.seminfo = new SemInfo(copy.seminfo); + } + public int token; + public SemInfo seminfo = new SemInfo(); + }; + + + public class LexState { + public int current; /* current character (charint) */ + public int linenumber; /* input line counter */ + public int lastline; /* line of last token `consumed' */ + public Token t = new Token(); /* current token */ + public Token lookahead = new Token(); /* look ahead token */ + public FuncState fs; /* `FuncState' is private to the parser */ + public lua_State L; + public ZIO z; /* input stream */ + public Mbuffer buff; /* buffer for tokens */ + public TString source; /* current source name */ + public char decpoint; /* locale decimal point */ + }; + + + public static void next(LexState ls) { ls.current = zgetc(ls.z); } + + + public static bool currIsNewline(LexState ls) { return (ls.current == '\n' || ls.current == '\r'); } + + + /* ORDER RESERVED */ + public static readonly string[] luaX_tokens = { + "and", "break", "do", "else", "elseif", + "end", "false", "for", "function", "if", + "in", "local", "nil", "not", "or", "repeat", + "return", "then", "true", "until", "while", + "..", "...", "==", ">=", "<=", "~=", + "", "", "", "" + }; + + + public static void save_and_next(LexState ls) {save(ls, ls.current); next(ls);} + + private static void save (LexState ls, int c) { + Mbuffer b = ls.buff; + if (b.n + 1 > b.buffsize) { + uint newsize; + if (b.buffsize >= MAX_SIZET/2) + luaX_lexerror(ls, "lexical element too long", 0); + newsize = b.buffsize * 2; + luaZ_resizebuffer(ls.L, b, (int)newsize); + } + b.buffer[b.n++] = (char)c; + } + + + public static void luaX_init (lua_State L) { + int i; + for (i=0; i= MAX_INT) + luaX_syntaxerror(ls, "chunk has too many lines"); + } + + + public static void luaX_setinput (lua_State L, LexState ls, ZIO z, TString source) { + ls.decpoint = '.'; + ls.L = L; + ls.lookahead.token = (int)RESERVED.TK_EOS; /* no look-ahead token */ + ls.z = z; + ls.fs = null; + ls.linenumber = 1; + ls.lastline = 1; + ls.source = source; + luaZ_resizebuffer(ls.L, ls.buff, LUA_MINBUFFER); /* initialize buffer */ + next(ls); /* read first char */ + } + + + + /* + ** ======================================================= + ** LEXICAL ANALYZER + ** ======================================================= + */ + + + private static int check_next (LexState ls, CharPtr set) { + if (strchr(set, (char)ls.current) == null) + return 0; + save_and_next(ls); + return 1; + } + + + private static void buffreplace (LexState ls, char from, char to) { + uint n = luaZ_bufflen(ls.buff); + CharPtr p = luaZ_buffer(ls.buff); + while ((n--) != 0) + if (p[n] == from) p[n] = to; + } + + + private static void trydecpoint (LexState ls, SemInfo seminfo) { + /* format error: try to update decimal point separator */ + // todo: add proper support for localeconv - mjf + //lconv cv = localeconv(); + char old = ls.decpoint; + ls.decpoint = '.'; // (cv ? cv.decimal_point[0] : '.'); + buffreplace(ls, old, ls.decpoint); /* try updated decimal separator */ + if (luaO_str2d(luaZ_buffer(ls.buff), out seminfo.r) == 0) + { + /* format error with correct decimal point: no more options */ + buffreplace(ls, ls.decpoint, '.'); /* undo change (for error message) */ + luaX_lexerror(ls, "malformed number", (int)RESERVED.TK_NUMBER); + } + } + + + /* LUA_NUMBER */ + private static void read_numeral (LexState ls, SemInfo seminfo) { + lua_assert(isdigit(ls.current)); + do { + save_and_next(ls); + } while (isdigit(ls.current) || ls.current == '.'); + if (check_next(ls, "Ee") != 0) /* `E'? */ + check_next(ls, "+-"); /* optional exponent sign */ + while (isalnum(ls.current) || ls.current == '_') + save_and_next(ls); + save(ls, '\0'); + buffreplace(ls, '.', ls.decpoint); /* follow locale for decimal point */ + if (luaO_str2d(luaZ_buffer(ls.buff), out seminfo.r) == 0) /* format error? */ + trydecpoint(ls, seminfo); /* try to update decimal point separator */ + } + + + private static int skip_sep (LexState ls) { + int count = 0; + int s = ls.current; + lua_assert(s == '[' || s == ']'); + save_and_next(ls); + while (ls.current == '=') { + save_and_next(ls); + count++; + } + return (ls.current == s) ? count : (-count) - 1; + } + + + private static void read_long_string (LexState ls, SemInfo seminfo, int sep) { + //int cont = 0; + //(void)(cont); /* avoid warnings when `cont' is not used */ + save_and_next(ls); /* skip 2nd `[' */ + if (currIsNewline(ls)) /* string starts with a newline? */ + inclinenumber(ls); /* skip it */ + for (;;) { + switch (ls.current) { + case EOZ: + luaX_lexerror(ls, (seminfo != null) ? "unfinished long string" : + "unfinished long comment", (int)RESERVED.TK_EOS); + break; /* to avoid warnings */ + #if LUA_COMPAT_LSTR + case '[': { + if (skip_sep(ls) == sep) { + save_and_next(ls); /* skip 2nd `[' */ + cont++; + #if LUA_COMPAT_LSTR + if (sep == 0) + luaX_lexerror(ls, "nesting of [[...]] is deprecated", '['); + #endif + } + break; + } + #endif + case ']': + if (skip_sep(ls) == sep) + { + save_and_next(ls); /* skip 2nd `]' */ + //#if defined(LUA_COMPAT_LSTR) && LUA_COMPAT_LSTR == 2 + // cont--; + // if (sep == 0 && cont >= 0) break; + //#endif + goto endloop; + } + break; + case '\n': + case '\r': + save(ls, '\n'); + inclinenumber(ls); + if (seminfo == null) luaZ_resetbuffer(ls.buff); /* avoid wasting space */ + break; + default: { + if (seminfo != null) save_and_next(ls); + else next(ls); + } + break; + } + } endloop: + if (seminfo != null) + { + seminfo.ts = luaX_newstring(ls, luaZ_buffer(ls.buff) + (2 + sep), + (uint)(luaZ_bufflen(ls.buff) - 2*(2 + sep))); + } + } + + + static void read_string (LexState ls, int del, SemInfo seminfo) { + save_and_next(ls); + while (ls.current != del) { + switch (ls.current) { + case EOZ: + luaX_lexerror(ls, "unfinished string", (int)RESERVED.TK_EOS); + continue; /* to avoid warnings */ + case '\n': + case '\r': + luaX_lexerror(ls, "unfinished string", (int)RESERVED.TK_STRING); + continue; /* to avoid warnings */ + case '\\': { + int c; + next(ls); /* do not save the `\' */ + switch (ls.current) { + case 'a': c = '\a'; break; + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + case '\n': /* go through */ + case '\r': save(ls, '\n'); inclinenumber(ls); continue; + case EOZ: continue; /* will raise an error next loop */ + default: { + if (!isdigit(ls.current)) + save_and_next(ls); /* handles \\, \", \', and \? */ + else { /* \xxx */ + int i = 0; + c = 0; + do { + c = 10*c + (ls.current-'0'); + next(ls); + } while (++i<3 && isdigit(ls.current)); + if (c > System.Byte.MaxValue) + luaX_lexerror(ls, "escape sequence too large", (int)RESERVED.TK_STRING); + save(ls, c); + } + continue; + } + } + save(ls, c); + next(ls); + continue; + } + default: + save_and_next(ls); + break; + } + } + save_and_next(ls); /* skip delimiter */ + seminfo.ts = luaX_newstring(ls, luaZ_buffer(ls.buff) + 1, + luaZ_bufflen(ls.buff) - 2); + } + + + private static int llex (LexState ls, SemInfo seminfo) { + luaZ_resetbuffer(ls.buff); + for (;;) { + switch (ls.current) { + case '\n': + case '\r': { + inclinenumber(ls); + continue; + } + case '-': { + next(ls); + if (ls.current != '-') return '-'; + /* else is a comment */ + next(ls); + if (ls.current == '[') { + int sep = skip_sep(ls); + luaZ_resetbuffer(ls.buff); /* `skip_sep' may dirty the buffer */ + if (sep >= 0) { + read_long_string(ls, null, sep); /* long comment */ + luaZ_resetbuffer(ls.buff); + continue; + } + } + /* else short comment */ + while (!currIsNewline(ls) && ls.current != EOZ) + next(ls); + continue; + } + case '[': { + int sep = skip_sep(ls); + if (sep >= 0) { + read_long_string(ls, seminfo, sep); + return (int)RESERVED.TK_STRING; + } + else if (sep == -1) return '['; + else luaX_lexerror(ls, "invalid long string delimiter", (int)RESERVED.TK_STRING); + } + break; + case '=': { + next(ls); + if (ls.current != '=') return '='; + else { next(ls); return (int)RESERVED.TK_EQ; } + } + case '<': { + next(ls); + if (ls.current != '=') return '<'; + else { next(ls); return (int)RESERVED.TK_LE; } + } + case '>': { + next(ls); + if (ls.current != '=') return '>'; + else { next(ls); return (int)RESERVED.TK_GE; } + } + case '~': { + next(ls); + if (ls.current != '=') return '~'; + else { next(ls); return (int)RESERVED.TK_NE; } + } + case '"': + case '\'': { + read_string(ls, ls.current, seminfo); + return (int)RESERVED.TK_STRING; + } + case '.': { + save_and_next(ls); + if (check_next(ls, ".") != 0) { + if (check_next(ls, ".") != 0) + return (int)RESERVED.TK_DOTS; /* ... */ + else return (int)RESERVED.TK_CONCAT; /* .. */ + } + else if (!isdigit(ls.current)) return '.'; + else { + read_numeral(ls, seminfo); + return (int)RESERVED.TK_NUMBER; + } + } + case EOZ: { + return (int)RESERVED.TK_EOS; + } + default: { + if (isspace(ls.current)) { + lua_assert(!currIsNewline(ls)); + next(ls); + continue; + } + else if (isdigit(ls.current)) { + read_numeral(ls, seminfo); + return (int)RESERVED.TK_NUMBER; + } + else if (isalpha(ls.current) || ls.current == '_') { + /* identifier or reserved word */ + TString ts; + do { + save_and_next(ls); + } while (isalnum(ls.current) || ls.current == '_'); + ts = luaX_newstring(ls, luaZ_buffer(ls.buff), + luaZ_bufflen(ls.buff)); + if (ts.tsv.reserved > 0) /* reserved word? */ + return ts.tsv.reserved - 1 + FIRST_RESERVED; + else { + seminfo.ts = ts; + return (int)RESERVED.TK_NAME; + } + } + else { + int c = ls.current; + next(ls); + return c; /* single-char tokens (+ - / ...) */ + } + } + } + } + } + + + public static void luaX_next (LexState ls) { + ls.lastline = ls.linenumber; + if (ls.lookahead.token != (int)RESERVED.TK_EOS) + { /* is there a look-ahead token? */ + ls.t = new Token(ls.lookahead); /* use this one */ + ls.lookahead.token = (int)RESERVED.TK_EOS; /* and discharge it */ + } + else + ls.t.token = llex(ls, ls.t.seminfo); /* read next token */ + } + + + public static void luaX_lookahead (LexState ls) { + lua_assert(ls.lookahead.token == (int)RESERVED.TK_EOS); + ls.lookahead.token = llex(ls, ls.lookahead.seminfo); + } + + } +} diff --git a/Core/KopiLua/llimits.cs b/Core/KopiLua/llimits.cs index c8db3cb005c2200ec8d00d47b2886b4ee5d37d4d..8e96f76eeb4466f99e71970964e874d8d9731432 100644 --- a/Core/KopiLua/llimits.cs +++ b/Core/KopiLua/llimits.cs @@ -1,159 +1,159 @@ -//#define lua_assert - -/* -** $Id: llimits.h,v 1.69.1.1 2007/12/27 13:02:25 roberto Exp $ -** Limits, basic types, and some other `installation-dependent' definitions -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -namespace KopiLua -{ - using lu_int32 = System.UInt32; - using lu_mem = System.UInt32; - using l_mem = System.Int32; - using lu_byte = System.Byte; - using l_uacNumber = System.Double; - using lua_Number = System.Double; - using Instruction = System.UInt32; - - public partial class Lua - { - - //typedef LUAI_UINT32 lu_int32; - - //typedef LUAI_UMEM lu_mem; - - //typedef LUAI_MEM l_mem; - - - - /* chars used as small naturals (so that `char' is reserved for characters) */ - //typedef unsigned char lu_byte; - - [CLSCompliantAttribute(false)] - public const uint MAX_SIZET = uint.MaxValue - 2; - [CLSCompliantAttribute(false)] - public const lu_mem MAX_LUMEM = lu_mem.MaxValue - 2; - - - public const int MAX_INT = (Int32.MaxValue - 2); /* maximum value of an int (-2 for safety) */ - - /* - ** conversion of pointer to integer - ** this is for hashing only; there is no problem if the integer - ** cannot hold the whole pointer value - */ - //#define IntPoint(p) ((uint)(lu_mem)(p)) - - - - /* type to ensure maximum alignment */ - //typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; - - - /* result of a `usual argument conversion' over lua_Number */ - //typedef LUAI_UACNUMBER l_uacNumber; - - - /* internal assertions for in-house debugging */ - -#if lua_assert - - [Conditional("DEBUG")] - internal static void lua_assert(bool c) {Debug.Assert(c);} - - [Conditional("DEBUG")] - internal static void lua_assert(int c) { Debug.Assert(c != 0); } - - internal static object check_exp(bool c, object e) {lua_assert(c); return e;} - internal static object check_exp(int c, object e) { lua_assert(c != 0); return e; } - -#else - - [Conditional("DEBUG")] - internal static void lua_assert(bool c) { } - - [Conditional("DEBUG")] - internal static void lua_assert(int c) { } - - internal static object check_exp(bool c, object e) { return e; } - internal static object check_exp(int c, object e) { return e; } - -#endif - - [Conditional("DEBUG")] - internal static void api_check(object o, bool e) { lua_assert(e); } - internal static void api_check(object o, int e) { lua_assert(e != 0); } - - //#define UNUSED(x) ((void)(x)) /* to avoid warnings */ - - - internal static lu_byte cast_byte(int i) { return (lu_byte)i; } - internal static lu_byte cast_byte(long i) { return (lu_byte)(int)i; } - internal static lu_byte cast_byte(bool i) { return i ? (lu_byte)1 : (lu_byte)0; } - internal static lu_byte cast_byte(lua_Number i) { return (lu_byte)i; } - internal static lu_byte cast_byte(object i) { return (lu_byte)(int)(i); } - - internal static int cast_int(int i) { return (int)i; } - internal static int cast_int(uint i) { return (int)i; } - internal static int cast_int(long i) { return (int)(int)i; } - internal static int cast_int(ulong i) { return (int)(int)i; } - internal static int cast_int(bool i) { return i ? (int)1 : (int)0; } - internal static int cast_int(lua_Number i) { return (int)i; } - internal static int cast_int(object i) { Debug.Assert(false, "Can't convert int."); return Convert.ToInt32(i); } - - internal static lua_Number cast_num(int i) { return (lua_Number)i; } - internal static lua_Number cast_num(uint i) { return (lua_Number)i; } - internal static lua_Number cast_num(long i) { return (lua_Number)i; } - internal static lua_Number cast_num(ulong i) { return (lua_Number)i; } - internal static lua_Number cast_num(bool i) { return i ? (lua_Number)1 : (lua_Number)0; } - internal static lua_Number cast_num(object i) { Debug.Assert(false, "Can't convert number."); return Convert.ToSingle(i); } - - /* - ** type for virtual-machine instructions - ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) - */ - //typedef lu_int32 Instruction; - - - - /* maximum stack for a Lua function */ - public const int MAXSTACK = 250; - - - - /* minimum size for the string table (must be power of 2) */ - public const int MINSTRTABSIZE = 32; - - - /* minimum size for string buffer */ - public const int LUA_MINBUFFER = 32; - - - #if !lua_lock - public static void lua_lock(lua_State L) { } - public static void lua_unlock(lua_State L) { } - #endif - - - #if !luai_threadyield - public static void luai_threadyield(lua_State L) {lua_unlock(L); lua_lock(L);} - #endif - - - /* - ** macro to control inclusion of some hard tests on stack reallocation - */ - //#ifndef HARDSTACKTESTS - //#define condhardstacktests(x) ((void)0) - //#else - //#define condhardstacktests(x) x - //#endif - - } -} +//#define lua_assert + +/* +** $Id: llimits.h,v 1.69.1.1 2007/12/27 13:02:25 roberto Exp $ +** Limits, basic types, and some other `installation-dependent' definitions +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace KopiLua +{ + using lu_int32 = System.UInt32; + using lu_mem = System.UInt32; + using l_mem = System.Int32; + using lu_byte = System.Byte; + using l_uacNumber = System.Double; + using lua_Number = System.Double; + using Instruction = System.UInt32; + + public partial class Lua + { + + //typedef LUAI_UINT32 lu_int32; + + //typedef LUAI_UMEM lu_mem; + + //typedef LUAI_MEM l_mem; + + + + /* chars used as small naturals (so that `char' is reserved for characters) */ + //typedef unsigned char lu_byte; + + [CLSCompliantAttribute(false)] + public const uint MAX_SIZET = uint.MaxValue - 2; + [CLSCompliantAttribute(false)] + public const lu_mem MAX_LUMEM = lu_mem.MaxValue - 2; + + + public const int MAX_INT = (Int32.MaxValue - 2); /* maximum value of an int (-2 for safety) */ + + /* + ** conversion of pointer to integer + ** this is for hashing only; there is no problem if the integer + ** cannot hold the whole pointer value + */ + //#define IntPoint(p) ((uint)(lu_mem)(p)) + + + + /* type to ensure maximum alignment */ + //typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; + + + /* result of a `usual argument conversion' over lua_Number */ + //typedef LUAI_UACNUMBER l_uacNumber; + + + /* internal assertions for in-house debugging */ + +#if lua_assert + + [Conditional("DEBUG")] + internal static void lua_assert(bool c) {Debug.Assert(c);} + + [Conditional("DEBUG")] + internal static void lua_assert(int c) { Debug.Assert(c != 0); } + + internal static object check_exp(bool c, object e) {lua_assert(c); return e;} + internal static object check_exp(int c, object e) { lua_assert(c != 0); return e; } + +#else + + [Conditional("DEBUG")] + internal static void lua_assert(bool c) { } + + [Conditional("DEBUG")] + internal static void lua_assert(int c) { } + + internal static object check_exp(bool c, object e) { return e; } + internal static object check_exp(int c, object e) { return e; } + +#endif + + [Conditional("DEBUG")] + internal static void api_check(object o, bool e) { lua_assert(e); } + internal static void api_check(object o, int e) { lua_assert(e != 0); } + + //#define UNUSED(x) ((void)(x)) /* to avoid warnings */ + + + internal static lu_byte cast_byte(int i) { return (lu_byte)i; } + internal static lu_byte cast_byte(long i) { return (lu_byte)(int)i; } + internal static lu_byte cast_byte(bool i) { return i ? (lu_byte)1 : (lu_byte)0; } + internal static lu_byte cast_byte(lua_Number i) { return (lu_byte)i; } + internal static lu_byte cast_byte(object i) { return (lu_byte)(int)(i); } + + internal static int cast_int(int i) { return (int)i; } + internal static int cast_int(uint i) { return (int)i; } + internal static int cast_int(long i) { return (int)(int)i; } + internal static int cast_int(ulong i) { return (int)(int)i; } + internal static int cast_int(bool i) { return i ? (int)1 : (int)0; } + internal static int cast_int(lua_Number i) { return (int)i; } + internal static int cast_int(object i) { Debug.Assert(false, "Can't convert int."); return Convert.ToInt32(i); } + + internal static lua_Number cast_num(int i) { return (lua_Number)i; } + internal static lua_Number cast_num(uint i) { return (lua_Number)i; } + internal static lua_Number cast_num(long i) { return (lua_Number)i; } + internal static lua_Number cast_num(ulong i) { return (lua_Number)i; } + internal static lua_Number cast_num(bool i) { return i ? (lua_Number)1 : (lua_Number)0; } + internal static lua_Number cast_num(object i) { Debug.Assert(false, "Can't convert number."); return Convert.ToSingle(i); } + + /* + ** type for virtual-machine instructions + ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) + */ + //typedef lu_int32 Instruction; + + + + /* maximum stack for a Lua function */ + public const int MAXSTACK = 250; + + + + /* minimum size for the string table (must be power of 2) */ + public const int MINSTRTABSIZE = 32; + + + /* minimum size for string buffer */ + public const int LUA_MINBUFFER = 32; + + + #if !lua_lock + public static void lua_lock(lua_State L) { } + public static void lua_unlock(lua_State L) { } + #endif + + + #if !luai_threadyield + public static void luai_threadyield(lua_State L) {lua_unlock(L); lua_lock(L);} + #endif + + + /* + ** macro to control inclusion of some hard tests on stack reallocation + */ + //#ifndef HARDSTACKTESTS + //#define condhardstacktests(x) ((void)0) + //#else + //#define condhardstacktests(x) x + //#endif + + } +} diff --git a/Core/KopiLua/lmathlib.cs b/Core/KopiLua/lmathlib.cs index f2f52dc6cc7f0f448cdb5073773fd7bd81defd91..47a27ceab5cb65ab9753716f19b0926f98e38b71 100644 --- a/Core/KopiLua/lmathlib.cs +++ b/Core/KopiLua/lmathlib.cs @@ -1,264 +1,264 @@ -/* -** $Id: lmathlib.c,v 1.67.1.1 2007/12/27 13:02:25 roberto Exp $ -** Standard mathematical library -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace KopiLua -{ - using lua_Number = System.Double; - - public partial class Lua - { - public const double PI = 3.14159265358979323846; - public const double RADIANS_PER_DEGREE = PI / 180.0; - - - - private static int math_abs (lua_State L) { - lua_pushnumber(L, Math.Abs(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_sin (lua_State L) { - lua_pushnumber(L, Math.Sin(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_sinh (lua_State L) { - lua_pushnumber(L, Math.Sinh(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_cos (lua_State L) { - lua_pushnumber(L, Math.Cos(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_cosh (lua_State L) { - lua_pushnumber(L, Math.Cosh(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_tan (lua_State L) { - lua_pushnumber(L, Math.Tan(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_tanh (lua_State L) { - lua_pushnumber(L, Math.Tanh(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_asin (lua_State L) { - lua_pushnumber(L, Math.Asin(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_acos (lua_State L) { - lua_pushnumber(L, Math.Acos(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_atan (lua_State L) { - lua_pushnumber(L, Math.Atan(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_atan2 (lua_State L) { - lua_pushnumber(L, Math.Atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); - return 1; - } - - private static int math_ceil (lua_State L) { - lua_pushnumber(L, Math.Ceiling(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_floor (lua_State L) { - lua_pushnumber(L, Math.Floor(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_fmod (lua_State L) { - lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); - return 1; - } - - private static int math_modf (lua_State L) { - double ip; - double fp = modf(luaL_checknumber(L, 1), out ip); - lua_pushnumber(L, ip); - lua_pushnumber(L, fp); - return 2; - } - - private static int math_sqrt (lua_State L) { - lua_pushnumber(L, Math.Sqrt(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_pow (lua_State L) { - lua_pushnumber(L, Math.Pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); - return 1; - } - - private static int math_log (lua_State L) { - lua_pushnumber(L, Math.Log(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_log10 (lua_State L) { - lua_pushnumber(L, Math.Log10(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_exp (lua_State L) { - lua_pushnumber(L, Math.Exp(luaL_checknumber(L, 1))); - return 1; - } - - private static int math_deg (lua_State L) { - lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); - return 1; - } - - private static int math_rad (lua_State L) { - lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); - return 1; - } - - private static int math_frexp (lua_State L) { - int e; - lua_pushnumber(L, frexp(luaL_checknumber(L, 1), out e)); - lua_pushinteger(L, e); - return 2; - } - - private static int math_ldexp (lua_State L) { - lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2))); - return 1; - } - - - - private static int math_min (lua_State L) { - int n = lua_gettop(L); /* number of arguments */ - lua_Number dmin = luaL_checknumber(L, 1); - int i; - for (i=2; i<=n; i++) { - lua_Number d = luaL_checknumber(L, i); - if (d < dmin) - dmin = d; - } - lua_pushnumber(L, dmin); - return 1; - } - - - private static int math_max (lua_State L) { - int n = lua_gettop(L); /* number of arguments */ - lua_Number dmax = luaL_checknumber(L, 1); - int i; - for (i=2; i<=n; i++) { - lua_Number d = luaL_checknumber(L, i); - if (d > dmax) - dmax = d; - } - lua_pushnumber(L, dmax); - return 1; - } - - private static Random rng = new Random(); - - private static int math_random (lua_State L) { - /* the `%' avoids the (rare) case of r==1, and is needed also because on - some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ - //lua_Number r = (lua_Number)(rng.Next()%RAND_MAX) / (lua_Number)RAND_MAX; - lua_Number r = (lua_Number)rng.NextDouble(); - switch (lua_gettop(L)) { /* check number of arguments */ - case 0: { /* no arguments */ - lua_pushnumber(L, r); /* Number between 0 and 1 */ - break; - } - case 1: { /* only upper limit */ - int u = luaL_checkint(L, 1); - luaL_argcheck(L, 1<=u, 1, "interval is empty"); - lua_pushnumber(L, Math.Floor(r*u)+1); /* int between 1 and `u' */ - break; - } - case 2: { /* lower and upper limits */ - int l = luaL_checkint(L, 1); - int u = luaL_checkint(L, 2); - luaL_argcheck(L, l<=u, 2, "interval is empty"); - lua_pushnumber(L, Math.Floor(r * (u - l + 1)) + l); /* int between `l' and `u' */ - break; - } - default: return luaL_error(L, "wrong number of arguments"); - } - return 1; - } - - - private static int math_randomseed (lua_State L) { - //srand(luaL_checkint(L, 1)); - rng = new Random(luaL_checkint(L, 1)); - return 0; - } - - - private readonly static luaL_Reg[] mathlib = { - new luaL_Reg("abs", math_abs), - new luaL_Reg("acos", math_acos), - new luaL_Reg("asin", math_asin), - new luaL_Reg("atan2", math_atan2), - new luaL_Reg("atan", math_atan), - new luaL_Reg("ceil", math_ceil), - new luaL_Reg("cosh", math_cosh), - new luaL_Reg("cos", math_cos), - new luaL_Reg("deg", math_deg), - new luaL_Reg("exp", math_exp), - new luaL_Reg("floor", math_floor), - new luaL_Reg("fmod", math_fmod), - new luaL_Reg("frexp", math_frexp), - new luaL_Reg("ldexp", math_ldexp), - new luaL_Reg("log10", math_log10), - new luaL_Reg("log", math_log), - new luaL_Reg("max", math_max), - new luaL_Reg("min", math_min), - new luaL_Reg("modf", math_modf), - new luaL_Reg("pow", math_pow), - new luaL_Reg("rad", math_rad), - new luaL_Reg("random", math_random), - new luaL_Reg("randomseed", math_randomseed), - new luaL_Reg("sinh", math_sinh), - new luaL_Reg("sin", math_sin), - new luaL_Reg("sqrt", math_sqrt), - new luaL_Reg("tanh", math_tanh), - new luaL_Reg("tan", math_tan), - new luaL_Reg(null, null) - }; - - - /* - ** Open math library - */ - public static int luaopen_math (lua_State L) { - luaL_register(L, LUA_MATHLIBNAME, mathlib); - lua_pushnumber(L, PI); - lua_setfield(L, -2, "pi"); - lua_pushnumber(L, HUGE_VAL); - lua_setfield(L, -2, "huge"); - #if LUA_COMPAT_MOD - lua_getfield(L, -1, "fmod"); - lua_setfield(L, -2, "mod"); - #endif - return 1; - } - - } -} +/* +** $Id: lmathlib.c,v 1.67.1.1 2007/12/27 13:02:25 roberto Exp $ +** Standard mathematical library +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace KopiLua +{ + using lua_Number = System.Double; + + public partial class Lua + { + public const double PI = 3.14159265358979323846; + public const double RADIANS_PER_DEGREE = PI / 180.0; + + + + private static int math_abs (lua_State L) { + lua_pushnumber(L, Math.Abs(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_sin (lua_State L) { + lua_pushnumber(L, Math.Sin(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_sinh (lua_State L) { + lua_pushnumber(L, Math.Sinh(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_cos (lua_State L) { + lua_pushnumber(L, Math.Cos(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_cosh (lua_State L) { + lua_pushnumber(L, Math.Cosh(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_tan (lua_State L) { + lua_pushnumber(L, Math.Tan(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_tanh (lua_State L) { + lua_pushnumber(L, Math.Tanh(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_asin (lua_State L) { + lua_pushnumber(L, Math.Asin(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_acos (lua_State L) { + lua_pushnumber(L, Math.Acos(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_atan (lua_State L) { + lua_pushnumber(L, Math.Atan(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_atan2 (lua_State L) { + lua_pushnumber(L, Math.Atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); + return 1; + } + + private static int math_ceil (lua_State L) { + lua_pushnumber(L, Math.Ceiling(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_floor (lua_State L) { + lua_pushnumber(L, Math.Floor(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_fmod (lua_State L) { + lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); + return 1; + } + + private static int math_modf (lua_State L) { + double ip; + double fp = modf(luaL_checknumber(L, 1), out ip); + lua_pushnumber(L, ip); + lua_pushnumber(L, fp); + return 2; + } + + private static int math_sqrt (lua_State L) { + lua_pushnumber(L, Math.Sqrt(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_pow (lua_State L) { + lua_pushnumber(L, Math.Pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); + return 1; + } + + private static int math_log (lua_State L) { + lua_pushnumber(L, Math.Log(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_log10 (lua_State L) { + lua_pushnumber(L, Math.Log10(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_exp (lua_State L) { + lua_pushnumber(L, Math.Exp(luaL_checknumber(L, 1))); + return 1; + } + + private static int math_deg (lua_State L) { + lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE); + return 1; + } + + private static int math_rad (lua_State L) { + lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE); + return 1; + } + + private static int math_frexp (lua_State L) { + int e; + lua_pushnumber(L, frexp(luaL_checknumber(L, 1), out e)); + lua_pushinteger(L, e); + return 2; + } + + private static int math_ldexp (lua_State L) { + lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2))); + return 1; + } + + + + private static int math_min (lua_State L) { + int n = lua_gettop(L); /* number of arguments */ + lua_Number dmin = luaL_checknumber(L, 1); + int i; + for (i=2; i<=n; i++) { + lua_Number d = luaL_checknumber(L, i); + if (d < dmin) + dmin = d; + } + lua_pushnumber(L, dmin); + return 1; + } + + + private static int math_max (lua_State L) { + int n = lua_gettop(L); /* number of arguments */ + lua_Number dmax = luaL_checknumber(L, 1); + int i; + for (i=2; i<=n; i++) { + lua_Number d = luaL_checknumber(L, i); + if (d > dmax) + dmax = d; + } + lua_pushnumber(L, dmax); + return 1; + } + + private static Random rng = new Random(); + + private static int math_random (lua_State L) { + /* the `%' avoids the (rare) case of r==1, and is needed also because on + some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */ + //lua_Number r = (lua_Number)(rng.Next()%RAND_MAX) / (lua_Number)RAND_MAX; + lua_Number r = (lua_Number)rng.NextDouble(); + switch (lua_gettop(L)) { /* check number of arguments */ + case 0: { /* no arguments */ + lua_pushnumber(L, r); /* Number between 0 and 1 */ + break; + } + case 1: { /* only upper limit */ + int u = luaL_checkint(L, 1); + luaL_argcheck(L, 1<=u, 1, "interval is empty"); + lua_pushnumber(L, Math.Floor(r*u)+1); /* int between 1 and `u' */ + break; + } + case 2: { /* lower and upper limits */ + int l = luaL_checkint(L, 1); + int u = luaL_checkint(L, 2); + luaL_argcheck(L, l<=u, 2, "interval is empty"); + lua_pushnumber(L, Math.Floor(r * (u - l + 1)) + l); /* int between `l' and `u' */ + break; + } + default: return luaL_error(L, "wrong number of arguments"); + } + return 1; + } + + + private static int math_randomseed (lua_State L) { + //srand(luaL_checkint(L, 1)); + rng = new Random(luaL_checkint(L, 1)); + return 0; + } + + + private readonly static luaL_Reg[] mathlib = { + new luaL_Reg("abs", math_abs), + new luaL_Reg("acos", math_acos), + new luaL_Reg("asin", math_asin), + new luaL_Reg("atan2", math_atan2), + new luaL_Reg("atan", math_atan), + new luaL_Reg("ceil", math_ceil), + new luaL_Reg("cosh", math_cosh), + new luaL_Reg("cos", math_cos), + new luaL_Reg("deg", math_deg), + new luaL_Reg("exp", math_exp), + new luaL_Reg("floor", math_floor), + new luaL_Reg("fmod", math_fmod), + new luaL_Reg("frexp", math_frexp), + new luaL_Reg("ldexp", math_ldexp), + new luaL_Reg("log10", math_log10), + new luaL_Reg("log", math_log), + new luaL_Reg("max", math_max), + new luaL_Reg("min", math_min), + new luaL_Reg("modf", math_modf), + new luaL_Reg("pow", math_pow), + new luaL_Reg("rad", math_rad), + new luaL_Reg("random", math_random), + new luaL_Reg("randomseed", math_randomseed), + new luaL_Reg("sinh", math_sinh), + new luaL_Reg("sin", math_sin), + new luaL_Reg("sqrt", math_sqrt), + new luaL_Reg("tanh", math_tanh), + new luaL_Reg("tan", math_tan), + new luaL_Reg(null, null) + }; + + + /* + ** Open math library + */ + public static int luaopen_math (lua_State L) { + luaL_register(L, LUA_MATHLIBNAME, mathlib); + lua_pushnumber(L, PI); + lua_setfield(L, -2, "pi"); + lua_pushnumber(L, HUGE_VAL); + lua_setfield(L, -2, "huge"); + #if LUA_COMPAT_MOD + lua_getfield(L, -1, "fmod"); + lua_setfield(L, -2, "mod"); + #endif + return 1; + } + + } +} diff --git a/Core/KopiLua/lmem.cs b/Core/KopiLua/lmem.cs index c6fc51b4843edd5fe98215384b554a187f98fcc9..662069d9e8261c1cc49f3a11f6a03694b7ca22c5 100644 --- a/Core/KopiLua/lmem.cs +++ b/Core/KopiLua/lmem.cs @@ -1,187 +1,187 @@ -/* -** $Id: lmem.c,v 1.70.1.1 2007/12/27 13:02:25 roberto Exp $ -** Interface to Memory Manager -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; -using System.Diagnostics; - -namespace KopiLua -{ - public partial class Lua - { - public const string MEMERRMSG = "not enough memory"; - - public static T[] luaM_reallocv(lua_State L, T[] block, int new_size) - { - return (T[])luaM_realloc_(L, block, new_size); - } - - //#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) - //#define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) - //public static void luaM_freearray(lua_State L, object b, int n, Type t) { luaM_reallocv(L, b, n, 0, Marshal.SizeOf(b)); } - - // C# has it's own gc, so nothing to do here...in theory... - public static void luaM_freemem(lua_State L, T b) { luaM_realloc_(L, new T[] {b}, 0); } - public static void luaM_free(lua_State L, T b) { luaM_realloc_(L, new T[] {b}, 0); } - public static void luaM_freearray(lua_State L, T[] b) { luaM_reallocv(L, b, 0); } - - public static T luaM_malloc(lua_State L) { return (T)luaM_realloc_(L); } - public static T luaM_new(lua_State L) { return (T)luaM_realloc_(L); } - public static T[] luaM_newvector(lua_State L, int n) - { - return luaM_reallocv(L, null, n); - } - - public static void luaM_growvector(lua_State L, ref T[] v, int nelems, ref int size, int limit, CharPtr e) - { - if (nelems + 1 > size) - v = (T[])luaM_growaux_(L, ref v, ref size, limit, e); - } - - public static T[] luaM_reallocvector(lua_State L, ref T[] v, int oldn, int n) - { - Debug.Assert((v == null && oldn == 0) || (v.Length == oldn)); - v = luaM_reallocv(L, v, n); - return v; - } - - - /* - ** About the realloc function: - ** void * frealloc (void *ud, void *ptr, uint osize, uint nsize); - ** (`osize' is the old size, `nsize' is the new size) - ** - ** Lua ensures that (ptr == null) iff (osize == 0). - ** - ** * frealloc(ud, null, 0, x) creates a new block of size `x' - ** - ** * frealloc(ud, p, x, 0) frees the block `p' - ** (in this specific case, frealloc must return null). - ** particularly, frealloc(ud, null, 0, 0) does nothing - ** (which is equivalent to free(null) in ANSI C) - ** - ** frealloc returns null if it cannot create or reallocate the area - ** (any reallocation to an equal or smaller size cannot fail!) - */ - - - - public const int MINSIZEARRAY = 4; - - - public static T[] luaM_growaux_(lua_State L, ref T[] block, ref int size, - int limit, CharPtr errormsg) - { - T[] newblock; - int newsize; - if (size >= limit / 2) - { /* cannot double it? */ - if (size >= limit) /* cannot grow even a little? */ - luaG_runerror(L, errormsg); - newsize = limit; /* still have at least one free place */ - } - else - { - newsize = size * 2; - if (newsize < MINSIZEARRAY) - newsize = MINSIZEARRAY; /* minimum size */ - } - newblock = luaM_reallocv(L, block, newsize); - size = newsize; /* update only when everything else is OK */ - return newblock; - } - - - public static object luaM_toobig (lua_State L) { - luaG_runerror(L, "memory allocation error: block too big"); - return null; /* to avoid warnings */ - } - - - - /* - ** generic allocation routine. - */ - - public static object luaM_realloc_(lua_State L, Type t) - { - int unmanaged_size = (int)GetUnmanagedSize(t); - int nsize = unmanaged_size; - object new_obj = System.Activator.CreateInstance(t); - AddTotalBytes(L, nsize); - return new_obj; - } - - public static object luaM_realloc_(lua_State L) - { - int unmanaged_size = (int)GetUnmanagedSize(typeof(T)); - int nsize = unmanaged_size; - T new_obj = (T)System.Activator.CreateInstance(typeof(T)); - AddTotalBytes(L, nsize); - return new_obj; - } - - public static object luaM_realloc_(lua_State L, T obj) - { - int unmanaged_size = (int)GetUnmanagedSize(typeof(T)); - int old_size = (obj == null) ? 0 : unmanaged_size; - int osize = old_size * unmanaged_size; - int nsize = unmanaged_size; - T new_obj = (T)System.Activator.CreateInstance(typeof(T)); - SubtractTotalBytes(L, osize); - AddTotalBytes(L, nsize); - return new_obj; - } - - public static object luaM_realloc_(lua_State L, T[] old_block, int new_size) - { - int unmanaged_size = (int)GetUnmanagedSize(typeof(T)); - int old_size = (old_block == null) ? 0 : old_block.Length; - int osize = old_size * unmanaged_size; - int nsize = new_size * unmanaged_size; - T[] new_block = new T[new_size]; - for (int i = 0; i < Math.Min(old_size, new_size); i++) - new_block[i] = old_block[i]; - for (int i = old_size; i < new_size; i++) - new_block[i] = (T)System.Activator.CreateInstance(typeof(T)); - if (CanIndex(typeof(T))) - for (int i = 0; i < new_size; i++) - { - ArrayElement elem = new_block[i] as ArrayElement; - Debug.Assert(elem != null, String.Format("Need to derive type {0} from ArrayElement", typeof(T).ToString())); - elem.set_index(i); - elem.set_array(new_block); - } - SubtractTotalBytes(L, osize); - AddTotalBytes(L, nsize); - return new_block; - } - - public static bool CanIndex(Type t) - { - if (t == typeof(char)) - return false; - if (t == typeof(byte)) - return false; - if (t == typeof(int)) - return false; - if (t == typeof(uint)) - return false; - if (t == typeof(LocVar)) - return false; - return true; - } - - static void AddTotalBytes(lua_State L, int num_bytes) { G(L).totalbytes += (uint)num_bytes; } - static void SubtractTotalBytes(lua_State L, int num_bytes) { G(L).totalbytes -= (uint)num_bytes; } - - static void AddTotalBytes(lua_State L, uint num_bytes) {G(L).totalbytes += num_bytes;} - static void SubtractTotalBytes(lua_State L, uint num_bytes) {G(L).totalbytes -= num_bytes;} - } -} +/* +** $Id: lmem.c,v 1.70.1.1 2007/12/27 13:02:25 roberto Exp $ +** Interface to Memory Manager +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Diagnostics; + +namespace KopiLua +{ + public partial class Lua + { + public const string MEMERRMSG = "not enough memory"; + + public static T[] luaM_reallocv(lua_State L, T[] block, int new_size) + { + return (T[])luaM_realloc_(L, block, new_size); + } + + //#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) + //#define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) + //public static void luaM_freearray(lua_State L, object b, int n, Type t) { luaM_reallocv(L, b, n, 0, Marshal.SizeOf(b)); } + + // C# has it's own gc, so nothing to do here...in theory... + public static void luaM_freemem(lua_State L, T b) { luaM_realloc_(L, new T[] {b}, 0); } + public static void luaM_free(lua_State L, T b) { luaM_realloc_(L, new T[] {b}, 0); } + public static void luaM_freearray(lua_State L, T[] b) { luaM_reallocv(L, b, 0); } + + public static T luaM_malloc(lua_State L) { return (T)luaM_realloc_(L); } + public static T luaM_new(lua_State L) { return (T)luaM_realloc_(L); } + public static T[] luaM_newvector(lua_State L, int n) + { + return luaM_reallocv(L, null, n); + } + + public static void luaM_growvector(lua_State L, ref T[] v, int nelems, ref int size, int limit, CharPtr e) + { + if (nelems + 1 > size) + v = (T[])luaM_growaux_(L, ref v, ref size, limit, e); + } + + public static T[] luaM_reallocvector(lua_State L, ref T[] v, int oldn, int n) + { + Debug.Assert((v == null && oldn == 0) || (v.Length == oldn)); + v = luaM_reallocv(L, v, n); + return v; + } + + + /* + ** About the realloc function: + ** void * frealloc (void *ud, void *ptr, uint osize, uint nsize); + ** (`osize' is the old size, `nsize' is the new size) + ** + ** Lua ensures that (ptr == null) iff (osize == 0). + ** + ** * frealloc(ud, null, 0, x) creates a new block of size `x' + ** + ** * frealloc(ud, p, x, 0) frees the block `p' + ** (in this specific case, frealloc must return null). + ** particularly, frealloc(ud, null, 0, 0) does nothing + ** (which is equivalent to free(null) in ANSI C) + ** + ** frealloc returns null if it cannot create or reallocate the area + ** (any reallocation to an equal or smaller size cannot fail!) + */ + + + + public const int MINSIZEARRAY = 4; + + + public static T[] luaM_growaux_(lua_State L, ref T[] block, ref int size, + int limit, CharPtr errormsg) + { + T[] newblock; + int newsize; + if (size >= limit / 2) + { /* cannot double it? */ + if (size >= limit) /* cannot grow even a little? */ + luaG_runerror(L, errormsg); + newsize = limit; /* still have at least one free place */ + } + else + { + newsize = size * 2; + if (newsize < MINSIZEARRAY) + newsize = MINSIZEARRAY; /* minimum size */ + } + newblock = luaM_reallocv(L, block, newsize); + size = newsize; /* update only when everything else is OK */ + return newblock; + } + + + public static object luaM_toobig (lua_State L) { + luaG_runerror(L, "memory allocation error: block too big"); + return null; /* to avoid warnings */ + } + + + + /* + ** generic allocation routine. + */ + + public static object luaM_realloc_(lua_State L, Type t) + { + int unmanaged_size = (int)GetUnmanagedSize(t); + int nsize = unmanaged_size; + object new_obj = System.Activator.CreateInstance(t); + AddTotalBytes(L, nsize); + return new_obj; + } + + public static object luaM_realloc_(lua_State L) + { + int unmanaged_size = (int)GetUnmanagedSize(typeof(T)); + int nsize = unmanaged_size; + T new_obj = (T)System.Activator.CreateInstance(typeof(T)); + AddTotalBytes(L, nsize); + return new_obj; + } + + public static object luaM_realloc_(lua_State L, T obj) + { + int unmanaged_size = (int)GetUnmanagedSize(typeof(T)); + int old_size = (obj == null) ? 0 : unmanaged_size; + int osize = old_size * unmanaged_size; + int nsize = unmanaged_size; + T new_obj = (T)System.Activator.CreateInstance(typeof(T)); + SubtractTotalBytes(L, osize); + AddTotalBytes(L, nsize); + return new_obj; + } + + public static object luaM_realloc_(lua_State L, T[] old_block, int new_size) + { + int unmanaged_size = (int)GetUnmanagedSize(typeof(T)); + int old_size = (old_block == null) ? 0 : old_block.Length; + int osize = old_size * unmanaged_size; + int nsize = new_size * unmanaged_size; + T[] new_block = new T[new_size]; + for (int i = 0; i < Math.Min(old_size, new_size); i++) + new_block[i] = old_block[i]; + for (int i = old_size; i < new_size; i++) + new_block[i] = (T)System.Activator.CreateInstance(typeof(T)); + if (CanIndex(typeof(T))) + for (int i = 0; i < new_size; i++) + { + ArrayElement elem = new_block[i] as ArrayElement; + Debug.Assert(elem != null, String.Format("Need to derive type {0} from ArrayElement", typeof(T).ToString())); + elem.set_index(i); + elem.set_array(new_block); + } + SubtractTotalBytes(L, osize); + AddTotalBytes(L, nsize); + return new_block; + } + + public static bool CanIndex(Type t) + { + if (t == typeof(char)) + return false; + if (t == typeof(byte)) + return false; + if (t == typeof(int)) + return false; + if (t == typeof(uint)) + return false; + if (t == typeof(LocVar)) + return false; + return true; + } + + static void AddTotalBytes(lua_State L, int num_bytes) { G(L).totalbytes += (uint)num_bytes; } + static void SubtractTotalBytes(lua_State L, int num_bytes) { G(L).totalbytes -= (uint)num_bytes; } + + static void AddTotalBytes(lua_State L, uint num_bytes) {G(L).totalbytes += num_bytes;} + static void SubtractTotalBytes(lua_State L, uint num_bytes) {G(L).totalbytes -= num_bytes;} + } +} diff --git a/Core/KopiLua/loadlib.cs b/Core/KopiLua/loadlib.cs index cb241331c61690f292a0d84e4fbf91c9b8b9b681..87568290a57c7b301cc1a2162ffc16ab5a189699 100644 --- a/Core/KopiLua/loadlib.cs +++ b/Core/KopiLua/loadlib.cs @@ -1,668 +1,668 @@ -/* -** $Id: loadlib.c,v 1.52.1.3 2008/08/06 13:29:28 roberto Exp $ -** Dynamic library loader for Lua -** See Copyright Notice in lua.h -** -** This module contains an implementation of loadlib for Unix systems -** that have dlfcn, an implementation for Darwin (Mac OS X), an -** implementation for Windows, and a stub for other systems. -*/ - -using System; -using System.IO; -using System.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; -using System.Diagnostics; - -namespace KopiLua -{ - public partial class Lua - { - - /* prefix for open functions in C libraries */ - public const string LUA_POF = "luaopen_"; - - /* separator for open functions in C libraries */ - public const string LUA_OFSEP = "_"; - - - public const string LIBPREFIX = "LOADLIB: "; - - public const string POF = LUA_POF; - public const string LIB_FAIL = "open"; - - - /* error codes for ll_loadfunc */ - public const int ERRLIB = 1; - public const int ERRFUNC = 2; - - //public static void setprogdir(lua_State L) { } - - public static void setprogdir(lua_State L) - { - CharPtr buff = Directory.GetCurrentDirectory(); - luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); - lua_remove(L, -2); /* remove original string */ - } - - - #if LUA_DL_DLOPEN - /* - ** {======================================================================== - ** This is an implementation of loadlib based on the dlfcn interface. - ** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, - ** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least - ** as an emulation layer on top of native functions. - ** ========================================================================= - */ - - //#include - - static void ll_unloadlib (void *lib) { - dlclose(lib); - } - - - static void *ll_load (lua_State L, readonly CharPtr path) { - void *lib = dlopen(path, RTLD_NOW); - if (lib == null) lua_pushstring(L, dlerror()); - return lib; - } - - - static lua_CFunction ll_sym (lua_State L, void *lib, readonly CharPtr sym) { - lua_CFunction f = (lua_CFunction)dlsym(lib, sym); - if (f == null) lua_pushstring(L, dlerror()); - return f; - } - - /* }====================================================== */ - - - - //#elif defined(LUA_DL_DLL) - /* - ** {====================================================================== - ** This is an implementation of loadlib for Windows using native functions. - ** ======================================================================= - */ - - //#include - - - //#undef setprogdir - - static void setprogdir (lua_State L) { - char buff[MAX_PATH + 1]; - char *lb; - DWORD nsize = sizeof(buff)/GetUnmanagedSize(typeof(char)); - DWORD n = GetModuleFileNameA(null, buff, nsize); - if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == null) - luaL_error(L, "unable to get ModuleFileName"); - else { - *lb = '\0'; - luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); - lua_remove(L, -2); /* remove original string */ - } - } - - - static void pusherror (lua_State L) { - int error = GetLastError(); - char buffer[128]; - if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, - null, error, 0, buffer, sizeof(buffer), null)) - lua_pushstring(L, buffer); - else - lua_pushfstring(L, "system error %d\n", error); - } - - static void ll_unloadlib (void *lib) { - FreeLibrary((HINSTANCE)lib); - } - - - static void *ll_load (lua_State L, readonly CharPtr path) { - HINSTANCE lib = LoadLibraryA(path); - if (lib == null) pusherror(L); - return lib; - } - - - static lua_CFunction ll_sym (lua_State L, void *lib, readonly CharPtr sym) { - lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); - if (f == null) pusherror(L); - return f; - } - - /* }====================================================== */ - - - -#elif LUA_DL_DYLD - /* - ** {====================================================================== - ** Native Mac OS X / Darwin Implementation - ** ======================================================================= - */ - - //#include - - - /* Mac appends a `_' before C function names */ - //#undef POF - //#define POF "_" LUA_POF - - - static void pusherror (lua_State L) { - CharPtr err_str; - CharPtr err_file; - NSLinkEditErrors err; - int err_num; - NSLinkEditError(err, err_num, err_file, err_str); - lua_pushstring(L, err_str); - } - - - static CharPtr errorfromcode (NSObjectFileImageReturnCode ret) { - switch (ret) { - case NSObjectFileImageInappropriateFile: - return "file is not a bundle"; - case NSObjectFileImageArch: - return "library is for wrong CPU type"; - case NSObjectFileImageFormat: - return "bad format"; - case NSObjectFileImageAccess: - return "cannot access file"; - case NSObjectFileImageFailure: - default: - return "unable to load library"; - } - } - - - static void ll_unloadlib (void *lib) { - NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); - } - - - static void *ll_load (lua_State L, readonly CharPtr path) { - NSObjectFileImage img; - NSObjectFileImageReturnCode ret; - /* this would be a rare case, but prevents crashing if it happens */ - if(!_dyld_present()) { - lua_pushliteral(L, "dyld not present"); - return null; - } - ret = NSCreateObjectFileImageFromFile(path, img); - if (ret == NSObjectFileImageSuccess) { - NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | - NSLINKMODULE_OPTION_RETURN_ON_ERROR); - NSDestroyObjectFileImage(img); - if (mod == null) pusherror(L); - return mod; - } - lua_pushstring(L, errorfromcode(ret)); - return null; - } - - - static lua_CFunction ll_sym (lua_State L, void *lib, readonly CharPtr sym) { - NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); - if (nss == null) { - lua_pushfstring(L, "symbol " + LUA_QS + " not found", sym); - return null; - } - return (lua_CFunction)NSAddressOfSymbol(nss); - } - - /* }====================================================== */ - - - -#else - /* - ** {====================================================== - ** Fallback for other systems - ** ======================================================= - */ - - //#undef LIB_FAIL - //#define LIB_FAIL "absent" - - - public const string DLMSG = "dynamic libraries not enabled; check your Lua installation"; - - - public static void ll_unloadlib (object lib) { - //(void)lib; /* to avoid warnings */ - } - - - public static object ll_load (lua_State L, CharPtr path) { - //(void)path; /* to avoid warnings */ - lua_pushliteral(L, DLMSG); - return null; - } - - - public static lua_CFunction ll_sym (lua_State L, object lib, CharPtr sym) { - //(void)lib; (void)sym; /* to avoid warnings */ - lua_pushliteral(L, DLMSG); - return null; - } - - /* }====================================================== */ - #endif - - - - private static object ll_register (lua_State L, CharPtr path) { - // todo: the whole usage of plib here is wrong, fix it - mjf - //void **plib; - object plib = null; - lua_pushfstring(L, "%s%s", LIBPREFIX, path); - lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ - if (!lua_isnil(L, -1)) /* is there an entry? */ - plib = lua_touserdata(L, -1); - else { /* no entry yet; create one */ - lua_pop(L, 1); - //plib = lua_newuserdata(L, (uint)Marshal.SizeOf(plib)); - //plib[0] = null; - luaL_getmetatable(L, "_LOADLIB"); - lua_setmetatable(L, -2); - lua_pushfstring(L, "%s%s", LIBPREFIX, path); - lua_pushvalue(L, -2); - lua_settable(L, LUA_REGISTRYINDEX); - } - return plib; - } - - - /* - ** __gc tag method: calls library's `ll_unloadlib' function with the lib - ** handle - */ - private static int gctm (lua_State L) { - object lib = luaL_checkudata(L, 1, "_LOADLIB"); - if (lib != null) ll_unloadlib(lib); - lib = null; /* mark library as closed */ - return 0; - } - - - private static int ll_loadfunc (lua_State L, CharPtr path, CharPtr sym) { - object reg = ll_register(L, path); - if (reg == null) reg = ll_load(L, path); - if (reg == null) - return ERRLIB; /* unable to load library */ - else { - lua_CFunction f = ll_sym(L, reg, sym); - if (f == null) - return ERRFUNC; /* unable to find function */ - lua_pushcfunction(L, f); - return 0; /* return function */ - } - } - - - private static int ll_loadlib (lua_State L) { - CharPtr path = luaL_checkstring(L, 1); - CharPtr init = luaL_checkstring(L, 2); - int stat = ll_loadfunc(L, path, init); - if (stat == 0) /* no errors? */ - return 1; /* return the loaded function */ - else { /* error; error message is on stack top */ - lua_pushnil(L); - lua_insert(L, -2); - lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); - return 3; /* return nil, error message, and where */ - } - } - - - - /* - ** {====================================================== - ** 'require' function - ** ======================================================= - */ - - - private static int readable (CharPtr filename) { - Stream f = fopen(filename, "r"); /* try to open file */ - if (f == null) return 0; /* open failed */ - fclose(f); - return 1; - } - - - private static CharPtr pushnexttemplate (lua_State L, CharPtr path) { - CharPtr l; - while (path[0] == LUA_PATHSEP[0]) path = path.next(); /* skip separators */ - if (path[0] == '\0') return null; /* no more templates */ - l = strchr(path, LUA_PATHSEP[0]); /* find next separator */ - if (l == null) l = path + strlen(path); - lua_pushlstring(L, path, (uint)(l - path)); /* template */ - return l; - } - - - private static CharPtr findfile (lua_State L, CharPtr name, - CharPtr pname) { - CharPtr path; - name = luaL_gsub(L, name, ".", LUA_DIRSEP); - lua_getfield(L, LUA_ENVIRONINDEX, pname); - path = lua_tostring(L, -1); - if (path == null) - luaL_error(L, LUA_QL("package.%s") + " must be a string", pname); - lua_pushliteral(L, ""); /* error accumulator */ - while ((path = pushnexttemplate(L, path)) != null) { - CharPtr filename; - filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); - lua_remove(L, -2); /* remove path template */ - if (readable(filename) != 0) /* does file exist and is readable? */ - return filename; /* return that file name */ - lua_pushfstring(L, "\n\tno file " + LUA_QS, filename); - lua_remove(L, -2); /* remove file name */ - lua_concat(L, 2); /* add entry to possible error message */ - } - return null; /* not found */ - } - - - private static void loaderror (lua_State L, CharPtr filename) { - luaL_error(L, "error loading module " + LUA_QS + " from file " + LUA_QS + ":\n\t%s", - lua_tostring(L, 1), filename, lua_tostring(L, -1)); - } - - - private static int loader_Lua (lua_State L) { - CharPtr filename; - CharPtr name = luaL_checkstring(L, 1); - filename = findfile(L, name, "path"); - if (filename == null) return 1; /* library not found in this path */ - if (luaL_loadfile(L, filename) != 0) - loaderror(L, filename); - return 1; /* library loaded successfully */ - } - - - private static CharPtr mkfuncname (lua_State L, CharPtr modname) { - CharPtr funcname; - CharPtr mark = strchr(modname, LUA_IGMARK[0]); - if (mark!=null) modname = mark + 1; - funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); - funcname = lua_pushfstring(L, POF + "%s", funcname); - lua_remove(L, -2); /* remove 'gsub' result */ - return funcname; - } - - - private static int loader_C (lua_State L) { - CharPtr funcname; - CharPtr name = luaL_checkstring(L, 1); - CharPtr filename = findfile(L, name, "cpath"); - if (filename == null) return 1; /* library not found in this path */ - funcname = mkfuncname(L, name); - if (ll_loadfunc(L, filename, funcname) != 0) - loaderror(L, filename); - return 1; /* library loaded successfully */ - } - - - private static int loader_Croot (lua_State L) { - CharPtr funcname; - CharPtr filename; - CharPtr name = luaL_checkstring(L, 1); - CharPtr p = strchr(name, '.'); - int stat; - if (p == null) return 0; /* is root */ - lua_pushlstring(L, name, (uint)(p - name)); - filename = findfile(L, lua_tostring(L, -1), "cpath"); - if (filename == null) return 1; /* root not found */ - funcname = mkfuncname(L, name); - if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { - if (stat != ERRFUNC) loaderror(L, filename); /* real error */ - lua_pushfstring(L, "\n\tno module " + LUA_QS + " in file " + LUA_QS, - name, filename); - return 1; /* function not found */ - } - return 1; - } - - - private static int loader_preload (lua_State L) { - CharPtr name = luaL_checkstring(L, 1); - lua_getfield(L, LUA_ENVIRONINDEX, "preload"); - if (!lua_istable(L, -1)) - luaL_error(L, LUA_QL("package.preload") + " must be a table"); - lua_getfield(L, -1, name); - if (lua_isnil(L, -1)) /* not found? */ - lua_pushfstring(L, "\n\tno field package.preload['%s']", name); - return 1; - } - - - public static object sentinel = new object(); - - - public static int ll_require (lua_State L) { - CharPtr name = luaL_checkstring(L, 1); - int i; - lua_settop(L, 1); /* _LOADED table will be at index 2 */ - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_getfield(L, 2, name); - if (lua_toboolean(L, -1) != 0) { /* is it there? */ - if (lua_touserdata(L, -1) == sentinel) /* check loops */ - luaL_error(L, "loop or previous error loading module " + LUA_QS, name); - return 1; /* package is already loaded */ - } - /* else must load it; iterate over available loaders */ - lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); - if (!lua_istable(L, -1)) - luaL_error(L, LUA_QL("package.loaders") + " must be a table"); - lua_pushliteral(L, ""); /* error message accumulator */ - for (i=1; ; i++) { - lua_rawgeti(L, -2, i); /* get a loader */ - if (lua_isnil(L, -1)) - luaL_error(L, "module " + LUA_QS + " not found:%s", - name, lua_tostring(L, -2)); - lua_pushstring(L, name); - lua_call(L, 1, 1); /* call it */ - if (lua_isfunction(L, -1)) /* did it find module? */ - break; /* module loaded successfully */ - else if (lua_isstring(L, -1) != 0) /* loader returned error message? */ - lua_concat(L, 2); /* accumulate it */ - else - lua_pop(L, 1); - } - lua_pushlightuserdata(L, sentinel); - lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ - lua_pushstring(L, name); /* pass name as argument to module */ - lua_call(L, 1, 1); /* run loaded module */ - if (!lua_isnil(L, -1)) /* non-nil return? */ - lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ - lua_getfield(L, 2, name); - if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ - lua_pushboolean(L, 1); /* use true as result */ - lua_pushvalue(L, -1); /* extra copy to be returned */ - lua_setfield(L, 2, name); /* _LOADED[name] = true */ - } - return 1; - } - - /* }====================================================== */ - - - - /* - ** {====================================================== - ** 'module' function - ** ======================================================= - */ - - - private static void setfenv (lua_State L) { - lua_Debug ar = new lua_Debug(); - if (lua_getstack(L, 1, ar) == 0 || - lua_getinfo(L, "f", ar) == 0 || /* get calling function */ - lua_iscfunction(L, -1)) - luaL_error(L, LUA_QL("module") + " not called from a Lua function"); - lua_pushvalue(L, -2); - lua_setfenv(L, -2); - lua_pop(L, 1); - } - - - private static void dooptions (lua_State L, int n) { - int i; - for (i = 2; i <= n; i++) { - lua_pushvalue(L, i); /* get option (a function) */ - lua_pushvalue(L, -2); /* module */ - lua_call(L, 1, 0); - } - } - - - private static void modinit (lua_State L, CharPtr modname) { - CharPtr dot; - lua_pushvalue(L, -1); - lua_setfield(L, -2, "_M"); /* module._M = module */ - lua_pushstring(L, modname); - lua_setfield(L, -2, "_NAME"); - dot = strrchr(modname, '.'); /* look for last dot in module name */ - if (dot == null) dot = modname; - else dot = dot.next(); - /* set _PACKAGE as package name (full module name minus last part) */ - lua_pushlstring(L, modname, (uint)(dot - modname)); - lua_setfield(L, -2, "_PACKAGE"); - } - - - private static int ll_module (lua_State L) { - CharPtr modname = luaL_checkstring(L, 1); - int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ - lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); - lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ - if (!lua_istable(L, -1)) { /* not found? */ - lua_pop(L, 1); /* remove previous result */ - /* try global variable (and create one if it does not exist) */ - if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != null) - return luaL_error(L, "name conflict for module " + LUA_QS, modname); - lua_pushvalue(L, -1); - lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ - } - /* check whether table already has a _NAME field */ - lua_getfield(L, -1, "_NAME"); - if (!lua_isnil(L, -1)) /* is table an initialized module? */ - lua_pop(L, 1); - else { /* no; initialize it */ - lua_pop(L, 1); - modinit(L, modname); - } - lua_pushvalue(L, -1); - setfenv(L); - dooptions(L, loaded - 1); - return 0; - } - - - private static int ll_seeall (lua_State L) { - luaL_checktype(L, 1, LUA_TTABLE); - if (lua_getmetatable(L, 1)==0) { - lua_createtable(L, 0, 1); /* create new metatable */ - lua_pushvalue(L, -1); - lua_setmetatable(L, 1); - } - lua_pushvalue(L, LUA_GLOBALSINDEX); - lua_setfield(L, -2, "__index"); /* mt.__index = _G */ - return 0; - } - - - /* }====================================================== */ - - - - /* auxiliary mark (for internal use) */ - public readonly static string AUXMARK = String.Format("{0}", (char)1); - - private static void setpath (lua_State L, CharPtr fieldname, CharPtr envname, - CharPtr def) { - CharPtr path = getenv(envname); - if (path == null) /* no environment variable? */ - lua_pushstring(L, def); /* use default */ - else { - /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ - path = luaL_gsub(L, path, LUA_PATHSEP + LUA_PATHSEP, - LUA_PATHSEP + AUXMARK + LUA_PATHSEP); - luaL_gsub(L, path, AUXMARK, def); - lua_remove(L, -2); - } - setprogdir(L); - lua_setfield(L, -2, fieldname); - } - - - private readonly static luaL_Reg[] pk_funcs = { - new luaL_Reg("loadlib", ll_loadlib), - new luaL_Reg("seeall", ll_seeall), - new luaL_Reg(null, null) - }; - - - private readonly static luaL_Reg[] ll_funcs = { - new luaL_Reg("module", ll_module), - new luaL_Reg("require", ll_require), - new luaL_Reg(null, null) - }; - - - public readonly static lua_CFunction[] loaders = - {loader_preload, loader_Lua, loader_C, loader_Croot, null}; - - - public static int luaopen_package (lua_State L) { - int i; - /* create new type _LOADLIB */ - luaL_newmetatable(L, "_LOADLIB"); - lua_pushcfunction(L, gctm); - lua_setfield(L, -2, "__gc"); - /* create `package' table */ - luaL_register(L, LUA_LOADLIBNAME, pk_funcs); - #if LUA_COMPAT_LOADLIB - lua_getfield(L, -1, "loadlib"); - lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); - #endif - lua_pushvalue(L, -1); - lua_replace(L, LUA_ENVIRONINDEX); - /* create `loaders' table */ - lua_createtable(L, loaders.Length - 1, 0); - /* fill it with pre-defined loaders */ - for (i=0; loaders[i] != null; i++) { - lua_pushcfunction(L, loaders[i]); - lua_rawseti(L, -2, i+1); - } - lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ - setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */ - setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ - /* store config information */ - lua_pushliteral(L, LUA_DIRSEP + "\n" + LUA_PATHSEP + "\n" + LUA_PATH_MARK + "\n" + - LUA_EXECDIR + "\n" + LUA_IGMARK); - lua_setfield(L, -2, "config"); - /* set field `loaded' */ - luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); - lua_setfield(L, -2, "loaded"); - /* set field `preload' */ - lua_newtable(L); - lua_setfield(L, -2, "preload"); - lua_pushvalue(L, LUA_GLOBALSINDEX); - luaL_register(L, null, ll_funcs); /* open lib into global table */ - lua_pop(L, 1); - return 1; /* return 'package' table */ - } - - } -} +/* +** $Id: loadlib.c,v 1.52.1.3 2008/08/06 13:29:28 roberto Exp $ +** Dynamic library loader for Lua +** See Copyright Notice in lua.h +** +** This module contains an implementation of loadlib for Unix systems +** that have dlfcn, an implementation for Darwin (Mac OS X), an +** implementation for Windows, and a stub for other systems. +*/ + +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Diagnostics; + +namespace KopiLua +{ + public partial class Lua + { + + /* prefix for open functions in C libraries */ + public const string LUA_POF = "luaopen_"; + + /* separator for open functions in C libraries */ + public const string LUA_OFSEP = "_"; + + + public const string LIBPREFIX = "LOADLIB: "; + + public const string POF = LUA_POF; + public const string LIB_FAIL = "open"; + + + /* error codes for ll_loadfunc */ + public const int ERRLIB = 1; + public const int ERRFUNC = 2; + + //public static void setprogdir(lua_State L) { } + + public static void setprogdir(lua_State L) + { + CharPtr buff = Directory.GetCurrentDirectory(); + luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); + lua_remove(L, -2); /* remove original string */ + } + + + #if LUA_DL_DLOPEN + /* + ** {======================================================================== + ** This is an implementation of loadlib based on the dlfcn interface. + ** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, + ** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least + ** as an emulation layer on top of native functions. + ** ========================================================================= + */ + + //#include + + static void ll_unloadlib (void *lib) { + dlclose(lib); + } + + + static void *ll_load (lua_State L, readonly CharPtr path) { + void *lib = dlopen(path, RTLD_NOW); + if (lib == null) lua_pushstring(L, dlerror()); + return lib; + } + + + static lua_CFunction ll_sym (lua_State L, void *lib, readonly CharPtr sym) { + lua_CFunction f = (lua_CFunction)dlsym(lib, sym); + if (f == null) lua_pushstring(L, dlerror()); + return f; + } + + /* }====================================================== */ + + + + //#elif defined(LUA_DL_DLL) + /* + ** {====================================================================== + ** This is an implementation of loadlib for Windows using native functions. + ** ======================================================================= + */ + + //#include + + + //#undef setprogdir + + static void setprogdir (lua_State L) { + char buff[MAX_PATH + 1]; + char *lb; + DWORD nsize = sizeof(buff)/GetUnmanagedSize(typeof(char)); + DWORD n = GetModuleFileNameA(null, buff, nsize); + if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == null) + luaL_error(L, "unable to get ModuleFileName"); + else { + *lb = '\0'; + luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); + lua_remove(L, -2); /* remove original string */ + } + } + + + static void pusherror (lua_State L) { + int error = GetLastError(); + char buffer[128]; + if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, + null, error, 0, buffer, sizeof(buffer), null)) + lua_pushstring(L, buffer); + else + lua_pushfstring(L, "system error %d\n", error); + } + + static void ll_unloadlib (void *lib) { + FreeLibrary((HINSTANCE)lib); + } + + + static void *ll_load (lua_State L, readonly CharPtr path) { + HINSTANCE lib = LoadLibraryA(path); + if (lib == null) pusherror(L); + return lib; + } + + + static lua_CFunction ll_sym (lua_State L, void *lib, readonly CharPtr sym) { + lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); + if (f == null) pusherror(L); + return f; + } + + /* }====================================================== */ + + + +#elif LUA_DL_DYLD + /* + ** {====================================================================== + ** Native Mac OS X / Darwin Implementation + ** ======================================================================= + */ + + //#include + + + /* Mac appends a `_' before C function names */ + //#undef POF + //#define POF "_" LUA_POF + + + static void pusherror (lua_State L) { + CharPtr err_str; + CharPtr err_file; + NSLinkEditErrors err; + int err_num; + NSLinkEditError(err, err_num, err_file, err_str); + lua_pushstring(L, err_str); + } + + + static CharPtr errorfromcode (NSObjectFileImageReturnCode ret) { + switch (ret) { + case NSObjectFileImageInappropriateFile: + return "file is not a bundle"; + case NSObjectFileImageArch: + return "library is for wrong CPU type"; + case NSObjectFileImageFormat: + return "bad format"; + case NSObjectFileImageAccess: + return "cannot access file"; + case NSObjectFileImageFailure: + default: + return "unable to load library"; + } + } + + + static void ll_unloadlib (void *lib) { + NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); + } + + + static void *ll_load (lua_State L, readonly CharPtr path) { + NSObjectFileImage img; + NSObjectFileImageReturnCode ret; + /* this would be a rare case, but prevents crashing if it happens */ + if(!_dyld_present()) { + lua_pushliteral(L, "dyld not present"); + return null; + } + ret = NSCreateObjectFileImageFromFile(path, img); + if (ret == NSObjectFileImageSuccess) { + NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | + NSLINKMODULE_OPTION_RETURN_ON_ERROR); + NSDestroyObjectFileImage(img); + if (mod == null) pusherror(L); + return mod; + } + lua_pushstring(L, errorfromcode(ret)); + return null; + } + + + static lua_CFunction ll_sym (lua_State L, void *lib, readonly CharPtr sym) { + NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); + if (nss == null) { + lua_pushfstring(L, "symbol " + LUA_QS + " not found", sym); + return null; + } + return (lua_CFunction)NSAddressOfSymbol(nss); + } + + /* }====================================================== */ + + + +#else + /* + ** {====================================================== + ** Fallback for other systems + ** ======================================================= + */ + + //#undef LIB_FAIL + //#define LIB_FAIL "absent" + + + public const string DLMSG = "dynamic libraries not enabled; check your Lua installation"; + + + public static void ll_unloadlib (object lib) { + //(void)lib; /* to avoid warnings */ + } + + + public static object ll_load (lua_State L, CharPtr path) { + //(void)path; /* to avoid warnings */ + lua_pushliteral(L, DLMSG); + return null; + } + + + public static lua_CFunction ll_sym (lua_State L, object lib, CharPtr sym) { + //(void)lib; (void)sym; /* to avoid warnings */ + lua_pushliteral(L, DLMSG); + return null; + } + + /* }====================================================== */ + #endif + + + + private static object ll_register (lua_State L, CharPtr path) { + // todo: the whole usage of plib here is wrong, fix it - mjf + //void **plib; + object plib = null; + lua_pushfstring(L, "%s%s", LIBPREFIX, path); + lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ + if (!lua_isnil(L, -1)) /* is there an entry? */ + plib = lua_touserdata(L, -1); + else { /* no entry yet; create one */ + lua_pop(L, 1); + //plib = lua_newuserdata(L, (uint)Marshal.SizeOf(plib)); + //plib[0] = null; + luaL_getmetatable(L, "_LOADLIB"); + lua_setmetatable(L, -2); + lua_pushfstring(L, "%s%s", LIBPREFIX, path); + lua_pushvalue(L, -2); + lua_settable(L, LUA_REGISTRYINDEX); + } + return plib; + } + + + /* + ** __gc tag method: calls library's `ll_unloadlib' function with the lib + ** handle + */ + private static int gctm (lua_State L) { + object lib = luaL_checkudata(L, 1, "_LOADLIB"); + if (lib != null) ll_unloadlib(lib); + lib = null; /* mark library as closed */ + return 0; + } + + + private static int ll_loadfunc (lua_State L, CharPtr path, CharPtr sym) { + object reg = ll_register(L, path); + if (reg == null) reg = ll_load(L, path); + if (reg == null) + return ERRLIB; /* unable to load library */ + else { + lua_CFunction f = ll_sym(L, reg, sym); + if (f == null) + return ERRFUNC; /* unable to find function */ + lua_pushcfunction(L, f); + return 0; /* return function */ + } + } + + + private static int ll_loadlib (lua_State L) { + CharPtr path = luaL_checkstring(L, 1); + CharPtr init = luaL_checkstring(L, 2); + int stat = ll_loadfunc(L, path, init); + if (stat == 0) /* no errors? */ + return 1; /* return the loaded function */ + else { /* error; error message is on stack top */ + lua_pushnil(L); + lua_insert(L, -2); + lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); + return 3; /* return nil, error message, and where */ + } + } + + + + /* + ** {====================================================== + ** 'require' function + ** ======================================================= + */ + + + private static int readable (CharPtr filename) { + Stream f = fopen(filename, "r"); /* try to open file */ + if (f == null) return 0; /* open failed */ + fclose(f); + return 1; + } + + + private static CharPtr pushnexttemplate (lua_State L, CharPtr path) { + CharPtr l; + while (path[0] == LUA_PATHSEP[0]) path = path.next(); /* skip separators */ + if (path[0] == '\0') return null; /* no more templates */ + l = strchr(path, LUA_PATHSEP[0]); /* find next separator */ + if (l == null) l = path + strlen(path); + lua_pushlstring(L, path, (uint)(l - path)); /* template */ + return l; + } + + + private static CharPtr findfile (lua_State L, CharPtr name, + CharPtr pname) { + CharPtr path; + name = luaL_gsub(L, name, ".", LUA_DIRSEP); + lua_getfield(L, LUA_ENVIRONINDEX, pname); + path = lua_tostring(L, -1); + if (path == null) + luaL_error(L, LUA_QL("package.%s") + " must be a string", pname); + lua_pushliteral(L, ""); /* error accumulator */ + while ((path = pushnexttemplate(L, path)) != null) { + CharPtr filename; + filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); + lua_remove(L, -2); /* remove path template */ + if (readable(filename) != 0) /* does file exist and is readable? */ + return filename; /* return that file name */ + lua_pushfstring(L, "\n\tno file " + LUA_QS, filename); + lua_remove(L, -2); /* remove file name */ + lua_concat(L, 2); /* add entry to possible error message */ + } + return null; /* not found */ + } + + + private static void loaderror (lua_State L, CharPtr filename) { + luaL_error(L, "error loading module " + LUA_QS + " from file " + LUA_QS + ":\n\t%s", + lua_tostring(L, 1), filename, lua_tostring(L, -1)); + } + + + private static int loader_Lua (lua_State L) { + CharPtr filename; + CharPtr name = luaL_checkstring(L, 1); + filename = findfile(L, name, "path"); + if (filename == null) return 1; /* library not found in this path */ + if (luaL_loadfile(L, filename) != 0) + loaderror(L, filename); + return 1; /* library loaded successfully */ + } + + + private static CharPtr mkfuncname (lua_State L, CharPtr modname) { + CharPtr funcname; + CharPtr mark = strchr(modname, LUA_IGMARK[0]); + if (mark!=null) modname = mark + 1; + funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); + funcname = lua_pushfstring(L, POF + "%s", funcname); + lua_remove(L, -2); /* remove 'gsub' result */ + return funcname; + } + + + private static int loader_C (lua_State L) { + CharPtr funcname; + CharPtr name = luaL_checkstring(L, 1); + CharPtr filename = findfile(L, name, "cpath"); + if (filename == null) return 1; /* library not found in this path */ + funcname = mkfuncname(L, name); + if (ll_loadfunc(L, filename, funcname) != 0) + loaderror(L, filename); + return 1; /* library loaded successfully */ + } + + + private static int loader_Croot (lua_State L) { + CharPtr funcname; + CharPtr filename; + CharPtr name = luaL_checkstring(L, 1); + CharPtr p = strchr(name, '.'); + int stat; + if (p == null) return 0; /* is root */ + lua_pushlstring(L, name, (uint)(p - name)); + filename = findfile(L, lua_tostring(L, -1), "cpath"); + if (filename == null) return 1; /* root not found */ + funcname = mkfuncname(L, name); + if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { + if (stat != ERRFUNC) loaderror(L, filename); /* real error */ + lua_pushfstring(L, "\n\tno module " + LUA_QS + " in file " + LUA_QS, + name, filename); + return 1; /* function not found */ + } + return 1; + } + + + private static int loader_preload (lua_State L) { + CharPtr name = luaL_checkstring(L, 1); + lua_getfield(L, LUA_ENVIRONINDEX, "preload"); + if (!lua_istable(L, -1)) + luaL_error(L, LUA_QL("package.preload") + " must be a table"); + lua_getfield(L, -1, name); + if (lua_isnil(L, -1)) /* not found? */ + lua_pushfstring(L, "\n\tno field package.preload['%s']", name); + return 1; + } + + + public static object sentinel = new object(); + + + public static int ll_require (lua_State L) { + CharPtr name = luaL_checkstring(L, 1); + int i; + lua_settop(L, 1); /* _LOADED table will be at index 2 */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_getfield(L, 2, name); + if (lua_toboolean(L, -1) != 0) { /* is it there? */ + if (lua_touserdata(L, -1) == sentinel) /* check loops */ + luaL_error(L, "loop or previous error loading module " + LUA_QS, name); + return 1; /* package is already loaded */ + } + /* else must load it; iterate over available loaders */ + lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); + if (!lua_istable(L, -1)) + luaL_error(L, LUA_QL("package.loaders") + " must be a table"); + lua_pushliteral(L, ""); /* error message accumulator */ + for (i=1; ; i++) { + lua_rawgeti(L, -2, i); /* get a loader */ + if (lua_isnil(L, -1)) + luaL_error(L, "module " + LUA_QS + " not found:%s", + name, lua_tostring(L, -2)); + lua_pushstring(L, name); + lua_call(L, 1, 1); /* call it */ + if (lua_isfunction(L, -1)) /* did it find module? */ + break; /* module loaded successfully */ + else if (lua_isstring(L, -1) != 0) /* loader returned error message? */ + lua_concat(L, 2); /* accumulate it */ + else + lua_pop(L, 1); + } + lua_pushlightuserdata(L, sentinel); + lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ + lua_pushstring(L, name); /* pass name as argument to module */ + lua_call(L, 1, 1); /* run loaded module */ + if (!lua_isnil(L, -1)) /* non-nil return? */ + lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ + lua_getfield(L, 2, name); + if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ + lua_pushboolean(L, 1); /* use true as result */ + lua_pushvalue(L, -1); /* extra copy to be returned */ + lua_setfield(L, 2, name); /* _LOADED[name] = true */ + } + return 1; + } + + /* }====================================================== */ + + + + /* + ** {====================================================== + ** 'module' function + ** ======================================================= + */ + + + private static void setfenv (lua_State L) { + lua_Debug ar = new lua_Debug(); + if (lua_getstack(L, 1, ar) == 0 || + lua_getinfo(L, "f", ar) == 0 || /* get calling function */ + lua_iscfunction(L, -1)) + luaL_error(L, LUA_QL("module") + " not called from a Lua function"); + lua_pushvalue(L, -2); + lua_setfenv(L, -2); + lua_pop(L, 1); + } + + + private static void dooptions (lua_State L, int n) { + int i; + for (i = 2; i <= n; i++) { + lua_pushvalue(L, i); /* get option (a function) */ + lua_pushvalue(L, -2); /* module */ + lua_call(L, 1, 0); + } + } + + + private static void modinit (lua_State L, CharPtr modname) { + CharPtr dot; + lua_pushvalue(L, -1); + lua_setfield(L, -2, "_M"); /* module._M = module */ + lua_pushstring(L, modname); + lua_setfield(L, -2, "_NAME"); + dot = strrchr(modname, '.'); /* look for last dot in module name */ + if (dot == null) dot = modname; + else dot = dot.next(); + /* set _PACKAGE as package name (full module name minus last part) */ + lua_pushlstring(L, modname, (uint)(dot - modname)); + lua_setfield(L, -2, "_PACKAGE"); + } + + + private static int ll_module (lua_State L) { + CharPtr modname = luaL_checkstring(L, 1); + int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ + lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); + lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ + if (!lua_istable(L, -1)) { /* not found? */ + lua_pop(L, 1); /* remove previous result */ + /* try global variable (and create one if it does not exist) */ + if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != null) + return luaL_error(L, "name conflict for module " + LUA_QS, modname); + lua_pushvalue(L, -1); + lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ + } + /* check whether table already has a _NAME field */ + lua_getfield(L, -1, "_NAME"); + if (!lua_isnil(L, -1)) /* is table an initialized module? */ + lua_pop(L, 1); + else { /* no; initialize it */ + lua_pop(L, 1); + modinit(L, modname); + } + lua_pushvalue(L, -1); + setfenv(L); + dooptions(L, loaded - 1); + return 0; + } + + + private static int ll_seeall (lua_State L) { + luaL_checktype(L, 1, LUA_TTABLE); + if (lua_getmetatable(L, 1)==0) { + lua_createtable(L, 0, 1); /* create new metatable */ + lua_pushvalue(L, -1); + lua_setmetatable(L, 1); + } + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_setfield(L, -2, "__index"); /* mt.__index = _G */ + return 0; + } + + + /* }====================================================== */ + + + + /* auxiliary mark (for internal use) */ + public readonly static string AUXMARK = String.Format("{0}", (char)1); + + private static void setpath (lua_State L, CharPtr fieldname, CharPtr envname, + CharPtr def) { + CharPtr path = getenv(envname); + if (path == null) /* no environment variable? */ + lua_pushstring(L, def); /* use default */ + else { + /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ + path = luaL_gsub(L, path, LUA_PATHSEP + LUA_PATHSEP, + LUA_PATHSEP + AUXMARK + LUA_PATHSEP); + luaL_gsub(L, path, AUXMARK, def); + lua_remove(L, -2); + } + setprogdir(L); + lua_setfield(L, -2, fieldname); + } + + + private readonly static luaL_Reg[] pk_funcs = { + new luaL_Reg("loadlib", ll_loadlib), + new luaL_Reg("seeall", ll_seeall), + new luaL_Reg(null, null) + }; + + + private readonly static luaL_Reg[] ll_funcs = { + new luaL_Reg("module", ll_module), + new luaL_Reg("require", ll_require), + new luaL_Reg(null, null) + }; + + + public readonly static lua_CFunction[] loaders = + {loader_preload, loader_Lua, loader_C, loader_Croot, null}; + + + public static int luaopen_package (lua_State L) { + int i; + /* create new type _LOADLIB */ + luaL_newmetatable(L, "_LOADLIB"); + lua_pushcfunction(L, gctm); + lua_setfield(L, -2, "__gc"); + /* create `package' table */ + luaL_register(L, LUA_LOADLIBNAME, pk_funcs); + #if LUA_COMPAT_LOADLIB + lua_getfield(L, -1, "loadlib"); + lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); + #endif + lua_pushvalue(L, -1); + lua_replace(L, LUA_ENVIRONINDEX); + /* create `loaders' table */ + lua_createtable(L, loaders.Length - 1, 0); + /* fill it with pre-defined loaders */ + for (i=0; loaders[i] != null; i++) { + lua_pushcfunction(L, loaders[i]); + lua_rawseti(L, -2, i+1); + } + lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ + setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */ + setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ + /* store config information */ + lua_pushliteral(L, LUA_DIRSEP + "\n" + LUA_PATHSEP + "\n" + LUA_PATH_MARK + "\n" + + LUA_EXECDIR + "\n" + LUA_IGMARK); + lua_setfield(L, -2, "config"); + /* set field `loaded' */ + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); + lua_setfield(L, -2, "loaded"); + /* set field `preload' */ + lua_newtable(L); + lua_setfield(L, -2, "preload"); + lua_pushvalue(L, LUA_GLOBALSINDEX); + luaL_register(L, null, ll_funcs); /* open lib into global table */ + lua_pop(L, 1); + return 1; /* return 'package' table */ + } + + } +} diff --git a/Core/KopiLua/lobject.cs b/Core/KopiLua/lobject.cs index ea8ad20c27f94decf9b6216a0e68673d6e3e600d..ea6b926953e63ee6e5e7544e7bc9298942aa07db 100644 --- a/Core/KopiLua/lobject.cs +++ b/Core/KopiLua/lobject.cs @@ -1,933 +1,933 @@ -/* -** $Id: lobject.c,v 2.22.1.1 2007/12/27 13:02:25 roberto Exp $ -** Some generic functions over Lua objects -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; -using System.Diagnostics; - -namespace KopiLua -{ - using TValue = Lua.lua_TValue; - using StkId = Lua.lua_TValue; - using lu_byte = System.Byte; - using lua_Number = System.Double; - using l_uacNumber = System.Double; - using Instruction = System.UInt32; - - public partial class Lua - { - /* tags for values visible from Lua */ - public const int LAST_TAG = LUA_TTHREAD; - - public const int NUM_TAGS = (LAST_TAG+1); - - - /* - ** Extra tags for non-values - */ - public const int LUA_TPROTO = (LAST_TAG+1); - public const int LUA_TUPVAL = (LAST_TAG+2); - public const int LUA_TDEADKEY = (LAST_TAG+3); - - public interface ArrayElement - { - void set_index(int index); - void set_array(object array); - } - - - /* - ** Common Header for all collectable objects (in macro form, to be - ** included in other objects) - */ - public class CommonHeader - { - public GCObject next; - public lu_byte tt; - public lu_byte marked; - } - - - /* - ** Common header in struct form - */ - public class GCheader : CommonHeader { - }; - - - - - /* - ** Union of all Lua values (in c# we use virtual data members and boxing) - */ - public class Value - { - - // in the original code Value is a struct, so all assignments in the code - // need to be replaced with a call to Copy. as it turns out, there are only - // a couple. the vast majority of references to Value are the instance that - // appears in the TValue class, so if you make that a virtual data member and - // omit the set accessor then you'll get a compiler error if anything tries - // to set it. - public void Copy(Value copy) - { - this.p = copy.p; - } - - public GCObject gc - { - get {return (GCObject)this.p;} - set {this.p = value;} - } - public object p; - public lua_Number n - { - get { return (lua_Number)this.p; } - set { this.p = (object)value; } - } - public int b - { - get { return (int)this.p; } - set { this.p = (object)value; } - } - }; - - - /* - ** Tagged Values - */ - - //#define TValuefields Value value; int tt - - public class lua_TValue : ArrayElement - { - private lua_TValue[] values = null; - private int index = -1; - - public void set_index(int index) - { - this.index = index; - } - - public void set_array(object array) - { - this.values = (lua_TValue[])array; - Debug.Assert(this.values != null); - } - - public lua_TValue this[int offset] - { - get { return this.values[this.index + offset]; } - } - - [CLSCompliantAttribute(false)] - public lua_TValue this[uint offset] - { - get { return this.values[this.index + (int)offset]; } - } - - public static lua_TValue operator +(lua_TValue value, int offset) - { - return value.values[value.index + offset]; - } - - public static lua_TValue operator +(int offset, lua_TValue value) - { - return value.values[value.index + offset]; - } - - public static lua_TValue operator -(lua_TValue value, int offset) - { - return value.values[value.index - offset]; - } - - public static int operator -(lua_TValue value, lua_TValue[] array) - { - Debug.Assert(value.values == array); - return value.index; - } - - public static int operator -(lua_TValue a, lua_TValue b) - { - Debug.Assert(a.values == b.values); - return a.index - b.index; - } - - public static bool operator <(lua_TValue a, lua_TValue b) - { - Debug.Assert(a.values == b.values); - return a.index < b.index; - } - - public static bool operator <=(lua_TValue a, lua_TValue b) - { - Debug.Assert(a.values == b.values); - return a.index <= b.index; - } - - public static bool operator >(lua_TValue a, lua_TValue b) - { - Debug.Assert(a.values == b.values); - return a.index > b.index; - } - - public static bool operator >=(lua_TValue a, lua_TValue b) - { - Debug.Assert(a.values == b.values); - return a.index >= b.index; - } - - public static lua_TValue inc(ref lua_TValue value) - { - value = value[1]; - return value[-1]; - } - - public static lua_TValue dec(ref lua_TValue value) - { - value = value[-1]; - return value[1]; - } - - public static implicit operator int(lua_TValue value) - { - return value.index; - } - - public lua_TValue() - { - } - - public lua_TValue(lua_TValue copy) - { - this.values = copy.values; - this.index = copy.index; - this.value.Copy(copy.value); - this.tt = copy.tt; - } - - public lua_TValue(Value value, int tt) - { - this.values = null; - this.index = 0; - this.value.Copy(value); - this.tt = tt; - } - - public Value value = new Value(); - public int tt; - - public override string ToString() - { - string typename = null; - string val = null; - switch (tt) - { - case LUA_TNIL: typename = "LUA_TNIL"; val = string.Empty; break; - case LUA_TNUMBER: typename = "LUA_TNUMBER"; val = value.n.ToString(); break; - case LUA_TSTRING: typename = "LUA_TSTRING"; val = value.gc.ts.ToString(); break; - case LUA_TTABLE: typename = "LUA_TTABLE"; break; - case LUA_TFUNCTION: typename = "LUA_TFUNCTION"; break; - case LUA_TBOOLEAN: typename = "LUA_TBOOLEAN"; break; - case LUA_TUSERDATA: typename = "LUA_TUSERDATA"; break; - case LUA_TTHREAD: typename = "LUA_TTHREAD"; break; - case LUA_TLIGHTUSERDATA: typename = "LUA_TLIGHTUSERDATA"; break; - default: typename = "unknown"; break; - } - return string.Format("TValue<{0}>({1})", typename, val); - } - }; - - /* Macros to test type */ - internal static bool ttisnil(TValue o) { return (ttype(o) == LUA_TNIL); } - internal static bool ttisnumber(TValue o) {return (ttype(o) == LUA_TNUMBER);} - internal static bool ttisstring(TValue o) {return (ttype(o) == LUA_TSTRING);} - internal static bool ttistable(TValue o) {return (ttype(o) == LUA_TTABLE);} - internal static bool ttisfunction(TValue o) {return (ttype(o) == LUA_TFUNCTION);} - internal static bool ttisboolean(TValue o) { return (ttype(o) == LUA_TBOOLEAN); } - internal static bool ttisuserdata(TValue o) { return (ttype(o) == LUA_TUSERDATA); } - internal static bool ttisthread(TValue o) {return (ttype(o) == LUA_TTHREAD);} - internal static bool ttislightuserdata(TValue o) { return (ttype(o) == LUA_TLIGHTUSERDATA); } - - /* Macros to access values */ -#if DEBUG - internal static int ttype(TValue o) { return o.tt; } - internal static int ttype(CommonHeader o) { return o.tt; } - internal static GCObject gcvalue(TValue o) { return (GCObject)check_exp(iscollectable(o), o.value.gc); } - internal static object pvalue(TValue o) { return (object)check_exp(ttislightuserdata(o), o.value.p); } - internal static lua_Number nvalue(TValue o) { return (lua_Number)check_exp(ttisnumber(o), o.value.n); } - internal static TString rawtsvalue(TValue o) { return (TString)check_exp(ttisstring(o), o.value.gc.ts); } - internal static TString_tsv tsvalue(TValue o) { return rawtsvalue(o).tsv; } - internal static Udata rawuvalue(TValue o) { return (Udata)check_exp(ttisuserdata(o), o.value.gc.u); } - internal static Udata_uv uvalue(TValue o) { return rawuvalue(o).uv; } - internal static Closure clvalue(TValue o) { return (Closure)check_exp(ttisfunction(o), o.value.gc.cl); } - internal static Table hvalue(TValue o) { return (Table)check_exp(ttistable(o), o.value.gc.h); } - internal static int bvalue(TValue o) { return (int)check_exp(ttisboolean(o), o.value.b); } - internal static lua_State thvalue(TValue o) { return (lua_State)check_exp(ttisthread(o), o.value.gc.th); } -#else - internal static int ttype(TValue o) { return o.tt; } - internal static int ttype(CommonHeader o) { return o.tt; } - internal static GCObject gcvalue(TValue o) { return o.value.gc; } - internal static object pvalue(TValue o) { return o.value.p; } - internal static lua_Number nvalue(TValue o) { return o.value.n; } - internal static TString rawtsvalue(TValue o) { return o.value.gc.ts; } - internal static TString_tsv tsvalue(TValue o) { return rawtsvalue(o).tsv; } - internal static Udata rawuvalue(TValue o) { return o.value.gc.u; } - internal static Udata_uv uvalue(TValue o) { return rawuvalue(o).uv; } - internal static Closure clvalue(TValue o) { return o.value.gc.cl; } - internal static Table hvalue(TValue o) { return o.value.gc.h; } - internal static int bvalue(TValue o) { return o.value.b; } - internal static lua_State thvalue(TValue o) { return (lua_State)check_exp(ttisthread(o), o.value.gc.th); } -#endif - - public static int l_isfalse(TValue o) { return ((ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))) ? 1 : 0; } - - /* - ** for internal debug only - */ - [Conditional("DEBUG")] - internal static void checkconsistency(TValue obj) - { - lua_assert(!iscollectable(obj) || (ttype(obj) == (obj).value.gc.gch.tt)); - } - - [Conditional("DEBUG")] - internal static void checkliveness(global_State g, TValue obj) - { - lua_assert(!iscollectable(obj) || - ((ttype(obj) == obj.value.gc.gch.tt) && !isdead(g, obj.value.gc))); - } - - /* Macros to set values */ - internal static void setnilvalue(TValue obj) { - obj.tt=LUA_TNIL; - } - - internal static void setnvalue(TValue obj, lua_Number x) { - obj.value.n = x; - obj.tt = LUA_TNUMBER; - } - - internal static void setpvalue( TValue obj, object x) { - obj.value.p = x; - obj.tt = LUA_TLIGHTUSERDATA; - } - - internal static void setbvalue(TValue obj, int x) { - obj.value.b = x; - obj.tt = LUA_TBOOLEAN; - } - - internal static void setsvalue(lua_State L, TValue obj, GCObject x) { - obj.value.gc = x; - obj.tt = LUA_TSTRING; - checkliveness(G(L), obj); - } - - internal static void setuvalue(lua_State L, TValue obj, GCObject x) { - obj.value.gc = x; - obj.tt = LUA_TUSERDATA; - checkliveness(G(L), obj); - } - - internal static void setthvalue(lua_State L, TValue obj, GCObject x) { - obj.value.gc = x; - obj.tt = LUA_TTHREAD; - checkliveness(G(L), obj); - } - - internal static void setclvalue(lua_State L, TValue obj, Closure x) { - obj.value.gc = x; - obj.tt = LUA_TFUNCTION; - checkliveness(G(L), obj); - } - - internal static void sethvalue(lua_State L, TValue obj, Table x) { - obj.value.gc = x; - obj.tt = LUA_TTABLE; - checkliveness(G(L), obj); - } - - internal static void setptvalue(lua_State L, TValue obj, Proto x) { - obj.value.gc = x; - obj.tt = LUA_TPROTO; - checkliveness(G(L), obj); - } - - internal static void setobj(lua_State L, TValue obj1, TValue obj2) { - obj1.value.Copy(obj2.value); - obj1.tt = obj2.tt; - checkliveness(G(L), obj1); - } - - - /* - ** different types of sets, according to destination - */ - - /* from stack to (same) stack */ - //#define setobjs2s setobj - internal static void setobjs2s(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); } - ///* to stack (not from same stack) */ - - //#define setobj2s setobj - internal static void setobj2s(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); } - - //#define setsvalue2s setsvalue - internal static void setsvalue2s(lua_State L, TValue obj, TString x) { setsvalue(L, obj, x); } - - //#define sethvalue2s sethvalue - internal static void sethvalue2s(lua_State L, TValue obj, Table x) { sethvalue(L, obj, x); } - - //#define setptvalue2s setptvalue - internal static void setptvalue2s(lua_State L, TValue obj, Proto x) { setptvalue(L, obj, x); } - - ///* from table to same table */ - //#define setobjt2t setobj - internal static void setobjt2t(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); } - - ///* to table */ - //#define setobj2t setobj - internal static void setobj2t(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); } - - ///* to new object */ - //#define setobj2n setobj - internal static void setobj2n(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); } - - //#define setsvalue2n setsvalue - internal static void setsvalue2n(lua_State L, TValue obj, TString x) { setsvalue(L, obj, x); } - - internal static void setttype(TValue obj, int tt) { obj.tt = tt; } - - - internal static bool iscollectable(TValue o) { return (ttype(o) >= LUA_TSTRING); } - - - - //typedef TValue *StkId; /* index to stack elements */ - - /* - ** String headers for string table - */ - public class TString_tsv : GCObject - { - public lu_byte reserved; - [CLSCompliantAttribute(false)] - public uint hash; - [CLSCompliantAttribute(false)] - public uint len; - }; - public class TString : TString_tsv { - //public L_Umaxalign dummy; /* ensures maximum alignment for strings */ - public TString_tsv tsv { get { return this; } } - - public TString() - { - } - public TString(CharPtr str) { this.str = str; } - - public CharPtr str; - - public override string ToString() { return str.ToString(); } // for debugging - }; - - public static CharPtr getstr(TString ts) { return ts.str; } - public static CharPtr svalue(StkId o) { return getstr(rawtsvalue(o)); } - - public class Udata_uv : GCObject - { - public Table metatable; - public Table env; - [CLSCompliantAttribute(false)] - public uint len; - }; - - public class Udata : Udata_uv - { - public Udata() { this.uv = this; } - - public new Udata_uv uv; - - //public L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ - - // in the original C code this was allocated alongside the structure memory. it would probably - // be possible to still do that by allocating memory and pinning it down, but we can do the - // same thing just as easily by allocating a seperate byte array for it instead. - public object user_data; - }; - - - - - /* - ** Function Prototypes - */ - public class Proto : GCObject { - - public Proto[] protos = null; - public int index = 0; - public Proto this[int offset] {get { return this.protos[this.index + offset]; }} - - public TValue[] k; /* constants used by the function */ - [CLSCompliantAttribute(false)] - public Instruction[] code; - public new Proto[] p; /* functions defined inside the function */ - public int[] lineinfo; /* map from opcodes to source lines */ - public LocVar[] locvars; /* information about local variables */ - public TString[] upvalues; /* upvalue names */ - public TString source; - public int sizeupvalues; - public int sizek; /* size of `k' */ - public int sizecode; - public int sizelineinfo; - public int sizep; /* size of `p' */ - public int sizelocvars; - public int linedefined; - public int lastlinedefined; - public GCObject gclist; - public lu_byte nups; /* number of upvalues */ - public lu_byte numparams; - public lu_byte is_vararg; - public lu_byte maxstacksize; - }; - - - /* masks for new-style vararg */ - public const int VARARG_HASARG = 1; - public const int VARARG_ISVARARG = 2; - public const int VARARG_NEEDSARG = 4; - - public class LocVar { - public TString varname; - public int startpc; /* first point where variable is active */ - public int endpc; /* first point where variable is dead */ - }; - - - - /* - ** Upvalues - */ - - public class UpVal : GCObject { - public TValue v; /* points to stack or to its own value */ - [CLSCompliantAttribute(false)] - public class _u { - public TValue value = new TValue(); /* the value (when closed) */ - [CLSCompliantAttribute(false)] - public class _l { /* double linked list (when open) */ - public UpVal prev; - public UpVal next; - }; - - public _l l = new _l(); - } - [CLSCompliantAttribute(false)] - public new _u u = new _u(); - }; - - - /* - ** Closures - */ - - public class ClosureHeader : GCObject { - public lu_byte isC; - public lu_byte nupvalues; - public GCObject gclist; - public Table env; - }; - - public class ClosureType { - - ClosureHeader header; - - public static implicit operator ClosureHeader(ClosureType ctype) {return ctype.header;} - public ClosureType(ClosureHeader header) {this.header = header;} - - public lu_byte isC { get { return header.isC; } set { header.isC = value; } } - public lu_byte nupvalues { get { return header.nupvalues; } set { header.nupvalues = value; } } - public GCObject gclist { get { return header.gclist; } set { header.gclist = value; } } - public Table env { get { return header.env; } set { header.env = value; } } - } - - public class CClosure : ClosureType { - public CClosure(ClosureHeader header) : base(header) { } - public lua_CFunction f; - public TValue[] upvalue; - }; - - - public class LClosure : ClosureType { - public LClosure(ClosureHeader header) : base(header) { } - public Proto p; - public UpVal[] upvals; - }; - - public class Closure : ClosureHeader - { - public Closure() - { - c = new CClosure(this); - l = new LClosure(this); - } - - public CClosure c; - public LClosure l; - }; - - - public static bool iscfunction(TValue o) { return ((ttype(o) == LUA_TFUNCTION) && (clvalue(o).c.isC != 0)); } - public static bool isLfunction(TValue o) { return ((ttype(o) == LUA_TFUNCTION) && (clvalue(o).c.isC==0)); } - - - /* - ** Tables - */ - - public class TKey_nk : TValue - { - public TKey_nk() { } - public TKey_nk(Value value, int tt, Node next) : base(value, tt) - { - this.next = next; - } - public Node next; /* for chaining */ - }; - - public class TKey { - public TKey() - { - this.nk = new TKey_nk(); - } - public TKey(TKey copy) - { - this.nk = new TKey_nk(copy.nk.value, copy.nk.tt, copy.nk.next); - } - public TKey(Value value, int tt, Node next) - { - this.nk = new TKey_nk(value, tt, next); - } - - public TKey_nk nk = new TKey_nk(); - public TValue tvk { get { return this.nk; } } - }; - - - public class Node : ArrayElement - { - private Node[] values = null; - private int index = -1; - - public void set_index(int index) - { - this.index = index; - } - - public void set_array(object array) - { - this.values = (Node[])array; - Debug.Assert(this.values != null); - } - - public Node() - { - this.i_val = new TValue(); - this.i_key = new TKey(); - } - - public Node(Node copy) - { - this.values = copy.values; - this.index = copy.index; - this.i_val = new TValue(copy.i_val); - this.i_key = new TKey(copy.i_key); - } - - public Node(TValue i_val, TKey i_key) - { - this.values = new Node[] { this }; - this.index = 0; - this.i_val = i_val; - this.i_key = i_key; - } - - public TValue i_val; - public TKey i_key; - - [CLSCompliantAttribute(false)] - public Node this[uint offset] - { - get { return this.values[this.index + (int)offset]; } - } - - public Node this[int offset] - { - get { return this.values[this.index + offset]; } - } - - public static int operator -(Node n1, Node n2) - { - Debug.Assert(n1.values == n2.values); - return n1.index - n2.index; - } - - public static Node inc(ref Node node) - { - node = node[1]; - return node[-1]; - } - - public static Node dec(ref Node node) - { - node = node[-1]; - return node[1]; - } - - public static bool operator >(Node n1, Node n2) { Debug.Assert(n1.values == n2.values); return n1.index > n2.index; } - public static bool operator >=(Node n1, Node n2) { Debug.Assert(n1.values == n2.values); return n1.index >= n2.index; } - public static bool operator <(Node n1, Node n2) { Debug.Assert(n1.values == n2.values); return n1.index < n2.index; } - public static bool operator <=(Node n1, Node n2) { Debug.Assert(n1.values == n2.values); return n1.index <= n2.index; } - public static bool operator ==(Node n1, Node n2) - { - object o1 = n1 as Node; - object o2 = n2 as Node; - if ((o1 == null) && (o2 == null)) return true; - if (o1 == null) return false; - if (o2 == null) return false; - if (n1.values != n2.values) return false; - return n1.index == n2.index; - } - public static bool operator !=(Node n1, Node n2) { return !(n1==n2); } - - public override bool Equals(object o) {return this == (Node)o;} - public override int GetHashCode() {return 0;} - }; - - - public class Table : GCObject { - public lu_byte flags; /* 1<

= 16) { - x = (x+1) >> 1; - e++; - } - if (x < 8) return (int)x; - else return ((e+1) << 3) | (cast_int(x) - 8); - } - - - /* converts back */ - public static int luaO_fb2int (int x) { - int e = (x >> 3) & 31; - if (e == 0) return x; - else return ((x & 7)+8) << (e - 1); - } - - - private readonly static lu_byte[] log_2 = { - 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 - }; - - [CLSCompliantAttribute(false)] - public static int luaO_log2 (uint x) { - int l = -1; - while (x >= 256) { l += 8; x >>= 8; } - return l + log_2[x]; - - } - - - public static int luaO_rawequalObj (TValue t1, TValue t2) { - if (ttype(t1) != ttype(t2)) return 0; - else switch (ttype(t1)) { - case LUA_TNIL: - return 1; - case LUA_TNUMBER: - return luai_numeq(nvalue(t1), nvalue(t2)) ? 1 : 0; - case LUA_TBOOLEAN: - return bvalue(t1) == bvalue(t2) ? 1 : 0; /* boolean true must be 1....but not in C# !! */ - case LUA_TLIGHTUSERDATA: - return pvalue(t1) == pvalue(t2) ? 1 : 0; - default: - lua_assert(iscollectable(t1)); - return gcvalue(t1) == gcvalue(t2) ? 1 : 0; - } - } - - public static int luaO_str2d (CharPtr s, out lua_Number result) { - CharPtr endptr; - result = lua_str2number(s, out endptr); - if (endptr == s) return 0; /* conversion failed */ - if (endptr[0] == 'x' || endptr[0] == 'X') /* maybe an hexadecimal constant? */ - result = cast_num(strtoul(s, out endptr, 16)); - if (endptr[0] == '\0') return 1; /* most common case */ - while (isspace(endptr[0])) endptr = endptr.next(); - if (endptr[0] != '\0') return 0; /* invalid trailing characters? */ - return 1; - } - - - - private static void pushstr (lua_State L, CharPtr str) { - setsvalue2s(L, L.top, luaS_new(L, str)); - incr_top(L); - } - - - /* this function handles only `%d', `%c', %f, %p, and `%s' formats */ - public static CharPtr luaO_pushvfstring (lua_State L, CharPtr fmt, params object[] argp) { - int parm_index = 0; - int n = 1; - pushstr(L, ""); - for (;;) { - CharPtr e = strchr(fmt, '%'); - if (e == null) break; - setsvalue2s(L, L.top, luaS_newlstr(L, fmt, (uint)(e-fmt))); - incr_top(L); - switch (e[1]) { - case 's': { - object o = argp[parm_index++]; - CharPtr s = o as CharPtr; - if (s == null) - s = (string)o; - if (s == null) s = "(null)"; - pushstr(L, s); - break; - } - case 'c': { - CharPtr buff = new char[2]; - buff[0] = (char)(int)argp[parm_index++]; - buff[1] = '\0'; - pushstr(L, buff); - break; - } - case 'd': { - setnvalue(L.top, (int)argp[parm_index++]); - incr_top(L); - break; - } - case 'f': { - setnvalue(L.top, (l_uacNumber)argp[parm_index++]); - incr_top(L); - break; - } - case 'p': { - //CharPtr buff = new char[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ - CharPtr buff = new char[32]; - sprintf(buff, "0x%08x", argp[parm_index++].GetHashCode()); - pushstr(L, buff); - break; - } - case '%': { - pushstr(L, "%"); - break; - } - default: { - CharPtr buff = new char[3]; - buff[0] = '%'; - buff[1] = e[1]; - buff[2] = '\0'; - pushstr(L, buff); - break; - } - } - n += 2; - fmt = e+2; - } - pushstr(L, fmt); - luaV_concat(L, n+1, cast_int(L.top - L.base_) - 1); - L.top -= n; - return svalue(L.top - 1); - } - - public static CharPtr luaO_pushfstring(lua_State L, CharPtr fmt, params object[] args) - { - return luaO_pushvfstring(L, fmt, args); - } - - [CLSCompliantAttribute(false)] - public static void luaO_chunkid (CharPtr out_, CharPtr source, uint bufflen) { - //out_ = ""; - if (source[0] == '=') { - strncpy(out_, source+1, (int)bufflen); /* remove first char */ - out_[bufflen-1] = '\0'; /* ensures null termination */ - } - else { /* out = "source", or "...source" */ - if (source[0] == '@') { - uint l; - source = source.next(); /* skip the `@' */ - bufflen -= (uint)(" '...' ".Length + 1); - l = (uint)strlen(source); - strcpy(out_, ""); - if (l > bufflen) { - source += (l-bufflen); /* get last part of file name */ - strcat(out_, "..."); - } - strcat(out_, source); - } - else { /* out = [string "string"] */ - uint len = strcspn(source, "\n\r"); /* stop at first newline */ - bufflen -= (uint)(" [string \"...\"] ".Length + 1); - if (len > bufflen) len = bufflen; - strcpy(out_, "[string \""); - if (source[len] != '\0') { /* must truncate? */ - strncat(out_, source, (int)len); - strcat(out_, "..."); - } - else - strcat(out_, source); - strcat(out_, "\"]"); - } - } - } - - } -} +/* +** $Id: lobject.c,v 2.22.1.1 2007/12/27 13:02:25 roberto Exp $ +** Some generic functions over Lua objects +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Diagnostics; + +namespace KopiLua +{ + using TValue = Lua.lua_TValue; + using StkId = Lua.lua_TValue; + using lu_byte = System.Byte; + using lua_Number = System.Double; + using l_uacNumber = System.Double; + using Instruction = System.UInt32; + + public partial class Lua + { + /* tags for values visible from Lua */ + public const int LAST_TAG = LUA_TTHREAD; + + public const int NUM_TAGS = (LAST_TAG+1); + + + /* + ** Extra tags for non-values + */ + public const int LUA_TPROTO = (LAST_TAG+1); + public const int LUA_TUPVAL = (LAST_TAG+2); + public const int LUA_TDEADKEY = (LAST_TAG+3); + + public interface ArrayElement + { + void set_index(int index); + void set_array(object array); + } + + + /* + ** Common Header for all collectable objects (in macro form, to be + ** included in other objects) + */ + public class CommonHeader + { + public GCObject next; + public lu_byte tt; + public lu_byte marked; + } + + + /* + ** Common header in struct form + */ + public class GCheader : CommonHeader { + }; + + + + + /* + ** Union of all Lua values (in c# we use virtual data members and boxing) + */ + public class Value + { + + // in the original code Value is a struct, so all assignments in the code + // need to be replaced with a call to Copy. as it turns out, there are only + // a couple. the vast majority of references to Value are the instance that + // appears in the TValue class, so if you make that a virtual data member and + // omit the set accessor then you'll get a compiler error if anything tries + // to set it. + public void Copy(Value copy) + { + this.p = copy.p; + } + + public GCObject gc + { + get {return (GCObject)this.p;} + set {this.p = value;} + } + public object p; + public lua_Number n + { + get { return (lua_Number)this.p; } + set { this.p = (object)value; } + } + public int b + { + get { return (int)this.p; } + set { this.p = (object)value; } + } + }; + + + /* + ** Tagged Values + */ + + //#define TValuefields Value value; int tt + + public class lua_TValue : ArrayElement + { + private lua_TValue[] values = null; + private int index = -1; + + public void set_index(int index) + { + this.index = index; + } + + public void set_array(object array) + { + this.values = (lua_TValue[])array; + Debug.Assert(this.values != null); + } + + public lua_TValue this[int offset] + { + get { return this.values[this.index + offset]; } + } + + [CLSCompliantAttribute(false)] + public lua_TValue this[uint offset] + { + get { return this.values[this.index + (int)offset]; } + } + + public static lua_TValue operator +(lua_TValue value, int offset) + { + return value.values[value.index + offset]; + } + + public static lua_TValue operator +(int offset, lua_TValue value) + { + return value.values[value.index + offset]; + } + + public static lua_TValue operator -(lua_TValue value, int offset) + { + return value.values[value.index - offset]; + } + + public static int operator -(lua_TValue value, lua_TValue[] array) + { + Debug.Assert(value.values == array); + return value.index; + } + + public static int operator -(lua_TValue a, lua_TValue b) + { + Debug.Assert(a.values == b.values); + return a.index - b.index; + } + + public static bool operator <(lua_TValue a, lua_TValue b) + { + Debug.Assert(a.values == b.values); + return a.index < b.index; + } + + public static bool operator <=(lua_TValue a, lua_TValue b) + { + Debug.Assert(a.values == b.values); + return a.index <= b.index; + } + + public static bool operator >(lua_TValue a, lua_TValue b) + { + Debug.Assert(a.values == b.values); + return a.index > b.index; + } + + public static bool operator >=(lua_TValue a, lua_TValue b) + { + Debug.Assert(a.values == b.values); + return a.index >= b.index; + } + + public static lua_TValue inc(ref lua_TValue value) + { + value = value[1]; + return value[-1]; + } + + public static lua_TValue dec(ref lua_TValue value) + { + value = value[-1]; + return value[1]; + } + + public static implicit operator int(lua_TValue value) + { + return value.index; + } + + public lua_TValue() + { + } + + public lua_TValue(lua_TValue copy) + { + this.values = copy.values; + this.index = copy.index; + this.value.Copy(copy.value); + this.tt = copy.tt; + } + + public lua_TValue(Value value, int tt) + { + this.values = null; + this.index = 0; + this.value.Copy(value); + this.tt = tt; + } + + public Value value = new Value(); + public int tt; + + public override string ToString() + { + string typename = null; + string val = null; + switch (tt) + { + case LUA_TNIL: typename = "LUA_TNIL"; val = string.Empty; break; + case LUA_TNUMBER: typename = "LUA_TNUMBER"; val = value.n.ToString(); break; + case LUA_TSTRING: typename = "LUA_TSTRING"; val = value.gc.ts.ToString(); break; + case LUA_TTABLE: typename = "LUA_TTABLE"; break; + case LUA_TFUNCTION: typename = "LUA_TFUNCTION"; break; + case LUA_TBOOLEAN: typename = "LUA_TBOOLEAN"; break; + case LUA_TUSERDATA: typename = "LUA_TUSERDATA"; break; + case LUA_TTHREAD: typename = "LUA_TTHREAD"; break; + case LUA_TLIGHTUSERDATA: typename = "LUA_TLIGHTUSERDATA"; break; + default: typename = "unknown"; break; + } + return string.Format("TValue<{0}>({1})", typename, val); + } + }; + + /* Macros to test type */ + internal static bool ttisnil(TValue o) { return (ttype(o) == LUA_TNIL); } + internal static bool ttisnumber(TValue o) {return (ttype(o) == LUA_TNUMBER);} + internal static bool ttisstring(TValue o) {return (ttype(o) == LUA_TSTRING);} + internal static bool ttistable(TValue o) {return (ttype(o) == LUA_TTABLE);} + internal static bool ttisfunction(TValue o) {return (ttype(o) == LUA_TFUNCTION);} + internal static bool ttisboolean(TValue o) { return (ttype(o) == LUA_TBOOLEAN); } + internal static bool ttisuserdata(TValue o) { return (ttype(o) == LUA_TUSERDATA); } + internal static bool ttisthread(TValue o) {return (ttype(o) == LUA_TTHREAD);} + internal static bool ttislightuserdata(TValue o) { return (ttype(o) == LUA_TLIGHTUSERDATA); } + + /* Macros to access values */ +#if DEBUG + internal static int ttype(TValue o) { return o.tt; } + internal static int ttype(CommonHeader o) { return o.tt; } + internal static GCObject gcvalue(TValue o) { return (GCObject)check_exp(iscollectable(o), o.value.gc); } + internal static object pvalue(TValue o) { return (object)check_exp(ttislightuserdata(o), o.value.p); } + internal static lua_Number nvalue(TValue o) { return (lua_Number)check_exp(ttisnumber(o), o.value.n); } + internal static TString rawtsvalue(TValue o) { return (TString)check_exp(ttisstring(o), o.value.gc.ts); } + internal static TString_tsv tsvalue(TValue o) { return rawtsvalue(o).tsv; } + internal static Udata rawuvalue(TValue o) { return (Udata)check_exp(ttisuserdata(o), o.value.gc.u); } + internal static Udata_uv uvalue(TValue o) { return rawuvalue(o).uv; } + internal static Closure clvalue(TValue o) { return (Closure)check_exp(ttisfunction(o), o.value.gc.cl); } + internal static Table hvalue(TValue o) { return (Table)check_exp(ttistable(o), o.value.gc.h); } + internal static int bvalue(TValue o) { return (int)check_exp(ttisboolean(o), o.value.b); } + internal static lua_State thvalue(TValue o) { return (lua_State)check_exp(ttisthread(o), o.value.gc.th); } +#else + internal static int ttype(TValue o) { return o.tt; } + internal static int ttype(CommonHeader o) { return o.tt; } + internal static GCObject gcvalue(TValue o) { return o.value.gc; } + internal static object pvalue(TValue o) { return o.value.p; } + internal static lua_Number nvalue(TValue o) { return o.value.n; } + internal static TString rawtsvalue(TValue o) { return o.value.gc.ts; } + internal static TString_tsv tsvalue(TValue o) { return rawtsvalue(o).tsv; } + internal static Udata rawuvalue(TValue o) { return o.value.gc.u; } + internal static Udata_uv uvalue(TValue o) { return rawuvalue(o).uv; } + internal static Closure clvalue(TValue o) { return o.value.gc.cl; } + internal static Table hvalue(TValue o) { return o.value.gc.h; } + internal static int bvalue(TValue o) { return o.value.b; } + internal static lua_State thvalue(TValue o) { return (lua_State)check_exp(ttisthread(o), o.value.gc.th); } +#endif + + public static int l_isfalse(TValue o) { return ((ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))) ? 1 : 0; } + + /* + ** for internal debug only + */ + [Conditional("DEBUG")] + internal static void checkconsistency(TValue obj) + { + lua_assert(!iscollectable(obj) || (ttype(obj) == (obj).value.gc.gch.tt)); + } + + [Conditional("DEBUG")] + internal static void checkliveness(global_State g, TValue obj) + { + lua_assert(!iscollectable(obj) || + ((ttype(obj) == obj.value.gc.gch.tt) && !isdead(g, obj.value.gc))); + } + + /* Macros to set values */ + internal static void setnilvalue(TValue obj) { + obj.tt=LUA_TNIL; + } + + internal static void setnvalue(TValue obj, lua_Number x) { + obj.value.n = x; + obj.tt = LUA_TNUMBER; + } + + internal static void setpvalue( TValue obj, object x) { + obj.value.p = x; + obj.tt = LUA_TLIGHTUSERDATA; + } + + internal static void setbvalue(TValue obj, int x) { + obj.value.b = x; + obj.tt = LUA_TBOOLEAN; + } + + internal static void setsvalue(lua_State L, TValue obj, GCObject x) { + obj.value.gc = x; + obj.tt = LUA_TSTRING; + checkliveness(G(L), obj); + } + + internal static void setuvalue(lua_State L, TValue obj, GCObject x) { + obj.value.gc = x; + obj.tt = LUA_TUSERDATA; + checkliveness(G(L), obj); + } + + internal static void setthvalue(lua_State L, TValue obj, GCObject x) { + obj.value.gc = x; + obj.tt = LUA_TTHREAD; + checkliveness(G(L), obj); + } + + internal static void setclvalue(lua_State L, TValue obj, Closure x) { + obj.value.gc = x; + obj.tt = LUA_TFUNCTION; + checkliveness(G(L), obj); + } + + internal static void sethvalue(lua_State L, TValue obj, Table x) { + obj.value.gc = x; + obj.tt = LUA_TTABLE; + checkliveness(G(L), obj); + } + + internal static void setptvalue(lua_State L, TValue obj, Proto x) { + obj.value.gc = x; + obj.tt = LUA_TPROTO; + checkliveness(G(L), obj); + } + + internal static void setobj(lua_State L, TValue obj1, TValue obj2) { + obj1.value.Copy(obj2.value); + obj1.tt = obj2.tt; + checkliveness(G(L), obj1); + } + + + /* + ** different types of sets, according to destination + */ + + /* from stack to (same) stack */ + //#define setobjs2s setobj + internal static void setobjs2s(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); } + ///* to stack (not from same stack) */ + + //#define setobj2s setobj + internal static void setobj2s(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); } + + //#define setsvalue2s setsvalue + internal static void setsvalue2s(lua_State L, TValue obj, TString x) { setsvalue(L, obj, x); } + + //#define sethvalue2s sethvalue + internal static void sethvalue2s(lua_State L, TValue obj, Table x) { sethvalue(L, obj, x); } + + //#define setptvalue2s setptvalue + internal static void setptvalue2s(lua_State L, TValue obj, Proto x) { setptvalue(L, obj, x); } + + ///* from table to same table */ + //#define setobjt2t setobj + internal static void setobjt2t(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); } + + ///* to table */ + //#define setobj2t setobj + internal static void setobj2t(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); } + + ///* to new object */ + //#define setobj2n setobj + internal static void setobj2n(lua_State L, TValue obj, TValue x) { setobj(L, obj, x); } + + //#define setsvalue2n setsvalue + internal static void setsvalue2n(lua_State L, TValue obj, TString x) { setsvalue(L, obj, x); } + + internal static void setttype(TValue obj, int tt) { obj.tt = tt; } + + + internal static bool iscollectable(TValue o) { return (ttype(o) >= LUA_TSTRING); } + + + + //typedef TValue *StkId; /* index to stack elements */ + + /* + ** String headers for string table + */ + public class TString_tsv : GCObject + { + public lu_byte reserved; + [CLSCompliantAttribute(false)] + public uint hash; + [CLSCompliantAttribute(false)] + public uint len; + }; + public class TString : TString_tsv { + //public L_Umaxalign dummy; /* ensures maximum alignment for strings */ + public TString_tsv tsv { get { return this; } } + + public TString() + { + } + public TString(CharPtr str) { this.str = str; } + + public CharPtr str; + + public override string ToString() { return str.ToString(); } // for debugging + }; + + public static CharPtr getstr(TString ts) { return ts.str; } + public static CharPtr svalue(StkId o) { return getstr(rawtsvalue(o)); } + + public class Udata_uv : GCObject + { + public Table metatable; + public Table env; + [CLSCompliantAttribute(false)] + public uint len; + }; + + public class Udata : Udata_uv + { + public Udata() { this.uv = this; } + + public new Udata_uv uv; + + //public L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ + + // in the original C code this was allocated alongside the structure memory. it would probably + // be possible to still do that by allocating memory and pinning it down, but we can do the + // same thing just as easily by allocating a seperate byte array for it instead. + public object user_data; + }; + + + + + /* + ** Function Prototypes + */ + public class Proto : GCObject { + + public Proto[] protos = null; + public int index = 0; + public Proto this[int offset] {get { return this.protos[this.index + offset]; }} + + public TValue[] k; /* constants used by the function */ + [CLSCompliantAttribute(false)] + public Instruction[] code; + public new Proto[] p; /* functions defined inside the function */ + public int[] lineinfo; /* map from opcodes to source lines */ + public LocVar[] locvars; /* information about local variables */ + public TString[] upvalues; /* upvalue names */ + public TString source; + public int sizeupvalues; + public int sizek; /* size of `k' */ + public int sizecode; + public int sizelineinfo; + public int sizep; /* size of `p' */ + public int sizelocvars; + public int linedefined; + public int lastlinedefined; + public GCObject gclist; + public lu_byte nups; /* number of upvalues */ + public lu_byte numparams; + public lu_byte is_vararg; + public lu_byte maxstacksize; + }; + + + /* masks for new-style vararg */ + public const int VARARG_HASARG = 1; + public const int VARARG_ISVARARG = 2; + public const int VARARG_NEEDSARG = 4; + + public class LocVar { + public TString varname; + public int startpc; /* first point where variable is active */ + public int endpc; /* first point where variable is dead */ + }; + + + + /* + ** Upvalues + */ + + public class UpVal : GCObject { + public TValue v; /* points to stack or to its own value */ + [CLSCompliantAttribute(false)] + public class _u { + public TValue value = new TValue(); /* the value (when closed) */ + [CLSCompliantAttribute(false)] + public class _l { /* double linked list (when open) */ + public UpVal prev; + public UpVal next; + }; + + public _l l = new _l(); + } + [CLSCompliantAttribute(false)] + public new _u u = new _u(); + }; + + + /* + ** Closures + */ + + public class ClosureHeader : GCObject { + public lu_byte isC; + public lu_byte nupvalues; + public GCObject gclist; + public Table env; + }; + + public class ClosureType { + + ClosureHeader header; + + public static implicit operator ClosureHeader(ClosureType ctype) {return ctype.header;} + public ClosureType(ClosureHeader header) {this.header = header;} + + public lu_byte isC { get { return header.isC; } set { header.isC = value; } } + public lu_byte nupvalues { get { return header.nupvalues; } set { header.nupvalues = value; } } + public GCObject gclist { get { return header.gclist; } set { header.gclist = value; } } + public Table env { get { return header.env; } set { header.env = value; } } + } + + public class CClosure : ClosureType { + public CClosure(ClosureHeader header) : base(header) { } + public lua_CFunction f; + public TValue[] upvalue; + }; + + + public class LClosure : ClosureType { + public LClosure(ClosureHeader header) : base(header) { } + public Proto p; + public UpVal[] upvals; + }; + + public class Closure : ClosureHeader + { + public Closure() + { + c = new CClosure(this); + l = new LClosure(this); + } + + public CClosure c; + public LClosure l; + }; + + + public static bool iscfunction(TValue o) { return ((ttype(o) == LUA_TFUNCTION) && (clvalue(o).c.isC != 0)); } + public static bool isLfunction(TValue o) { return ((ttype(o) == LUA_TFUNCTION) && (clvalue(o).c.isC==0)); } + + + /* + ** Tables + */ + + public class TKey_nk : TValue + { + public TKey_nk() { } + public TKey_nk(Value value, int tt, Node next) : base(value, tt) + { + this.next = next; + } + public Node next; /* for chaining */ + }; + + public class TKey { + public TKey() + { + this.nk = new TKey_nk(); + } + public TKey(TKey copy) + { + this.nk = new TKey_nk(copy.nk.value, copy.nk.tt, copy.nk.next); + } + public TKey(Value value, int tt, Node next) + { + this.nk = new TKey_nk(value, tt, next); + } + + public TKey_nk nk = new TKey_nk(); + public TValue tvk { get { return this.nk; } } + }; + + + public class Node : ArrayElement + { + private Node[] values = null; + private int index = -1; + + public void set_index(int index) + { + this.index = index; + } + + public void set_array(object array) + { + this.values = (Node[])array; + Debug.Assert(this.values != null); + } + + public Node() + { + this.i_val = new TValue(); + this.i_key = new TKey(); + } + + public Node(Node copy) + { + this.values = copy.values; + this.index = copy.index; + this.i_val = new TValue(copy.i_val); + this.i_key = new TKey(copy.i_key); + } + + public Node(TValue i_val, TKey i_key) + { + this.values = new Node[] { this }; + this.index = 0; + this.i_val = i_val; + this.i_key = i_key; + } + + public TValue i_val; + public TKey i_key; + + [CLSCompliantAttribute(false)] + public Node this[uint offset] + { + get { return this.values[this.index + (int)offset]; } + } + + public Node this[int offset] + { + get { return this.values[this.index + offset]; } + } + + public static int operator -(Node n1, Node n2) + { + Debug.Assert(n1.values == n2.values); + return n1.index - n2.index; + } + + public static Node inc(ref Node node) + { + node = node[1]; + return node[-1]; + } + + public static Node dec(ref Node node) + { + node = node[-1]; + return node[1]; + } + + public static bool operator >(Node n1, Node n2) { Debug.Assert(n1.values == n2.values); return n1.index > n2.index; } + public static bool operator >=(Node n1, Node n2) { Debug.Assert(n1.values == n2.values); return n1.index >= n2.index; } + public static bool operator <(Node n1, Node n2) { Debug.Assert(n1.values == n2.values); return n1.index < n2.index; } + public static bool operator <=(Node n1, Node n2) { Debug.Assert(n1.values == n2.values); return n1.index <= n2.index; } + public static bool operator ==(Node n1, Node n2) + { + object o1 = n1 as Node; + object o2 = n2 as Node; + if ((o1 == null) && (o2 == null)) return true; + if (o1 == null) return false; + if (o2 == null) return false; + if (n1.values != n2.values) return false; + return n1.index == n2.index; + } + public static bool operator !=(Node n1, Node n2) { return !(n1==n2); } + + public override bool Equals(object o) {return this == (Node)o;} + public override int GetHashCode() {return 0;} + }; + + + public class Table : GCObject { + public lu_byte flags; /* 1<

= 16) { + x = (x+1) >> 1; + e++; + } + if (x < 8) return (int)x; + else return ((e+1) << 3) | (cast_int(x) - 8); + } + + + /* converts back */ + public static int luaO_fb2int (int x) { + int e = (x >> 3) & 31; + if (e == 0) return x; + else return ((x & 7)+8) << (e - 1); + } + + + private readonly static lu_byte[] log_2 = { + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 + }; + + [CLSCompliantAttribute(false)] + public static int luaO_log2 (uint x) { + int l = -1; + while (x >= 256) { l += 8; x >>= 8; } + return l + log_2[x]; + + } + + + public static int luaO_rawequalObj (TValue t1, TValue t2) { + if (ttype(t1) != ttype(t2)) return 0; + else switch (ttype(t1)) { + case LUA_TNIL: + return 1; + case LUA_TNUMBER: + return luai_numeq(nvalue(t1), nvalue(t2)) ? 1 : 0; + case LUA_TBOOLEAN: + return bvalue(t1) == bvalue(t2) ? 1 : 0; /* boolean true must be 1....but not in C# !! */ + case LUA_TLIGHTUSERDATA: + return pvalue(t1) == pvalue(t2) ? 1 : 0; + default: + lua_assert(iscollectable(t1)); + return gcvalue(t1) == gcvalue(t2) ? 1 : 0; + } + } + + public static int luaO_str2d (CharPtr s, out lua_Number result) { + CharPtr endptr; + result = lua_str2number(s, out endptr); + if (endptr == s) return 0; /* conversion failed */ + if (endptr[0] == 'x' || endptr[0] == 'X') /* maybe an hexadecimal constant? */ + result = cast_num(strtoul(s, out endptr, 16)); + if (endptr[0] == '\0') return 1; /* most common case */ + while (isspace(endptr[0])) endptr = endptr.next(); + if (endptr[0] != '\0') return 0; /* invalid trailing characters? */ + return 1; + } + + + + private static void pushstr (lua_State L, CharPtr str) { + setsvalue2s(L, L.top, luaS_new(L, str)); + incr_top(L); + } + + + /* this function handles only `%d', `%c', %f, %p, and `%s' formats */ + public static CharPtr luaO_pushvfstring (lua_State L, CharPtr fmt, params object[] argp) { + int parm_index = 0; + int n = 1; + pushstr(L, ""); + for (;;) { + CharPtr e = strchr(fmt, '%'); + if (e == null) break; + setsvalue2s(L, L.top, luaS_newlstr(L, fmt, (uint)(e-fmt))); + incr_top(L); + switch (e[1]) { + case 's': { + object o = argp[parm_index++]; + CharPtr s = o as CharPtr; + if (s == null) + s = (string)o; + if (s == null) s = "(null)"; + pushstr(L, s); + break; + } + case 'c': { + CharPtr buff = new char[2]; + buff[0] = (char)(int)argp[parm_index++]; + buff[1] = '\0'; + pushstr(L, buff); + break; + } + case 'd': { + setnvalue(L.top, (int)argp[parm_index++]); + incr_top(L); + break; + } + case 'f': { + setnvalue(L.top, (l_uacNumber)argp[parm_index++]); + incr_top(L); + break; + } + case 'p': { + //CharPtr buff = new char[4*sizeof(void *) + 8]; /* should be enough space for a `%p' */ + CharPtr buff = new char[32]; + sprintf(buff, "0x%08x", argp[parm_index++].GetHashCode()); + pushstr(L, buff); + break; + } + case '%': { + pushstr(L, "%"); + break; + } + default: { + CharPtr buff = new char[3]; + buff[0] = '%'; + buff[1] = e[1]; + buff[2] = '\0'; + pushstr(L, buff); + break; + } + } + n += 2; + fmt = e+2; + } + pushstr(L, fmt); + luaV_concat(L, n+1, cast_int(L.top - L.base_) - 1); + L.top -= n; + return svalue(L.top - 1); + } + + public static CharPtr luaO_pushfstring(lua_State L, CharPtr fmt, params object[] args) + { + return luaO_pushvfstring(L, fmt, args); + } + + [CLSCompliantAttribute(false)] + public static void luaO_chunkid (CharPtr out_, CharPtr source, uint bufflen) { + //out_ = ""; + if (source[0] == '=') { + strncpy(out_, source+1, (int)bufflen); /* remove first char */ + out_[bufflen-1] = '\0'; /* ensures null termination */ + } + else { /* out = "source", or "...source" */ + if (source[0] == '@') { + uint l; + source = source.next(); /* skip the `@' */ + bufflen -= (uint)(" '...' ".Length + 1); + l = (uint)strlen(source); + strcpy(out_, ""); + if (l > bufflen) { + source += (l-bufflen); /* get last part of file name */ + strcat(out_, "..."); + } + strcat(out_, source); + } + else { /* out = [string "string"] */ + uint len = strcspn(source, "\n\r"); /* stop at first newline */ + bufflen -= (uint)(" [string \"...\"] ".Length + 1); + if (len > bufflen) len = bufflen; + strcpy(out_, "[string \""); + if (source[len] != '\0') { /* must truncate? */ + strncat(out_, source, (int)len); + strcat(out_, "..."); + } + else + strcat(out_, source); + strcat(out_, "\"]"); + } + } + } + + } +} diff --git a/Core/KopiLua/lopcodes.cs b/Core/KopiLua/lopcodes.cs index 96f96415685d9292114998b69394a7d4e7046e04..0f240141bc5cdc21d4e1548127eea7e3f7d733e3 100644 --- a/Core/KopiLua/lopcodes.cs +++ b/Core/KopiLua/lopcodes.cs @@ -1,412 +1,412 @@ -/* -** $Id: lopcodes.c,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $ -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace KopiLua -{ - using lu_byte = System.Byte; - using Instruction = System.UInt32; - - public partial class Lua - { - /*=========================================================================== - We assume that instructions are unsigned numbers. - All instructions have an opcode in the first 6 bits. - Instructions can have the following fields: - `A' : 8 bits - `B' : 9 bits - `C' : 9 bits - `Bx' : 18 bits (`B' and `C' together) - `sBx' : signed Bx - - A signed argument is represented in excess K; that is, the number - value is the unsigned value minus K. K is exactly the maximum value - for that argument (so that -max is represented by 0, and +max is - represented by 2*max), which is half the maximum for the corresponding - unsigned argument. - ===========================================================================*/ - - - public enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ - - - /* - ** size and position of opcode arguments. - */ - public const int SIZE_C = 9; - public const int SIZE_B = 9; - public const int SIZE_Bx = (SIZE_C + SIZE_B); - public const int SIZE_A = 8; - - public const int SIZE_OP = 6; - - public const int POS_OP = 0; - public const int POS_A = (POS_OP + SIZE_OP); - public const int POS_C = (POS_A + SIZE_A); - public const int POS_B = (POS_C + SIZE_C); - public const int POS_Bx = POS_C; - - - /* - ** limits for opcode arguments. - ** we use (signed) int to manipulate most arguments, - ** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) - */ - //#if SIZE_Bx < LUAI_BITSINT-1 - public const int MAXARG_Bx = ((1<>1); /* `sBx' is signed */ - //#else - //public const int MAXARG_Bx = System.Int32.MaxValue; - //public const int MAXARG_sBx = System.Int32.MaxValue; - //#endif - - [CLSCompliantAttribute(false)] - public const uint MAXARG_A = (uint)((1 << (int)SIZE_A) -1); - [CLSCompliantAttribute(false)] - public const uint MAXARG_B = (uint)((1 << (int)SIZE_B) -1); - [CLSCompliantAttribute(false)] - public const uint MAXARG_C = (uint)((1 << (int)SIZE_C) -1); - - - /* creates a mask with `n' 1 bits at position `p' */ - //public static int MASK1(int n, int p) { return ((~((~(Instruction)0) << n)) << p); } - internal static uint MASK1(int n, int p) { return (uint)((~((~0) << n)) << p); } - - /* creates a mask with `n' 0 bits at position `p' */ - internal static uint MASK0(int n, int p) { return (uint)(~MASK1(n, p)); } - - /* - ** the following macros help to manipulate instructions - */ - - internal static OpCode GET_OPCODE(Instruction i) - { - return (OpCode)((i >> POS_OP) & MASK1(SIZE_OP, 0)); - } - internal static OpCode GET_OPCODE(InstructionPtr i) { return GET_OPCODE(i[0]); } - - internal static void SET_OPCODE(ref Instruction i, Instruction o) - { - i = (Instruction)(i & MASK0(SIZE_OP, POS_OP)) | ((o << POS_OP) & MASK1(SIZE_OP, POS_OP)); - } - internal static void SET_OPCODE(ref Instruction i, OpCode opcode) - { - i = (Instruction)(i & MASK0(SIZE_OP, POS_OP)) | (((uint)opcode << POS_OP) & MASK1(SIZE_OP, POS_OP)); - } - internal static void SET_OPCODE(InstructionPtr i, OpCode opcode) { SET_OPCODE(ref i.codes[i.pc], opcode); } - - internal static int GETARG_A(Instruction i) - { - return (int)((i >> POS_A) & MASK1(SIZE_A, 0)); - } - internal static int GETARG_A(InstructionPtr i) { return GETARG_A(i[0]); } - - internal static void SETARG_A(InstructionPtr i, int u) - { - i[0] = (Instruction)((i[0] & MASK0(SIZE_A, POS_A)) | ((u << POS_A) & MASK1(SIZE_A, POS_A))); - } - - internal static int GETARG_B(Instruction i) - { - return (int)((i>>POS_B) & MASK1(SIZE_B,0)); - } - internal static int GETARG_B(InstructionPtr i) { return GETARG_B(i[0]); } - - internal static void SETARG_B(InstructionPtr i, int b) - { - i[0] = (Instruction)((i[0] & MASK0(SIZE_B, POS_B)) | ((b << POS_B) & MASK1(SIZE_B, POS_B))); - } - - internal static int GETARG_C(Instruction i) - { - return (int)((i>>POS_C) & MASK1(SIZE_C,0)); - } - internal static int GETARG_C(InstructionPtr i) { return GETARG_C(i[0]); } - - internal static void SETARG_C(InstructionPtr i, int b) - { - i[0] = (Instruction)((i[0] & MASK0(SIZE_C, POS_C)) | ((b << POS_C) & MASK1(SIZE_C, POS_C))); - } - - internal static int GETARG_Bx(Instruction i) - { - return (int)((i>>POS_Bx) & MASK1(SIZE_Bx,0)); - } - internal static int GETARG_Bx(InstructionPtr i) { return GETARG_Bx(i[0]); } - - internal static void SETARG_Bx(InstructionPtr i, int b) - { - i[0] = (Instruction)((i[0] & MASK0(SIZE_Bx, POS_Bx)) | ((b << POS_Bx) & MASK1(SIZE_Bx, POS_Bx))); - } - - internal static int GETARG_sBx(Instruction i) - { - return (GETARG_Bx(i) - MAXARG_sBx); - } - internal static int GETARG_sBx(InstructionPtr i) { return GETARG_sBx(i[0]); } - - internal static void SETARG_sBx(InstructionPtr i, int b) - { - SETARG_Bx(i, b + MAXARG_sBx); - } - - internal static int CREATE_ABC(OpCode o, int a, int b, int c) - { - return (int)(((int)o << POS_OP) | (a << POS_A) | (b << POS_B) | (c << POS_C)); - } - - internal static int CREATE_ABx(OpCode o, int a, int bc) - { - int result = (int)(((int)o << POS_OP) | (a << POS_A) | (bc << POS_Bx)); - return result; - } - - - /* - ** Macros to operate RK indices - */ - - /* this bit 1 means constant (0 means register) */ - internal readonly static int BITRK = (1 << (SIZE_B - 1)); - - /* test whether value is a constant */ - internal static int ISK(int x) { return x & BITRK; } - - /* gets the index of the constant */ - internal static int INDEXK(int r) { return r & (~BITRK); } - - internal static readonly int MAXINDEXRK = BITRK - 1; - - /* code a constant index as a RK value */ - internal static int RKASK(int x) { return x | BITRK; } - - - /* - ** invalid register that fits in 8 bits - */ - internal static readonly int NO_REG = (int)MAXARG_A; - - - /* - ** R(x) - register - ** Kst(x) - constant (in constant table) - ** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x) - */ - - - /* - ** grep "ORDER OP" if you change these enums - */ - - public enum OpCode { - /*---------------------------------------------------------------------- - name args description - ------------------------------------------------------------------------*/ - OP_MOVE,/* A B R(A) := R(B) */ - OP_LOADK,/* A Bx R(A) := Kst(Bx) */ - OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */ - OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */ - OP_GETUPVAL,/* A B R(A) := UpValue[B] */ - - OP_GETGLOBAL,/* A Bx R(A) := Gbl[Kst(Bx)] */ - OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */ - - OP_SETGLOBAL,/* A Bx Gbl[Kst(Bx)] := R(A) */ - OP_SETUPVAL,/* A B UpValue[B] := R(A) */ - OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */ - - OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */ - - OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */ - - OP_ADD,/* A B C R(A) := RK(B) + RK(C) */ - OP_SUB,/* A B C R(A) := RK(B) - RK(C) */ - OP_MUL,/* A B C R(A) := RK(B) * RK(C) */ - OP_DIV,/* A B C R(A) := RK(B) / RK(C) */ - OP_MOD,/* A B C R(A) := RK(B) % RK(C) */ - OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */ - OP_UNM,/* A B R(A) := -R(B) */ - OP_NOT,/* A B R(A) := not R(B) */ - OP_LEN,/* A B R(A) := length of R(B) */ - - OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ - - OP_JMP,/* sBx pc+=sBx */ - - OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ - OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ - OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ - - OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ - OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ - - OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ - OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ - OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ - - OP_FORLOOP,/* A sBx R(A)+=R(A+2); - if R(A) =) R(A)*/ - OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ - - OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ - }; - - - public const int NUM_OPCODES = (int)OpCode.OP_VARARG; - - - - /*=========================================================================== - Notes: - (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, - and can be 0: OP_CALL then sets `top' to last_result+1, so - next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. - - (*) In OP_VARARG, if (B == 0) then use actual number of varargs and - set top (like in OP_CALL with C == 0). - - (*) In OP_RETURN, if (B == 0) then return up to `top' - - (*) In OP_SETLIST, if (B == 0) then B = `top'; - if (C == 0) then next `instruction' is real C - - (*) For comparisons, A specifies what condition the test should accept - (true or false). - - (*) All `skips' (pc++) assume that next instruction is a jump - ===========================================================================*/ - - - /* - ** masks for instruction properties. The format is: - ** bits 0-1: op mode - ** bits 2-3: C arg mode - ** bits 4-5: B arg mode - ** bit 6: instruction set register A - ** bit 7: operator is a test - */ - - public enum OpArgMask { - OpArgN, /* argument is not used */ - OpArgU, /* argument is used */ - OpArgR, /* argument is a register or a jump offset */ - OpArgK /* argument is a constant or register/constant */ - }; - - public static OpMode getOpMode(OpCode m) {return (OpMode)(luaP_opmodes[(int)m] & 3);} - public static OpArgMask getBMode(OpCode m) { return (OpArgMask)((luaP_opmodes[(int)m] >> 4) & 3); } - public static OpArgMask getCMode(OpCode m) { return (OpArgMask)((luaP_opmodes[(int)m] >> 2) & 3); } - public static int testAMode(OpCode m) { return luaP_opmodes[(int)m] & (1 << 6); } - public static int testTMode(OpCode m) { return luaP_opmodes[(int)m] & (1 << 7); } - - - /* number of list items to accumulate before a SETLIST instruction */ - public const int LFIELDS_PER_FLUSH = 50; - - - - /* ORDER OP */ - - private readonly static CharPtr[] luaP_opnames = { - "MOVE", - "LOADK", - "LOADBOOL", - "LOADNIL", - "GETUPVAL", - "GETGLOBAL", - "GETTABLE", - "SETGLOBAL", - "SETUPVAL", - "SETTABLE", - "NEWTABLE", - "SELF", - "ADD", - "SUB", - "MUL", - "DIV", - "MOD", - "POW", - "UNM", - "NOT", - "LEN", - "CONCAT", - "JMP", - "EQ", - "LT", - "LE", - "TEST", - "TESTSET", - "CALL", - "TAILCALL", - "RETURN", - "FORLOOP", - "FORPREP", - "TFORLOOP", - "SETLIST", - "CLOSE", - "CLOSURE", - "VARARG", - }; - - - private static lu_byte opmode(lu_byte t, lu_byte a, OpArgMask b, OpArgMask c, OpMode m) - { - return (lu_byte)(((t) << 7) | ((a) << 6) | (((lu_byte)b) << 4) | (((lu_byte)c) << 2) | ((lu_byte)m)); - } - - private readonly static lu_byte[] luaP_opmodes = { - /* T A B C mode opcode */ - opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_MOVE */ - ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgN, OpMode.iABx) /* OP_LOADK */ - ,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_LOADBOOL */ - ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_LOADNIL */ - ,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABC) /* OP_GETUPVAL */ - ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgN, OpMode.iABx) /* OP_GETGLOBAL */ - ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgK, OpMode.iABC) /* OP_GETTABLE */ - ,opmode(0, 0, OpArgMask.OpArgK, OpArgMask.OpArgN, OpMode.iABx) /* OP_SETGLOBAL */ - ,opmode(0, 0, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABC) /* OP_SETUPVAL */ - ,opmode(0, 0, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_SETTABLE */ - ,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_NEWTABLE */ - ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgK, OpMode.iABC) /* OP_SELF */ - ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_ADD */ - ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_SUB */ - ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_MUL */ - ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_DIV */ - ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_MOD */ - ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_POW */ - ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_UNM */ - ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_NOT */ - ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_LEN */ - ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgR, OpMode.iABC) /* OP_CONCAT */ - ,opmode(0, 0, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iAsBx) /* OP_JMP */ - ,opmode(1, 0, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_EQ */ - ,opmode(1, 0, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_LT */ - ,opmode(1, 0, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_LE */ - ,opmode(1, 1, OpArgMask.OpArgR, OpArgMask.OpArgU, OpMode.iABC) /* OP_TEST */ - ,opmode(1, 1, OpArgMask.OpArgR, OpArgMask.OpArgU, OpMode.iABC) /* OP_TESTSET */ - ,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_CALL */ - ,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_TAILCALL */ - ,opmode(0, 0, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABC) /* OP_RETURN */ - ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iAsBx) /* OP_FORLOOP */ - ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iAsBx) /* OP_FORPREP */ - ,opmode(1, 0, OpArgMask.OpArgN, OpArgMask.OpArgU, OpMode.iABC) /* OP_TFORLOOP */ - ,opmode(0, 0, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_SETLIST */ - ,opmode(0, 0, OpArgMask.OpArgN, OpArgMask.OpArgN, OpMode.iABC) /* OP_CLOSE */ - ,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABx) /* OP_CLOSURE */ - ,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABC) /* OP_VARARG */ - }; - - } -} +/* +** $Id: lopcodes.c,v 1.37.1.1 2007/12/27 13:02:25 roberto Exp $ +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace KopiLua +{ + using lu_byte = System.Byte; + using Instruction = System.UInt32; + + public partial class Lua + { + /*=========================================================================== + We assume that instructions are unsigned numbers. + All instructions have an opcode in the first 6 bits. + Instructions can have the following fields: + `A' : 8 bits + `B' : 9 bits + `C' : 9 bits + `Bx' : 18 bits (`B' and `C' together) + `sBx' : signed Bx + + A signed argument is represented in excess K; that is, the number + value is the unsigned value minus K. K is exactly the maximum value + for that argument (so that -max is represented by 0, and +max is + represented by 2*max), which is half the maximum for the corresponding + unsigned argument. + ===========================================================================*/ + + + public enum OpMode {iABC, iABx, iAsBx}; /* basic instruction format */ + + + /* + ** size and position of opcode arguments. + */ + public const int SIZE_C = 9; + public const int SIZE_B = 9; + public const int SIZE_Bx = (SIZE_C + SIZE_B); + public const int SIZE_A = 8; + + public const int SIZE_OP = 6; + + public const int POS_OP = 0; + public const int POS_A = (POS_OP + SIZE_OP); + public const int POS_C = (POS_A + SIZE_A); + public const int POS_B = (POS_C + SIZE_C); + public const int POS_Bx = POS_C; + + + /* + ** limits for opcode arguments. + ** we use (signed) int to manipulate most arguments, + ** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) + */ + //#if SIZE_Bx < LUAI_BITSINT-1 + public const int MAXARG_Bx = ((1<>1); /* `sBx' is signed */ + //#else + //public const int MAXARG_Bx = System.Int32.MaxValue; + //public const int MAXARG_sBx = System.Int32.MaxValue; + //#endif + + [CLSCompliantAttribute(false)] + public const uint MAXARG_A = (uint)((1 << (int)SIZE_A) -1); + [CLSCompliantAttribute(false)] + public const uint MAXARG_B = (uint)((1 << (int)SIZE_B) -1); + [CLSCompliantAttribute(false)] + public const uint MAXARG_C = (uint)((1 << (int)SIZE_C) -1); + + + /* creates a mask with `n' 1 bits at position `p' */ + //public static int MASK1(int n, int p) { return ((~((~(Instruction)0) << n)) << p); } + internal static uint MASK1(int n, int p) { return (uint)((~((~0) << n)) << p); } + + /* creates a mask with `n' 0 bits at position `p' */ + internal static uint MASK0(int n, int p) { return (uint)(~MASK1(n, p)); } + + /* + ** the following macros help to manipulate instructions + */ + + internal static OpCode GET_OPCODE(Instruction i) + { + return (OpCode)((i >> POS_OP) & MASK1(SIZE_OP, 0)); + } + internal static OpCode GET_OPCODE(InstructionPtr i) { return GET_OPCODE(i[0]); } + + internal static void SET_OPCODE(ref Instruction i, Instruction o) + { + i = (Instruction)(i & MASK0(SIZE_OP, POS_OP)) | ((o << POS_OP) & MASK1(SIZE_OP, POS_OP)); + } + internal static void SET_OPCODE(ref Instruction i, OpCode opcode) + { + i = (Instruction)(i & MASK0(SIZE_OP, POS_OP)) | (((uint)opcode << POS_OP) & MASK1(SIZE_OP, POS_OP)); + } + internal static void SET_OPCODE(InstructionPtr i, OpCode opcode) { SET_OPCODE(ref i.codes[i.pc], opcode); } + + internal static int GETARG_A(Instruction i) + { + return (int)((i >> POS_A) & MASK1(SIZE_A, 0)); + } + internal static int GETARG_A(InstructionPtr i) { return GETARG_A(i[0]); } + + internal static void SETARG_A(InstructionPtr i, int u) + { + i[0] = (Instruction)((i[0] & MASK0(SIZE_A, POS_A)) | ((u << POS_A) & MASK1(SIZE_A, POS_A))); + } + + internal static int GETARG_B(Instruction i) + { + return (int)((i>>POS_B) & MASK1(SIZE_B,0)); + } + internal static int GETARG_B(InstructionPtr i) { return GETARG_B(i[0]); } + + internal static void SETARG_B(InstructionPtr i, int b) + { + i[0] = (Instruction)((i[0] & MASK0(SIZE_B, POS_B)) | ((b << POS_B) & MASK1(SIZE_B, POS_B))); + } + + internal static int GETARG_C(Instruction i) + { + return (int)((i>>POS_C) & MASK1(SIZE_C,0)); + } + internal static int GETARG_C(InstructionPtr i) { return GETARG_C(i[0]); } + + internal static void SETARG_C(InstructionPtr i, int b) + { + i[0] = (Instruction)((i[0] & MASK0(SIZE_C, POS_C)) | ((b << POS_C) & MASK1(SIZE_C, POS_C))); + } + + internal static int GETARG_Bx(Instruction i) + { + return (int)((i>>POS_Bx) & MASK1(SIZE_Bx,0)); + } + internal static int GETARG_Bx(InstructionPtr i) { return GETARG_Bx(i[0]); } + + internal static void SETARG_Bx(InstructionPtr i, int b) + { + i[0] = (Instruction)((i[0] & MASK0(SIZE_Bx, POS_Bx)) | ((b << POS_Bx) & MASK1(SIZE_Bx, POS_Bx))); + } + + internal static int GETARG_sBx(Instruction i) + { + return (GETARG_Bx(i) - MAXARG_sBx); + } + internal static int GETARG_sBx(InstructionPtr i) { return GETARG_sBx(i[0]); } + + internal static void SETARG_sBx(InstructionPtr i, int b) + { + SETARG_Bx(i, b + MAXARG_sBx); + } + + internal static int CREATE_ABC(OpCode o, int a, int b, int c) + { + return (int)(((int)o << POS_OP) | (a << POS_A) | (b << POS_B) | (c << POS_C)); + } + + internal static int CREATE_ABx(OpCode o, int a, int bc) + { + int result = (int)(((int)o << POS_OP) | (a << POS_A) | (bc << POS_Bx)); + return result; + } + + + /* + ** Macros to operate RK indices + */ + + /* this bit 1 means constant (0 means register) */ + internal readonly static int BITRK = (1 << (SIZE_B - 1)); + + /* test whether value is a constant */ + internal static int ISK(int x) { return x & BITRK; } + + /* gets the index of the constant */ + internal static int INDEXK(int r) { return r & (~BITRK); } + + internal static readonly int MAXINDEXRK = BITRK - 1; + + /* code a constant index as a RK value */ + internal static int RKASK(int x) { return x | BITRK; } + + + /* + ** invalid register that fits in 8 bits + */ + internal static readonly int NO_REG = (int)MAXARG_A; + + + /* + ** R(x) - register + ** Kst(x) - constant (in constant table) + ** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x) + */ + + + /* + ** grep "ORDER OP" if you change these enums + */ + + public enum OpCode { + /*---------------------------------------------------------------------- + name args description + ------------------------------------------------------------------------*/ + OP_MOVE,/* A B R(A) := R(B) */ + OP_LOADK,/* A Bx R(A) := Kst(Bx) */ + OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */ + OP_LOADNIL,/* A B R(A) := ... := R(B) := nil */ + OP_GETUPVAL,/* A B R(A) := UpValue[B] */ + + OP_GETGLOBAL,/* A Bx R(A) := Gbl[Kst(Bx)] */ + OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */ + + OP_SETGLOBAL,/* A Bx Gbl[Kst(Bx)] := R(A) */ + OP_SETUPVAL,/* A B UpValue[B] := R(A) */ + OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */ + + OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */ + + OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */ + + OP_ADD,/* A B C R(A) := RK(B) + RK(C) */ + OP_SUB,/* A B C R(A) := RK(B) - RK(C) */ + OP_MUL,/* A B C R(A) := RK(B) * RK(C) */ + OP_DIV,/* A B C R(A) := RK(B) / RK(C) */ + OP_MOD,/* A B C R(A) := RK(B) % RK(C) */ + OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */ + OP_UNM,/* A B R(A) := -R(B) */ + OP_NOT,/* A B R(A) := not R(B) */ + OP_LEN,/* A B R(A) := length of R(B) */ + + OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ + + OP_JMP,/* sBx pc+=sBx */ + + OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ + OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ + OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ + + OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ + OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ + + OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ + OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ + OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ + + OP_FORLOOP,/* A sBx R(A)+=R(A+2); + if R(A) =) R(A)*/ + OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ + + OP_VARARG/* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ + }; + + + public const int NUM_OPCODES = (int)OpCode.OP_VARARG; + + + + /*=========================================================================== + Notes: + (*) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1, + and can be 0: OP_CALL then sets `top' to last_result+1, so + next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'. + + (*) In OP_VARARG, if (B == 0) then use actual number of varargs and + set top (like in OP_CALL with C == 0). + + (*) In OP_RETURN, if (B == 0) then return up to `top' + + (*) In OP_SETLIST, if (B == 0) then B = `top'; + if (C == 0) then next `instruction' is real C + + (*) For comparisons, A specifies what condition the test should accept + (true or false). + + (*) All `skips' (pc++) assume that next instruction is a jump + ===========================================================================*/ + + + /* + ** masks for instruction properties. The format is: + ** bits 0-1: op mode + ** bits 2-3: C arg mode + ** bits 4-5: B arg mode + ** bit 6: instruction set register A + ** bit 7: operator is a test + */ + + public enum OpArgMask { + OpArgN, /* argument is not used */ + OpArgU, /* argument is used */ + OpArgR, /* argument is a register or a jump offset */ + OpArgK /* argument is a constant or register/constant */ + }; + + public static OpMode getOpMode(OpCode m) {return (OpMode)(luaP_opmodes[(int)m] & 3);} + public static OpArgMask getBMode(OpCode m) { return (OpArgMask)((luaP_opmodes[(int)m] >> 4) & 3); } + public static OpArgMask getCMode(OpCode m) { return (OpArgMask)((luaP_opmodes[(int)m] >> 2) & 3); } + public static int testAMode(OpCode m) { return luaP_opmodes[(int)m] & (1 << 6); } + public static int testTMode(OpCode m) { return luaP_opmodes[(int)m] & (1 << 7); } + + + /* number of list items to accumulate before a SETLIST instruction */ + public const int LFIELDS_PER_FLUSH = 50; + + + + /* ORDER OP */ + + private readonly static CharPtr[] luaP_opnames = { + "MOVE", + "LOADK", + "LOADBOOL", + "LOADNIL", + "GETUPVAL", + "GETGLOBAL", + "GETTABLE", + "SETGLOBAL", + "SETUPVAL", + "SETTABLE", + "NEWTABLE", + "SELF", + "ADD", + "SUB", + "MUL", + "DIV", + "MOD", + "POW", + "UNM", + "NOT", + "LEN", + "CONCAT", + "JMP", + "EQ", + "LT", + "LE", + "TEST", + "TESTSET", + "CALL", + "TAILCALL", + "RETURN", + "FORLOOP", + "FORPREP", + "TFORLOOP", + "SETLIST", + "CLOSE", + "CLOSURE", + "VARARG", + }; + + + private static lu_byte opmode(lu_byte t, lu_byte a, OpArgMask b, OpArgMask c, OpMode m) + { + return (lu_byte)(((t) << 7) | ((a) << 6) | (((lu_byte)b) << 4) | (((lu_byte)c) << 2) | ((lu_byte)m)); + } + + private readonly static lu_byte[] luaP_opmodes = { + /* T A B C mode opcode */ + opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_MOVE */ + ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgN, OpMode.iABx) /* OP_LOADK */ + ,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_LOADBOOL */ + ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_LOADNIL */ + ,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABC) /* OP_GETUPVAL */ + ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgN, OpMode.iABx) /* OP_GETGLOBAL */ + ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgK, OpMode.iABC) /* OP_GETTABLE */ + ,opmode(0, 0, OpArgMask.OpArgK, OpArgMask.OpArgN, OpMode.iABx) /* OP_SETGLOBAL */ + ,opmode(0, 0, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABC) /* OP_SETUPVAL */ + ,opmode(0, 0, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_SETTABLE */ + ,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_NEWTABLE */ + ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgK, OpMode.iABC) /* OP_SELF */ + ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_ADD */ + ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_SUB */ + ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_MUL */ + ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_DIV */ + ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_MOD */ + ,opmode(0, 1, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_POW */ + ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_UNM */ + ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_NOT */ + ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iABC) /* OP_LEN */ + ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgR, OpMode.iABC) /* OP_CONCAT */ + ,opmode(0, 0, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iAsBx) /* OP_JMP */ + ,opmode(1, 0, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_EQ */ + ,opmode(1, 0, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_LT */ + ,opmode(1, 0, OpArgMask.OpArgK, OpArgMask.OpArgK, OpMode.iABC) /* OP_LE */ + ,opmode(1, 1, OpArgMask.OpArgR, OpArgMask.OpArgU, OpMode.iABC) /* OP_TEST */ + ,opmode(1, 1, OpArgMask.OpArgR, OpArgMask.OpArgU, OpMode.iABC) /* OP_TESTSET */ + ,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_CALL */ + ,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_TAILCALL */ + ,opmode(0, 0, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABC) /* OP_RETURN */ + ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iAsBx) /* OP_FORLOOP */ + ,opmode(0, 1, OpArgMask.OpArgR, OpArgMask.OpArgN, OpMode.iAsBx) /* OP_FORPREP */ + ,opmode(1, 0, OpArgMask.OpArgN, OpArgMask.OpArgU, OpMode.iABC) /* OP_TFORLOOP */ + ,opmode(0, 0, OpArgMask.OpArgU, OpArgMask.OpArgU, OpMode.iABC) /* OP_SETLIST */ + ,opmode(0, 0, OpArgMask.OpArgN, OpArgMask.OpArgN, OpMode.iABC) /* OP_CLOSE */ + ,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABx) /* OP_CLOSURE */ + ,opmode(0, 1, OpArgMask.OpArgU, OpArgMask.OpArgN, OpMode.iABC) /* OP_VARARG */ + }; + + } +} diff --git a/Core/KopiLua/loslib.cs b/Core/KopiLua/loslib.cs index 77a041a6bf43a9a59a6c00f9aa5b365deaf1a2da..888ae3b84016666a3d63e2162fa9c1c2256a1f83 100644 --- a/Core/KopiLua/loslib.cs +++ b/Core/KopiLua/loslib.cs @@ -1,277 +1,277 @@ -/* -** $Id: loslib.c,v 1.19.1.3 2008/01/18 16:38:18 roberto Exp $ -** Standard Operating System library -** See Copyright Notice in lua.h -*/ - -using System; -using System.Threading; -using System.IO; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -namespace KopiLua -{ - using TValue = Lua.lua_TValue; - using StkId = Lua.lua_TValue; - using lua_Integer = System.Int32; - using lua_Number = System.Double; - - public partial class Lua - { - private static int os_pushresult (lua_State L, int i, CharPtr filename) { - int en = errno(); /* calls to Lua API may change this value */ - if (i != 0) { - lua_pushboolean(L, 1); - return 1; - } - else { - lua_pushnil(L); - lua_pushfstring(L, "%s: %s", filename, strerror(en)); - lua_pushinteger(L, en); - return 3; - } - } - - - private static int os_execute (lua_State L) { -#if XBOX || SILVERLIGHT - luaL_error(L, "os_execute not supported on XBox360"); -#else - CharPtr strCmdLine = "/C regenresx " + luaL_optstring(L, 1, null); - System.Diagnostics.Process proc = new System.Diagnostics.Process(); - proc.EnableRaisingEvents=false; - proc.StartInfo.FileName = "CMD.exe"; - proc.StartInfo.Arguments = strCmdLine.ToString(); - proc.Start(); - proc.WaitForExit(); - lua_pushinteger(L, proc.ExitCode); -#endif - return 1; - } - - - private static int os_remove (lua_State L) { - CharPtr filename = luaL_checkstring(L, 1); - int result = 1; - try {File.Delete(filename.ToString());} catch {result = 0;} - return os_pushresult(L, result, filename); - } - - - private static int os_rename (lua_State L) { - CharPtr fromname = luaL_checkstring(L, 1); - CharPtr toname = luaL_checkstring(L, 2); - int result; - try - { - File.Move(fromname.ToString(), toname.ToString()); - result = 0; - } - catch - { - result = 1; // todo: this should be a proper error code - } - return os_pushresult(L, result, fromname); - } - - - private static int os_tmpname (lua_State L) { -#if XBOX - luaL_error(L, "os_tmpname not supported on Xbox360"); -#else - lua_pushstring(L, Path.GetTempFileName()); -#endif - return 1; - } - - - private static int os_getenv (lua_State L) { - lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if null push nil */ - return 1; - } - - - private static int os_clock (lua_State L) { - long ticks = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; - lua_pushnumber(L, ((lua_Number)ticks)/(lua_Number)1000); - return 1; - } - - - /* - ** {====================================================== - ** Time/Date operations - ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, - ** wday=%w+1, yday=%j, isdst=? } - ** ======================================================= - */ - - private static void setfield (lua_State L, CharPtr key, int value) { - lua_pushinteger(L, value); - lua_setfield(L, -2, key); - } - - private static void setboolfield (lua_State L, CharPtr key, int value) { - if (value < 0) /* undefined? */ - return; /* does not set field */ - lua_pushboolean(L, value); - lua_setfield(L, -2, key); - } - - private static int getboolfield (lua_State L, CharPtr key) { - int res; - lua_getfield(L, -1, key); - res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); - lua_pop(L, 1); - return res; - } - - private static int getfield (lua_State L, CharPtr key, int d) { - int res; - lua_getfield(L, -1, key); - if (lua_isnumber(L, -1) != 0) - res = (int)lua_tointeger(L, -1); - else { - if (d < 0) - return luaL_error(L, "field " + LUA_QS + " missing in date table", key); - res = d; - } - lua_pop(L, 1); - return res; - } - - - private static int os_date (lua_State L) { - CharPtr s = luaL_optstring(L, 1, "%c"); - DateTime stm; - if (s[0] == '!') { /* UTC? */ - stm = DateTime.UtcNow; - s.inc(); /* skip `!' */ - } - else - stm = DateTime.Now; - if (strcmp(s, "*t") == 0) { - lua_createtable(L, 0, 9); /* 9 = number of fields */ - setfield(L, "sec", stm.Second); - setfield(L, "min", stm.Minute); - setfield(L, "hour", stm.Hour); - setfield(L, "day", stm.Day); - setfield(L, "month", stm.Month); - setfield(L, "year", stm.Year); - setfield(L, "wday", (int)stm.DayOfWeek); - setfield(L, "yday", stm.DayOfYear); - setboolfield(L, "isdst", stm.IsDaylightSavingTime() ? 1 : 0); - } - else { - luaL_error(L, "strftime not implemented yet"); // todo: implement this - mjf -#if false - CharPtr cc = new char[3]; - luaL_Buffer b; - cc[0] = '%'; cc[2] = '\0'; - luaL_buffinit(L, b); - for (; s[0] != 0; s.inc()) { - if (s[0] != '%' || s[1] == '\0') /* no conversion specifier? */ - luaL_addchar(b, s[0]); - else { - uint reslen; - CharPtr buff = new char[200]; /* should be big enough for any conversion result */ - s.inc(); - cc[1] = s[0]; - reslen = strftime(buff, buff.Length, cc, stm); - luaL_addlstring(b, buff, reslen); - } - } - luaL_pushresult(b); -#endif // #if 0 - } - return 1; - } - - - private static int os_time (lua_State L) { - DateTime t; - if (lua_isnoneornil(L, 1)) /* called without args? */ - t = DateTime.Now; /* get current time */ - else { - luaL_checktype(L, 1, LUA_TTABLE); - lua_settop(L, 1); /* make sure table is at the top */ - int sec = getfield(L, "sec", 0); - int min = getfield(L, "min", 0); - int hour = getfield(L, "hour", 12); - int day = getfield(L, "day", -1); - int month = getfield(L, "month", -1) - 1; - int year = getfield(L, "year", -1) - 1900; - /*int isdst = */getboolfield(L, "isdst"); // todo: implement this - mjf - t = new DateTime(year, month, day, hour, min, sec); - } - lua_pushnumber(L, t.Ticks); - return 1; - } - - - private static int os_difftime (lua_State L) { - long ticks = (long)luaL_checknumber(L, 1) - (long)luaL_optnumber(L, 2, 0); - lua_pushnumber(L, ticks/TimeSpan.TicksPerSecond); - return 1; - } - - /* }====================================================== */ - - // locale not supported yet - private static int os_setlocale (lua_State L) { - /* - static string[] cat = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, - LC_NUMERIC, LC_TIME}; - static string[] catnames[] = {"all", "collate", "ctype", "monetary", - "numeric", "time", null}; - CharPtr l = luaL_optstring(L, 1, null); - int op = luaL_checkoption(L, 2, "all", catnames); - lua_pushstring(L, setlocale(cat[op], l)); - */ - CharPtr l = luaL_optstring(L, 1, null); - lua_pushstring(L, "C"); - return (l.ToString() == "C") ? 1 : 0; - } - - - private static int os_exit (lua_State L) { -#if XBOX - luaL_error(L, "os_exit not supported on XBox360"); -#else -#if SILVERLIGHT - throw new SystemException(); -#else - Environment.Exit(EXIT_SUCCESS); -#endif -#endif - return 0; - } - - private readonly static luaL_Reg[] syslib = { - new luaL_Reg("clock", os_clock), - new luaL_Reg("date", os_date), - new luaL_Reg("difftime", os_difftime), - new luaL_Reg("execute", os_execute), - new luaL_Reg("exit", os_exit), - new luaL_Reg("getenv", os_getenv), - new luaL_Reg("remove", os_remove), - new luaL_Reg("rename", os_rename), - new luaL_Reg("setlocale", os_setlocale), - new luaL_Reg("time", os_time), - new luaL_Reg("tmpname", os_tmpname), - new luaL_Reg(null, null) - }; - - /* }====================================================== */ - - - - public static int luaopen_os (lua_State L) { - luaL_register(L, LUA_OSLIBNAME, syslib); - return 1; - } - - } -} +/* +** $Id: loslib.c,v 1.19.1.3 2008/01/18 16:38:18 roberto Exp $ +** Standard Operating System library +** See Copyright Notice in lua.h +*/ + +using System; +using System.Threading; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace KopiLua +{ + using TValue = Lua.lua_TValue; + using StkId = Lua.lua_TValue; + using lua_Integer = System.Int32; + using lua_Number = System.Double; + + public partial class Lua + { + private static int os_pushresult (lua_State L, int i, CharPtr filename) { + int en = errno(); /* calls to Lua API may change this value */ + if (i != 0) { + lua_pushboolean(L, 1); + return 1; + } + else { + lua_pushnil(L); + lua_pushfstring(L, "%s: %s", filename, strerror(en)); + lua_pushinteger(L, en); + return 3; + } + } + + + private static int os_execute (lua_State L) { +#if XBOX || SILVERLIGHT + luaL_error(L, "os_execute not supported on XBox360"); +#else + CharPtr strCmdLine = "/C regenresx " + luaL_optstring(L, 1, null); + System.Diagnostics.Process proc = new System.Diagnostics.Process(); + proc.EnableRaisingEvents=false; + proc.StartInfo.FileName = "CMD.exe"; + proc.StartInfo.Arguments = strCmdLine.ToString(); + proc.Start(); + proc.WaitForExit(); + lua_pushinteger(L, proc.ExitCode); +#endif + return 1; + } + + + private static int os_remove (lua_State L) { + CharPtr filename = luaL_checkstring(L, 1); + int result = 1; + try {File.Delete(filename.ToString());} catch {result = 0;} + return os_pushresult(L, result, filename); + } + + + private static int os_rename (lua_State L) { + CharPtr fromname = luaL_checkstring(L, 1); + CharPtr toname = luaL_checkstring(L, 2); + int result; + try + { + File.Move(fromname.ToString(), toname.ToString()); + result = 0; + } + catch + { + result = 1; // todo: this should be a proper error code + } + return os_pushresult(L, result, fromname); + } + + + private static int os_tmpname (lua_State L) { +#if XBOX + luaL_error(L, "os_tmpname not supported on Xbox360"); +#else + lua_pushstring(L, Path.GetTempFileName()); +#endif + return 1; + } + + + private static int os_getenv (lua_State L) { + lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if null push nil */ + return 1; + } + + + private static int os_clock (lua_State L) { + long ticks = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; + lua_pushnumber(L, ((lua_Number)ticks)/(lua_Number)1000); + return 1; + } + + + /* + ** {====================================================== + ** Time/Date operations + ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, + ** wday=%w+1, yday=%j, isdst=? } + ** ======================================================= + */ + + private static void setfield (lua_State L, CharPtr key, int value) { + lua_pushinteger(L, value); + lua_setfield(L, -2, key); + } + + private static void setboolfield (lua_State L, CharPtr key, int value) { + if (value < 0) /* undefined? */ + return; /* does not set field */ + lua_pushboolean(L, value); + lua_setfield(L, -2, key); + } + + private static int getboolfield (lua_State L, CharPtr key) { + int res; + lua_getfield(L, -1, key); + res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1); + lua_pop(L, 1); + return res; + } + + private static int getfield (lua_State L, CharPtr key, int d) { + int res; + lua_getfield(L, -1, key); + if (lua_isnumber(L, -1) != 0) + res = (int)lua_tointeger(L, -1); + else { + if (d < 0) + return luaL_error(L, "field " + LUA_QS + " missing in date table", key); + res = d; + } + lua_pop(L, 1); + return res; + } + + + private static int os_date (lua_State L) { + CharPtr s = luaL_optstring(L, 1, "%c"); + DateTime stm; + if (s[0] == '!') { /* UTC? */ + stm = DateTime.UtcNow; + s.inc(); /* skip `!' */ + } + else + stm = DateTime.Now; + if (strcmp(s, "*t") == 0) { + lua_createtable(L, 0, 9); /* 9 = number of fields */ + setfield(L, "sec", stm.Second); + setfield(L, "min", stm.Minute); + setfield(L, "hour", stm.Hour); + setfield(L, "day", stm.Day); + setfield(L, "month", stm.Month); + setfield(L, "year", stm.Year); + setfield(L, "wday", (int)stm.DayOfWeek); + setfield(L, "yday", stm.DayOfYear); + setboolfield(L, "isdst", stm.IsDaylightSavingTime() ? 1 : 0); + } + else { + luaL_error(L, "strftime not implemented yet"); // todo: implement this - mjf +#if false + CharPtr cc = new char[3]; + luaL_Buffer b; + cc[0] = '%'; cc[2] = '\0'; + luaL_buffinit(L, b); + for (; s[0] != 0; s.inc()) { + if (s[0] != '%' || s[1] == '\0') /* no conversion specifier? */ + luaL_addchar(b, s[0]); + else { + uint reslen; + CharPtr buff = new char[200]; /* should be big enough for any conversion result */ + s.inc(); + cc[1] = s[0]; + reslen = strftime(buff, buff.Length, cc, stm); + luaL_addlstring(b, buff, reslen); + } + } + luaL_pushresult(b); +#endif // #if 0 + } + return 1; + } + + + private static int os_time (lua_State L) { + DateTime t; + if (lua_isnoneornil(L, 1)) /* called without args? */ + t = DateTime.Now; /* get current time */ + else { + luaL_checktype(L, 1, LUA_TTABLE); + lua_settop(L, 1); /* make sure table is at the top */ + int sec = getfield(L, "sec", 0); + int min = getfield(L, "min", 0); + int hour = getfield(L, "hour", 12); + int day = getfield(L, "day", -1); + int month = getfield(L, "month", -1) - 1; + int year = getfield(L, "year", -1) - 1900; + /*int isdst = */getboolfield(L, "isdst"); // todo: implement this - mjf + t = new DateTime(year, month, day, hour, min, sec); + } + lua_pushnumber(L, t.Ticks); + return 1; + } + + + private static int os_difftime (lua_State L) { + long ticks = (long)luaL_checknumber(L, 1) - (long)luaL_optnumber(L, 2, 0); + lua_pushnumber(L, ticks/TimeSpan.TicksPerSecond); + return 1; + } + + /* }====================================================== */ + + // locale not supported yet + private static int os_setlocale (lua_State L) { + /* + static string[] cat = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, + LC_NUMERIC, LC_TIME}; + static string[] catnames[] = {"all", "collate", "ctype", "monetary", + "numeric", "time", null}; + CharPtr l = luaL_optstring(L, 1, null); + int op = luaL_checkoption(L, 2, "all", catnames); + lua_pushstring(L, setlocale(cat[op], l)); + */ + CharPtr l = luaL_optstring(L, 1, null); + lua_pushstring(L, "C"); + return (l.ToString() == "C") ? 1 : 0; + } + + + private static int os_exit (lua_State L) { +#if XBOX + luaL_error(L, "os_exit not supported on XBox360"); +#else +#if SILVERLIGHT + throw new SystemException(); +#else + Environment.Exit(EXIT_SUCCESS); +#endif +#endif + return 0; + } + + private readonly static luaL_Reg[] syslib = { + new luaL_Reg("clock", os_clock), + new luaL_Reg("date", os_date), + new luaL_Reg("difftime", os_difftime), + new luaL_Reg("execute", os_execute), + new luaL_Reg("exit", os_exit), + new luaL_Reg("getenv", os_getenv), + new luaL_Reg("remove", os_remove), + new luaL_Reg("rename", os_rename), + new luaL_Reg("setlocale", os_setlocale), + new luaL_Reg("time", os_time), + new luaL_Reg("tmpname", os_tmpname), + new luaL_Reg(null, null) + }; + + /* }====================================================== */ + + + + public static int luaopen_os (lua_State L) { + luaL_register(L, LUA_OSLIBNAME, syslib); + return 1; + } + + } +} diff --git a/Core/KopiLua/lparser.cs b/Core/KopiLua/lparser.cs index 45bd28a30dfe5deac7bcb13f0a36bf7941de26ee..7e4cd3cab60967027ebd5570c7d5b0b0f1f94ed6 100644 --- a/Core/KopiLua/lparser.cs +++ b/Core/KopiLua/lparser.cs @@ -1,1458 +1,1458 @@ -/* -** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $ -** Lua Parser -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; - -namespace KopiLua -{ - using lu_byte = System.Byte; - using lua_Number = System.Double; - using ZIO = Lua.Zio; - - public partial class Lua - { - /* - ** Expression descriptor - */ - - public enum expkind { - VVOID, /* no value */ - VNIL, - VTRUE, - VFALSE, - VK, /* info = index of constant in `k' */ - VKNUM, /* nval = numerical value */ - VLOCAL, /* info = local register */ - VUPVAL, /* info = index of upvalue in `upvalues' */ - VGLOBAL, /* info = index of table; aux = index of global name in `k' */ - VINDEXED, /* info = table register; aux = index register (or `k') */ - VJMP, /* info = instruction pc */ - VRELOCABLE, /* info = instruction pc */ - VNONRELOC, /* info = result register */ - VCALL, /* info = instruction pc */ - VVARARG /* info = instruction pc */ - }; - - - - public class expdesc { - - public void Copy(expdesc e) - { - this.k = e.k; - this.u.Copy(e.u); - this.t = e.t; - this.f = e.f; - } - - public expkind k; - - [CLSCompliantAttribute(false)] - public class _u - { - public void Copy(_u u) - { - this.s.Copy(u.s); - this.nval = u.nval; - } - - [CLSCompliantAttribute(false)] - public class _s - { - public void Copy(_s s) - { - this.info = s.info; - this.aux = s.aux; - } - public int info, aux; - }; - public _s s = new _s(); - public lua_Number nval; - }; - - [CLSCompliantAttribute(false)] - public _u u = new _u(); - - public int t; /* patch list of `exit when true' */ - public int f; /* patch list of `exit when false' */ - }; - - - public class upvaldesc { - public lu_byte k; - public lu_byte info; - }; - - - /* state needed to generate code for a given function */ - public class FuncState { - public FuncState() - { - for (int i=0; i (l)) errorlimit(fs, l, m); } - - - /* - ** nodes for block list (list of active blocks) - */ - public class BlockCnt { - public BlockCnt previous; /* chain */ - public int breaklist; /* list of jumps out of this loop */ - public lu_byte nactvar; /* # active locals outside the breakable structure */ - public lu_byte upval; /* true if some variable in the block is an upvalue */ - public lu_byte isbreakable; /* true if `block' is a loop */ - }; - - - - private static void anchor_token (LexState ls) { - if (ls.t.token == (int)RESERVED.TK_NAME || ls.t.token == (int)RESERVED.TK_STRING) { - TString ts = ls.t.seminfo.ts; - luaX_newstring(ls, getstr(ts), ts.tsv.len); - } - } - - - private static void error_expected (LexState ls, int token) { - luaX_syntaxerror(ls, - luaO_pushfstring(ls.L, LUA_QS + " expected", luaX_token2str(ls, token))); - } - - - private static void errorlimit (FuncState fs, int limit, CharPtr what) { - CharPtr msg = (fs.f.linedefined == 0) ? - luaO_pushfstring(fs.L, "main function has more than %d %s", limit, what) : - luaO_pushfstring(fs.L, "function at line %d has more than %d %s", - fs.f.linedefined, limit, what); - luaX_lexerror(fs.ls, msg, 0); - } - - - private static int testnext (LexState ls, int c) { - if (ls.t.token == c) { - luaX_next(ls); - return 1; - } - else return 0; - } - - - private static void check (LexState ls, int c) { - if (ls.t.token != c) - error_expected(ls, c); - } - - private static void checknext (LexState ls, int c) { - check(ls, c); - luaX_next(ls); - } - - - public static void check_condition(LexState ls, bool c, CharPtr msg) { - if (!(c)) luaX_syntaxerror(ls, msg); - } - - private static void check_match (LexState ls, int what, int who, int where) { - if (testnext(ls, what)==0) { - if (where == ls.linenumber) - error_expected(ls, what); - else { - luaX_syntaxerror(ls, luaO_pushfstring(ls.L, - LUA_QS + " expected (to close " + LUA_QS + " at line %d)", - luaX_token2str(ls, what), luaX_token2str(ls, who), where)); - } - } - } - - private static TString str_checkname (LexState ls) { - TString ts; - check(ls, (int)RESERVED.TK_NAME); - ts = ls.t.seminfo.ts; - luaX_next(ls); - return ts; - } - - - private static void init_exp (expdesc e, expkind k, int i) { - e.f = e.t = NO_JUMP; - e.k = k; - e.u.s.info = i; - } - - - private static void codestring (LexState ls, expdesc e, TString s) { - init_exp(e, expkind.VK, luaK_stringK(ls.fs, s)); - } - - - private static void checkname(LexState ls, expdesc e) { - codestring(ls, e, str_checkname(ls)); - } - - - private static int registerlocalvar (LexState ls, TString varname) { - FuncState fs = ls.fs; - Proto f = fs.f; - int oldsize = f.sizelocvars; - luaM_growvector(ls.L, ref f.locvars, fs.nlocvars, ref f.sizelocvars, - (int)SHRT_MAX, "too many local variables"); - while (oldsize < f.sizelocvars) f.locvars[oldsize++].varname = null; - f.locvars[fs.nlocvars].varname = varname; - luaC_objbarrier(ls.L, f, varname); - return fs.nlocvars++; - } - - - public static void new_localvarliteral(LexState ls, CharPtr v, int n) { - new_localvar(ls, luaX_newstring(ls, "" + v, (uint)(v.chars.Length - 1)), n); - } - - - private static void new_localvar (LexState ls, TString name, int n) { - FuncState fs = ls.fs; - luaY_checklimit(fs, fs.nactvar+n+1, LUAI_MAXVARS, "local variables"); - fs.actvar[fs.nactvar+n] = (ushort)registerlocalvar(ls, name); - } - - - private static void adjustlocalvars (LexState ls, int nvars) { - FuncState fs = ls.fs; - fs.nactvar = cast_byte(fs.nactvar + nvars); - for (; nvars!=0; nvars--) { - getlocvar(fs, fs.nactvar - nvars).startpc = fs.pc; - } - } - - - private static void removevars (LexState ls, int tolevel) { - FuncState fs = ls.fs; - while (fs.nactvar > tolevel) - getlocvar(fs, --fs.nactvar).endpc = fs.pc; - } - - - private static int indexupvalue (FuncState fs, TString name, expdesc v) { - int i; - Proto f = fs.f; - int oldsize = f.sizeupvalues; - for (i=0; i= 0; i--) { - if (n == getlocvar(fs, i).varname) - return i; - } - return -1; /* not found */ - } - - - private static void markupval (FuncState fs, int level) { - BlockCnt bl = fs.bl; - while ((bl!=null) && bl.nactvar > level) bl = bl.previous; - if (bl != null) bl.upval = 1; - } - - - private static expkind singlevaraux(FuncState fs, TString n, expdesc var, int base_) - { - if (fs == null) { /* no more levels? */ - init_exp(var, expkind.VGLOBAL, NO_REG); /* default is global variable */ - return expkind.VGLOBAL; - } - else { - int v = searchvar(fs, n); /* look up at current level */ - if (v >= 0) { - init_exp(var, expkind.VLOCAL, v); - if (base_==0) - markupval(fs, v); /* local will be used as an upval */ - return expkind.VLOCAL; - } - else { /* not found at current level; try upper one */ - if (singlevaraux(fs.prev, n, var, 0) == expkind.VGLOBAL) - return expkind.VGLOBAL; - var.u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ - var.k = expkind.VUPVAL; /* upvalue in this level */ - return expkind.VUPVAL; - } - } - } - - - private static void singlevar (LexState ls, expdesc var) { - TString varname = str_checkname(ls); - FuncState fs = ls.fs; - if (singlevaraux(fs, varname, var, 1) == expkind.VGLOBAL) - var.u.s.info = luaK_stringK(fs, varname); /* info points to global name */ - } - - - private static void adjust_assign (LexState ls, int nvars, int nexps, expdesc e) { - FuncState fs = ls.fs; - int extra = nvars - nexps; - if (hasmultret(e.k) != 0) { - extra++; /* includes call itself */ - if (extra < 0) extra = 0; - luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ - if (extra > 1) luaK_reserveregs(fs, extra-1); - } - else { - if (e.k != expkind.VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ - if (extra > 0) { - int reg = fs.freereg; - luaK_reserveregs(fs, extra); - luaK_nil(fs, reg, extra); - } - } - } - - - private static void enterlevel (LexState ls) { - if (++ls.L.nCcalls > LUAI_MAXCCALLS) - luaX_lexerror(ls, "chunk has too many syntax levels", 0); - } - - - private static void leavelevel(LexState ls) { ls.L.nCcalls--; } - - - private static void enterblock (FuncState fs, BlockCnt bl, lu_byte isbreakable) { - bl.breaklist = NO_JUMP; - bl.isbreakable = isbreakable; - bl.nactvar = fs.nactvar; - bl.upval = 0; - bl.previous = fs.bl; - fs.bl = bl; - lua_assert(fs.freereg == fs.nactvar); - } - - - private static void leaveblock (FuncState fs) { - BlockCnt bl = fs.bl; - fs.bl = bl.previous; - removevars(fs.ls, bl.nactvar); - if (bl.upval != 0) - luaK_codeABC(fs, OpCode.OP_CLOSE, bl.nactvar, 0, 0); - /* a block either controls scope or breaks (never both) */ - lua_assert((bl.isbreakable==0) || (bl.upval==0)); - lua_assert(bl.nactvar == fs.nactvar); - fs.freereg = fs.nactvar; /* free registers */ - luaK_patchtohere(fs, bl.breaklist); - } - - - private static void pushclosure (LexState ls, FuncState func, expdesc v) { - FuncState fs = ls.fs; - Proto f = fs.f; - int oldsize = f.sizep; - int i; - luaM_growvector(ls.L, ref f.p, fs.np, ref f.sizep, - MAXARG_Bx, "constant table overflow"); - while (oldsize < f.sizep) f.p[oldsize++] = null; - f.p[fs.np++] = func.f; - luaC_objbarrier(ls.L, f, func.f); - init_exp(v, expkind.VRELOCABLE, luaK_codeABx(fs, OpCode.OP_CLOSURE, 0, fs.np - 1)); - for (i=0; i 0); - if (ls.t.token == '}') break; - closelistfield(fs, cc); - switch(ls.t.token) { - case (int)RESERVED.TK_NAME: { /* may be listfields or recfields */ - luaX_lookahead(ls); - if (ls.lookahead.token != '=') /* expression? */ - listfield(ls, cc); - else - recfield(ls, cc); - break; - } - case '[': { /* constructor_item . recfield */ - recfield(ls, cc); - break; - } - default: { /* constructor_part . listfield */ - listfield(ls, cc); - break; - } - } - } while ((testnext(ls, ',')!=0) || (testnext(ls, ';')!=0)); - check_match(ls, '}', '{', line); - lastlistfield(fs, cc); - SETARG_B(new InstructionPtr(fs.f.code, pc), luaO_int2fb((uint)cc.na)); /* set initial array size */ - SETARG_C(new InstructionPtr(fs.f.code, pc), luaO_int2fb((uint)cc.nh)); /* set initial table size */ - } - - /* }====================================================================== */ - - - - private static void parlist (LexState ls) { - /* parlist . [ param { `,' param } ] */ - FuncState fs = ls.fs; - Proto f = fs.f; - int nparams = 0; - f.is_vararg = 0; - if (ls.t.token != ')') { /* is `parlist' not empty? */ - do { - switch (ls.t.token) { - case (int)RESERVED.TK_NAME: { /* param . NAME */ - new_localvar(ls, str_checkname(ls), nparams++); - break; - } - case (int)RESERVED.TK_DOTS: { /* param . `...' */ - luaX_next(ls); - #if LUA_COMPAT_VARARG - /* use `arg' as default name */ - new_localvarliteral(ls, "arg", nparams++); - f.is_vararg = VARARG_HASARG | VARARG_NEEDSARG; - #endif - f.is_vararg |= VARARG_ISVARARG; - break; - } - default: luaX_syntaxerror(ls, " or " + LUA_QL("...") + " expected"); break; - } - } while ((f.is_vararg==0) && (testnext(ls, ',')!=0)); - } - adjustlocalvars(ls, nparams); - f.numparams = cast_byte(fs.nactvar - (f.is_vararg & VARARG_HASARG)); - luaK_reserveregs(fs, fs.nactvar); /* reserve register for parameters */ - } - - - private static void body (LexState ls, expdesc e, int needself, int line) { - /* body . `(' parlist `)' chunk END */ - FuncState new_fs = new FuncState(); - open_func(ls, new_fs); - new_fs.f.linedefined = line; - checknext(ls, '('); - if (needself != 0) { - new_localvarliteral(ls, "self", 0); - adjustlocalvars(ls, 1); - } - parlist(ls); - checknext(ls, ')'); - chunk(ls); - new_fs.f.lastlinedefined = ls.linenumber; - check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_FUNCTION, line); - close_func(ls); - pushclosure(ls, new_fs, e); - } - - - private static int explist1 (LexState ls, expdesc v) { - /* explist1 . expr { `,' expr } */ - int n = 1; /* at least one expression */ - expr(ls, v); - while (testnext(ls, ',') != 0) { - luaK_exp2nextreg(ls.fs, v); - expr(ls, v); - n++; - } - return n; - } - - - private static void funcargs (LexState ls, expdesc f) { - FuncState fs = ls.fs; - expdesc args = new expdesc(); - int base_, nparams; - int line = ls.linenumber; - switch (ls.t.token) { - case '(': { /* funcargs . `(' [ explist1 ] `)' */ - if (line != ls.lastline) - luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); - luaX_next(ls); - if (ls.t.token == ')') /* arg list is empty? */ - args.k = expkind.VVOID; - else { - explist1(ls, args); - luaK_setmultret(fs, args); - } - check_match(ls, ')', '(', line); - break; - } - case '{': { /* funcargs . constructor */ - constructor(ls, args); - break; - } - case (int)RESERVED.TK_STRING: { /* funcargs . STRING */ - codestring(ls, args, ls.t.seminfo.ts); - luaX_next(ls); /* must use `seminfo' before `next' */ - break; - } - default: { - luaX_syntaxerror(ls, "function arguments expected"); - return; - } - } - lua_assert(f.k == expkind.VNONRELOC); - base_ = f.u.s.info; /* base_ register for call */ - if (hasmultret(args.k) != 0) - nparams = LUA_MULTRET; /* open call */ - else { - if (args.k != expkind.VVOID) - luaK_exp2nextreg(fs, args); /* close last argument */ - nparams = fs.freereg - (base_+1); - } - init_exp(f, expkind.VCALL, luaK_codeABC(fs, OpCode.OP_CALL, base_, nparams + 1, 2)); - luaK_fixline(fs, line); - fs.freereg = base_+1; /* call remove function and arguments and leaves - (unless changed) one result */ - } - - - - - /* - ** {====================================================================== - ** Expression parsing - ** ======================================================================= - */ - - - private static void prefixexp (LexState ls, expdesc v) { - /* prefixexp . NAME | '(' expr ')' */ - switch (ls.t.token) { - case '(': { - int line = ls.linenumber; - luaX_next(ls); - expr(ls, v); - check_match(ls, ')', '(', line); - luaK_dischargevars(ls.fs, v); - return; - } - case (int)RESERVED.TK_NAME: { - singlevar(ls, v); - return; - } - default: { - luaX_syntaxerror(ls, "unexpected symbol"); - return; - } - } - } - - private static void primaryexp (LexState ls, expdesc v) { - /* primaryexp . - prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ - FuncState fs = ls.fs; - prefixexp(ls, v); - for (;;) { - switch (ls.t.token) { - case '.': { /* field */ - field(ls, v); - break; - } - case '[': { /* `[' exp1 `]' */ - expdesc key = new expdesc(); - luaK_exp2anyreg(fs, v); - yindex(ls, key); - luaK_indexed(fs, v, key); - break; - } - case ':': { /* `:' NAME funcargs */ - expdesc key = new expdesc(); - luaX_next(ls); - checkname(ls, key); - luaK_self(fs, v, key); - funcargs(ls, v); - break; - } - case '(': case (int)RESERVED.TK_STRING: case '{': { /* funcargs */ - luaK_exp2nextreg(fs, v); - funcargs(ls, v); - break; - } - default: return; - } - } - } - - - private static void simpleexp (LexState ls, expdesc v) { - /* simpleexp . NUMBER | STRING | NIL | true | false | ... | - constructor | FUNCTION body | primaryexp */ - switch (ls.t.token) { - case (int)RESERVED.TK_NUMBER: { - init_exp(v, expkind.VKNUM, 0); - v.u.nval = ls.t.seminfo.r; - break; - } - case (int)RESERVED.TK_STRING: { - codestring(ls, v, ls.t.seminfo.ts); - break; - } - case (int)RESERVED.TK_NIL: { - init_exp(v, expkind.VNIL, 0); - break; - } - case (int)RESERVED.TK_TRUE: { - init_exp(v, expkind.VTRUE, 0); - break; - } - case (int)RESERVED.TK_FALSE: { - init_exp(v, expkind.VFALSE, 0); - break; - } - case (int)RESERVED.TK_DOTS: { /* vararg */ - FuncState fs = ls.fs; - check_condition(ls, fs.f.is_vararg!=0, - "cannot use " + LUA_QL("...") + " outside a vararg function"); - fs.f.is_vararg &= unchecked((lu_byte)(~VARARG_NEEDSARG)); /* don't need 'arg' */ - init_exp(v, expkind.VVARARG, luaK_codeABC(fs, OpCode.OP_VARARG, 0, 1, 0)); - break; - } - case '{': { /* constructor */ - constructor(ls, v); - return; - } - case (int)RESERVED.TK_FUNCTION: { - luaX_next(ls); - body(ls, v, 0, ls.linenumber); - return; - } - default: { - primaryexp(ls, v); - return; - } - } - luaX_next(ls); - } - - - private static UnOpr getunopr (int op) { - switch (op) { - case (int)RESERVED.TK_NOT: return UnOpr.OPR_NOT; - case '-': return UnOpr.OPR_MINUS; - case '#': return UnOpr.OPR_LEN; - default: return UnOpr.OPR_NOUNOPR; - } - } - - - private static BinOpr getbinopr (int op) { - switch (op) { - case '+': return BinOpr.OPR_ADD; - case '-': return BinOpr.OPR_SUB; - case '*': return BinOpr.OPR_MUL; - case '/': return BinOpr.OPR_DIV; - case '%': return BinOpr.OPR_MOD; - case '^': return BinOpr.OPR_POW; - case (int)RESERVED.TK_CONCAT: return BinOpr.OPR_CONCAT; - case (int)RESERVED.TK_NE: return BinOpr.OPR_NE; - case (int)RESERVED.TK_EQ: return BinOpr.OPR_EQ; - case '<': return BinOpr.OPR_LT; - case (int)RESERVED.TK_LE: return BinOpr.OPR_LE; - case '>': return BinOpr.OPR_GT; - case (int)RESERVED.TK_GE: return BinOpr.OPR_GE; - case (int)RESERVED.TK_AND: return BinOpr.OPR_AND; - case (int)RESERVED.TK_OR: return BinOpr.OPR_OR; - default: return BinOpr.OPR_NOBINOPR; - } - } - - - private class priority_ { - public priority_(lu_byte left, lu_byte right) - { - this.left = left; - this.right = right; - } - - public lu_byte left; /* left priority for each binary operator */ - public lu_byte right; /* right priority */ - } - - private static priority_[] priority = { /* ORDER OPR */ - - new priority_(6, 6), - new priority_(6, 6), - new priority_(7, 7), - new priority_(7, 7), - new priority_(7, 7), /* `+' `-' `/' `%' */ - - new priority_(10, 9), - new priority_(5, 4), /* power and concat (right associative) */ - - new priority_(3, 3), - new priority_(3, 3), /* equality and inequality */ - - new priority_(3, 3), - new priority_(3, 3), - new priority_(3, 3), - new priority_(3, 3), /* order */ - - new priority_(2, 2), - new priority_(1, 1) /* logical (and/or) */ - }; - - public const int UNARY_PRIORITY = 8; /* priority for unary operators */ - - - /* - ** subexpr . (simpleexp | unop subexpr) { binop subexpr } - ** where `binop' is any binary operator with a priority higher than `limit' - */ - private static BinOpr subexpr (LexState ls, expdesc v, uint limit) { - BinOpr op = new BinOpr(); - UnOpr uop = new UnOpr(); - enterlevel(ls); - uop = getunopr(ls.t.token); - if (uop != UnOpr.OPR_NOUNOPR) { - luaX_next(ls); - subexpr(ls, v, UNARY_PRIORITY); - luaK_prefix(ls.fs, uop, v); - } - else simpleexp(ls, v); - /* expand while operators have priorities higher than `limit' */ - op = getbinopr(ls.t.token); - while (op != BinOpr.OPR_NOBINOPR && priority[(int)op].left > limit) - { - expdesc v2 = new expdesc(); - BinOpr nextop; - luaX_next(ls); - luaK_infix(ls.fs, op, v); - /* read sub-expression with higher priority */ - nextop = subexpr(ls, v2, priority[(int)op].right); - luaK_posfix(ls.fs, op, v, v2); - op = nextop; - } - leavelevel(ls); - return op; /* return first untreated operator */ - } - - - private static void expr (LexState ls, expdesc v) { - subexpr(ls, v, 0); - } - - /* }==================================================================== */ - - - - /* - ** {====================================================================== - ** Rules for Statements - ** ======================================================================= - */ - - - private static int block_follow (int token) { - switch (token) { - case (int)RESERVED.TK_ELSE: case (int)RESERVED.TK_ELSEIF: case (int)RESERVED.TK_END: - case (int)RESERVED.TK_UNTIL: case (int)RESERVED.TK_EOS: - return 1; - default: return 0; - } - } - - - private static void block (LexState ls) { - /* block . chunk */ - FuncState fs = ls.fs; - BlockCnt bl = new BlockCnt(); - enterblock(fs, bl, 0); - chunk(ls); - lua_assert(bl.breaklist == NO_JUMP); - leaveblock(fs); - } - - - /* - ** structure to chain all variables in the left-hand side of an - ** assignment - */ - public class LHS_assign { - public LHS_assign prev; - public expdesc v = new expdesc(); /* variable (global, local, upvalue, or indexed) */ - }; - - - /* - ** check whether, in an assignment to a local variable, the local variable - ** is needed in a previous assignment (to a table). If so, save original - ** local value in a safe place and use this safe copy in the previous - ** assignment. - */ - private static void check_conflict (LexState ls, LHS_assign lh, expdesc v) { - FuncState fs = ls.fs; - int extra = fs.freereg; /* eventual position to save local variable */ - int conflict = 0; - for (; lh!=null; lh = lh.prev) { - if (lh.v.k == expkind.VINDEXED) { - if (lh.v.u.s.info == v.u.s.info) { /* conflict? */ - conflict = 1; - lh.v.u.s.info = extra; /* previous assignment will use safe copy */ - } - if (lh.v.u.s.aux == v.u.s.info) { /* conflict? */ - conflict = 1; - lh.v.u.s.aux = extra; /* previous assignment will use safe copy */ - } - } - } - if (conflict != 0) { - luaK_codeABC(fs, OpCode.OP_MOVE, fs.freereg, v.u.s.info, 0); /* make copy */ - luaK_reserveregs(fs, 1); - } - } - - - private static void assignment (LexState ls, LHS_assign lh, int nvars) { - expdesc e = new expdesc(); - check_condition(ls, expkind.VLOCAL <= lh.v.k && lh.v.k <= expkind.VINDEXED, - "syntax error"); - if (testnext(ls, ',') != 0) { /* assignment . `,' primaryexp assignment */ - LHS_assign nv = new LHS_assign(); - nv.prev = lh; - primaryexp(ls, nv.v); - if (nv.v.k == expkind.VLOCAL) - check_conflict(ls, lh, nv.v); - luaY_checklimit(ls.fs, nvars, LUAI_MAXCCALLS - ls.L.nCcalls, - "variables in assignment"); - assignment(ls, nv, nvars+1); - } - else { /* assignment . `=' explist1 */ - int nexps; - checknext(ls, '='); - nexps = explist1(ls, e); - if (nexps != nvars) { - adjust_assign(ls, nvars, nexps, e); - if (nexps > nvars) - ls.fs.freereg -= nexps - nvars; /* remove extra values */ - } - else { - luaK_setoneret(ls.fs, e); /* close last expression */ - luaK_storevar(ls.fs, lh.v, e); - return; /* avoid default */ - } - } - init_exp(e, expkind.VNONRELOC, ls.fs.freereg - 1); /* default assignment */ - luaK_storevar(ls.fs, lh.v, e); - } - - - private static int cond (LexState ls) { - /* cond . exp */ - expdesc v = new expdesc(); - expr(ls, v); /* read condition */ - if (v.k == expkind.VNIL) v.k = expkind.VFALSE; /* `falses' are all equal here */ - luaK_goiftrue(ls.fs, v); - return v.f; - } - - - private static void breakstat (LexState ls) { - FuncState fs = ls.fs; - BlockCnt bl = fs.bl; - int upval = 0; - while ((bl!=null) && (bl.isbreakable==0)) { - upval |= bl.upval; - bl = bl.previous; - } - if (bl==null) - luaX_syntaxerror(ls, "no loop to break"); - if (upval != 0) - luaK_codeABC(fs, OpCode.OP_CLOSE, bl.nactvar, 0, 0); - luaK_concat(fs, ref bl.breaklist, luaK_jump(fs)); - } - - - private static void whilestat (LexState ls, int line) { - /* whilestat . WHILE cond DO block END */ - FuncState fs = ls.fs; - int whileinit; - int condexit; - BlockCnt bl = new BlockCnt(); - luaX_next(ls); /* skip WHILE */ - whileinit = luaK_getlabel(fs); - condexit = cond(ls); - enterblock(fs, bl, 1); - checknext(ls, (int)RESERVED.TK_DO); - block(ls); - luaK_patchlist(fs, luaK_jump(fs), whileinit); - check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_WHILE, line); - leaveblock(fs); - luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ - } - - - private static void repeatstat (LexState ls, int line) { - /* repeatstat . REPEAT block UNTIL cond */ - int condexit; - FuncState fs = ls.fs; - int repeat_init = luaK_getlabel(fs); - BlockCnt bl1 = new BlockCnt(), bl2 = new BlockCnt(); - enterblock(fs, bl1, 1); /* loop block */ - enterblock(fs, bl2, 0); /* scope block */ - luaX_next(ls); /* skip REPEAT */ - chunk(ls); - check_match(ls, (int)RESERVED.TK_UNTIL, (int)RESERVED.TK_REPEAT, line); - condexit = cond(ls); /* read condition (inside scope block) */ - if (bl2.upval==0) { /* no upvalues? */ - leaveblock(fs); /* finish scope */ - luaK_patchlist(ls.fs, condexit, repeat_init); /* close the loop */ - } - else { /* complete semantics when there are upvalues */ - breakstat(ls); /* if condition then break */ - luaK_patchtohere(ls.fs, condexit); /* else... */ - leaveblock(fs); /* finish scope... */ - luaK_patchlist(ls.fs, luaK_jump(fs), repeat_init); /* and repeat */ - } - leaveblock(fs); /* finish loop */ - } - - - private static int exp1 (LexState ls) { - expdesc e = new expdesc(); - int k; - expr(ls, e); - k = (int)e.k; - luaK_exp2nextreg(ls.fs, e); - return k; - } - - - private static void forbody (LexState ls, int base_, int line, int nvars, int isnum) { - /* forbody . DO block */ - BlockCnt bl = new BlockCnt(); - FuncState fs = ls.fs; - int prep, endfor; - adjustlocalvars(ls, 3); /* control variables */ - checknext(ls, (int)RESERVED.TK_DO); - prep = (isnum != 0) ? luaK_codeAsBx(fs, OpCode.OP_FORPREP, base_, NO_JUMP) : luaK_jump(fs); - enterblock(fs, bl, 0); /* scope for declared variables */ - adjustlocalvars(ls, nvars); - luaK_reserveregs(fs, nvars); - block(ls); - leaveblock(fs); /* end of scope for declared variables */ - luaK_patchtohere(fs, prep); - endfor = (isnum!=0) ? luaK_codeAsBx(fs, OpCode.OP_FORLOOP, base_, NO_JUMP) : - luaK_codeABC(fs, OpCode.OP_TFORLOOP, base_, 0, nvars); - luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ - luaK_patchlist(fs, ((isnum!=0) ? endfor : luaK_jump(fs)), prep + 1); - } - - - private static void fornum (LexState ls, TString varname, int line) { - /* fornum . NAME = exp1,exp1[,exp1] forbody */ - FuncState fs = ls.fs; - int base_ = fs.freereg; - new_localvarliteral(ls, "(for index)", 0); - new_localvarliteral(ls, "(for limit)", 1); - new_localvarliteral(ls, "(for step)", 2); - new_localvar(ls, varname, 3); - checknext(ls, '='); - exp1(ls); /* initial value */ - checknext(ls, ','); - exp1(ls); /* limit */ - if (testnext(ls, ',') != 0) - exp1(ls); /* optional step */ - else { /* default step = 1 */ - luaK_codeABx(fs, OpCode.OP_LOADK, fs.freereg, luaK_numberK(fs, 1)); - luaK_reserveregs(fs, 1); - } - forbody(ls, base_, line, 1, 1); - } - - - private static void forlist (LexState ls, TString indexname) { - /* forlist . NAME {,NAME} IN explist1 forbody */ - FuncState fs = ls.fs; - expdesc e = new expdesc(); - int nvars = 0; - int line; - int base_ = fs.freereg; - /* create control variables */ - new_localvarliteral(ls, "(for generator)", nvars++); - new_localvarliteral(ls, "(for state)", nvars++); - new_localvarliteral(ls, "(for control)", nvars++); - /* create declared variables */ - new_localvar(ls, indexname, nvars++); - while (testnext(ls, ',') != 0) - new_localvar(ls, str_checkname(ls), nvars++); - checknext(ls, (int)RESERVED.TK_IN); - line = ls.linenumber; - adjust_assign(ls, 3, explist1(ls, e), e); - luaK_checkstack(fs, 3); /* extra space to call generator */ - forbody(ls, base_, line, nvars - 3, 0); - } - - - private static void forstat (LexState ls, int line) { - /* forstat . FOR (fornum | forlist) END */ - FuncState fs = ls.fs; - TString varname; - BlockCnt bl = new BlockCnt(); - enterblock(fs, bl, 1); /* scope for loop and control variables */ - luaX_next(ls); /* skip `for' */ - varname = str_checkname(ls); /* first variable name */ - switch (ls.t.token) { - case '=': fornum(ls, varname, line); break; - case ',': - case (int)RESERVED.TK_IN: - forlist(ls, varname); - break; - default: luaX_syntaxerror(ls, LUA_QL("=") + " or " + LUA_QL("in") + " expected"); break; - } - check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_FOR, line); - leaveblock(fs); /* loop scope (`break' jumps to this point) */ - } - - - private static int test_then_block (LexState ls) { - /* test_then_block . [IF | ELSEIF] cond THEN block */ - int condexit; - luaX_next(ls); /* skip IF or ELSEIF */ - condexit = cond(ls); - checknext(ls, (int)RESERVED.TK_THEN); - block(ls); /* `then' part */ - return condexit; - } - - - private static void ifstat (LexState ls, int line) { - /* ifstat . IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ - FuncState fs = ls.fs; - int flist; - int escapelist = NO_JUMP; - flist = test_then_block(ls); /* IF cond THEN block */ - while (ls.t.token == (int)RESERVED.TK_ELSEIF) { - luaK_concat(fs, ref escapelist, luaK_jump(fs)); - luaK_patchtohere(fs, flist); - flist = test_then_block(ls); /* ELSEIF cond THEN block */ - } - if (ls.t.token == (int)RESERVED.TK_ELSE) { - luaK_concat(fs, ref escapelist, luaK_jump(fs)); - luaK_patchtohere(fs, flist); - luaX_next(ls); /* skip ELSE (after patch, for correct line info) */ - block(ls); /* `else' part */ - } - else - luaK_concat(fs, ref escapelist, flist); - luaK_patchtohere(fs, escapelist); - check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_IF, line); - } - - - private static void localfunc (LexState ls) { - expdesc v = new expdesc(), b = new expdesc(); - FuncState fs = ls.fs; - new_localvar(ls, str_checkname(ls), 0); - init_exp(v, expkind.VLOCAL, fs.freereg); - luaK_reserveregs(fs, 1); - adjustlocalvars(ls, 1); - body(ls, b, 0, ls.linenumber); - luaK_storevar(fs, v, b); - /* debug information will only see the variable after this point! */ - getlocvar(fs, fs.nactvar - 1).startpc = fs.pc; - } - - - private static void localstat (LexState ls) { - /* stat . LOCAL NAME {`,' NAME} [`=' explist1] */ - int nvars = 0; - int nexps; - expdesc e = new expdesc(); - do { - new_localvar(ls, str_checkname(ls), nvars++); - } while (testnext(ls, ',') != 0); - if (testnext(ls, '=') != 0) - nexps = explist1(ls, e); - else { - e.k = expkind.VVOID; - nexps = 0; - } - adjust_assign(ls, nvars, nexps, e); - adjustlocalvars(ls, nvars); - } - - - private static int funcname (LexState ls, expdesc v) { - /* funcname . NAME {field} [`:' NAME] */ - int needself = 0; - singlevar(ls, v); - while (ls.t.token == '.') - field(ls, v); - if (ls.t.token == ':') { - needself = 1; - field(ls, v); - } - return needself; - } - - - private static void funcstat (LexState ls, int line) { - /* funcstat . FUNCTION funcname body */ - int needself; - expdesc v = new expdesc(), b = new expdesc(); - luaX_next(ls); /* skip FUNCTION */ - needself = funcname(ls, v); - body(ls, b, needself, line); - luaK_storevar(ls.fs, v, b); - luaK_fixline(ls.fs, line); /* definition `happens' in the first line */ - } - - - private static void exprstat (LexState ls) { - /* stat . func | assignment */ - FuncState fs = ls.fs; - LHS_assign v = new LHS_assign(); - primaryexp(ls, v.v); - if (v.v.k == expkind.VCALL) /* stat . func */ - SETARG_C(getcode(fs, v.v), 1); /* call statement uses no results */ - else { /* stat . assignment */ - v.prev = null; - assignment(ls, v, 1); - } - } - - - private static void retstat (LexState ls) { - /* stat . RETURN explist */ - FuncState fs = ls.fs; - expdesc e = new expdesc(); - int first, nret; /* registers with returned values */ - luaX_next(ls); /* skip RETURN */ - if ((block_follow(ls.t.token)!=0) || ls.t.token == ';') - first = nret = 0; /* return no values */ - else { - nret = explist1(ls, e); /* optional return values */ - if (hasmultret(e.k) != 0) { - luaK_setmultret(fs, e); - if (e.k == expkind.VCALL && nret == 1) { /* tail call? */ - SET_OPCODE(getcode(fs,e), OpCode.OP_TAILCALL); - lua_assert(GETARG_A(getcode(fs,e)) == fs.nactvar); - } - first = fs.nactvar; - nret = LUA_MULTRET; /* return all values */ - } - else { - if (nret == 1) /* only one single value? */ - first = luaK_exp2anyreg(fs, e); - else { - luaK_exp2nextreg(fs, e); /* values must go to the `stack' */ - first = fs.nactvar; /* return all `active' values */ - lua_assert(nret == fs.freereg - first); - } - } - } - luaK_ret(fs, first, nret); - } - - - private static int statement (LexState ls) { - int line = ls.linenumber; /* may be needed for error messages */ - switch (ls.t.token) { - case (int)RESERVED.TK_IF: { /* stat . ifstat */ - ifstat(ls, line); - return 0; - } - case (int)RESERVED.TK_WHILE: { /* stat . whilestat */ - whilestat(ls, line); - return 0; - } - case (int)RESERVED.TK_DO: { /* stat . DO block END */ - luaX_next(ls); /* skip DO */ - block(ls); - check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_DO, line); - return 0; - } - case (int)RESERVED.TK_FOR: { /* stat . forstat */ - forstat(ls, line); - return 0; - } - case (int)RESERVED.TK_REPEAT: { /* stat . repeatstat */ - repeatstat(ls, line); - return 0; - } - case (int)RESERVED.TK_FUNCTION: { - funcstat(ls, line); /* stat . funcstat */ - return 0; - } - case (int)RESERVED.TK_LOCAL: { /* stat . localstat */ - luaX_next(ls); /* skip LOCAL */ - if (testnext(ls, (int)RESERVED.TK_FUNCTION) != 0) /* local function? */ - localfunc(ls); - else - localstat(ls); - return 0; - } - case (int)RESERVED.TK_RETURN: { /* stat . retstat */ - retstat(ls); - return 1; /* must be last statement */ - } - case (int)RESERVED.TK_BREAK: { /* stat . breakstat */ - luaX_next(ls); /* skip BREAK */ - breakstat(ls); - return 1; /* must be last statement */ - } - default: { - exprstat(ls); - return 0; /* to avoid warnings */ - } - } - } - - - private static void chunk (LexState ls) { - /* chunk . { stat [`;'] } */ - int islast = 0; - enterlevel(ls); - while ((islast==0) && (block_follow(ls.t.token)==0)) { - islast = statement(ls); - testnext(ls, ';'); - lua_assert(ls.fs.f.maxstacksize >= ls.fs.freereg && - ls.fs.freereg >= ls.fs.nactvar); - ls.fs.freereg = ls.fs.nactvar; /* free registers */ - } - leavelevel(ls); - } - - /* }====================================================================== */ - - } +/* +** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $ +** Lua Parser +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace KopiLua +{ + using lu_byte = System.Byte; + using lua_Number = System.Double; + using ZIO = Lua.Zio; + + public partial class Lua + { + /* + ** Expression descriptor + */ + + public enum expkind { + VVOID, /* no value */ + VNIL, + VTRUE, + VFALSE, + VK, /* info = index of constant in `k' */ + VKNUM, /* nval = numerical value */ + VLOCAL, /* info = local register */ + VUPVAL, /* info = index of upvalue in `upvalues' */ + VGLOBAL, /* info = index of table; aux = index of global name in `k' */ + VINDEXED, /* info = table register; aux = index register (or `k') */ + VJMP, /* info = instruction pc */ + VRELOCABLE, /* info = instruction pc */ + VNONRELOC, /* info = result register */ + VCALL, /* info = instruction pc */ + VVARARG /* info = instruction pc */ + }; + + + + public class expdesc { + + public void Copy(expdesc e) + { + this.k = e.k; + this.u.Copy(e.u); + this.t = e.t; + this.f = e.f; + } + + public expkind k; + + [CLSCompliantAttribute(false)] + public class _u + { + public void Copy(_u u) + { + this.s.Copy(u.s); + this.nval = u.nval; + } + + [CLSCompliantAttribute(false)] + public class _s + { + public void Copy(_s s) + { + this.info = s.info; + this.aux = s.aux; + } + public int info, aux; + }; + public _s s = new _s(); + public lua_Number nval; + }; + + [CLSCompliantAttribute(false)] + public _u u = new _u(); + + public int t; /* patch list of `exit when true' */ + public int f; /* patch list of `exit when false' */ + }; + + + public class upvaldesc { + public lu_byte k; + public lu_byte info; + }; + + + /* state needed to generate code for a given function */ + public class FuncState { + public FuncState() + { + for (int i=0; i (l)) errorlimit(fs, l, m); } + + + /* + ** nodes for block list (list of active blocks) + */ + public class BlockCnt { + public BlockCnt previous; /* chain */ + public int breaklist; /* list of jumps out of this loop */ + public lu_byte nactvar; /* # active locals outside the breakable structure */ + public lu_byte upval; /* true if some variable in the block is an upvalue */ + public lu_byte isbreakable; /* true if `block' is a loop */ + }; + + + + private static void anchor_token (LexState ls) { + if (ls.t.token == (int)RESERVED.TK_NAME || ls.t.token == (int)RESERVED.TK_STRING) { + TString ts = ls.t.seminfo.ts; + luaX_newstring(ls, getstr(ts), ts.tsv.len); + } + } + + + private static void error_expected (LexState ls, int token) { + luaX_syntaxerror(ls, + luaO_pushfstring(ls.L, LUA_QS + " expected", luaX_token2str(ls, token))); + } + + + private static void errorlimit (FuncState fs, int limit, CharPtr what) { + CharPtr msg = (fs.f.linedefined == 0) ? + luaO_pushfstring(fs.L, "main function has more than %d %s", limit, what) : + luaO_pushfstring(fs.L, "function at line %d has more than %d %s", + fs.f.linedefined, limit, what); + luaX_lexerror(fs.ls, msg, 0); + } + + + private static int testnext (LexState ls, int c) { + if (ls.t.token == c) { + luaX_next(ls); + return 1; + } + else return 0; + } + + + private static void check (LexState ls, int c) { + if (ls.t.token != c) + error_expected(ls, c); + } + + private static void checknext (LexState ls, int c) { + check(ls, c); + luaX_next(ls); + } + + + public static void check_condition(LexState ls, bool c, CharPtr msg) { + if (!(c)) luaX_syntaxerror(ls, msg); + } + + private static void check_match (LexState ls, int what, int who, int where) { + if (testnext(ls, what)==0) { + if (where == ls.linenumber) + error_expected(ls, what); + else { + luaX_syntaxerror(ls, luaO_pushfstring(ls.L, + LUA_QS + " expected (to close " + LUA_QS + " at line %d)", + luaX_token2str(ls, what), luaX_token2str(ls, who), where)); + } + } + } + + private static TString str_checkname (LexState ls) { + TString ts; + check(ls, (int)RESERVED.TK_NAME); + ts = ls.t.seminfo.ts; + luaX_next(ls); + return ts; + } + + + private static void init_exp (expdesc e, expkind k, int i) { + e.f = e.t = NO_JUMP; + e.k = k; + e.u.s.info = i; + } + + + private static void codestring (LexState ls, expdesc e, TString s) { + init_exp(e, expkind.VK, luaK_stringK(ls.fs, s)); + } + + + private static void checkname(LexState ls, expdesc e) { + codestring(ls, e, str_checkname(ls)); + } + + + private static int registerlocalvar (LexState ls, TString varname) { + FuncState fs = ls.fs; + Proto f = fs.f; + int oldsize = f.sizelocvars; + luaM_growvector(ls.L, ref f.locvars, fs.nlocvars, ref f.sizelocvars, + (int)SHRT_MAX, "too many local variables"); + while (oldsize < f.sizelocvars) f.locvars[oldsize++].varname = null; + f.locvars[fs.nlocvars].varname = varname; + luaC_objbarrier(ls.L, f, varname); + return fs.nlocvars++; + } + + + public static void new_localvarliteral(LexState ls, CharPtr v, int n) { + new_localvar(ls, luaX_newstring(ls, "" + v, (uint)(v.chars.Length - 1)), n); + } + + + private static void new_localvar (LexState ls, TString name, int n) { + FuncState fs = ls.fs; + luaY_checklimit(fs, fs.nactvar+n+1, LUAI_MAXVARS, "local variables"); + fs.actvar[fs.nactvar+n] = (ushort)registerlocalvar(ls, name); + } + + + private static void adjustlocalvars (LexState ls, int nvars) { + FuncState fs = ls.fs; + fs.nactvar = cast_byte(fs.nactvar + nvars); + for (; nvars!=0; nvars--) { + getlocvar(fs, fs.nactvar - nvars).startpc = fs.pc; + } + } + + + private static void removevars (LexState ls, int tolevel) { + FuncState fs = ls.fs; + while (fs.nactvar > tolevel) + getlocvar(fs, --fs.nactvar).endpc = fs.pc; + } + + + private static int indexupvalue (FuncState fs, TString name, expdesc v) { + int i; + Proto f = fs.f; + int oldsize = f.sizeupvalues; + for (i=0; i= 0; i--) { + if (n == getlocvar(fs, i).varname) + return i; + } + return -1; /* not found */ + } + + + private static void markupval (FuncState fs, int level) { + BlockCnt bl = fs.bl; + while ((bl!=null) && bl.nactvar > level) bl = bl.previous; + if (bl != null) bl.upval = 1; + } + + + private static expkind singlevaraux(FuncState fs, TString n, expdesc var, int base_) + { + if (fs == null) { /* no more levels? */ + init_exp(var, expkind.VGLOBAL, NO_REG); /* default is global variable */ + return expkind.VGLOBAL; + } + else { + int v = searchvar(fs, n); /* look up at current level */ + if (v >= 0) { + init_exp(var, expkind.VLOCAL, v); + if (base_==0) + markupval(fs, v); /* local will be used as an upval */ + return expkind.VLOCAL; + } + else { /* not found at current level; try upper one */ + if (singlevaraux(fs.prev, n, var, 0) == expkind.VGLOBAL) + return expkind.VGLOBAL; + var.u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */ + var.k = expkind.VUPVAL; /* upvalue in this level */ + return expkind.VUPVAL; + } + } + } + + + private static void singlevar (LexState ls, expdesc var) { + TString varname = str_checkname(ls); + FuncState fs = ls.fs; + if (singlevaraux(fs, varname, var, 1) == expkind.VGLOBAL) + var.u.s.info = luaK_stringK(fs, varname); /* info points to global name */ + } + + + private static void adjust_assign (LexState ls, int nvars, int nexps, expdesc e) { + FuncState fs = ls.fs; + int extra = nvars - nexps; + if (hasmultret(e.k) != 0) { + extra++; /* includes call itself */ + if (extra < 0) extra = 0; + luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ + if (extra > 1) luaK_reserveregs(fs, extra-1); + } + else { + if (e.k != expkind.VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ + if (extra > 0) { + int reg = fs.freereg; + luaK_reserveregs(fs, extra); + luaK_nil(fs, reg, extra); + } + } + } + + + private static void enterlevel (LexState ls) { + if (++ls.L.nCcalls > LUAI_MAXCCALLS) + luaX_lexerror(ls, "chunk has too many syntax levels", 0); + } + + + private static void leavelevel(LexState ls) { ls.L.nCcalls--; } + + + private static void enterblock (FuncState fs, BlockCnt bl, lu_byte isbreakable) { + bl.breaklist = NO_JUMP; + bl.isbreakable = isbreakable; + bl.nactvar = fs.nactvar; + bl.upval = 0; + bl.previous = fs.bl; + fs.bl = bl; + lua_assert(fs.freereg == fs.nactvar); + } + + + private static void leaveblock (FuncState fs) { + BlockCnt bl = fs.bl; + fs.bl = bl.previous; + removevars(fs.ls, bl.nactvar); + if (bl.upval != 0) + luaK_codeABC(fs, OpCode.OP_CLOSE, bl.nactvar, 0, 0); + /* a block either controls scope or breaks (never both) */ + lua_assert((bl.isbreakable==0) || (bl.upval==0)); + lua_assert(bl.nactvar == fs.nactvar); + fs.freereg = fs.nactvar; /* free registers */ + luaK_patchtohere(fs, bl.breaklist); + } + + + private static void pushclosure (LexState ls, FuncState func, expdesc v) { + FuncState fs = ls.fs; + Proto f = fs.f; + int oldsize = f.sizep; + int i; + luaM_growvector(ls.L, ref f.p, fs.np, ref f.sizep, + MAXARG_Bx, "constant table overflow"); + while (oldsize < f.sizep) f.p[oldsize++] = null; + f.p[fs.np++] = func.f; + luaC_objbarrier(ls.L, f, func.f); + init_exp(v, expkind.VRELOCABLE, luaK_codeABx(fs, OpCode.OP_CLOSURE, 0, fs.np - 1)); + for (i=0; i 0); + if (ls.t.token == '}') break; + closelistfield(fs, cc); + switch(ls.t.token) { + case (int)RESERVED.TK_NAME: { /* may be listfields or recfields */ + luaX_lookahead(ls); + if (ls.lookahead.token != '=') /* expression? */ + listfield(ls, cc); + else + recfield(ls, cc); + break; + } + case '[': { /* constructor_item . recfield */ + recfield(ls, cc); + break; + } + default: { /* constructor_part . listfield */ + listfield(ls, cc); + break; + } + } + } while ((testnext(ls, ',')!=0) || (testnext(ls, ';')!=0)); + check_match(ls, '}', '{', line); + lastlistfield(fs, cc); + SETARG_B(new InstructionPtr(fs.f.code, pc), luaO_int2fb((uint)cc.na)); /* set initial array size */ + SETARG_C(new InstructionPtr(fs.f.code, pc), luaO_int2fb((uint)cc.nh)); /* set initial table size */ + } + + /* }====================================================================== */ + + + + private static void parlist (LexState ls) { + /* parlist . [ param { `,' param } ] */ + FuncState fs = ls.fs; + Proto f = fs.f; + int nparams = 0; + f.is_vararg = 0; + if (ls.t.token != ')') { /* is `parlist' not empty? */ + do { + switch (ls.t.token) { + case (int)RESERVED.TK_NAME: { /* param . NAME */ + new_localvar(ls, str_checkname(ls), nparams++); + break; + } + case (int)RESERVED.TK_DOTS: { /* param . `...' */ + luaX_next(ls); + #if LUA_COMPAT_VARARG + /* use `arg' as default name */ + new_localvarliteral(ls, "arg", nparams++); + f.is_vararg = VARARG_HASARG | VARARG_NEEDSARG; + #endif + f.is_vararg |= VARARG_ISVARARG; + break; + } + default: luaX_syntaxerror(ls, " or " + LUA_QL("...") + " expected"); break; + } + } while ((f.is_vararg==0) && (testnext(ls, ',')!=0)); + } + adjustlocalvars(ls, nparams); + f.numparams = cast_byte(fs.nactvar - (f.is_vararg & VARARG_HASARG)); + luaK_reserveregs(fs, fs.nactvar); /* reserve register for parameters */ + } + + + private static void body (LexState ls, expdesc e, int needself, int line) { + /* body . `(' parlist `)' chunk END */ + FuncState new_fs = new FuncState(); + open_func(ls, new_fs); + new_fs.f.linedefined = line; + checknext(ls, '('); + if (needself != 0) { + new_localvarliteral(ls, "self", 0); + adjustlocalvars(ls, 1); + } + parlist(ls); + checknext(ls, ')'); + chunk(ls); + new_fs.f.lastlinedefined = ls.linenumber; + check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_FUNCTION, line); + close_func(ls); + pushclosure(ls, new_fs, e); + } + + + private static int explist1 (LexState ls, expdesc v) { + /* explist1 . expr { `,' expr } */ + int n = 1; /* at least one expression */ + expr(ls, v); + while (testnext(ls, ',') != 0) { + luaK_exp2nextreg(ls.fs, v); + expr(ls, v); + n++; + } + return n; + } + + + private static void funcargs (LexState ls, expdesc f) { + FuncState fs = ls.fs; + expdesc args = new expdesc(); + int base_, nparams; + int line = ls.linenumber; + switch (ls.t.token) { + case '(': { /* funcargs . `(' [ explist1 ] `)' */ + if (line != ls.lastline) + luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); + luaX_next(ls); + if (ls.t.token == ')') /* arg list is empty? */ + args.k = expkind.VVOID; + else { + explist1(ls, args); + luaK_setmultret(fs, args); + } + check_match(ls, ')', '(', line); + break; + } + case '{': { /* funcargs . constructor */ + constructor(ls, args); + break; + } + case (int)RESERVED.TK_STRING: { /* funcargs . STRING */ + codestring(ls, args, ls.t.seminfo.ts); + luaX_next(ls); /* must use `seminfo' before `next' */ + break; + } + default: { + luaX_syntaxerror(ls, "function arguments expected"); + return; + } + } + lua_assert(f.k == expkind.VNONRELOC); + base_ = f.u.s.info; /* base_ register for call */ + if (hasmultret(args.k) != 0) + nparams = LUA_MULTRET; /* open call */ + else { + if (args.k != expkind.VVOID) + luaK_exp2nextreg(fs, args); /* close last argument */ + nparams = fs.freereg - (base_+1); + } + init_exp(f, expkind.VCALL, luaK_codeABC(fs, OpCode.OP_CALL, base_, nparams + 1, 2)); + luaK_fixline(fs, line); + fs.freereg = base_+1; /* call remove function and arguments and leaves + (unless changed) one result */ + } + + + + + /* + ** {====================================================================== + ** Expression parsing + ** ======================================================================= + */ + + + private static void prefixexp (LexState ls, expdesc v) { + /* prefixexp . NAME | '(' expr ')' */ + switch (ls.t.token) { + case '(': { + int line = ls.linenumber; + luaX_next(ls); + expr(ls, v); + check_match(ls, ')', '(', line); + luaK_dischargevars(ls.fs, v); + return; + } + case (int)RESERVED.TK_NAME: { + singlevar(ls, v); + return; + } + default: { + luaX_syntaxerror(ls, "unexpected symbol"); + return; + } + } + } + + private static void primaryexp (LexState ls, expdesc v) { + /* primaryexp . + prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ + FuncState fs = ls.fs; + prefixexp(ls, v); + for (;;) { + switch (ls.t.token) { + case '.': { /* field */ + field(ls, v); + break; + } + case '[': { /* `[' exp1 `]' */ + expdesc key = new expdesc(); + luaK_exp2anyreg(fs, v); + yindex(ls, key); + luaK_indexed(fs, v, key); + break; + } + case ':': { /* `:' NAME funcargs */ + expdesc key = new expdesc(); + luaX_next(ls); + checkname(ls, key); + luaK_self(fs, v, key); + funcargs(ls, v); + break; + } + case '(': case (int)RESERVED.TK_STRING: case '{': { /* funcargs */ + luaK_exp2nextreg(fs, v); + funcargs(ls, v); + break; + } + default: return; + } + } + } + + + private static void simpleexp (LexState ls, expdesc v) { + /* simpleexp . NUMBER | STRING | NIL | true | false | ... | + constructor | FUNCTION body | primaryexp */ + switch (ls.t.token) { + case (int)RESERVED.TK_NUMBER: { + init_exp(v, expkind.VKNUM, 0); + v.u.nval = ls.t.seminfo.r; + break; + } + case (int)RESERVED.TK_STRING: { + codestring(ls, v, ls.t.seminfo.ts); + break; + } + case (int)RESERVED.TK_NIL: { + init_exp(v, expkind.VNIL, 0); + break; + } + case (int)RESERVED.TK_TRUE: { + init_exp(v, expkind.VTRUE, 0); + break; + } + case (int)RESERVED.TK_FALSE: { + init_exp(v, expkind.VFALSE, 0); + break; + } + case (int)RESERVED.TK_DOTS: { /* vararg */ + FuncState fs = ls.fs; + check_condition(ls, fs.f.is_vararg!=0, + "cannot use " + LUA_QL("...") + " outside a vararg function"); + fs.f.is_vararg &= unchecked((lu_byte)(~VARARG_NEEDSARG)); /* don't need 'arg' */ + init_exp(v, expkind.VVARARG, luaK_codeABC(fs, OpCode.OP_VARARG, 0, 1, 0)); + break; + } + case '{': { /* constructor */ + constructor(ls, v); + return; + } + case (int)RESERVED.TK_FUNCTION: { + luaX_next(ls); + body(ls, v, 0, ls.linenumber); + return; + } + default: { + primaryexp(ls, v); + return; + } + } + luaX_next(ls); + } + + + private static UnOpr getunopr (int op) { + switch (op) { + case (int)RESERVED.TK_NOT: return UnOpr.OPR_NOT; + case '-': return UnOpr.OPR_MINUS; + case '#': return UnOpr.OPR_LEN; + default: return UnOpr.OPR_NOUNOPR; + } + } + + + private static BinOpr getbinopr (int op) { + switch (op) { + case '+': return BinOpr.OPR_ADD; + case '-': return BinOpr.OPR_SUB; + case '*': return BinOpr.OPR_MUL; + case '/': return BinOpr.OPR_DIV; + case '%': return BinOpr.OPR_MOD; + case '^': return BinOpr.OPR_POW; + case (int)RESERVED.TK_CONCAT: return BinOpr.OPR_CONCAT; + case (int)RESERVED.TK_NE: return BinOpr.OPR_NE; + case (int)RESERVED.TK_EQ: return BinOpr.OPR_EQ; + case '<': return BinOpr.OPR_LT; + case (int)RESERVED.TK_LE: return BinOpr.OPR_LE; + case '>': return BinOpr.OPR_GT; + case (int)RESERVED.TK_GE: return BinOpr.OPR_GE; + case (int)RESERVED.TK_AND: return BinOpr.OPR_AND; + case (int)RESERVED.TK_OR: return BinOpr.OPR_OR; + default: return BinOpr.OPR_NOBINOPR; + } + } + + + private class priority_ { + public priority_(lu_byte left, lu_byte right) + { + this.left = left; + this.right = right; + } + + public lu_byte left; /* left priority for each binary operator */ + public lu_byte right; /* right priority */ + } + + private static priority_[] priority = { /* ORDER OPR */ + + new priority_(6, 6), + new priority_(6, 6), + new priority_(7, 7), + new priority_(7, 7), + new priority_(7, 7), /* `+' `-' `/' `%' */ + + new priority_(10, 9), + new priority_(5, 4), /* power and concat (right associative) */ + + new priority_(3, 3), + new priority_(3, 3), /* equality and inequality */ + + new priority_(3, 3), + new priority_(3, 3), + new priority_(3, 3), + new priority_(3, 3), /* order */ + + new priority_(2, 2), + new priority_(1, 1) /* logical (and/or) */ + }; + + public const int UNARY_PRIORITY = 8; /* priority for unary operators */ + + + /* + ** subexpr . (simpleexp | unop subexpr) { binop subexpr } + ** where `binop' is any binary operator with a priority higher than `limit' + */ + private static BinOpr subexpr (LexState ls, expdesc v, uint limit) { + BinOpr op = new BinOpr(); + UnOpr uop = new UnOpr(); + enterlevel(ls); + uop = getunopr(ls.t.token); + if (uop != UnOpr.OPR_NOUNOPR) { + luaX_next(ls); + subexpr(ls, v, UNARY_PRIORITY); + luaK_prefix(ls.fs, uop, v); + } + else simpleexp(ls, v); + /* expand while operators have priorities higher than `limit' */ + op = getbinopr(ls.t.token); + while (op != BinOpr.OPR_NOBINOPR && priority[(int)op].left > limit) + { + expdesc v2 = new expdesc(); + BinOpr nextop; + luaX_next(ls); + luaK_infix(ls.fs, op, v); + /* read sub-expression with higher priority */ + nextop = subexpr(ls, v2, priority[(int)op].right); + luaK_posfix(ls.fs, op, v, v2); + op = nextop; + } + leavelevel(ls); + return op; /* return first untreated operator */ + } + + + private static void expr (LexState ls, expdesc v) { + subexpr(ls, v, 0); + } + + /* }==================================================================== */ + + + + /* + ** {====================================================================== + ** Rules for Statements + ** ======================================================================= + */ + + + private static int block_follow (int token) { + switch (token) { + case (int)RESERVED.TK_ELSE: case (int)RESERVED.TK_ELSEIF: case (int)RESERVED.TK_END: + case (int)RESERVED.TK_UNTIL: case (int)RESERVED.TK_EOS: + return 1; + default: return 0; + } + } + + + private static void block (LexState ls) { + /* block . chunk */ + FuncState fs = ls.fs; + BlockCnt bl = new BlockCnt(); + enterblock(fs, bl, 0); + chunk(ls); + lua_assert(bl.breaklist == NO_JUMP); + leaveblock(fs); + } + + + /* + ** structure to chain all variables in the left-hand side of an + ** assignment + */ + public class LHS_assign { + public LHS_assign prev; + public expdesc v = new expdesc(); /* variable (global, local, upvalue, or indexed) */ + }; + + + /* + ** check whether, in an assignment to a local variable, the local variable + ** is needed in a previous assignment (to a table). If so, save original + ** local value in a safe place and use this safe copy in the previous + ** assignment. + */ + private static void check_conflict (LexState ls, LHS_assign lh, expdesc v) { + FuncState fs = ls.fs; + int extra = fs.freereg; /* eventual position to save local variable */ + int conflict = 0; + for (; lh!=null; lh = lh.prev) { + if (lh.v.k == expkind.VINDEXED) { + if (lh.v.u.s.info == v.u.s.info) { /* conflict? */ + conflict = 1; + lh.v.u.s.info = extra; /* previous assignment will use safe copy */ + } + if (lh.v.u.s.aux == v.u.s.info) { /* conflict? */ + conflict = 1; + lh.v.u.s.aux = extra; /* previous assignment will use safe copy */ + } + } + } + if (conflict != 0) { + luaK_codeABC(fs, OpCode.OP_MOVE, fs.freereg, v.u.s.info, 0); /* make copy */ + luaK_reserveregs(fs, 1); + } + } + + + private static void assignment (LexState ls, LHS_assign lh, int nvars) { + expdesc e = new expdesc(); + check_condition(ls, expkind.VLOCAL <= lh.v.k && lh.v.k <= expkind.VINDEXED, + "syntax error"); + if (testnext(ls, ',') != 0) { /* assignment . `,' primaryexp assignment */ + LHS_assign nv = new LHS_assign(); + nv.prev = lh; + primaryexp(ls, nv.v); + if (nv.v.k == expkind.VLOCAL) + check_conflict(ls, lh, nv.v); + luaY_checklimit(ls.fs, nvars, LUAI_MAXCCALLS - ls.L.nCcalls, + "variables in assignment"); + assignment(ls, nv, nvars+1); + } + else { /* assignment . `=' explist1 */ + int nexps; + checknext(ls, '='); + nexps = explist1(ls, e); + if (nexps != nvars) { + adjust_assign(ls, nvars, nexps, e); + if (nexps > nvars) + ls.fs.freereg -= nexps - nvars; /* remove extra values */ + } + else { + luaK_setoneret(ls.fs, e); /* close last expression */ + luaK_storevar(ls.fs, lh.v, e); + return; /* avoid default */ + } + } + init_exp(e, expkind.VNONRELOC, ls.fs.freereg - 1); /* default assignment */ + luaK_storevar(ls.fs, lh.v, e); + } + + + private static int cond (LexState ls) { + /* cond . exp */ + expdesc v = new expdesc(); + expr(ls, v); /* read condition */ + if (v.k == expkind.VNIL) v.k = expkind.VFALSE; /* `falses' are all equal here */ + luaK_goiftrue(ls.fs, v); + return v.f; + } + + + private static void breakstat (LexState ls) { + FuncState fs = ls.fs; + BlockCnt bl = fs.bl; + int upval = 0; + while ((bl!=null) && (bl.isbreakable==0)) { + upval |= bl.upval; + bl = bl.previous; + } + if (bl==null) + luaX_syntaxerror(ls, "no loop to break"); + if (upval != 0) + luaK_codeABC(fs, OpCode.OP_CLOSE, bl.nactvar, 0, 0); + luaK_concat(fs, ref bl.breaklist, luaK_jump(fs)); + } + + + private static void whilestat (LexState ls, int line) { + /* whilestat . WHILE cond DO block END */ + FuncState fs = ls.fs; + int whileinit; + int condexit; + BlockCnt bl = new BlockCnt(); + luaX_next(ls); /* skip WHILE */ + whileinit = luaK_getlabel(fs); + condexit = cond(ls); + enterblock(fs, bl, 1); + checknext(ls, (int)RESERVED.TK_DO); + block(ls); + luaK_patchlist(fs, luaK_jump(fs), whileinit); + check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_WHILE, line); + leaveblock(fs); + luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ + } + + + private static void repeatstat (LexState ls, int line) { + /* repeatstat . REPEAT block UNTIL cond */ + int condexit; + FuncState fs = ls.fs; + int repeat_init = luaK_getlabel(fs); + BlockCnt bl1 = new BlockCnt(), bl2 = new BlockCnt(); + enterblock(fs, bl1, 1); /* loop block */ + enterblock(fs, bl2, 0); /* scope block */ + luaX_next(ls); /* skip REPEAT */ + chunk(ls); + check_match(ls, (int)RESERVED.TK_UNTIL, (int)RESERVED.TK_REPEAT, line); + condexit = cond(ls); /* read condition (inside scope block) */ + if (bl2.upval==0) { /* no upvalues? */ + leaveblock(fs); /* finish scope */ + luaK_patchlist(ls.fs, condexit, repeat_init); /* close the loop */ + } + else { /* complete semantics when there are upvalues */ + breakstat(ls); /* if condition then break */ + luaK_patchtohere(ls.fs, condexit); /* else... */ + leaveblock(fs); /* finish scope... */ + luaK_patchlist(ls.fs, luaK_jump(fs), repeat_init); /* and repeat */ + } + leaveblock(fs); /* finish loop */ + } + + + private static int exp1 (LexState ls) { + expdesc e = new expdesc(); + int k; + expr(ls, e); + k = (int)e.k; + luaK_exp2nextreg(ls.fs, e); + return k; + } + + + private static void forbody (LexState ls, int base_, int line, int nvars, int isnum) { + /* forbody . DO block */ + BlockCnt bl = new BlockCnt(); + FuncState fs = ls.fs; + int prep, endfor; + adjustlocalvars(ls, 3); /* control variables */ + checknext(ls, (int)RESERVED.TK_DO); + prep = (isnum != 0) ? luaK_codeAsBx(fs, OpCode.OP_FORPREP, base_, NO_JUMP) : luaK_jump(fs); + enterblock(fs, bl, 0); /* scope for declared variables */ + adjustlocalvars(ls, nvars); + luaK_reserveregs(fs, nvars); + block(ls); + leaveblock(fs); /* end of scope for declared variables */ + luaK_patchtohere(fs, prep); + endfor = (isnum!=0) ? luaK_codeAsBx(fs, OpCode.OP_FORLOOP, base_, NO_JUMP) : + luaK_codeABC(fs, OpCode.OP_TFORLOOP, base_, 0, nvars); + luaK_fixline(fs, line); /* pretend that `OP_FOR' starts the loop */ + luaK_patchlist(fs, ((isnum!=0) ? endfor : luaK_jump(fs)), prep + 1); + } + + + private static void fornum (LexState ls, TString varname, int line) { + /* fornum . NAME = exp1,exp1[,exp1] forbody */ + FuncState fs = ls.fs; + int base_ = fs.freereg; + new_localvarliteral(ls, "(for index)", 0); + new_localvarliteral(ls, "(for limit)", 1); + new_localvarliteral(ls, "(for step)", 2); + new_localvar(ls, varname, 3); + checknext(ls, '='); + exp1(ls); /* initial value */ + checknext(ls, ','); + exp1(ls); /* limit */ + if (testnext(ls, ',') != 0) + exp1(ls); /* optional step */ + else { /* default step = 1 */ + luaK_codeABx(fs, OpCode.OP_LOADK, fs.freereg, luaK_numberK(fs, 1)); + luaK_reserveregs(fs, 1); + } + forbody(ls, base_, line, 1, 1); + } + + + private static void forlist (LexState ls, TString indexname) { + /* forlist . NAME {,NAME} IN explist1 forbody */ + FuncState fs = ls.fs; + expdesc e = new expdesc(); + int nvars = 0; + int line; + int base_ = fs.freereg; + /* create control variables */ + new_localvarliteral(ls, "(for generator)", nvars++); + new_localvarliteral(ls, "(for state)", nvars++); + new_localvarliteral(ls, "(for control)", nvars++); + /* create declared variables */ + new_localvar(ls, indexname, nvars++); + while (testnext(ls, ',') != 0) + new_localvar(ls, str_checkname(ls), nvars++); + checknext(ls, (int)RESERVED.TK_IN); + line = ls.linenumber; + adjust_assign(ls, 3, explist1(ls, e), e); + luaK_checkstack(fs, 3); /* extra space to call generator */ + forbody(ls, base_, line, nvars - 3, 0); + } + + + private static void forstat (LexState ls, int line) { + /* forstat . FOR (fornum | forlist) END */ + FuncState fs = ls.fs; + TString varname; + BlockCnt bl = new BlockCnt(); + enterblock(fs, bl, 1); /* scope for loop and control variables */ + luaX_next(ls); /* skip `for' */ + varname = str_checkname(ls); /* first variable name */ + switch (ls.t.token) { + case '=': fornum(ls, varname, line); break; + case ',': + case (int)RESERVED.TK_IN: + forlist(ls, varname); + break; + default: luaX_syntaxerror(ls, LUA_QL("=") + " or " + LUA_QL("in") + " expected"); break; + } + check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_FOR, line); + leaveblock(fs); /* loop scope (`break' jumps to this point) */ + } + + + private static int test_then_block (LexState ls) { + /* test_then_block . [IF | ELSEIF] cond THEN block */ + int condexit; + luaX_next(ls); /* skip IF or ELSEIF */ + condexit = cond(ls); + checknext(ls, (int)RESERVED.TK_THEN); + block(ls); /* `then' part */ + return condexit; + } + + + private static void ifstat (LexState ls, int line) { + /* ifstat . IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ + FuncState fs = ls.fs; + int flist; + int escapelist = NO_JUMP; + flist = test_then_block(ls); /* IF cond THEN block */ + while (ls.t.token == (int)RESERVED.TK_ELSEIF) { + luaK_concat(fs, ref escapelist, luaK_jump(fs)); + luaK_patchtohere(fs, flist); + flist = test_then_block(ls); /* ELSEIF cond THEN block */ + } + if (ls.t.token == (int)RESERVED.TK_ELSE) { + luaK_concat(fs, ref escapelist, luaK_jump(fs)); + luaK_patchtohere(fs, flist); + luaX_next(ls); /* skip ELSE (after patch, for correct line info) */ + block(ls); /* `else' part */ + } + else + luaK_concat(fs, ref escapelist, flist); + luaK_patchtohere(fs, escapelist); + check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_IF, line); + } + + + private static void localfunc (LexState ls) { + expdesc v = new expdesc(), b = new expdesc(); + FuncState fs = ls.fs; + new_localvar(ls, str_checkname(ls), 0); + init_exp(v, expkind.VLOCAL, fs.freereg); + luaK_reserveregs(fs, 1); + adjustlocalvars(ls, 1); + body(ls, b, 0, ls.linenumber); + luaK_storevar(fs, v, b); + /* debug information will only see the variable after this point! */ + getlocvar(fs, fs.nactvar - 1).startpc = fs.pc; + } + + + private static void localstat (LexState ls) { + /* stat . LOCAL NAME {`,' NAME} [`=' explist1] */ + int nvars = 0; + int nexps; + expdesc e = new expdesc(); + do { + new_localvar(ls, str_checkname(ls), nvars++); + } while (testnext(ls, ',') != 0); + if (testnext(ls, '=') != 0) + nexps = explist1(ls, e); + else { + e.k = expkind.VVOID; + nexps = 0; + } + adjust_assign(ls, nvars, nexps, e); + adjustlocalvars(ls, nvars); + } + + + private static int funcname (LexState ls, expdesc v) { + /* funcname . NAME {field} [`:' NAME] */ + int needself = 0; + singlevar(ls, v); + while (ls.t.token == '.') + field(ls, v); + if (ls.t.token == ':') { + needself = 1; + field(ls, v); + } + return needself; + } + + + private static void funcstat (LexState ls, int line) { + /* funcstat . FUNCTION funcname body */ + int needself; + expdesc v = new expdesc(), b = new expdesc(); + luaX_next(ls); /* skip FUNCTION */ + needself = funcname(ls, v); + body(ls, b, needself, line); + luaK_storevar(ls.fs, v, b); + luaK_fixline(ls.fs, line); /* definition `happens' in the first line */ + } + + + private static void exprstat (LexState ls) { + /* stat . func | assignment */ + FuncState fs = ls.fs; + LHS_assign v = new LHS_assign(); + primaryexp(ls, v.v); + if (v.v.k == expkind.VCALL) /* stat . func */ + SETARG_C(getcode(fs, v.v), 1); /* call statement uses no results */ + else { /* stat . assignment */ + v.prev = null; + assignment(ls, v, 1); + } + } + + + private static void retstat (LexState ls) { + /* stat . RETURN explist */ + FuncState fs = ls.fs; + expdesc e = new expdesc(); + int first, nret; /* registers with returned values */ + luaX_next(ls); /* skip RETURN */ + if ((block_follow(ls.t.token)!=0) || ls.t.token == ';') + first = nret = 0; /* return no values */ + else { + nret = explist1(ls, e); /* optional return values */ + if (hasmultret(e.k) != 0) { + luaK_setmultret(fs, e); + if (e.k == expkind.VCALL && nret == 1) { /* tail call? */ + SET_OPCODE(getcode(fs,e), OpCode.OP_TAILCALL); + lua_assert(GETARG_A(getcode(fs,e)) == fs.nactvar); + } + first = fs.nactvar; + nret = LUA_MULTRET; /* return all values */ + } + else { + if (nret == 1) /* only one single value? */ + first = luaK_exp2anyreg(fs, e); + else { + luaK_exp2nextreg(fs, e); /* values must go to the `stack' */ + first = fs.nactvar; /* return all `active' values */ + lua_assert(nret == fs.freereg - first); + } + } + } + luaK_ret(fs, first, nret); + } + + + private static int statement (LexState ls) { + int line = ls.linenumber; /* may be needed for error messages */ + switch (ls.t.token) { + case (int)RESERVED.TK_IF: { /* stat . ifstat */ + ifstat(ls, line); + return 0; + } + case (int)RESERVED.TK_WHILE: { /* stat . whilestat */ + whilestat(ls, line); + return 0; + } + case (int)RESERVED.TK_DO: { /* stat . DO block END */ + luaX_next(ls); /* skip DO */ + block(ls); + check_match(ls, (int)RESERVED.TK_END, (int)RESERVED.TK_DO, line); + return 0; + } + case (int)RESERVED.TK_FOR: { /* stat . forstat */ + forstat(ls, line); + return 0; + } + case (int)RESERVED.TK_REPEAT: { /* stat . repeatstat */ + repeatstat(ls, line); + return 0; + } + case (int)RESERVED.TK_FUNCTION: { + funcstat(ls, line); /* stat . funcstat */ + return 0; + } + case (int)RESERVED.TK_LOCAL: { /* stat . localstat */ + luaX_next(ls); /* skip LOCAL */ + if (testnext(ls, (int)RESERVED.TK_FUNCTION) != 0) /* local function? */ + localfunc(ls); + else + localstat(ls); + return 0; + } + case (int)RESERVED.TK_RETURN: { /* stat . retstat */ + retstat(ls); + return 1; /* must be last statement */ + } + case (int)RESERVED.TK_BREAK: { /* stat . breakstat */ + luaX_next(ls); /* skip BREAK */ + breakstat(ls); + return 1; /* must be last statement */ + } + default: { + exprstat(ls); + return 0; /* to avoid warnings */ + } + } + } + + + private static void chunk (LexState ls) { + /* chunk . { stat [`;'] } */ + int islast = 0; + enterlevel(ls); + while ((islast==0) && (block_follow(ls.t.token)==0)) { + islast = statement(ls); + testnext(ls, ';'); + lua_assert(ls.fs.f.maxstacksize >= ls.fs.freereg && + ls.fs.freereg >= ls.fs.nactvar); + ls.fs.freereg = ls.fs.nactvar; /* free registers */ + } + leavelevel(ls); + } + + /* }====================================================================== */ + + } } \ No newline at end of file diff --git a/Core/KopiLua/lstate.cs b/Core/KopiLua/lstate.cs index 492676143a6d3871db4fbcfc9a6c83d49fe7be58..d9cb6acad39663daf219a8b41291d17ee2eb64a9 100644 --- a/Core/KopiLua/lstate.cs +++ b/Core/KopiLua/lstate.cs @@ -1,542 +1,542 @@ -/* -** $Id: lstate.c,v 2.36.1.2 2008/01/03 15:20:39 roberto Exp $ -** Global State -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; -using System.Diagnostics; - -namespace KopiLua -{ - using lu_byte = System.Byte; - using lu_int32 = System.Int32; - using lu_mem = System.UInt32; - using TValue = Lua.lua_TValue; - using StkId = Lua.lua_TValue; - using ptrdiff_t = System.Int32; - using Instruction = System.UInt32; - - public partial class Lua - { - /* table of globals */ - public static TValue gt(lua_State L) {return L.l_gt;} - - /* registry */ - public static TValue registry(lua_State L) {return G(L).l_registry;} - - - /* extra stack space to handle TM calls and some other extras */ - public const int EXTRA_STACK = 5; - - - public const int BASIC_CI_SIZE = 8; - - public const int BASIC_STACK_SIZE = (2*LUA_MINSTACK); - - - - public class stringtable { - public GCObject[] hash; - public lu_int32 nuse; /* number of elements */ - public int size; - }; - - - /* - ** informations about a call - */ - public class CallInfo : ArrayElement - { - private CallInfo[] values = null; - private int index = -1; - - public void set_index(int index) - { - this.index = index; - } - - public void set_array(object array) - { - this.values = (CallInfo[])array; - Debug.Assert(this.values != null); - } - - public CallInfo this[int offset] - { - get { return values[index+offset]; } - } - - public static CallInfo operator +(CallInfo value, int offset) - { - return value.values[value.index + offset]; - } - - public static CallInfo operator -(CallInfo value, int offset) - { - return value.values[value.index - offset]; - } - - public static int operator -(CallInfo ci, CallInfo[] values) - { - Debug.Assert(ci.values == values); - return ci.index; - } - - public static int operator -(CallInfo ci1, CallInfo ci2) - { - Debug.Assert(ci1.values == ci2.values); - return ci1.index - ci2.index; - } - - public static bool operator <(CallInfo ci1, CallInfo ci2) - { - Debug.Assert(ci1.values == ci2.values); - return ci1.index < ci2.index; - } - - public static bool operator <=(CallInfo ci1, CallInfo ci2) - { - Debug.Assert(ci1.values == ci2.values); - return ci1.index <= ci2.index; - } - - public static bool operator >(CallInfo ci1, CallInfo ci2) - { - Debug.Assert(ci1.values == ci2.values); - return ci1.index > ci2.index; - } - - public static bool operator >=(CallInfo ci1, CallInfo ci2) - { - Debug.Assert(ci1.values == ci2.values); - return ci1.index >= ci2.index; - } - - public static CallInfo inc(ref CallInfo value) - { - value = value[1]; - return value[-1]; - } - - public static CallInfo dec(ref CallInfo value) - { - value = value[-1]; - return value[1]; - } - - public StkId base_; /* base for this function */ - public StkId func; /* function index in the stack */ - public StkId top; /* top for this function */ - public InstructionPtr savedpc; - public int nresults; /* expected number of results from this function */ - public int tailcalls; /* number of tail calls lost under this entry */ - }; - - - - public static Closure curr_func(lua_State L) { return (clvalue(L.ci.func)); } - public static Closure ci_func(CallInfo ci) { return (clvalue(ci.func)); } - public static bool f_isLua(CallInfo ci) {return ci_func(ci).c.isC==0;} - public static bool isLua(CallInfo ci) {return (ttisfunction((ci).func) && f_isLua(ci));} - - - /* - ** `global state', shared by all threads of this state - */ - public class global_State { - public stringtable strt = new stringtable(); /* hash table for strings */ - public lua_Alloc frealloc; /* function to reallocate memory */ - public object ud; /* auxiliary data to `frealloc' */ - public lu_byte currentwhite; - public lu_byte gcstate; /* state of garbage collector */ - public int sweepstrgc; /* position of sweep in `strt' */ - public GCObject rootgc; /* list of all collectable objects */ - public GCObjectRef sweepgc; /* position of sweep in `rootgc' */ - public GCObject gray; /* list of gray objects */ - public GCObject grayagain; /* list of objects to be traversed atomically */ - public GCObject weak; /* list of weak tables (to be cleared) */ - public GCObject tmudata; /* last element of list of userdata to be GC */ - public Mbuffer buff = new Mbuffer(); /* temporary buffer for string concatentation */ - [CLSCompliantAttribute(false)] - public lu_mem GCthreshold; - [CLSCompliantAttribute(false)] - public lu_mem totalbytes; /* number of bytes currently allocated */ - [CLSCompliantAttribute(false)] - public lu_mem estimate; /* an estimate of number of bytes actually in use */ - [CLSCompliantAttribute(false)] - public lu_mem gcdept; /* how much GC is `behind schedule' */ - public int gcpause; /* size of pause between successive GCs */ - public int gcstepmul; /* GC `granularity' */ - public lua_CFunction panic; /* to be called in unprotected errors */ - public TValue l_registry = new TValue(); - public lua_State mainthread; - public UpVal uvhead = new UpVal(); /* head of double-linked list of all open upvalues */ - public Table[] mt = new Table[NUM_TAGS]; /* metatables for basic types */ - public TString[] tmname = new TString[(int)TMS.TM_N]; /* array with tag-method names */ - }; - - - /* - ** `per thread' state - */ - public class lua_State : GCObject { - - public lu_byte status; - public StkId top; /* first free slot in the stack */ - public StkId base_; /* base of current function */ - public global_State l_G; - public CallInfo ci; /* call info for current function */ - public InstructionPtr savedpc = new InstructionPtr(); /* `savedpc' of current function */ - public StkId stack_last; /* last free slot in the stack */ - public StkId[] stack; /* stack base */ - public CallInfo end_ci; /* points after end of ci array*/ - public CallInfo[] base_ci; /* array of CallInfo's */ - public int stacksize; - public int size_ci; /* size of array `base_ci' */ - [CLSCompliantAttribute(false)] - public ushort nCcalls; /* number of nested C calls */ - [CLSCompliantAttribute(false)] - public ushort baseCcalls; /* nested C calls when resuming coroutine */ - public lu_byte hookmask; - public lu_byte allowhook; - public int basehookcount; - public int hookcount; - public lua_Hook hook; - public TValue l_gt = new TValue(); /* table of globals */ - public TValue env = new TValue(); /* temporary place for environments */ - public GCObject openupval; /* list of open upvalues in this stack */ - public GCObject gclist; - public lua_longjmp errorJmp; /* current error recover point */ - public ptrdiff_t errfunc; /* current error handling function (stack index) */ - }; - - - public static global_State G(lua_State L) {return L.l_G;} - public static void G_set(lua_State L, global_State s) { L.l_G = s; } - - - /* - ** Union of all collectable objects (not a union anymore in the C# port) - */ - public class GCObject : GCheader, ArrayElement - { - public void set_index(int index) - { - //this.index = index; - } - - public void set_array(object array) - { - //this.values = (GCObject[])array; - //Debug.Assert(this.values != null); - } - - public GCheader gch {get{return (GCheader)this;}} - public TString ts {get{return (TString)this;}} - public Udata u {get{return (Udata)this;}} - public Closure cl {get{return (Closure)this;}} - public Table h {get{return (Table)this;}} - public Proto p {get{return (Proto)this;}} - public UpVal uv {get{return (UpVal)this;}} - public lua_State th {get{return (lua_State)this;}} - }; - - /* this interface and is used for implementing GCObject references, - it's used to emulate the behaviour of a C-style GCObject ** - */ - public interface GCObjectRef - { - void set(GCObject value); - GCObject get(); - } - - public class ArrayRef : GCObjectRef, ArrayElement - { - public ArrayRef() - { - this.array_elements = null; - this.array_index = 0; - this.vals = null; - this.index = 0; - } - public ArrayRef(GCObject[] array_elements, int array_index) - { - this.array_elements = array_elements; - this.array_index = array_index; - this.vals = null; - this.index = 0; - } - public void set(GCObject value) { array_elements[array_index] = value; } - public GCObject get() { return array_elements[array_index]; } - - public void set_index(int index) - { - this.index = index; - } - public void set_array(object vals) - { - // don't actually need this - this.vals = (ArrayRef[])vals; - Debug.Assert(this.vals != null); - } - - // ArrayRef is used to reference GCObject objects in an array, the next two members - // point to that array and the index of the GCObject element we are referencing - GCObject[] array_elements; - int array_index; - - // ArrayRef is itself stored in an array and derived from ArrayElement, the next - // two members refer to itself i.e. the array and index of it's own instance. - ArrayRef[] vals; - int index; - } - - public class OpenValRef : GCObjectRef - { - public OpenValRef(lua_State L) { this.L = L; } - public void set(GCObject value) { this.L.openupval = value; } - public GCObject get() { return this.L.openupval; } - lua_State L; - } - - public class RootGCRef : GCObjectRef - { - public RootGCRef(global_State g) { this.g = g; } - public void set(GCObject value) { this.g.rootgc = value; } - public GCObject get() { return this.g.rootgc; } - global_State g; - } - - public class NextRef : GCObjectRef - { - public NextRef(GCheader header) { this.header = header; } - public void set(GCObject value) { this.header.next = value; } - public GCObject get() { return this.header.next; } - GCheader header; - } - - - /* macros to convert a GCObject into a specific value */ - public static TString rawgco2ts(GCObject o) { return (TString)check_exp(o.gch.tt == LUA_TSTRING, o.ts); } - public static TString gco2ts(GCObject o) { return (TString)(rawgco2ts(o).tsv); } - public static Udata rawgco2u(GCObject o) { return (Udata)check_exp(o.gch.tt == LUA_TUSERDATA, o.u); } - public static Udata gco2u(GCObject o) { return (Udata)(rawgco2u(o).uv); } - public static Closure gco2cl(GCObject o) { return (Closure)check_exp(o.gch.tt == LUA_TFUNCTION, o.cl); } - public static Table gco2h(GCObject o) { return (Table)check_exp(o.gch.tt == LUA_TTABLE, o.h); } - public static Proto gco2p(GCObject o) { return (Proto)check_exp(o.gch.tt == LUA_TPROTO, o.p); } - public static UpVal gco2uv(GCObject o) { return (UpVal)check_exp(o.gch.tt == LUA_TUPVAL, o.uv); } - public static UpVal ngcotouv(GCObject o) {return (UpVal)check_exp((o == null) || (o.gch.tt == LUA_TUPVAL), o.uv); } - public static lua_State gco2th(GCObject o) { return (lua_State)check_exp(o.gch.tt == LUA_TTHREAD, o.th); } - - /* macro to convert any Lua object into a GCObject */ - public static GCObject obj2gco(object v) {return (GCObject)v;} - - - public static int state_size(object x) { return Marshal.SizeOf(x) + LUAI_EXTRASPACE; } - /* - public static lu_byte fromstate(object l) - { - return (lu_byte)(l - LUAI_EXTRASPACE); - } - */ - public static lua_State tostate(object l) - { - Debug.Assert(LUAI_EXTRASPACE == 0, "LUAI_EXTRASPACE not supported"); - return (lua_State)l; - } - - - /* - ** Main thread combines a thread state and the global state - */ - public class LG : lua_State { - public lua_State l {get {return this;}} - public global_State g = new global_State(); - }; - - - - private static void stack_init (lua_State L1, lua_State L) { - /* initialize CallInfo array */ - L1.base_ci = luaM_newvector(L, BASIC_CI_SIZE); - L1.ci = L1.base_ci[0]; - L1.size_ci = BASIC_CI_SIZE; - L1.end_ci = L1.base_ci[L1.size_ci - 1]; - /* initialize stack array */ - L1.stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK); - L1.stacksize = BASIC_STACK_SIZE + EXTRA_STACK; - L1.top = L1.stack[0]; - L1.stack_last = L1.stack[L1.stacksize - EXTRA_STACK - 1]; - /* initialize first ci */ - L1.ci.func = L1.top; - setnilvalue(StkId.inc(ref L1.top)); /* `function' entry for this `ci' */ - L1.base_ = L1.ci.base_ = L1.top; - L1.ci.top = L1.top + LUA_MINSTACK; - } - - - private static void freestack (lua_State L, lua_State L1) { - luaM_freearray(L, L1.base_ci); - luaM_freearray(L, L1.stack); - } - - - /* - ** open parts that may cause memory-allocation errors - */ - private static void f_luaopen (lua_State L, object ud) { - global_State g = G(L); - //UNUSED(ud); - stack_init(L, L); /* init stack */ - sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */ - sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */ - luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ - luaT_init(L); - luaX_init(L); - luaS_fix(luaS_newliteral(L, MEMERRMSG)); - g.GCthreshold = 4*g.totalbytes; - } - - - private static void preinit_state (lua_State L, global_State g) { - G_set(L, g); - L.stack = null; - L.stacksize = 0; - L.errorJmp = null; - L.hook = null; - L.hookmask = 0; - L.basehookcount = 0; - L.allowhook = 1; - resethookcount(L); - L.openupval = null; - L.size_ci = 0; - L.nCcalls = L.baseCcalls = 0; - L.status = 0; - L.base_ci = null; - L.ci = null; - L.savedpc = new InstructionPtr(); - L.errfunc = 0; - setnilvalue(gt(L)); - } - - - private static void close_state (lua_State L) { - global_State g = G(L); - luaF_close(L, L.stack[0]); /* close all upvalues for this thread */ - luaC_freeall(L); /* collect all objects */ - lua_assert(g.rootgc == obj2gco(L)); - lua_assert(g.strt.nuse == 0); - luaM_freearray(L, G(L).strt.hash); - luaZ_freebuffer(L, g.buff); - freestack(L, L); - lua_assert(g.totalbytes == GetUnmanagedSize(typeof(LG))); - //g.frealloc(g.ud, fromstate(L), (uint)state_size(typeof(LG)), 0); - } - - - private static lua_State luaE_newthread (lua_State L) { - //lua_State L1 = tostate(luaM_malloc(L, state_size(typeof(lua_State)))); - lua_State L1 = luaM_new(L); - luaC_link(L, obj2gco(L1), LUA_TTHREAD); - preinit_state(L1, G(L)); - stack_init(L1, L); /* init stack */ - setobj2n(L, gt(L1), gt(L)); /* share table of globals */ - L1.hookmask = L.hookmask; - L1.basehookcount = L.basehookcount; - L1.hook = L.hook; - resethookcount(L1); - lua_assert(iswhite(obj2gco(L1))); - return L1; - } - - - private static void luaE_freethread (lua_State L, lua_State L1) { - luaF_close(L1, L1.stack[0]); /* close all upvalues for this thread */ - lua_assert(L1.openupval == null); - luai_userstatefree(L1); - freestack(L, L1); - //luaM_freemem(L, fromstate(L1)); - } - - - public static lua_State lua_newstate (lua_Alloc f, object ud) { - int i; - lua_State L; - global_State g; - //object l = f(ud, null, 0, (uint)state_size(typeof(LG))); - object l = f(typeof(LG)); - if (l == null) return null; - L = tostate(l); - g = (L as LG).g; - L.next = null; - L.tt = LUA_TTHREAD; - g.currentwhite = (lu_byte)bit2mask(WHITE0BIT, FIXEDBIT); - L.marked = luaC_white(g); - lu_byte marked = L.marked; // can't pass properties in as ref - set2bits(ref marked, FIXEDBIT, SFIXEDBIT); - L.marked = marked; - preinit_state(L, g); - g.frealloc = f; - g.ud = ud; - g.mainthread = L; - g.uvhead.u.l.prev = g.uvhead; - g.uvhead.u.l.next = g.uvhead; - g.GCthreshold = 0; /* mark it as unfinished state */ - g.strt.size = 0; - g.strt.nuse = 0; - g.strt.hash = null; - setnilvalue(registry(L)); - luaZ_initbuffer(L, g.buff); - g.panic = null; - g.gcstate = GCSpause; - g.rootgc = obj2gco(L); - g.sweepstrgc = 0; - g.sweepgc = new RootGCRef(g); - g.gray = null; - g.grayagain = null; - g.weak = null; - g.tmudata = null; - g.totalbytes = (uint)GetUnmanagedSize(typeof(LG)); - g.gcpause = LUAI_GCPAUSE; - g.gcstepmul = LUAI_GCMUL; - g.gcdept = 0; - for (i=0; i(CallInfo ci1, CallInfo ci2) + { + Debug.Assert(ci1.values == ci2.values); + return ci1.index > ci2.index; + } + + public static bool operator >=(CallInfo ci1, CallInfo ci2) + { + Debug.Assert(ci1.values == ci2.values); + return ci1.index >= ci2.index; + } + + public static CallInfo inc(ref CallInfo value) + { + value = value[1]; + return value[-1]; + } + + public static CallInfo dec(ref CallInfo value) + { + value = value[-1]; + return value[1]; + } + + public StkId base_; /* base for this function */ + public StkId func; /* function index in the stack */ + public StkId top; /* top for this function */ + public InstructionPtr savedpc; + public int nresults; /* expected number of results from this function */ + public int tailcalls; /* number of tail calls lost under this entry */ + }; + + + + public static Closure curr_func(lua_State L) { return (clvalue(L.ci.func)); } + public static Closure ci_func(CallInfo ci) { return (clvalue(ci.func)); } + public static bool f_isLua(CallInfo ci) {return ci_func(ci).c.isC==0;} + public static bool isLua(CallInfo ci) {return (ttisfunction((ci).func) && f_isLua(ci));} + + + /* + ** `global state', shared by all threads of this state + */ + public class global_State { + public stringtable strt = new stringtable(); /* hash table for strings */ + public lua_Alloc frealloc; /* function to reallocate memory */ + public object ud; /* auxiliary data to `frealloc' */ + public lu_byte currentwhite; + public lu_byte gcstate; /* state of garbage collector */ + public int sweepstrgc; /* position of sweep in `strt' */ + public GCObject rootgc; /* list of all collectable objects */ + public GCObjectRef sweepgc; /* position of sweep in `rootgc' */ + public GCObject gray; /* list of gray objects */ + public GCObject grayagain; /* list of objects to be traversed atomically */ + public GCObject weak; /* list of weak tables (to be cleared) */ + public GCObject tmudata; /* last element of list of userdata to be GC */ + public Mbuffer buff = new Mbuffer(); /* temporary buffer for string concatentation */ + [CLSCompliantAttribute(false)] + public lu_mem GCthreshold; + [CLSCompliantAttribute(false)] + public lu_mem totalbytes; /* number of bytes currently allocated */ + [CLSCompliantAttribute(false)] + public lu_mem estimate; /* an estimate of number of bytes actually in use */ + [CLSCompliantAttribute(false)] + public lu_mem gcdept; /* how much GC is `behind schedule' */ + public int gcpause; /* size of pause between successive GCs */ + public int gcstepmul; /* GC `granularity' */ + public lua_CFunction panic; /* to be called in unprotected errors */ + public TValue l_registry = new TValue(); + public lua_State mainthread; + public UpVal uvhead = new UpVal(); /* head of double-linked list of all open upvalues */ + public Table[] mt = new Table[NUM_TAGS]; /* metatables for basic types */ + public TString[] tmname = new TString[(int)TMS.TM_N]; /* array with tag-method names */ + }; + + + /* + ** `per thread' state + */ + public class lua_State : GCObject { + + public lu_byte status; + public StkId top; /* first free slot in the stack */ + public StkId base_; /* base of current function */ + public global_State l_G; + public CallInfo ci; /* call info for current function */ + public InstructionPtr savedpc = new InstructionPtr(); /* `savedpc' of current function */ + public StkId stack_last; /* last free slot in the stack */ + public StkId[] stack; /* stack base */ + public CallInfo end_ci; /* points after end of ci array*/ + public CallInfo[] base_ci; /* array of CallInfo's */ + public int stacksize; + public int size_ci; /* size of array `base_ci' */ + [CLSCompliantAttribute(false)] + public ushort nCcalls; /* number of nested C calls */ + [CLSCompliantAttribute(false)] + public ushort baseCcalls; /* nested C calls when resuming coroutine */ + public lu_byte hookmask; + public lu_byte allowhook; + public int basehookcount; + public int hookcount; + public lua_Hook hook; + public TValue l_gt = new TValue(); /* table of globals */ + public TValue env = new TValue(); /* temporary place for environments */ + public GCObject openupval; /* list of open upvalues in this stack */ + public GCObject gclist; + public lua_longjmp errorJmp; /* current error recover point */ + public ptrdiff_t errfunc; /* current error handling function (stack index) */ + }; + + + public static global_State G(lua_State L) {return L.l_G;} + public static void G_set(lua_State L, global_State s) { L.l_G = s; } + + + /* + ** Union of all collectable objects (not a union anymore in the C# port) + */ + public class GCObject : GCheader, ArrayElement + { + public void set_index(int index) + { + //this.index = index; + } + + public void set_array(object array) + { + //this.values = (GCObject[])array; + //Debug.Assert(this.values != null); + } + + public GCheader gch {get{return (GCheader)this;}} + public TString ts {get{return (TString)this;}} + public Udata u {get{return (Udata)this;}} + public Closure cl {get{return (Closure)this;}} + public Table h {get{return (Table)this;}} + public Proto p {get{return (Proto)this;}} + public UpVal uv {get{return (UpVal)this;}} + public lua_State th {get{return (lua_State)this;}} + }; + + /* this interface and is used for implementing GCObject references, + it's used to emulate the behaviour of a C-style GCObject ** + */ + public interface GCObjectRef + { + void set(GCObject value); + GCObject get(); + } + + public class ArrayRef : GCObjectRef, ArrayElement + { + public ArrayRef() + { + this.array_elements = null; + this.array_index = 0; + this.vals = null; + this.index = 0; + } + public ArrayRef(GCObject[] array_elements, int array_index) + { + this.array_elements = array_elements; + this.array_index = array_index; + this.vals = null; + this.index = 0; + } + public void set(GCObject value) { array_elements[array_index] = value; } + public GCObject get() { return array_elements[array_index]; } + + public void set_index(int index) + { + this.index = index; + } + public void set_array(object vals) + { + // don't actually need this + this.vals = (ArrayRef[])vals; + Debug.Assert(this.vals != null); + } + + // ArrayRef is used to reference GCObject objects in an array, the next two members + // point to that array and the index of the GCObject element we are referencing + GCObject[] array_elements; + int array_index; + + // ArrayRef is itself stored in an array and derived from ArrayElement, the next + // two members refer to itself i.e. the array and index of it's own instance. + ArrayRef[] vals; + int index; + } + + public class OpenValRef : GCObjectRef + { + public OpenValRef(lua_State L) { this.L = L; } + public void set(GCObject value) { this.L.openupval = value; } + public GCObject get() { return this.L.openupval; } + lua_State L; + } + + public class RootGCRef : GCObjectRef + { + public RootGCRef(global_State g) { this.g = g; } + public void set(GCObject value) { this.g.rootgc = value; } + public GCObject get() { return this.g.rootgc; } + global_State g; + } + + public class NextRef : GCObjectRef + { + public NextRef(GCheader header) { this.header = header; } + public void set(GCObject value) { this.header.next = value; } + public GCObject get() { return this.header.next; } + GCheader header; + } + + + /* macros to convert a GCObject into a specific value */ + public static TString rawgco2ts(GCObject o) { return (TString)check_exp(o.gch.tt == LUA_TSTRING, o.ts); } + public static TString gco2ts(GCObject o) { return (TString)(rawgco2ts(o).tsv); } + public static Udata rawgco2u(GCObject o) { return (Udata)check_exp(o.gch.tt == LUA_TUSERDATA, o.u); } + public static Udata gco2u(GCObject o) { return (Udata)(rawgco2u(o).uv); } + public static Closure gco2cl(GCObject o) { return (Closure)check_exp(o.gch.tt == LUA_TFUNCTION, o.cl); } + public static Table gco2h(GCObject o) { return (Table)check_exp(o.gch.tt == LUA_TTABLE, o.h); } + public static Proto gco2p(GCObject o) { return (Proto)check_exp(o.gch.tt == LUA_TPROTO, o.p); } + public static UpVal gco2uv(GCObject o) { return (UpVal)check_exp(o.gch.tt == LUA_TUPVAL, o.uv); } + public static UpVal ngcotouv(GCObject o) {return (UpVal)check_exp((o == null) || (o.gch.tt == LUA_TUPVAL), o.uv); } + public static lua_State gco2th(GCObject o) { return (lua_State)check_exp(o.gch.tt == LUA_TTHREAD, o.th); } + + /* macro to convert any Lua object into a GCObject */ + public static GCObject obj2gco(object v) {return (GCObject)v;} + + + public static int state_size(object x) { return Marshal.SizeOf(x) + LUAI_EXTRASPACE; } + /* + public static lu_byte fromstate(object l) + { + return (lu_byte)(l - LUAI_EXTRASPACE); + } + */ + public static lua_State tostate(object l) + { + Debug.Assert(LUAI_EXTRASPACE == 0, "LUAI_EXTRASPACE not supported"); + return (lua_State)l; + } + + + /* + ** Main thread combines a thread state and the global state + */ + public class LG : lua_State { + public lua_State l {get {return this;}} + public global_State g = new global_State(); + }; + + + + private static void stack_init (lua_State L1, lua_State L) { + /* initialize CallInfo array */ + L1.base_ci = luaM_newvector(L, BASIC_CI_SIZE); + L1.ci = L1.base_ci[0]; + L1.size_ci = BASIC_CI_SIZE; + L1.end_ci = L1.base_ci[L1.size_ci - 1]; + /* initialize stack array */ + L1.stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK); + L1.stacksize = BASIC_STACK_SIZE + EXTRA_STACK; + L1.top = L1.stack[0]; + L1.stack_last = L1.stack[L1.stacksize - EXTRA_STACK - 1]; + /* initialize first ci */ + L1.ci.func = L1.top; + setnilvalue(StkId.inc(ref L1.top)); /* `function' entry for this `ci' */ + L1.base_ = L1.ci.base_ = L1.top; + L1.ci.top = L1.top + LUA_MINSTACK; + } + + + private static void freestack (lua_State L, lua_State L1) { + luaM_freearray(L, L1.base_ci); + luaM_freearray(L, L1.stack); + } + + + /* + ** open parts that may cause memory-allocation errors + */ + private static void f_luaopen (lua_State L, object ud) { + global_State g = G(L); + //UNUSED(ud); + stack_init(L, L); /* init stack */ + sethvalue(L, gt(L), luaH_new(L, 0, 2)); /* table of globals */ + sethvalue(L, registry(L), luaH_new(L, 0, 2)); /* registry */ + luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ + luaT_init(L); + luaX_init(L); + luaS_fix(luaS_newliteral(L, MEMERRMSG)); + g.GCthreshold = 4*g.totalbytes; + } + + + private static void preinit_state (lua_State L, global_State g) { + G_set(L, g); + L.stack = null; + L.stacksize = 0; + L.errorJmp = null; + L.hook = null; + L.hookmask = 0; + L.basehookcount = 0; + L.allowhook = 1; + resethookcount(L); + L.openupval = null; + L.size_ci = 0; + L.nCcalls = L.baseCcalls = 0; + L.status = 0; + L.base_ci = null; + L.ci = null; + L.savedpc = new InstructionPtr(); + L.errfunc = 0; + setnilvalue(gt(L)); + } + + + private static void close_state (lua_State L) { + global_State g = G(L); + luaF_close(L, L.stack[0]); /* close all upvalues for this thread */ + luaC_freeall(L); /* collect all objects */ + lua_assert(g.rootgc == obj2gco(L)); + lua_assert(g.strt.nuse == 0); + luaM_freearray(L, G(L).strt.hash); + luaZ_freebuffer(L, g.buff); + freestack(L, L); + lua_assert(g.totalbytes == GetUnmanagedSize(typeof(LG))); + //g.frealloc(g.ud, fromstate(L), (uint)state_size(typeof(LG)), 0); + } + + + private static lua_State luaE_newthread (lua_State L) { + //lua_State L1 = tostate(luaM_malloc(L, state_size(typeof(lua_State)))); + lua_State L1 = luaM_new(L); + luaC_link(L, obj2gco(L1), LUA_TTHREAD); + preinit_state(L1, G(L)); + stack_init(L1, L); /* init stack */ + setobj2n(L, gt(L1), gt(L)); /* share table of globals */ + L1.hookmask = L.hookmask; + L1.basehookcount = L.basehookcount; + L1.hook = L.hook; + resethookcount(L1); + lua_assert(iswhite(obj2gco(L1))); + return L1; + } + + + private static void luaE_freethread (lua_State L, lua_State L1) { + luaF_close(L1, L1.stack[0]); /* close all upvalues for this thread */ + lua_assert(L1.openupval == null); + luai_userstatefree(L1); + freestack(L, L1); + //luaM_freemem(L, fromstate(L1)); + } + + + public static lua_State lua_newstate (lua_Alloc f, object ud) { + int i; + lua_State L; + global_State g; + //object l = f(ud, null, 0, (uint)state_size(typeof(LG))); + object l = f(typeof(LG)); + if (l == null) return null; + L = tostate(l); + g = (L as LG).g; + L.next = null; + L.tt = LUA_TTHREAD; + g.currentwhite = (lu_byte)bit2mask(WHITE0BIT, FIXEDBIT); + L.marked = luaC_white(g); + lu_byte marked = L.marked; // can't pass properties in as ref + set2bits(ref marked, FIXEDBIT, SFIXEDBIT); + L.marked = marked; + preinit_state(L, g); + g.frealloc = f; + g.ud = ud; + g.mainthread = L; + g.uvhead.u.l.prev = g.uvhead; + g.uvhead.u.l.next = g.uvhead; + g.GCthreshold = 0; /* mark it as unfinished state */ + g.strt.size = 0; + g.strt.nuse = 0; + g.strt.hash = null; + setnilvalue(registry(L)); + luaZ_initbuffer(L, g.buff); + g.panic = null; + g.gcstate = GCSpause; + g.rootgc = obj2gco(L); + g.sweepstrgc = 0; + g.sweepgc = new RootGCRef(g); + g.gray = null; + g.grayagain = null; + g.weak = null; + g.tmudata = null; + g.totalbytes = (uint)GetUnmanagedSize(typeof(LG)); + g.gcpause = LUAI_GCPAUSE; + g.gcstepmul = LUAI_GCMUL; + g.gcdept = 0; + for (i=0; i MAX_SIZET /GetUnmanagedSize(typeof(char))) - luaM_toobig(L); - ts = new TString(new char[l+1]); - AddTotalBytes(L, (int)(l + 1) * GetUnmanagedSize(typeof(char)) + GetUnmanagedSize(typeof(TString))); - ts.tsv.len = l; - ts.tsv.hash = h; - ts.tsv.marked = luaC_white(G(L)); - ts.tsv.tt = LUA_TSTRING; - ts.tsv.reserved = 0; - //memcpy(ts+1, str, l*GetUnmanagedSize(typeof(char))); - memcpy(ts.str.chars, str.chars, str.index, (int)l); - ts.str[l] = '\0'; /* ending 0 */ - tb = G(L).strt; - h = (uint)lmod(h, tb.size); - ts.tsv.next = tb.hash[h]; /* chain new entry */ - tb.hash[h] = obj2gco(ts); - tb.nuse++; - if ((tb.nuse > (int)tb.size) && (tb.size <= MAX_INT/2)) - luaS_resize(L, tb.size*2); /* too crowded */ - return ts; - } - - [CLSCompliantAttribute(false)] - public static TString luaS_newlstr (lua_State L, CharPtr str, uint l) { - GCObject o; - uint h = (uint)l; /* seed */ - uint step = (l>>5)+1; /* if string is too long, don't hash all its chars */ - uint l1; - for (l1=l; l1>=step; l1-=step) /* compute hash */ - h = h ^ ((h<<5)+(h>>2)+(byte)str[l1-1]); - for (o = G(L).strt.hash[lmod(h, G(L).strt.size)]; - o != null; - o = o.gch.next) { - TString ts = rawgco2ts(o); - if (ts.tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { - /* string may be dead */ - if (isdead(G(L), o)) changewhite(o); - return ts; - } - } - //return newlstr(L, str, l, h); /* not found */ - TString res = newlstr(L, str, l, h); - return res; - } - - [CLSCompliantAttribute(false)] - public static Udata luaS_newudata(lua_State L, uint s, Table e) - { - Udata u = new Udata(); - u.uv.marked = luaC_white(G(L)); /* is not finalized */ - u.uv.tt = LUA_TUSERDATA; - u.uv.len = s; - u.uv.metatable = null; - u.uv.env = e; - u.user_data = new byte[s]; - AddTotalBytes(L, GetUnmanagedSize(typeof(Udata)) + sizeudata(u)); - /* chain it on udata list (after main thread) */ - u.uv.next = G(L).mainthread.next; - G(L).mainthread.next = obj2gco(u); - return u; - } - - internal static Udata luaS_newudata(lua_State L, Type t, Table e) - { - Udata u = new Udata(); - u.uv.marked = luaC_white(G(L)); /* is not finalized */ - u.uv.tt = LUA_TUSERDATA; - u.uv.len = 0; /* gfoot: not sizeof(t)? */ - u.uv.metatable = null; - u.uv.env = e; - u.user_data = luaM_realloc_(L, t); - AddTotalBytes(L, GetUnmanagedSize(typeof(Udata))); - /* chain it on udata list (after main thread) */ - u.uv.next = G(L).mainthread.next; - G(L).mainthread.next = obj2gco(u); - return u; - } - - } -} +/* +** $Id: lstring.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $ +** String table (keeps all strings handled by Lua) +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace KopiLua +{ + using lu_byte = System.Byte; + + public partial class Lua + { + public static int sizestring(TString s) {return ((int)s.len + 1) * GetUnmanagedSize(typeof(char)); } + + public static int sizeudata(Udata u) { return (int)u.len; } + + public static TString luaS_new(lua_State L, CharPtr s) { return luaS_newlstr(L, s, (uint)strlen(s)); } + public static TString luaS_newliteral(lua_State L, CharPtr s) { return luaS_newlstr(L, s, (uint)strlen(s)); } + + public static void luaS_fix(TString s) + { + lu_byte marked = s.tsv.marked; // can't pass properties in as ref + l_setbit(ref marked, FIXEDBIT); + s.tsv.marked = marked; + } + + public static void luaS_resize (lua_State L, int newsize) { + GCObject[] newhash; + stringtable tb; + int i; + if (G(L).gcstate == GCSsweepstring) + return; /* cannot resize during GC traverse */ + newhash = new GCObject[newsize]; + AddTotalBytes(L, newsize * GetUnmanagedSize(typeof(GCObjectRef))); + tb = G(L).strt; + for (i=0; i MAX_SIZET /GetUnmanagedSize(typeof(char))) + luaM_toobig(L); + ts = new TString(new char[l+1]); + AddTotalBytes(L, (int)(l + 1) * GetUnmanagedSize(typeof(char)) + GetUnmanagedSize(typeof(TString))); + ts.tsv.len = l; + ts.tsv.hash = h; + ts.tsv.marked = luaC_white(G(L)); + ts.tsv.tt = LUA_TSTRING; + ts.tsv.reserved = 0; + //memcpy(ts+1, str, l*GetUnmanagedSize(typeof(char))); + memcpy(ts.str.chars, str.chars, str.index, (int)l); + ts.str[l] = '\0'; /* ending 0 */ + tb = G(L).strt; + h = (uint)lmod(h, tb.size); + ts.tsv.next = tb.hash[h]; /* chain new entry */ + tb.hash[h] = obj2gco(ts); + tb.nuse++; + if ((tb.nuse > (int)tb.size) && (tb.size <= MAX_INT/2)) + luaS_resize(L, tb.size*2); /* too crowded */ + return ts; + } + + [CLSCompliantAttribute(false)] + public static TString luaS_newlstr (lua_State L, CharPtr str, uint l) { + GCObject o; + uint h = (uint)l; /* seed */ + uint step = (l>>5)+1; /* if string is too long, don't hash all its chars */ + uint l1; + for (l1=l; l1>=step; l1-=step) /* compute hash */ + h = h ^ ((h<<5)+(h>>2)+(byte)str[l1-1]); + for (o = G(L).strt.hash[lmod(h, G(L).strt.size)]; + o != null; + o = o.gch.next) { + TString ts = rawgco2ts(o); + if (ts.tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) { + /* string may be dead */ + if (isdead(G(L), o)) changewhite(o); + return ts; + } + } + //return newlstr(L, str, l, h); /* not found */ + TString res = newlstr(L, str, l, h); + return res; + } + + [CLSCompliantAttribute(false)] + public static Udata luaS_newudata(lua_State L, uint s, Table e) + { + Udata u = new Udata(); + u.uv.marked = luaC_white(G(L)); /* is not finalized */ + u.uv.tt = LUA_TUSERDATA; + u.uv.len = s; + u.uv.metatable = null; + u.uv.env = e; + u.user_data = new byte[s]; + AddTotalBytes(L, GetUnmanagedSize(typeof(Udata)) + sizeudata(u)); + /* chain it on udata list (after main thread) */ + u.uv.next = G(L).mainthread.next; + G(L).mainthread.next = obj2gco(u); + return u; + } + + internal static Udata luaS_newudata(lua_State L, Type t, Table e) + { + Udata u = new Udata(); + u.uv.marked = luaC_white(G(L)); /* is not finalized */ + u.uv.tt = LUA_TUSERDATA; + u.uv.len = 0; /* gfoot: not sizeof(t)? */ + u.uv.metatable = null; + u.uv.env = e; + u.user_data = luaM_realloc_(L, t); + AddTotalBytes(L, GetUnmanagedSize(typeof(Udata))); + /* chain it on udata list (after main thread) */ + u.uv.next = G(L).mainthread.next; + G(L).mainthread.next = obj2gco(u); + return u; + } + + } +} diff --git a/Core/KopiLua/lstrlib.cs b/Core/KopiLua/lstrlib.cs index 61389690beb1046b7282aaab6365b8b4a5b45b76..184b8e5a6f8be6a56e8a8c71b9f77ddde30cc1fa 100644 --- a/Core/KopiLua/lstrlib.cs +++ b/Core/KopiLua/lstrlib.cs @@ -1,966 +1,966 @@ -/* -** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $ -** Standard library for string operations and pattern-matching -** See Copyright Notice in lua.h -*/ - -using System; -using System.IO; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -namespace KopiLua -{ - using ptrdiff_t = System.Int32; - using lua_Integer = System.Int32; - using LUA_INTFRM_T = System.Int64; - using UNSIGNED_LUA_INTFRM_T = System.UInt64; - - public partial class Lua - { - private static int str_len (lua_State L) { - uint l; - luaL_checklstring(L, 1, out l); - lua_pushinteger(L, (int)l); - return 1; - } - - - private static ptrdiff_t posrelat (ptrdiff_t pos, uint len) { - /* relative string position: negative means back from end */ - if (pos < 0) pos += (ptrdiff_t)len + 1; - return (pos >= 0) ? pos : 0; - } - - - private static int str_sub (lua_State L) { - uint l; - CharPtr s = luaL_checklstring(L, 1, out l); - ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); - ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); - if (start < 1) start = 1; - if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; - if (start <= end) - lua_pushlstring(L, s+start-1, (uint)(end-start+1)); - else lua_pushliteral(L, ""); - return 1; - } - - - private static int str_reverse (lua_State L) { - uint l; - luaL_Buffer b = new luaL_Buffer(); - CharPtr s = luaL_checklstring(L, 1, out l); - luaL_buffinit(L, b); - while ((l--) != 0) luaL_addchar(b, s[l]); - luaL_pushresult(b); - return 1; - } - - - private static int str_lower (lua_State L) { - uint l; - uint i; - luaL_Buffer b = new luaL_Buffer(); - CharPtr s = luaL_checklstring(L, 1, out l); - luaL_buffinit(L, b); - for (i=0; i 0) - luaL_addlstring(b, s, l); - luaL_pushresult(b); - return 1; - } - - - private static int str_byte (lua_State L) { - uint l; - CharPtr s = luaL_checklstring(L, 1, out l); - ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); - ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); - int n, i; - if (posi <= 0) posi = 1; - if ((uint)pose > l) pose = (int)l; - if (posi > pose) return 0; /* empty interval; return no values */ - n = (int)(pose - posi + 1); - if (posi + n <= pose) /* overflow? */ - luaL_error(L, "string slice too long"); - luaL_checkstack(L, n, "string slice too long"); - for (i=0; i= ms.level || ms.capture[l].len == CAP_UNFINISHED) - return luaL_error(ms.L, "invalid capture index"); - return l; - } - - - private static int capture_to_close (MatchState ms) { - int level = ms.level; - for (level--; level>=0; level--) - if (ms.capture[level].len == CAP_UNFINISHED) return level; - return luaL_error(ms.L, "invalid pattern capture"); - } - - - private static CharPtr classend (MatchState ms, CharPtr p) { - p = new CharPtr(p); - char c = p[0]; - p = p.next(); - switch (c) { - case L_ESC: { - if (p[0] == '\0') - luaL_error(ms.L, "malformed pattern (ends with " + LUA_QL("%%") + ")"); - return p+1; - } - case '[': { - if (p[0] == '^') p = p.next(); - do { /* look for a `]' */ - if (p[0] == '\0') - luaL_error(ms.L, "malformed pattern (missing " + LUA_QL("]") + ")"); - c = p[0]; - p = p.next(); - if (c == L_ESC && p[0] != '\0') - p = p.next(); /* skip escapes (e.g. `%]') */ - } while (p[0] != ']'); - return p+1; - } - default: { - return p; - } - } - } - - - private static int match_class (int c, int cl) { - bool res; - switch (tolower(cl)) { - case 'a' : res = isalpha(c); break; - case 'c' : res = iscntrl(c); break; - case 'd' : res = isdigit(c); break; - case 'l' : res = islower(c); break; - case 'p' : res = ispunct(c); break; - case 's' : res = isspace(c); break; - case 'u' : res = isupper(c); break; - case 'w' : res = isalnum(c); break; - case 'x' : res = isxdigit((char)c); break; - case 'z' : res = (c == 0); break; - default: return (cl == c) ? 1 : 0; - } - return (islower(cl) ? (res ? 1 : 0) : ((!res) ? 1 : 0)); - } - - - private static int matchbracketclass (int c, CharPtr p, CharPtr ec) { - int sig = 1; - if (p[1] == '^') { - sig = 0; - p = p.next(); /* skip the `^' */ - } - while ((p=p.next()) < ec) { - if (p == L_ESC) { - p = p.next(); - if (match_class(c, (byte)(p[0])) != 0) - return sig; - } - else if ((p[1] == '-') && (p + 2 < ec)) { - p+=2; - if ((byte)((p[-2])) <= c && (c <= (byte)p[0])) - return sig; - } - else if ((byte)(p[0]) == c) return sig; - } - return (sig == 0) ? 1 : 0; - } - - - private static int singlematch (int c, CharPtr p, CharPtr ep) { - switch (p[0]) { - case '.': return 1; /* matches any char */ - case L_ESC: return match_class(c, (byte)(p[1])); - case '[': return matchbracketclass(c, p, ep-1); - default: return ((byte)(p[0]) == c) ? 1 : 0; - } - } - - - private static CharPtr matchbalance (MatchState ms, CharPtr s, - CharPtr p) { - if ((p[0] == 0) || (p[1] == 0)) - luaL_error(ms.L, "unbalanced pattern"); - if (s[0] != p[0]) return null; - else { - int b = p[0]; - int e = p[1]; - int cont = 1; - while ((s=s.next()) < ms.src_end) { - if (s[0] == e) { - if (--cont == 0) return s+1; - } - else if (s[0] == b) cont++; - } - } - return null; /* string ends out of balance */ - } - - - private static CharPtr max_expand (MatchState ms, CharPtr s, - CharPtr p, CharPtr ep) { - ptrdiff_t i = 0; /* counts maximum expand for item */ - while ( (s+i < ms.src_end) && (singlematch((byte)(s[i]), p, ep) != 0) ) - i++; - /* keeps trying to match with the maximum repetitions */ - while (i>=0) { - CharPtr res = match(ms, (s+i), ep+1); - if (res != null) return res; - i--; /* else didn't match; reduce 1 repetition to try again */ - } - return null; - } - - - private static CharPtr min_expand (MatchState ms, CharPtr s, - CharPtr p, CharPtr ep) { - for (;;) { - CharPtr res = match(ms, s, ep+1); - if (res != null) - return res; - else if ( (s < ms.src_end) && (singlematch((byte)(s[0]), p, ep) != 0) ) - s = s.next(); /* try with one more repetition */ - else return null; - } - } - - - private static CharPtr start_capture (MatchState ms, CharPtr s, - CharPtr p, int what) { - CharPtr res; - int level = ms.level; - if (level >= LUA_MAXCAPTURES) luaL_error(ms.L, "too many captures"); - ms.capture[level].init = s; - ms.capture[level].len = what; - ms.level = level+1; - if ((res=match(ms, s, p)) == null) /* match failed? */ - ms.level--; /* undo capture */ - return res; - } - - - private static CharPtr end_capture(MatchState ms, CharPtr s, - CharPtr p) { - int l = capture_to_close(ms); - CharPtr res; - ms.capture[l].len = s - ms.capture[l].init; /* close capture */ - if ((res = match(ms, s, p)) == null) /* match failed? */ - ms.capture[l].len = CAP_UNFINISHED; /* undo capture */ - return res; - } - - - private static CharPtr match_capture(MatchState ms, CharPtr s, int l) - { - uint len; - l = check_capture(ms, l); - len = (uint)ms.capture[l].len; - if ((uint)(ms.src_end-s) >= len && - memcmp(ms.capture[l].init, s, len) == 0) - return s+len; - else return null; - } - - - private static CharPtr match (MatchState ms, CharPtr s, CharPtr p) { - s = new CharPtr(s); - p = new CharPtr(p); - init: /* using goto's to optimize tail recursion */ - switch (p[0]) { - case '(': { /* start capture */ - if (p[1] == ')') /* position capture? */ - return start_capture(ms, s, p+2, CAP_POSITION); - else - return start_capture(ms, s, p+1, CAP_UNFINISHED); - } - case ')': { /* end capture */ - return end_capture(ms, s, p+1); - } - case L_ESC: { - switch (p[1]) { - case 'b': { /* balanced string? */ - s = matchbalance(ms, s, p+2); - if (s == null) return null; - p+=4; goto init; /* else return match(ms, s, p+4); */ - } - case 'f': { /* frontier? */ - CharPtr ep; char previous; - p += 2; - if (p[0] != '[') - luaL_error(ms.L, "missing " + LUA_QL("[") + " after " + - LUA_QL("%%f") + " in pattern"); - ep = classend(ms, p); /* points to what is next */ - previous = (s == ms.src_init) ? '\0' : s[-1]; - if ((matchbracketclass((byte)(previous), p, ep-1)!=0) || - (matchbracketclass((byte)(s[0]), p, ep-1)==0)) return null; - p=ep; goto init; /* else return match(ms, s, ep); */ - } - default: { - if (isdigit((byte)(p[1]))) { /* capture results (%0-%9)? */ - s = match_capture(ms, s, (byte)(p[1])); - if (s == null) return null; - p+=2; goto init; /* else return match(ms, s, p+2) */ - } - //ismeretlen hiba miatt lett ide átmásolva - { /* it is a pattern item */ - CharPtr ep = classend(ms, p); /* points to what is next */ - int m = (s l1) return null; /* avoids a negative `l1' */ - else { - CharPtr init; /* to search for a `*s2' inside `s1' */ - l2--; /* 1st char will be checked by `memchr' */ - l1 = l1-l2; /* `s2' cannot be found after that */ - while (l1 > 0 && (init = memchr(s1, s2[0], l1)) != null) { - init = init.next(); /* 1st char is already checked */ - if (memcmp(init, s2+1, l2) == 0) - return init-1; - else { /* correct `l1' and `s1' to try again */ - l1 -= (uint)(init-s1); - s1 = init; - } - } - return null; /* not found */ - } - } - - - private static void push_onecapture (MatchState ms, int i, CharPtr s, - CharPtr e) { - if (i >= ms.level) { - if (i == 0) /* ms.level == 0, too */ - lua_pushlstring(ms.L, s, (uint)(e - s)); /* add whole match */ - else - luaL_error(ms.L, "invalid capture index"); - } - else { - ptrdiff_t l = ms.capture[i].len; - if (l == CAP_UNFINISHED) luaL_error(ms.L, "unfinished capture"); - if (l == CAP_POSITION) - lua_pushinteger(ms.L, ms.capture[i].init - ms.src_init + 1); - else - lua_pushlstring(ms.L, ms.capture[i].init, (uint)l); - } - } - - - private static int push_captures (MatchState ms, CharPtr s, CharPtr e) { - int i; - int nlevels = ((ms.level == 0) && (s!=null)) ? 1 : ms.level; - luaL_checkstack(ms.L, nlevels, "too many captures"); - for (i = 0; i < nlevels; i++) - push_onecapture(ms, i, s, e); - return nlevels; /* number of strings pushed */ - } - - - private static int str_find_aux (lua_State L, int find) { - uint l1, l2; - CharPtr s = luaL_checklstring(L, 1, out l1); - CharPtr p = luaL_checklstring(L, 2, out l2); - ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; - if (init < 0) init = 0; - else if ((uint)(init) > l1) init = (ptrdiff_t)l1; - if ((find!=0) && ((lua_toboolean(L, 4)!=0) || /* explicit request? */ - strpbrk(p, SPECIALS) == null)) { /* or no special characters? */ - /* do a plain search */ - CharPtr s2 = lmemfind(s+init, (uint)(l1-init), p, (uint)(l2)); - if (s2 != null) { - lua_pushinteger(L, s2-s+1); - lua_pushinteger(L, (int)(s2-s+l2)); - return 2; - } - } - else { - MatchState ms = new MatchState(); - int anchor = 0; - if (p[0] == '^') - { - p = p.next(); - anchor = 1; - } - CharPtr s1=s+init; - ms.L = L; - ms.src_init = s; - ms.src_end = s+l1; - do { - CharPtr res; - ms.level = 0; - if ((res=match(ms, s1, p)) != null) { - if (find != 0) { - lua_pushinteger(L, s1-s+1); /* start */ - lua_pushinteger(L, res-s); /* end */ - return push_captures(ms, null, null) + 2; - } - else - return push_captures(ms, s1, res); - } - } while (((s1=s1.next()) <= ms.src_end) && (anchor==0)); - } - lua_pushnil(L); /* not found */ - return 1; - } - - - private static int str_find (lua_State L) { - return str_find_aux(L, 1); - } - - - private static int str_match (lua_State L) { - return str_find_aux(L, 0); - } - - - private static int gmatch_aux (lua_State L) { - MatchState ms = new MatchState(); - uint ls; - CharPtr s = lua_tolstring(L, lua_upvalueindex(1), out ls); - CharPtr p = lua_tostring(L, lua_upvalueindex(2)); - CharPtr src; - ms.L = L; - ms.src_init = s; - ms.src_end = s+ls; - for (src = s + (uint)lua_tointeger(L, lua_upvalueindex(3)); - src <= ms.src_end; - src = src.next()) { - CharPtr e; - ms.level = 0; - if ((e = match(ms, src, p)) != null) { - lua_Integer newstart = e-s; - if (e == src) newstart++; /* empty match? go at least one position */ - lua_pushinteger(L, newstart); - lua_replace(L, lua_upvalueindex(3)); - return push_captures(ms, src, e); - } - } - return 0; /* not found */ - } - - - private static int gmatch (lua_State L) { - luaL_checkstring(L, 1); - luaL_checkstring(L, 2); - lua_settop(L, 2); - lua_pushinteger(L, 0); - lua_pushcclosure(L, gmatch_aux, 3); - return 1; - } - - - private static int gfind_nodef (lua_State L) { - return luaL_error(L, LUA_QL("string.gfind") + " was renamed to " + - LUA_QL("string.gmatch")); - } - - - private static void add_s (MatchState ms, luaL_Buffer b, CharPtr s, - CharPtr e) { - uint l, i; - CharPtr news = lua_tolstring(ms.L, 3, out l); - for (i = 0; i < l; i++) { - if (news[i] != L_ESC) - luaL_addchar(b, news[i]); - else { - i++; /* skip ESC */ - if (!isdigit((byte)(news[i]))) - luaL_addchar(b, news[i]); - else if (news[i] == '0') - luaL_addlstring(b, s, (uint)(e - s)); - else { - push_onecapture(ms, news[i] - '1', s, e); - luaL_addvalue(b); /* add capture to accumulated result */ - } - } - } - } - - - private static void add_value (MatchState ms, luaL_Buffer b, CharPtr s, - CharPtr e) { - lua_State L = ms.L; - switch (lua_type(L, 3)) { - case LUA_TNUMBER: - case LUA_TSTRING: { - add_s(ms, b, s, e); - return; - } - case LUA_TUSERDATA: - case LUA_TFUNCTION: { - int n; - lua_pushvalue(L, 3); - n = push_captures(ms, s, e); - lua_call(L, n, 1); - break; - } - case LUA_TTABLE: { - push_onecapture(ms, 0, s, e); - lua_gettable(L, 3); - break; - } - } - if (lua_toboolean(L, -1)==0) { /* nil or false? */ - lua_pop(L, 1); - lua_pushlstring(L, s, (uint)(e - s)); /* keep original text */ - } - else if (lua_isstring(L, -1)==0) - luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); - luaL_addvalue(b); /* add result to accumulator */ - } - - - private static int str_gsub (lua_State L) { - uint srcl; - CharPtr src = luaL_checklstring(L, 1, out srcl); - CharPtr p = luaL_checkstring(L, 2); - int tr = lua_type(L, 3); - int max_s = luaL_optint(L, 4, (int)(srcl+1)); - int anchor = 0; - if (p[0] == '^') - { - p = p.next(); - anchor = 1; - } - int n = 0; - MatchState ms = new MatchState(); - luaL_Buffer b = new luaL_Buffer(); - luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || - tr == LUA_TFUNCTION || tr == LUA_TTABLE || - tr == LUA_TUSERDATA, 3, - "string/function/table expected"); - luaL_buffinit(L, b); - ms.L = L; - ms.src_init = src; - ms.src_end = src+srcl; - while (n < max_s) { - CharPtr e; - ms.level = 0; - e = match(ms, src, p); - if (e != null) { - n++; - add_value(ms, b, src, e); - } - if ((e!=null) && e>src) /* non empty match? */ - src = e; /* skip it */ - else if (src < ms.src_end) - { - char c = src[0]; - src = src.next(); - luaL_addchar(b, c); - } - else break; - if (anchor != 0) break; - } - luaL_addlstring(b, src, (uint)(ms.src_end-src)); - luaL_pushresult(b); - lua_pushinteger(L, n); /* number of substitutions */ - return 2; - } - - /* }====================================================== */ - - - /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ - public const int MAX_ITEM = 512; - /* valid flags in a format specification */ - public const string FLAGS = "-+ #0"; - /* - ** maximum size of each format specification (such as '%-099.99d') - ** (+10 accounts for %99.99x plus margin of error) - */ - public static readonly int MAX_FORMAT = (FLAGS.Length+1) + (LUA_INTFRMLEN.Length+1) + 10; - - - private static void addquoted (lua_State L, luaL_Buffer b, int arg) { - uint l; - CharPtr s = luaL_checklstring(L, arg, out l); - luaL_addchar(b, '"'); - while ((l--) != 0) { - switch (s[0]) { - case '"': case '\\': case '\n': { - luaL_addchar(b, '\\'); - luaL_addchar(b, s[0]); - break; - } - case '\r': { - luaL_addlstring(b, "\\r", 2); - break; - } - case '\0': { - luaL_addlstring(b, "\\000", 4); - break; - } - default: { - luaL_addchar(b, s[0]); - break; - } - } - s = s.next(); - } - luaL_addchar(b, '"'); - } - - private static CharPtr scanformat (lua_State L, CharPtr strfrmt, CharPtr form) { - CharPtr p = strfrmt; - while (p[0] != '\0' && strchr(FLAGS, p[0]) != null) p = p.next(); /* skip flags */ - if ((uint)(p - strfrmt) >= (FLAGS.Length+1)) - luaL_error(L, "invalid format (repeated flags)"); - if (isdigit((byte)(p[0]))) p = p.next(); /* skip width */ - if (isdigit((byte)(p[0]))) p = p.next(); /* (2 digits at most) */ - if (p[0] == '.') { - p = p.next(); - if (isdigit((byte)(p[0]))) p = p.next(); /* skip precision */ - if (isdigit((byte)(p[0]))) p = p.next(); /* (2 digits at most) */ - } - if (isdigit((byte)(p[0]))) - luaL_error(L, "invalid format (width or precision too long)"); - form[0] = '%'; - form = form.next(); - strncpy(form, strfrmt, p - strfrmt + 1); - form += p - strfrmt + 1; - form[0] = '\0'; - return p; - } - - - private static void addintlen (CharPtr form) { - uint l = (uint)strlen(form); - char spec = form[l - 1]; - strcpy(form + l - 1, LUA_INTFRMLEN); - form[l + (LUA_INTFRMLEN.Length + 1) - 2] = spec; - form[l + (LUA_INTFRMLEN.Length + 1) - 1] = '\0'; - } - - - private static int str_format (lua_State L) { - int arg = 1; - uint sfl; - CharPtr strfrmt = luaL_checklstring(L, arg, out sfl); - CharPtr strfrmt_end = strfrmt+sfl; - luaL_Buffer b = new luaL_Buffer(); - luaL_buffinit(L, b); - while (strfrmt < strfrmt_end) { - if (strfrmt[0] != L_ESC) - { - luaL_addchar(b, strfrmt[0]); - strfrmt = strfrmt.next(); - } - else if (strfrmt[1] == L_ESC) - { - luaL_addchar(b, strfrmt[0]); /* %% */ - strfrmt = strfrmt + 2; - } - else - { /* format item */ - strfrmt = strfrmt.next(); - CharPtr form = new char[MAX_FORMAT]; /* to store the format (`%...') */ - CharPtr buff = new char[MAX_ITEM]; /* to store the formatted item */ - arg++; - strfrmt = scanformat(L, strfrmt, form); - char ch = strfrmt[0]; - strfrmt = strfrmt.next(); - switch (ch) - { - case 'c': - { - sprintf(buff, form, (int)luaL_checknumber(L, arg)); - break; - } - case 'd': - case 'i': - { - addintlen(form); - sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); - break; - } - case 'o': - case 'u': - case 'x': - case 'X': - { - addintlen(form); - sprintf(buff, form, (UNSIGNED_LUA_INTFRM_T)luaL_checknumber(L, arg)); - break; - } - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - { - sprintf(buff, form, (double)luaL_checknumber(L, arg)); - break; - } - case 'q': - { - addquoted(L, b, arg); - continue; /* skip the 'addsize' at the end */ - } - case 's': - { - uint l; - CharPtr s = luaL_checklstring(L, arg, out l); - if ((strchr(form, '.') == null) && l >= 100) - { - /* no precision and string is too long to be formatted; - keep original string */ - lua_pushvalue(L, arg); - luaL_addvalue(b); - continue; /* skip the `addsize' at the end */ - } - else - { - sprintf(buff, form, s); - break; - } - } - default: - { /* also treat cases `pnLlh' */ - return luaL_error(L, "invalid option " + LUA_QL("%%%c") + " to " + - LUA_QL("format"), strfrmt[-1]); - } - } - luaL_addlstring(b, buff, (uint)strlen(buff)); - } - } - luaL_pushresult(b); - return 1; - } - - - private readonly static luaL_Reg[] strlib = { - new luaL_Reg("byte", str_byte), - new luaL_Reg("char", str_char), - new luaL_Reg("dump", str_dump), - new luaL_Reg("find", str_find), - new luaL_Reg("format", str_format), - new luaL_Reg("gfind", gfind_nodef), - new luaL_Reg("gmatch", gmatch), - new luaL_Reg("gsub", str_gsub), - new luaL_Reg("len", str_len), - new luaL_Reg("lower", str_lower), - new luaL_Reg("match", str_match), - new luaL_Reg("rep", str_rep), - new luaL_Reg("reverse", str_reverse), - new luaL_Reg("sub", str_sub), - new luaL_Reg("upper", str_upper), - new luaL_Reg(null, null) - }; - - - private static void createmetatable (lua_State L) { - lua_createtable(L, 0, 1); /* create metatable for strings */ - lua_pushliteral(L, ""); /* dummy string */ - lua_pushvalue(L, -2); - lua_setmetatable(L, -2); /* set string metatable */ - lua_pop(L, 1); /* pop dummy string */ - lua_pushvalue(L, -2); /* string library... */ - lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ - lua_pop(L, 1); /* pop metatable */ - } - - - /* - ** Open string library - */ - public static int luaopen_string (lua_State L) { - luaL_register(L, LUA_STRLIBNAME, strlib); - #if LUA_COMPAT_GFIND - lua_getfield(L, -1, "gmatch"); - lua_setfield(L, -2, "gfind"); - #endif - createmetatable(L); - return 1; - } - - } -} +/* +** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $ +** Standard library for string operations and pattern-matching +** See Copyright Notice in lua.h +*/ + +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace KopiLua +{ + using ptrdiff_t = System.Int32; + using lua_Integer = System.Int32; + using LUA_INTFRM_T = System.Int64; + using UNSIGNED_LUA_INTFRM_T = System.UInt64; + + public partial class Lua + { + private static int str_len (lua_State L) { + uint l; + luaL_checklstring(L, 1, out l); + lua_pushinteger(L, (int)l); + return 1; + } + + + private static ptrdiff_t posrelat (ptrdiff_t pos, uint len) { + /* relative string position: negative means back from end */ + if (pos < 0) pos += (ptrdiff_t)len + 1; + return (pos >= 0) ? pos : 0; + } + + + private static int str_sub (lua_State L) { + uint l; + CharPtr s = luaL_checklstring(L, 1, out l); + ptrdiff_t start = posrelat(luaL_checkinteger(L, 2), l); + ptrdiff_t end = posrelat(luaL_optinteger(L, 3, -1), l); + if (start < 1) start = 1; + if (end > (ptrdiff_t)l) end = (ptrdiff_t)l; + if (start <= end) + lua_pushlstring(L, s+start-1, (uint)(end-start+1)); + else lua_pushliteral(L, ""); + return 1; + } + + + private static int str_reverse (lua_State L) { + uint l; + luaL_Buffer b = new luaL_Buffer(); + CharPtr s = luaL_checklstring(L, 1, out l); + luaL_buffinit(L, b); + while ((l--) != 0) luaL_addchar(b, s[l]); + luaL_pushresult(b); + return 1; + } + + + private static int str_lower (lua_State L) { + uint l; + uint i; + luaL_Buffer b = new luaL_Buffer(); + CharPtr s = luaL_checklstring(L, 1, out l); + luaL_buffinit(L, b); + for (i=0; i 0) + luaL_addlstring(b, s, l); + luaL_pushresult(b); + return 1; + } + + + private static int str_byte (lua_State L) { + uint l; + CharPtr s = luaL_checklstring(L, 1, out l); + ptrdiff_t posi = posrelat(luaL_optinteger(L, 2, 1), l); + ptrdiff_t pose = posrelat(luaL_optinteger(L, 3, posi), l); + int n, i; + if (posi <= 0) posi = 1; + if ((uint)pose > l) pose = (int)l; + if (posi > pose) return 0; /* empty interval; return no values */ + n = (int)(pose - posi + 1); + if (posi + n <= pose) /* overflow? */ + luaL_error(L, "string slice too long"); + luaL_checkstack(L, n, "string slice too long"); + for (i=0; i= ms.level || ms.capture[l].len == CAP_UNFINISHED) + return luaL_error(ms.L, "invalid capture index"); + return l; + } + + + private static int capture_to_close (MatchState ms) { + int level = ms.level; + for (level--; level>=0; level--) + if (ms.capture[level].len == CAP_UNFINISHED) return level; + return luaL_error(ms.L, "invalid pattern capture"); + } + + + private static CharPtr classend (MatchState ms, CharPtr p) { + p = new CharPtr(p); + char c = p[0]; + p = p.next(); + switch (c) { + case L_ESC: { + if (p[0] == '\0') + luaL_error(ms.L, "malformed pattern (ends with " + LUA_QL("%%") + ")"); + return p+1; + } + case '[': { + if (p[0] == '^') p = p.next(); + do { /* look for a `]' */ + if (p[0] == '\0') + luaL_error(ms.L, "malformed pattern (missing " + LUA_QL("]") + ")"); + c = p[0]; + p = p.next(); + if (c == L_ESC && p[0] != '\0') + p = p.next(); /* skip escapes (e.g. `%]') */ + } while (p[0] != ']'); + return p+1; + } + default: { + return p; + } + } + } + + + private static int match_class (int c, int cl) { + bool res; + switch (tolower(cl)) { + case 'a' : res = isalpha(c); break; + case 'c' : res = iscntrl(c); break; + case 'd' : res = isdigit(c); break; + case 'l' : res = islower(c); break; + case 'p' : res = ispunct(c); break; + case 's' : res = isspace(c); break; + case 'u' : res = isupper(c); break; + case 'w' : res = isalnum(c); break; + case 'x' : res = isxdigit((char)c); break; + case 'z' : res = (c == 0); break; + default: return (cl == c) ? 1 : 0; + } + return (islower(cl) ? (res ? 1 : 0) : ((!res) ? 1 : 0)); + } + + + private static int matchbracketclass (int c, CharPtr p, CharPtr ec) { + int sig = 1; + if (p[1] == '^') { + sig = 0; + p = p.next(); /* skip the `^' */ + } + while ((p=p.next()) < ec) { + if (p == L_ESC) { + p = p.next(); + if (match_class(c, (byte)(p[0])) != 0) + return sig; + } + else if ((p[1] == '-') && (p + 2 < ec)) { + p+=2; + if ((byte)((p[-2])) <= c && (c <= (byte)p[0])) + return sig; + } + else if ((byte)(p[0]) == c) return sig; + } + return (sig == 0) ? 1 : 0; + } + + + private static int singlematch (int c, CharPtr p, CharPtr ep) { + switch (p[0]) { + case '.': return 1; /* matches any char */ + case L_ESC: return match_class(c, (byte)(p[1])); + case '[': return matchbracketclass(c, p, ep-1); + default: return ((byte)(p[0]) == c) ? 1 : 0; + } + } + + + private static CharPtr matchbalance (MatchState ms, CharPtr s, + CharPtr p) { + if ((p[0] == 0) || (p[1] == 0)) + luaL_error(ms.L, "unbalanced pattern"); + if (s[0] != p[0]) return null; + else { + int b = p[0]; + int e = p[1]; + int cont = 1; + while ((s=s.next()) < ms.src_end) { + if (s[0] == e) { + if (--cont == 0) return s+1; + } + else if (s[0] == b) cont++; + } + } + return null; /* string ends out of balance */ + } + + + private static CharPtr max_expand (MatchState ms, CharPtr s, + CharPtr p, CharPtr ep) { + ptrdiff_t i = 0; /* counts maximum expand for item */ + while ( (s+i < ms.src_end) && (singlematch((byte)(s[i]), p, ep) != 0) ) + i++; + /* keeps trying to match with the maximum repetitions */ + while (i>=0) { + CharPtr res = match(ms, (s+i), ep+1); + if (res != null) return res; + i--; /* else didn't match; reduce 1 repetition to try again */ + } + return null; + } + + + private static CharPtr min_expand (MatchState ms, CharPtr s, + CharPtr p, CharPtr ep) { + for (;;) { + CharPtr res = match(ms, s, ep+1); + if (res != null) + return res; + else if ( (s < ms.src_end) && (singlematch((byte)(s[0]), p, ep) != 0) ) + s = s.next(); /* try with one more repetition */ + else return null; + } + } + + + private static CharPtr start_capture (MatchState ms, CharPtr s, + CharPtr p, int what) { + CharPtr res; + int level = ms.level; + if (level >= LUA_MAXCAPTURES) luaL_error(ms.L, "too many captures"); + ms.capture[level].init = s; + ms.capture[level].len = what; + ms.level = level+1; + if ((res=match(ms, s, p)) == null) /* match failed? */ + ms.level--; /* undo capture */ + return res; + } + + + private static CharPtr end_capture(MatchState ms, CharPtr s, + CharPtr p) { + int l = capture_to_close(ms); + CharPtr res; + ms.capture[l].len = s - ms.capture[l].init; /* close capture */ + if ((res = match(ms, s, p)) == null) /* match failed? */ + ms.capture[l].len = CAP_UNFINISHED; /* undo capture */ + return res; + } + + + private static CharPtr match_capture(MatchState ms, CharPtr s, int l) + { + uint len; + l = check_capture(ms, l); + len = (uint)ms.capture[l].len; + if ((uint)(ms.src_end-s) >= len && + memcmp(ms.capture[l].init, s, len) == 0) + return s+len; + else return null; + } + + + private static CharPtr match (MatchState ms, CharPtr s, CharPtr p) { + s = new CharPtr(s); + p = new CharPtr(p); + init: /* using goto's to optimize tail recursion */ + switch (p[0]) { + case '(': { /* start capture */ + if (p[1] == ')') /* position capture? */ + return start_capture(ms, s, p+2, CAP_POSITION); + else + return start_capture(ms, s, p+1, CAP_UNFINISHED); + } + case ')': { /* end capture */ + return end_capture(ms, s, p+1); + } + case L_ESC: { + switch (p[1]) { + case 'b': { /* balanced string? */ + s = matchbalance(ms, s, p+2); + if (s == null) return null; + p+=4; goto init; /* else return match(ms, s, p+4); */ + } + case 'f': { /* frontier? */ + CharPtr ep; char previous; + p += 2; + if (p[0] != '[') + luaL_error(ms.L, "missing " + LUA_QL("[") + " after " + + LUA_QL("%%f") + " in pattern"); + ep = classend(ms, p); /* points to what is next */ + previous = (s == ms.src_init) ? '\0' : s[-1]; + if ((matchbracketclass((byte)(previous), p, ep-1)!=0) || + (matchbracketclass((byte)(s[0]), p, ep-1)==0)) return null; + p=ep; goto init; /* else return match(ms, s, ep); */ + } + default: { + if (isdigit((byte)(p[1]))) { /* capture results (%0-%9)? */ + s = match_capture(ms, s, (byte)(p[1])); + if (s == null) return null; + p+=2; goto init; /* else return match(ms, s, p+2) */ + } + //ismeretlen hiba miatt lett ide átmásolva + { /* it is a pattern item */ + CharPtr ep = classend(ms, p); /* points to what is next */ + int m = (s l1) return null; /* avoids a negative `l1' */ + else { + CharPtr init; /* to search for a `*s2' inside `s1' */ + l2--; /* 1st char will be checked by `memchr' */ + l1 = l1-l2; /* `s2' cannot be found after that */ + while (l1 > 0 && (init = memchr(s1, s2[0], l1)) != null) { + init = init.next(); /* 1st char is already checked */ + if (memcmp(init, s2+1, l2) == 0) + return init-1; + else { /* correct `l1' and `s1' to try again */ + l1 -= (uint)(init-s1); + s1 = init; + } + } + return null; /* not found */ + } + } + + + private static void push_onecapture (MatchState ms, int i, CharPtr s, + CharPtr e) { + if (i >= ms.level) { + if (i == 0) /* ms.level == 0, too */ + lua_pushlstring(ms.L, s, (uint)(e - s)); /* add whole match */ + else + luaL_error(ms.L, "invalid capture index"); + } + else { + ptrdiff_t l = ms.capture[i].len; + if (l == CAP_UNFINISHED) luaL_error(ms.L, "unfinished capture"); + if (l == CAP_POSITION) + lua_pushinteger(ms.L, ms.capture[i].init - ms.src_init + 1); + else + lua_pushlstring(ms.L, ms.capture[i].init, (uint)l); + } + } + + + private static int push_captures (MatchState ms, CharPtr s, CharPtr e) { + int i; + int nlevels = ((ms.level == 0) && (s!=null)) ? 1 : ms.level; + luaL_checkstack(ms.L, nlevels, "too many captures"); + for (i = 0; i < nlevels; i++) + push_onecapture(ms, i, s, e); + return nlevels; /* number of strings pushed */ + } + + + private static int str_find_aux (lua_State L, int find) { + uint l1, l2; + CharPtr s = luaL_checklstring(L, 1, out l1); + CharPtr p = luaL_checklstring(L, 2, out l2); + ptrdiff_t init = posrelat(luaL_optinteger(L, 3, 1), l1) - 1; + if (init < 0) init = 0; + else if ((uint)(init) > l1) init = (ptrdiff_t)l1; + if ((find!=0) && ((lua_toboolean(L, 4)!=0) || /* explicit request? */ + strpbrk(p, SPECIALS) == null)) { /* or no special characters? */ + /* do a plain search */ + CharPtr s2 = lmemfind(s+init, (uint)(l1-init), p, (uint)(l2)); + if (s2 != null) { + lua_pushinteger(L, s2-s+1); + lua_pushinteger(L, (int)(s2-s+l2)); + return 2; + } + } + else { + MatchState ms = new MatchState(); + int anchor = 0; + if (p[0] == '^') + { + p = p.next(); + anchor = 1; + } + CharPtr s1=s+init; + ms.L = L; + ms.src_init = s; + ms.src_end = s+l1; + do { + CharPtr res; + ms.level = 0; + if ((res=match(ms, s1, p)) != null) { + if (find != 0) { + lua_pushinteger(L, s1-s+1); /* start */ + lua_pushinteger(L, res-s); /* end */ + return push_captures(ms, null, null) + 2; + } + else + return push_captures(ms, s1, res); + } + } while (((s1=s1.next()) <= ms.src_end) && (anchor==0)); + } + lua_pushnil(L); /* not found */ + return 1; + } + + + private static int str_find (lua_State L) { + return str_find_aux(L, 1); + } + + + private static int str_match (lua_State L) { + return str_find_aux(L, 0); + } + + + private static int gmatch_aux (lua_State L) { + MatchState ms = new MatchState(); + uint ls; + CharPtr s = lua_tolstring(L, lua_upvalueindex(1), out ls); + CharPtr p = lua_tostring(L, lua_upvalueindex(2)); + CharPtr src; + ms.L = L; + ms.src_init = s; + ms.src_end = s+ls; + for (src = s + (uint)lua_tointeger(L, lua_upvalueindex(3)); + src <= ms.src_end; + src = src.next()) { + CharPtr e; + ms.level = 0; + if ((e = match(ms, src, p)) != null) { + lua_Integer newstart = e-s; + if (e == src) newstart++; /* empty match? go at least one position */ + lua_pushinteger(L, newstart); + lua_replace(L, lua_upvalueindex(3)); + return push_captures(ms, src, e); + } + } + return 0; /* not found */ + } + + + private static int gmatch (lua_State L) { + luaL_checkstring(L, 1); + luaL_checkstring(L, 2); + lua_settop(L, 2); + lua_pushinteger(L, 0); + lua_pushcclosure(L, gmatch_aux, 3); + return 1; + } + + + private static int gfind_nodef (lua_State L) { + return luaL_error(L, LUA_QL("string.gfind") + " was renamed to " + + LUA_QL("string.gmatch")); + } + + + private static void add_s (MatchState ms, luaL_Buffer b, CharPtr s, + CharPtr e) { + uint l, i; + CharPtr news = lua_tolstring(ms.L, 3, out l); + for (i = 0; i < l; i++) { + if (news[i] != L_ESC) + luaL_addchar(b, news[i]); + else { + i++; /* skip ESC */ + if (!isdigit((byte)(news[i]))) + luaL_addchar(b, news[i]); + else if (news[i] == '0') + luaL_addlstring(b, s, (uint)(e - s)); + else { + push_onecapture(ms, news[i] - '1', s, e); + luaL_addvalue(b); /* add capture to accumulated result */ + } + } + } + } + + + private static void add_value (MatchState ms, luaL_Buffer b, CharPtr s, + CharPtr e) { + lua_State L = ms.L; + switch (lua_type(L, 3)) { + case LUA_TNUMBER: + case LUA_TSTRING: { + add_s(ms, b, s, e); + return; + } + case LUA_TUSERDATA: + case LUA_TFUNCTION: { + int n; + lua_pushvalue(L, 3); + n = push_captures(ms, s, e); + lua_call(L, n, 1); + break; + } + case LUA_TTABLE: { + push_onecapture(ms, 0, s, e); + lua_gettable(L, 3); + break; + } + } + if (lua_toboolean(L, -1)==0) { /* nil or false? */ + lua_pop(L, 1); + lua_pushlstring(L, s, (uint)(e - s)); /* keep original text */ + } + else if (lua_isstring(L, -1)==0) + luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); + luaL_addvalue(b); /* add result to accumulator */ + } + + + private static int str_gsub (lua_State L) { + uint srcl; + CharPtr src = luaL_checklstring(L, 1, out srcl); + CharPtr p = luaL_checkstring(L, 2); + int tr = lua_type(L, 3); + int max_s = luaL_optint(L, 4, (int)(srcl+1)); + int anchor = 0; + if (p[0] == '^') + { + p = p.next(); + anchor = 1; + } + int n = 0; + MatchState ms = new MatchState(); + luaL_Buffer b = new luaL_Buffer(); + luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || + tr == LUA_TFUNCTION || tr == LUA_TTABLE || + tr == LUA_TUSERDATA, 3, + "string/function/table expected"); + luaL_buffinit(L, b); + ms.L = L; + ms.src_init = src; + ms.src_end = src+srcl; + while (n < max_s) { + CharPtr e; + ms.level = 0; + e = match(ms, src, p); + if (e != null) { + n++; + add_value(ms, b, src, e); + } + if ((e!=null) && e>src) /* non empty match? */ + src = e; /* skip it */ + else if (src < ms.src_end) + { + char c = src[0]; + src = src.next(); + luaL_addchar(b, c); + } + else break; + if (anchor != 0) break; + } + luaL_addlstring(b, src, (uint)(ms.src_end-src)); + luaL_pushresult(b); + lua_pushinteger(L, n); /* number of substitutions */ + return 2; + } + + /* }====================================================== */ + + + /* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */ + public const int MAX_ITEM = 512; + /* valid flags in a format specification */ + public const string FLAGS = "-+ #0"; + /* + ** maximum size of each format specification (such as '%-099.99d') + ** (+10 accounts for %99.99x plus margin of error) + */ + public static readonly int MAX_FORMAT = (FLAGS.Length+1) + (LUA_INTFRMLEN.Length+1) + 10; + + + private static void addquoted (lua_State L, luaL_Buffer b, int arg) { + uint l; + CharPtr s = luaL_checklstring(L, arg, out l); + luaL_addchar(b, '"'); + while ((l--) != 0) { + switch (s[0]) { + case '"': case '\\': case '\n': { + luaL_addchar(b, '\\'); + luaL_addchar(b, s[0]); + break; + } + case '\r': { + luaL_addlstring(b, "\\r", 2); + break; + } + case '\0': { + luaL_addlstring(b, "\\000", 4); + break; + } + default: { + luaL_addchar(b, s[0]); + break; + } + } + s = s.next(); + } + luaL_addchar(b, '"'); + } + + private static CharPtr scanformat (lua_State L, CharPtr strfrmt, CharPtr form) { + CharPtr p = strfrmt; + while (p[0] != '\0' && strchr(FLAGS, p[0]) != null) p = p.next(); /* skip flags */ + if ((uint)(p - strfrmt) >= (FLAGS.Length+1)) + luaL_error(L, "invalid format (repeated flags)"); + if (isdigit((byte)(p[0]))) p = p.next(); /* skip width */ + if (isdigit((byte)(p[0]))) p = p.next(); /* (2 digits at most) */ + if (p[0] == '.') { + p = p.next(); + if (isdigit((byte)(p[0]))) p = p.next(); /* skip precision */ + if (isdigit((byte)(p[0]))) p = p.next(); /* (2 digits at most) */ + } + if (isdigit((byte)(p[0]))) + luaL_error(L, "invalid format (width or precision too long)"); + form[0] = '%'; + form = form.next(); + strncpy(form, strfrmt, p - strfrmt + 1); + form += p - strfrmt + 1; + form[0] = '\0'; + return p; + } + + + private static void addintlen (CharPtr form) { + uint l = (uint)strlen(form); + char spec = form[l - 1]; + strcpy(form + l - 1, LUA_INTFRMLEN); + form[l + (LUA_INTFRMLEN.Length + 1) - 2] = spec; + form[l + (LUA_INTFRMLEN.Length + 1) - 1] = '\0'; + } + + + private static int str_format (lua_State L) { + int arg = 1; + uint sfl; + CharPtr strfrmt = luaL_checklstring(L, arg, out sfl); + CharPtr strfrmt_end = strfrmt+sfl; + luaL_Buffer b = new luaL_Buffer(); + luaL_buffinit(L, b); + while (strfrmt < strfrmt_end) { + if (strfrmt[0] != L_ESC) + { + luaL_addchar(b, strfrmt[0]); + strfrmt = strfrmt.next(); + } + else if (strfrmt[1] == L_ESC) + { + luaL_addchar(b, strfrmt[0]); /* %% */ + strfrmt = strfrmt + 2; + } + else + { /* format item */ + strfrmt = strfrmt.next(); + CharPtr form = new char[MAX_FORMAT]; /* to store the format (`%...') */ + CharPtr buff = new char[MAX_ITEM]; /* to store the formatted item */ + arg++; + strfrmt = scanformat(L, strfrmt, form); + char ch = strfrmt[0]; + strfrmt = strfrmt.next(); + switch (ch) + { + case 'c': + { + sprintf(buff, form, (int)luaL_checknumber(L, arg)); + break; + } + case 'd': + case 'i': + { + addintlen(form); + sprintf(buff, form, (LUA_INTFRM_T)luaL_checknumber(L, arg)); + break; + } + case 'o': + case 'u': + case 'x': + case 'X': + { + addintlen(form); + sprintf(buff, form, (UNSIGNED_LUA_INTFRM_T)luaL_checknumber(L, arg)); + break; + } + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + { + sprintf(buff, form, (double)luaL_checknumber(L, arg)); + break; + } + case 'q': + { + addquoted(L, b, arg); + continue; /* skip the 'addsize' at the end */ + } + case 's': + { + uint l; + CharPtr s = luaL_checklstring(L, arg, out l); + if ((strchr(form, '.') == null) && l >= 100) + { + /* no precision and string is too long to be formatted; + keep original string */ + lua_pushvalue(L, arg); + luaL_addvalue(b); + continue; /* skip the `addsize' at the end */ + } + else + { + sprintf(buff, form, s); + break; + } + } + default: + { /* also treat cases `pnLlh' */ + return luaL_error(L, "invalid option " + LUA_QL("%%%c") + " to " + + LUA_QL("format"), strfrmt[-1]); + } + } + luaL_addlstring(b, buff, (uint)strlen(buff)); + } + } + luaL_pushresult(b); + return 1; + } + + + private readonly static luaL_Reg[] strlib = { + new luaL_Reg("byte", str_byte), + new luaL_Reg("char", str_char), + new luaL_Reg("dump", str_dump), + new luaL_Reg("find", str_find), + new luaL_Reg("format", str_format), + new luaL_Reg("gfind", gfind_nodef), + new luaL_Reg("gmatch", gmatch), + new luaL_Reg("gsub", str_gsub), + new luaL_Reg("len", str_len), + new luaL_Reg("lower", str_lower), + new luaL_Reg("match", str_match), + new luaL_Reg("rep", str_rep), + new luaL_Reg("reverse", str_reverse), + new luaL_Reg("sub", str_sub), + new luaL_Reg("upper", str_upper), + new luaL_Reg(null, null) + }; + + + private static void createmetatable (lua_State L) { + lua_createtable(L, 0, 1); /* create metatable for strings */ + lua_pushliteral(L, ""); /* dummy string */ + lua_pushvalue(L, -2); + lua_setmetatable(L, -2); /* set string metatable */ + lua_pop(L, 1); /* pop dummy string */ + lua_pushvalue(L, -2); /* string library... */ + lua_setfield(L, -2, "__index"); /* ...is the __index metamethod */ + lua_pop(L, 1); /* pop metatable */ + } + + + /* + ** Open string library + */ + public static int luaopen_string (lua_State L) { + luaL_register(L, LUA_STRLIBNAME, strlib); + #if LUA_COMPAT_GFIND + lua_getfield(L, -1, "gmatch"); + lua_setfield(L, -2, "gfind"); + #endif + createmetatable(L); + return 1; + } + + } +} diff --git a/Core/KopiLua/ltable.cs b/Core/KopiLua/ltable.cs index ef9369e1384ee330d867bbc315fbd5bf10242d42..18124ef6b8ae8b31a4672887d9c7ad40bb625eca 100644 --- a/Core/KopiLua/ltable.cs +++ b/Core/KopiLua/ltable.cs @@ -1,600 +1,600 @@ -/* -** $Id: ltable.c,v 2.32.1.2 2007/12/28 15:32:23 roberto Exp $ -** Lua tables (hash) -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace KopiLua -{ - using TValue = Lua.lua_TValue; - using StkId = Lua.lua_TValue; - using lua_Number = System.Double; - - public partial class Lua - { - /* - ** Implementation of tables (aka arrays, objects, or hash tables). - ** Tables keep its elements in two parts: an array part and a hash part. - ** Non-negative integer keys are all candidates to be kept in the array - ** part. The actual size of the array is the largest `n' such that at - ** least half the slots between 0 and n are in use. - ** Hash uses a mix of chained scatter table with Brent's variation. - ** A main invariant of these tables is that, if an element is not - ** in its main position (i.e. the `original' position that its hash gives - ** to it), then the colliding element is in its own main position. - ** Hence even when the load factor reaches 100%, performance remains good. - */ - - internal static Node gnode(Table t, int i) { return t.node[i]; } - internal static TKey_nk gkey(Node n) { return n.i_key.nk; } - internal static TValue gval(Node n) { return n.i_val; } - internal static Node gnext(Node n) { return n.i_key.nk.next; } - - internal static void gnext_set(Node n, Node v) { n.i_key.nk.next = v; } - - internal static TValue key2tval(Node n) { return n.i_key.tvk; } - - - /* - ** max size of array part is 2^MAXBITS - */ - //#if LUAI_BITSINT > 26 - public const int MAXBITS = 26; /* in the dotnet port LUAI_BITSINT is 32 */ - //#else - //public const int MAXBITS = (LUAI_BITSINT-2); - //#endif - - public const int MAXASIZE = (1 << MAXBITS); - - - //public static Node gnode(Table t, int i) {return t.node[i];} - internal static Node hashpow2(Table t, lua_Number n) { return gnode(t, (int)lmod(n, sizenode(t))); } - - public static Node hashstr(Table t, TString str) {return hashpow2(t, str.tsv.hash);} - public static Node hashboolean(Table t, int p) {return hashpow2(t, p);} - - - /* - ** for some types, it is better to avoid modulus by power of 2, as - ** they tend to have many 2 factors. - */ - public static Node hashmod(Table t, int n) { return gnode(t, (int)((uint)n % ((sizenode(t) - 1) | 1))); } - - public static Node hashpointer(Table t, object p) { return hashmod(t, p.GetHashCode()); } - - - /* - ** number of ints inside a lua_Number - */ - public const int numints = sizeof(lua_Number) / sizeof(int); - - - //static const Node dummynode_ = { - //{{null}, LUA_TNIL}, /* value */ - //{{{null}, LUA_TNIL, null}} /* key */ - //}; - public static Node dummynode_ = new Node(new TValue(new Value(), LUA_TNIL), new TKey(new Value(), LUA_TNIL, null)); - public static Node dummynode = dummynode_; - - /* - ** hash for lua_Numbers - */ - private static Node hashnum (Table t, lua_Number n) { - byte[] a = BitConverter.GetBytes(n); - for (int i = 1; i < a.Length; i++) a[0] += a[i]; - return hashmod(t, (int)a[0]); - } - - - - /* - ** returns the `main' position of an element in a table (that is, the index - ** of its hash value) - */ - private static Node mainposition (Table t, TValue key) { - switch (ttype(key)) { - case LUA_TNUMBER: - return hashnum(t, nvalue(key)); - case LUA_TSTRING: - return hashstr(t, rawtsvalue(key)); - case LUA_TBOOLEAN: - return hashboolean(t, bvalue(key)); - case LUA_TLIGHTUSERDATA: - return hashpointer(t, pvalue(key)); - default: - return hashpointer(t, gcvalue(key)); - } - } - - - /* - ** returns the index for `key' if `key' is an appropriate key to live in - ** the array part of the table, -1 otherwise. - */ - private static int arrayindex (TValue key) { - if (ttisnumber(key)) { - lua_Number n = nvalue(key); - int k; - lua_number2int(out k, n); - if (luai_numeq(cast_num(k), n)) - return k; - } - return -1; /* `key' did not match some condition */ - } - - - /* - ** returns the index of a `key' for table traversals. First goes all - ** elements in the array part, then elements in the hash part. The - ** beginning of a traversal is signalled by -1. - */ - private static int findindex (lua_State L, Table t, StkId key) { - int i; - if (ttisnil(key)) return -1; /* first iteration */ - i = arrayindex(key); - if (0 < i && i <= t.sizearray) /* is `key' inside array part? */ - return i-1; /* yes; that's the index (corrected to C) */ - else { - Node n = mainposition(t, key); - do { /* check whether `key' is somewhere in the chain */ - /* key may be dead already, but it is ok to use it in `next' */ - if ((luaO_rawequalObj(key2tval(n), key) != 0) || - (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && - gcvalue(gkey(n)) == gcvalue(key))) { - i = cast_int(n - gnode(t, 0)); /* key index in hash table */ - /* hash elements are numbered after array ones */ - return i + t.sizearray; - } - else n = gnext(n); - } while (n != null); - luaG_runerror(L, "invalid key to " + LUA_QL("next")); /* key not found */ - return 0; /* to avoid warnings */ - } - } - - - public static int luaH_next (lua_State L, Table t, StkId key) { - int i = findindex(L, t, key); /* find original element */ - for (i++; i < t.sizearray; i++) { /* try first array part */ - if (!ttisnil(t.array[i])) { /* a non-nil value? */ - setnvalue(key, cast_num(i+1)); - setobj2s(L, key+1, t.array[i]); - return 1; - } - } - for (i -= t.sizearray; i < sizenode(t); i++) { /* then hash part */ - if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ - setobj2s(L, key, key2tval(gnode(t, i))); - setobj2s(L, key+1, gval(gnode(t, i))); - return 1; - } - } - return 0; /* no more elements */ - } - - - /* - ** {============================================================= - ** Rehash - ** ============================================================== - */ - - - private static int computesizes (int[] nums, ref int narray) { - int i; - int twotoi; /* 2^i */ - int a = 0; /* number of elements smaller than 2^i */ - int na = 0; /* number of elements to go to array part */ - int n = 0; /* optimal size for array part */ - for (i = 0, twotoi = 1; twotoi/2 < narray; i++, twotoi *= 2) { - if (nums[i] > 0) { - a += nums[i]; - if (a > twotoi/2) { /* more than half elements present? */ - n = twotoi; /* optimal size (till now) */ - na = a; /* all elements smaller than n will go to array part */ - } - } - if (a == narray) break; /* all elements already counted */ - } - narray = n; - lua_assert(narray/2 <= na && na <= narray); - return na; - } - - - private static int countint (TValue key, int[] nums) { - int k = arrayindex(key); - if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ - nums[ceillog2(k)]++; /* count as such */ - return 1; - } - else - return 0; - } - - - private static int numusearray (Table t, int[] nums) { - int lg; - int ttlg; /* 2^lg */ - int ause = 0; /* summation of `nums' */ - int i = 1; /* count to traverse all array keys */ - for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */ - int lc = 0; /* counter */ - int lim = ttlg; - if (lim > t.sizearray) { - lim = t.sizearray; /* adjust upper limit */ - if (i > lim) - break; /* no more elements to count */ - } - /* count elements in range (2^(lg-1), 2^lg] */ - for (; i <= lim; i++) { - if (!ttisnil(t.array[i-1])) - lc++; - } - nums[lg] += lc; - ause += lc; - } - return ause; - } - - - private static int numusehash (Table t, int[] nums, ref int pnasize) { - int totaluse = 0; /* total number of elements */ - int ause = 0; /* summation of `nums' */ - int i = sizenode(t); - while ((i--) != 0) { - Node n = t.node[i]; - if (!ttisnil(gval(n))) { - ause += countint(key2tval(n), nums); - totaluse++; - } - } - pnasize += ause; - return totaluse; - } - - - private static void setarrayvector (lua_State L, Table t, int size) { - int i; - luaM_reallocvector(L, ref t.array, t.sizearray, size/*, TValue*/); - for (i=t.sizearray; i MAXBITS) - luaG_runerror(L, "table overflow"); - size = twoto(lsize); - Node[] nodes = luaM_newvector(L, size); - t.node = nodes; - for (i=0; i oldasize) /* array part must grow? */ - setarrayvector(L, t, nasize); - /* create new hash part with appropriate size */ - setnodevector(L, t, nhsize); - if (nasize < oldasize) { /* array part must shrink? */ - t.sizearray = nasize; - /* re-insert elements from vanishing slice */ - for (i=nasize; i(L, ref t.array, oldasize, nasize/*, TValue*/); - } - /* re-insert elements from hash part */ - for (i = twoto(oldhsize) - 1; i >= 0; i--) { - Node old = nold[i]; - if (!ttisnil(gval(old))) - setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); - } - if (nold[0] != dummynode) - luaM_freearray(L, nold); /* free old array */ - } - - - public static void luaH_resizearray (lua_State L, Table t, int nasize) { - int nsize = (t.node[0] == dummynode) ? 0 : sizenode(t); - resize(L, t, nasize, nsize); - } - - - private static void rehash (lua_State L, Table t, TValue ek) { - int nasize, na; - int[] nums = new int[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */ - int i; - int totaluse; - for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ - nasize = numusearray(t, nums); /* count keys in array part */ - totaluse = nasize; /* all those keys are integer keys */ - totaluse += numusehash(t, nums, ref nasize); /* count keys in hash part */ - /* count extra key */ - nasize += countint(ek, nums); - totaluse++; - /* compute new size for array part */ - na = computesizes(nums, ref nasize); - /* resize the table to new computed sizes */ - resize(L, t, nasize, totaluse - na); - } - - - - /* - ** }============================================================= - */ - - - public static Table luaH_new (lua_State L, int narray, int nhash) { - Table t = luaM_new(L); - luaC_link(L, obj2gco(t), LUA_TTABLE); - t.metatable = null; - t.flags = cast_byte(~0); - /* temporary values (kept only if some malloc fails) */ - t.array = null; - t.sizearray = 0; - t.lsizenode = 0; - t.node = new Node[] { dummynode }; - setarrayvector(L, t, narray); - setnodevector(L, t, nhash); - return t; - } - - - public static void luaH_free (lua_State L, Table t) { - if (t.node[0] != dummynode) - luaM_freearray(L, t.node); - luaM_freearray(L, t.array); - luaM_free(L, t); - } - - - private static Node getfreepos (Table t) { - while (t.lastfree-- > 0) { - if (ttisnil(gkey(t.node[t.lastfree]))) - return t.node[t.lastfree]; - } - return null; /* could not find a free place */ - } - - - - /* - ** inserts a new key into a hash table; first, check whether key's main - ** position is free. If not, check whether colliding node is in its main - ** position or not: if it is not, move colliding node to an empty place and - ** put new key in its main position; otherwise (colliding node is in its main - ** position), new key goes to an empty position. - */ - private static TValue newkey (lua_State L, Table t, TValue key) { - Node mp = mainposition(t, key); - if (!ttisnil(gval(mp)) || mp == dummynode) { - Node othern; - Node n = getfreepos(t); /* get a free place */ - if (n == null) { /* cannot find a free place? */ - rehash(L, t, key); /* grow table */ - return luaH_set(L, t, key); /* re-insert key into grown table */ - } - lua_assert(n != dummynode); - othern = mainposition(t, key2tval(mp)); - if (othern != mp) { /* is colliding node out of its main position? */ - /* yes; move colliding node into free position */ - while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ - gnext_set(othern, n); /* redo the chain with `n' in place of `mp' */ - n.i_val = new TValue(mp.i_val); /* copy colliding node into free pos. (mp.next also goes) */ - n.i_key = new TKey(mp.i_key); - gnext_set(mp, null); /* now `mp' is free */ - setnilvalue(gval(mp)); - } - else { /* colliding node is in its own main position */ - /* new node will go into free position */ - gnext_set(n, gnext(mp)); /* chain new position */ - gnext_set(mp, n); - mp = n; - } - } - gkey(mp).value.Copy(key.value); gkey(mp).tt = key.tt; - luaC_barriert(L, t, key); - lua_assert(ttisnil(gval(mp))); - return gval(mp); - } - - /* - ** search function for integers - */ - public static TValue luaH_getnum(Table t, int key) - { - /* (1 <= key && key <= t.sizearray) */ - if ((uint)(key-1) < (uint)t.sizearray) - return t.array[key-1]; - else { - lua_Number nk = cast_num(key); - Node n = hashnum(t, nk); - do { /* check whether `key' is somewhere in the chain */ - if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) - return gval(n); /* that's it */ - else n = gnext(n); - } while (n != null); - return luaO_nilobject; - } - } - - - /* - ** search function for strings - */ - public static TValue luaH_getstr (Table t, TString key) { - Node n = hashstr(t, key); - do { /* check whether `key' is somewhere in the chain */ - if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) - return gval(n); /* that's it */ - else n = gnext(n); - } while (n != null); - return luaO_nilobject; - } - - - /* - ** main search function - */ - public static TValue luaH_get (Table t, TValue key) { - switch (ttype(key)) { - case LUA_TNIL: return luaO_nilobject; - case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); - case LUA_TNUMBER: { - int k; - lua_Number n = nvalue(key); - lua_number2int(out k, n); - if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ - return luaH_getnum(t, k); /* use specialized version */ - /* else go through ... actually on second thoughts don't, because this is C#*/ - Node node = mainposition(t, key); - do - { /* check whether `key' is somewhere in the chain */ - if (luaO_rawequalObj(key2tval(node), key) != 0) - return gval(node); /* that's it */ - else node = gnext(node); - } while (node != null); - return luaO_nilobject; - } - default: { - Node node = mainposition(t, key); - do { /* check whether `key' is somewhere in the chain */ - if (luaO_rawequalObj(key2tval(node), key) != 0) - return gval(node); /* that's it */ - else node = gnext(node); - } while (node != null); - return luaO_nilobject; - } - } - } - - - public static TValue luaH_set (lua_State L, Table t, TValue key) { - TValue p = luaH_get(t, key); - t.flags = 0; - if (p != luaO_nilobject) - return (TValue)p; - else { - if (ttisnil(key)) luaG_runerror(L, "table index is nil"); - else if (ttisnumber(key) && luai_numisnan(nvalue(key))) - luaG_runerror(L, "table index is NaN"); - return newkey(L, t, key); - } - } - - - public static TValue luaH_setnum (lua_State L, Table t, int key) { - TValue p = luaH_getnum(t, key); - if (p != luaO_nilobject) - return (TValue)p; - else { - TValue k = new TValue(); - setnvalue(k, cast_num(key)); - return newkey(L, t, k); - } - } - - public static TValue luaH_setstr (lua_State L, Table t, TString key) { - TValue p = luaH_getstr(t, key); - if (p != luaO_nilobject) - return (TValue)p; - else { - TValue k = new TValue(); - setsvalue(L, k, key); - return newkey(L, t, k); - } - } - - [CLSCompliantAttribute(false)] - public static int unbound_search (Table t, uint j) { - uint i = j; /* i is zero or a present index */ - j++; - /* find `i' and `j' such that i is present and j is not */ - while (!ttisnil(luaH_getnum(t, (int)j))) { - i = j; - j *= 2; - if (j > (uint)MAX_INT) { /* overflow? */ - /* table was built with bad purposes: resort to linear search */ - i = 1; - while (!ttisnil(luaH_getnum(t, (int)i))) i++; - return (int)(i - 1); - } - } - /* now do a binary search between them */ - while (j - i > 1) { - uint m = (i+j)/2; - if (ttisnil(luaH_getnum(t, (int)m))) j = m; - else i = m; - } - return (int)i; - } - - - /* - ** Try to find a boundary in table `t'. A `boundary' is an integer index - ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). - */ - public static int luaH_getn (Table t) { - uint j = (uint)t.sizearray; - if (j > 0 && ttisnil(t.array[j - 1])) { - /* there is a boundary in the array part: (binary) search for it */ - uint i = 0; - while (j - i > 1) { - uint m = (i+j)/2; - if (ttisnil(t.array[m - 1])) j = m; - else i = m; - } - return (int)i; - } - /* else must find a boundary in hash part */ - else if (t.node[0] == dummynode) /* hash part is empty? */ - return (int)j; /* that is easy... */ - else return unbound_search(t, j); - } - - - - //#if defined(LUA_DEBUG) - - //Node *luaH_mainposition (const Table *t, const TValue *key) { - // return mainposition(t, key); - //} - - //int luaH_isdummy (Node *n) { return n == dummynode; } - - //#endif - - } -} +/* +** $Id: ltable.c,v 2.32.1.2 2007/12/28 15:32:23 roberto Exp $ +** Lua tables (hash) +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace KopiLua +{ + using TValue = Lua.lua_TValue; + using StkId = Lua.lua_TValue; + using lua_Number = System.Double; + + public partial class Lua + { + /* + ** Implementation of tables (aka arrays, objects, or hash tables). + ** Tables keep its elements in two parts: an array part and a hash part. + ** Non-negative integer keys are all candidates to be kept in the array + ** part. The actual size of the array is the largest `n' such that at + ** least half the slots between 0 and n are in use. + ** Hash uses a mix of chained scatter table with Brent's variation. + ** A main invariant of these tables is that, if an element is not + ** in its main position (i.e. the `original' position that its hash gives + ** to it), then the colliding element is in its own main position. + ** Hence even when the load factor reaches 100%, performance remains good. + */ + + internal static Node gnode(Table t, int i) { return t.node[i]; } + internal static TKey_nk gkey(Node n) { return n.i_key.nk; } + internal static TValue gval(Node n) { return n.i_val; } + internal static Node gnext(Node n) { return n.i_key.nk.next; } + + internal static void gnext_set(Node n, Node v) { n.i_key.nk.next = v; } + + internal static TValue key2tval(Node n) { return n.i_key.tvk; } + + + /* + ** max size of array part is 2^MAXBITS + */ + //#if LUAI_BITSINT > 26 + public const int MAXBITS = 26; /* in the dotnet port LUAI_BITSINT is 32 */ + //#else + //public const int MAXBITS = (LUAI_BITSINT-2); + //#endif + + public const int MAXASIZE = (1 << MAXBITS); + + + //public static Node gnode(Table t, int i) {return t.node[i];} + internal static Node hashpow2(Table t, lua_Number n) { return gnode(t, (int)lmod(n, sizenode(t))); } + + public static Node hashstr(Table t, TString str) {return hashpow2(t, str.tsv.hash);} + public static Node hashboolean(Table t, int p) {return hashpow2(t, p);} + + + /* + ** for some types, it is better to avoid modulus by power of 2, as + ** they tend to have many 2 factors. + */ + public static Node hashmod(Table t, int n) { return gnode(t, (int)((uint)n % ((sizenode(t) - 1) | 1))); } + + public static Node hashpointer(Table t, object p) { return hashmod(t, p.GetHashCode()); } + + + /* + ** number of ints inside a lua_Number + */ + public const int numints = sizeof(lua_Number) / sizeof(int); + + + //static const Node dummynode_ = { + //{{null}, LUA_TNIL}, /* value */ + //{{{null}, LUA_TNIL, null}} /* key */ + //}; + public static Node dummynode_ = new Node(new TValue(new Value(), LUA_TNIL), new TKey(new Value(), LUA_TNIL, null)); + public static Node dummynode = dummynode_; + + /* + ** hash for lua_Numbers + */ + private static Node hashnum (Table t, lua_Number n) { + byte[] a = BitConverter.GetBytes(n); + for (int i = 1; i < a.Length; i++) a[0] += a[i]; + return hashmod(t, (int)a[0]); + } + + + + /* + ** returns the `main' position of an element in a table (that is, the index + ** of its hash value) + */ + private static Node mainposition (Table t, TValue key) { + switch (ttype(key)) { + case LUA_TNUMBER: + return hashnum(t, nvalue(key)); + case LUA_TSTRING: + return hashstr(t, rawtsvalue(key)); + case LUA_TBOOLEAN: + return hashboolean(t, bvalue(key)); + case LUA_TLIGHTUSERDATA: + return hashpointer(t, pvalue(key)); + default: + return hashpointer(t, gcvalue(key)); + } + } + + + /* + ** returns the index for `key' if `key' is an appropriate key to live in + ** the array part of the table, -1 otherwise. + */ + private static int arrayindex (TValue key) { + if (ttisnumber(key)) { + lua_Number n = nvalue(key); + int k; + lua_number2int(out k, n); + if (luai_numeq(cast_num(k), n)) + return k; + } + return -1; /* `key' did not match some condition */ + } + + + /* + ** returns the index of a `key' for table traversals. First goes all + ** elements in the array part, then elements in the hash part. The + ** beginning of a traversal is signalled by -1. + */ + private static int findindex (lua_State L, Table t, StkId key) { + int i; + if (ttisnil(key)) return -1; /* first iteration */ + i = arrayindex(key); + if (0 < i && i <= t.sizearray) /* is `key' inside array part? */ + return i-1; /* yes; that's the index (corrected to C) */ + else { + Node n = mainposition(t, key); + do { /* check whether `key' is somewhere in the chain */ + /* key may be dead already, but it is ok to use it in `next' */ + if ((luaO_rawequalObj(key2tval(n), key) != 0) || + (ttype(gkey(n)) == LUA_TDEADKEY && iscollectable(key) && + gcvalue(gkey(n)) == gcvalue(key))) { + i = cast_int(n - gnode(t, 0)); /* key index in hash table */ + /* hash elements are numbered after array ones */ + return i + t.sizearray; + } + else n = gnext(n); + } while (n != null); + luaG_runerror(L, "invalid key to " + LUA_QL("next")); /* key not found */ + return 0; /* to avoid warnings */ + } + } + + + public static int luaH_next (lua_State L, Table t, StkId key) { + int i = findindex(L, t, key); /* find original element */ + for (i++; i < t.sizearray; i++) { /* try first array part */ + if (!ttisnil(t.array[i])) { /* a non-nil value? */ + setnvalue(key, cast_num(i+1)); + setobj2s(L, key+1, t.array[i]); + return 1; + } + } + for (i -= t.sizearray; i < sizenode(t); i++) { /* then hash part */ + if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ + setobj2s(L, key, key2tval(gnode(t, i))); + setobj2s(L, key+1, gval(gnode(t, i))); + return 1; + } + } + return 0; /* no more elements */ + } + + + /* + ** {============================================================= + ** Rehash + ** ============================================================== + */ + + + private static int computesizes (int[] nums, ref int narray) { + int i; + int twotoi; /* 2^i */ + int a = 0; /* number of elements smaller than 2^i */ + int na = 0; /* number of elements to go to array part */ + int n = 0; /* optimal size for array part */ + for (i = 0, twotoi = 1; twotoi/2 < narray; i++, twotoi *= 2) { + if (nums[i] > 0) { + a += nums[i]; + if (a > twotoi/2) { /* more than half elements present? */ + n = twotoi; /* optimal size (till now) */ + na = a; /* all elements smaller than n will go to array part */ + } + } + if (a == narray) break; /* all elements already counted */ + } + narray = n; + lua_assert(narray/2 <= na && na <= narray); + return na; + } + + + private static int countint (TValue key, int[] nums) { + int k = arrayindex(key); + if (0 < k && k <= MAXASIZE) { /* is `key' an appropriate array index? */ + nums[ceillog2(k)]++; /* count as such */ + return 1; + } + else + return 0; + } + + + private static int numusearray (Table t, int[] nums) { + int lg; + int ttlg; /* 2^lg */ + int ause = 0; /* summation of `nums' */ + int i = 1; /* count to traverse all array keys */ + for (lg=0, ttlg=1; lg<=MAXBITS; lg++, ttlg*=2) { /* for each slice */ + int lc = 0; /* counter */ + int lim = ttlg; + if (lim > t.sizearray) { + lim = t.sizearray; /* adjust upper limit */ + if (i > lim) + break; /* no more elements to count */ + } + /* count elements in range (2^(lg-1), 2^lg] */ + for (; i <= lim; i++) { + if (!ttisnil(t.array[i-1])) + lc++; + } + nums[lg] += lc; + ause += lc; + } + return ause; + } + + + private static int numusehash (Table t, int[] nums, ref int pnasize) { + int totaluse = 0; /* total number of elements */ + int ause = 0; /* summation of `nums' */ + int i = sizenode(t); + while ((i--) != 0) { + Node n = t.node[i]; + if (!ttisnil(gval(n))) { + ause += countint(key2tval(n), nums); + totaluse++; + } + } + pnasize += ause; + return totaluse; + } + + + private static void setarrayvector (lua_State L, Table t, int size) { + int i; + luaM_reallocvector(L, ref t.array, t.sizearray, size/*, TValue*/); + for (i=t.sizearray; i MAXBITS) + luaG_runerror(L, "table overflow"); + size = twoto(lsize); + Node[] nodes = luaM_newvector(L, size); + t.node = nodes; + for (i=0; i oldasize) /* array part must grow? */ + setarrayvector(L, t, nasize); + /* create new hash part with appropriate size */ + setnodevector(L, t, nhsize); + if (nasize < oldasize) { /* array part must shrink? */ + t.sizearray = nasize; + /* re-insert elements from vanishing slice */ + for (i=nasize; i(L, ref t.array, oldasize, nasize/*, TValue*/); + } + /* re-insert elements from hash part */ + for (i = twoto(oldhsize) - 1; i >= 0; i--) { + Node old = nold[i]; + if (!ttisnil(gval(old))) + setobjt2t(L, luaH_set(L, t, key2tval(old)), gval(old)); + } + if (nold[0] != dummynode) + luaM_freearray(L, nold); /* free old array */ + } + + + public static void luaH_resizearray (lua_State L, Table t, int nasize) { + int nsize = (t.node[0] == dummynode) ? 0 : sizenode(t); + resize(L, t, nasize, nsize); + } + + + private static void rehash (lua_State L, Table t, TValue ek) { + int nasize, na; + int[] nums = new int[MAXBITS+1]; /* nums[i] = number of keys between 2^(i-1) and 2^i */ + int i; + int totaluse; + for (i=0; i<=MAXBITS; i++) nums[i] = 0; /* reset counts */ + nasize = numusearray(t, nums); /* count keys in array part */ + totaluse = nasize; /* all those keys are integer keys */ + totaluse += numusehash(t, nums, ref nasize); /* count keys in hash part */ + /* count extra key */ + nasize += countint(ek, nums); + totaluse++; + /* compute new size for array part */ + na = computesizes(nums, ref nasize); + /* resize the table to new computed sizes */ + resize(L, t, nasize, totaluse - na); + } + + + + /* + ** }============================================================= + */ + + + public static Table luaH_new (lua_State L, int narray, int nhash) { + Table t = luaM_new
(L); + luaC_link(L, obj2gco(t), LUA_TTABLE); + t.metatable = null; + t.flags = cast_byte(~0); + /* temporary values (kept only if some malloc fails) */ + t.array = null; + t.sizearray = 0; + t.lsizenode = 0; + t.node = new Node[] { dummynode }; + setarrayvector(L, t, narray); + setnodevector(L, t, nhash); + return t; + } + + + public static void luaH_free (lua_State L, Table t) { + if (t.node[0] != dummynode) + luaM_freearray(L, t.node); + luaM_freearray(L, t.array); + luaM_free(L, t); + } + + + private static Node getfreepos (Table t) { + while (t.lastfree-- > 0) { + if (ttisnil(gkey(t.node[t.lastfree]))) + return t.node[t.lastfree]; + } + return null; /* could not find a free place */ + } + + + + /* + ** inserts a new key into a hash table; first, check whether key's main + ** position is free. If not, check whether colliding node is in its main + ** position or not: if it is not, move colliding node to an empty place and + ** put new key in its main position; otherwise (colliding node is in its main + ** position), new key goes to an empty position. + */ + private static TValue newkey (lua_State L, Table t, TValue key) { + Node mp = mainposition(t, key); + if (!ttisnil(gval(mp)) || mp == dummynode) { + Node othern; + Node n = getfreepos(t); /* get a free place */ + if (n == null) { /* cannot find a free place? */ + rehash(L, t, key); /* grow table */ + return luaH_set(L, t, key); /* re-insert key into grown table */ + } + lua_assert(n != dummynode); + othern = mainposition(t, key2tval(mp)); + if (othern != mp) { /* is colliding node out of its main position? */ + /* yes; move colliding node into free position */ + while (gnext(othern) != mp) othern = gnext(othern); /* find previous */ + gnext_set(othern, n); /* redo the chain with `n' in place of `mp' */ + n.i_val = new TValue(mp.i_val); /* copy colliding node into free pos. (mp.next also goes) */ + n.i_key = new TKey(mp.i_key); + gnext_set(mp, null); /* now `mp' is free */ + setnilvalue(gval(mp)); + } + else { /* colliding node is in its own main position */ + /* new node will go into free position */ + gnext_set(n, gnext(mp)); /* chain new position */ + gnext_set(mp, n); + mp = n; + } + } + gkey(mp).value.Copy(key.value); gkey(mp).tt = key.tt; + luaC_barriert(L, t, key); + lua_assert(ttisnil(gval(mp))); + return gval(mp); + } + + /* + ** search function for integers + */ + public static TValue luaH_getnum(Table t, int key) + { + /* (1 <= key && key <= t.sizearray) */ + if ((uint)(key-1) < (uint)t.sizearray) + return t.array[key-1]; + else { + lua_Number nk = cast_num(key); + Node n = hashnum(t, nk); + do { /* check whether `key' is somewhere in the chain */ + if (ttisnumber(gkey(n)) && luai_numeq(nvalue(gkey(n)), nk)) + return gval(n); /* that's it */ + else n = gnext(n); + } while (n != null); + return luaO_nilobject; + } + } + + + /* + ** search function for strings + */ + public static TValue luaH_getstr (Table t, TString key) { + Node n = hashstr(t, key); + do { /* check whether `key' is somewhere in the chain */ + if (ttisstring(gkey(n)) && rawtsvalue(gkey(n)) == key) + return gval(n); /* that's it */ + else n = gnext(n); + } while (n != null); + return luaO_nilobject; + } + + + /* + ** main search function + */ + public static TValue luaH_get (Table t, TValue key) { + switch (ttype(key)) { + case LUA_TNIL: return luaO_nilobject; + case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); + case LUA_TNUMBER: { + int k; + lua_Number n = nvalue(key); + lua_number2int(out k, n); + if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ + return luaH_getnum(t, k); /* use specialized version */ + /* else go through ... actually on second thoughts don't, because this is C#*/ + Node node = mainposition(t, key); + do + { /* check whether `key' is somewhere in the chain */ + if (luaO_rawequalObj(key2tval(node), key) != 0) + return gval(node); /* that's it */ + else node = gnext(node); + } while (node != null); + return luaO_nilobject; + } + default: { + Node node = mainposition(t, key); + do { /* check whether `key' is somewhere in the chain */ + if (luaO_rawequalObj(key2tval(node), key) != 0) + return gval(node); /* that's it */ + else node = gnext(node); + } while (node != null); + return luaO_nilobject; + } + } + } + + + public static TValue luaH_set (lua_State L, Table t, TValue key) { + TValue p = luaH_get(t, key); + t.flags = 0; + if (p != luaO_nilobject) + return (TValue)p; + else { + if (ttisnil(key)) luaG_runerror(L, "table index is nil"); + else if (ttisnumber(key) && luai_numisnan(nvalue(key))) + luaG_runerror(L, "table index is NaN"); + return newkey(L, t, key); + } + } + + + public static TValue luaH_setnum (lua_State L, Table t, int key) { + TValue p = luaH_getnum(t, key); + if (p != luaO_nilobject) + return (TValue)p; + else { + TValue k = new TValue(); + setnvalue(k, cast_num(key)); + return newkey(L, t, k); + } + } + + public static TValue luaH_setstr (lua_State L, Table t, TString key) { + TValue p = luaH_getstr(t, key); + if (p != luaO_nilobject) + return (TValue)p; + else { + TValue k = new TValue(); + setsvalue(L, k, key); + return newkey(L, t, k); + } + } + + [CLSCompliantAttribute(false)] + public static int unbound_search (Table t, uint j) { + uint i = j; /* i is zero or a present index */ + j++; + /* find `i' and `j' such that i is present and j is not */ + while (!ttisnil(luaH_getnum(t, (int)j))) { + i = j; + j *= 2; + if (j > (uint)MAX_INT) { /* overflow? */ + /* table was built with bad purposes: resort to linear search */ + i = 1; + while (!ttisnil(luaH_getnum(t, (int)i))) i++; + return (int)(i - 1); + } + } + /* now do a binary search between them */ + while (j - i > 1) { + uint m = (i+j)/2; + if (ttisnil(luaH_getnum(t, (int)m))) j = m; + else i = m; + } + return (int)i; + } + + + /* + ** Try to find a boundary in table `t'. A `boundary' is an integer index + ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). + */ + public static int luaH_getn (Table t) { + uint j = (uint)t.sizearray; + if (j > 0 && ttisnil(t.array[j - 1])) { + /* there is a boundary in the array part: (binary) search for it */ + uint i = 0; + while (j - i > 1) { + uint m = (i+j)/2; + if (ttisnil(t.array[m - 1])) j = m; + else i = m; + } + return (int)i; + } + /* else must find a boundary in hash part */ + else if (t.node[0] == dummynode) /* hash part is empty? */ + return (int)j; /* that is easy... */ + else return unbound_search(t, j); + } + + + + //#if defined(LUA_DEBUG) + + //Node *luaH_mainposition (const Table *t, const TValue *key) { + // return mainposition(t, key); + //} + + //int luaH_isdummy (Node *n) { return n == dummynode; } + + //#endif + + } +} diff --git a/Core/KopiLua/ltablib.cs b/Core/KopiLua/ltablib.cs index 0f60c77835dca3f80df713e8e2f9e1c5286f92ab..11c9f9fb8ca0bcc3c33725617f0a662702db7227 100644 --- a/Core/KopiLua/ltablib.cs +++ b/Core/KopiLua/ltablib.cs @@ -1,298 +1,298 @@ -/* -** $Id: ltablib.c,v 1.38.1.3 2008/02/14 16:46:58 roberto Exp $ -** Library for Table Manipulation -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace KopiLua -{ - using lua_Number = System.Double; - - public partial class Lua - { - private static int aux_getn(lua_State L, int n) {luaL_checktype(L, n, LUA_TTABLE); return luaL_getn(L, n);} - - private static int foreachi (lua_State L) { - int i; - int n = aux_getn(L, 1); - luaL_checktype(L, 2, LUA_TFUNCTION); - for (i=1; i <= n; i++) { - lua_pushvalue(L, 2); /* function */ - lua_pushinteger(L, i); /* 1st argument */ - lua_rawgeti(L, 1, i); /* 2nd argument */ - lua_call(L, 2, 1); - if (!lua_isnil(L, -1)) - return 1; - lua_pop(L, 1); /* remove nil result */ - } - return 0; - } - - - private static int _foreach (lua_State L) { - luaL_checktype(L, 1, LUA_TTABLE); - luaL_checktype(L, 2, LUA_TFUNCTION); - lua_pushnil(L); /* first key */ - while (lua_next(L, 1) != 0) { - lua_pushvalue(L, 2); /* function */ - lua_pushvalue(L, -3); /* key */ - lua_pushvalue(L, -3); /* value */ - lua_call(L, 2, 1); - if (!lua_isnil(L, -1)) - return 1; - lua_pop(L, 2); /* remove value and result */ - } - return 0; - } - - - private static int maxn (lua_State L) { - lua_Number max = 0; - luaL_checktype(L, 1, LUA_TTABLE); - lua_pushnil(L); /* first key */ - while (lua_next(L, 1) != 0) { - lua_pop(L, 1); /* remove value */ - if (lua_type(L, -1) == LUA_TNUMBER) { - lua_Number v = lua_tonumber(L, -1); - if (v > max) max = v; - } - } - lua_pushnumber(L, max); - return 1; - } - - - private static int getn (lua_State L) { - lua_pushinteger(L, aux_getn(L, 1)); - return 1; - } - - - private static int setn (lua_State L) { - luaL_checktype(L, 1, LUA_TTABLE); - //#ifndef luaL_setn - //luaL_setn(L, 1, luaL_checkint(L, 2)); - //#else - luaL_error(L, LUA_QL("setn") + " is obsolete"); - //#endif - lua_pushvalue(L, 1); - return 1; - } - - - private static int tinsert (lua_State L) { - int e = aux_getn(L, 1) + 1; /* first empty element */ - int pos; /* where to insert new element */ - switch (lua_gettop(L)) { - case 2: { /* called with only 2 arguments */ - pos = e; /* insert new element at the end */ - break; - } - case 3: { - int i; - pos = luaL_checkint(L, 2); /* 2nd argument is the position */ - if (pos > e) e = pos; /* `grow' array if necessary */ - for (i = e; i > pos; i--) { /* move up elements */ - lua_rawgeti(L, 1, i-1); - lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ - } - break; - } - default: { - return luaL_error(L, "wrong number of arguments to " + LUA_QL("insert")); - } - } - luaL_setn(L, 1, e); /* new size */ - lua_rawseti(L, 1, pos); /* t[pos] = v */ - return 0; - } - - - private static int tremove (lua_State L) { - int e = aux_getn(L, 1); - int pos = luaL_optint(L, 2, e); - if (!(1 <= pos && pos <= e)) /* position is outside bounds? */ - return 0; /* nothing to remove */ - luaL_setn(L, 1, e - 1); /* t.n = n-1 */ - lua_rawgeti(L, 1, pos); /* result = t[pos] */ - for ( ;pos= P */ - while (auxsort_loop1(L, ref i) != 0) { - if (i>u) luaL_error(L, "invalid order function for sorting"); - lua_pop(L, 1); /* remove a[i] */ - } - /* repeat --j until a[j] <= P */ - while (auxsort_loop2(L, ref j) != 0) { - if (j max) max = v; + } + } + lua_pushnumber(L, max); + return 1; + } + + + private static int getn (lua_State L) { + lua_pushinteger(L, aux_getn(L, 1)); + return 1; + } + + + private static int setn (lua_State L) { + luaL_checktype(L, 1, LUA_TTABLE); + //#ifndef luaL_setn + //luaL_setn(L, 1, luaL_checkint(L, 2)); + //#else + luaL_error(L, LUA_QL("setn") + " is obsolete"); + //#endif + lua_pushvalue(L, 1); + return 1; + } + + + private static int tinsert (lua_State L) { + int e = aux_getn(L, 1) + 1; /* first empty element */ + int pos; /* where to insert new element */ + switch (lua_gettop(L)) { + case 2: { /* called with only 2 arguments */ + pos = e; /* insert new element at the end */ + break; + } + case 3: { + int i; + pos = luaL_checkint(L, 2); /* 2nd argument is the position */ + if (pos > e) e = pos; /* `grow' array if necessary */ + for (i = e; i > pos; i--) { /* move up elements */ + lua_rawgeti(L, 1, i-1); + lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ + } + break; + } + default: { + return luaL_error(L, "wrong number of arguments to " + LUA_QL("insert")); + } + } + luaL_setn(L, 1, e); /* new size */ + lua_rawseti(L, 1, pos); /* t[pos] = v */ + return 0; + } + + + private static int tremove (lua_State L) { + int e = aux_getn(L, 1); + int pos = luaL_optint(L, 2, e); + if (!(1 <= pos && pos <= e)) /* position is outside bounds? */ + return 0; /* nothing to remove */ + luaL_setn(L, 1, e - 1); /* t.n = n-1 */ + lua_rawgeti(L, 1, pos); /* result = t[pos] */ + for ( ;pos= P */ + while (auxsort_loop1(L, ref i) != 0) { + if (i>u) luaL_error(L, "invalid order function for sorting"); + lua_pop(L, 1); /* remove a[i] */ + } + /* repeat --j until a[j] <= P */ + while (auxsort_loop2(L, ref j) != 0) { + if (jLua') */ - public const string LUA_SIGNATURE = "\x01bLua"; - - /* option for multiple returns in `lua_pcall' and `lua_call' */ - public const int LUA_MULTRET = (-1); - - - /* - ** pseudo-indices - */ - public const int LUA_REGISTRYINDEX = (-10000); - public const int LUA_ENVIRONINDEX = (-10001); - public const int LUA_GLOBALSINDEX = (-10002); - public static int lua_upvalueindex(int i) {return LUA_GLOBALSINDEX-i;} - - - /* thread status; 0 is OK */ - public const int LUA_YIELD = 1; - public const int LUA_ERRRUN = 2; - public const int LUA_ERRSYNTAX = 3; - public const int LUA_ERRMEM = 4; - public const int LUA_ERRERR = 5; - - - public delegate int lua_CFunction(lua_State L); - - - /* - ** functions that read/write blocks when loading/dumping Lua chunks - */ - [CLSCompliantAttribute(false)] - public delegate CharPtr lua_Reader(lua_State L, object ud, out uint sz); - [CLSCompliantAttribute(false)] - public delegate int lua_Writer(lua_State L, CharPtr p, uint sz, object ud); - - - /* - ** prototype for memory-allocation functions - */ - //public delegate object lua_Alloc(object ud, object ptr, uint osize, uint nsize); - public delegate object lua_Alloc(Type t); - - - /* - ** basic types - */ - public const int LUA_TNONE = -1; - - public const int LUA_TNIL = 0; - public const int LUA_TBOOLEAN = 1; - public const int LUA_TLIGHTUSERDATA = 2; - public const int LUA_TNUMBER = 3; - public const int LUA_TSTRING = 4; - public const int LUA_TTABLE = 5; - public const int LUA_TFUNCTION = 6; - public const int LUA_TUSERDATA = 7; - public const int LUA_TTHREAD = 8; - - - - /* minimum Lua stack available to a C function */ - public const int LUA_MINSTACK = 20; - - - /* type of numbers in Lua */ - //typedef LUA_NUMBER lua_Number; - - - /* type for integer functions */ - //typedef LUA_INTEGER lua_Integer; - - /* - ** garbage-collection function and options - */ - - public const int LUA_GCSTOP = 0; - public const int LUA_GCRESTART = 1; - public const int LUA_GCCOLLECT = 2; - public const int LUA_GCCOUNT = 3; - public const int LUA_GCCOUNTB = 4; - public const int LUA_GCSTEP = 5; - public const int LUA_GCSETPAUSE = 6; - public const int LUA_GCSETSTEPMUL = 7; - - /* - ** =============================================================== - ** some useful macros - ** =============================================================== - */ - - public static void lua_pop(lua_State L, int n) - { - lua_settop(L, -(n) - 1); - } - - public static void lua_newtable(lua_State L) - { - lua_createtable(L, 0, 0); - } - - public static void lua_register(lua_State L, CharPtr n, lua_CFunction f) - { - lua_pushcfunction(L, f); - lua_setglobal(L, n); - } - - public static void lua_pushcfunction(lua_State L, lua_CFunction f) - { - lua_pushcclosure(L, f, 0); - } - - [CLSCompliantAttribute(false)] - public static uint lua_strlen(lua_State L, int i) - { - return lua_objlen(L, i); - } - - public static bool lua_isfunction(lua_State L, int n) - { - return lua_type(L, n) == LUA_TFUNCTION; - } - - public static bool lua_istable(lua_State L, int n) - { - return lua_type(L, n) == LUA_TTABLE; - } - - public static bool lua_islightuserdata(lua_State L, int n) - { - return lua_type(L, n) == LUA_TLIGHTUSERDATA; - } - - public static bool lua_isnil(lua_State L, int n) - { - return lua_type(L, n) == LUA_TNIL; - } - - public static bool lua_isboolean(lua_State L, int n) - { - return lua_type(L, n) == LUA_TBOOLEAN; - } - - public static bool lua_isthread(lua_State L, int n) - { - return lua_type(L, n) == LUA_TTHREAD; - } - - public static bool lua_isnone(lua_State L, int n) - { - return lua_type(L, n) == LUA_TNONE; - } - - public static bool lua_isnoneornil(lua_State L, lua_Number n) - { - return lua_type(L, (int)n) <= 0; - } - - public static void lua_pushliteral(lua_State L, CharPtr s) - { - //TODO: Implement use using lua_pushlstring instead of lua_pushstring - //lua_pushlstring(L, "" s, (sizeof(s)/GetUnmanagedSize(typeof(char)))-1) - lua_pushstring(L, s); - } - - public static void lua_setglobal(lua_State L, CharPtr s) - { - lua_setfield(L, LUA_GLOBALSINDEX, s); - } - - public static void lua_getglobal(lua_State L, CharPtr s) - { - lua_getfield(L, LUA_GLOBALSINDEX, s); - } - - public static CharPtr lua_tostring(lua_State L, int i) - { - uint blah; - return lua_tolstring(L, i, out blah); - } - - ////#define lua_open() luaL_newstate() - public static lua_State lua_open() - { - return luaL_newstate(); - } - - ////#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) - public static void lua_getregistry(lua_State L) - { - lua_pushvalue(L, LUA_REGISTRYINDEX); - } - - ////#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) - public static int lua_getgccount(lua_State L) - { - return lua_gc(L, LUA_GCCOUNT, 0); - } - - //#define lua_Chunkreader lua_Reader - //#define lua_Chunkwriter lua_Writer - - - /* - ** {====================================================================== - ** Debug API - ** ======================================================================= - */ - - - /* - ** Event codes - */ - public const int LUA_HOOKCALL = 0; - public const int LUA_HOOKRET = 1; - public const int LUA_HOOKLINE = 2; - public const int LUA_HOOKCOUNT = 3; - public const int LUA_HOOKTAILRET = 4; - - - /* - ** Event masks - */ - public const int LUA_MASKCALL = (1 << LUA_HOOKCALL); - public const int LUA_MASKRET = (1 << LUA_HOOKRET); - public const int LUA_MASKLINE = (1 << LUA_HOOKLINE); - public const int LUA_MASKCOUNT = (1 << LUA_HOOKCOUNT); - - /* Functions to be called by the debuger in specific events */ - public delegate void lua_Hook(lua_State L, lua_Debug ar); - - - public class lua_Debug { - public int event_; - public CharPtr name; /* (n) */ - public CharPtr namewhat; /* (n) `global', `local', `field', `method' */ - public CharPtr what; /* (S) `Lua', `C', `main', `tail' */ - public CharPtr source; /* (S) */ - public int currentline; /* (l) */ - public int nups; /* (u) number of upvalues */ - public int linedefined; /* (S) */ - public int lastlinedefined; /* (S) */ - public CharPtr short_src = new char[LUA_IDSIZE]; /* (S) */ - /* private part */ - public int i_ci; /* active function */ - }; - - /* }====================================================================== */ - - - /****************************************************************************** - * Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved. - * - * 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: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * 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. - ******************************************************************************/ - - } -} +/* +** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $ +** Lua - An Extensible Extension Language +** Lua.org, PUC-Rio, Brazil (http://www.lua.org) +** See Copyright Notice at the end of this file +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace KopiLua +{ + using lua_Number = Double; + using lua_Integer = System.Int32; + + [CLSCompliantAttribute(true)] + public partial class Lua + { + + public const string LUA_VERSION = "Lua 5.1"; + public const string LUA_RELEASE = "Lua 5.1.4"; + public const int LUA_VERSION_NUM = 501; + public const string LUA_COPYRIGHT = "Copyright (C) 1994-2008 Lua.org, PUC-Rio"; + public const string LUA_AUTHORS = "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"; + + + /* mark for precompiled code (`Lua') */ + public const string LUA_SIGNATURE = "\x01bLua"; + + /* option for multiple returns in `lua_pcall' and `lua_call' */ + public const int LUA_MULTRET = (-1); + + + /* + ** pseudo-indices + */ + public const int LUA_REGISTRYINDEX = (-10000); + public const int LUA_ENVIRONINDEX = (-10001); + public const int LUA_GLOBALSINDEX = (-10002); + public static int lua_upvalueindex(int i) {return LUA_GLOBALSINDEX-i;} + + + /* thread status; 0 is OK */ + public const int LUA_YIELD = 1; + public const int LUA_ERRRUN = 2; + public const int LUA_ERRSYNTAX = 3; + public const int LUA_ERRMEM = 4; + public const int LUA_ERRERR = 5; + + + public delegate int lua_CFunction(lua_State L); + + + /* + ** functions that read/write blocks when loading/dumping Lua chunks + */ + [CLSCompliantAttribute(false)] + public delegate CharPtr lua_Reader(lua_State L, object ud, out uint sz); + [CLSCompliantAttribute(false)] + public delegate int lua_Writer(lua_State L, CharPtr p, uint sz, object ud); + + + /* + ** prototype for memory-allocation functions + */ + //public delegate object lua_Alloc(object ud, object ptr, uint osize, uint nsize); + public delegate object lua_Alloc(Type t); + + + /* + ** basic types + */ + public const int LUA_TNONE = -1; + + public const int LUA_TNIL = 0; + public const int LUA_TBOOLEAN = 1; + public const int LUA_TLIGHTUSERDATA = 2; + public const int LUA_TNUMBER = 3; + public const int LUA_TSTRING = 4; + public const int LUA_TTABLE = 5; + public const int LUA_TFUNCTION = 6; + public const int LUA_TUSERDATA = 7; + public const int LUA_TTHREAD = 8; + + + + /* minimum Lua stack available to a C function */ + public const int LUA_MINSTACK = 20; + + + /* type of numbers in Lua */ + //typedef LUA_NUMBER lua_Number; + + + /* type for integer functions */ + //typedef LUA_INTEGER lua_Integer; + + /* + ** garbage-collection function and options + */ + + public const int LUA_GCSTOP = 0; + public const int LUA_GCRESTART = 1; + public const int LUA_GCCOLLECT = 2; + public const int LUA_GCCOUNT = 3; + public const int LUA_GCCOUNTB = 4; + public const int LUA_GCSTEP = 5; + public const int LUA_GCSETPAUSE = 6; + public const int LUA_GCSETSTEPMUL = 7; + + /* + ** =============================================================== + ** some useful macros + ** =============================================================== + */ + + public static void lua_pop(lua_State L, int n) + { + lua_settop(L, -(n) - 1); + } + + public static void lua_newtable(lua_State L) + { + lua_createtable(L, 0, 0); + } + + public static void lua_register(lua_State L, CharPtr n, lua_CFunction f) + { + lua_pushcfunction(L, f); + lua_setglobal(L, n); + } + + public static void lua_pushcfunction(lua_State L, lua_CFunction f) + { + lua_pushcclosure(L, f, 0); + } + + [CLSCompliantAttribute(false)] + public static uint lua_strlen(lua_State L, int i) + { + return lua_objlen(L, i); + } + + public static bool lua_isfunction(lua_State L, int n) + { + return lua_type(L, n) == LUA_TFUNCTION; + } + + public static bool lua_istable(lua_State L, int n) + { + return lua_type(L, n) == LUA_TTABLE; + } + + public static bool lua_islightuserdata(lua_State L, int n) + { + return lua_type(L, n) == LUA_TLIGHTUSERDATA; + } + + public static bool lua_isnil(lua_State L, int n) + { + return lua_type(L, n) == LUA_TNIL; + } + + public static bool lua_isboolean(lua_State L, int n) + { + return lua_type(L, n) == LUA_TBOOLEAN; + } + + public static bool lua_isthread(lua_State L, int n) + { + return lua_type(L, n) == LUA_TTHREAD; + } + + public static bool lua_isnone(lua_State L, int n) + { + return lua_type(L, n) == LUA_TNONE; + } + + public static bool lua_isnoneornil(lua_State L, lua_Number n) + { + return lua_type(L, (int)n) <= 0; + } + + public static void lua_pushliteral(lua_State L, CharPtr s) + { + //TODO: Implement use using lua_pushlstring instead of lua_pushstring + //lua_pushlstring(L, "" s, (sizeof(s)/GetUnmanagedSize(typeof(char)))-1) + lua_pushstring(L, s); + } + + public static void lua_setglobal(lua_State L, CharPtr s) + { + lua_setfield(L, LUA_GLOBALSINDEX, s); + } + + public static void lua_getglobal(lua_State L, CharPtr s) + { + lua_getfield(L, LUA_GLOBALSINDEX, s); + } + + public static CharPtr lua_tostring(lua_State L, int i) + { + uint blah; + return lua_tolstring(L, i, out blah); + } + + ////#define lua_open() luaL_newstate() + public static lua_State lua_open() + { + return luaL_newstate(); + } + + ////#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) + public static void lua_getregistry(lua_State L) + { + lua_pushvalue(L, LUA_REGISTRYINDEX); + } + + ////#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) + public static int lua_getgccount(lua_State L) + { + return lua_gc(L, LUA_GCCOUNT, 0); + } + + //#define lua_Chunkreader lua_Reader + //#define lua_Chunkwriter lua_Writer + + + /* + ** {====================================================================== + ** Debug API + ** ======================================================================= + */ + + + /* + ** Event codes + */ + public const int LUA_HOOKCALL = 0; + public const int LUA_HOOKRET = 1; + public const int LUA_HOOKLINE = 2; + public const int LUA_HOOKCOUNT = 3; + public const int LUA_HOOKTAILRET = 4; + + + /* + ** Event masks + */ + public const int LUA_MASKCALL = (1 << LUA_HOOKCALL); + public const int LUA_MASKRET = (1 << LUA_HOOKRET); + public const int LUA_MASKLINE = (1 << LUA_HOOKLINE); + public const int LUA_MASKCOUNT = (1 << LUA_HOOKCOUNT); + + /* Functions to be called by the debuger in specific events */ + public delegate void lua_Hook(lua_State L, lua_Debug ar); + + + public class lua_Debug { + public int event_; + public CharPtr name; /* (n) */ + public CharPtr namewhat; /* (n) `global', `local', `field', `method' */ + public CharPtr what; /* (S) `Lua', `C', `main', `tail' */ + public CharPtr source; /* (S) */ + public int currentline; /* (l) */ + public int nups; /* (u) number of upvalues */ + public int linedefined; /* (S) */ + public int lastlinedefined; /* (S) */ + public CharPtr short_src = new char[LUA_IDSIZE]; /* (S) */ + /* private part */ + public int i_ci; /* active function */ + }; + + /* }====================================================================== */ + + + /****************************************************************************** + * Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved. + * + * 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: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * 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. + ******************************************************************************/ + + } +} diff --git a/Core/KopiLua/luaconf.cs b/Core/KopiLua/luaconf.cs index 84f1d78968ee0f920eef1d7b6279b0b4fff7d7f6..ea0a30e19c66631ae6cadd2926fc5704c20723d7 100644 --- a/Core/KopiLua/luaconf.cs +++ b/Core/KopiLua/luaconf.cs @@ -1,1683 +1,1683 @@ -/* -** $Id: luaconf.h,v 1.82.1.7 2008/02/11 16:25:08 roberto Exp $ -** Configuration file for Lua -** See Copyright Notice in lua.h -*/ - -using System; -using System.IO; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; -using AT.MIN; - -namespace KopiLua -{ - using LUA_INTEGER = System.Int32; - using LUA_NUMBER = System.Double; - using LUAI_UACNUMBER = System.Double; - using LUA_INTFRM_T = System.Int64; - using TValue = Lua.lua_TValue; - using lua_Number = System.Double; - using System.Globalization; - - public partial class Lua - { - /* - ** ================================================================== - ** Search for "@@" to find all configurable definitions. - ** =================================================================== - */ - - - /* - @@ LUA_ANSI controls the use of non-ansi features. - ** CHANGE it (define it) if you want Lua to avoid the use of any - ** non-ansi feature or library. - */ - //#if defined(__STRICT_ANSI__) - //#define LUA_ANSI - //#endif - - - //#if !defined(LUA_ANSI) && _WIN32 - //#define LUA_WIN - //#endif - - //#if defined(LUA_USE_LINUX) - //#define LUA_USE_POSIX - //#define LUA_USE_DLOPEN /* needs an extra library: -ldl */ - //#define LUA_USE_READLINE /* needs some extra libraries */ - //#endif - - //#if defined(LUA_USE_MACOSX) - //#define LUA_USE_POSIX - //#define LUA_DL_DYLD /* does not need extra library */ - //#endif - - - - /* - @@ LUA_USE_POSIX includes all functionallity listed as X/Open System - @* Interfaces Extension (XSI). - ** CHANGE it (define it) if your system is XSI compatible. - */ - //#if defined(LUA_USE_POSIX) - //#define LUA_USE_MKSTEMP - //#define LUA_USE_ISATTY - //#define LUA_USE_POPEN - //#define LUA_USE_ULONGJMP - //#endif - - - /* - @@ LUA_PATH and LUA_CPATH are the names of the environment variables that - @* Lua check to set its paths. - @@ LUA_INIT is the name of the environment variable that Lua - @* checks for initialization code. - ** CHANGE them if you want different names. - */ - public const string LUA_PATH = "LUA_PATH"; - public const string LUA_CPATH = "LUA_CPATH"; - public const string LUA_INIT = "LUA_INIT"; - - - /* - @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for - @* Lua libraries. - @@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for - @* C libraries. - ** CHANGE them if your machine has a non-conventional directory - ** hierarchy or if you want to install your libraries in - ** non-conventional directories. - */ - #if _WIN32 - /* - ** In Windows, any exclamation mark ('!') in the path is replaced by the - ** path of the directory of the executable file of the current process. - */ - public const string LUA_LDIR = "!\\lua\\"; - public const string LUA_CDIR = "!\\"; - public const string LUA_PATH_DEFAULT = - ".\\?.lua;" + LUA_LDIR + "?.lua;" + LUA_LDIR + "?\\init.lua;" - + LUA_CDIR + "?.lua;" + LUA_CDIR + "?\\init.lua"; - public const string LUA_CPATH_DEFAULT = - ".\\?.dll;" + LUA_CDIR + "?.dll;" + LUA_CDIR + "loadall.dll"; - - #else - public const string LUA_ROOT = "/usr/local/"; - public const string LUA_LDIR = LUA_ROOT + "share/lua/5.1/"; - public const string LUA_CDIR = LUA_ROOT + "lib/lua/5.1/"; - public const string LUA_PATH_DEFAULT = - "./?.lua;" + LUA_LDIR + "?.lua;" + LUA_LDIR + "?/init.lua;" + - LUA_CDIR + "?.lua;" + LUA_CDIR + "?/init.lua"; - public const string LUA_CPATH_DEFAULT = - "./?.so;" + LUA_CDIR + "?.so;" + LUA_CDIR + "loadall.so"; -#endif - - - /* - @@ LUA_DIRSEP is the directory separator (for submodules). - ** CHANGE it if your machine does not use "/" as the directory separator - ** and is not Windows. (On Windows Lua automatically uses "\".) - */ - #if _WIN32 - public const string LUA_DIRSEP = "\\"; - #else - public const string LUA_DIRSEP = "/"; -#endif - - - /* - @@ LUA_PATHSEP is the character that separates templates in a path. - @@ LUA_PATH_MARK is the string that marks the substitution points in a - @* template. - @@ LUA_EXECDIR in a Windows path is replaced by the executable's - @* directory. - @@ LUA_IGMARK is a mark to ignore all before it when bulding the - @* luaopen_ function name. - ** CHANGE them if for some reason your system cannot use those - ** characters. (E.g., if one of those characters is a common character - ** in file/directory names.) Probably you do not need to change them. - */ - public const string LUA_PATHSEP = ";"; - public const string LUA_PATH_MARK = "?"; - public const string LUA_EXECDIR = "!"; - public const string LUA_IGMARK = "-"; - - - /* - @@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. - ** CHANGE that if ptrdiff_t is not adequate on your machine. (On most - ** machines, ptrdiff_t gives a good choice between int or long.) - */ - //#define LUA_INTEGER ptrdiff_t - - - /* - @@ LUA_API is a mark for all core API functions. - @@ LUALIB_API is a mark for all standard library functions. - ** CHANGE them if you need to define those functions in some special way. - ** For instance, if you want to create one Windows DLL with the core and - ** the libraries, you may want to use the following definition (define - ** LUA_BUILD_AS_DLL to get it). - */ - //#if LUA_BUILD_AS_DLL - - //#if defined(LUA_CORE) || defined(LUA_LIB) - //#define LUA_API __declspec(dllexport) - //#else - //#define LUA_API __declspec(dllimport) - //#endif - - //#else - - //#define LUA_API extern - - //#endif - - /* more often than not the libs go together with the core */ - //#define LUALIB_API LUA_API - - - /* - @@ LUAI_FUNC is a mark for all extern functions that are not to be - @* exported to outside modules. - @@ LUAI_DATA is a mark for all extern (const) variables that are not to - @* be exported to outside modules. - ** CHANGE them if you need to mark them in some special way. Elf/gcc - ** (versions 3.2 and later) mark them as "hidden" to optimize access - ** when Lua is compiled as a shared library. - */ - //#if defined(luaall_c) - //#define LUAI_FUNC static - //#define LUAI_DATA /* empty */ - - //#elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ - // defined(__ELF__) - //#define LUAI_FUNC __attribute__((visibility("hidden"))) extern - //#define LUAI_DATA LUAI_FUNC - - //#else - //#define LUAI_FUNC extern - //#define LUAI_DATA extern - //#endif - - - - /* - @@ LUA_QL describes how error messages quote program elements. - ** CHANGE it if you want a different appearance. - */ - public static CharPtr LUA_QL(string x) {return "'" + x + "'";} - public static CharPtr LUA_QS {get {return LUA_QL("%s"); }} - - - /* - @@ LUA_IDSIZE gives the maximum size for the description of the source - @* of a function in debug information. - ** CHANGE it if you want a different size. - */ - public const int LUA_IDSIZE = 60; - - - /* - ** {================================================================== - ** Stand-alone configuration - ** =================================================================== - */ - - //#if lua_c || luaall_c - - /* - @@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that - @* is, whether we're running lua interactively). - ** CHANGE it if you have a better definition for non-POSIX/non-Windows - ** systems. - */ - #if LUA_USE_ISATTY - //#include - //#define lua_stdin_is_tty() isatty(0) - #elif LUA_WIN - //#include - //#include - //#define lua_stdin_is_tty() _isatty(_fileno(stdin)) - #else - public static int lua_stdin_is_tty() { return 1; } /* assume stdin is a tty */ - #endif - - - /* - @@ LUA_PROMPT is the default prompt used by stand-alone Lua. - @@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua. - ** CHANGE them if you want different prompts. (You can also change the - ** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.) - */ - public const string LUA_PROMPT = "> "; - public const string LUA_PROMPT2 = ">> "; - - - /* - @@ LUA_PROGNAME is the default name for the stand-alone Lua program. - ** CHANGE it if your stand-alone interpreter has a different name and - ** your system is not able to detect that name automatically. - */ - public const string LUA_PROGNAME = "lua"; - - - /* - @@ LUA_MAXINPUT is the maximum length for an input line in the - @* stand-alone interpreter. - ** CHANGE it if you need longer lines. - */ - public const int LUA_MAXINPUT = 512; - - - /* - @@ lua_readline defines how to show a prompt and then read a line from - @* the standard input. - @@ lua_saveline defines how to "save" a read line in a "history". - @@ lua_freeline defines how to free a line read by lua_readline. - ** CHANGE them if you want to improve this functionality (e.g., by using - ** GNU readline and history facilities). - */ -#if LUA_USE_READLINE - //#include - //#include - //#include - //#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != null) - //#define lua_saveline(L,idx) \ - // if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ - // add_history(lua_tostring(L, idx)); /* add it to history */ - //#define lua_freeline(L,b) ((void)L, free(b)) -#else - public static bool lua_readline(lua_State L, CharPtr b, CharPtr p) - { - fputs(p, stdout); - fflush(stdout); /* show prompt */ - return (fgets(b, stdin) != null); /* get line */ - } - public static void lua_saveline(lua_State L, int idx) {} - public static void lua_freeline(lua_State L, CharPtr b) {} -#endif - -//#endif - - /* }================================================================== */ - - - /* - @@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles - @* as a percentage. - ** CHANGE it if you want the GC to run faster or slower (higher values - ** mean larger pauses which mean slower collection.) You can also change - ** this value dynamically. - */ - public const int LUAI_GCPAUSE = 200; /* 200% (wait memory to double before next GC) */ - - - /* - @@ LUAI_GCMUL defines the default speed of garbage collection relative to - @* memory allocation as a percentage. - ** CHANGE it if you want to change the granularity of the garbage - ** collection. (Higher values mean coarser collections. 0 represents - ** infinity, where each step performs a full collection.) You can also - ** change this value dynamically. - */ - public const int LUAI_GCMUL = 200; /* GC runs 'twice the speed' of memory allocation */ - - /* - @@ LUA_COMPAT_GETN controls compatibility with old getn behavior. - ** CHANGE it (define it) if you want exact compatibility with the - ** behavior of setn/getn in Lua 5.0. - */ - //#undef LUA_COMPAT_GETN /* dotnet port doesn't define in the first place */ - - /* - @@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib. - ** CHANGE it to undefined as soon as you do not need a global 'loadlib' - ** function (the function is still available as 'package.loadlib'). - */ - //#undef LUA_COMPAT_LOADLIB /* dotnet port doesn't define in the first place */ - - /* - @@ LUA_COMPAT_VARARG controls compatibility with old vararg feature. - ** CHANGE it to undefined as soon as your programs use only '...' to - ** access vararg parameters (instead of the old 'arg' table). - */ - //#define LUA_COMPAT_VARARG /* defined higher up */ - - /* - @@ LUA_COMPAT_MOD controls compatibility with old math.mod function. - ** CHANGE it to undefined as soon as your programs use 'math.fmod' or - ** the new '%' operator instead of 'math.mod'. - */ - //#define LUA_COMPAT_MOD /* defined higher up */ - - /* - @@ LUA_COMPAT_LSTR controls compatibility with old long string nesting - @* facility. - ** CHANGE it to 2 if you want the old behaviour, or undefine it to turn - ** off the advisory error when nesting [[...]]. - */ - //#define LUA_COMPAT_LSTR 1 - //#define LUA_COMPAT_LSTR /* defined higher up */ - - /* - @@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name. - ** CHANGE it to undefined as soon as you rename 'string.gfind' to - ** 'string.gmatch'. - */ - //#define LUA_COMPAT_GFIND /* defined higher up */ - - /* - @@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib' - @* behavior. - ** CHANGE it to undefined as soon as you replace to 'luaL_register' - ** your uses of 'luaL_openlib' - */ - //#define LUA_COMPAT_OPENLIB /* defined higher up */ - - - - /* - @@ luai_apicheck is the assert macro used by the Lua-C API. - ** CHANGE luai_apicheck if you want Lua to perform some checks in the - ** parameters it gets from API calls. This may slow down the interpreter - ** a bit, but may be quite useful when debugging C code that interfaces - ** with Lua. A useful redefinition is to use assert.h. - */ - #if LUA_USE_APICHECK - public static void luai_apicheck(lua_State L, bool o) {Debug.Assert(o);} - public static void luai_apicheck(lua_State L, int o) {Debug.Assert(o != 0);} - #else - public static void luai_apicheck(lua_State L, bool o) {} - public static void luai_apicheck(lua_State L, int o) { } - #endif - - - /* - @@ LUAI_BITSINT defines the number of bits in an int. - ** CHANGE here if Lua cannot automatically detect the number of bits of - ** your machine. Probably you do not need to change this. - */ - /* avoid overflows in comparison */ - //#if INT_MAX-20 < 32760 - //public const int LUAI_BITSINT = 16 - //#elif INT_MAX > 2147483640L - /* int has at least 32 bits */ - public const int LUAI_BITSINT = 32; - //#else - //#error "you must define LUA_BITSINT with number of bits in an integer" - //#endif - - - /* - @@ LUAI_UINT32 is an unsigned integer with at least 32 bits. - @@ LUAI_INT32 is an signed integer with at least 32 bits. - @@ LUAI_UMEM is an unsigned integer big enough to count the total - @* memory used by Lua. - @@ LUAI_MEM is a signed integer big enough to count the total memory - @* used by Lua. - ** CHANGE here if for some weird reason the default definitions are not - ** good enough for your machine. (The definitions in the 'else' - ** part always works, but may waste space on machines with 64-bit - ** longs.) Probably you do not need to change this. - */ - //#if LUAI_BITSINT >= 32 - //#define LUAI_UINT32 unsigned int - //#define LUAI_INT32 int - //#define LUAI_MAXINT32 INT_MAX - //#define LUAI_UMEM uint - //#define LUAI_MEM ptrdiff_t - //#else - ///* 16-bit ints */ - //#define LUAI_UINT32 unsigned long - //#define LUAI_INT32 long - //#define LUAI_MAXINT32 LONG_MAX - //#define LUAI_UMEM unsigned long - //#define LUAI_MEM long - //#endif - - - /* - @@ LUAI_MAXCALLS limits the number of nested calls. - ** CHANGE it if you need really deep recursive calls. This limit is - ** arbitrary; its only purpose is to stop infinite recursion before - ** exhausting memory. - */ - public const int LUAI_MAXCALLS = 20000; - - - /* - @@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function - @* can use. - ** CHANGE it if you need lots of (Lua) stack space for your C - ** functions. This limit is arbitrary; its only purpose is to stop C - ** functions to consume unlimited stack space. (must be smaller than - ** -LUA_REGISTRYINDEX) - */ - public const int LUAI_MAXCSTACK = 8000; - - - - /* - ** {================================================================== - ** CHANGE (to smaller values) the following definitions if your system - ** has a small C stack. (Or you may want to change them to larger - ** values if your system has a large C stack and these limits are - ** too rigid for you.) Some of these constants control the size of - ** stack-allocated arrays used by the compiler or the interpreter, while - ** others limit the maximum number of recursive calls that the compiler - ** or the interpreter can perform. Values too large may cause a C stack - ** overflow for some forms of deep constructs. - ** =================================================================== - */ - - - /* - @@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and - @* syntactical nested non-terminals in a program. - */ - public const int LUAI_MAXCCALLS = 200; - - - /* - @@ LUAI_MAXVARS is the maximum number of local variables per function - @* (must be smaller than 250). - */ - public const int LUAI_MAXVARS = 200; - - - /* - @@ LUAI_MAXUPVALUES is the maximum number of upvalues per function - @* (must be smaller than 250). - */ - public const int LUAI_MAXUPVALUES = 60; - - - /* - @@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. - */ - public const int LUAL_BUFFERSIZE = 1024; // BUFSIZ; todo: check this - mjf - - /* }================================================================== */ - - - - - /* - ** {================================================================== - @@ LUA_NUMBER is the type of numbers in Lua. - ** CHANGE the following definitions only if you want to build Lua - ** with a number type different from double. You may also need to - ** change lua_number2int & lua_number2integer. - ** =================================================================== - */ - - //#define LUA_NUMBER_DOUBLE - //#define LUA_NUMBER double /* declared in dotnet build with using statement */ - - /* - @@ LUAI_UACNUMBER is the result of an 'usual argument conversion' - @* over a number. - */ - //#define LUAI_UACNUMBER double /* declared in dotnet build with using statement */ - - - /* - @@ LUA_NUMBER_SCAN is the format for reading numbers. - @@ LUA_NUMBER_FMT is the format for writing numbers. - @@ lua_number2str converts a number to a string. - @@ LUAI_MAXNUMBER2STR is maximum size of previous conversion. - @@ lua_str2number converts a string to a number. - */ - public const string LUA_NUMBER_SCAN = "%lf"; - public const string LUA_NUMBER_FMT = "%.14g"; - public static CharPtr lua_number2str(double n) { return String.Format("{0}", n); } - public const int LUAI_MAXNUMBER2STR = 32; /* 16 digits, sign, point, and \0 */ - - private const string number_chars = "0123456789+-eE."; - public static double lua_str2number(CharPtr s, out CharPtr end) - { - end = new CharPtr(s.chars, s.index); - string str = ""; - while (end[0] == ' ') - end = end.next(); - while (number_chars.IndexOf(end[0]) >= 0) - { - str += end[0]; - end = end.next(); - } - - try - { - return Convert.ToDouble(str.ToString(), Culture("en-US")); - } - catch (System.OverflowException) - { - // this is a hack, fix it - mjf - if (str[0] == '-') - return System.Double.NegativeInfinity; - else - return System.Double.PositiveInfinity; - } - catch - { - end = new CharPtr(s.chars, s.index); - return 0; - } - } - - private static IFormatProvider Culture(string p) - { -#if SILVERLIGHT - return new CultureInfo(p); -#else - return CultureInfo.GetCultureInfo(p); -#endif - } - - /* - @@ The luai_num* macros define the primitive operations over numbers. - */ - #if LUA_CORE - //#include - public delegate lua_Number op_delegate(lua_Number a, lua_Number b); - public static lua_Number luai_numadd(lua_Number a, lua_Number b) { return ((a) + (b)); } - public static lua_Number luai_numsub(lua_Number a, lua_Number b) { return ((a) - (b)); } - public static lua_Number luai_nummul(lua_Number a, lua_Number b) { return ((a) * (b)); } - public static lua_Number luai_numdiv(lua_Number a, lua_Number b) { return ((a) / (b)); } - public static lua_Number luai_nummod(lua_Number a, lua_Number b) { return ((a) - Math.Floor((a) / (b)) * (b)); } - public static lua_Number luai_numpow(lua_Number a, lua_Number b) { return (Math.Pow(a, b)); } - public static lua_Number luai_numunm(lua_Number a) { return (-(a)); } - public static bool luai_numeq(lua_Number a, lua_Number b) { return ((a) == (b)); } - public static bool luai_numlt(lua_Number a, lua_Number b) { return ((a) < (b)); } - public static bool luai_numle(lua_Number a, lua_Number b) { return ((a) <= (b)); } - public static bool luai_numisnan(lua_Number a) { return lua_Number.IsNaN(a); } - #endif - - - /* - @@ lua_number2int is a macro to convert lua_Number to int. - @@ lua_number2integer is a macro to convert lua_Number to lua_Integer. - ** CHANGE them if you know a faster way to convert a lua_Number to - ** int (with any rounding method and without throwing errors) in your - ** system. In Pentium machines, a naive typecast from double to int - ** in C is extremely slow, so any alternative is worth trying. - */ - - /* On a Pentium, resort to a trick */ - //#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \ - // (defined(__i386) || defined (_M_IX86) || defined(__i386__)) - - /* On a Microsoft compiler, use assembler */ - //#if defined(_MSC_VER) - - //#define lua_number2int(i,d) __asm fld d __asm fistp i - //#define lua_number2integer(i,n) lua_number2int(i, n) - - /* the next trick should work on any Pentium, but sometimes clashes - with a DirectX idiosyncrasy */ - //#else - - //union luai_Cast { double l_d; long l_l; }; - //#define lua_number2int(i,d) \ - // { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; } - //#define lua_number2integer(i,n) lua_number2int(i, n) - - //#endif - - - /* this option always works, but may be slow */ - //#else - //#define lua_number2int(i,d) ((i)=(int)(d)) - //#define lua_number2integer(i,d) ((i)=(lua_Integer)(d)) - - //#endif - - private static void lua_number2int(out int i,lua_Number d) {i = (int)d;} - private static void lua_number2integer(out int i, lua_Number n) { i = (int)n; } - - /* }================================================================== */ - - - /* - @@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment. - ** CHANGE it if your system requires alignments larger than double. (For - ** instance, if your system supports long doubles and they must be - ** aligned in 16-byte boundaries, then you should add long double in the - ** union.) Probably you do not need to change this. - */ - //#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } - - public class LuaException : Exception - { - public lua_State L; - public lua_longjmp c; - - public LuaException(lua_State L, lua_longjmp c) { this.L = L; this.c = c; } - } - - /* - @@ LUAI_THROW/LUAI_TRY define how Lua does exception handling. - ** CHANGE them if you prefer to use longjmp/setjmp even with C++ - ** or if want/don't to use _longjmp/_setjmp instead of regular - ** longjmp/setjmp. By default, Lua handles errors with exceptions when - ** compiling as C++ code, with _longjmp/_setjmp when asked to use them, - ** and with longjmp/setjmp otherwise. - */ - //#if defined(__cplusplus) - ///* C++ exceptions */ - public static void LUAI_THROW(lua_State L, lua_longjmp c) {throw new LuaException(L, c);} - //#define LUAI_TRY(L,c,a) try { a } catch(...) \ - // { if ((c).status == 0) (c).status = -1; } - public static void LUAI_TRY(lua_State L, lua_longjmp c, object a) { - if (c.status == 0) c.status = -1; - } - //#define luai_jmpbuf int /* dummy variable */ - - //#elif defined(LUA_USE_ULONGJMP) - ///* in Unix, try _longjmp/_setjmp (more efficient) */ - //#define LUAI_THROW(L,c) _longjmp((c).b, 1) - //#define LUAI_TRY(L,c,a) if (_setjmp((c).b) == 0) { a } - //#define luai_jmpbuf jmp_buf - - //#else - ///* default handling with long jumps */ - //public static void LUAI_THROW(lua_State L, lua_longjmp c) { c.b(1); } - //#define LUAI_TRY(L,c,a) if (setjmp((c).b) == 0) { a } - //#define luai_jmpbuf jmp_buf - - //#endif - - - /* - @@ LUA_MAXCAPTURES is the maximum number of captures that a pattern - @* can do during pattern-matching. - ** CHANGE it if you need more captures. This limit is arbitrary. - */ - public const int LUA_MAXCAPTURES = 32; - - - /* - @@ lua_tmpnam is the function that the OS library uses to create a - @* temporary name. - @@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam. - ** CHANGE them if you have an alternative to tmpnam (which is considered - ** insecure) or if you want the original tmpnam anyway. By default, Lua - ** uses tmpnam except when POSIX is available, where it uses mkstemp. - */ - #if loslib_c || luaall_c - - #if LUA_USE_MKSTEMP - //#include - public const int LUA_TMPNAMBUFSIZE = 32; - //#define lua_tmpnam(b,e) { \ - // strcpy(b, "/tmp/lua_XXXXXX"); \ - // e = mkstemp(b); \ - // if (e != -1) close(e); \ - // e = (e == -1); } - - #else - public const int LUA_TMPNAMBUFSIZE = L_tmpnam; - public static void lua_tmpnam(CharPtr b, int e) { e = (tmpnam(b) == null) ? 1 : 0; } - #endif - - #endif - - - /* - @@ lua_popen spawns a new process connected to the current one through - @* the file streams. - ** CHANGE it if you have a way to implement it in your system. - */ - //#if LUA_USE_POPEN - - //#define lua_popen(L,c,m) ((void)L, fflush(null), popen(c,m)) - //#define lua_pclose(L,file) ((void)L, (pclose(file) != -1)) - - //#elif LUA_WIN - - //#define lua_popen(L,c,m) ((void)L, _popen(c,m)) - //#define lua_pclose(L,file) ((void)L, (_pclose(file) != -1)) - - //#else - - public static Stream lua_popen(lua_State L, CharPtr c, CharPtr m) { luaL_error(L, LUA_QL("popen") + " not supported"); return null; } - public static int lua_pclose(lua_State L, Stream file) { return 0; } - - //#endif - - /* - @@ LUA_DL_* define which dynamic-library system Lua should use. - ** CHANGE here if Lua has problems choosing the appropriate - ** dynamic-library system for your platform (either Windows' DLL, Mac's - ** dyld, or Unix's dlopen). If your system is some kind of Unix, there - ** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for - ** it. To use dlopen you also need to adapt the src/Makefile (probably - ** adding -ldl to the linker options), so Lua does not select it - ** automatically. (When you change the makefile to add -ldl, you must - ** also add -DLUA_USE_DLOPEN.) - ** If you do not want any kind of dynamic library, undefine all these - ** options. - ** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD. - */ - //#if LUA_USE_DLOPEN - //#define LUA_DL_DLOPEN - //#endif - - //#if LUA_WIN - //#define LUA_DL_DLL - //#endif - - - /* - @@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State - @* (the data goes just *before* the lua_State pointer). - ** CHANGE (define) this if you really need that. This value must be - ** a multiple of the maximum alignment required for your machine. - */ - public const int LUAI_EXTRASPACE = 0; - - - /* - @@ luai_userstate* allow user-specific actions on threads. - ** CHANGE them if you defined LUAI_EXTRASPACE and need to do something - ** extra when a thread is created/deleted/resumed/yielded. - */ - public static void luai_userstateopen(lua_State L) {} - public static void luai_userstateclose(lua_State L) {} - public static void luai_userstatethread(lua_State L, lua_State L1) {} - public static void luai_userstatefree(lua_State L) {} - public static void luai_userstateresume(lua_State L,int n) {} - public static void luai_userstateyield(lua_State L,int n) {} - - - /* - @@ LUA_INTFRMLEN is the length modifier for integer conversions - @* in 'string.format'. - @@ LUA_INTFRM_T is the integer type correspoding to the previous length - @* modifier. - ** CHANGE them if your system supports long long or does not support long. - */ - - #if LUA_USELONGLONG - - public const string LUA_INTFRMLEN = "ll"; - //#define LUA_INTFRM_T long long - - #else - - public const string LUA_INTFRMLEN = "l"; - //#define LUA_INTFRM_T long /* declared in dotnet build with using statement */ - - #endif - - - - /* =================================================================== */ - - /* - ** Local configuration. You can use this space to add your redefinitions - ** without modifying the main part of the file. - */ - - // misc stuff needed for the compile - - public static bool isalpha(char c) { return Char.IsLetter(c); } - public static bool iscntrl(char c) { return Char.IsControl(c); } - public static bool isdigit(char c) { return Char.IsDigit(c); } - public static bool islower(char c) { return Char.IsLower(c); } - public static bool ispunct(char c) { return Char.IsPunctuation(c); } - public static bool isspace(char c) { return (c==' ') || (c>=(char)0x09 && c<=(char)0x0D); } - public static bool isupper(char c) { return Char.IsUpper(c); } - public static bool isalnum(char c) { return Char.IsLetterOrDigit(c); } - public static bool isxdigit(char c) { return "0123456789ABCDEFabcdef".IndexOf(c) >= 0; } - - public static bool isalpha(int c) { return Char.IsLetter((char)c); } - public static bool iscntrl(int c) { return Char.IsControl((char)c); } - public static bool isdigit(int c) { return Char.IsDigit((char)c); } - public static bool islower(int c) { return Char.IsLower((char)c); } - public static bool ispunct(int c) { return ((char)c != ' ') && !isalnum((char)c); } // *not* the same as Char.IsPunctuation - public static bool isspace(int c) { return ((char)c == ' ') || ((char)c >= (char)0x09 && (char)c <= (char)0x0D); } - public static bool isupper(int c) { return Char.IsUpper((char)c); } - public static bool isalnum(int c) { return Char.IsLetterOrDigit((char)c); } - - public static char tolower(char c) { return Char.ToLower(c); } - public static char toupper(char c) { return Char.ToUpper(c); } - public static char tolower(int c) { return Char.ToLower((char)c); } - public static char toupper(int c) { return Char.ToUpper((char)c); } - - [CLSCompliantAttribute(false)] - public static ulong strtoul(CharPtr s, out CharPtr end, int base_) - { - try - { - end = new CharPtr(s.chars, s.index); - - // skip over any leading whitespace - while (end[0] == ' ') - end = end.next(); - - // ignore any leading 0x - if ((end[0] == '0') && (end[1] == 'x')) - end = end.next().next(); - else if ((end[0] == '0') && (end[1] == 'X')) - end = end.next().next(); - - // do we have a leading + or - sign? - bool negate = false; - if (end[0] == '+') - end = end.next(); - else if (end[0] == '-') - { - negate = true; - end = end.next(); - } - - // loop through all chars - bool invalid = false; - bool had_digits = false; - ulong result = 0; - while (true) - { - // get this char - char ch = end[0]; - - // which digit is this? - int this_digit = 0; - if (isdigit(ch)) - this_digit = ch - '0'; - else if (isalpha(ch)) - this_digit = tolower(ch) - 'a' + 10; - else - break; - - // is this digit valid? - if (this_digit >= base_) - invalid = true; - else - { - had_digits = true; - result = result * (ulong)base_ + (ulong)this_digit; - } - - end = end.next(); - } - - // were any of the digits invalid? - if (invalid || (!had_digits)) - { - end = s; - return System.UInt64.MaxValue; - } - - // if the value was a negative then negate it here - if (negate) - result = (ulong)-(long)result; - - // ok, we're done - return (ulong)result; - } - catch - { - end = s; - return 0; - } - } - - public static void putchar(char ch) - { - Console.Write(ch); - } - - public static void putchar(int ch) - { - Console.Write((char)ch); - } - - public static bool isprint(byte c) - { - return (c >= (byte)' ') && (c <= (byte)127); - } - - public static int parse_scanf(string str, CharPtr fmt, params object[] argp) - { - int parm_index = 0; - int index = 0; - while (fmt[index] != 0) - { - if (fmt[index++]=='%') - switch (fmt[index++]) - { - case 's': - { - argp[parm_index++] = str; - break; - } - case 'c': - { - argp[parm_index++] = Convert.ToChar(str, Culture("en-US")); - break; - } - case 'd': - { - argp[parm_index++] = Convert.ToInt32(str, Culture("en-US")); - break; - } - case 'l': - { - argp[parm_index++] = Convert.ToDouble(str, Culture("en-US")); - break; - } - case 'f': - { - argp[parm_index++] = Convert.ToDouble(str, Culture("en-US")); - break; - } - //case 'p': - // { - // result += "(pointer)"; - // break; - // } - } - } - return parm_index; - } - - public static void printf(CharPtr str, params object[] argv) - { - Tools.printf(str.ToString(), argv); - } - - public static void sprintf(CharPtr buffer, CharPtr str, params object[] argv) - { - string temp = Tools.sprintf(str.ToString(), argv); - strcpy(buffer, temp); - } - - public static int fprintf(Stream stream, CharPtr str, params object[] argv) - { - string result = Tools.sprintf(str.ToString(), argv); - char[] chars = result.ToCharArray(); - byte[] bytes = new byte[chars.Length]; - for (int i=0; i(CharPtr ptr1, CharPtr ptr2) { - Debug.Assert(ptr1.chars == ptr2.chars); return ptr1.index > ptr2.index; } - public static bool operator >=(CharPtr ptr1, CharPtr ptr2) { - Debug.Assert(ptr1.chars == ptr2.chars); return ptr1.index >= ptr2.index; } - public static bool operator ==(CharPtr ptr1, CharPtr ptr2) { - object o1 = ptr1 as CharPtr; - object o2 = ptr2 as CharPtr; - if ((o1 == null) && (o2 == null)) return true; - if (o1 == null) return false; - if (o2 == null) return false; - return (ptr1.chars == ptr2.chars) && (ptr1.index == ptr2.index); } - public static bool operator !=(CharPtr ptr1, CharPtr ptr2) {return !(ptr1 == ptr2); } - - public override bool Equals(object o) - { - return this == (o as CharPtr); - } - - public override int GetHashCode() - { - return 0; - } - public override string ToString() - { - string result = ""; - for (int i = index; (i 0)) - dst[dst_index++] = src[src_index++]; - return dst; - } - - [CLSCompliantAttribute(false)] - public static uint strcspn(CharPtr str, CharPtr charset) - { - int index = str.ToString().IndexOfAny(charset.ToString().ToCharArray()); - if (index < 0) - index = str.ToString().Length; - return (uint)index; - } - - public static CharPtr strncpy(CharPtr dst, CharPtr src, int length) - { - int index = 0; - while ((src[index] != '\0') && (index 0) - f.Seek(-1, SeekOrigin.Current); - } - -#if XBOX || SILVERLIGHT - public static Stream stdout; - public static Stream stdin; - public static Stream stderr; -#else - public static Stream stdout = Console.OpenStandardOutput(); - public static Stream stdin = Console.OpenStandardInput(); - public static Stream stderr = Console.OpenStandardError(); -#endif - public static int EOF = -1; - - public static void fputs(CharPtr str, Stream stream) - { - Console.Write(str.ToString()); - } - - public static int feof(Stream s) - { - return (s.Position >= s.Length) ? 1 : 0; - } - - public static int fread(CharPtr ptr, int size, int num, Stream stream) - { - int num_bytes = num * size; - byte[] bytes = new byte[num_bytes]; - try - { - int result = stream.Read(bytes, 0, num_bytes); - for (int i = 0; i < result; i++) - ptr[i] = (char)bytes[i]; - return result/size; - } - catch - { - return 0; - } - } - - public static int fwrite(CharPtr ptr, int size, int num, Stream stream) - { - int num_bytes = num * size; - byte[] bytes = new byte[num_bytes]; - for (int i = 0; i < num_bytes; i++) - bytes[i] = (byte)ptr[i]; - try - { - stream.Write(bytes, 0, num_bytes); - } - catch - { - return 0; - } - return num; - } - - public static int strcmp(CharPtr s1, CharPtr s2) - { - if (s1 == s2) - return 0; - if (s1 == null) - return -1; - if (s2 == null) - return 1; - - for (int i = 0; ; i++) - { - if (s1[i] != s2[i]) - { - if (s1[i] < s2[i]) - return -1; - else - return 1; - } - if (s1[i] == '\0') - return 0; - } - } - - public static CharPtr fgets(CharPtr str, Stream stream) - { - int index = 0; - try - { - while (true) - { - str[index] = (char)stream.ReadByte(); - if (str[index] == '\n') - break; - if (index >= str.chars.Length) - break; - index++; - } - } - catch - { - } - return str; - } - - public static double frexp(double x, out int expptr) - { -#if XBOX - expptr = (int)(Math.Log(x) / Math.Log(2)) + 1; -#else - expptr = (int)Math.Log(x, 2) + 1; -#endif - double s = x / Math.Pow(2, expptr); - return s; - } - - public static double ldexp(double x, int expptr) - { - return x * Math.Pow(2, expptr); - } - - public static CharPtr strstr(CharPtr str, CharPtr substr) - { - int index = str.ToString().IndexOf(substr.ToString()); - if (index < 0) - return null; - return new CharPtr(str + index); - } - - public static CharPtr strrchr(CharPtr str, char ch) - { - int index = str.ToString().LastIndexOf(ch); - if (index < 0) - return null; - return str + index; - } - - public static Stream fopen(CharPtr filename, CharPtr mode) - { - string str = filename.ToString(); - FileMode filemode = FileMode.Open; - FileAccess fileaccess = (FileAccess)0; - for (int i=0; mode[i] != '\0'; i++) - switch (mode[i]) - { - case 'r': - fileaccess = fileaccess | FileAccess.Read; - if (!File.Exists(str)) - return null; - break; - - case 'w': - filemode = FileMode.Create; - fileaccess = fileaccess | FileAccess.Write; - break; - } - try - { - return new FileStream(str, filemode, fileaccess); - } - catch - { - return null; - } - } - - public static Stream freopen(CharPtr filename, CharPtr mode, Stream stream) - { - try - { - stream.Flush(); - stream.Close(); - } - catch { } - - return fopen(filename, mode); - } - - public static void fflush(Stream stream) - { - stream.Flush(); - } - - public static int ferror(Stream stream) - { - return 0; // todo: fix this - mjf - } - - public static int fclose(Stream stream) - { - stream.Close(); - return 0; - } - -#if !XBOX - public static Stream tmpfile() - { - return new FileStream(Path.GetTempFileName(), FileMode.Create, FileAccess.ReadWrite); - } -#endif - - public static int fscanf(Stream f, CharPtr format, params object[] argp) - { - string str = Console.ReadLine(); - return parse_scanf(str, format, argp); - } - - public static int fseek(Stream f, long offset, int origin) - { - try - { - f.Seek(offset, (SeekOrigin)origin); - return 0; - } - catch - { - return 1; - } - } - - - public static int ftell(Stream f) - { - return (int)f.Position; - } - - public static int clearerr(Stream f) - { - //Debug.Assert(false, "clearerr not implemented yet - mjf"); - return 0; - } - - [CLSCompliantAttribute(false)] - public static int setvbuf(Stream stream, CharPtr buffer, int mode, uint size) - { - Debug.Assert(false, "setvbuf not implemented yet - mjf"); - return 0; - } - - public static void memcpy(T[] dst, T[] src, int length) - { - for (int i = 0; i < length; i++) - dst[i] = src[i]; - } - - public static void memcpy(T[] dst, int offset, T[] src, int length) - { - for (int i=0; i(T[] dst, T[] src, int srcofs, int length) - { - for (int i = 0; i < length; i++) - dst[i] = src[srcofs+i]; - } - - [CLSCompliantAttribute(false)] - public static void memcpy(CharPtr ptr1, CharPtr ptr2, uint size) { memcpy(ptr1, ptr2, (int)size); } - public static void memcpy(CharPtr ptr1, CharPtr ptr2, int size) - { - for (int i = 0; i < size; i++) - ptr1[i] = ptr2[i]; - } - - public static object VOID(object f) { return f; } - - public const double HUGE_VAL = System.Double.MaxValue; - [CLSCompliantAttribute(false)] - public const uint SHRT_MAX = System.UInt16.MaxValue; - - [CLSCompliantAttribute(false)] - public const int _IONBF = 0; - [CLSCompliantAttribute(false)] - public const int _IOFBF = 1; - [CLSCompliantAttribute(false)] - public const int _IOLBF = 2; - - public const int SEEK_SET = 0; - public const int SEEK_CUR = 1; - public const int SEEK_END = 2; - - // one of the primary objectives of this port is to match the C version of Lua as closely as - // possible. a key part of this is also matching the behaviour of the garbage collector, as - // that affects the operation of things such as weak tables. in order for this to occur the - // size of structures that are allocated must be reported as identical to their C++ equivelents. - // that this means that variables such as global_State.totalbytes no longer indicate the true - // amount of memory allocated. - public static int GetUnmanagedSize(Type t) - { - if (t == typeof(global_State)) - return 228; - else if (t == typeof(LG)) - return 376; - else if (t == typeof(CallInfo)) - return 24; - else if (t == typeof(lua_TValue)) - return 16; - else if (t == typeof(Table)) - return 32; - else if (t == typeof(Node)) - return 32; - else if (t == typeof(GCObject)) - return 120; - else if (t == typeof(GCObjectRef)) - return 4; - else if (t == typeof(ArrayRef)) - return 4; - else if (t == typeof(Closure)) - return 0; // handle this one manually in the code - else if (t == typeof(Proto)) - return 76; - else if (t == typeof(luaL_Reg)) - return 8; - else if (t == typeof(luaL_Buffer)) - return 524; - else if (t == typeof(lua_State)) - return 120; - else if (t == typeof(lua_Debug)) - return 100; - else if (t == typeof(CallS)) - return 8; - else if (t == typeof(LoadF)) - return 520; - else if (t == typeof(LoadS)) - return 8; - else if (t == typeof(lua_longjmp)) - return 72; - else if (t == typeof(SParser)) - return 20; - else if (t == typeof(Token)) - return 16; - else if (t == typeof(LexState)) - return 52; - else if (t == typeof(FuncState)) - return 572; - else if (t == typeof(GCheader)) - return 8; - else if (t == typeof(lua_TValue)) - return 16; - else if (t == typeof(TString)) - return 16; - else if (t == typeof(LocVar)) - return 12; - else if (t == typeof(UpVal)) - return 32; - else if (t == typeof(CClosure)) - return 40; - else if (t == typeof(LClosure)) - return 24; - else if (t == typeof(TKey)) - return 16; - else if (t == typeof(ConsControl)) - return 40; - else if (t == typeof(LHS_assign)) - return 32; - else if (t == typeof(expdesc)) - return 24; - else if (t == typeof(upvaldesc)) - return 2; - else if (t == typeof(BlockCnt)) - return 12; - else if (t == typeof(Zio)) - return 20; - else if (t == typeof(Mbuffer)) - return 12; - else if (t == typeof(LoadState)) - return 16; - else if (t == typeof(MatchState)) - return 272; - else if (t == typeof(stringtable)) - return 12; - else if (t == typeof(FilePtr)) - return 4; - else if (t == typeof(Udata)) - return 24; - else if (t == typeof(Char)) - return 1; - else if (t == typeof(UInt16)) - return 2; - else if (t == typeof(Int16)) - return 2; - else if (t == typeof(UInt32)) - return 4; - else if (t == typeof(Int32)) - return 4; - else if (t == typeof(Single)) - return 4; - Debug.Assert(false, "Trying to get unknown sized of unmanaged type " + t.ToString()); - return 0; - } - } -} +/* +** $Id: luaconf.h,v 1.82.1.7 2008/02/11 16:25:08 roberto Exp $ +** Configuration file for Lua +** See Copyright Notice in lua.h +*/ + +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; +using AT.MIN; + +namespace KopiLua +{ + using LUA_INTEGER = System.Int32; + using LUA_NUMBER = System.Double; + using LUAI_UACNUMBER = System.Double; + using LUA_INTFRM_T = System.Int64; + using TValue = Lua.lua_TValue; + using lua_Number = System.Double; + using System.Globalization; + + public partial class Lua + { + /* + ** ================================================================== + ** Search for "@@" to find all configurable definitions. + ** =================================================================== + */ + + + /* + @@ LUA_ANSI controls the use of non-ansi features. + ** CHANGE it (define it) if you want Lua to avoid the use of any + ** non-ansi feature or library. + */ + //#if defined(__STRICT_ANSI__) + //#define LUA_ANSI + //#endif + + + //#if !defined(LUA_ANSI) && _WIN32 + //#define LUA_WIN + //#endif + + //#if defined(LUA_USE_LINUX) + //#define LUA_USE_POSIX + //#define LUA_USE_DLOPEN /* needs an extra library: -ldl */ + //#define LUA_USE_READLINE /* needs some extra libraries */ + //#endif + + //#if defined(LUA_USE_MACOSX) + //#define LUA_USE_POSIX + //#define LUA_DL_DYLD /* does not need extra library */ + //#endif + + + + /* + @@ LUA_USE_POSIX includes all functionallity listed as X/Open System + @* Interfaces Extension (XSI). + ** CHANGE it (define it) if your system is XSI compatible. + */ + //#if defined(LUA_USE_POSIX) + //#define LUA_USE_MKSTEMP + //#define LUA_USE_ISATTY + //#define LUA_USE_POPEN + //#define LUA_USE_ULONGJMP + //#endif + + + /* + @@ LUA_PATH and LUA_CPATH are the names of the environment variables that + @* Lua check to set its paths. + @@ LUA_INIT is the name of the environment variable that Lua + @* checks for initialization code. + ** CHANGE them if you want different names. + */ + public const string LUA_PATH = "LUA_PATH"; + public const string LUA_CPATH = "LUA_CPATH"; + public const string LUA_INIT = "LUA_INIT"; + + + /* + @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for + @* Lua libraries. + @@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for + @* C libraries. + ** CHANGE them if your machine has a non-conventional directory + ** hierarchy or if you want to install your libraries in + ** non-conventional directories. + */ + #if _WIN32 + /* + ** In Windows, any exclamation mark ('!') in the path is replaced by the + ** path of the directory of the executable file of the current process. + */ + public const string LUA_LDIR = "!\\lua\\"; + public const string LUA_CDIR = "!\\"; + public const string LUA_PATH_DEFAULT = + ".\\?.lua;" + LUA_LDIR + "?.lua;" + LUA_LDIR + "?\\init.lua;" + + LUA_CDIR + "?.lua;" + LUA_CDIR + "?\\init.lua"; + public const string LUA_CPATH_DEFAULT = + ".\\?.dll;" + LUA_CDIR + "?.dll;" + LUA_CDIR + "loadall.dll"; + + #else + public const string LUA_ROOT = "/usr/local/"; + public const string LUA_LDIR = LUA_ROOT + "share/lua/5.1/"; + public const string LUA_CDIR = LUA_ROOT + "lib/lua/5.1/"; + public const string LUA_PATH_DEFAULT = + "./?.lua;" + LUA_LDIR + "?.lua;" + LUA_LDIR + "?/init.lua;" + + LUA_CDIR + "?.lua;" + LUA_CDIR + "?/init.lua"; + public const string LUA_CPATH_DEFAULT = + "./?.so;" + LUA_CDIR + "?.so;" + LUA_CDIR + "loadall.so"; +#endif + + + /* + @@ LUA_DIRSEP is the directory separator (for submodules). + ** CHANGE it if your machine does not use "/" as the directory separator + ** and is not Windows. (On Windows Lua automatically uses "\".) + */ + #if _WIN32 + public const string LUA_DIRSEP = "\\"; + #else + public const string LUA_DIRSEP = "/"; +#endif + + + /* + @@ LUA_PATHSEP is the character that separates templates in a path. + @@ LUA_PATH_MARK is the string that marks the substitution points in a + @* template. + @@ LUA_EXECDIR in a Windows path is replaced by the executable's + @* directory. + @@ LUA_IGMARK is a mark to ignore all before it when bulding the + @* luaopen_ function name. + ** CHANGE them if for some reason your system cannot use those + ** characters. (E.g., if one of those characters is a common character + ** in file/directory names.) Probably you do not need to change them. + */ + public const string LUA_PATHSEP = ";"; + public const string LUA_PATH_MARK = "?"; + public const string LUA_EXECDIR = "!"; + public const string LUA_IGMARK = "-"; + + + /* + @@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger. + ** CHANGE that if ptrdiff_t is not adequate on your machine. (On most + ** machines, ptrdiff_t gives a good choice between int or long.) + */ + //#define LUA_INTEGER ptrdiff_t + + + /* + @@ LUA_API is a mark for all core API functions. + @@ LUALIB_API is a mark for all standard library functions. + ** CHANGE them if you need to define those functions in some special way. + ** For instance, if you want to create one Windows DLL with the core and + ** the libraries, you may want to use the following definition (define + ** LUA_BUILD_AS_DLL to get it). + */ + //#if LUA_BUILD_AS_DLL + + //#if defined(LUA_CORE) || defined(LUA_LIB) + //#define LUA_API __declspec(dllexport) + //#else + //#define LUA_API __declspec(dllimport) + //#endif + + //#else + + //#define LUA_API extern + + //#endif + + /* more often than not the libs go together with the core */ + //#define LUALIB_API LUA_API + + + /* + @@ LUAI_FUNC is a mark for all extern functions that are not to be + @* exported to outside modules. + @@ LUAI_DATA is a mark for all extern (const) variables that are not to + @* be exported to outside modules. + ** CHANGE them if you need to mark them in some special way. Elf/gcc + ** (versions 3.2 and later) mark them as "hidden" to optimize access + ** when Lua is compiled as a shared library. + */ + //#if defined(luaall_c) + //#define LUAI_FUNC static + //#define LUAI_DATA /* empty */ + + //#elif defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ + // defined(__ELF__) + //#define LUAI_FUNC __attribute__((visibility("hidden"))) extern + //#define LUAI_DATA LUAI_FUNC + + //#else + //#define LUAI_FUNC extern + //#define LUAI_DATA extern + //#endif + + + + /* + @@ LUA_QL describes how error messages quote program elements. + ** CHANGE it if you want a different appearance. + */ + public static CharPtr LUA_QL(string x) {return "'" + x + "'";} + public static CharPtr LUA_QS {get {return LUA_QL("%s"); }} + + + /* + @@ LUA_IDSIZE gives the maximum size for the description of the source + @* of a function in debug information. + ** CHANGE it if you want a different size. + */ + public const int LUA_IDSIZE = 60; + + + /* + ** {================================================================== + ** Stand-alone configuration + ** =================================================================== + */ + + //#if lua_c || luaall_c + + /* + @@ lua_stdin_is_tty detects whether the standard input is a 'tty' (that + @* is, whether we're running lua interactively). + ** CHANGE it if you have a better definition for non-POSIX/non-Windows + ** systems. + */ + #if LUA_USE_ISATTY + //#include + //#define lua_stdin_is_tty() isatty(0) + #elif LUA_WIN + //#include + //#include + //#define lua_stdin_is_tty() _isatty(_fileno(stdin)) + #else + public static int lua_stdin_is_tty() { return 1; } /* assume stdin is a tty */ + #endif + + + /* + @@ LUA_PROMPT is the default prompt used by stand-alone Lua. + @@ LUA_PROMPT2 is the default continuation prompt used by stand-alone Lua. + ** CHANGE them if you want different prompts. (You can also change the + ** prompts dynamically, assigning to globals _PROMPT/_PROMPT2.) + */ + public const string LUA_PROMPT = "> "; + public const string LUA_PROMPT2 = ">> "; + + + /* + @@ LUA_PROGNAME is the default name for the stand-alone Lua program. + ** CHANGE it if your stand-alone interpreter has a different name and + ** your system is not able to detect that name automatically. + */ + public const string LUA_PROGNAME = "lua"; + + + /* + @@ LUA_MAXINPUT is the maximum length for an input line in the + @* stand-alone interpreter. + ** CHANGE it if you need longer lines. + */ + public const int LUA_MAXINPUT = 512; + + + /* + @@ lua_readline defines how to show a prompt and then read a line from + @* the standard input. + @@ lua_saveline defines how to "save" a read line in a "history". + @@ lua_freeline defines how to free a line read by lua_readline. + ** CHANGE them if you want to improve this functionality (e.g., by using + ** GNU readline and history facilities). + */ +#if LUA_USE_READLINE + //#include + //#include + //#include + //#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != null) + //#define lua_saveline(L,idx) \ + // if (lua_strlen(L,idx) > 0) /* non-empty line? */ \ + // add_history(lua_tostring(L, idx)); /* add it to history */ + //#define lua_freeline(L,b) ((void)L, free(b)) +#else + public static bool lua_readline(lua_State L, CharPtr b, CharPtr p) + { + fputs(p, stdout); + fflush(stdout); /* show prompt */ + return (fgets(b, stdin) != null); /* get line */ + } + public static void lua_saveline(lua_State L, int idx) {} + public static void lua_freeline(lua_State L, CharPtr b) {} +#endif + +//#endif + + /* }================================================================== */ + + + /* + @@ LUAI_GCPAUSE defines the default pause between garbage-collector cycles + @* as a percentage. + ** CHANGE it if you want the GC to run faster or slower (higher values + ** mean larger pauses which mean slower collection.) You can also change + ** this value dynamically. + */ + public const int LUAI_GCPAUSE = 200; /* 200% (wait memory to double before next GC) */ + + + /* + @@ LUAI_GCMUL defines the default speed of garbage collection relative to + @* memory allocation as a percentage. + ** CHANGE it if you want to change the granularity of the garbage + ** collection. (Higher values mean coarser collections. 0 represents + ** infinity, where each step performs a full collection.) You can also + ** change this value dynamically. + */ + public const int LUAI_GCMUL = 200; /* GC runs 'twice the speed' of memory allocation */ + + /* + @@ LUA_COMPAT_GETN controls compatibility with old getn behavior. + ** CHANGE it (define it) if you want exact compatibility with the + ** behavior of setn/getn in Lua 5.0. + */ + //#undef LUA_COMPAT_GETN /* dotnet port doesn't define in the first place */ + + /* + @@ LUA_COMPAT_LOADLIB controls compatibility about global loadlib. + ** CHANGE it to undefined as soon as you do not need a global 'loadlib' + ** function (the function is still available as 'package.loadlib'). + */ + //#undef LUA_COMPAT_LOADLIB /* dotnet port doesn't define in the first place */ + + /* + @@ LUA_COMPAT_VARARG controls compatibility with old vararg feature. + ** CHANGE it to undefined as soon as your programs use only '...' to + ** access vararg parameters (instead of the old 'arg' table). + */ + //#define LUA_COMPAT_VARARG /* defined higher up */ + + /* + @@ LUA_COMPAT_MOD controls compatibility with old math.mod function. + ** CHANGE it to undefined as soon as your programs use 'math.fmod' or + ** the new '%' operator instead of 'math.mod'. + */ + //#define LUA_COMPAT_MOD /* defined higher up */ + + /* + @@ LUA_COMPAT_LSTR controls compatibility with old long string nesting + @* facility. + ** CHANGE it to 2 if you want the old behaviour, or undefine it to turn + ** off the advisory error when nesting [[...]]. + */ + //#define LUA_COMPAT_LSTR 1 + //#define LUA_COMPAT_LSTR /* defined higher up */ + + /* + @@ LUA_COMPAT_GFIND controls compatibility with old 'string.gfind' name. + ** CHANGE it to undefined as soon as you rename 'string.gfind' to + ** 'string.gmatch'. + */ + //#define LUA_COMPAT_GFIND /* defined higher up */ + + /* + @@ LUA_COMPAT_OPENLIB controls compatibility with old 'luaL_openlib' + @* behavior. + ** CHANGE it to undefined as soon as you replace to 'luaL_register' + ** your uses of 'luaL_openlib' + */ + //#define LUA_COMPAT_OPENLIB /* defined higher up */ + + + + /* + @@ luai_apicheck is the assert macro used by the Lua-C API. + ** CHANGE luai_apicheck if you want Lua to perform some checks in the + ** parameters it gets from API calls. This may slow down the interpreter + ** a bit, but may be quite useful when debugging C code that interfaces + ** with Lua. A useful redefinition is to use assert.h. + */ + #if LUA_USE_APICHECK + public static void luai_apicheck(lua_State L, bool o) {Debug.Assert(o);} + public static void luai_apicheck(lua_State L, int o) {Debug.Assert(o != 0);} + #else + public static void luai_apicheck(lua_State L, bool o) {} + public static void luai_apicheck(lua_State L, int o) { } + #endif + + + /* + @@ LUAI_BITSINT defines the number of bits in an int. + ** CHANGE here if Lua cannot automatically detect the number of bits of + ** your machine. Probably you do not need to change this. + */ + /* avoid overflows in comparison */ + //#if INT_MAX-20 < 32760 + //public const int LUAI_BITSINT = 16 + //#elif INT_MAX > 2147483640L + /* int has at least 32 bits */ + public const int LUAI_BITSINT = 32; + //#else + //#error "you must define LUA_BITSINT with number of bits in an integer" + //#endif + + + /* + @@ LUAI_UINT32 is an unsigned integer with at least 32 bits. + @@ LUAI_INT32 is an signed integer with at least 32 bits. + @@ LUAI_UMEM is an unsigned integer big enough to count the total + @* memory used by Lua. + @@ LUAI_MEM is a signed integer big enough to count the total memory + @* used by Lua. + ** CHANGE here if for some weird reason the default definitions are not + ** good enough for your machine. (The definitions in the 'else' + ** part always works, but may waste space on machines with 64-bit + ** longs.) Probably you do not need to change this. + */ + //#if LUAI_BITSINT >= 32 + //#define LUAI_UINT32 unsigned int + //#define LUAI_INT32 int + //#define LUAI_MAXINT32 INT_MAX + //#define LUAI_UMEM uint + //#define LUAI_MEM ptrdiff_t + //#else + ///* 16-bit ints */ + //#define LUAI_UINT32 unsigned long + //#define LUAI_INT32 long + //#define LUAI_MAXINT32 LONG_MAX + //#define LUAI_UMEM unsigned long + //#define LUAI_MEM long + //#endif + + + /* + @@ LUAI_MAXCALLS limits the number of nested calls. + ** CHANGE it if you need really deep recursive calls. This limit is + ** arbitrary; its only purpose is to stop infinite recursion before + ** exhausting memory. + */ + public const int LUAI_MAXCALLS = 20000; + + + /* + @@ LUAI_MAXCSTACK limits the number of Lua stack slots that a C function + @* can use. + ** CHANGE it if you need lots of (Lua) stack space for your C + ** functions. This limit is arbitrary; its only purpose is to stop C + ** functions to consume unlimited stack space. (must be smaller than + ** -LUA_REGISTRYINDEX) + */ + public const int LUAI_MAXCSTACK = 8000; + + + + /* + ** {================================================================== + ** CHANGE (to smaller values) the following definitions if your system + ** has a small C stack. (Or you may want to change them to larger + ** values if your system has a large C stack and these limits are + ** too rigid for you.) Some of these constants control the size of + ** stack-allocated arrays used by the compiler or the interpreter, while + ** others limit the maximum number of recursive calls that the compiler + ** or the interpreter can perform. Values too large may cause a C stack + ** overflow for some forms of deep constructs. + ** =================================================================== + */ + + + /* + @@ LUAI_MAXCCALLS is the maximum depth for nested C calls (short) and + @* syntactical nested non-terminals in a program. + */ + public const int LUAI_MAXCCALLS = 200; + + + /* + @@ LUAI_MAXVARS is the maximum number of local variables per function + @* (must be smaller than 250). + */ + public const int LUAI_MAXVARS = 200; + + + /* + @@ LUAI_MAXUPVALUES is the maximum number of upvalues per function + @* (must be smaller than 250). + */ + public const int LUAI_MAXUPVALUES = 60; + + + /* + @@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. + */ + public const int LUAL_BUFFERSIZE = 1024; // BUFSIZ; todo: check this - mjf + + /* }================================================================== */ + + + + + /* + ** {================================================================== + @@ LUA_NUMBER is the type of numbers in Lua. + ** CHANGE the following definitions only if you want to build Lua + ** with a number type different from double. You may also need to + ** change lua_number2int & lua_number2integer. + ** =================================================================== + */ + + //#define LUA_NUMBER_DOUBLE + //#define LUA_NUMBER double /* declared in dotnet build with using statement */ + + /* + @@ LUAI_UACNUMBER is the result of an 'usual argument conversion' + @* over a number. + */ + //#define LUAI_UACNUMBER double /* declared in dotnet build with using statement */ + + + /* + @@ LUA_NUMBER_SCAN is the format for reading numbers. + @@ LUA_NUMBER_FMT is the format for writing numbers. + @@ lua_number2str converts a number to a string. + @@ LUAI_MAXNUMBER2STR is maximum size of previous conversion. + @@ lua_str2number converts a string to a number. + */ + public const string LUA_NUMBER_SCAN = "%lf"; + public const string LUA_NUMBER_FMT = "%.14g"; + public static CharPtr lua_number2str(double n) { return String.Format("{0}", n); } + public const int LUAI_MAXNUMBER2STR = 32; /* 16 digits, sign, point, and \0 */ + + private const string number_chars = "0123456789+-eE."; + public static double lua_str2number(CharPtr s, out CharPtr end) + { + end = new CharPtr(s.chars, s.index); + string str = ""; + while (end[0] == ' ') + end = end.next(); + while (number_chars.IndexOf(end[0]) >= 0) + { + str += end[0]; + end = end.next(); + } + + try + { + return Convert.ToDouble(str.ToString(), Culture("en-US")); + } + catch (System.OverflowException) + { + // this is a hack, fix it - mjf + if (str[0] == '-') + return System.Double.NegativeInfinity; + else + return System.Double.PositiveInfinity; + } + catch + { + end = new CharPtr(s.chars, s.index); + return 0; + } + } + + private static IFormatProvider Culture(string p) + { +#if SILVERLIGHT + return new CultureInfo(p); +#else + return CultureInfo.GetCultureInfo(p); +#endif + } + + /* + @@ The luai_num* macros define the primitive operations over numbers. + */ + #if LUA_CORE + //#include + public delegate lua_Number op_delegate(lua_Number a, lua_Number b); + public static lua_Number luai_numadd(lua_Number a, lua_Number b) { return ((a) + (b)); } + public static lua_Number luai_numsub(lua_Number a, lua_Number b) { return ((a) - (b)); } + public static lua_Number luai_nummul(lua_Number a, lua_Number b) { return ((a) * (b)); } + public static lua_Number luai_numdiv(lua_Number a, lua_Number b) { return ((a) / (b)); } + public static lua_Number luai_nummod(lua_Number a, lua_Number b) { return ((a) - Math.Floor((a) / (b)) * (b)); } + public static lua_Number luai_numpow(lua_Number a, lua_Number b) { return (Math.Pow(a, b)); } + public static lua_Number luai_numunm(lua_Number a) { return (-(a)); } + public static bool luai_numeq(lua_Number a, lua_Number b) { return ((a) == (b)); } + public static bool luai_numlt(lua_Number a, lua_Number b) { return ((a) < (b)); } + public static bool luai_numle(lua_Number a, lua_Number b) { return ((a) <= (b)); } + public static bool luai_numisnan(lua_Number a) { return lua_Number.IsNaN(a); } + #endif + + + /* + @@ lua_number2int is a macro to convert lua_Number to int. + @@ lua_number2integer is a macro to convert lua_Number to lua_Integer. + ** CHANGE them if you know a faster way to convert a lua_Number to + ** int (with any rounding method and without throwing errors) in your + ** system. In Pentium machines, a naive typecast from double to int + ** in C is extremely slow, so any alternative is worth trying. + */ + + /* On a Pentium, resort to a trick */ + //#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) && !defined(__SSE2__) && \ + // (defined(__i386) || defined (_M_IX86) || defined(__i386__)) + + /* On a Microsoft compiler, use assembler */ + //#if defined(_MSC_VER) + + //#define lua_number2int(i,d) __asm fld d __asm fistp i + //#define lua_number2integer(i,n) lua_number2int(i, n) + + /* the next trick should work on any Pentium, but sometimes clashes + with a DirectX idiosyncrasy */ + //#else + + //union luai_Cast { double l_d; long l_l; }; + //#define lua_number2int(i,d) \ + // { volatile union luai_Cast u; u.l_d = (d) + 6755399441055744.0; (i) = u.l_l; } + //#define lua_number2integer(i,n) lua_number2int(i, n) + + //#endif + + + /* this option always works, but may be slow */ + //#else + //#define lua_number2int(i,d) ((i)=(int)(d)) + //#define lua_number2integer(i,d) ((i)=(lua_Integer)(d)) + + //#endif + + private static void lua_number2int(out int i,lua_Number d) {i = (int)d;} + private static void lua_number2integer(out int i, lua_Number n) { i = (int)n; } + + /* }================================================================== */ + + + /* + @@ LUAI_USER_ALIGNMENT_T is a type that requires maximum alignment. + ** CHANGE it if your system requires alignments larger than double. (For + ** instance, if your system supports long doubles and they must be + ** aligned in 16-byte boundaries, then you should add long double in the + ** union.) Probably you do not need to change this. + */ + //#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; } + + public class LuaException : Exception + { + public lua_State L; + public lua_longjmp c; + + public LuaException(lua_State L, lua_longjmp c) { this.L = L; this.c = c; } + } + + /* + @@ LUAI_THROW/LUAI_TRY define how Lua does exception handling. + ** CHANGE them if you prefer to use longjmp/setjmp even with C++ + ** or if want/don't to use _longjmp/_setjmp instead of regular + ** longjmp/setjmp. By default, Lua handles errors with exceptions when + ** compiling as C++ code, with _longjmp/_setjmp when asked to use them, + ** and with longjmp/setjmp otherwise. + */ + //#if defined(__cplusplus) + ///* C++ exceptions */ + public static void LUAI_THROW(lua_State L, lua_longjmp c) {throw new LuaException(L, c);} + //#define LUAI_TRY(L,c,a) try { a } catch(...) \ + // { if ((c).status == 0) (c).status = -1; } + public static void LUAI_TRY(lua_State L, lua_longjmp c, object a) { + if (c.status == 0) c.status = -1; + } + //#define luai_jmpbuf int /* dummy variable */ + + //#elif defined(LUA_USE_ULONGJMP) + ///* in Unix, try _longjmp/_setjmp (more efficient) */ + //#define LUAI_THROW(L,c) _longjmp((c).b, 1) + //#define LUAI_TRY(L,c,a) if (_setjmp((c).b) == 0) { a } + //#define luai_jmpbuf jmp_buf + + //#else + ///* default handling with long jumps */ + //public static void LUAI_THROW(lua_State L, lua_longjmp c) { c.b(1); } + //#define LUAI_TRY(L,c,a) if (setjmp((c).b) == 0) { a } + //#define luai_jmpbuf jmp_buf + + //#endif + + + /* + @@ LUA_MAXCAPTURES is the maximum number of captures that a pattern + @* can do during pattern-matching. + ** CHANGE it if you need more captures. This limit is arbitrary. + */ + public const int LUA_MAXCAPTURES = 32; + + + /* + @@ lua_tmpnam is the function that the OS library uses to create a + @* temporary name. + @@ LUA_TMPNAMBUFSIZE is the maximum size of a name created by lua_tmpnam. + ** CHANGE them if you have an alternative to tmpnam (which is considered + ** insecure) or if you want the original tmpnam anyway. By default, Lua + ** uses tmpnam except when POSIX is available, where it uses mkstemp. + */ + #if loslib_c || luaall_c + + #if LUA_USE_MKSTEMP + //#include + public const int LUA_TMPNAMBUFSIZE = 32; + //#define lua_tmpnam(b,e) { \ + // strcpy(b, "/tmp/lua_XXXXXX"); \ + // e = mkstemp(b); \ + // if (e != -1) close(e); \ + // e = (e == -1); } + + #else + public const int LUA_TMPNAMBUFSIZE = L_tmpnam; + public static void lua_tmpnam(CharPtr b, int e) { e = (tmpnam(b) == null) ? 1 : 0; } + #endif + + #endif + + + /* + @@ lua_popen spawns a new process connected to the current one through + @* the file streams. + ** CHANGE it if you have a way to implement it in your system. + */ + //#if LUA_USE_POPEN + + //#define lua_popen(L,c,m) ((void)L, fflush(null), popen(c,m)) + //#define lua_pclose(L,file) ((void)L, (pclose(file) != -1)) + + //#elif LUA_WIN + + //#define lua_popen(L,c,m) ((void)L, _popen(c,m)) + //#define lua_pclose(L,file) ((void)L, (_pclose(file) != -1)) + + //#else + + public static Stream lua_popen(lua_State L, CharPtr c, CharPtr m) { luaL_error(L, LUA_QL("popen") + " not supported"); return null; } + public static int lua_pclose(lua_State L, Stream file) { return 0; } + + //#endif + + /* + @@ LUA_DL_* define which dynamic-library system Lua should use. + ** CHANGE here if Lua has problems choosing the appropriate + ** dynamic-library system for your platform (either Windows' DLL, Mac's + ** dyld, or Unix's dlopen). If your system is some kind of Unix, there + ** is a good chance that it has dlopen, so LUA_DL_DLOPEN will work for + ** it. To use dlopen you also need to adapt the src/Makefile (probably + ** adding -ldl to the linker options), so Lua does not select it + ** automatically. (When you change the makefile to add -ldl, you must + ** also add -DLUA_USE_DLOPEN.) + ** If you do not want any kind of dynamic library, undefine all these + ** options. + ** By default, _WIN32 gets LUA_DL_DLL and MAC OS X gets LUA_DL_DYLD. + */ + //#if LUA_USE_DLOPEN + //#define LUA_DL_DLOPEN + //#endif + + //#if LUA_WIN + //#define LUA_DL_DLL + //#endif + + + /* + @@ LUAI_EXTRASPACE allows you to add user-specific data in a lua_State + @* (the data goes just *before* the lua_State pointer). + ** CHANGE (define) this if you really need that. This value must be + ** a multiple of the maximum alignment required for your machine. + */ + public const int LUAI_EXTRASPACE = 0; + + + /* + @@ luai_userstate* allow user-specific actions on threads. + ** CHANGE them if you defined LUAI_EXTRASPACE and need to do something + ** extra when a thread is created/deleted/resumed/yielded. + */ + public static void luai_userstateopen(lua_State L) {} + public static void luai_userstateclose(lua_State L) {} + public static void luai_userstatethread(lua_State L, lua_State L1) {} + public static void luai_userstatefree(lua_State L) {} + public static void luai_userstateresume(lua_State L,int n) {} + public static void luai_userstateyield(lua_State L,int n) {} + + + /* + @@ LUA_INTFRMLEN is the length modifier for integer conversions + @* in 'string.format'. + @@ LUA_INTFRM_T is the integer type correspoding to the previous length + @* modifier. + ** CHANGE them if your system supports long long or does not support long. + */ + + #if LUA_USELONGLONG + + public const string LUA_INTFRMLEN = "ll"; + //#define LUA_INTFRM_T long long + + #else + + public const string LUA_INTFRMLEN = "l"; + //#define LUA_INTFRM_T long /* declared in dotnet build with using statement */ + + #endif + + + + /* =================================================================== */ + + /* + ** Local configuration. You can use this space to add your redefinitions + ** without modifying the main part of the file. + */ + + // misc stuff needed for the compile + + public static bool isalpha(char c) { return Char.IsLetter(c); } + public static bool iscntrl(char c) { return Char.IsControl(c); } + public static bool isdigit(char c) { return Char.IsDigit(c); } + public static bool islower(char c) { return Char.IsLower(c); } + public static bool ispunct(char c) { return Char.IsPunctuation(c); } + public static bool isspace(char c) { return (c==' ') || (c>=(char)0x09 && c<=(char)0x0D); } + public static bool isupper(char c) { return Char.IsUpper(c); } + public static bool isalnum(char c) { return Char.IsLetterOrDigit(c); } + public static bool isxdigit(char c) { return "0123456789ABCDEFabcdef".IndexOf(c) >= 0; } + + public static bool isalpha(int c) { return Char.IsLetter((char)c); } + public static bool iscntrl(int c) { return Char.IsControl((char)c); } + public static bool isdigit(int c) { return Char.IsDigit((char)c); } + public static bool islower(int c) { return Char.IsLower((char)c); } + public static bool ispunct(int c) { return ((char)c != ' ') && !isalnum((char)c); } // *not* the same as Char.IsPunctuation + public static bool isspace(int c) { return ((char)c == ' ') || ((char)c >= (char)0x09 && (char)c <= (char)0x0D); } + public static bool isupper(int c) { return Char.IsUpper((char)c); } + public static bool isalnum(int c) { return Char.IsLetterOrDigit((char)c); } + + public static char tolower(char c) { return Char.ToLower(c); } + public static char toupper(char c) { return Char.ToUpper(c); } + public static char tolower(int c) { return Char.ToLower((char)c); } + public static char toupper(int c) { return Char.ToUpper((char)c); } + + [CLSCompliantAttribute(false)] + public static ulong strtoul(CharPtr s, out CharPtr end, int base_) + { + try + { + end = new CharPtr(s.chars, s.index); + + // skip over any leading whitespace + while (end[0] == ' ') + end = end.next(); + + // ignore any leading 0x + if ((end[0] == '0') && (end[1] == 'x')) + end = end.next().next(); + else if ((end[0] == '0') && (end[1] == 'X')) + end = end.next().next(); + + // do we have a leading + or - sign? + bool negate = false; + if (end[0] == '+') + end = end.next(); + else if (end[0] == '-') + { + negate = true; + end = end.next(); + } + + // loop through all chars + bool invalid = false; + bool had_digits = false; + ulong result = 0; + while (true) + { + // get this char + char ch = end[0]; + + // which digit is this? + int this_digit = 0; + if (isdigit(ch)) + this_digit = ch - '0'; + else if (isalpha(ch)) + this_digit = tolower(ch) - 'a' + 10; + else + break; + + // is this digit valid? + if (this_digit >= base_) + invalid = true; + else + { + had_digits = true; + result = result * (ulong)base_ + (ulong)this_digit; + } + + end = end.next(); + } + + // were any of the digits invalid? + if (invalid || (!had_digits)) + { + end = s; + return System.UInt64.MaxValue; + } + + // if the value was a negative then negate it here + if (negate) + result = (ulong)-(long)result; + + // ok, we're done + return (ulong)result; + } + catch + { + end = s; + return 0; + } + } + + public static void putchar(char ch) + { + Console.Write(ch); + } + + public static void putchar(int ch) + { + Console.Write((char)ch); + } + + public static bool isprint(byte c) + { + return (c >= (byte)' ') && (c <= (byte)127); + } + + public static int parse_scanf(string str, CharPtr fmt, params object[] argp) + { + int parm_index = 0; + int index = 0; + while (fmt[index] != 0) + { + if (fmt[index++]=='%') + switch (fmt[index++]) + { + case 's': + { + argp[parm_index++] = str; + break; + } + case 'c': + { + argp[parm_index++] = Convert.ToChar(str, Culture("en-US")); + break; + } + case 'd': + { + argp[parm_index++] = Convert.ToInt32(str, Culture("en-US")); + break; + } + case 'l': + { + argp[parm_index++] = Convert.ToDouble(str, Culture("en-US")); + break; + } + case 'f': + { + argp[parm_index++] = Convert.ToDouble(str, Culture("en-US")); + break; + } + //case 'p': + // { + // result += "(pointer)"; + // break; + // } + } + } + return parm_index; + } + + public static void printf(CharPtr str, params object[] argv) + { + Tools.printf(str.ToString(), argv); + } + + public static void sprintf(CharPtr buffer, CharPtr str, params object[] argv) + { + string temp = Tools.sprintf(str.ToString(), argv); + strcpy(buffer, temp); + } + + public static int fprintf(Stream stream, CharPtr str, params object[] argv) + { + string result = Tools.sprintf(str.ToString(), argv); + char[] chars = result.ToCharArray(); + byte[] bytes = new byte[chars.Length]; + for (int i=0; i(CharPtr ptr1, CharPtr ptr2) { + Debug.Assert(ptr1.chars == ptr2.chars); return ptr1.index > ptr2.index; } + public static bool operator >=(CharPtr ptr1, CharPtr ptr2) { + Debug.Assert(ptr1.chars == ptr2.chars); return ptr1.index >= ptr2.index; } + public static bool operator ==(CharPtr ptr1, CharPtr ptr2) { + object o1 = ptr1 as CharPtr; + object o2 = ptr2 as CharPtr; + if ((o1 == null) && (o2 == null)) return true; + if (o1 == null) return false; + if (o2 == null) return false; + return (ptr1.chars == ptr2.chars) && (ptr1.index == ptr2.index); } + public static bool operator !=(CharPtr ptr1, CharPtr ptr2) {return !(ptr1 == ptr2); } + + public override bool Equals(object o) + { + return this == (o as CharPtr); + } + + public override int GetHashCode() + { + return 0; + } + public override string ToString() + { + string result = ""; + for (int i = index; (i 0)) + dst[dst_index++] = src[src_index++]; + return dst; + } + + [CLSCompliantAttribute(false)] + public static uint strcspn(CharPtr str, CharPtr charset) + { + int index = str.ToString().IndexOfAny(charset.ToString().ToCharArray()); + if (index < 0) + index = str.ToString().Length; + return (uint)index; + } + + public static CharPtr strncpy(CharPtr dst, CharPtr src, int length) + { + int index = 0; + while ((src[index] != '\0') && (index 0) + f.Seek(-1, SeekOrigin.Current); + } + +#if XBOX || SILVERLIGHT + public static Stream stdout; + public static Stream stdin; + public static Stream stderr; +#else + public static Stream stdout = Console.OpenStandardOutput(); + public static Stream stdin = Console.OpenStandardInput(); + public static Stream stderr = Console.OpenStandardError(); +#endif + public static int EOF = -1; + + public static void fputs(CharPtr str, Stream stream) + { + Console.Write(str.ToString()); + } + + public static int feof(Stream s) + { + return (s.Position >= s.Length) ? 1 : 0; + } + + public static int fread(CharPtr ptr, int size, int num, Stream stream) + { + int num_bytes = num * size; + byte[] bytes = new byte[num_bytes]; + try + { + int result = stream.Read(bytes, 0, num_bytes); + for (int i = 0; i < result; i++) + ptr[i] = (char)bytes[i]; + return result/size; + } + catch + { + return 0; + } + } + + public static int fwrite(CharPtr ptr, int size, int num, Stream stream) + { + int num_bytes = num * size; + byte[] bytes = new byte[num_bytes]; + for (int i = 0; i < num_bytes; i++) + bytes[i] = (byte)ptr[i]; + try + { + stream.Write(bytes, 0, num_bytes); + } + catch + { + return 0; + } + return num; + } + + public static int strcmp(CharPtr s1, CharPtr s2) + { + if (s1 == s2) + return 0; + if (s1 == null) + return -1; + if (s2 == null) + return 1; + + for (int i = 0; ; i++) + { + if (s1[i] != s2[i]) + { + if (s1[i] < s2[i]) + return -1; + else + return 1; + } + if (s1[i] == '\0') + return 0; + } + } + + public static CharPtr fgets(CharPtr str, Stream stream) + { + int index = 0; + try + { + while (true) + { + str[index] = (char)stream.ReadByte(); + if (str[index] == '\n') + break; + if (index >= str.chars.Length) + break; + index++; + } + } + catch + { + } + return str; + } + + public static double frexp(double x, out int expptr) + { +#if XBOX + expptr = (int)(Math.Log(x) / Math.Log(2)) + 1; +#else + expptr = (int)Math.Log(x, 2) + 1; +#endif + double s = x / Math.Pow(2, expptr); + return s; + } + + public static double ldexp(double x, int expptr) + { + return x * Math.Pow(2, expptr); + } + + public static CharPtr strstr(CharPtr str, CharPtr substr) + { + int index = str.ToString().IndexOf(substr.ToString()); + if (index < 0) + return null; + return new CharPtr(str + index); + } + + public static CharPtr strrchr(CharPtr str, char ch) + { + int index = str.ToString().LastIndexOf(ch); + if (index < 0) + return null; + return str + index; + } + + public static Stream fopen(CharPtr filename, CharPtr mode) + { + string str = filename.ToString(); + FileMode filemode = FileMode.Open; + FileAccess fileaccess = (FileAccess)0; + for (int i=0; mode[i] != '\0'; i++) + switch (mode[i]) + { + case 'r': + fileaccess = fileaccess | FileAccess.Read; + if (!File.Exists(str)) + return null; + break; + + case 'w': + filemode = FileMode.Create; + fileaccess = fileaccess | FileAccess.Write; + break; + } + try + { + return new FileStream(str, filemode, fileaccess); + } + catch + { + return null; + } + } + + public static Stream freopen(CharPtr filename, CharPtr mode, Stream stream) + { + try + { + stream.Flush(); + stream.Close(); + } + catch { } + + return fopen(filename, mode); + } + + public static void fflush(Stream stream) + { + stream.Flush(); + } + + public static int ferror(Stream stream) + { + return 0; // todo: fix this - mjf + } + + public static int fclose(Stream stream) + { + stream.Close(); + return 0; + } + +#if !XBOX + public static Stream tmpfile() + { + return new FileStream(Path.GetTempFileName(), FileMode.Create, FileAccess.ReadWrite); + } +#endif + + public static int fscanf(Stream f, CharPtr format, params object[] argp) + { + string str = Console.ReadLine(); + return parse_scanf(str, format, argp); + } + + public static int fseek(Stream f, long offset, int origin) + { + try + { + f.Seek(offset, (SeekOrigin)origin); + return 0; + } + catch + { + return 1; + } + } + + + public static int ftell(Stream f) + { + return (int)f.Position; + } + + public static int clearerr(Stream f) + { + //Debug.Assert(false, "clearerr not implemented yet - mjf"); + return 0; + } + + [CLSCompliantAttribute(false)] + public static int setvbuf(Stream stream, CharPtr buffer, int mode, uint size) + { + Debug.Assert(false, "setvbuf not implemented yet - mjf"); + return 0; + } + + public static void memcpy(T[] dst, T[] src, int length) + { + for (int i = 0; i < length; i++) + dst[i] = src[i]; + } + + public static void memcpy(T[] dst, int offset, T[] src, int length) + { + for (int i=0; i(T[] dst, T[] src, int srcofs, int length) + { + for (int i = 0; i < length; i++) + dst[i] = src[srcofs+i]; + } + + [CLSCompliantAttribute(false)] + public static void memcpy(CharPtr ptr1, CharPtr ptr2, uint size) { memcpy(ptr1, ptr2, (int)size); } + public static void memcpy(CharPtr ptr1, CharPtr ptr2, int size) + { + for (int i = 0; i < size; i++) + ptr1[i] = ptr2[i]; + } + + public static object VOID(object f) { return f; } + + public const double HUGE_VAL = System.Double.MaxValue; + [CLSCompliantAttribute(false)] + public const uint SHRT_MAX = System.UInt16.MaxValue; + + [CLSCompliantAttribute(false)] + public const int _IONBF = 0; + [CLSCompliantAttribute(false)] + public const int _IOFBF = 1; + [CLSCompliantAttribute(false)] + public const int _IOLBF = 2; + + public const int SEEK_SET = 0; + public const int SEEK_CUR = 1; + public const int SEEK_END = 2; + + // one of the primary objectives of this port is to match the C version of Lua as closely as + // possible. a key part of this is also matching the behaviour of the garbage collector, as + // that affects the operation of things such as weak tables. in order for this to occur the + // size of structures that are allocated must be reported as identical to their C++ equivelents. + // that this means that variables such as global_State.totalbytes no longer indicate the true + // amount of memory allocated. + public static int GetUnmanagedSize(Type t) + { + if (t == typeof(global_State)) + return 228; + else if (t == typeof(LG)) + return 376; + else if (t == typeof(CallInfo)) + return 24; + else if (t == typeof(lua_TValue)) + return 16; + else if (t == typeof(Table)) + return 32; + else if (t == typeof(Node)) + return 32; + else if (t == typeof(GCObject)) + return 120; + else if (t == typeof(GCObjectRef)) + return 4; + else if (t == typeof(ArrayRef)) + return 4; + else if (t == typeof(Closure)) + return 0; // handle this one manually in the code + else if (t == typeof(Proto)) + return 76; + else if (t == typeof(luaL_Reg)) + return 8; + else if (t == typeof(luaL_Buffer)) + return 524; + else if (t == typeof(lua_State)) + return 120; + else if (t == typeof(lua_Debug)) + return 100; + else if (t == typeof(CallS)) + return 8; + else if (t == typeof(LoadF)) + return 520; + else if (t == typeof(LoadS)) + return 8; + else if (t == typeof(lua_longjmp)) + return 72; + else if (t == typeof(SParser)) + return 20; + else if (t == typeof(Token)) + return 16; + else if (t == typeof(LexState)) + return 52; + else if (t == typeof(FuncState)) + return 572; + else if (t == typeof(GCheader)) + return 8; + else if (t == typeof(lua_TValue)) + return 16; + else if (t == typeof(TString)) + return 16; + else if (t == typeof(LocVar)) + return 12; + else if (t == typeof(UpVal)) + return 32; + else if (t == typeof(CClosure)) + return 40; + else if (t == typeof(LClosure)) + return 24; + else if (t == typeof(TKey)) + return 16; + else if (t == typeof(ConsControl)) + return 40; + else if (t == typeof(LHS_assign)) + return 32; + else if (t == typeof(expdesc)) + return 24; + else if (t == typeof(upvaldesc)) + return 2; + else if (t == typeof(BlockCnt)) + return 12; + else if (t == typeof(Zio)) + return 20; + else if (t == typeof(Mbuffer)) + return 12; + else if (t == typeof(LoadState)) + return 16; + else if (t == typeof(MatchState)) + return 272; + else if (t == typeof(stringtable)) + return 12; + else if (t == typeof(FilePtr)) + return 4; + else if (t == typeof(Udata)) + return 24; + else if (t == typeof(Char)) + return 1; + else if (t == typeof(UInt16)) + return 2; + else if (t == typeof(Int16)) + return 2; + else if (t == typeof(UInt32)) + return 4; + else if (t == typeof(Int32)) + return 4; + else if (t == typeof(Single)) + return 4; + Debug.Assert(false, "Trying to get unknown sized of unmanaged type " + t.ToString()); + return 0; + } + } +} diff --git a/Core/KopiLua/lualib.cs b/Core/KopiLua/lualib.cs index 40e9dd6c43300e77cefeaff8a3d7248b53ac6aed..4004c5f8ad55183df14f722b61218cc76274748e 100644 --- a/Core/KopiLua/lualib.cs +++ b/Core/KopiLua/lualib.cs @@ -1,28 +1,28 @@ -/* -** $Id: lualib.h,v 1.36.1.1 2007/12/27 13:02:25 roberto Exp $ -** Lua standard libraries -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; - -namespace KopiLua -{ - public partial class Lua - { - /* Key to file-handle type */ - public const string LUA_FILEHANDLE = "FILE*"; - - public const string LUA_COLIBNAME = "coroutine"; - public const string LUA_TABLIBNAME = "table"; - public const string LUA_IOLIBNAME = "io"; - public const string LUA_OSLIBNAME = "os"; - public const string LUA_STRLIBNAME = "string"; - public const string LUA_MATHLIBNAME = "math"; - public const string LUA_DBLIBNAME = "debug"; - public const string LUA_LOADLIBNAME = "package"; - - } -} +/* +** $Id: lualib.h,v 1.36.1.1 2007/12/27 13:02:25 roberto Exp $ +** Lua standard libraries +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace KopiLua +{ + public partial class Lua + { + /* Key to file-handle type */ + public const string LUA_FILEHANDLE = "FILE*"; + + public const string LUA_COLIBNAME = "coroutine"; + public const string LUA_TABLIBNAME = "table"; + public const string LUA_IOLIBNAME = "io"; + public const string LUA_OSLIBNAME = "os"; + public const string LUA_STRLIBNAME = "string"; + public const string LUA_MATHLIBNAME = "math"; + public const string LUA_DBLIBNAME = "debug"; + public const string LUA_LOADLIBNAME = "package"; + + } +} diff --git a/Core/KopiLua/lundump.cs b/Core/KopiLua/lundump.cs index ab651df3e28cee12ea927dd223acf820230774b1..97f7df6dae4e3ca874cfd5416da4440399233664 100644 --- a/Core/KopiLua/lundump.cs +++ b/Core/KopiLua/lundump.cs @@ -1,275 +1,275 @@ -/* -** $Id: lundump.c,v 2.7.1.4 2008/04/04 19:51:41 roberto Exp $ -** load precompiled Lua chunks -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; - -namespace KopiLua -{ - using TValue = Lua.lua_TValue; - using lua_Number = System.Double; - using lu_byte = System.Byte; - using StkId = Lua.lua_TValue; - using Instruction = System.UInt32; - using ZIO = Lua.Zio; - - public partial class Lua - { - /* for header of binary files -- this is Lua 5.1 */ - public const int LUAC_VERSION = 0x51; - - /* for header of binary files -- this is the official format */ - public const int LUAC_FORMAT = 0; - - /* size of header of binary files */ - public const int LUAC_HEADERSIZE = 12; - - public class LoadState{ - public lua_State L; - public ZIO Z; - public Mbuffer b; - public CharPtr name; - }; - - //#ifdef LUAC_TRUST_BINARIES - //#define IF(c,s) - //#define error(S,s) - //#else - //#define IF(c,s) if (c) error(S,s) - - public static void IF(int c, string s) { } - public static void IF(bool c, string s) { } - - static void error(LoadState S, CharPtr why) - { - luaO_pushfstring(S.L,"%s: %s in precompiled chunk",S.name,why); - luaD_throw(S.L,LUA_ERRSYNTAX); - } - //#endif - - public static object LoadMem(LoadState S, Type t) - { - int size = Marshal.SizeOf(t); - CharPtr str = new char[size]; - LoadBlock(S, str, size); - byte[] bytes = new byte[str.chars.Length]; - for (int i = 0; i < str.chars.Length; i++) - bytes[i] = (byte)str.chars[i]; - GCHandle pinnedPacket = GCHandle.Alloc(bytes, GCHandleType.Pinned); - object b = Marshal.PtrToStructure(pinnedPacket.AddrOfPinnedObject(), t); - pinnedPacket.Free(); - return b; - } - - public static object LoadMem(LoadState S, Type t, int n) - { -#if SILVERLIGHT - List array = new List(); - for (int i = 0; i < n; i++) - array.Add(LoadMem(S, t)); - return array.ToArray(); -#else - ArrayList array = new ArrayList(); - for (int i=0; i(S.L, n); - f.sizecode=n; - f.code = (Instruction[])LoadVector(S, typeof(Instruction), n); - } - - private static void LoadConstants(LoadState S, Proto f) - { - int i,n; - n=LoadInt(S); - f.k = luaM_newvector(S.L, n); - f.sizek=n; - for (i=0; i(S.L,n); - f.sizep=n; - for (i=0; i(S.L,n); - f.sizelineinfo=n; - f.lineinfo = (int[])LoadVector(S, typeof(int), n); - n=LoadInt(S); - f.locvars=luaM_newvector(S.L,n); - f.sizelocvars=n; - for (i=0; i(S.L, n); - f.sizeupvalues=n; - for (i=0; i LUAI_MAXCCALLS) error(S,"code too deep"); - f=luaF_newproto(S.L); - setptvalue2s(S.L,S.L.top,f); incr_top(S.L); - f.source=LoadString(S); if (f.source==null) f.source=p; - f.linedefined=LoadInt(S); - f.lastlinedefined=LoadInt(S); - f.nups=LoadByte(S); - f.numparams=LoadByte(S); - f.is_vararg=LoadByte(S); - f.maxstacksize=LoadByte(S); - LoadCode(S,f); - LoadConstants(S,f); - LoadDebug(S,f); - IF (luaG_checkcode(f)==0 ? 1 : 0, "bad code"); - StkId.dec(ref S.L.top); - S.L.nCcalls--; - return f; - } - - private static void LoadHeader(LoadState S) - { - CharPtr h = new char[LUAC_HEADERSIZE]; - CharPtr s = new char[LUAC_HEADERSIZE]; - luaU_header(h); - LoadBlock(S, s, LUAC_HEADERSIZE); - IF (memcmp(h, s, LUAC_HEADERSIZE)!=0, "bad header"); - } - - /* - ** load precompiled chunk - */ - public static Proto luaU_undump (lua_State L, ZIO Z, Mbuffer buff, CharPtr name) - { - LoadState S = new LoadState(); - if (name[0] == '@' || name[0] == '=') - S.name = name+1; - else if (name[0]==LUA_SIGNATURE[0]) - S.name="binary string"; - else - S.name=name; - S.L=L; - S.Z=Z; - S.b=buff; - LoadHeader(S); - return LoadFunction(S,luaS_newliteral(L,"=?")); - } - - /* - * make header - */ - public static void luaU_header(CharPtr h) - { - h = new CharPtr(h); - int x=1; - memcpy(h, LUA_SIGNATURE, LUA_SIGNATURE.Length); - h = h.add(LUA_SIGNATURE.Length); - h[0] = (char)LUAC_VERSION; - h.inc(); - h[0] = (char)LUAC_FORMAT; - h.inc(); - //*h++=(char)*(char*)&x; /* endianness */ - h[0] = (char)x; /* endianness */ - h.inc(); - h[0] = (char)sizeof(int); - h.inc(); - h[0] = (char)sizeof(uint); - h.inc(); - h[0] = (char)sizeof(Instruction); - h.inc(); - h[0] = (char)sizeof(lua_Number); - h.inc(); - - //(h++)[0] = ((lua_Number)0.5 == 0) ? 0 : 1; /* is lua_Number integral? */ - h[0] = (char)0; // always 0 on this build - } - - } -} +/* +** $Id: lundump.c,v 2.7.1.4 2008/04/04 19:51:41 roberto Exp $ +** load precompiled Lua chunks +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; + +namespace KopiLua +{ + using TValue = Lua.lua_TValue; + using lua_Number = System.Double; + using lu_byte = System.Byte; + using StkId = Lua.lua_TValue; + using Instruction = System.UInt32; + using ZIO = Lua.Zio; + + public partial class Lua + { + /* for header of binary files -- this is Lua 5.1 */ + public const int LUAC_VERSION = 0x51; + + /* for header of binary files -- this is the official format */ + public const int LUAC_FORMAT = 0; + + /* size of header of binary files */ + public const int LUAC_HEADERSIZE = 12; + + public class LoadState{ + public lua_State L; + public ZIO Z; + public Mbuffer b; + public CharPtr name; + }; + + //#ifdef LUAC_TRUST_BINARIES + //#define IF(c,s) + //#define error(S,s) + //#else + //#define IF(c,s) if (c) error(S,s) + + public static void IF(int c, string s) { } + public static void IF(bool c, string s) { } + + static void error(LoadState S, CharPtr why) + { + luaO_pushfstring(S.L,"%s: %s in precompiled chunk",S.name,why); + luaD_throw(S.L,LUA_ERRSYNTAX); + } + //#endif + + public static object LoadMem(LoadState S, Type t) + { + int size = Marshal.SizeOf(t); + CharPtr str = new char[size]; + LoadBlock(S, str, size); + byte[] bytes = new byte[str.chars.Length]; + for (int i = 0; i < str.chars.Length; i++) + bytes[i] = (byte)str.chars[i]; + GCHandle pinnedPacket = GCHandle.Alloc(bytes, GCHandleType.Pinned); + object b = Marshal.PtrToStructure(pinnedPacket.AddrOfPinnedObject(), t); + pinnedPacket.Free(); + return b; + } + + public static object LoadMem(LoadState S, Type t, int n) + { +#if SILVERLIGHT + List array = new List(); + for (int i = 0; i < n; i++) + array.Add(LoadMem(S, t)); + return array.ToArray(); +#else + ArrayList array = new ArrayList(); + for (int i=0; i(S.L, n); + f.sizecode=n; + f.code = (Instruction[])LoadVector(S, typeof(Instruction), n); + } + + private static void LoadConstants(LoadState S, Proto f) + { + int i,n; + n=LoadInt(S); + f.k = luaM_newvector(S.L, n); + f.sizek=n; + for (i=0; i(S.L,n); + f.sizep=n; + for (i=0; i(S.L,n); + f.sizelineinfo=n; + f.lineinfo = (int[])LoadVector(S, typeof(int), n); + n=LoadInt(S); + f.locvars=luaM_newvector(S.L,n); + f.sizelocvars=n; + for (i=0; i(S.L, n); + f.sizeupvalues=n; + for (i=0; i LUAI_MAXCCALLS) error(S,"code too deep"); + f=luaF_newproto(S.L); + setptvalue2s(S.L,S.L.top,f); incr_top(S.L); + f.source=LoadString(S); if (f.source==null) f.source=p; + f.linedefined=LoadInt(S); + f.lastlinedefined=LoadInt(S); + f.nups=LoadByte(S); + f.numparams=LoadByte(S); + f.is_vararg=LoadByte(S); + f.maxstacksize=LoadByte(S); + LoadCode(S,f); + LoadConstants(S,f); + LoadDebug(S,f); + IF (luaG_checkcode(f)==0 ? 1 : 0, "bad code"); + StkId.dec(ref S.L.top); + S.L.nCcalls--; + return f; + } + + private static void LoadHeader(LoadState S) + { + CharPtr h = new char[LUAC_HEADERSIZE]; + CharPtr s = new char[LUAC_HEADERSIZE]; + luaU_header(h); + LoadBlock(S, s, LUAC_HEADERSIZE); + IF (memcmp(h, s, LUAC_HEADERSIZE)!=0, "bad header"); + } + + /* + ** load precompiled chunk + */ + public static Proto luaU_undump (lua_State L, ZIO Z, Mbuffer buff, CharPtr name) + { + LoadState S = new LoadState(); + if (name[0] == '@' || name[0] == '=') + S.name = name+1; + else if (name[0]==LUA_SIGNATURE[0]) + S.name="binary string"; + else + S.name=name; + S.L=L; + S.Z=Z; + S.b=buff; + LoadHeader(S); + return LoadFunction(S,luaS_newliteral(L,"=?")); + } + + /* + * make header + */ + public static void luaU_header(CharPtr h) + { + h = new CharPtr(h); + int x=1; + memcpy(h, LUA_SIGNATURE, LUA_SIGNATURE.Length); + h = h.add(LUA_SIGNATURE.Length); + h[0] = (char)LUAC_VERSION; + h.inc(); + h[0] = (char)LUAC_FORMAT; + h.inc(); + //*h++=(char)*(char*)&x; /* endianness */ + h[0] = (char)x; /* endianness */ + h.inc(); + h[0] = (char)sizeof(int); + h.inc(); + h[0] = (char)sizeof(uint); + h.inc(); + h[0] = (char)sizeof(Instruction); + h.inc(); + h[0] = (char)sizeof(lua_Number); + h.inc(); + + //(h++)[0] = ((lua_Number)0.5 == 0) ? 0 : 1; /* is lua_Number integral? */ + h[0] = (char)0; // always 0 on this build + } + + } +} diff --git a/Core/KopiLua/lvm.cs b/Core/KopiLua/lvm.cs index 719e22dd79f265bf076d9d4dc4cbc54ca4a0314e..4bc26acea1695403f031ed25bc56a94dfee34911 100644 --- a/Core/KopiLua/lvm.cs +++ b/Core/KopiLua/lvm.cs @@ -1,925 +1,925 @@ -/* -** $Id: lvm.c,v 2.63.1.3 2007/12/28 15:32:23 roberto Exp $ -** Lua virtual machine -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -namespace KopiLua -{ - using TValue = Lua.lua_TValue; - using StkId = Lua.lua_TValue; - using lua_Number = System.Double; - using lu_byte = System.Byte; - using ptrdiff_t = System.Int32; - using Instruction = System.UInt32; - - public partial class Lua - { - [CLSCompliantAttribute(false)] - public static int tostring(lua_State L, StkId o) { - return ((ttype(o) == LUA_TSTRING) || (luaV_tostring(L, o) != 0)) ? 1 : 0; - } - - public static int tonumber(ref StkId o, TValue n) { - return ((ttype(o) == LUA_TNUMBER || (((o) = luaV_tonumber(o, n)) != null))) ? 1 : 0; - } - - public static int equalobj(lua_State L, TValue o1, TValue o2) { - return ((ttype(o1) == ttype(o2)) && (luaV_equalval(L, o1, o2) != 0)) ? 1 : 0; - } - - - /* limit for table tag-method chains (to avoid loops) */ - public const int MAXTAGLOOP = 100; - - - public static TValue luaV_tonumber (TValue obj, TValue n) { - lua_Number num; - if (ttisnumber(obj)) return obj; - if (ttisstring(obj) && (luaO_str2d(svalue(obj), out num)!=0)) { - setnvalue(n, num); - return n; - } - else - return null; - } - - - public static int luaV_tostring (lua_State L, StkId obj) { - if (!ttisnumber(obj)) - return 0; - else { - lua_Number n = nvalue(obj); - CharPtr s = lua_number2str(n); - setsvalue2s(L, obj, luaS_new(L, s)); - return 1; - } - } - - - private static void traceexec (lua_State L, InstructionPtr pc) { - lu_byte mask = L.hookmask; - InstructionPtr oldpc = InstructionPtr.Assign(L.savedpc); - L.savedpc = InstructionPtr.Assign(pc); - if (((mask & LUA_MASKCOUNT) != 0) && (L.hookcount == 0)) { - resethookcount(L); - luaD_callhook(L, LUA_HOOKCOUNT, -1); - } - if ((mask & LUA_MASKLINE) != 0) { - Proto p = ci_func(L.ci).l.p; - int npc = pcRel(pc, p); - int newline = getline(p, npc); - /* call linehook when enter a new function, when jump back (loop), - or when enter a new line */ - if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) - luaD_callhook(L, LUA_HOOKLINE, newline); - } - } - - - private static void callTMres (lua_State L, StkId res, TValue f, - TValue p1, TValue p2) { - ptrdiff_t result = savestack(L, res); - setobj2s(L, L.top, f); /* push function */ - setobj2s(L, L.top+1, p1); /* 1st argument */ - setobj2s(L, L.top+2, p2); /* 2nd argument */ - luaD_checkstack(L, 3); - L.top += 3; - luaD_call(L, L.top-3, 1); - res = restorestack(L, result); - StkId.dec(ref L.top); - setobjs2s(L, res, L.top); - } - - - - private static void callTM (lua_State L, TValue f, TValue p1, - TValue p2, TValue p3) { - setobj2s(L, L.top, f); /* push function */ - setobj2s(L, L.top + 1, p1); /* 1st argument */ - setobj2s(L, L.top + 2, p2); /* 2nd argument */ - setobj2s(L, L.top + 3, p3); /* 3th argument */ - luaD_checkstack(L, 4); - L.top += 4; - luaD_call(L, L.top - 4, 0); - } - - - public static void luaV_gettable (lua_State L, TValue t, TValue key, StkId val) { - int loop; - for (loop = 0; loop < MAXTAGLOOP; loop++) { - TValue tm; - if (ttistable(t)) { /* `t' is a table? */ - Table h = hvalue(t); - TValue res = luaH_get(h, key); /* do a primitive get */ - if (!ttisnil(res) || /* result is no nil? */ - (tm = fasttm(L, h.metatable, TMS.TM_INDEX)) == null) { /* or no TM? */ - setobj2s(L, val, res); - return; - } - /* else will try the tag method */ - } - else if (ttisnil(tm = luaT_gettmbyobj(L, t, TMS.TM_INDEX))) - luaG_typeerror(L, t, "index"); - if (ttisfunction(tm)) { - callTMres(L, val, tm, t, key); - return; - } - t = tm; /* else repeat with `tm' */ - } - luaG_runerror(L, "loop in gettable"); - } - - public static void luaV_settable (lua_State L, TValue t, TValue key, StkId val) { - int loop; - - for (loop = 0; loop < MAXTAGLOOP; loop++) { - TValue tm; - if (ttistable(t)) { /* `t' is a table? */ - Table h = hvalue(t); - TValue oldval = luaH_set(L, h, key); /* do a primitive set */ - if (!ttisnil(oldval) || /* result is no nil? */ - (tm = fasttm(L, h.metatable, TMS.TM_NEWINDEX)) == null) { /* or no TM? */ - setobj2t(L, oldval, val); - luaC_barriert(L, h, val); - return; - } - /* else will try the tag method */ - } - else if (ttisnil(tm = luaT_gettmbyobj(L, t, TMS.TM_NEWINDEX))) - luaG_typeerror(L, t, "index"); - if (ttisfunction(tm)) { - callTM(L, tm, t, key, val); - return; - } - t = tm; /* else repeat with `tm' */ - } - luaG_runerror(L, "loop in settable"); - } - - - private static int call_binTM (lua_State L, TValue p1, TValue p2, - StkId res, TMS event_) { - TValue tm = luaT_gettmbyobj(L, p1, event_); /* try first operand */ - if (ttisnil(tm)) - tm = luaT_gettmbyobj(L, p2, event_); /* try second operand */ - if (ttisnil(tm)) return 0; - callTMres(L, res, tm, p1, p2); - return 1; - } - - - private static TValue get_compTM (lua_State L, Table mt1, Table mt2, - TMS event_) { - TValue tm1 = fasttm(L, mt1, event_); - TValue tm2; - if (tm1 == null) return null; /* no metamethod */ - if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ - tm2 = fasttm(L, mt2, event_); - if (tm2 == null) return null; /* no metamethod */ - if (luaO_rawequalObj(tm1, tm2) != 0) /* same metamethods? */ - return tm1; - return null; - } - - - private static int call_orderTM (lua_State L, TValue p1, TValue p2, - TMS event_) { - TValue tm1 = luaT_gettmbyobj(L, p1, event_); - TValue tm2; - if (ttisnil(tm1)) return -1; /* no metamethod? */ - tm2 = luaT_gettmbyobj(L, p2, event_); - if (luaO_rawequalObj(tm1, tm2)==0) /* different metamethods? */ - return -1; - callTMres(L, L.top, tm1, p1, p2); - return l_isfalse(L.top) == 0 ? 1 : 0; - } - - - private static int l_strcmp (TString ls, TString rs) { - CharPtr l = getstr(ls); - uint ll = ls.tsv.len; - CharPtr r = getstr(rs); - uint lr = rs.tsv.len; - for (;;) { - //int temp = strcoll(l, r); - int temp = String.Compare(l.ToString(), r.ToString()); - if (temp != 0) return temp; - else { /* strings are equal up to a `\0' */ - uint len = (uint)l.ToString().Length; /* index of first `\0' in both strings */ - if (len == lr) /* r is finished? */ - return (len == ll) ? 0 : 1; - else if (len == ll) /* l is finished? */ - return -1; /* l is smaller than r (because r is not finished) */ - /* both strings longer than `len'; go on comparing (after the `\0') */ - len++; - l += len; ll -= len; r += len; lr -= len; - } - } - } - - - public static int luaV_lessthan (lua_State L, TValue l, TValue r) { - int res; - if (ttype(l) != ttype(r)) - return luaG_ordererror(L, l, r); - else if (ttisnumber(l)) - return luai_numlt(nvalue(l), nvalue(r)) ? 1 : 0; - else if (ttisstring(l)) - return (l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0) ? 1 : 0; - else if ((res = call_orderTM(L, l, r, TMS.TM_LT)) != -1) - return res; - return luaG_ordererror(L, l, r); - } - - - private static int lessequal (lua_State L, TValue l, TValue r) { - int res; - if (ttype(l) != ttype(r)) - return luaG_ordererror(L, l, r); - else if (ttisnumber(l)) - return luai_numle(nvalue(l), nvalue(r)) ? 1 : 0; - else if (ttisstring(l)) - return (l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0) ? 1 : 0; - else if ((res = call_orderTM(L, l, r, TMS.TM_LE)) != -1) /* first try `le' */ - return res; - else if ((res = call_orderTM(L, r, l, TMS.TM_LT)) != -1) /* else try `lt' */ - return (res == 0) ? 1 : 0; - return luaG_ordererror(L, l, r); - } - - static CharPtr mybuff = null; - - public static int luaV_equalval (lua_State L, TValue t1, TValue t2) { - TValue tm = null; - lua_assert(ttype(t1) == ttype(t2)); - switch (ttype(t1)) { - case LUA_TNIL: return 1; - case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)) ? 1 : 0; - case LUA_TBOOLEAN: return (bvalue(t1) == bvalue(t2)) ? 1 : 0; /* true must be 1 !! */ - case LUA_TLIGHTUSERDATA: return (pvalue(t1) == pvalue(t2)) ? 1 : 0; - case LUA_TUSERDATA: { - if (uvalue(t1) == uvalue(t2)) return 1; - tm = get_compTM(L, uvalue(t1).metatable, uvalue(t2).metatable, - TMS.TM_EQ); - break; /* will try TM */ - } - case LUA_TTABLE: { - if (hvalue(t1) == hvalue(t2)) return 1; - tm = get_compTM(L, hvalue(t1).metatable, hvalue(t2).metatable, TMS.TM_EQ); - break; /* will try TM */ - } - default: return (gcvalue(t1) == gcvalue(t2)) ? 1 : 0; - } - if (tm == null) return 0; /* no TM? */ - callTMres(L, L.top, tm, t1, t2); /* call TM */ - return l_isfalse(L.top) == 0 ? 1 : 0; - } - - - public static void luaV_concat (lua_State L, int total, int last) { - do { - StkId top = L.base_ + last + 1; - int n = 2; /* number of elements handled in this pass (at least 2) */ - if (!(ttisstring(top-2) || ttisnumber(top-2)) || (tostring(L, top-1)==0)) { - if (call_binTM(L, top-2, top-1, top-2, TMS.TM_CONCAT)==0) - luaG_concaterror(L, top-2, top-1); - } else if (tsvalue(top-1).len == 0) /* second op is empty? */ - tostring(L, top - 2); /* result is first op (as string) */ - else { - /* at least two string values; get as many as possible */ - uint tl = tsvalue(top-1).len; - CharPtr buffer; - int i; - /* collect total length */ - for (n = 1; n < total && (tostring(L, top-n-1)!=0); n++) { - uint l = tsvalue(top-n-1).len; - if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); - tl += l; - } - buffer = luaZ_openspace(L, G(L).buff, tl); - if (mybuff == null) - mybuff = buffer; - tl = 0; - for (i=n; i>0; i--) { /* concat all strings */ - uint l = tsvalue(top-i).len; - memcpy(buffer.chars, (int)tl, svalue(top-i).chars, (int)l); - tl += l; - } - setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); - } - total -= n-1; /* got `n' strings to create 1 new */ - last -= n-1; - } while (total > 1); /* repeat until only 1 result left */ - } - - - public static void Arith (lua_State L, StkId ra, TValue rb, - TValue rc, TMS op) { - TValue tempb = new TValue(), tempc = new TValue(); - TValue b, c; - if ((b = luaV_tonumber(rb, tempb)) != null && - (c = luaV_tonumber(rc, tempc)) != null) { - lua_Number nb = nvalue(b), nc = nvalue(c); - switch (op) { - case TMS.TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; - case TMS.TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; - case TMS.TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; - case TMS.TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; - case TMS.TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; - case TMS.TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; - case TMS.TM_UNM: setnvalue(ra, luai_numunm(nb)); break; - default: lua_assert(false); break; - } - } - else if (call_binTM(L, rb, rc, ra, op) == 0) - luaG_aritherror(L, rb, rc); - } - - - - /* - ** some macros for common tasks in `luaV_execute' - */ - - public static void runtime_check(lua_State L, bool c) { Debug.Assert(c); } - - //#define RA(i) (base+GETARG_A(i)) - /* to be used after possible stack reallocation */ - //#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgMask.OpArgR, base+GETARG_B(i)) - //#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgMask.OpArgR, base+GETARG_C(i)) - //#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgMask.OpArgK, \ - //ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) - //#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgMask.OpArgK, \ - // ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) - //#define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgMask.OpArgK, k+GETARG_Bx(i)) - - // todo: implement proper checks, as above - internal static TValue RA(lua_State L, StkId base_, Instruction i) { return base_ + GETARG_A(i); } - internal static TValue RB(lua_State L, StkId base_, Instruction i) { return base_ + GETARG_B(i); } - internal static TValue RC(lua_State L, StkId base_, Instruction i) { return base_ + GETARG_C(i); } - internal static TValue RKB(lua_State L, StkId base_, Instruction i, TValue[] k) { return ISK(GETARG_B(i)) != 0 ? k[INDEXK(GETARG_B(i))] : base_ + GETARG_B(i); } - internal static TValue RKC(lua_State L, StkId base_, Instruction i, TValue[] k) { return ISK(GETARG_C(i)) != 0 ? k[INDEXK(GETARG_C(i))] : base_ + GETARG_C(i); } - internal static TValue KBx(lua_State L, Instruction i, TValue[] k) { return k[GETARG_Bx(i)]; } - - - public static void dojump(lua_State L, InstructionPtr pc, int i) { pc.pc += i; luai_threadyield(L); } - - - //#define Protect(x) { L.savedpc = pc; {x;}; base = L.base_; } - - [CLSCompliantAttribute(false)] - public static void arith_op(lua_State L, op_delegate op, TMS tm, StkId base_, Instruction i, TValue[] k, StkId ra, InstructionPtr pc) { - TValue rb = RKB(L, base_, i, k); - TValue rc = RKC(L, base_, i, k); - if (ttisnumber(rb) && ttisnumber(rc)) - { - lua_Number nb = nvalue(rb), nc = nvalue(rc); - setnvalue(ra, op(nb, nc)); - } - else - { - //Protect( - L.savedpc = InstructionPtr.Assign(pc); - Arith(L, ra, rb, rc, tm); - base_ = L.base_; - //); - } - } - - internal static void Dump(int pc, Instruction i) - { - int A = GETARG_A(i); - int B = GETARG_B(i); - int C = GETARG_C(i); - int Bx = GETARG_Bx(i); - int sBx = GETARG_sBx(i); - if ((sBx & 0x100) != 0) - sBx = - (sBx & 0xff); - - Console.Write("{0,5} ({1,10}): ", pc, i); - Console.Write("{0,-10}\t", luaP_opnames[(int)GET_OPCODE(i)]); - switch (GET_OPCODE(i)) - { - case OpCode.OP_CLOSE: - Console.Write("{0}", A); - break; - - case OpCode.OP_MOVE: - case OpCode.OP_LOADNIL: - case OpCode.OP_GETUPVAL: - case OpCode.OP_SETUPVAL: - case OpCode.OP_UNM: - case OpCode.OP_NOT: - case OpCode.OP_RETURN: - Console.Write("{0}, {1}", A, B); - break; - - case OpCode.OP_LOADBOOL: - case OpCode.OP_GETTABLE: - case OpCode.OP_SETTABLE: - case OpCode.OP_NEWTABLE: - case OpCode.OP_SELF: - case OpCode.OP_ADD: - case OpCode.OP_SUB: - case OpCode.OP_MUL: - case OpCode.OP_DIV: - case OpCode.OP_POW: - case OpCode.OP_CONCAT: - case OpCode.OP_EQ: - case OpCode.OP_LT: - case OpCode.OP_LE: - case OpCode.OP_TEST: - case OpCode.OP_CALL: - case OpCode.OP_TAILCALL: - Console.Write("{0}, {1}, {2}", A, B, C); - break; - - case OpCode.OP_LOADK: - Console.Write("{0}, {1}", A, Bx); - break; - - case OpCode.OP_GETGLOBAL: - case OpCode.OP_SETGLOBAL: - case OpCode.OP_SETLIST: - case OpCode.OP_CLOSURE: - Console.Write("{0}, {1}", A, Bx); - break; - - case OpCode.OP_TFORLOOP: - Console.Write("{0}, {1}", A, C); - break; - - case OpCode.OP_JMP: - case OpCode.OP_FORLOOP: - case OpCode.OP_FORPREP: - Console.Write("{0}, {1}", A, sBx); - break; - } - Console.WriteLine(); - - } - - public static void luaV_execute (lua_State L, int nexeccalls) { - LClosure cl; - StkId base_; - TValue[] k; - /*const*/ InstructionPtr pc; - reentry: /* entry point */ - lua_assert(isLua(L.ci)); - pc = InstructionPtr.Assign(L.savedpc); - cl = clvalue(L.ci.func).l; - base_ = L.base_; - k = cl.p.k; - /* main loop of interpreter */ - for (;;) { - /*const*/ Instruction i = InstructionPtr.inc(ref pc)[0]; - StkId ra; - if ( ((L.hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) != 0) && - (((--L.hookcount) == 0) || ((L.hookmask & LUA_MASKLINE) != 0))) { - traceexec(L, pc); - if (L.status == LUA_YIELD) { /* did hook yield? */ - L.savedpc = new InstructionPtr(pc.codes, pc.pc - 1); - return; - } - base_ = L.base_; - } - /* warning!! several calls may realloc the stack and invalidate `ra' */ - ra = RA(L, base_, i); - lua_assert(base_ == L.base_ && L.base_ == L.ci.base_); - lua_assert(base_ <= L.top && ((L.top - L.stack) <= L.stacksize)); - lua_assert(L.top == L.ci.top || (luaG_checkopenop(i)!=0)); - //Dump(pc.pc, i); - switch (GET_OPCODE(i)) { - case OpCode.OP_MOVE: { - setobjs2s(L, ra, RB(L, base_, i)); - continue; - } - case OpCode.OP_LOADK: { - setobj2s(L, ra, KBx(L, i, k)); - continue; - } - case OpCode.OP_LOADBOOL: { - setbvalue(ra, GETARG_B(i)); - if (GETARG_C(i) != 0) InstructionPtr.inc(ref pc); /* skip next instruction (if C) */ - continue; - } - case OpCode.OP_LOADNIL: { - TValue rb = RB(L, base_, i); - do { - setnilvalue(StkId.dec(ref rb)); - } while (rb >= ra); - continue; - } - case OpCode.OP_GETUPVAL: { - int b = GETARG_B(i); - setobj2s(L, ra, cl.upvals[b].v); - continue; - } - case OpCode.OP_GETGLOBAL: { - TValue g = new TValue(); - TValue rb = KBx(L, i, k); - sethvalue(L, g, cl.env); - lua_assert(ttisstring(rb)); - //Protect( - L.savedpc = InstructionPtr.Assign(pc); - luaV_gettable(L, g, rb, ra); - base_ = L.base_; - //); - L.savedpc = InstructionPtr.Assign(pc); - continue; - } - case OpCode.OP_GETTABLE: { - //Protect( - L.savedpc = InstructionPtr.Assign(pc); - luaV_gettable(L, RB(L, base_, i), RKC(L, base_, i, k), ra); - base_ = L.base_; - //); - L.savedpc = InstructionPtr.Assign(pc); - continue; - } - case OpCode.OP_SETGLOBAL: { - TValue g = new TValue(); - sethvalue(L, g, cl.env); - lua_assert(ttisstring(KBx(L, i, k))); - //Protect( - L.savedpc = InstructionPtr.Assign(pc); - luaV_settable(L, g, KBx(L, i, k), ra); - base_ = L.base_; - //); - L.savedpc = InstructionPtr.Assign(pc); - continue; - } - case OpCode.OP_SETUPVAL: { - UpVal uv = cl.upvals[GETARG_B(i)]; - setobj(L, uv.v, ra); - luaC_barrier(L, uv, ra); - continue; - } - case OpCode.OP_SETTABLE: { - //Protect( - L.savedpc = InstructionPtr.Assign(pc); - luaV_settable(L, ra, RKB(L, base_, i, k), RKC(L, base_, i, k)); - base_ = L.base_; - //); - L.savedpc = InstructionPtr.Assign(pc); - continue; - } - case OpCode.OP_NEWTABLE: { - int b = GETARG_B(i); - int c = GETARG_C(i); - sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); - //Protect( - L.savedpc = InstructionPtr.Assign(pc); - luaC_checkGC(L); - base_ = L.base_; - //); - L.savedpc = InstructionPtr.Assign(pc); - continue; - } - case OpCode.OP_SELF: { - StkId rb = RB(L, base_, i); - setobjs2s(L, ra + 1, rb); - //Protect( - L.savedpc = InstructionPtr.Assign(pc); - luaV_gettable(L, rb, RKC(L, base_, i, k), ra); - base_ = L.base_; - //); - L.savedpc = InstructionPtr.Assign(pc); - continue; - } - case OpCode.OP_ADD: { - arith_op(L, luai_numadd, TMS.TM_ADD, base_, i, k, ra, pc); - continue; - } - case OpCode.OP_SUB: { - arith_op(L, luai_numsub, TMS.TM_SUB, base_, i, k, ra, pc); - continue; - } - case OpCode.OP_MUL: { - arith_op(L, luai_nummul, TMS.TM_MUL, base_, i, k, ra, pc); - continue; - } - case OpCode.OP_DIV: { - arith_op(L, luai_numdiv, TMS.TM_DIV, base_, i, k, ra, pc); - continue; - } - case OpCode.OP_MOD: { - arith_op(L, luai_nummod, TMS.TM_MOD, base_, i, k, ra, pc); - continue; - } - case OpCode.OP_POW: { - arith_op(L, luai_numpow, TMS.TM_POW, base_, i, k, ra, pc); - continue; - } - case OpCode.OP_UNM: { - TValue rb = RB(L, base_, i); - if (ttisnumber(rb)) { - lua_Number nb = nvalue(rb); - setnvalue(ra, luai_numunm(nb)); - } - else { - //Protect( - L.savedpc = InstructionPtr.Assign(pc); - Arith(L, ra, rb, rb, TMS.TM_UNM); - base_ = L.base_; - //); - L.savedpc = InstructionPtr.Assign(pc); - } - continue; - } - case OpCode.OP_NOT: { - int res = l_isfalse(RB(L, base_, i)) == 0 ? 0 : 1; /* next assignment may change this value */ - setbvalue(ra, res); - continue; - } - case OpCode.OP_LEN: { - TValue rb = RB(L, base_, i); - switch (ttype(rb)) { - case LUA_TTABLE: { - setnvalue(ra, (lua_Number)luaH_getn(hvalue(rb))); - break; - } - case LUA_TSTRING: { - setnvalue(ra, (lua_Number)tsvalue(rb).len); - break; - } - default: { /* try metamethod */ - //Protect( - L.savedpc = InstructionPtr.Assign(pc); - if (call_binTM(L, rb, luaO_nilobject, ra, TMS.TM_LEN) == 0) - luaG_typeerror(L, rb, "get length of"); - base_ = L.base_; - //) - break; - } - } - continue; - } - case OpCode.OP_CONCAT: { - int b = GETARG_B(i); - int c = GETARG_C(i); - //Protect( - L.savedpc = InstructionPtr.Assign(pc); - luaV_concat(L, c-b+1, c); luaC_checkGC(L); - base_ = L.base_; - //); - setobjs2s(L, RA(L, base_, i), base_ + b); - continue; - } - case OpCode.OP_JMP: { - dojump(L, pc, GETARG_sBx(i)); - continue; - } - case OpCode.OP_EQ: { - TValue rb = RKB(L, base_, i, k); - TValue rc = RKC(L, base_, i, k); - //Protect( - L.savedpc = InstructionPtr.Assign(pc); - if (equalobj(L, rb, rc) == GETARG_A(i)) - dojump(L, pc, GETARG_sBx(pc[0])); - base_ = L.base_; - //); - InstructionPtr.inc(ref pc); - continue; - } - case OpCode.OP_LT: { - //Protect( - L.savedpc = InstructionPtr.Assign(pc); - if (luaV_lessthan(L, RKB(L, base_, i, k), RKC(L, base_, i, k)) == GETARG_A(i)) - dojump(L, pc, GETARG_sBx(pc[0])); - base_ = L.base_; - //); - InstructionPtr.inc(ref pc); - continue; - } - case OpCode.OP_LE: { - //Protect( - L.savedpc = InstructionPtr.Assign(pc); - if (lessequal(L, RKB(L, base_, i, k), RKC(L, base_, i, k)) == GETARG_A(i)) - dojump(L, pc, GETARG_sBx(pc[0])); - base_ = L.base_; - //); - InstructionPtr.inc(ref pc); - continue; - } - case OpCode.OP_TEST: { - if (l_isfalse(ra) != GETARG_C(i)) - dojump(L, pc, GETARG_sBx(pc[0])); - InstructionPtr.inc(ref pc); - continue; - } - case OpCode.OP_TESTSET: { - TValue rb = RB(L, base_, i); - if (l_isfalse(rb) != GETARG_C(i)) { - setobjs2s(L, ra, rb); - dojump(L, pc, GETARG_sBx(pc[0])); - } - InstructionPtr.inc(ref pc); - continue; - } - case OpCode.OP_CALL: { - int b = GETARG_B(i); - int nresults = GETARG_C(i) - 1; - if (b != 0) L.top = ra + b; /* else previous instruction set top */ - L.savedpc = InstructionPtr.Assign(pc); - switch (luaD_precall(L, ra, nresults)) { - case PCRLUA: { - nexeccalls++; - goto reentry; /* restart luaV_execute over new Lua function */ - } - case PCRC: { - /* it was a C function (`precall' called it); adjust results */ - if (nresults >= 0) L.top = L.ci.top; - base_ = L.base_; - continue; - } - default: { - return; /* yield */ - } - } - } - case OpCode.OP_TAILCALL: { - int b = GETARG_B(i); - if (b != 0) L.top = ra + b; /* else previous instruction set top */ - L.savedpc = InstructionPtr.Assign(pc); - lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); - switch (luaD_precall(L, ra, LUA_MULTRET)) { - case PCRLUA: { - /* tail call: put new frame in place of previous one */ - CallInfo ci = L.ci - 1; /* previous frame */ - int aux; - StkId func = ci.func; - StkId pfunc = (ci+1).func; /* previous function index */ - if (L.openupval != null) luaF_close(L, ci.base_); - L.base_ = ci.base_ = ci.func + (ci[1].base_ - pfunc); - for (aux = 0; pfunc+aux < L.top; aux++) /* move frame down */ - setobjs2s(L, func+aux, pfunc+aux); - ci.top = L.top = func+aux; /* correct top */ - lua_assert(L.top == L.base_ + clvalue(func).l.p.maxstacksize); - ci.savedpc = InstructionPtr.Assign(L.savedpc); - ci.tailcalls++; /* one more call lost */ - CallInfo.dec(ref L.ci); /* remove new frame */ - goto reentry; - } - case PCRC: { /* it was a C function (`precall' called it) */ - base_ = L.base_; - continue; - } - default: { - return; /* yield */ - } - } - } - case OpCode.OP_RETURN: { - int b = GETARG_B(i); - if (b != 0) L.top = ra+b-1; - if (L.openupval != null) luaF_close(L, base_); - L.savedpc = InstructionPtr.Assign(pc); - b = luaD_poscall(L, ra); - if (--nexeccalls == 0) /* was previous function running `here'? */ - return; /* no: return */ - else { /* yes: continue its execution */ - if (b != 0) L.top = L.ci.top; - lua_assert(isLua(L.ci)); - lua_assert(GET_OPCODE(L.ci.savedpc[-1]) == OpCode.OP_CALL); - goto reentry; - } - } - case OpCode.OP_FORLOOP: { - lua_Number step = nvalue(ra+2); - lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ - lua_Number limit = nvalue(ra+1); - if (luai_numlt(0, step) ? luai_numle(idx, limit) - : luai_numle(limit, idx)) { - dojump(L, pc, GETARG_sBx(i)); /* jump back */ - setnvalue(ra, idx); /* update internal index... */ - setnvalue(ra+3, idx); /* ...and external index */ - } - continue; - } - case OpCode.OP_FORPREP: { - TValue init = ra; - TValue plimit = ra+1; - TValue pstep = ra+2; - L.savedpc = InstructionPtr.Assign(pc); /* next steps may throw errors */ - if (tonumber(ref init, ra) == 0) - luaG_runerror(L, LUA_QL("for") + " initial value must be a number"); - else if (tonumber(ref plimit, ra+1) == 0) - luaG_runerror(L, LUA_QL("for") + " limit must be a number"); - else if (tonumber(ref pstep, ra+2) == 0) - luaG_runerror(L, LUA_QL("for") + " step must be a number"); - setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); - dojump(L, pc, GETARG_sBx(i)); - continue; - } - case OpCode.OP_TFORLOOP: { - StkId cb = ra + 3; /* call base */ - setobjs2s(L, cb+2, ra+2); - setobjs2s(L, cb+1, ra+1); - setobjs2s(L, cb, ra); - L.top = cb+3; /* func. + 2 args (state and index) */ - //Protect( - L.savedpc = InstructionPtr.Assign(pc); - luaD_call(L, cb, GETARG_C(i)); - base_ = L.base_; - //); - L.top = L.ci.top; - cb = RA(L, base_, i) + 3; /* previous call may change the stack */ - if (!ttisnil(cb)) { /* continue loop? */ - setobjs2s(L, cb-1, cb); /* save control variable */ - dojump(L, pc, GETARG_sBx(pc[0])); /* jump back */ - } - InstructionPtr.inc(ref pc); - continue; - } - case OpCode.OP_SETLIST: { - int n = GETARG_B(i); - int c = GETARG_C(i); - int last; - Table h; - if (n == 0) { - n = cast_int(L.top - ra) - 1; - L.top = L.ci.top; - } - if (c == 0) - { - c = cast_int(pc[0]); - InstructionPtr.inc(ref pc); - } - runtime_check(L, ttistable(ra)); - h = hvalue(ra); - last = ((c-1)*LFIELDS_PER_FLUSH) + n; - if (last > h.sizearray) /* needs more space? */ - luaH_resizearray(L, h, last); /* pre-alloc it at once */ - for (; n > 0; n--) { - TValue val = ra+n; - setobj2t(L, luaH_setnum(L, h, last--), val); - luaC_barriert(L, h, val); - } - continue; - } - case OpCode.OP_CLOSE: { - luaF_close(L, ra); - continue; - } - case OpCode.OP_CLOSURE: { - Proto p; - Closure ncl; - int nup, j; - p = cl.p.p[GETARG_Bx(i)]; - nup = p.nups; - ncl = luaF_newLclosure(L, nup, cl.env); - ncl.l.p = p; - for (j=0; j same metamethods */ + tm2 = fasttm(L, mt2, event_); + if (tm2 == null) return null; /* no metamethod */ + if (luaO_rawequalObj(tm1, tm2) != 0) /* same metamethods? */ + return tm1; + return null; + } + + + private static int call_orderTM (lua_State L, TValue p1, TValue p2, + TMS event_) { + TValue tm1 = luaT_gettmbyobj(L, p1, event_); + TValue tm2; + if (ttisnil(tm1)) return -1; /* no metamethod? */ + tm2 = luaT_gettmbyobj(L, p2, event_); + if (luaO_rawequalObj(tm1, tm2)==0) /* different metamethods? */ + return -1; + callTMres(L, L.top, tm1, p1, p2); + return l_isfalse(L.top) == 0 ? 1 : 0; + } + + + private static int l_strcmp (TString ls, TString rs) { + CharPtr l = getstr(ls); + uint ll = ls.tsv.len; + CharPtr r = getstr(rs); + uint lr = rs.tsv.len; + for (;;) { + //int temp = strcoll(l, r); + int temp = String.Compare(l.ToString(), r.ToString()); + if (temp != 0) return temp; + else { /* strings are equal up to a `\0' */ + uint len = (uint)l.ToString().Length; /* index of first `\0' in both strings */ + if (len == lr) /* r is finished? */ + return (len == ll) ? 0 : 1; + else if (len == ll) /* l is finished? */ + return -1; /* l is smaller than r (because r is not finished) */ + /* both strings longer than `len'; go on comparing (after the `\0') */ + len++; + l += len; ll -= len; r += len; lr -= len; + } + } + } + + + public static int luaV_lessthan (lua_State L, TValue l, TValue r) { + int res; + if (ttype(l) != ttype(r)) + return luaG_ordererror(L, l, r); + else if (ttisnumber(l)) + return luai_numlt(nvalue(l), nvalue(r)) ? 1 : 0; + else if (ttisstring(l)) + return (l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0) ? 1 : 0; + else if ((res = call_orderTM(L, l, r, TMS.TM_LT)) != -1) + return res; + return luaG_ordererror(L, l, r); + } + + + private static int lessequal (lua_State L, TValue l, TValue r) { + int res; + if (ttype(l) != ttype(r)) + return luaG_ordererror(L, l, r); + else if (ttisnumber(l)) + return luai_numle(nvalue(l), nvalue(r)) ? 1 : 0; + else if (ttisstring(l)) + return (l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0) ? 1 : 0; + else if ((res = call_orderTM(L, l, r, TMS.TM_LE)) != -1) /* first try `le' */ + return res; + else if ((res = call_orderTM(L, r, l, TMS.TM_LT)) != -1) /* else try `lt' */ + return (res == 0) ? 1 : 0; + return luaG_ordererror(L, l, r); + } + + static CharPtr mybuff = null; + + public static int luaV_equalval (lua_State L, TValue t1, TValue t2) { + TValue tm = null; + lua_assert(ttype(t1) == ttype(t2)); + switch (ttype(t1)) { + case LUA_TNIL: return 1; + case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)) ? 1 : 0; + case LUA_TBOOLEAN: return (bvalue(t1) == bvalue(t2)) ? 1 : 0; /* true must be 1 !! */ + case LUA_TLIGHTUSERDATA: return (pvalue(t1) == pvalue(t2)) ? 1 : 0; + case LUA_TUSERDATA: { + if (uvalue(t1) == uvalue(t2)) return 1; + tm = get_compTM(L, uvalue(t1).metatable, uvalue(t2).metatable, + TMS.TM_EQ); + break; /* will try TM */ + } + case LUA_TTABLE: { + if (hvalue(t1) == hvalue(t2)) return 1; + tm = get_compTM(L, hvalue(t1).metatable, hvalue(t2).metatable, TMS.TM_EQ); + break; /* will try TM */ + } + default: return (gcvalue(t1) == gcvalue(t2)) ? 1 : 0; + } + if (tm == null) return 0; /* no TM? */ + callTMres(L, L.top, tm, t1, t2); /* call TM */ + return l_isfalse(L.top) == 0 ? 1 : 0; + } + + + public static void luaV_concat (lua_State L, int total, int last) { + do { + StkId top = L.base_ + last + 1; + int n = 2; /* number of elements handled in this pass (at least 2) */ + if (!(ttisstring(top-2) || ttisnumber(top-2)) || (tostring(L, top-1)==0)) { + if (call_binTM(L, top-2, top-1, top-2, TMS.TM_CONCAT)==0) + luaG_concaterror(L, top-2, top-1); + } else if (tsvalue(top-1).len == 0) /* second op is empty? */ + tostring(L, top - 2); /* result is first op (as string) */ + else { + /* at least two string values; get as many as possible */ + uint tl = tsvalue(top-1).len; + CharPtr buffer; + int i; + /* collect total length */ + for (n = 1; n < total && (tostring(L, top-n-1)!=0); n++) { + uint l = tsvalue(top-n-1).len; + if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); + tl += l; + } + buffer = luaZ_openspace(L, G(L).buff, tl); + if (mybuff == null) + mybuff = buffer; + tl = 0; + for (i=n; i>0; i--) { /* concat all strings */ + uint l = tsvalue(top-i).len; + memcpy(buffer.chars, (int)tl, svalue(top-i).chars, (int)l); + tl += l; + } + setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); + } + total -= n-1; /* got `n' strings to create 1 new */ + last -= n-1; + } while (total > 1); /* repeat until only 1 result left */ + } + + + public static void Arith (lua_State L, StkId ra, TValue rb, + TValue rc, TMS op) { + TValue tempb = new TValue(), tempc = new TValue(); + TValue b, c; + if ((b = luaV_tonumber(rb, tempb)) != null && + (c = luaV_tonumber(rc, tempc)) != null) { + lua_Number nb = nvalue(b), nc = nvalue(c); + switch (op) { + case TMS.TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; + case TMS.TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; + case TMS.TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; + case TMS.TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; + case TMS.TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; + case TMS.TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; + case TMS.TM_UNM: setnvalue(ra, luai_numunm(nb)); break; + default: lua_assert(false); break; + } + } + else if (call_binTM(L, rb, rc, ra, op) == 0) + luaG_aritherror(L, rb, rc); + } + + + + /* + ** some macros for common tasks in `luaV_execute' + */ + + public static void runtime_check(lua_State L, bool c) { Debug.Assert(c); } + + //#define RA(i) (base+GETARG_A(i)) + /* to be used after possible stack reallocation */ + //#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgMask.OpArgR, base+GETARG_B(i)) + //#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgMask.OpArgR, base+GETARG_C(i)) + //#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgMask.OpArgK, \ + //ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) + //#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgMask.OpArgK, \ + // ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) + //#define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgMask.OpArgK, k+GETARG_Bx(i)) + + // todo: implement proper checks, as above + internal static TValue RA(lua_State L, StkId base_, Instruction i) { return base_ + GETARG_A(i); } + internal static TValue RB(lua_State L, StkId base_, Instruction i) { return base_ + GETARG_B(i); } + internal static TValue RC(lua_State L, StkId base_, Instruction i) { return base_ + GETARG_C(i); } + internal static TValue RKB(lua_State L, StkId base_, Instruction i, TValue[] k) { return ISK(GETARG_B(i)) != 0 ? k[INDEXK(GETARG_B(i))] : base_ + GETARG_B(i); } + internal static TValue RKC(lua_State L, StkId base_, Instruction i, TValue[] k) { return ISK(GETARG_C(i)) != 0 ? k[INDEXK(GETARG_C(i))] : base_ + GETARG_C(i); } + internal static TValue KBx(lua_State L, Instruction i, TValue[] k) { return k[GETARG_Bx(i)]; } + + + public static void dojump(lua_State L, InstructionPtr pc, int i) { pc.pc += i; luai_threadyield(L); } + + + //#define Protect(x) { L.savedpc = pc; {x;}; base = L.base_; } + + [CLSCompliantAttribute(false)] + public static void arith_op(lua_State L, op_delegate op, TMS tm, StkId base_, Instruction i, TValue[] k, StkId ra, InstructionPtr pc) { + TValue rb = RKB(L, base_, i, k); + TValue rc = RKC(L, base_, i, k); + if (ttisnumber(rb) && ttisnumber(rc)) + { + lua_Number nb = nvalue(rb), nc = nvalue(rc); + setnvalue(ra, op(nb, nc)); + } + else + { + //Protect( + L.savedpc = InstructionPtr.Assign(pc); + Arith(L, ra, rb, rc, tm); + base_ = L.base_; + //); + } + } + + internal static void Dump(int pc, Instruction i) + { + int A = GETARG_A(i); + int B = GETARG_B(i); + int C = GETARG_C(i); + int Bx = GETARG_Bx(i); + int sBx = GETARG_sBx(i); + if ((sBx & 0x100) != 0) + sBx = - (sBx & 0xff); + + Console.Write("{0,5} ({1,10}): ", pc, i); + Console.Write("{0,-10}\t", luaP_opnames[(int)GET_OPCODE(i)]); + switch (GET_OPCODE(i)) + { + case OpCode.OP_CLOSE: + Console.Write("{0}", A); + break; + + case OpCode.OP_MOVE: + case OpCode.OP_LOADNIL: + case OpCode.OP_GETUPVAL: + case OpCode.OP_SETUPVAL: + case OpCode.OP_UNM: + case OpCode.OP_NOT: + case OpCode.OP_RETURN: + Console.Write("{0}, {1}", A, B); + break; + + case OpCode.OP_LOADBOOL: + case OpCode.OP_GETTABLE: + case OpCode.OP_SETTABLE: + case OpCode.OP_NEWTABLE: + case OpCode.OP_SELF: + case OpCode.OP_ADD: + case OpCode.OP_SUB: + case OpCode.OP_MUL: + case OpCode.OP_DIV: + case OpCode.OP_POW: + case OpCode.OP_CONCAT: + case OpCode.OP_EQ: + case OpCode.OP_LT: + case OpCode.OP_LE: + case OpCode.OP_TEST: + case OpCode.OP_CALL: + case OpCode.OP_TAILCALL: + Console.Write("{0}, {1}, {2}", A, B, C); + break; + + case OpCode.OP_LOADK: + Console.Write("{0}, {1}", A, Bx); + break; + + case OpCode.OP_GETGLOBAL: + case OpCode.OP_SETGLOBAL: + case OpCode.OP_SETLIST: + case OpCode.OP_CLOSURE: + Console.Write("{0}, {1}", A, Bx); + break; + + case OpCode.OP_TFORLOOP: + Console.Write("{0}, {1}", A, C); + break; + + case OpCode.OP_JMP: + case OpCode.OP_FORLOOP: + case OpCode.OP_FORPREP: + Console.Write("{0}, {1}", A, sBx); + break; + } + Console.WriteLine(); + + } + + public static void luaV_execute (lua_State L, int nexeccalls) { + LClosure cl; + StkId base_; + TValue[] k; + /*const*/ InstructionPtr pc; + reentry: /* entry point */ + lua_assert(isLua(L.ci)); + pc = InstructionPtr.Assign(L.savedpc); + cl = clvalue(L.ci.func).l; + base_ = L.base_; + k = cl.p.k; + /* main loop of interpreter */ + for (;;) { + /*const*/ Instruction i = InstructionPtr.inc(ref pc)[0]; + StkId ra; + if ( ((L.hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) != 0) && + (((--L.hookcount) == 0) || ((L.hookmask & LUA_MASKLINE) != 0))) { + traceexec(L, pc); + if (L.status == LUA_YIELD) { /* did hook yield? */ + L.savedpc = new InstructionPtr(pc.codes, pc.pc - 1); + return; + } + base_ = L.base_; + } + /* warning!! several calls may realloc the stack and invalidate `ra' */ + ra = RA(L, base_, i); + lua_assert(base_ == L.base_ && L.base_ == L.ci.base_); + lua_assert(base_ <= L.top && ((L.top - L.stack) <= L.stacksize)); + lua_assert(L.top == L.ci.top || (luaG_checkopenop(i)!=0)); + //Dump(pc.pc, i); + switch (GET_OPCODE(i)) { + case OpCode.OP_MOVE: { + setobjs2s(L, ra, RB(L, base_, i)); + continue; + } + case OpCode.OP_LOADK: { + setobj2s(L, ra, KBx(L, i, k)); + continue; + } + case OpCode.OP_LOADBOOL: { + setbvalue(ra, GETARG_B(i)); + if (GETARG_C(i) != 0) InstructionPtr.inc(ref pc); /* skip next instruction (if C) */ + continue; + } + case OpCode.OP_LOADNIL: { + TValue rb = RB(L, base_, i); + do { + setnilvalue(StkId.dec(ref rb)); + } while (rb >= ra); + continue; + } + case OpCode.OP_GETUPVAL: { + int b = GETARG_B(i); + setobj2s(L, ra, cl.upvals[b].v); + continue; + } + case OpCode.OP_GETGLOBAL: { + TValue g = new TValue(); + TValue rb = KBx(L, i, k); + sethvalue(L, g, cl.env); + lua_assert(ttisstring(rb)); + //Protect( + L.savedpc = InstructionPtr.Assign(pc); + luaV_gettable(L, g, rb, ra); + base_ = L.base_; + //); + L.savedpc = InstructionPtr.Assign(pc); + continue; + } + case OpCode.OP_GETTABLE: { + //Protect( + L.savedpc = InstructionPtr.Assign(pc); + luaV_gettable(L, RB(L, base_, i), RKC(L, base_, i, k), ra); + base_ = L.base_; + //); + L.savedpc = InstructionPtr.Assign(pc); + continue; + } + case OpCode.OP_SETGLOBAL: { + TValue g = new TValue(); + sethvalue(L, g, cl.env); + lua_assert(ttisstring(KBx(L, i, k))); + //Protect( + L.savedpc = InstructionPtr.Assign(pc); + luaV_settable(L, g, KBx(L, i, k), ra); + base_ = L.base_; + //); + L.savedpc = InstructionPtr.Assign(pc); + continue; + } + case OpCode.OP_SETUPVAL: { + UpVal uv = cl.upvals[GETARG_B(i)]; + setobj(L, uv.v, ra); + luaC_barrier(L, uv, ra); + continue; + } + case OpCode.OP_SETTABLE: { + //Protect( + L.savedpc = InstructionPtr.Assign(pc); + luaV_settable(L, ra, RKB(L, base_, i, k), RKC(L, base_, i, k)); + base_ = L.base_; + //); + L.savedpc = InstructionPtr.Assign(pc); + continue; + } + case OpCode.OP_NEWTABLE: { + int b = GETARG_B(i); + int c = GETARG_C(i); + sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); + //Protect( + L.savedpc = InstructionPtr.Assign(pc); + luaC_checkGC(L); + base_ = L.base_; + //); + L.savedpc = InstructionPtr.Assign(pc); + continue; + } + case OpCode.OP_SELF: { + StkId rb = RB(L, base_, i); + setobjs2s(L, ra + 1, rb); + //Protect( + L.savedpc = InstructionPtr.Assign(pc); + luaV_gettable(L, rb, RKC(L, base_, i, k), ra); + base_ = L.base_; + //); + L.savedpc = InstructionPtr.Assign(pc); + continue; + } + case OpCode.OP_ADD: { + arith_op(L, luai_numadd, TMS.TM_ADD, base_, i, k, ra, pc); + continue; + } + case OpCode.OP_SUB: { + arith_op(L, luai_numsub, TMS.TM_SUB, base_, i, k, ra, pc); + continue; + } + case OpCode.OP_MUL: { + arith_op(L, luai_nummul, TMS.TM_MUL, base_, i, k, ra, pc); + continue; + } + case OpCode.OP_DIV: { + arith_op(L, luai_numdiv, TMS.TM_DIV, base_, i, k, ra, pc); + continue; + } + case OpCode.OP_MOD: { + arith_op(L, luai_nummod, TMS.TM_MOD, base_, i, k, ra, pc); + continue; + } + case OpCode.OP_POW: { + arith_op(L, luai_numpow, TMS.TM_POW, base_, i, k, ra, pc); + continue; + } + case OpCode.OP_UNM: { + TValue rb = RB(L, base_, i); + if (ttisnumber(rb)) { + lua_Number nb = nvalue(rb); + setnvalue(ra, luai_numunm(nb)); + } + else { + //Protect( + L.savedpc = InstructionPtr.Assign(pc); + Arith(L, ra, rb, rb, TMS.TM_UNM); + base_ = L.base_; + //); + L.savedpc = InstructionPtr.Assign(pc); + } + continue; + } + case OpCode.OP_NOT: { + int res = l_isfalse(RB(L, base_, i)) == 0 ? 0 : 1; /* next assignment may change this value */ + setbvalue(ra, res); + continue; + } + case OpCode.OP_LEN: { + TValue rb = RB(L, base_, i); + switch (ttype(rb)) { + case LUA_TTABLE: { + setnvalue(ra, (lua_Number)luaH_getn(hvalue(rb))); + break; + } + case LUA_TSTRING: { + setnvalue(ra, (lua_Number)tsvalue(rb).len); + break; + } + default: { /* try metamethod */ + //Protect( + L.savedpc = InstructionPtr.Assign(pc); + if (call_binTM(L, rb, luaO_nilobject, ra, TMS.TM_LEN) == 0) + luaG_typeerror(L, rb, "get length of"); + base_ = L.base_; + //) + break; + } + } + continue; + } + case OpCode.OP_CONCAT: { + int b = GETARG_B(i); + int c = GETARG_C(i); + //Protect( + L.savedpc = InstructionPtr.Assign(pc); + luaV_concat(L, c-b+1, c); luaC_checkGC(L); + base_ = L.base_; + //); + setobjs2s(L, RA(L, base_, i), base_ + b); + continue; + } + case OpCode.OP_JMP: { + dojump(L, pc, GETARG_sBx(i)); + continue; + } + case OpCode.OP_EQ: { + TValue rb = RKB(L, base_, i, k); + TValue rc = RKC(L, base_, i, k); + //Protect( + L.savedpc = InstructionPtr.Assign(pc); + if (equalobj(L, rb, rc) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(pc[0])); + base_ = L.base_; + //); + InstructionPtr.inc(ref pc); + continue; + } + case OpCode.OP_LT: { + //Protect( + L.savedpc = InstructionPtr.Assign(pc); + if (luaV_lessthan(L, RKB(L, base_, i, k), RKC(L, base_, i, k)) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(pc[0])); + base_ = L.base_; + //); + InstructionPtr.inc(ref pc); + continue; + } + case OpCode.OP_LE: { + //Protect( + L.savedpc = InstructionPtr.Assign(pc); + if (lessequal(L, RKB(L, base_, i, k), RKC(L, base_, i, k)) == GETARG_A(i)) + dojump(L, pc, GETARG_sBx(pc[0])); + base_ = L.base_; + //); + InstructionPtr.inc(ref pc); + continue; + } + case OpCode.OP_TEST: { + if (l_isfalse(ra) != GETARG_C(i)) + dojump(L, pc, GETARG_sBx(pc[0])); + InstructionPtr.inc(ref pc); + continue; + } + case OpCode.OP_TESTSET: { + TValue rb = RB(L, base_, i); + if (l_isfalse(rb) != GETARG_C(i)) { + setobjs2s(L, ra, rb); + dojump(L, pc, GETARG_sBx(pc[0])); + } + InstructionPtr.inc(ref pc); + continue; + } + case OpCode.OP_CALL: { + int b = GETARG_B(i); + int nresults = GETARG_C(i) - 1; + if (b != 0) L.top = ra + b; /* else previous instruction set top */ + L.savedpc = InstructionPtr.Assign(pc); + switch (luaD_precall(L, ra, nresults)) { + case PCRLUA: { + nexeccalls++; + goto reentry; /* restart luaV_execute over new Lua function */ + } + case PCRC: { + /* it was a C function (`precall' called it); adjust results */ + if (nresults >= 0) L.top = L.ci.top; + base_ = L.base_; + continue; + } + default: { + return; /* yield */ + } + } + } + case OpCode.OP_TAILCALL: { + int b = GETARG_B(i); + if (b != 0) L.top = ra + b; /* else previous instruction set top */ + L.savedpc = InstructionPtr.Assign(pc); + lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); + switch (luaD_precall(L, ra, LUA_MULTRET)) { + case PCRLUA: { + /* tail call: put new frame in place of previous one */ + CallInfo ci = L.ci - 1; /* previous frame */ + int aux; + StkId func = ci.func; + StkId pfunc = (ci+1).func; /* previous function index */ + if (L.openupval != null) luaF_close(L, ci.base_); + L.base_ = ci.base_ = ci.func + (ci[1].base_ - pfunc); + for (aux = 0; pfunc+aux < L.top; aux++) /* move frame down */ + setobjs2s(L, func+aux, pfunc+aux); + ci.top = L.top = func+aux; /* correct top */ + lua_assert(L.top == L.base_ + clvalue(func).l.p.maxstacksize); + ci.savedpc = InstructionPtr.Assign(L.savedpc); + ci.tailcalls++; /* one more call lost */ + CallInfo.dec(ref L.ci); /* remove new frame */ + goto reentry; + } + case PCRC: { /* it was a C function (`precall' called it) */ + base_ = L.base_; + continue; + } + default: { + return; /* yield */ + } + } + } + case OpCode.OP_RETURN: { + int b = GETARG_B(i); + if (b != 0) L.top = ra+b-1; + if (L.openupval != null) luaF_close(L, base_); + L.savedpc = InstructionPtr.Assign(pc); + b = luaD_poscall(L, ra); + if (--nexeccalls == 0) /* was previous function running `here'? */ + return; /* no: return */ + else { /* yes: continue its execution */ + if (b != 0) L.top = L.ci.top; + lua_assert(isLua(L.ci)); + lua_assert(GET_OPCODE(L.ci.savedpc[-1]) == OpCode.OP_CALL); + goto reentry; + } + } + case OpCode.OP_FORLOOP: { + lua_Number step = nvalue(ra+2); + lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ + lua_Number limit = nvalue(ra+1); + if (luai_numlt(0, step) ? luai_numle(idx, limit) + : luai_numle(limit, idx)) { + dojump(L, pc, GETARG_sBx(i)); /* jump back */ + setnvalue(ra, idx); /* update internal index... */ + setnvalue(ra+3, idx); /* ...and external index */ + } + continue; + } + case OpCode.OP_FORPREP: { + TValue init = ra; + TValue plimit = ra+1; + TValue pstep = ra+2; + L.savedpc = InstructionPtr.Assign(pc); /* next steps may throw errors */ + if (tonumber(ref init, ra) == 0) + luaG_runerror(L, LUA_QL("for") + " initial value must be a number"); + else if (tonumber(ref plimit, ra+1) == 0) + luaG_runerror(L, LUA_QL("for") + " limit must be a number"); + else if (tonumber(ref pstep, ra+2) == 0) + luaG_runerror(L, LUA_QL("for") + " step must be a number"); + setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); + dojump(L, pc, GETARG_sBx(i)); + continue; + } + case OpCode.OP_TFORLOOP: { + StkId cb = ra + 3; /* call base */ + setobjs2s(L, cb+2, ra+2); + setobjs2s(L, cb+1, ra+1); + setobjs2s(L, cb, ra); + L.top = cb+3; /* func. + 2 args (state and index) */ + //Protect( + L.savedpc = InstructionPtr.Assign(pc); + luaD_call(L, cb, GETARG_C(i)); + base_ = L.base_; + //); + L.top = L.ci.top; + cb = RA(L, base_, i) + 3; /* previous call may change the stack */ + if (!ttisnil(cb)) { /* continue loop? */ + setobjs2s(L, cb-1, cb); /* save control variable */ + dojump(L, pc, GETARG_sBx(pc[0])); /* jump back */ + } + InstructionPtr.inc(ref pc); + continue; + } + case OpCode.OP_SETLIST: { + int n = GETARG_B(i); + int c = GETARG_C(i); + int last; + Table h; + if (n == 0) { + n = cast_int(L.top - ra) - 1; + L.top = L.ci.top; + } + if (c == 0) + { + c = cast_int(pc[0]); + InstructionPtr.inc(ref pc); + } + runtime_check(L, ttistable(ra)); + h = hvalue(ra); + last = ((c-1)*LFIELDS_PER_FLUSH) + n; + if (last > h.sizearray) /* needs more space? */ + luaH_resizearray(L, h, last); /* pre-alloc it at once */ + for (; n > 0; n--) { + TValue val = ra+n; + setobj2t(L, luaH_setnum(L, h, last--), val); + luaC_barriert(L, h, val); + } + continue; + } + case OpCode.OP_CLOSE: { + luaF_close(L, ra); + continue; + } + case OpCode.OP_CLOSURE: { + Proto p; + Closure ncl; + int nup, j; + p = cl.p.p[GETARG_Bx(i)]; + nup = p.nups; + ncl = luaF_newLclosure(L, nup, cl.env); + ncl.l.p = p; + for (j=0; j 0) - { - int ch = char2int(z.p[0]); - z.p.inc(); - return ch; - } - else - return luaZ_fill(z); - } - - public class Mbuffer { - public CharPtr buffer = new CharPtr(); - [CLSCompliantAttribute(false)] - public uint n; - [CLSCompliantAttribute(false)] - public uint buffsize; - }; - - public static void luaZ_initbuffer(lua_State L, Mbuffer buff) - { - buff.buffer = null; - } - - public static CharPtr luaZ_buffer(Mbuffer buff) {return buff.buffer;} - [CLSCompliantAttribute(false)] - public static uint luaZ_sizebuffer(Mbuffer buff) { return buff.buffsize; } - [CLSCompliantAttribute(false)] - public static uint luaZ_bufflen(Mbuffer buff) {return buff.n;} - public static void luaZ_resetbuffer(Mbuffer buff) {buff.n = 0;} - - - public static void luaZ_resizebuffer(lua_State L, Mbuffer buff, int size) - { - if (buff.buffer == null) - buff.buffer = new CharPtr(); - luaM_reallocvector(L, ref buff.buffer.chars, (int)buff.buffsize, size); - buff.buffsize = (uint)buff.buffer.chars.Length; - } - - public static void luaZ_freebuffer(lua_State L, Mbuffer buff) {luaZ_resizebuffer(L, buff, 0);} - - - - /* --------- Private Part ------------------ */ - - public class Zio { - [CLSCompliantAttribute(false)] - public uint n; /* bytes still unread */ - public CharPtr p; /* current position in buffer */ - [CLSCompliantAttribute(false)] - public lua_Reader reader; - public object data; /* additional data */ - public lua_State L; /* Lua state (for reader) */ - }; - - - public static int luaZ_fill (ZIO z) { - uint size; - lua_State L = z.L; - CharPtr buff; - lua_unlock(L); - buff = z.reader(L, z.data, out size); - lua_lock(L); - if (buff == null || size == 0) return EOZ; - z.n = size - 1; - z.p = new CharPtr(buff); - int result = char2int(z.p[0]); - z.p.inc(); - return result; - } - - - public static int luaZ_lookahead (ZIO z) { - if (z.n == 0) { - if (luaZ_fill(z) == EOZ) - return EOZ; - else { - z.n++; /* luaZ_fill removed first byte; put back it */ - z.p.dec(); - } - } - return char2int(z.p[0]); - } - - [CLSCompliantAttribute(false)] - public static void luaZ_init(lua_State L, ZIO z, lua_Reader reader, object data) - { - z.L = L; - z.reader = reader; - z.data = data; - z.n = 0; - z.p = null; - } - - - /* --------------------------------------------------------------- read --- */ - [CLSCompliantAttribute(false)] - public static uint luaZ_read (ZIO z, CharPtr b, uint n) { - b = new CharPtr(b); - while (n != 0) { - uint m; - if (luaZ_lookahead(z) == EOZ) - return n; // return number of missing bytes - m = (n <= z.n) ? n : z.n; // min. between n and z.n - memcpy(b, z.p, m); - z.n -= m; - z.p += m; - b = b + m; - n -= m; - } - return 0; - } - - /* ------------------------------------------------------------------------ */ - [CLSCompliantAttribute(false)] - public static CharPtr luaZ_openspace (lua_State L, Mbuffer buff, uint n) { - if (n > buff.buffsize) { - if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; - luaZ_resizebuffer(L, buff, (int)n); - } - return buff.buffer; - } - - - } -} +/* +** $Id: lzio.c,v 1.31.1.1 2007/12/27 13:02:25 roberto Exp $ +** a generic input stream interface +** See Copyright Notice in lua.h +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace KopiLua +{ + using ZIO = Lua.Zio; + + public partial class Lua + { + public const int EOZ = -1; /* end of stream */ + + //public class ZIO : Zio { }; + + public static int char2int(char c) { return (int)c; } + + public static int zgetc(ZIO z) + { + if (z.n-- > 0) + { + int ch = char2int(z.p[0]); + z.p.inc(); + return ch; + } + else + return luaZ_fill(z); + } + + public class Mbuffer { + public CharPtr buffer = new CharPtr(); + [CLSCompliantAttribute(false)] + public uint n; + [CLSCompliantAttribute(false)] + public uint buffsize; + }; + + public static void luaZ_initbuffer(lua_State L, Mbuffer buff) + { + buff.buffer = null; + } + + public static CharPtr luaZ_buffer(Mbuffer buff) {return buff.buffer;} + [CLSCompliantAttribute(false)] + public static uint luaZ_sizebuffer(Mbuffer buff) { return buff.buffsize; } + [CLSCompliantAttribute(false)] + public static uint luaZ_bufflen(Mbuffer buff) {return buff.n;} + public static void luaZ_resetbuffer(Mbuffer buff) {buff.n = 0;} + + + public static void luaZ_resizebuffer(lua_State L, Mbuffer buff, int size) + { + if (buff.buffer == null) + buff.buffer = new CharPtr(); + luaM_reallocvector(L, ref buff.buffer.chars, (int)buff.buffsize, size); + buff.buffsize = (uint)buff.buffer.chars.Length; + } + + public static void luaZ_freebuffer(lua_State L, Mbuffer buff) {luaZ_resizebuffer(L, buff, 0);} + + + + /* --------- Private Part ------------------ */ + + public class Zio { + [CLSCompliantAttribute(false)] + public uint n; /* bytes still unread */ + public CharPtr p; /* current position in buffer */ + [CLSCompliantAttribute(false)] + public lua_Reader reader; + public object data; /* additional data */ + public lua_State L; /* Lua state (for reader) */ + }; + + + public static int luaZ_fill (ZIO z) { + uint size; + lua_State L = z.L; + CharPtr buff; + lua_unlock(L); + buff = z.reader(L, z.data, out size); + lua_lock(L); + if (buff == null || size == 0) return EOZ; + z.n = size - 1; + z.p = new CharPtr(buff); + int result = char2int(z.p[0]); + z.p.inc(); + return result; + } + + + public static int luaZ_lookahead (ZIO z) { + if (z.n == 0) { + if (luaZ_fill(z) == EOZ) + return EOZ; + else { + z.n++; /* luaZ_fill removed first byte; put back it */ + z.p.dec(); + } + } + return char2int(z.p[0]); + } + + [CLSCompliantAttribute(false)] + public static void luaZ_init(lua_State L, ZIO z, lua_Reader reader, object data) + { + z.L = L; + z.reader = reader; + z.data = data; + z.n = 0; + z.p = null; + } + + + /* --------------------------------------------------------------- read --- */ + [CLSCompliantAttribute(false)] + public static uint luaZ_read (ZIO z, CharPtr b, uint n) { + b = new CharPtr(b); + while (n != 0) { + uint m; + if (luaZ_lookahead(z) == EOZ) + return n; // return number of missing bytes + m = (n <= z.n) ? n : z.n; // min. between n and z.n + memcpy(b, z.p, m); + z.n -= m; + z.p += m; + b = b + m; + n -= m; + } + return 0; + } + + /* ------------------------------------------------------------------------ */ + [CLSCompliantAttribute(false)] + public static CharPtr luaZ_openspace (lua_State L, Mbuffer buff, uint n) { + if (n > buff.buffsize) { + if (n < LUA_MINBUFFER) n = LUA_MINBUFFER; + luaZ_resizebuffer(L, buff, (int)n); + } + return buff.buffer; + } + + + } +} diff --git a/Core/KopiLua/print.cs b/Core/KopiLua/print.cs index 2490f8303e5c312d74a87db9fb50323c195456b1..b492375fd41b4758f2a90e3179679ccfa80548cd 100644 --- a/Core/KopiLua/print.cs +++ b/Core/KopiLua/print.cs @@ -1,233 +1,233 @@ -/* -** $Id: print.c,v 1.55a 2006/05/31 13:30:05 lhf Exp $ -** print bytecodes -** See Copyright Notice in lua.h -*/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Runtime.InteropServices; -using System.Diagnostics; - -namespace KopiLua -{ - using TValue = Lua.lua_TValue; - using Instruction = System.UInt32; - - public partial class Lua - { - - public static void luaU_print(Proto f, int full) {PrintFunction(f, full);} - - //#define Sizeof(x) ((int)sizeof(x)) - //#define VOID(p) ((const void*)(p)) - - public static void PrintString(TString ts) - { - CharPtr s=getstr(ts); - uint i,n=ts.tsv.len; - putchar('"'); - for (i=0; i0) printf("[%d]\t",line); else printf("[-]\t"); - printf("%-9s\t",luaP_opnames[(int)o]); - switch (getOpMode(o)) - { - case OpMode.iABC: - printf("%d",a); - if (getBMode(o) != OpArgMask.OpArgN) printf(" %d", (ISK(b) != 0) ? (-1 - INDEXK(b)) : b); - if (getCMode(o) != OpArgMask.OpArgN) printf(" %d", (ISK(c) != 0) ? (-1 - INDEXK(c)) : c); - break; - case OpMode.iABx: - if (getBMode(o)==OpArgMask.OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx); - break; - case OpMode.iAsBx: - if (o==OpCode.OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); - break; - } - switch (o) - { - case OpCode.OP_LOADK: - printf("\t; "); PrintConstant(f,bx); - break; - case OpCode.OP_GETUPVAL: - case OpCode.OP_SETUPVAL: - printf("\t; %s", (f.sizeupvalues>0) ? getstr(f.upvalues[b]) : "-"); - break; - case OpCode.OP_GETGLOBAL: - case OpCode.OP_SETGLOBAL: - printf("\t; %s",svalue(f.k[bx])); - break; - case OpCode.OP_GETTABLE: - case OpCode.OP_SELF: - if (ISK(c) != 0) { printf("\t; "); PrintConstant(f,INDEXK(c)); } - break; - case OpCode.OP_SETTABLE: - case OpCode.OP_ADD: - case OpCode.OP_SUB: - case OpCode.OP_MUL: - case OpCode.OP_DIV: - case OpCode.OP_POW: - case OpCode.OP_EQ: - case OpCode.OP_LT: - case OpCode.OP_LE: - if (ISK(b)!=0 || ISK(c)!=0) - { - printf("\t; "); - if (ISK(b) != 0) PrintConstant(f,INDEXK(b)); else printf("-"); - printf(" "); - if (ISK(c) != 0) PrintConstant(f,INDEXK(c)); else printf("-"); - } - break; - case OpCode.OP_JMP: - case OpCode.OP_FORLOOP: - case OpCode.OP_FORPREP: - printf("\t; to %d",sbx+pc+2); - break; - case OpCode.OP_CLOSURE: - printf("\t; %p",VOID(f.p[bx])); - break; - case OpCode.OP_SETLIST: - if (c==0) printf("\t; %d",(int)code[++pc]); - else printf("\t; %d",c); - break; - default: - break; - } - printf("\n"); - } - } - - public static string SS(int x) { return (x == 1) ? "" : "s"; } - //#define S(x) x,SS(x) - - private static void PrintHeader(Proto f) - { - CharPtr s=getstr(f.source); - if (s[0]=='@' || s[0]=='=') - s = s.next(); - else if (s[0]==LUA_SIGNATURE[0]) - s="(bstring)"; - else - s="(string)"; - printf("\n%s <%s:%d,%d> (%d Instruction%s, %d bytes at %p)\n", - (f.linedefined==0)?"main":"function",s, - f.linedefined,f.lastlinedefined, - f.sizecode, SS(f.sizecode), f.sizecode * GetUnmanagedSize(typeof(Instruction)), VOID(f)); - printf("%d%s param%s, %d slot%s, %d upvalue%s, ", - f.numparams,(f.is_vararg != 0) ? "+" : "", SS(f.numparams), - f.maxstacksize, SS(f.maxstacksize), f.nups, SS(f.nups)); - printf("%d local%s, %d constant%s, %d function%s\n", - f.sizelocvars, SS(f.sizelocvars), f.sizek, SS(f.sizek), f.sizep, SS(f.sizep)); - } - - private static void PrintConstants(Proto f) - { - int i,n=f.sizek; - printf("constants (%d) for %p:\n",n,VOID(f)); - for (i=0; i0) printf("[%d]\t",line); else printf("[-]\t"); + printf("%-9s\t",luaP_opnames[(int)o]); + switch (getOpMode(o)) + { + case OpMode.iABC: + printf("%d",a); + if (getBMode(o) != OpArgMask.OpArgN) printf(" %d", (ISK(b) != 0) ? (-1 - INDEXK(b)) : b); + if (getCMode(o) != OpArgMask.OpArgN) printf(" %d", (ISK(c) != 0) ? (-1 - INDEXK(c)) : c); + break; + case OpMode.iABx: + if (getBMode(o)==OpArgMask.OpArgK) printf("%d %d",a,-1-bx); else printf("%d %d",a,bx); + break; + case OpMode.iAsBx: + if (o==OpCode.OP_JMP) printf("%d",sbx); else printf("%d %d",a,sbx); + break; + } + switch (o) + { + case OpCode.OP_LOADK: + printf("\t; "); PrintConstant(f,bx); + break; + case OpCode.OP_GETUPVAL: + case OpCode.OP_SETUPVAL: + printf("\t; %s", (f.sizeupvalues>0) ? getstr(f.upvalues[b]) : "-"); + break; + case OpCode.OP_GETGLOBAL: + case OpCode.OP_SETGLOBAL: + printf("\t; %s",svalue(f.k[bx])); + break; + case OpCode.OP_GETTABLE: + case OpCode.OP_SELF: + if (ISK(c) != 0) { printf("\t; "); PrintConstant(f,INDEXK(c)); } + break; + case OpCode.OP_SETTABLE: + case OpCode.OP_ADD: + case OpCode.OP_SUB: + case OpCode.OP_MUL: + case OpCode.OP_DIV: + case OpCode.OP_POW: + case OpCode.OP_EQ: + case OpCode.OP_LT: + case OpCode.OP_LE: + if (ISK(b)!=0 || ISK(c)!=0) + { + printf("\t; "); + if (ISK(b) != 0) PrintConstant(f,INDEXK(b)); else printf("-"); + printf(" "); + if (ISK(c) != 0) PrintConstant(f,INDEXK(c)); else printf("-"); + } + break; + case OpCode.OP_JMP: + case OpCode.OP_FORLOOP: + case OpCode.OP_FORPREP: + printf("\t; to %d",sbx+pc+2); + break; + case OpCode.OP_CLOSURE: + printf("\t; %p",VOID(f.p[bx])); + break; + case OpCode.OP_SETLIST: + if (c==0) printf("\t; %d",(int)code[++pc]); + else printf("\t; %d",c); + break; + default: + break; + } + printf("\n"); + } + } + + public static string SS(int x) { return (x == 1) ? "" : "s"; } + //#define S(x) x,SS(x) + + private static void PrintHeader(Proto f) + { + CharPtr s=getstr(f.source); + if (s[0]=='@' || s[0]=='=') + s = s.next(); + else if (s[0]==LUA_SIGNATURE[0]) + s="(bstring)"; + else + s="(string)"; + printf("\n%s <%s:%d,%d> (%d Instruction%s, %d bytes at %p)\n", + (f.linedefined==0)?"main":"function",s, + f.linedefined,f.lastlinedefined, + f.sizecode, SS(f.sizecode), f.sizecode * GetUnmanagedSize(typeof(Instruction)), VOID(f)); + printf("%d%s param%s, %d slot%s, %d upvalue%s, ", + f.numparams,(f.is_vararg != 0) ? "+" : "", SS(f.numparams), + f.maxstacksize, SS(f.maxstacksize), f.nups, SS(f.nups)); + printf("%d local%s, %d constant%s, %d function%s\n", + f.sizelocvars, SS(f.sizelocvars), f.sizek, SS(f.sizek), f.sizep, SS(f.sizep)); + } + + private static void PrintConstants(Proto f) + { + int i,n=f.sizek; + printf("constants (%d) for %p:\n",n,VOID(f)); + for (i=0; i - /// Determines whether the specified value is of numeric type. - /// - /// The object to check. - /// - /// true if o is a numeric type; otherwise, false. - /// - public static bool IsNumericType( object o ) - { - return ( o is byte || - o is sbyte || - o is short || - o is ushort || - o is int || - o is uint || - o is long || - o is ulong || - o is float || - o is double || - o is decimal ); - } - #endregion - #region IsPositive - /// - /// Determines whether the specified value is positive. - /// - /// The value. - /// if set to true treats 0 as positive. - /// - /// true if the specified value is positive; otherwise, false. - /// - public static bool IsPositive( object Value, bool ZeroIsPositive ) - { - switch ( Type.GetTypeCode( Value.GetType() ) ) - { - case TypeCode.SByte: - return ( ZeroIsPositive ? (sbyte)Value >= 0 : (sbyte)Value > 0 ); - case TypeCode.Int16: - return ( ZeroIsPositive ? (short)Value >= 0 : (short)Value > 0 ); - case TypeCode.Int32: - return ( ZeroIsPositive ? (int)Value >= 0 : (int)Value > 0 ); - case TypeCode.Int64: - return ( ZeroIsPositive ? (long)Value >= 0 : (long)Value > 0 ); - case TypeCode.Single: - return ( ZeroIsPositive ? (float)Value >= 0 : (float)Value > 0 ); - case TypeCode.Double: - return ( ZeroIsPositive ? (double)Value >= 0 : (double)Value > 0 ); - case TypeCode.Decimal: - return ( ZeroIsPositive ? (decimal)Value >= 0 : (decimal)Value > 0 ); - case TypeCode.Byte: - return ( ZeroIsPositive ? true : (byte)Value > 0 ); - case TypeCode.UInt16: - return ( ZeroIsPositive ? true : (ushort)Value > 0 ); - case TypeCode.UInt32: - return ( ZeroIsPositive ? true : (uint)Value > 0 ); - case TypeCode.UInt64: - return ( ZeroIsPositive ? true : (ulong)Value > 0 ); - case TypeCode.Char: - return ( ZeroIsPositive ? true : (char)Value != '\0' ); - default: - return false; - } - } - #endregion - #region ToUnsigned - /// - /// Converts the specified values boxed type to its correpsonding unsigned - /// type. - /// - /// The value. - /// A boxed numeric object whos type is unsigned. - public static object ToUnsigned( object Value ) - { - switch ( Type.GetTypeCode( Value.GetType() ) ) - { - case TypeCode.SByte: - return (byte)( (sbyte)Value ); - case TypeCode.Int16: - return (ushort)( (short)Value ); - case TypeCode.Int32: - return (uint)( (int)Value ); - case TypeCode.Int64: - return (ulong)( (long)Value ); - - case TypeCode.Byte: - return Value; - case TypeCode.UInt16: - return Value; - case TypeCode.UInt32: - return Value; - case TypeCode.UInt64: - return Value; - - case TypeCode.Single: - return (UInt32)( (float)Value ); - case TypeCode.Double: - return (ulong)( (double)Value ); - case TypeCode.Decimal: - return (ulong)( (decimal)Value ); - - default: - return null; - } - } - #endregion - #region ToInteger - /// - /// Converts the specified values boxed type to its correpsonding integer - /// type. - /// - /// The value. - /// A boxed numeric object whos type is an integer type. - public static object ToInteger( object Value, bool Round ) - { - switch ( Type.GetTypeCode( Value.GetType() ) ) - { - case TypeCode.SByte: - return Value; - case TypeCode.Int16: - return Value; - case TypeCode.Int32: - return Value; - case TypeCode.Int64: - return Value; - - case TypeCode.Byte: - return Value; - case TypeCode.UInt16: - return Value; - case TypeCode.UInt32: - return Value; - case TypeCode.UInt64: - return Value; - - case TypeCode.Single: - return ( Round ? (int)Math.Round( (float)Value ) : (int)( (float)Value ) ); - case TypeCode.Double: - return ( Round ? (long)Math.Round( (double)Value ) : (long)( (double)Value ) ); - case TypeCode.Decimal: - return ( Round ? Math.Round( (decimal)Value ) : (decimal)Value ); - - default: - return null; - } - } - #endregion - #region UnboxToLong - public static long UnboxToLong( object Value, bool Round ) - { - switch ( Type.GetTypeCode( Value.GetType() ) ) - { - case TypeCode.SByte: - return (long)( (sbyte)Value ); - case TypeCode.Int16: - return (long)( (short)Value ); - case TypeCode.Int32: - return (long)( (int)Value ); - case TypeCode.Int64: - return (long)Value; - - case TypeCode.Byte: - return (long)( (byte)Value ); - case TypeCode.UInt16: - return (long)( (ushort)Value ); - case TypeCode.UInt32: - return (long)( (uint)Value ); - case TypeCode.UInt64: - return (long)( (ulong)Value ); - - case TypeCode.Single: - return ( Round ? (long)Math.Round( (float)Value ) : (long)( (float)Value ) ); - case TypeCode.Double: - return ( Round ? (long)Math.Round( (double)Value ) : (long)( (double)Value ) ); - case TypeCode.Decimal: - return ( Round ? (long)Math.Round( (decimal)Value ) : (long)( (decimal)Value ) ); - - default: - return 0; - } - } - #endregion - #region ReplaceMetaChars - /// - /// Replaces the string representations of meta chars with their corresponding - /// character values. - /// - /// The input. - /// A string with all string meta chars are replaced - public static string ReplaceMetaChars( string input ) - { - return Regex.Replace( input, @"(\\)(\d{3}|[^\d])?", new MatchEvaluator( ReplaceMetaCharsMatch ) ); - } - private static string ReplaceMetaCharsMatch( Match m ) - { - // convert octal quotes (like \040) - if ( m.Groups[2].Length == 3 ) - return Convert.ToChar( Convert.ToByte( m.Groups[2].Value, 8 ) ).ToString(); - else - { - // convert all other special meta characters - //TODO: \xhhh hex and possible dec !! - switch ( m.Groups[2].Value ) - { - case "0": // null - return "\0"; - case "a": // alert (beep) - return "\a"; - case "b": // BS - return "\b"; - case "f": // FF - return "\f"; - case "v": // vertical tab - return "\v"; - case "r": // CR - return "\r"; - case "n": // LF - return "\n"; - case "t": // Tab - return "\t"; - default: - // if neither an octal quote nor a special meta character - // so just remove the backslash - return m.Groups[2].Value; - } - } - } - #endregion - #region printf - public static void printf( string Format, params object[] Parameters ) - { - Console.Write( Tools.sprintf( Format, Parameters ) ); - } - #endregion - #region fprintf - public static void fprintf( TextWriter Destination, string Format, params object[] Parameters ) - { - Destination.Write( Tools.sprintf( Format, Parameters ) ); - } - - internal static Regex r = new Regex(@"\%(\d*\$)?([\'\#\-\+ ]*)(\d*)(?:\.(\d+))?([hl])?([dioxXucsfeEgGpn%])"); - - #endregion - #region sprintf - public static string sprintf( string Format, params object[] Parameters ) - { - #region Variables - StringBuilder f = new StringBuilder(); - //Regex r = new Regex( @"\%(\d*\$)?([\'\#\-\+ ]*)(\d*)(?:\.(\d+))?([hl])?([dioxXucsfeEgGpn%])" ); - //"%[parameter][flags][width][.precision][length]type" - Match m = null; - string w = String.Empty; - int defaultParamIx = 0; - int paramIx; - object o = null; - - bool flagLeft2Right = false; - bool flagAlternate = false; - bool flagPositiveSign = false; - bool flagPositiveSpace = false; - bool flagZeroPadding = false; - bool flagGroupThousands = false; - - int fieldLength = 0; - int fieldPrecision = 0; - char shortLongIndicator = '\0'; - char formatSpecifier = '\0'; - char paddingCharacter = ' '; - #endregion - - // find all format parameters in format string - f.Append( Format ); - m = r.Match( f.ToString() ); - while ( m.Success ) - { - #region parameter index - paramIx = defaultParamIx; - if ( m.Groups[1] != null && m.Groups[1].Value.Length > 0 ) - { - string val = m.Groups[1].Value.Substring( 0, m.Groups[1].Value.Length - 1 ); - paramIx = Convert.ToInt32( val ) - 1; - }; - #endregion - - #region format flags - // extract format flags - flagAlternate = false; - flagLeft2Right = false; - flagPositiveSign = false; - flagPositiveSpace = false; - flagZeroPadding = false; - flagGroupThousands = false; - if ( m.Groups[2] != null && m.Groups[2].Value.Length > 0 ) - { - string flags = m.Groups[2].Value; - - flagAlternate = ( flags.IndexOf( '#' ) >= 0 ); - flagLeft2Right = ( flags.IndexOf( '-' ) >= 0 ); - flagPositiveSign = ( flags.IndexOf( '+' ) >= 0 ); - flagPositiveSpace = ( flags.IndexOf( ' ' ) >= 0 ); - flagGroupThousands = ( flags.IndexOf( '\'' ) >= 0 ); - - // positive + indicator overrides a - // positive space character - if ( flagPositiveSign && flagPositiveSpace ) - flagPositiveSpace = false; - } - #endregion - - #region field length - // extract field length and - // pading character - paddingCharacter = ' '; - fieldLength = int.MinValue; - if ( m.Groups[3] != null && m.Groups[3].Value.Length > 0 ) - { - fieldLength = Convert.ToInt32( m.Groups[3].Value ); - flagZeroPadding = ( m.Groups[3].Value[0] == '0' ); - } - #endregion - - if ( flagZeroPadding ) - paddingCharacter = '0'; - - // left2right allignment overrides zero padding - if ( flagLeft2Right && flagZeroPadding ) - { - flagZeroPadding = false; - paddingCharacter = ' '; - } - - #region field precision - // extract field precision - fieldPrecision = int.MinValue; - if ( m.Groups[4] != null && m.Groups[4].Value.Length > 0 ) - fieldPrecision = Convert.ToInt32( m.Groups[4].Value ); - #endregion - - #region short / long indicator - // extract short / long indicator - shortLongIndicator = Char.MinValue; - if ( m.Groups[5] != null && m.Groups[5].Value.Length > 0 ) - shortLongIndicator = m.Groups[5].Value[0]; - #endregion - - #region format specifier - // extract format - formatSpecifier = Char.MinValue; - if ( m.Groups[6] != null && m.Groups[6].Value.Length > 0 ) - formatSpecifier = m.Groups[6].Value[0]; - #endregion - - // default precision is 6 digits if none is specified except - if ( fieldPrecision == int.MinValue && - formatSpecifier != 's' && - formatSpecifier != 'c' && - Char.ToUpper( formatSpecifier ) != 'X' && - formatSpecifier != 'o' ) - fieldPrecision = 6; - - #region get next value parameter - // get next value parameter and convert value parameter depending on short / long indicator - if ( Parameters == null || paramIx >= Parameters.Length ) - o = null; - else - { - o = Parameters[paramIx]; - - if ( shortLongIndicator == 'h' ) - { - if ( o is int ) - o = (short)( (int)o ); - else if ( o is long ) - o = (short)( (long)o ); - else if ( o is uint ) - o = (ushort)( (uint)o ); - else if ( o is ulong ) - o = (ushort)( (ulong)o ); - } - else if ( shortLongIndicator == 'l' ) - { - if ( o is short ) - o = (long)( (short)o ); - else if ( o is int ) - o = (long)( (int)o ); - else if ( o is ushort ) - o = (ulong)( (ushort)o ); - else if ( o is uint ) - o = (ulong)( (uint)o ); - } - } - #endregion - - // convert value parameters to a string depending on the formatSpecifier - w = String.Empty; - switch ( formatSpecifier ) - { - #region % - character - case '%': // % character - w = "%"; - break; - #endregion - #region d - integer - case 'd': // integer - w = FormatNumber( ( flagGroupThousands ? "n" : "d" ), flagAlternate, - fieldLength, int.MinValue, flagLeft2Right, - flagPositiveSign, flagPositiveSpace, - paddingCharacter, o ); - defaultParamIx++; - break; - #endregion - #region i - integer - case 'i': // integer - goto case 'd'; - #endregion - #region o - octal integer - case 'o': // octal integer - no leading zero - w = FormatOct( "o", flagAlternate, - fieldLength, int.MinValue, flagLeft2Right, - paddingCharacter, o ); - defaultParamIx++; - break; - #endregion - #region x - hex integer - case 'x': // hex integer - no leading zero - w = FormatHex( "x", flagAlternate, - fieldLength, fieldPrecision, flagLeft2Right, - paddingCharacter, o ); - defaultParamIx++; - break; - #endregion - #region X - hex integer - case 'X': // same as x but with capital hex characters - w = FormatHex( "X", flagAlternate, - fieldLength, fieldPrecision, flagLeft2Right, - paddingCharacter, o ); - defaultParamIx++; - break; - #endregion - #region u - unsigned integer - case 'u': // unsigned integer - w = FormatNumber( ( flagGroupThousands ? "n" : "d" ), flagAlternate, - fieldLength, int.MinValue, flagLeft2Right, - false, false, - paddingCharacter, ToUnsigned( o ) ); - defaultParamIx++; - break; - #endregion - #region c - character - case 'c': // character - if ( IsNumericType( o ) ) - w = Convert.ToChar( o ).ToString(); - else if ( o is char ) - w = ( (char)o ).ToString(); - else if ( o is string && ( (string)o ).Length > 0 ) - w = ( (string)o )[0].ToString(); - defaultParamIx++; - break; - #endregion - #region s - string - case 's': // string - //string t = "{0" + ( fieldLength != int.MinValue ? "," + ( flagLeft2Right ? "-" : String.Empty ) + fieldLength.ToString() : String.Empty ) + ":s}"; - w = o.ToString(); - if ( fieldPrecision >= 0 ) - w = w.Substring( 0, fieldPrecision ); - - if ( fieldLength != int.MinValue ) - if ( flagLeft2Right ) - w = w.PadRight( fieldLength, paddingCharacter ); - else - w = w.PadLeft( fieldLength, paddingCharacter ); - defaultParamIx++; - break; - #endregion - #region f - double number - case 'f': // double - w = FormatNumber( ( flagGroupThousands ? "n" : "f" ), flagAlternate, - fieldLength, fieldPrecision, flagLeft2Right, - flagPositiveSign, flagPositiveSpace, - paddingCharacter, o ); - defaultParamIx++; - break; - #endregion - #region e - exponent number - case 'e': // double / exponent - w = FormatNumber( "e", flagAlternate, - fieldLength, fieldPrecision, flagLeft2Right, - flagPositiveSign, flagPositiveSpace, - paddingCharacter, o ); - defaultParamIx++; - break; - #endregion - #region E - exponent number - case 'E': // double / exponent - w = FormatNumber( "E", flagAlternate, - fieldLength, fieldPrecision, flagLeft2Right, - flagPositiveSign, flagPositiveSpace, - paddingCharacter, o ); - defaultParamIx++; - break; - #endregion - #region g - general number - case 'g': // double / exponent - w = FormatNumber( "g", flagAlternate, - fieldLength, fieldPrecision, flagLeft2Right, - flagPositiveSign, flagPositiveSpace, - paddingCharacter, o ); - defaultParamIx++; - break; - #endregion - #region G - general number - case 'G': // double / exponent - w = FormatNumber( "G", flagAlternate, - fieldLength, fieldPrecision, flagLeft2Right, - flagPositiveSign, flagPositiveSpace, - paddingCharacter, o ); - defaultParamIx++; - break; - #endregion - #region p - pointer - case 'p': // pointer - if ( o is IntPtr ) -#if XBOX || SILVERLIGHT - w = ( (IntPtr)o ).ToString(); -#else - w = "0x" + ( (IntPtr)o ).ToString( "x" ); -#endif - defaultParamIx++; - break; - #endregion - #region n - number of processed chars so far - case 'n': // number of characters so far - w = FormatNumber( "d", flagAlternate, - fieldLength, int.MinValue, flagLeft2Right, - flagPositiveSign, flagPositiveSpace, - paddingCharacter, m.Index ); - break; - #endregion - default: - w = String.Empty; - defaultParamIx++; - break; - } - - // replace format parameter with parameter value - // and start searching for the next format parameter - // AFTER the position of the current inserted value - // to prohibit recursive matches if the value also - // includes a format specifier - f.Remove( m.Index, m.Length ); - f.Insert( m.Index, w ); - m = r.Match( f.ToString(), m.Index + w.Length ); - } - - return f.ToString(); - } - #endregion - #endregion - - #region Private Methods - #region FormatOCT - private static string FormatOct( string NativeFormat, bool Alternate, - int FieldLength, int FieldPrecision, - bool Left2Right, - char Padding, object Value ) - { - string w = String.Empty; - string lengthFormat = "{0" + ( FieldLength != int.MinValue ? - "," + ( Left2Right ? - "-" : - String.Empty ) + FieldLength.ToString() : - String.Empty ) + "}"; - - if ( IsNumericType( Value ) ) - { - w = Convert.ToString( UnboxToLong( Value, true ), 8 ); - - if ( Left2Right || Padding == ' ' ) - { - if ( Alternate && w != "0" ) - w = "0" + w; - w = String.Format( lengthFormat, w ); - } - else - { - if ( FieldLength != int.MinValue ) - w = w.PadLeft( FieldLength - ( Alternate && w != "0" ? 1 : 0 ), Padding ); - if ( Alternate && w != "0" ) - w = "0" + w; - } - } - - return w; - } - #endregion - #region FormatHEX - private static string FormatHex( string NativeFormat, bool Alternate, - int FieldLength, int FieldPrecision, - bool Left2Right, - char Padding, object Value ) - { - string w = String.Empty; - string lengthFormat = "{0" + ( FieldLength != int.MinValue ? - "," + ( Left2Right ? - "-" : - String.Empty ) + FieldLength.ToString() : - String.Empty ) + "}"; - string numberFormat = "{0:" + NativeFormat + ( FieldPrecision != int.MinValue ? - FieldPrecision.ToString() : - String.Empty ) + "}"; - - if ( IsNumericType( Value ) ) - { - w = String.Format( numberFormat, Value ); - - if ( Left2Right || Padding == ' ' ) - { - if ( Alternate ) - w = ( NativeFormat == "x" ? "0x" : "0X" ) + w; - w = String.Format( lengthFormat, w ); - } - else - { - if ( FieldLength != int.MinValue ) - w = w.PadLeft( FieldLength - ( Alternate ? 2 : 0 ), Padding ); - if ( Alternate ) - w = ( NativeFormat == "x" ? "0x" : "0X" ) + w; - } - } - - return w; - } - #endregion - #region FormatNumber - private static string FormatNumber( string NativeFormat, bool Alternate, - int FieldLength, int FieldPrecision, - bool Left2Right, - bool PositiveSign, bool PositiveSpace, - char Padding, object Value ) - { - string w = String.Empty; - string lengthFormat = "{0" + ( FieldLength != int.MinValue ? - "," + ( Left2Right ? - "-" : - String.Empty ) + FieldLength.ToString() : - String.Empty ) + "}"; - string numberFormat = "{0:" + NativeFormat + ( FieldPrecision != int.MinValue ? - FieldPrecision.ToString() : - "0" ) + "}"; - - if ( IsNumericType( Value ) ) - { - w = String.Format( numberFormat, Value ); - - if ( Left2Right || Padding == ' ' ) - { - if ( IsPositive( Value, true ) ) - w = ( PositiveSign ? - "+" : ( PositiveSpace ? " " : String.Empty ) ) + w; - w = String.Format( lengthFormat, w ); - } - else - { - if ( w.StartsWith( "-" ) ) - w = w.Substring( 1 ); - if ( FieldLength != int.MinValue ) - w = w.PadLeft( FieldLength - 1, Padding ); - if ( IsPositive( Value, true ) ) - w = ( PositiveSign ? - "+" : ( PositiveSpace ? - " " : ( FieldLength != int.MinValue ? - Padding.ToString() : String.Empty ) ) ) + w; - else - w = "-" + w; - } - } - - return w; - } - #endregion - #endregion - } -} - - +#region Usings +using System; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +#endregion + +namespace AT.MIN +{ + public static class Tools + { + #region Public Methods + #region IsNumericType + /// + /// Determines whether the specified value is of numeric type. + /// + /// The object to check. + /// + /// true if o is a numeric type; otherwise, false. + /// + public static bool IsNumericType( object o ) + { + return ( o is byte || + o is sbyte || + o is short || + o is ushort || + o is int || + o is uint || + o is long || + o is ulong || + o is float || + o is double || + o is decimal ); + } + #endregion + #region IsPositive + /// + /// Determines whether the specified value is positive. + /// + /// The value. + /// if set to true treats 0 as positive. + /// + /// true if the specified value is positive; otherwise, false. + /// + public static bool IsPositive( object Value, bool ZeroIsPositive ) + { + switch ( Type.GetTypeCode( Value.GetType() ) ) + { + case TypeCode.SByte: + return ( ZeroIsPositive ? (sbyte)Value >= 0 : (sbyte)Value > 0 ); + case TypeCode.Int16: + return ( ZeroIsPositive ? (short)Value >= 0 : (short)Value > 0 ); + case TypeCode.Int32: + return ( ZeroIsPositive ? (int)Value >= 0 : (int)Value > 0 ); + case TypeCode.Int64: + return ( ZeroIsPositive ? (long)Value >= 0 : (long)Value > 0 ); + case TypeCode.Single: + return ( ZeroIsPositive ? (float)Value >= 0 : (float)Value > 0 ); + case TypeCode.Double: + return ( ZeroIsPositive ? (double)Value >= 0 : (double)Value > 0 ); + case TypeCode.Decimal: + return ( ZeroIsPositive ? (decimal)Value >= 0 : (decimal)Value > 0 ); + case TypeCode.Byte: + return ( ZeroIsPositive ? true : (byte)Value > 0 ); + case TypeCode.UInt16: + return ( ZeroIsPositive ? true : (ushort)Value > 0 ); + case TypeCode.UInt32: + return ( ZeroIsPositive ? true : (uint)Value > 0 ); + case TypeCode.UInt64: + return ( ZeroIsPositive ? true : (ulong)Value > 0 ); + case TypeCode.Char: + return ( ZeroIsPositive ? true : (char)Value != '\0' ); + default: + return false; + } + } + #endregion + #region ToUnsigned + /// + /// Converts the specified values boxed type to its correpsonding unsigned + /// type. + /// + /// The value. + /// A boxed numeric object whos type is unsigned. + public static object ToUnsigned( object Value ) + { + switch ( Type.GetTypeCode( Value.GetType() ) ) + { + case TypeCode.SByte: + return (byte)( (sbyte)Value ); + case TypeCode.Int16: + return (ushort)( (short)Value ); + case TypeCode.Int32: + return (uint)( (int)Value ); + case TypeCode.Int64: + return (ulong)( (long)Value ); + + case TypeCode.Byte: + return Value; + case TypeCode.UInt16: + return Value; + case TypeCode.UInt32: + return Value; + case TypeCode.UInt64: + return Value; + + case TypeCode.Single: + return (UInt32)( (float)Value ); + case TypeCode.Double: + return (ulong)( (double)Value ); + case TypeCode.Decimal: + return (ulong)( (decimal)Value ); + + default: + return null; + } + } + #endregion + #region ToInteger + /// + /// Converts the specified values boxed type to its correpsonding integer + /// type. + /// + /// The value. + /// A boxed numeric object whos type is an integer type. + public static object ToInteger( object Value, bool Round ) + { + switch ( Type.GetTypeCode( Value.GetType() ) ) + { + case TypeCode.SByte: + return Value; + case TypeCode.Int16: + return Value; + case TypeCode.Int32: + return Value; + case TypeCode.Int64: + return Value; + + case TypeCode.Byte: + return Value; + case TypeCode.UInt16: + return Value; + case TypeCode.UInt32: + return Value; + case TypeCode.UInt64: + return Value; + + case TypeCode.Single: + return ( Round ? (int)Math.Round( (float)Value ) : (int)( (float)Value ) ); + case TypeCode.Double: + return ( Round ? (long)Math.Round( (double)Value ) : (long)( (double)Value ) ); + case TypeCode.Decimal: + return ( Round ? Math.Round( (decimal)Value ) : (decimal)Value ); + + default: + return null; + } + } + #endregion + #region UnboxToLong + public static long UnboxToLong( object Value, bool Round ) + { + switch ( Type.GetTypeCode( Value.GetType() ) ) + { + case TypeCode.SByte: + return (long)( (sbyte)Value ); + case TypeCode.Int16: + return (long)( (short)Value ); + case TypeCode.Int32: + return (long)( (int)Value ); + case TypeCode.Int64: + return (long)Value; + + case TypeCode.Byte: + return (long)( (byte)Value ); + case TypeCode.UInt16: + return (long)( (ushort)Value ); + case TypeCode.UInt32: + return (long)( (uint)Value ); + case TypeCode.UInt64: + return (long)( (ulong)Value ); + + case TypeCode.Single: + return ( Round ? (long)Math.Round( (float)Value ) : (long)( (float)Value ) ); + case TypeCode.Double: + return ( Round ? (long)Math.Round( (double)Value ) : (long)( (double)Value ) ); + case TypeCode.Decimal: + return ( Round ? (long)Math.Round( (decimal)Value ) : (long)( (decimal)Value ) ); + + default: + return 0; + } + } + #endregion + #region ReplaceMetaChars + /// + /// Replaces the string representations of meta chars with their corresponding + /// character values. + /// + /// The input. + /// A string with all string meta chars are replaced + public static string ReplaceMetaChars( string input ) + { + return Regex.Replace( input, @"(\\)(\d{3}|[^\d])?", new MatchEvaluator( ReplaceMetaCharsMatch ) ); + } + private static string ReplaceMetaCharsMatch( Match m ) + { + // convert octal quotes (like \040) + if ( m.Groups[2].Length == 3 ) + return Convert.ToChar( Convert.ToByte( m.Groups[2].Value, 8 ) ).ToString(); + else + { + // convert all other special meta characters + //TODO: \xhhh hex and possible dec !! + switch ( m.Groups[2].Value ) + { + case "0": // null + return "\0"; + case "a": // alert (beep) + return "\a"; + case "b": // BS + return "\b"; + case "f": // FF + return "\f"; + case "v": // vertical tab + return "\v"; + case "r": // CR + return "\r"; + case "n": // LF + return "\n"; + case "t": // Tab + return "\t"; + default: + // if neither an octal quote nor a special meta character + // so just remove the backslash + return m.Groups[2].Value; + } + } + } + #endregion + #region printf + public static void printf( string Format, params object[] Parameters ) + { + Console.Write( Tools.sprintf( Format, Parameters ) ); + } + #endregion + #region fprintf + public static void fprintf( TextWriter Destination, string Format, params object[] Parameters ) + { + Destination.Write( Tools.sprintf( Format, Parameters ) ); + } + + internal static Regex r = new Regex(@"\%(\d*\$)?([\'\#\-\+ ]*)(\d*)(?:\.(\d+))?([hl])?([dioxXucsfeEgGpn%])"); + + #endregion + #region sprintf + public static string sprintf( string Format, params object[] Parameters ) + { + #region Variables + StringBuilder f = new StringBuilder(); + //Regex r = new Regex( @"\%(\d*\$)?([\'\#\-\+ ]*)(\d*)(?:\.(\d+))?([hl])?([dioxXucsfeEgGpn%])" ); + //"%[parameter][flags][width][.precision][length]type" + Match m = null; + string w = String.Empty; + int defaultParamIx = 0; + int paramIx; + object o = null; + + bool flagLeft2Right = false; + bool flagAlternate = false; + bool flagPositiveSign = false; + bool flagPositiveSpace = false; + bool flagZeroPadding = false; + bool flagGroupThousands = false; + + int fieldLength = 0; + int fieldPrecision = 0; + char shortLongIndicator = '\0'; + char formatSpecifier = '\0'; + char paddingCharacter = ' '; + #endregion + + // find all format parameters in format string + f.Append( Format ); + m = r.Match( f.ToString() ); + while ( m.Success ) + { + #region parameter index + paramIx = defaultParamIx; + if ( m.Groups[1] != null && m.Groups[1].Value.Length > 0 ) + { + string val = m.Groups[1].Value.Substring( 0, m.Groups[1].Value.Length - 1 ); + paramIx = Convert.ToInt32( val ) - 1; + }; + #endregion + + #region format flags + // extract format flags + flagAlternate = false; + flagLeft2Right = false; + flagPositiveSign = false; + flagPositiveSpace = false; + flagZeroPadding = false; + flagGroupThousands = false; + if ( m.Groups[2] != null && m.Groups[2].Value.Length > 0 ) + { + string flags = m.Groups[2].Value; + + flagAlternate = ( flags.IndexOf( '#' ) >= 0 ); + flagLeft2Right = ( flags.IndexOf( '-' ) >= 0 ); + flagPositiveSign = ( flags.IndexOf( '+' ) >= 0 ); + flagPositiveSpace = ( flags.IndexOf( ' ' ) >= 0 ); + flagGroupThousands = ( flags.IndexOf( '\'' ) >= 0 ); + + // positive + indicator overrides a + // positive space character + if ( flagPositiveSign && flagPositiveSpace ) + flagPositiveSpace = false; + } + #endregion + + #region field length + // extract field length and + // pading character + paddingCharacter = ' '; + fieldLength = int.MinValue; + if ( m.Groups[3] != null && m.Groups[3].Value.Length > 0 ) + { + fieldLength = Convert.ToInt32( m.Groups[3].Value ); + flagZeroPadding = ( m.Groups[3].Value[0] == '0' ); + } + #endregion + + if ( flagZeroPadding ) + paddingCharacter = '0'; + + // left2right allignment overrides zero padding + if ( flagLeft2Right && flagZeroPadding ) + { + flagZeroPadding = false; + paddingCharacter = ' '; + } + + #region field precision + // extract field precision + fieldPrecision = int.MinValue; + if ( m.Groups[4] != null && m.Groups[4].Value.Length > 0 ) + fieldPrecision = Convert.ToInt32( m.Groups[4].Value ); + #endregion + + #region short / long indicator + // extract short / long indicator + shortLongIndicator = Char.MinValue; + if ( m.Groups[5] != null && m.Groups[5].Value.Length > 0 ) + shortLongIndicator = m.Groups[5].Value[0]; + #endregion + + #region format specifier + // extract format + formatSpecifier = Char.MinValue; + if ( m.Groups[6] != null && m.Groups[6].Value.Length > 0 ) + formatSpecifier = m.Groups[6].Value[0]; + #endregion + + // default precision is 6 digits if none is specified except + if ( fieldPrecision == int.MinValue && + formatSpecifier != 's' && + formatSpecifier != 'c' && + Char.ToUpper( formatSpecifier ) != 'X' && + formatSpecifier != 'o' ) + fieldPrecision = 6; + + #region get next value parameter + // get next value parameter and convert value parameter depending on short / long indicator + if ( Parameters == null || paramIx >= Parameters.Length ) + o = null; + else + { + o = Parameters[paramIx]; + + if ( shortLongIndicator == 'h' ) + { + if ( o is int ) + o = (short)( (int)o ); + else if ( o is long ) + o = (short)( (long)o ); + else if ( o is uint ) + o = (ushort)( (uint)o ); + else if ( o is ulong ) + o = (ushort)( (ulong)o ); + } + else if ( shortLongIndicator == 'l' ) + { + if ( o is short ) + o = (long)( (short)o ); + else if ( o is int ) + o = (long)( (int)o ); + else if ( o is ushort ) + o = (ulong)( (ushort)o ); + else if ( o is uint ) + o = (ulong)( (uint)o ); + } + } + #endregion + + // convert value parameters to a string depending on the formatSpecifier + w = String.Empty; + switch ( formatSpecifier ) + { + #region % - character + case '%': // % character + w = "%"; + break; + #endregion + #region d - integer + case 'd': // integer + w = FormatNumber( ( flagGroupThousands ? "n" : "d" ), flagAlternate, + fieldLength, int.MinValue, flagLeft2Right, + flagPositiveSign, flagPositiveSpace, + paddingCharacter, o ); + defaultParamIx++; + break; + #endregion + #region i - integer + case 'i': // integer + goto case 'd'; + #endregion + #region o - octal integer + case 'o': // octal integer - no leading zero + w = FormatOct( "o", flagAlternate, + fieldLength, int.MinValue, flagLeft2Right, + paddingCharacter, o ); + defaultParamIx++; + break; + #endregion + #region x - hex integer + case 'x': // hex integer - no leading zero + w = FormatHex( "x", flagAlternate, + fieldLength, fieldPrecision, flagLeft2Right, + paddingCharacter, o ); + defaultParamIx++; + break; + #endregion + #region X - hex integer + case 'X': // same as x but with capital hex characters + w = FormatHex( "X", flagAlternate, + fieldLength, fieldPrecision, flagLeft2Right, + paddingCharacter, o ); + defaultParamIx++; + break; + #endregion + #region u - unsigned integer + case 'u': // unsigned integer + w = FormatNumber( ( flagGroupThousands ? "n" : "d" ), flagAlternate, + fieldLength, int.MinValue, flagLeft2Right, + false, false, + paddingCharacter, ToUnsigned( o ) ); + defaultParamIx++; + break; + #endregion + #region c - character + case 'c': // character + if ( IsNumericType( o ) ) + w = Convert.ToChar( o ).ToString(); + else if ( o is char ) + w = ( (char)o ).ToString(); + else if ( o is string && ( (string)o ).Length > 0 ) + w = ( (string)o )[0].ToString(); + defaultParamIx++; + break; + #endregion + #region s - string + case 's': // string + //string t = "{0" + ( fieldLength != int.MinValue ? "," + ( flagLeft2Right ? "-" : String.Empty ) + fieldLength.ToString() : String.Empty ) + ":s}"; + w = o.ToString(); + if ( fieldPrecision >= 0 ) + w = w.Substring( 0, fieldPrecision ); + + if ( fieldLength != int.MinValue ) + if ( flagLeft2Right ) + w = w.PadRight( fieldLength, paddingCharacter ); + else + w = w.PadLeft( fieldLength, paddingCharacter ); + defaultParamIx++; + break; + #endregion + #region f - double number + case 'f': // double + w = FormatNumber( ( flagGroupThousands ? "n" : "f" ), flagAlternate, + fieldLength, fieldPrecision, flagLeft2Right, + flagPositiveSign, flagPositiveSpace, + paddingCharacter, o ); + defaultParamIx++; + break; + #endregion + #region e - exponent number + case 'e': // double / exponent + w = FormatNumber( "e", flagAlternate, + fieldLength, fieldPrecision, flagLeft2Right, + flagPositiveSign, flagPositiveSpace, + paddingCharacter, o ); + defaultParamIx++; + break; + #endregion + #region E - exponent number + case 'E': // double / exponent + w = FormatNumber( "E", flagAlternate, + fieldLength, fieldPrecision, flagLeft2Right, + flagPositiveSign, flagPositiveSpace, + paddingCharacter, o ); + defaultParamIx++; + break; + #endregion + #region g - general number + case 'g': // double / exponent + w = FormatNumber( "g", flagAlternate, + fieldLength, fieldPrecision, flagLeft2Right, + flagPositiveSign, flagPositiveSpace, + paddingCharacter, o ); + defaultParamIx++; + break; + #endregion + #region G - general number + case 'G': // double / exponent + w = FormatNumber( "G", flagAlternate, + fieldLength, fieldPrecision, flagLeft2Right, + flagPositiveSign, flagPositiveSpace, + paddingCharacter, o ); + defaultParamIx++; + break; + #endregion + #region p - pointer + case 'p': // pointer + if ( o is IntPtr ) +#if XBOX || SILVERLIGHT + w = ( (IntPtr)o ).ToString(); +#else + w = "0x" + ( (IntPtr)o ).ToString( "x" ); +#endif + defaultParamIx++; + break; + #endregion + #region n - number of processed chars so far + case 'n': // number of characters so far + w = FormatNumber( "d", flagAlternate, + fieldLength, int.MinValue, flagLeft2Right, + flagPositiveSign, flagPositiveSpace, + paddingCharacter, m.Index ); + break; + #endregion + default: + w = String.Empty; + defaultParamIx++; + break; + } + + // replace format parameter with parameter value + // and start searching for the next format parameter + // AFTER the position of the current inserted value + // to prohibit recursive matches if the value also + // includes a format specifier + f.Remove( m.Index, m.Length ); + f.Insert( m.Index, w ); + m = r.Match( f.ToString(), m.Index + w.Length ); + } + + return f.ToString(); + } + #endregion + #endregion + + #region Private Methods + #region FormatOCT + private static string FormatOct( string NativeFormat, bool Alternate, + int FieldLength, int FieldPrecision, + bool Left2Right, + char Padding, object Value ) + { + string w = String.Empty; + string lengthFormat = "{0" + ( FieldLength != int.MinValue ? + "," + ( Left2Right ? + "-" : + String.Empty ) + FieldLength.ToString() : + String.Empty ) + "}"; + + if ( IsNumericType( Value ) ) + { + w = Convert.ToString( UnboxToLong( Value, true ), 8 ); + + if ( Left2Right || Padding == ' ' ) + { + if ( Alternate && w != "0" ) + w = "0" + w; + w = String.Format( lengthFormat, w ); + } + else + { + if ( FieldLength != int.MinValue ) + w = w.PadLeft( FieldLength - ( Alternate && w != "0" ? 1 : 0 ), Padding ); + if ( Alternate && w != "0" ) + w = "0" + w; + } + } + + return w; + } + #endregion + #region FormatHEX + private static string FormatHex( string NativeFormat, bool Alternate, + int FieldLength, int FieldPrecision, + bool Left2Right, + char Padding, object Value ) + { + string w = String.Empty; + string lengthFormat = "{0" + ( FieldLength != int.MinValue ? + "," + ( Left2Right ? + "-" : + String.Empty ) + FieldLength.ToString() : + String.Empty ) + "}"; + string numberFormat = "{0:" + NativeFormat + ( FieldPrecision != int.MinValue ? + FieldPrecision.ToString() : + String.Empty ) + "}"; + + if ( IsNumericType( Value ) ) + { + w = String.Format( numberFormat, Value ); + + if ( Left2Right || Padding == ' ' ) + { + if ( Alternate ) + w = ( NativeFormat == "x" ? "0x" : "0X" ) + w; + w = String.Format( lengthFormat, w ); + } + else + { + if ( FieldLength != int.MinValue ) + w = w.PadLeft( FieldLength - ( Alternate ? 2 : 0 ), Padding ); + if ( Alternate ) + w = ( NativeFormat == "x" ? "0x" : "0X" ) + w; + } + } + + return w; + } + #endregion + #region FormatNumber + private static string FormatNumber( string NativeFormat, bool Alternate, + int FieldLength, int FieldPrecision, + bool Left2Right, + bool PositiveSign, bool PositiveSpace, + char Padding, object Value ) + { + string w = String.Empty; + string lengthFormat = "{0" + ( FieldLength != int.MinValue ? + "," + ( Left2Right ? + "-" : + String.Empty ) + FieldLength.ToString() : + String.Empty ) + "}"; + string numberFormat = "{0:" + NativeFormat + ( FieldPrecision != int.MinValue ? + FieldPrecision.ToString() : + "0" ) + "}"; + + if ( IsNumericType( Value ) ) + { + w = String.Format( numberFormat, Value ); + + if ( Left2Right || Padding == ' ' ) + { + if ( IsPositive( Value, true ) ) + w = ( PositiveSign ? + "+" : ( PositiveSpace ? " " : String.Empty ) ) + w; + w = String.Format( lengthFormat, w ); + } + else + { + if ( w.StartsWith( "-" ) ) + w = w.Substring( 1 ); + if ( FieldLength != int.MinValue ) + w = w.PadLeft( FieldLength - 1, Padding ); + if ( IsPositive( Value, true ) ) + w = ( PositiveSign ? + "+" : ( PositiveSpace ? + " " : ( FieldLength != int.MinValue ? + Padding.ToString() : String.Empty ) ) ) + w; + else + w = "-" + w; + } + } + + return w; + } + #endregion + #endregion + } +} + + diff --git a/Core/LuaInterface/CheckType.cs b/Core/LuaInterface/CheckType.cs index 5451953a4c3a53ec24792cb0f9d65c8f9b264de2..78ea39ab921f1fc009486a9acef867d2464de003 100644 --- a/Core/LuaInterface/CheckType.cs +++ b/Core/LuaInterface/CheckType.cs @@ -1,371 +1,371 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Reflection; -using System.Collections.Generic; -using LuaInterface.Method; -using LuaInterface.Extensions; - -namespace LuaInterface -{ - using LuaCore = KopiLua.Lua; - - /* - * Type checking and conversion functions. - * - * Author: Fabio Mascarenhas - * Version: 1.0 - */ - class CheckType - { - private Dictionary extractValues = new Dictionary(); - private ExtractValue extractNetObject; - private ObjectTranslator translator; - - public CheckType(ObjectTranslator translator) - { - this.translator = translator; - extractValues.Add(typeof(object).TypeHandle.Value.ToInt64(), new ExtractValue(getAsObject)); - extractValues.Add(typeof(sbyte).TypeHandle.Value.ToInt64(), new ExtractValue(getAsSbyte)); - extractValues.Add(typeof(byte).TypeHandle.Value.ToInt64(), new ExtractValue(getAsByte)); - extractValues.Add(typeof(short).TypeHandle.Value.ToInt64(), new ExtractValue(getAsShort)); - extractValues.Add(typeof(ushort).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUshort)); - extractValues.Add(typeof(int).TypeHandle.Value.ToInt64(), new ExtractValue(getAsInt)); - extractValues.Add(typeof(uint).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUint)); - extractValues.Add(typeof(long).TypeHandle.Value.ToInt64(), new ExtractValue(getAsLong)); - extractValues.Add(typeof(ulong).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUlong)); - extractValues.Add(typeof(double).TypeHandle.Value.ToInt64(), new ExtractValue(getAsDouble)); - extractValues.Add(typeof(char).TypeHandle.Value.ToInt64(), new ExtractValue(getAsChar)); - extractValues.Add(typeof(float).TypeHandle.Value.ToInt64(), new ExtractValue(getAsFloat)); - extractValues.Add(typeof(decimal).TypeHandle.Value.ToInt64(), new ExtractValue(getAsDecimal)); - extractValues.Add(typeof(bool).TypeHandle.Value.ToInt64(), new ExtractValue(getAsBoolean)); - extractValues.Add(typeof(string).TypeHandle.Value.ToInt64(), new ExtractValue(getAsString)); - extractValues.Add(typeof(LuaFunction).TypeHandle.Value.ToInt64(), new ExtractValue(getAsFunction)); - extractValues.Add(typeof(LuaTable).TypeHandle.Value.ToInt64(), new ExtractValue(getAsTable)); - extractValues.Add(typeof(LuaUserData).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUserdata)); - extractNetObject = new ExtractValue(getAsNetObject); - } - - /* - * Checks if the value at Lua stack index stackPos matches paramType, - * returning a conversion function if it does and null otherwise. - */ - internal ExtractValue getExtractor(IReflect paramType) - { - return getExtractor(paramType.UnderlyingSystemType); - } - - internal ExtractValue getExtractor(Type paramType) - { - if(paramType.IsByRef) - paramType = paramType.GetElementType(); - - long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64(); - return extractValues.ContainsKey(runtimeHandleValue) ? extractValues[runtimeHandleValue] : extractNetObject; - } - - internal ExtractValue checkType(LuaCore.lua_State luaState, int stackPos, Type paramType) - { - var luatype = LuaLib.lua_type(luaState, stackPos); - - if(paramType.IsByRef) - paramType = paramType.GetElementType(); - - var underlyingType = Nullable.GetUnderlyingType(paramType); - - if(!underlyingType.IsNull()) - paramType = underlyingType; // Silently convert nullable types to their non null requics - - long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64(); - - if(paramType.Equals(typeof(object))) - return extractValues[runtimeHandleValue]; - - //CP: Added support for generic parameters - if(paramType.IsGenericParameter) - { - if(luatype == LuaTypes.Boolean) - return extractValues[typeof(bool).TypeHandle.Value.ToInt64()]; - else if(luatype == LuaTypes.String) - return extractValues[typeof(string).TypeHandle.Value.ToInt64()]; - else if(luatype == LuaTypes.Table) - return extractValues[typeof(LuaTable).TypeHandle.Value.ToInt64()]; - else if(luatype == LuaTypes.UserData) - return extractValues[typeof(object).TypeHandle.Value.ToInt64()]; - else if(luatype == LuaTypes.Function) - return extractValues[typeof(LuaFunction).TypeHandle.Value.ToInt64()]; - else if(luatype == LuaTypes.Number) - return extractValues[typeof(double).TypeHandle.Value.ToInt64()]; - //else - //;//an unsupported type was encountered - } - - if(LuaLib.lua_isnumber(luaState, stackPos)) - return extractValues[runtimeHandleValue]; - - if(paramType == typeof(bool)) - { - if(LuaLib.lua_isboolean(luaState, stackPos)) - return extractValues[runtimeHandleValue]; - } - else if(paramType == typeof(string)) - { - if(LuaLib.lua_isstring(luaState, stackPos)) - return extractValues[runtimeHandleValue]; - else if(luatype == LuaTypes.Nil) - return extractNetObject; // kevinh - silently convert nil to a null string pointer - } - else if(paramType == typeof(LuaTable)) - { - if(luatype == LuaTypes.Table) - return extractValues[runtimeHandleValue]; - } - else if(paramType == typeof(LuaUserData)) - { - if(luatype == LuaTypes.UserData) - return extractValues[runtimeHandleValue]; - } - else if(paramType == typeof(LuaFunction)) - { - if(luatype == LuaTypes.Function) - return extractValues[runtimeHandleValue]; - } - else if(typeof(Delegate).IsAssignableFrom(paramType) && luatype == LuaTypes.Function) - return new ExtractValue(new DelegateGenerator(translator, paramType).extractGenerated); - else if(paramType.IsInterface && luatype == LuaTypes.Table) - return new ExtractValue(new ClassGenerator(translator, paramType).extractGenerated); - else if((paramType.IsInterface || paramType.IsClass) && luatype == LuaTypes.Nil) - { - // kevinh - allow nil to be silently converted to null - extractNetObject will return null when the item ain't found - return extractNetObject; - } - else if(LuaLib.lua_type(luaState, stackPos) == LuaTypes.Table) - { - if(LuaLib.luaL_getmetafield(luaState, stackPos, "__index")) - { - object obj = translator.getNetObject(luaState, -1); - LuaLib.lua_settop(luaState, -2); - if(!obj.IsNull() && paramType.IsAssignableFrom(obj.GetType())) - return extractNetObject; - } - else - return null; - } - else - { - object obj = translator.getNetObject(luaState, stackPos); - if(!obj.IsNull() && paramType.IsAssignableFrom(obj.GetType())) - return extractNetObject; - } - - return null; - } - - /* - * The following functions return the value in the Lua stack - * index stackPos as the desired type if it can, or null - * otherwise. - */ - private object getAsSbyte(LuaCore.lua_State luaState, int stackPos) - { - sbyte retVal = (sbyte)LuaLib.lua_tonumber(luaState, stackPos); - if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) - return null; - - return retVal; - } - - private object getAsByte(LuaCore.lua_State luaState, int stackPos) - { - byte retVal = (byte)LuaLib.lua_tonumber(luaState, stackPos); - if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) - return null; - - return retVal; - } - - private object getAsShort(LuaCore.lua_State luaState, int stackPos) - { - short retVal = (short)LuaLib.lua_tonumber(luaState, stackPos); - if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) - return null; - - return retVal; - } - - private object getAsUshort(LuaCore.lua_State luaState, int stackPos) - { - ushort retVal = (ushort)LuaLib.lua_tonumber(luaState, stackPos); - if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) - return null; - - return retVal; - } - - private object getAsInt(LuaCore.lua_State luaState, int stackPos) - { - int retVal = (int)LuaLib.lua_tonumber(luaState, stackPos); - if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) - return null; - - return retVal; - } - - private object getAsUint(LuaCore.lua_State luaState, int stackPos) - { - uint retVal = (uint)LuaLib.lua_tonumber(luaState, stackPos); - if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) - return null; - - return retVal; - } - - private object getAsLong(LuaCore.lua_State luaState, int stackPos) - { - long retVal = (long)LuaLib.lua_tonumber(luaState, stackPos); - if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) - return null; - - return retVal; - } - - private object getAsUlong(LuaCore.lua_State luaState, int stackPos) - { - ulong retVal = (ulong)LuaLib.lua_tonumber(luaState, stackPos); - if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) - return null; - - return retVal; - } - - private object getAsDouble(LuaCore.lua_State luaState, int stackPos) - { - double retVal = LuaLib.lua_tonumber(luaState, stackPos); - if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) - return null; - - return retVal; - } - - private object getAsChar(LuaCore.lua_State luaState, int stackPos) - { - char retVal = (char)LuaLib.lua_tonumber(luaState, stackPos); - if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) - return null; - - return retVal; - } - - private object getAsFloat(LuaCore.lua_State luaState, int stackPos) - { - float retVal = (float)LuaLib.lua_tonumber(luaState, stackPos); - if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) - return null; - - return retVal; - } - - private object getAsDecimal(LuaCore.lua_State luaState, int stackPos) - { - decimal retVal = (decimal)LuaLib.lua_tonumber(luaState, stackPos); - if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) - return null; - - return retVal; - } - - private object getAsBoolean(LuaCore.lua_State luaState, int stackPos) - { - return LuaLib.lua_toboolean(luaState, stackPos); - } - - private object getAsString(LuaCore.lua_State luaState, int stackPos) - { - string retVal = LuaLib.lua_tostring(luaState, stackPos).ToString(); - if(retVal == string.Empty && !LuaLib.lua_isstring(luaState, stackPos)) - return null; - - return retVal; - } - - private object getAsTable(LuaCore.lua_State luaState, int stackPos) - { - return translator.getTable(luaState, stackPos); - } - - private object getAsFunction(LuaCore.lua_State luaState, int stackPos) - { - return translator.getFunction(luaState, stackPos); - } - - private object getAsUserdata(LuaCore.lua_State luaState, int stackPos) - { - return translator.getUserData(luaState, stackPos); - } - - public object getAsObject(LuaCore.lua_State luaState, int stackPos) - { - if(LuaLib.lua_type(luaState, stackPos) == LuaTypes.Table) - { - if(LuaLib.luaL_getmetafield(luaState, stackPos, "__index")) - { - if(LuaLib.luaL_checkmetatable(luaState, -1)) - { - LuaLib.lua_insert(luaState, stackPos); - LuaLib.lua_remove(luaState, stackPos+1); - } - else - LuaLib.lua_settop(luaState, -2); - } - } - - object obj = translator.getObject(luaState, stackPos); - return obj; - } - - public object getAsNetObject(LuaCore.lua_State luaState, int stackPos) - { - object obj = translator.getNetObject(luaState, stackPos); - - if(obj.IsNull() && LuaLib.lua_type(luaState, stackPos) == LuaTypes.Table) - { - if(LuaLib.luaL_getmetafield(luaState, stackPos, "__index")) - { - if(LuaLib.luaL_checkmetatable(luaState, -1)) - { - LuaLib.lua_insert(luaState, stackPos); - LuaLib.lua_remove(luaState, stackPos+1); - obj = translator.getNetObject(luaState, stackPos); - } - else - LuaLib.lua_settop(luaState, -2); - } - } - - return obj; - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Reflection; +using System.Collections.Generic; +using LuaInterface.Method; +using LuaInterface.Extensions; + +namespace LuaInterface +{ + using LuaCore = KopiLua.Lua; + + /* + * Type checking and conversion functions. + * + * Author: Fabio Mascarenhas + * Version: 1.0 + */ + class CheckType + { + private Dictionary extractValues = new Dictionary(); + private ExtractValue extractNetObject; + private ObjectTranslator translator; + + public CheckType(ObjectTranslator translator) + { + this.translator = translator; + extractValues.Add(typeof(object).TypeHandle.Value.ToInt64(), new ExtractValue(getAsObject)); + extractValues.Add(typeof(sbyte).TypeHandle.Value.ToInt64(), new ExtractValue(getAsSbyte)); + extractValues.Add(typeof(byte).TypeHandle.Value.ToInt64(), new ExtractValue(getAsByte)); + extractValues.Add(typeof(short).TypeHandle.Value.ToInt64(), new ExtractValue(getAsShort)); + extractValues.Add(typeof(ushort).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUshort)); + extractValues.Add(typeof(int).TypeHandle.Value.ToInt64(), new ExtractValue(getAsInt)); + extractValues.Add(typeof(uint).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUint)); + extractValues.Add(typeof(long).TypeHandle.Value.ToInt64(), new ExtractValue(getAsLong)); + extractValues.Add(typeof(ulong).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUlong)); + extractValues.Add(typeof(double).TypeHandle.Value.ToInt64(), new ExtractValue(getAsDouble)); + extractValues.Add(typeof(char).TypeHandle.Value.ToInt64(), new ExtractValue(getAsChar)); + extractValues.Add(typeof(float).TypeHandle.Value.ToInt64(), new ExtractValue(getAsFloat)); + extractValues.Add(typeof(decimal).TypeHandle.Value.ToInt64(), new ExtractValue(getAsDecimal)); + extractValues.Add(typeof(bool).TypeHandle.Value.ToInt64(), new ExtractValue(getAsBoolean)); + extractValues.Add(typeof(string).TypeHandle.Value.ToInt64(), new ExtractValue(getAsString)); + extractValues.Add(typeof(LuaFunction).TypeHandle.Value.ToInt64(), new ExtractValue(getAsFunction)); + extractValues.Add(typeof(LuaTable).TypeHandle.Value.ToInt64(), new ExtractValue(getAsTable)); + extractValues.Add(typeof(LuaUserData).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUserdata)); + extractNetObject = new ExtractValue(getAsNetObject); + } + + /* + * Checks if the value at Lua stack index stackPos matches paramType, + * returning a conversion function if it does and null otherwise. + */ + internal ExtractValue getExtractor(IReflect paramType) + { + return getExtractor(paramType.UnderlyingSystemType); + } + + internal ExtractValue getExtractor(Type paramType) + { + if(paramType.IsByRef) + paramType = paramType.GetElementType(); + + long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64(); + return extractValues.ContainsKey(runtimeHandleValue) ? extractValues[runtimeHandleValue] : extractNetObject; + } + + internal ExtractValue checkType(LuaCore.lua_State luaState, int stackPos, Type paramType) + { + var luatype = LuaLib.lua_type(luaState, stackPos); + + if(paramType.IsByRef) + paramType = paramType.GetElementType(); + + var underlyingType = Nullable.GetUnderlyingType(paramType); + + if(!underlyingType.IsNull()) + paramType = underlyingType; // Silently convert nullable types to their non null requics + + long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64(); + + if(paramType.Equals(typeof(object))) + return extractValues[runtimeHandleValue]; + + //CP: Added support for generic parameters + if(paramType.IsGenericParameter) + { + if(luatype == LuaTypes.Boolean) + return extractValues[typeof(bool).TypeHandle.Value.ToInt64()]; + else if(luatype == LuaTypes.String) + return extractValues[typeof(string).TypeHandle.Value.ToInt64()]; + else if(luatype == LuaTypes.Table) + return extractValues[typeof(LuaTable).TypeHandle.Value.ToInt64()]; + else if(luatype == LuaTypes.UserData) + return extractValues[typeof(object).TypeHandle.Value.ToInt64()]; + else if(luatype == LuaTypes.Function) + return extractValues[typeof(LuaFunction).TypeHandle.Value.ToInt64()]; + else if(luatype == LuaTypes.Number) + return extractValues[typeof(double).TypeHandle.Value.ToInt64()]; + //else + //;//an unsupported type was encountered + } + + if(LuaLib.lua_isnumber(luaState, stackPos)) + return extractValues[runtimeHandleValue]; + + if(paramType == typeof(bool)) + { + if(LuaLib.lua_isboolean(luaState, stackPos)) + return extractValues[runtimeHandleValue]; + } + else if(paramType == typeof(string)) + { + if(LuaLib.lua_isstring(luaState, stackPos)) + return extractValues[runtimeHandleValue]; + else if(luatype == LuaTypes.Nil) + return extractNetObject; // kevinh - silently convert nil to a null string pointer + } + else if(paramType == typeof(LuaTable)) + { + if(luatype == LuaTypes.Table) + return extractValues[runtimeHandleValue]; + } + else if(paramType == typeof(LuaUserData)) + { + if(luatype == LuaTypes.UserData) + return extractValues[runtimeHandleValue]; + } + else if(paramType == typeof(LuaFunction)) + { + if(luatype == LuaTypes.Function) + return extractValues[runtimeHandleValue]; + } + else if(typeof(Delegate).IsAssignableFrom(paramType) && luatype == LuaTypes.Function) + return new ExtractValue(new DelegateGenerator(translator, paramType).extractGenerated); + else if(paramType.IsInterface && luatype == LuaTypes.Table) + return new ExtractValue(new ClassGenerator(translator, paramType).extractGenerated); + else if((paramType.IsInterface || paramType.IsClass) && luatype == LuaTypes.Nil) + { + // kevinh - allow nil to be silently converted to null - extractNetObject will return null when the item ain't found + return extractNetObject; + } + else if(LuaLib.lua_type(luaState, stackPos) == LuaTypes.Table) + { + if(LuaLib.luaL_getmetafield(luaState, stackPos, "__index")) + { + object obj = translator.getNetObject(luaState, -1); + LuaLib.lua_settop(luaState, -2); + if(!obj.IsNull() && paramType.IsAssignableFrom(obj.GetType())) + return extractNetObject; + } + else + return null; + } + else + { + object obj = translator.getNetObject(luaState, stackPos); + if(!obj.IsNull() && paramType.IsAssignableFrom(obj.GetType())) + return extractNetObject; + } + + return null; + } + + /* + * The following functions return the value in the Lua stack + * index stackPos as the desired type if it can, or null + * otherwise. + */ + private object getAsSbyte(LuaCore.lua_State luaState, int stackPos) + { + sbyte retVal = (sbyte)LuaLib.lua_tonumber(luaState, stackPos); + if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) + return null; + + return retVal; + } + + private object getAsByte(LuaCore.lua_State luaState, int stackPos) + { + byte retVal = (byte)LuaLib.lua_tonumber(luaState, stackPos); + if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) + return null; + + return retVal; + } + + private object getAsShort(LuaCore.lua_State luaState, int stackPos) + { + short retVal = (short)LuaLib.lua_tonumber(luaState, stackPos); + if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) + return null; + + return retVal; + } + + private object getAsUshort(LuaCore.lua_State luaState, int stackPos) + { + ushort retVal = (ushort)LuaLib.lua_tonumber(luaState, stackPos); + if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) + return null; + + return retVal; + } + + private object getAsInt(LuaCore.lua_State luaState, int stackPos) + { + int retVal = (int)LuaLib.lua_tonumber(luaState, stackPos); + if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) + return null; + + return retVal; + } + + private object getAsUint(LuaCore.lua_State luaState, int stackPos) + { + uint retVal = (uint)LuaLib.lua_tonumber(luaState, stackPos); + if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) + return null; + + return retVal; + } + + private object getAsLong(LuaCore.lua_State luaState, int stackPos) + { + long retVal = (long)LuaLib.lua_tonumber(luaState, stackPos); + if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) + return null; + + return retVal; + } + + private object getAsUlong(LuaCore.lua_State luaState, int stackPos) + { + ulong retVal = (ulong)LuaLib.lua_tonumber(luaState, stackPos); + if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) + return null; + + return retVal; + } + + private object getAsDouble(LuaCore.lua_State luaState, int stackPos) + { + double retVal = LuaLib.lua_tonumber(luaState, stackPos); + if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) + return null; + + return retVal; + } + + private object getAsChar(LuaCore.lua_State luaState, int stackPos) + { + char retVal = (char)LuaLib.lua_tonumber(luaState, stackPos); + if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) + return null; + + return retVal; + } + + private object getAsFloat(LuaCore.lua_State luaState, int stackPos) + { + float retVal = (float)LuaLib.lua_tonumber(luaState, stackPos); + if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) + return null; + + return retVal; + } + + private object getAsDecimal(LuaCore.lua_State luaState, int stackPos) + { + decimal retVal = (decimal)LuaLib.lua_tonumber(luaState, stackPos); + if(retVal == 0 && !LuaLib.lua_isnumber(luaState, stackPos)) + return null; + + return retVal; + } + + private object getAsBoolean(LuaCore.lua_State luaState, int stackPos) + { + return LuaLib.lua_toboolean(luaState, stackPos); + } + + private object getAsString(LuaCore.lua_State luaState, int stackPos) + { + string retVal = LuaLib.lua_tostring(luaState, stackPos).ToString(); + if(retVal == string.Empty && !LuaLib.lua_isstring(luaState, stackPos)) + return null; + + return retVal; + } + + private object getAsTable(LuaCore.lua_State luaState, int stackPos) + { + return translator.getTable(luaState, stackPos); + } + + private object getAsFunction(LuaCore.lua_State luaState, int stackPos) + { + return translator.getFunction(luaState, stackPos); + } + + private object getAsUserdata(LuaCore.lua_State luaState, int stackPos) + { + return translator.getUserData(luaState, stackPos); + } + + public object getAsObject(LuaCore.lua_State luaState, int stackPos) + { + if(LuaLib.lua_type(luaState, stackPos) == LuaTypes.Table) + { + if(LuaLib.luaL_getmetafield(luaState, stackPos, "__index")) + { + if(LuaLib.luaL_checkmetatable(luaState, -1)) + { + LuaLib.lua_insert(luaState, stackPos); + LuaLib.lua_remove(luaState, stackPos+1); + } + else + LuaLib.lua_settop(luaState, -2); + } + } + + object obj = translator.getObject(luaState, stackPos); + return obj; + } + + public object getAsNetObject(LuaCore.lua_State luaState, int stackPos) + { + object obj = translator.getNetObject(luaState, stackPos); + + if(obj.IsNull() && LuaLib.lua_type(luaState, stackPos) == LuaTypes.Table) + { + if(LuaLib.luaL_getmetafield(luaState, stackPos, "__index")) + { + if(LuaLib.luaL_checkmetatable(luaState, -1)) + { + LuaLib.lua_insert(luaState, stackPos); + LuaLib.lua_remove(luaState, stackPos+1); + obj = translator.getNetObject(luaState, stackPos); + } + else + LuaLib.lua_settop(luaState, -2); + } + } + + return obj; + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/Event/DebugHookEventArgs.cs b/Core/LuaInterface/Event/DebugHookEventArgs.cs index f9ba221881f7573fa4091e2b5a382466ca48b590..bf8d6c783def7c2435e251238aa721993291e208 100644 --- a/Core/LuaInterface/Event/DebugHookEventArgs.cs +++ b/Core/LuaInterface/Event/DebugHookEventArgs.cs @@ -1,50 +1,50 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface.Event -{ - using LuaCore = KopiLua.Lua; - - /// - /// Event args for hook callback event - /// - /// Reinhard Ostermeier - public class DebugHookEventArgs : EventArgs - { - private readonly LuaCore.lua_Debug luaDebug; - - public DebugHookEventArgs(LuaCore.lua_Debug luaDebug) - { - this.luaDebug = luaDebug; - } - - public LuaCore.lua_Debug LuaDebug - { - get { return luaDebug; } - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface.Event +{ + using LuaCore = KopiLua.Lua; + + /// + /// Event args for hook callback event + /// + /// Reinhard Ostermeier + public class DebugHookEventArgs : EventArgs + { + private readonly LuaCore.lua_Debug luaDebug; + + public DebugHookEventArgs(LuaCore.lua_Debug luaDebug) + { + this.luaDebug = luaDebug; + } + + public LuaCore.lua_Debug LuaDebug + { + get { return luaDebug; } + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/Event/EventCodes.cs b/Core/LuaInterface/Event/EventCodes.cs index a38eea57874634b994b997df2c2d754b530164b4..4eadadaf0d6dc9aa8b5d3948a4e32c23a85c303e 100644 --- a/Core/LuaInterface/Event/EventCodes.cs +++ b/Core/LuaInterface/Event/EventCodes.cs @@ -1,45 +1,45 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface.Event -{ - /// - /// Event codes for lua hook function - /// - /// - /// Do not change any of the values because they must match the lua values - /// - /// Reinhard Ostermeier - public enum EventCodes - { - LUA_HOOKCALL = 0, - LUA_HOOKRET = 1, - LUA_HOOKLINE = 2, - LUA_HOOKCOUNT = 3, - LUA_HOOKTAILRET = 4 - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface.Event +{ + /// + /// Event codes for lua hook function + /// + /// + /// Do not change any of the values because they must match the lua values + /// + /// Reinhard Ostermeier + public enum EventCodes + { + LUA_HOOKCALL = 0, + LUA_HOOKRET = 1, + LUA_HOOKLINE = 2, + LUA_HOOKCOUNT = 3, + LUA_HOOKTAILRET = 4 + } } \ No newline at end of file diff --git a/Core/LuaInterface/Event/EventMasks.cs b/Core/LuaInterface/Event/EventMasks.cs index 43d31632d1c70ddeecca56b717024dca1fb06d3c..b9cbcfd9ab407d67fa1b3fffd0ffce9149ac913c 100644 --- a/Core/LuaInterface/Event/EventMasks.cs +++ b/Core/LuaInterface/Event/EventMasks.cs @@ -1,46 +1,46 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface.Event -{ - /// - /// Event masks for lua hook callback - /// - /// - /// Do not change any of the values because they must match the lua values - /// - /// Reinhard Ostermeier - [Flags] - public enum EventMasks - { - LUA_MASKCALL = (1 << EventCodes.LUA_HOOKCALL), - LUA_MASKRET = (1 << EventCodes.LUA_HOOKRET), - LUA_MASKLINE = (1 << EventCodes.LUA_HOOKLINE), - LUA_MASKCOUNT = (1 << EventCodes.LUA_HOOKCOUNT), - LUA_MASKALL = Int32.MaxValue - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface.Event +{ + /// + /// Event masks for lua hook callback + /// + /// + /// Do not change any of the values because they must match the lua values + /// + /// Reinhard Ostermeier + [Flags] + public enum EventMasks + { + LUA_MASKCALL = (1 << EventCodes.LUA_HOOKCALL), + LUA_MASKRET = (1 << EventCodes.LUA_HOOKRET), + LUA_MASKLINE = (1 << EventCodes.LUA_HOOKLINE), + LUA_MASKCOUNT = (1 << EventCodes.LUA_HOOKCOUNT), + LUA_MASKALL = Int32.MaxValue + } } \ No newline at end of file diff --git a/Core/LuaInterface/Event/HookExceptionEventArgs.cs b/Core/LuaInterface/Event/HookExceptionEventArgs.cs index 554ae824ee0bef7ae4402fb5ba788ebabdf50762..cf0b3f7f37f700ee68e33566b8ac731db1e93900 100644 --- a/Core/LuaInterface/Event/HookExceptionEventArgs.cs +++ b/Core/LuaInterface/Event/HookExceptionEventArgs.cs @@ -1,44 +1,44 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface.Event -{ - public class HookExceptionEventArgs : EventArgs - { - private readonly Exception m_Exception; - - public Exception Exception - { - get { return m_Exception; } - } - - public HookExceptionEventArgs(Exception ex) - { - m_Exception = ex; - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface.Event +{ + public class HookExceptionEventArgs : EventArgs + { + private readonly Exception m_Exception; + + public Exception Exception + { + get { return m_Exception; } + } + + public HookExceptionEventArgs(Exception ex) + { + m_Exception = ex; + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/Exceptions/LuaException.cs b/Core/LuaInterface/Exceptions/LuaException.cs index 9a030242f638f16de3e4906d55b38de3e57ad701..fcddb4f2f8d683f183162702104f0e9d4da33b9e 100644 --- a/Core/LuaInterface/Exceptions/LuaException.cs +++ b/Core/LuaInterface/Exceptions/LuaException.cs @@ -1,53 +1,53 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Runtime.Serialization; - -namespace LuaInterface.Exceptions -{ - /// - /// Exceptions thrown by the Lua runtime - /// - [Serializable] - public class LuaException : Exception - { - public LuaException() - { - } - - public LuaException(string message) : base(message) - { - } - - public LuaException(string message, Exception innerException) : base(message, innerException) - { - } - - protected LuaException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Runtime.Serialization; + +namespace LuaInterface.Exceptions +{ + /// + /// Exceptions thrown by the Lua runtime + /// + [Serializable] + public class LuaException : Exception + { + public LuaException() + { + } + + public LuaException(string message) : base(message) + { + } + + public LuaException(string message, Exception innerException) : base(message, innerException) + { + } + + protected LuaException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/Exceptions/LuaScriptException.cs b/Core/LuaInterface/Exceptions/LuaScriptException.cs index 8de92d6cd13bf72d50ae499a7b1a8fbd5e5b45f8..f748ee261564e2e423322e4975fb75457acf38cb 100644 --- a/Core/LuaInterface/Exceptions/LuaScriptException.cs +++ b/Core/LuaInterface/Exceptions/LuaScriptException.cs @@ -1,74 +1,74 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface.Exceptions -{ - /// - /// Exceptions thrown by the Lua runtime because of errors in the script - /// - public class LuaScriptException : LuaException - { - /// - /// Returns true if the exception has occured as the result of a .NET exception in user code - /// - public bool IsNetException { get; private set; } - private readonly string source; - - /// - /// The position in the script where the exception was triggered. - /// - public override string Source { get { return source; } } - - /// - /// Creates a new Lua-only exception. - /// - /// The message that describes the error. - /// The position in the script where the exception was triggered. - public LuaScriptException(string message, string source) : base(message) - { - this.source = source; - } - - /// - /// Creates a new .NET wrapping exception. - /// - /// The .NET exception triggered by user-code. - /// The position in the script where the exception was triggered. - public LuaScriptException(Exception innerException, string source) - : base("A .NET exception occured in user-code", innerException) - { - this.source = source; - this.IsNetException = true; - } - - public override string ToString() - { - // Prepend the error source - return GetType().FullName + ": " + source + Message; - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface.Exceptions +{ + /// + /// Exceptions thrown by the Lua runtime because of errors in the script + /// + public class LuaScriptException : LuaException + { + /// + /// Returns true if the exception has occured as the result of a .NET exception in user code + /// + public bool IsNetException { get; private set; } + private readonly string source; + + /// + /// The position in the script where the exception was triggered. + /// + public override string Source { get { return source; } } + + /// + /// Creates a new Lua-only exception. + /// + /// The message that describes the error. + /// The position in the script where the exception was triggered. + public LuaScriptException(string message, string source) : base(message) + { + this.source = source; + } + + /// + /// Creates a new .NET wrapping exception. + /// + /// The .NET exception triggered by user-code. + /// The position in the script where the exception was triggered. + public LuaScriptException(Exception innerException, string source) + : base("A .NET exception occured in user-code", innerException) + { + this.source = source; + this.IsNetException = true; + } + + public override string ToString() + { + // Prepend the error source + return GetType().FullName + ": " + source + Message; + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/Extensions/GeneralExtensions.cs b/Core/LuaInterface/Extensions/GeneralExtensions.cs index dd2df7f359235b428ec26fed0a5ce757faa71b3a..aff4d920c306042fc4b6879489be0175cf64eefc 100644 --- a/Core/LuaInterface/Extensions/GeneralExtensions.cs +++ b/Core/LuaInterface/Extensions/GeneralExtensions.cs @@ -1,46 +1,46 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface.Extensions -{ - /// - /// Some random extension stuff. - /// - static class GeneralExtensions - { - /// - /// Determines whether the specified obj is null. - /// - /// The obj. - /// - /// true if the specified obj is null; otherwise, false. - /// - public static bool IsNull(this object obj) - { - return (obj == null); - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface.Extensions +{ + /// + /// Some random extension stuff. + /// + static class GeneralExtensions + { + /// + /// Determines whether the specified obj is null. + /// + /// The obj. + /// + /// true if the specified obj is null; otherwise, false. + /// + public static bool IsNull(this object obj) + { + return (obj == null); + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/GenerateEventAssembly/ClassGenerator.cs b/Core/LuaInterface/GenerateEventAssembly/ClassGenerator.cs index c99df05674d189ad2e8f7946a39f4238971b5edd..b2415edbc37c8bd833ce6ce34f6b6ab9065090dc 100644 --- a/Core/LuaInterface/GenerateEventAssembly/ClassGenerator.cs +++ b/Core/LuaInterface/GenerateEventAssembly/ClassGenerator.cs @@ -1,53 +1,53 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface -{ - /* - * Class used for generating delegates that get a table from the Lua - * stack as a an object of a specific type. - * - * Author: Fabio Mascarenhas - * Version: 1.0 - */ - class ClassGenerator - { - private ObjectTranslator translator; - private Type klass; - - public ClassGenerator(ObjectTranslator translator, Type klass) - { - this.translator = translator; - this.klass = klass; - } - - public object extractGenerated(KopiLua.Lua.lua_State luaState, int stackPos) - { - return CodeGeneration.Instance.GetClassInstance(klass, translator.getTable(luaState, stackPos)); - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface +{ + /* + * Class used for generating delegates that get a table from the Lua + * stack as a an object of a specific type. + * + * Author: Fabio Mascarenhas + * Version: 1.0 + */ + class ClassGenerator + { + private ObjectTranslator translator; + private Type klass; + + public ClassGenerator(ObjectTranslator translator, Type klass) + { + this.translator = translator; + this.klass = klass; + } + + public object extractGenerated(KopiLua.Lua.lua_State luaState, int stackPos) + { + return CodeGeneration.Instance.GetClassInstance(klass, translator.getTable(luaState, stackPos)); + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/GenerateEventAssembly/CodeGeneration.cs b/Core/LuaInterface/GenerateEventAssembly/CodeGeneration.cs index d90fac64c8dcc1bb00dfa75e05debcd067fdc349..9e36b9a8f21a598fa5e7f2f9cae74cdf0a65261c 100644 --- a/Core/LuaInterface/GenerateEventAssembly/CodeGeneration.cs +++ b/Core/LuaInterface/GenerateEventAssembly/CodeGeneration.cs @@ -1,685 +1,685 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Threading; -using System.Reflection; -using System.Reflection.Emit; -using System.Collections; -using System.Collections.Generic; -using LuaInterface.Method; - -namespace LuaInterface -{ - /* - * Dynamically generates new types from existing types and - * Lua function and table values. Generated types are event handlers, - * delegates, interface implementations and subclasses. - * - * Author: Fabio Mascarenhas - * Version: 1.0 - */ - class CodeGeneration - { - private Dictionary classCollection = new Dictionary(); - private Dictionary eventHandlerCollection = new Dictionary(); - private Dictionary delegateCollection = new Dictionary(); - private static readonly CodeGeneration instance = new CodeGeneration(); - private Type eventHandlerParent = typeof(LuaEventHandler); - private Type delegateParent = typeof(LuaDelegate); - private Type classHelper = typeof(LuaClassHelper); - private AssemblyName assemblyName; - private AssemblyBuilder newAssembly; - private ModuleBuilder newModule; - private int luaClassNumber = 1; - - static CodeGeneration() - { - } - - private CodeGeneration() - { - // Create an assembly name - assemblyName = new AssemblyName(); - assemblyName.Name = "LuaInterface_generatedcode"; - // Create a new assembly with one module. - newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); - newModule = newAssembly.DefineDynamicModule("LuaInterface_generatedcode"); - } - - /* - * Singleton instance of the class - */ - public static CodeGeneration Instance - { - get { return instance; } - } - - /* - * Generates an event handler that calls a Lua function - */ - private Type GenerateEvent(Type eventHandlerType) - { - string typeName; - lock(this) - { - typeName = "LuaGeneratedClass" + luaClassNumber; - luaClassNumber++; - } - - // Define a public class in the assembly, called typeName - var myType = newModule.DefineType(typeName, TypeAttributes.Public, eventHandlerParent); - - // Defines the handler method. Its signature is void(object, ) - var paramTypes = new Type[2]; - paramTypes[0] = typeof(object); - paramTypes[1] = eventHandlerType; - var returnType = typeof(void); - var handleMethod = myType.DefineMethod("HandleEvent", MethodAttributes.Public | MethodAttributes.HideBySig, returnType, paramTypes); - - // Emits the IL for the method. It loads the arguments - // and calls the handleEvent method of the base class - ILGenerator generator = handleMethod.GetILGenerator(); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldarg_2); - var miGenericEventHandler = eventHandlerParent.GetMethod("handleEvent"); - generator.Emit(OpCodes.Call, miGenericEventHandler); - // returns - generator.Emit(OpCodes.Ret); - // creates the new type - return myType.CreateType(); - } - - /* - * Generates a type that can be used for instantiating a delegate - * of the provided type, given a Lua function. - */ - private Type GenerateDelegate(Type delegateType) - { - string typeName; - lock(this) - { - typeName = "LuaGeneratedClass" + luaClassNumber; - luaClassNumber++; - } - - // Define a public class in the assembly, called typeName - var myType = newModule.DefineType(typeName, TypeAttributes.Public, delegateParent); - - // Defines the delegate method with the same signature as the - // Invoke method of delegateType - var invokeMethod = delegateType.GetMethod("Invoke"); - var paramInfo = invokeMethod.GetParameters(); - var paramTypes = new Type[paramInfo.Length]; - var returnType = invokeMethod.ReturnType; - - // Counts out and ref params, for use later - int nOutParams = 0; int nOutAndRefParams = 0; - - for(int i = 0; i < paramTypes.Length; i++) - { - paramTypes[i] = paramInfo[i].ParameterType; - - if((!paramInfo[i].IsIn) && paramInfo[i].IsOut) - nOutParams++; - - if(paramTypes[i].IsByRef) - nOutAndRefParams++; - } - - int[] refArgs = new int[nOutAndRefParams]; - var delegateMethod = myType.DefineMethod("CallFunction", invokeMethod.Attributes, returnType, paramTypes); - - // Generates the IL for the method - ILGenerator generator = delegateMethod.GetILGenerator( ); - generator.DeclareLocal(typeof(object[])); // original arguments - generator.DeclareLocal(typeof(object[])); // with out-only arguments removed - generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments - - if(!(returnType == typeof(void))) // return value - generator.DeclareLocal(returnType); - else - generator.DeclareLocal(typeof(object)); - - // Initializes local variables - generator.Emit(OpCodes.Ldc_I4, paramTypes.Length); - generator.Emit(OpCodes.Newarr, typeof(object)); - generator.Emit(OpCodes.Stloc_0); - generator.Emit(OpCodes.Ldc_I4, paramTypes.Length-nOutParams); - generator.Emit(OpCodes.Newarr, typeof(object)); - generator.Emit(OpCodes.Stloc_1); - generator.Emit(OpCodes.Ldc_I4, nOutAndRefParams); - generator.Emit(OpCodes.Newarr, typeof(int)); - generator.Emit(OpCodes.Stloc_2); - - // Stores the arguments in the local variables - for(int iArgs = 0, iInArgs = 0, iOutArgs = 0; iArgs < paramTypes.Length; iArgs++) - { - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldc_I4, iArgs); - generator.Emit(OpCodes.Ldarg, iArgs+1); - - if(paramTypes[iArgs].IsByRef) - { - if(paramTypes[iArgs].GetElementType().IsValueType) - { - generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); - generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); - } - else - generator.Emit(OpCodes.Ldind_Ref); - } - else - { - if(paramTypes[iArgs].IsValueType) - generator.Emit(OpCodes.Box, paramTypes[iArgs]); - } - - generator.Emit(OpCodes.Stelem_Ref); - - if(paramTypes[iArgs].IsByRef) - { - generator.Emit(OpCodes.Ldloc_2); - generator.Emit(OpCodes.Ldc_I4, iOutArgs); - generator.Emit(OpCodes.Ldc_I4, iArgs); - generator.Emit(OpCodes.Stelem_I4); - refArgs[iOutArgs] = iArgs; - iOutArgs++; - } - - if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut)) - { - generator.Emit(OpCodes.Ldloc_1); - generator.Emit(OpCodes.Ldc_I4, iInArgs); - generator.Emit(OpCodes.Ldarg, iArgs+1); - - if(paramTypes[iArgs].IsByRef) - { - if(paramTypes[iArgs].GetElementType().IsValueType) - { - generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); - generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); - } - else - generator.Emit(OpCodes.Ldind_Ref); - } - else - { - if(paramTypes[iArgs].IsValueType) - generator.Emit(OpCodes.Box, paramTypes[iArgs]); - } - - generator.Emit(OpCodes.Stelem_Ref); - iInArgs++; - } - } - - // Calls the callFunction method of the base class - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldloc_1); - generator.Emit(OpCodes.Ldloc_2); - var miGenericEventHandler = delegateParent.GetMethod("callFunction"); - generator.Emit(OpCodes.Call, miGenericEventHandler); - - // Stores return value - if(returnType == typeof(void)) - { - generator.Emit(OpCodes.Pop); - generator.Emit(OpCodes.Ldnull); - } - else if(returnType.IsValueType) - { - generator.Emit(OpCodes.Unbox, returnType); - generator.Emit(OpCodes.Ldobj, returnType); - } - else - generator.Emit(OpCodes.Castclass, returnType); - - generator.Emit(OpCodes.Stloc_3); - - // Stores new value of out and ref params - for(int i = 0; i < refArgs.Length; i++) - { - generator.Emit(OpCodes.Ldarg, refArgs[i]+1); - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldc_I4, refArgs[i]); - generator.Emit(OpCodes.Ldelem_Ref); - - if(paramTypes[refArgs[i]].GetElementType().IsValueType) - { - generator.Emit(OpCodes.Unbox, paramTypes[refArgs[i]].GetElementType()); - generator.Emit(OpCodes.Ldobj, paramTypes[refArgs[i]].GetElementType()); - generator.Emit(OpCodes.Stobj, paramTypes[refArgs[i]].GetElementType()); - } - else - { - generator.Emit(OpCodes.Castclass, paramTypes[refArgs[i]].GetElementType()); - generator.Emit(OpCodes.Stind_Ref); - } - } - - // Returns - if(!(returnType == typeof(void))) - generator.Emit(OpCodes.Ldloc_3); - - generator.Emit(OpCodes.Ret); - return myType.CreateType(); // creates the new type - } - - /* - * Generates an implementation of klass, if it is an interface, or - * a subclass of klass that delegates its virtual methods to a Lua table. - */ - public void GenerateClass(Type klass, out Type newType, out Type[][] returnTypes) - { - string typeName; - lock(this) - { - typeName = "LuaGeneratedClass" + luaClassNumber; - luaClassNumber++; - } - - TypeBuilder myType; - // Define a public class in the assembly, called typeName - if(klass.IsInterface) - myType = newModule.DefineType(typeName, TypeAttributes.Public, typeof(object), new Type[] { klass, typeof(ILuaGeneratedType) }); - else - myType = newModule.DefineType(typeName, TypeAttributes.Public, klass, new Type[] { typeof(ILuaGeneratedType) }); - - // Field that stores the Lua table - var luaTableField = myType.DefineField("__luaInterface_luaTable", typeof(LuaTable), FieldAttributes.Public); - // Field that stores the return types array - var returnTypesField = myType.DefineField("__luaInterface_returnTypes", typeof(Type[][]), FieldAttributes.Public); - // Generates the constructor for the new type, it takes a Lua table and an array - // of return types and stores them in the respective fields - var constructor = myType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(LuaTable), typeof(Type[][]) }); - ILGenerator generator = constructor.GetILGenerator(); - generator.Emit(OpCodes.Ldarg_0); - - if(klass.IsInterface) - generator.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); - else - generator.Emit(OpCodes.Call, klass.GetConstructor(Type.EmptyTypes)); - - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Stfld, luaTableField); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldarg_2); - generator.Emit(OpCodes.Stfld, returnTypesField); - generator.Emit(OpCodes.Ret); - // Generates overriden versions of the klass' public virtual methods - var classMethods = klass.GetMethods(); - returnTypes = new Type[classMethods.Length][]; - int i = 0; - - foreach(var method in classMethods) - { - if(klass.IsInterface) - { - GenerateMethod(myType, method, MethodAttributes.HideBySig|MethodAttributes.Virtual|MethodAttributes.NewSlot, - i, luaTableField, returnTypesField, false, out returnTypes[i]); - i++; - } - else - { - if(!method.IsPrivate && !method.IsFinal && method.IsVirtual) - { - GenerateMethod(myType, method, (method.Attributes|MethodAttributes.NewSlot)^MethodAttributes.NewSlot, i, - luaTableField, returnTypesField, true, out returnTypes[i]); - i++; - } - } - } - - // Generates an implementation of the __luaInterface_getLuaTable method - var returnTableMethod = myType.DefineMethod("__luaInterface_getLuaTable", - MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(LuaTable), new Type[0]); - myType.DefineMethodOverride(returnTableMethod, typeof(ILuaGeneratedType).GetMethod("__luaInterface_getLuaTable")); - generator = returnTableMethod.GetILGenerator(); - generator.Emit(OpCodes.Ldfld, luaTableField); - generator.Emit(OpCodes.Ret); - newType = myType.CreateType(); // Creates the type - } - - /* - * Generates an overriden implementation of method inside myType that delegates - * to a function in a Lua table with the same name, if the function exists. If it - * doesn't the method calls the base method (or does nothing, in case of interface - * implementations). - */ - private void GenerateMethod(TypeBuilder myType, MethodInfo method, MethodAttributes attributes, int methodIndex, - FieldInfo luaTableField, FieldInfo returnTypesField, bool generateBase, out Type[] returnTypes) - { - var paramInfo = method.GetParameters(); - var paramTypes = new Type[paramInfo.Length]; - var returnTypesList = new List(); - - // Counts out and ref parameters, for later use, - // and creates the list of return types - int nOutParams = 0; - int nOutAndRefParams = 0; - var returnType = method.ReturnType; - returnTypesList.Add(returnType); - - for(int i = 0; i < paramTypes.Length; i++) - { - paramTypes[i] = paramInfo[i].ParameterType; - if((!paramInfo[i].IsIn) && paramInfo[i].IsOut) - nOutParams++; - - if(paramTypes[i].IsByRef) - { - returnTypesList.Add(paramTypes[i].GetElementType()); - nOutAndRefParams++; - } - } - - int[] refArgs = new int[nOutAndRefParams]; - returnTypes = returnTypesList.ToArray(); - - // Generates a version of the method that calls the base implementation - // directly, for use by the base field of the table - if(generateBase) - { - var baseMethod = myType.DefineMethod("__luaInterface_base_"+method.Name, - MethodAttributes.Private|MethodAttributes.NewSlot|MethodAttributes.HideBySig, - returnType, paramTypes); - ILGenerator generatorBase = baseMethod.GetILGenerator(); - generatorBase.Emit(OpCodes.Ldarg_0); - - for(int i = 0; i < paramTypes.Length; i++) - generatorBase.Emit(OpCodes.Ldarg, i+1); - - generatorBase.Emit(OpCodes.Call, method); - - if(returnType == typeof(void)) - generatorBase.Emit(OpCodes.Pop); - - generatorBase.Emit(OpCodes.Ret); - } - - // Defines the method - var methodImpl = myType.DefineMethod(method.Name, attributes, returnType, paramTypes); - - // If it's an implementation of an interface tells what method it - // is overriding - if(myType.BaseType.Equals(typeof(object))) - myType.DefineMethodOverride(methodImpl, method); - - ILGenerator generator = methodImpl.GetILGenerator( ); - generator.DeclareLocal(typeof(object[])); // original arguments - generator.DeclareLocal(typeof(object[])); // with out-only arguments removed - generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments - - if(!(returnType == typeof(void))) // return value - generator.DeclareLocal(returnType); - else - generator.DeclareLocal(typeof(object)); - - // Initializes local variables - generator.Emit(OpCodes.Ldc_I4, paramTypes.Length); - generator.Emit(OpCodes.Newarr, typeof(object)); - generator.Emit(OpCodes.Stloc_0); - generator.Emit(OpCodes.Ldc_I4, paramTypes.Length-nOutParams+1); - generator.Emit(OpCodes.Newarr, typeof(object)); - generator.Emit(OpCodes.Stloc_1); - generator.Emit(OpCodes.Ldc_I4, nOutAndRefParams); - generator.Emit(OpCodes.Newarr, typeof(int)); - generator.Emit(OpCodes.Stloc_2); - generator.Emit(OpCodes.Ldloc_1); - generator.Emit(OpCodes.Ldc_I4_0); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, luaTableField); - generator.Emit(OpCodes.Stelem_Ref); - - // Stores the arguments into the local variables, as needed - for(int iArgs = 0, iInArgs = 1, iOutArgs = 0; iArgs < paramTypes.Length; iArgs++) - { - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldc_I4, iArgs); - generator.Emit(OpCodes.Ldarg, iArgs+1); - - if(paramTypes[iArgs].IsByRef) - { - if(paramTypes[iArgs].GetElementType().IsValueType) - { - generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); - generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); - } - else - generator.Emit(OpCodes.Ldind_Ref); - } - else - { - if(paramTypes[iArgs].IsValueType) - generator.Emit(OpCodes.Box, paramTypes[iArgs]); - } - - generator.Emit(OpCodes.Stelem_Ref); - - if(paramTypes[iArgs].IsByRef) - { - generator.Emit(OpCodes.Ldloc_2); - generator.Emit(OpCodes.Ldc_I4, iOutArgs); - generator.Emit(OpCodes.Ldc_I4, iArgs); - generator.Emit(OpCodes.Stelem_I4); - refArgs[iOutArgs] = iArgs; - iOutArgs++; - } - - if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut)) - { - generator.Emit(OpCodes.Ldloc_1); - generator.Emit(OpCodes.Ldc_I4, iInArgs); - generator.Emit(OpCodes.Ldarg, iArgs+1); - - if(paramTypes[iArgs].IsByRef) - { - if(paramTypes[iArgs].GetElementType().IsValueType) - { - generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); - generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); - } - else - generator.Emit(OpCodes.Ldind_Ref); - } - else - { - if(paramTypes[iArgs].IsValueType) - generator.Emit(OpCodes.Box, paramTypes[iArgs]); - } - - generator.Emit(OpCodes.Stelem_Ref); - iInArgs++; - } - } - - // Gets the function the method will delegate to by calling - // the getTableFunction method of class LuaClassHelper - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, luaTableField); - generator.Emit(OpCodes.Ldstr, method.Name); - generator.Emit(OpCodes.Call, classHelper.GetMethod("getTableFunction")); - var lab1 = generator.DefineLabel(); - generator.Emit(OpCodes.Dup); - generator.Emit(OpCodes.Brtrue_S, lab1); - // Function does not exist, call base method - generator.Emit(OpCodes.Pop); - - if(!method.IsAbstract) - { - generator.Emit(OpCodes.Ldarg_0); - - for(int i = 0; i < paramTypes.Length; i++) - generator.Emit(OpCodes.Ldarg, i+1); - - generator.Emit(OpCodes.Call, method); - - if(returnType == typeof(void)) - generator.Emit(OpCodes.Pop); - - generator.Emit(OpCodes.Ret); - generator.Emit(OpCodes.Ldnull); - } - else - generator.Emit(OpCodes.Ldnull); - - var lab2 = generator.DefineLabel(); - generator.Emit(OpCodes.Br_S, lab2); - generator.MarkLabel(lab1); - // Function exists, call using method callFunction of LuaClassHelper - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, returnTypesField); - generator.Emit(OpCodes.Ldc_I4, methodIndex); - generator.Emit(OpCodes.Ldelem_Ref); - generator.Emit(OpCodes.Ldloc_1); - generator.Emit(OpCodes.Ldloc_2); - generator.Emit(OpCodes.Call, classHelper.GetMethod("callFunction")); - generator.MarkLabel(lab2); - - // Stores the function return value - if(returnType == typeof(void)) - { - generator.Emit(OpCodes.Pop); - generator.Emit(OpCodes.Ldnull); - } - else if(returnType.IsValueType) - { - generator.Emit(OpCodes.Unbox, returnType); - generator.Emit(OpCodes.Ldobj, returnType); - } - else - generator.Emit(OpCodes.Castclass, returnType); - - generator.Emit(OpCodes.Stloc_3); - - // Sets return values of out and ref parameters - for(int i = 0; i < refArgs.Length; i++) - { - generator.Emit(OpCodes.Ldarg, refArgs[i]+1); - generator.Emit(OpCodes.Ldloc_0); - generator.Emit(OpCodes.Ldc_I4, refArgs[i]); - generator.Emit(OpCodes.Ldelem_Ref); - - if(paramTypes[refArgs[i]].GetElementType().IsValueType) - { - generator.Emit(OpCodes.Unbox, paramTypes[refArgs[i]].GetElementType()); - generator.Emit(OpCodes.Ldobj, paramTypes[refArgs[i]].GetElementType()); - generator.Emit(OpCodes.Stobj, paramTypes[refArgs[i]].GetElementType()); - } - else - { - generator.Emit(OpCodes.Castclass, paramTypes[refArgs[i]].GetElementType()); - generator.Emit(OpCodes.Stind_Ref); - } - } - - // Returns - if(!(returnType == typeof(void))) - generator.Emit(OpCodes.Ldloc_3); - - generator.Emit(OpCodes.Ret); - } - - /* - * Gets an event handler for the event type that delegates to the eventHandler Lua function. - * Caches the generated type. - */ - public LuaEventHandler GetEvent(Type eventHandlerType, LuaFunction eventHandler) - { - Type eventConsumerType; - - if(eventHandlerCollection.ContainsKey(eventHandlerType)) - eventConsumerType = eventHandlerCollection[eventHandlerType]; - else - { - eventConsumerType = GenerateEvent(eventHandlerType); - eventHandlerCollection[eventHandlerType] = eventConsumerType; - } - - var luaEventHandler = (LuaEventHandler)Activator.CreateInstance(eventConsumerType); - luaEventHandler.handler = eventHandler; - return luaEventHandler; - } - - /* - * Gets a delegate with delegateType that calls the luaFunc Lua function - * Caches the generated type. - */ - public Delegate GetDelegate(Type delegateType, LuaFunction luaFunc) - { - var returnTypes = new List(); - Type luaDelegateType; - - if(delegateCollection.ContainsKey(delegateType)) - luaDelegateType = delegateCollection[delegateType]; - else - { - luaDelegateType = GenerateDelegate(delegateType); - delegateCollection[delegateType] = luaDelegateType; - } - - var methodInfo = delegateType.GetMethod("Invoke"); - returnTypes.Add(methodInfo.ReturnType); - - foreach(ParameterInfo paramInfo in methodInfo.GetParameters()) - { - if(paramInfo.ParameterType.IsByRef) - returnTypes.Add(paramInfo.ParameterType); - } - - var luaDelegate = (LuaDelegate)Activator.CreateInstance(luaDelegateType); - luaDelegate.function = luaFunc; - luaDelegate.returnTypes = returnTypes.ToArray(); - return Delegate.CreateDelegate(delegateType, luaDelegate, "CallFunction"); - } - - /* - * Gets an instance of an implementation of the klass interface or - * subclass of klass that delegates public virtual methods to the - * luaTable table. - * Caches the generated type. - */ - public object GetClassInstance(Type klass, LuaTable luaTable) - { - LuaClassType luaClassType; - - if(classCollection.ContainsKey(klass)) - luaClassType = classCollection[klass]; - else - { - luaClassType = new LuaClassType(); - GenerateClass(klass, out luaClassType.klass, out luaClassType.returnTypes); - classCollection[klass] = luaClassType; - } - - return Activator.CreateInstance(luaClassType.klass, new object[] {luaTable, luaClassType.returnTypes}); - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Threading; +using System.Reflection; +using System.Reflection.Emit; +using System.Collections; +using System.Collections.Generic; +using LuaInterface.Method; + +namespace LuaInterface +{ + /* + * Dynamically generates new types from existing types and + * Lua function and table values. Generated types are event handlers, + * delegates, interface implementations and subclasses. + * + * Author: Fabio Mascarenhas + * Version: 1.0 + */ + class CodeGeneration + { + private Dictionary classCollection = new Dictionary(); + private Dictionary eventHandlerCollection = new Dictionary(); + private Dictionary delegateCollection = new Dictionary(); + private static readonly CodeGeneration instance = new CodeGeneration(); + private Type eventHandlerParent = typeof(LuaEventHandler); + private Type delegateParent = typeof(LuaDelegate); + private Type classHelper = typeof(LuaClassHelper); + private AssemblyName assemblyName; + private AssemblyBuilder newAssembly; + private ModuleBuilder newModule; + private int luaClassNumber = 1; + + static CodeGeneration() + { + } + + private CodeGeneration() + { + // Create an assembly name + assemblyName = new AssemblyName(); + assemblyName.Name = "LuaInterface_generatedcode"; + // Create a new assembly with one module. + newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); + newModule = newAssembly.DefineDynamicModule("LuaInterface_generatedcode"); + } + + /* + * Singleton instance of the class + */ + public static CodeGeneration Instance + { + get { return instance; } + } + + /* + * Generates an event handler that calls a Lua function + */ + private Type GenerateEvent(Type eventHandlerType) + { + string typeName; + lock(this) + { + typeName = "LuaGeneratedClass" + luaClassNumber; + luaClassNumber++; + } + + // Define a public class in the assembly, called typeName + var myType = newModule.DefineType(typeName, TypeAttributes.Public, eventHandlerParent); + + // Defines the handler method. Its signature is void(object, ) + var paramTypes = new Type[2]; + paramTypes[0] = typeof(object); + paramTypes[1] = eventHandlerType; + var returnType = typeof(void); + var handleMethod = myType.DefineMethod("HandleEvent", MethodAttributes.Public | MethodAttributes.HideBySig, returnType, paramTypes); + + // Emits the IL for the method. It loads the arguments + // and calls the handleEvent method of the base class + ILGenerator generator = handleMethod.GetILGenerator(); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldarg_1); + generator.Emit(OpCodes.Ldarg_2); + var miGenericEventHandler = eventHandlerParent.GetMethod("handleEvent"); + generator.Emit(OpCodes.Call, miGenericEventHandler); + // returns + generator.Emit(OpCodes.Ret); + // creates the new type + return myType.CreateType(); + } + + /* + * Generates a type that can be used for instantiating a delegate + * of the provided type, given a Lua function. + */ + private Type GenerateDelegate(Type delegateType) + { + string typeName; + lock(this) + { + typeName = "LuaGeneratedClass" + luaClassNumber; + luaClassNumber++; + } + + // Define a public class in the assembly, called typeName + var myType = newModule.DefineType(typeName, TypeAttributes.Public, delegateParent); + + // Defines the delegate method with the same signature as the + // Invoke method of delegateType + var invokeMethod = delegateType.GetMethod("Invoke"); + var paramInfo = invokeMethod.GetParameters(); + var paramTypes = new Type[paramInfo.Length]; + var returnType = invokeMethod.ReturnType; + + // Counts out and ref params, for use later + int nOutParams = 0; int nOutAndRefParams = 0; + + for(int i = 0; i < paramTypes.Length; i++) + { + paramTypes[i] = paramInfo[i].ParameterType; + + if((!paramInfo[i].IsIn) && paramInfo[i].IsOut) + nOutParams++; + + if(paramTypes[i].IsByRef) + nOutAndRefParams++; + } + + int[] refArgs = new int[nOutAndRefParams]; + var delegateMethod = myType.DefineMethod("CallFunction", invokeMethod.Attributes, returnType, paramTypes); + + // Generates the IL for the method + ILGenerator generator = delegateMethod.GetILGenerator( ); + generator.DeclareLocal(typeof(object[])); // original arguments + generator.DeclareLocal(typeof(object[])); // with out-only arguments removed + generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments + + if(!(returnType == typeof(void))) // return value + generator.DeclareLocal(returnType); + else + generator.DeclareLocal(typeof(object)); + + // Initializes local variables + generator.Emit(OpCodes.Ldc_I4, paramTypes.Length); + generator.Emit(OpCodes.Newarr, typeof(object)); + generator.Emit(OpCodes.Stloc_0); + generator.Emit(OpCodes.Ldc_I4, paramTypes.Length-nOutParams); + generator.Emit(OpCodes.Newarr, typeof(object)); + generator.Emit(OpCodes.Stloc_1); + generator.Emit(OpCodes.Ldc_I4, nOutAndRefParams); + generator.Emit(OpCodes.Newarr, typeof(int)); + generator.Emit(OpCodes.Stloc_2); + + // Stores the arguments in the local variables + for(int iArgs = 0, iInArgs = 0, iOutArgs = 0; iArgs < paramTypes.Length; iArgs++) + { + generator.Emit(OpCodes.Ldloc_0); + generator.Emit(OpCodes.Ldc_I4, iArgs); + generator.Emit(OpCodes.Ldarg, iArgs+1); + + if(paramTypes[iArgs].IsByRef) + { + if(paramTypes[iArgs].GetElementType().IsValueType) + { + generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); + generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); + } + else + generator.Emit(OpCodes.Ldind_Ref); + } + else + { + if(paramTypes[iArgs].IsValueType) + generator.Emit(OpCodes.Box, paramTypes[iArgs]); + } + + generator.Emit(OpCodes.Stelem_Ref); + + if(paramTypes[iArgs].IsByRef) + { + generator.Emit(OpCodes.Ldloc_2); + generator.Emit(OpCodes.Ldc_I4, iOutArgs); + generator.Emit(OpCodes.Ldc_I4, iArgs); + generator.Emit(OpCodes.Stelem_I4); + refArgs[iOutArgs] = iArgs; + iOutArgs++; + } + + if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut)) + { + generator.Emit(OpCodes.Ldloc_1); + generator.Emit(OpCodes.Ldc_I4, iInArgs); + generator.Emit(OpCodes.Ldarg, iArgs+1); + + if(paramTypes[iArgs].IsByRef) + { + if(paramTypes[iArgs].GetElementType().IsValueType) + { + generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); + generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); + } + else + generator.Emit(OpCodes.Ldind_Ref); + } + else + { + if(paramTypes[iArgs].IsValueType) + generator.Emit(OpCodes.Box, paramTypes[iArgs]); + } + + generator.Emit(OpCodes.Stelem_Ref); + iInArgs++; + } + } + + // Calls the callFunction method of the base class + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldloc_0); + generator.Emit(OpCodes.Ldloc_1); + generator.Emit(OpCodes.Ldloc_2); + var miGenericEventHandler = delegateParent.GetMethod("callFunction"); + generator.Emit(OpCodes.Call, miGenericEventHandler); + + // Stores return value + if(returnType == typeof(void)) + { + generator.Emit(OpCodes.Pop); + generator.Emit(OpCodes.Ldnull); + } + else if(returnType.IsValueType) + { + generator.Emit(OpCodes.Unbox, returnType); + generator.Emit(OpCodes.Ldobj, returnType); + } + else + generator.Emit(OpCodes.Castclass, returnType); + + generator.Emit(OpCodes.Stloc_3); + + // Stores new value of out and ref params + for(int i = 0; i < refArgs.Length; i++) + { + generator.Emit(OpCodes.Ldarg, refArgs[i]+1); + generator.Emit(OpCodes.Ldloc_0); + generator.Emit(OpCodes.Ldc_I4, refArgs[i]); + generator.Emit(OpCodes.Ldelem_Ref); + + if(paramTypes[refArgs[i]].GetElementType().IsValueType) + { + generator.Emit(OpCodes.Unbox, paramTypes[refArgs[i]].GetElementType()); + generator.Emit(OpCodes.Ldobj, paramTypes[refArgs[i]].GetElementType()); + generator.Emit(OpCodes.Stobj, paramTypes[refArgs[i]].GetElementType()); + } + else + { + generator.Emit(OpCodes.Castclass, paramTypes[refArgs[i]].GetElementType()); + generator.Emit(OpCodes.Stind_Ref); + } + } + + // Returns + if(!(returnType == typeof(void))) + generator.Emit(OpCodes.Ldloc_3); + + generator.Emit(OpCodes.Ret); + return myType.CreateType(); // creates the new type + } + + /* + * Generates an implementation of klass, if it is an interface, or + * a subclass of klass that delegates its virtual methods to a Lua table. + */ + public void GenerateClass(Type klass, out Type newType, out Type[][] returnTypes) + { + string typeName; + lock(this) + { + typeName = "LuaGeneratedClass" + luaClassNumber; + luaClassNumber++; + } + + TypeBuilder myType; + // Define a public class in the assembly, called typeName + if(klass.IsInterface) + myType = newModule.DefineType(typeName, TypeAttributes.Public, typeof(object), new Type[] { klass, typeof(ILuaGeneratedType) }); + else + myType = newModule.DefineType(typeName, TypeAttributes.Public, klass, new Type[] { typeof(ILuaGeneratedType) }); + + // Field that stores the Lua table + var luaTableField = myType.DefineField("__luaInterface_luaTable", typeof(LuaTable), FieldAttributes.Public); + // Field that stores the return types array + var returnTypesField = myType.DefineField("__luaInterface_returnTypes", typeof(Type[][]), FieldAttributes.Public); + // Generates the constructor for the new type, it takes a Lua table and an array + // of return types and stores them in the respective fields + var constructor = myType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(LuaTable), typeof(Type[][]) }); + ILGenerator generator = constructor.GetILGenerator(); + generator.Emit(OpCodes.Ldarg_0); + + if(klass.IsInterface) + generator.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); + else + generator.Emit(OpCodes.Call, klass.GetConstructor(Type.EmptyTypes)); + + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldarg_1); + generator.Emit(OpCodes.Stfld, luaTableField); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldarg_2); + generator.Emit(OpCodes.Stfld, returnTypesField); + generator.Emit(OpCodes.Ret); + // Generates overriden versions of the klass' public virtual methods + var classMethods = klass.GetMethods(); + returnTypes = new Type[classMethods.Length][]; + int i = 0; + + foreach(var method in classMethods) + { + if(klass.IsInterface) + { + GenerateMethod(myType, method, MethodAttributes.HideBySig|MethodAttributes.Virtual|MethodAttributes.NewSlot, + i, luaTableField, returnTypesField, false, out returnTypes[i]); + i++; + } + else + { + if(!method.IsPrivate && !method.IsFinal && method.IsVirtual) + { + GenerateMethod(myType, method, (method.Attributes|MethodAttributes.NewSlot)^MethodAttributes.NewSlot, i, + luaTableField, returnTypesField, true, out returnTypes[i]); + i++; + } + } + } + + // Generates an implementation of the __luaInterface_getLuaTable method + var returnTableMethod = myType.DefineMethod("__luaInterface_getLuaTable", + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(LuaTable), new Type[0]); + myType.DefineMethodOverride(returnTableMethod, typeof(ILuaGeneratedType).GetMethod("__luaInterface_getLuaTable")); + generator = returnTableMethod.GetILGenerator(); + generator.Emit(OpCodes.Ldfld, luaTableField); + generator.Emit(OpCodes.Ret); + newType = myType.CreateType(); // Creates the type + } + + /* + * Generates an overriden implementation of method inside myType that delegates + * to a function in a Lua table with the same name, if the function exists. If it + * doesn't the method calls the base method (or does nothing, in case of interface + * implementations). + */ + private void GenerateMethod(TypeBuilder myType, MethodInfo method, MethodAttributes attributes, int methodIndex, + FieldInfo luaTableField, FieldInfo returnTypesField, bool generateBase, out Type[] returnTypes) + { + var paramInfo = method.GetParameters(); + var paramTypes = new Type[paramInfo.Length]; + var returnTypesList = new List(); + + // Counts out and ref parameters, for later use, + // and creates the list of return types + int nOutParams = 0; + int nOutAndRefParams = 0; + var returnType = method.ReturnType; + returnTypesList.Add(returnType); + + for(int i = 0; i < paramTypes.Length; i++) + { + paramTypes[i] = paramInfo[i].ParameterType; + if((!paramInfo[i].IsIn) && paramInfo[i].IsOut) + nOutParams++; + + if(paramTypes[i].IsByRef) + { + returnTypesList.Add(paramTypes[i].GetElementType()); + nOutAndRefParams++; + } + } + + int[] refArgs = new int[nOutAndRefParams]; + returnTypes = returnTypesList.ToArray(); + + // Generates a version of the method that calls the base implementation + // directly, for use by the base field of the table + if(generateBase) + { + var baseMethod = myType.DefineMethod("__luaInterface_base_"+method.Name, + MethodAttributes.Private|MethodAttributes.NewSlot|MethodAttributes.HideBySig, + returnType, paramTypes); + ILGenerator generatorBase = baseMethod.GetILGenerator(); + generatorBase.Emit(OpCodes.Ldarg_0); + + for(int i = 0; i < paramTypes.Length; i++) + generatorBase.Emit(OpCodes.Ldarg, i+1); + + generatorBase.Emit(OpCodes.Call, method); + + if(returnType == typeof(void)) + generatorBase.Emit(OpCodes.Pop); + + generatorBase.Emit(OpCodes.Ret); + } + + // Defines the method + var methodImpl = myType.DefineMethod(method.Name, attributes, returnType, paramTypes); + + // If it's an implementation of an interface tells what method it + // is overriding + if(myType.BaseType.Equals(typeof(object))) + myType.DefineMethodOverride(methodImpl, method); + + ILGenerator generator = methodImpl.GetILGenerator( ); + generator.DeclareLocal(typeof(object[])); // original arguments + generator.DeclareLocal(typeof(object[])); // with out-only arguments removed + generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments + + if(!(returnType == typeof(void))) // return value + generator.DeclareLocal(returnType); + else + generator.DeclareLocal(typeof(object)); + + // Initializes local variables + generator.Emit(OpCodes.Ldc_I4, paramTypes.Length); + generator.Emit(OpCodes.Newarr, typeof(object)); + generator.Emit(OpCodes.Stloc_0); + generator.Emit(OpCodes.Ldc_I4, paramTypes.Length-nOutParams+1); + generator.Emit(OpCodes.Newarr, typeof(object)); + generator.Emit(OpCodes.Stloc_1); + generator.Emit(OpCodes.Ldc_I4, nOutAndRefParams); + generator.Emit(OpCodes.Newarr, typeof(int)); + generator.Emit(OpCodes.Stloc_2); + generator.Emit(OpCodes.Ldloc_1); + generator.Emit(OpCodes.Ldc_I4_0); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldfld, luaTableField); + generator.Emit(OpCodes.Stelem_Ref); + + // Stores the arguments into the local variables, as needed + for(int iArgs = 0, iInArgs = 1, iOutArgs = 0; iArgs < paramTypes.Length; iArgs++) + { + generator.Emit(OpCodes.Ldloc_0); + generator.Emit(OpCodes.Ldc_I4, iArgs); + generator.Emit(OpCodes.Ldarg, iArgs+1); + + if(paramTypes[iArgs].IsByRef) + { + if(paramTypes[iArgs].GetElementType().IsValueType) + { + generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); + generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); + } + else + generator.Emit(OpCodes.Ldind_Ref); + } + else + { + if(paramTypes[iArgs].IsValueType) + generator.Emit(OpCodes.Box, paramTypes[iArgs]); + } + + generator.Emit(OpCodes.Stelem_Ref); + + if(paramTypes[iArgs].IsByRef) + { + generator.Emit(OpCodes.Ldloc_2); + generator.Emit(OpCodes.Ldc_I4, iOutArgs); + generator.Emit(OpCodes.Ldc_I4, iArgs); + generator.Emit(OpCodes.Stelem_I4); + refArgs[iOutArgs] = iArgs; + iOutArgs++; + } + + if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut)) + { + generator.Emit(OpCodes.Ldloc_1); + generator.Emit(OpCodes.Ldc_I4, iInArgs); + generator.Emit(OpCodes.Ldarg, iArgs+1); + + if(paramTypes[iArgs].IsByRef) + { + if(paramTypes[iArgs].GetElementType().IsValueType) + { + generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); + generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); + } + else + generator.Emit(OpCodes.Ldind_Ref); + } + else + { + if(paramTypes[iArgs].IsValueType) + generator.Emit(OpCodes.Box, paramTypes[iArgs]); + } + + generator.Emit(OpCodes.Stelem_Ref); + iInArgs++; + } + } + + // Gets the function the method will delegate to by calling + // the getTableFunction method of class LuaClassHelper + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldfld, luaTableField); + generator.Emit(OpCodes.Ldstr, method.Name); + generator.Emit(OpCodes.Call, classHelper.GetMethod("getTableFunction")); + var lab1 = generator.DefineLabel(); + generator.Emit(OpCodes.Dup); + generator.Emit(OpCodes.Brtrue_S, lab1); + // Function does not exist, call base method + generator.Emit(OpCodes.Pop); + + if(!method.IsAbstract) + { + generator.Emit(OpCodes.Ldarg_0); + + for(int i = 0; i < paramTypes.Length; i++) + generator.Emit(OpCodes.Ldarg, i+1); + + generator.Emit(OpCodes.Call, method); + + if(returnType == typeof(void)) + generator.Emit(OpCodes.Pop); + + generator.Emit(OpCodes.Ret); + generator.Emit(OpCodes.Ldnull); + } + else + generator.Emit(OpCodes.Ldnull); + + var lab2 = generator.DefineLabel(); + generator.Emit(OpCodes.Br_S, lab2); + generator.MarkLabel(lab1); + // Function exists, call using method callFunction of LuaClassHelper + generator.Emit(OpCodes.Ldloc_0); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldfld, returnTypesField); + generator.Emit(OpCodes.Ldc_I4, methodIndex); + generator.Emit(OpCodes.Ldelem_Ref); + generator.Emit(OpCodes.Ldloc_1); + generator.Emit(OpCodes.Ldloc_2); + generator.Emit(OpCodes.Call, classHelper.GetMethod("callFunction")); + generator.MarkLabel(lab2); + + // Stores the function return value + if(returnType == typeof(void)) + { + generator.Emit(OpCodes.Pop); + generator.Emit(OpCodes.Ldnull); + } + else if(returnType.IsValueType) + { + generator.Emit(OpCodes.Unbox, returnType); + generator.Emit(OpCodes.Ldobj, returnType); + } + else + generator.Emit(OpCodes.Castclass, returnType); + + generator.Emit(OpCodes.Stloc_3); + + // Sets return values of out and ref parameters + for(int i = 0; i < refArgs.Length; i++) + { + generator.Emit(OpCodes.Ldarg, refArgs[i]+1); + generator.Emit(OpCodes.Ldloc_0); + generator.Emit(OpCodes.Ldc_I4, refArgs[i]); + generator.Emit(OpCodes.Ldelem_Ref); + + if(paramTypes[refArgs[i]].GetElementType().IsValueType) + { + generator.Emit(OpCodes.Unbox, paramTypes[refArgs[i]].GetElementType()); + generator.Emit(OpCodes.Ldobj, paramTypes[refArgs[i]].GetElementType()); + generator.Emit(OpCodes.Stobj, paramTypes[refArgs[i]].GetElementType()); + } + else + { + generator.Emit(OpCodes.Castclass, paramTypes[refArgs[i]].GetElementType()); + generator.Emit(OpCodes.Stind_Ref); + } + } + + // Returns + if(!(returnType == typeof(void))) + generator.Emit(OpCodes.Ldloc_3); + + generator.Emit(OpCodes.Ret); + } + + /* + * Gets an event handler for the event type that delegates to the eventHandler Lua function. + * Caches the generated type. + */ + public LuaEventHandler GetEvent(Type eventHandlerType, LuaFunction eventHandler) + { + Type eventConsumerType; + + if(eventHandlerCollection.ContainsKey(eventHandlerType)) + eventConsumerType = eventHandlerCollection[eventHandlerType]; + else + { + eventConsumerType = GenerateEvent(eventHandlerType); + eventHandlerCollection[eventHandlerType] = eventConsumerType; + } + + var luaEventHandler = (LuaEventHandler)Activator.CreateInstance(eventConsumerType); + luaEventHandler.handler = eventHandler; + return luaEventHandler; + } + + /* + * Gets a delegate with delegateType that calls the luaFunc Lua function + * Caches the generated type. + */ + public Delegate GetDelegate(Type delegateType, LuaFunction luaFunc) + { + var returnTypes = new List(); + Type luaDelegateType; + + if(delegateCollection.ContainsKey(delegateType)) + luaDelegateType = delegateCollection[delegateType]; + else + { + luaDelegateType = GenerateDelegate(delegateType); + delegateCollection[delegateType] = luaDelegateType; + } + + var methodInfo = delegateType.GetMethod("Invoke"); + returnTypes.Add(methodInfo.ReturnType); + + foreach(ParameterInfo paramInfo in methodInfo.GetParameters()) + { + if(paramInfo.ParameterType.IsByRef) + returnTypes.Add(paramInfo.ParameterType); + } + + var luaDelegate = (LuaDelegate)Activator.CreateInstance(luaDelegateType); + luaDelegate.function = luaFunc; + luaDelegate.returnTypes = returnTypes.ToArray(); + return Delegate.CreateDelegate(delegateType, luaDelegate, "CallFunction"); + } + + /* + * Gets an instance of an implementation of the klass interface or + * subclass of klass that delegates public virtual methods to the + * luaTable table. + * Caches the generated type. + */ + public object GetClassInstance(Type klass, LuaTable luaTable) + { + LuaClassType luaClassType; + + if(classCollection.ContainsKey(klass)) + luaClassType = classCollection[klass]; + else + { + luaClassType = new LuaClassType(); + GenerateClass(klass, out luaClassType.klass, out luaClassType.returnTypes); + classCollection[klass] = luaClassType; + } + + return Activator.CreateInstance(luaClassType.klass, new object[] {luaTable, luaClassType.returnTypes}); + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/GenerateEventAssembly/DelegateGenerator.cs b/Core/LuaInterface/GenerateEventAssembly/DelegateGenerator.cs index c5979831fb316c55589a776e28854f26a433fb3c..8571c4e7e3d63df11611f99e6aa4895a77c9a871 100644 --- a/Core/LuaInterface/GenerateEventAssembly/DelegateGenerator.cs +++ b/Core/LuaInterface/GenerateEventAssembly/DelegateGenerator.cs @@ -1,53 +1,53 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface -{ - /* - * Class used for generating delegates that get a function from the Lua - * stack as a delegate of a specific type. - * - * Author: Fabio Mascarenhas - * Version: 1.0 - */ - class DelegateGenerator - { - private ObjectTranslator translator; - private Type delegateType; - - public DelegateGenerator(ObjectTranslator translator, Type delegateType) - { - this.translator = translator; - this.delegateType = delegateType; - } - - public object extractGenerated(KopiLua.Lua.lua_State luaState, int stackPos) - { - return CodeGeneration.Instance.GetDelegate(delegateType, translator.getFunction(luaState, stackPos)); - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface +{ + /* + * Class used for generating delegates that get a function from the Lua + * stack as a delegate of a specific type. + * + * Author: Fabio Mascarenhas + * Version: 1.0 + */ + class DelegateGenerator + { + private ObjectTranslator translator; + private Type delegateType; + + public DelegateGenerator(ObjectTranslator translator, Type delegateType) + { + this.translator = translator; + this.delegateType = delegateType; + } + + public object extractGenerated(KopiLua.Lua.lua_State luaState, int stackPos) + { + return CodeGeneration.Instance.GetDelegate(delegateType, translator.getFunction(luaState, stackPos)); + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/GenerateEventAssembly/ILuaGeneratedType.cs b/Core/LuaInterface/GenerateEventAssembly/ILuaGeneratedType.cs index 78e3d99cc48e2e432bf96d63f477c201fc06e510..e6d6aceaee2079ba1f6d66282c6c3171dc1607ca 100644 --- a/Core/LuaInterface/GenerateEventAssembly/ILuaGeneratedType.cs +++ b/Core/LuaInterface/GenerateEventAssembly/ILuaGeneratedType.cs @@ -1,38 +1,38 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface -{ - /* - * Common interface for types generated from tables. The method - * returns the table that overrides some or all of the type's methods. - */ - public interface ILuaGeneratedType - { - LuaTable __luaInterface_getLuaTable(); - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface +{ + /* + * Common interface for types generated from tables. The method + * returns the table that overrides some or all of the type's methods. + */ + public interface ILuaGeneratedType + { + LuaTable __luaInterface_getLuaTable(); + } } \ No newline at end of file diff --git a/Core/LuaInterface/GenerateEventAssembly/LuaClassType.cs b/Core/LuaInterface/GenerateEventAssembly/LuaClassType.cs index 072c42f1de7e94560a3049a42cc35b1344ca6921..bbd10af3f815bef524bce51f92e17ef88eca3bec 100644 --- a/Core/LuaInterface/GenerateEventAssembly/LuaClassType.cs +++ b/Core/LuaInterface/GenerateEventAssembly/LuaClassType.cs @@ -1,40 +1,40 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface -{ - /* - * Structure to store a type and the return types of - * its methods (the type of the returned value and out/ref - * parameters). - */ - struct LuaClassType - { - public Type klass; - public Type[][] returnTypes; - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface +{ + /* + * Structure to store a type and the return types of + * its methods (the type of the returned value and out/ref + * parameters). + */ + struct LuaClassType + { + public Type klass; + public Type[][] returnTypes; + } } \ No newline at end of file diff --git a/Core/LuaInterface/Lua.cs b/Core/LuaInterface/Lua.cs index d09d524c7a58e8b1227902872c19155c2a82bff1..31459ff5163eccde8040f9fb2070ecb22ded9363 100644 --- a/Core/LuaInterface/Lua.cs +++ b/Core/LuaInterface/Lua.cs @@ -1,1093 +1,1093 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.IO; -using System.Threading; -using System.Reflection; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using LuaInterface.Event; -using LuaInterface.Method; -using LuaInterface.Exceptions; -using LuaInterface.Extensions; - -namespace LuaInterface -{ - using LuaCore = KopiLua.Lua; - - /* - * Main class of LuaInterface - * Object-oriented wrapper to Lua API - * - * Author: Fabio Mascarenhas - * Version: 1.0 - * - * // steffenj: important changes in Lua class: - * - removed all Open*Lib() functions - * - all libs automatically open in the Lua class constructor (just assign nil to unwanted libs) - * */ - [CLSCompliant(true)] - public class Lua : IDisposable - { - #region lua debug functions - /// - /// Event that is raised when an exception occures during a hook call. - /// - /// Reinhard Ostermeier - public event EventHandler HookException; - /// - /// Event when lua hook callback is called - /// - /// - /// Is only raised if SetDebugHook is called before. - /// - /// Reinhard Ostermeier - public event EventHandler DebugHook; - /// - /// lua hook calback delegate - /// - /// Reinhard Ostermeier - private LuaCore.lua_Hook hookCallback = null; - #endregion - #region Globals auto-complete - private readonly List globals = new List(); - private bool globalsSorted; - #endregion - private /*readonly */ LuaCore.lua_State luaState; - /// - /// True while a script is being executed - /// - public bool IsExecuting { get { return executing; } } - private LuaCore.lua_CFunction panicCallback; - private ObjectTranslator translator; - /// - /// Used to ensure multiple .net threads all get serialized by this single lock for access to the lua stack/objects - /// - //private object luaLock = new object(); - private bool _StatePassed; - private bool executing; - - static string init_luanet = - "local metatable = {} \n" + - "local import_type = luanet.import_type \n" + - "local load_assembly = luanet.load_assembly \n" + - " \n" + - "-- Lookup a .NET identifier component. \n" + - "function metatable:__index(key) -- key is e.g. \"Form\" \n" + - " -- Get the fully-qualified name, e.g. \"System.Windows.Forms.Form\" \n" + - " local fqn = ((rawget(self, \".fqn\") and rawget(self, \".fqn\") .. \n" + - " \".\") or \"\") .. key \n" + - " \n" + - " -- Try to find either a luanet function or a CLR type \n" + - " local obj = rawget(luanet, key) or import_type(fqn) \n" + - " \n" + - " -- If key is neither a luanet function or a CLR type, then it is simply \n" + - " -- an identifier component. \n" + - " if obj == nil then \n" + - " -- It might be an assembly, so we load it too. \n" + - " load_assembly(fqn) \n" + - " obj = { [\".fqn\"] = fqn } \n" + - " setmetatable(obj, metatable) \n" + - " end \n" + - " \n" + - " -- Cache this lookup \n" + - " rawset(self, key, obj) \n" + - " return obj \n" + - "end \n" + - " \n" + - "-- A non-type has been called; e.g. foo = System.Foo() \n" + - "function metatable:__call(...) \n" + - " error(\"No such type: \" .. rawget(self, \".fqn\"), 2) \n" + - "end \n" + - " \n" + - "-- This is the root of the .NET namespace \n" + - "luanet[\".fqn\"] = false \n" + - "setmetatable(luanet, metatable) \n" + - " \n" + - "-- Preload the mscorlib assembly \n" + - "luanet.load_assembly(\"mscorlib\") \n"; - - #region Globals auto-complete - /// - /// An alphabetically sorted list of all globals (objects, methods, etc.) externally added to this Lua instance - /// - /// Members of globals are also listed. The formatting is optimized for text input auto-completion. - public IEnumerable Globals - { - get - { - // Only sort list when necessary - if(!globalsSorted) - { - globals.Sort(); - globalsSorted = true; - } - - return globals; - } - } - #endregion - - public Lua() - { - luaState = LuaLib.luaL_newstate(); // steffenj: Lua 5.1.1 API change (lua_open is gone) - //LuaLib.luaopen_base(luaState); // steffenj: luaopen_* no longer used - LuaLib.luaL_openlibs(luaState); // steffenj: Lua 5.1.1 API change (luaopen_base is gone, just open all libs right here) - LuaLib.lua_pushstring(luaState, "LUAINTERFACE LOADED"); - LuaLib.lua_pushboolean(luaState, true); - LuaLib.lua_settable(luaState, (int)LuaIndexes.Registry); - LuaLib.lua_newtable(luaState); - LuaLib.lua_setglobal(luaState, "luanet"); - LuaLib.lua_pushvalue(luaState, (int)LuaIndexes.Globals); - LuaLib.lua_getglobal(luaState, "luanet"); - LuaLib.lua_pushstring(luaState, "getmetatable"); - LuaLib.lua_getglobal(luaState, "getmetatable"); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_replace(luaState, (int)LuaIndexes.Globals); - translator = new ObjectTranslator(this, luaState); - LuaLib.lua_replace(luaState, (int)LuaIndexes.Globals); - LuaLib.luaL_dostring(luaState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring - - // We need to keep this in a managed reference so the delegate doesn't get garbage collected - panicCallback = new LuaCore.lua_CFunction(PanicCallback); - LuaLib.lua_atpanic(luaState, panicCallback); - - //LuaLib.lua_atlock(luaState, lockCallback = new LuaCore.lua_CFunction(LockCallback)); - //LuaLib.lua_atunlock(luaState, unlockCallback = new LuaCore.lua_CFunction(UnlockCallback)); - } - - /* - * CAUTION: LuaInterface.Lua instances can't share the same lua state! - */ - public Lua(LuaCore.lua_State lState) - { - LuaLib.lua_pushstring(lState, "LUAINTERFACE LOADED"); - LuaLib.lua_gettable(lState, (int)LuaIndexes.Registry); - - if(LuaLib.lua_toboolean(lState, -1)) - { - LuaLib.lua_settop(lState, -2); - throw new LuaException("There is already a LuaInterface.Lua instance associated with this Lua state"); - } - else - { - LuaLib.lua_settop(lState, -2); - LuaLib.lua_pushstring(lState, "LUAINTERFACE LOADED"); - LuaLib.lua_pushboolean(lState, true); - LuaLib.lua_settable(lState, (int)LuaIndexes.Registry); - luaState = lState; - LuaLib.lua_pushvalue(lState, (int)LuaIndexes.Globals); - LuaLib.lua_getglobal(lState, "luanet"); - LuaLib.lua_pushstring(lState, "getmetatable"); - LuaLib.lua_getglobal(lState, "getmetatable"); - LuaLib.lua_settable(lState, -3); - LuaLib.lua_replace(lState, (int)LuaIndexes.Globals); - translator = new ObjectTranslator(this, luaState); - LuaLib.lua_replace(lState, (int)LuaIndexes.Globals); - LuaLib.luaL_dostring(lState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring - } - - _StatePassed = true; - } - - /// - /// Called for each lua_lock call - /// - /// - /// Not yet used - /*int LockCallback(LuaCore.lua_State luaState) - { - // Monitor.Enter(luaLock); - return 0; - }*/ - - /// - /// Called for each lua_unlock call - /// - /// - /// Not yet used - /*int UnlockCallback(LuaCore.lua_State luaState) - { - // Monitor.Exit(luaLock); - return 0; - }*/ - - public void Close() - { - if(_StatePassed) - return; - - ////// if(luaState != LuaCore.lua_State.Zero) - if(!luaState.IsNull()) - LuaCore.lua_close(luaState); - //luaState = LuaCore.lua_State.Zero; <- suggested by Christopher Cebulski http://luaforge.net/forum/forum.php?thread_id = 44593&forum_id = 146 - } - - static int PanicCallback(LuaCore.lua_State luaState) - { - // string desc = LuaLib.lua_tostring(luaState, 1); - string reason = string.Format("unprotected error in call to Lua API ({0})", LuaLib.lua_tostring(luaState, -1)); - // lua_tostring(L, -1); - throw new LuaException(reason); - } - - /// - /// Assuming we have a Lua error string sitting on the stack, throw a C# exception out to the user's app - /// - /// Thrown if the script caused an exception - private void ThrowExceptionFromError(int oldTop) - { - object err = translator.getObject(luaState, -1); - LuaLib.lua_settop(luaState, oldTop); - - // A pre-wrapped exception - just rethrow it (stack trace of InnerException will be preserved) - var luaEx = err as LuaScriptException; - - if(!luaEx.IsNull()) - throw luaEx; - - // A non-wrapped Lua error (best interpreted as a string) - wrap it and throw it - if(err.IsNull()) - err = "Unknown Lua Error"; - - throw new LuaScriptException(err.ToString(), string.Empty); - } - - /// - /// Convert C# exceptions into Lua errors - /// - /// num of things on stack - /// null for no pending exception - internal int SetPendingException(Exception e) - { - var caughtExcept = e; - - if(!caughtExcept.IsNull()) - { - translator.throwError(luaState, caughtExcept); - LuaLib.lua_pushnil(luaState); - return 1; - } - else - return 0; - } - - /// - /// - /// - /// - /// - /// - public LuaFunction LoadString(string chunk, string name) - { - int oldTop = LuaLib.lua_gettop(luaState); - executing = true; - - try - { - if(LuaLib.luaL_loadbuffer(luaState, chunk, name) != 0) - ThrowExceptionFromError(oldTop); - } - finally - { - executing = false; - } - - var result = translator.getFunction(luaState, -1); - translator.popValues(luaState, oldTop); - return result; - } - - /// - /// - /// - /// - /// - public LuaFunction LoadFile(string fileName) - { - int oldTop = LuaLib.lua_gettop(luaState); - - if(LuaLib.luaL_loadfile(luaState, fileName) != 0) - ThrowExceptionFromError(oldTop); - - var result = translator.getFunction(luaState, -1); - translator.popValues(luaState, oldTop); - return result; - } - - /* - * Excutes a Lua chunk and returns all the chunk's return - * values in an array - */ - public object[] DoString(string chunk) - { - int oldTop = LuaLib.lua_gettop(luaState); - - if(LuaLib.luaL_loadbuffer(luaState, chunk, "chunk") == 0) - { - executing = true; - - try - { - if(LuaLib.lua_pcall(luaState, 0, -1, 0) == 0) - return translator.popValues(luaState, oldTop); - else - ThrowExceptionFromError(oldTop); - } - finally - { - executing = false; - } - } - else - ThrowExceptionFromError(oldTop); - - return null; // Never reached - keeps compiler happy - } - - /// - /// Executes a Lua chnk and returns all the chunk's return values in an array. - /// - /// Chunk to execute - /// Name to associate with the chunk - /// - public object[] DoString(string chunk, string chunkName) - { - int oldTop = LuaLib.lua_gettop(luaState); - executing = true; - - if(LuaLib.luaL_loadbuffer(luaState, chunk, chunkName) == 0) - { - try - { - if(LuaLib.lua_pcall(luaState, 0, -1, 0) == 0) - return translator.popValues(luaState, oldTop); - else - ThrowExceptionFromError(oldTop); - } - finally - { - executing = false; - } - } - else - ThrowExceptionFromError(oldTop); - - return null; // Never reached - keeps compiler happy - } - - /* - * Excutes a Lua file and returns all the chunk's return - * values in an array - */ - public object[] DoFile(string fileName) - { - int oldTop = LuaLib.lua_gettop(luaState); - - if(LuaLib.luaL_loadfile(luaState, fileName) == 0) - { - executing = true; - - try - { - if(LuaLib.lua_pcall(luaState, 0, -1, 0) == 0) - return translator.popValues(luaState, oldTop); - else - ThrowExceptionFromError(oldTop); - } - finally - { - executing = false; - } - } - else - ThrowExceptionFromError(oldTop); - - return null; // Never reached - keeps compiler happy - } - - - /* - * Indexer for global variables from the LuaInterpreter - * Supports navigation of tables by using . operator - */ - public object this[string fullPath] - { - get - { - object returnValue = null; - int oldTop = LuaLib.lua_gettop(luaState); - string[] path = fullPath.Split(new char[] { '.' }); - LuaLib.lua_getglobal(luaState, path[0]); - returnValue = translator.getObject(luaState, -1); - - if(path.Length>1) - { - string[] remainingPath = new string[path.Length-1]; - Array.Copy(path, 1, remainingPath, 0, path.Length-1); - returnValue = getObject(remainingPath); - } - - LuaLib.lua_settop(luaState, oldTop); - return returnValue; - } - set - { - int oldTop = LuaLib.lua_gettop(luaState); - string[] path = fullPath.Split(new char[] { '.' }); - - if(path.Length == 1) - { - translator.push(luaState, value); - LuaLib.lua_setglobal(luaState, fullPath); - } - else - { - LuaLib.lua_getglobal(luaState, path[0]); - string[] remainingPath = new string[path.Length-1]; - Array.Copy(path, 1, remainingPath, 0, path.Length-1); - setObject(remainingPath, value); - } - - LuaLib.lua_settop(luaState, oldTop); - - // Globals auto-complete - if(value.IsNull()) - { - // Remove now obsolete entries - globals.Remove(fullPath); - } - else - { - // Add new entries - if(!globals.Contains(fullPath)) - registerGlobal(fullPath, value.GetType(), 0); - } - } - } - - #region Globals auto-complete - /// - /// Adds an entry to (recursivley handles 2 levels of members) - /// - /// The index accessor path ot the entry - /// The type of the entry - /// How deep have we gone with recursion? - private void registerGlobal(string path, Type type, int recursionCounter) - { - // If the type is a global method, list it directly - if(type == typeof(LuaCore.lua_CFunction)) - { - // Format for easy method invocation - globals.Add(path + "("); - } - // If the type is a class or an interface and recursion hasn't been running too long, list the members - else if((type.IsClass || type.IsInterface) && type != typeof(string) && recursionCounter < 2) - { - #region Methods - foreach(var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance)) - { - if( - // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied - (method.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) && - (method.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0) && - // Exclude some generic .NET methods that wouldn't be very usefull in Lua - method.Name != "GetType" && method.Name != "GetHashCode" && method.Name != "Equals" && - method.Name != "ToString" && method.Name != "Clone" && method.Name != "Dispose" && - method.Name != "GetEnumerator" && method.Name != "CopyTo" && - !method.Name.StartsWith("get_", StringComparison.Ordinal) && - !method.Name.StartsWith("set_", StringComparison.Ordinal) && - !method.Name.StartsWith("add_", StringComparison.Ordinal) && - !method.Name.StartsWith("remove_", StringComparison.Ordinal)) - { - // Format for easy method invocation - string command = path + ":" + method.Name + "("; - - if(method.GetParameters().Length == 0) command += ")"; - globals.Add(command); - } - } - #endregion - - #region Fields - foreach(var field in type.GetFields(BindingFlags.Public | BindingFlags.Instance)) - { - if( - // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied - (field.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) && - (field.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0)) - { - // Go into recursion for members - registerGlobal(path + "." + field.Name, field.FieldType, recursionCounter + 1); - } - } - #endregion - - #region Properties - foreach(var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) - { - if( - // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied - (property.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) && - (property.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0) - // Exclude some generic .NET properties that wouldn't be very usefull in Lua - && property.Name != "Item") - { - // Go into recursion for members - registerGlobal(path + "." + property.Name, property.PropertyType, recursionCounter + 1); - } - } - #endregion - } - else - globals.Add(path); // Otherwise simply add the element to the list - - // List will need to be sorted on next access - globalsSorted = false; - } - #endregion - - /* - * Navigates a table in the top of the stack, returning - * the value of the specified field - */ - internal object getObject(string[] remainingPath) - { - object returnValue = null; - - for(int i = 0; i < remainingPath.Length; i++) - { - LuaLib.lua_pushstring(luaState, remainingPath[i]); - LuaLib.lua_gettable(luaState, -2); - returnValue = translator.getObject(luaState, -1); - - if(returnValue.IsNull()) - break; - } - - return returnValue; - } - - /* - * Gets a numeric global variable - */ - public double GetNumber(string fullPath) - { - return (double)this[fullPath]; - } - - /* - * Gets a string global variable - */ - public string GetString(string fullPath) - { - return this[fullPath].ToString(); - } - - /* - * Gets a table global variable - */ - public LuaTable GetTable(string fullPath) - { - return (LuaTable)this[fullPath]; - } - - /* - * Gets a table global variable as an object implementing - * the interfaceType interface - */ - public object GetTable(Type interfaceType, string fullPath) - { - return CodeGeneration.Instance.GetClassInstance(interfaceType, GetTable(fullPath)); - } - - /* - * Gets a function global variable - */ - public LuaFunction GetFunction(string fullPath) - { - object obj = this[fullPath]; - return (obj is LuaCore.lua_CFunction ? new LuaFunction((LuaCore.lua_CFunction)obj, this) : (LuaFunction)obj); - } - - /* - * Gets a function global variable as a delegate of - * type delegateType - */ - public Delegate GetFunction(Type delegateType, string fullPath) - { - return CodeGeneration.Instance.GetDelegate(delegateType, GetFunction(fullPath)); - } - - /* - * Calls the object as a function with the provided arguments, - * returning the function's returned values inside an array - */ - internal object[] callFunction(object function, object[] args) - { - return callFunction(function, args, null); - } - - /* - * Calls the object as a function with the provided arguments and - * casting returned values to the types in returnTypes before returning - * them in an array - */ - internal object[] callFunction(object function, object[] args, Type[] returnTypes) - { - int nArgs = 0; - int oldTop = LuaLib.lua_gettop(luaState); - - if(!LuaLib.lua_checkstack(luaState, args.Length+6)) - throw new LuaException("Lua stack overflow"); - - translator.push(luaState, function); - - if(!args.IsNull()) - { - nArgs = args.Length; - - for(int i = 0; i < args.Length; i++) - translator.push(luaState, args[i]); - } - - executing = true; - - try - { - int error = LuaLib.lua_pcall(luaState, nArgs, -1, 0); - if(error != 0) - ThrowExceptionFromError(oldTop); - } - finally - { - executing = false; - } - - return !returnTypes.IsNull() ? translator.popValues(luaState, oldTop, returnTypes) : translator.popValues(luaState, oldTop); - } - - /* - * Navigates a table to set the value of one of its fields - */ - internal void setObject(string[] remainingPath, object val) - { - for(int i = 0; i < remainingPath.Length-1; i++) - { - LuaLib.lua_pushstring(luaState, remainingPath[i]); - LuaLib.lua_gettable(luaState, -2); - } - - LuaLib.lua_pushstring(luaState, remainingPath[remainingPath.Length-1]); - translator.push(luaState, val); - LuaLib.lua_settable(luaState, -3); - } - - /* - * Creates a new table as a global variable or as a field - * inside an existing table - */ - public void NewTable(string fullPath) - { - string[] path = fullPath.Split(new char[] { '.' }); - int oldTop = LuaLib.lua_gettop(luaState); - - if(path.Length == 1) - { - LuaLib.lua_newtable(luaState); - LuaLib.lua_setglobal(luaState, fullPath); - } - else - { - LuaLib.lua_getglobal(luaState, path[0]); - - for(int i = 1; i < path.Length-1; i++) - { - LuaLib.lua_pushstring(luaState, path[i]); - LuaLib.lua_gettable(luaState, -2); - } - - LuaLib.lua_pushstring(luaState, path[path.Length-1]); - LuaLib.lua_newtable(luaState); - LuaLib.lua_settable(luaState, -3); - } - - LuaLib.lua_settop(luaState, oldTop); - } - - public ListDictionary GetTableDict(LuaTable table) - { - var dict = new ListDictionary(); - int oldTop = LuaLib.lua_gettop(luaState); - translator.push(luaState, table); - LuaLib.lua_pushnil(luaState); - - while(LuaLib.lua_next(luaState, -2) != 0) - { - dict[translator.getObject(luaState, -2)] = translator.getObject(luaState, -1); - LuaLib.lua_settop(luaState, -2); - } - - LuaLib.lua_settop(luaState, oldTop); - return dict; - } - - /* - * Lets go of a previously allocated reference to a table, function - * or userdata - */ - #region lua debug functions - /// - /// Activates the debug hook - /// - /// Mask - /// Count - /// see lua docs. -1 if hook is already set - /// Reinhard Ostermeier - public int SetDebugHook(EventMasks mask, int count) - { - if(hookCallback.IsNull()) - { - hookCallback = new LuaCore.lua_Hook(DebugHookCallback); - return LuaCore.lua_sethook(luaState, hookCallback, (int)mask, count); - } - - return -1; - } - - /// - /// Removes the debug hook - /// - /// see lua docs - /// Reinhard Ostermeier - public int RemoveDebugHook() - { - hookCallback = null; - return LuaCore.lua_sethook(luaState, null, 0, 0); - } - - /// - /// Gets the hook mask. - /// - /// hook mask - /// Reinhard Ostermeier - public EventMasks GetHookMask() - { - return (EventMasks)LuaCore.lua_gethookmask(luaState); - } - - /// - /// Gets the hook count - /// - /// see lua docs - /// Reinhard Ostermeier - public int GetHookCount() - { - return LuaCore.lua_gethookcount(luaState); - } - - /// - /// Gets the stack entry on a given level - /// - /// level - /// lua debug structure - /// Returns true if level was allowed, false if level was invalid. - /// Reinhard Ostermeier - /*public bool GetStack(int level, out LuaCore.lua_Debug luaDebug) - { - luaDebug = new LuaDebug(); - LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug)); - System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false); - try - { - return LuaLib.lua_getstack(luaState, level, luaDebug) != 0; - } - finally - { - luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug)); - System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); - } - }*/ - - /// - /// Gets info (see lua docs) - /// - /// what (see lua docs) - /// lua debug structure - /// see lua docs - /// Reinhard Ostermeier - /*public int GetInfo(String what, ref LuaCore.lua_Debug luaDebug) - { - LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug)); - System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false); - try - { - return LuaLib.lua_getinfo(luaState, what, ld); - } - finally - { - luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug)); - System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); - } - }*/ - - /// - /// Gets local (see lua docs) - /// - /// lua debug structure - /// see lua docs - /// see lua docs - /// Reinhard Ostermeier - public string GetLocal(LuaCore.lua_Debug luaDebug, int n) - { - try - { - return LuaCore.lua_getlocal(luaState, luaDebug, n).ToString(); - } - finally - { - //System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); - } - } - - /// - /// Sets local (see lua docs) - /// - /// lua debug structure - /// see lua docs - /// see lua docs - /// Reinhard Ostermeier - public string SetLocal(LuaCore.lua_Debug luaDebug, int n) - { - try - { - return LuaCore.lua_setlocal(luaState, luaDebug, n).ToString(); - } - finally - { - //System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); - } - } - - /// - /// Gets up value (see lua docs) - /// - /// see lua docs - /// see lua docs - /// see lua docs - /// Reinhard Ostermeier - public string GetUpValue(int funcindex, int n) - { - return LuaCore.lua_getupvalue(luaState, funcindex, n).ToString(); - } - - /// - /// Sets up value (see lua docs) - /// - /// see lua docs - /// see lua docs - /// see lua docs - /// Reinhard Ostermeier - public string SetUpValue(int funcindex, int n) - { - return LuaCore.lua_setupvalue(luaState, funcindex, n).ToString(); - } - - /// - /// Delegate that is called on lua hook callback - /// - /// lua state - /// Pointer to LuaDebug (lua_debug) structure - /// Reinhard Ostermeier - private void DebugHookCallback(LuaCore.lua_State luaState, LuaCore.lua_Debug luaDebug) - { - try - { - var temp = DebugHook; - - if(!temp.IsNull()) - temp(this, new DebugHookEventArgs(luaDebug)); - } - catch(Exception ex) - { - OnHookException(new HookExceptionEventArgs(ex)); - } - } - - private void OnHookException(HookExceptionEventArgs e) - { - var temp = HookException; - if(!temp.IsNull()) - temp(this, e); - } - - /// - /// Pops a value from the lua stack. - /// - /// Returns the top value from the lua stack. - /// Reinhard Ostermeier - public object Pop() - { - int top = LuaLib.lua_gettop(luaState); - return translator.popValues(luaState, top - 1)[0]; - } - - /// - /// Pushes a value onto the lua stack. - /// - /// Value to push. - /// Reinhard Ostermeier - public void Push(object value) - { - translator.push(luaState, value); - } - #endregion - - internal void dispose(int reference) - { - if(!luaState.IsNull()) //Fix submitted by Qingrui Li - LuaLib.lua_unref(luaState, reference); - } - - /* - * Gets a field of the table corresponding to the provided reference - * using rawget (do not use metatables) - */ - internal object rawGetObject(int reference, string field) - { - int oldTop = LuaLib.lua_gettop(luaState); - LuaLib.lua_getref(luaState, reference); - LuaLib.lua_pushstring(luaState, field); - LuaLib.lua_rawget(luaState, -2); - object obj = translator.getObject(luaState, -1); - LuaLib.lua_settop(luaState, oldTop); - return obj; - } - - /* - * Gets a field of the table or userdata corresponding to the provided reference - */ - internal object getObject(int reference, string field) - { - int oldTop = LuaLib.lua_gettop(luaState); - LuaLib.lua_getref(luaState, reference); - object returnValue = getObject(field.Split(new char[] {'.'})); - LuaLib.lua_settop(luaState, oldTop); - return returnValue; - } - - /* - * Gets a numeric field of the table or userdata corresponding the the provided reference - */ - - internal object getObject(int reference, object field) - { - int oldTop = LuaLib.lua_gettop(luaState); - LuaLib.lua_getref(luaState, reference); - translator.push(luaState, field); - LuaLib.lua_gettable(luaState, -2); - object returnValue = translator.getObject(luaState, -1); - LuaLib.lua_settop(luaState, oldTop); - return returnValue; - } - - /* - * Sets a field of the table or userdata corresponding the the provided reference - * to the provided value - */ - internal void setObject(int reference, string field, object val) - { - int oldTop = LuaLib.lua_gettop(luaState); - LuaLib.lua_getref(luaState, reference); - setObject(field.Split(new char[] {'.'}), val); - LuaLib.lua_settop(luaState, oldTop); - } - - /* - * Sets a numeric field of the table or userdata corresponding the the provided reference - * to the provided value - */ - internal void setObject(int reference, object field, object val) - { - int oldTop = LuaLib.lua_gettop(luaState); - LuaLib.lua_getref(luaState, reference); - translator.push(luaState, field); - translator.push(luaState, val); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_settop(luaState, oldTop); - } - - /* - * Registers an object's method as a Lua function (global or table field) - * The method may have any signature - */ - public LuaFunction RegisterFunction(string path, object target, MethodBase function /*MethodInfo function*/) //CP: Fix for struct constructor by Alexander Kappner (link: http://luaforge.net/forum/forum.php?thread_id = 2859&forum_id = 145) - { - // We leave nothing on the stack when we are done - int oldTop = LuaLib.lua_gettop(luaState); - var wrapper = new LuaMethodWrapper(translator, target, function.DeclaringType, function); - translator.push(luaState, new LuaCore.lua_CFunction(wrapper.call)); - this[path] = translator.getObject(luaState, -1); - var f = GetFunction(path); - LuaLib.lua_settop(luaState, oldTop); - return f; - } - - /* - * Compares the two values referenced by ref1 and ref2 for equality - */ - internal bool compareRef(int ref1, int ref2) - { - int top = LuaLib.lua_gettop(luaState); - LuaLib.lua_getref(luaState, ref1); - LuaLib.lua_getref(luaState, ref2); - int equal = LuaLib.lua_equal(luaState, -1, -2); - LuaLib.lua_settop(luaState, top); - return (equal != 0); - } - - internal void pushCSFunction(LuaCore.lua_CFunction function) - { - translator.pushFunction(luaState, function); - } - - #region IDisposable Members - public virtual void Dispose() - { - if(!translator.IsNull()) - { - translator.pendingEvents.Dispose(); - translator = null; - } - - this.Close(); - GC.Collect(); - GC.WaitForPendingFinalizers(); - } - #endregion - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.IO; +using System.Threading; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using LuaInterface.Event; +using LuaInterface.Method; +using LuaInterface.Exceptions; +using LuaInterface.Extensions; + +namespace LuaInterface +{ + using LuaCore = KopiLua.Lua; + + /* + * Main class of LuaInterface + * Object-oriented wrapper to Lua API + * + * Author: Fabio Mascarenhas + * Version: 1.0 + * + * // steffenj: important changes in Lua class: + * - removed all Open*Lib() functions + * - all libs automatically open in the Lua class constructor (just assign nil to unwanted libs) + * */ + [CLSCompliant(true)] + public class Lua : IDisposable + { + #region lua debug functions + /// + /// Event that is raised when an exception occures during a hook call. + /// + /// Reinhard Ostermeier + public event EventHandler HookException; + /// + /// Event when lua hook callback is called + /// + /// + /// Is only raised if SetDebugHook is called before. + /// + /// Reinhard Ostermeier + public event EventHandler DebugHook; + /// + /// lua hook calback delegate + /// + /// Reinhard Ostermeier + private LuaCore.lua_Hook hookCallback = null; + #endregion + #region Globals auto-complete + private readonly List globals = new List(); + private bool globalsSorted; + #endregion + private /*readonly */ LuaCore.lua_State luaState; + /// + /// True while a script is being executed + /// + public bool IsExecuting { get { return executing; } } + private LuaCore.lua_CFunction panicCallback; + private ObjectTranslator translator; + /// + /// Used to ensure multiple .net threads all get serialized by this single lock for access to the lua stack/objects + /// + //private object luaLock = new object(); + private bool _StatePassed; + private bool executing; + + static string init_luanet = + "local metatable = {} \n" + + "local import_type = luanet.import_type \n" + + "local load_assembly = luanet.load_assembly \n" + + " \n" + + "-- Lookup a .NET identifier component. \n" + + "function metatable:__index(key) -- key is e.g. \"Form\" \n" + + " -- Get the fully-qualified name, e.g. \"System.Windows.Forms.Form\" \n" + + " local fqn = ((rawget(self, \".fqn\") and rawget(self, \".fqn\") .. \n" + + " \".\") or \"\") .. key \n" + + " \n" + + " -- Try to find either a luanet function or a CLR type \n" + + " local obj = rawget(luanet, key) or import_type(fqn) \n" + + " \n" + + " -- If key is neither a luanet function or a CLR type, then it is simply \n" + + " -- an identifier component. \n" + + " if obj == nil then \n" + + " -- It might be an assembly, so we load it too. \n" + + " load_assembly(fqn) \n" + + " obj = { [\".fqn\"] = fqn } \n" + + " setmetatable(obj, metatable) \n" + + " end \n" + + " \n" + + " -- Cache this lookup \n" + + " rawset(self, key, obj) \n" + + " return obj \n" + + "end \n" + + " \n" + + "-- A non-type has been called; e.g. foo = System.Foo() \n" + + "function metatable:__call(...) \n" + + " error(\"No such type: \" .. rawget(self, \".fqn\"), 2) \n" + + "end \n" + + " \n" + + "-- This is the root of the .NET namespace \n" + + "luanet[\".fqn\"] = false \n" + + "setmetatable(luanet, metatable) \n" + + " \n" + + "-- Preload the mscorlib assembly \n" + + "luanet.load_assembly(\"mscorlib\") \n"; + + #region Globals auto-complete + /// + /// An alphabetically sorted list of all globals (objects, methods, etc.) externally added to this Lua instance + /// + /// Members of globals are also listed. The formatting is optimized for text input auto-completion. + public IEnumerable Globals + { + get + { + // Only sort list when necessary + if(!globalsSorted) + { + globals.Sort(); + globalsSorted = true; + } + + return globals; + } + } + #endregion + + public Lua() + { + luaState = LuaLib.luaL_newstate(); // steffenj: Lua 5.1.1 API change (lua_open is gone) + //LuaLib.luaopen_base(luaState); // steffenj: luaopen_* no longer used + LuaLib.luaL_openlibs(luaState); // steffenj: Lua 5.1.1 API change (luaopen_base is gone, just open all libs right here) + LuaLib.lua_pushstring(luaState, "LUAINTERFACE LOADED"); + LuaLib.lua_pushboolean(luaState, true); + LuaLib.lua_settable(luaState, (int)LuaIndexes.Registry); + LuaLib.lua_newtable(luaState); + LuaLib.lua_setglobal(luaState, "luanet"); + LuaLib.lua_pushvalue(luaState, (int)LuaIndexes.Globals); + LuaLib.lua_getglobal(luaState, "luanet"); + LuaLib.lua_pushstring(luaState, "getmetatable"); + LuaLib.lua_getglobal(luaState, "getmetatable"); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_replace(luaState, (int)LuaIndexes.Globals); + translator = new ObjectTranslator(this, luaState); + LuaLib.lua_replace(luaState, (int)LuaIndexes.Globals); + LuaLib.luaL_dostring(luaState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring + + // We need to keep this in a managed reference so the delegate doesn't get garbage collected + panicCallback = new LuaCore.lua_CFunction(PanicCallback); + LuaLib.lua_atpanic(luaState, panicCallback); + + //LuaLib.lua_atlock(luaState, lockCallback = new LuaCore.lua_CFunction(LockCallback)); + //LuaLib.lua_atunlock(luaState, unlockCallback = new LuaCore.lua_CFunction(UnlockCallback)); + } + + /* + * CAUTION: LuaInterface.Lua instances can't share the same lua state! + */ + public Lua(LuaCore.lua_State lState) + { + LuaLib.lua_pushstring(lState, "LUAINTERFACE LOADED"); + LuaLib.lua_gettable(lState, (int)LuaIndexes.Registry); + + if(LuaLib.lua_toboolean(lState, -1)) + { + LuaLib.lua_settop(lState, -2); + throw new LuaException("There is already a LuaInterface.Lua instance associated with this Lua state"); + } + else + { + LuaLib.lua_settop(lState, -2); + LuaLib.lua_pushstring(lState, "LUAINTERFACE LOADED"); + LuaLib.lua_pushboolean(lState, true); + LuaLib.lua_settable(lState, (int)LuaIndexes.Registry); + luaState = lState; + LuaLib.lua_pushvalue(lState, (int)LuaIndexes.Globals); + LuaLib.lua_getglobal(lState, "luanet"); + LuaLib.lua_pushstring(lState, "getmetatable"); + LuaLib.lua_getglobal(lState, "getmetatable"); + LuaLib.lua_settable(lState, -3); + LuaLib.lua_replace(lState, (int)LuaIndexes.Globals); + translator = new ObjectTranslator(this, luaState); + LuaLib.lua_replace(lState, (int)LuaIndexes.Globals); + LuaLib.luaL_dostring(lState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring + } + + _StatePassed = true; + } + + /// + /// Called for each lua_lock call + /// + /// + /// Not yet used + /*int LockCallback(LuaCore.lua_State luaState) + { + // Monitor.Enter(luaLock); + return 0; + }*/ + + /// + /// Called for each lua_unlock call + /// + /// + /// Not yet used + /*int UnlockCallback(LuaCore.lua_State luaState) + { + // Monitor.Exit(luaLock); + return 0; + }*/ + + public void Close() + { + if(_StatePassed) + return; + + ////// if(luaState != LuaCore.lua_State.Zero) + if(!luaState.IsNull()) + LuaCore.lua_close(luaState); + //luaState = LuaCore.lua_State.Zero; <- suggested by Christopher Cebulski http://luaforge.net/forum/forum.php?thread_id = 44593&forum_id = 146 + } + + static int PanicCallback(LuaCore.lua_State luaState) + { + // string desc = LuaLib.lua_tostring(luaState, 1); + string reason = string.Format("unprotected error in call to Lua API ({0})", LuaLib.lua_tostring(luaState, -1)); + // lua_tostring(L, -1); + throw new LuaException(reason); + } + + /// + /// Assuming we have a Lua error string sitting on the stack, throw a C# exception out to the user's app + /// + /// Thrown if the script caused an exception + private void ThrowExceptionFromError(int oldTop) + { + object err = translator.getObject(luaState, -1); + LuaLib.lua_settop(luaState, oldTop); + + // A pre-wrapped exception - just rethrow it (stack trace of InnerException will be preserved) + var luaEx = err as LuaScriptException; + + if(!luaEx.IsNull()) + throw luaEx; + + // A non-wrapped Lua error (best interpreted as a string) - wrap it and throw it + if(err.IsNull()) + err = "Unknown Lua Error"; + + throw new LuaScriptException(err.ToString(), string.Empty); + } + + /// + /// Convert C# exceptions into Lua errors + /// + /// num of things on stack + /// null for no pending exception + internal int SetPendingException(Exception e) + { + var caughtExcept = e; + + if(!caughtExcept.IsNull()) + { + translator.throwError(luaState, caughtExcept); + LuaLib.lua_pushnil(luaState); + return 1; + } + else + return 0; + } + + /// + /// + /// + /// + /// + /// + public LuaFunction LoadString(string chunk, string name) + { + int oldTop = LuaLib.lua_gettop(luaState); + executing = true; + + try + { + if(LuaLib.luaL_loadbuffer(luaState, chunk, name) != 0) + ThrowExceptionFromError(oldTop); + } + finally + { + executing = false; + } + + var result = translator.getFunction(luaState, -1); + translator.popValues(luaState, oldTop); + return result; + } + + /// + /// + /// + /// + /// + public LuaFunction LoadFile(string fileName) + { + int oldTop = LuaLib.lua_gettop(luaState); + + if(LuaLib.luaL_loadfile(luaState, fileName) != 0) + ThrowExceptionFromError(oldTop); + + var result = translator.getFunction(luaState, -1); + translator.popValues(luaState, oldTop); + return result; + } + + /* + * Excutes a Lua chunk and returns all the chunk's return + * values in an array + */ + public object[] DoString(string chunk) + { + int oldTop = LuaLib.lua_gettop(luaState); + + if(LuaLib.luaL_loadbuffer(luaState, chunk, "chunk") == 0) + { + executing = true; + + try + { + if(LuaLib.lua_pcall(luaState, 0, -1, 0) == 0) + return translator.popValues(luaState, oldTop); + else + ThrowExceptionFromError(oldTop); + } + finally + { + executing = false; + } + } + else + ThrowExceptionFromError(oldTop); + + return null; // Never reached - keeps compiler happy + } + + /// + /// Executes a Lua chnk and returns all the chunk's return values in an array. + /// + /// Chunk to execute + /// Name to associate with the chunk + /// + public object[] DoString(string chunk, string chunkName) + { + int oldTop = LuaLib.lua_gettop(luaState); + executing = true; + + if(LuaLib.luaL_loadbuffer(luaState, chunk, chunkName) == 0) + { + try + { + if(LuaLib.lua_pcall(luaState, 0, -1, 0) == 0) + return translator.popValues(luaState, oldTop); + else + ThrowExceptionFromError(oldTop); + } + finally + { + executing = false; + } + } + else + ThrowExceptionFromError(oldTop); + + return null; // Never reached - keeps compiler happy + } + + /* + * Excutes a Lua file and returns all the chunk's return + * values in an array + */ + public object[] DoFile(string fileName) + { + int oldTop = LuaLib.lua_gettop(luaState); + + if(LuaLib.luaL_loadfile(luaState, fileName) == 0) + { + executing = true; + + try + { + if(LuaLib.lua_pcall(luaState, 0, -1, 0) == 0) + return translator.popValues(luaState, oldTop); + else + ThrowExceptionFromError(oldTop); + } + finally + { + executing = false; + } + } + else + ThrowExceptionFromError(oldTop); + + return null; // Never reached - keeps compiler happy + } + + + /* + * Indexer for global variables from the LuaInterpreter + * Supports navigation of tables by using . operator + */ + public object this[string fullPath] + { + get + { + object returnValue = null; + int oldTop = LuaLib.lua_gettop(luaState); + string[] path = fullPath.Split(new char[] { '.' }); + LuaLib.lua_getglobal(luaState, path[0]); + returnValue = translator.getObject(luaState, -1); + + if(path.Length>1) + { + string[] remainingPath = new string[path.Length-1]; + Array.Copy(path, 1, remainingPath, 0, path.Length-1); + returnValue = getObject(remainingPath); + } + + LuaLib.lua_settop(luaState, oldTop); + return returnValue; + } + set + { + int oldTop = LuaLib.lua_gettop(luaState); + string[] path = fullPath.Split(new char[] { '.' }); + + if(path.Length == 1) + { + translator.push(luaState, value); + LuaLib.lua_setglobal(luaState, fullPath); + } + else + { + LuaLib.lua_getglobal(luaState, path[0]); + string[] remainingPath = new string[path.Length-1]; + Array.Copy(path, 1, remainingPath, 0, path.Length-1); + setObject(remainingPath, value); + } + + LuaLib.lua_settop(luaState, oldTop); + + // Globals auto-complete + if(value.IsNull()) + { + // Remove now obsolete entries + globals.Remove(fullPath); + } + else + { + // Add new entries + if(!globals.Contains(fullPath)) + registerGlobal(fullPath, value.GetType(), 0); + } + } + } + + #region Globals auto-complete + /// + /// Adds an entry to (recursivley handles 2 levels of members) + /// + /// The index accessor path ot the entry + /// The type of the entry + /// How deep have we gone with recursion? + private void registerGlobal(string path, Type type, int recursionCounter) + { + // If the type is a global method, list it directly + if(type == typeof(LuaCore.lua_CFunction)) + { + // Format for easy method invocation + globals.Add(path + "("); + } + // If the type is a class or an interface and recursion hasn't been running too long, list the members + else if((type.IsClass || type.IsInterface) && type != typeof(string) && recursionCounter < 2) + { + #region Methods + foreach(var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance)) + { + if( + // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied + (method.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) && + (method.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0) && + // Exclude some generic .NET methods that wouldn't be very usefull in Lua + method.Name != "GetType" && method.Name != "GetHashCode" && method.Name != "Equals" && + method.Name != "ToString" && method.Name != "Clone" && method.Name != "Dispose" && + method.Name != "GetEnumerator" && method.Name != "CopyTo" && + !method.Name.StartsWith("get_", StringComparison.Ordinal) && + !method.Name.StartsWith("set_", StringComparison.Ordinal) && + !method.Name.StartsWith("add_", StringComparison.Ordinal) && + !method.Name.StartsWith("remove_", StringComparison.Ordinal)) + { + // Format for easy method invocation + string command = path + ":" + method.Name + "("; + + if(method.GetParameters().Length == 0) command += ")"; + globals.Add(command); + } + } + #endregion + + #region Fields + foreach(var field in type.GetFields(BindingFlags.Public | BindingFlags.Instance)) + { + if( + // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied + (field.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) && + (field.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0)) + { + // Go into recursion for members + registerGlobal(path + "." + field.Name, field.FieldType, recursionCounter + 1); + } + } + #endregion + + #region Properties + foreach(var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) + { + if( + // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied + (property.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) && + (property.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0) + // Exclude some generic .NET properties that wouldn't be very usefull in Lua + && property.Name != "Item") + { + // Go into recursion for members + registerGlobal(path + "." + property.Name, property.PropertyType, recursionCounter + 1); + } + } + #endregion + } + else + globals.Add(path); // Otherwise simply add the element to the list + + // List will need to be sorted on next access + globalsSorted = false; + } + #endregion + + /* + * Navigates a table in the top of the stack, returning + * the value of the specified field + */ + internal object getObject(string[] remainingPath) + { + object returnValue = null; + + for(int i = 0; i < remainingPath.Length; i++) + { + LuaLib.lua_pushstring(luaState, remainingPath[i]); + LuaLib.lua_gettable(luaState, -2); + returnValue = translator.getObject(luaState, -1); + + if(returnValue.IsNull()) + break; + } + + return returnValue; + } + + /* + * Gets a numeric global variable + */ + public double GetNumber(string fullPath) + { + return (double)this[fullPath]; + } + + /* + * Gets a string global variable + */ + public string GetString(string fullPath) + { + return this[fullPath].ToString(); + } + + /* + * Gets a table global variable + */ + public LuaTable GetTable(string fullPath) + { + return (LuaTable)this[fullPath]; + } + + /* + * Gets a table global variable as an object implementing + * the interfaceType interface + */ + public object GetTable(Type interfaceType, string fullPath) + { + return CodeGeneration.Instance.GetClassInstance(interfaceType, GetTable(fullPath)); + } + + /* + * Gets a function global variable + */ + public LuaFunction GetFunction(string fullPath) + { + object obj = this[fullPath]; + return (obj is LuaCore.lua_CFunction ? new LuaFunction((LuaCore.lua_CFunction)obj, this) : (LuaFunction)obj); + } + + /* + * Gets a function global variable as a delegate of + * type delegateType + */ + public Delegate GetFunction(Type delegateType, string fullPath) + { + return CodeGeneration.Instance.GetDelegate(delegateType, GetFunction(fullPath)); + } + + /* + * Calls the object as a function with the provided arguments, + * returning the function's returned values inside an array + */ + internal object[] callFunction(object function, object[] args) + { + return callFunction(function, args, null); + } + + /* + * Calls the object as a function with the provided arguments and + * casting returned values to the types in returnTypes before returning + * them in an array + */ + internal object[] callFunction(object function, object[] args, Type[] returnTypes) + { + int nArgs = 0; + int oldTop = LuaLib.lua_gettop(luaState); + + if(!LuaLib.lua_checkstack(luaState, args.Length+6)) + throw new LuaException("Lua stack overflow"); + + translator.push(luaState, function); + + if(!args.IsNull()) + { + nArgs = args.Length; + + for(int i = 0; i < args.Length; i++) + translator.push(luaState, args[i]); + } + + executing = true; + + try + { + int error = LuaLib.lua_pcall(luaState, nArgs, -1, 0); + if(error != 0) + ThrowExceptionFromError(oldTop); + } + finally + { + executing = false; + } + + return !returnTypes.IsNull() ? translator.popValues(luaState, oldTop, returnTypes) : translator.popValues(luaState, oldTop); + } + + /* + * Navigates a table to set the value of one of its fields + */ + internal void setObject(string[] remainingPath, object val) + { + for(int i = 0; i < remainingPath.Length-1; i++) + { + LuaLib.lua_pushstring(luaState, remainingPath[i]); + LuaLib.lua_gettable(luaState, -2); + } + + LuaLib.lua_pushstring(luaState, remainingPath[remainingPath.Length-1]); + translator.push(luaState, val); + LuaLib.lua_settable(luaState, -3); + } + + /* + * Creates a new table as a global variable or as a field + * inside an existing table + */ + public void NewTable(string fullPath) + { + string[] path = fullPath.Split(new char[] { '.' }); + int oldTop = LuaLib.lua_gettop(luaState); + + if(path.Length == 1) + { + LuaLib.lua_newtable(luaState); + LuaLib.lua_setglobal(luaState, fullPath); + } + else + { + LuaLib.lua_getglobal(luaState, path[0]); + + for(int i = 1; i < path.Length-1; i++) + { + LuaLib.lua_pushstring(luaState, path[i]); + LuaLib.lua_gettable(luaState, -2); + } + + LuaLib.lua_pushstring(luaState, path[path.Length-1]); + LuaLib.lua_newtable(luaState); + LuaLib.lua_settable(luaState, -3); + } + + LuaLib.lua_settop(luaState, oldTop); + } + + public ListDictionary GetTableDict(LuaTable table) + { + var dict = new ListDictionary(); + int oldTop = LuaLib.lua_gettop(luaState); + translator.push(luaState, table); + LuaLib.lua_pushnil(luaState); + + while(LuaLib.lua_next(luaState, -2) != 0) + { + dict[translator.getObject(luaState, -2)] = translator.getObject(luaState, -1); + LuaLib.lua_settop(luaState, -2); + } + + LuaLib.lua_settop(luaState, oldTop); + return dict; + } + + /* + * Lets go of a previously allocated reference to a table, function + * or userdata + */ + #region lua debug functions + /// + /// Activates the debug hook + /// + /// Mask + /// Count + /// see lua docs. -1 if hook is already set + /// Reinhard Ostermeier + public int SetDebugHook(EventMasks mask, int count) + { + if(hookCallback.IsNull()) + { + hookCallback = new LuaCore.lua_Hook(DebugHookCallback); + return LuaCore.lua_sethook(luaState, hookCallback, (int)mask, count); + } + + return -1; + } + + /// + /// Removes the debug hook + /// + /// see lua docs + /// Reinhard Ostermeier + public int RemoveDebugHook() + { + hookCallback = null; + return LuaCore.lua_sethook(luaState, null, 0, 0); + } + + /// + /// Gets the hook mask. + /// + /// hook mask + /// Reinhard Ostermeier + public EventMasks GetHookMask() + { + return (EventMasks)LuaCore.lua_gethookmask(luaState); + } + + /// + /// Gets the hook count + /// + /// see lua docs + /// Reinhard Ostermeier + public int GetHookCount() + { + return LuaCore.lua_gethookcount(luaState); + } + + /// + /// Gets the stack entry on a given level + /// + /// level + /// lua debug structure + /// Returns true if level was allowed, false if level was invalid. + /// Reinhard Ostermeier + /*public bool GetStack(int level, out LuaCore.lua_Debug luaDebug) + { + luaDebug = new LuaDebug(); + LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug)); + System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false); + try + { + return LuaLib.lua_getstack(luaState, level, luaDebug) != 0; + } + finally + { + luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug)); + System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); + } + }*/ + + /// + /// Gets info (see lua docs) + /// + /// what (see lua docs) + /// lua debug structure + /// see lua docs + /// Reinhard Ostermeier + /*public int GetInfo(String what, ref LuaCore.lua_Debug luaDebug) + { + LuaCore.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug)); + System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false); + try + { + return LuaLib.lua_getinfo(luaState, what, ld); + } + finally + { + luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug)); + System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); + } + }*/ + + /// + /// Gets local (see lua docs) + /// + /// lua debug structure + /// see lua docs + /// see lua docs + /// Reinhard Ostermeier + public string GetLocal(LuaCore.lua_Debug luaDebug, int n) + { + try + { + return LuaCore.lua_getlocal(luaState, luaDebug, n).ToString(); + } + finally + { + //System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); + } + } + + /// + /// Sets local (see lua docs) + /// + /// lua debug structure + /// see lua docs + /// see lua docs + /// Reinhard Ostermeier + public string SetLocal(LuaCore.lua_Debug luaDebug, int n) + { + try + { + return LuaCore.lua_setlocal(luaState, luaDebug, n).ToString(); + } + finally + { + //System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); + } + } + + /// + /// Gets up value (see lua docs) + /// + /// see lua docs + /// see lua docs + /// see lua docs + /// Reinhard Ostermeier + public string GetUpValue(int funcindex, int n) + { + return LuaCore.lua_getupvalue(luaState, funcindex, n).ToString(); + } + + /// + /// Sets up value (see lua docs) + /// + /// see lua docs + /// see lua docs + /// see lua docs + /// Reinhard Ostermeier + public string SetUpValue(int funcindex, int n) + { + return LuaCore.lua_setupvalue(luaState, funcindex, n).ToString(); + } + + /// + /// Delegate that is called on lua hook callback + /// + /// lua state + /// Pointer to LuaDebug (lua_debug) structure + /// Reinhard Ostermeier + private void DebugHookCallback(LuaCore.lua_State luaState, LuaCore.lua_Debug luaDebug) + { + try + { + var temp = DebugHook; + + if(!temp.IsNull()) + temp(this, new DebugHookEventArgs(luaDebug)); + } + catch(Exception ex) + { + OnHookException(new HookExceptionEventArgs(ex)); + } + } + + private void OnHookException(HookExceptionEventArgs e) + { + var temp = HookException; + if(!temp.IsNull()) + temp(this, e); + } + + /// + /// Pops a value from the lua stack. + /// + /// Returns the top value from the lua stack. + /// Reinhard Ostermeier + public object Pop() + { + int top = LuaLib.lua_gettop(luaState); + return translator.popValues(luaState, top - 1)[0]; + } + + /// + /// Pushes a value onto the lua stack. + /// + /// Value to push. + /// Reinhard Ostermeier + public void Push(object value) + { + translator.push(luaState, value); + } + #endregion + + internal void dispose(int reference) + { + if(!luaState.IsNull()) //Fix submitted by Qingrui Li + LuaLib.lua_unref(luaState, reference); + } + + /* + * Gets a field of the table corresponding to the provided reference + * using rawget (do not use metatables) + */ + internal object rawGetObject(int reference, string field) + { + int oldTop = LuaLib.lua_gettop(luaState); + LuaLib.lua_getref(luaState, reference); + LuaLib.lua_pushstring(luaState, field); + LuaLib.lua_rawget(luaState, -2); + object obj = translator.getObject(luaState, -1); + LuaLib.lua_settop(luaState, oldTop); + return obj; + } + + /* + * Gets a field of the table or userdata corresponding to the provided reference + */ + internal object getObject(int reference, string field) + { + int oldTop = LuaLib.lua_gettop(luaState); + LuaLib.lua_getref(luaState, reference); + object returnValue = getObject(field.Split(new char[] {'.'})); + LuaLib.lua_settop(luaState, oldTop); + return returnValue; + } + + /* + * Gets a numeric field of the table or userdata corresponding the the provided reference + */ + + internal object getObject(int reference, object field) + { + int oldTop = LuaLib.lua_gettop(luaState); + LuaLib.lua_getref(luaState, reference); + translator.push(luaState, field); + LuaLib.lua_gettable(luaState, -2); + object returnValue = translator.getObject(luaState, -1); + LuaLib.lua_settop(luaState, oldTop); + return returnValue; + } + + /* + * Sets a field of the table or userdata corresponding the the provided reference + * to the provided value + */ + internal void setObject(int reference, string field, object val) + { + int oldTop = LuaLib.lua_gettop(luaState); + LuaLib.lua_getref(luaState, reference); + setObject(field.Split(new char[] {'.'}), val); + LuaLib.lua_settop(luaState, oldTop); + } + + /* + * Sets a numeric field of the table or userdata corresponding the the provided reference + * to the provided value + */ + internal void setObject(int reference, object field, object val) + { + int oldTop = LuaLib.lua_gettop(luaState); + LuaLib.lua_getref(luaState, reference); + translator.push(luaState, field); + translator.push(luaState, val); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_settop(luaState, oldTop); + } + + /* + * Registers an object's method as a Lua function (global or table field) + * The method may have any signature + */ + public LuaFunction RegisterFunction(string path, object target, MethodBase function /*MethodInfo function*/) //CP: Fix for struct constructor by Alexander Kappner (link: http://luaforge.net/forum/forum.php?thread_id = 2859&forum_id = 145) + { + // We leave nothing on the stack when we are done + int oldTop = LuaLib.lua_gettop(luaState); + var wrapper = new LuaMethodWrapper(translator, target, function.DeclaringType, function); + translator.push(luaState, new LuaCore.lua_CFunction(wrapper.call)); + this[path] = translator.getObject(luaState, -1); + var f = GetFunction(path); + LuaLib.lua_settop(luaState, oldTop); + return f; + } + + /* + * Compares the two values referenced by ref1 and ref2 for equality + */ + internal bool compareRef(int ref1, int ref2) + { + int top = LuaLib.lua_gettop(luaState); + LuaLib.lua_getref(luaState, ref1); + LuaLib.lua_getref(luaState, ref2); + int equal = LuaLib.lua_equal(luaState, -1, -2); + LuaLib.lua_settop(luaState, top); + return (equal != 0); + } + + internal void pushCSFunction(LuaCore.lua_CFunction function) + { + translator.pushFunction(luaState, function); + } + + #region IDisposable Members + public virtual void Dispose() + { + if(!translator.IsNull()) + { + translator.pendingEvents.Dispose(); + translator = null; + } + + this.Close(); + GC.Collect(); + GC.WaitForPendingFinalizers(); + } + #endregion + } } \ No newline at end of file diff --git a/Core/LuaInterface/LuaBase.cs b/Core/LuaInterface/LuaBase.cs index 0cb2e3cd19a87233629618b20060ab21d5e38135..303d958e4cdd102f9ff8a10f61a24f2062d797b1 100644 --- a/Core/LuaInterface/LuaBase.cs +++ b/Core/LuaInterface/LuaBase.cs @@ -1,85 +1,85 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Text; -using System.Collections.Generic; - -namespace LuaInterface -{ - /// - /// Base class to provide consistent disposal flow across lua objects. Uses code provided by Yves Duhoux and suggestions by Hans Schmeidenbacher and Qingrui Li - /// - public abstract class LuaBase : IDisposable - { - private bool _Disposed; - [CLSCompliantAttribute(false)] - protected int _Reference; - [CLSCompliantAttribute(false)] - protected Lua _Interpreter; - - ~LuaBase() - { - Dispose(false); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - public virtual void Dispose(bool disposeManagedResources) - { - if(!_Disposed) - { - if(disposeManagedResources) - { - if(_Reference != 0) - _Interpreter.dispose(_Reference); - } - - _Interpreter = null; - _Disposed = true; - } - } - - public override bool Equals(object o) - { - if(o is LuaBase) - { - var l = (LuaBase)o; - return _Interpreter.compareRef(l._Reference, _Reference); - } - else - return false; - } - - public override int GetHashCode() - { - return _Reference; - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Text; +using System.Collections.Generic; + +namespace LuaInterface +{ + /// + /// Base class to provide consistent disposal flow across lua objects. Uses code provided by Yves Duhoux and suggestions by Hans Schmeidenbacher and Qingrui Li + /// + public abstract class LuaBase : IDisposable + { + private bool _Disposed; + [CLSCompliantAttribute(false)] + protected int _Reference; + [CLSCompliantAttribute(false)] + protected Lua _Interpreter; + + ~LuaBase() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public virtual void Dispose(bool disposeManagedResources) + { + if(!_Disposed) + { + if(disposeManagedResources) + { + if(_Reference != 0) + _Interpreter.dispose(_Reference); + } + + _Interpreter = null; + _Disposed = true; + } + } + + public override bool Equals(object o) + { + if(o is LuaBase) + { + var l = (LuaBase)o; + return _Interpreter.compareRef(l._Reference, _Reference); + } + else + return false; + } + + public override int GetHashCode() + { + return _Reference; + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/LuaFunction.cs b/Core/LuaInterface/LuaFunction.cs index c8e4dd927fea9b76a145eb21ec4e6d9b4aaa20e3..79d3985fd166a2bcead33a13cb8e236780e529bb 100644 --- a/Core/LuaInterface/LuaFunction.cs +++ b/Core/LuaInterface/LuaFunction.cs @@ -1,106 +1,106 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Text; -using System.Collections.Generic; - -namespace LuaInterface -{ - using LuaCore = KopiLua.Lua; - - public class LuaFunction : LuaBase - { - internal LuaCore.lua_CFunction function; - - public LuaFunction(int reference, Lua interpreter) - { - _Reference = reference; - this.function = null; - _Interpreter = interpreter; - } - - public LuaFunction(LuaCore.lua_CFunction function, Lua interpreter) - { - _Reference = 0; - this.function = function; - _Interpreter = interpreter; - } - - /* - * Calls the function casting return values to the types - * in returnTypes - */ - internal object[] call(object[] args, Type[] returnTypes) - { - return _Interpreter.callFunction(this, args, returnTypes); - } - - /* - * Calls the function and returns its return values inside - * an array - */ - public object[] Call(params object[] args) - { - return _Interpreter.callFunction(this, args); - } - - /* - * Pushes the function into the Lua stack - */ - internal void push(LuaCore.lua_State luaState) - { - if(_Reference != 0) - LuaLib.lua_getref(luaState, _Reference); - else - _Interpreter.pushCSFunction(function); - } - - public override string ToString() - { - return "function"; - } - - public override bool Equals(object o) - { - if(o is LuaFunction) - { - var l = (LuaFunction)o; - - if(this._Reference != 0 && l._Reference != 0) - return _Interpreter.compareRef(l._Reference, this._Reference); - else - return this.function == l.function; - } - else - return false; - } - - public override int GetHashCode() - { - return _Reference != 0 ? _Reference : function.GetHashCode(); - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Text; +using System.Collections.Generic; + +namespace LuaInterface +{ + using LuaCore = KopiLua.Lua; + + public class LuaFunction : LuaBase + { + internal LuaCore.lua_CFunction function; + + public LuaFunction(int reference, Lua interpreter) + { + _Reference = reference; + this.function = null; + _Interpreter = interpreter; + } + + public LuaFunction(LuaCore.lua_CFunction function, Lua interpreter) + { + _Reference = 0; + this.function = function; + _Interpreter = interpreter; + } + + /* + * Calls the function casting return values to the types + * in returnTypes + */ + internal object[] call(object[] args, Type[] returnTypes) + { + return _Interpreter.callFunction(this, args, returnTypes); + } + + /* + * Calls the function and returns its return values inside + * an array + */ + public object[] Call(params object[] args) + { + return _Interpreter.callFunction(this, args); + } + + /* + * Pushes the function into the Lua stack + */ + internal void push(LuaCore.lua_State luaState) + { + if(_Reference != 0) + LuaLib.lua_getref(luaState, _Reference); + else + _Interpreter.pushCSFunction(function); + } + + public override string ToString() + { + return "function"; + } + + public override bool Equals(object o) + { + if(o is LuaFunction) + { + var l = (LuaFunction)o; + + if(this._Reference != 0 && l._Reference != 0) + return _Interpreter.compareRef(l._Reference, this._Reference); + else + return this.function == l.function; + } + else + return false; + } + + public override int GetHashCode() + { + return _Reference != 0 ? _Reference : function.GetHashCode(); + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/LuaGlobalAttribute.cs b/Core/LuaInterface/LuaGlobalAttribute.cs index 92191c44bad7c95a9cf22be45e9ac616e18da11a..825802c1b910c540b3c3ce567f62cbb345fde990 100644 --- a/Core/LuaInterface/LuaGlobalAttribute.cs +++ b/Core/LuaInterface/LuaGlobalAttribute.cs @@ -1,48 +1,48 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface -{ - /// - /// Marks a method for global usage in Lua scripts - /// - /// - /// - [AttributeUsage(AttributeTargets.Method)] - public sealed class LuaGlobalAttribute : Attribute - { - /// - /// An alternative name to use for calling the function in Lua - leave empty for CLR name - /// - public string Name { get; set; } - - /// - /// A description of the function - /// - public string Description { get; set; } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface +{ + /// + /// Marks a method for global usage in Lua scripts + /// + /// + /// + [AttributeUsage(AttributeTargets.Method)] + public sealed class LuaGlobalAttribute : Attribute + { + /// + /// An alternative name to use for calling the function in Lua - leave empty for CLR name + /// + public string Name { get; set; } + + /// + /// A description of the function + /// + public string Description { get; set; } + } } \ No newline at end of file diff --git a/Core/LuaInterface/LuaHideAttribute.cs b/Core/LuaInterface/LuaHideAttribute.cs index 55f83379f95f8d8bc36d0fd29bc3a5db74960529..20514f05983a7cb5905db56afd3324c66e6ca73f 100644 --- a/Core/LuaInterface/LuaHideAttribute.cs +++ b/Core/LuaInterface/LuaHideAttribute.cs @@ -1,37 +1,37 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface -{ - /// - /// Marks a method, field or property to be hidden from Lua auto-completion - /// - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] - public sealed class LuaHideAttribute : Attribute - { - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface +{ + /// + /// Marks a method, field or property to be hidden from Lua auto-completion + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)] + public sealed class LuaHideAttribute : Attribute + { + } } \ No newline at end of file diff --git a/Core/LuaInterface/LuaInterface.csproj b/Core/LuaInterface/LuaInterface.csproj index 48f0e947ef8ba498c986ca525cfbaefc32802b9e..68882cc26346aac0d803064fdbb2974489d17560 100644 --- a/Core/LuaInterface/LuaInterface.csproj +++ b/Core/LuaInterface/LuaInterface.csproj @@ -1,122 +1,122 @@ - - - - Debug - x86 - 9.0.21022 - 2.0 - {F55CABBB-4108-4A39-94E1-581FD46DC021} - Library - Properties - LuaInterface - LuaInterface - 2.x - - - true - full - false - ..\..\Run\Debug - DEBUG - prompt - 4 - x86 - - - none - true - ..\..\Run\Release - RELEASE - prompt - 4 - x86 - - - true - full - false - ..\..\Run\Debug_x64 - DEBUG - prompt - 4 - x64 - - - none - true - ..\..\Run\Release_x64 - RELEASE - prompt - 4 - x64 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {E8DDBC21-EF74-4ABA-9C49-BFC702BE25D8} - KopiLua - - - - - - - - - - - + + + + Debug + x86 + 9.0.21022 + 2.0 + {F55CABBB-4108-4A39-94E1-581FD46DC021} + Library + Properties + LuaInterface + LuaInterface + 2.x + + + true + full + false + ..\..\Run\Debug + DEBUG + prompt + 4 + x86 + + + none + true + ..\..\Run\Release + RELEASE + prompt + 4 + x86 + + + true + full + false + ..\..\Run\Debug_x64 + DEBUG + prompt + 4 + x64 + + + none + true + ..\..\Run\Release_x64 + RELEASE + prompt + 4 + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {E8DDBC21-EF74-4ABA-9C49-BFC702BE25D8} + KopiLua + + + + + + + + + + + diff --git a/Core/LuaInterface/LuaLib/LuaEnums.cs b/Core/LuaInterface/LuaLib/LuaEnums.cs index 6875e482d2f8b541a0322205d5890138083fd8f4..8178065517ce71e95d44d46baa730fc9bcf62a70 100644 --- a/Core/LuaInterface/LuaLib/LuaEnums.cs +++ b/Core/LuaInterface/LuaLib/LuaEnums.cs @@ -1,76 +1,76 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2009 Joshua Simmons - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface -{ - /// - /// Enumeration of basic lua globals. - /// - public enum LuaEnums : int - { - /// - /// Option for multiple returns in `lua_pcall' and `lua_call' - /// - MultiRet = -1, - - /// - /// Everything is OK. - /// - Ok = 0, - - /// - /// Thread status, Ok or Yield - /// - Yield = 1, - - /// - /// A Runtime error. - /// - ErrorRun = 2, - - /// - /// A syntax error. - /// - ErrorSyntax = 3, - - /// - /// A memory allocation error. For such errors, Lua does not call the error handler function. - /// - ErrorMemory = 4, - - /// - /// An error in the error handling function. - /// - ErrorError = 5, - - /// - /// An extra error for file load errors when using luaL_loadfile. - /// - ErrorFile = 6 - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2009 Joshua Simmons + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface +{ + /// + /// Enumeration of basic lua globals. + /// + public enum LuaEnums : int + { + /// + /// Option for multiple returns in `lua_pcall' and `lua_call' + /// + MultiRet = -1, + + /// + /// Everything is OK. + /// + Ok = 0, + + /// + /// Thread status, Ok or Yield + /// + Yield = 1, + + /// + /// A Runtime error. + /// + ErrorRun = 2, + + /// + /// A syntax error. + /// + ErrorSyntax = 3, + + /// + /// A memory allocation error. For such errors, Lua does not call the error handler function. + /// + ErrorMemory = 4, + + /// + /// An error in the error handling function. + /// + ErrorError = 5, + + /// + /// An extra error for file load errors when using luaL_loadfile. + /// + ErrorFile = 6 + } } \ No newline at end of file diff --git a/Core/LuaInterface/LuaLib/LuaTypes.cs b/Core/LuaInterface/LuaLib/LuaTypes.cs index 5575a1a2a7f5f13441ae063d76ee796b9bb5e205..fe0c2e0f6fba06012eb7e6e880e61ddbe3ef29ae 100644 --- a/Core/LuaInterface/LuaLib/LuaTypes.cs +++ b/Core/LuaInterface/LuaLib/LuaTypes.cs @@ -1,48 +1,48 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2009 Joshua Simmons - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.IO; -using System.Runtime.InteropServices; -using System.Runtime.Serialization.Formatters.Binary; -using LuaInterface.Extensions; - -namespace LuaInterface -{ - public enum LuaTypes : int - { - None = -1, - Nil = 0, - Boolean = 1, - LightUserdata = 2, - Number = 3, - String = 4, - Table = 5, - Function = 6, - UserData = 7, - Thread = 8 - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2009 Joshua Simmons + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.Serialization.Formatters.Binary; +using LuaInterface.Extensions; + +namespace LuaInterface +{ + public enum LuaTypes : int + { + None = -1, + Nil = 0, + Boolean = 1, + LightUserdata = 2, + Number = 3, + String = 4, + Table = 5, + Function = 6, + UserData = 7, + Thread = 8 + } } \ No newline at end of file diff --git a/Core/LuaInterface/LuaLib/References.cs b/Core/LuaInterface/LuaLib/References.cs index d498e74feef00f8dd5b0ba744c14b118ffcc057b..aafa835471eedd2be5f8516867dc85c10b1f813d 100644 --- a/Core/LuaInterface/LuaLib/References.cs +++ b/Core/LuaInterface/LuaLib/References.cs @@ -1,36 +1,36 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2009 Joshua Simmons - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface -{ - public enum References : int - { - RefNil = -1, - NoRef = -2 - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2009 Joshua Simmons + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface +{ + public enum References : int + { + RefNil = -1, + NoRef = -2 + } } \ No newline at end of file diff --git a/Core/LuaInterface/LuaRegistrationHelper.cs b/Core/LuaInterface/LuaRegistrationHelper.cs index 6272a10a325b44ca917be7c7c1d2817245922769..b5a429c7a238db62c143dc7a1a9310fd057f6064 100644 --- a/Core/LuaInterface/LuaRegistrationHelper.cs +++ b/Core/LuaInterface/LuaRegistrationHelper.cs @@ -1,127 +1,127 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Reflection; -using System.Diagnostics.CodeAnalysis; -using LuaInterface.Extensions; - -namespace LuaInterface -{ - public static class LuaRegistrationHelper - { - #region Tagged instance methods - /// - /// Registers all public instance methods in an object tagged with as Lua global functions - /// - /// The Lua VM to add the methods to - /// The object to get the methods from - public static void TaggedInstanceMethods(Lua lua, object o) - { - #region Sanity checks - if(lua.IsNull()) - throw new ArgumentNullException("lua"); - - if(o.IsNull()) - throw new ArgumentNullException("o"); - #endregion - - foreach(var method in o.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public)) - { - foreach(LuaGlobalAttribute attribute in method.GetCustomAttributes(typeof(LuaGlobalAttribute), true)) - { - if(string.IsNullOrEmpty(attribute.Name)) - lua.RegisterFunction(method.Name, o, method); // CLR name - else - lua.RegisterFunction(attribute.Name, o, method); // Custom name - } - } - } - #endregion - - #region Tagged static methods - /// - /// Registers all public static methods in a class tagged with as Lua global functions - /// - /// The Lua VM to add the methods to - /// The class type to get the methods from - public static void TaggedStaticMethods(Lua lua, Type type) - { - #region Sanity checks - if(lua.IsNull()) - throw new ArgumentNullException("lua"); - - if(type.IsNull()) - throw new ArgumentNullException("type"); - - if(!type.IsClass) - throw new ArgumentException("The type must be a class!", "type"); - #endregion - - foreach(var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public)) - { - foreach(LuaGlobalAttribute attribute in method.GetCustomAttributes(typeof(LuaGlobalAttribute), false)) - { - if(string.IsNullOrEmpty(attribute.Name)) - lua.RegisterFunction(method.Name, null, method); // CLR name - else - lua.RegisterFunction(attribute.Name, null, method); // Custom name - } - } - } - #endregion - - #region Enumeration - /// - /// Registers an enumeration's values for usage as a Lua variable table - /// - /// The enum type to register - /// The Lua VM to add the enum to - [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "The type parameter is used to select an enum type")] - public static void Enumeration(Lua lua) - { - #region Sanity checks - if(lua.IsNull()) - throw new ArgumentNullException("lua"); - #endregion - - var type = typeof(T); - - if(!type.IsEnum) - throw new ArgumentException("The type must be an enumeration!"); - - string[] names = Enum.GetNames(type); - var values = (T[])Enum.GetValues(type); - lua.NewTable(type.Name); - - for(int i = 0; i < names.Length; i++) - { - string path = type.Name + "." + names[i]; - lua[path] = values[i]; - } - } - #endregion - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Reflection; +using System.Diagnostics.CodeAnalysis; +using LuaInterface.Extensions; + +namespace LuaInterface +{ + public static class LuaRegistrationHelper + { + #region Tagged instance methods + /// + /// Registers all public instance methods in an object tagged with as Lua global functions + /// + /// The Lua VM to add the methods to + /// The object to get the methods from + public static void TaggedInstanceMethods(Lua lua, object o) + { + #region Sanity checks + if(lua.IsNull()) + throw new ArgumentNullException("lua"); + + if(o.IsNull()) + throw new ArgumentNullException("o"); + #endregion + + foreach(var method in o.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public)) + { + foreach(LuaGlobalAttribute attribute in method.GetCustomAttributes(typeof(LuaGlobalAttribute), true)) + { + if(string.IsNullOrEmpty(attribute.Name)) + lua.RegisterFunction(method.Name, o, method); // CLR name + else + lua.RegisterFunction(attribute.Name, o, method); // Custom name + } + } + } + #endregion + + #region Tagged static methods + /// + /// Registers all public static methods in a class tagged with as Lua global functions + /// + /// The Lua VM to add the methods to + /// The class type to get the methods from + public static void TaggedStaticMethods(Lua lua, Type type) + { + #region Sanity checks + if(lua.IsNull()) + throw new ArgumentNullException("lua"); + + if(type.IsNull()) + throw new ArgumentNullException("type"); + + if(!type.IsClass) + throw new ArgumentException("The type must be a class!", "type"); + #endregion + + foreach(var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public)) + { + foreach(LuaGlobalAttribute attribute in method.GetCustomAttributes(typeof(LuaGlobalAttribute), false)) + { + if(string.IsNullOrEmpty(attribute.Name)) + lua.RegisterFunction(method.Name, null, method); // CLR name + else + lua.RegisterFunction(attribute.Name, null, method); // Custom name + } + } + } + #endregion + + #region Enumeration + /// + /// Registers an enumeration's values for usage as a Lua variable table + /// + /// The enum type to register + /// The Lua VM to add the enum to + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "The type parameter is used to select an enum type")] + public static void Enumeration(Lua lua) + { + #region Sanity checks + if(lua.IsNull()) + throw new ArgumentNullException("lua"); + #endregion + + var type = typeof(T); + + if(!type.IsEnum) + throw new ArgumentException("The type must be an enumeration!"); + + string[] names = Enum.GetNames(type); + var values = (T[])Enum.GetValues(type); + lua.NewTable(type.Name); + + for(int i = 0; i < names.Length; i++) + { + string path = type.Name + "." + names[i]; + lua[path] = values[i]; + } + } + #endregion + } } \ No newline at end of file diff --git a/Core/LuaInterface/LuaTable.cs b/Core/LuaInterface/LuaTable.cs index ef04f2ee4b0610021a4ea1044cebd17195b2ea25..a60d34956fbac9b47478af6d89f1d49e11e5da57 100644 --- a/Core/LuaInterface/LuaTable.cs +++ b/Core/LuaInterface/LuaTable.cs @@ -1,126 +1,126 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Text; -using System.Collections; -using System.Collections.Generic; - -namespace LuaInterface -{ - using LuaCore = KopiLua.Lua; - - /* - * Wrapper class for Lua tables - * - * Author: Fabio Mascarenhas - * Version: 1.0 - */ - public class LuaTable : LuaBase - { - public LuaTable(int reference, Lua interpreter) - { - _Reference = reference; - _Interpreter = interpreter; - } - - /* - * Indexer for string fields of the table - */ - public object this[string field] - { - get - { - return _Interpreter.getObject(_Reference, field); - } - set - { - _Interpreter.setObject(_Reference, field, value); - } - } - - /* - * Indexer for numeric fields of the table - */ - public object this[object field] - { - get - { - return _Interpreter.getObject(_Reference, field); - } - set - { - _Interpreter.setObject(_Reference, field, value); - } - } - - public System.Collections.IDictionaryEnumerator GetEnumerator() - { - return _Interpreter.GetTableDict(this).GetEnumerator(); - } - - public ICollection Keys - { - get { return _Interpreter.GetTableDict(this).Keys; } - } - - public ICollection Values - { - get { return _Interpreter.GetTableDict(this).Values; } - } - - /* - * Gets an string fields of a table ignoring its metatable, - * if it exists - */ - internal object rawget(string field) - { - return _Interpreter.rawGetObject(_Reference, field); - } - - internal object rawgetFunction(string field) - { - object obj = _Interpreter.rawGetObject(_Reference, field); - - if(obj is LuaCore.lua_CFunction) - return new LuaFunction((LuaCore.lua_CFunction)obj, _Interpreter); - else - return obj; - } - - /* - * Pushes this table into the Lua stack - */ - internal void push(LuaCore.lua_State luaState) - { - LuaLib.lua_getref(luaState, _Reference); - } - - public override string ToString() - { - return "table"; - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Text; +using System.Collections; +using System.Collections.Generic; + +namespace LuaInterface +{ + using LuaCore = KopiLua.Lua; + + /* + * Wrapper class for Lua tables + * + * Author: Fabio Mascarenhas + * Version: 1.0 + */ + public class LuaTable : LuaBase + { + public LuaTable(int reference, Lua interpreter) + { + _Reference = reference; + _Interpreter = interpreter; + } + + /* + * Indexer for string fields of the table + */ + public object this[string field] + { + get + { + return _Interpreter.getObject(_Reference, field); + } + set + { + _Interpreter.setObject(_Reference, field, value); + } + } + + /* + * Indexer for numeric fields of the table + */ + public object this[object field] + { + get + { + return _Interpreter.getObject(_Reference, field); + } + set + { + _Interpreter.setObject(_Reference, field, value); + } + } + + public System.Collections.IDictionaryEnumerator GetEnumerator() + { + return _Interpreter.GetTableDict(this).GetEnumerator(); + } + + public ICollection Keys + { + get { return _Interpreter.GetTableDict(this).Keys; } + } + + public ICollection Values + { + get { return _Interpreter.GetTableDict(this).Values; } + } + + /* + * Gets an string fields of a table ignoring its metatable, + * if it exists + */ + internal object rawget(string field) + { + return _Interpreter.rawGetObject(_Reference, field); + } + + internal object rawgetFunction(string field) + { + object obj = _Interpreter.rawGetObject(_Reference, field); + + if(obj is LuaCore.lua_CFunction) + return new LuaFunction((LuaCore.lua_CFunction)obj, _Interpreter); + else + return obj; + } + + /* + * Pushes this table into the Lua stack + */ + internal void push(LuaCore.lua_State luaState) + { + LuaLib.lua_getref(luaState, _Reference); + } + + public override string ToString() + { + return "table"; + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/LuaUserData.cs b/Core/LuaInterface/LuaUserData.cs index 62cf6661040aaf25148da72a452ad90c8c5a424d..923db6f3474b20e273603fc949b833a5e46b8205 100644 --- a/Core/LuaInterface/LuaUserData.cs +++ b/Core/LuaInterface/LuaUserData.cs @@ -1,94 +1,94 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Text; -using System.Collections.Generic; - -namespace LuaInterface -{ - using LuaCore = KopiLua.Lua; - - public class LuaUserData : LuaBase - { - public LuaUserData(int reference, Lua interpreter) - { - _Reference = reference; - _Interpreter = interpreter; - } - - /* - * Indexer for string fields of the userdata - */ - public object this[string field] - { - get - { - return _Interpreter.getObject(_Reference, field); - } - set - { - _Interpreter.setObject(_Reference, field, value); - } - } - - /* - * Indexer for numeric fields of the userdata - */ - public object this[object field] - { - get - { - return _Interpreter.getObject(_Reference, field); - } - set - { - _Interpreter.setObject(_Reference, field, value); - } - } - - /* - * Calls the userdata and returns its return values inside - * an array - */ - public object[] Call(params object[] args) - { - return _Interpreter.callFunction(this, args); - } - - /* - * Pushes the userdata into the Lua stack - */ - internal void push(LuaCore.lua_State luaState) - { - LuaLib.lua_getref(luaState, _Reference); - } - - public override string ToString() - { - return "userdata"; - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Text; +using System.Collections.Generic; + +namespace LuaInterface +{ + using LuaCore = KopiLua.Lua; + + public class LuaUserData : LuaBase + { + public LuaUserData(int reference, Lua interpreter) + { + _Reference = reference; + _Interpreter = interpreter; + } + + /* + * Indexer for string fields of the userdata + */ + public object this[string field] + { + get + { + return _Interpreter.getObject(_Reference, field); + } + set + { + _Interpreter.setObject(_Reference, field, value); + } + } + + /* + * Indexer for numeric fields of the userdata + */ + public object this[object field] + { + get + { + return _Interpreter.getObject(_Reference, field); + } + set + { + _Interpreter.setObject(_Reference, field, value); + } + } + + /* + * Calls the userdata and returns its return values inside + * an array + */ + public object[] Call(params object[] args) + { + return _Interpreter.callFunction(this, args); + } + + /* + * Pushes the userdata into the Lua stack + */ + internal void push(LuaCore.lua_State luaState) + { + LuaLib.lua_getref(luaState, _Reference); + } + + public override string ToString() + { + return "userdata"; + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/Makefile.am b/Core/LuaInterface/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..a99b55f10e997e8a6f66f2981523a445aad4748f --- /dev/null +++ b/Core/LuaInterface/Makefile.am @@ -0,0 +1,163 @@ + +EXTRA_DIST = + +# Warning: This is an automatically generated file, do not edit! + +if ENABLE_DEBUG_X86 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize- -debug "-define:DEBUG" +ASSEMBLY = ../../Run/Debug/LuaInterface.dll +ASSEMBLY_MDB = $(ASSEMBLY).mdb +COMPILE_TARGET = library +PROJECT_REFERENCES = \ + ../../Run/Debug/KopiLua.dll +BUILD_DIR = ../../Run/Debug + +LUAINTERFACE_DLL_MDB_SOURCE=../../Run/Debug/LuaInterface.dll.mdb +LUAINTERFACE_DLL_MDB=$(BUILD_DIR)/LuaInterface.dll.mdb +KOPILUA_DLL_SOURCE=../../Run/Debug/KopiLua.dll + +endif + +if ENABLE_RELEASE_X86 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize+ "-define:RELEASE" +ASSEMBLY = ../../Run/Release/LuaInterface.dll +ASSEMBLY_MDB = +COMPILE_TARGET = library +PROJECT_REFERENCES = \ + ../../Run/Release/KopiLua.dll +BUILD_DIR = ../../Run/Release + +LUAINTERFACE_DLL_MDB= +KOPILUA_DLL_SOURCE=../../Run/Release/KopiLua.dll + +endif + +if ENABLE_DEBUG_X64 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize- -debug "-define:DEBUG" +ASSEMBLY = ../../Run/Debug_x64/LuaInterface.dll +ASSEMBLY_MDB = $(ASSEMBLY).mdb +COMPILE_TARGET = library +PROJECT_REFERENCES = \ + ../../Run/Debug_x64/KopiLua.dll +BUILD_DIR = ../../Run/Debug_x64 + +LUAINTERFACE_DLL_MDB_SOURCE=../../Run/Debug_x64/LuaInterface.dll.mdb +LUAINTERFACE_DLL_MDB=$(BUILD_DIR)/LuaInterface.dll.mdb +KOPILUA_DLL_SOURCE=../../Run/Debug_x64/KopiLua.dll + +endif + +if ENABLE_RELEASE_X64 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize+ "-define:RELEASE" +ASSEMBLY = ../../Run/Release_x64/LuaInterface.dll +ASSEMBLY_MDB = +COMPILE_TARGET = library +PROJECT_REFERENCES = \ + ../../Run/Release_x64/KopiLua.dll +BUILD_DIR = ../../Run/Release_x64 + +LUAINTERFACE_DLL_MDB= +KOPILUA_DLL_SOURCE=../../Run/Release_x64/KopiLua.dll + +endif + +AL=al +SATELLITE_ASSEMBLY_NAME=$(notdir $(basename $(ASSEMBLY))).resources.dll + +PROGRAMFILES = \ + $(LUAINTERFACE_DLL_MDB) \ + $(KOPILUA_DLL) + +LINUX_PKGCONFIG = \ + $(LUAINTERFACE_PC) + + +RESGEN=resgen2 + +all: $(ASSEMBLY) $(PROGRAMFILES) $(LINUX_PKGCONFIG) + +FILES = \ + CheckType.cs \ + Lua.cs \ + Metatables.cs \ + ObjectTranslator.cs \ + ProxyType.cs \ + Properties/AssemblyInfo.cs \ + LuaBase.cs \ + LuaFunction.cs \ + LuaGlobalAttribute.cs \ + LuaHideAttribute.cs \ + LuaRegistrationHelper.cs \ + LuaTable.cs \ + LuaUserData.cs \ + Extensions/GeneralExtensions.cs \ + GenerateEventAssembly/LuaClassType.cs \ + GenerateEventAssembly/ILuaGeneratedType.cs \ + GenerateEventAssembly/DelegateGenerator.cs \ + GenerateEventAssembly/ClassGenerator.cs \ + GenerateEventAssembly/CodeGeneration.cs \ + Event/EventCodes.cs \ + Event/EventMasks.cs \ + Event/DebugHookEventArgs.cs \ + Event/HookExceptionEventArgs.cs \ + Exceptions/LuaException.cs \ + Exceptions/LuaScriptException.cs \ + LuaLib/LuaEnums.cs \ + LuaLib/References.cs \ + LuaLib/LuaTypes.cs \ + Method/MethodCache.cs \ + Method/MethodArgs.cs \ + Method/LuaMethodWrapper.cs \ + Method/EventHandlerContainer.cs \ + Method/RegisterEventHandler.cs \ + Method/LuaEventHandler.cs \ + Method/LuaDelegate.cs \ + Method/LuaClassHelper.cs \ + LuaLib/LuaIndexes.cs \ + LuaLib/GCOptions.cs \ + LuaLib/LuaLib.cs \ + Config/LuaInterfaceConfig.cs + +DATA_FILES = + +RESOURCES = + +EXTRAS = \ + Extensions \ + GenerateEventAssembly \ + Event \ + Exceptions \ + Method \ + Config \ + luainterface.pc.in + +REFERENCES = \ + System \ + System.Data \ + System.Xml + +DLL_REFERENCES = + +CLEANFILES = $(PROGRAMFILES) $(LINUX_PKGCONFIG) + +include $(top_srcdir)/Makefile.include + +KOPILUA_DLL = $(BUILD_DIR)/KopiLua.dll +LUAINTERFACE_PC = $(BUILD_DIR)/luainterface.pc + +$(eval $(call emit-deploy-wrapper,LUAINTERFACE_PC,luainterface.pc)) + + +$(eval $(call emit_resgen_targets)) +$(build_xamlg_list): %.xaml.g.cs: %.xaml + xamlg '$<' + +$(ASSEMBLY_MDB): $(ASSEMBLY) + +$(ASSEMBLY): $(build_sources) $(build_resources) $(build_datafiles) $(DLL_REFERENCES) $(PROJECT_REFERENCES) $(build_xamlg_list) $(build_satellite_assembly_list) + mkdir -p $(shell dirname $(ASSEMBLY)) + $(ASSEMBLY_COMPILER_COMMAND) $(ASSEMBLY_COMPILER_FLAGS) -out:$(ASSEMBLY) -target:$(COMPILE_TARGET) $(build_sources_embed) $(build_resources_embed) $(build_references_ref) diff --git a/Core/LuaInterface/Metatables.cs b/Core/LuaInterface/Metatables.cs index 1bd74ce967a8785102163880f1403bf7e5ece6db..f0915415fb75f4ca08073e87a9eb2ff03cc88ed8 100644 --- a/Core/LuaInterface/Metatables.cs +++ b/Core/LuaInterface/Metatables.cs @@ -1,986 +1,986 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.IO; -using System.Collections; -using System.Reflection; -using System.Diagnostics; -using System.Collections.Generic; -using System.Runtime.InteropServices; -using LuaInterface.Method; -using LuaInterface.Extensions; - -namespace LuaInterface -{ - using LuaCore = KopiLua.Lua; - - /* - * Functions used in the metatables of userdata representing - * CLR objects - * - * Author: Fabio Mascarenhas - * Version: 1.0 - */ - class MetaFunctions - { - internal LuaCore.lua_CFunction gcFunction, indexFunction, newindexFunction, baseIndexFunction, - classIndexFunction, classNewindexFunction, execDelegateFunction, callConstructorFunction, toStringFunction; - private Hashtable memberCache = new Hashtable(); - private ObjectTranslator translator; - - /* - * __index metafunction for CLR objects. Implemented in Lua. - */ - internal static string luaIndexFunction = - "local function index(obj,name) \n" + - " local meta=getmetatable(obj) \n" + - " local cached=meta.cache[name] \n" + - " if cached~=nil then \n" + - " return cached \n" + - " else \n" + - " local value,isFunc=get_object_member(obj,name) \n" + - " if isFunc then \n" + - " meta.cache[name]=value \n" + - " end \n" + - " return value \n" + - " end \n" + - "end \n" + - "return index "; - - public MetaFunctions(ObjectTranslator translator) - { - this.translator = translator; - gcFunction = new LuaCore.lua_CFunction(this.collectObject); - toStringFunction = new LuaCore.lua_CFunction(this.toString); - indexFunction = new LuaCore.lua_CFunction(this.getMethod); - newindexFunction = new LuaCore.lua_CFunction(this.setFieldOrProperty); - baseIndexFunction = new LuaCore.lua_CFunction(this.getBaseMethod); - callConstructorFunction = new LuaCore.lua_CFunction(this.callConstructor); - classIndexFunction = new LuaCore.lua_CFunction(this.getClassMethod); - classNewindexFunction = new LuaCore.lua_CFunction(this.setClassFieldOrProperty); - execDelegateFunction = new LuaCore.lua_CFunction(this.runFunctionDelegate); - } - - /* - * __call metafunction of CLR delegates, retrieves and calls the delegate. - */ - private int runFunctionDelegate(LuaCore.lua_State luaState) - { - LuaCore.lua_CFunction func = (LuaCore.lua_CFunction)translator.getRawNetObject(luaState, 1); - LuaLib.lua_remove(luaState, 1); - return func(luaState); - } - - /* - * __gc metafunction of CLR objects. - */ - private int collectObject(LuaCore.lua_State luaState) - { - int udata = LuaLib.luanet_rawnetobj(luaState, 1); - - if(udata != -1) - translator.collectObject(udata); - else - { - // Debug.WriteLine("not found: " + udata); - } - - return 0; - } - - /* - * __tostring metafunction of CLR objects. - */ - private int toString(LuaCore.lua_State luaState) - { - object obj = translator.getRawNetObject(luaState, 1); - - if(!obj.IsNull()) - translator.push(luaState, obj.ToString() + ": " + obj.GetHashCode()); - else - LuaLib.lua_pushnil(luaState); - - return 1; - } - - - /// - /// Debug tool to dump the lua stack - /// - /// FIXME, move somewhere else - public static void dumpStack(ObjectTranslator translator, LuaCore.lua_State luaState) - { - int depth = LuaLib.lua_gettop(luaState); - Debug.WriteLine("lua stack depth: " + depth); - - for(int i = 1; i <= depth; i++) - { - var type = LuaLib.lua_type(luaState, i); - // we dump stacks when deep in calls, calling typename while the stack is in flux can fail sometimes, so manually check for key types - string typestr = (type == LuaTypes.Table) ? "table" : LuaLib.lua_typename(luaState, type); - string strrep = LuaLib.lua_tostring(luaState, i).ToString(); - - if(type == LuaTypes.UserData) - { - object obj = translator.getRawNetObject(luaState, i); - strrep = obj.ToString(); - } - - Debug.Print("{0}: ({1}) {2}", i, typestr, strrep); - } - } - - /* - * Called by the __index metafunction of CLR objects in case the - * method is not cached or it is a field/property/event. - * Receives the object and the member name as arguments and returns - * either the value of the member or a delegate to call it. - * If the member does not exist returns nil. - */ - private int getMethod(LuaCore.lua_State luaState) - { - object obj = translator.getRawNetObject(luaState, 1); - - if(obj.IsNull()) - { - translator.throwError(luaState, "trying to index an invalid object reference"); - LuaLib.lua_pushnil(luaState); - return 1; - } - - object index = translator.getObject(luaState, 2); - //var indexType = index.GetType(); - string methodName = index as string; // will be null if not a string arg - var objType = obj.GetType(); - - // Handle the most common case, looking up the method by name. - - // CP: This will fail when using indexers and attempting to get a value with the same name as a property of the object, - // ie: xmlelement['item'] <- item is a property of xmlelement - try - { - if(!methodName.IsNull() && isMemberPresent(objType, methodName)) - return getMember(luaState, objType, obj, methodName, BindingFlags.Instance | BindingFlags.IgnoreCase); - } - catch - { - } - - // Try to access by array if the type is right and index is an int (lua numbers always come across as double) - if(objType.IsArray && index is double) - { - int intIndex = (int)((double)index); - - if(objType.UnderlyingSystemType == typeof(float[])) - { - float[] arr = ((float[])obj); - translator.push(luaState, arr[intIndex]); - } - else if(objType.UnderlyingSystemType == typeof(double[])) - { - double[] arr = ((double[])obj); - translator.push(luaState, arr[intIndex]); - } - else if(objType.UnderlyingSystemType == typeof(int[])) - { - int[] arr = ((int[])obj); - translator.push(luaState, arr[intIndex]); - } - else - { - object[] arr = (object[])obj; - translator.push(luaState, arr[intIndex]); - } - } - else - { - // Try to use get_Item to index into this .net object - //MethodInfo getter = objType.GetMethod("get_Item"); - var methods = objType.GetMethods(); - - foreach(var mInfo in methods) - { - if(mInfo.Name == "get_Item") - { - //check if the signature matches the input - if(mInfo.GetParameters().Length == 1) - { - var getter = mInfo; - var actualParms = (!getter.IsNull()) ? getter.GetParameters() : null; - - if(actualParms.IsNull() || actualParms.Length != 1) - { - translator.throwError(luaState, "method not found (or no indexer): " + index); - LuaLib.lua_pushnil(luaState); - } - else - { - // Get the index in a form acceptable to the getter - index = translator.getAsType(luaState, 2, actualParms[0].ParameterType); - object[] args = new object[1]; - - // Just call the indexer - if out of bounds an exception will happen - args[0] = index; - - try - { - object result = getter.Invoke(obj, args); - translator.push(luaState, result); - } - catch(TargetInvocationException e) - { - // Provide a more readable description for the common case of key not found - if(e.InnerException is KeyNotFoundException) - translator.throwError(luaState, "key '" + index + "' not found "); - else - translator.throwError(luaState, "exception indexing '" + index + "' " + e.Message); - - LuaLib.lua_pushnil(luaState); - } - } - } - } - } - } - - LuaLib.lua_pushboolean(luaState, false); - return 2; - } - - /* - * __index metafunction of base classes (the base field of Lua tables). - * Adds a prefix to the method name to call the base version of the method. - */ - private int getBaseMethod(LuaCore.lua_State luaState) - { - object obj = translator.getRawNetObject(luaState, 1); - - if(obj.IsNull()) - { - translator.throwError(luaState, "trying to index an invalid object reference"); - LuaLib.lua_pushnil(luaState); - LuaLib.lua_pushboolean(luaState, false); - return 2; - } - - string methodName = LuaLib.lua_tostring(luaState, 2).ToString(); - - if(methodName.IsNull()) - { - LuaLib.lua_pushnil(luaState); - LuaLib.lua_pushboolean(luaState, false); - return 2; - } - - getMember(luaState, obj.GetType(), obj, "__luaInterface_base_" + methodName, BindingFlags.Instance | BindingFlags.IgnoreCase); - LuaLib.lua_settop(luaState, -2); - - if(LuaLib.lua_type(luaState, -1) == LuaTypes.Nil) - { - LuaLib.lua_settop(luaState, -2); - return getMember(luaState, obj.GetType(), obj, methodName, BindingFlags.Instance | BindingFlags.IgnoreCase); - } - - LuaLib.lua_pushboolean(luaState, false); - return 2; - } - - /// - /// Does this method exist as either an instance or static? - /// - /// - /// - /// - bool isMemberPresent(IReflect objType, string methodName) - { - object cachedMember = checkMemberCache(memberCache, objType, methodName); - - if(!cachedMember.IsNull()) - return true; - - //CP: Removed NonPublic binding search - var members = objType.GetMember(methodName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase/* | BindingFlags.NonPublic*/); - return (members.Length > 0); - } - - /* - * Pushes the value of a member or a delegate to call it, depending on the type of - * the member. Works with static or instance members. - * Uses reflection to find members, and stores the reflected MemberInfo object in - * a cache (indexed by the type of the object and the name of the member). - */ - private int getMember(LuaCore.lua_State luaState, IReflect objType, object obj, string methodName, BindingFlags bindingType) - { - bool implicitStatic = false; - MemberInfo member = null; - object cachedMember = checkMemberCache(memberCache, objType, methodName); - //object cachedMember=null; - - if(cachedMember is LuaCore.lua_CFunction) - { - translator.pushFunction(luaState, (LuaCore.lua_CFunction)cachedMember); - translator.push(luaState, true); - return 2; - } - else if(!cachedMember.IsNull()) - member = (MemberInfo)cachedMember; - else - { - //CP: Removed NonPublic binding search - var members = objType.GetMember(methodName, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase/*| BindingFlags.NonPublic*/); - - if(members.Length > 0) - member = members[0]; - else - { - // If we can't find any suitable instance members, try to find them as statics - but we only want to allow implicit static - // lookups for fields/properties/events -kevinh - //CP: Removed NonPublic binding search and made case insensitive - members = objType.GetMember(methodName, bindingType | BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase/*| BindingFlags.NonPublic*/); - - if(members.Length > 0) - { - member = members[0]; - implicitStatic = true; - } - } - } - - if(!member.IsNull()) - { - if(member.MemberType == MemberTypes.Field) - { - var field = (FieldInfo)member; - - if(cachedMember.IsNull()) - setMemberCache(memberCache, objType, methodName, member); - - try - { - translator.push(luaState, field.GetValue(obj)); - } - catch - { - LuaLib.lua_pushnil(luaState); - } - } - else if(member.MemberType == MemberTypes.Property) - { - var property = (PropertyInfo)member; - if(cachedMember.IsNull()) - setMemberCache(memberCache, objType, methodName, member); - - try - { - object val = property.GetValue(obj, null); - translator.push(luaState, val); - } - catch(ArgumentException) - { - // If we can't find the getter in our class, recurse up to the base class and see - // if they can help. - if(objType is Type && !(((Type)objType) == typeof(object))) - return getMember(luaState, ((Type)objType).BaseType, obj, methodName, bindingType); - else - LuaLib.lua_pushnil(luaState); - } - catch(TargetInvocationException e) // Convert this exception into a Lua error - { - ThrowError(luaState, e); - LuaLib.lua_pushnil(luaState); - } - } - else if(member.MemberType == MemberTypes.Event) - { - var eventInfo = (EventInfo)member; - if(cachedMember.IsNull()) - setMemberCache(memberCache, objType, methodName, member); - - translator.push(luaState, new RegisterEventHandler(translator.pendingEvents, obj, eventInfo)); - } - else if(!implicitStatic) - { - if(member.MemberType == MemberTypes.NestedType) - { - // kevinh - added support for finding nested types - // cache us - if(cachedMember.IsNull()) - setMemberCache(memberCache, objType, methodName, member); - - // Find the name of our class - string name = member.Name; - var dectype = member.DeclaringType; - - // Build a new long name and try to find the type by name - string longname = dectype.FullName + "+" + name; - var nestedType = translator.FindType(longname); - translator.pushType(luaState, nestedType); - } - else - { - // Member type must be 'method' - var wrapper = new LuaCore.lua_CFunction((new LuaMethodWrapper(translator, objType, methodName, bindingType)).call); - - if(cachedMember.IsNull()) - setMemberCache(memberCache, objType, methodName, wrapper); - - translator.pushFunction(luaState, wrapper); - translator.push(luaState, true); - return 2; - } - } - else - { - // If we reach this point we found a static method, but can't use it in this context because the user passed in an instance - translator.throwError(luaState, "can't pass instance to static method " + methodName); - LuaLib.lua_pushnil(luaState); - } - } - else - { - // kevinh - we want to throw an exception because meerly returning 'nil' in this case - // is not sufficient. valid data members may return nil and therefore there must be some - // way to know the member just doesn't exist. - translator.throwError(luaState, "unknown member name " + methodName); - LuaLib.lua_pushnil(luaState); - } - - // push false because we are NOT returning a function (see luaIndexFunction) - translator.push(luaState, false); - return 2; - } - - /* - * Checks if a MemberInfo object is cached, returning it or null. - */ - private object checkMemberCache(Hashtable memberCache, IReflect objType, string memberName) - { - var members = (Hashtable)memberCache[objType]; - return !members.IsNull() ? members[memberName] : null; - } - - /* - * Stores a MemberInfo object in the member cache. - */ - private void setMemberCache(Hashtable memberCache, IReflect objType, string memberName, object member) - { - var members = (Hashtable)memberCache[objType]; - - if(members.IsNull()) - { - members = new Hashtable(); - memberCache[objType] = members; - } - - members[memberName] = member; - } - - /* - * __newindex metafunction of CLR objects. Receives the object, - * the member name and the value to be stored as arguments. Throws - * and error if the assignment is invalid. - */ - private int setFieldOrProperty(LuaCore.lua_State luaState) - { - object target = translator.getRawNetObject(luaState, 1); - - if(target.IsNull()) - { - translator.throwError(luaState, "trying to index and invalid object reference"); - return 0; - } - - var type = target.GetType(); - - // First try to look up the parameter as a property name - string detailMessage; - bool didMember = trySetMember(luaState, type, target, BindingFlags.Instance | BindingFlags.IgnoreCase, out detailMessage); - - if(didMember) - return 0; // Must have found the property name - - // We didn't find a property name, now see if we can use a [] style this accessor to set array contents - try - { - if(type.IsArray && LuaLib.lua_isnumber(luaState, 2)) - { - int index = (int)LuaLib.lua_tonumber(luaState, 2); - var arr = (Array)target; - object val = translator.getAsType(luaState, 3, arr.GetType().GetElementType()); - arr.SetValue(val, index); - } - else - { - // Try to see if we have a this[] accessor - var setter = type.GetMethod("set_Item"); - if(!setter.IsNull()) - { - var args = setter.GetParameters(); - var valueType = args[1].ParameterType; - - // The new val ue the user specified - object val = translator.getAsType(luaState, 3, valueType); - var indexType = args[0].ParameterType; - object index = translator.getAsType(luaState, 2, indexType); - - object[] methodArgs = new object[2]; - - // Just call the indexer - if out of bounds an exception will happen - methodArgs[0] = index; - methodArgs[1] = val; - setter.Invoke(target, methodArgs); - } - else - translator.throwError(luaState, detailMessage); // Pass the original message from trySetMember because it is probably best - } - } - catch(SEHException) - { - // If we are seeing a C++ exception - this must actually be for Lua's private use. Let it handle it - throw; - } - catch(Exception e) - { - ThrowError(luaState, e); - } - - return 0; - } - - /// - /// Tries to set a named property or field - /// - /// - /// - /// - /// - /// false if unable to find the named member, true for success - private bool trySetMember(LuaCore.lua_State luaState, IReflect targetType, object target, BindingFlags bindingType, out string detailMessage) - { - detailMessage = null; // No error yet - - // If not already a string just return - we don't want to call tostring - which has the side effect of - // changing the lua typecode to string - // Note: We don't use isstring because the standard lua C isstring considers either strings or numbers to - // be true for isstring. - if(LuaLib.lua_type(luaState, 2) != LuaTypes.String) - { - detailMessage = "property names must be strings"; - return false; - } - - // We only look up property names by string - string fieldName = LuaLib.lua_tostring(luaState, 2).ToString(); - if(fieldName.IsNull() || fieldName.Length < 1 || !(char.IsLetter(fieldName[0]) || fieldName[0] == '_')) - { - detailMessage = "invalid property name"; - return false; - } - - // Find our member via reflection or the cache - var member = (MemberInfo)checkMemberCache(memberCache, targetType, fieldName); - if(member.IsNull()) - { - //CP: Removed NonPublic binding search and made case insensitive - var members = targetType.GetMember(fieldName, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase/*| BindingFlags.NonPublic*/); - - if(members.Length > 0) - { - member = members[0]; - setMemberCache(memberCache, targetType, fieldName, member); - } - else - { - detailMessage = "field or property '" + fieldName + "' does not exist"; - return false; - } - } - - if(member.MemberType == MemberTypes.Field) - { - var field = (FieldInfo)member; - object val = translator.getAsType(luaState, 3, field.FieldType); - - try - { - field.SetValue(target, val); - } - catch (Exception e) - { - ThrowError(luaState, e); - } - - // We did a call - return true; - } - else if(member.MemberType == MemberTypes.Property) - { - var property = (PropertyInfo)member; - object val = translator.getAsType(luaState, 3, property.PropertyType); - - try - { - property.SetValue(target, val, null); - } - catch (Exception e) - { - ThrowError(luaState, e); - } - - // We did a call - return true; - } - - detailMessage = "'" + fieldName + "' is not a .net field or property"; - return false; - } - - /* - * Writes to fields or properties, either static or instance. Throws an error - * if the operation is invalid. - */ - private int setMember(LuaCore.lua_State luaState, IReflect targetType, object target, BindingFlags bindingType) - { - string detail; - bool success = trySetMember(luaState, targetType, target, bindingType, out detail); - - if(!success) - translator.throwError(luaState, detail); - - return 0; - } - - /// - /// Convert a C# exception into a Lua error - /// - /// - /// We try to look into the exception to give the most meaningful description - void ThrowError(LuaCore.lua_State luaState, Exception e) - { - // If we got inside a reflection show what really happened - var te = e as TargetInvocationException; - - if (!te.IsNull()) - e = te.InnerException; - - translator.throwError(luaState, e); - } - - /* - * __index metafunction of type references, works on static members. - */ - private int getClassMethod(LuaCore.lua_State luaState) - { - IReflect klass; - object obj = translator.getRawNetObject(luaState, 1); - - if(obj.IsNull() || !(obj is IReflect)) - { - translator.throwError(luaState, "trying to index an invalid type reference"); - LuaLib.lua_pushnil(luaState); - return 1; - } - else - klass = (IReflect)obj; - - if(LuaLib.lua_isnumber(luaState, 2)) - { - int size = (int)LuaLib.lua_tonumber(luaState, 2); - translator.push(luaState, Array.CreateInstance(klass.UnderlyingSystemType, size)); - return 1; - } - else - { - string methodName = LuaLib.lua_tostring(luaState, 2).ToString(); - - if(methodName.IsNull()) - { - LuaLib.lua_pushnil(luaState); - return 1; - } //CP: Ignore case - else - return getMember(luaState, klass, null, methodName, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.IgnoreCase); - } - } - - /* - * __newindex function of type references, works on static members. - */ - private int setClassFieldOrProperty(LuaCore.lua_State luaState) - { - IReflect target; - object obj = translator.getRawNetObject(luaState, 1); - - if(obj.IsNull() || !(obj is IReflect)) - { - translator.throwError(luaState, "trying to index an invalid type reference"); - return 0; - } - else - target = (IReflect)obj; - - return setMember(luaState, target, null, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.IgnoreCase); - } - - /* - * __call metafunction of type references. Searches for and calls - * a constructor for the type. Returns nil if the constructor is not - * found or if the arguments are invalid. Throws an error if the constructor - * generates an exception. - */ - private int callConstructor(LuaCore.lua_State luaState) - { - var validConstructor = new MethodCache(); - IReflect klass; - object obj = translator.getRawNetObject(luaState, 1); - - if(obj.IsNull() || !(obj is IReflect)) - { - translator.throwError(luaState, "trying to call constructor on an invalid type reference"); - LuaLib.lua_pushnil(luaState); - return 1; - } - else - klass = (IReflect)obj; - - LuaLib.lua_remove(luaState, 1); - var constructors = klass.UnderlyingSystemType.GetConstructors(); - - foreach(var constructor in constructors) - { - bool isConstructor = matchParameters(luaState, constructor, ref validConstructor); - - if(isConstructor) - { - try - { - translator.push(luaState, constructor.Invoke(validConstructor.args)); - } - catch(TargetInvocationException e) - { - ThrowError(luaState, e); - LuaLib.lua_pushnil(luaState); - } - catch - { - LuaLib.lua_pushnil(luaState); - } - - return 1; - } - } - - string constructorName = (constructors.Length == 0) ? "unknown" : constructors[0].Name; - translator.throwError(luaState, String.Format("{0} does not contain constructor({1}) argument match", - klass.UnderlyingSystemType, constructorName)); - LuaLib.lua_pushnil(luaState); - return 1; - } - - /* - * Matches a method against its arguments in the Lua stack. Returns - * if the match was succesful. It it was also returns the information - * necessary to invoke the method. - */ - internal bool matchParameters(LuaCore.lua_State luaState, MethodBase method, ref MethodCache methodCache) - { - ExtractValue extractValue; - bool isMethod = true; - var paramInfo = method.GetParameters(); - int currentLuaParam = 1; - int nLuaParams = LuaLib.lua_gettop(luaState); - var paramList = new ArrayList(); - var outList = new List(); - var argTypes = new List(); - - foreach(var currentNetParam in paramInfo) - { - if(!currentNetParam.IsIn && currentNetParam.IsOut) // Skips out params - outList.Add(paramList.Add(null)); - else if(currentLuaParam > nLuaParams) // Adds optional parameters - { - if(currentNetParam.IsOptional) - paramList.Add(currentNetParam.DefaultValue); - else - { - isMethod = false; - break; - } - } - else if(_IsTypeCorrect(luaState, currentLuaParam, currentNetParam, out extractValue)) // Type checking - { - int index = paramList.Add(extractValue(luaState, currentLuaParam)); - var methodArg = new MethodArgs(); - methodArg.index = index; - methodArg.extractValue = extractValue; - argTypes.Add(methodArg); - - if(currentNetParam.ParameterType.IsByRef) - outList.Add(index); - - currentLuaParam++; - } // Type does not match, ignore if the parameter is optional - else if(_IsParamsArray(luaState, currentLuaParam, currentNetParam, out extractValue)) - { - object luaParamValue = extractValue(luaState, currentLuaParam); - var paramArrayType = currentNetParam.ParameterType.GetElementType(); - Array paramArray; - - if(luaParamValue is LuaTable) - { - var table = (LuaTable)luaParamValue; - var tableEnumerator = table.GetEnumerator(); - paramArray = Array.CreateInstance(paramArrayType, table.Values.Count); - tableEnumerator.Reset(); - int paramArrayIndex = 0; - - while(tableEnumerator.MoveNext()) - { - paramArray.SetValue(Convert.ChangeType(tableEnumerator.Value, currentNetParam.ParameterType.GetElementType()), paramArrayIndex); - paramArrayIndex++; - } - } - else - { - paramArray = Array.CreateInstance(paramArrayType, 1); - paramArray.SetValue(luaParamValue, 0); - } - - int index = paramList.Add(paramArray); - var methodArg = new MethodArgs(); - methodArg.index = index; - methodArg.extractValue = extractValue; - methodArg.isParamsArray = true; - methodArg.paramsArrayType = paramArrayType; - argTypes.Add(methodArg); - currentLuaParam++; - } - else if(currentNetParam.IsOptional) - paramList.Add(currentNetParam.DefaultValue); - else // No match - { - isMethod = false; - break; - } - } - - if(currentLuaParam != nLuaParams + 1) // Number of parameters does not match - isMethod = false; - if(isMethod) - { - methodCache.args = paramList.ToArray(); - methodCache.cachedMethod = method; - methodCache.outList = outList.ToArray(); - methodCache.argTypes = argTypes.ToArray(); - } - - return isMethod; - } - - /// - /// CP: Fix for operator overloading failure - /// Returns true if the type is set and assigns the extract value - /// - /// - /// - /// - /// - /// - private bool _IsTypeCorrect(LuaCore.lua_State luaState, int currentLuaParam, ParameterInfo currentNetParam, out ExtractValue extractValue) - { - try - { - return (extractValue = translator.typeChecker.checkType(luaState, currentLuaParam, currentNetParam.ParameterType)) != null; - } - catch - { - extractValue = null; - Debug.WriteLine("Type wasn't correct"); - return false; - } - } - - private bool _IsParamsArray(LuaCore.lua_State luaState, int currentLuaParam, ParameterInfo currentNetParam, out ExtractValue extractValue) - { - extractValue = null; - - if (currentNetParam.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0) - { - LuaTypes luaType; - - try - { - luaType = LuaLib.lua_type(luaState, currentLuaParam); - } - catch(Exception ex) - { - Debug.WriteLine("Could not retrieve lua type while attempting to determine params Array Status."); - Debug.WriteLine(ex.Message); - extractValue = null; - return false; - } - - if(luaType == LuaTypes.Table) - { - try - { - extractValue = translator.typeChecker.getExtractor(typeof(LuaTable)); - } - catch(Exception/* ex*/) - { - Debug.WriteLine("An error occurred during an attempt to retrieve a LuaTable extractor while checking for params array status."); - } - - if(!extractValue.IsNull()) - { - return true; - } - } - else - { - var paramElementType = currentNetParam.ParameterType.GetElementType(); - - try - { - extractValue = translator.typeChecker.checkType(luaState, currentLuaParam, paramElementType); - } - catch (Exception/* ex*/) - { - Debug.WriteLine(string.Format("An error occurred during an attempt to retrieve an extractor ({0}) while checking for params array status.", paramElementType.FullName)); - } - - if(!extractValue.IsNull()) - { - return true; - } - } - } - - Debug.WriteLine("Type wasn't Params object."); - return false; - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.IO; +using System.Collections; +using System.Reflection; +using System.Diagnostics; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using LuaInterface.Method; +using LuaInterface.Extensions; + +namespace LuaInterface +{ + using LuaCore = KopiLua.Lua; + + /* + * Functions used in the metatables of userdata representing + * CLR objects + * + * Author: Fabio Mascarenhas + * Version: 1.0 + */ + class MetaFunctions + { + internal LuaCore.lua_CFunction gcFunction, indexFunction, newindexFunction, baseIndexFunction, + classIndexFunction, classNewindexFunction, execDelegateFunction, callConstructorFunction, toStringFunction; + private Hashtable memberCache = new Hashtable(); + private ObjectTranslator translator; + + /* + * __index metafunction for CLR objects. Implemented in Lua. + */ + internal static string luaIndexFunction = + "local function index(obj,name) \n" + + " local meta=getmetatable(obj) \n" + + " local cached=meta.cache[name] \n" + + " if cached~=nil then \n" + + " return cached \n" + + " else \n" + + " local value,isFunc=get_object_member(obj,name) \n" + + " if isFunc then \n" + + " meta.cache[name]=value \n" + + " end \n" + + " return value \n" + + " end \n" + + "end \n" + + "return index "; + + public MetaFunctions(ObjectTranslator translator) + { + this.translator = translator; + gcFunction = new LuaCore.lua_CFunction(this.collectObject); + toStringFunction = new LuaCore.lua_CFunction(this.toString); + indexFunction = new LuaCore.lua_CFunction(this.getMethod); + newindexFunction = new LuaCore.lua_CFunction(this.setFieldOrProperty); + baseIndexFunction = new LuaCore.lua_CFunction(this.getBaseMethod); + callConstructorFunction = new LuaCore.lua_CFunction(this.callConstructor); + classIndexFunction = new LuaCore.lua_CFunction(this.getClassMethod); + classNewindexFunction = new LuaCore.lua_CFunction(this.setClassFieldOrProperty); + execDelegateFunction = new LuaCore.lua_CFunction(this.runFunctionDelegate); + } + + /* + * __call metafunction of CLR delegates, retrieves and calls the delegate. + */ + private int runFunctionDelegate(LuaCore.lua_State luaState) + { + LuaCore.lua_CFunction func = (LuaCore.lua_CFunction)translator.getRawNetObject(luaState, 1); + LuaLib.lua_remove(luaState, 1); + return func(luaState); + } + + /* + * __gc metafunction of CLR objects. + */ + private int collectObject(LuaCore.lua_State luaState) + { + int udata = LuaLib.luanet_rawnetobj(luaState, 1); + + if(udata != -1) + translator.collectObject(udata); + else + { + // Debug.WriteLine("not found: " + udata); + } + + return 0; + } + + /* + * __tostring metafunction of CLR objects. + */ + private int toString(LuaCore.lua_State luaState) + { + object obj = translator.getRawNetObject(luaState, 1); + + if(!obj.IsNull()) + translator.push(luaState, obj.ToString() + ": " + obj.GetHashCode()); + else + LuaLib.lua_pushnil(luaState); + + return 1; + } + + + /// + /// Debug tool to dump the lua stack + /// + /// FIXME, move somewhere else + public static void dumpStack(ObjectTranslator translator, LuaCore.lua_State luaState) + { + int depth = LuaLib.lua_gettop(luaState); + Debug.WriteLine("lua stack depth: " + depth); + + for(int i = 1; i <= depth; i++) + { + var type = LuaLib.lua_type(luaState, i); + // we dump stacks when deep in calls, calling typename while the stack is in flux can fail sometimes, so manually check for key types + string typestr = (type == LuaTypes.Table) ? "table" : LuaLib.lua_typename(luaState, type); + string strrep = LuaLib.lua_tostring(luaState, i).ToString(); + + if(type == LuaTypes.UserData) + { + object obj = translator.getRawNetObject(luaState, i); + strrep = obj.ToString(); + } + + Debug.Print("{0}: ({1}) {2}", i, typestr, strrep); + } + } + + /* + * Called by the __index metafunction of CLR objects in case the + * method is not cached or it is a field/property/event. + * Receives the object and the member name as arguments and returns + * either the value of the member or a delegate to call it. + * If the member does not exist returns nil. + */ + private int getMethod(LuaCore.lua_State luaState) + { + object obj = translator.getRawNetObject(luaState, 1); + + if(obj.IsNull()) + { + translator.throwError(luaState, "trying to index an invalid object reference"); + LuaLib.lua_pushnil(luaState); + return 1; + } + + object index = translator.getObject(luaState, 2); + //var indexType = index.GetType(); + string methodName = index as string; // will be null if not a string arg + var objType = obj.GetType(); + + // Handle the most common case, looking up the method by name. + + // CP: This will fail when using indexers and attempting to get a value with the same name as a property of the object, + // ie: xmlelement['item'] <- item is a property of xmlelement + try + { + if(!methodName.IsNull() && isMemberPresent(objType, methodName)) + return getMember(luaState, objType, obj, methodName, BindingFlags.Instance | BindingFlags.IgnoreCase); + } + catch + { + } + + // Try to access by array if the type is right and index is an int (lua numbers always come across as double) + if(objType.IsArray && index is double) + { + int intIndex = (int)((double)index); + + if(objType.UnderlyingSystemType == typeof(float[])) + { + float[] arr = ((float[])obj); + translator.push(luaState, arr[intIndex]); + } + else if(objType.UnderlyingSystemType == typeof(double[])) + { + double[] arr = ((double[])obj); + translator.push(luaState, arr[intIndex]); + } + else if(objType.UnderlyingSystemType == typeof(int[])) + { + int[] arr = ((int[])obj); + translator.push(luaState, arr[intIndex]); + } + else + { + object[] arr = (object[])obj; + translator.push(luaState, arr[intIndex]); + } + } + else + { + // Try to use get_Item to index into this .net object + //MethodInfo getter = objType.GetMethod("get_Item"); + var methods = objType.GetMethods(); + + foreach(var mInfo in methods) + { + if(mInfo.Name == "get_Item") + { + //check if the signature matches the input + if(mInfo.GetParameters().Length == 1) + { + var getter = mInfo; + var actualParms = (!getter.IsNull()) ? getter.GetParameters() : null; + + if(actualParms.IsNull() || actualParms.Length != 1) + { + translator.throwError(luaState, "method not found (or no indexer): " + index); + LuaLib.lua_pushnil(luaState); + } + else + { + // Get the index in a form acceptable to the getter + index = translator.getAsType(luaState, 2, actualParms[0].ParameterType); + object[] args = new object[1]; + + // Just call the indexer - if out of bounds an exception will happen + args[0] = index; + + try + { + object result = getter.Invoke(obj, args); + translator.push(luaState, result); + } + catch(TargetInvocationException e) + { + // Provide a more readable description for the common case of key not found + if(e.InnerException is KeyNotFoundException) + translator.throwError(luaState, "key '" + index + "' not found "); + else + translator.throwError(luaState, "exception indexing '" + index + "' " + e.Message); + + LuaLib.lua_pushnil(luaState); + } + } + } + } + } + } + + LuaLib.lua_pushboolean(luaState, false); + return 2; + } + + /* + * __index metafunction of base classes (the base field of Lua tables). + * Adds a prefix to the method name to call the base version of the method. + */ + private int getBaseMethod(LuaCore.lua_State luaState) + { + object obj = translator.getRawNetObject(luaState, 1); + + if(obj.IsNull()) + { + translator.throwError(luaState, "trying to index an invalid object reference"); + LuaLib.lua_pushnil(luaState); + LuaLib.lua_pushboolean(luaState, false); + return 2; + } + + string methodName = LuaLib.lua_tostring(luaState, 2).ToString(); + + if(methodName.IsNull()) + { + LuaLib.lua_pushnil(luaState); + LuaLib.lua_pushboolean(luaState, false); + return 2; + } + + getMember(luaState, obj.GetType(), obj, "__luaInterface_base_" + methodName, BindingFlags.Instance | BindingFlags.IgnoreCase); + LuaLib.lua_settop(luaState, -2); + + if(LuaLib.lua_type(luaState, -1) == LuaTypes.Nil) + { + LuaLib.lua_settop(luaState, -2); + return getMember(luaState, obj.GetType(), obj, methodName, BindingFlags.Instance | BindingFlags.IgnoreCase); + } + + LuaLib.lua_pushboolean(luaState, false); + return 2; + } + + /// + /// Does this method exist as either an instance or static? + /// + /// + /// + /// + bool isMemberPresent(IReflect objType, string methodName) + { + object cachedMember = checkMemberCache(memberCache, objType, methodName); + + if(!cachedMember.IsNull()) + return true; + + //CP: Removed NonPublic binding search + var members = objType.GetMember(methodName, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase/* | BindingFlags.NonPublic*/); + return (members.Length > 0); + } + + /* + * Pushes the value of a member or a delegate to call it, depending on the type of + * the member. Works with static or instance members. + * Uses reflection to find members, and stores the reflected MemberInfo object in + * a cache (indexed by the type of the object and the name of the member). + */ + private int getMember(LuaCore.lua_State luaState, IReflect objType, object obj, string methodName, BindingFlags bindingType) + { + bool implicitStatic = false; + MemberInfo member = null; + object cachedMember = checkMemberCache(memberCache, objType, methodName); + //object cachedMember=null; + + if(cachedMember is LuaCore.lua_CFunction) + { + translator.pushFunction(luaState, (LuaCore.lua_CFunction)cachedMember); + translator.push(luaState, true); + return 2; + } + else if(!cachedMember.IsNull()) + member = (MemberInfo)cachedMember; + else + { + //CP: Removed NonPublic binding search + var members = objType.GetMember(methodName, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase/*| BindingFlags.NonPublic*/); + + if(members.Length > 0) + member = members[0]; + else + { + // If we can't find any suitable instance members, try to find them as statics - but we only want to allow implicit static + // lookups for fields/properties/events -kevinh + //CP: Removed NonPublic binding search and made case insensitive + members = objType.GetMember(methodName, bindingType | BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase/*| BindingFlags.NonPublic*/); + + if(members.Length > 0) + { + member = members[0]; + implicitStatic = true; + } + } + } + + if(!member.IsNull()) + { + if(member.MemberType == MemberTypes.Field) + { + var field = (FieldInfo)member; + + if(cachedMember.IsNull()) + setMemberCache(memberCache, objType, methodName, member); + + try + { + translator.push(luaState, field.GetValue(obj)); + } + catch + { + LuaLib.lua_pushnil(luaState); + } + } + else if(member.MemberType == MemberTypes.Property) + { + var property = (PropertyInfo)member; + if(cachedMember.IsNull()) + setMemberCache(memberCache, objType, methodName, member); + + try + { + object val = property.GetValue(obj, null); + translator.push(luaState, val); + } + catch(ArgumentException) + { + // If we can't find the getter in our class, recurse up to the base class and see + // if they can help. + if(objType is Type && !(((Type)objType) == typeof(object))) + return getMember(luaState, ((Type)objType).BaseType, obj, methodName, bindingType); + else + LuaLib.lua_pushnil(luaState); + } + catch(TargetInvocationException e) // Convert this exception into a Lua error + { + ThrowError(luaState, e); + LuaLib.lua_pushnil(luaState); + } + } + else if(member.MemberType == MemberTypes.Event) + { + var eventInfo = (EventInfo)member; + if(cachedMember.IsNull()) + setMemberCache(memberCache, objType, methodName, member); + + translator.push(luaState, new RegisterEventHandler(translator.pendingEvents, obj, eventInfo)); + } + else if(!implicitStatic) + { + if(member.MemberType == MemberTypes.NestedType) + { + // kevinh - added support for finding nested types + // cache us + if(cachedMember.IsNull()) + setMemberCache(memberCache, objType, methodName, member); + + // Find the name of our class + string name = member.Name; + var dectype = member.DeclaringType; + + // Build a new long name and try to find the type by name + string longname = dectype.FullName + "+" + name; + var nestedType = translator.FindType(longname); + translator.pushType(luaState, nestedType); + } + else + { + // Member type must be 'method' + var wrapper = new LuaCore.lua_CFunction((new LuaMethodWrapper(translator, objType, methodName, bindingType)).call); + + if(cachedMember.IsNull()) + setMemberCache(memberCache, objType, methodName, wrapper); + + translator.pushFunction(luaState, wrapper); + translator.push(luaState, true); + return 2; + } + } + else + { + // If we reach this point we found a static method, but can't use it in this context because the user passed in an instance + translator.throwError(luaState, "can't pass instance to static method " + methodName); + LuaLib.lua_pushnil(luaState); + } + } + else + { + // kevinh - we want to throw an exception because meerly returning 'nil' in this case + // is not sufficient. valid data members may return nil and therefore there must be some + // way to know the member just doesn't exist. + translator.throwError(luaState, "unknown member name " + methodName); + LuaLib.lua_pushnil(luaState); + } + + // push false because we are NOT returning a function (see luaIndexFunction) + translator.push(luaState, false); + return 2; + } + + /* + * Checks if a MemberInfo object is cached, returning it or null. + */ + private object checkMemberCache(Hashtable memberCache, IReflect objType, string memberName) + { + var members = (Hashtable)memberCache[objType]; + return !members.IsNull() ? members[memberName] : null; + } + + /* + * Stores a MemberInfo object in the member cache. + */ + private void setMemberCache(Hashtable memberCache, IReflect objType, string memberName, object member) + { + var members = (Hashtable)memberCache[objType]; + + if(members.IsNull()) + { + members = new Hashtable(); + memberCache[objType] = members; + } + + members[memberName] = member; + } + + /* + * __newindex metafunction of CLR objects. Receives the object, + * the member name and the value to be stored as arguments. Throws + * and error if the assignment is invalid. + */ + private int setFieldOrProperty(LuaCore.lua_State luaState) + { + object target = translator.getRawNetObject(luaState, 1); + + if(target.IsNull()) + { + translator.throwError(luaState, "trying to index and invalid object reference"); + return 0; + } + + var type = target.GetType(); + + // First try to look up the parameter as a property name + string detailMessage; + bool didMember = trySetMember(luaState, type, target, BindingFlags.Instance | BindingFlags.IgnoreCase, out detailMessage); + + if(didMember) + return 0; // Must have found the property name + + // We didn't find a property name, now see if we can use a [] style this accessor to set array contents + try + { + if(type.IsArray && LuaLib.lua_isnumber(luaState, 2)) + { + int index = (int)LuaLib.lua_tonumber(luaState, 2); + var arr = (Array)target; + object val = translator.getAsType(luaState, 3, arr.GetType().GetElementType()); + arr.SetValue(val, index); + } + else + { + // Try to see if we have a this[] accessor + var setter = type.GetMethod("set_Item"); + if(!setter.IsNull()) + { + var args = setter.GetParameters(); + var valueType = args[1].ParameterType; + + // The new val ue the user specified + object val = translator.getAsType(luaState, 3, valueType); + var indexType = args[0].ParameterType; + object index = translator.getAsType(luaState, 2, indexType); + + object[] methodArgs = new object[2]; + + // Just call the indexer - if out of bounds an exception will happen + methodArgs[0] = index; + methodArgs[1] = val; + setter.Invoke(target, methodArgs); + } + else + translator.throwError(luaState, detailMessage); // Pass the original message from trySetMember because it is probably best + } + } + catch(SEHException) + { + // If we are seeing a C++ exception - this must actually be for Lua's private use. Let it handle it + throw; + } + catch(Exception e) + { + ThrowError(luaState, e); + } + + return 0; + } + + /// + /// Tries to set a named property or field + /// + /// + /// + /// + /// + /// false if unable to find the named member, true for success + private bool trySetMember(LuaCore.lua_State luaState, IReflect targetType, object target, BindingFlags bindingType, out string detailMessage) + { + detailMessage = null; // No error yet + + // If not already a string just return - we don't want to call tostring - which has the side effect of + // changing the lua typecode to string + // Note: We don't use isstring because the standard lua C isstring considers either strings or numbers to + // be true for isstring. + if(LuaLib.lua_type(luaState, 2) != LuaTypes.String) + { + detailMessage = "property names must be strings"; + return false; + } + + // We only look up property names by string + string fieldName = LuaLib.lua_tostring(luaState, 2).ToString(); + if(fieldName.IsNull() || fieldName.Length < 1 || !(char.IsLetter(fieldName[0]) || fieldName[0] == '_')) + { + detailMessage = "invalid property name"; + return false; + } + + // Find our member via reflection or the cache + var member = (MemberInfo)checkMemberCache(memberCache, targetType, fieldName); + if(member.IsNull()) + { + //CP: Removed NonPublic binding search and made case insensitive + var members = targetType.GetMember(fieldName, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase/*| BindingFlags.NonPublic*/); + + if(members.Length > 0) + { + member = members[0]; + setMemberCache(memberCache, targetType, fieldName, member); + } + else + { + detailMessage = "field or property '" + fieldName + "' does not exist"; + return false; + } + } + + if(member.MemberType == MemberTypes.Field) + { + var field = (FieldInfo)member; + object val = translator.getAsType(luaState, 3, field.FieldType); + + try + { + field.SetValue(target, val); + } + catch (Exception e) + { + ThrowError(luaState, e); + } + + // We did a call + return true; + } + else if(member.MemberType == MemberTypes.Property) + { + var property = (PropertyInfo)member; + object val = translator.getAsType(luaState, 3, property.PropertyType); + + try + { + property.SetValue(target, val, null); + } + catch (Exception e) + { + ThrowError(luaState, e); + } + + // We did a call + return true; + } + + detailMessage = "'" + fieldName + "' is not a .net field or property"; + return false; + } + + /* + * Writes to fields or properties, either static or instance. Throws an error + * if the operation is invalid. + */ + private int setMember(LuaCore.lua_State luaState, IReflect targetType, object target, BindingFlags bindingType) + { + string detail; + bool success = trySetMember(luaState, targetType, target, bindingType, out detail); + + if(!success) + translator.throwError(luaState, detail); + + return 0; + } + + /// + /// Convert a C# exception into a Lua error + /// + /// + /// We try to look into the exception to give the most meaningful description + void ThrowError(LuaCore.lua_State luaState, Exception e) + { + // If we got inside a reflection show what really happened + var te = e as TargetInvocationException; + + if (!te.IsNull()) + e = te.InnerException; + + translator.throwError(luaState, e); + } + + /* + * __index metafunction of type references, works on static members. + */ + private int getClassMethod(LuaCore.lua_State luaState) + { + IReflect klass; + object obj = translator.getRawNetObject(luaState, 1); + + if(obj.IsNull() || !(obj is IReflect)) + { + translator.throwError(luaState, "trying to index an invalid type reference"); + LuaLib.lua_pushnil(luaState); + return 1; + } + else + klass = (IReflect)obj; + + if(LuaLib.lua_isnumber(luaState, 2)) + { + int size = (int)LuaLib.lua_tonumber(luaState, 2); + translator.push(luaState, Array.CreateInstance(klass.UnderlyingSystemType, size)); + return 1; + } + else + { + string methodName = LuaLib.lua_tostring(luaState, 2).ToString(); + + if(methodName.IsNull()) + { + LuaLib.lua_pushnil(luaState); + return 1; + } //CP: Ignore case + else + return getMember(luaState, klass, null, methodName, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.IgnoreCase); + } + } + + /* + * __newindex function of type references, works on static members. + */ + private int setClassFieldOrProperty(LuaCore.lua_State luaState) + { + IReflect target; + object obj = translator.getRawNetObject(luaState, 1); + + if(obj.IsNull() || !(obj is IReflect)) + { + translator.throwError(luaState, "trying to index an invalid type reference"); + return 0; + } + else + target = (IReflect)obj; + + return setMember(luaState, target, null, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.IgnoreCase); + } + + /* + * __call metafunction of type references. Searches for and calls + * a constructor for the type. Returns nil if the constructor is not + * found or if the arguments are invalid. Throws an error if the constructor + * generates an exception. + */ + private int callConstructor(LuaCore.lua_State luaState) + { + var validConstructor = new MethodCache(); + IReflect klass; + object obj = translator.getRawNetObject(luaState, 1); + + if(obj.IsNull() || !(obj is IReflect)) + { + translator.throwError(luaState, "trying to call constructor on an invalid type reference"); + LuaLib.lua_pushnil(luaState); + return 1; + } + else + klass = (IReflect)obj; + + LuaLib.lua_remove(luaState, 1); + var constructors = klass.UnderlyingSystemType.GetConstructors(); + + foreach(var constructor in constructors) + { + bool isConstructor = matchParameters(luaState, constructor, ref validConstructor); + + if(isConstructor) + { + try + { + translator.push(luaState, constructor.Invoke(validConstructor.args)); + } + catch(TargetInvocationException e) + { + ThrowError(luaState, e); + LuaLib.lua_pushnil(luaState); + } + catch + { + LuaLib.lua_pushnil(luaState); + } + + return 1; + } + } + + string constructorName = (constructors.Length == 0) ? "unknown" : constructors[0].Name; + translator.throwError(luaState, String.Format("{0} does not contain constructor({1}) argument match", + klass.UnderlyingSystemType, constructorName)); + LuaLib.lua_pushnil(luaState); + return 1; + } + + /* + * Matches a method against its arguments in the Lua stack. Returns + * if the match was succesful. It it was also returns the information + * necessary to invoke the method. + */ + internal bool matchParameters(LuaCore.lua_State luaState, MethodBase method, ref MethodCache methodCache) + { + ExtractValue extractValue; + bool isMethod = true; + var paramInfo = method.GetParameters(); + int currentLuaParam = 1; + int nLuaParams = LuaLib.lua_gettop(luaState); + var paramList = new ArrayList(); + var outList = new List(); + var argTypes = new List(); + + foreach(var currentNetParam in paramInfo) + { + if(!currentNetParam.IsIn && currentNetParam.IsOut) // Skips out params + outList.Add(paramList.Add(null)); + else if(currentLuaParam > nLuaParams) // Adds optional parameters + { + if(currentNetParam.IsOptional) + paramList.Add(currentNetParam.DefaultValue); + else + { + isMethod = false; + break; + } + } + else if(_IsTypeCorrect(luaState, currentLuaParam, currentNetParam, out extractValue)) // Type checking + { + int index = paramList.Add(extractValue(luaState, currentLuaParam)); + var methodArg = new MethodArgs(); + methodArg.index = index; + methodArg.extractValue = extractValue; + argTypes.Add(methodArg); + + if(currentNetParam.ParameterType.IsByRef) + outList.Add(index); + + currentLuaParam++; + } // Type does not match, ignore if the parameter is optional + else if(_IsParamsArray(luaState, currentLuaParam, currentNetParam, out extractValue)) + { + object luaParamValue = extractValue(luaState, currentLuaParam); + var paramArrayType = currentNetParam.ParameterType.GetElementType(); + Array paramArray; + + if(luaParamValue is LuaTable) + { + var table = (LuaTable)luaParamValue; + var tableEnumerator = table.GetEnumerator(); + paramArray = Array.CreateInstance(paramArrayType, table.Values.Count); + tableEnumerator.Reset(); + int paramArrayIndex = 0; + + while(tableEnumerator.MoveNext()) + { + paramArray.SetValue(Convert.ChangeType(tableEnumerator.Value, currentNetParam.ParameterType.GetElementType()), paramArrayIndex); + paramArrayIndex++; + } + } + else + { + paramArray = Array.CreateInstance(paramArrayType, 1); + paramArray.SetValue(luaParamValue, 0); + } + + int index = paramList.Add(paramArray); + var methodArg = new MethodArgs(); + methodArg.index = index; + methodArg.extractValue = extractValue; + methodArg.isParamsArray = true; + methodArg.paramsArrayType = paramArrayType; + argTypes.Add(methodArg); + currentLuaParam++; + } + else if(currentNetParam.IsOptional) + paramList.Add(currentNetParam.DefaultValue); + else // No match + { + isMethod = false; + break; + } + } + + if(currentLuaParam != nLuaParams + 1) // Number of parameters does not match + isMethod = false; + if(isMethod) + { + methodCache.args = paramList.ToArray(); + methodCache.cachedMethod = method; + methodCache.outList = outList.ToArray(); + methodCache.argTypes = argTypes.ToArray(); + } + + return isMethod; + } + + /// + /// CP: Fix for operator overloading failure + /// Returns true if the type is set and assigns the extract value + /// + /// + /// + /// + /// + /// + private bool _IsTypeCorrect(LuaCore.lua_State luaState, int currentLuaParam, ParameterInfo currentNetParam, out ExtractValue extractValue) + { + try + { + return (extractValue = translator.typeChecker.checkType(luaState, currentLuaParam, currentNetParam.ParameterType)) != null; + } + catch + { + extractValue = null; + Debug.WriteLine("Type wasn't correct"); + return false; + } + } + + private bool _IsParamsArray(LuaCore.lua_State luaState, int currentLuaParam, ParameterInfo currentNetParam, out ExtractValue extractValue) + { + extractValue = null; + + if (currentNetParam.GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0) + { + LuaTypes luaType; + + try + { + luaType = LuaLib.lua_type(luaState, currentLuaParam); + } + catch(Exception ex) + { + Debug.WriteLine("Could not retrieve lua type while attempting to determine params Array Status."); + Debug.WriteLine(ex.Message); + extractValue = null; + return false; + } + + if(luaType == LuaTypes.Table) + { + try + { + extractValue = translator.typeChecker.getExtractor(typeof(LuaTable)); + } + catch(Exception/* ex*/) + { + Debug.WriteLine("An error occurred during an attempt to retrieve a LuaTable extractor while checking for params array status."); + } + + if(!extractValue.IsNull()) + { + return true; + } + } + else + { + var paramElementType = currentNetParam.ParameterType.GetElementType(); + + try + { + extractValue = translator.typeChecker.checkType(luaState, currentLuaParam, paramElementType); + } + catch (Exception/* ex*/) + { + Debug.WriteLine(string.Format("An error occurred during an attempt to retrieve an extractor ({0}) while checking for params array status.", paramElementType.FullName)); + } + + if(!extractValue.IsNull()) + { + return true; + } + } + } + + Debug.WriteLine("Type wasn't Params object."); + return false; + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/Method/EventHandlerContainer.cs b/Core/LuaInterface/Method/EventHandlerContainer.cs index 21ce6ecb6d8e700cecfc466923b36908ea0b1c8e..9fdc11865b10f9cf76edae68bcf1a1cd4d86b120 100644 --- a/Core/LuaInterface/Method/EventHandlerContainer.cs +++ b/Core/LuaInterface/Method/EventHandlerContainer.cs @@ -1,61 +1,61 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Diagnostics; -using System.Collections.Generic; - -namespace LuaInterface.Method -{ - /// - /// We keep track of what delegates we have auto attached to an event - to allow us to cleanly exit a LuaInterface session - /// - class EventHandlerContainer : IDisposable - { - private Dictionary dict = new Dictionary(); - - public void Add(Delegate handler, RegisterEventHandler eventInfo) - { - dict.Add(handler, eventInfo); - } - - public void Remove(Delegate handler) - { - bool found = dict.Remove(handler); - Debug.Assert(found); - } - - /// - /// Remove any still registered handlers - /// - public void Dispose() - { - foreach(KeyValuePair pair in dict) - pair.Value.RemovePending(pair.Key); - - dict.Clear(); - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Diagnostics; +using System.Collections.Generic; + +namespace LuaInterface.Method +{ + /// + /// We keep track of what delegates we have auto attached to an event - to allow us to cleanly exit a LuaInterface session + /// + class EventHandlerContainer : IDisposable + { + private Dictionary dict = new Dictionary(); + + public void Add(Delegate handler, RegisterEventHandler eventInfo) + { + dict.Add(handler, eventInfo); + } + + public void Remove(Delegate handler) + { + bool found = dict.Remove(handler); + Debug.Assert(found); + } + + /// + /// Remove any still registered handlers + /// + public void Dispose() + { + foreach(KeyValuePair pair in dict) + pair.Value.RemovePending(pair.Key); + + dict.Clear(); + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/Method/LuaClassHelper.cs b/Core/LuaInterface/Method/LuaClassHelper.cs index 119ff94d781e451d273fb470344cbeb32fb33d4b..62dd32b50a4b30a6a399c1b9a80b76868871239f 100644 --- a/Core/LuaInterface/Method/LuaClassHelper.cs +++ b/Core/LuaInterface/Method/LuaClassHelper.cs @@ -1,84 +1,84 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface.Method -{ - /* - * Static helper methods for Lua tables acting as CLR objects. - * - * Author: Fabio Mascarenhas - * Version: 1.0 - */ - public class LuaClassHelper - { - /* - * Gets the function called name from the provided table, - * returning null if it does not exist - */ - public static LuaFunction getTableFunction(LuaTable luaTable, string name) - { - object funcObj = luaTable.rawget(name); - - if(funcObj is LuaFunction) - return (LuaFunction)funcObj; - else - return null; - } - - /* - * Calls the provided function with the provided parameters - */ - public static object callFunction(LuaFunction function, object[] args, Type[] returnTypes, object[] inArgs, int[] outArgs) - { - // args is the return array of arguments, inArgs is the actual array - // of arguments passed to the function (with in parameters only), outArgs - // has the positions of out parameters - object returnValue; - int iRefArgs; - object[] returnValues = function.call(inArgs, returnTypes); - - if(returnTypes[0] == typeof(void)) - { - returnValue = null; - iRefArgs = 0; - } - else - { - returnValue = returnValues[0]; - iRefArgs = 1; - } - - for(int i = 0; i < outArgs.Length; i++) - { - args[outArgs[i]] = returnValues[iRefArgs]; - iRefArgs++; - } - - return returnValue; - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface.Method +{ + /* + * Static helper methods for Lua tables acting as CLR objects. + * + * Author: Fabio Mascarenhas + * Version: 1.0 + */ + public class LuaClassHelper + { + /* + * Gets the function called name from the provided table, + * returning null if it does not exist + */ + public static LuaFunction getTableFunction(LuaTable luaTable, string name) + { + object funcObj = luaTable.rawget(name); + + if(funcObj is LuaFunction) + return (LuaFunction)funcObj; + else + return null; + } + + /* + * Calls the provided function with the provided parameters + */ + public static object callFunction(LuaFunction function, object[] args, Type[] returnTypes, object[] inArgs, int[] outArgs) + { + // args is the return array of arguments, inArgs is the actual array + // of arguments passed to the function (with in parameters only), outArgs + // has the positions of out parameters + object returnValue; + int iRefArgs; + object[] returnValues = function.call(inArgs, returnTypes); + + if(returnTypes[0] == typeof(void)) + { + returnValue = null; + iRefArgs = 0; + } + else + { + returnValue = returnValues[0]; + iRefArgs = 1; + } + + for(int i = 0; i < outArgs.Length; i++) + { + args[outArgs[i]] = returnValues[iRefArgs]; + iRefArgs++; + } + + return returnValue; + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/Method/LuaDelegate.cs b/Core/LuaInterface/Method/LuaDelegate.cs index 740950505a6d802ac434a5ba189402c5565a00ec..fb203746059c2af5603d7af08fba95caa7bc2e94 100644 --- a/Core/LuaInterface/Method/LuaDelegate.cs +++ b/Core/LuaInterface/Method/LuaDelegate.cs @@ -1,80 +1,80 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface.Method -{ - /* - * Wrapper class for Lua functions as delegates - * Subclasses with correct signatures are created - * at runtime. - * - * Author: Fabio Mascarenhas - * Version: 1.0 - */ - public class LuaDelegate - { - public LuaFunction function; - public Type[] returnTypes; - - public LuaDelegate() - { - function = null; - returnTypes = null; - } - - public object callFunction(object[] args, object[] inArgs, int[] outArgs) - { - // args is the return array of arguments, inArgs is the actual array - // of arguments passed to the function (with in parameters only), outArgs - // has the positions of out parameters - object returnValue; - int iRefArgs; - object[] returnValues = function.call(inArgs, returnTypes); - - if(returnTypes[0] == typeof(void)) - { - returnValue = null; - iRefArgs = 0; - } - else - { - returnValue = returnValues[0]; - iRefArgs = 1; - } - - // Sets the value of out and ref parameters (from - // the values returned by the Lua function). - for(int i = 0; i < outArgs.Length; i++) - { - args[outArgs[i]] = returnValues[iRefArgs]; - iRefArgs++; - } - - return returnValue; - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface.Method +{ + /* + * Wrapper class for Lua functions as delegates + * Subclasses with correct signatures are created + * at runtime. + * + * Author: Fabio Mascarenhas + * Version: 1.0 + */ + public class LuaDelegate + { + public LuaFunction function; + public Type[] returnTypes; + + public LuaDelegate() + { + function = null; + returnTypes = null; + } + + public object callFunction(object[] args, object[] inArgs, int[] outArgs) + { + // args is the return array of arguments, inArgs is the actual array + // of arguments passed to the function (with in parameters only), outArgs + // has the positions of out parameters + object returnValue; + int iRefArgs; + object[] returnValues = function.call(inArgs, returnTypes); + + if(returnTypes[0] == typeof(void)) + { + returnValue = null; + iRefArgs = 0; + } + else + { + returnValue = returnValues[0]; + iRefArgs = 1; + } + + // Sets the value of out and ref parameters (from + // the values returned by the Lua function). + for(int i = 0; i < outArgs.Length; i++) + { + args[outArgs[i]] = returnValues[iRefArgs]; + iRefArgs++; + } + + return returnValue; + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/Method/LuaEventHandler.cs b/Core/LuaInterface/Method/LuaEventHandler.cs index f12c1c2873215c3fb0a203e293eabb365b3d18ff..ac9182681b77e8af23c1d8a1e558231c877fe4be 100644 --- a/Core/LuaInterface/Method/LuaEventHandler.cs +++ b/Core/LuaInterface/Method/LuaEventHandler.cs @@ -1,53 +1,53 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface.Method -{ - /* - * Base wrapper class for Lua function event handlers. - * Subclasses that do actual event handling are created - * at runtime. - * - * Author: Fabio Mascarenhas - * Version: 1.0 - */ - public class LuaEventHandler - { - public LuaFunction handler = null; - - // CP: Fix provided by Ben Bryant for delegates with one param - // link: http://luaforge.net/forum/message.php?msg_id=9318 - public void handleEvent(object[] args) - { - handler.Call(args); - } - //public void handleEvent(object sender,object data) - //{ - // handler.call(new object[] { sender,data },new Type[0]); - //} - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface.Method +{ + /* + * Base wrapper class for Lua function event handlers. + * Subclasses that do actual event handling are created + * at runtime. + * + * Author: Fabio Mascarenhas + * Version: 1.0 + */ + public class LuaEventHandler + { + public LuaFunction handler = null; + + // CP: Fix provided by Ben Bryant for delegates with one param + // link: http://luaforge.net/forum/message.php?msg_id=9318 + public void handleEvent(object[] args) + { + handler.Call(args); + } + //public void handleEvent(object sender,object data) + //{ + // handler.call(new object[] { sender,data },new Type[0]); + //} + } } \ No newline at end of file diff --git a/Core/LuaInterface/Method/LuaMethodWrapper.cs b/Core/LuaInterface/Method/LuaMethodWrapper.cs index f5e892f2fe923be043bb9ead475924055cc8544e..dfaf8fd6836efcd75db6d1e7f5a86efa063d58da 100644 --- a/Core/LuaInterface/Method/LuaMethodWrapper.cs +++ b/Core/LuaInterface/Method/LuaMethodWrapper.cs @@ -1,335 +1,335 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Reflection; -using System.Collections.Generic; -using LuaInterface.Exceptions; -using LuaInterface.Extensions; - -namespace LuaInterface.Method -{ - using LuaCore = KopiLua.Lua; - - /* - * Argument extraction with type-conversion function - */ - delegate object ExtractValue(LuaCore.lua_State luaState, int stackPos); - - /* - * Wrapper class for methods/constructors accessed from Lua. - * - * Author: Fabio Mascarenhas - * Version: 1.0 - */ - class LuaMethodWrapper - { - private ObjectTranslator _Translator; - private MethodBase _Method; - private MethodCache _LastCalledMethod = new MethodCache(); - private string _MethodName; - private MemberInfo[] _Members; - private IReflect _TargetType; - private ExtractValue _ExtractTarget; - private object _Target; - private BindingFlags _BindingType; - - /* - * Constructs the wrapper for a known MethodBase instance - */ - public LuaMethodWrapper(ObjectTranslator translator, object target, IReflect targetType, MethodBase method) - { - _Translator = translator; - _Target = target; - _TargetType = targetType; - - if(!targetType.IsNull()) - _ExtractTarget = translator.typeChecker.getExtractor(targetType); - - _Method = method; - _MethodName = method.Name; - - if(method.IsStatic) - _BindingType = BindingFlags.Static; - else - _BindingType = BindingFlags.Instance; - } - - /* - * Constructs the wrapper for a known method name - */ - public LuaMethodWrapper(ObjectTranslator translator, IReflect targetType, string methodName, BindingFlags bindingType) - { - _Translator = translator; - _MethodName = methodName; - _TargetType = targetType; - - if(!targetType.IsNull()) - _ExtractTarget = translator.typeChecker.getExtractor(targetType); - - _BindingType = bindingType; - //CP: Removed NonPublic binding search and added IgnoreCase - _Members = targetType.UnderlyingSystemType.GetMember(methodName, MemberTypes.Method, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase/*|BindingFlags.NonPublic*/); - } - - /// - /// Convert C# exceptions into Lua errors - /// - /// num of things on stack - /// null for no pending exception - int SetPendingException(Exception e) - { - return _Translator.interpreter.SetPendingException(e); - } - - /* - * Calls the method. Receives the arguments from the Lua stack - * and returns values in it. - */ - public int call(LuaCore.lua_State luaState) - { - var methodToCall = _Method; - object targetObject = _Target; - bool failedCall = true; - int nReturnValues = 0; - - if(!LuaLib.lua_checkstack(luaState, 5)) - throw new LuaException("Lua stack overflow"); - - bool isStatic = (_BindingType & BindingFlags.Static) == BindingFlags.Static; - SetPendingException(null); - - if(methodToCall.IsNull()) // Method from name - { - if(isStatic) - targetObject = null; - else - targetObject = _ExtractTarget(luaState, 1); - - //LuaLib.lua_remove(luaState,1); // Pops the receiver - if(!_LastCalledMethod.cachedMethod.IsNull()) // Cached? - { - int numStackToSkip = isStatic ? 0 : 1; // If this is an instance invoe we will have an extra arg on the stack for the targetObject - int numArgsPassed = LuaLib.lua_gettop(luaState) - numStackToSkip; - - if(numArgsPassed == _LastCalledMethod.argTypes.Length) // No. of args match? - { - if(!LuaLib.lua_checkstack(luaState, _LastCalledMethod.outList.Length + 6)) - throw new LuaException("Lua stack overflow"); - - try - { - for(int i = 0; i < _LastCalledMethod.argTypes.Length; i++) - { - if(_LastCalledMethod.argTypes[i].isParamsArray) - { - object luaParamValue = _LastCalledMethod.argTypes[i].extractValue(luaState, i + 1 + numStackToSkip); - var paramArrayType = _LastCalledMethod.argTypes[i].paramsArrayType; - Array paramArray; - - if(luaParamValue is LuaTable) - { - var table = (LuaTable)luaParamValue; - paramArray = Array.CreateInstance(paramArrayType, table.Values.Count); - - for(int x = 1; x <= table.Values.Count; x++) - paramArray.SetValue(Convert.ChangeType(table[x], paramArrayType), x - 1); - } - else - { - paramArray = Array.CreateInstance(paramArrayType, 1); - paramArray.SetValue(luaParamValue, 0); - } - - _LastCalledMethod.args[_LastCalledMethod.argTypes[i].index] = paramArray; - } - else - { - _LastCalledMethod.args[_LastCalledMethod.argTypes[i].index] = - _LastCalledMethod.argTypes[i].extractValue(luaState, i + 1 + numStackToSkip); - } - - if(_LastCalledMethod.args[_LastCalledMethod.argTypes[i].index] == null && - !LuaLib.lua_isnil(luaState, i + 1 + numStackToSkip)) - throw new LuaException("argument number " + (i + 1) + " is invalid"); - } - - if((_BindingType & BindingFlags.Static) == BindingFlags.Static) - _Translator.push(luaState, _LastCalledMethod.cachedMethod.Invoke(null, _LastCalledMethod.args)); - else - { - if(_LastCalledMethod.cachedMethod.IsConstructor) - _Translator.push(luaState, ((ConstructorInfo)_LastCalledMethod.cachedMethod).Invoke(_LastCalledMethod.args)); - else - _Translator.push(luaState, _LastCalledMethod.cachedMethod.Invoke(targetObject, _LastCalledMethod.args)); - } - - failedCall = false; - } - catch(TargetInvocationException e) - { - // Failure of method invocation - return SetPendingException(e.GetBaseException()); - } - catch(Exception e) - { - if(_Members.Length == 1) // Is the method overloaded? - // No, throw error - return SetPendingException(e); - } - } - } - - // Cache miss - if(failedCall) - { - // System.Diagnostics.Debug.WriteLine("cache miss on " + methodName); - // If we are running an instance variable, we can now pop the targetObject from the stack - if(!isStatic) - { - if(targetObject.IsNull()) - { - _Translator.throwError(luaState, String.Format("instance method '{0}' requires a non null target object", _MethodName)); - LuaLib.lua_pushnil(luaState); - return 1; - } - - LuaLib.lua_remove(luaState, 1); // Pops the receiver - } - - bool hasMatch = false; - string candidateName = null; - - foreach(var member in _Members) - { - candidateName = member.ReflectedType.Name + "." + member.Name; - var m = (MethodInfo)member; - bool isMethod = _Translator.matchParameters(luaState, m, ref _LastCalledMethod); - - if(isMethod) - { - hasMatch = true; - break; - } - } - - if(!hasMatch) - { - string msg = (candidateName == null) ? "invalid arguments to method call" : ("invalid arguments to method: " + candidateName); - _Translator.throwError(luaState, msg); - LuaLib.lua_pushnil(luaState); - return 1; - } - } - } - else // Method from MethodBase instance - { - if(methodToCall.ContainsGenericParameters) - { - /*bool isMethod = */_Translator.matchParameters(luaState, methodToCall, ref _LastCalledMethod); - - if(methodToCall.IsGenericMethodDefinition) - { - //need to make a concrete type of the generic method definition - var typeArgs = new List(); - - foreach(object arg in _LastCalledMethod.args) - typeArgs.Add(arg.GetType()); - - var concreteMethod = (methodToCall as MethodInfo).MakeGenericMethod(typeArgs.ToArray()); - _Translator.push(luaState, concreteMethod.Invoke(targetObject, _LastCalledMethod.args)); - failedCall = false; - } - else if(methodToCall.ContainsGenericParameters) - { - _Translator.throwError(luaState, "unable to invoke method on generic class as the current method is an open generic method"); - LuaLib.lua_pushnil(luaState); - return 1; - } - } - else - { - if(!methodToCall.IsStatic && !methodToCall.IsConstructor && targetObject == null) - { - targetObject = _ExtractTarget(luaState, 1); - LuaLib.lua_remove(luaState, 1); // Pops the receiver - } - - if(!_Translator.matchParameters(luaState, methodToCall, ref _LastCalledMethod)) - { - _Translator.throwError(luaState, "invalid arguments to method call"); - LuaLib.lua_pushnil(luaState); - return 1; - } - } - } - - if(failedCall) - { - if(!LuaLib.lua_checkstack(luaState, _LastCalledMethod.outList.Length + 6)) - throw new LuaException("Lua stack overflow"); - - try - { - if(isStatic) - _Translator.push(luaState, _LastCalledMethod.cachedMethod.Invoke(null, _LastCalledMethod.args)); - else - { - if(_LastCalledMethod.cachedMethod.IsConstructor) - _Translator.push(luaState, ((ConstructorInfo)_LastCalledMethod.cachedMethod).Invoke(_LastCalledMethod.args)); - else - _Translator.push(luaState, _LastCalledMethod.cachedMethod.Invoke(targetObject, _LastCalledMethod.args)); - } - } - catch(TargetInvocationException e) - { - return SetPendingException(e.GetBaseException()); - } - catch(Exception e) - { - return SetPendingException(e); - } - } - - // Pushes out and ref return values - for(int index = 0; index < _LastCalledMethod.outList.Length; index++) - { - nReturnValues++; - //for(int i=0;i 0) - nReturnValues++; - - return nReturnValues < 1 ? 1 : nReturnValues; - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Reflection; +using System.Collections.Generic; +using LuaInterface.Exceptions; +using LuaInterface.Extensions; + +namespace LuaInterface.Method +{ + using LuaCore = KopiLua.Lua; + + /* + * Argument extraction with type-conversion function + */ + delegate object ExtractValue(LuaCore.lua_State luaState, int stackPos); + + /* + * Wrapper class for methods/constructors accessed from Lua. + * + * Author: Fabio Mascarenhas + * Version: 1.0 + */ + class LuaMethodWrapper + { + private ObjectTranslator _Translator; + private MethodBase _Method; + private MethodCache _LastCalledMethod = new MethodCache(); + private string _MethodName; + private MemberInfo[] _Members; + private IReflect _TargetType; + private ExtractValue _ExtractTarget; + private object _Target; + private BindingFlags _BindingType; + + /* + * Constructs the wrapper for a known MethodBase instance + */ + public LuaMethodWrapper(ObjectTranslator translator, object target, IReflect targetType, MethodBase method) + { + _Translator = translator; + _Target = target; + _TargetType = targetType; + + if(!targetType.IsNull()) + _ExtractTarget = translator.typeChecker.getExtractor(targetType); + + _Method = method; + _MethodName = method.Name; + + if(method.IsStatic) + _BindingType = BindingFlags.Static; + else + _BindingType = BindingFlags.Instance; + } + + /* + * Constructs the wrapper for a known method name + */ + public LuaMethodWrapper(ObjectTranslator translator, IReflect targetType, string methodName, BindingFlags bindingType) + { + _Translator = translator; + _MethodName = methodName; + _TargetType = targetType; + + if(!targetType.IsNull()) + _ExtractTarget = translator.typeChecker.getExtractor(targetType); + + _BindingType = bindingType; + //CP: Removed NonPublic binding search and added IgnoreCase + _Members = targetType.UnderlyingSystemType.GetMember(methodName, MemberTypes.Method, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase/*|BindingFlags.NonPublic*/); + } + + /// + /// Convert C# exceptions into Lua errors + /// + /// num of things on stack + /// null for no pending exception + int SetPendingException(Exception e) + { + return _Translator.interpreter.SetPendingException(e); + } + + /* + * Calls the method. Receives the arguments from the Lua stack + * and returns values in it. + */ + public int call(LuaCore.lua_State luaState) + { + var methodToCall = _Method; + object targetObject = _Target; + bool failedCall = true; + int nReturnValues = 0; + + if(!LuaLib.lua_checkstack(luaState, 5)) + throw new LuaException("Lua stack overflow"); + + bool isStatic = (_BindingType & BindingFlags.Static) == BindingFlags.Static; + SetPendingException(null); + + if(methodToCall.IsNull()) // Method from name + { + if(isStatic) + targetObject = null; + else + targetObject = _ExtractTarget(luaState, 1); + + //LuaLib.lua_remove(luaState,1); // Pops the receiver + if(!_LastCalledMethod.cachedMethod.IsNull()) // Cached? + { + int numStackToSkip = isStatic ? 0 : 1; // If this is an instance invoe we will have an extra arg on the stack for the targetObject + int numArgsPassed = LuaLib.lua_gettop(luaState) - numStackToSkip; + + if(numArgsPassed == _LastCalledMethod.argTypes.Length) // No. of args match? + { + if(!LuaLib.lua_checkstack(luaState, _LastCalledMethod.outList.Length + 6)) + throw new LuaException("Lua stack overflow"); + + try + { + for(int i = 0; i < _LastCalledMethod.argTypes.Length; i++) + { + if(_LastCalledMethod.argTypes[i].isParamsArray) + { + object luaParamValue = _LastCalledMethod.argTypes[i].extractValue(luaState, i + 1 + numStackToSkip); + var paramArrayType = _LastCalledMethod.argTypes[i].paramsArrayType; + Array paramArray; + + if(luaParamValue is LuaTable) + { + var table = (LuaTable)luaParamValue; + paramArray = Array.CreateInstance(paramArrayType, table.Values.Count); + + for(int x = 1; x <= table.Values.Count; x++) + paramArray.SetValue(Convert.ChangeType(table[x], paramArrayType), x - 1); + } + else + { + paramArray = Array.CreateInstance(paramArrayType, 1); + paramArray.SetValue(luaParamValue, 0); + } + + _LastCalledMethod.args[_LastCalledMethod.argTypes[i].index] = paramArray; + } + else + { + _LastCalledMethod.args[_LastCalledMethod.argTypes[i].index] = + _LastCalledMethod.argTypes[i].extractValue(luaState, i + 1 + numStackToSkip); + } + + if(_LastCalledMethod.args[_LastCalledMethod.argTypes[i].index] == null && + !LuaLib.lua_isnil(luaState, i + 1 + numStackToSkip)) + throw new LuaException("argument number " + (i + 1) + " is invalid"); + } + + if((_BindingType & BindingFlags.Static) == BindingFlags.Static) + _Translator.push(luaState, _LastCalledMethod.cachedMethod.Invoke(null, _LastCalledMethod.args)); + else + { + if(_LastCalledMethod.cachedMethod.IsConstructor) + _Translator.push(luaState, ((ConstructorInfo)_LastCalledMethod.cachedMethod).Invoke(_LastCalledMethod.args)); + else + _Translator.push(luaState, _LastCalledMethod.cachedMethod.Invoke(targetObject, _LastCalledMethod.args)); + } + + failedCall = false; + } + catch(TargetInvocationException e) + { + // Failure of method invocation + return SetPendingException(e.GetBaseException()); + } + catch(Exception e) + { + if(_Members.Length == 1) // Is the method overloaded? + // No, throw error + return SetPendingException(e); + } + } + } + + // Cache miss + if(failedCall) + { + // System.Diagnostics.Debug.WriteLine("cache miss on " + methodName); + // If we are running an instance variable, we can now pop the targetObject from the stack + if(!isStatic) + { + if(targetObject.IsNull()) + { + _Translator.throwError(luaState, String.Format("instance method '{0}' requires a non null target object", _MethodName)); + LuaLib.lua_pushnil(luaState); + return 1; + } + + LuaLib.lua_remove(luaState, 1); // Pops the receiver + } + + bool hasMatch = false; + string candidateName = null; + + foreach(var member in _Members) + { + candidateName = member.ReflectedType.Name + "." + member.Name; + var m = (MethodInfo)member; + bool isMethod = _Translator.matchParameters(luaState, m, ref _LastCalledMethod); + + if(isMethod) + { + hasMatch = true; + break; + } + } + + if(!hasMatch) + { + string msg = (candidateName == null) ? "invalid arguments to method call" : ("invalid arguments to method: " + candidateName); + _Translator.throwError(luaState, msg); + LuaLib.lua_pushnil(luaState); + return 1; + } + } + } + else // Method from MethodBase instance + { + if(methodToCall.ContainsGenericParameters) + { + /*bool isMethod = */_Translator.matchParameters(luaState, methodToCall, ref _LastCalledMethod); + + if(methodToCall.IsGenericMethodDefinition) + { + //need to make a concrete type of the generic method definition + var typeArgs = new List(); + + foreach(object arg in _LastCalledMethod.args) + typeArgs.Add(arg.GetType()); + + var concreteMethod = (methodToCall as MethodInfo).MakeGenericMethod(typeArgs.ToArray()); + _Translator.push(luaState, concreteMethod.Invoke(targetObject, _LastCalledMethod.args)); + failedCall = false; + } + else if(methodToCall.ContainsGenericParameters) + { + _Translator.throwError(luaState, "unable to invoke method on generic class as the current method is an open generic method"); + LuaLib.lua_pushnil(luaState); + return 1; + } + } + else + { + if(!methodToCall.IsStatic && !methodToCall.IsConstructor && targetObject == null) + { + targetObject = _ExtractTarget(luaState, 1); + LuaLib.lua_remove(luaState, 1); // Pops the receiver + } + + if(!_Translator.matchParameters(luaState, methodToCall, ref _LastCalledMethod)) + { + _Translator.throwError(luaState, "invalid arguments to method call"); + LuaLib.lua_pushnil(luaState); + return 1; + } + } + } + + if(failedCall) + { + if(!LuaLib.lua_checkstack(luaState, _LastCalledMethod.outList.Length + 6)) + throw new LuaException("Lua stack overflow"); + + try + { + if(isStatic) + _Translator.push(luaState, _LastCalledMethod.cachedMethod.Invoke(null, _LastCalledMethod.args)); + else + { + if(_LastCalledMethod.cachedMethod.IsConstructor) + _Translator.push(luaState, ((ConstructorInfo)_LastCalledMethod.cachedMethod).Invoke(_LastCalledMethod.args)); + else + _Translator.push(luaState, _LastCalledMethod.cachedMethod.Invoke(targetObject, _LastCalledMethod.args)); + } + } + catch(TargetInvocationException e) + { + return SetPendingException(e.GetBaseException()); + } + catch(Exception e) + { + return SetPendingException(e); + } + } + + // Pushes out and ref return values + for(int index = 0; index < _LastCalledMethod.outList.Length; index++) + { + nReturnValues++; + //for(int i=0;i 0) + nReturnValues++; + + return nReturnValues < 1 ? 1 : nReturnValues; + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/Method/MethodArgs.cs b/Core/LuaInterface/Method/MethodArgs.cs index d6621ac9012e4f7f844cfc9829fb34cbcfff4aec..4a751f7367d9084814d3a45c8b9bb1e24c5ebf69 100644 --- a/Core/LuaInterface/Method/MethodArgs.cs +++ b/Core/LuaInterface/Method/MethodArgs.cs @@ -1,42 +1,42 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; - -namespace LuaInterface.Method -{ - /* - * Parameter information - */ - struct MethodArgs - { - // Position of parameter - public int index; - // Type-conversion function - public ExtractValue extractValue; - public bool isParamsArray; - public Type paramsArrayType; - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; + +namespace LuaInterface.Method +{ + /* + * Parameter information + */ + struct MethodArgs + { + // Position of parameter + public int index; + // Type-conversion function + public ExtractValue extractValue; + public bool isParamsArray; + public Type paramsArrayType; + } } \ No newline at end of file diff --git a/Core/LuaInterface/Method/MethodCache.cs b/Core/LuaInterface/Method/MethodCache.cs index 098bd57d936a880822cd2df629051d6e9b77dbbf..2d7156c904d9c06f9d7ec697222b2dff3754f96d 100644 --- a/Core/LuaInterface/Method/MethodCache.cs +++ b/Core/LuaInterface/Method/MethodCache.cs @@ -1,63 +1,63 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Reflection; -using LuaInterface.Extensions; - -namespace LuaInterface.Method -{ - /* - * Cached method - */ - struct MethodCache - { - private MethodBase _cachedMethod; - - public MethodBase cachedMethod - { - get - { - return _cachedMethod; - } - set - { - _cachedMethod = value; - var mi = value as MethodInfo; - - if(!mi.IsNull()) - IsReturnVoid = string.Compare(mi.ReturnType.Name, "System.Void", true) == 0; - } - } - - public bool IsReturnVoid; - // List or arguments - public object[] args; - // Positions of out parameters - public int[] outList; - // Types of parameters - public MethodArgs[] argTypes; - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Reflection; +using LuaInterface.Extensions; + +namespace LuaInterface.Method +{ + /* + * Cached method + */ + struct MethodCache + { + private MethodBase _cachedMethod; + + public MethodBase cachedMethod + { + get + { + return _cachedMethod; + } + set + { + _cachedMethod = value; + var mi = value as MethodInfo; + + if(!mi.IsNull()) + IsReturnVoid = string.Compare(mi.ReturnType.Name, "System.Void", true) == 0; + } + } + + public bool IsReturnVoid; + // List or arguments + public object[] args; + // Positions of out parameters + public int[] outList; + // Types of parameters + public MethodArgs[] argTypes; + } } \ No newline at end of file diff --git a/Core/LuaInterface/Method/RegisterEventHandler.cs b/Core/LuaInterface/Method/RegisterEventHandler.cs index 490b2551ec43f67d3a20b08d23a5cc04a20d69a4..a57f2ad4835eb282eb72f78b8ada7dcbadba6d6f 100644 --- a/Core/LuaInterface/Method/RegisterEventHandler.cs +++ b/Core/LuaInterface/Method/RegisterEventHandler.cs @@ -1,89 +1,89 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Reflection; - -namespace LuaInterface.Method -{ - /* - * Wrapper class for events that does registration/deregistration - * of event handlers. - * - * Author: Fabio Mascarenhas - * Version: 1.0 - */ - class RegisterEventHandler - { - private EventHandlerContainer pendingEvents; - private EventInfo eventInfo; - private object target; - - public RegisterEventHandler(EventHandlerContainer pendingEvents, object target, EventInfo eventInfo) - { - this.target = target; - this.eventInfo = eventInfo; - this.pendingEvents = pendingEvents; - } - - /* - * Adds a new event handler - */ - public Delegate Add(LuaFunction function) - { - //CP: Fix by Ben Bryant for event handling with one parameter - //link: http://luaforge.net/forum/message.php?msg_id=9266 - Delegate handlerDelegate = CodeGeneration.Instance.GetDelegate(eventInfo.EventHandlerType, function); - eventInfo.AddEventHandler(target, handlerDelegate); - pendingEvents.Add(handlerDelegate, this); - - return handlerDelegate; - //MethodInfo mi = eventInfo.EventHandlerType.GetMethod("Invoke"); - //ParameterInfo[] pi = mi.GetParameters(); - //LuaEventHandler handler=CodeGeneration.Instance.GetEvent(pi[1].ParameterType,function); - //Delegate handlerDelegate=Delegate.CreateDelegate(eventInfo.EventHandlerType,handler,"HandleEvent"); - //eventInfo.AddEventHandler(target,handlerDelegate); - //pendingEvents.Add(handlerDelegate, this); - //return handlerDelegate; - } - - /* - * Removes an existing event handler - */ - public void Remove(Delegate handlerDelegate) - { - RemovePending(handlerDelegate); - pendingEvents.Remove(handlerDelegate); - } - - /* - * Removes an existing event handler (without updating the pending handlers list) - */ - internal void RemovePending(Delegate handlerDelegate) - { - eventInfo.RemoveEventHandler(target, handlerDelegate); - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Reflection; + +namespace LuaInterface.Method +{ + /* + * Wrapper class for events that does registration/deregistration + * of event handlers. + * + * Author: Fabio Mascarenhas + * Version: 1.0 + */ + class RegisterEventHandler + { + private EventHandlerContainer pendingEvents; + private EventInfo eventInfo; + private object target; + + public RegisterEventHandler(EventHandlerContainer pendingEvents, object target, EventInfo eventInfo) + { + this.target = target; + this.eventInfo = eventInfo; + this.pendingEvents = pendingEvents; + } + + /* + * Adds a new event handler + */ + public Delegate Add(LuaFunction function) + { + //CP: Fix by Ben Bryant for event handling with one parameter + //link: http://luaforge.net/forum/message.php?msg_id=9266 + Delegate handlerDelegate = CodeGeneration.Instance.GetDelegate(eventInfo.EventHandlerType, function); + eventInfo.AddEventHandler(target, handlerDelegate); + pendingEvents.Add(handlerDelegate, this); + + return handlerDelegate; + //MethodInfo mi = eventInfo.EventHandlerType.GetMethod("Invoke"); + //ParameterInfo[] pi = mi.GetParameters(); + //LuaEventHandler handler=CodeGeneration.Instance.GetEvent(pi[1].ParameterType,function); + //Delegate handlerDelegate=Delegate.CreateDelegate(eventInfo.EventHandlerType,handler,"HandleEvent"); + //eventInfo.AddEventHandler(target,handlerDelegate); + //pendingEvents.Add(handlerDelegate, this); + //return handlerDelegate; + } + + /* + * Removes an existing event handler + */ + public void Remove(Delegate handlerDelegate) + { + RemovePending(handlerDelegate); + pendingEvents.Remove(handlerDelegate); + } + + /* + * Removes an existing event handler (without updating the pending handlers list) + */ + internal void RemovePending(Delegate handlerDelegate) + { + eventInfo.RemoveEventHandler(target, handlerDelegate); + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/ObjectTranslator.cs b/Core/LuaInterface/ObjectTranslator.cs index 953e74ab237eb85ee8c5139df8ff67e1be110d11..c7f8fa4cc484e3ce74f8e209ed2b548266bb07ae 100644 --- a/Core/LuaInterface/ObjectTranslator.cs +++ b/Core/LuaInterface/ObjectTranslator.cs @@ -1,854 +1,854 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.IO; -using System.Reflection; -using System.Diagnostics; -using System.Collections; -using System.Collections.Generic; -using LuaInterface.Method; -using LuaInterface.Exceptions; -using LuaInterface.Extensions; - -namespace LuaInterface -{ - using LuaCore = KopiLua.Lua; - - /* - * Passes objects from the CLR to Lua and vice-versa - * - * Author: Fabio Mascarenhas - * Version: 1.0 - */ - public class ObjectTranslator - { - private LuaCore.lua_CFunction registerTableFunction, unregisterTableFunction, getMethodSigFunction, - getConstructorSigFunction, importTypeFunction, loadAssemblyFunction; - // object to object # - public readonly Dictionary objectsBackMap = new Dictionary(); - // object # to object (FIXME - it should be possible to get object address as an object #) - public readonly Dictionary objects = new Dictionary(); - internal EventHandlerContainer pendingEvents = new EventHandlerContainer(); - private MetaFunctions metaFunctions; - private List assemblies; - internal CheckType typeChecker; - internal Lua interpreter; - /// - /// We want to ensure that objects always have a unique ID - /// - private int nextObj = 0; - - public ObjectTranslator(Lua interpreter, LuaCore.lua_State luaState) - { - this.interpreter = interpreter; - typeChecker = new CheckType(this); - metaFunctions = new MetaFunctions(this); - assemblies = new List(); - - importTypeFunction = new LuaCore.lua_CFunction(this.importType); - loadAssemblyFunction = new LuaCore.lua_CFunction(this.loadAssembly); - registerTableFunction = new LuaCore.lua_CFunction(this.registerTable); - unregisterTableFunction = new LuaCore.lua_CFunction(this.unregisterTable); - getMethodSigFunction = new LuaCore.lua_CFunction(this.getMethodSignature); - getConstructorSigFunction = new LuaCore.lua_CFunction(this.getConstructorSignature); - - createLuaObjectList(luaState); - createIndexingMetaFunction(luaState); - createBaseClassMetatable(luaState); - createClassMetatable(luaState); - createFunctionMetatable(luaState); - setGlobalFunctions(luaState); - } - - /* - * Sets up the list of objects in the Lua side - */ - private void createLuaObjectList(LuaCore.lua_State luaState) - { - LuaLib.lua_pushstring(luaState, "luaNet_objects"); - LuaLib.lua_newtable(luaState); - LuaLib.lua_newtable(luaState); - LuaLib.lua_pushstring(luaState, "__mode"); - LuaLib.lua_pushstring(luaState, "v"); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_setmetatable(luaState, -2); - LuaLib.lua_settable(luaState, (int)LuaIndexes.Registry); - } - - /* - * Registers the indexing function of CLR objects - * passed to Lua - */ - private void createIndexingMetaFunction(LuaCore.lua_State luaState) - { - LuaLib.lua_pushstring(luaState, "luaNet_indexfunction"); - LuaLib.luaL_dostring(luaState, MetaFunctions.luaIndexFunction); // steffenj: lua_dostring renamed to luaL_dostring - //LuaLib.lua_pushstdcallcfunction(luaState, indexFunction); - LuaLib.lua_rawset(luaState, (int)LuaIndexes.Registry); - } - - /* - * Creates the metatable for superclasses (the base - * field of registered tables) - */ - private void createBaseClassMetatable(LuaCore.lua_State luaState) - { - LuaLib.luaL_newmetatable(luaState, "luaNet_searchbase"); - LuaLib.lua_pushstring(luaState, "__gc"); - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.gcFunction); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_pushstring(luaState, "__tostring"); - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.toStringFunction); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_pushstring(luaState, "__index"); - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.baseIndexFunction); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_pushstring(luaState, "__newindex"); - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.newindexFunction); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_settop(luaState, -2); - } - - /* - * Creates the metatable for type references - */ - private void createClassMetatable(LuaCore.lua_State luaState) - { - LuaLib.luaL_newmetatable(luaState, "luaNet_class"); - LuaLib.lua_pushstring(luaState, "__gc"); - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.gcFunction); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_pushstring(luaState, "__tostring"); - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.toStringFunction); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_pushstring(luaState, "__index"); - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.classIndexFunction); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_pushstring(luaState, "__newindex"); - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.classNewindexFunction); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_pushstring(luaState, "__call"); - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.callConstructorFunction); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_settop(luaState, -2); - } - - /* - * Registers the global functions used by LuaInterface - */ - private void setGlobalFunctions(LuaCore.lua_State luaState) - { - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.indexFunction); - LuaLib.lua_setglobal(luaState, "get_object_member"); - LuaLib.lua_pushstdcallcfunction(luaState, importTypeFunction); - LuaLib.lua_setglobal(luaState, "import_type"); - LuaLib.lua_pushstdcallcfunction(luaState, loadAssemblyFunction); - LuaLib.lua_setglobal(luaState, "load_assembly"); - LuaLib.lua_pushstdcallcfunction(luaState, registerTableFunction); - LuaLib.lua_setglobal(luaState, "make_object"); - LuaLib.lua_pushstdcallcfunction(luaState, unregisterTableFunction); - LuaLib.lua_setglobal(luaState, "free_object"); - LuaLib.lua_pushstdcallcfunction(luaState, getMethodSigFunction); - LuaLib.lua_setglobal(luaState, "get_method_bysig"); - LuaLib.lua_pushstdcallcfunction(luaState, getConstructorSigFunction); - LuaLib.lua_setglobal(luaState, "get_constructor_bysig"); - } - - /* - * Creates the metatable for delegates - */ - private void createFunctionMetatable(LuaCore.lua_State luaState) - { - LuaLib.luaL_newmetatable(luaState, "luaNet_function"); - LuaLib.lua_pushstring(luaState, "__gc"); - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.gcFunction); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_pushstring(luaState, "__call"); - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.execDelegateFunction); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_settop(luaState, -2); - } - - /* - * Passes errors (argument e) to the Lua interpreter - */ - internal void throwError(LuaCore.lua_State luaState, object e) - { - // We use this to remove anything pushed by luaL_where - int oldTop = LuaLib.lua_gettop(luaState); - - // Stack frame #1 is our C# wrapper, so not very interesting to the user - // Stack frame #2 must be the lua code that called us, so that's what we want to use - LuaLib.luaL_where(luaState, 1); - var curlev = popValues(luaState, oldTop); - - // Determine the position in the script where the exception was triggered - string errLocation = string.Empty; - - if(curlev.Length > 0) - errLocation = curlev[0].ToString(); - - string message = e as string; - - if(!message.IsNull()) - { - // Wrap Lua error (just a string) and store the error location - e = new LuaScriptException(message, errLocation); - } - else - { - var ex = e as Exception; - - if(!ex.IsNull()) - { - // Wrap generic .NET exception as an InnerException and store the error location - e = new LuaScriptException(ex, errLocation); - } - } - - push(luaState, e); - LuaLib.lua_error(luaState); - } - - /* - * Implementation of load_assembly. Throws an error - * if the assembly is not found. - */ - private int loadAssembly(LuaCore.lua_State luaState) - { - try - { - string assemblyName = LuaLib.lua_tostring(luaState, 1).ToString(); - Assembly assembly = null; - - try - { - assembly = Assembly.Load(assemblyName); - } - catch(BadImageFormatException) - { - // The assemblyName was invalid. It is most likely a path. - } - - if(assembly.IsNull()) - assembly = Assembly.Load(AssemblyName.GetAssemblyName(assemblyName)); - - if(!assembly.IsNull() && !assemblies.Contains(assembly)) - assemblies.Add(assembly); - } - catch(Exception e) - { - throwError(luaState, e); - } - - return 0; - } - - internal Type FindType(string className) - { - foreach(var assembly in assemblies) - { - var klass = assembly.GetType(className); - - if(!klass.IsNull()) - return klass; - } - return null; - } - - /* - * Implementation of import_type. Returns nil if the - * type is not found. - */ - private int importType(LuaCore.lua_State luaState) - { - string className = LuaLib.lua_tostring(luaState, 1).ToString(); - var klass = FindType(className); - - if(!klass.IsNull()) - pushType(luaState, klass); - else - LuaLib.lua_pushnil(luaState); - - return 1; - } - - /* - * Implementation of make_object. Registers a table (first - * argument in the stack) as an object subclassing the - * type passed as second argument in the stack. - */ - private int registerTable(LuaCore.lua_State luaState) - { - if(LuaLib.lua_type(luaState, 1) == LuaTypes.Table) - { - var luaTable = getTable(luaState, 1); - string superclassName = LuaLib.lua_tostring(luaState, 2).ToString(); - - if(!superclassName.IsNull()) - { - var klass = FindType(superclassName); - - if(!klass.IsNull()) - { - // Creates and pushes the object in the stack, setting - // it as the metatable of the first argument - object obj = CodeGeneration.Instance.GetClassInstance(klass, luaTable); - pushObject(luaState, obj, "luaNet_metatable"); - LuaLib.lua_newtable(luaState); - LuaLib.lua_pushstring(luaState, "__index"); - LuaLib.lua_pushvalue(luaState, -3); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_pushstring(luaState, "__newindex"); - LuaLib.lua_pushvalue(luaState, -3); - LuaLib.lua_settable(luaState, -3); - LuaLib.lua_setmetatable(luaState, 1); - // Pushes the object again, this time as the base field - // of the table and with the luaNet_searchbase metatable - LuaLib.lua_pushstring(luaState, "base"); - int index = addObject(obj); - pushNewObject(luaState, obj, index, "luaNet_searchbase"); - LuaLib.lua_rawset(luaState, 1); - } - else - throwError(luaState, "register_table: can not find superclass '" + superclassName + "'"); - } - else - throwError(luaState, "register_table: superclass name can not be null"); - } - else - throwError(luaState, "register_table: first arg is not a table"); - - return 0; - } - - /* - * Implementation of free_object. Clears the metatable and the - * base field, freeing the created object for garbage-collection - */ - private int unregisterTable(LuaCore.lua_State luaState) - { - try - { - if(LuaLib.lua_getmetatable(luaState, 1) != 0) - { - LuaLib.lua_pushstring(luaState, "__index"); - LuaLib.lua_gettable(luaState, -2); - object obj = getRawNetObject(luaState, -1); - - if(obj.IsNull()) - throwError(luaState, "unregister_table: arg is not valid table"); - - var luaTableField = obj.GetType().GetField("__luaInterface_luaTable"); - - if(luaTableField.IsNull()) - throwError(luaState, "unregister_table: arg is not valid table"); - - luaTableField.SetValue(obj, null); - LuaLib.lua_pushnil(luaState); - LuaLib.lua_setmetatable(luaState, 1); - LuaLib.lua_pushstring(luaState, "base"); - LuaLib.lua_pushnil(luaState); - LuaLib.lua_settable(luaState, 1); - } - else - throwError(luaState, "unregister_table: arg is not valid table"); - } - catch(Exception e) - { - throwError(luaState, e.Message); - } - - return 0; - } - - /* - * Implementation of get_method_bysig. Returns nil - * if no matching method is not found. - */ - private int getMethodSignature(LuaCore.lua_State luaState) - { - IReflect klass; - object target; - int udata = LuaLib.luanet_checkudata(luaState, 1, "luaNet_class"); - - if(udata != -1) - { - klass = (IReflect)objects[udata]; - target = null; - } - else - { - target = getRawNetObject(luaState, 1); - - if(target.IsNull()) - { - throwError(luaState, "get_method_bysig: first arg is not type or object reference"); - LuaLib.lua_pushnil(luaState); - return 1; - } - - klass = target.GetType(); - } - - string methodName = LuaLib.lua_tostring(luaState, 2).ToString(); - var signature = new Type[LuaLib.lua_gettop(luaState)-2]; - - for(int i = 0; i < signature.Length; i++) - signature[i] = FindType(LuaLib.lua_tostring(luaState, i+3).ToString()); - - try - { - //CP: Added ignore case - var method = klass.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static | - BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.IgnoreCase, null, signature, null); - pushFunction(luaState, new LuaCore.lua_CFunction((new LuaMethodWrapper(this, target, klass, method)).call)); - } - catch(Exception e) - { - throwError(luaState, e); - LuaLib.lua_pushnil(luaState); - } - - return 1; - } - - /* - * Implementation of get_constructor_bysig. Returns nil - * if no matching constructor is found. - */ - private int getConstructorSignature(LuaCore.lua_State luaState) - { - IReflect klass = null; - int udata = LuaLib.luanet_checkudata(luaState, 1, "luaNet_class"); - - if(udata != -1) - klass = (IReflect)objects[udata]; - - if(klass.IsNull()) - throwError(luaState, "get_constructor_bysig: first arg is invalid type reference"); - - var signature = new Type[LuaLib.lua_gettop(luaState)-1]; - - for(int i = 0; i < signature.Length; i++) - signature[i] = FindType(LuaLib.lua_tostring(luaState, i+2).ToString()); - - try - { - ConstructorInfo constructor = klass.UnderlyingSystemType.GetConstructor(signature); - pushFunction(luaState, new LuaCore.lua_CFunction((new LuaMethodWrapper(this, null, klass, constructor)).call)); - } - catch(Exception e) - { - throwError(luaState, e); - LuaLib.lua_pushnil(luaState); - } - - return 1; - } - - /* - * Pushes a type reference into the stack - */ - internal void pushType(LuaCore.lua_State luaState, Type t) - { - pushObject(luaState, new ProxyType(t), "luaNet_class"); - } - - /* - * Pushes a delegate into the stack - */ - internal void pushFunction(LuaCore.lua_State luaState, LuaCore.lua_CFunction func) - { - pushObject(luaState, func, "luaNet_function"); - } - - /* - * Pushes a CLR object into the Lua stack as an userdata - * with the provided metatable - */ - internal void pushObject(LuaCore.lua_State luaState, object o, string metatable) - { - int index = -1; - - // Pushes nil - if(o.IsNull()) - { - LuaLib.lua_pushnil(luaState); - return; - } - - // Object already in the list of Lua objects? Push the stored reference. - bool found = objectsBackMap.TryGetValue(o, out index); - - if(found) - { - LuaLib.luaL_getmetatable(luaState, "luaNet_objects"); - LuaLib.lua_rawgeti(luaState, -1, index); - - // Note: starting with lua5.1 the garbage collector may remove weak reference items (such as our luaNet_objects values) when the initial GC sweep - // occurs, but the actual call of the __gc finalizer for that object may not happen until a little while later. During that window we might call - // this routine and find the element missing from luaNet_objects, but collectObject() has not yet been called. In that case, we go ahead and call collect - // object here - // did we find a non nil object in our table? if not, we need to call collect object - var type = LuaLib.lua_type(luaState, -1); - if(type != LuaTypes.Nil) - { - LuaLib.lua_remove(luaState, -2); // drop the metatable - we're going to leave our object on the stack - return; - } - - // MetaFunctions.dumpStack(this, luaState); - LuaLib.lua_remove(luaState, -1); // remove the nil object value - LuaLib.lua_remove(luaState, -1); // remove the metatable - collectObject(o, index); // Remove from both our tables and fall out to get a new ID - } - - index = addObject(o); - pushNewObject(luaState, o, index, metatable); - } - - /* - * Pushes a new object into the Lua stack with the provided - * metatable - */ - private void pushNewObject(LuaCore.lua_State luaState, object o, int index, string metatable) - { - if(metatable == "luaNet_metatable") - { - // Gets or creates the metatable for the object's type - LuaLib.luaL_getmetatable(luaState, o.GetType().AssemblyQualifiedName); - - if(LuaLib.lua_isnil(luaState, -1)) - { - LuaLib.lua_settop(luaState, -2); - LuaLib.luaL_newmetatable(luaState, o.GetType().AssemblyQualifiedName); - LuaLib.lua_pushstring(luaState, "cache"); - LuaLib.lua_newtable(luaState); - LuaLib.lua_rawset(luaState, -3); - LuaLib.lua_pushlightuserdata(luaState, LuaLib.luanet_gettag()); - LuaLib.lua_pushnumber(luaState, 1); - LuaLib.lua_rawset(luaState, -3); - LuaLib.lua_pushstring(luaState, "__index"); - LuaLib.lua_pushstring(luaState, "luaNet_indexfunction"); - LuaLib.lua_rawget(luaState, (int)LuaIndexes.Registry); - LuaLib.lua_rawset(luaState, -3); - LuaLib.lua_pushstring(luaState, "__gc"); - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.gcFunction); - LuaLib.lua_rawset(luaState, -3); - LuaLib.lua_pushstring(luaState, "__tostring"); - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.toStringFunction); - LuaLib.lua_rawset(luaState, -3); - LuaLib.lua_pushstring(luaState, "__newindex"); - LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.newindexFunction); - LuaLib.lua_rawset(luaState, -3); - } - } - else - LuaLib.luaL_getmetatable(luaState, metatable); - - // Stores the object index in the Lua list and pushes the - // index into the Lua stack - LuaLib.luaL_getmetatable(luaState, "luaNet_objects"); - LuaLib.luanet_newudata(luaState, index); - LuaLib.lua_pushvalue(luaState, -3); - LuaLib.lua_remove(luaState, -4); - LuaLib.lua_setmetatable(luaState, -2); - LuaLib.lua_pushvalue(luaState, -1); - LuaLib.lua_rawseti(luaState, -3, index); - LuaLib.lua_remove(luaState, -2); - } - - /* - * Gets an object from the Lua stack with the desired type, if it matches, otherwise - * returns null. - */ - internal object getAsType(LuaCore.lua_State luaState, int stackPos, Type paramType) - { - var extractor = typeChecker.checkType(luaState, stackPos, paramType); - return !extractor.IsNull() ? extractor(luaState, stackPos) : null; - } - - /// - /// Given the Lua int ID for an object remove it from our maps - /// - /// - internal void collectObject(int udata) - { - object o; - bool found = objects.TryGetValue(udata, out o); - - // The other variant of collectObject might have gotten here first, in that case we will silently ignore the missing entry - if(found) - { - // Debug.WriteLine("Removing " + o.ToString() + " @ " + udata); - objects.Remove(udata); - objectsBackMap.Remove(o); - } - } - - /// - /// Given an object reference, remove it from our maps - /// - /// - private void collectObject(object o, int udata) - { - // Debug.WriteLine("Removing " + o.ToString() + " @ " + udata); - objects.Remove(udata); - objectsBackMap.Remove(o); - } - - private int addObject(object obj) - { - // New object: inserts it in the list - int index = nextObj++; - // Debug.WriteLine("Adding " + obj.ToString() + " @ " + index); - objects[index] = obj; - objectsBackMap[obj] = index; - return index; - } - - /* - * Gets an object from the Lua stack according to its Lua type. - */ - internal object getObject(LuaCore.lua_State luaState, int index) - { - var type = LuaLib.lua_type(luaState, index); - - switch(type) - { - case LuaTypes.Number: - { - return LuaLib.lua_tonumber(luaState, index); - } - case LuaTypes.String: - { - return LuaLib.lua_tostring(luaState, index); - } - case LuaTypes.Boolean: - { - return LuaLib.lua_toboolean(luaState, index); - } - case LuaTypes.Table: - { - return getTable(luaState, index); - } - case LuaTypes.Function: - { - return getFunction(luaState, index); - } - case LuaTypes.UserData: - { - int udata = LuaLib.luanet_tonetobject(luaState, index); - return udata != -1 ? objects[udata] : getUserData(luaState, index); - } - default: - return null; - } - } - - /* - * Gets the table in the index positon of the Lua stack. - */ - internal LuaTable getTable(LuaCore.lua_State luaState, int index) - { - LuaLib.lua_pushvalue(luaState, index); - return new LuaTable(LuaLib.lua_ref(luaState, 1), interpreter); - } - - /* - * Gets the userdata in the index positon of the Lua stack. - */ - internal LuaUserData getUserData(LuaCore.lua_State luaState, int index) - { - LuaLib.lua_pushvalue(luaState, index); - return new LuaUserData(LuaLib.lua_ref(luaState, 1), interpreter); - } - - /* - * Gets the function in the index positon of the Lua stack. - */ - internal LuaFunction getFunction(LuaCore.lua_State luaState, int index) - { - LuaLib.lua_pushvalue(luaState, index); - return new LuaFunction(LuaLib.lua_ref(luaState, 1), interpreter); - } - - /* - * Gets the CLR object in the index positon of the Lua stack. Returns - * delegates as Lua functions. - */ - internal object getNetObject(LuaCore.lua_State luaState, int index) - { - int idx = LuaLib.luanet_tonetobject(luaState, index); - return idx != -1 ? objects[idx] : null; - } - - /* - * Gets the CLR object in the index positon of the Lua stack. Returns - * delegates as is. - */ - internal object getRawNetObject(LuaCore.lua_State luaState, int index) - { - int udata = LuaLib.luanet_rawnetobj(luaState, index); - return udata != -1 ? objects[udata] : null; - } - - /* - * Pushes the entire array into the Lua stack and returns the number - * of elements pushed. - */ - internal int returnValues(LuaCore.lua_State luaState, object[] returnValues) - { - if(LuaLib.lua_checkstack(luaState, returnValues.Length+5)) - { - for(int i = 0; i < returnValues.Length; i++) - push(luaState, returnValues[i]); - - return returnValues.Length; - } - else - return 0; - } - - /* - * Gets the values from the provided index to - * the top of the stack and returns them in an array. - */ - internal object[] popValues(LuaCore.lua_State luaState, int oldTop) - { - int newTop = LuaLib.lua_gettop(luaState); - - if(oldTop == newTop) - return null; - else - { - var returnValues = new ArrayList(); - for(int i = oldTop+1; i <= newTop; i++) - returnValues.Add(getObject(luaState, i)); - - LuaLib.lua_settop(luaState, oldTop); - return returnValues.ToArray(); - } - } - - /* - * Gets the values from the provided index to - * the top of the stack and returns them in an array, casting - * them to the provided types. - */ - internal object[] popValues(LuaCore.lua_State luaState, int oldTop, Type[] popTypes) - { - int newTop = LuaLib.lua_gettop(luaState); - - if(oldTop == newTop) - return null; - else - { - int iTypes; - var returnValues = new ArrayList(); - - if(popTypes[0] == typeof(void)) - iTypes = 1; - else - iTypes = 0; - - for(int i = oldTop+1; i <= newTop; i++) - { - returnValues.Add(getAsType(luaState, i, popTypes[iTypes])); - iTypes++; - } - - LuaLib.lua_settop(luaState, oldTop); - return returnValues.ToArray(); - } - } - - // kevinh - the following line doesn't work for remoting proxies - they always return a match for 'is' - // else if(o is ILuaGeneratedType) - private static bool IsILua(object o) - { - if(o is ILuaGeneratedType) - { - // Make sure we are _really_ ILuaGenerated - var typ = o.GetType(); - return (!typ.GetInterface("ILuaGeneratedType").IsNull ()); - } - else - return false; - } - - /* - * Pushes the object into the Lua stack according to its type. - */ - internal void push(LuaCore.lua_State luaState, object o) - { - if(o.IsNull()) - LuaLib.lua_pushnil(luaState); - else if(o is sbyte || o is byte || o is short || o is ushort || - o is int || o is uint || o is long || o is float || - o is ulong || o is decimal || o is double) - { - double d = Convert.ToDouble(o); - LuaLib.lua_pushnumber(luaState, d); - } - else if(o is char) - { - double d = (char)o; - LuaLib.lua_pushnumber(luaState, d); - } - else if(o is string) - { - string str = (string)o; - LuaLib.lua_pushstring(luaState, str); - } - else if(o is bool) - { - bool b = (bool)o; - LuaLib.lua_pushboolean(luaState, b); - } - else if(IsILua(o)) - (((ILuaGeneratedType)o).__luaInterface_getLuaTable()).push(luaState); - else if(o is LuaTable) - ((LuaTable)o).push(luaState); - else if(o is LuaCore.lua_CFunction) - pushFunction(luaState, (LuaCore.lua_CFunction)o); - else if(o is LuaFunction) - ((LuaFunction)o).push(luaState); - else - pushObject(luaState, o, "luaNet_metatable"); - } - - /* - * Checks if the method matches the arguments in the Lua stack, getting - * the arguments if it does. - */ - internal bool matchParameters(LuaCore.lua_State luaState, MethodBase method, ref MethodCache methodCache) - { - return metaFunctions.matchParameters(luaState, method, ref methodCache); - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.IO; +using System.Reflection; +using System.Diagnostics; +using System.Collections; +using System.Collections.Generic; +using LuaInterface.Method; +using LuaInterface.Exceptions; +using LuaInterface.Extensions; + +namespace LuaInterface +{ + using LuaCore = KopiLua.Lua; + + /* + * Passes objects from the CLR to Lua and vice-versa + * + * Author: Fabio Mascarenhas + * Version: 1.0 + */ + public class ObjectTranslator + { + private LuaCore.lua_CFunction registerTableFunction, unregisterTableFunction, getMethodSigFunction, + getConstructorSigFunction, importTypeFunction, loadAssemblyFunction; + // object to object # + public readonly Dictionary objectsBackMap = new Dictionary(); + // object # to object (FIXME - it should be possible to get object address as an object #) + public readonly Dictionary objects = new Dictionary(); + internal EventHandlerContainer pendingEvents = new EventHandlerContainer(); + private MetaFunctions metaFunctions; + private List assemblies; + internal CheckType typeChecker; + internal Lua interpreter; + /// + /// We want to ensure that objects always have a unique ID + /// + private int nextObj = 0; + + public ObjectTranslator(Lua interpreter, LuaCore.lua_State luaState) + { + this.interpreter = interpreter; + typeChecker = new CheckType(this); + metaFunctions = new MetaFunctions(this); + assemblies = new List(); + + importTypeFunction = new LuaCore.lua_CFunction(this.importType); + loadAssemblyFunction = new LuaCore.lua_CFunction(this.loadAssembly); + registerTableFunction = new LuaCore.lua_CFunction(this.registerTable); + unregisterTableFunction = new LuaCore.lua_CFunction(this.unregisterTable); + getMethodSigFunction = new LuaCore.lua_CFunction(this.getMethodSignature); + getConstructorSigFunction = new LuaCore.lua_CFunction(this.getConstructorSignature); + + createLuaObjectList(luaState); + createIndexingMetaFunction(luaState); + createBaseClassMetatable(luaState); + createClassMetatable(luaState); + createFunctionMetatable(luaState); + setGlobalFunctions(luaState); + } + + /* + * Sets up the list of objects in the Lua side + */ + private void createLuaObjectList(LuaCore.lua_State luaState) + { + LuaLib.lua_pushstring(luaState, "luaNet_objects"); + LuaLib.lua_newtable(luaState); + LuaLib.lua_newtable(luaState); + LuaLib.lua_pushstring(luaState, "__mode"); + LuaLib.lua_pushstring(luaState, "v"); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_setmetatable(luaState, -2); + LuaLib.lua_settable(luaState, (int)LuaIndexes.Registry); + } + + /* + * Registers the indexing function of CLR objects + * passed to Lua + */ + private void createIndexingMetaFunction(LuaCore.lua_State luaState) + { + LuaLib.lua_pushstring(luaState, "luaNet_indexfunction"); + LuaLib.luaL_dostring(luaState, MetaFunctions.luaIndexFunction); // steffenj: lua_dostring renamed to luaL_dostring + //LuaLib.lua_pushstdcallcfunction(luaState, indexFunction); + LuaLib.lua_rawset(luaState, (int)LuaIndexes.Registry); + } + + /* + * Creates the metatable for superclasses (the base + * field of registered tables) + */ + private void createBaseClassMetatable(LuaCore.lua_State luaState) + { + LuaLib.luaL_newmetatable(luaState, "luaNet_searchbase"); + LuaLib.lua_pushstring(luaState, "__gc"); + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.gcFunction); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_pushstring(luaState, "__tostring"); + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.toStringFunction); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_pushstring(luaState, "__index"); + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.baseIndexFunction); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_pushstring(luaState, "__newindex"); + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.newindexFunction); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_settop(luaState, -2); + } + + /* + * Creates the metatable for type references + */ + private void createClassMetatable(LuaCore.lua_State luaState) + { + LuaLib.luaL_newmetatable(luaState, "luaNet_class"); + LuaLib.lua_pushstring(luaState, "__gc"); + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.gcFunction); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_pushstring(luaState, "__tostring"); + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.toStringFunction); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_pushstring(luaState, "__index"); + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.classIndexFunction); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_pushstring(luaState, "__newindex"); + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.classNewindexFunction); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_pushstring(luaState, "__call"); + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.callConstructorFunction); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_settop(luaState, -2); + } + + /* + * Registers the global functions used by LuaInterface + */ + private void setGlobalFunctions(LuaCore.lua_State luaState) + { + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.indexFunction); + LuaLib.lua_setglobal(luaState, "get_object_member"); + LuaLib.lua_pushstdcallcfunction(luaState, importTypeFunction); + LuaLib.lua_setglobal(luaState, "import_type"); + LuaLib.lua_pushstdcallcfunction(luaState, loadAssemblyFunction); + LuaLib.lua_setglobal(luaState, "load_assembly"); + LuaLib.lua_pushstdcallcfunction(luaState, registerTableFunction); + LuaLib.lua_setglobal(luaState, "make_object"); + LuaLib.lua_pushstdcallcfunction(luaState, unregisterTableFunction); + LuaLib.lua_setglobal(luaState, "free_object"); + LuaLib.lua_pushstdcallcfunction(luaState, getMethodSigFunction); + LuaLib.lua_setglobal(luaState, "get_method_bysig"); + LuaLib.lua_pushstdcallcfunction(luaState, getConstructorSigFunction); + LuaLib.lua_setglobal(luaState, "get_constructor_bysig"); + } + + /* + * Creates the metatable for delegates + */ + private void createFunctionMetatable(LuaCore.lua_State luaState) + { + LuaLib.luaL_newmetatable(luaState, "luaNet_function"); + LuaLib.lua_pushstring(luaState, "__gc"); + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.gcFunction); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_pushstring(luaState, "__call"); + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.execDelegateFunction); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_settop(luaState, -2); + } + + /* + * Passes errors (argument e) to the Lua interpreter + */ + internal void throwError(LuaCore.lua_State luaState, object e) + { + // We use this to remove anything pushed by luaL_where + int oldTop = LuaLib.lua_gettop(luaState); + + // Stack frame #1 is our C# wrapper, so not very interesting to the user + // Stack frame #2 must be the lua code that called us, so that's what we want to use + LuaLib.luaL_where(luaState, 1); + var curlev = popValues(luaState, oldTop); + + // Determine the position in the script where the exception was triggered + string errLocation = string.Empty; + + if(curlev.Length > 0) + errLocation = curlev[0].ToString(); + + string message = e as string; + + if(!message.IsNull()) + { + // Wrap Lua error (just a string) and store the error location + e = new LuaScriptException(message, errLocation); + } + else + { + var ex = e as Exception; + + if(!ex.IsNull()) + { + // Wrap generic .NET exception as an InnerException and store the error location + e = new LuaScriptException(ex, errLocation); + } + } + + push(luaState, e); + LuaLib.lua_error(luaState); + } + + /* + * Implementation of load_assembly. Throws an error + * if the assembly is not found. + */ + private int loadAssembly(LuaCore.lua_State luaState) + { + try + { + string assemblyName = LuaLib.lua_tostring(luaState, 1).ToString(); + Assembly assembly = null; + + try + { + assembly = Assembly.Load(assemblyName); + } + catch(BadImageFormatException) + { + // The assemblyName was invalid. It is most likely a path. + } + + if(assembly.IsNull()) + assembly = Assembly.Load(AssemblyName.GetAssemblyName(assemblyName)); + + if(!assembly.IsNull() && !assemblies.Contains(assembly)) + assemblies.Add(assembly); + } + catch(Exception e) + { + throwError(luaState, e); + } + + return 0; + } + + internal Type FindType(string className) + { + foreach(var assembly in assemblies) + { + var klass = assembly.GetType(className); + + if(!klass.IsNull()) + return klass; + } + return null; + } + + /* + * Implementation of import_type. Returns nil if the + * type is not found. + */ + private int importType(LuaCore.lua_State luaState) + { + string className = LuaLib.lua_tostring(luaState, 1).ToString(); + var klass = FindType(className); + + if(!klass.IsNull()) + pushType(luaState, klass); + else + LuaLib.lua_pushnil(luaState); + + return 1; + } + + /* + * Implementation of make_object. Registers a table (first + * argument in the stack) as an object subclassing the + * type passed as second argument in the stack. + */ + private int registerTable(LuaCore.lua_State luaState) + { + if(LuaLib.lua_type(luaState, 1) == LuaTypes.Table) + { + var luaTable = getTable(luaState, 1); + string superclassName = LuaLib.lua_tostring(luaState, 2).ToString(); + + if(!superclassName.IsNull()) + { + var klass = FindType(superclassName); + + if(!klass.IsNull()) + { + // Creates and pushes the object in the stack, setting + // it as the metatable of the first argument + object obj = CodeGeneration.Instance.GetClassInstance(klass, luaTable); + pushObject(luaState, obj, "luaNet_metatable"); + LuaLib.lua_newtable(luaState); + LuaLib.lua_pushstring(luaState, "__index"); + LuaLib.lua_pushvalue(luaState, -3); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_pushstring(luaState, "__newindex"); + LuaLib.lua_pushvalue(luaState, -3); + LuaLib.lua_settable(luaState, -3); + LuaLib.lua_setmetatable(luaState, 1); + // Pushes the object again, this time as the base field + // of the table and with the luaNet_searchbase metatable + LuaLib.lua_pushstring(luaState, "base"); + int index = addObject(obj); + pushNewObject(luaState, obj, index, "luaNet_searchbase"); + LuaLib.lua_rawset(luaState, 1); + } + else + throwError(luaState, "register_table: can not find superclass '" + superclassName + "'"); + } + else + throwError(luaState, "register_table: superclass name can not be null"); + } + else + throwError(luaState, "register_table: first arg is not a table"); + + return 0; + } + + /* + * Implementation of free_object. Clears the metatable and the + * base field, freeing the created object for garbage-collection + */ + private int unregisterTable(LuaCore.lua_State luaState) + { + try + { + if(LuaLib.lua_getmetatable(luaState, 1) != 0) + { + LuaLib.lua_pushstring(luaState, "__index"); + LuaLib.lua_gettable(luaState, -2); + object obj = getRawNetObject(luaState, -1); + + if(obj.IsNull()) + throwError(luaState, "unregister_table: arg is not valid table"); + + var luaTableField = obj.GetType().GetField("__luaInterface_luaTable"); + + if(luaTableField.IsNull()) + throwError(luaState, "unregister_table: arg is not valid table"); + + luaTableField.SetValue(obj, null); + LuaLib.lua_pushnil(luaState); + LuaLib.lua_setmetatable(luaState, 1); + LuaLib.lua_pushstring(luaState, "base"); + LuaLib.lua_pushnil(luaState); + LuaLib.lua_settable(luaState, 1); + } + else + throwError(luaState, "unregister_table: arg is not valid table"); + } + catch(Exception e) + { + throwError(luaState, e.Message); + } + + return 0; + } + + /* + * Implementation of get_method_bysig. Returns nil + * if no matching method is not found. + */ + private int getMethodSignature(LuaCore.lua_State luaState) + { + IReflect klass; + object target; + int udata = LuaLib.luanet_checkudata(luaState, 1, "luaNet_class"); + + if(udata != -1) + { + klass = (IReflect)objects[udata]; + target = null; + } + else + { + target = getRawNetObject(luaState, 1); + + if(target.IsNull()) + { + throwError(luaState, "get_method_bysig: first arg is not type or object reference"); + LuaLib.lua_pushnil(luaState); + return 1; + } + + klass = target.GetType(); + } + + string methodName = LuaLib.lua_tostring(luaState, 2).ToString(); + var signature = new Type[LuaLib.lua_gettop(luaState)-2]; + + for(int i = 0; i < signature.Length; i++) + signature[i] = FindType(LuaLib.lua_tostring(luaState, i+3).ToString()); + + try + { + //CP: Added ignore case + var method = klass.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static | + BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.IgnoreCase, null, signature, null); + pushFunction(luaState, new LuaCore.lua_CFunction((new LuaMethodWrapper(this, target, klass, method)).call)); + } + catch(Exception e) + { + throwError(luaState, e); + LuaLib.lua_pushnil(luaState); + } + + return 1; + } + + /* + * Implementation of get_constructor_bysig. Returns nil + * if no matching constructor is found. + */ + private int getConstructorSignature(LuaCore.lua_State luaState) + { + IReflect klass = null; + int udata = LuaLib.luanet_checkudata(luaState, 1, "luaNet_class"); + + if(udata != -1) + klass = (IReflect)objects[udata]; + + if(klass.IsNull()) + throwError(luaState, "get_constructor_bysig: first arg is invalid type reference"); + + var signature = new Type[LuaLib.lua_gettop(luaState)-1]; + + for(int i = 0; i < signature.Length; i++) + signature[i] = FindType(LuaLib.lua_tostring(luaState, i+2).ToString()); + + try + { + ConstructorInfo constructor = klass.UnderlyingSystemType.GetConstructor(signature); + pushFunction(luaState, new LuaCore.lua_CFunction((new LuaMethodWrapper(this, null, klass, constructor)).call)); + } + catch(Exception e) + { + throwError(luaState, e); + LuaLib.lua_pushnil(luaState); + } + + return 1; + } + + /* + * Pushes a type reference into the stack + */ + internal void pushType(LuaCore.lua_State luaState, Type t) + { + pushObject(luaState, new ProxyType(t), "luaNet_class"); + } + + /* + * Pushes a delegate into the stack + */ + internal void pushFunction(LuaCore.lua_State luaState, LuaCore.lua_CFunction func) + { + pushObject(luaState, func, "luaNet_function"); + } + + /* + * Pushes a CLR object into the Lua stack as an userdata + * with the provided metatable + */ + internal void pushObject(LuaCore.lua_State luaState, object o, string metatable) + { + int index = -1; + + // Pushes nil + if(o.IsNull()) + { + LuaLib.lua_pushnil(luaState); + return; + } + + // Object already in the list of Lua objects? Push the stored reference. + bool found = objectsBackMap.TryGetValue(o, out index); + + if(found) + { + LuaLib.luaL_getmetatable(luaState, "luaNet_objects"); + LuaLib.lua_rawgeti(luaState, -1, index); + + // Note: starting with lua5.1 the garbage collector may remove weak reference items (such as our luaNet_objects values) when the initial GC sweep + // occurs, but the actual call of the __gc finalizer for that object may not happen until a little while later. During that window we might call + // this routine and find the element missing from luaNet_objects, but collectObject() has not yet been called. In that case, we go ahead and call collect + // object here + // did we find a non nil object in our table? if not, we need to call collect object + var type = LuaLib.lua_type(luaState, -1); + if(type != LuaTypes.Nil) + { + LuaLib.lua_remove(luaState, -2); // drop the metatable - we're going to leave our object on the stack + return; + } + + // MetaFunctions.dumpStack(this, luaState); + LuaLib.lua_remove(luaState, -1); // remove the nil object value + LuaLib.lua_remove(luaState, -1); // remove the metatable + collectObject(o, index); // Remove from both our tables and fall out to get a new ID + } + + index = addObject(o); + pushNewObject(luaState, o, index, metatable); + } + + /* + * Pushes a new object into the Lua stack with the provided + * metatable + */ + private void pushNewObject(LuaCore.lua_State luaState, object o, int index, string metatable) + { + if(metatable == "luaNet_metatable") + { + // Gets or creates the metatable for the object's type + LuaLib.luaL_getmetatable(luaState, o.GetType().AssemblyQualifiedName); + + if(LuaLib.lua_isnil(luaState, -1)) + { + LuaLib.lua_settop(luaState, -2); + LuaLib.luaL_newmetatable(luaState, o.GetType().AssemblyQualifiedName); + LuaLib.lua_pushstring(luaState, "cache"); + LuaLib.lua_newtable(luaState); + LuaLib.lua_rawset(luaState, -3); + LuaLib.lua_pushlightuserdata(luaState, LuaLib.luanet_gettag()); + LuaLib.lua_pushnumber(luaState, 1); + LuaLib.lua_rawset(luaState, -3); + LuaLib.lua_pushstring(luaState, "__index"); + LuaLib.lua_pushstring(luaState, "luaNet_indexfunction"); + LuaLib.lua_rawget(luaState, (int)LuaIndexes.Registry); + LuaLib.lua_rawset(luaState, -3); + LuaLib.lua_pushstring(luaState, "__gc"); + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.gcFunction); + LuaLib.lua_rawset(luaState, -3); + LuaLib.lua_pushstring(luaState, "__tostring"); + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.toStringFunction); + LuaLib.lua_rawset(luaState, -3); + LuaLib.lua_pushstring(luaState, "__newindex"); + LuaLib.lua_pushstdcallcfunction(luaState, metaFunctions.newindexFunction); + LuaLib.lua_rawset(luaState, -3); + } + } + else + LuaLib.luaL_getmetatable(luaState, metatable); + + // Stores the object index in the Lua list and pushes the + // index into the Lua stack + LuaLib.luaL_getmetatable(luaState, "luaNet_objects"); + LuaLib.luanet_newudata(luaState, index); + LuaLib.lua_pushvalue(luaState, -3); + LuaLib.lua_remove(luaState, -4); + LuaLib.lua_setmetatable(luaState, -2); + LuaLib.lua_pushvalue(luaState, -1); + LuaLib.lua_rawseti(luaState, -3, index); + LuaLib.lua_remove(luaState, -2); + } + + /* + * Gets an object from the Lua stack with the desired type, if it matches, otherwise + * returns null. + */ + internal object getAsType(LuaCore.lua_State luaState, int stackPos, Type paramType) + { + var extractor = typeChecker.checkType(luaState, stackPos, paramType); + return !extractor.IsNull() ? extractor(luaState, stackPos) : null; + } + + /// + /// Given the Lua int ID for an object remove it from our maps + /// + /// + internal void collectObject(int udata) + { + object o; + bool found = objects.TryGetValue(udata, out o); + + // The other variant of collectObject might have gotten here first, in that case we will silently ignore the missing entry + if(found) + { + // Debug.WriteLine("Removing " + o.ToString() + " @ " + udata); + objects.Remove(udata); + objectsBackMap.Remove(o); + } + } + + /// + /// Given an object reference, remove it from our maps + /// + /// + private void collectObject(object o, int udata) + { + // Debug.WriteLine("Removing " + o.ToString() + " @ " + udata); + objects.Remove(udata); + objectsBackMap.Remove(o); + } + + private int addObject(object obj) + { + // New object: inserts it in the list + int index = nextObj++; + // Debug.WriteLine("Adding " + obj.ToString() + " @ " + index); + objects[index] = obj; + objectsBackMap[obj] = index; + return index; + } + + /* + * Gets an object from the Lua stack according to its Lua type. + */ + internal object getObject(LuaCore.lua_State luaState, int index) + { + var type = LuaLib.lua_type(luaState, index); + + switch(type) + { + case LuaTypes.Number: + { + return LuaLib.lua_tonumber(luaState, index); + } + case LuaTypes.String: + { + return LuaLib.lua_tostring(luaState, index); + } + case LuaTypes.Boolean: + { + return LuaLib.lua_toboolean(luaState, index); + } + case LuaTypes.Table: + { + return getTable(luaState, index); + } + case LuaTypes.Function: + { + return getFunction(luaState, index); + } + case LuaTypes.UserData: + { + int udata = LuaLib.luanet_tonetobject(luaState, index); + return udata != -1 ? objects[udata] : getUserData(luaState, index); + } + default: + return null; + } + } + + /* + * Gets the table in the index positon of the Lua stack. + */ + internal LuaTable getTable(LuaCore.lua_State luaState, int index) + { + LuaLib.lua_pushvalue(luaState, index); + return new LuaTable(LuaLib.lua_ref(luaState, 1), interpreter); + } + + /* + * Gets the userdata in the index positon of the Lua stack. + */ + internal LuaUserData getUserData(LuaCore.lua_State luaState, int index) + { + LuaLib.lua_pushvalue(luaState, index); + return new LuaUserData(LuaLib.lua_ref(luaState, 1), interpreter); + } + + /* + * Gets the function in the index positon of the Lua stack. + */ + internal LuaFunction getFunction(LuaCore.lua_State luaState, int index) + { + LuaLib.lua_pushvalue(luaState, index); + return new LuaFunction(LuaLib.lua_ref(luaState, 1), interpreter); + } + + /* + * Gets the CLR object in the index positon of the Lua stack. Returns + * delegates as Lua functions. + */ + internal object getNetObject(LuaCore.lua_State luaState, int index) + { + int idx = LuaLib.luanet_tonetobject(luaState, index); + return idx != -1 ? objects[idx] : null; + } + + /* + * Gets the CLR object in the index positon of the Lua stack. Returns + * delegates as is. + */ + internal object getRawNetObject(LuaCore.lua_State luaState, int index) + { + int udata = LuaLib.luanet_rawnetobj(luaState, index); + return udata != -1 ? objects[udata] : null; + } + + /* + * Pushes the entire array into the Lua stack and returns the number + * of elements pushed. + */ + internal int returnValues(LuaCore.lua_State luaState, object[] returnValues) + { + if(LuaLib.lua_checkstack(luaState, returnValues.Length+5)) + { + for(int i = 0; i < returnValues.Length; i++) + push(luaState, returnValues[i]); + + return returnValues.Length; + } + else + return 0; + } + + /* + * Gets the values from the provided index to + * the top of the stack and returns them in an array. + */ + internal object[] popValues(LuaCore.lua_State luaState, int oldTop) + { + int newTop = LuaLib.lua_gettop(luaState); + + if(oldTop == newTop) + return null; + else + { + var returnValues = new ArrayList(); + for(int i = oldTop+1; i <= newTop; i++) + returnValues.Add(getObject(luaState, i)); + + LuaLib.lua_settop(luaState, oldTop); + return returnValues.ToArray(); + } + } + + /* + * Gets the values from the provided index to + * the top of the stack and returns them in an array, casting + * them to the provided types. + */ + internal object[] popValues(LuaCore.lua_State luaState, int oldTop, Type[] popTypes) + { + int newTop = LuaLib.lua_gettop(luaState); + + if(oldTop == newTop) + return null; + else + { + int iTypes; + var returnValues = new ArrayList(); + + if(popTypes[0] == typeof(void)) + iTypes = 1; + else + iTypes = 0; + + for(int i = oldTop+1; i <= newTop; i++) + { + returnValues.Add(getAsType(luaState, i, popTypes[iTypes])); + iTypes++; + } + + LuaLib.lua_settop(luaState, oldTop); + return returnValues.ToArray(); + } + } + + // kevinh - the following line doesn't work for remoting proxies - they always return a match for 'is' + // else if(o is ILuaGeneratedType) + private static bool IsILua(object o) + { + if(o is ILuaGeneratedType) + { + // Make sure we are _really_ ILuaGenerated + var typ = o.GetType(); + return (!typ.GetInterface("ILuaGeneratedType").IsNull ()); + } + else + return false; + } + + /* + * Pushes the object into the Lua stack according to its type. + */ + internal void push(LuaCore.lua_State luaState, object o) + { + if(o.IsNull()) + LuaLib.lua_pushnil(luaState); + else if(o is sbyte || o is byte || o is short || o is ushort || + o is int || o is uint || o is long || o is float || + o is ulong || o is decimal || o is double) + { + double d = Convert.ToDouble(o); + LuaLib.lua_pushnumber(luaState, d); + } + else if(o is char) + { + double d = (char)o; + LuaLib.lua_pushnumber(luaState, d); + } + else if(o is string) + { + string str = (string)o; + LuaLib.lua_pushstring(luaState, str); + } + else if(o is bool) + { + bool b = (bool)o; + LuaLib.lua_pushboolean(luaState, b); + } + else if(IsILua(o)) + (((ILuaGeneratedType)o).__luaInterface_getLuaTable()).push(luaState); + else if(o is LuaTable) + ((LuaTable)o).push(luaState); + else if(o is LuaCore.lua_CFunction) + pushFunction(luaState, (LuaCore.lua_CFunction)o); + else if(o is LuaFunction) + ((LuaFunction)o).push(luaState); + else + pushObject(luaState, o, "luaNet_metatable"); + } + + /* + * Checks if the method matches the arguments in the Lua stack, getting + * the arguments if it does. + */ + internal bool matchParameters(LuaCore.lua_State luaState, MethodBase method, ref MethodCache methodCache) + { + return metaFunctions.matchParameters(luaState, method, ref methodCache); + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/Properties/AssemblyInfo.cs b/Core/LuaInterface/Properties/AssemblyInfo.cs index c5b66930a83d0dd361a38cbf3fc5eaefeef371a5..54422d7ffe990b1d48c519e001bbc73b0e91bf8e 100644 --- a/Core/LuaInterface/Properties/AssemblyInfo.cs +++ b/Core/LuaInterface/Properties/AssemblyInfo.cs @@ -1,61 +1,61 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using LuaInterface.Config; - -// Information about this assembly is defined by the following attributes. -// Change them to the values specific to your project. - -[assembly: AssemblyTitle("LuaInterface")] -[assembly: AssemblyDescription(Consts.LuaInterfaceDescription)] -[assembly: AssemblyConfiguration(Consts.LuaInterfaceConfiguration)] -[assembly: AssemblyCompany(Consts.LuaInterfaceCompany)] -[assembly: AssemblyProduct(Consts.LuaInterfaceProduct)] -[assembly: AssemblyCopyright(Consts.LuaInterfaceCopyright)] -[assembly: AssemblyTrademark(Consts.LuaInterfaceTrademark)] - -[assembly: CLSCompliant(true)] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion(Consts.LuaInterfaceVersion)] +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using LuaInterface.Config; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("LuaInterface")] +[assembly: AssemblyDescription(Consts.LuaInterfaceDescription)] +[assembly: AssemblyConfiguration(Consts.LuaInterfaceConfiguration)] +[assembly: AssemblyCompany(Consts.LuaInterfaceCompany)] +[assembly: AssemblyProduct(Consts.LuaInterfaceProduct)] +[assembly: AssemblyCopyright(Consts.LuaInterfaceCopyright)] +[assembly: AssemblyTrademark(Consts.LuaInterfaceTrademark)] + +[assembly: CLSCompliant(true)] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion(Consts.LuaInterfaceVersion)] [assembly: AssemblyFileVersion(Consts.LuaInterfaceFileVersion)] \ No newline at end of file diff --git a/Core/LuaInterface/ProxyType.cs b/Core/LuaInterface/ProxyType.cs index c4668c5679991fc5797606a0d71188ca90ae1a61..c315924839ffc82f9d246159905e3fd3628dd610 100644 --- a/Core/LuaInterface/ProxyType.cs +++ b/Core/LuaInterface/ProxyType.cs @@ -1,115 +1,115 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Globalization; -using System.Reflection; - -namespace LuaInterface -{ - using LuaCore = KopiLua.Lua; - - /// - /// Summary description for ProxyType. - /// - public class ProxyType : IReflect - { - private Type proxy; - - public ProxyType(Type proxy) - { - this.proxy = proxy; - } - - /// - /// Provide human readable short hand for this proxy object - /// - /// - public override string ToString() - { - return "ProxyType(" + UnderlyingSystemType + ")"; - } - - public Type UnderlyingSystemType - { - get { return proxy; } - } - - public FieldInfo GetField(string name, BindingFlags bindingAttr) - { - return proxy.GetField(name, bindingAttr); - } - - public FieldInfo[] GetFields(BindingFlags bindingAttr) - { - return proxy.GetFields(bindingAttr); - } - - public MemberInfo[] GetMember(string name, BindingFlags bindingAttr) - { - return proxy.GetMember(name, bindingAttr); - } - - public MemberInfo[] GetMembers(BindingFlags bindingAttr) - { - return proxy.GetMembers(bindingAttr); - } - - public MethodInfo GetMethod(string name, BindingFlags bindingAttr) - { - return proxy.GetMethod(name, bindingAttr); - } - - public MethodInfo GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) - { - return proxy.GetMethod(name, bindingAttr, binder, types, modifiers); - } - - public MethodInfo[] GetMethods(BindingFlags bindingAttr) - { - return proxy.GetMethods(bindingAttr); - } - - public PropertyInfo GetProperty(string name, BindingFlags bindingAttr) - { - return proxy.GetProperty(name, bindingAttr); - } - - public PropertyInfo GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) - { - return proxy.GetProperty(name, bindingAttr, binder, returnType, types, modifiers); - } - - public PropertyInfo[] GetProperties(BindingFlags bindingAttr) - { - return proxy.GetProperties(bindingAttr); - } - - public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) - { - return proxy.InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters); - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Globalization; +using System.Reflection; + +namespace LuaInterface +{ + using LuaCore = KopiLua.Lua; + + /// + /// Summary description for ProxyType. + /// + public class ProxyType : IReflect + { + private Type proxy; + + public ProxyType(Type proxy) + { + this.proxy = proxy; + } + + /// + /// Provide human readable short hand for this proxy object + /// + /// + public override string ToString() + { + return "ProxyType(" + UnderlyingSystemType + ")"; + } + + public Type UnderlyingSystemType + { + get { return proxy; } + } + + public FieldInfo GetField(string name, BindingFlags bindingAttr) + { + return proxy.GetField(name, bindingAttr); + } + + public FieldInfo[] GetFields(BindingFlags bindingAttr) + { + return proxy.GetFields(bindingAttr); + } + + public MemberInfo[] GetMember(string name, BindingFlags bindingAttr) + { + return proxy.GetMember(name, bindingAttr); + } + + public MemberInfo[] GetMembers(BindingFlags bindingAttr) + { + return proxy.GetMembers(bindingAttr); + } + + public MethodInfo GetMethod(string name, BindingFlags bindingAttr) + { + return proxy.GetMethod(name, bindingAttr); + } + + public MethodInfo GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) + { + return proxy.GetMethod(name, bindingAttr, binder, types, modifiers); + } + + public MethodInfo[] GetMethods(BindingFlags bindingAttr) + { + return proxy.GetMethods(bindingAttr); + } + + public PropertyInfo GetProperty(string name, BindingFlags bindingAttr) + { + return proxy.GetProperty(name, bindingAttr); + } + + public PropertyInfo GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) + { + return proxy.GetProperty(name, bindingAttr, binder, returnType, types, modifiers); + } + + public PropertyInfo[] GetProperties(BindingFlags bindingAttr) + { + return proxy.GetProperties(bindingAttr); + } + + public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) + { + return proxy.InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters); + } + } } \ No newline at end of file diff --git a/Core/LuaInterface/luainterface.pc.in b/Core/LuaInterface/luainterface.pc.in new file mode 100644 index 0000000000000000000000000000000000000000..fd43937db4127910ae97bb61c638198b5638c43e --- /dev/null +++ b/Core/LuaInterface/luainterface.pc.in @@ -0,0 +1,6 @@ +Name: LuaInterface +Description: LuaInterface +Version: 2.x + +Requires: +Libs: -r:@expanded_libdir@/@PACKAGE@/LuaInterface.dll diff --git a/Core/Makefile.am b/Core/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..bcf7837a802fec6fa59aca8d272765c4626dc6bb --- /dev/null +++ b/Core/Makefile.am @@ -0,0 +1,16 @@ + +EXTRA_DIST = + +#Warning: This is an automatically generated file, do not edit! +if ENABLE_DEBUG_X86 + SUBDIRS = KopiLua LuaInterface +endif +if ENABLE_RELEASE_X86 + SUBDIRS = KopiLua LuaInterface +endif +if ENABLE_DEBUG_X64 + SUBDIRS = KopiLua LuaInterface +endif +if ENABLE_RELEASE_X64 + SUBDIRS = KopiLua LuaInterface +endif diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..9828be637e76c02ea746763bc5e252498848decf --- /dev/null +++ b/Makefile.am @@ -0,0 +1,16 @@ + +EXTRA_DIST = expansions.m4 + +#Warning: This is an automatically generated file, do not edit! +if ENABLE_DEBUG_X86 + SUBDIRS = Core Test/TestLuaInterface Applications/LuaRunner +endif +if ENABLE_RELEASE_X86 + SUBDIRS = Core Test/TestLuaInterface Applications/LuaRunner +endif +if ENABLE_DEBUG_X64 + SUBDIRS = Core Test/TestLuaInterface Applications/LuaRunner +endif +if ENABLE_RELEASE_X64 + SUBDIRS = Core Test/TestLuaInterface Applications/LuaRunner +endif diff --git a/Makefile.include b/Makefile.include new file mode 100644 index 0000000000000000000000000000000000000000..e578071c4e9c093d4db6a95c3143f28e44bf2b6c --- /dev/null +++ b/Makefile.include @@ -0,0 +1,119 @@ +VALID_CULTURES = ar bg ca zh-CHS cs da de el en es fi fr he hu is it ja ko nl no pl pt ro ru hr sk sq sv th tr id uk be sl et lv lt fa vi hy eu mk af ka fo hi sw gu ta te kn mr gl kok ar-SA bg-BG ca-ES zh-TW cs-CZ da-DK de-DE el-GR en-US fi-FI fr-FR he-IL hu-HU is-IS it-IT ja-JP ko-KR nl-NL nb-NO pl-PL pt-BR ro-RO ru-RU hr-HR sk-SK sq-AL sv-SE th-TH tr-TR id-ID uk-UA be-BY sl-SI et-EE lv-LV lt-LT fa-IR vi-VN hy-AM eu-ES mk-MK af-ZA ka-GE fo-FO hi-IN sw-KE gu-IN ta-IN te-IN kn-IN mr-IN gl-ES kok-IN ar-IQ zh-CN de-CH en-GB es-MX fr-BE it-CH nl-BE nn-NO pt-PT sv-FI ar-EG zh-HK de-AT en-AU es-ES fr-CA ar-LY zh-SG de-LU en-CA es-GT fr-CH ar-DZ zh-MO en-NZ es-CR fr-LU ar-MA en-IE es-PA ar-TN en-ZA es-DO ar-OM es-VE ar-YE es-CO ar-SY es-PE ar-JO en-TT es-AR ar-LB en-ZW es-EC ar-KW en-PH es-CL ar-AE es-UY ar-BH es-PY ar-QA es-BO es-SV es-HN es-NI es-PR zh-CHT + +s2q=$(subst \ ,?,$1) +q2s=$(subst ?,\ ,$1) +# use this when result will be quoted +unesc2=$(subst ?, ,$1) + +build_sources = $(FILES) $(GENERATED_FILES) +build_sources_esc= $(call s2q,$(build_sources)) +# use unesc2, as build_sources_embed is quoted +build_sources_embed= $(call unesc2,$(build_sources_esc:%='$(srcdir)/%')) + +comma__=, +get_resource_name = $(firstword $(subst $(comma__), ,$1)) +get_culture = $(lastword $(subst ., ,$(basename $1))) +is_cultured_resource = $(and $(word 3,$(subst ., ,$1)), $(filter $(VALID_CULTURES),$(lastword $(subst ., ,$(basename $1))))) + +RESOURCES_ESC=$(call s2q,$(RESOURCES)) + +build_resx_list = $(foreach res, $(RESOURCES_ESC), $(if $(filter %.resx, $(call get_resource_name,$(res))),$(res),)) +build_non_culture_resx_list = $(foreach res, $(build_resx_list),$(if $(call is_cultured_resource,$(call get_resource_name,$(res))),,$(res))) +build_non_culture_others_list = $(foreach res, $(filter-out $(build_resx_list),$(RESOURCES_ESC)),$(if $(call is_cultured_resource,$(call get_resource_name,$(res))),,$(res))) +build_others_list = $(build_non_culture_others_list) +build_xamlg_list = $(filter %.xaml.g.cs, $(FILES)) + +# resgen all .resx resources +build_resx_files = $(foreach res, $(build_resx_list), $(call get_resource_name,$(res))) +build_resx_resources_esc = $(build_resx_files:.resx=.resources) +build_resx_resources = $(call q2s,$(build_resx_resources_esc)) + +# embed resources for the main assembly +build_resx_resources_hack = $(subst .resx,.resources, $(build_non_culture_resx_list)) +# use unesc2, as build_resx_resources_embed is quoted +build_resx_resources_embed = $(call unesc2,$(build_resx_resources_hack:%='-resource:%')) +build_others_files = $(call q2s,$(foreach res, $(build_others_list),$(call get_resource_name,$(res)))) +build_others_resources = $(build_others_files) +# use unesc2, as build_others_resources_embed is quoted +build_others_resources_embed = $(call unesc2,$(build_others_list:%='-resource:$(srcdir)/%')) + +build_resources = $(build_resx_resources) $(build_others_resources) +build_resources_embed = $(build_resx_resources_embed) $(build_others_resources_embed) + +# -usesourcepath is available only for resgen2 +emit_resgen_target_1=$(call q2s,$1) : $(call q2s,$(subst .resources,.resx,$1)); cd '$$(shell dirname '$$<')' && MONO_IOMAP=drive $$(RESGEN) '$$(shell basename '$$<')' '$$(shell basename '$$@')' +emit_resgen_target_2=$(call q2s,$1) : $(call q2s,$(subst .resources,.resx,$1)); MONO_IOMAP=drive $$(RESGEN) -usesourcepath '$$<' '$$@' + +emit_resgen_target=$(if $(filter resgen2,$(RESGEN)),$(emit_resgen_target_2),$(emit_resgen_target_1)) +emit_resgen_targets=$(foreach res,$(build_resx_resources_esc),$(eval $(call emit_resgen_target,$(res)))) + +build_references_ref = $(call q2s,$(foreach ref, $(call s2q,$(REFERENCES)), $(if $(filter -pkg:%, $(ref)), $(ref), $(if $(filter -r:%, $(ref)), $(ref), -r:$(ref))))) +build_references_ref += $(call q2s,$(foreach ref, $(call s2q,$(DLL_REFERENCES)), -r:$(ref))) +build_references_ref += $(call q2s,$(foreach ref, $(call s2q,$(PROJECT_REFERENCES)), -r:$(ref))) + +s2q2s=$(call unesc2,$(call s2q,$1)) +cp_actual=test -z $1 || cp $1 $2 +cp=$(call cp_actual,'$(call s2q2s,$1)','$(call s2q2s,$2)') + +rm_actual=test -z '$1' || rm -f '$2' +rm=$(call rm_actual,$(call s2q2s,$1),$(call s2q2s,$2)/$(shell basename '$(call s2q2s,$1)')) + +EXTRA_DIST += $(build_sources) $(build_resx_files) $(build_others_files) $(ASSEMBLY_WRAPPER_IN) $(EXTRAS) $(DATA_FILES) $(build_culture_res_files) +CLEANFILES += $(ASSEMBLY) $(ASSEMBLY).mdb $(BINARIES) $(build_resx_resources) $(build_satellite_assembly_list) +DISTCLEANFILES = $(GENERATED_FILES) $(pc_files) $(BUILD_DIR)/* + +programfilesdir = $(pkglibdir) +programfiles_DATA = $(ASSEMBLY) +bin_SCRIPTS = $(BINARIES) + +programfilesdir = @libdir@/@PACKAGE@ +programfiles_DATA = $(PROGRAMFILES) +linuxpkgconfigdir = @libdir@/pkgconfig +linuxpkgconfig_DATA = $(LINUX_PKGCONFIG) + + +# macros + +# $(call emit-deploy-target,deploy-variable-name) +define emit-deploy-target +$($1): $($1_SOURCE) + mkdir -p '$$(shell dirname '$$@')' + cp '$$<' '$$@' +endef + +# $(call emit-deploy-wrapper,wrapper-variable-name,wrapper-sourcefile,x) +# assumes that for a wrapper foo.pc its source template is foo.pc.in +# if $3 is non-empty then wrapper is marked exec +define emit-deploy-wrapper +$($1): $2 + mkdir -p '$$(shell dirname '$$@')' + cp '$$<' '$$@' + $(if $3,chmod +x '$$@') + +endef + +# generating satellite assemblies + +culture_resources = $(foreach res, $(RESOURCES_ESC), $(if $(call is_cultured_resource,$(call get_resource_name, $(res))),$(res))) +cultures = $(sort $(foreach res, $(culture_resources), $(call get_culture,$(call get_resource_name,$(res))))) +culture_resource_dependencies = $(call q2s,$(BUILD_DIR)/$1/$(SATELLITE_ASSEMBLY_NAME): $(subst .resx,.resources,$2)) +culture_resource_commandlines = $(call unesc2,cmd_line_satellite_$1 += '/embed:$(subst .resx,.resources,$2)') +build_satellite_assembly_list = $(call q2s,$(cultures:%=$(BUILD_DIR)/%/$(SATELLITE_ASSEMBLY_NAME))) +build_culture_res_files = $(call q2s,$(foreach res, $(culture_resources),$(call get_resource_name,$(res)))) +install_satellite_assembly_list = $(subst $(BUILD_DIR),$(DESTDIR)$(libdir)/$(PACKAGE),$(build_satellite_assembly_list)) + +$(eval $(foreach res, $(culture_resources), $(eval $(call culture_resource_dependencies,$(call get_culture,$(call get_resource_name,$(res))),$(call get_resource_name,$(res)))))) +$(eval $(foreach res, $(culture_resources), $(eval $(call culture_resource_commandlines,$(call get_culture,$(call get_resource_name,$(res))),$(res))))) + +$(build_satellite_assembly_list): $(BUILD_DIR)/%/$(SATELLITE_ASSEMBLY_NAME): + mkdir -p '$(@D)' + $(AL) -out:'$@' -culture:$* -t:lib $(cmd_line_satellite_$*) + +$(install_satellite_assembly_list): + mkdir -p '$(@D)' + cp $(subst $(DESTDIR)$(libdir)/$(PACKAGE), $(BUILD_DIR), $@) $@ + +install-satellite-assemblies: $(install_satellite_assembly_list) + +uninstall-satellite-assemblies: + rm -rf $(install_satellite_assembly_list) \ No newline at end of file diff --git a/README b/README index 02cf07c15fe3122b3a55e53bacf050f5ff7fec67..35d23fc74362f2cad72d01768438b225358516e4 100644 --- a/README +++ b/README @@ -1,188 +1,188 @@ -LuaInterface 2.0.4 ------------------- - -Copyright 2003-2006 Fabio Mascarenhas de Queiroz - -Maintainer: Craig Presti, craig@vastpark.com - -lua51.dll and lua51.exe are Copyright 2005 Tecgraf, PUC-Rio - - -Getting started with LuaInterface: ---------- -* Use LuaRunner.exe to run samples/testluaform.lua -* Run TestLua.exe to see some more test cases -* Look at src/TestLuaInterface/TestLua to see example usage from C# -(optionally run this from inside of the LuaInterface solution in -the debugger). Also provides a good example of how to override .net -methods from Lua and use LuaInterface from within your .net application. -* Look at samples/testluaform.lua to see examples of how to use -.net from inside Lua -* More instructions for installing and using in the doc/guide.pdf file. - -What's new in LuaInterface 2.0.3 ------------------------------- -* Fix: Private methods accessible via LuaInterface -* Fix: Method overload lookup failures -* Fix: Lua DoFile memory leaks when file not found (submitted by Paul Moore) -* Fix: Lua Dispose not freeing memory (submitted by Paul Moore) -* Fix: Better support for accessing indexers -* Fix: Parsing error for MBCS characters (qingrui.li) -* Fix: Dispose errors originating from LuaTable, LuaFunction, LuaUserData -* Fix: LuaInterface no longer disposes the state when passed one via the overloaded constructor -* Added: LoadString and LoadFile (submitted by Paul Moore) -* Added: Overloaded DoString -* Added: Lua debugging support (rostermeier) - - -What's new in LuaInterface 2.0.1 ------------------------------- -* Apparently the 2.0 built binaries had an issue for some users, this is just a rebuild with the lua sources pulled into the LuaInterface.zip - -What's new in LuaInterface 2.0 ------------------------------- -* The base lua5.1.2 library is now built as entirely manged code. LuaInterface is now pure CIL -* Various adapters to connect the older x86 version of lua are no longer needed -* Performance fixes contributed by Toby Lawrence, Oliver Nemoz and Craig Presti - -What's new in LuaInterface 1.5.3 ----------- -* Internal lua panics (due to API violations) now throw LuaExceptions into .net -* If .net code throws an exception into Lua and lua does not handle it, the -original exception is forwarded back out to .net land. -* Fix bug in the Lua 5.1.1 gmatch C code - it was improperly assuming gmatch -only works with tables. - -What's new in LuaInterface 1.5.2 ----------- -* Overriding C# methods from Lua is fixed (broken with .net 2.0!) -* Registering static C# functions for Lua is fixed (broken with Lua-5.1.1) -* Rebuilt to fix linking problems with the binaries included in 1.5.1 -* RegisterFunction has been leaking things onto the stack - -What's new in LuaInterface 1.5.1 ----------- -Fix a serious bug w.r.t. garbage collection - made especially apparent -with the new lua5.1 switch: If you were *very* unlucky with timing -sometimes Lua would loose track of pointers to CLR functions. - -When I added support for static methods, I allowed the user to use either a -colon or a dot to separate the method from the class name. This was not -correct - it broke disambiguation between overloaded static methods. -Therefore, LuaInterface is now more strict: If you want to call a static -method, you must use dot to separate the method name from the class name. Of -course you can still use a colon if an _instance_ is being used. - -Static method calls are now much faster (due to better caching). - -What's new in LuaInterface 1.5 ----------- -LuaInterface is now updated to be based on Lua5.1.1. You can either use -your own build/binaries for Lua5.1.1 or use the version distributed here. -(Lots of thanks to Steffen Itterheim for this work!) - -LuaInterface.Lua no longer has OpenLibs etc... The base mechanism for -library loading for Lua has changed, and we haven't yet broken appart -the library loading for LuaInterface. Instead, all standard Lua libraries -are automatically loaded at start up. - -Fixed a bug where calls of some static methods would reference an -invalid pointer. - -Fixed a bug when strings with embedded null characters are passed in or -out of Lua (Thanks to Daniel Nri for the report & fix!) - -The native components in LuaInterface (i.e. Lua51 and the loader) are -both built as release builds - to prevent problems loading standard -windows libraries. - -Note: You do not need to download/build lua-5.1.1.zip unless you want to -modify Lua internals (a built version of lua51.dll is included in the -regular LuaInterface distribution) - -What's New in LuaInterface 1.4 ----------- - -Note: Fabio area of interest has moved off in other directions (hopefully only temporarily). -I've talked with Fabio and he's said he's okay with me doing a new release with various fixes -I've made over the last few months. Changes since 1.3: - -Visual Studio 2005/.Net 2.0 is supported. - -Compat-5.1 is modified to expect backslash as the path seperator. - -LuaInterface will now work correctly with Generic C# classes. - -CLR inner types are now supported. - -Fixed a problem where sometimes Lua proxy objects would be associated with the wrong CLR object. - -If a CLR class has an array accessor, the elements can be accessed using the regular Lua indexing -interface. - -Add CLRPackage.lua to the samples directory. This class makes it much easier to automatically -load referenced assemblies. In the next release this loading will be automatic. - -To see an quick demonstration of LuaInterface, cd into luainterface/samples and then -type: ..\..\Built\debug\LuaRunner.exe testluaform.lua - -Various other minor fixes that I've forgotten. I'll keep better track next time. - -Note: LuaInterface is still based on Lua 5.0.2. If someone really wants us to upgrade to Lua 5.1 -please send me a note. In the mean time, I'm also distributing a version of -Lua 5.0.2 with an appropriate VS 2005 project file. You do not need to -download this file unless you want to modify Lua internals (a built version -of lua50.dll is included in the regular LuaInterface distribution) - -What's New in LuaInterface 1.3 ----------- - -LuaInterface now works with LuaBinaries Release 2 (http://luabinaries.luaforge.net) -and Compat-5.1 Release 3 (http://luaforge.net/projects/compat). The loader DLL is now -called luanet.dll, and does not need a luainterface.lua file anymore -(just put LuaInterface.dll in the GAC, luanet.dll in your package.cpath, and -do require"luanet"). - -Fixed a bug in the treatment of the char type (thanks to Ron Scott). - -LuaInterface.dll now has a strong name, and can be put in the GAC (thanks to Ivan Voras). - -You can now use foreach with instances of LuaTable (thanks to Zachary Landau). - -There is an alternate form of loading assemblies and importing types (based on an -anonymous contribution in the Lua wiki). Check the _alt files in the samples folder. - - -What's New in LuaInterface 1.2.1 --------------------------------- - -Now checks if two LuaInterface.Lua instances are trying to share the same Lua state, -and throws an exception if this is the case. Also included readonly clauses in public -members of the Lua and ObjectTranslator classes. - -This version includes the source of LuaInterfaceLoader.dll, with VS.Net 2003 project -files. - -What's New in LuaInterface 1.2 ------------------------------- - -LuaInterface now can be loaded as a module, so you can use the lua standalone -interpreter to run scripts. Thanks to Paul Winwood for this idea and sample code -showing how to load the CLR from a C++ program. The module is "luainterface". Make -sure Lua can find luainterface.lua, and LuaInterfaceLoader.dll is either in the -current directory or the GAC. The samples now load LuaInterface as a module, in -its own namespace. - -The get_method_bysig, get_constructor_bysig and make_object were changed: now you -pass the *names* of the types to them, instead of the types themselves. E.g: - - get_method_bysig(obj,"method","System.String") - -instead of - - String = import_type("System.String") - get_method_bysig(obj,"method",String) - -Make sure the assemblies of the types you are passing have been loaded, or the call -will fail. The test cases in src/TestLuaInterface/TestLua.cs have examples of the new -functions. +LuaInterface 2.0.4 +------------------ + +Copyright 2003-2006 Fabio Mascarenhas de Queiroz + +Maintainer: Craig Presti, craig@vastpark.com + +lua51.dll and lua51.exe are Copyright 2005 Tecgraf, PUC-Rio + + +Getting started with LuaInterface: +--------- +* Use LuaRunner.exe to run samples/testluaform.lua +* Run TestLua.exe to see some more test cases +* Look at src/TestLuaInterface/TestLua to see example usage from C# +(optionally run this from inside of the LuaInterface solution in +the debugger). Also provides a good example of how to override .net +methods from Lua and use LuaInterface from within your .net application. +* Look at samples/testluaform.lua to see examples of how to use +.net from inside Lua +* More instructions for installing and using in the doc/guide.pdf file. + +What's new in LuaInterface 2.0.3 +------------------------------ +* Fix: Private methods accessible via LuaInterface +* Fix: Method overload lookup failures +* Fix: Lua DoFile memory leaks when file not found (submitted by Paul Moore) +* Fix: Lua Dispose not freeing memory (submitted by Paul Moore) +* Fix: Better support for accessing indexers +* Fix: Parsing error for MBCS characters (qingrui.li) +* Fix: Dispose errors originating from LuaTable, LuaFunction, LuaUserData +* Fix: LuaInterface no longer disposes the state when passed one via the overloaded constructor +* Added: LoadString and LoadFile (submitted by Paul Moore) +* Added: Overloaded DoString +* Added: Lua debugging support (rostermeier) + + +What's new in LuaInterface 2.0.1 +------------------------------ +* Apparently the 2.0 built binaries had an issue for some users, this is just a rebuild with the lua sources pulled into the LuaInterface.zip + +What's new in LuaInterface 2.0 +------------------------------ +* The base lua5.1.2 library is now built as entirely manged code. LuaInterface is now pure CIL +* Various adapters to connect the older x86 version of lua are no longer needed +* Performance fixes contributed by Toby Lawrence, Oliver Nemoz and Craig Presti + +What's new in LuaInterface 1.5.3 +---------- +* Internal lua panics (due to API violations) now throw LuaExceptions into .net +* If .net code throws an exception into Lua and lua does not handle it, the +original exception is forwarded back out to .net land. +* Fix bug in the Lua 5.1.1 gmatch C code - it was improperly assuming gmatch +only works with tables. + +What's new in LuaInterface 1.5.2 +---------- +* Overriding C# methods from Lua is fixed (broken with .net 2.0!) +* Registering static C# functions for Lua is fixed (broken with Lua-5.1.1) +* Rebuilt to fix linking problems with the binaries included in 1.5.1 +* RegisterFunction has been leaking things onto the stack + +What's new in LuaInterface 1.5.1 +---------- +Fix a serious bug w.r.t. garbage collection - made especially apparent +with the new lua5.1 switch: If you were *very* unlucky with timing +sometimes Lua would loose track of pointers to CLR functions. + +When I added support for static methods, I allowed the user to use either a +colon or a dot to separate the method from the class name. This was not +correct - it broke disambiguation between overloaded static methods. +Therefore, LuaInterface is now more strict: If you want to call a static +method, you must use dot to separate the method name from the class name. Of +course you can still use a colon if an _instance_ is being used. + +Static method calls are now much faster (due to better caching). + +What's new in LuaInterface 1.5 +---------- +LuaInterface is now updated to be based on Lua5.1.1. You can either use +your own build/binaries for Lua5.1.1 or use the version distributed here. +(Lots of thanks to Steffen Itterheim for this work!) + +LuaInterface.Lua no longer has OpenLibs etc... The base mechanism for +library loading for Lua has changed, and we haven't yet broken appart +the library loading for LuaInterface. Instead, all standard Lua libraries +are automatically loaded at start up. + +Fixed a bug where calls of some static methods would reference an +invalid pointer. + +Fixed a bug when strings with embedded null characters are passed in or +out of Lua (Thanks to Daniel Nri for the report & fix!) + +The native components in LuaInterface (i.e. Lua51 and the loader) are +both built as release builds - to prevent problems loading standard +windows libraries. + +Note: You do not need to download/build lua-5.1.1.zip unless you want to +modify Lua internals (a built version of lua51.dll is included in the +regular LuaInterface distribution) + +What's New in LuaInterface 1.4 +---------- + +Note: Fabio area of interest has moved off in other directions (hopefully only temporarily). +I've talked with Fabio and he's said he's okay with me doing a new release with various fixes +I've made over the last few months. Changes since 1.3: + +Visual Studio 2005/.Net 2.0 is supported. + +Compat-5.1 is modified to expect backslash as the path seperator. + +LuaInterface will now work correctly with Generic C# classes. + +CLR inner types are now supported. + +Fixed a problem where sometimes Lua proxy objects would be associated with the wrong CLR object. + +If a CLR class has an array accessor, the elements can be accessed using the regular Lua indexing +interface. + +Add CLRPackage.lua to the samples directory. This class makes it much easier to automatically +load referenced assemblies. In the next release this loading will be automatic. + +To see an quick demonstration of LuaInterface, cd into luainterface/samples and then +type: ..\..\Built\debug\LuaRunner.exe testluaform.lua + +Various other minor fixes that I've forgotten. I'll keep better track next time. + +Note: LuaInterface is still based on Lua 5.0.2. If someone really wants us to upgrade to Lua 5.1 +please send me a note. In the mean time, I'm also distributing a version of +Lua 5.0.2 with an appropriate VS 2005 project file. You do not need to +download this file unless you want to modify Lua internals (a built version +of lua50.dll is included in the regular LuaInterface distribution) + +What's New in LuaInterface 1.3 +---------- + +LuaInterface now works with LuaBinaries Release 2 (http://luabinaries.luaforge.net) +and Compat-5.1 Release 3 (http://luaforge.net/projects/compat). The loader DLL is now +called luanet.dll, and does not need a luainterface.lua file anymore +(just put LuaInterface.dll in the GAC, luanet.dll in your package.cpath, and +do require"luanet"). + +Fixed a bug in the treatment of the char type (thanks to Ron Scott). + +LuaInterface.dll now has a strong name, and can be put in the GAC (thanks to Ivan Voras). + +You can now use foreach with instances of LuaTable (thanks to Zachary Landau). + +There is an alternate form of loading assemblies and importing types (based on an +anonymous contribution in the Lua wiki). Check the _alt files in the samples folder. + + +What's New in LuaInterface 1.2.1 +-------------------------------- + +Now checks if two LuaInterface.Lua instances are trying to share the same Lua state, +and throws an exception if this is the case. Also included readonly clauses in public +members of the Lua and ObjectTranslator classes. + +This version includes the source of LuaInterfaceLoader.dll, with VS.Net 2003 project +files. + +What's New in LuaInterface 1.2 +------------------------------ + +LuaInterface now can be loaded as a module, so you can use the lua standalone +interpreter to run scripts. Thanks to Paul Winwood for this idea and sample code +showing how to load the CLR from a C++ program. The module is "luainterface". Make +sure Lua can find luainterface.lua, and LuaInterfaceLoader.dll is either in the +current directory or the GAC. The samples now load LuaInterface as a module, in +its own namespace. + +The get_method_bysig, get_constructor_bysig and make_object were changed: now you +pass the *names* of the types to them, instead of the types themselves. E.g: + + get_method_bysig(obj,"method","System.String") + +instead of + + String = import_type("System.String") + get_method_bysig(obj,"method",String) + +Make sure the assemblies of the types you are passing have been loaded, or the call +will fail. The test cases in src/TestLuaInterface/TestLua.cs have examples of the new +functions. diff --git a/Samples/CLRPackage.lua b/Samples/CLRPackage.lua index c253b108c3093e462106eeb158c0825b45c9e1eb..88761a126396a98ee013050724f0a8f2f852fbb8 100644 --- a/Samples/CLRPackage.lua +++ b/Samples/CLRPackage.lua @@ -1,35 +1,35 @@ ---- ---- This lua module provides auto importing of .net classes into a named package. ---- Makes for super easy use of LuaInterface glue ---- ---- example: ---- Threading = CLRPackage("System", "System.Threading") ---- Threading.Thread.Sleep(100) - -local mt = { - --- Lookup a previously unfound class and add it to our table - __index = function(package, classname) - local class = rawget(package, classname) - - if class == nil then - class = luanet.import_type(package.packageName .. "." .. classname) - package[classname] = class -- keep what we found around, so it will be shared - end - - return class - end - } - ---- Create a new Package class -function CLRPackage(assemblyName, packageName) - local table = {} - - luanet.load_assembly(assemblyName) -- Make sure our assembly is loaded - - -- FIXME - table.packageName could instead be a private index (see Lua 13.4.4) - table.packageName = packageName - setmetatable(table, mt) - - return table -end - +--- +--- This lua module provides auto importing of .net classes into a named package. +--- Makes for super easy use of LuaInterface glue +--- +--- example: +--- Threading = CLRPackage("System", "System.Threading") +--- Threading.Thread.Sleep(100) + +local mt = { + --- Lookup a previously unfound class and add it to our table + __index = function(package, classname) + local class = rawget(package, classname) + + if class == nil then + class = luanet.import_type(package.packageName .. "." .. classname) + package[classname] = class -- keep what we found around, so it will be shared + end + + return class + end + } + +--- Create a new Package class +function CLRPackage(assemblyName, packageName) + local table = {} + + luanet.load_assembly(assemblyName) -- Make sure our assembly is loaded + + -- FIXME - table.packageName could instead be a private index (see Lua 13.4.4) + table.packageName = packageName + setmetatable(table, mt) + + return table +end + diff --git a/Samples/README.txt b/Samples/README.txt index a47e479c96db1b84acdfea60f75fadcc20bdb2ce..1e00415dd7e783a57e24da8b5d524fda6d8e6680 100644 --- a/Samples/README.txt +++ b/Samples/README.txt @@ -1,7 +1,7 @@ -Some example scripts, showing what LuaInterface can do. - -form A simple form, basic event handling -socket Fetches the content of a web site and prints to the - console -testluaform A more complex WinForms example, type some Lua code in - the textbox and run it, or load a Lua script. +Some example scripts, showing what LuaInterface can do. + +form A simple form, basic event handling +socket Fetches the content of a web site and prints to the + console +testluaform A more complex WinForms example, type some Lua code in + the textbox and run it, or load a Lua script. diff --git a/Samples/form.lua b/Samples/form.lua index 1ecd3f18bd18a64d4810d7ab6fd5d01890da6494..4764bdae3beea508a809eef2a012d76d244aad3f 100644 --- a/Samples/form.lua +++ b/Samples/form.lua @@ -1,38 +1,38 @@ --- kevinh - the following lines are part of our standard init --- require("compat-5.1") - -luanet.load_assembly("System.Windows.Forms") -luanet.load_assembly("System.Drawing") - -Form=luanet.import_type("System.Windows.Forms.Form") -Button=luanet.import_type("System.Windows.Forms.Button") -Point=luanet.import_type("System.Drawing.Point") - -form1=Form() -button1=Button() -button2=Button() - -function handleClick(sender,data) - if sender.Text=="OK" then - sender.Text="Clicked" - else - sender.Text="OK" - end - button1.MouseUp:Remove(handler) - print(sender:ToString()) -end - -button1.Text = "OK" -button1.Location=Point(10,10) -button2.Text = "Cancel" -button2.Location=Point(button1.Left, button1.Height + button1.Top + 10) -handler=button1.MouseUp:Add(handleClick) -form1.Text = "My Dialog Box" -form1.HelpButton = true -form1.MaximizeBox=false -form1.MinimizeBox=false -form1.AcceptButton = button1 -form1.CancelButton = button2 -form1.Controls:Add(button1) -form1.Controls:Add(button2) -form1:ShowDialog() +-- kevinh - the following lines are part of our standard init +-- require("compat-5.1") + +luanet.load_assembly("System.Windows.Forms") +luanet.load_assembly("System.Drawing") + +Form=luanet.import_type("System.Windows.Forms.Form") +Button=luanet.import_type("System.Windows.Forms.Button") +Point=luanet.import_type("System.Drawing.Point") + +form1=Form() +button1=Button() +button2=Button() + +function handleClick(sender,data) + if sender.Text=="OK" then + sender.Text="Clicked" + else + sender.Text="OK" + end + button1.MouseUp:Remove(handler) + print(sender:ToString()) +end + +button1.Text = "OK" +button1.Location=Point(10,10) +button2.Text = "Cancel" +button2.Location=Point(button1.Left, button1.Height + button1.Top + 10) +handler=button1.MouseUp:Add(handleClick) +form1.Text = "My Dialog Box" +form1.HelpButton = true +form1.MaximizeBox=false +form1.MinimizeBox=false +form1.AcceptButton = button1 +form1.CancelButton = button2 +form1.Controls:Add(button1) +form1.Controls:Add(button2) +form1:ShowDialog() diff --git a/Samples/form_alt.lua b/Samples/form_alt.lua index a349b22b44dd1ee9dde44c6818044b25eeafb475..1a2aa28901d8d56d90eaa17b82761403b7e0c587 100644 --- a/Samples/form_alt.lua +++ b/Samples/form_alt.lua @@ -1,36 +1,36 @@ ---require("compat-5.1") - -Forms=luanet.System.Windows.Forms - -Form=Forms.Form -Button=Forms.Button -Point=luanet.System.Drawing.Point - -form1=Form() -button1=Button() -button2=Button() - -function handleClick(sender,data) - if sender.Text=="OK" then - sender.Text="Clicked" - else - sender.Text="OK" - end - button1.MouseUp:Remove(handler) - print(sender:ToString()) -end - -button1.Text = "OK" -button1.Location=Point(10,10) -button2.Text = "Cancel" -button2.Location=Point(button1.Left, button1.Height + button1.Top + 10) -handler=button1.MouseUp:Add(handleClick) -form1.Text = "My Dialog Box" -form1.HelpButton = true -form1.MaximizeBox=false -form1.MinimizeBox=false -form1.AcceptButton = button1 -form1.CancelButton = button2 -form1.Controls:Add(button1) -form1.Controls:Add(button2) -form1:ShowDialog() +--require("compat-5.1") + +Forms=luanet.System.Windows.Forms + +Form=Forms.Form +Button=Forms.Button +Point=luanet.System.Drawing.Point + +form1=Form() +button1=Button() +button2=Button() + +function handleClick(sender,data) + if sender.Text=="OK" then + sender.Text="Clicked" + else + sender.Text="OK" + end + button1.MouseUp:Remove(handler) + print(sender:ToString()) +end + +button1.Text = "OK" +button1.Location=Point(10,10) +button2.Text = "Cancel" +button2.Location=Point(button1.Left, button1.Height + button1.Top + 10) +handler=button1.MouseUp:Add(handleClick) +form1.Text = "My Dialog Box" +form1.HelpButton = true +form1.MaximizeBox=false +form1.MinimizeBox=false +form1.AcceptButton = button1 +form1.CancelButton = button2 +form1.Controls:Add(button1) +form1.Controls:Add(button2) +form1:ShowDialog() diff --git a/Samples/socket.lua b/Samples/socket.lua index 7fd9d6f3533385bf0c1b7df086b2419d9b3e4a39..4e64439b4ed09f99caf7546c37c7045455210662 100644 --- a/Samples/socket.lua +++ b/Samples/socket.lua @@ -1,19 +1,19 @@ ---require("compat-5.1") - -luanet.load_assembly("System") - -WebClient=luanet.import_type("System.Net.WebClient") -StreamReader=luanet.import_type("System.IO.StreamReader") -Math=luanet.import_type("System.Math") - -print(Math:Pow(2,3)) - -myWebClient = WebClient() -myStream = myWebClient:OpenRead(arg[1]) -sr = StreamReader(myStream) -line=sr:ReadLine() -repeat - print(line) - line=sr:ReadLine() -until not line -myStream:Close() +--require("compat-5.1") + +luanet.load_assembly("System") + +WebClient=luanet.import_type("System.Net.WebClient") +StreamReader=luanet.import_type("System.IO.StreamReader") +Math=luanet.import_type("System.Math") + +print(Math:Pow(2,3)) + +myWebClient = WebClient() +myStream = myWebClient:OpenRead(arg[1]) +sr = StreamReader(myStream) +line=sr:ReadLine() +repeat + print(line) + line=sr:ReadLine() +until not line +myStream:Close() diff --git a/Samples/socket_alt.lua b/Samples/socket_alt.lua index eded36c31b3d7c84ff9fc83b49286bd77ef11b5e..03e6b8b845a3894c821a2ca0b8f82afb8c59672c 100644 --- a/Samples/socket_alt.lua +++ b/Samples/socket_alt.lua @@ -1,19 +1,19 @@ ---require("compat-5.1") - -System=luanet.System - -WebClient=System.Net.WebClient -StreamReader=System.IO.StreamReader -Math=System.Math - -print(Math:Pow(2,3)) - -myWebClient = WebClient() -myStream = myWebClient:OpenRead(arg[1]) -sr = StreamReader(myStream) -line=sr:ReadLine() -repeat - print(line) - line=sr:ReadLine() -until not line -myStream:Close() +--require("compat-5.1") + +System=luanet.System + +WebClient=System.Net.WebClient +StreamReader=System.IO.StreamReader +Math=System.Math + +print(Math:Pow(2,3)) + +myWebClient = WebClient() +myStream = myWebClient:OpenRead(arg[1]) +sr = StreamReader(myStream) +line=sr:ReadLine() +repeat + print(line) + line=sr:ReadLine() +until not line +myStream:Close() diff --git a/Samples/testluaform.lua b/Samples/testluaform.lua index de4abff05e326e43fdd132f82c5327205e59f090..589153fe12b1c41838f6b350c3902a11362343ba 100644 --- a/Samples/testluaform.lua +++ b/Samples/testluaform.lua @@ -1,122 +1,122 @@ -require("CLRPackage") - -Forms = CLRPackage("System.Windows.Forms", "System.Windows.Forms") -Drawing = CLRPackage("System.Drawing", "System.Drawing") -LuaInterface = CLRPackage("LuaInterface", "LuaInterface") -IO = CLRPackage("System.IO", "System.IO") -System = CLRPackage("System", "System") - -Form=Forms.Form -TextBox=Forms.TextBox -Label=Forms.Label -ListBox=Forms.ListBox -Button=Forms.Button -Point=Drawing.Point -Size=Drawing.Size -Lua=LuaInterface.Lua -OpenFileDialog=Forms.OpenFileDialog -File=IO.File -StreamReader=IO.StreamReader -FileMode=IO.FileMode -ScrollBars=Forms.ScrollBars -FormBorderStyle=Forms.FormBorderStyle -FormStartPosition=Forms.FormStartPosition - -function clear_click(sender,args) - code:Clear() -end - -function execute_click(sender,args) - results.Items:Clear() - result=lua:DoString(code.Text) - if result then - for i=0,result.Length-1 do - results.Items:Add(result[i]) - end - end -end - -function load_click(sender,args) - open_file:ShowDialog() - file=StreamReader(open_file.FileName) - code.Text=file:ReadToEnd() - file:Close() -end - -form = Form() -code = TextBox() -label1 = Label() -execute = Button() -clear = Button() -results = ListBox() -label2 = Label() -load = Button() -lua = Lua() ---lua:OpenBaseLib() -- steffenj: Open*Lib() functions no longer exist -open_file = OpenFileDialog() - -form:SuspendLayout() - -code.Location = Point(16, 24) -code.Multiline = true -code.Name = "Code" -code.Size = Size(440, 128) -code.ScrollBars = ScrollBars.Vertical -code.TabIndex = 0 -code.Text = "" - -label1.Location = Point(16, 8) -label1.Name = "label1" -label1.Size = Size(100, 16) -label1.TabIndex = 1 -label1.Text = "Lua Code:" - -execute.Location = Point(96, 160) -execute.Name = "Execute" -execute.TabIndex = 2 -execute.Text = "Execute" -execute.Click:Add(execute_click) - -clear.Location = Point(176, 160) -clear.Name = "Clear" -clear.TabIndex = 3 -clear.Text = "Clear" -clear.Click:Add(clear_click) - -results.Location = Point(16, 208) -results.Name = "Results" -results.Size = Size(440, 95) -results.TabIndex = 4 - -label2.Location = Point(16, 192) -label2.Name = "label2" -label2.Size = Size(100, 16) -label2.TabIndex = 5 -label2.Text = "Results:" - -load.Location = Point(16, 160) -load.Name = "Load" -load.TabIndex = 6 -load.Text = "Load..." -load.Click:Add(load_click) - -open_file.DefaultExt = "lua" -open_file.Filter = "Lua Scripts|*.lua|All Files|*.*" -open_file.Title = "Pick a File" - -form.AutoScaleBaseSize = Size(5, 13) -form.ClientSize = Size(472, 315) -form.Controls:Add(load) -form.Controls:Add(label2) -form.Controls:Add(results) -form.Controls:Add(clear) -form.Controls:Add(execute) -form.Controls:Add(label1) -form.Controls:Add(code) -form.Name = "MainForm" -form.Text = "LuaNet" -form.FormBorderStyle = FormBorderStyle.Fixed3D -form.StartPosition = FormStartPosition.CenterScreen -form:ResumeLayout(false) - -form:ShowDialog() +require("CLRPackage") + +Forms = CLRPackage("System.Windows.Forms", "System.Windows.Forms") +Drawing = CLRPackage("System.Drawing", "System.Drawing") +LuaInterface = CLRPackage("LuaInterface", "LuaInterface") +IO = CLRPackage("System.IO", "System.IO") +System = CLRPackage("System", "System") + +Form=Forms.Form +TextBox=Forms.TextBox +Label=Forms.Label +ListBox=Forms.ListBox +Button=Forms.Button +Point=Drawing.Point +Size=Drawing.Size +Lua=LuaInterface.Lua +OpenFileDialog=Forms.OpenFileDialog +File=IO.File +StreamReader=IO.StreamReader +FileMode=IO.FileMode +ScrollBars=Forms.ScrollBars +FormBorderStyle=Forms.FormBorderStyle +FormStartPosition=Forms.FormStartPosition + +function clear_click(sender,args) + code:Clear() +end + +function execute_click(sender,args) + results.Items:Clear() + result=lua:DoString(code.Text) + if result then + for i=0,result.Length-1 do + results.Items:Add(result[i]) + end + end +end + +function load_click(sender,args) + open_file:ShowDialog() + file=StreamReader(open_file.FileName) + code.Text=file:ReadToEnd() + file:Close() +end + +form = Form() +code = TextBox() +label1 = Label() +execute = Button() +clear = Button() +results = ListBox() +label2 = Label() +load = Button() +lua = Lua() +--lua:OpenBaseLib() -- steffenj: Open*Lib() functions no longer exist +open_file = OpenFileDialog() + +form:SuspendLayout() + +code.Location = Point(16, 24) +code.Multiline = true +code.Name = "Code" +code.Size = Size(440, 128) +code.ScrollBars = ScrollBars.Vertical +code.TabIndex = 0 +code.Text = "" + +label1.Location = Point(16, 8) +label1.Name = "label1" +label1.Size = Size(100, 16) +label1.TabIndex = 1 +label1.Text = "Lua Code:" + +execute.Location = Point(96, 160) +execute.Name = "Execute" +execute.TabIndex = 2 +execute.Text = "Execute" +execute.Click:Add(execute_click) + +clear.Location = Point(176, 160) +clear.Name = "Clear" +clear.TabIndex = 3 +clear.Text = "Clear" +clear.Click:Add(clear_click) + +results.Location = Point(16, 208) +results.Name = "Results" +results.Size = Size(440, 95) +results.TabIndex = 4 + +label2.Location = Point(16, 192) +label2.Name = "label2" +label2.Size = Size(100, 16) +label2.TabIndex = 5 +label2.Text = "Results:" + +load.Location = Point(16, 160) +load.Name = "Load" +load.TabIndex = 6 +load.Text = "Load..." +load.Click:Add(load_click) + +open_file.DefaultExt = "lua" +open_file.Filter = "Lua Scripts|*.lua|All Files|*.*" +open_file.Title = "Pick a File" + +form.AutoScaleBaseSize = Size(5, 13) +form.ClientSize = Size(472, 315) +form.Controls:Add(load) +form.Controls:Add(label2) +form.Controls:Add(results) +form.Controls:Add(clear) +form.Controls:Add(execute) +form.Controls:Add(label1) +form.Controls:Add(code) +form.Name = "MainForm" +form.Text = "LuaNet" +form.FormBorderStyle = FormBorderStyle.Fixed3D +form.StartPosition = FormStartPosition.CenterScreen +form:ResumeLayout(false) + +form:ShowDialog() diff --git a/Samples/testluaform_alt.lua b/Samples/testluaform_alt.lua index 3f22be657691dfce6f0cab68b05f4215de51f901..682be2c7f1c59c05e07d6aa47828cdb2a119c777 100644 --- a/Samples/testluaform_alt.lua +++ b/Samples/testluaform_alt.lua @@ -1,121 +1,121 @@ ---require("compat-5.1") - -Forms=luanet.System.Windows.Forms -Drawing=luanet.System.Drawing -LuaInterface=luanet.LuaInterface -IO=luanet.System.IO - -Form=Forms.Form -TextBox=Forms.TextBox -Label=Forms.Label -ListBox=Forms.ListBox -Button=Forms.Button -Point=Drawing.Point -Size=Drawing.Size -Lua=LuaInterface.Lua -OpenFileDialog=Forms.OpenFileDialog -File=IO.File -StreamReader=IO.StreamReader -FileMode=IO.FileMode -ScrollBars=Forms.ScrollBars -FormBorderStyle=Forms.FormBorderStyle -FormStartPosition=Forms.FormStartPosition - -function clear_click(sender,args) - code:Clear() -end - -function execute_click(sender,args) - results.Items:Clear() - result=lua:DoString(code.Text) - if result then - for i=0,result.Length-1 do - results.Items:Add(result[i]) - end - end -end - -function load_click(sender,args) - open_file:ShowDialog() - file=StreamReader(open_file.FileName) - code.Text=file:ReadToEnd() - file:Close() -end - -form = Form() -code = TextBox() -label1 = Label() -execute = Button() -clear = Button() -results = ListBox() -label2 = Label() -load = Button() -lua = Lua() ---lua:OpenBaseLib() -- steffenj: Open*Lib() functions no longer exist -open_file = OpenFileDialog() - -form:SuspendLayout() - -code.Location = Point(16, 24) -code.Multiline = true -code.Name = "Code" -code.Size = Size(440, 128) -code.ScrollBars = ScrollBars.Vertical -code.TabIndex = 0 -code.Text = "" - -label1.Location = Point(16, 8) -label1.Name = "label1" -label1.Size = Size(100, 16) -label1.TabIndex = 1 -label1.Text = "Lua Code:" - -execute.Location = Point(96, 160) -execute.Name = "Execute" -execute.TabIndex = 2 -execute.Text = "Execute" -execute.Click:Add(execute_click) - -clear.Location = Point(176, 160) -clear.Name = "Clear" -clear.TabIndex = 3 -clear.Text = "Clear" -clear.Click:Add(clear_click) - -results.Location = Point(16, 208) -results.Name = "Results" -results.Size = Size(440, 95) -results.TabIndex = 4 - -label2.Location = Point(16, 192) -label2.Name = "label2" -label2.Size = Size(100, 16) -label2.TabIndex = 5 -label2.Text = "Results:" - -load.Location = Point(16, 160) -load.Name = "Load" -load.TabIndex = 6 -load.Text = "Load..." -load.Click:Add(load_click) - -open_file.DefaultExt = "lua" -open_file.Filter = "Lua Scripts|*.lua|All Files|*.*" -open_file.Title = "Pick a File" - -form.AutoScaleBaseSize = Size(5, 13) -form.ClientSize = Size(472, 315) -form.Controls:Add(load) -form.Controls:Add(label2) -form.Controls:Add(results) -form.Controls:Add(clear) -form.Controls:Add(execute) -form.Controls:Add(label1) -form.Controls:Add(code) -form.Name = "MainForm" -form.Text = "LuaNet" -form.FormBorderStyle = FormBorderStyle.Fixed3D -form.StartPosition = FormStartPosition.CenterScreen -form:ResumeLayout(false) - -form:ShowDialog() +--require("compat-5.1") + +Forms=luanet.System.Windows.Forms +Drawing=luanet.System.Drawing +LuaInterface=luanet.LuaInterface +IO=luanet.System.IO + +Form=Forms.Form +TextBox=Forms.TextBox +Label=Forms.Label +ListBox=Forms.ListBox +Button=Forms.Button +Point=Drawing.Point +Size=Drawing.Size +Lua=LuaInterface.Lua +OpenFileDialog=Forms.OpenFileDialog +File=IO.File +StreamReader=IO.StreamReader +FileMode=IO.FileMode +ScrollBars=Forms.ScrollBars +FormBorderStyle=Forms.FormBorderStyle +FormStartPosition=Forms.FormStartPosition + +function clear_click(sender,args) + code:Clear() +end + +function execute_click(sender,args) + results.Items:Clear() + result=lua:DoString(code.Text) + if result then + for i=0,result.Length-1 do + results.Items:Add(result[i]) + end + end +end + +function load_click(sender,args) + open_file:ShowDialog() + file=StreamReader(open_file.FileName) + code.Text=file:ReadToEnd() + file:Close() +end + +form = Form() +code = TextBox() +label1 = Label() +execute = Button() +clear = Button() +results = ListBox() +label2 = Label() +load = Button() +lua = Lua() +--lua:OpenBaseLib() -- steffenj: Open*Lib() functions no longer exist +open_file = OpenFileDialog() + +form:SuspendLayout() + +code.Location = Point(16, 24) +code.Multiline = true +code.Name = "Code" +code.Size = Size(440, 128) +code.ScrollBars = ScrollBars.Vertical +code.TabIndex = 0 +code.Text = "" + +label1.Location = Point(16, 8) +label1.Name = "label1" +label1.Size = Size(100, 16) +label1.TabIndex = 1 +label1.Text = "Lua Code:" + +execute.Location = Point(96, 160) +execute.Name = "Execute" +execute.TabIndex = 2 +execute.Text = "Execute" +execute.Click:Add(execute_click) + +clear.Location = Point(176, 160) +clear.Name = "Clear" +clear.TabIndex = 3 +clear.Text = "Clear" +clear.Click:Add(clear_click) + +results.Location = Point(16, 208) +results.Name = "Results" +results.Size = Size(440, 95) +results.TabIndex = 4 + +label2.Location = Point(16, 192) +label2.Name = "label2" +label2.Size = Size(100, 16) +label2.TabIndex = 5 +label2.Text = "Results:" + +load.Location = Point(16, 160) +load.Name = "Load" +load.TabIndex = 6 +load.Text = "Load..." +load.Click:Add(load_click) + +open_file.DefaultExt = "lua" +open_file.Filter = "Lua Scripts|*.lua|All Files|*.*" +open_file.Title = "Pick a File" + +form.AutoScaleBaseSize = Size(5, 13) +form.ClientSize = Size(472, 315) +form.Controls:Add(load) +form.Controls:Add(label2) +form.Controls:Add(results) +form.Controls:Add(clear) +form.Controls:Add(execute) +form.Controls:Add(label1) +form.Controls:Add(code) +form.Name = "MainForm" +form.Text = "LuaNet" +form.FormBorderStyle = FormBorderStyle.Fixed3D +form.StartPosition = FormStartPosition.CenterScreen +form:ResumeLayout(false) + +form:ShowDialog() diff --git a/TODO b/TODO index f108917e94fca7e145cf33f421a6b0dfa2170ea2..5edbd947552d353cf4c30343672ae0d8d5378c6b 100644 --- a/TODO +++ b/TODO @@ -1,2 +1,2 @@ -Error: +Error: - TestLua.exe -> TestThreading() ==Problem with threading!== \ No newline at end of file diff --git a/Test/TestLuaInterface/Entity.cs b/Test/TestLuaInterface/Entity.cs index 5e68030a215772162a84a5642e145abe31439532..07db8c80a250ca06a5503501a20e8a1094a944d7 100644 --- a/Test/TestLuaInterface/Entity.cs +++ b/Test/TestLuaInterface/Entity.cs @@ -1,53 +1,53 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Text; -using System.Collections.Generic; - -namespace LuaInterface.Tests -{ - public class Entity - { - public event EventHandler Clicked; - - protected virtual void OnEntityClicked(EventArgs e) - { - var handler = Clicked; - - if(handler != null) - handler(this, e); // Use the () operator to raise the event. - } - - public Entity() - { - } - - public void Click() - { - OnEntityClicked(new EventArgs()); - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Text; +using System.Collections.Generic; + +namespace LuaInterface.Tests +{ + public class Entity + { + public event EventHandler Clicked; + + protected virtual void OnEntityClicked(EventArgs e) + { + var handler = Clicked; + + if(handler != null) + handler(this, e); // Use the () operator to raise the event. + } + + public Entity() + { + } + + public void Click() + { + OnEntityClicked(new EventArgs()); + } + } } \ No newline at end of file diff --git a/Test/TestLuaInterface/Makefile.am b/Test/TestLuaInterface/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..f37d43f5370f791b750757880c8b37b49d4b544c --- /dev/null +++ b/Test/TestLuaInterface/Makefile.am @@ -0,0 +1,19 @@ + +EXTRA_DIST = + +#Warning: This is an automatically generated file, do not edit! +if ENABLE_DEBUG_X86 + SUBDIRS = . +endif +if ENABLE_RELEASE_X86 + SUBDIRS = . +endif +if ENABLE_DEBUG_X64 + SUBDIRS = . +endif +if ENABLE_RELEASE_X64 + SUBDIRS = . +endif + +# Projekt-specifikus makefile beszúrása +include TestLuaInterface.make \ No newline at end of file diff --git a/Test/TestLuaInterface/TestLua.cs b/Test/TestLuaInterface/TestLua.cs index 99a15e2163bb772a8e5866cc6caaed99f5b72540..e1d6a3dbb86338ff6b95f72aa07a1a9ec338f5c9 100644 --- a/Test/TestLuaInterface/TestLua.cs +++ b/Test/TestLuaInterface/TestLua.cs @@ -1,427 +1,427 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Threading; -using System.Reflection; -using System.Diagnostics; -using LuaInterface; - -namespace LuaInterface.Tests -{ - /* - * Delegates used for testing Lua function -> delegate translation - */ - public delegate int TestDelegate1(int a, int b); - public delegate int TestDelegate2(int a, out int b); - public delegate void TestDelegate3(int a, ref int b); - public delegate TestClass TestDelegate4(int a, int b); - public delegate int TestDelegate5(TestClass a, TestClass b); - public delegate int TestDelegate6(int a, out TestClass b); - public delegate void TestDelegate7(int a, ref TestClass b); - - /* - * Interface used for testing Lua table -> interface translation - */ - public interface ITest - { - int intProp - { - get; - set; - } - TestClass refProp - { - get; - set; - } - int test1(int a,int b); - int test2(int a, out int b); - void test3(int a, ref int b); - TestClass test4(int a, int b); - int test5(TestClass a, TestClass b); - int test6(int a, out TestClass b); - void test7(int a, ref TestClass b); - } - - public interface IFoo1 - { - int foo(); - } - - public interface IFoo2 - { - int foo(); - } - - class MyClass - { - public int Func1() { return 1;} - } - - /// - /// Use to test threading - /// - class DoWorkClass - { - //private object _Lock = new object(); - - public void DoWork() - { - //lock (_Lock) - //{ - //simulate work by sleeping - //Console.WriteLine("Started to do work on thread: " + Thread.CurrentThread.ManagedThreadId); - Thread.Sleep(new Random().Next(0, 1000)); - //Console.WriteLine("Finished work on thread: " + Thread.CurrentThread.ManagedThreadId); - //} - } - } - - /// - /// test structure passing - /// - public struct TestStruct - { - public TestStruct(float val) - { - v = val; - } - - public float v; - - public float val - { - get { return v; } - set { v = value; } - } - } - - /// - /// Generic class with generic and non-generic methods - /// - /// - public class TestClassGeneric - { - private object _PassedValue; - - private bool _RegularMethodSuccess; - - public bool RegularMethodSuccess - { - get { return _RegularMethodSuccess; } - } - - private bool _GenericMethodSuccess; - - public bool GenericMethodSuccess - { - get { return _GenericMethodSuccess; } - } - - public void GenericMethod(T value) - { - _PassedValue = value; - _GenericMethodSuccess = true; - } - - public void RegularMethod() - { - _RegularMethodSuccess = true; - } - - /// - /// Returns true if the generic method was successfully passed a matching value - /// - /// - /// - public bool Validate(T value) - { - return value.Equals(_PassedValue); - } - } - - /// - /// Normal class containing a generic method - /// - public class TestClassWithGenericMethod - { - private object _PassedValue; - - public object PassedValue - { - get { return _PassedValue; } - } - - private bool _GenericMethodSuccess; - - public bool GenericMethodSuccess - { - get { return _GenericMethodSuccess; } - } - - public void GenericMethod(T value) - { - _PassedValue = value; - _GenericMethodSuccess = true; - } - - internal bool Validate(T value) - { - return value.Equals(_PassedValue); - } - } - - /* - * Sample class used in several test cases to check if - * Lua scripts are accessing objects correctly - */ - public class TestClass : IFoo1, IFoo2 - { - public int val; - private string strVal; - public TestClass() - { - val = 0; - } - public TestClass(int val) - { - this.val = val; - } - public TestClass(string val) - { - this.strVal = val; - } - public static TestClass makeFromString(String str) - { - return new TestClass(str); - } - - bool? nb2 = null; - - public bool? NullableBool - { - get { return nb2; } - set { nb2 = value; } - } - - - TestStruct s = new TestStruct(); - - public TestStruct Struct - { - get { return s; } - set { s = (TestStruct)value; } - } - - public int testval - { - get - { - return this.val; - } - set - { - this.val = value; - } - } - public int this[int index] - { - get { return 1; } - set { } - } - public int this[string index] - { - get { return 1; } - set { } - } - public int sum(int x, int y) - { - return x + y; - } - public void setVal(int newVal) - { - val = newVal; - } - public void setVal(string newVal) - { - strVal = newVal; - } - public int getVal() - { - return val; - } - public string getStrVal() - { - return strVal; - } - public int outVal(out int val) - { - val = 5; - return 3; - } - public int outVal(out int val, int val2) - { - val = 5; - return val2; - } - public int outVal(int val, ref int val2) - { - val2 = val + val2; - return val; - } - public int callDelegate1(TestDelegate1 del) - { - return del(2, 3); - } - public int callDelegate2(TestDelegate2 del) - { - int a = 3; - int b = del(2, out a); - return a + b; - } - public int callDelegate3(TestDelegate3 del) - { - int a = 3; - del(2, ref a); - //Console.WriteLine(a); - return a; - } - public int callDelegate4(TestDelegate4 del) - { - return del(2, 3).testval; - } - public int callDelegate5(TestDelegate5 del) - { - return del(new TestClass(2), new TestClass(3)); - } - public int callDelegate6(TestDelegate6 del) - { - TestClass test = new TestClass(); - int a = del(2, out test); - return a + test.testval; - } - public int callDelegate7(TestDelegate7 del) - { - TestClass test = new TestClass(3); - del(2, ref test); - return test.testval; - } - public int callInterface1(ITest itest) - { - return itest.test1(2, 3); - } - public int callInterface2(ITest itest) - { - int a = 3; - int b = itest.test2(2, out a); - return a + b; - } - public int callInterface3(ITest itest) - { - int a = 3; - itest.test3(2, ref a); - //Console.WriteLine(a); - return a; - } - public int callInterface4(ITest itest) - { - return itest.test4(2, 3).testval; - } - public int callInterface5(ITest itest) - { - return itest.test5(new TestClass(2), new TestClass(3)); - } - public int callInterface6(ITest itest) - { - TestClass test = new TestClass(); - int a = itest.test6(2, out test); - return a + test.testval; - } - public int callInterface7(ITest itest) - { - TestClass test = new TestClass(3); - itest.test7(2, ref test); - return test.testval; - } - public int callInterface8(ITest itest) - { - itest.intProp = 3; - return itest.intProp; - } - public int callInterface9(ITest itest) - { - itest.refProp = new TestClass(3); - return itest.refProp.testval; - } - public void exceptionMethod() - { - throw new Exception("exception test"); - } - public virtual int overridableMethod(int x, int y) - { - return x + y; - } - public static int callOverridable(TestClass test, int x, int y) - { - return test.overridableMethod(x, y); - } - int IFoo1.foo() - { - return 3; - } - public int foo() - { - return 5; - } - - private void _PrivateMethod() - { - Console.WriteLine("Private method called"); - } - - public void MethodOverload() - { - Console.WriteLine("Method with no params"); - } - - - public void MethodOverload(TestClass testClass) - { - Console.WriteLine("Method with testclass param"); - } - - public void MethodOverload(int i, int j, int k) - { - Console.WriteLine("Overload without out param: " + i + ", " + j + ", " + k); - } - - public void MethodOverload(int i, int j, out int k) - { - k = 5; - Console.WriteLine("Overload with out param" + i + ", " + j); - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Threading; +using System.Reflection; +using System.Diagnostics; +using LuaInterface; + +namespace LuaInterface.Tests +{ + /* + * Delegates used for testing Lua function -> delegate translation + */ + public delegate int TestDelegate1(int a, int b); + public delegate int TestDelegate2(int a, out int b); + public delegate void TestDelegate3(int a, ref int b); + public delegate TestClass TestDelegate4(int a, int b); + public delegate int TestDelegate5(TestClass a, TestClass b); + public delegate int TestDelegate6(int a, out TestClass b); + public delegate void TestDelegate7(int a, ref TestClass b); + + /* + * Interface used for testing Lua table -> interface translation + */ + public interface ITest + { + int intProp + { + get; + set; + } + TestClass refProp + { + get; + set; + } + int test1(int a,int b); + int test2(int a, out int b); + void test3(int a, ref int b); + TestClass test4(int a, int b); + int test5(TestClass a, TestClass b); + int test6(int a, out TestClass b); + void test7(int a, ref TestClass b); + } + + public interface IFoo1 + { + int foo(); + } + + public interface IFoo2 + { + int foo(); + } + + class MyClass + { + public int Func1() { return 1;} + } + + /// + /// Use to test threading + /// + class DoWorkClass + { + //private object _Lock = new object(); + + public void DoWork() + { + //lock (_Lock) + //{ + //simulate work by sleeping + //Console.WriteLine("Started to do work on thread: " + Thread.CurrentThread.ManagedThreadId); + Thread.Sleep(new Random().Next(0, 1000)); + //Console.WriteLine("Finished work on thread: " + Thread.CurrentThread.ManagedThreadId); + //} + } + } + + /// + /// test structure passing + /// + public struct TestStruct + { + public TestStruct(float val) + { + v = val; + } + + public float v; + + public float val + { + get { return v; } + set { v = value; } + } + } + + /// + /// Generic class with generic and non-generic methods + /// + /// + public class TestClassGeneric + { + private object _PassedValue; + + private bool _RegularMethodSuccess; + + public bool RegularMethodSuccess + { + get { return _RegularMethodSuccess; } + } + + private bool _GenericMethodSuccess; + + public bool GenericMethodSuccess + { + get { return _GenericMethodSuccess; } + } + + public void GenericMethod(T value) + { + _PassedValue = value; + _GenericMethodSuccess = true; + } + + public void RegularMethod() + { + _RegularMethodSuccess = true; + } + + /// + /// Returns true if the generic method was successfully passed a matching value + /// + /// + /// + public bool Validate(T value) + { + return value.Equals(_PassedValue); + } + } + + /// + /// Normal class containing a generic method + /// + public class TestClassWithGenericMethod + { + private object _PassedValue; + + public object PassedValue + { + get { return _PassedValue; } + } + + private bool _GenericMethodSuccess; + + public bool GenericMethodSuccess + { + get { return _GenericMethodSuccess; } + } + + public void GenericMethod(T value) + { + _PassedValue = value; + _GenericMethodSuccess = true; + } + + internal bool Validate(T value) + { + return value.Equals(_PassedValue); + } + } + + /* + * Sample class used in several test cases to check if + * Lua scripts are accessing objects correctly + */ + public class TestClass : IFoo1, IFoo2 + { + public int val; + private string strVal; + public TestClass() + { + val = 0; + } + public TestClass(int val) + { + this.val = val; + } + public TestClass(string val) + { + this.strVal = val; + } + public static TestClass makeFromString(String str) + { + return new TestClass(str); + } + + bool? nb2 = null; + + public bool? NullableBool + { + get { return nb2; } + set { nb2 = value; } + } + + + TestStruct s = new TestStruct(); + + public TestStruct Struct + { + get { return s; } + set { s = (TestStruct)value; } + } + + public int testval + { + get + { + return this.val; + } + set + { + this.val = value; + } + } + public int this[int index] + { + get { return 1; } + set { } + } + public int this[string index] + { + get { return 1; } + set { } + } + public int sum(int x, int y) + { + return x + y; + } + public void setVal(int newVal) + { + val = newVal; + } + public void setVal(string newVal) + { + strVal = newVal; + } + public int getVal() + { + return val; + } + public string getStrVal() + { + return strVal; + } + public int outVal(out int val) + { + val = 5; + return 3; + } + public int outVal(out int val, int val2) + { + val = 5; + return val2; + } + public int outVal(int val, ref int val2) + { + val2 = val + val2; + return val; + } + public int callDelegate1(TestDelegate1 del) + { + return del(2, 3); + } + public int callDelegate2(TestDelegate2 del) + { + int a = 3; + int b = del(2, out a); + return a + b; + } + public int callDelegate3(TestDelegate3 del) + { + int a = 3; + del(2, ref a); + //Console.WriteLine(a); + return a; + } + public int callDelegate4(TestDelegate4 del) + { + return del(2, 3).testval; + } + public int callDelegate5(TestDelegate5 del) + { + return del(new TestClass(2), new TestClass(3)); + } + public int callDelegate6(TestDelegate6 del) + { + TestClass test = new TestClass(); + int a = del(2, out test); + return a + test.testval; + } + public int callDelegate7(TestDelegate7 del) + { + TestClass test = new TestClass(3); + del(2, ref test); + return test.testval; + } + public int callInterface1(ITest itest) + { + return itest.test1(2, 3); + } + public int callInterface2(ITest itest) + { + int a = 3; + int b = itest.test2(2, out a); + return a + b; + } + public int callInterface3(ITest itest) + { + int a = 3; + itest.test3(2, ref a); + //Console.WriteLine(a); + return a; + } + public int callInterface4(ITest itest) + { + return itest.test4(2, 3).testval; + } + public int callInterface5(ITest itest) + { + return itest.test5(new TestClass(2), new TestClass(3)); + } + public int callInterface6(ITest itest) + { + TestClass test = new TestClass(); + int a = itest.test6(2, out test); + return a + test.testval; + } + public int callInterface7(ITest itest) + { + TestClass test = new TestClass(3); + itest.test7(2, ref test); + return test.testval; + } + public int callInterface8(ITest itest) + { + itest.intProp = 3; + return itest.intProp; + } + public int callInterface9(ITest itest) + { + itest.refProp = new TestClass(3); + return itest.refProp.testval; + } + public void exceptionMethod() + { + throw new Exception("exception test"); + } + public virtual int overridableMethod(int x, int y) + { + return x + y; + } + public static int callOverridable(TestClass test, int x, int y) + { + return test.overridableMethod(x, y); + } + int IFoo1.foo() + { + return 3; + } + public int foo() + { + return 5; + } + + private void _PrivateMethod() + { + Console.WriteLine("Private method called"); + } + + public void MethodOverload() + { + Console.WriteLine("Method with no params"); + } + + + public void MethodOverload(TestClass testClass) + { + Console.WriteLine("Method with testclass param"); + } + + public void MethodOverload(int i, int j, int k) + { + Console.WriteLine("Overload without out param: " + i + ", " + j + ", " + k); + } + + public void MethodOverload(int i, int j, out int k) + { + k = 5; + Console.WriteLine("Overload with out param" + i + ", " + j); + } + } } \ No newline at end of file diff --git a/Test/TestLuaInterface/TestLuaInterface.cs b/Test/TestLuaInterface/TestLuaInterface.cs index d35679c463f6c84b8713a09d98b5568c26c62c44..f389e78854ed5da37fe8e0ceb45281c64f8aa1d5 100644 --- a/Test/TestLuaInterface/TestLuaInterface.cs +++ b/Test/TestLuaInterface/TestLuaInterface.cs @@ -1,1534 +1,1534 @@ -/* - * This file is part of LuaInterface. - * - * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. - * Copyright (C) 2012 Megax - * - * 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: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * 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. - */ - -using System; -using System.Text; -using System.Threading; -using System.Reflection; -using System.Collections.Generic; -using LuaInterface.Exceptions; - -namespace LuaInterface.Tests -{ - /* - * Automated test cases for LuaInterface - * - * Author: Fabio Mascarenhas - * Version: 1.0 - */ - public class TestLuaInterface - { - private Lua _Lua; - - /* - * Executed before each test case - */ - public void Init() - { - _Lua = new Lua(); - GC.Collect(); // runs GC to expose unprotected delegates - } - - /* - * Executed after each test case - */ - public void Destroy() - { - _Lua = null; - } - -#if false - // I've commented out the nunit based tests until they can run standalone - so that users don't need nunit to run TestLua - - /* - * Tests if DoString is correctly returning values - */ - [Test] - public void DoString() - { - object[] res=lua.DoString("a=2\nreturn a,3"); - //Console.WriteLine("a="+res[0]+", b="+res[1]); - Assertion.AssertEquals(res[0],2); - Assertion.AssertEquals(res[1],3); - } - /* - * Tests getting of global numeric variables - */ - [Test] - public void GetGlobalNumber() - { - lua.DoString("a=2"); - double num=lua.GetNumber("a"); - //Console.WriteLine("a="+num); - Assertion.AssertEquals(num,2); - } - /* - * Tests setting of global numeric variables - */ - [Test] - public void SetGlobalNumber() - { - lua.DoString("a=2"); - lua["a"]=3; - double num=lua.GetNumber("a"); - //Console.WriteLine("a="+num); - Assertion.AssertEquals(num,3); - } - /* - * Tests getting of numeric variables from tables - * by specifying variable path - */ - [Test] - public void GetNumberInTable() - { - lua.DoString("a={b={c=2}}"); - double num=lua.GetNumber("a.b.c"); - //Console.WriteLine("a.b.c="+num); - Assertion.AssertEquals(num,2); - } - /* - * Tests setting of numeric variables from tables - * by specifying variable path - */ - [Test] - public void SetNumberInTable() - { - lua.DoString("a={b={c=2}}"); - lua["a.b.c"]=3; - double num=lua.GetNumber("a.b.c"); - //Console.WriteLine("a.b.c="+num); - Assertion.AssertEquals(num,3); - } - /* - * Tests getting of global string variables - */ - [Test] - public void GetGlobalString() - { - lua.DoString("a=\"test\""); - string str=lua.GetString("a"); - //Console.WriteLine("a="+str); - Assertion.AssertEquals(str,"test"); - } - /* - * Tests setting of global string variables - */ - [Test] - public void SetGlobalString() - { - lua.DoString("a=\"test\""); - lua["a"]="new test"; - string str=lua.GetString("a"); - //Console.WriteLine("a="+str); - Assertion.AssertEquals(str,"new test"); - } - /* - * Tests getting of string variables from tables - * by specifying variable path - */ - [Test] - public void GetStringInTable() - { - lua.DoString("a={b={c=\"test\"}}"); - string str=lua.GetString("a.b.c"); - //Console.WriteLine("a.b.c="+str); - Assertion.AssertEquals(str,"test"); - } - /* - * Tests setting of string variables from tables - * by specifying variable path - */ - [Test] - public void SetStringInTable() - { - lua.DoString("a={b={c=\"test\"}}"); - lua["a.b.c"]="new test"; - string str=lua.GetString("a.b.c"); - //Console.WriteLine("a.b.c="+str); - Assertion.AssertEquals(str,"new test"); - } - /* - * Tests getting and setting of global table variables - */ - [Test] - public void GetAndSetTable() - { - lua.DoString("a={b={c=2}}\nb={c=3}"); - LuaTable tab=lua.GetTable("b"); - lua["a.b"]=tab; - double num=lua.GetNumber("a.b.c"); - //Console.WriteLine("a.b.c="+num); - Assertion.AssertEquals(num,3); - } - /* - * Tests getting of numeric field of a table - */ - [Test] - public void GetTableNumericField1() - { - lua.DoString("a={b={c=2}}"); - LuaTable tab=lua.GetTable("a.b"); - double num=(double)tab["c"]; - //Console.WriteLine("a.b.c="+num); - Assertion.AssertEquals(num,2); - } - /* - * Tests getting of numeric field of a table - * (the field is inside a subtable) - */ - [Test] - public void GetTableNumericField2() - { - lua.DoString("a={b={c=2}}"); - LuaTable tab=lua.GetTable("a"); - double num=(double)tab["b.c"]; - //Console.WriteLine("a.b.c="+num); - Assertion.AssertEquals(num,2); - } - /* - * Tests setting of numeric field of a table - */ - [Test] - public void SetTableNumericField1() - { - lua.DoString("a={b={c=2}}"); - LuaTable tab=lua.GetTable("a.b"); - tab["c"]=3; - double num=lua.GetNumber("a.b.c"); - //Console.WriteLine("a.b.c="+num); - Assertion.AssertEquals(num,3); - } - /* - * Tests setting of numeric field of a table - * (the field is inside a subtable) - */ - [Test] - public void SetTableNumericField2() - { - lua.DoString("a={b={c=2}}"); - LuaTable tab=lua.GetTable("a"); - tab["b.c"]=3; - double num=lua.GetNumber("a.b.c"); - //Console.WriteLine("a.b.c="+num); - Assertion.AssertEquals(num,3); - } - /* - * Tests getting of string field of a table - */ - [Test] - public void GetTableStringField1() - { - lua.DoString("a={b={c=\"test\"}}"); - LuaTable tab=lua.GetTable("a.b"); - string str=(string)tab["c"]; - //Console.WriteLine("a.b.c="+str); - Assertion.AssertEquals(str,"test"); - } - /* - * Tests getting of string field of a table - * (the field is inside a subtable) - */ - [Test] - public void GetTableStringField2() - { - lua.DoString("a={b={c=\"test\"}}"); - LuaTable tab=lua.GetTable("a"); - string str=(string)tab["b.c"]; - //Console.WriteLine("a.b.c="+str); - Assertion.AssertEquals(str,"test"); - } - /* - * Tests setting of string field of a table - */ - [Test] - public void SetTableStringField1() - { - lua.DoString("a={b={c=\"test\"}}"); - LuaTable tab=lua.GetTable("a.b"); - tab["c"]="new test"; - string str=lua.GetString("a.b.c"); - //Console.WriteLine("a.b.c="+str); - Assertion.AssertEquals(str,"new test"); - } - /* - * Tests setting of string field of a table - * (the field is inside a subtable) - */ - [Test] - public void SetTableStringField2() - { - lua.DoString("a={b={c=\"test\"}}"); - LuaTable tab=lua.GetTable("a"); - tab["b.c"]="new test"; - string str=lua.GetString("a.b.c"); - //Console.WriteLine("a.b.c="+str); - Assertion.AssertEquals(str,"new test"); - } - /* - * Tests calling of a global function with zero arguments - */ - [Test] - public void CallGlobalFunctionNoArgs() - { - lua.DoString("a=2\nfunction f()\na=3\nend"); - lua.GetFunction("f").Call(); - double num=lua.GetNumber("a"); - //Console.WriteLine("a="+num); - Assertion.AssertEquals(num,3); - } - /* - * Tests calling of a global function with one argument - */ - [Test] - public void CallGlobalFunctionOneArg() - { - lua.DoString("a=2\nfunction f(x)\na=a+x\nend"); - lua.GetFunction("f").Call(1); - double num=lua.GetNumber("a"); - //Console.WriteLine("a="+num); - Assertion.AssertEquals(num,3); - } - /* - * Tests calling of a global function with two arguments - */ - [Test] - public void CallGlobalFunctionTwoArgs() - { - lua.DoString("a=2\nfunction f(x,y)\na=x+y\nend"); - lua.GetFunction("f").Call(1,3); - double num=lua.GetNumber("a"); - //Console.WriteLine("a="+num); - Assertion.AssertEquals(num,4); - } - /* - * Tests calling of a global function that returns one value - */ - [Test] - public void CallGlobalFunctionOneReturn() - { - lua.DoString("function f(x)\nreturn x+2\nend"); - object[] ret=lua.GetFunction("f").Call(3); - //Console.WriteLine("ret="+ret[0]); - Assertion.AssertEquals(1,ret.Length); - Assertion.AssertEquals(5,ret[0]); - } - /* - * Tests calling of a global function that returns two values - */ - [Test] - public void CallGlobalFunctionTwoReturns() - { - lua.DoString("function f(x,y)\nreturn x,x+y\nend"); - object[] ret=lua.GetFunction("f").Call(3,2); - //Console.WriteLine("ret="+ret[0]+","+ret[1]); - Assertion.AssertEquals(2,ret.Length); - Assertion.AssertEquals(3,ret[0]); - Assertion.AssertEquals(5,ret[1]); - } - /* - * Tests calling of a function inside a table - */ - [Test] - public void CallTableFunctionTwoReturns() - { - lua.DoString("a={}\nfunction a.f(x,y)\nreturn x,x+y\nend"); - object[] ret=lua.GetFunction("a.f").Call(3,2); - //Console.WriteLine("ret="+ret[0]+","+ret[1]); - Assertion.AssertEquals(2,ret.Length); - Assertion.AssertEquals(3,ret[0]); - Assertion.AssertEquals(5,ret[1]); - } - /* - * Tests setting of a global variable to a CLR object value - */ - [Test] - public void SetGlobalObject() - { - TestClass t1=new TestClass(); - t1.testval=4; - lua["netobj"]=t1; - object o=lua["netobj"]; - TestClass t2=(TestClass)lua["netobj"]; - Assertion.AssertEquals(t2.testval,4); - Assertion.Assert(t1==t2); - } - /* - * Tests if CLR object is being correctly collected by Lua - */ - [Test] - public void GarbageCollection() - { - TestClass t1=new TestClass(); - t1.testval=4; - lua["netobj"]=t1; - TestClass t2=(TestClass)lua["netobj"]; - Assertion.Assert(lua.translator.objects[0]!=null); - lua.DoString("netobj=nil;collectgarbage();"); - Assertion.Assert(lua.translator.objects[0]==null); - } - /* - * Tests setting of a table field to a CLR object value - */ - [Test] - public void SetTableObjectField1() - { - lua.DoString("a={b={c=\"test\"}}"); - LuaTable tab=lua.GetTable("a.b"); - TestClass t1=new TestClass(); - t1.testval=4; - tab["c"]=t1; - TestClass t2=(TestClass)lua["a.b.c"]; - //Console.WriteLine("a.b.c="+t2.testval); - Assertion.AssertEquals(t2.testval,4); - Assertion.Assert(t1==t2); - } - /* - * Tests reading and writing of an object's field - */ - [Test] - public void AccessObjectField() - { - TestClass t1=new TestClass(); - t1.val=4; - lua["netobj"]=t1; - lua.DoString("var=netobj.val"); - double var=(double)lua["var"]; - //Console.WriteLine("value from Lua="+var); - Assertion.AssertEquals(4,var); - lua.DoString("netobj.val=3"); - Assertion.AssertEquals(3,t1.val); - //Console.WriteLine("new val (from Lua)="+t1.val); - } - /* - * Tests reading and writing of an object's non-indexed - * property - */ - [Test] - public void AccessObjectProperty() - { - TestClass t1=new TestClass(); - t1.testval=4; - lua["netobj"]=t1; - lua.DoString("var=netobj.testval"); - double var=(double)lua["var"]; - //Console.WriteLine("value from Lua="+var); - Assertion.AssertEquals(4,var); - lua.DoString("netobj.testval=3"); - Assertion.AssertEquals(3,t1.testval); - //Console.WriteLine("new val (from Lua)="+t1.testval); - } - /* - * Tests calling of an object's method with no overloads - */ - [Test] - public void CallObjectMethod() - { - TestClass t1=new TestClass(); - t1.testval=4; - lua["netobj"]=t1; - lua.DoString("netobj:setVal(3)"); - Assertion.AssertEquals(3,t1.testval); - //Console.WriteLine("new val(from C#)="+t1.testval); - lua.DoString("val=netobj:getVal()"); - int val=(int)lua.GetNumber("val"); - Assertion.AssertEquals(3,val); - //Console.WriteLine("new val(from Lua)="+val); - } - /* - * Tests calling of an object's method with overloading - */ - [Test] - public void CallObjectMethodByType() - { - TestClass t1=new TestClass(); - lua["netobj"]=t1; - lua.DoString("netobj:setVal('str')"); - Assertion.AssertEquals("str",t1.getStrVal()); - //Console.WriteLine("new val(from C#)="+t1.getStrVal()); - } - /* - * Tests calling of an object's method with no overloading - * and out parameters - */ - [Test] - public void CallObjectMethodOutParam() - { - TestClass t1=new TestClass(); - lua["netobj"]=t1; - lua.DoString("a,b=netobj:outVal()"); - int a=(int)lua.GetNumber("a"); - int b=(int)lua.GetNumber("b"); - Assertion.AssertEquals(3,a); - Assertion.AssertEquals(5,b); - //Console.WriteLine("function returned (from lua)="+a+","+b); - } - /* - * Tests calling of an object's method with overloading and - * out params - */ - [Test] - public void CallObjectMethodOverloadedOutParam() - { - TestClass t1=new TestClass(); - lua["netobj"]=t1; - lua.DoString("a,b=netobj:outVal(2)"); - int a=(int)lua.GetNumber("a"); - int b=(int)lua.GetNumber("b"); - Assertion.AssertEquals(2,a); - Assertion.AssertEquals(5,b); - //Console.WriteLine("function returned (from lua)="+a+","+b); - } - /* - * Tests calling of an object's method with ref params - */ - [Test] - public void CallObjectMethodByRefParam() - { - TestClass t1=new TestClass(); - lua["netobj"]=t1; - lua.DoString("a,b=netobj:outVal(2,3)"); - int a=(int)lua.GetNumber("a"); - int b=(int)lua.GetNumber("b"); - Assertion.AssertEquals(2,a); - Assertion.AssertEquals(5,b); - //Console.WriteLine("function returned (from lua)="+a+","+b); - } - /* - * Tests calling of two versions of an object's method that have - * the same name and signature but implement different interfaces - */ - [Test] - public void CallObjectMethodDistinctInterfaces() - { - TestClass t1=new TestClass(); - lua["netobj"]=t1; - lua.DoString("a=netobj:foo()"); - lua.DoString("b=netobj['LuaInterface.Tests.IFoo1.foo'](netobj)"); - int a=(int)lua.GetNumber("a"); - int b=(int)lua.GetNumber("b"); - Assertion.AssertEquals(5,a); - Assertion.AssertEquals(3,b); - //Console.WriteLine("function returned (from lua)="+a+","+b); - } - /* - * Tests instantiating an object with no-argument constructor - */ - [Test] - public void CreateNetObjectNoArgsCons() - { - lua.DoString("load_assembly(\"TestLua\")"); - lua.DoString("TestClass=import_type(\"LuaInterface.Tests.TestClass\")"); - lua.DoString("test=TestClass()"); - lua.DoString("test:setVal(3)"); - object[] res=lua.DoString("return test"); - TestClass test=(TestClass)res[0]; - //Console.WriteLine("returned: "+test.testval); - Assertion.AssertEquals(3,test.testval); - } - /* - * Tests instantiating an object with one-argument constructor - */ - [Test] - public void CreateNetObjectOneArgCons() - { - lua.DoString("load_assembly(\"TestLua\")"); - lua.DoString("TestClass=import_type(\"LuaInterface.Tests.TestClass\")"); - lua.DoString("test=TestClass(3)"); - object[] res=lua.DoString("return test"); - TestClass test=(TestClass)res[0]; - //Console.WriteLine("returned: "+test.testval); - Assertion.AssertEquals(3,test.testval); - } - /* - * Tests instantiating an object with overloaded constructor - */ - [Test] - public void CreateNetObjectOverloadedCons() - { - lua.DoString("load_assembly(\"TestLua\")"); - lua.DoString("TestClass=import_type(\"LuaInterface.Tests.TestClass\")"); - lua.DoString("test=TestClass('str')"); - object[] res=lua.DoString("return test"); - TestClass test=(TestClass)res[0]; - //Console.WriteLine("returned: "+test.getStrVal()); - Assertion.AssertEquals("str",test.getStrVal()); - } - /* - * Tests getting item of a CLR array - */ - [Test] - public void ReadArrayField() - { - string[] arr=new string[] { "str1", "str2", "str3" }; - lua["netobj"]=arr; - lua.DoString("val=netobj[1]"); - string val=lua.GetString("val"); - Assertion.AssertEquals("str2",val); - //Console.WriteLine("new val(from array to Lua)="+val); - } - /* - * Tests setting item of a CLR array - */ - [Test] - public void WriteArrayField() - { - string[] arr=new string[] { "str1", "str2", "str3" }; - lua["netobj"]=arr; - lua.DoString("netobj[1]='test'"); - Assertion.AssertEquals("test",arr[1]); - //Console.WriteLine("new val(from Lua to array)="+arr[1]); - } - /* - * Tests creating a new CLR array - */ - [Test] - public void CreateArray() - { - lua.DoString("load_assembly(\"TestLua\")"); - lua.DoString("TestClass=import_type(\"LuaInterface.Tests.TestClass\")"); - lua.DoString("arr=TestClass[3]"); - lua.DoString("for i=0,2 do arr[i]=TestClass(i+1) end"); - TestClass[] arr=(TestClass[])lua["arr"]; - Assertion.AssertEquals(arr[1].testval,2); - } - /* - * Tests passing a Lua function to a delegate - * with value-type arguments - */ - [Test] - public void LuaDelegateValueTypes() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("function func(x,y) return x+y; end"); - lua.DoString("test=TestClass()"); - lua.DoString("a=test:callDelegate1(func)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(5,a); - //Console.WriteLine("delegate returned: "+a); - } - /* - * Tests passing a Lua function to a delegate - * with value-type arguments and out params - */ - [Test] - public void LuaDelegateValueTypesOutParam() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("function func(x) return x,x*2; end"); - lua.DoString("test=TestClass()"); - lua.DoString("a=test:callDelegate2(func)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(6,a); - //Console.WriteLine("delegate returned: "+a); - } - /* - * Tests passing a Lua function to a delegate - * with value-type arguments and ref params - */ - [Test] - public void LuaDelegateValueTypesByRefParam() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("function func(x,y) return x+y; end"); - lua.DoString("test=TestClass()"); - lua.DoString("a=test:callDelegate3(func)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(5,a); - //Console.WriteLine("delegate returned: "+a); - } - /* - * Tests passing a Lua function to a delegate - * with value-type arguments that returns a reference type - */ - [Test] - public void LuaDelegateValueTypesReturnReferenceType() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("function func(x,y) return TestClass(x+y); end"); - lua.DoString("test=TestClass()"); - lua.DoString("a=test:callDelegate4(func)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(5,a); - //Console.WriteLine("delegate returned: "+a); - } - /* - * Tests passing a Lua function to a delegate - * with reference type arguments - */ - [Test] - public void LuaDelegateReferenceTypes() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("function func(x,y) return x.testval+y.testval; end"); - lua.DoString("test=TestClass()"); - lua.DoString("a=test:callDelegate5(func)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(5,a); - //Console.WriteLine("delegate returned: "+a); - } - /* - * Tests passing a Lua function to a delegate - * with reference type arguments and an out param - */ - [Test] - public void LuaDelegateReferenceTypesOutParam() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("function func(x) return x,TestClass(x*2); end"); - lua.DoString("test=TestClass()"); - lua.DoString("a=test:callDelegate6(func)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(6,a); - //Console.WriteLine("delegate returned: "+a); - } - /* - * Tests passing a Lua function to a delegate - * with reference type arguments and a ref param - */ - [Test] - public void LuaDelegateReferenceTypesByRefParam() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("function func(x,y) return TestClass(x+y.testval); end"); - lua.DoString("a=test:callDelegate7(func)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(5,a); - //Console.WriteLine("delegate returned: "+a); - } - /* - * Tests passing a Lua table as an interface and - * calling one of its methods with value-type params - */ - [Test] - public void LuaInterfaceValueTypes() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("itest={}"); - lua.DoString("function itest:test1(x,y) return x+y; end"); - lua.DoString("test=TestClass()"); - lua.DoString("a=test:callInterface1(itest)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(5,a); - //Console.WriteLine("interface returned: "+a); - } - /* - * Tests passing a Lua table as an interface and - * calling one of its methods with value-type params - * and an out param - */ - [Test] - public void LuaInterfaceValueTypesOutParam() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("itest={}"); - lua.DoString("function itest:test2(x) return x,x*2; end"); - lua.DoString("test=TestClass()"); - lua.DoString("a=test:callInterface2(itest)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(6,a); - //Console.WriteLine("interface returned: "+a); - } - /* - * Tests passing a Lua table as an interface and - * calling one of its methods with value-type params - * and a ref param - */ - [Test] - public void LuaInterfaceValueTypesByRefParam() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("itest={}"); - lua.DoString("function itest:test3(x,y) return x+y; end"); - lua.DoString("test=TestClass()"); - lua.DoString("a=test:callInterface3(itest)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(5,a); - //Console.WriteLine("interface returned: "+a); - } - /* - * Tests passing a Lua table as an interface and - * calling one of its methods with value-type params - * returning a reference type param - */ - [Test] - public void LuaInterfaceValueTypesReturnReferenceType() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("itest={}"); - lua.DoString("function itest:test4(x,y) return TestClass(x+y); end"); - lua.DoString("test=TestClass()"); - lua.DoString("a=test:callInterface4(itest)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(5,a); - //Console.WriteLine("interface returned: "+a); - } - /* - * Tests passing a Lua table as an interface and - * calling one of its methods with reference type params - */ - [Test] - public void LuaInterfaceReferenceTypes() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("itest={}"); - lua.DoString("function itest:test5(x,y) return x.testval+y.testval; end"); - lua.DoString("test=TestClass()"); - lua.DoString("a=test:callInterface5(itest)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(5,a); - //Console.WriteLine("interface returned: "+a); - } - /* - * Tests passing a Lua table as an interface and - * calling one of its methods with reference type params - * and an out param - */ - [Test] - public void LuaInterfaceReferenceTypesOutParam() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("itest={}"); - lua.DoString("function itest:test6(x) return x,TestClass(x*2); end"); - lua.DoString("test=TestClass()"); - lua.DoString("a=test:callInterface6(itest)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(6,a); - //Console.WriteLine("interface returned: "+a); - } - /* - * Tests passing a Lua table as an interface and - * calling one of its methods with reference type params - * and a ref param - */ - [Test] - public void LuaInterfaceReferenceTypesByRefParam() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("itest={}"); - lua.DoString("function itest:test7(x,y) return TestClass(x+y.testval); end"); - lua.DoString("a=test:callInterface7(itest)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(5,a); - //Console.WriteLine("interface returned: "+a); - } - /* - * Tests passing a Lua table as an interface and - * accessing one of its value-type properties - */ - [Test] - public void LuaInterfaceValueProperty() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("itest={}"); - lua.DoString("function itest:get_intProp() return itest.int_prop; end"); - lua.DoString("function itest:set_intProp(val) itest.int_prop=val; end"); - lua.DoString("a=test:callInterface8(itest)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(3,a); - //Console.WriteLine("interface returned: "+a); - } - /* - * Tests passing a Lua table as an interface and - * accessing one of its reference type properties - */ - [Test] - public void LuaInterfaceReferenceProperty() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("itest={}"); - lua.DoString("function itest:get_refProp() return TestClass(itest.int_prop); end"); - lua.DoString("function itest:set_refProp(val) itest.int_prop=val.testval; end"); - lua.DoString("a=test:callInterface9(itest)"); - int a=(int)lua.GetNumber("a"); - Assertion.AssertEquals(3,a); - //Console.WriteLine("interface returned: "+a); - } - - - /* - * Tests making an object from a Lua table and calling the base - * class version of one of the methods the table overrides. - */ - [Test] - public void LuaTableBaseMethod() - { - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test={}"); - lua.DoString("function test:overridableMethod(x,y) return 2*self.base:overridableMethod(x,y); end"); - lua.DoString("make_object(test,'LuaInterface.Tests.TestClass')"); - lua.DoString("a=TestClass:callOverridable(test,2,3)"); - int a=(int)lua.GetNumber("a"); - lua.DoString("free_object(test)"); - Assertion.AssertEquals(10,a); - //Console.WriteLine("interface returned: "+a); - } - /* - * Tests getting an object's method by its signature - * (from object) - */ - [Test] - public void GetMethodBySignatureFromObj() - { - lua.DoString("load_assembly('mscorlib')"); - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("setMethod=get_method_bysig(test,'setVal','System.String')"); - lua.DoString("setMethod('test')"); - TestClass test=(TestClass)lua["test"]; - Assertion.AssertEquals("test",test.getStrVal()); - //Console.WriteLine("interface returned: "+test.getStrVal()); - } - /* - * Tests getting an object's method by its signature - * (from type) - */ - [Test] - public void GetMethodBySignatureFromType() - { - lua.DoString("load_assembly('mscorlib')"); - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test=TestClass()"); - lua.DoString("setMethod=get_method_bysig(TestClass,'setVal','System.String')"); - lua.DoString("setMethod(test,'test')"); - TestClass test=(TestClass)lua["test"]; - Assertion.AssertEquals("test",test.getStrVal()); - //Console.WriteLine("interface returned: "+test.getStrVal()); - } - /* - * Tests getting a type's method by its signature - */ - [Test] - public void GetStaticMethodBySignature() - { - lua.DoString("load_assembly('mscorlib')"); - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("make_method=get_method_bysig(TestClass,'makeFromString','System.String')"); - lua.DoString("test=make_method('test')"); - TestClass test=(TestClass)lua["test"]; - Assertion.AssertEquals("test",test.getStrVal()); - //Console.WriteLine("interface returned: "+test.getStrVal()); - } - /* - * Tests getting an object's constructor by its signature - */ - [Test] - public void GetConstructorBySignature() - { - lua.DoString("load_assembly('mscorlib')"); - lua.DoString("load_assembly('TestLua')"); - lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); - lua.DoString("test_cons=get_constructor_bysig(TestClass,'System.String')"); - lua.DoString("test=test_cons('test')"); - TestClass test=(TestClass)lua["test"]; - Assertion.AssertEquals("test",test.getStrVal()); - //Console.WriteLine("interface returned: "+test.getStrVal()); - } -#endif - void TestOk(bool flag) - { - if(flag) - Console.WriteLine("Test Passed."); - else - Console.WriteLine("Test Failed!!!!"); - } - - /* - * Tests capturing an exception - */ - public void ThrowException() - { - Init(); - _Lua.DoString("luanet.load_assembly('mscorlib')"); - _Lua.DoString("luanet.load_assembly('TestLua')"); - _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); - _Lua.DoString("test=TestClass()"); - _Lua.DoString("err,errMsg=pcall(test.exceptionMethod,test)"); - bool err = (bool)_Lua["err"]; - Exception errMsg = (Exception)_Lua["errMsg"]; - TestOk(!err); - TestOk(errMsg.InnerException != null); - - if(errMsg.InnerException != null) - TestOk("exception test" == errMsg.InnerException.Message); - - //Console.WriteLine("interface returned: "+errMsg.ToString()); - Destroy(); - } - - /* - * Tests capturing an exception - */ - public void ThrowUncaughtException() - { - Init(); - _Lua.DoString("luanet.load_assembly('mscorlib')"); - _Lua.DoString("luanet.load_assembly('TestLua')"); - _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); - _Lua.DoString("test=TestClass()"); - - try - { - _Lua.DoString("test:exceptionMethod()"); - Console.WriteLine("Test failed!!! Should have thrown an exception all the way out of Lua"); - } - catch (Exception) - { - Console.WriteLine("Uncaught exception success"); - } - - Destroy(); - } - - /* - * Tests nullable fields - */ - public void TestNullable() - { - Init(); - _Lua.DoString("luanet.load_assembly('mscorlib')"); - _Lua.DoString("luanet.load_assembly('TestLua')"); - _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); - _Lua.DoString("test=TestClass()"); - _Lua.DoString("val=test.NullableBool"); - TestOk(((object)_Lua["val"]) == null); - _Lua.DoString("test.NullableBool = true"); - _Lua.DoString("val=test.NullableBool"); - TestOk(((bool)_Lua["val"]) == true); - Destroy(); - } - - /* - * Tests structure assignment - */ - public void TestStructs() - { - Init(); - _Lua.DoString("luanet.load_assembly('TestLua')"); - _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); - _Lua.DoString("test=TestClass()"); - _Lua.DoString("TestStruct=luanet.import_type('LuaInterface.Tests.TestStruct')"); - _Lua.DoString("struct=TestStruct(2)"); - _Lua.DoString("test.Struct = struct"); - _Lua.DoString("val=test.Struct.val"); - TestOk(((double)_Lua["val"]) == 2.0); - Destroy(); - } - - public void TestMethodOverloads() - { - Init(); - _Lua.DoString("luanet.load_assembly('mscorlib')"); - _Lua.DoString("luanet.load_assembly('TestLua')"); - _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); - _Lua.DoString("test=TestClass()"); - _Lua.DoString("test:MethodOverload()"); - _Lua.DoString("test:MethodOverload(test)"); - _Lua.DoString("test:MethodOverload(1,1,1)"); - _Lua.DoString("test:MethodOverload(2,2,i)\r\nprint(i)"); - } - - private void TestDispose() - { - GC.Collect(); - long startingMem = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; - - for(int i = 0; i < 10000; i++) - { - using (Lua lua = new Lua()) - { - _Calc(lua, i); - } - } - - Console.WriteLine("Was using " + startingMem / 1024 / 1024 + "MB, now using: " + System.Diagnostics.Process.GetCurrentProcess().WorkingSet64 / 1024 / 1024 + "MB"); - } - - private void _Calc(Lua lua, int i) - { - lua.DoString( - "sqrt = math.sqrt;" + - "sqr = function(x) return math.pow(x,2); end;" + - "log = math.log;" + - "log10 = math.log10;" + - "exp = math.exp;" + - "sin = math.sin;" + - "cos = math.cos;" + - "tan = math.tan;" + - "abs = math.abs;" - ); - - lua.DoString("function calcVP(a,b) return a+b end"); - LuaFunction lf = lua.GetFunction("calcVP"); - /*Object[] ret = */lf.Call(i, 20); - } - - private void TestThreading() - { - Init(); - var doWork = new DoWorkClass(); - _Lua.RegisterFunction("dowork", doWork, typeof(DoWorkClass).GetMethod("DoWork")); - - bool failureDetected = false; - int completed = 0; - int iterations = 500; - - for(int i = 0; i < iterations; i++) - { - ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object o) - { - try - { - _Lua.DoString("dowork()"); - } - catch - { - failureDetected = true; - } - - completed++; - })); - } - - while(completed < iterations && !failureDetected) - Thread.Sleep(50); - - if(failureDetected) - Console.WriteLine("==Problem with threading!=="); - } - - private void TestPrivateMethod() - { - Init(); - _Lua.DoString("luanet.load_assembly('mscorlib')"); - _Lua.DoString("luanet.load_assembly('TestLua')"); - _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); - _Lua.DoString("test=TestClass()"); - - try - { - _Lua.DoString("test:_PrivateMethod()"); - } - catch - { - Console.WriteLine("Test Passed"); - return; - } - - Console.WriteLine("Test Failed"); - } - - /* - * Tests functions - */ - public void TestFunctions() - { - Init(); - _Lua.DoString("luanet.load_assembly('mscorlib')"); - _Lua.DoString("luanet.load_assembly('TestLua')"); - _Lua.RegisterFunction("p", null, typeof(System.Console).GetMethod("WriteLine", new Type[] { typeof(String) })); - - /// Lua command that works (prints to console) - _Lua.DoString("p('Foo')"); - - /// Yet this works... - _Lua.DoString("string.gsub('some string', '(%w+)', function(s) p(s) end)"); - - /// This fails if you don't fix Lua5.1 lstrlib.c/add_value to treat LUA_TUSERDATA the same as LUA_FUNCTION - _Lua.DoString("string.gsub('some string', '(%w+)', p)"); - Destroy(); - } - - /* - * Tests making an object from a Lua table and calling one of - * methods the table overrides. - */ - public void LuaTableOverridedMethod() - { - Init(); - _Lua.DoString("luanet.load_assembly('TestLua')"); - _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); - _Lua.DoString("test={}"); - _Lua.DoString("function test:overridableMethod(x,y) return x*y; end"); - _Lua.DoString("luanet.make_object(test,'LuaInterface.Tests.TestClass')"); - _Lua.DoString("a=TestClass.callOverridable(test,2,3)"); - int a = (int)_Lua.GetNumber("a"); - _Lua.DoString("luanet.free_object(test)"); - TestOk(6 == a); - //Console.WriteLine("interface returned: "+a); - } - - /* - * Tests making an object from a Lua table and calling a method - * the table does not override. - */ - public void LuaTableInheritedMethod() - { - Init(); - _Lua.DoString("luanet.load_assembly('TestLua')"); - _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); - _Lua.DoString("test={}"); - _Lua.DoString("function test:overridableMethod(x,y) return x*y; end"); - _Lua.DoString("luanet.make_object(test,'LuaInterface.Tests.TestClass')"); - _Lua.DoString("test:setVal(3)"); - _Lua.DoString("a=test.testval"); - int a = (int)_Lua.GetNumber("a"); - _Lua.DoString("luanet.free_object(test)"); - TestOk(3 == a); - //Console.WriteLine("interface returned: "+a); - } - - /// - /// Basic multiply method which expects 2 floats - /// - /// - /// - /// - private float _TestException(float val, float val2) - { - return val * val2; - } - - public void TestEventException() - { - Init(); - - //Register a C# function - MethodInfo testException = this.GetType().GetMethod("_TestException", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance, null, new Type[] { typeof(float), typeof(float) }, null); - _Lua.RegisterFunction("Multiply", this, testException); - - //create the lua event handler code for the entity - //includes the bad code! - _Lua.DoString("function OnClick(sender, eventArgs)\r\n" + - "--Multiply expects 2 floats, but instead receives 2 strings\r\n" + - "Multiply(asd, we)\r\n" + - "end"); - - //create the lua event handler code for the entity - //good code - //lua.DoString("function OnClick(sender, eventArgs)\r\n" + - // "--Multiply expects 2 floats\r\n" + - // "Multiply(2, 50)\r\n" + - // "end"); - - //Create the event handler script - _Lua.DoString("function SubscribeEntity(e)\r\ne.Clicked:Add(OnClick)\r\nend"); - - //Create the entity object - var entity = new Entity(); - - //Register the entity object with the event handler inside lua - LuaFunction lf = _Lua.GetFunction("SubscribeEntity"); - lf.Call(new object[1] { entity }); - - try - { - //Cause the event to be fired - entity.Click(); - - Console.WriteLine("Test failed!!! Should have thrown an exception all the way out of Lua"); - } - catch (LuaException) - { - Console.WriteLine("Event exception success"); - } - } - - public void TestExceptionWithChunkOverload() - { - Init(); - - try - { - _Lua.DoString("thiswillthrowanerror", "MyChunk"); - } - catch(Exception e) - { - if (e.Message.StartsWith("[string \"MyChunk\"]")) - Console.WriteLine("Chunk overload passed"); - else - Console.WriteLine("Chunk overload failed"); - } - } - - public void TestGenerics() - { - Init(); - - //Im not sure support for generic classes is possible to implement, see: http://msdn.microsoft.com/en-us/library/system.reflection.methodinfo.containsgenericparameters.aspx - //specifically the line that says: "If the ContainsGenericParameters property returns true, the method cannot be invoked" - - //TestClassGeneric genericClass = new TestClassGeneric(); - - //_Lua.RegisterFunction("genericMethod", genericClass, typeof(TestClassGeneric<>).GetMethod("GenericMethod")); - //_Lua.RegisterFunction("regularMethod", genericClass, typeof(TestClassGeneric<>).GetMethod("RegularMethod")); - - //try - //{ - // _Lua.DoString("genericMethod('thestring')"); - //} - //catch { } - - //try - //{ - // _Lua.DoString("regularMethod()"); - //} - //catch { } - - //if (genericClass.GenericMethodSuccess && genericClass.RegularMethodSuccess && genericClass.Validate("thestring")) - // Console.WriteLine("Generic class passed"); - //else - // Console.WriteLine("Generic class failed"); - - bool passed = true; - TestClassWithGenericMethod classWithGenericMethod = new TestClassWithGenericMethod(); - - _Lua.RegisterFunction("genericMethod2", classWithGenericMethod, typeof(TestClassWithGenericMethod).GetMethod("GenericMethod")); - - try - { - _Lua.DoString("genericMethod2(100)"); - } - catch - { - - } - - if(!classWithGenericMethod.GenericMethodSuccess || !classWithGenericMethod.Validate(100)) //note the gotcha: numbers are all being passed to generic methods as doubles - passed = false; - - try - { - _Lua.DoString("luanet.load_assembly('TestLua')"); - _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); - _Lua.DoString("test=TestClass(56)"); - _Lua.DoString("genericMethod2(test)"); - } - catch - { - - } - - if(!classWithGenericMethod.GenericMethodSuccess || (classWithGenericMethod.PassedValue as TestClass).val != 56) - passed = false; - - if(passed) - Console.WriteLine("Class with generic method passed"); - else - Console.WriteLine("Class with generic method failed"); - } - - public static int func(int x, int y) - { - return x + y; - } - public int funcInstance(int x, int y) - { - return x + y; - } - - public void RegisterFunctionStressTest() - { - LuaFunction fc = null; - const int Count = 200; // it seems to work with 41 - - Init(); - var t = new MyClass(); - - for(int i = 1; i < Count - 1; ++i) - fc = _Lua.RegisterFunction("func" + i, t, typeof(MyClass).GetMethod("Func1")); - - fc = _Lua.RegisterFunction("func" + (Count - 1), t, typeof(MyClass).GetMethod("Func1")); - _Lua.DoString("print(func1())"); - } - - /* - * Sample test script that shows some of the capabilities of - * LuaInterface - */ - public static void Main() - { - Console.WriteLine("Starting interpreter..."); - var l = new Lua(); - - // Pause so we can connect with the debugger - // Thread.Sleep(30000); - Console.WriteLine("Reading test.lua file..."); - l.DoFile("test.lua"); - double width = l.GetNumber("width"); - double height = l.GetNumber("height"); - string message = l.GetString("message"); - double color_r = l.GetNumber("color.r"); - double color_g = l.GetNumber("color.g"); - double color_b = l.GetNumber("color.b"); - Console.WriteLine("Printing values of global variables width, height and message..."); - Console.WriteLine("width: " + width); - Console.WriteLine("height: " + height); - Console.WriteLine("message: " + message); - Console.WriteLine("Printing values of the 'color' table's fields..."); - Console.WriteLine("color.r: " + color_r); - Console.WriteLine("color.g: " + color_g); - Console.WriteLine("color.b: " + color_b); - width = 150; - Console.WriteLine("Changing width's value and calling Lua function print to show it..."); - l["width"] = width; - l.GetFunction("print").Call(width); - message = "LuaNet Interface Test"; - Console.WriteLine("Changing message's value and calling Lua function print to show it..."); - l["message"] = message; - l.GetFunction("print").Call(message); - color_r = 30; - color_g = 10; - color_b = 200; - Console.WriteLine("Changing color's fields' values and calling Lua function print to show it..."); - l["color.r"] = color_r; - l["color.g"] = color_g; - l["color.b"] = color_b; - l.DoString("print(color.r,color.g,color.b)"); - Console.WriteLine("Printing values of the tree table's fields..."); - double leaf1 = l.GetNumber("tree.branch1.leaf1"); - string leaf2 = l.GetString("tree.branch1.leaf2"); - string leaf3 = l.GetString("tree.leaf3"); - Console.WriteLine("leaf1: " + leaf1); - Console.WriteLine("leaf2: " + leaf2); - Console.WriteLine("leaf3: " + leaf3); - leaf1 = 30; leaf2 = "new leaf2"; - Console.WriteLine("Changing tree's fields' values and calling Lua function print to show it..."); - l["tree.branch1.leaf1"] = leaf1; l["tree.branch1.leaf2"] = leaf2; - l.DoString("print(tree.branch1.leaf1,tree.branch1.leaf2)"); - Console.WriteLine("Returning values from Lua with 'return'..."); - object[] vals = l.DoString("return 2,3"); - Console.WriteLine("Returned: " + vals[0] + " and " + vals[1]); - Console.WriteLine("Calling a Lua function that returns multiple values..."); - object[] vals1 = l.GetFunction("func").Call(2, 3); - Console.WriteLine("Returned: " + vals1[0] + " and " + vals1[1]); - Console.WriteLine("Creating a table and filling it from C#..."); - l.NewTable("tab"); - l.NewTable("tab.tab"); - l["tab.a"] = "a!"; - l["tab.b"] = 5.5; - l["tab.tab.c"] = 6.5; - l.DoString("print(tab.a,tab.b,tab.tab.c)"); - Console.WriteLine("Setting a table as another table's field..."); - l["tab.a"] = l["tab.tab"]; - l.DoString("print(tab.a.c)"); - Console.WriteLine("Registering a C# static method and calling it from Lua..."); - - // Pause so we can connect with the debugger - // Thread.Sleep(30000); - l.RegisterFunction("func1", null, typeof(TestLuaInterface).GetMethod("func")); - vals1 = l.GetFunction("func1").Call(2, 3); - Console.WriteLine("Returned: " + vals1[0]); - TestLuaInterface obj = new TestLuaInterface(); - Console.WriteLine("Registering a C# instance method and calling it from Lua..."); - l.RegisterFunction("func2", obj, typeof(TestLuaInterface).GetMethod("funcInstance")); - vals1 = l.GetFunction("func2").Call(2, 3); - Console.WriteLine("Returned: " + vals1[0]); - - Console.WriteLine("Testing throwing an exception..."); - obj.ThrowUncaughtException(); - - Console.WriteLine("Testing catching an exception..."); - obj.ThrowException(); - - Console.WriteLine("Testing inheriting a method from Lua..."); - obj.LuaTableInheritedMethod(); - - Console.WriteLine("Testing overriding a C# method with Lua..."); - obj.LuaTableOverridedMethod(); - - Console.WriteLine("Stress test RegisterFunction (based on a reported bug).."); - obj.RegisterFunctionStressTest(); - - Console.WriteLine("Test structures..."); - obj.TestStructs(); - - Console.WriteLine("Test Nullable types..."); - obj.TestNullable(); - - Console.WriteLine("Test functions..."); - obj.TestFunctions(); - - Console.WriteLine("Test method overloads..."); - obj.TestMethodOverloads(); - - Console.WriteLine("Test accessing private method..."); - obj.TestPrivateMethod(); - - Console.WriteLine("Test event exceptions..."); - obj.TestEventException(); - - Console.WriteLine("Test chunk overload exception..."); - obj.TestExceptionWithChunkOverload(); - - Console.WriteLine("Test generics..."); - obj.TestGenerics(); - - Console.WriteLine("Test threading..."); - obj.TestThreading(); - - Console.WriteLine("Test memory leakage..."); - obj.TestDispose(); - - Console.WriteLine("Press enter to exit."); - Console.ReadLine(); - } - } +/* + * This file is part of LuaInterface. + * + * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. + * Copyright (C) 2012 Megax + * + * 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: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 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. + */ + +using System; +using System.Text; +using System.Threading; +using System.Reflection; +using System.Collections.Generic; +using LuaInterface.Exceptions; + +namespace LuaInterface.Tests +{ + /* + * Automated test cases for LuaInterface + * + * Author: Fabio Mascarenhas + * Version: 1.0 + */ + public class TestLuaInterface + { + private Lua _Lua; + + /* + * Executed before each test case + */ + public void Init() + { + _Lua = new Lua(); + GC.Collect(); // runs GC to expose unprotected delegates + } + + /* + * Executed after each test case + */ + public void Destroy() + { + _Lua = null; + } + +#if false + // I've commented out the nunit based tests until they can run standalone - so that users don't need nunit to run TestLua + + /* + * Tests if DoString is correctly returning values + */ + [Test] + public void DoString() + { + object[] res=lua.DoString("a=2\nreturn a,3"); + //Console.WriteLine("a="+res[0]+", b="+res[1]); + Assertion.AssertEquals(res[0],2); + Assertion.AssertEquals(res[1],3); + } + /* + * Tests getting of global numeric variables + */ + [Test] + public void GetGlobalNumber() + { + lua.DoString("a=2"); + double num=lua.GetNumber("a"); + //Console.WriteLine("a="+num); + Assertion.AssertEquals(num,2); + } + /* + * Tests setting of global numeric variables + */ + [Test] + public void SetGlobalNumber() + { + lua.DoString("a=2"); + lua["a"]=3; + double num=lua.GetNumber("a"); + //Console.WriteLine("a="+num); + Assertion.AssertEquals(num,3); + } + /* + * Tests getting of numeric variables from tables + * by specifying variable path + */ + [Test] + public void GetNumberInTable() + { + lua.DoString("a={b={c=2}}"); + double num=lua.GetNumber("a.b.c"); + //Console.WriteLine("a.b.c="+num); + Assertion.AssertEquals(num,2); + } + /* + * Tests setting of numeric variables from tables + * by specifying variable path + */ + [Test] + public void SetNumberInTable() + { + lua.DoString("a={b={c=2}}"); + lua["a.b.c"]=3; + double num=lua.GetNumber("a.b.c"); + //Console.WriteLine("a.b.c="+num); + Assertion.AssertEquals(num,3); + } + /* + * Tests getting of global string variables + */ + [Test] + public void GetGlobalString() + { + lua.DoString("a=\"test\""); + string str=lua.GetString("a"); + //Console.WriteLine("a="+str); + Assertion.AssertEquals(str,"test"); + } + /* + * Tests setting of global string variables + */ + [Test] + public void SetGlobalString() + { + lua.DoString("a=\"test\""); + lua["a"]="new test"; + string str=lua.GetString("a"); + //Console.WriteLine("a="+str); + Assertion.AssertEquals(str,"new test"); + } + /* + * Tests getting of string variables from tables + * by specifying variable path + */ + [Test] + public void GetStringInTable() + { + lua.DoString("a={b={c=\"test\"}}"); + string str=lua.GetString("a.b.c"); + //Console.WriteLine("a.b.c="+str); + Assertion.AssertEquals(str,"test"); + } + /* + * Tests setting of string variables from tables + * by specifying variable path + */ + [Test] + public void SetStringInTable() + { + lua.DoString("a={b={c=\"test\"}}"); + lua["a.b.c"]="new test"; + string str=lua.GetString("a.b.c"); + //Console.WriteLine("a.b.c="+str); + Assertion.AssertEquals(str,"new test"); + } + /* + * Tests getting and setting of global table variables + */ + [Test] + public void GetAndSetTable() + { + lua.DoString("a={b={c=2}}\nb={c=3}"); + LuaTable tab=lua.GetTable("b"); + lua["a.b"]=tab; + double num=lua.GetNumber("a.b.c"); + //Console.WriteLine("a.b.c="+num); + Assertion.AssertEquals(num,3); + } + /* + * Tests getting of numeric field of a table + */ + [Test] + public void GetTableNumericField1() + { + lua.DoString("a={b={c=2}}"); + LuaTable tab=lua.GetTable("a.b"); + double num=(double)tab["c"]; + //Console.WriteLine("a.b.c="+num); + Assertion.AssertEquals(num,2); + } + /* + * Tests getting of numeric field of a table + * (the field is inside a subtable) + */ + [Test] + public void GetTableNumericField2() + { + lua.DoString("a={b={c=2}}"); + LuaTable tab=lua.GetTable("a"); + double num=(double)tab["b.c"]; + //Console.WriteLine("a.b.c="+num); + Assertion.AssertEquals(num,2); + } + /* + * Tests setting of numeric field of a table + */ + [Test] + public void SetTableNumericField1() + { + lua.DoString("a={b={c=2}}"); + LuaTable tab=lua.GetTable("a.b"); + tab["c"]=3; + double num=lua.GetNumber("a.b.c"); + //Console.WriteLine("a.b.c="+num); + Assertion.AssertEquals(num,3); + } + /* + * Tests setting of numeric field of a table + * (the field is inside a subtable) + */ + [Test] + public void SetTableNumericField2() + { + lua.DoString("a={b={c=2}}"); + LuaTable tab=lua.GetTable("a"); + tab["b.c"]=3; + double num=lua.GetNumber("a.b.c"); + //Console.WriteLine("a.b.c="+num); + Assertion.AssertEquals(num,3); + } + /* + * Tests getting of string field of a table + */ + [Test] + public void GetTableStringField1() + { + lua.DoString("a={b={c=\"test\"}}"); + LuaTable tab=lua.GetTable("a.b"); + string str=(string)tab["c"]; + //Console.WriteLine("a.b.c="+str); + Assertion.AssertEquals(str,"test"); + } + /* + * Tests getting of string field of a table + * (the field is inside a subtable) + */ + [Test] + public void GetTableStringField2() + { + lua.DoString("a={b={c=\"test\"}}"); + LuaTable tab=lua.GetTable("a"); + string str=(string)tab["b.c"]; + //Console.WriteLine("a.b.c="+str); + Assertion.AssertEquals(str,"test"); + } + /* + * Tests setting of string field of a table + */ + [Test] + public void SetTableStringField1() + { + lua.DoString("a={b={c=\"test\"}}"); + LuaTable tab=lua.GetTable("a.b"); + tab["c"]="new test"; + string str=lua.GetString("a.b.c"); + //Console.WriteLine("a.b.c="+str); + Assertion.AssertEquals(str,"new test"); + } + /* + * Tests setting of string field of a table + * (the field is inside a subtable) + */ + [Test] + public void SetTableStringField2() + { + lua.DoString("a={b={c=\"test\"}}"); + LuaTable tab=lua.GetTable("a"); + tab["b.c"]="new test"; + string str=lua.GetString("a.b.c"); + //Console.WriteLine("a.b.c="+str); + Assertion.AssertEquals(str,"new test"); + } + /* + * Tests calling of a global function with zero arguments + */ + [Test] + public void CallGlobalFunctionNoArgs() + { + lua.DoString("a=2\nfunction f()\na=3\nend"); + lua.GetFunction("f").Call(); + double num=lua.GetNumber("a"); + //Console.WriteLine("a="+num); + Assertion.AssertEquals(num,3); + } + /* + * Tests calling of a global function with one argument + */ + [Test] + public void CallGlobalFunctionOneArg() + { + lua.DoString("a=2\nfunction f(x)\na=a+x\nend"); + lua.GetFunction("f").Call(1); + double num=lua.GetNumber("a"); + //Console.WriteLine("a="+num); + Assertion.AssertEquals(num,3); + } + /* + * Tests calling of a global function with two arguments + */ + [Test] + public void CallGlobalFunctionTwoArgs() + { + lua.DoString("a=2\nfunction f(x,y)\na=x+y\nend"); + lua.GetFunction("f").Call(1,3); + double num=lua.GetNumber("a"); + //Console.WriteLine("a="+num); + Assertion.AssertEquals(num,4); + } + /* + * Tests calling of a global function that returns one value + */ + [Test] + public void CallGlobalFunctionOneReturn() + { + lua.DoString("function f(x)\nreturn x+2\nend"); + object[] ret=lua.GetFunction("f").Call(3); + //Console.WriteLine("ret="+ret[0]); + Assertion.AssertEquals(1,ret.Length); + Assertion.AssertEquals(5,ret[0]); + } + /* + * Tests calling of a global function that returns two values + */ + [Test] + public void CallGlobalFunctionTwoReturns() + { + lua.DoString("function f(x,y)\nreturn x,x+y\nend"); + object[] ret=lua.GetFunction("f").Call(3,2); + //Console.WriteLine("ret="+ret[0]+","+ret[1]); + Assertion.AssertEquals(2,ret.Length); + Assertion.AssertEquals(3,ret[0]); + Assertion.AssertEquals(5,ret[1]); + } + /* + * Tests calling of a function inside a table + */ + [Test] + public void CallTableFunctionTwoReturns() + { + lua.DoString("a={}\nfunction a.f(x,y)\nreturn x,x+y\nend"); + object[] ret=lua.GetFunction("a.f").Call(3,2); + //Console.WriteLine("ret="+ret[0]+","+ret[1]); + Assertion.AssertEquals(2,ret.Length); + Assertion.AssertEquals(3,ret[0]); + Assertion.AssertEquals(5,ret[1]); + } + /* + * Tests setting of a global variable to a CLR object value + */ + [Test] + public void SetGlobalObject() + { + TestClass t1=new TestClass(); + t1.testval=4; + lua["netobj"]=t1; + object o=lua["netobj"]; + TestClass t2=(TestClass)lua["netobj"]; + Assertion.AssertEquals(t2.testval,4); + Assertion.Assert(t1==t2); + } + /* + * Tests if CLR object is being correctly collected by Lua + */ + [Test] + public void GarbageCollection() + { + TestClass t1=new TestClass(); + t1.testval=4; + lua["netobj"]=t1; + TestClass t2=(TestClass)lua["netobj"]; + Assertion.Assert(lua.translator.objects[0]!=null); + lua.DoString("netobj=nil;collectgarbage();"); + Assertion.Assert(lua.translator.objects[0]==null); + } + /* + * Tests setting of a table field to a CLR object value + */ + [Test] + public void SetTableObjectField1() + { + lua.DoString("a={b={c=\"test\"}}"); + LuaTable tab=lua.GetTable("a.b"); + TestClass t1=new TestClass(); + t1.testval=4; + tab["c"]=t1; + TestClass t2=(TestClass)lua["a.b.c"]; + //Console.WriteLine("a.b.c="+t2.testval); + Assertion.AssertEquals(t2.testval,4); + Assertion.Assert(t1==t2); + } + /* + * Tests reading and writing of an object's field + */ + [Test] + public void AccessObjectField() + { + TestClass t1=new TestClass(); + t1.val=4; + lua["netobj"]=t1; + lua.DoString("var=netobj.val"); + double var=(double)lua["var"]; + //Console.WriteLine("value from Lua="+var); + Assertion.AssertEquals(4,var); + lua.DoString("netobj.val=3"); + Assertion.AssertEquals(3,t1.val); + //Console.WriteLine("new val (from Lua)="+t1.val); + } + /* + * Tests reading and writing of an object's non-indexed + * property + */ + [Test] + public void AccessObjectProperty() + { + TestClass t1=new TestClass(); + t1.testval=4; + lua["netobj"]=t1; + lua.DoString("var=netobj.testval"); + double var=(double)lua["var"]; + //Console.WriteLine("value from Lua="+var); + Assertion.AssertEquals(4,var); + lua.DoString("netobj.testval=3"); + Assertion.AssertEquals(3,t1.testval); + //Console.WriteLine("new val (from Lua)="+t1.testval); + } + /* + * Tests calling of an object's method with no overloads + */ + [Test] + public void CallObjectMethod() + { + TestClass t1=new TestClass(); + t1.testval=4; + lua["netobj"]=t1; + lua.DoString("netobj:setVal(3)"); + Assertion.AssertEquals(3,t1.testval); + //Console.WriteLine("new val(from C#)="+t1.testval); + lua.DoString("val=netobj:getVal()"); + int val=(int)lua.GetNumber("val"); + Assertion.AssertEquals(3,val); + //Console.WriteLine("new val(from Lua)="+val); + } + /* + * Tests calling of an object's method with overloading + */ + [Test] + public void CallObjectMethodByType() + { + TestClass t1=new TestClass(); + lua["netobj"]=t1; + lua.DoString("netobj:setVal('str')"); + Assertion.AssertEquals("str",t1.getStrVal()); + //Console.WriteLine("new val(from C#)="+t1.getStrVal()); + } + /* + * Tests calling of an object's method with no overloading + * and out parameters + */ + [Test] + public void CallObjectMethodOutParam() + { + TestClass t1=new TestClass(); + lua["netobj"]=t1; + lua.DoString("a,b=netobj:outVal()"); + int a=(int)lua.GetNumber("a"); + int b=(int)lua.GetNumber("b"); + Assertion.AssertEquals(3,a); + Assertion.AssertEquals(5,b); + //Console.WriteLine("function returned (from lua)="+a+","+b); + } + /* + * Tests calling of an object's method with overloading and + * out params + */ + [Test] + public void CallObjectMethodOverloadedOutParam() + { + TestClass t1=new TestClass(); + lua["netobj"]=t1; + lua.DoString("a,b=netobj:outVal(2)"); + int a=(int)lua.GetNumber("a"); + int b=(int)lua.GetNumber("b"); + Assertion.AssertEquals(2,a); + Assertion.AssertEquals(5,b); + //Console.WriteLine("function returned (from lua)="+a+","+b); + } + /* + * Tests calling of an object's method with ref params + */ + [Test] + public void CallObjectMethodByRefParam() + { + TestClass t1=new TestClass(); + lua["netobj"]=t1; + lua.DoString("a,b=netobj:outVal(2,3)"); + int a=(int)lua.GetNumber("a"); + int b=(int)lua.GetNumber("b"); + Assertion.AssertEquals(2,a); + Assertion.AssertEquals(5,b); + //Console.WriteLine("function returned (from lua)="+a+","+b); + } + /* + * Tests calling of two versions of an object's method that have + * the same name and signature but implement different interfaces + */ + [Test] + public void CallObjectMethodDistinctInterfaces() + { + TestClass t1=new TestClass(); + lua["netobj"]=t1; + lua.DoString("a=netobj:foo()"); + lua.DoString("b=netobj['LuaInterface.Tests.IFoo1.foo'](netobj)"); + int a=(int)lua.GetNumber("a"); + int b=(int)lua.GetNumber("b"); + Assertion.AssertEquals(5,a); + Assertion.AssertEquals(3,b); + //Console.WriteLine("function returned (from lua)="+a+","+b); + } + /* + * Tests instantiating an object with no-argument constructor + */ + [Test] + public void CreateNetObjectNoArgsCons() + { + lua.DoString("load_assembly(\"TestLua\")"); + lua.DoString("TestClass=import_type(\"LuaInterface.Tests.TestClass\")"); + lua.DoString("test=TestClass()"); + lua.DoString("test:setVal(3)"); + object[] res=lua.DoString("return test"); + TestClass test=(TestClass)res[0]; + //Console.WriteLine("returned: "+test.testval); + Assertion.AssertEquals(3,test.testval); + } + /* + * Tests instantiating an object with one-argument constructor + */ + [Test] + public void CreateNetObjectOneArgCons() + { + lua.DoString("load_assembly(\"TestLua\")"); + lua.DoString("TestClass=import_type(\"LuaInterface.Tests.TestClass\")"); + lua.DoString("test=TestClass(3)"); + object[] res=lua.DoString("return test"); + TestClass test=(TestClass)res[0]; + //Console.WriteLine("returned: "+test.testval); + Assertion.AssertEquals(3,test.testval); + } + /* + * Tests instantiating an object with overloaded constructor + */ + [Test] + public void CreateNetObjectOverloadedCons() + { + lua.DoString("load_assembly(\"TestLua\")"); + lua.DoString("TestClass=import_type(\"LuaInterface.Tests.TestClass\")"); + lua.DoString("test=TestClass('str')"); + object[] res=lua.DoString("return test"); + TestClass test=(TestClass)res[0]; + //Console.WriteLine("returned: "+test.getStrVal()); + Assertion.AssertEquals("str",test.getStrVal()); + } + /* + * Tests getting item of a CLR array + */ + [Test] + public void ReadArrayField() + { + string[] arr=new string[] { "str1", "str2", "str3" }; + lua["netobj"]=arr; + lua.DoString("val=netobj[1]"); + string val=lua.GetString("val"); + Assertion.AssertEquals("str2",val); + //Console.WriteLine("new val(from array to Lua)="+val); + } + /* + * Tests setting item of a CLR array + */ + [Test] + public void WriteArrayField() + { + string[] arr=new string[] { "str1", "str2", "str3" }; + lua["netobj"]=arr; + lua.DoString("netobj[1]='test'"); + Assertion.AssertEquals("test",arr[1]); + //Console.WriteLine("new val(from Lua to array)="+arr[1]); + } + /* + * Tests creating a new CLR array + */ + [Test] + public void CreateArray() + { + lua.DoString("load_assembly(\"TestLua\")"); + lua.DoString("TestClass=import_type(\"LuaInterface.Tests.TestClass\")"); + lua.DoString("arr=TestClass[3]"); + lua.DoString("for i=0,2 do arr[i]=TestClass(i+1) end"); + TestClass[] arr=(TestClass[])lua["arr"]; + Assertion.AssertEquals(arr[1].testval,2); + } + /* + * Tests passing a Lua function to a delegate + * with value-type arguments + */ + [Test] + public void LuaDelegateValueTypes() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("function func(x,y) return x+y; end"); + lua.DoString("test=TestClass()"); + lua.DoString("a=test:callDelegate1(func)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(5,a); + //Console.WriteLine("delegate returned: "+a); + } + /* + * Tests passing a Lua function to a delegate + * with value-type arguments and out params + */ + [Test] + public void LuaDelegateValueTypesOutParam() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("function func(x) return x,x*2; end"); + lua.DoString("test=TestClass()"); + lua.DoString("a=test:callDelegate2(func)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(6,a); + //Console.WriteLine("delegate returned: "+a); + } + /* + * Tests passing a Lua function to a delegate + * with value-type arguments and ref params + */ + [Test] + public void LuaDelegateValueTypesByRefParam() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("function func(x,y) return x+y; end"); + lua.DoString("test=TestClass()"); + lua.DoString("a=test:callDelegate3(func)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(5,a); + //Console.WriteLine("delegate returned: "+a); + } + /* + * Tests passing a Lua function to a delegate + * with value-type arguments that returns a reference type + */ + [Test] + public void LuaDelegateValueTypesReturnReferenceType() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("function func(x,y) return TestClass(x+y); end"); + lua.DoString("test=TestClass()"); + lua.DoString("a=test:callDelegate4(func)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(5,a); + //Console.WriteLine("delegate returned: "+a); + } + /* + * Tests passing a Lua function to a delegate + * with reference type arguments + */ + [Test] + public void LuaDelegateReferenceTypes() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("function func(x,y) return x.testval+y.testval; end"); + lua.DoString("test=TestClass()"); + lua.DoString("a=test:callDelegate5(func)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(5,a); + //Console.WriteLine("delegate returned: "+a); + } + /* + * Tests passing a Lua function to a delegate + * with reference type arguments and an out param + */ + [Test] + public void LuaDelegateReferenceTypesOutParam() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("function func(x) return x,TestClass(x*2); end"); + lua.DoString("test=TestClass()"); + lua.DoString("a=test:callDelegate6(func)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(6,a); + //Console.WriteLine("delegate returned: "+a); + } + /* + * Tests passing a Lua function to a delegate + * with reference type arguments and a ref param + */ + [Test] + public void LuaDelegateReferenceTypesByRefParam() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("function func(x,y) return TestClass(x+y.testval); end"); + lua.DoString("a=test:callDelegate7(func)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(5,a); + //Console.WriteLine("delegate returned: "+a); + } + /* + * Tests passing a Lua table as an interface and + * calling one of its methods with value-type params + */ + [Test] + public void LuaInterfaceValueTypes() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("itest={}"); + lua.DoString("function itest:test1(x,y) return x+y; end"); + lua.DoString("test=TestClass()"); + lua.DoString("a=test:callInterface1(itest)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(5,a); + //Console.WriteLine("interface returned: "+a); + } + /* + * Tests passing a Lua table as an interface and + * calling one of its methods with value-type params + * and an out param + */ + [Test] + public void LuaInterfaceValueTypesOutParam() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("itest={}"); + lua.DoString("function itest:test2(x) return x,x*2; end"); + lua.DoString("test=TestClass()"); + lua.DoString("a=test:callInterface2(itest)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(6,a); + //Console.WriteLine("interface returned: "+a); + } + /* + * Tests passing a Lua table as an interface and + * calling one of its methods with value-type params + * and a ref param + */ + [Test] + public void LuaInterfaceValueTypesByRefParam() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("itest={}"); + lua.DoString("function itest:test3(x,y) return x+y; end"); + lua.DoString("test=TestClass()"); + lua.DoString("a=test:callInterface3(itest)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(5,a); + //Console.WriteLine("interface returned: "+a); + } + /* + * Tests passing a Lua table as an interface and + * calling one of its methods with value-type params + * returning a reference type param + */ + [Test] + public void LuaInterfaceValueTypesReturnReferenceType() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("itest={}"); + lua.DoString("function itest:test4(x,y) return TestClass(x+y); end"); + lua.DoString("test=TestClass()"); + lua.DoString("a=test:callInterface4(itest)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(5,a); + //Console.WriteLine("interface returned: "+a); + } + /* + * Tests passing a Lua table as an interface and + * calling one of its methods with reference type params + */ + [Test] + public void LuaInterfaceReferenceTypes() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("itest={}"); + lua.DoString("function itest:test5(x,y) return x.testval+y.testval; end"); + lua.DoString("test=TestClass()"); + lua.DoString("a=test:callInterface5(itest)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(5,a); + //Console.WriteLine("interface returned: "+a); + } + /* + * Tests passing a Lua table as an interface and + * calling one of its methods with reference type params + * and an out param + */ + [Test] + public void LuaInterfaceReferenceTypesOutParam() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("itest={}"); + lua.DoString("function itest:test6(x) return x,TestClass(x*2); end"); + lua.DoString("test=TestClass()"); + lua.DoString("a=test:callInterface6(itest)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(6,a); + //Console.WriteLine("interface returned: "+a); + } + /* + * Tests passing a Lua table as an interface and + * calling one of its methods with reference type params + * and a ref param + */ + [Test] + public void LuaInterfaceReferenceTypesByRefParam() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("itest={}"); + lua.DoString("function itest:test7(x,y) return TestClass(x+y.testval); end"); + lua.DoString("a=test:callInterface7(itest)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(5,a); + //Console.WriteLine("interface returned: "+a); + } + /* + * Tests passing a Lua table as an interface and + * accessing one of its value-type properties + */ + [Test] + public void LuaInterfaceValueProperty() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("itest={}"); + lua.DoString("function itest:get_intProp() return itest.int_prop; end"); + lua.DoString("function itest:set_intProp(val) itest.int_prop=val; end"); + lua.DoString("a=test:callInterface8(itest)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(3,a); + //Console.WriteLine("interface returned: "+a); + } + /* + * Tests passing a Lua table as an interface and + * accessing one of its reference type properties + */ + [Test] + public void LuaInterfaceReferenceProperty() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("itest={}"); + lua.DoString("function itest:get_refProp() return TestClass(itest.int_prop); end"); + lua.DoString("function itest:set_refProp(val) itest.int_prop=val.testval; end"); + lua.DoString("a=test:callInterface9(itest)"); + int a=(int)lua.GetNumber("a"); + Assertion.AssertEquals(3,a); + //Console.WriteLine("interface returned: "+a); + } + + + /* + * Tests making an object from a Lua table and calling the base + * class version of one of the methods the table overrides. + */ + [Test] + public void LuaTableBaseMethod() + { + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test={}"); + lua.DoString("function test:overridableMethod(x,y) return 2*self.base:overridableMethod(x,y); end"); + lua.DoString("make_object(test,'LuaInterface.Tests.TestClass')"); + lua.DoString("a=TestClass:callOverridable(test,2,3)"); + int a=(int)lua.GetNumber("a"); + lua.DoString("free_object(test)"); + Assertion.AssertEquals(10,a); + //Console.WriteLine("interface returned: "+a); + } + /* + * Tests getting an object's method by its signature + * (from object) + */ + [Test] + public void GetMethodBySignatureFromObj() + { + lua.DoString("load_assembly('mscorlib')"); + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("setMethod=get_method_bysig(test,'setVal','System.String')"); + lua.DoString("setMethod('test')"); + TestClass test=(TestClass)lua["test"]; + Assertion.AssertEquals("test",test.getStrVal()); + //Console.WriteLine("interface returned: "+test.getStrVal()); + } + /* + * Tests getting an object's method by its signature + * (from type) + */ + [Test] + public void GetMethodBySignatureFromType() + { + lua.DoString("load_assembly('mscorlib')"); + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test=TestClass()"); + lua.DoString("setMethod=get_method_bysig(TestClass,'setVal','System.String')"); + lua.DoString("setMethod(test,'test')"); + TestClass test=(TestClass)lua["test"]; + Assertion.AssertEquals("test",test.getStrVal()); + //Console.WriteLine("interface returned: "+test.getStrVal()); + } + /* + * Tests getting a type's method by its signature + */ + [Test] + public void GetStaticMethodBySignature() + { + lua.DoString("load_assembly('mscorlib')"); + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("make_method=get_method_bysig(TestClass,'makeFromString','System.String')"); + lua.DoString("test=make_method('test')"); + TestClass test=(TestClass)lua["test"]; + Assertion.AssertEquals("test",test.getStrVal()); + //Console.WriteLine("interface returned: "+test.getStrVal()); + } + /* + * Tests getting an object's constructor by its signature + */ + [Test] + public void GetConstructorBySignature() + { + lua.DoString("load_assembly('mscorlib')"); + lua.DoString("load_assembly('TestLua')"); + lua.DoString("TestClass=import_type('LuaInterface.Tests.TestClass')"); + lua.DoString("test_cons=get_constructor_bysig(TestClass,'System.String')"); + lua.DoString("test=test_cons('test')"); + TestClass test=(TestClass)lua["test"]; + Assertion.AssertEquals("test",test.getStrVal()); + //Console.WriteLine("interface returned: "+test.getStrVal()); + } +#endif + void TestOk(bool flag) + { + if(flag) + Console.WriteLine("Test Passed."); + else + Console.WriteLine("Test Failed!!!!"); + } + + /* + * Tests capturing an exception + */ + public void ThrowException() + { + Init(); + _Lua.DoString("luanet.load_assembly('mscorlib')"); + _Lua.DoString("luanet.load_assembly('TestLua')"); + _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); + _Lua.DoString("test=TestClass()"); + _Lua.DoString("err,errMsg=pcall(test.exceptionMethod,test)"); + bool err = (bool)_Lua["err"]; + Exception errMsg = (Exception)_Lua["errMsg"]; + TestOk(!err); + TestOk(errMsg.InnerException != null); + + if(errMsg.InnerException != null) + TestOk("exception test" == errMsg.InnerException.Message); + + //Console.WriteLine("interface returned: "+errMsg.ToString()); + Destroy(); + } + + /* + * Tests capturing an exception + */ + public void ThrowUncaughtException() + { + Init(); + _Lua.DoString("luanet.load_assembly('mscorlib')"); + _Lua.DoString("luanet.load_assembly('TestLua')"); + _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); + _Lua.DoString("test=TestClass()"); + + try + { + _Lua.DoString("test:exceptionMethod()"); + Console.WriteLine("Test failed!!! Should have thrown an exception all the way out of Lua"); + } + catch (Exception) + { + Console.WriteLine("Uncaught exception success"); + } + + Destroy(); + } + + /* + * Tests nullable fields + */ + public void TestNullable() + { + Init(); + _Lua.DoString("luanet.load_assembly('mscorlib')"); + _Lua.DoString("luanet.load_assembly('TestLua')"); + _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); + _Lua.DoString("test=TestClass()"); + _Lua.DoString("val=test.NullableBool"); + TestOk(((object)_Lua["val"]) == null); + _Lua.DoString("test.NullableBool = true"); + _Lua.DoString("val=test.NullableBool"); + TestOk(((bool)_Lua["val"]) == true); + Destroy(); + } + + /* + * Tests structure assignment + */ + public void TestStructs() + { + Init(); + _Lua.DoString("luanet.load_assembly('TestLua')"); + _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); + _Lua.DoString("test=TestClass()"); + _Lua.DoString("TestStruct=luanet.import_type('LuaInterface.Tests.TestStruct')"); + _Lua.DoString("struct=TestStruct(2)"); + _Lua.DoString("test.Struct = struct"); + _Lua.DoString("val=test.Struct.val"); + TestOk(((double)_Lua["val"]) == 2.0); + Destroy(); + } + + public void TestMethodOverloads() + { + Init(); + _Lua.DoString("luanet.load_assembly('mscorlib')"); + _Lua.DoString("luanet.load_assembly('TestLua')"); + _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); + _Lua.DoString("test=TestClass()"); + _Lua.DoString("test:MethodOverload()"); + _Lua.DoString("test:MethodOverload(test)"); + _Lua.DoString("test:MethodOverload(1,1,1)"); + _Lua.DoString("test:MethodOverload(2,2,i)\r\nprint(i)"); + } + + private void TestDispose() + { + GC.Collect(); + long startingMem = System.Diagnostics.Process.GetCurrentProcess().WorkingSet64; + + for(int i = 0; i < 10000; i++) + { + using (Lua lua = new Lua()) + { + _Calc(lua, i); + } + } + + Console.WriteLine("Was using " + startingMem / 1024 / 1024 + "MB, now using: " + System.Diagnostics.Process.GetCurrentProcess().WorkingSet64 / 1024 / 1024 + "MB"); + } + + private void _Calc(Lua lua, int i) + { + lua.DoString( + "sqrt = math.sqrt;" + + "sqr = function(x) return math.pow(x,2); end;" + + "log = math.log;" + + "log10 = math.log10;" + + "exp = math.exp;" + + "sin = math.sin;" + + "cos = math.cos;" + + "tan = math.tan;" + + "abs = math.abs;" + ); + + lua.DoString("function calcVP(a,b) return a+b end"); + LuaFunction lf = lua.GetFunction("calcVP"); + /*Object[] ret = */lf.Call(i, 20); + } + + private void TestThreading() + { + Init(); + var doWork = new DoWorkClass(); + _Lua.RegisterFunction("dowork", doWork, typeof(DoWorkClass).GetMethod("DoWork")); + + bool failureDetected = false; + int completed = 0; + int iterations = 500; + + for(int i = 0; i < iterations; i++) + { + ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object o) + { + try + { + _Lua.DoString("dowork()"); + } + catch + { + failureDetected = true; + } + + completed++; + })); + } + + while(completed < iterations && !failureDetected) + Thread.Sleep(50); + + if(failureDetected) + Console.WriteLine("==Problem with threading!=="); + } + + private void TestPrivateMethod() + { + Init(); + _Lua.DoString("luanet.load_assembly('mscorlib')"); + _Lua.DoString("luanet.load_assembly('TestLua')"); + _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); + _Lua.DoString("test=TestClass()"); + + try + { + _Lua.DoString("test:_PrivateMethod()"); + } + catch + { + Console.WriteLine("Test Passed"); + return; + } + + Console.WriteLine("Test Failed"); + } + + /* + * Tests functions + */ + public void TestFunctions() + { + Init(); + _Lua.DoString("luanet.load_assembly('mscorlib')"); + _Lua.DoString("luanet.load_assembly('TestLua')"); + _Lua.RegisterFunction("p", null, typeof(System.Console).GetMethod("WriteLine", new Type[] { typeof(String) })); + + /// Lua command that works (prints to console) + _Lua.DoString("p('Foo')"); + + /// Yet this works... + _Lua.DoString("string.gsub('some string', '(%w+)', function(s) p(s) end)"); + + /// This fails if you don't fix Lua5.1 lstrlib.c/add_value to treat LUA_TUSERDATA the same as LUA_FUNCTION + _Lua.DoString("string.gsub('some string', '(%w+)', p)"); + Destroy(); + } + + /* + * Tests making an object from a Lua table and calling one of + * methods the table overrides. + */ + public void LuaTableOverridedMethod() + { + Init(); + _Lua.DoString("luanet.load_assembly('TestLua')"); + _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); + _Lua.DoString("test={}"); + _Lua.DoString("function test:overridableMethod(x,y) return x*y; end"); + _Lua.DoString("luanet.make_object(test,'LuaInterface.Tests.TestClass')"); + _Lua.DoString("a=TestClass.callOverridable(test,2,3)"); + int a = (int)_Lua.GetNumber("a"); + _Lua.DoString("luanet.free_object(test)"); + TestOk(6 == a); + //Console.WriteLine("interface returned: "+a); + } + + /* + * Tests making an object from a Lua table and calling a method + * the table does not override. + */ + public void LuaTableInheritedMethod() + { + Init(); + _Lua.DoString("luanet.load_assembly('TestLua')"); + _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); + _Lua.DoString("test={}"); + _Lua.DoString("function test:overridableMethod(x,y) return x*y; end"); + _Lua.DoString("luanet.make_object(test,'LuaInterface.Tests.TestClass')"); + _Lua.DoString("test:setVal(3)"); + _Lua.DoString("a=test.testval"); + int a = (int)_Lua.GetNumber("a"); + _Lua.DoString("luanet.free_object(test)"); + TestOk(3 == a); + //Console.WriteLine("interface returned: "+a); + } + + /// + /// Basic multiply method which expects 2 floats + /// + /// + /// + /// + private float _TestException(float val, float val2) + { + return val * val2; + } + + public void TestEventException() + { + Init(); + + //Register a C# function + MethodInfo testException = this.GetType().GetMethod("_TestException", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance, null, new Type[] { typeof(float), typeof(float) }, null); + _Lua.RegisterFunction("Multiply", this, testException); + + //create the lua event handler code for the entity + //includes the bad code! + _Lua.DoString("function OnClick(sender, eventArgs)\r\n" + + "--Multiply expects 2 floats, but instead receives 2 strings\r\n" + + "Multiply(asd, we)\r\n" + + "end"); + + //create the lua event handler code for the entity + //good code + //lua.DoString("function OnClick(sender, eventArgs)\r\n" + + // "--Multiply expects 2 floats\r\n" + + // "Multiply(2, 50)\r\n" + + // "end"); + + //Create the event handler script + _Lua.DoString("function SubscribeEntity(e)\r\ne.Clicked:Add(OnClick)\r\nend"); + + //Create the entity object + var entity = new Entity(); + + //Register the entity object with the event handler inside lua + LuaFunction lf = _Lua.GetFunction("SubscribeEntity"); + lf.Call(new object[1] { entity }); + + try + { + //Cause the event to be fired + entity.Click(); + + Console.WriteLine("Test failed!!! Should have thrown an exception all the way out of Lua"); + } + catch (LuaException) + { + Console.WriteLine("Event exception success"); + } + } + + public void TestExceptionWithChunkOverload() + { + Init(); + + try + { + _Lua.DoString("thiswillthrowanerror", "MyChunk"); + } + catch(Exception e) + { + if (e.Message.StartsWith("[string \"MyChunk\"]")) + Console.WriteLine("Chunk overload passed"); + else + Console.WriteLine("Chunk overload failed"); + } + } + + public void TestGenerics() + { + Init(); + + //Im not sure support for generic classes is possible to implement, see: http://msdn.microsoft.com/en-us/library/system.reflection.methodinfo.containsgenericparameters.aspx + //specifically the line that says: "If the ContainsGenericParameters property returns true, the method cannot be invoked" + + //TestClassGeneric genericClass = new TestClassGeneric(); + + //_Lua.RegisterFunction("genericMethod", genericClass, typeof(TestClassGeneric<>).GetMethod("GenericMethod")); + //_Lua.RegisterFunction("regularMethod", genericClass, typeof(TestClassGeneric<>).GetMethod("RegularMethod")); + + //try + //{ + // _Lua.DoString("genericMethod('thestring')"); + //} + //catch { } + + //try + //{ + // _Lua.DoString("regularMethod()"); + //} + //catch { } + + //if (genericClass.GenericMethodSuccess && genericClass.RegularMethodSuccess && genericClass.Validate("thestring")) + // Console.WriteLine("Generic class passed"); + //else + // Console.WriteLine("Generic class failed"); + + bool passed = true; + TestClassWithGenericMethod classWithGenericMethod = new TestClassWithGenericMethod(); + + _Lua.RegisterFunction("genericMethod2", classWithGenericMethod, typeof(TestClassWithGenericMethod).GetMethod("GenericMethod")); + + try + { + _Lua.DoString("genericMethod2(100)"); + } + catch + { + + } + + if(!classWithGenericMethod.GenericMethodSuccess || !classWithGenericMethod.Validate(100)) //note the gotcha: numbers are all being passed to generic methods as doubles + passed = false; + + try + { + _Lua.DoString("luanet.load_assembly('TestLua')"); + _Lua.DoString("TestClass=luanet.import_type('LuaInterface.Tests.TestClass')"); + _Lua.DoString("test=TestClass(56)"); + _Lua.DoString("genericMethod2(test)"); + } + catch + { + + } + + if(!classWithGenericMethod.GenericMethodSuccess || (classWithGenericMethod.PassedValue as TestClass).val != 56) + passed = false; + + if(passed) + Console.WriteLine("Class with generic method passed"); + else + Console.WriteLine("Class with generic method failed"); + } + + public static int func(int x, int y) + { + return x + y; + } + public int funcInstance(int x, int y) + { + return x + y; + } + + public void RegisterFunctionStressTest() + { + LuaFunction fc = null; + const int Count = 200; // it seems to work with 41 + + Init(); + var t = new MyClass(); + + for(int i = 1; i < Count - 1; ++i) + fc = _Lua.RegisterFunction("func" + i, t, typeof(MyClass).GetMethod("Func1")); + + fc = _Lua.RegisterFunction("func" + (Count - 1), t, typeof(MyClass).GetMethod("Func1")); + _Lua.DoString("print(func1())"); + } + + /* + * Sample test script that shows some of the capabilities of + * LuaInterface + */ + public static void Main() + { + Console.WriteLine("Starting interpreter..."); + var l = new Lua(); + + // Pause so we can connect with the debugger + // Thread.Sleep(30000); + Console.WriteLine("Reading test.lua file..."); + l.DoFile("test.lua"); + double width = l.GetNumber("width"); + double height = l.GetNumber("height"); + string message = l.GetString("message"); + double color_r = l.GetNumber("color.r"); + double color_g = l.GetNumber("color.g"); + double color_b = l.GetNumber("color.b"); + Console.WriteLine("Printing values of global variables width, height and message..."); + Console.WriteLine("width: " + width); + Console.WriteLine("height: " + height); + Console.WriteLine("message: " + message); + Console.WriteLine("Printing values of the 'color' table's fields..."); + Console.WriteLine("color.r: " + color_r); + Console.WriteLine("color.g: " + color_g); + Console.WriteLine("color.b: " + color_b); + width = 150; + Console.WriteLine("Changing width's value and calling Lua function print to show it..."); + l["width"] = width; + l.GetFunction("print").Call(width); + message = "LuaNet Interface Test"; + Console.WriteLine("Changing message's value and calling Lua function print to show it..."); + l["message"] = message; + l.GetFunction("print").Call(message); + color_r = 30; + color_g = 10; + color_b = 200; + Console.WriteLine("Changing color's fields' values and calling Lua function print to show it..."); + l["color.r"] = color_r; + l["color.g"] = color_g; + l["color.b"] = color_b; + l.DoString("print(color.r,color.g,color.b)"); + Console.WriteLine("Printing values of the tree table's fields..."); + double leaf1 = l.GetNumber("tree.branch1.leaf1"); + string leaf2 = l.GetString("tree.branch1.leaf2"); + string leaf3 = l.GetString("tree.leaf3"); + Console.WriteLine("leaf1: " + leaf1); + Console.WriteLine("leaf2: " + leaf2); + Console.WriteLine("leaf3: " + leaf3); + leaf1 = 30; leaf2 = "new leaf2"; + Console.WriteLine("Changing tree's fields' values and calling Lua function print to show it..."); + l["tree.branch1.leaf1"] = leaf1; l["tree.branch1.leaf2"] = leaf2; + l.DoString("print(tree.branch1.leaf1,tree.branch1.leaf2)"); + Console.WriteLine("Returning values from Lua with 'return'..."); + object[] vals = l.DoString("return 2,3"); + Console.WriteLine("Returned: " + vals[0] + " and " + vals[1]); + Console.WriteLine("Calling a Lua function that returns multiple values..."); + object[] vals1 = l.GetFunction("func").Call(2, 3); + Console.WriteLine("Returned: " + vals1[0] + " and " + vals1[1]); + Console.WriteLine("Creating a table and filling it from C#..."); + l.NewTable("tab"); + l.NewTable("tab.tab"); + l["tab.a"] = "a!"; + l["tab.b"] = 5.5; + l["tab.tab.c"] = 6.5; + l.DoString("print(tab.a,tab.b,tab.tab.c)"); + Console.WriteLine("Setting a table as another table's field..."); + l["tab.a"] = l["tab.tab"]; + l.DoString("print(tab.a.c)"); + Console.WriteLine("Registering a C# static method and calling it from Lua..."); + + // Pause so we can connect with the debugger + // Thread.Sleep(30000); + l.RegisterFunction("func1", null, typeof(TestLuaInterface).GetMethod("func")); + vals1 = l.GetFunction("func1").Call(2, 3); + Console.WriteLine("Returned: " + vals1[0]); + TestLuaInterface obj = new TestLuaInterface(); + Console.WriteLine("Registering a C# instance method and calling it from Lua..."); + l.RegisterFunction("func2", obj, typeof(TestLuaInterface).GetMethod("funcInstance")); + vals1 = l.GetFunction("func2").Call(2, 3); + Console.WriteLine("Returned: " + vals1[0]); + + Console.WriteLine("Testing throwing an exception..."); + obj.ThrowUncaughtException(); + + Console.WriteLine("Testing catching an exception..."); + obj.ThrowException(); + + Console.WriteLine("Testing inheriting a method from Lua..."); + obj.LuaTableInheritedMethod(); + + Console.WriteLine("Testing overriding a C# method with Lua..."); + obj.LuaTableOverridedMethod(); + + Console.WriteLine("Stress test RegisterFunction (based on a reported bug).."); + obj.RegisterFunctionStressTest(); + + Console.WriteLine("Test structures..."); + obj.TestStructs(); + + Console.WriteLine("Test Nullable types..."); + obj.TestNullable(); + + Console.WriteLine("Test functions..."); + obj.TestFunctions(); + + Console.WriteLine("Test method overloads..."); + obj.TestMethodOverloads(); + + Console.WriteLine("Test accessing private method..."); + obj.TestPrivateMethod(); + + Console.WriteLine("Test event exceptions..."); + obj.TestEventException(); + + Console.WriteLine("Test chunk overload exception..."); + obj.TestExceptionWithChunkOverload(); + + Console.WriteLine("Test generics..."); + obj.TestGenerics(); + + Console.WriteLine("Test threading..."); + obj.TestThreading(); + + Console.WriteLine("Test memory leakage..."); + obj.TestDispose(); + + Console.WriteLine("Press enter to exit."); + Console.ReadLine(); + } + } } \ No newline at end of file diff --git a/Test/TestLuaInterface/TestLuaInterface.csproj b/Test/TestLuaInterface/TestLuaInterface.csproj index 28c92cd6cc38ee26415d177eab3f0f50d7a488dd..be4d23fad8d54a8bfed81967429048005c0bfdde 100644 --- a/Test/TestLuaInterface/TestLuaInterface.csproj +++ b/Test/TestLuaInterface/TestLuaInterface.csproj @@ -1,105 +1,105 @@ - - - - Debug - x86 - 9.0.30729 - 2.0 - {AEAB974E-4F69-4840-A2C4-7BC55F7C7C3E} - Exe - Properties - LuaInterface.Tests - TestLua - 2.x - - - true - full - false - ..\..\Run\Debug - DEBUG - prompt - 4 - x86 - AllRules.ruleset - - - none - true - ..\..\Run\Release - RELEASE - prompt - 4 - x86 - AllRules.ruleset - - - true - full - false - ..\..\Run\Debug_x64 - DEBUG - prompt - 4 - x64 - AllRules.ruleset - - - none - true - ..\..\Run\Release_x64 - RELEASE - prompt - 4 - x64 - AllRules.ruleset - - - - - - - - - - - - - - - {F55CABBB-4108-4A39-94E1-581FD46DC021} - LuaInterface - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - - - + + + + Debug + x86 + 9.0.30729 + 2.0 + {AEAB974E-4F69-4840-A2C4-7BC55F7C7C3E} + Exe + Properties + LuaInterface.Tests + TestLua + 2.x + + + true + full + false + ..\..\Run\Debug + DEBUG + prompt + 4 + x86 + AllRules.ruleset + + + none + true + ..\..\Run\Release + RELEASE + prompt + 4 + x86 + AllRules.ruleset + + + true + full + false + ..\..\Run\Debug_x64 + DEBUG + prompt + 4 + x64 + AllRules.ruleset + + + none + true + ..\..\Run\Release_x64 + RELEASE + prompt + 4 + x64 + AllRules.ruleset + + + + + + + + + + + + + + + {F55CABBB-4108-4A39-94E1-581FD46DC021} + LuaInterface + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + + + \ No newline at end of file diff --git a/Test/TestLuaInterface/TestLuaInterface.make b/Test/TestLuaInterface/TestLuaInterface.make new file mode 100644 index 0000000000000000000000000000000000000000..b565cca0dc5ac9728157085926efbc0fc2d8b68b --- /dev/null +++ b/Test/TestLuaInterface/TestLuaInterface.make @@ -0,0 +1,128 @@ + + +# Warning: This is an automatically generated file, do not edit! + +if ENABLE_DEBUG_X86 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize- -debug "-define:DEBUG" +ASSEMBLY = ../../Run/Debug/TestLua.exe +ASSEMBLY_MDB = $(ASSEMBLY).mdb +COMPILE_TARGET = exe +PROJECT_REFERENCES = \ + ../../Run/Debug/LuaInterface.dll +BUILD_DIR = ../../Run/Debug + +TESTLUA_EXE_MDB_SOURCE=../../Run/Debug/TestLua.exe.mdb +TESTLUA_EXE_MDB=$(BUILD_DIR)/TestLua.exe.mdb +LUAINTERFACE_DLL_SOURCE=../../Run/Debug/LuaInterface.dll +KOPILUA_DLL_SOURCE=../../Run/Debug/KopiLua.dll + +endif + +if ENABLE_RELEASE_X86 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize+ "-define:RELEASE" +ASSEMBLY = ../../Run/Release/TestLua.exe +ASSEMBLY_MDB = +COMPILE_TARGET = exe +PROJECT_REFERENCES = \ + ../../Run/Release/LuaInterface.dll +BUILD_DIR = ../../Run/Release + +TESTLUA_EXE_MDB= +LUAINTERFACE_DLL_SOURCE=../../Run/Release/LuaInterface.dll +KOPILUA_DLL_SOURCE=../../Run/Release/KopiLua.dll + +endif + +if ENABLE_DEBUG_X64 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize- -debug "-define:DEBUG" +ASSEMBLY = ../../Run/Debug_x64/TestLua.exe +ASSEMBLY_MDB = $(ASSEMBLY).mdb +COMPILE_TARGET = exe +PROJECT_REFERENCES = \ + ../../Run/Debug_x64/LuaInterface.dll +BUILD_DIR = ../../Run/Debug_x64 + +TESTLUA_EXE_MDB_SOURCE=../../Run/Debug_x64/TestLua.exe.mdb +TESTLUA_EXE_MDB=$(BUILD_DIR)/TestLua.exe.mdb +LUAINTERFACE_DLL_SOURCE=../../Run/Debug_x64/LuaInterface.dll +KOPILUA_DLL_SOURCE=../../Run/Debug_x64/KopiLua.dll + +endif + +if ENABLE_RELEASE_X64 +ASSEMBLY_COMPILER_COMMAND = dmcs +ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize+ "-define:RELEASE" +ASSEMBLY = ../../Run/Release_x64/TestLua.exe +ASSEMBLY_MDB = +COMPILE_TARGET = exe +PROJECT_REFERENCES = \ + ../../Run/Release_x64/LuaInterface.dll +BUILD_DIR = ../../Run/Release_x64 + +TESTLUA_EXE_MDB= +LUAINTERFACE_DLL_SOURCE=../../Run/Release_x64/LuaInterface.dll +KOPILUA_DLL_SOURCE=../../Run/Release_x64/KopiLua.dll + +endif + +AL=al +SATELLITE_ASSEMBLY_NAME=$(notdir $(basename $(ASSEMBLY))).resources.dll + +PROGRAMFILES = \ + $(TESTLUA_EXE_MDB) \ + $(LUAINTERFACE_DLL) \ + $(KOPILUA_DLL) + +BINARIES = \ + $(TESTLUAINTERFACE) + + +RESGEN=resgen2 + +all: $(ASSEMBLY) $(PROGRAMFILES) $(BINARIES) + +FILES = \ + Entity.cs \ + TestLua.cs \ + TestLuaInterface.cs \ + Properties/AssemblyInfo.cs + +DATA_FILES = + +RESOURCES = + +EXTRAS = \ + Properties \ + Readme.txt \ + testluainterface.in + +REFERENCES = \ + System \ + System.Data \ + System.Xml + +DLL_REFERENCES = + +CLEANFILES = $(PROGRAMFILES) $(BINARIES) + +include $(top_srcdir)/Makefile.include + +LUAINTERFACE_DLL = $(BUILD_DIR)/LuaInterface.dll +KOPILUA_DLL = $(BUILD_DIR)/KopiLua.dll +TESTLUAINTERFACE = $(BUILD_DIR)/testluainterface + +$(eval $(call emit-deploy-wrapper,TESTLUAINTERFACE,testluainterface,x)) + + +$(eval $(call emit_resgen_targets)) +$(build_xamlg_list): %.xaml.g.cs: %.xaml + xamlg '$<' + +$(ASSEMBLY_MDB): $(ASSEMBLY) + +$(ASSEMBLY): $(build_sources) $(build_resources) $(build_datafiles) $(DLL_REFERENCES) $(PROJECT_REFERENCES) $(build_xamlg_list) $(build_satellite_assembly_list) + mkdir -p $(shell dirname $(ASSEMBLY)) + $(ASSEMBLY_COMPILER_COMMAND) $(ASSEMBLY_COMPILER_FLAGS) -out:$(ASSEMBLY) -target:$(COMPILE_TARGET) $(build_sources_embed) $(build_resources_embed) $(build_references_ref) diff --git a/Test/TestLuaInterface/testluainterface.in b/Test/TestLuaInterface/testluainterface.in new file mode 100644 index 0000000000000000000000000000000000000000..5b8286c04663513ab6763af0b292707231bc545f --- /dev/null +++ b/Test/TestLuaInterface/testluainterface.in @@ -0,0 +1,3 @@ +#!/bin/sh + +exec mono "@expanded_libdir@/@PACKAGE@/TestLua.exe" "$@" diff --git a/autogen.sh b/autogen.sh new file mode 100644 index 0000000000000000000000000000000000000000..8d847f870777566f43f740a958e847eb83324a64 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,83 @@ +#! /bin/sh + +PROJECT=LuaInterface +FILE= +CONFIGURE=configure.ac + +: ${AUTOCONF=autoconf} +: ${AUTOHEADER=autoheader} +: ${AUTOMAKE=automake} +: ${LIBTOOLIZE=libtoolize} +: ${ACLOCAL=aclocal} +: ${LIBTOOL=libtool} + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +ORIGDIR=`pwd` +cd $srcdir +TEST_TYPE=-f +aclocalinclude="-I . $ACLOCAL_FLAGS" + +DIE=0 + +($AUTOCONF --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have autoconf installed to compile $PROJECT." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have automake installed to compile $PROJECT." + echo "Get ftp://sourceware.cygnus.com/pub/automake/automake-1.4.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 +} + +(grep "^AM_PROG_LIBTOOL" $CONFIGURE >/dev/null) && { + ($LIBTOOL --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`libtool' installed to compile $PROJECT." + echo "Get ftp://ftp.gnu.org/pub/gnu/libtool-1.2d.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 + } +} + +if test "$DIE" -eq 1; then + exit 1 +fi + +#test $TEST_TYPE $FILE || { +# echo "You must run this script in the top-level $PROJECT directory" +# exit 1 +#} + +if test -z "$*"; then + echo "I am going to run ./configure with no arguments - if you wish " + echo "to pass any to it, please specify them on the $0 command line." +fi + +case $CC in +*xlc | *xlc\ * | *lcc | *lcc\ *) am_opt=--include-deps;; +esac + +(grep "^AM_PROG_LIBTOOL" $CONFIGURE >/dev/null) && { + echo "Running $LIBTOOLIZE ..." + $LIBTOOLIZE --force --copy +} + +echo "Running $ACLOCAL $aclocalinclude ..." +$ACLOCAL $aclocalinclude + +echo "Running $AUTOMAKE --gnu $am_opt ..." +$AUTOMAKE --add-missing --gnu $am_opt + +echo "Running $AUTOCONF ..." +$AUTOCONF + +echo Running $srcdir/configure $conf_flags "$@" ... +$srcdir/configure --enable-maintainer-mode $conf_flags "$@" \ diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000000000000000000000000000000000000..f3bfe9a8dc01f96636acf72c56871093616a10e0 --- /dev/null +++ b/configure.ac @@ -0,0 +1,83 @@ +dnl Warning: This is an automatically generated file, do not edit! +dnl Process this file with autoconf to produce a configure script. +AC_PREREQ([2.54]) +AC_INIT([LuaInterface], [2.x]) +AM_INIT_AUTOMAKE([foreign]) +AM_MAINTAINER_MODE + +dnl pkg-config +AC_PATH_PROG(PKG_CONFIG, pkg-config, no) +if test "x$PKG_CONFIG" = "xno"; then + AC_MSG_ERROR([You need to install pkg-config]) +fi + +SHAMROCK_EXPAND_LIBDIR +SHAMROCK_EXPAND_BINDIR +SHAMROCK_EXPAND_DATADIR + +AC_PROG_INSTALL + +AC_PATH_PROG(DMCS, dmcs, no) +if test "x$DMCS" = "xno"; then + AC_MSG_ERROR([dmcs Not found]) +fi + + +AC_ARG_ENABLE(debug_x86, + AC_HELP_STRING([--enable-debug_x86], + [Use 'DEBUG_X86' Configuration [default=NO]]), + enable_debug_x86=yes, enable_debug_x86=no) +AM_CONDITIONAL(ENABLE_DEBUG_X86, test x$enable_debug_x86 = xyes) +if test "x$enable_debug_x86" = "xyes" ; then + CONFIG_REQUESTED="yes" +fi +AC_ARG_ENABLE(release_x86, + AC_HELP_STRING([--enable-release_x86], + [Use 'RELEASE_X86' Configuration [default=YES]]), + enable_release_x86=yes, enable_release_x86=no) +AM_CONDITIONAL(ENABLE_RELEASE_X86, test x$enable_release_x86 = xyes) +if test "x$enable_release_x86" = "xyes" ; then + CONFIG_REQUESTED="yes" +fi +AC_ARG_ENABLE(debug_x64, + AC_HELP_STRING([--enable-debug_x64], + [Use 'DEBUG_X64' Configuration [default=NO]]), + enable_debug_x64=yes, enable_debug_x64=no) +AM_CONDITIONAL(ENABLE_DEBUG_X64, test x$enable_debug_x64 = xyes) +if test "x$enable_debug_x64" = "xyes" ; then + CONFIG_REQUESTED="yes" +fi +AC_ARG_ENABLE(release_x64, + AC_HELP_STRING([--enable-release_x64], + [Use 'RELEASE_X64' Configuration [default=NO]]), + enable_release_x64=yes, enable_release_x64=no) +AM_CONDITIONAL(ENABLE_RELEASE_X64, test x$enable_release_x64 = xyes) +if test "x$enable_release_x64" = "xyes" ; then + CONFIG_REQUESTED="yes" +fi +if test -z "$CONFIG_REQUESTED" ; then + AM_CONDITIONAL(ENABLE_RELEASE_X86, true) + enable_release_x86=yes +fi + + +dnl package checks, common for all configs + +dnl package checks, per config + + +AC_CONFIG_FILES([ +Core/KopiLua/kopilua.pc +Core/KopiLua/Makefile +Core/LuaInterface/luainterface.pc +Core/LuaInterface/Makefile +Core/Makefile +Test/TestLuaInterface/testluainterface +Test/TestLuaInterface/Makefile +Applications/LuaRunner/luarunner +Applications/LuaRunner/Makefile +Makefile + +]) + +AC_OUTPUT diff --git a/expansions.m4 b/expansions.m4 new file mode 100644 index 0000000000000000000000000000000000000000..ba623565e4c3cdcda2020017a18caf92b19ba4a5 --- /dev/null +++ b/expansions.m4 @@ -0,0 +1,50 @@ +AC_DEFUN([SHAMROCK_EXPAND_LIBDIR], +[ + expanded_libdir=`( + case $prefix in + NONE) prefix=$ac_default_prefix ;; + *) ;; + esac + case $exec_prefix in + NONE) exec_prefix=$prefix ;; + *) ;; + esac + eval echo $libdir + )` + AC_SUBST(expanded_libdir) +]) + +AC_DEFUN([SHAMROCK_EXPAND_BINDIR], +[ + expanded_bindir=`( + case $prefix in + NONE) prefix=$ac_default_prefix ;; + *) ;; + esac + case $exec_prefix in + NONE) exec_prefix=$prefix ;; + *) ;; + esac + eval echo $bindir + )` + AC_SUBST(expanded_bindir) +]) + +AC_DEFUN([SHAMROCK_EXPAND_DATADIR], +[ + case $prefix in + NONE) prefix=$ac_default_prefix ;; + *) ;; + esac + + case $exec_prefix in + NONE) exec_prefix=$prefix ;; + *) ;; + esac + + expanded_datadir=`(eval echo $datadir)` + expanded_datadir=`(eval echo $expanded_datadir)` + + AC_SUBST(expanded_datadir) +]) +