├── .gitignore ├── LICENSE ├── LuaTest ├── LuaTest.csproj ├── Program.cs └── Properties │ └── AssemblyInfo.cs ├── LuaUnits ├── LuaObjectTests.cs ├── LuaTableTests.cs ├── LuaUnits.csproj ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── NetLua.sln ├── NetLua ├── Ast │ └── Ast.cs ├── Libraries │ ├── IoLibrary.cs │ └── MathLibrary.cs ├── Lua.cs ├── LuaCompiler.cs ├── LuaContext.cs ├── LuaEvents.cs ├── LuaGrammar.cs ├── LuaObject.cs ├── NetLua.csproj ├── NetLua.nuspec ├── Parser.cs ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── README.md └── packages ├── Irony.0.9.1-net40 ├── Irony.0.9.1-net40.nupkg ├── Irony.0.9.1-net40.nuspec ├── lib │ └── net40 │ │ ├── Irony.dll │ │ └── Irony.xml └── tools │ ├── FastColoredTextBox.dll │ ├── Irony.GrammarExplorer.exe │ ├── Irony.GrammarExplorer.exe.config │ ├── Irony.Interpreter.dll │ └── Irony.dll ├── NUnit.2.6.3 ├── NUnit.2.6.3.nupkg ├── NUnit.2.6.3.nuspec ├── lib │ ├── nunit.framework.dll │ └── nunit.framework.xml └── license.txt └── repositories.config /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 20 | !packages/*/build/ 21 | 22 | # MSTest test Results 23 | [Tt]est[Rr]esult*/ 24 | [Bb]uild[Ll]og.* 25 | 26 | #NUNIT 27 | *.VisualState.xml 28 | TestResult.xml 29 | 30 | *_i.c 31 | *_p.c 32 | *_i.h 33 | *.ilk 34 | *.meta 35 | *.obj 36 | *.pch 37 | *.pdb 38 | *.pgc 39 | *.pgd 40 | *.rsp 41 | *.sbr 42 | *.tlb 43 | *.tli 44 | *.tlh 45 | *.tmp 46 | *.tmp_proj 47 | *.log 48 | *.vspscc 49 | *.vssscc 50 | .builds 51 | *.pidb 52 | *.svclog 53 | *.scc 54 | 55 | # Chutzpah Test files 56 | _Chutzpah* 57 | 58 | # Visual C++ cache files 59 | ipch/ 60 | *.aps 61 | *.ncb 62 | *.opensdf 63 | *.sdf 64 | *.cachefile 65 | 66 | # Visual Studio profiler 67 | *.psess 68 | *.vsp 69 | *.vspx 70 | 71 | # TFS 2012 Local Workspace 72 | $tf/ 73 | 74 | # Guidance Automation Toolkit 75 | *.gpState 76 | 77 | # ReSharper is a .NET coding add-in 78 | _ReSharper*/ 79 | *.[Rr]e[Ss]harper 80 | *.DotSettings.user 81 | 82 | # JustCode is a .NET coding addin-in 83 | .JustCode 84 | 85 | # TeamCity is a build add-in 86 | _TeamCity* 87 | 88 | # DotCover is a Code Coverage Tool 89 | *.dotCover 90 | 91 | # NCrunch 92 | *.ncrunch* 93 | _NCrunch_* 94 | .*crunch*.local.xml 95 | 96 | # MightyMoose 97 | *.mm.* 98 | AutoTest.Net/ 99 | 100 | # Installshield output folder 101 | [Ee]xpress/ 102 | 103 | # DocProject is a documentation generator add-in 104 | DocProject/buildhelp/ 105 | DocProject/Help/*.HxT 106 | DocProject/Help/*.HxC 107 | DocProject/Help/*.hhc 108 | DocProject/Help/*.hhk 109 | DocProject/Help/*.hhp 110 | DocProject/Help/Html2 111 | DocProject/Help/html 112 | 113 | # Click-Once directory 114 | publish/ 115 | 116 | # Publish Web Output 117 | *.Publish.xml 118 | *.azurePubxml 119 | 120 | # NuGet Packages Directory 121 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 122 | #packages/ 123 | ## TODO: If the tool you use requires repositories.config, also uncomment the next line 124 | #!packages/repositories.config 125 | 126 | # Windows Azure Build Output 127 | csx/ 128 | *.build.csdef 129 | 130 | # Windows Store app package directory 131 | AppPackages/ 132 | 133 | # Others 134 | sql/ 135 | *.Cache 136 | ClientBin/ 137 | [Ss]tyle[Cc]op.* 138 | ~$* 139 | *~ 140 | *.dbmdl 141 | *.dbproj.schemaview 142 | *.[Pp]ublish.xml 143 | *.pfx 144 | *.publishsettings 145 | 146 | # RIA/Silverlight projects 147 | Generated_Code/ 148 | 149 | # Backup & report files from converting an old project file to a newer 150 | # Visual Studio version. Backup files are not needed, because we have git ;-) 151 | _UpgradeReport_Files/ 152 | Backup*/ 153 | UpgradeLog*.XML 154 | UpgradeLog*.htm 155 | 156 | # SQL Server files 157 | App_Data/*.mdf 158 | App_Data/*.ldf 159 | 160 | # Business Intelligence projects 161 | *.rdl.data 162 | *.bim.layout 163 | *.bim_*.settings 164 | 165 | # Microsoft Fakes 166 | FakesAssemblies/ 167 | 168 | # ========================= 169 | # Windows detritus 170 | # ========================= 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Francesco Bertolaccini and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /LuaTest/LuaTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {265397E0-58C3-444B-9C26-3FA585AADB10} 9 | Exe 10 | Properties 11 | LuaTest 12 | LuaTest 13 | v4.0 14 | Client 15 | 512 16 | 17 | 18 | x86 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | x86 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | {6B52EB11-E6A7-4771-94B0-7F87EA28211D} 52 | NetLua 53 | 54 | 55 | 56 | 63 | -------------------------------------------------------------------------------- /LuaTest/Program.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * See LICENSE file 3 | */ 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | 10 | using NetLua; 11 | 12 | namespace LuaTest 13 | { 14 | class Program 15 | { 16 | static LuaArguments print(LuaArguments args) 17 | { 18 | Console.WriteLine(String.Join("\t", Array.ConvertAll(args, x=>x.ToString()))); 19 | return Lua.Return(); 20 | } 21 | 22 | static LuaArguments io_write(LuaArguments args) 23 | { 24 | Console.Write(args[0].ToString()); 25 | return Lua.Return(); 26 | } 27 | 28 | static LuaArguments read(LuaArguments args) 29 | { 30 | return Lua.Return(Console.ReadLine()); 31 | } 32 | 33 | static void Main(string[] args) 34 | { 35 | Lua lua = new Lua(); 36 | lua.DynamicContext.print = (LuaFunction)print; 37 | lua.DynamicContext.read = (LuaFunction)read; 38 | 39 | MathLibrary.AddMathLibrary(lua.Context); 40 | IoLibrary.AddIoLibrary(lua.Context); 41 | 42 | lua.DoFile("life.lua"); 43 | 44 | while (true) 45 | { 46 | lua.DoString(Console.ReadLine()); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /LuaTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("LuaTest")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("LuaTest")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("6040c764-1a4b-476b-93e4-7ff4b4204b2a")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /LuaUnits/LuaObjectTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * See LICENSE file 3 | */ 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using NetLua; 10 | using NUnit.Framework; 11 | 12 | namespace LuaUnits 13 | { 14 | [TestFixture] 15 | public static class LuaObjectTests 16 | { 17 | [Test] 18 | public static void ObjectEqualityNumber() 19 | { 20 | LuaObject obj1 = 10; 21 | LuaObject obj2 = 10; 22 | 23 | Assert.IsTrue(obj1.Equals(obj2)); 24 | Assert.IsTrue(obj2.Equals(obj1)); 25 | } 26 | 27 | [Test] 28 | public static void ObjectEqualityString() 29 | { 30 | LuaObject obj1 = "test"; 31 | LuaObject obj2 = "test"; 32 | 33 | Assert.IsTrue(obj1.Equals(obj2)); 34 | Assert.IsTrue(obj2.Equals(obj1)); 35 | } 36 | 37 | [Test] 38 | public static void ObjectEqualityCoercion() 39 | { 40 | LuaObject obj1 = "10"; 41 | LuaObject obj2 = 10; 42 | 43 | Assert.IsFalse(obj1.Equals(obj2)); 44 | Assert.IsFalse(obj2.Equals(obj1)); 45 | } 46 | 47 | [Test] 48 | public static void GeneralEquality() 49 | { 50 | LuaObject a = "test"; 51 | 52 | Assert.IsTrue(a == "test"); 53 | } 54 | 55 | [Test] 56 | public static void LogicalOperators() 57 | { 58 | LuaObject a = "test"; 59 | LuaObject b = LuaObject.Nil; 60 | 61 | Assert.IsTrue((a | b) == a); 62 | Assert.IsTrue((a | null) == a); 63 | 64 | Assert.IsTrue((a & b) == b); 65 | Assert.IsTrue((a & null) == LuaObject.Nil); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /LuaUnits/LuaTableTests.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * See LICENSE file 3 | */ 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using NetLua; 10 | using NUnit.Framework; 11 | 12 | namespace LuaUnits 13 | { 14 | [TestFixture] 15 | public static class LuaTableTests 16 | { 17 | [Test] 18 | public static void FirstTableTest() 19 | { 20 | NetLua.Lua lua = new NetLua.Lua(); 21 | lua.DoString( 22 | @" a={} 23 | k = 'x' 24 | a[k] = 10 25 | a[20] = 'great'"); 26 | LuaObject obj1 = 10; 27 | LuaObject obj2 = lua.DoString("return a['x']")[0]; 28 | Assert.IsTrue(obj1.Equals(obj2)); 29 | 30 | lua.DoString("k = 20"); 31 | obj1 = "great"; 32 | obj2 = lua.DoString("return a[k]")[0]; 33 | Assert.IsTrue(obj1.Equals(obj2)); 34 | } 35 | 36 | [Test] 37 | public static void SecondTableTest() 38 | { 39 | NetLua.Lua lua = new NetLua.Lua(); 40 | lua.DoString( 41 | @" a={} 42 | a['x'] = 10 43 | b = a"); 44 | LuaObject obj1 = 10; 45 | LuaObject obj2 = lua.DoString("return b['x']")[0]; 46 | Assert.IsTrue(obj1.Equals(obj2)); 47 | 48 | lua.DoString("b['x'] = 20"); 49 | obj1 = 20; 50 | obj2 = lua.DoString("return a['x']")[0]; 51 | Assert.IsTrue(obj1.Equals(obj2)); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /LuaUnits/LuaUnits.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {06793FC0-CF27-4AFD-AB8C-2F938829B8DB} 9 | Exe 10 | Properties 11 | LuaUnits 12 | LuaUnits 13 | v4.0 14 | Client 15 | 512 16 | 17 | 18 | x86 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | x86 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | ..\packages\NUnit.2.6.3\lib\nunit.framework.dll 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | {6B52EB11-E6A7-4771-94B0-7F87EA28211D} 57 | NetLua 58 | 59 | 60 | 61 | 62 | 63 | 64 | 71 | -------------------------------------------------------------------------------- /LuaUnits/Program.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * See LICENSE file 3 | */ 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | 10 | namespace LuaUnits 11 | { 12 | class Program 13 | { 14 | static void Main(string[] args) 15 | { 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LuaUnits/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("LuaUnits")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("LuaUnits")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("30b6e916-3040-4e70-afd2-a1b63eb90847")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /LuaUnits/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /NetLua.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetLua", "NetLua\NetLua.csproj", "{6B52EB11-E6A7-4771-94B0-7F87EA28211D}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuaTest", "LuaTest\LuaTest.csproj", "{265397E0-58C3-444B-9C26-3FA585AADB10}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuaUnits", "LuaUnits\LuaUnits.csproj", "{06793FC0-CF27-4AFD-AB8C-2F938829B8DB}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|Mixed Platforms = Debug|Mixed Platforms 14 | Debug|x86 = Debug|x86 15 | Release|Any CPU = Release|Any CPU 16 | Release|Mixed Platforms = Release|Mixed Platforms 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {6B52EB11-E6A7-4771-94B0-7F87EA28211D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {6B52EB11-E6A7-4771-94B0-7F87EA28211D}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {6B52EB11-E6A7-4771-94B0-7F87EA28211D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 23 | {6B52EB11-E6A7-4771-94B0-7F87EA28211D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 24 | {6B52EB11-E6A7-4771-94B0-7F87EA28211D}.Debug|x86.ActiveCfg = Debug|Any CPU 25 | {6B52EB11-E6A7-4771-94B0-7F87EA28211D}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {6B52EB11-E6A7-4771-94B0-7F87EA28211D}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {6B52EB11-E6A7-4771-94B0-7F87EA28211D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 28 | {6B52EB11-E6A7-4771-94B0-7F87EA28211D}.Release|Mixed Platforms.Build.0 = Release|Any CPU 29 | {6B52EB11-E6A7-4771-94B0-7F87EA28211D}.Release|x86.ActiveCfg = Release|Any CPU 30 | {265397E0-58C3-444B-9C26-3FA585AADB10}.Debug|Any CPU.ActiveCfg = Debug|x86 31 | {265397E0-58C3-444B-9C26-3FA585AADB10}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 32 | {265397E0-58C3-444B-9C26-3FA585AADB10}.Debug|Mixed Platforms.Build.0 = Debug|x86 33 | {265397E0-58C3-444B-9C26-3FA585AADB10}.Debug|x86.ActiveCfg = Debug|x86 34 | {265397E0-58C3-444B-9C26-3FA585AADB10}.Debug|x86.Build.0 = Debug|x86 35 | {265397E0-58C3-444B-9C26-3FA585AADB10}.Release|Any CPU.ActiveCfg = Release|x86 36 | {265397E0-58C3-444B-9C26-3FA585AADB10}.Release|Mixed Platforms.ActiveCfg = Release|x86 37 | {265397E0-58C3-444B-9C26-3FA585AADB10}.Release|Mixed Platforms.Build.0 = Release|x86 38 | {265397E0-58C3-444B-9C26-3FA585AADB10}.Release|x86.ActiveCfg = Release|x86 39 | {265397E0-58C3-444B-9C26-3FA585AADB10}.Release|x86.Build.0 = Release|x86 40 | {06793FC0-CF27-4AFD-AB8C-2F938829B8DB}.Debug|Any CPU.ActiveCfg = Debug|x86 41 | {06793FC0-CF27-4AFD-AB8C-2F938829B8DB}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 42 | {06793FC0-CF27-4AFD-AB8C-2F938829B8DB}.Debug|Mixed Platforms.Build.0 = Debug|x86 43 | {06793FC0-CF27-4AFD-AB8C-2F938829B8DB}.Debug|x86.ActiveCfg = Debug|x86 44 | {06793FC0-CF27-4AFD-AB8C-2F938829B8DB}.Debug|x86.Build.0 = Debug|x86 45 | {06793FC0-CF27-4AFD-AB8C-2F938829B8DB}.Release|Any CPU.ActiveCfg = Release|x86 46 | {06793FC0-CF27-4AFD-AB8C-2F938829B8DB}.Release|Mixed Platforms.ActiveCfg = Release|x86 47 | {06793FC0-CF27-4AFD-AB8C-2F938829B8DB}.Release|Mixed Platforms.Build.0 = Release|x86 48 | {06793FC0-CF27-4AFD-AB8C-2F938829B8DB}.Release|x86.ActiveCfg = Release|x86 49 | {06793FC0-CF27-4AFD-AB8C-2F938829B8DB}.Release|x86.Build.0 = Release|x86 50 | EndGlobalSection 51 | GlobalSection(SolutionProperties) = preSolution 52 | HideSolutionNode = FALSE 53 | EndGlobalSection 54 | EndGlobal 55 | -------------------------------------------------------------------------------- /NetLua/Ast/Ast.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2013 Francesco Bertolaccini 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | using System.Collections.Generic; 25 | 26 | namespace NetLua.Ast 27 | { 28 | public enum BinaryOp 29 | { 30 | Addition, 31 | Subtraction, 32 | Multiplication, 33 | Division, 34 | Power, 35 | Modulo, 36 | Concat, 37 | GreaterThan, 38 | GreaterOrEqual, 39 | LessThan, 40 | LessOrEqual, 41 | Equal, 42 | Different, 43 | And, 44 | Or 45 | } 46 | 47 | public enum UnaryOp 48 | { 49 | Negate, 50 | Invert, 51 | Length 52 | } 53 | 54 | public interface IVisitable 55 | { 56 | void Accept(IVisitor visitor); 57 | } 58 | 59 | public interface IStatement : IVisitable { } 60 | 61 | public interface IExpression : IVisitable { } 62 | 63 | public interface IAssignable : IExpression { } 64 | 65 | public interface IVisitor 66 | { 67 | void Visit(Variable arg); 68 | void Visit(StringLiteral arg); 69 | void Visit(NumberLiteral arg); 70 | void Visit(NilLiteral arg); 71 | void Visit(BoolLiteral arg); 72 | void Visit(VarargsLiteral arg); 73 | void Visit(FunctionCall arg); 74 | void Visit(TableAccess arg); 75 | void Visit(FunctionDefinition arg); 76 | void Visit(BinaryExpression arg); 77 | void Visit(UnaryExpression arg); 78 | void Visit(TableConstructor arg); 79 | void Visit(Assignment arg); 80 | void Visit(ReturnStat arg); 81 | void Visit(BreakStat arg); 82 | void Visit(LocalAssignment arg); 83 | void Visit(Block arg); 84 | void Visit(WhileStat arg); 85 | void Visit(RepeatStat arg); 86 | void Visit(NumericFor arg); 87 | void Visit(GenericFor arg); 88 | void Visit(IfStat arg); 89 | } 90 | 91 | public class Variable : IExpression, IAssignable 92 | { 93 | // Prefix.Name 94 | public IExpression Prefix; 95 | public string Name; 96 | 97 | public void Accept(IVisitor visitor) 98 | { 99 | visitor.Visit(this); 100 | } 101 | } 102 | 103 | public class Argument 104 | { 105 | public string Name; 106 | } 107 | 108 | public class StringLiteral : IExpression 109 | { 110 | public string Value; 111 | 112 | public void Accept(IVisitor visitor) 113 | { 114 | visitor.Visit(this); 115 | } 116 | } 117 | 118 | public class NumberLiteral : IExpression 119 | { 120 | public double Value; 121 | 122 | public void Accept(IVisitor visitor) 123 | { 124 | visitor.Visit(this); 125 | } 126 | } 127 | 128 | public class NilLiteral : IExpression 129 | { 130 | public void Accept(IVisitor visitor) 131 | { 132 | visitor.Visit(this); 133 | } 134 | } 135 | 136 | public class BoolLiteral : IExpression 137 | { 138 | public bool Value; 139 | 140 | public void Accept(IVisitor visitor) 141 | { 142 | visitor.Visit(this); 143 | } 144 | } 145 | 146 | public class VarargsLiteral : IExpression 147 | { 148 | public void Accept(IVisitor visitor) 149 | { 150 | visitor.Visit(this); 151 | } 152 | } 153 | 154 | public class FunctionCall : IStatement, IExpression 155 | { 156 | public IExpression Function; 157 | public List Arguments = new List(); 158 | 159 | public void Accept(IVisitor visitor) 160 | { 161 | visitor.Visit(this); 162 | } 163 | } 164 | 165 | public class TableAccess : IExpression, IAssignable 166 | { 167 | // Expression[Index] 168 | public IExpression Expression; 169 | public IExpression Index; 170 | 171 | public void Accept(IVisitor visitor) 172 | { 173 | visitor.Visit(this); 174 | } 175 | } 176 | 177 | public class FunctionDefinition : IExpression 178 | { 179 | // function(Arguments) Body end 180 | public List Arguments = new List(); 181 | public Block Body; 182 | 183 | public void Accept(IVisitor visitor) 184 | { 185 | visitor.Visit(this); 186 | } 187 | } 188 | 189 | public class BinaryExpression : IExpression 190 | { 191 | public IExpression Left, Right; 192 | public BinaryOp Operation; 193 | 194 | public void Accept(IVisitor visitor) 195 | { 196 | visitor.Visit(this); 197 | } 198 | } 199 | 200 | public class UnaryExpression : IExpression 201 | { 202 | public IExpression Expression; 203 | public UnaryOp Operation; 204 | 205 | public void Accept(IVisitor visitor) 206 | { 207 | visitor.Visit(this); 208 | } 209 | } 210 | 211 | public class TableConstructor : IExpression 212 | { 213 | public Dictionary Values = new Dictionary(); 214 | 215 | public void Accept(IVisitor visitor) 216 | { 217 | visitor.Visit(this); 218 | } 219 | } 220 | 221 | public class Assignment : IStatement 222 | { 223 | // Var1, Var2, Var3 = Exp1, Exp2, Exp3 224 | //public Variable[] Variables; 225 | //public IExpression[] Expressions; 226 | 227 | public List Variables = new List(); 228 | public List Expressions = new List(); 229 | 230 | public void Accept(IVisitor visitor) 231 | { 232 | visitor.Visit(this); 233 | } 234 | } 235 | 236 | public class ReturnStat : IStatement 237 | { 238 | public List Expressions = new List(); 239 | 240 | public void Accept(IVisitor visitor) 241 | { 242 | visitor.Visit(this); 243 | } 244 | } 245 | 246 | public class BreakStat : IStatement 247 | { 248 | public void Accept(IVisitor visitor) 249 | { 250 | visitor.Visit(this); 251 | } 252 | } 253 | 254 | public class LocalAssignment : IStatement 255 | { 256 | public List Names = new List(); 257 | public List Values = new List(); 258 | 259 | public void Accept(IVisitor visitor) 260 | { 261 | visitor.Visit(this); 262 | } 263 | } 264 | 265 | public class Block : IStatement 266 | { 267 | public List Statements = new List(); 268 | 269 | public void Accept(IVisitor visitor) 270 | { 271 | visitor.Visit(this); 272 | } 273 | } 274 | 275 | public class WhileStat : IStatement 276 | { 277 | public IExpression Condition; 278 | public Block Block; 279 | 280 | public void Accept(IVisitor visitor) 281 | { 282 | visitor.Visit(this); 283 | } 284 | } 285 | 286 | public class RepeatStat : IStatement 287 | { 288 | public Block Block; 289 | public IExpression Condition; 290 | 291 | public void Accept(IVisitor visitor) 292 | { 293 | visitor.Visit(this); 294 | } 295 | } 296 | 297 | public class NumericFor : IStatement 298 | { 299 | public IExpression Var, Limit, Step; 300 | public string Variable; 301 | public Block Block; 302 | 303 | public void Accept(IVisitor visitor) 304 | { 305 | visitor.Visit(this); 306 | } 307 | } 308 | 309 | public class GenericFor : IStatement 310 | { 311 | public List Variables = new List(); 312 | public List Expressions = new List(); 313 | public Block Block; 314 | 315 | public void Accept(IVisitor visitor) 316 | { 317 | visitor.Visit(this); 318 | } 319 | } 320 | 321 | public class IfStat : IStatement 322 | { 323 | public IExpression Condition; 324 | public Block Block; 325 | public List ElseIfs = new List(); 326 | public Block ElseBlock; 327 | 328 | public void Accept(IVisitor visitor) 329 | { 330 | visitor.Visit(this); 331 | } 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /NetLua/Libraries/IoLibrary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.IO; 6 | 7 | namespace NetLua 8 | { 9 | public static class IoLibrary 10 | { 11 | // TODO: implment lines, read 12 | class FileObject 13 | { 14 | public FileObject(Stream s) 15 | { 16 | stream = s; 17 | if (s.CanRead) 18 | reader = new StreamReader(s); 19 | if (s.CanWrite) 20 | writer = new StreamWriter(s); 21 | } 22 | 23 | public Stream stream; 24 | public StreamReader reader; 25 | public StreamWriter writer; 26 | } 27 | 28 | static dynamic FileMetatable = LuaObject.NewTable(); 29 | 30 | static LuaObject currentInput = LuaObject.Nil, currentOutput = LuaObject.Nil; 31 | 32 | static bool isStream(LuaObject obj) 33 | { 34 | return (obj.IsUserData && obj.luaobj is FileObject); 35 | } 36 | 37 | static LuaObject CreateFileObject(Stream stream) 38 | { 39 | LuaObject obj = LuaObject.FromObject(new FileObject(stream)); 40 | obj.Metatable = FileMetatable; 41 | 42 | return obj; 43 | } 44 | 45 | static LuaObject CreateFileObject(Stream stream, bool autoflush) 46 | { 47 | FileObject fobj = new FileObject(stream); 48 | fobj.writer.AutoFlush = autoflush; 49 | LuaObject obj = LuaObject.FromObject(fobj); 50 | obj.Metatable = FileMetatable; 51 | 52 | return obj; 53 | } 54 | 55 | public static void AddIoLibrary(LuaContext Context) 56 | { 57 | dynamic io = LuaObject.NewTable(); 58 | 59 | FileMetatable.__index = LuaObject.NewTable(); 60 | FileMetatable.__index.write = (LuaFunction)write; 61 | FileMetatable.__index.close = (LuaFunction)close; 62 | FileMetatable.__index.flush = (LuaFunction)flush; 63 | FileMetatable.__index.seek = (LuaFunction)seek; 64 | FileMetatable.__index.read = (LuaFunction)read; 65 | 66 | io.open = (LuaFunction)io_open; 67 | io.type = (LuaFunction)io_type; 68 | io.input = (LuaFunction)io_input; 69 | io.output = (LuaFunction)io_output; 70 | io.temp = (LuaFunction)io_temp; 71 | io.flush = (LuaFunction)io_flush; 72 | io.write = (LuaFunction)io_write; 73 | io.read = (LuaFunction)io_read; 74 | 75 | currentInput = CreateFileObject(Console.OpenStandardInput()); 76 | currentOutput = CreateFileObject(Console.OpenStandardOutput(), true); 77 | io.stdin = currentInput; 78 | io.stdout = currentOutput; 79 | io.stderr = CreateFileObject(Console.OpenStandardError(), true); 80 | 81 | Context.Set("io", io); 82 | } 83 | 84 | static LuaArguments io_open(LuaArguments args) 85 | { 86 | var file = args[0]; 87 | var mode = args[1]; 88 | 89 | if (file.IsString) 90 | { 91 | FileMode fmode = FileMode.Open; 92 | FileAccess faccess = FileAccess.Read; 93 | if (mode.IsString) 94 | { 95 | switch (mode.ToString()) 96 | { 97 | case "r": 98 | faccess = FileAccess.Read; break; 99 | case "w": 100 | fmode = FileMode.Create; faccess = FileAccess.ReadWrite; break; 101 | case "a": 102 | fmode = FileMode.Append; faccess = FileAccess.Write; break; 103 | case "r+": 104 | case "w+": 105 | case "a+": 106 | // TODO: Implement rwa+ 107 | throw new NotImplementedException(); 108 | } 109 | } 110 | FileStream stream = new FileStream(file.ToString(), fmode, faccess); 111 | 112 | return Lua.Return(CreateFileObject(stream)); 113 | } 114 | else 115 | return Lua.Return(); 116 | } 117 | 118 | static LuaArguments io_type(LuaArguments args) 119 | { 120 | var obj = args[0]; 121 | if (isStream(obj)) 122 | { 123 | FileObject fobj = obj.luaobj as FileObject; 124 | if (!fobj.stream.CanWrite && !fobj.stream.CanRead) 125 | return Lua.Return("closed file"); 126 | else 127 | return Lua.Return("file"); 128 | } 129 | return Lua.Return(); 130 | } 131 | 132 | static LuaArguments io_input(LuaArguments args) 133 | { 134 | var obj = args[0]; 135 | if (isStream(obj)) 136 | { 137 | currentInput = obj; 138 | return Lua.Return(currentInput); 139 | } 140 | else if (obj.IsString) 141 | { 142 | currentInput = io_open(args)[0]; 143 | return Lua.Return(currentInput); 144 | } 145 | else if (args.Length == 0) 146 | return Lua.Return(currentInput); 147 | else 148 | throw new LuaException("Invalid argument"); 149 | } 150 | 151 | static LuaArguments io_output(LuaArguments args) 152 | { 153 | var obj = args[0]; 154 | if (isStream(obj)) 155 | { 156 | currentOutput = obj; 157 | return Lua.Return(currentOutput); 158 | } 159 | else if (obj.IsString) 160 | { 161 | FileStream stream = new FileStream(obj.ToString(), FileMode.OpenOrCreate); 162 | currentOutput = CreateFileObject(stream); 163 | return Lua.Return(currentOutput); 164 | } 165 | else if (args.Length == 0) 166 | return Lua.Return(currentOutput); 167 | else 168 | throw new LuaException("Invalid argument"); 169 | } 170 | 171 | static LuaArguments io_temp(LuaArguments args) 172 | { 173 | string path = Path.GetTempFileName(); 174 | Stream s = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Write, Int16.MaxValue, FileOptions.DeleteOnClose); 175 | 176 | return Lua.Return(CreateFileObject(s)); 177 | } 178 | 179 | static LuaArguments io_write(LuaArguments args) 180 | { 181 | var obj = args[0]; 182 | if (!obj.IsNil) 183 | return currentOutput["write"].MethodCall(currentOutput, args); 184 | else 185 | return Lua.Return(); 186 | } 187 | 188 | static LuaArguments io_flush(LuaArguments args) 189 | { 190 | var obj = args[0]; 191 | if (obj.IsNil) 192 | return currentOutput["flush"].MethodCall(currentOutput, args); 193 | else 194 | return obj["flush"].MethodCall(obj, args); 195 | } 196 | 197 | static LuaArguments io_close(LuaArguments args) 198 | { 199 | var obj = args[0]; 200 | if (obj.IsNil) 201 | return currentOutput["close"].MethodCall(currentOutput, args); 202 | else 203 | return obj["close"].MethodCall(obj, args); 204 | } 205 | 206 | static LuaArguments io_read(LuaArguments args) 207 | { 208 | return currentInput["read"].MethodCall(currentInput, args); 209 | } 210 | 211 | static LuaArguments write(LuaArguments args) 212 | { 213 | var self = args[0]; 214 | if (isStream(self)) 215 | { 216 | FileObject fobj = self.luaobj as FileObject; 217 | foreach (var arg in args) 218 | { 219 | if (arg == self) 220 | continue; 221 | 222 | if (!(arg.IsString || arg.IsNumber)) 223 | Lua.Return(); 224 | 225 | if (fobj.stream.CanWrite) 226 | fobj.writer.Write(arg.ToString()); 227 | else 228 | Lua.Return(); 229 | } 230 | return Lua.Return(self); 231 | } 232 | else 233 | return Lua.Return(); 234 | } 235 | 236 | static LuaArguments close(LuaArguments args) 237 | { 238 | var obj = args[0]; 239 | if (isStream(obj)) 240 | { 241 | FileObject fobj = obj.luaobj as FileObject; 242 | fobj.stream.Close(); 243 | } 244 | return Lua.Return(); 245 | } 246 | 247 | static LuaArguments flush(LuaArguments args) 248 | { 249 | var obj = args[0]; 250 | if (isStream(obj)) 251 | { 252 | FileObject fobj = obj.luaobj as FileObject; 253 | fobj.writer.Flush(); 254 | } 255 | return Lua.Return(); 256 | } 257 | 258 | static LuaArguments seek(LuaArguments args) 259 | { 260 | var obj = args[0]; 261 | var whence = args[1] | "cur"; 262 | var offset = args[2] | 0; 263 | 264 | if (isStream(obj)) 265 | { 266 | var fobj = obj.luaobj as FileObject; 267 | switch (whence.ToString()) 268 | { 269 | case "cur": 270 | fobj.stream.Position += (long)offset; break; 271 | case "set": 272 | fobj.stream.Position = (long)offset; break; 273 | case "end": 274 | fobj.stream.Position = fobj.stream.Length + (long)offset; break; 275 | } 276 | return Lua.Return(fobj.stream.Position); 277 | } 278 | return Lua.Return(); 279 | } 280 | 281 | static LuaArguments read(LuaArguments args) 282 | { 283 | var self = args[0]; 284 | if (isStream(self)) 285 | { 286 | var fobj = self.luaobj as FileObject; 287 | if (args.Length == 1) 288 | { 289 | var line = fobj.reader.ReadLine(); 290 | 291 | return Lua.Return(line); 292 | } 293 | else 294 | { 295 | List ret = new List(); 296 | foreach (var arg in args) 297 | { 298 | if (arg == self) 299 | continue; 300 | if (arg.IsNumber) 301 | { 302 | StringBuilder bld = new StringBuilder(); 303 | for (int i = 0; i < arg; i++) 304 | { 305 | bld.Append((char)fobj.reader.Read()); 306 | } 307 | ret.Add(bld.ToString()); 308 | } 309 | else if (arg == "*a") 310 | ret.Add(fobj.reader.ReadToEnd()); 311 | else if (arg == "*l") 312 | ret.Add(fobj.reader.ReadLine()); 313 | else if (arg == "*n") 314 | { 315 | //TODO: Implement io.read("*n") 316 | throw new NotImplementedException(); 317 | } 318 | } 319 | return Lua.Return(ret.ToArray()); 320 | } 321 | } 322 | else 323 | return Lua.Return(); 324 | } 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /NetLua/Libraries/MathLibrary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NetLua 7 | { 8 | public static class MathLibrary 9 | { 10 | static LuaArguments math_abs(LuaArguments args) 11 | { 12 | return Lua.Return(Math.Abs(args[0])); 13 | } 14 | 15 | static LuaArguments math_acos(LuaArguments args) 16 | { 17 | return Lua.Return(Math.Acos(args[0])); 18 | } 19 | 20 | static LuaArguments math_asin(LuaArguments args) 21 | { 22 | return Lua.Return(Math.Asin(args[0])); 23 | } 24 | 25 | static LuaArguments math_atan(LuaArguments args) 26 | { 27 | return Lua.Return(Math.Atan(args[0])); 28 | } 29 | 30 | static LuaArguments math_atan2(LuaArguments args) 31 | { 32 | return Lua.Return(Math.Atan2(args[0], args[1])); 33 | } 34 | 35 | static LuaArguments math_ceil(LuaArguments args) 36 | { 37 | return Lua.Return(Math.Ceiling(args[0])); 38 | } 39 | 40 | static LuaArguments math_cos(LuaArguments args) 41 | { 42 | return Lua.Return(Math.Cos(args[0])); 43 | } 44 | 45 | static LuaArguments math_cosh(LuaArguments args) 46 | { 47 | return Lua.Return(Math.Cosh(args[0])); 48 | } 49 | 50 | static LuaArguments math_exp(LuaArguments args) 51 | { 52 | return Lua.Return(Math.Exp(args[0])); 53 | } 54 | 55 | static LuaArguments math_floor(LuaArguments args) 56 | { 57 | return Lua.Return(Math.Floor(args[0])); 58 | } 59 | 60 | static LuaArguments math_log(LuaArguments args) 61 | { 62 | return Lua.Return(Math.Log(args[0], args[1] | Math.E)); 63 | } 64 | 65 | static LuaArguments math_max(LuaArguments args) 66 | { 67 | var max = args[0]; 68 | foreach (LuaObject o in args) 69 | { 70 | max = Math.Max(max, o); 71 | } 72 | return Lua.Return(max); 73 | } 74 | 75 | static LuaArguments math_min(LuaArguments args) 76 | { 77 | var min = args[0]; 78 | foreach (LuaObject o in args) 79 | { 80 | min = Math.Min(min, o); 81 | } 82 | return Lua.Return(min); 83 | } 84 | 85 | static LuaArguments math_pow(LuaArguments args) 86 | { 87 | return Lua.Return(Math.Pow(args[0], args[1])); 88 | } 89 | 90 | static LuaArguments math_sin(LuaArguments args) 91 | { 92 | return Lua.Return(Math.Sin(args[0])); 93 | } 94 | 95 | static LuaArguments math_sinh(LuaArguments args) 96 | { 97 | return Lua.Return(Math.Sinh(args[0])); 98 | } 99 | 100 | static LuaArguments math_sqrt(LuaArguments args) 101 | { 102 | return Lua.Return(Math.Sqrt(args[0])); 103 | } 104 | 105 | static LuaArguments math_tan(LuaArguments args) 106 | { 107 | return Lua.Return(Math.Tan(args[0])); 108 | } 109 | 110 | static LuaArguments math_tanh(LuaArguments args) 111 | { 112 | return Lua.Return(Math.Tanh(args[0])); 113 | } 114 | 115 | public static void AddMathLibrary(LuaContext Context) 116 | { 117 | dynamic math = LuaObject.NewTable(); 118 | math.abs = (LuaFunction)math_abs; 119 | math.acos = (LuaFunction)math_acos; 120 | math.asin = (LuaFunction)math_asin; 121 | math.atan = (LuaFunction)math_atan; 122 | math.atan2 = (LuaFunction)math_atan2; 123 | math.ceil = (LuaFunction)math_ceil; 124 | math.cos = (LuaFunction)math_cos; 125 | math.cosh = (LuaFunction)math_cosh; 126 | math.exp = (LuaFunction)math_exp; 127 | math.floor = (LuaFunction)math_floor; 128 | math.log = (LuaFunction)math_log; 129 | math.max = (LuaFunction)math_max; 130 | math.min = (LuaFunction)math_min; 131 | math.pow = (LuaFunction)math_pow; 132 | math.sin = (LuaFunction)math_sin; 133 | math.sinh = (LuaFunction)math_sinh; 134 | math.sqrt = (LuaFunction)math_sqrt; 135 | math.tan = (LuaFunction)math_tan; 136 | math.tanh = (LuaFunction)math_tanh; 137 | 138 | math.pi = Math.PI; 139 | 140 | Context.Set("math", math); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /NetLua/Lua.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * See LICENSE file 3 | */ 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq.Expressions; 8 | using System.Text; 9 | using System.Dynamic; 10 | 11 | using NetLua.Ast; 12 | 13 | namespace NetLua 14 | { 15 | public class Lua : DynamicObject 16 | { 17 | LuaContext ctx = new LuaContext(); 18 | Parser p = new Parser(); 19 | 20 | /// 21 | /// Helper function for returning Nil from a function 22 | /// 23 | /// Nil 24 | public static LuaArguments Return() 25 | { 26 | return new LuaObject[] { LuaObject.Nil }; 27 | } 28 | 29 | /// 30 | /// Helper function for returning objects from a function 31 | /// 32 | /// The objects to return 33 | public static LuaArguments Return(params LuaObject[] values) 34 | { 35 | return values; 36 | } 37 | 38 | /// 39 | /// Creates a new Lua context with the base functions already set 40 | /// 41 | public Lua() 42 | { 43 | ctx.Set("assert", (LuaFunction)assert); 44 | ctx.Set("dofile", (LuaFunction)dofile); 45 | ctx.Set("error", (LuaFunction)error); 46 | ctx.Set("getmetatable", (LuaFunction)getmetatable); 47 | ctx.Set("setmetatable", (LuaFunction)setmetatable); 48 | ctx.Set("rawequal", (LuaFunction)rawequal); 49 | ctx.Set("rawget", (LuaFunction)rawget); 50 | ctx.Set("rawset", (LuaFunction)rawset); 51 | ctx.Set("rawlen", (LuaFunction)rawlen); 52 | ctx.Set("tonumber", (LuaFunction)tonumber); 53 | ctx.Set("tostring", (LuaFunction)tostring); 54 | ctx.Set("type", (LuaFunction)type); 55 | ctx.Set("ipairs", (LuaFunction)ipairs); 56 | ctx.Set("next", (LuaFunction)next); 57 | ctx.Set("pairs", (LuaFunction)pairs); 58 | } 59 | 60 | /// 61 | /// Parses and executes the specified file 62 | /// 63 | /// The file to execute 64 | public LuaArguments DoFile(string Filename) 65 | { 66 | FunctionDefinition def = new FunctionDefinition(); 67 | def.Arguments = new List(); 68 | def.Body = p.ParseFile(Filename); 69 | var function = LuaCompiler.CompileFunction(def, Expression.Constant(ctx)).Compile(); 70 | return function().Call(Lua.Return()); 71 | } 72 | 73 | /// 74 | /// Parses and executes the specified string 75 | /// 76 | public LuaArguments DoString(string Chunk) 77 | { 78 | FunctionDefinition def = new FunctionDefinition(); 79 | def.Arguments = new List(); 80 | def.Body = p.ParseString(Chunk); 81 | var function = LuaCompiler.CompileFunction(def, Expression.Constant(ctx)).Compile(); 82 | return function().Call(Lua.Return()); 83 | } 84 | 85 | /// 86 | /// Parses and executes the specified parsed block 87 | /// 88 | public LuaArguments DoAst(Block block) 89 | { 90 | FunctionDefinition def = new FunctionDefinition(); 91 | def.Arguments = new List(); 92 | def.Body = block; 93 | var function = LuaCompiler.CompileFunction(def, Expression.Constant(ctx)).Compile(); 94 | return function().Call(Lua.Return()); 95 | } 96 | 97 | /// 98 | /// The base context 99 | /// 100 | public LuaContext Context 101 | { 102 | get 103 | { 104 | return ctx; 105 | } 106 | } 107 | 108 | /// 109 | /// The base context 110 | /// 111 | public dynamic DynamicContext 112 | { 113 | get 114 | { 115 | return ctx; 116 | } 117 | } 118 | 119 | #region Dynamic methods 120 | 121 | public override bool TryGetMember(GetMemberBinder binder, out object result) 122 | { 123 | result = null; 124 | LuaObject obj = ctx.Get(binder.Name); 125 | if (obj.IsNil) 126 | return false; 127 | else 128 | { 129 | result = LuaObject.getObject(obj); 130 | return true; 131 | } 132 | } 133 | 134 | public override bool TrySetMember(SetMemberBinder binder, object value) 135 | { 136 | if (value is LuaObject) 137 | ctx.Set(binder.Name, value as LuaObject); 138 | else 139 | ctx.Set(binder.Name, LuaObject.FromObject(value)); 140 | return true; 141 | } 142 | 143 | #endregion 144 | 145 | #region Basic functions 146 | 147 | LuaArguments assert(LuaArguments args) 148 | { 149 | if (args.Length > 0) 150 | { 151 | if (args[0].AsBool() == false) 152 | { 153 | if (args.Length == 1) 154 | throw new LuaException("Assertion failed"); 155 | else 156 | throw new LuaException(args[1].ToString()); 157 | } 158 | } 159 | return Return(); 160 | } 161 | 162 | LuaArguments dofile(LuaArguments args) 163 | { 164 | return DoFile(args[0].ToString()); 165 | } 166 | 167 | LuaArguments error(LuaArguments args) 168 | { 169 | throw new LuaException(args[0].ToString()); 170 | } 171 | 172 | LuaArguments getmetatable(LuaArguments args) 173 | { 174 | return Return(args[0].Metatable); 175 | } 176 | 177 | LuaArguments setmetatable(LuaArguments args) 178 | { 179 | args[0].Metatable = args[1]; 180 | return Return(); 181 | } 182 | 183 | LuaArguments rawequal(LuaArguments args) 184 | { 185 | return Return(args[0] == args[1]); 186 | } 187 | 188 | LuaArguments rawget(LuaArguments args) 189 | { 190 | return Return(LuaEvents.rawget(args[0], args[1])); 191 | } 192 | 193 | LuaArguments rawset(LuaArguments args) 194 | { 195 | LuaEvents.rawset(args[0], args[1], args[2]); 196 | return Return(args[0]); 197 | } 198 | 199 | LuaArguments rawlen(LuaArguments args) 200 | { 201 | LuaObject obj = args[0]; 202 | if (obj.IsString) 203 | return Return(obj.AsString().Length); 204 | else if (obj.IsTable) 205 | return Return(obj.AsTable().Count); 206 | else 207 | throw new LuaException("invalid argument"); 208 | } 209 | 210 | LuaArguments tonumber(LuaArguments args) 211 | { 212 | LuaObject obj = args[0]; 213 | if (args.Length == 1) 214 | { 215 | double d = 0; 216 | if (obj.IsString) 217 | { 218 | if (double.TryParse(obj.AsString(), out d)) 219 | return Return(d); 220 | else 221 | return Return(); 222 | } 223 | else if (obj.IsNumber) 224 | { 225 | return Return(obj.AsNumber()); 226 | } 227 | else 228 | { 229 | return Return(); 230 | } 231 | } 232 | else 233 | { 234 | //TODO: Implement tonumber for bases different from 10 235 | throw new NotImplementedException(); 236 | } 237 | } 238 | 239 | LuaArguments tostring(LuaArguments args) 240 | { 241 | return Return(LuaEvents.tostring_event(args[0])); 242 | } 243 | 244 | LuaArguments type(LuaArguments args) 245 | { 246 | switch (args[0].Type) 247 | { 248 | case LuaType.boolean: 249 | return Return("boolean"); 250 | case LuaType.function: 251 | return Return("function"); 252 | case LuaType.nil: 253 | return Return("nil"); 254 | case LuaType.number: 255 | return Return("number"); 256 | case LuaType.@string: 257 | return Return("string"); 258 | case LuaType.table: 259 | return Return("table"); 260 | case LuaType.thread: 261 | return Return("thread"); 262 | case LuaType.userdata: 263 | return Return("userdata"); 264 | } 265 | return Return(); 266 | } 267 | 268 | LuaArguments ipairs(LuaArguments args) 269 | { 270 | LuaObject handler = LuaEvents.getMetamethod(args[0], "__ipairs"); 271 | if (!handler.IsNil) 272 | { 273 | return handler.Call(args); 274 | } 275 | else 276 | { 277 | if (args[0].IsTable) 278 | { 279 | LuaFunction f = delegate(LuaArguments x) 280 | { 281 | var s = x[0]; 282 | var var = x[1].AsNumber() + 1; 283 | 284 | var val = s[var]; 285 | if (val == LuaObject.Nil) 286 | return Return(LuaObject.Nil); 287 | else 288 | return Return(var, val); 289 | }; 290 | return Return(f, args[0], 0); 291 | } 292 | else 293 | { 294 | throw new LuaException("t must be a table"); 295 | } 296 | } 297 | } 298 | 299 | LuaArguments next(LuaArguments args) 300 | { 301 | var table = args[0]; 302 | var index = args[1]; 303 | if (!table.IsTable) 304 | { 305 | throw new LuaException("t must be a table"); 306 | } 307 | List keys = new List(table.AsTable().Keys); 308 | if (index.IsNil) 309 | { 310 | if (keys.Count == 0) 311 | return Return(); 312 | return Return(keys[0], table[keys[0]]); 313 | } 314 | else 315 | { 316 | int pos = keys.IndexOf(index); 317 | if (pos == keys.Count - 1) 318 | { 319 | return Return(); 320 | } 321 | else 322 | { 323 | return Return(keys[pos + 1], table[keys[pos + 1]]); 324 | } 325 | } 326 | } 327 | 328 | LuaArguments pairs(LuaArguments args) 329 | { 330 | LuaObject handler = LuaEvents.getMetamethod(args[0], "__pairs"); 331 | if (!handler.IsNil) 332 | { 333 | return handler.Call(args); 334 | } 335 | else 336 | { 337 | return Return((LuaFunction)next, args[0], LuaObject.Nil); 338 | } 339 | } 340 | 341 | #endregion 342 | } 343 | } 344 | -------------------------------------------------------------------------------- /NetLua/LuaCompiler.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * See LICENSE file 3 | */ 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Linq.Expressions; 10 | using System.Reflection; 11 | 12 | using NetLua.Ast; 13 | 14 | namespace NetLua 15 | { 16 | public static class LuaCompiler 17 | { 18 | static Type LuaContext_Type = typeof(LuaContext); 19 | static Type LuaArguments_Type = typeof(LuaArguments); 20 | static Type LuaEvents_Type = typeof(LuaEvents); 21 | static Type LuaObject_Type = typeof(LuaObject); 22 | 23 | static MethodInfo LuaContext_Get = LuaContext_Type.GetMethod("Get"); 24 | static MethodInfo LuaContext_SetLocal = LuaContext_Type.GetMethod("SetLocal"); 25 | static MethodInfo LuaContext_SetGlobal = LuaContext_Type.GetMethod("SetGlobal"); 26 | static MethodInfo LuaContext_Set = LuaContext_Type.GetMethod("Set"); 27 | 28 | static MethodInfo LuaArguments_Concat = LuaArguments_Type.GetMethod("Concat"); 29 | static MethodInfo LuaArguments_Add = LuaArguments_Type.GetMethod("Add"); 30 | 31 | static ConstructorInfo LuaContext_New_parent = LuaContext_Type.GetConstructor(new[] { typeof(LuaContext) }); 32 | static ConstructorInfo LuaArguments_New = LuaArguments_Type.GetConstructor(new[] { typeof(LuaObject[]) }); 33 | static ConstructorInfo LuaArguments_New_arglist = LuaArguments_Type.GetConstructor(new[] { typeof(LuaArguments[]) }); 34 | static ConstructorInfo LuaArguments_New_void = LuaArguments_Type.GetConstructor(new Type[] { }); 35 | 36 | static MethodInfo LuaEvents_eq = LuaEvents_Type.GetMethod("eq_event", BindingFlags.NonPublic | BindingFlags.Static); 37 | static MethodInfo LuaEvents_concat = LuaEvents_Type.GetMethod("concat_event", BindingFlags.NonPublic | BindingFlags.Static); 38 | static MethodInfo LuaEvents_len = LuaEvents_Type.GetMethod("len_event", BindingFlags.NonPublic | BindingFlags.Static); 39 | static MethodInfo LuaEvents_toNumber = LuaEvents_Type.GetMethod("toNumber", BindingFlags.NonPublic | BindingFlags.Static); 40 | 41 | static MethodInfo LuaObject_Call = LuaObject_Type.GetMethod("Call", new[] { LuaArguments_Type }); 42 | static MethodInfo LuaObject_AsBool = LuaObject_Type.GetMethod("AsBool"); 43 | 44 | static LuaArguments VoidArguments = new LuaArguments(); 45 | 46 | #region Helpers 47 | static Expression ToNumber(Expression Expression) 48 | { 49 | return Expression.Call(LuaEvents_toNumber, Expression); 50 | } 51 | 52 | static Expression CreateLuaArguments(params Expression[] Expressions) 53 | { 54 | var array = Expression.NewArrayInit(typeof(LuaObject), Expressions); 55 | return Expression.New(LuaArguments_New, array); 56 | } 57 | 58 | static Expression GetFirstArgument(Expression Expression) 59 | { 60 | if (Expression.Type == typeof(LuaArguments)) 61 | return Expression.Property(Expression, "Item", Expression.Constant(0)); 62 | else 63 | return Expression.ArrayAccess(Expression, Expression.Constant(0)); 64 | } 65 | 66 | static Expression GetFirstArgumentAsBool(Expression Expression) 67 | { 68 | Expression e = GetFirstArgument(Expression); 69 | return Expression.Call(e, LuaObject_AsBool); 70 | } 71 | 72 | static Expression GetAsBool(Expression Expression) 73 | { 74 | return Expression.Call(Expression, LuaObject_AsBool); 75 | } 76 | 77 | static Expression GetArgument(Expression Expression, int n) 78 | { 79 | if (Expression.Type == typeof(LuaArguments)) 80 | return Expression.Property(Expression, "Item", Expression.Constant(n)); 81 | else 82 | return Expression.ArrayAccess(Expression, Expression.Constant(n)); 83 | } 84 | #endregion 85 | 86 | #region Expressions 87 | static Expression CompileBinaryExpression(Ast.BinaryExpression expr, Expression Context) 88 | { 89 | var left = CompileSingleExpression(expr.Left, Context); 90 | var right = CompileSingleExpression(expr.Right, Context); 91 | switch (expr.Operation) 92 | { 93 | case BinaryOp.Addition: 94 | return Expression.Add(left, right); 95 | case BinaryOp.And: 96 | return Expression.And(left, right); 97 | case BinaryOp.Concat: 98 | return Expression.Call(LuaEvents_concat, left, right); 99 | case BinaryOp.Different: 100 | return Expression.Not(Expression.Call(LuaEvents_eq, left, right)); 101 | case BinaryOp.Division: 102 | return Expression.Divide(left, right); 103 | case BinaryOp.Equal: 104 | return Expression.Call(LuaEvents_eq, left, right); 105 | case BinaryOp.GreaterOrEqual: 106 | return Expression.GreaterThanOrEqual(left, right); 107 | case BinaryOp.GreaterThan: 108 | return Expression.GreaterThan(left, right); 109 | case BinaryOp.LessOrEqual: 110 | return Expression.LessThanOrEqual(left, right); 111 | case BinaryOp.LessThan: 112 | return Expression.LessThan(left, right); 113 | case BinaryOp.Modulo: 114 | return Expression.Modulo(left, right); 115 | case BinaryOp.Multiplication: 116 | return Expression.Multiply(left, right); 117 | case BinaryOp.Or: 118 | return Expression.Or(left, right); 119 | case BinaryOp.Power: 120 | return Expression.ExclusiveOr(left, right); 121 | case BinaryOp.Subtraction: 122 | return Expression.Subtract(left, right); 123 | default: 124 | throw new NotImplementedException(); 125 | } 126 | } 127 | 128 | static Expression CompileUnaryExpression(Ast.UnaryExpression expr, Expression Context) 129 | { 130 | var e = CompileSingleExpression(expr.Expression, Context); 131 | switch (expr.Operation) 132 | { 133 | case UnaryOp.Invert: 134 | return Expression.Negate(e); 135 | case UnaryOp.Negate: 136 | return Expression.Not(e); 137 | case UnaryOp.Length: 138 | return Expression.Call(LuaEvents_len, e); 139 | default: 140 | throw new NotImplementedException(); 141 | } 142 | } 143 | 144 | static Expression GetVariable(Ast.Variable expr, Expression Context) 145 | { 146 | if (expr.Prefix == null) 147 | return Expression.Call(Context, LuaContext_Get, Expression.Constant(expr.Name)); 148 | else 149 | { 150 | Expression p = CompileSingleExpression(expr.Prefix, Context); 151 | return Expression.Property(p, "Item", Expression.Convert(Expression.Constant(expr.Name), LuaObject_Type)); 152 | } 153 | } 154 | 155 | static Expression GetTableAccess(Ast.TableAccess expr, Expression Context) 156 | { 157 | var e = CompileSingleExpression(expr.Expression, Context); 158 | var i = CompileSingleExpression(expr.Index, Context); 159 | 160 | return Expression.Property(e, "Item", i); 161 | } 162 | 163 | // This function returns a Expression with type LuaArguments. Similar to CompileSingleExpression 164 | static Expression CompileExpression(IExpression expr, Expression Context) 165 | { 166 | if (expr is NumberLiteral) 167 | return CreateLuaArguments(Expression.Constant((LuaObject)((expr as NumberLiteral).Value))); 168 | if (expr is StringLiteral) 169 | return CreateLuaArguments(Expression.Constant((LuaObject)((expr as StringLiteral).Value))); 170 | if (expr is BoolLiteral) 171 | return CreateLuaArguments(Expression.Constant((LuaObject)((expr as BoolLiteral).Value))); 172 | if (expr is NilLiteral) 173 | return CreateLuaArguments(Expression.Constant(LuaObject.Nil)); 174 | 175 | if (expr is Ast.BinaryExpression) 176 | return CreateLuaArguments(CompileBinaryExpression(expr as Ast.BinaryExpression, Context)); 177 | if (expr is Ast.UnaryExpression) 178 | return CreateLuaArguments(CompileUnaryExpression(expr as Ast.UnaryExpression, Context)); 179 | if (expr is Ast.Variable) 180 | return CreateLuaArguments(GetVariable(expr as Ast.Variable, Context)); 181 | if (expr is Ast.TableAccess) 182 | return CreateLuaArguments(GetTableAccess(expr as Ast.TableAccess, Context)); 183 | if (expr is Ast.FunctionCall) 184 | return CompileFunctionCallExpr(expr as Ast.FunctionCall, Context); 185 | if (expr is Ast.FunctionDefinition) 186 | return CreateLuaArguments(CompileFunctionDef(expr as Ast.FunctionDefinition, Context)); 187 | if (expr is Ast.VarargsLiteral) 188 | return CompileVarargs(Context); 189 | if (expr is Ast.TableConstructor) 190 | return CreateLuaArguments(CompileTableConstructor(expr as Ast.TableConstructor, Context)); 191 | throw new NotImplementedException(); 192 | } 193 | 194 | // This function returns a Expression with type LuaObject. Similar to CompileExpression 195 | static Expression CompileSingleExpression(IExpression expr, Expression Context) 196 | { 197 | if (expr is NumberLiteral) 198 | return (Expression.Constant((LuaObject)((expr as NumberLiteral).Value))); 199 | if (expr is StringLiteral) 200 | return (Expression.Constant((LuaObject)((expr as StringLiteral).Value))); 201 | if (expr is BoolLiteral) 202 | return (Expression.Constant((LuaObject)((expr as BoolLiteral).Value))); 203 | if (expr is NilLiteral) 204 | return (Expression.Constant(LuaObject.Nil)); 205 | 206 | if (expr is Ast.BinaryExpression) 207 | return (CompileBinaryExpression(expr as Ast.BinaryExpression, Context)); 208 | if (expr is Ast.UnaryExpression) 209 | return (CompileUnaryExpression(expr as Ast.UnaryExpression, Context)); 210 | if (expr is Ast.Variable) 211 | return (GetVariable(expr as Ast.Variable, Context)); 212 | if (expr is Ast.TableAccess) 213 | return (GetTableAccess(expr as Ast.TableAccess, Context)); 214 | if (expr is Ast.FunctionCall) 215 | return GetFirstArgument(CompileFunctionCallExpr(expr as Ast.FunctionCall, Context)); 216 | if (expr is Ast.FunctionDefinition) 217 | return (CompileFunctionDef(expr as Ast.FunctionDefinition, Context)); 218 | if (expr is Ast.VarargsLiteral) 219 | return GetFirstArgument(CompileVarargs(Context)); 220 | if (expr is Ast.TableConstructor) 221 | return (CompileTableConstructor(expr as Ast.TableConstructor, Context)); 222 | throw new NotImplementedException(); 223 | } 224 | 225 | static Expression CompileTableConstructor(Ast.TableConstructor table, Expression Context) 226 | { 227 | var values = new List>(); 228 | int i = 0; 229 | var exprs = new List(); 230 | var type = typeof(Dictionary); 231 | var add = type.GetMethod("Add", new[] { LuaObject_Type, LuaObject_Type }); 232 | var variable = Expression.Parameter(type); 233 | var assign = Expression.Assign(variable, Expression.New(type.GetConstructor(new Type[] { }))); 234 | exprs.Add(assign); 235 | foreach (KeyValuePair kvpair in table.Values) 236 | { 237 | if (i == table.Values.Count - 1) 238 | { 239 | var k = CompileSingleExpression(kvpair.Key, Context); 240 | var v = CompileExpression(kvpair.Value, Context); 241 | var singlev = GetFirstArgument(v); 242 | var ifFalse = Expression.Call(variable, add, k, singlev); 243 | 244 | var counter = Expression.Parameter(typeof(int)); 245 | var value = Expression.Parameter(LuaArguments_Type); 246 | var @break = Expression.Label(); 247 | var breakLabel = Expression.Label(@break); 248 | var assignValue = Expression.Assign(value, v); 249 | var assignCounter = Expression.Assign(counter, Expression.Constant(0)); 250 | var incrementCounter = Expression.Assign(counter, Expression.Increment(counter)); 251 | var loopCondition = Expression.LessThan(counter, Expression.Property(v, "Length")); 252 | var addValue = Expression.Call(variable, add, 253 | Expression.Add(k, 254 | Expression.Call(LuaObject_Type.GetMethod("FromNumber"), 255 | Expression.Convert(counter, typeof(double) ) ) ), 256 | Expression.Property(value, "Item", counter) ); 257 | 258 | var check = Expression.IfThenElse(loopCondition, Expression.Block(addValue, incrementCounter), Expression.Break(@break)); 259 | var loopBody = Expression.Loop(check); 260 | var ifTrue = Expression.Block(new[] { counter, value }, assignCounter, assignValue, loopBody, breakLabel); 261 | 262 | var condition = Expression.IsTrue(Expression.Property(k, "IsNumber")); 263 | var ifblock = Expression.IfThenElse(condition, ifTrue, ifFalse); 264 | exprs.Add(ifblock); 265 | } 266 | else 267 | { 268 | var k = CompileSingleExpression(kvpair.Key, Context); 269 | var v = CompileSingleExpression(kvpair.Value, Context); 270 | 271 | exprs.Add(Expression.Call(variable, add, k, v)); 272 | } 273 | i++; 274 | } 275 | exprs.Add(Expression.Call(LuaObject_Type.GetMethod("FromTable"), variable)); 276 | var block = Expression.Block(new[] { variable }, exprs.ToArray()); 277 | return Expression.Invoke(Expression.Lambda>(block)); 278 | } 279 | 280 | static Expression CompileVarargs(Expression Context) 281 | { 282 | return Expression.Property(Context, "Varargs"); 283 | } 284 | 285 | static Expression CompileFunctionDef(FunctionDefinition def, Expression Context) 286 | { 287 | return Expression.Invoke(CompileFunction(def, Context)); 288 | } 289 | 290 | static Expression CompileFunctionCallExpr(Ast.FunctionCall expr, Expression Context) 291 | { 292 | var function = CompileSingleExpression(expr.Function, Context); 293 | var args = new List(); 294 | Expression lastArg = null; 295 | int i = 0; 296 | foreach (IExpression e in expr.Arguments) 297 | { 298 | if (i == expr.Arguments.Count - 1) 299 | lastArg = CompileExpression(e, Context); 300 | else 301 | args.Add(CompileSingleExpression(e, Context)); 302 | i++; 303 | } 304 | var arg = Expression.NewArrayInit(LuaObject_Type, args.ToArray()); 305 | var luaarg = Expression.New(LuaArguments_New, arg); 306 | 307 | if (lastArg == null) 308 | return Expression.Call(function, LuaObject_Call, luaarg); 309 | else 310 | return Expression.Call(function, LuaObject_Call, Expression.Call(luaarg, LuaArguments_Concat, lastArg)); 311 | } 312 | 313 | public static Expression> CompileFunction(Ast.FunctionDefinition func, Expression Context) 314 | { 315 | var exprs = new List(); 316 | 317 | var args = Expression.Parameter(LuaArguments_Type, "args"); 318 | var label = Expression.Label(LuaArguments_Type, "exit"); 319 | var @break = Expression.Label("break"); 320 | 321 | var scopeVar = Expression.Parameter(LuaContext_Type, "funcScope"); 322 | var assignScope = Expression.Assign(scopeVar, Expression.New(LuaContext_New_parent, Context)); 323 | 324 | #region Arguments init 325 | var len = Expression.Property(args, "Length"); 326 | var argLen = Expression.Constant(func.Arguments.Count); 327 | var argCount = Expression.Constant(func.Arguments.Count); 328 | 329 | var i = Expression.Parameter(typeof(int), "i"); 330 | var assignI = Expression.Assign(i, Expression.Constant(0)); 331 | var names = Expression.Parameter(typeof(string[]), "names"); 332 | var assignNames = Expression.Assign(names, Expression.Constant(Array.ConvertAll(func.Arguments.ToArray(), x => x.Name))); 333 | 334 | var innerCond = Expression.LessThan(i, argLen); 335 | var outerCond = Expression.LessThan(i, len); 336 | 337 | var innerIf = Expression.Call(scopeVar, LuaContext_SetLocal, Expression.ArrayAccess(names, i), Expression.Property(args, "Item", i)); 338 | var varargs = Expression.Property(scopeVar, "Varargs"); 339 | var innerElse = Expression.Call(varargs, LuaArguments_Add, Expression.Property(args, "Item", i)); 340 | 341 | var outerIf = Expression.Block(Expression.IfThenElse(innerCond, innerIf, innerElse), Expression.Assign(i, Expression.Add(i, Expression.Constant(1)))); 342 | var outerElse = Expression.Break(@break); 343 | 344 | var loopBody = Expression.IfThenElse(outerCond, outerIf, outerElse); 345 | var loop = Expression.Loop(loopBody); 346 | 347 | var breakLabel = Expression.Label(@break); 348 | #endregion 349 | 350 | var body = CompileBlock(func.Body, label, null, scopeVar); 351 | 352 | exprs.Add(assignScope); 353 | exprs.Add(assignI); 354 | exprs.Add(assignNames); 355 | exprs.Add(loop); 356 | exprs.Add(breakLabel); 357 | exprs.Add(body); 358 | exprs.Add(Expression.Label(label, Expression.Constant(VoidArguments))); 359 | 360 | var funcBody = Expression.Block(new[] { i, names, scopeVar }, exprs.ToArray()); 361 | 362 | var function = Expression.Lambda(funcBody, args); 363 | var returnValue = Expression.Lambda>(Expression.Convert(function, LuaObject_Type), null); 364 | 365 | return returnValue; 366 | } 367 | #endregion 368 | 369 | #region Statements 370 | static Expression SetVariable(Ast.Variable expr, Expression value, Expression Context) 371 | { 372 | if (expr.Prefix == null) 373 | return Expression.Call(Context, LuaContext_Set, Expression.Constant(expr.Name), value); 374 | else 375 | { 376 | var prefix = CompileSingleExpression(expr.Prefix, Context); 377 | var index = Expression.Constant((LuaObject)(expr.Name)); 378 | var set = Expression.Property(prefix, "Item", index); 379 | return Expression.Assign(set, value); 380 | } 381 | } 382 | 383 | static Expression CompileAssignment(Ast.Assignment assign, Expression Context) 384 | { 385 | var variable = Expression.Parameter(typeof(LuaArguments), "vars"); 386 | var stats = new List(); 387 | 388 | stats.Add(Expression.Assign(variable, Expression.New(LuaArguments_New_void))); 389 | foreach (IExpression expr in assign.Expressions) 390 | { 391 | var ret = CompileExpression(expr, Context); 392 | stats.Add(Expression.Call(variable, LuaArguments_Concat, ret)); 393 | } 394 | int i = 0; 395 | foreach (IAssignable var in assign.Variables) 396 | { 397 | var arg = GetArgument(variable, i); 398 | if (var is Ast.Variable) 399 | { 400 | var x = var as Ast.Variable; 401 | stats.Add(SetVariable(x, arg, Context)); 402 | } 403 | else if (var is Ast.TableAccess) 404 | { 405 | var x = var as Ast.TableAccess; 406 | 407 | var expression = CompileSingleExpression(x.Expression, Context); 408 | var index = CompileSingleExpression(x.Index, Context); 409 | 410 | var set = Expression.Property(expression, "Item", index); 411 | stats.Add(Expression.Assign(set, arg)); 412 | } 413 | i++; 414 | } 415 | 416 | return Expression.Block(new[] { variable }, stats.ToArray()); 417 | } 418 | 419 | static Expression CompileLocalAssignment(Ast.LocalAssignment assign, Expression Context) 420 | { 421 | var variable = Expression.Parameter(typeof(LuaArguments), "vars"); 422 | var stats = new List(); 423 | 424 | stats.Add(Expression.Assign(variable, Expression.New(LuaArguments_New_void))); 425 | foreach (IExpression expr in assign.Values) 426 | { 427 | var ret = CompileExpression(expr, Context); 428 | stats.Add(Expression.Call(variable, LuaArguments_Concat, ret)); 429 | } 430 | int i = 0; 431 | foreach (string var in assign.Names) 432 | { 433 | var arg = GetArgument(variable, i); 434 | stats.Add(Expression.Call(Context, LuaContext_SetLocal, Expression.Constant(var), arg)); 435 | i++; 436 | } 437 | 438 | return Expression.Block(new[] { variable }, stats.ToArray()); 439 | } 440 | 441 | static Expression CompileFunctionCallStat(Ast.FunctionCall call, Expression Context) 442 | { 443 | var variable = Expression.Parameter(typeof(LuaArguments), "vars"); 444 | var stats = new List(); 445 | 446 | stats.Add(Expression.Assign(variable, Expression.New(LuaArguments_New_void))); 447 | 448 | var expression = CompileSingleExpression(call.Function, Context); 449 | int i = 0; 450 | 451 | foreach (Ast.IExpression arg in call.Arguments) 452 | { 453 | if (i == call.Arguments.Count - 1) 454 | { 455 | var exp = CompileExpression(arg, Context); 456 | stats.Add(Expression.Call(variable, LuaArguments_Concat, exp)); 457 | } 458 | else 459 | { 460 | var exp = CompileSingleExpression(arg, Context); 461 | stats.Add(Expression.Call(variable, LuaArguments_Add, exp)); 462 | } 463 | i++; 464 | } 465 | stats.Add(Expression.Call(expression, LuaObject_Call, variable)); 466 | 467 | return Expression.Block(new[] { variable }, stats.ToArray()); 468 | } 469 | 470 | static Expression CompileBlock(Ast.Block block, LabelTarget returnTarget, LabelTarget breakTarget, Expression Context) 471 | { 472 | var exprs = new List(); 473 | var scope = Expression.Parameter(LuaContext_Type); 474 | exprs.Add(Expression.Assign(scope, Context)); 475 | 476 | foreach (IStatement s in block.Statements) 477 | { 478 | exprs.Add(CompileStatement(s, returnTarget, breakTarget, scope)); 479 | } 480 | 481 | return Expression.Block(new[] { scope }, exprs.ToArray()); 482 | } 483 | 484 | static Expression CompileWhileStat(Ast.WhileStat stat, LabelTarget returnTarget, Expression Context) 485 | { 486 | var cond = GetAsBool(CompileSingleExpression(stat.Condition, Context)); 487 | var breakTarget = Expression.Label("break"); 488 | var loopBody = CompileBlock(stat.Block, returnTarget, breakTarget, Expression.New(LuaContext_New_parent, Context)); 489 | var condition = Expression.IfThenElse(cond, loopBody, Expression.Break(breakTarget)); 490 | var loop = Expression.Loop(condition); 491 | 492 | return Expression.Block(loop, Expression.Label(breakTarget)); 493 | } 494 | 495 | static Expression CompileIfStat(Ast.IfStat ifstat, LabelTarget returnTarget, LabelTarget breakTarget, Expression Context) 496 | { 497 | var condition = GetAsBool(CompileSingleExpression(ifstat.Condition, Context)); 498 | var block = CompileBlock(ifstat.Block, returnTarget, breakTarget, Expression.New(LuaContext_New_parent, Context)); 499 | 500 | if (ifstat.ElseIfs.Count == 0) 501 | { 502 | if (ifstat.ElseBlock == null) 503 | return Expression.IfThen(condition, block); 504 | else 505 | { 506 | var elseBlock = CompileBlock(ifstat.ElseBlock, returnTarget, breakTarget, Expression.New(LuaContext_New_parent, Context)); 507 | return Expression.IfThenElse(condition, block, elseBlock); 508 | } 509 | } 510 | else 511 | { 512 | Expression b = null; 513 | for (int i = ifstat.ElseIfs.Count - 1; i >= 0; i--) 514 | { 515 | IfStat branch = ifstat.ElseIfs[i]; 516 | var cond = GetAsBool(CompileSingleExpression(branch.Condition, Context)); 517 | var body = CompileBlock(branch.Block, returnTarget, breakTarget, Expression.New(LuaContext_New_parent, Context)); 518 | if (b == null) 519 | { 520 | if (ifstat.ElseBlock == null) 521 | b = Expression.IfThen(cond, body); 522 | else 523 | { 524 | var elseBlock = CompileBlock(ifstat.ElseBlock, returnTarget, breakTarget, Expression.New(LuaContext_New_parent, Context)); 525 | b = Expression.IfThenElse(cond, body, elseBlock); 526 | } 527 | } 528 | else 529 | b = Expression.IfThenElse(cond, body, b); 530 | } 531 | 532 | var tree = Expression.IfThenElse(condition, block, b); 533 | return tree; 534 | } 535 | } 536 | 537 | static Expression CompileReturnStat(Ast.ReturnStat ret, LabelTarget returnTarget, Expression Context) 538 | { 539 | var variable = Expression.Parameter(LuaArguments_Type); 540 | var body = new List(); 541 | var ctor = Expression.New(LuaArguments_New_void); 542 | body.Add(Expression.Assign(variable, ctor)); 543 | 544 | int i = 0; 545 | foreach (IExpression expr in ret.Expressions) 546 | { 547 | if (i == ret.Expressions.Count - 1) 548 | { 549 | var exp = CompileExpression(expr, Context); 550 | body.Add(Expression.Call(variable, LuaArguments_Concat, exp)); 551 | } 552 | else 553 | { 554 | var exp = CompileSingleExpression(expr, Context); 555 | body.Add(Expression.Call(variable, LuaArguments_Add, exp)); 556 | } 557 | } 558 | 559 | body.Add(Expression.Return(returnTarget, variable)); 560 | 561 | return Expression.Block(new[] { variable }, body.ToArray()); 562 | } 563 | 564 | static Expression CompileRepeatStatement(Ast.RepeatStat stat, LabelTarget returnTarget, Expression Context) 565 | { 566 | var ctx = Expression.New(LuaContext_New_parent, Context); 567 | var scope = Expression.Parameter(LuaContext_Type); 568 | var assignScope = Expression.Assign(scope, ctx); 569 | var @break = Expression.Label(); 570 | 571 | var condition = GetAsBool(CompileSingleExpression(stat.Condition, scope)); 572 | var body = CompileBlock(stat.Block, returnTarget, @break, scope); 573 | var check = Expression.IfThen(condition, Expression.Break(@break)); 574 | var loop = Expression.Loop(Expression.Block(body, check)); 575 | var block = Expression.Block(new[] { scope }, assignScope, loop, Expression.Label(@break)); 576 | return block; 577 | } 578 | 579 | static Expression CompileNumericFor(Ast.NumericFor stat, LabelTarget returnTarget, Expression Context) 580 | { 581 | var varValue = ToNumber(CompileSingleExpression(stat.Var, Context)); 582 | var limit = ToNumber(CompileSingleExpression(stat.Limit, Context)); 583 | var step = ToNumber(CompileSingleExpression(stat.Step, Context)); 584 | 585 | var var = Expression.Parameter(LuaObject_Type); 586 | var scope = Expression.Parameter(LuaContext_Type); 587 | var @break = Expression.Label(); 588 | var assignScope = Expression.Assign(scope, Expression.New(LuaContext_New_parent, Context)); 589 | var assignVar = Expression.Assign(var, varValue); 590 | 591 | var condition = 592 | Expression.Or( 593 | Expression.And( 594 | Expression.GreaterThan(step, Expression.Constant((LuaObject)0)), 595 | Expression.LessThanOrEqual(var, limit)), 596 | Expression.And( 597 | Expression.LessThanOrEqual(step, Expression.Constant((LuaObject)0)), 598 | Expression.GreaterThanOrEqual(var, limit))); 599 | var setLocalVar = Expression.Call(scope, LuaContext_SetLocal, Expression.Constant(stat.Variable), var); 600 | var innerBlock = CompileBlock(stat.Block, returnTarget, @break, scope); 601 | var sum = Expression.Assign(var, Expression.Add(var, step)); 602 | var check = Expression.IfThenElse(GetAsBool(condition), Expression.Block(setLocalVar, innerBlock, sum), Expression.Break(@break)); 603 | var loop = Expression.Loop(check); 604 | 605 | var body = Expression.Block(new[]{var, scope}, assignScope, assignVar, loop, Expression.Label(@break)); 606 | 607 | return body; 608 | } 609 | 610 | static Expression CompileGenericFor(Ast.GenericFor stat, LabelTarget returnTarget, Expression Context) 611 | { 612 | var body = new List(); 613 | var args = Expression.Parameter(LuaArguments_Type); 614 | var f = GetArgument(args, 0); 615 | var s = GetArgument(args, 1); 616 | var var = GetArgument(args, 2); 617 | var fVar = Expression.Parameter(LuaObject_Type); 618 | var sVar = Expression.Parameter(LuaObject_Type); 619 | var varVar = Expression.Parameter(LuaObject_Type); 620 | var scope = Expression.Parameter(LuaContext_Type); 621 | 622 | var @break = Expression.Label(); 623 | 624 | body.Add(Expression.Assign(args, Expression.New(LuaArguments_New_void))); 625 | foreach (IExpression expr in stat.Expressions) 626 | { 627 | body.Add(Expression.Call(args, LuaArguments_Concat,CompileExpression(expr, Context))); 628 | } 629 | body.Add(Expression.Assign(fVar, f)); 630 | body.Add(Expression.Assign(sVar, s)); 631 | body.Add(Expression.Assign(varVar, var)); 632 | 633 | body.Add(Expression.Assign(scope, Expression.New(LuaContext_New_parent, Context))); 634 | 635 | var res = Expression.Parameter(LuaArguments_Type); 636 | var buildArgs = Expression.New(LuaArguments_New, Expression.NewArrayInit(typeof(LuaObject), sVar, varVar)); 637 | var resAssign = Expression.Assign(res, Expression.Call(fVar, LuaObject_Call, buildArgs)); 638 | List exprs = new List(); 639 | exprs.Add(resAssign); 640 | for (int i = 0; i < stat.Variables.Count; i++) 641 | { 642 | var val = GetArgument(res, i); 643 | exprs.Add(Expression.Call(scope, LuaContext_SetLocal, Expression.Constant(stat.Variables[i]), val)); 644 | } 645 | var check = Expression.IfThen(Expression.Property(GetArgument(res, 0), "IsNil"), Expression.Break(@break)); 646 | exprs.Add(check); 647 | exprs.Add(Expression.Assign(varVar, GetFirstArgument(res))); 648 | exprs.Add(CompileBlock(stat.Block, returnTarget, @break, scope)); 649 | 650 | var loopBody = Expression.Block(new[] { res }, exprs.ToArray()); 651 | var loop = Expression.Loop(loopBody); 652 | body.Add(loop); 653 | body.Add(Expression.Label(@break)); 654 | 655 | var block = Expression.Block(new[] { args, scope, fVar, sVar, varVar }, body.ToArray()); 656 | 657 | return block; 658 | } 659 | 660 | static Expression CompileStatement(IStatement stat, LabelTarget returnTarget, LabelTarget breakTarget, Expression Context) 661 | { 662 | if (stat is Ast.Assignment) 663 | return CompileAssignment(stat as Ast.Assignment, Context); 664 | else if (stat is Ast.LocalAssignment) 665 | return CompileLocalAssignment(stat as Ast.LocalAssignment, Context); 666 | else if (stat is Ast.FunctionCall) 667 | return CompileFunctionCallStat(stat as Ast.FunctionCall, Context); 668 | else if (stat is Ast.Block) 669 | return CompileBlock(stat as Ast.Block, returnTarget, breakTarget, Context); 670 | else if (stat is Ast.IfStat) 671 | return CompileIfStat(stat as Ast.IfStat, returnTarget, breakTarget, Context); 672 | else if (stat is Ast.ReturnStat) 673 | return CompileReturnStat(stat as Ast.ReturnStat, returnTarget, Context); 674 | else if (stat is Ast.BreakStat) 675 | return Expression.Break(breakTarget); 676 | else if (stat is Ast.WhileStat) 677 | return CompileWhileStat(stat as Ast.WhileStat, returnTarget, Context); 678 | else if (stat is Ast.RepeatStat) 679 | return CompileRepeatStatement(stat as Ast.RepeatStat, returnTarget, Context); 680 | else if (stat is Ast.GenericFor) 681 | return CompileGenericFor(stat as Ast.GenericFor, returnTarget, Context); 682 | else if (stat is Ast.NumericFor) 683 | return CompileNumericFor(stat as Ast.NumericFor, returnTarget, Context); 684 | else 685 | throw new NotImplementedException(); 686 | } 687 | #endregion 688 | } 689 | } 690 | -------------------------------------------------------------------------------- /NetLua/LuaContext.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * See LICENSE file 3 | */ 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | 10 | using System.Dynamic; 11 | 12 | namespace NetLua 13 | { 14 | /// 15 | /// Holds a scope and its variables 16 | /// 17 | public class LuaContext : DynamicObject 18 | { 19 | LuaContext parent; 20 | Dictionary variables; 21 | LuaArguments varargs; 22 | 23 | /// 24 | /// Used to create scopes 25 | /// 26 | public LuaContext(LuaContext Parent) 27 | { 28 | parent = Parent; 29 | variables = new Dictionary(); 30 | varargs = new LuaArguments(new LuaObject[] { }); 31 | } 32 | 33 | /// 34 | /// Creates a base context 35 | /// 36 | public LuaContext() : this(null) { } 37 | 38 | /// 39 | /// Sets or creates a variable in the local scope 40 | /// 41 | public void SetLocal(string Name, LuaObject Value) 42 | { 43 | variables[Name] = Value; 44 | } 45 | 46 | /// 47 | /// Sets or creates a variable in the global scope 48 | /// 49 | public void SetGlobal(string Name, LuaObject Value) 50 | { 51 | if (parent == null) 52 | variables[Name] = Value; 53 | else 54 | parent.SetGlobal(Name, Value); 55 | } 56 | 57 | /// 58 | /// Returns the nearest declared variable value or nil 59 | /// 60 | public LuaObject Get(string Name) 61 | { 62 | var obj = LuaObject.Nil; 63 | if (variables.TryGetValue(Name, out obj) || parent == null) 64 | { 65 | if (obj == null) 66 | return LuaObject.Nil; 67 | else 68 | return obj; 69 | } 70 | else 71 | { 72 | return parent.Get(Name); 73 | } 74 | } 75 | 76 | /// 77 | /// Sets the nearest declared variable or creates a new one 78 | /// 79 | public void Set(string Name, LuaObject Value) 80 | { 81 | var obj = LuaObject.Nil; 82 | if (parent == null || variables.TryGetValue(Name, out obj)) 83 | variables[Name] = Value; 84 | else 85 | parent.Set(Name, Value); 86 | } 87 | 88 | internal LuaArguments Varargs 89 | { 90 | get 91 | { 92 | return varargs; 93 | } 94 | 95 | set 96 | { 97 | varargs = value; 98 | } 99 | } 100 | 101 | #region DynamicObject 102 | public override bool TryGetMember(GetMemberBinder binder, out object result) 103 | { 104 | result = Get(binder.Name); 105 | if (result == LuaObject.Nil) 106 | return false; 107 | return true; 108 | } 109 | 110 | public override bool TrySetMember(SetMemberBinder binder, object value) 111 | { 112 | Set(binder.Name, LuaObject.FromObject(value)); 113 | return true; 114 | } 115 | #endregion 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /NetLua/LuaEvents.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * See LICENSE file 3 | */ 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | 10 | namespace NetLua 11 | { 12 | static class LuaEvents 13 | { 14 | // This is all based on the Lua 5.2 manual 15 | // http://www.lua.org/manual/5.2/manual.html#2.4 16 | 17 | public static LuaObject rawget(LuaObject table, LuaObject index) 18 | { 19 | if (table.IsTable) 20 | { 21 | LuaObject obj; 22 | if (table.AsTable().TryGetValue(index, out obj)) 23 | return obj; 24 | else 25 | return LuaObject.Nil; 26 | } 27 | else 28 | throw new LuaException("Invalid operation"); 29 | } 30 | 31 | public static void rawset(LuaObject table, LuaObject key, LuaObject value) 32 | { 33 | if (table.IsTable) 34 | { 35 | var t = table.AsTable(); 36 | if (t.ContainsKey(key)) 37 | t[key] = value; 38 | else 39 | t.Add(key, value); 40 | } 41 | else 42 | throw new LuaException("Invalid operation"); 43 | } 44 | 45 | static LuaObject getBinhandler(LuaObject a, LuaObject b, string f) 46 | { 47 | var f1 = getMetamethod(a, f); 48 | var f2 = getMetamethod(b, f); 49 | 50 | return f1 | f2; 51 | } 52 | 53 | static LuaObject getEqualhandler(LuaObject a, LuaObject b) 54 | { 55 | if ((a.Type != b.Type) || (a.IsTable && b.IsUserData)) 56 | return LuaObject.Nil; 57 | var mm1 = getMetamethod(a, "__eq"); 58 | var mm2 = getMetamethod(b, "__eq"); 59 | if (mm1 == mm2) 60 | return mm1; 61 | else 62 | return LuaObject.Nil; 63 | } 64 | 65 | internal static LuaObject toNumber(LuaObject obj) 66 | { 67 | if (obj.IsNumber) 68 | return LuaObject.FromNumber(obj.AsNumber()); 69 | else if (obj.IsString) 70 | { 71 | double d; 72 | if (double.TryParse(obj.AsString(), out d)) 73 | return LuaObject.FromNumber(d); 74 | else 75 | return LuaObject.Nil; 76 | } 77 | else 78 | return LuaObject.Nil; 79 | } 80 | 81 | internal static bool ConvertToNumber(LuaObject obj, out double value) 82 | { 83 | if (obj.IsNumber) 84 | { 85 | value = (double)obj.luaobj; 86 | return true; 87 | } 88 | else if (obj.IsString) 89 | { 90 | if (double.TryParse(obj.AsString(), out value)) 91 | return true; 92 | else 93 | return false; 94 | } 95 | else 96 | { 97 | value = 0d; 98 | return false; 99 | } 100 | } 101 | 102 | internal static LuaObject getMetamethod(LuaObject obj, string e) 103 | { 104 | if (obj.Metatable == null || obj.Metatable.IsNil) 105 | return LuaObject.Nil; 106 | else 107 | return obj.Metatable[e]; 108 | } 109 | 110 | internal static LuaObject add_event(LuaObject op1, LuaObject op2) 111 | { 112 | double a, b; 113 | 114 | if (ConvertToNumber(op1, out a) && ConvertToNumber(op2, out b)) 115 | return LuaObject.FromNumber(a + b); 116 | else 117 | { 118 | var handler = getBinhandler(op1, op2, "__add"); 119 | if (!handler.IsNil) 120 | return handler.Call(op1, op2)[0]; 121 | } 122 | 123 | throw new LuaException("Invalid arithmetic operation"); 124 | } 125 | 126 | internal static LuaObject sub_event(LuaObject op1, LuaObject op2) 127 | { 128 | double a, b; 129 | 130 | if (ConvertToNumber(op1, out a) && ConvertToNumber(op2, out b)) 131 | return LuaObject.FromNumber(a - b); 132 | else 133 | { 134 | var handler = getBinhandler(op1, op2, "__sub"); 135 | if (!handler.IsNil) 136 | return handler.Call(op1, op2)[0]; 137 | } 138 | 139 | throw new LuaException("Invalid arithmetic operation"); 140 | } 141 | 142 | internal static LuaObject mul_event(LuaObject op1, LuaObject op2) 143 | { 144 | double a, b; 145 | 146 | if (ConvertToNumber(op1, out a) && ConvertToNumber(op2, out b)) 147 | return LuaObject.FromNumber(a * b); 148 | else 149 | { 150 | var handler = getBinhandler(op1, op2, "__mul"); 151 | if (!handler.IsNil) 152 | return handler.Call(op1, op2)[0]; 153 | } 154 | 155 | throw new LuaException("Invalid arithmetic operation"); 156 | } 157 | 158 | internal static LuaObject div_event(LuaObject op1, LuaObject op2) 159 | { 160 | double a, b; 161 | 162 | if (ConvertToNumber(op1, out a) && ConvertToNumber(op2, out b)) 163 | return LuaObject.FromNumber(a / b); 164 | else 165 | { 166 | var handler = getBinhandler(op1, op2, "__div"); 167 | if (!handler.IsNil) 168 | return handler.Call(op1, op2)[0]; 169 | } 170 | 171 | throw new LuaException("Invalid arithmetic operation"); 172 | } 173 | 174 | internal static LuaObject mod_event(LuaObject op1, LuaObject op2) 175 | { 176 | double a, b; 177 | 178 | if (ConvertToNumber(op1, out a) && ConvertToNumber(op2, out b)) 179 | return LuaObject.FromNumber(a - Math.Floor(a / b) * b); 180 | else 181 | { 182 | var handler = getBinhandler(op1, op2, "__mod"); 183 | if (!handler.IsNil) 184 | return handler.Call(op1, op2)[0]; 185 | } 186 | 187 | throw new LuaException("Invalid arithmetic operation"); 188 | } 189 | 190 | internal static LuaObject pow_event(LuaObject op1, LuaObject op2) 191 | { 192 | double a, b; 193 | 194 | if (ConvertToNumber(op1, out a) && ConvertToNumber(op2, out b)) 195 | return LuaObject.FromNumber(Math.Pow(a, b)); 196 | else 197 | { 198 | var handler = getBinhandler(op1, op2, "__pow"); 199 | if (!handler.IsNil) 200 | return handler.Call(op1, op2)[0]; 201 | } 202 | 203 | throw new LuaException("Invalid arithmetic operation"); 204 | } 205 | 206 | internal static LuaObject unm_event(LuaObject op) 207 | { 208 | double a; 209 | 210 | if (ConvertToNumber(op, out a)) 211 | { 212 | return LuaObject.FromNumber(-a); 213 | } 214 | else 215 | { 216 | var handler = getMetamethod(op, "__unm"); 217 | if (!handler.IsNil) 218 | return handler.Call(op)[0]; 219 | } 220 | 221 | throw new LuaException("Invalid arithmetic operation"); 222 | } 223 | 224 | internal static LuaObject index_event(LuaObject table, LuaObject key) 225 | { 226 | LuaObject handler; 227 | 228 | if (table.IsTable) 229 | { 230 | var v = rawget(table, key); 231 | if (!v.IsNil) 232 | return v; 233 | else 234 | { 235 | handler = getMetamethod(table, "__index"); 236 | if (handler.IsNil) 237 | return LuaObject.Nil; 238 | } 239 | } 240 | else 241 | { 242 | handler = getMetamethod(table, "__index"); 243 | if (handler.IsNil) 244 | throw new LuaException("Invalid argument"); 245 | } 246 | 247 | if (handler.IsFunction) 248 | return handler.AsFunction()(new LuaObject[]{table, key})[0]; 249 | else if (!handler.IsNil) 250 | return handler[key]; 251 | else 252 | return LuaObject.Nil; 253 | } 254 | 255 | internal static LuaObject newindex_event(LuaObject table, LuaObject key, LuaObject value) 256 | { 257 | LuaObject handler; 258 | if (table.IsTable) 259 | { 260 | var v = rawget(table, key); 261 | if (!v.IsNil) 262 | { 263 | rawset(table, key, value); 264 | return LuaObject.Nil; 265 | } 266 | handler = getMetamethod(table, "__newindex"); 267 | if (handler.IsNil) 268 | { 269 | rawset(table, key, value); 270 | return LuaObject.Nil; 271 | } 272 | } 273 | else 274 | { 275 | handler = getMetamethod(table, "__newindex"); 276 | if (handler.IsNil) 277 | throw new LuaException("Invalid op"); 278 | } 279 | 280 | if (handler.IsFunction) 281 | handler.AsFunction()(new LuaObject[]{table, key, value}); 282 | else 283 | handler[key] = value; 284 | return LuaObject.Nil; 285 | } 286 | 287 | internal static LuaArguments call_event(LuaObject func, LuaArguments args) 288 | { 289 | if (func.IsFunction) 290 | return func.AsFunction()(args); 291 | else 292 | { 293 | var handler = getMetamethod(func, "__call"); 294 | if (handler.IsFunction) 295 | { 296 | var argslist = new List(); 297 | argslist.Add(func); argslist.AddRange(args); 298 | return handler.AsFunction()(argslist.ToArray()); 299 | } 300 | else 301 | throw new LuaException("Cannot call nonfunction"); 302 | } 303 | } 304 | 305 | internal static LuaObject len_event(LuaObject op) 306 | { 307 | if (op.IsString) 308 | return op.AsString().Length; 309 | else 310 | { 311 | var handler = getMetamethod(op, "__len"); 312 | if (!handler.IsNil) 313 | return handler.Call(op)[0]; 314 | else if (op.IsTable) 315 | return op.AsTable().Count; 316 | else 317 | throw new LuaException("Invalid op"); 318 | } 319 | } 320 | 321 | internal static LuaObject concat_event(LuaObject op1, LuaObject op2) 322 | { 323 | if ((op1.IsString || op1.IsNumber) && (op2.IsString || op2.IsNumber)) 324 | return string.Concat(op1, op2); 325 | else 326 | { 327 | var handler = getBinhandler(op1, op2, "__concat"); 328 | if (!handler.IsNil) 329 | return handler.Call(op1, op2)[0]; 330 | else 331 | throw new LuaException("Invalid op"); 332 | } 333 | } 334 | 335 | internal static LuaObject eq_event(LuaObject op1, LuaObject op2) 336 | { 337 | if (op1 == op2) 338 | return true; 339 | var handler = getEqualhandler(op1, op2); 340 | if (!handler.IsNil) 341 | return !(!(handler.Call(op1, op2)[0].AsBool())); 342 | else 343 | return false; 344 | } 345 | 346 | internal static LuaObject lt_event(LuaObject op1, LuaObject op2) 347 | { 348 | if (op1.IsNumber && op2.IsNumber) 349 | return op1.AsNumber() < op2.AsNumber(); 350 | else if (op1.IsString && op2.IsString) 351 | { 352 | int n = StringComparer.CurrentCulture.Compare(op1.AsString(), op2.AsString()); 353 | return (n < 0); 354 | } 355 | else 356 | { 357 | var handler = getBinhandler(op1, op2, "__lt"); 358 | if (!handler.IsNil) 359 | return !(!(handler.Call(op1, op2)[0].AsBool())); 360 | else 361 | throw new ArgumentException("attempt to compare " + op1.type.ToString() + " with " + op2.type.ToString()); 362 | } 363 | } 364 | 365 | internal static LuaObject le_event(LuaObject op1, LuaObject op2) 366 | { 367 | if (op1.IsNumber && op2.IsNumber) 368 | return op1.AsNumber() <= op2.AsNumber(); 369 | else if (op1.IsString && op2.IsString) 370 | { 371 | int n = StringComparer.CurrentCulture.Compare(op1.AsString(), op2.AsString()); 372 | return (n <= 0); 373 | } 374 | else 375 | { 376 | var handler = getBinhandler(op1, op2, "__le"); 377 | if (!handler.IsNil) 378 | return !(!(handler.Call(op1, op2)[0].AsBool())); 379 | else 380 | throw new ArgumentException("attempt to compare " + op1.type.ToString() + " with " + op2.type.ToString()); 381 | } 382 | } 383 | 384 | internal static LuaObject gc_event(LuaObject op) 385 | { 386 | var handler = getMetamethod(op, "__gc"); 387 | if (handler.IsFunction) 388 | handler.AsFunction()(new LuaObject[] {op}); 389 | return LuaObject.Nil; 390 | } 391 | 392 | internal static LuaObject tostring_event(LuaObject op) 393 | { 394 | var handler = getMetamethod(op, "__tostring"); 395 | if (!handler.IsNil) 396 | return handler.Call(op)[0]; 397 | else 398 | return op.ToString(); 399 | } 400 | } 401 | } 402 | -------------------------------------------------------------------------------- /NetLua/LuaGrammar.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * See LICENSE file 3 | */ 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | 10 | using Irony.Parsing; 11 | using Irony.Ast; 12 | 13 | namespace NetLua 14 | { 15 | class LuaGrammar : Grammar 16 | { 17 | public LuaGrammar() 18 | : base(true) 19 | { 20 | #region Terminals 21 | Terminal Identifier = new IdentifierTerminal("identifier"); 22 | Terminal SingleString = new StringLiteral("string", "'", StringOptions.AllowsAllEscapes); 23 | Terminal DoubleString = new StringLiteral("string", "\"", StringOptions.AllowsAllEscapes); 24 | Terminal Number = new NumberLiteral("number", NumberOptions.AllowSign); 25 | 26 | Terminal LineComment = new CommentTerminal("Comment", "--", "\n", "\r"); 27 | Terminal LongComment = new CommentTerminal("LongComment", "--[[", "]]"); 28 | 29 | base.NonGrammarTerminals.Add(LineComment); 30 | base.NonGrammarTerminals.Add(LongComment); 31 | #endregion 32 | 33 | #region Nonterminals 34 | NonTerminal Chunk = new NonTerminal("Chunk"); 35 | 36 | NonTerminal Prefix = new NonTerminal("Prefix"); 37 | NonTerminal Variable = new NonTerminal("Variable"); 38 | NonTerminal FunctionCall = new NonTerminal("FunctionCall"); 39 | NonTerminal CallArguments = new NonTerminal("FunctionCallArguments"); 40 | NonTerminal OopCall = new NonTerminal("OopCall"); 41 | NonTerminal CallArgumentsFragment = new NonTerminal(""); 42 | NonTerminal Expression = new NonTerminal("Expression"); 43 | NonTerminal FunctionDef = new NonTerminal("FunctionDef"); 44 | NonTerminal DefArguments = new NonTerminal("FunctionDefArguments"); 45 | NonTerminal DefArgumentsFragment = new NonTerminal(""); 46 | 47 | NonTerminal Statement = new NonTerminal("Statement"); 48 | NonTerminal ReturnStatement = new NonTerminal("ReturnStat"); 49 | NonTerminal BreakStatement = new NonTerminal("BreakStat"); 50 | NonTerminal Assignment = new NonTerminal("Assignment"); 51 | NonTerminal LocalAssignment = new NonTerminal("LocalAssignment"); 52 | NonTerminal FunctionDecl = new NonTerminal("FunctionDecl"); 53 | NonTerminal DoBlock = new NonTerminal("DoBlock"); 54 | NonTerminal If = new NonTerminal("If"); 55 | NonTerminal Elseif = new NonTerminal("Elseif"); 56 | NonTerminal Else = new NonTerminal("Else"); 57 | NonTerminal While = new NonTerminal("While"); 58 | NonTerminal Repeat = new NonTerminal("Repeat"); 59 | NonTerminal For = new NonTerminal("For"); 60 | 61 | NonTerminal PowerOp = new NonTerminal("PowerOp"); 62 | NonTerminal MulOp = new NonTerminal("MulOp"); 63 | NonTerminal AddOp = new NonTerminal("AddOp"); 64 | NonTerminal ConcatOp = new NonTerminal("ConcatOp"); 65 | NonTerminal RelOp = new NonTerminal("RelOp"); 66 | NonTerminal AndOp = new NonTerminal("AndOp"); 67 | NonTerminal OrOp = new NonTerminal("OrOp"); 68 | NonTerminal UnaryExpr = new NonTerminal("UnaryExpr"); 69 | 70 | NonTerminal TableConstruct = new NonTerminal("TableConstruct"); 71 | NonTerminal TableConstructFragment = new NonTerminal("TableConstructFragment"); 72 | #endregion 73 | 74 | #region Fragments 75 | CallArgumentsFragment.Rule = Expression | Expression + "," + CallArgumentsFragment; 76 | 77 | CallArguments.Rule = "(" + (CallArgumentsFragment | Empty) + ")"; 78 | 79 | DefArgumentsFragment.Rule = Identifier | Identifier + "," + DefArgumentsFragment; 80 | 81 | DefArguments.Rule = "(" + (DefArgumentsFragment | Empty) + ")"; 82 | 83 | Chunk.Rule = MakeStarRule(Chunk, Statement); 84 | #endregion 85 | 86 | #region Expressions 87 | PowerOp.Rule = Expression + ("^" + Expression | Empty); 88 | MulOp.Rule = PowerOp + ((ToTerm("*") | "/" | "%") + PowerOp | Empty); 89 | AddOp.Rule = MulOp + ((ToTerm("+") | "-") + MulOp | Empty); 90 | ConcatOp.Rule = AddOp + (".." + AddOp | Empty); 91 | RelOp.Rule = ConcatOp + ((ToTerm(">") | ">=" | "<" | "<=" | "==" | "~=") + ConcatOp | Empty); 92 | AndOp.Rule = RelOp + ("and" + RelOp | Empty); 93 | OrOp.Rule = AndOp + ("or" + AndOp | Empty); 94 | 95 | UnaryExpr.Rule = (ToTerm("not") | "-" | "#") + Expression; 96 | 97 | Prefix.Rule = 98 | OopCall 99 | | FunctionCall 100 | | Variable 101 | | "(" + Expression + ")"; 102 | 103 | Variable.Rule = 104 | Prefix + "." + Identifier 105 | | Prefix + "[" + Expression + "]" 106 | | Identifier; 107 | 108 | FunctionCall.Rule = Prefix + CallArguments; 109 | OopCall.Rule = Prefix + ":" + Identifier + CallArguments; 110 | 111 | FunctionDef.Rule = 112 | ToTerm("function") + DefArguments 113 | + Chunk + ToTerm("end"); 114 | 115 | var tableSep = new NonTerminal(""); 116 | tableSep.Rule = ToTerm(";") | ","; 117 | TableConstructFragment.Rule = 118 | ( 119 | ( 120 | ( 121 | (Identifier | "[" + Expression + "]") + "=" 122 | ) 123 | + Expression 124 | | Expression 125 | ) 126 | + (";" + TableConstructFragment | "," + TableConstructFragment | Empty) 127 | ) | Empty; 128 | TableConstruct.Rule = "{" + TableConstructFragment + "}"; 129 | 130 | var varargs = new NonTerminal("Varargs"); 131 | varargs.Rule = "..."; 132 | 133 | Expression.Rule = 134 | varargs 135 | | Prefix 136 | | OrOp 137 | | UnaryExpr 138 | | ToTerm("true") 139 | | "false" 140 | | "nil" 141 | | SingleString 142 | | DoubleString 143 | | Number 144 | | FunctionDef 145 | | TableConstruct; 146 | #endregion 147 | 148 | #region Statements 149 | FunctionDecl.Rule = "function" + Variable + (":" + Identifier | Empty) + DefArguments + Chunk + "end"; 150 | 151 | 152 | var RetChunk = new NonTerminal("RetChunk"); 153 | RetChunk.Rule = Expression + (("," + RetChunk) | Empty); 154 | 155 | ReturnStatement.Rule = 156 | "return" + (RetChunk | Empty); 157 | 158 | var AssignExpChunk = new NonTerminal("AssignExpChunk"); 159 | AssignExpChunk.Rule = Expression + (("," + AssignExpChunk) | Empty); 160 | var AssignVarChunk = new NonTerminal("AssignVarChunk"); 161 | AssignVarChunk.Rule = Variable + (("," + AssignVarChunk) | Empty); 162 | 163 | Assignment.Rule = 164 | AssignVarChunk + "=" + AssignExpChunk; 165 | 166 | var LocalAssignNameChunk = new NonTerminal("AssignNameChunk"); 167 | var LocalFunction = new NonTerminal("LocalFunction"); 168 | LocalAssignNameChunk.Rule = Identifier + (("," + LocalAssignNameChunk) | Empty); 169 | LocalFunction.Rule = "function" + Identifier + DefArguments + Chunk + "end"; 170 | LocalAssignment.Rule = "local" + (LocalAssignNameChunk + ("=" + AssignExpChunk | Empty) | LocalFunction); 171 | 172 | Elseif.Rule = "elseif" + Expression + "then" + Chunk + (Elseif | Empty); 173 | Else.Rule = "else" + Chunk; 174 | 175 | If.Rule = "if" + Expression + "then" + Chunk + (Elseif | Empty) + (Else | Empty) + "end"; 176 | 177 | While.Rule = "while" + Expression + DoBlock; 178 | 179 | DoBlock.Rule = "do" + Chunk + "end"; 180 | 181 | Repeat.Rule = "repeat" + Chunk + "until" + Expression; 182 | 183 | BreakStatement.Rule = "break"; 184 | 185 | var NumericFor = new NonTerminal("NumericFor"); 186 | NumericFor.Rule = Identifier + "=" + Expression + "," + Expression + ("," + Expression | Empty); 187 | var GenericFor = new NonTerminal("GenericFor"); 188 | var NameList = new NonTerminal("NameList"); 189 | var ExpList = new NonTerminal("ExpList"); 190 | NameList.Rule = Identifier + (("," + NameList) | Empty); 191 | ExpList.Rule = Expression + (("," + ExpList) | Empty); 192 | GenericFor.Rule = NameList + "in" + ExpList; 193 | 194 | For.Rule = "for" + (GenericFor | NumericFor) + DoBlock; 195 | 196 | Statement.Rule = 197 | ";" 198 | | ReturnStatement 199 | | BreakStatement 200 | | Assignment 201 | | LocalAssignment 202 | | FunctionCall 203 | | OopCall 204 | | FunctionDecl 205 | | For 206 | | If 207 | | While 208 | | DoBlock 209 | | Repeat; 210 | #endregion 211 | 212 | this.Root = Chunk; 213 | this.MarkReservedWords( 214 | "true", "false", 215 | "nil", "local", 216 | "function", "while", 217 | "if", "for", "repeat", "until", 218 | "end", "do", "return", "break"); 219 | 220 | this.MarkPunctuation(".", ",", ";", "(", ")", "[", "]", "{", "}", "=", ":"); 221 | this.MarkTransient(Statement); 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /NetLua/LuaObject.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * See LICENSE file 3 | */ 4 | 5 | using System; 6 | using System.Linq; 7 | using System.Collections; 8 | using System.Collections.Generic; 9 | using System.Threading; 10 | 11 | using System.Dynamic; 12 | 13 | namespace NetLua 14 | { 15 | using LuaTable = IDictionary; 16 | using LuaTableImpl = Dictionary; 17 | using LuaTableItem = KeyValuePair; 18 | 19 | /// 20 | /// An exception thrown by the Lua interpreter 21 | /// 22 | public class LuaException : Exception 23 | { 24 | /// 25 | /// An exception thrown by a syntactical error 26 | /// 27 | /// The file wich contains the error 28 | /// The row of the error 29 | /// The column of the error 30 | /// The kind of the error 31 | public LuaException(string file, int row, int col, string message) 32 | : base(string.Format("Error in {0}({1},{2}): {3}", file, row, col, message)) 33 | { } 34 | 35 | public LuaException(string message) 36 | : base("Error (unknown context): " + message) 37 | { } 38 | } 39 | 40 | /// 41 | /// A Lua function 42 | /// 43 | public delegate LuaArguments LuaFunction(LuaArguments args); 44 | 45 | public class LuaArguments : IEnumerable 46 | { 47 | List list; 48 | 49 | public LuaArguments() 50 | { 51 | list = new List(); 52 | } 53 | 54 | public LuaArguments(List List) 55 | { 56 | list = List; 57 | } 58 | 59 | public LuaArguments(params LuaObject[] Objects) 60 | { 61 | list = new List(Objects); 62 | } 63 | 64 | public LuaArguments(params LuaArguments[] Objects) 65 | { 66 | foreach (LuaArguments arg in Objects) 67 | { 68 | if (list == null) 69 | list = new List(arg.list); 70 | else 71 | list.AddRange(arg.list); 72 | } 73 | } 74 | 75 | public int Length 76 | { 77 | get 78 | { 79 | return list.Count; 80 | } 81 | } 82 | 83 | public LuaObject this[int Index] 84 | { 85 | get 86 | { 87 | if (Index < list.Count) 88 | return list[Index]; 89 | else 90 | return LuaObject.Nil; 91 | } 92 | set 93 | { 94 | if (Index < list.Count) 95 | list[Index] = value; 96 | } 97 | } 98 | 99 | public void Add(LuaObject obj) 100 | { 101 | list.Add(obj); 102 | } 103 | 104 | public LuaArguments Concat(LuaArguments args) 105 | { 106 | list.AddRange(args.list); 107 | return this; 108 | } 109 | 110 | public IEnumerator GetEnumerator() 111 | { 112 | return list.GetEnumerator(); 113 | } 114 | 115 | IEnumerator IEnumerable.GetEnumerator() 116 | { 117 | return this.GetEnumerator(); 118 | } 119 | 120 | public static implicit operator LuaArguments(LuaObject[] array) 121 | { 122 | return new LuaArguments(array); 123 | } 124 | 125 | public static implicit operator LuaObject[] (LuaArguments args) 126 | { 127 | return args.list.ToArray(); 128 | } 129 | 130 | public LuaArguments GetSubset(int startIndex) 131 | { 132 | if (startIndex >= list.Count) 133 | { 134 | return new LuaArguments(new LuaObject[] { }); 135 | } 136 | else 137 | { 138 | return new LuaArguments(list.GetRange(startIndex, list.Count - startIndex)); 139 | } 140 | } 141 | } 142 | 143 | // http://www.lua.org/pil/2.html 144 | /// 145 | /// A Lua type 146 | /// 147 | public enum LuaType : byte 148 | { 149 | nil = 0, 150 | boolean, 151 | number, 152 | @string, 153 | userdata, 154 | function, 155 | thread, 156 | table 157 | } 158 | 159 | /// 160 | /// A Lua object. Can be any of the standard Lua objects 161 | /// 162 | public class LuaObject : DynamicObject, IEnumerable> 163 | { 164 | internal object luaobj; 165 | internal LuaType type; 166 | private LuaObject metatable = Nil; 167 | 168 | public LuaObject() 169 | { 170 | this.metatable = Nil; 171 | } 172 | 173 | private LuaObject(object Obj, LuaType Type) 174 | { 175 | this.metatable = Nil; 176 | this.luaobj = Obj; 177 | this.type = Type; 178 | } 179 | 180 | ~LuaObject() 181 | { 182 | LuaEvents.gc_event(this); 183 | } 184 | 185 | /// 186 | /// Gets or sets the object's metatable 187 | /// 188 | public LuaObject Metatable 189 | { 190 | get 191 | { 192 | return metatable; 193 | } 194 | set 195 | { 196 | metatable = value; 197 | } 198 | } 199 | 200 | #region Common objects 201 | /// 202 | /// An empty/unset value 203 | /// 204 | public static readonly LuaObject Nil = new LuaObject() { luaobj = null, type = LuaType.nil }; 205 | 206 | /// 207 | /// A standard true boolean value 208 | /// 209 | public static readonly LuaObject True = new LuaObject { luaobj = true, type = LuaType.boolean, Metatable = Nil }; 210 | 211 | /// 212 | /// A standard false boolean value 213 | /// 214 | public static readonly LuaObject False = new LuaObject { luaobj = false, type = LuaType.boolean, Metatable = Nil }; 215 | 216 | /// 217 | /// Zero (number) 218 | /// 219 | public static readonly LuaObject Zero = new LuaObject { luaobj = 0d, type = LuaType.number, Metatable = Nil }; 220 | 221 | /// 222 | /// And empty string 223 | /// 224 | public static readonly LuaObject EmptyString = new LuaObject { luaobj = "", type = LuaType.@string, Metatable = Nil }; 225 | #endregion 226 | 227 | /// 228 | /// Gets the underlying Lua type 229 | /// 230 | public LuaType Type { get { return type; } internal set { type = value; } } 231 | 232 | /// 233 | /// Checks whether the type matches or not 234 | /// 235 | public bool Is(LuaType type) 236 | { 237 | return this.type == type; 238 | } 239 | 240 | /// 241 | /// Creates a Lua object from a .NET object 242 | /// Automatically checks if there is a matching Lua type. 243 | /// If not, creates a userdata value 244 | /// 245 | public static LuaObject FromObject(object obj) 246 | { 247 | if (obj == null) 248 | return Nil; 249 | 250 | if (obj is LuaObject) 251 | return (LuaObject)obj; 252 | 253 | if (obj is bool) 254 | return FromBool((bool)obj); 255 | 256 | { 257 | var str = obj as string; 258 | if (str != null) 259 | return FromString(str); 260 | } 261 | 262 | { 263 | var @delegate = obj as LuaFunction; 264 | if (@delegate != null) 265 | return FromFunction(@delegate); 266 | } 267 | 268 | { 269 | var dictionary = obj as LuaTable; 270 | if (dictionary != null) 271 | return FromTable(dictionary); 272 | } 273 | 274 | if (obj is double) return FromNumber((double)obj); 275 | if (obj is float) return FromNumber((float)obj); 276 | if (obj is int) return FromNumber((int)obj); 277 | if (obj is uint) return FromNumber((uint)obj); 278 | if (obj is short) return FromNumber((short)obj); 279 | if (obj is ushort) return FromNumber((ushort)obj); 280 | if (obj is long) return FromNumber((long)obj); 281 | if (obj is ulong) return FromNumber((ulong)obj); 282 | if (obj is byte) return FromNumber((byte)obj); 283 | if (obj is sbyte) return FromNumber((sbyte)obj); 284 | if (obj is Thread) return new LuaObject { luaobj = obj, type = LuaType.thread }; 285 | return FromUserData(obj); 286 | } 287 | 288 | #region Boolean 289 | /// 290 | /// Creates a Lua object from a boolean value 291 | /// 292 | public static LuaObject FromBool(bool bln) 293 | { 294 | if (bln) 295 | return True; 296 | 297 | return False; 298 | } 299 | 300 | public static implicit operator LuaObject(bool bln) 301 | { 302 | return FromBool(bln); 303 | } 304 | 305 | public static implicit operator bool(LuaObject obj) 306 | { 307 | return obj.AsBool(); 308 | } 309 | 310 | /// 311 | /// Gets whether this is a boolean object 312 | /// 313 | public bool IsBool { get { return type == LuaType.boolean; } } 314 | 315 | /// 316 | /// Converts this Lua object into a boolean 317 | /// 318 | /// 319 | public bool AsBool() 320 | { 321 | if (luaobj == null) 322 | return false; 323 | 324 | if (luaobj is bool && ((bool)luaobj) == false) 325 | return false; 326 | 327 | return true; 328 | } 329 | #endregion 330 | 331 | #region Number 332 | /// 333 | /// Creates a Lua object from a double 334 | /// 335 | public static LuaObject FromNumber(double number) 336 | { 337 | if (number == 0d) 338 | return Zero; 339 | 340 | return new LuaObject(number, LuaType.number); 341 | } 342 | 343 | public static implicit operator LuaObject(double number) 344 | { 345 | return FromNumber(number); 346 | } 347 | 348 | public static implicit operator double(LuaObject obj) 349 | { 350 | return obj.AsNumber(); 351 | } 352 | 353 | /// 354 | /// Gets whether this is a number object 355 | /// 356 | public bool IsNumber { get { return type == LuaType.number; } } 357 | 358 | /// 359 | /// Converts this object into a number 360 | /// 361 | public double AsNumber() 362 | { 363 | return (double)luaobj; 364 | } 365 | #endregion 366 | 367 | #region String 368 | /// 369 | /// Creates a Lua object from a string 370 | /// 371 | public static LuaObject FromString(string str) 372 | { 373 | if (str == null) 374 | return Nil; 375 | 376 | if (str.Length == 0) 377 | return EmptyString; 378 | 379 | return new LuaObject(str, LuaType.@string); 380 | } 381 | 382 | public static implicit operator LuaObject(string str) 383 | { 384 | return FromString(str); 385 | } 386 | 387 | public static implicit operator string(LuaObject obj) 388 | { 389 | return obj.AsString(); 390 | } 391 | 392 | public bool IsString { get { return type == LuaType.@string; } } 393 | 394 | public string AsString() 395 | { 396 | return luaobj.ToString(); 397 | } 398 | #endregion 399 | 400 | #region Function 401 | /// 402 | /// Creates a Lua object from a Lua function 403 | /// 404 | public static LuaObject FromFunction(LuaFunction fn) 405 | { 406 | if (fn == null) 407 | return Nil; 408 | 409 | return new LuaObject(fn, LuaType.function); 410 | } 411 | 412 | public static implicit operator LuaObject(LuaFunction fn) 413 | { 414 | return FromFunction(fn); 415 | } 416 | 417 | public bool IsFunction { get { return type == LuaType.function; } } 418 | 419 | public LuaFunction AsFunction() 420 | { 421 | var fn = luaobj as LuaFunction; 422 | if (fn == null) 423 | throw new LuaException("cannot call non-function"); 424 | 425 | return fn; 426 | } 427 | #endregion 428 | 429 | #region Table 430 | /// 431 | /// Creates a Lua object from a Lua table 432 | /// 433 | public static LuaObject FromTable(LuaTable table) 434 | { 435 | if (table == null) 436 | return Nil; 437 | 438 | return new LuaObject(table, LuaType.table); 439 | } 440 | 441 | /// 442 | /// Creates and initializes a Lua object with a table value 443 | /// 444 | /// The initial items of the table to create 445 | public static LuaObject NewTable(params LuaTableItem[] initItems) 446 | { 447 | var table = FromTable(new LuaTableImpl()); 448 | 449 | foreach (var item in initItems) 450 | table[item.Key] = item.Value; 451 | 452 | return table; 453 | } 454 | 455 | public bool IsTable { get { return type == LuaType.table; } } 456 | 457 | public LuaTable AsTable() 458 | { 459 | return luaobj as LuaTable; 460 | } 461 | #endregion 462 | 463 | #region Userdata 464 | /// 465 | /// Creates a Lua object from a .NET object 466 | /// 467 | public static LuaObject FromUserData(object userdata) 468 | { 469 | if (userdata == null) 470 | return Nil; 471 | 472 | //return new LuaObject { luaobj = userdata, type = LuaType.userdata }; 473 | return new LuaObject(userdata, LuaType.userdata); 474 | } 475 | 476 | /// 477 | /// Gets whether this object is nil 478 | /// 479 | public bool IsNil { get { return type == LuaType.nil; } } 480 | 481 | /// 482 | /// Gets whether this object is userdata 483 | /// 484 | public bool IsUserData { get { return type == LuaType.userdata; } } 485 | 486 | /// 487 | /// Returns the CLI object underneath the wrapper 488 | /// 489 | public object AsUserData() 490 | { 491 | return luaobj; 492 | } 493 | #endregion 494 | 495 | public static LuaObject operator +(LuaObject a, LuaObject b) 496 | { 497 | return LuaEvents.add_event(a, b); 498 | } 499 | 500 | public static LuaObject operator -(LuaObject a, LuaObject b) 501 | { 502 | return LuaEvents.sub_event(a, b); 503 | } 504 | 505 | public static LuaObject operator *(LuaObject a, LuaObject b) 506 | { 507 | return LuaEvents.mul_event(a, b); 508 | } 509 | 510 | public static LuaObject operator /(LuaObject a, LuaObject b) 511 | { 512 | return LuaEvents.div_event(a, b); 513 | } 514 | 515 | public static LuaObject operator %(LuaObject a, LuaObject b) 516 | { 517 | return LuaEvents.mod_event(a, b); 518 | } 519 | 520 | public static LuaObject operator ^(LuaObject a, LuaObject b) 521 | { 522 | return LuaEvents.pow_event(a, b); 523 | } 524 | 525 | public static LuaObject operator <(LuaObject a, LuaObject b) 526 | { 527 | return LuaEvents.lt_event(a, b); 528 | } 529 | 530 | public static LuaObject operator >(LuaObject a, LuaObject b) 531 | { 532 | return LuaEvents.lt_event(b, a); 533 | } 534 | 535 | public static LuaObject operator <=(LuaObject a, LuaObject b) 536 | { 537 | return LuaEvents.le_event(a, b); 538 | } 539 | 540 | public static LuaObject operator >=(LuaObject a, LuaObject b) 541 | { 542 | return LuaEvents.le_event(b, a); 543 | } 544 | 545 | public static bool operator ==(LuaObject a, object b) 546 | { 547 | if (b == null) 548 | return LuaObject.FromObject(a).IsNil; 549 | 550 | if (a.IsNil) 551 | { 552 | if (b == null) 553 | return true; 554 | else 555 | { 556 | if (b is LuaObject) 557 | return (b as LuaObject).IsNil; 558 | else 559 | return false; 560 | } 561 | } 562 | else 563 | { 564 | if (b == null) 565 | return false; 566 | else 567 | { 568 | if (b is LuaObject) 569 | { 570 | if ((b as LuaObject).IsNil) 571 | return a.IsNil; 572 | 573 | return (b as LuaObject).luaobj.Equals(a.luaobj); 574 | } 575 | else 576 | return a.luaobj.Equals(b); 577 | } 578 | } 579 | } 580 | 581 | public static bool operator !=(LuaObject a, object b) 582 | { 583 | return !(a == b); 584 | } 585 | 586 | public static LuaObject operator |(LuaObject a, object b) 587 | { 588 | if (a.IsNil || !a.AsBool()) 589 | { 590 | if (b is LuaObject) 591 | return b as LuaObject; 592 | else 593 | return LuaObject.FromObject(b); 594 | } 595 | else 596 | return a; 597 | } 598 | 599 | public static LuaObject operator &(LuaObject a, object b) 600 | { 601 | if (a.IsNil || !a.AsBool()) 602 | return a; 603 | else 604 | { 605 | if (b is LuaObject) 606 | return b as LuaObject; 607 | else 608 | return LuaObject.FromObject(b); 609 | } 610 | } 611 | 612 | public static LuaObject operator !(LuaObject a) 613 | { 614 | if (a == null || a.IsNil || !a.AsBool()) 615 | { 616 | return True; 617 | } 618 | else 619 | { 620 | return False; 621 | } 622 | } 623 | 624 | public static LuaObject operator -(LuaObject a) 625 | { 626 | return LuaEvents.unm_event(a); 627 | } 628 | 629 | public IEnumerator> GetEnumerator() 630 | { 631 | var table = luaobj as IEnumerable>; 632 | if (table == null) 633 | return null; 634 | 635 | return table.GetEnumerator(); 636 | } 637 | 638 | IEnumerator IEnumerable.GetEnumerator() 639 | { 640 | return GetEnumerator(); 641 | } 642 | 643 | public LuaObject this[LuaObject key] 644 | { 645 | get 646 | { 647 | if (IsTable) 648 | { 649 | var table = AsTable(); 650 | LuaObject obj; 651 | if (table.TryGetValue(key, out obj)) 652 | return obj; 653 | else 654 | return LuaEvents.index_event(this, key); 655 | } 656 | else 657 | return LuaEvents.index_event(this, key); 658 | } 659 | set 660 | { 661 | if (IsTable) 662 | { 663 | var table = AsTable(); 664 | LuaObject obj; 665 | if (table.TryGetValue(key, out obj)) 666 | table[key] = value; 667 | else 668 | LuaEvents.newindex_event(this, key, value); 669 | } 670 | else 671 | LuaEvents.newindex_event(this, key, value); 672 | } 673 | } 674 | 675 | // Unlike AsString, this will return string representations of nil, tables, and functions 676 | public override string ToString() 677 | { 678 | if (IsNil) 679 | return "nil"; 680 | 681 | if (IsTable) 682 | return "table"; 683 | 684 | if (IsFunction) 685 | return "function"; 686 | 687 | if (IsBool) 688 | return luaobj.ToString().ToLower(); 689 | 690 | return luaobj.ToString(); 691 | } 692 | 693 | public override bool Equals(object obj) 694 | { 695 | if (obj is LuaObject) 696 | return luaobj.Equals((obj as LuaObject).luaobj); 697 | else 698 | return luaobj.Equals(obj); 699 | } 700 | 701 | public override int GetHashCode() 702 | { 703 | unchecked 704 | { 705 | return (luaobj != null ? luaobj.GetHashCode() : 0) ^ (byte)type; 706 | } 707 | } 708 | 709 | /// 710 | /// Calls the object passing the instance as first argument. Uses the metafield __call 711 | /// 712 | /// The object to be passed as first argument 713 | /// Arguments to be passed after the object 714 | public LuaArguments MethodCall(LuaObject instance, LuaArguments args) 715 | { 716 | var objs = new LuaObject[args.Length + 1]; 717 | objs[0] = instance; 718 | for (int i = 0; i < args.Length; i++) 719 | { 720 | objs[i + 1] = args[i]; 721 | } 722 | 723 | return this.Call(objs); 724 | } 725 | 726 | /// 727 | /// Calls the object. If this is not a function, it calls the metatable field __call 728 | /// 729 | /// The arguments to pass 730 | public LuaArguments Call(params LuaObject[] args) 731 | { 732 | return this.Call(new LuaArguments(args)); 733 | } 734 | 735 | /// 736 | /// Calls the object. If this is not a function, it calls the metatable field __call 737 | /// 738 | /// The arguments to pass 739 | public LuaArguments Call(LuaArguments args) 740 | { 741 | return LuaEvents.call_event(this, args); 742 | } 743 | 744 | #region DynamicObject 745 | 746 | /// 747 | /// Gets a standard .NET value froma LuaObject 748 | /// 749 | /// The LuaObject is is a function or a table, its underlying luaobj if not 750 | internal static object getObject(LuaObject a) 751 | { 752 | if (a.Type != LuaType.table && a.Type != LuaType.function) 753 | return a.luaobj; 754 | else 755 | return a; 756 | } 757 | 758 | public override bool TryGetMember(GetMemberBinder binder, out object result) 759 | { 760 | result = null; 761 | LuaObject obj = this[binder.Name]; 762 | if (obj.IsNil) 763 | return false; 764 | else 765 | { 766 | result = getObject(obj); 767 | return true; 768 | } 769 | } 770 | 771 | public override bool TrySetMember(SetMemberBinder binder, object value) 772 | { 773 | if (value is LuaObject) 774 | this[binder.Name] = (LuaObject)value; 775 | else 776 | this[binder.Name] = LuaObject.FromObject(value); 777 | return true; 778 | } 779 | 780 | public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) 781 | { 782 | LuaObject[] passingArgs = Array.ConvertAll(args, 783 | x => (x is LuaObject ? (LuaObject)x : LuaObject.FromObject(x))); 784 | LuaArguments ret = this.Call(passingArgs); 785 | if (ret.Length == 1) 786 | { 787 | if (ret[0].IsNil) 788 | result = null; 789 | else 790 | result = getObject(ret[0]); 791 | return true; 792 | } 793 | else 794 | { 795 | object[] res = Array.ConvertAll(ret.ToArray(), x => getObject(x)); 796 | result = res; 797 | return true; 798 | } 799 | } 800 | #endregion 801 | } 802 | } 803 | -------------------------------------------------------------------------------- /NetLua/NetLua.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {6B52EB11-E6A7-4771-94B0-7F87EA28211D} 9 | Library 10 | Properties 11 | NetLua 12 | NetLua 13 | v4.0 14 | 512 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | TRACE;DEBUG;COMPILED 22 | prompt 23 | 4 24 | MinimumRecommendedRules.ruleset 25 | false 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE;COMPILED 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\Irony.0.9.1-net40\lib\net40\Irony.dll 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 75 | -------------------------------------------------------------------------------- /NetLua/NetLua.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $id$ 5 | 0.0.1-alpha 6 | $title$ 7 | $author$ 8 | $author$ 9 | https://github.com/frabert/NetLua 10 | false 11 | $description$ 12 | Alpha release. Not for production use. 13 | Copyright 2014 14 | lua netlua 15 | 16 | -------------------------------------------------------------------------------- /NetLua/Parser.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * See LICENSE file 3 | */ 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | 10 | using Irony.Parsing; 11 | using Irony.Ast; 12 | 13 | namespace NetLua 14 | { 15 | public class Parser 16 | { 17 | public Ast.Block block; 18 | 19 | LuaGrammar grammar = new LuaGrammar(); 20 | LanguageData language; 21 | Irony.Parsing.Parser parser; 22 | 23 | public Parser() 24 | { 25 | language = new LanguageData(grammar); 26 | parser = new Irony.Parsing.Parser(language); 27 | } 28 | 29 | public Ast.Block ParseString(string Chunk) 30 | { 31 | ParseTree parseTree = parser.Parse(Chunk); 32 | ParseTreeNode root = parseTree.Root; 33 | if (root == null) 34 | { 35 | Irony.LogMessage msg = parseTree.ParserMessages[0]; 36 | throw new LuaException("", msg.Location.Line, msg.Location.Column, msg.Message); 37 | } 38 | return (ParseBlock(root)); 39 | } 40 | 41 | public Ast.Block ParseFile(string Filename) 42 | { 43 | string source = System.IO.File.ReadAllText(Filename); 44 | ParseTree parseTree = parser.Parse(source, Filename); 45 | ParseTreeNode root = parseTree.Root; 46 | if (root == null) 47 | { 48 | Irony.LogMessage msg = parseTree.ParserMessages[0]; 49 | throw new LuaException(Filename, msg.Location.Line, msg.Location.Column, msg.Message); 50 | } 51 | return (ParseBlock(root)); 52 | } 53 | 54 | #region Binary expression tree 55 | Ast.IExpression ParseOrOp(ParseTreeNode node) 56 | { 57 | if (node.Term.Name == "OrOp") 58 | { 59 | ParseTreeNode left = node.ChildNodes[0]; 60 | Ast.IExpression lexpr = ParseAndOp(left); 61 | if (node.ChildNodes[1].ChildNodes.Count == 0) 62 | return lexpr; 63 | ParseTreeNode right = node.ChildNodes[1].ChildNodes[1]; 64 | Ast.IExpression rexpr = ParseAndOp(right); 65 | 66 | return new Ast.BinaryExpression() { Left = lexpr, Right = rexpr, Operation = Ast.BinaryOp.Or }; 67 | } 68 | throw new Exception("Invalid OrOp node"); 69 | } 70 | 71 | Ast.IExpression ParseAndOp(ParseTreeNode node) 72 | { 73 | if (node.Term.Name == "AndOp") 74 | { 75 | ParseTreeNode left = node.ChildNodes[0]; 76 | Ast.IExpression lexpr = ParseRelOp(left); 77 | if (node.ChildNodes[1].ChildNodes.Count == 0) 78 | return lexpr; 79 | ParseTreeNode right = node.ChildNodes[1].ChildNodes[1]; 80 | Ast.IExpression rexpr = ParseRelOp(right); 81 | 82 | return new Ast.BinaryExpression() { Left = lexpr, Right = rexpr, Operation = Ast.BinaryOp.And }; 83 | } 84 | throw new Exception("Invalid AndOp node"); 85 | } 86 | 87 | Ast.IExpression ParseRelOp(ParseTreeNode node) 88 | { 89 | if (node.Term.Name == "RelOp") 90 | { 91 | ParseTreeNode left = node.ChildNodes[0]; 92 | Ast.IExpression lexpr = ParseConcatOp(left); 93 | if (node.ChildNodes[1].ChildNodes.Count == 0) 94 | return lexpr; 95 | string opstring = node.ChildNodes[1].ChildNodes[0].ChildNodes[0].Token.ValueString; 96 | Ast.BinaryOp op; 97 | switch (opstring) 98 | { 99 | case ">": 100 | op = Ast.BinaryOp.GreaterThan; break; 101 | case ">=": 102 | op = Ast.BinaryOp.GreaterOrEqual; break; 103 | case "<": 104 | op = Ast.BinaryOp.LessThan; break; 105 | case "<=": 106 | op = Ast.BinaryOp.LessOrEqual; break; 107 | case "==": 108 | op = Ast.BinaryOp.Equal; break; 109 | case "~=": 110 | op = Ast.BinaryOp.Different; break; 111 | default: 112 | throw new Exception("Invalid operator"); 113 | } 114 | 115 | ParseTreeNode right = node.ChildNodes[1].ChildNodes[1]; 116 | Ast.IExpression rexpr = ParseConcatOp(right); 117 | 118 | return new Ast.BinaryExpression() { Left = lexpr, Right = rexpr, Operation = op }; 119 | } 120 | throw new Exception("Invalid RelOp node"); 121 | } 122 | 123 | Ast.IExpression ParseConcatOp(ParseTreeNode node) 124 | { 125 | if (node.Term.Name == "ConcatOp") 126 | { 127 | ParseTreeNode left = node.ChildNodes[0]; 128 | Ast.IExpression lexpr = ParseAddOp(left); 129 | if (node.ChildNodes[1].ChildNodes.Count == 0) 130 | return lexpr; 131 | string opstring = node.ChildNodes[1].ChildNodes[0].Token.ValueString; 132 | Ast.BinaryOp op = Ast.BinaryOp.Concat; 133 | 134 | ParseTreeNode right = node.ChildNodes[1].ChildNodes[1]; 135 | Ast.IExpression rexpr = ParseAddOp(right); 136 | 137 | return new Ast.BinaryExpression() { Left = lexpr, Right = rexpr, Operation = op }; 138 | } 139 | throw new Exception("Invalid ConcatOp node"); 140 | } 141 | 142 | Ast.IExpression ParseAddOp(ParseTreeNode node) 143 | { 144 | if (node.Term.Name == "AddOp") 145 | { 146 | ParseTreeNode left = node.ChildNodes[0]; 147 | Ast.IExpression lexpr = ParseMulOp(left); 148 | if (node.ChildNodes[1].ChildNodes.Count == 0) 149 | return lexpr; 150 | string opstring = node.ChildNodes[1].ChildNodes[0].ChildNodes[0].Token.ValueString; 151 | Ast.BinaryOp op; 152 | switch (opstring) 153 | { 154 | case "+": 155 | op = Ast.BinaryOp.Addition; break; 156 | case "-": 157 | op = Ast.BinaryOp.Subtraction; break; 158 | default: 159 | throw new Exception("Invalid operator"); 160 | } 161 | 162 | ParseTreeNode right = node.ChildNodes[1].ChildNodes[1]; 163 | Ast.IExpression rexpr = ParseMulOp(right); 164 | 165 | return new Ast.BinaryExpression() { Left = lexpr, Right = rexpr, Operation = op }; 166 | } 167 | throw new Exception("Invalid AddOp node"); 168 | } 169 | 170 | Ast.IExpression ParseMulOp(ParseTreeNode node) 171 | { 172 | if (node.Term.Name == "MulOp") 173 | { 174 | ParseTreeNode left = node.ChildNodes[0]; 175 | Ast.IExpression lexpr = ParsePowerOp(left); 176 | if (node.ChildNodes[1].ChildNodes.Count == 0) 177 | return lexpr; 178 | string opstring = node.ChildNodes[1].ChildNodes[0].ChildNodes[0].Token.ValueString; 179 | Ast.BinaryOp op; 180 | switch (opstring) 181 | { 182 | case "*": 183 | op = Ast.BinaryOp.Multiplication; break; 184 | case "/": 185 | op = Ast.BinaryOp.Division; break; 186 | case "%": 187 | op = Ast.BinaryOp.Modulo; break; 188 | default: 189 | throw new Exception("Invalid operator"); 190 | } 191 | 192 | ParseTreeNode right = node.ChildNodes[1].ChildNodes[1]; 193 | Ast.IExpression rexpr = ParsePowerOp(right); 194 | 195 | return new Ast.BinaryExpression() { Left = lexpr, Right = rexpr, Operation = op }; 196 | } 197 | throw new Exception("Invalid MulOp node"); 198 | } 199 | 200 | Ast.IExpression ParsePowerOp(ParseTreeNode node) 201 | { 202 | if (node.Term.Name == "PowerOp") 203 | { 204 | ParseTreeNode left = node.ChildNodes[0]; 205 | Ast.IExpression lexpr = ParseExpression(left); 206 | if (node.ChildNodes[1].ChildNodes.Count == 0) 207 | return lexpr; 208 | 209 | ParseTreeNode right = node.ChildNodes[1].ChildNodes[1]; 210 | Ast.IExpression rexpr = ParseExpression(right); 211 | 212 | return new Ast.BinaryExpression() { Left = lexpr, Right = rexpr, Operation = Ast.BinaryOp.Power }; 213 | } 214 | throw new Exception("Invalid PowerOp node"); 215 | } 216 | #endregion 217 | 218 | #region Statements 219 | Ast.FunctionCall ParseFunctionCall(ParseTreeNode node) 220 | { 221 | if (node.Term.Name == "FunctionCall") 222 | { 223 | Ast.IExpression expr = ParsePrefix(node.ChildNodes[0]); 224 | Ast.FunctionCall call = new Ast.FunctionCall(); 225 | call.Arguments = new List(); 226 | call.Function = expr; 227 | 228 | var root = node.ChildNodes[1].ChildNodes[0]; 229 | if (root.ChildNodes.Count != 0) 230 | { 231 | root = root.ChildNodes[0]; 232 | while (true) 233 | { 234 | call.Arguments.Add(ParseExpression(root.ChildNodes[0])); 235 | if (root.ChildNodes.Count == 1) 236 | break; 237 | else 238 | root = root.ChildNodes[1]; 239 | } 240 | } 241 | return call; 242 | } 243 | throw new Exception("Invalid FunctionCall node"); 244 | } 245 | 246 | Ast.FunctionCall ParseOopCall(ParseTreeNode node) 247 | { 248 | if (node.Term.Name == "OopCall") 249 | { 250 | Ast.IExpression expr = ParsePrefix(node.ChildNodes[0]); 251 | string name = node.ChildNodes[1].Token.ValueString; 252 | Ast.FunctionCall call = new Ast.FunctionCall(); 253 | call.Arguments.Add(expr); 254 | call.Function = new Ast.Variable() { Name = name, Prefix = expr }; 255 | 256 | var root = node.ChildNodes[2].ChildNodes[0]; 257 | if (root.ChildNodes.Count != 0) 258 | { 259 | root = root.ChildNodes[0]; 260 | while (true) 261 | { 262 | call.Arguments.Add(ParseExpression(root.ChildNodes[0])); 263 | if (root.ChildNodes.Count == 1) 264 | break; 265 | else 266 | root = root.ChildNodes[1]; 267 | } 268 | } 269 | return call; 270 | } 271 | throw new Exception("Invalid OopCall node"); 272 | } 273 | 274 | Ast.Assignment ParseAssign(ParseTreeNode node) 275 | { 276 | if (node.Term.Name == "Assignment") 277 | { 278 | Ast.Assignment assign = new Ast.Assignment(); 279 | 280 | var left = node.ChildNodes[0]; 281 | var right = node.ChildNodes[1]; 282 | 283 | assign.Variables.Add(ParseVariable(left.ChildNodes[0])); 284 | assign.Expressions.Add(ParseExpression(right.ChildNodes[0])); 285 | 286 | left = left.ChildNodes[1]; 287 | right = right.ChildNodes[1]; 288 | 289 | while (left.ChildNodes.Count > 0) 290 | { 291 | left = left.ChildNodes[0]; 292 | assign.Variables.Add(ParseVariable(left.ChildNodes[0])); 293 | left = left.ChildNodes[1]; 294 | } 295 | 296 | while (right.ChildNodes.Count > 0) 297 | { 298 | right = right.ChildNodes[0]; 299 | assign.Expressions.Add(ParseExpression(right.ChildNodes[0])); 300 | right = right.ChildNodes[1]; 301 | } 302 | 303 | return assign; 304 | } 305 | throw new Exception("Invalid Assignment node"); 306 | } 307 | 308 | Ast.LocalAssignment ParseLocalAssign(ParseTreeNode node) 309 | { 310 | if (node.Term.Name == "LocalAssignment") 311 | { 312 | Ast.LocalAssignment assign = new Ast.LocalAssignment(); 313 | 314 | 315 | var child = node.ChildNodes[1]; 316 | 317 | if (child.ChildNodes[0].Term.Name == "LocalFunction") 318 | { 319 | child = child.ChildNodes[0]; 320 | 321 | var argsNode = child.ChildNodes[2]; 322 | var blockNode = child.ChildNodes[3]; 323 | 324 | assign.Names.Add(child.ChildNodes[1].Token.ValueString); 325 | var func = new Ast.FunctionDefinition(); 326 | 327 | if (argsNode.ChildNodes.Count > 0) 328 | { 329 | argsNode = argsNode.ChildNodes[0]; 330 | while (argsNode.ChildNodes.Count > 0) 331 | { 332 | string ident = argsNode.ChildNodes[0].Token.ValueString; 333 | func.Arguments.Add(new Ast.Argument() { Name = ident }); 334 | if (argsNode.ChildNodes.Count == 1) 335 | break; 336 | argsNode = argsNode.ChildNodes[1]; 337 | } 338 | } 339 | 340 | func.Body = ParseBlock(blockNode); 341 | 342 | assign.Values.Add(func); 343 | return assign; 344 | } 345 | 346 | var left = child.ChildNodes[0]; 347 | var right = child.ChildNodes[1]; 348 | 349 | assign.Names.Add(left.ChildNodes[0].Token.ValueString); 350 | 351 | left = left.ChildNodes[1]; 352 | 353 | while (left.ChildNodes.Count > 0) 354 | { 355 | left = left.ChildNodes[0]; 356 | assign.Names.Add(left.ChildNodes[0].Token.ValueString); 357 | left = left.ChildNodes[1]; 358 | } 359 | 360 | while (right.ChildNodes.Count > 0) 361 | { 362 | right = right.ChildNodes[0]; 363 | assign.Values.Add(ParseExpression(right.ChildNodes[0])); 364 | right = right.ChildNodes[1]; 365 | } 366 | 367 | return assign; 368 | } 369 | throw new Exception("Invalid LocalAssignment node"); 370 | } 371 | 372 | Ast.ReturnStat ParseReturnStat(ParseTreeNode node) 373 | { 374 | if (node.Term.Name == "ReturnStat") 375 | { 376 | Ast.ReturnStat ret = new Ast.ReturnStat(); 377 | var child = node.ChildNodes[1]; 378 | while (child.ChildNodes.Count > 0) 379 | { 380 | child = child.ChildNodes[0]; 381 | ret.Expressions.Add(ParseExpression(child.ChildNodes[0])); 382 | child = child.ChildNodes[1]; 383 | } 384 | return ret; 385 | } 386 | throw new Exception("Invalid ReturnStat node"); 387 | } 388 | 389 | Ast.Block ParseDoBlock(ParseTreeNode node) 390 | { 391 | if (node.Term.Name == "DoBlock") 392 | return ParseBlock(node.ChildNodes[1]); 393 | throw new Exception("Invalid DoBlock node"); 394 | } 395 | 396 | Ast.RepeatStat ParseRepeat(ParseTreeNode node) 397 | { 398 | if (node.Term.Name == "Repeat") 399 | { 400 | Ast.Block block = ParseBlock(node.ChildNodes[1]); 401 | Ast.IExpression condition = ParseExpression(node.ChildNodes[3]); 402 | 403 | return new Ast.RepeatStat() 404 | { 405 | Block = block, 406 | Condition = condition 407 | }; 408 | } 409 | throw new Exception("Invalid Repeat node"); 410 | } 411 | 412 | Ast.WhileStat ParseWhile(ParseTreeNode node) 413 | { 414 | if (node.Term.Name == "While") 415 | { 416 | return new Ast.WhileStat() 417 | { 418 | Condition = ParseExpression(node.ChildNodes[1]), 419 | Block = ParseDoBlock(node.ChildNodes[2]) 420 | }; 421 | } 422 | throw new Exception("Invalid While node"); 423 | } 424 | 425 | Ast.IfStat ParseIf(ParseTreeNode node) 426 | { 427 | if (node.Term.Name == "If") 428 | { 429 | Ast.IExpression condition = ParseExpression(node.ChildNodes[1]); 430 | Ast.Block block = ParseBlock(node.ChildNodes[3]); 431 | 432 | Ast.IfStat If = new Ast.IfStat(); 433 | If.Block = block; 434 | If.Condition = condition; 435 | If.ElseIfs = new List(); 436 | 437 | ParseTreeNode ElseifNode = node.ChildNodes[4]; 438 | ParseTreeNode ElseNode = node.ChildNodes[5]; 439 | 440 | while (ElseifNode.ChildNodes.Count != 0) 441 | { 442 | var childnode = ElseifNode.ChildNodes[0]; 443 | Ast.IfStat elseif = new Ast.IfStat(); 444 | elseif.Condition = ParseExpression(childnode.ChildNodes[1]); 445 | elseif.Block = ParseBlock(childnode.ChildNodes[3]); 446 | 447 | If.ElseIfs.Add(elseif); 448 | 449 | ElseifNode = childnode.ChildNodes[4]; 450 | } 451 | 452 | if (ElseNode.ChildNodes.Count != 0) 453 | If.ElseBlock = ParseBlock(ElseNode.ChildNodes[0].ChildNodes[1]); 454 | 455 | return If; 456 | } 457 | throw new Exception("Invalid If node"); 458 | } 459 | 460 | Ast.Assignment ParseFunctionDecl(ParseTreeNode node) 461 | { 462 | if (node.Term.Name == "FunctionDecl") 463 | { 464 | Ast.IAssignable expr = ParseVariable(node.ChildNodes[1]); 465 | 466 | ParseTreeNode argsNode = node.ChildNodes[3].ChildNodes[0]; 467 | ParseTreeNode chunkNode = node.ChildNodes[4]; 468 | 469 | Ast.Block block = ParseBlock(chunkNode); 470 | Ast.FunctionDefinition def = new Ast.FunctionDefinition(); 471 | def.Arguments = new List(); 472 | 473 | var nameNode = node.ChildNodes[2]; 474 | if (nameNode.ChildNodes.Count > 0) 475 | { 476 | def.Arguments.Add(new Ast.Argument() { Name = "self" }); 477 | expr = new Ast.Variable() 478 | { 479 | Name = nameNode.ChildNodes[0].Token.ValueString, 480 | Prefix = expr 481 | }; 482 | } 483 | def.Body = block; 484 | if (argsNode.ChildNodes.Count > 0) 485 | { 486 | argsNode = argsNode.ChildNodes[0]; 487 | while (argsNode.ChildNodes.Count > 0) 488 | { 489 | string ident = argsNode.ChildNodes[0].Token.ValueString; 490 | def.Arguments.Add(new Ast.Argument() { Name = ident }); 491 | if (argsNode.ChildNodes.Count == 1) 492 | break; 493 | argsNode = argsNode.ChildNodes[1]; 494 | } 495 | } 496 | Ast.Assignment assign = new Ast.Assignment(); 497 | assign.Variables.Add(expr); 498 | assign.Expressions.Add(def); 499 | return assign; 500 | } 501 | throw new Exception("Invalid FunctionDecl node"); 502 | } 503 | #endregion 504 | 505 | #region Expressions 506 | Ast.UnaryExpression ParseUnaryExpr(ParseTreeNode node) 507 | { 508 | if (node.Term.Name == "UnaryExpr") 509 | { 510 | Ast.IExpression expr = ParseExpression(node.ChildNodes[1]); 511 | var opNode = node.ChildNodes[0].ChildNodes[0]; 512 | Ast.UnaryOp op = Ast.UnaryOp.Invert; 513 | switch (opNode.Token.ValueString) 514 | { 515 | case "not": 516 | op = Ast.UnaryOp.Negate; break; 517 | case "-": 518 | op = Ast.UnaryOp.Invert; break; 519 | case "#": 520 | op = Ast.UnaryOp.Length; break; 521 | } 522 | return new Ast.UnaryExpression() 523 | { 524 | Expression = expr, 525 | Operation = op 526 | }; 527 | } 528 | throw new Exception("Invalid UnaryExpr node"); 529 | } 530 | 531 | Ast.FunctionDefinition ParseFunctionDef(ParseTreeNode node) 532 | { 533 | if (node.Term.Name == "FunctionDef") 534 | { 535 | ParseTreeNode argsNode = node.ChildNodes[1].ChildNodes[0]; 536 | ParseTreeNode chunkNode = node.ChildNodes[2]; 537 | 538 | Ast.Block block = ParseBlock(chunkNode); 539 | Ast.FunctionDefinition def = new Ast.FunctionDefinition(); 540 | def.Body = block; 541 | def.Arguments = new List(); 542 | 543 | if (argsNode.ChildNodes.Count == 0) 544 | return def; 545 | if (argsNode.ChildNodes.Count > 0) 546 | { 547 | argsNode = argsNode.ChildNodes[0]; 548 | while (argsNode.ChildNodes.Count > 0) 549 | { 550 | string ident = argsNode.ChildNodes[0].Token.ValueString; 551 | def.Arguments.Add(new Ast.Argument() { Name = ident }); 552 | if (argsNode.ChildNodes.Count == 1) 553 | break; 554 | argsNode = argsNode.ChildNodes[1]; 555 | } 556 | } 557 | return def; 558 | } 559 | throw new Exception("Invalid FunctionDef node"); 560 | } 561 | 562 | Ast.IExpression ParsePrefix(ParseTreeNode node) 563 | { 564 | if (node.Term != null) 565 | { 566 | if (node.Term.Name == "Prefix") 567 | { 568 | ParseTreeNode child = node.ChildNodes[0]; 569 | if (child.Term.Name == "Variable") 570 | { 571 | return ParseVariable(child); 572 | } 573 | else if (child.Term.Name == "Expression") 574 | { 575 | return ParseExpression(child); 576 | } 577 | else if (child.Term.Name == "FunctionCall") 578 | { 579 | return ParseFunctionCall(child); 580 | } 581 | else if (child.Term.Name == "OopCall") 582 | { 583 | return ParseOopCall(child); 584 | } 585 | } 586 | } 587 | throw new Exception("Invalid Prefix node"); 588 | } 589 | 590 | Ast.IAssignable ParseVariable(ParseTreeNode node) 591 | { 592 | if (node.Term != null) 593 | { 594 | if (node.ChildNodes.Count == 1) 595 | { 596 | string name = node.ChildNodes[0].Token.ValueString; 597 | return new Ast.Variable() { Name = name }; 598 | } 599 | else 600 | { 601 | Ast.IExpression prefix = ParsePrefix(node.ChildNodes[0]); 602 | if (node.ChildNodes[1].Term.Name == "Expression") 603 | { 604 | Ast.IExpression index = ParseExpression(node.ChildNodes[1]); 605 | return new Ast.TableAccess() { Expression = prefix, Index = index }; 606 | } 607 | else 608 | { 609 | string name = node.ChildNodes[1].Token.ValueString; 610 | return new Ast.Variable() { Name = name, Prefix = prefix }; 611 | } 612 | } 613 | } 614 | throw new Exception("Invalid Variable node"); 615 | } 616 | 617 | Ast.TableConstructor ParseTableConstruct(ParseTreeNode node) 618 | { 619 | if (node.Term.Name == "TableConstruct") 620 | { 621 | if (node.ChildNodes.Count == 0) 622 | { 623 | return new Ast.TableConstructor() { Values = new Dictionary() }; 624 | } 625 | else 626 | { 627 | var child = node.ChildNodes[0]; 628 | Ast.TableConstructor t = new Ast.TableConstructor(); 629 | t.Values = new Dictionary(); 630 | 631 | int i = 1; 632 | while (true) 633 | { 634 | if (child.ChildNodes.Count == 0) 635 | break; 636 | 637 | var value = child.ChildNodes[0]; 638 | 639 | if (value.ChildNodes.Count == 1) 640 | { 641 | t.Values.Add(new Ast.NumberLiteral() { Value = i }, ParseExpression(value.ChildNodes[0])); 642 | i++; 643 | } 644 | else 645 | { 646 | var prefix = value.ChildNodes[0]; 647 | 648 | Ast.IExpression key; 649 | if (prefix.ChildNodes[0].Term.Name == "identifier") 650 | key = new Ast.StringLiteral() { Value = prefix.ChildNodes[0].Token.ValueString }; 651 | else 652 | key = ParseExpression(prefix.ChildNodes[0]); 653 | 654 | var expr = value.ChildNodes[1]; 655 | Ast.IExpression val = ParseExpression(expr); 656 | 657 | t.Values.Add(key, val); 658 | } 659 | 660 | //child = child.ChildNodes[1].ChildNodes[0]; 661 | child = child.ChildNodes[1]; 662 | if (child.ChildNodes.Count == 0) 663 | break; 664 | child = child.ChildNodes[0]; 665 | } 666 | return t; 667 | } 668 | } 669 | throw new Exception("Invalid TableConstruct node"); 670 | } 671 | 672 | Ast.IExpression ParseExpression(ParseTreeNode node) 673 | { 674 | if (node.Term.Name == "Expression") 675 | { 676 | ParseTreeNode child = node.ChildNodes[0]; 677 | if (child.Token != null && child.Token.Terminal is NumberLiteral) 678 | { 679 | return new Ast.NumberLiteral() { Value = (child.Token.Value is double ? (double)(child.Token.Value) : (int)(child.Token.Value)) }; 680 | } 681 | else if (child.Token != null && child.Token.Terminal is StringLiteral) 682 | { 683 | return new Ast.StringLiteral() { Value = (string)(child.Token.Value) }; 684 | } 685 | else if (child.Token != null && child.Token.Terminal is KeyTerm) 686 | { 687 | string val = child.Token.ValueString; 688 | if (val == "true") 689 | return new Ast.BoolLiteral() { Value = true }; 690 | else if (val == "false") 691 | return new Ast.BoolLiteral() { Value = false }; 692 | else if (val == "nil") 693 | return new Ast.NilLiteral(); 694 | } 695 | else if (child.Term != null && child.Term.Name == "Prefix") 696 | { 697 | return ParsePrefix(child); 698 | } 699 | else if (child.Term != null && child.Term.Name == "OrOp") 700 | { 701 | return ParseOrOp(child); 702 | } 703 | else if (child.Term != null && child.Term.Name == "FunctionDef") 704 | { 705 | return ParseFunctionDef(child); 706 | } 707 | else if (child.Term != null && child.Term.Name == "UnaryExpr") 708 | { 709 | return ParseUnaryExpr(child); 710 | } 711 | else if (child.Term != null && child.Term.Name == "TableConstruct") 712 | { 713 | return ParseTableConstruct(child); 714 | } 715 | else if (child.Term != null && child.Term.Name == "OopCall") 716 | { 717 | return ParseOopCall(child); 718 | } 719 | else if (child.Term != null && child.Term.Name == "Varargs") 720 | { 721 | return new Ast.VarargsLiteral(); 722 | } 723 | } 724 | throw new Exception("Invalid Expression node"); 725 | } 726 | #endregion 727 | 728 | Ast.Block ParseBlock(ParseTreeNode node) 729 | { 730 | Ast.Block block = new Ast.Block(); 731 | block.Statements = new List(); 732 | foreach (ParseTreeNode child in node.ChildNodes) 733 | { 734 | switch (child.Term.Name) 735 | { 736 | case "Assignment": 737 | block.Statements.Add(ParseAssign(child)); break; 738 | case "LocalAssignment": 739 | block.Statements.Add(ParseLocalAssign(child)); break; 740 | case "FunctionCall": 741 | block.Statements.Add(ParseFunctionCall(child)); break; 742 | case "ReturnStat": 743 | block.Statements.Add(ParseReturnStat(child)); break; 744 | case "BreakStat": 745 | block.Statements.Add(new Ast.BreakStat()); break; 746 | case "DoBlock": 747 | block.Statements.Add(ParseDoBlock(child)); break; 748 | case "If": 749 | block.Statements.Add(ParseIf(child)); break; 750 | case "While": 751 | block.Statements.Add(ParseWhile(child)); break; 752 | case "Repeat": 753 | block.Statements.Add(ParseRepeat(child)); break; 754 | case "FunctionDecl": 755 | block.Statements.Add(ParseFunctionDecl(child)); break; 756 | case "For": 757 | block.Statements.Add(ParseFor(child)); break; 758 | case "OopCall": 759 | block.Statements.Add(ParseOopCall(child)); break; 760 | case ";": 761 | break; 762 | default: 763 | throw new NotImplementedException("Node not yet implemented"); 764 | } 765 | } 766 | return block; 767 | } 768 | 769 | Ast.IStatement ParseFor(ParseTreeNode node) 770 | { 771 | if (node.Term.Name == "For") 772 | { 773 | var block = ParseDoBlock(node.ChildNodes[2]); 774 | var type = node.ChildNodes[1].ChildNodes[0]; 775 | if (type.Term.Name == "NumericFor") 776 | { 777 | var cycle = new Ast.NumericFor(); 778 | cycle.Block = block; 779 | cycle.Variable = type.ChildNodes[0].Token.ValueString; 780 | cycle.Var = ParseExpression(type.ChildNodes[1]); 781 | cycle.Limit = ParseExpression(type.ChildNodes[2]); 782 | cycle.Step = new Ast.NumberLiteral() { Value = 1 }; 783 | if (type.ChildNodes[3].ChildNodes.Count > 0) 784 | { 785 | var child = type.ChildNodes[3].ChildNodes[0]; 786 | cycle.Step = ParseExpression(child); 787 | } 788 | 789 | return cycle; 790 | } 791 | else 792 | { 793 | var cycle = new Ast.GenericFor(); 794 | cycle.Block = block; 795 | 796 | var nameList = type.ChildNodes[0]; 797 | var exprList = type.ChildNodes[2]; 798 | 799 | while (true) 800 | { 801 | var name = nameList.ChildNodes[0].Token.ValueString; 802 | cycle.Variables.Add(name); 803 | var child = nameList.ChildNodes[1]; 804 | if (child.ChildNodes.Count > 0) 805 | nameList = child.ChildNodes[0]; 806 | else 807 | break; 808 | } 809 | 810 | while (true) 811 | { 812 | var expr = ParseExpression(exprList.ChildNodes[0]); 813 | cycle.Expressions.Add(expr); 814 | var child = exprList.ChildNodes[1]; 815 | if (child.ChildNodes.Count > 0) 816 | exprList = child.ChildNodes[0]; 817 | else 818 | break; 819 | } 820 | 821 | return cycle; 822 | } 823 | } 824 | throw new Exception("Invalid For node"); 825 | } 826 | } 827 | } 828 | -------------------------------------------------------------------------------- /NetLua/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("NetLua")] 9 | [assembly: AssemblyDescription("100% .NET Lua implementation")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Francesco Bertolaccini")] 12 | [assembly: AssemblyProduct("NetLua")] 13 | [assembly: AssemblyCopyright("Copyright (c) 2014 Francesco Bertolaccini")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("238e0a1f-6d76-42ed-820f-bb83206b5057")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("0.0.1.0")] 36 | [assembly: AssemblyFileVersion("0.0.1.0")] 37 | -------------------------------------------------------------------------------- /NetLua/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | NetLua 2 | ====== 3 | 4 | Project description 5 | ------------------- 6 | 7 | NetLua is a completely managed interpreter for the Lua dynamic language. 8 | It was inspired by (and the LuaObject class is loosely based on) AluminumLua 9 | by Alexander Corrado. 10 | Check his project out at http://github.com/chkn/AluminumLua 11 | 12 | Why? 13 | ---- 14 | 15 | I started this project because I needed a managed Lua interpreter and AluminumLua 16 | had a few bugs and caveats that were difficult to solve because of its structure. 17 | I so decided to do my own attempt at it. 18 | 19 | Source code parsing 20 | ------------------- 21 | 22 | As of now, the parsing is made using Irony, but any LALR parser can be used 23 | to build the internal AST interpreted by NetLua. 24 | Irony looks a bit slow, but it is the easiest solution for a neat C# LALR Parser. 25 | 26 | Examples 27 | ======== 28 | 29 | Using Lua from C# 30 | ----------------- 31 | 32 | ```c# 33 | Lua lua = new Lua(); 34 | lua.DoString("a={4, b=6, [7]=10}"); // Interpreting Lua 35 | 36 | var a = lua.Context.Get("a"); // Accessing Lua from C# 37 | var a_b = a["b"].AsNumber(); 38 | 39 | double number = a[7]; // Automatic type coercion 40 | ``` 41 | 42 | Registering C# methods 43 | ---------------------- 44 | 45 | ```c# 46 | static LuaArguments print(LuaArguments args) 47 | { 48 | string[] strings = Array.ConvertAll(args, x => x.ToString()); // LuaArguments can be used as a LuaObject array 49 | Console.WriteLine(String.Join("\t", strings)); 50 | return Lua.Return(); // You can use the Lua.Return helper function to return values 51 | } 52 | 53 | Lua lua = new Lua(); 54 | lua.Context.SetGlobal("print", (LuaFunction)print); 55 | ``` 56 | 57 | Using .NET 4.0 dynamic features 58 | ------------------------------- 59 | 60 | ```c# 61 | dynamic lua = new Lua(); 62 | dynamic luaVariable = lua.var; // Lua.DynamicContext provides a dynamic version of Lua.Context 63 | 64 | double a = luaVariable.numberValue; // Automatic type casting 65 | double d = luaVariable.someFunc(a); // Automatic function arguments and result boxing / unboxing 66 | 67 | lua.x = 5; 68 | ``` 69 | 70 | 71 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/frabert/netlua/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 72 | [![Build status](https://ci.appveyor.com/api/projects/status/l548w3aa5lcj92r3/branch/master?svg=true)](https://ci.appveyor.com/project/frabert/NetLua/branch/master) 73 | -------------------------------------------------------------------------------- /packages/Irony.0.9.1-net40/Irony.0.9.1-net40.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frabert/NetLua/319043e47f599f4137cfb7ac9e481be8d88744ec/packages/Irony.0.9.1-net40/Irony.0.9.1-net40.nupkg -------------------------------------------------------------------------------- /packages/Irony.0.9.1-net40/Irony.0.9.1-net40.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Irony 5 | 0.9.1-net40 6 | Roman Ivantsov 7 | Roman Ivantsov 8 | https://irony.codeplex.com/license 9 | https://irony.codeplex.com/ 10 | false 11 | Irony is a development kit for implementing languages on .NET platform. In Irony the target language grammar is coded directly in c# using operator overloading to express grammar constructs. Irony's scanner and parser modules use the grammar encoded as c# class to control the parsing process. 12 | Copyright (c) 2013 Roman Ivantsov 13 | en-US 14 | irony ast grammar bnf 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /packages/Irony.0.9.1-net40/lib/net40/Irony.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frabert/NetLua/319043e47f599f4137cfb7ac9e481be8d88744ec/packages/Irony.0.9.1-net40/lib/net40/Irony.dll -------------------------------------------------------------------------------- /packages/Irony.0.9.1-net40/tools/FastColoredTextBox.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frabert/NetLua/319043e47f599f4137cfb7ac9e481be8d88744ec/packages/Irony.0.9.1-net40/tools/FastColoredTextBox.dll -------------------------------------------------------------------------------- /packages/Irony.0.9.1-net40/tools/Irony.GrammarExplorer.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frabert/NetLua/319043e47f599f4137cfb7ac9e481be8d88744ec/packages/Irony.0.9.1-net40/tools/Irony.GrammarExplorer.exe -------------------------------------------------------------------------------- /packages/Irony.0.9.1-net40/tools/Irony.GrammarExplorer.exe.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 0 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | False 24 | 25 | 26 | False 27 | 28 | 29 | True 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /packages/Irony.0.9.1-net40/tools/Irony.Interpreter.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frabert/NetLua/319043e47f599f4137cfb7ac9e481be8d88744ec/packages/Irony.0.9.1-net40/tools/Irony.Interpreter.dll -------------------------------------------------------------------------------- /packages/Irony.0.9.1-net40/tools/Irony.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frabert/NetLua/319043e47f599f4137cfb7ac9e481be8d88744ec/packages/Irony.0.9.1-net40/tools/Irony.dll -------------------------------------------------------------------------------- /packages/NUnit.2.6.3/NUnit.2.6.3.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frabert/NetLua/319043e47f599f4137cfb7ac9e481be8d88744ec/packages/NUnit.2.6.3/NUnit.2.6.3.nupkg -------------------------------------------------------------------------------- /packages/NUnit.2.6.3/NUnit.2.6.3.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NUnit 5 | 2.6.3 6 | NUnit 7 | Charlie Poole 8 | Charlie Poole 9 | http://nunit.org/nuget/license.html 10 | http://nunit.org/ 11 | http://nunit.org/nuget/nunit_32x32.png 12 | false 13 | NUnit features a fluent assert syntax, parameterized, generic and theory tests and is user-extensible. A number of runners, both from the NUnit project and by third parties, are able to execute NUnit tests. 14 | 15 | Version 2.6 is the seventh major release of this well-known and well-tested programming tool. 16 | 17 | This package includes only the framework assembly. You will need to install the NUnit.Runners package unless you are using a third-party runner. 18 | NUnit is a unit-testing framework for all .Net languages with a strong TDD focus. 19 | Version 2.6 is the seventh major release of NUnit. 20 | 21 | Unlike earlier versions, this package includes only the framework assembly. You will need to install the NUnit.Runners package unless you are using a third-party runner. 22 | 23 | The nunit.mocks assembly is now provided by the NUnit.Mocks package. The pnunit.framework assembly is provided by the pNUnit package. 24 | en-US 25 | nunit test testing tdd framework fluent assert theory plugin addin 26 | 27 | -------------------------------------------------------------------------------- /packages/NUnit.2.6.3/lib/nunit.framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frabert/NetLua/319043e47f599f4137cfb7ac9e481be8d88744ec/packages/NUnit.2.6.3/lib/nunit.framework.dll -------------------------------------------------------------------------------- /packages/NUnit.2.6.3/license.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frabert/NetLua/319043e47f599f4137cfb7ac9e481be8d88744ec/packages/NUnit.2.6.3/license.txt -------------------------------------------------------------------------------- /packages/repositories.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | --------------------------------------------------------------------------------