├── LuaInterface
├── CallLua
│ └── CallLua.csproj
├── LuaInterface.csproj
├── LuaInterface.sln
├── LuaNetRunner
│ └── LuaNetRunner.csproj
└── Tests
│ ├── Tests.csproj
│ └── bin
│ ├── Debug
│ └── test.lua
│ └── Linux
│ └── test.lua
├── README.md
├── bin
└── lua
│ ├── CLRForm.lua
│ └── CLRPackage.lua
├── doc
├── LuaInterface.txt
├── LuaRunner.txt
├── guide.pdf
└── luainterface.pdf
├── samples
├── NPlot.dll
├── TextBox.cs
├── TextBox.dll
├── auto1.wlua
├── auto2.wlua
├── autoform.wlua
├── com.lua
├── ctype.lua
├── error.lua
├── form.lua
├── form1.wlua
├── form2.wlua
├── form3.wlua
├── gtk-list.lua
├── gui.glade
├── hello-glade.lua
├── hello-gtk.lua
├── hello1.lua
├── hello2.lua
├── hello3.lua
├── hello4.lua
├── ilua.lua
├── layout0.wlua
├── layout1.wlua
├── lconsole.lua
├── lua-gtk.lua
├── lua.lua
├── nplot1.lua
├── socket.lua
├── table1.wlua
├── test-com.lua
├── testbox.wlua
└── testluaform.lua
├── src
├── AssemblyInfo.cs
├── CheckType.cs
├── GenerateEventAssembly.cs
├── Lua.cs
├── LuaBase.cs
├── LuaDLL.cs
├── LuaException.cs
├── LuaFunction.cs
├── LuaGlobalAttribute.cs
├── LuaHideAttribute.cs
├── LuaNetRunner.cs
├── LuaRegistrationHelper.cs
├── LuaScriptException.cs
├── LuaTable.cs
├── LuaUserData.cs
├── Metatables.cs
├── MethodWrapper.cs
├── ObjectTranslator.cs
├── ProxyType.cs
├── README.txt
├── config.win
├── configure
├── install
├── luastdcall-unix.h
├── luastdcall-windows.h
├── luastdcall.c
├── makefile
├── makefile.win
└── rmakefile.win
└── tests
├── CallLua.cs
├── Entity.cs
├── TestLua.cs
├── makefile
├── makefile.win
└── test.lua
/LuaInterface/CallLua/CallLua.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | x86
6 | 9.0.21022
7 | 2.0
8 | {DF85F36C-5970-462F-874D-564D0C4214F2}
9 | Exe
10 | CallLua
11 | CallLua
12 | v3.5
13 |
14 |
15 | true
16 | full
17 | false
18 | bin\Debug
19 | DEBUG
20 | prompt
21 | 4
22 | x86
23 |
24 |
25 | none
26 | false
27 | bin\Release
28 | prompt
29 | 4
30 | x86
31 |
32 |
33 | none
34 | false
35 | bin\Unix
36 | 4
37 |
38 |
39 | full
40 | false
41 | bin\Linux
42 | 4
43 | true
44 |
45 |
46 | none
47 | false
48 | bin\Windows
49 | 4
50 |
51 |
52 |
53 |
54 |
55 |
56 | {E915A0A4-2641-4F7E-8A88-8F123FA88BF1}
57 | LuaInterface
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/LuaInterface/LuaInterface.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 9.0.21022
7 | 2.0
8 | {E915A0A4-2641-4F7E-8A88-8F123FA88BF1}
9 | Library
10 | LuaInterface
11 | LuaInterface
12 | v3.5
13 |
14 |
15 | true
16 | full
17 | true
18 | bin\Debug
19 | DEBUG __Windows__
20 | prompt
21 | 4
22 | x86
23 |
24 |
25 | none
26 | false
27 | bin\Release
28 | prompt
29 | 4
30 | x86
31 |
32 |
33 | none
34 | false
35 | bin\Unix
36 | 4
37 | true
38 |
39 |
40 | none
41 | false
42 | bin\Unix
43 | 4
44 |
45 |
46 | none
47 | false
48 | bin\Debug
49 | 4
50 |
51 |
52 | none
53 | false
54 | bin\Release
55 | 4
56 |
57 |
58 | true
59 | full
60 | false
61 | bin\Linux
62 | DEBUG __lib__ __dot__
63 | 4
64 |
65 |
66 | none
67 | false
68 | bin\Windows
69 | 4
70 | __Windows__
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/LuaInterface/LuaInterface.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 10.00
3 | # Visual Studio 2008
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuaInterface", "LuaInterface.csproj", "{E915A0A4-2641-4F7E-8A88-8F123FA88BF1}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CallLua", "CallLua\CallLua.csproj", "{DF85F36C-5970-462F-874D-564D0C4214F2}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuaNetRunner", "LuaNetRunner\LuaNetRunner.csproj", "{378C7B25-6C91-4F74-B5A7-A18F6D685EB1}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{EED940BE-E828-463E-BF90-8BC824758149}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|x86 = Debug|x86
15 | Release|x86 = Release|x86
16 | Linux|Any CPU = Linux|Any CPU
17 | Windows|Any CPU = Windows|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {378C7B25-6C91-4F74-B5A7-A18F6D685EB1}.Debug|x86.ActiveCfg = Debug|x86
21 | {378C7B25-6C91-4F74-B5A7-A18F6D685EB1}.Debug|x86.Build.0 = Debug|x86
22 | {378C7B25-6C91-4F74-B5A7-A18F6D685EB1}.Linux|Any CPU.ActiveCfg = Linux|Any CPU
23 | {378C7B25-6C91-4F74-B5A7-A18F6D685EB1}.Linux|Any CPU.Build.0 = Linux|Any CPU
24 | {378C7B25-6C91-4F74-B5A7-A18F6D685EB1}.Release|x86.ActiveCfg = Release|x86
25 | {378C7B25-6C91-4F74-B5A7-A18F6D685EB1}.Release|x86.Build.0 = Release|x86
26 | {378C7B25-6C91-4F74-B5A7-A18F6D685EB1}.Windows|Any CPU.ActiveCfg = Windows|Any CPU
27 | {378C7B25-6C91-4F74-B5A7-A18F6D685EB1}.Windows|Any CPU.Build.0 = Windows|Any CPU
28 | {DF85F36C-5970-462F-874D-564D0C4214F2}.Debug|x86.ActiveCfg = Debug|x86
29 | {DF85F36C-5970-462F-874D-564D0C4214F2}.Debug|x86.Build.0 = Debug|x86
30 | {DF85F36C-5970-462F-874D-564D0C4214F2}.Linux|Any CPU.ActiveCfg = Linux|Any CPU
31 | {DF85F36C-5970-462F-874D-564D0C4214F2}.Linux|Any CPU.Build.0 = Linux|Any CPU
32 | {DF85F36C-5970-462F-874D-564D0C4214F2}.Release|x86.ActiveCfg = Release|x86
33 | {DF85F36C-5970-462F-874D-564D0C4214F2}.Release|x86.Build.0 = Release|x86
34 | {DF85F36C-5970-462F-874D-564D0C4214F2}.Windows|Any CPU.ActiveCfg = Windows|Any CPU
35 | {DF85F36C-5970-462F-874D-564D0C4214F2}.Windows|Any CPU.Build.0 = Windows|Any CPU
36 | {E915A0A4-2641-4F7E-8A88-8F123FA88BF1}.Debug|x86.ActiveCfg = Debug|x86
37 | {E915A0A4-2641-4F7E-8A88-8F123FA88BF1}.Debug|x86.Build.0 = Debug|x86
38 | {E915A0A4-2641-4F7E-8A88-8F123FA88BF1}.Linux|Any CPU.ActiveCfg = Linux|Any CPU
39 | {E915A0A4-2641-4F7E-8A88-8F123FA88BF1}.Linux|Any CPU.Build.0 = Linux|Any CPU
40 | {E915A0A4-2641-4F7E-8A88-8F123FA88BF1}.Release|x86.ActiveCfg = Release|x86
41 | {E915A0A4-2641-4F7E-8A88-8F123FA88BF1}.Release|x86.Build.0 = Release|x86
42 | {E915A0A4-2641-4F7E-8A88-8F123FA88BF1}.Windows|Any CPU.ActiveCfg = Windows|Any CPU
43 | {E915A0A4-2641-4F7E-8A88-8F123FA88BF1}.Windows|Any CPU.Build.0 = Windows|Any CPU
44 | {EED940BE-E828-463E-BF90-8BC824758149}.Debug|x86.ActiveCfg = Debug|x86
45 | {EED940BE-E828-463E-BF90-8BC824758149}.Debug|x86.Build.0 = Debug|x86
46 | {EED940BE-E828-463E-BF90-8BC824758149}.Linux|Any CPU.ActiveCfg = Linux|Any CPU
47 | {EED940BE-E828-463E-BF90-8BC824758149}.Linux|Any CPU.Build.0 = Linux|Any CPU
48 | {EED940BE-E828-463E-BF90-8BC824758149}.Release|x86.ActiveCfg = Release|x86
49 | {EED940BE-E828-463E-BF90-8BC824758149}.Release|x86.Build.0 = Release|x86
50 | {EED940BE-E828-463E-BF90-8BC824758149}.Windows|Any CPU.ActiveCfg = Windows|Any CPU
51 | {EED940BE-E828-463E-BF90-8BC824758149}.Windows|Any CPU.Build.0 = Windows|Any CPU
52 | EndGlobalSection
53 | GlobalSection(MonoDevelopProperties) = preSolution
54 | StartupItem = CallLua\CallLua.csproj
55 | EndGlobalSection
56 | EndGlobal
57 |
--------------------------------------------------------------------------------
/LuaInterface/LuaNetRunner/LuaNetRunner.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | x86
6 | 9.0.21022
7 | 2.0
8 | {378C7B25-6C91-4F74-B5A7-A18F6D685EB1}
9 | Exe
10 | LuaNetRunner
11 | LuaNetRunner
12 | v3.5
13 |
14 |
15 | true
16 | full
17 | false
18 | bin\Debug
19 | DEBUG;
20 | prompt
21 | 4
22 | x86
23 | false
24 |
25 |
26 | none
27 | true
28 | bin\Release
29 | prompt
30 | 4
31 | x86
32 | false
33 |
34 |
35 | none
36 | false
37 | bin\Unix
38 | 4
39 |
40 |
41 | none
42 | false
43 | bin\Linux
44 | 4
45 |
46 |
47 | none
48 | false
49 | bin\Windows
50 | 4
51 |
52 |
53 |
54 |
55 | LuaNetRunner.cs
56 |
57 |
58 |
59 |
60 | {E915A0A4-2641-4F7E-8A88-8F123FA88BF1}
61 | LuaInterface
62 |
63 |
64 |
--------------------------------------------------------------------------------
/LuaInterface/Tests/Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | x86
6 | 9.0.21022
7 | 2.0
8 | {EED940BE-E828-463E-BF90-8BC824758149}
9 | Exe
10 | Tests
11 | v3.5
12 |
13 |
14 | true
15 | full
16 | false
17 | bin\Debug
18 | DEBUG;
19 | prompt
20 | 4
21 | x86
22 | false
23 | TestLua
24 |
25 |
26 | none
27 | true
28 | bin\Release
29 | prompt
30 | 4
31 | x86
32 | false
33 | TestLua
34 |
35 |
36 | none
37 | false
38 | bin\Linux
39 | 4
40 | TestLua
41 |
42 |
43 | none
44 | false
45 | bin\Windows
46 | 4
47 | Tests
48 |
49 |
50 |
51 |
52 | Entity.cs
53 |
54 |
55 | TestLua.cs
56 |
57 |
58 |
59 |
60 | {E915A0A4-2641-4F7E-8A88-8F123FA88BF1}
61 | LuaInterface
62 |
63 |
64 |
--------------------------------------------------------------------------------
/LuaInterface/Tests/bin/Debug/test.lua:
--------------------------------------------------------------------------------
1 | width=100
2 | height=200
3 | message="Hello World!"
4 | color={r=100,g=20,b=50}
5 | tree={branch1={leaf1=10,leaf2="leaf2"},leaf3="leaf3"}
6 |
7 | function func(x,y)
8 | return x,x+y
9 | end
10 |
--------------------------------------------------------------------------------
/LuaInterface/Tests/bin/Linux/test.lua:
--------------------------------------------------------------------------------
1 | width=100
2 | height=200
3 | message="Hello World!"
4 | color={r=100,g=20,b=50}
5 | tree={branch1={leaf1=10,leaf2="leaf2"},leaf3="leaf3"}
6 |
7 | function func(x,y)
8 | return x,x+y
9 | end
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | LuaInterface is a library for integration between the Lua language and Microsoft
2 | .NET platform's Common Language Runtime (CLR). Lua scripts can use it to
3 | instantiate CLR objects, access properties, call methods, and even handle
4 | events with Lua functions.
5 |
6 | Originally written by Fabio Mascarenhas, and currently maintained by Craig
7 | Presti at
8 | [here](http://code.google.com/p/luainterface)
9 |
10 | This corresponds to the latest version 2.0.3, backported to use P/Invoke against
11 | standard Lua 5.1 shared libraries. It provides a working version of LuaInterface
12 | buildable on Mono.
13 |
14 | On Debian/Ubuntu, you will need the `liblua5.1-dev` and `mono-devel` packages.
15 |
16 | To build, go into the src directory, and:
17 |
18 | $ ./configure
19 |
20 | This requires a Lua installation to run, but no other dependencies. It will look
21 | for the Lua headers in the usual places, `/usr/include` and `/usr/include/lua51`,
22 | if your Lua directory is somewhere else altogether set LUA_INCLUDE:
23 |
24 | $ ./configure LUA_INCLUDE=/home/you/lua-5.1.5/src DEFINES=lua
25 |
26 | `DEFINES` here is overriding the default on Linux, which is to assume
27 | the Lua shared library looks like `liblua5.1.so` rather than `lua51.so`.
28 |
29 | Configuration of LuaInterface is controlled by two C# preprocessor defines,
30 | `__Windows__` and `__liblua__`. The first makes the shared library extension '.dll',
31 | and the second makes the Lua shared library name 'liblua5.1' rather than 'lua51'.
32 | The latter is the default for Linux, at least for Debian/Ubuntu. Look at
33 | `src/LuaDLL.cs` to see how these are used, and how to modify for your
34 | configuration.
35 |
36 | (Currently, this project builds against Lua 5.1 or LuaJIT.)
37 |
38 | $ make
39 | $ ./
40 |
41 | Last step assumes you have a `~/bin` directory, but you can install globally with
42 |
43 | $ sudo ./install /usr/local/bin
44 |
45 | (You can also install globally with e.g `sudo ./install /usr/local/bin`)
46 |
47 | It will generate a wrapper script called `luai` looking like this:
48 |
49 | #!/bin/sh
50 | LUAI=/home/azisa/lua/MonoLuaInterface/bin
51 | export LD_LIBRARY_PATH=$LUAI
52 | export LUA_PATH=";;$LUAI/lua/?.lua"
53 | /usr/bin/mono $LUAI/luai.exe $*
54 |
55 | We have to locally mess with `LD_LIBRARY_PATH` (or `DYLD_LIBRARY_PATH` on
56 | OS X) because LuaInterface will need to find both the Lua shared library and the
57 | stub library `luanet.so`.
58 |
59 | The samples directory contains the original samples, plus some extended ones
60 | from the Lua for Windows project.
61 |
62 | Here is the proverbial 'Hello World':
63 |
64 | ```lua
65 | -- hello.lua
66 | luanet.load_assembly "System"
67 | local Console = luanet.import_type "System.Console"
68 | local Math = luanet.import_type "System.Math"
69 |
70 | Console.WriteLine("sqrt(2) is {0}",Math.Sqrt(2))
71 | ```
72 |
73 | Using the `CLRPackage` utilities, it is even simpler, since individual classes will be
74 | loaded as needed:
75 |
76 | ```lua
77 | -- hello2.lua
78 | require 'CLRPackage'
79 | import "System"
80 | Console.WriteLine("sqrt(2) is {0}",Math.Sqrt(2))
81 | ```
82 |
83 | If you want an interactive prompt, then there is a Lua interpreter in Lua, called
84 | `lua.lua`, in the samples directory:
85 |
86 | ```
87 | samples$ luai lua.lua
88 | Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
89 | lua.lua (c) David Manura, 2008-08
90 | > require 'CLRPackage'
91 | > Console.WriteLine("hello from Mono") -- 'System' is already loaded...
92 | hello from Mono
93 | >
94 | ```
95 |
96 | It is straightforward to write GTK# applications in Lua - note that here the
97 | `import` call is passed the package name and the namespace, in cases where
98 | they are not the same:
99 |
100 | ```Lua
101 | -- hello-gtk.lua
102 | require 'CLRPackage'
103 | import ('gtk-sharp','Gtk')
104 |
105 | Application.Init()
106 |
107 | local win = Window("Hello from GTK#")
108 |
109 | win.DeleteEvent:Add(function()
110 | Application.Quit()
111 | end)
112 |
113 | win:Resize(300,300)
114 |
115 | local label = Label()
116 | label.Text = "Hello World!"
117 | win:Add(label)
118 |
119 | win:ShowAll()
120 |
121 | Application.Run()
122 |
123 | ```
124 |
125 | This automatically creates globals, which is the only way that Lua can mimick the
126 | usual C# scope resolution rules. For larger programs, this is probably not a
127 | good idea, and so there's a way of explicitly creating namespaces:
128 |
129 |
130 | ```Lua
131 | -- hello-gtk2.lua
132 | require 'CLRPackage'
133 | luanet.load_assembly 'gtk-sharp'
134 | local gtk = luanet.namespace 'Gtk'
135 |
136 | gtk.Application.Init()
137 |
138 | local win = gtk.Window("Hello from GTK#")
139 |
140 | win.DeleteEvent:Add(function()
141 | gtk.Application.Quit()
142 | end)
143 |
144 | win:Resize(300,300)
145 |
146 | local label = gtk.Label()
147 | label.Text = "Hello World!"
148 | win:Add(label)
149 |
150 | win:ShowAll()
151 |
152 | gtk.Application.Run()
153 |
154 | ```
155 |
156 | ## LuaInterface from C#
157 |
158 | LuaInterface is usually used by CLR applications which need a scripting language.
159 | An example of the high-level interface with Lua is `tests/CallLua.cs`; this directory
160 | also has the original C# tests. (These all pass, except for passing a managed function
161 | to `string.gsub`, which is a Lua limitation.)
162 |
163 | A basic C# program is here; it evaluates Lua expressions:
164 |
165 | ```C#
166 | using System;
167 | using LuaInterface;
168 |
169 | public class TestLua {
170 |
171 | public static void Main(string[] args) {
172 | if (args.Length == 0) {
173 | Console.WriteLine("provide a Lua expression!");
174 | } else {
175 | Lua L = new Lua(); // will open all the standard Lua libraries
176 | try {
177 | object[] results = L.DoString("return "+args[0]);
178 | Console.WriteLine("answer is {0}",results[0]);
179 | } catch(Exception e) {
180 | Console.WriteLine("error: {0}",e.Message);
181 | }
182 | L.Close();
183 | }
184 | }
185 |
186 | }
187 | ```
188 |
189 | It must be compiled with a reference to LuaInterface.dll, and both luanet.so and liblua5.1.so must
190 | be accessible on the library path.
191 |
192 | ## Lua API
193 |
194 | These are contained in the global table `luanet`:
195 |
196 | ''luanet.load_assembly''
197 |
198 | Loads a CLR assembly; will throw an error if not found.
199 |
200 | ''luanet.import_type''
201 |
202 | Bring in a class using the fully qualified name, e.g.
203 | `C = luanet.import_type 'System.Console'`. The assembly must have been previously
204 | loaded.
205 |
206 | ''luanet.get_object_member''
207 |
208 | This is given an object, and an index (string or integer). It can be used to look
209 | up a property value, and will return nil + error message if the property does
210 | not exist. (Looking up fields and indices directly will fail with an error).
211 |
212 | ''luanet.make_object''
213 |
214 | This takes a table and a CLR class name and allows you to override any virtual methods
215 | of that class.
216 |
217 | For instance, given this C# class:
218 |
219 | ```C#
220 | public class CSharp {
221 | public virtual string MyMethod(string s) {
222 | return s.ToUpper();
223 | }
224 |
225 | public static string UseMe (CSharp obj, string val) {
226 | return obj.MyMethod(val);
227 | }
228 | }
229 | ```
230 |
231 | then the following Lua code creates a proxy object where `MyMethod` is overriden:
232 |
233 | ```Lua
234 | luanet.load_assembly 'CallLua' -- load the assembly containing CSharp
235 | local CSharp = luanet.import_type 'CSharp'
236 | local T = {}
237 | function T:MyMethod(s)
238 | return s:lower()
239 | end
240 | luanet.make_object(T,'CSharp')
241 | print(CSharp.UseMe(T,'CoOl'))
242 | ```
243 |
244 | There is a corresponding ``luanet.free_object`` for explicit disposal.
245 |
246 | (See tests/CallLua.cs)
247 |
248 | In addition, this version of LuaInterface defines two extra functions
249 |
250 | ''luanet.ctype''
251 |
252 | This is the equivalent of `typeof` in C#; given a class proxy object, return the
253 | actual CLR type.
254 |
255 | ```Lua
256 | samples $ luai lua.lua
257 | Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
258 | lua.lua (c) David Manura, 2008-08
259 | > = String
260 | ProxyType(System.String): 54267293
261 | > ctype = luanet.ctype
262 | > = ctype(String)
263 | System.String: 2033388324
264 |
265 | ```
266 |
267 | ''luanet.enum''
268 |
269 | This has two forms. The first casts an integer into an enum type:
270 |
271 | ```Lua
272 | > enum = luanet.enum
273 | > import 'System.Reflection'
274 | > = BindingFlags.Static
275 | Static: 8
276 | > = enum(BindingFlags,8)
277 | Static: 8
278 | ```
279 |
280 | The second form parses a string representation for an enumeration type.
281 | This is useful for enum flags:
282 |
283 | ```Lua
284 | > = enum(BindingFlags,'Static,Public')
285 | Static, Public: 24
286 | ```
287 |
288 | It's now possible to use CLR reflection in a non-clumsy way; see `tests/ctype.lua`
289 | for an example of using the Lua API directly from Lua itself, by importing all
290 | static methods of the `LuaDLL` class.
291 |
292 | ## CLRPackage
293 |
294 | This Lua module provides some very useful shortcuts. We have already seen `import`,
295 | which brings classes into the global Lua table. This is not appropriate for larger
296 | applications, so there is `luanet.namespace`. Note that its argument may be a table:
297 |
298 | ```Lua
299 | local gtk,gdk = luanet.namespace {'Gtk','Gdk'}
300 | ```
301 |
302 | (You do have to explicitly load the assemblies before using this)
303 |
304 | ''luanet.make_array''
305 |
306 | This is a convenience function for creating CLR arrays; it is passed a class (the proxy,
307 | not the type) and a table of values.
308 |
309 | Note that the Lua expression `Class[10]` already makes us a `Class[]` array!
310 |
311 | Bear in mind that CLR arrays index from zero, and throw a range error if the index
312 | is out of bounds.
313 |
314 | ''luanet.each''
315 |
316 | This constructs a Lua iterator from an IEnumerable interface:
317 |
318 | ```Lua
319 | > dd = make_array(Double,{1,2,10})
320 | > for x in each(dd) do print(x) end
321 | 1
322 | 2
323 | 10
324 | > import 'System.Collections'
325 | > al = ArrayList()
326 | > al:Add(10)
327 | > al:Add('hello')
328 | > for o in each(al) do print(o) end
329 | 10
330 | hello
331 | > ht = Hashtable()
332 | > ht.one = 1
333 | > ht.two = 2
334 | > for p in each(ht) do print(p.Key,p.value) end
335 | one 1
336 | two 2
337 |
338 | ```
339 |
340 |
341 |
342 |
343 |
344 |
345 |
--------------------------------------------------------------------------------
/bin/lua/CLRForm.lua:
--------------------------------------------------------------------------------
1 | require "CLRPackage"
2 | import "System"
3 | import "System.Windows.Forms"
4 | import "System.Drawing"
5 | local Directory = luanet.import_type("System.IO.Directory")
6 | local Path = luanet.import_type("System.IO.Path")
7 | local File = luanet.import_type("System.IO.File")
8 | local append = table.insert
9 | local ferr = io.stderr -- for debugging
10 |
11 | ----------- some generally useful functions -----------------
12 | --- Can be used to set multiple properties of an object, by supplying a table.
13 | -- e.g. set(button,{Text="Click Me",Dock = DockStyle.Fill})
14 | function set (obj,props)
15 | for k,v in pairs(props) do
16 | if type(k) == 'string' then
17 | obj[k] = v
18 | end
19 | end
20 | end
21 |
22 | --- works like AddRange, except it takes a table of controls
23 | -- e.g add_controls(form,{button1,button2})
24 | function add_controls (ctrl,ctrls)
25 | for k,v in pairs(ctrls) do
26 | ctrl.Controls:Add(v)
27 | end
28 | end
29 |
30 | function ShowMessageBox (caption,icon)
31 | icon = icon or MessageBoxIcon.Information
32 | MessageBox.Show(caption,arg[0],MessageBoxButtons.OK,icon)
33 | end
34 |
35 | function ShowError (caption)
36 | ShowMessageBox(caption,MessageBoxIcon.Error)
37 | end
38 |
39 | ---------- Utility function for creating classes -------------
40 | --- Does single-inheritance and _delegation_
41 | function class(base)
42 | local c = {} -- a new class instance, which is the metatable for all objects of this type
43 | local mt = {} -- a metatable for the class instance
44 | local userdata_base
45 | if base == nil then
46 | --nada
47 | elseif type(base) == 'table' then
48 | -- our new class is a shallow copy of the base class!
49 | for i,v in pairs(base) do
50 | c[i] = v
51 | end
52 | c._base = base
53 | -- inherit the 'not found' handler, if present
54 | if c._handler then mt.__index = c._handler end
55 | end
56 | -- the class will be the metatable for all its objects,
57 | -- and they will look up their methods in it.
58 | c.__index = c
59 |
60 | -- expose a ctor which can be called by ()
61 | mt.__call = function(class_tbl,...)
62 | local obj= {}
63 | setmetatable(obj,c)
64 | -- nice alias for the base class ctor (which you have to call explicitly if you have a ctor)
65 | if base then c.super = base._init end
66 | if c._init then
67 | c._init(obj,...)
68 | else
69 | -- make sure that any stuff from the base class is initialized!
70 | if base and base._init then
71 | base._init(obj,...)
72 | end
73 | end
74 | return obj
75 | end
76 |
77 | -- Call Class.catch to set a handler for methods/properties not found in the class!
78 | c.catch = function(handler)
79 | c._handler = handler
80 | mt.__index = handler
81 | end
82 | c._init = ctor
83 | c.is_a = function(self,klass)
84 | local m = getmetatable(self)
85 | if not m then return false end --*can't be an object!
86 | while m do
87 | if m == klass then return true end
88 | m = rawget(m,'_base')
89 | end
90 | return false
91 | end
92 | c.class_of = function(obj)
93 | return c.is_a(obj,c)
94 | end
95 | -- any object can have a specified delegate which is called with unrecognized methods
96 | -- if _handler exists and obj[key] is nil, then pass onto handler!
97 | c.delegate = function(self,obj)
98 | local me = self
99 | mt.__index = function(tbl,key)
100 | -- handling fields!
101 | local getter = rawget(c,"Get_"..key)
102 | if getter then return getter(me) end
103 | getter = rawget(me,"_"..key)
104 | if getter then return getter end
105 | local method = obj[key]
106 | if method then
107 | -- it exists in the delegate! First check if it's callable
108 | if type(method) == 'function' or getmetatable(method).__call then
109 | return function(self,...)
110 | return method(obj,...)
111 | end
112 | else -- otherwise, just return
113 | return method
114 | end
115 | elseif self._handler then
116 | return self._handler(tbl,key)
117 | end
118 | end
119 | c.__newindex = function(self,key,val)
120 | local setter = rawget(c,"Set_"..key)
121 | if setter then
122 | setter(self,val)
123 | else
124 | obj[key] = val
125 | end
126 | end
127 | end
128 | setmetatable(c,mt)
129 | return c
130 | end
131 |
132 | ----------- Creating Menus -----------------------------
133 |
134 | local ShortcutType = Shortcut.F1:GetType()
135 |
136 | local function parse_shortcut (s)
137 | local res
138 | if pcall(function() -- we have to catch the exception!
139 | res = Enum.Parse(ShortcutType,s,false)
140 | end) then return res end
141 | end
142 |
143 | local function add_menu_items (item,tbl)
144 | for i = 1,#tbl,2 do
145 | item.MenuItems:Add(create_menu_item(tbl[i],tbl[i+1]))
146 | end
147 | end
148 |
149 | function create_menu_item (label,action)
150 | local item = MenuItem()
151 | local shortcut = label:match('%((%w+)%)')
152 | if shortcut then
153 | local shortcut = parse_shortcut(shortcut)
154 | if shortcut then item.Shortcut = shortcut end
155 | label = label:match('(.+)%(')
156 | end
157 | item.Text = label
158 | if type(action) == 'function' then
159 | item.Click:Add(action)
160 | else
161 | add_menu_items(item,action)
162 | end
163 | return item
164 | end
165 |
166 | function main_menu (tbl)
167 | local mm = MainMenu()
168 | add_menu_items(mm,tbl)
169 | return mm
170 | end
171 |
172 | function popup_menu (tbl)
173 | local mm = ContextMenu()
174 | add_menu_items(mm,tbl)
175 | return mm
176 | end
177 |
178 | -- a useful function for creating menu callbacks to methods of a given object.
179 | function method (obj,fun)
180 | return function()
181 | fun(obj)
182 | end
183 | end
184 |
185 | local function populate_control (form,tbl)
186 | set(form,tbl)
187 | if #tbl > 0 then -- has an array part, containing controls
188 | if #tbl == 1 then
189 | table.insert(tbl,1,"Fill")
190 | end
191 | local i = 1
192 | while i <= #tbl do
193 | local c = tbl[i]
194 | local dock
195 | if type(c) == 'string' then
196 | dock = c
197 | c = tbl[i+1]
198 | i = i + 1
199 | c.Dock = DockStyle[dock]
200 | end
201 | form.Controls:Add(c)
202 | i = i + 1
203 | end
204 | end
205 | return form
206 | end
207 |
208 | function LuaForm (tbl)
209 | return populate_control(Form(),tbl)
210 | end
211 |
212 | function LuaPanel (tbl)
213 | return populate_control(Panel(),tbl)
214 | end
215 |
216 |
217 | ---------------- Stream Layout --------------
218 | StreamLayout = class()
219 |
220 | function StreamLayout:_init(panel)
221 | self.xsep = 10
222 | self.X = self.xsep
223 | self.Y = self.xsep
224 | self.panel = panel
225 | self.newline = true
226 | self.maxX = 0
227 | self.maxHeight = 0
228 | self.labels = {}
229 | self.panel:SuspendLayout()
230 | end
231 |
232 | function StreamLayout:Add(c,like)
233 | if like then self.X = like.Left end
234 | c.Location = Point(self.X,self.Y)
235 | self.panel.Controls:Add(c)
236 | self.X = self.X + c.Width + self.xsep
237 | self.maxX = math.max(self.maxX,self.X)
238 | self.maxHeight = math.max(self.maxHeight,c.Height)
239 | if self.newline then
240 | self.firstC = c
241 | self.newline = false
242 | self.maxHeight = 0
243 | end
244 | end
245 |
246 | function StreamLayout:AddRow(lbl,...)
247 | local row = {...}
248 | if lbl then
249 | local label = Label()
250 | label.AutoSize = true
251 | label.Text = lbl
252 | row.label = label
253 | append(self.labels,row)
254 | self:Add(label)
255 | end
256 | for i,c in ipairs(row) do
257 | self:Add(c)
258 | end
259 | self:NextRow()
260 | end
261 |
262 | function StreamLayout:Height()
263 | return self.Y + self.maxHeight + self.xsep
264 | end
265 |
266 | function StreamLayout:Width()
267 | return self.maxX
268 | end
269 |
270 | function StreamLayout:NextRow()
271 | self.Y = self:Height()
272 | self.X = self.xsep
273 | self.newline = true
274 | end
275 |
276 | function StreamLayout:Finish ()
277 | local width = 0
278 | for i,row in ipairs(self.labels) do
279 | width = math.max(width,row.label.Width)
280 | end
281 | if width > 0 then -- i.e there is an explicit row of labels
282 | for i,row in ipairs(self.labels) do
283 | local lbl = row.label
284 | for j,c in ipairs(row) do
285 | c.Left = c.Left + (width - lbl.Width)
286 | self.maxX = math.max(self.maxX,c.Left+c.Width+self.xsep)
287 | end
288 | end
289 | end
290 | self.panel:ResumeLayout(false)
291 | end
292 |
293 | LayoutForm = class()
294 |
295 | function LayoutForm:_init ()
296 | self.form = Form()
297 | self.layout = StreamLayout(self.form)
298 | self.hasButtons = false
299 | self.ok = false
300 | self.cancel = false
301 | self.finishedLayout = false
302 | -- this method can only be called once we've set up our own fields!
303 | self:delegate(self.form)
304 | self.FormBorderStyle = FormBorderStyle.FixedDialog
305 | self.MaximizeBox = false
306 | self.MinimizeBox = false
307 | end
308 |
309 | function LayoutForm:AddControl(c)
310 | self.layout:Add(c)
311 | end
312 |
313 | function LayoutForm:AddControlRow(lbl,...)
314 | self.layout:AddRow(lbl,...)
315 | end
316 |
317 | function LayoutForm:AddTextBoxRow(lbl)
318 | local textBox = TextBox()
319 | self:AddControlRow(lbl,textBox)
320 | return textBox
321 | end
322 |
323 | function LayoutForm:Btn (title,res)
324 | local b = Button()
325 | b.Text = title
326 | if res == DialogResult.OK then
327 | self.AcceptButton = b
328 | elseif res == DialogResult.Cancel then
329 | self.CancelButton = b
330 | end
331 | self.layout:Add(b)
332 | self.hasButtons = true
333 | return b
334 | end
335 |
336 | function LayoutForm:OkBtn (title)
337 | return self:Btn(title,DialogResult.OK)
338 | end
339 |
340 | function LayoutForm:CancelBtn (title)
341 | return self:Btn(title,DialogResult.Cancel)
342 | end
343 |
344 | function LayoutForm:NextRow()
345 | self.layout:NextRow()
346 | end
347 |
348 | function LayoutForm:OkCancel ()
349 | if not self.layout.newline then self:NextRow() end
350 | self.ok = self:OkBtn "OK"
351 | self.cancel = self:CancelBtn "Cancel"
352 | end
353 |
354 | function LayoutForm:OnOK()
355 | return true
356 | end
357 |
358 | function LayoutForm:CenterControls (...)
359 | local w = 0
360 | local ctrls = {...}
361 | for _,c in ipairs(ctrls) do
362 | w = w + c.Width
363 | end
364 | local diff = (self.layout:Width() - w)/(#ctrls + 1)
365 | local xx = diff
366 | for _,c in ipairs(ctrls) do
367 | c.Left = xx
368 | xx = xx + c.Width + diff
369 | end
370 | end
371 |
372 | function LayoutForm:FinishLayout()
373 | if not self.hasButtons then
374 | self:OkCancel()
375 | self:CenterControls(self.ok,self.cancel)
376 | self.ok.Click:Add(function()
377 | if self:OnOK() then
378 | self.DialogResult = DialogResult.OK
379 | else
380 | self.DialogResult = DialogResult.None
381 | end
382 | end)
383 | end
384 | local layout = self.layout
385 | layout:Finish()
386 | self.ClientSize = Size(layout:Width(), layout:Height())
387 | self.finishedLayout = true
388 | end
389 |
390 | function LayoutForm:ShowDialogOK ()
391 | if not self.finishedLayout then
392 | self:FinishLayout()
393 | end
394 | return self:ShowDialog() == DialogResult.OK
395 | end
396 |
397 | ------------------- Converters ------------------------------
398 | -- These classes convert values between controls and Lua values, and provide basic verification,
399 | -- like ensuring that a string is a valid number, for instance.
400 | -- They provide an appropriate control for editing the particular value.
401 | Converter = class()
402 |
403 | function Converter:Control ()
404 | self.box = TextBox()
405 | return self.box
406 | end
407 |
408 | function Converter:Read (c)
409 | return c.Text
410 | end
411 |
412 | function Converter:Write (c,text)
413 | c.Text = text
414 | end
415 |
416 | NumberConverter = class(Converter)
417 |
418 | function NumberConverter:Read (c)
419 | local txt = c.Text
420 | local value = tonumber(txt)
421 | if not value then return nil, "Cannot convert '"..txt.."' to a number" end
422 | return value
423 | end
424 |
425 | BoolConverter = class(Converter)
426 |
427 | function BoolConverter:Control ()
428 | return CheckBox()
429 | end
430 |
431 | function BoolConverter:Read (c)
432 | return c.Checked
433 | end
434 |
435 | function BoolConverter:Write (c,val)
436 | c.Checked = val
437 | end
438 |
439 | ListConverter = class(Converter)
440 |
441 | function ListConverter:_init (list)
442 | self.list = list
443 | end
444 |
445 | function ListConverter:Control ()
446 | local c = ComboBox()
447 | if not self.list.Editable then
448 | c.DropDownStyle = ComboBoxStyle.DropDownList
449 | end
450 | for i,item in ipairs(self.list) do
451 | c.Items:Add(item)
452 | end
453 | return c
454 | end
455 |
456 | function ListConverter:Read (c)
457 | local val = c.SelectedItem
458 | if not val then val = c.Text end
459 | return val
460 | end
461 |
462 | function ListConverter:Write (c,val)
463 | c.SelectedItem = val
464 | end
465 |
466 | FileConverter = class(Converter)
467 |
468 | function FileConverter:_init (reading,mask)
469 | -- the filter is in a simplified form like 'Lua Files (*.lua)|C# Files (*.cs)"
470 | -- this will expand it into the required form.
471 | self.filter = mask:gsub("%((.-)%)",function(pat)
472 | return "("..pat..")|"..pat
473 | end)
474 | self.reading = reading
475 | end
476 |
477 | -- ExtraControl is an optional method which gives a converter the opportunity of adding another
478 | -- control to the row after the primary control. In this case, we create a file browser button.
479 | function FileConverter:ExtraControl ()
480 | local btn = Button()
481 | local box = self.box
482 | btn.Width = 30
483 | btn.Text = ".."
484 | btn.Click:Add(function()
485 | -- if possible, open the file browser in the same directory as the filename
486 | local path = self:Read(box)
487 | if not File.Exists(path) then
488 | path = Directory.GetCurrentDirectory()
489 | else
490 | path = Path.GetDirectoryName(path)
491 | end
492 | -- depending on whether we want a file to read or write ("Save as"), pick the file dialog.
493 | local filebox
494 | if self.reading then filebox = OpenFileDialog
495 | else filebox = SaveFileDialog end
496 | local dlg = filebox()
497 | dlg.Filter = self.filter
498 | dlg.InitialDirectory = path
499 | if dlg:ShowDialog() == DialogResult.OK then
500 | self:Write(box,dlg.FileName)
501 | end
502 | end)
503 | return btn
504 | end
505 |
506 | -- Note an important convention: this converter puts the full file path in the text box's Tag field,
507 |
508 | function FileConverter:Write (c,val)
509 | c.Text = Path.GetFileName(val)
510 | c.Tag = val
511 | end
512 |
513 | function FileConverter:Read (c)
514 | return c.Tag
515 | end
516 |
517 | -- there are then two subclasses, depending if you want to open a file for reading or writing.
518 |
519 | FileIn = class(FileConverter)
520 |
521 | function FileIn:_init (mask)
522 | self:super(true,mask)
523 | end
524 |
525 | FileOut = class(FileConverter)
526 |
527 | function FileOut:_init (mask)
528 | self:super(false,mask)
529 | end
530 |
531 | local converters = {
532 | number = NumberConverter(),
533 | string = Converter(),
534 | boolean = BoolConverter(),
535 | }
536 |
537 | function Converter.AddConverter (typename,conv)
538 | converters[typename] = conv
539 | end
540 |
541 | ---------------- AutoVarDialog ------------------------------
542 |
543 | local function callable (method)
544 | local mt = getmetatable(method)
545 | return type(method) == 'function' or (mt and mt.__call)
546 | end
547 |
548 | local function simple_list (nxt)
549 | return type(nxt) == 'table' and #nxt > 0
550 | end
551 |
552 | AutoVarDialog = class(LayoutForm)
553 |
554 | function AutoVarDialog:_init (tbl)
555 | self.rows = {}
556 | self.T = tbl.Object or _G
557 | self.verify = tbl.Verify
558 | self.verify_exists = tbl.Verify ~= nil
559 | --end of local fields; NOW we can initialize the form!
560 | self.super(self)
561 | self.Text = tbl.Text or "untitled"
562 | local i,n = 1,#tbl
563 | while i <= n do
564 | local converter,constraint,extra
565 | local lbl = tbl[i]
566 | local var = tbl[i+1]
567 | local value = self.T[var]
568 | local vtype = type(value)
569 | -- is there a particular default or constraint set?
570 | if i+1 < n then
571 | local nxt = tbl[i+2]
572 | if type(nxt) ~= 'string' then
573 | if callable(nxt) then
574 | constraint = nxt
575 | elseif simple_list(nxt) then
576 | -- have been given a list of possible values
577 | converter = ListConverter(nxt)
578 | elseif Converter.class_of(nxt) then
579 | converter = nxt
580 | else
581 | ShowError("Unknown converter or verify function: "..nxt)
582 | return
583 | end
584 | i = i + 1
585 | end
586 | end
587 | if not converter then
588 | -- use a default converter appropriate to this type
589 | converter = converters[vtype]
590 | if not converter then
591 | ShowError("Cannot find a converter for type: "..vtype)
592 | return
593 | end
594 | end
595 | local c = converter:Control()
596 | self:AddControlRow(lbl,c,converter.ExtraControl and converter:ExtraControl())
597 | converter:Write(c,value)
598 | append(self.rows,{cntrl=c,converter=converter,var=var, constraint=constraint})
599 | i = i + 2
600 | end
601 | end
602 |
603 | function AutoVarDialog:OnOK ()
604 | local T = {}
605 | for _,t in ipairs(self.rows) do
606 | local value,err = t.converter:Read(t.cntrl)
607 | if not err and t.constraint then
608 | err = t.constraint(value)
609 | end
610 | if err then
611 | ShowError(err)
612 | t.cntrl:Focus()
613 | return false
614 | end
615 | T[t.var] = value
616 | end
617 | -- a function to verify the fields has been supplied
618 | if self.verify_exists then
619 | local err = self.verify(T)
620 | if err then
621 | ShowError(err)
622 | return false
623 | end
624 | end
625 | -- NOW we can finally copy the changed values into the target table!
626 | for k,v in pairs(T) do
627 | self.T[k] = v
628 | end
629 | return true
630 | end
631 |
632 | function Match (pat,err)
633 | return function (s)
634 | --ferr:write(',',s,',',pat,'\n')
635 | if not s:find(pat) then return err end
636 | end
637 | end
638 |
639 | function Range (x1,x2)
640 | if not x2 then -- unbound upper range
641 | return function(x)
642 | if x < x1 then return "Must be greater than "..x1 end
643 | end
644 | elseif not x1 then -- unbound lower range
645 | return function(x)
646 | if x > x2 then return "Must be less than "..x2 end
647 | end
648 | else
649 | return function(x)
650 | if x < x1 or x > x2 then return "Must be in range "..x1.." to "..x2 end
651 | end
652 | end
653 | end
654 |
655 | NonBlank = Match ('%S+','Must be a non-blank string')
656 | Word = Match('^%w+$','Must be a word')
657 |
658 | --- A useful function for prompting a user for a single value.
659 | -- returns a non-nil value if the user clicks on OK or presses .
660 | function PromptForString (caption,prompt,default)
661 | local tbl = {val = default or ""}
662 | local form = AutoVarDialog {Text = caption, Object = tbl;
663 | prompt,"val"
664 | }
665 | if form:ShowDialogOK() then
666 | return tbl.val
667 | end
668 | end
669 |
--------------------------------------------------------------------------------
/bin/lua/CLRPackage.lua:
--------------------------------------------------------------------------------
1 | ---
2 | --- This lua module provides auto importing of .net classes into a named package.
3 | --- Makes for super easy use of LuaInterface glue
4 | ---
5 | --- example:
6 | --- Threading = CLRPackage("System", "System.Threading")
7 | --- Threading.Thread.Sleep(100)
8 | ---
9 | --- Extensions:
10 | --- import() is a version of CLRPackage() which puts the package into a list which is used by a global __index lookup,
11 | --- and thus works rather like C#'s using statement. It also recognizes the case where one is importing a local
12 | --- assembly, which must end with an explicit .dll extension.
13 |
14 | --- Alternatively, luanet.namespace can be used for convenience without polluting the global namespace:
15 | --- local sys,sysi = luanet.namespace {'System','System.IO'}
16 | -- sys.Console.WriteLine("we are at {0}",sysi.Directory.GetCurrentDirectory())
17 |
18 |
19 | -- LuaInterface hosted with stock Lua interpreter will need to explicitly require this...
20 | if not luanet then require 'luanet' end
21 |
22 | local import_type, load_assembly = luanet.import_type, luanet.load_assembly
23 |
24 | local mt = {
25 | --- Lookup a previously unfound class and add it to our table
26 | __index = function(package, classname)
27 | local class = rawget(package, classname)
28 | if class == nil then
29 | class = import_type(package.packageName .. "." .. classname)
30 | package[classname] = class -- keep what we found around, so it will be shared
31 | end
32 | return class
33 | end
34 | }
35 |
36 | function luanet.namespace(ns)
37 | if type(ns) == 'table' then
38 | local res = {}
39 | for i = 1,#ns do
40 | res[i] = luanet.namespace(ns[i])
41 | end
42 | return unpack(res)
43 | end
44 | -- FIXME - table.packageName could instead be a private index (see Lua 13.4.4)
45 | local t = { packageName = ns }
46 | setmetatable(t,mt)
47 | return t
48 | end
49 |
50 | local globalMT, packages
51 |
52 | local function set_global_mt()
53 | packages = {}
54 | globalMT = {
55 | __index = function(T,classname)
56 | for i,package in ipairs(packages) do
57 | local class = package[classname]
58 | if class then
59 | _G[classname] = class
60 | return class
61 | end
62 | end
63 | end
64 | }
65 | setmetatable(_G, globalMT)
66 | end
67 |
68 | --- Create a new Package class
69 | function CLRPackage(assemblyName, packageName)
70 | -- a sensible default...
71 | packageName = packageName or assemblyName
72 | local ok = pcall(load_assembly,assemblyName) -- Make sure our assembly is loaded
73 | return luanet.namespace(packageName)
74 | end
75 |
76 | function import (assemblyName, packageName)
77 | if not globalMT then
78 | set_global_mt()
79 | end
80 | if not packageName then
81 | local i = assemblyName:find('%.dll$')
82 | if i then packageName = assemblyName:sub(1,i-1)
83 | else packageName = assemblyName end
84 | end
85 | local t = CLRPackage(assemblyName,packageName)
86 | table.insert(packages,t)
87 | return t
88 | end
89 |
90 |
91 | function luanet.make_array (tp,tbl)
92 | local arr = tp[#tbl]
93 | for i,v in ipairs(tbl) do
94 | arr:SetValue(v,i-1)
95 | end
96 | return arr
97 | end
98 |
99 | function luanet.each(o)
100 | local e = o:GetEnumerator()
101 | return function()
102 | if e:MoveNext() then
103 | return e.Current
104 | end
105 | end
106 | end
107 |
108 |
--------------------------------------------------------------------------------
/doc/LuaRunner.txt:
--------------------------------------------------------------------------------
1 | LuaRunner -- runs Lua scripts with CLR access
2 | Usage: luarunner [{}]
3 |
--------------------------------------------------------------------------------
/doc/guide.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevedonovan/MonoLuaInterface/b923c54ccc36c7d8788ff049e9778bb8e9278668/doc/guide.pdf
--------------------------------------------------------------------------------
/doc/luainterface.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevedonovan/MonoLuaInterface/b923c54ccc36c7d8788ff049e9778bb8e9278668/doc/luainterface.pdf
--------------------------------------------------------------------------------
/samples/NPlot.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevedonovan/MonoLuaInterface/b923c54ccc36c7d8788ff049e9778bb8e9278668/samples/NPlot.dll
--------------------------------------------------------------------------------
/samples/TextBox.cs:
--------------------------------------------------------------------------------
1 | // build@ csc /debug /nologo /target:library TextBox.cs
2 | using System;
3 | using System.Windows.Forms;
4 | using System.Drawing;
5 |
6 | namespace TextBox {
7 |
8 | public delegate bool SpecialKeyHandler(Keys key);
9 |
10 | class ConsoleTextBox : RichTextBox {
11 | public SpecialKeyHandler handler;
12 |
13 | protected const int WM_KEYDOWN = 0x0100;
14 |
15 | public void SetHandler(SpecialKeyHandler handler_) {
16 | handler = handler_;
17 | }
18 |
19 | public override bool PreProcessMessage(ref Message msg) {
20 | if (msg.Msg == WM_KEYDOWN) {
21 | Keys keyData = ((Keys) (int) msg.WParam) | ModifierKeys;
22 | if (keyData == Keys.Enter || keyData == Keys.Escape || keyData == Keys.Tab ||
23 | keyData == Keys.Up || keyData == Keys.Down )
24 | {
25 | if (handler(keyData)) {
26 | return true;
27 | }
28 | }
29 | }
30 | return base.PreProcessMessage(ref msg);
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/samples/TextBox.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevedonovan/MonoLuaInterface/b923c54ccc36c7d8788ff049e9778bb8e9278668/samples/TextBox.dll
--------------------------------------------------------------------------------
/samples/auto1.wlua:
--------------------------------------------------------------------------------
1 | -- auto1.wlua
2 | require "CLRForm"
3 |
4 | data = {
5 | firstname = "",
6 | lastname = "",
7 | age = 0,
8 | title = "",
9 | phone = "",
10 | email = ""
11 | }
12 |
13 | form = AutoVarDialog { Text = "Please Supply Details", Object = data;
14 | "First Name:","firstname",
15 | "Last Name:","lastname",
16 | "Age:","age",
17 | "Title:","title",
18 | "Phone number:","phone",
19 | "E-mail Address:","email"
20 | }
21 |
22 | if form:ShowDialogOK() then
23 | print 'ok'
24 | os.exit(0)
25 | end
26 |
27 |
28 |
--------------------------------------------------------------------------------
/samples/auto2.wlua:
--------------------------------------------------------------------------------
1 | -- auto1.wlua
2 | require "CLRForm"
3 |
4 | data = {
5 | firstname = "steve",
6 | lastname = "donovan",
7 | age = 16,
8 | title = "Mr",
9 | phone = "+27116481212",
10 | email = "steve.j.donovan@gmail.com"
11 | }
12 |
13 | form = AutoVarDialog { Text = "Please Supply Details", Object = data;
14 | "First Name:","firstname",NonBlank,
15 | "Last Name:","lastname",NonBlank,
16 | "Age:","age",Range(16,120),
17 | "Title:","title",{"Mr","Ms","Dr","Prof"},
18 | "Phone number:","phone",Match ('^%+%d+$',"Must be a valid phone number"),
19 | "E-mail Address:","email",Match ("%S+@%S+","Must be valid email address")
20 | }
21 |
22 | if form:ShowDialogOK() then
23 | print 'ok'
24 | end
25 |
26 | os.exit(0)
27 |
28 |
29 |
--------------------------------------------------------------------------------
/samples/autoform.wlua:
--------------------------------------------------------------------------------
1 | -- autoform.wlua
2 | require "CLRForm"
3 |
4 | tbl = {
5 | x = 2.3,
6 | y = 10.2,
7 | z = "two",
8 | t = -1.0,
9 | file = "c:\\lang\\lua\\ilua.lua",
10 | outfile = "",
11 | res = true,
12 | }
13 |
14 | form = AutoVarDialog { Text = "Test AutoVar", Object = tbl;
15 | "First variable:","x", Range(0,4),
16 | "Second Variable:","y",
17 | "Domain name:","z", {"one","two","three"; Editable=true},
18 | "Blonheim's Little Adjustment:","t",
19 | "Input File:","file",FileIn "Lua (*.lua)|C# (*.cs)",
20 | "Output File:","outfile",FileOut "Text (*.txt)",
21 | "Make a Note?","res",
22 | }
23 |
24 | if form:ShowDialogOK() then
25 | print(tbl.x,tbl.z,tbl.res,tbl.file)
26 | end
27 |
28 | os.exit(0)
29 |
--------------------------------------------------------------------------------
/samples/com.lua:
--------------------------------------------------------------------------------
1 | --require 'luanet'
2 | require 'CLRPackage'
3 | import 'System'
4 | import 'System.Reflection'
5 | local get_flags = luanet.enum(BindingFlags,'GetProperty,IgnoreCase,Public')
6 | local put_flags = luanet.enum(BindingFlags,'SetProperty,IgnoreCase,Public')
7 | local call_flags = luanet.enum(BindingFlags,'InvokeMethod,IgnoreCase,Public')
8 |
9 | local function A(a)
10 | return luanet.make_array(Object,a)
11 | end
12 |
13 | local empty = A{}
14 | local com_wrapper
15 | local T = luanet.ctype(__ComObject)
16 |
17 |
18 | local function maybe_wrap(res)
19 | if type(res) == 'userdata' then
20 | if res:GetType() == T then return com_wrapper(res) end
21 | end
22 | return res
23 | end
24 |
25 |
26 | local function caller(obj,key)
27 | local T = obj:GetType()
28 | return setmetatable({},{
29 | __call = function(t,o,...)
30 | return maybe_wrap(T:InvokeMember(key,call_flags,nil,obj,A{...}))
31 | end
32 | })
33 | end
34 |
35 | function com_wrapper(obj)
36 | local T = obj:GetType()
37 | return setmetatable({},{
38 | __index = function(self,key)
39 | local ok,res = pcall(T.InvokeMember,T,key,get_flags,nil,obj,empty)
40 | if not ok then
41 | res = tostring(res)
42 | if res:match 'Member not found' then
43 | return caller(obj,key) --local c =
44 | --~ rawset(self,key,c)
45 | --~ return c
46 | else
47 | error("cannot find "..key,2)
48 | end
49 | else
50 | return maybe_wrap(res)
51 | end
52 | end;
53 | __newindex = function(self,key,value)
54 | T:InvokeMember(key,put_flags,nil,A{value})
55 | end
56 | })
57 | end
58 |
59 | com = {}
60 |
61 | function com.CreateObject(progid)
62 | local ft = Type.GetTypeFromProgID(progid)
63 | local f = Activator.CreateInstance(ft)
64 | return com_wrapper(f)
65 | end
66 |
67 | com.wrap = maybe_wrap
68 |
69 | return com
70 |
--------------------------------------------------------------------------------
/samples/ctype.lua:
--------------------------------------------------------------------------------
1 | require 'CLRPackage'
2 | import 'System.Reflection'
3 | import 'LuaInterface'
4 |
5 | local ctype, enum = luanet.ctype, luanet.enum
6 |
7 | -- get all the static methods of LuaDLL and import them into global
8 | local mm = ctype(LuaDLL):GetMethods(enum(BindingFlags,'Static,Public'))
9 | for i = 0, mm.Length-1 do
10 | local name = mm[i].Name
11 | _G[name] = LuaDLL[name]
12 | end
13 |
14 | -- we can now do standard Lua API things in Lua...
15 | local L = luaL_newstate()
16 | luaL_openlibs(L)
17 | lua_pushstring(L,"hello dolly")
18 | print(lua_gettop(L))
19 | print(lua_tostring(L,-1))
20 |
21 |
--------------------------------------------------------------------------------
/samples/error.lua:
--------------------------------------------------------------------------------
1 | require 'CLRPackage'
2 | import 'System'
3 | local arr = luanet.make_array(Double,{1,2})
4 | print(arr.Length)
5 | print(arr.Foo)
6 |
--------------------------------------------------------------------------------
/samples/form.lua:
--------------------------------------------------------------------------------
1 | -- kevinh - the following lines are part of our standard init
2 | -- require("compat-5.1")
3 |
4 | luanet.load_assembly("System.Windows.Forms")
5 | luanet.load_assembly("System.Drawing")
6 |
7 | Form=luanet.import_type("System.Windows.Forms.Form")
8 | Button=luanet.import_type("System.Windows.Forms.Button")
9 | Point=luanet.import_type("System.Drawing.Point")
10 |
11 | form1=Form()
12 | button1=Button()
13 | button2=Button()
14 |
15 | function handleClick(sender,data)
16 | if sender.Text=="OK" then
17 | sender.Text="Clicked"
18 | else
19 | sender.Text="OK"
20 | end
21 | button1.MouseUp:Remove(handler)
22 | print(sender:ToString())
23 | end
24 |
25 | button1.Text = "OK"
26 | button1.Location=Point(10,10)
27 | button2.Text = "Cancel"
28 | button2.Location=Point(button1.Left, button1.Height + button1.Top + 10)
29 | handler=button1.MouseUp:Add(handleClick)
30 | form1.Text = "My Dialog Box"
31 | form1.HelpButton = true
32 | form1.MaximizeBox=false
33 | form1.MinimizeBox=false
34 | form1.AcceptButton = button1
35 | form1.CancelButton = button2
36 | form1.Controls:Add(button1)
37 | form1.Controls:Add(button2)
38 | form1:ShowDialog()
39 |
--------------------------------------------------------------------------------
/samples/form1.wlua:
--------------------------------------------------------------------------------
1 | require 'luanet'
2 | luanet.load_assembly "System.Windows.Forms"
3 | Form = luanet.import_type "System.Windows.Forms.Form"
4 | form = Form()
5 | form.Text = "Hello, World!"
6 | form:ShowDialog()
7 |
--------------------------------------------------------------------------------
/samples/form2.wlua:
--------------------------------------------------------------------------------
1 | require 'CLRPackage'
2 | import "System.Windows.Forms"
3 | import "System.Drawing"
4 |
5 | form = Form()
6 | form.Text = "Hello, World!"
7 | button = Button()
8 | button.Text = "Click Me!"
9 | button.Location = Point(20,20)
10 | button.Click:Add(function()
11 | MessageBox.Show("We wuz clicked!",arg[0],MessageBoxButtons.OK)
12 | end)
13 |
14 | form.Controls:Add(button)
15 | form:ShowDialog()
16 |
--------------------------------------------------------------------------------
/samples/form3.wlua:
--------------------------------------------------------------------------------
1 | -- form3.wlua
2 | require 'CLRPackage'
3 | import "System.Windows.Forms"
4 | import "System.Drawing"
5 |
6 | button = Button()
7 | button.Text = "Click!"
8 | button.Dock = DockStyle.Top
9 | edit = RichTextBox()
10 | edit.Dock = DockStyle.Fill
11 |
12 | form = Form()
13 | form.Text = "Hello, World!"
14 | form.Controls:Add(edit)
15 | form.Controls:Add(button)
16 | form:ShowDialog()
17 |
--------------------------------------------------------------------------------
/samples/gtk-list.lua:
--------------------------------------------------------------------------------
1 | require 'CLRPackage'
2 | import 'System'
3 | import ('gtk-sharp','Gtk')
4 | import('glib-sharp','GLib')
5 | local ctype = luanet.ctype
6 |
7 | Application.Init()
8 |
9 | local win = Window("Hello from GTK#")
10 | win.DeleteEvent:Add(function()
11 | Application.Quit()
12 | end)
13 |
14 | win:Resize(300,300)
15 |
16 | local store = ListStore({GType.String,GType.String})
17 | --local store = ListStore({ctype(String),ctype(String)})
18 | store:AppendValues {"Dachsie","Fritz"}
19 | store:AppendValues {"Collie","Butch"}
20 |
21 | local view = TreeView()
22 | view.Model = store
23 | view.HeadersVisible = true
24 |
25 | -- the long way to make a column
26 | function new_col(title,kind,idx)
27 | local col = TreeViewColumn()
28 | col.Title = title
29 | local r = CellRendererText()
30 | col:PackStart(r,true)
31 | col:AddAttribute(r,kind,idx)
32 | view:AppendColumn(col)
33 | end
34 |
35 | new_col("Dogs","text",0)
36 | --new_col("Name","text",1)
37 |
38 | -- and the short way
39 | local col = TreeViewColumn("Name",CellRendererText(),{"text",1})
40 | view:AppendColumn(col)
41 |
42 | view.Selection.Changed:Add(function(o,args)
43 | local selected, model, iter = o:GetSelected();
44 | if selected then
45 | local val = model:GetValue(iter,0)
46 | print("selected",val)
47 | end
48 | end)
49 |
50 | win:Add(view)
51 |
52 | win:ShowAll()
53 |
54 | Application.Run()
55 |
56 |
57 |
--------------------------------------------------------------------------------
/samples/gui.glade:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | True
8 | Glade Window
9 | GTK_WINDOW_TOPLEVEL
10 | GTK_WIN_POS_CENTER
11 | False
12 | 256
13 | 256
14 | True
15 | False
16 | True
17 | False
18 | False
19 | GDK_WINDOW_TYPE_HINT_NORMAL
20 | GDK_GRAVITY_NORTH_WEST
21 | True
22 |
23 |
24 |
25 | True
26 | True
27 | GTK_POLICY_ALWAYS
28 | GTK_POLICY_ALWAYS
29 | GTK_SHADOW_IN
30 | GTK_CORNER_TOP_LEFT
31 |
32 |
33 |
34 | True
35 | 400
36 | 400
37 | 0 0 400 10 212.4 236
38 | 0 0 400 10 212.4 236
39 |
40 |
41 |
42 | 38
43 | 17
44 | True
45 | label1
46 | False
47 | False
48 | GTK_JUSTIFY_LEFT
49 | False
50 | False
51 | 0.5
52 | 0.5
53 | 0
54 | 0
55 | PANGO_ELLIPSIZE_NONE
56 | -1
57 | False
58 | 0
59 |
60 |
61 | 96
62 | 88
63 |
64 |
65 |
66 |
67 |
68 | 60
69 | 27
70 | True
71 | True
72 | button1
73 | True
74 | GTK_RELIEF_NORMAL
75 | True
76 |
77 |
78 | 88
79 | 168
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/samples/hello-glade.lua:
--------------------------------------------------------------------------------
1 | require 'CLRPackage'
2 | import ('System')
3 | import ('gtk-sharp','Gtk')
4 | import ('glade-sharp','Glade')
5 |
6 | Application.Init()
7 |
8 | local gxml = XML("gui.glade","window1",nil) --(nil,"gui.glade","window1",nil)
9 | --gxml:AutoConnect (nil)
10 | local win = gxml:GetWidget "window1"
11 | win.DeleteEvent:Add(function()
12 | Application.Quit()
13 | end)
14 |
15 | local btn = gxml:GetWidget "button1"
16 | btn.Clicked:Add(function(e,a)
17 | -- Console.WriteLine("I was clicked")
18 | -- note how we have to pass an empty Object[] as the last argument!
19 | local args = luanet.make_array(Object,{})
20 | local md = MessageDialog(win,
21 | DialogFlags.DestroyWithParent,
22 | MessageType.Question,
23 | ButtonsType.YesNo, "Are you sure you wanted to click that button?",
24 | args
25 | )
26 | local res = md:Run()
27 | res = luanet.enum(ResponseType,res)
28 | if res == ResponseType.Yes then
29 | Console.WriteLine("ok!")
30 | end
31 | md:Destroy()
32 | end)
33 |
34 |
35 | Application.Run()
36 |
37 |
38 |
--------------------------------------------------------------------------------
/samples/hello-gtk.lua:
--------------------------------------------------------------------------------
1 | require 'CLRPackage'
2 | import ('gtk-sharp','Gtk')
3 |
4 | Application.Init()
5 |
6 | local win = Window("Hello from GTK#")
7 | win.DeleteEvent:Add(function()
8 | Application.Quit()
9 | end)
10 |
11 | win:Resize(300,300)
12 |
13 | local label = Label()
14 | label.Text = "Hello World!"
15 | win:Add(label)
16 |
17 | win:ShowAll()
18 |
19 | Application.Run()
20 |
21 |
22 |
--------------------------------------------------------------------------------
/samples/hello1.lua:
--------------------------------------------------------------------------------
1 | luanet.load_assembly "System"
2 | Console = luanet.import_type "System.Console"
3 | Math = luanet.import_type "System.Math"
4 | Directory = luanet.import_type "System.IO.Directory"
5 |
6 | Console.WriteLine("we are at {0}",Directory.GetCurrentDirectory())
7 | Console.WriteLine("sqrt(2) is {0}",Math.Sqrt(2))
8 |
--------------------------------------------------------------------------------
/samples/hello2.lua:
--------------------------------------------------------------------------------
1 | require 'CLRPackage'
2 | import "System"
3 | Console.WriteLine("sqrt(2) is {0}",Math.Sqrt(2))
4 |
--------------------------------------------------------------------------------
/samples/hello3.lua:
--------------------------------------------------------------------------------
1 | #!/home/azisa/bin/luai
2 | require 'CLRPackage'
3 | import "System"
4 | import "System.IO"
5 | Console.WriteLine("we are at {0}",Directory.GetCurrentDirectory())
6 |
--------------------------------------------------------------------------------
/samples/hello4.lua:
--------------------------------------------------------------------------------
1 | #!/home/azisa/bin/luai
2 | --- another variant of hello3: look, Ma, no globals!
3 | require 'CLRPackage'
4 | local sys,sysi = luanet.namespace {'System','System.IO'}
5 | sys.Console.WriteLine("we are at {0}",sysi.Directory.GetCurrentDirectory())
6 |
--------------------------------------------------------------------------------
/samples/ilua.lua:
--------------------------------------------------------------------------------
1 | -- ilua.lua
2 | -- A more friendly Lua interactive prompt
3 | -- doesn't need '=', and will try to print out tables recursively.
4 | -- On Unix, will use readline.so if available.
5 | -- Steve Donovan, 2007
6 | --
7 | local usage = [[ilua -lLtTvsq (lua files)
8 | -l load a library
9 | -L load a library and bring into global namespace
10 | -t write transcript to file; ilua.log if not specified
11 | -T write transcript to file of format ilua_yyyy_mm_dd_HH_MM.log
12 | -s switch off strict mode (don't report undeclared globals)
13 | -v be verbose
14 | -q require standalone expressions to end with '?' (e.g, 23*1.5?)
15 | If a file called ilua-defs is on your library path, it will be loaded first.
16 | ]]
17 |
18 | local pretty_print_limit = 20
19 | local max_depth = 7
20 | local table_clever = true
21 | local prompt = '> '
22 | local verbose = false
23 | local strict = false
24 | local que = false
25 | -- suppress strict warnings
26 | _ = true
27 |
28 | -- imported global functions
29 | local sub = string.sub
30 | local match = string.match
31 | local find = string.find
32 | local push = table.insert
33 | local pop = table.remove
34 | local append = table.insert
35 | local concat = table.concat
36 | local floor = math.floor
37 | local write = io.write
38 | local read = io.read
39 |
40 |
41 |
42 | local savef
43 | local collisions = {}
44 | local G_LIB = {}
45 | local declared = {}
46 | local line_handler_fn, global_handler_fn
47 | local print_handlers = {}
48 |
49 | ilua = {}
50 |
51 | function ilua.set_writer (writer)
52 | write = writer
53 | end
54 |
55 | local num_prec
56 | local num_all
57 |
58 | local jstack = {}
59 |
60 | local function oprint(...)
61 | if savef then
62 | savef:write(concat({...},' '),'\n')
63 | end
64 | write(...)
65 | --write '\r\n'
66 | write '\n'
67 | end
68 |
69 | local function is_map_like(tbl)
70 | for k,v in pairs(tbl) do
71 | if type(k) ~= 'number' then
72 | return true
73 | end
74 | end
75 | return false
76 | end
77 |
78 | local function join(tbl,delim,limit,depth)
79 | if not limit then limit = pretty_print_limit end
80 | if not depth then depth = max_depth end
81 | local n = #tbl
82 | local res = ''
83 | local k = 0
84 | -- very important to avoid disgracing ourselves with circular references or
85 | -- excessively nested tables...
86 | if #jstack > depth then
87 | return "..."
88 | end
89 | for i,t in ipairs(jstack) do
90 | if tbl == t then
91 | return ""
92 | end
93 | end
94 | push(jstack,tbl)
95 | -- a table may have a 'list-like' part if it has a non-zero size
96 | -- and may have have a 'map-like' part if it has non-numerical keys
97 | -- you can switch off this cleverness with ilua.table_options {clever = false}
98 | local is_list,is_map
99 | if table_clever then
100 | is_list = #tbl > 0
101 | is_map = is_map_like(tbl)
102 | else
103 | is_map = true -- that is, treat all keys equally
104 | end
105 | if is_list then
106 | for i,v in ipairs(tbl) do
107 | res = res..delim..val2str(v)
108 | k = k + 1
109 | if k > limit then
110 | res = res.." ... "
111 | break
112 | end
113 | end
114 | end
115 | if is_map then
116 | for key,v in pairs(tbl) do
117 | local num = type(key) == 'number'
118 | key = tostring(key)
119 | if not num or (num and not is_list) then
120 | if num then
121 | key = '['..key..']'
122 | end
123 | res = res..delim..key..'='..val2str(v)
124 | k = k + 1
125 | if k > limit then
126 | res = res.." ... "
127 | break
128 | end
129 | end
130 | end
131 | end
132 | pop(jstack)
133 | return sub(res,2)
134 | end
135 |
136 |
137 | function val2str(val)
138 | local tp = type(val)
139 | if print_handlers[tp] then
140 | local s = print_handlers[tp](val)
141 | return s or '?'
142 | end
143 | if tp == 'function' then
144 | return tostring(val)
145 | elseif tp == 'table' then
146 | if val.__tostring then
147 | return tostring(val)
148 | else
149 | return '{'..join(val,',')..'}'
150 | end
151 | elseif tp == 'string' then
152 | return "'"..val.."'"
153 | elseif tp == 'number' then
154 | -- we try only to apply floating-point precision for numbers deemed to be floating-point,
155 | -- unless the 3rd arg to precision() is true.
156 | if num_prec and (num_all or floor(val) ~= val) then
157 | return num_prec:format(val)
158 | else
159 | return tostring(val)
160 | end
161 | else
162 | return tostring(val)
163 | end
164 | end
165 |
166 | function _pretty_print(...)
167 | local args = {n=select('#',...),...}
168 | for i = 1,args.n do
169 | oprint(val2str(args[i]))
170 | end
171 | _G['_'] = args[1]
172 | end
173 |
174 | local function compile(line)
175 | if verbose then oprint(line) end
176 | local f,err = loadstring(line,'local')
177 | return err,f
178 | end
179 |
180 | local function evaluate(chunk)
181 | local ok,res = pcall(chunk)
182 | if not ok then
183 | return res
184 | end
185 | return nil -- meaning, fine!
186 | end
187 |
188 | function eval_lua(line)
189 | -- write to transcript, if open
190 | if savef then savef:write(prompt,line,'\n') end
191 | -- is the line handler interested?
192 | if line_handler_fn then
193 | -- returning nil here means that the handler doesn't want Lua to see the string
194 | line = line_handler_fn(line)
195 | if not line then return end
196 | end
197 | local err,chunk
198 | --~ if not que then -- try compiling first as expression, then as statement
199 | --~ -- is it an expression?
200 | --~ err,chunk = compile('_pretty_print('..line..')')
201 | --~ if err then -- otherwise, a statement?
202 | --~ err,chunk = compile(line)
203 | --~ end
204 | --~ else -- expressions must be explicitly terminated with ?
205 | if line:match '^%s*=' then --or line:match '%?$' then
206 | line = line:gsub ('^%s*=','')
207 | err,chunk = compile('_pretty_print('..line..')')
208 | else
209 | err,chunk = compile(line)
210 | end
211 | --~ end
212 | if not err then
213 | -- we can now execute the chunk
214 | err = evaluate(chunk)
215 | end
216 | if err then -- if there was any compile or runtime error, print it out
217 | oprint(err)
218 | end
219 | end
220 |
221 | local function quit(code,msg)
222 | io.stderr:write(msg,'\n')
223 | os.exit(code)
224 | end
225 |
226 | -- functions available in scripts
227 | function ilua.precision(len,prec,all)
228 | if not len then num_prec = nil
229 | else
230 | num_prec = '%'..len..'.'..prec..'f'
231 | end
232 | num_all = all
233 | end
234 |
235 | function ilua.table_options(t)
236 | if t.limit then pretty_print_limit = t.limit end
237 | if t.depth then max_depth = t.depth end
238 | if t.clever ~= nil then table_clever = t.clever end
239 | end
240 |
241 | -- inject @tbl into the global namespace
242 | function ilua.import(tbl,dont_complain,lib)
243 | lib = lib or ''
244 | if type(tbl) == 'table' then
245 | for k,v in pairs(tbl) do
246 | local key = rawget(_G,k)
247 | -- NB to keep track of collisions!
248 | if key and k ~= '_M' and k ~= '_NAME' and k ~= '_PACKAGE' and k ~= '_VERSION' then
249 | append(collisions,{k,lib,G_LIB[k]})
250 | end
251 | _G[k] = v
252 | G_LIB[k] = lib
253 | end
254 | end
255 | if not dont_complain and #collisions > 0 then
256 | for i, coll in ipairs(collisions) do
257 | local name,lib,oldlib = coll[1],coll[2],coll[3]
258 | write('warning: ',lib,'.',name,' overwrites ')
259 | if oldlib then
260 | write(oldlib,'.',name,'\n')
261 | else
262 | write('global ',name,'\n')
263 | end
264 | end
265 | end
266 | end
267 |
268 | function ilua.print_handler(name,handler)
269 | print_handlers[name] = handler
270 | end
271 |
272 | function ilua.line_handler(handler)
273 | line_handler_fn = handler
274 | end
275 |
276 | function ilua.global_handler(handler)
277 | global_handler_fn = handler
278 | end
279 |
280 | function ilua.print_variables()
281 | for name,v in pairs(declared) do
282 | print(name,type(_G[name]))
283 | end
284 | end
285 | --
286 | -- strict.lua
287 | -- checks uses of undeclared global variables
288 | -- All global variables must be 'declared' through a regular assignment
289 | -- (even assigning nil will do) in a main chunk before being used
290 | -- anywhere.
291 | --
292 | local function set_strict()
293 |
294 | local mt = getmetatable(_G)
295 | if mt == nil then
296 | mt = {}
297 | setmetatable(_G, mt)
298 | end
299 |
300 | local function what ()
301 | local d = debug.getinfo(3, "S")
302 | return d and d.what or "C"
303 | end
304 |
305 | declared.__tostring = true
306 |
307 | mt.__newindex = function (t, n, v)
308 | declared[n] = true
309 | rawset(t, n, v)
310 | end
311 |
312 | mt.__index = function (t, n)
313 | if not declared[n] and what() ~= "C" then
314 | local lookup = global_handler_fn and global_handler_fn(n)
315 | if not lookup then
316 | error("variable '"..n.."' is not declared", 2)
317 | else
318 | return lookup
319 | end
320 | end
321 | return rawget(t, n)
322 | end
323 |
324 | end
325 |
326 | --- Initial operations which may not succeed!
327 | -- try to bring in any ilua configuration file; don't complain if this is unsuccessful
328 | pcall(function()
329 | require 'ilua-defs'
330 | end)
331 |
332 | -- Unix readline support, if readline.so is available...
333 | local rl,readline,saveline
334 | err = pcall(function()
335 | rl = require 'readline'
336 | readline = rl.readline
337 | saveline = rl.add_history
338 | end)
339 | if not rl then
340 | readline = function(prompt)
341 | write(prompt)
342 | return read()
343 | end
344 | saveline = function(s) end
345 | end
346 |
347 | -- process command-line parameters
348 | if arg then
349 | local i = 1
350 |
351 | local function parm_value(opt,parm,def)
352 | local val = parm:sub(3)
353 | if #val == 0 then
354 | i = i + 1
355 | if i > #arg then
356 | if not def then
357 | quit(-1,"expecting parameter for option '-"..opt.."'")
358 | else
359 | return def
360 | end
361 | end
362 | val = arg[i]
363 | end
364 | return val
365 | end
366 |
367 | while i <= #arg do
368 | local v = arg[i]
369 | local opt = v:sub(1,1)
370 | if opt == '-' then
371 | opt = v:sub(2,2)
372 | if opt == 'h' then
373 | quit(0,usage)
374 | elseif opt == 'l' then
375 | require (parm_value(opt,v))
376 | elseif opt == 'L' then
377 | local lib = parm_value(opt,v)
378 | local tbl = require (lib)
379 | -- we cannot always trust require to return the table!
380 | if type(tbl) ~= 'table' then
381 | tbl = _G[lib]
382 | end
383 | ilua.import(tbl,true,lib)
384 | elseif opt == 't' or opt == 'T' then
385 | local file
386 | if opt == 'T' then
387 | file = 'ilua_'..os.date ('%y_%m_%d_%H_%M')..'.log'
388 | else
389 | file = parm_value(opt,v,"ilua.log")
390 | end
391 | print('saving transcript "'..file..'"')
392 | savef = io.open(file,'w')
393 | savef:write('! ilua ',concat(arg,' '),'\n')
394 | elseif opt == 's' then
395 | strict = true
396 | elseif opt == 'v' then
397 | verbose = true
398 | elseif opt == 'q' then
399 | que = true
400 | end
401 | else -- a plain file to be executed immediately
402 | dofile(v)
403 | end
404 | i = i + 1
405 | end
406 |
407 |
408 | end
409 |
410 | if not arg or arg[0]:match('\\ilua%.lua$') then
411 | print 'ILUA: Lua 5.1.2 Copyright (C) 1994-2007 Lua.org, PUC-Rio\n"quit" to end'
412 |
413 | -- any import complaints?
414 | ilua.import()
415 |
416 | -- enable 'not declared' error
417 | if strict then
418 | set_strict()
419 | end
420 |
421 | local line = readline(prompt)
422 | while line do
423 | if line == 'quit' then break end
424 | eval_lua(line)
425 | saveline(line)
426 | line = readline(prompt)
427 | end
428 |
429 | if savef then
430 | savef:close()
431 | end
432 | end
433 |
434 |
435 |
--------------------------------------------------------------------------------
/samples/layout0.wlua:
--------------------------------------------------------------------------------
1 | -- layout0.wlua
2 | require 'CLRPackage'
3 | import "System.Windows.Forms"
4 |
5 | panel = FlowLayoutPanel()
6 |
7 | function button(text,callback)
8 | local b = Button()
9 | callback = callback or function() print(text) end
10 | b.Text = text
11 | b.Click:Add(callback)
12 | return b
13 | end
14 |
15 | function add2panel(c)
16 | panel.Controls:Add(c)
17 | end
18 |
19 | --panel.WrapContents = false
20 | b = button ("Toggle Wrap",function()
21 | panel.WrapContents = not panel.WrapContents
22 | end)
23 | add2panel(b)
24 | b = button "Two"
25 | add2panel(b)
26 | b = button "Three"
27 | add2panel(b)
28 |
29 | form = Form()
30 | form.Text = "Hello, World!"
31 | panel.Dock = DockStyle.Fill
32 |
33 | form.Controls:Add(panel)
34 | form:ShowDialog()
35 |
--------------------------------------------------------------------------------
/samples/layout1.wlua:
--------------------------------------------------------------------------------
1 | -- layout1.wlua
2 | require 'CLRForm'
3 |
4 | panel = Panel()
5 | layout = StreamLayout(panel)
6 | b = Button()
7 | b.Text = "One"
8 | layout:Add(b)
9 | b = Button()
10 | b.Text = "Two"
11 | layout:Add(b)
12 | t = TextBox()
13 | layout:Add(t)
14 | layout:Finish()
15 |
16 | form = Form()
17 | form.Text = "Hello, World!"
18 | panel.Dock = DockStyle.Top
19 |
20 | form.Controls:Add(panel)
21 | form:ShowDialog()
22 |
--------------------------------------------------------------------------------
/samples/lconsole.lua:
--------------------------------------------------------------------------------
1 | require "CLRPackage"
2 | require "ilua"
3 | require "CLRForm"
4 | import "System.Windows.Forms"
5 | import "System.Drawing"
6 | import "System.IO"
7 |
8 | import "TextBox.dll"
9 |
10 | local ferr = io.stderr --debug
11 | local append = table.insert
12 |
13 | -- it appears necessary to force a delayed evaluation, for which we use a timer....
14 | local timer = Timer()
15 | timer.Interval = 10
16 | local callback
17 |
18 | timer.Tick:Add(function()
19 | timer:Stop()
20 | if not pcall(callback) then
21 | ferr:write 'callback hosed\n'
22 | end
23 | end)
24 |
25 | local function call_later (fun)
26 | callback = fun
27 | timer:Start()
28 | end
29 |
30 | local function readfile (file)
31 | local f = io.open(file,'r')
32 | if not f then return end
33 | local res = f:read("*a")
34 | f:close()
35 | return res
36 | end
37 |
38 | local function writefile (file,s)
39 | local f = io.open(file,'w')
40 | if not f then return end
41 | f:write(s)
42 | f:close()
43 | return true
44 | end
45 |
46 | function current_line (pane)
47 | return pane:GetLineFromCharIndex(pane.SelectionStart)
48 | end
49 |
50 | -- a useful function for selecting lines in Rich text boxes; if lno is not specified,
51 | -- then use the current line
52 | function select_line (pane,lno)
53 | if not lno then -- current line
54 | lno = current_line(pane)
55 | end
56 | local pos = pane.SelectionStart
57 | local start = pane:GetFirstCharIndexFromLine(lno)
58 | pane:Select(start,pos - start + 1)
59 | end
60 |
61 | local lines = {}
62 | local list = ListBox()
63 | local no_name = true
64 | local this_dir = Environment.CurrentDirectory
65 | local user_dir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
66 | local session_dir = user_dir..'/'..'li-session'
67 |
68 | if Directory.Exists(session_dir) then
69 | local files = Directory.GetFiles(session_dir,"*.lua")
70 | for i = 1,files.Length do
71 | list.Items:Add(Path.GetFileNameWithoutExtension(files[i-1]))
72 | end
73 | else
74 | Directory.CreateDirectory(session_dir)
75 | end
76 |
77 | local function list_contains (name)
78 | for i = 1,list.Items.Count do
79 | if list.Items[i-1] == name then return true end
80 | end
81 | end
82 |
83 | local function add_to_list (name)
84 | list.Items:Add(name)
85 | list.SelectedItem = name
86 | current_name = name
87 | end
88 |
89 | local function session_file (name)
90 | if not name then return end
91 | return session_dir..'/'..name..'.lua'
92 | end
93 |
94 | local code = ConsoleTextBox() --RichTextBox()
95 | code.Font = Font("Tahoma",10,FontStyle.Bold)
96 | code.WordWrap = false
97 |
98 | code:SetHandler(function(key)
99 | if key == Keys.Tab then
100 | code.SelectedText = " "
101 | return true
102 | end
103 | return false
104 | end)
105 |
106 | local text = ConsoleTextBox() --RichTextBox()
107 | text.Font = code.Font
108 | text.WordWrap = false
109 |
110 | -- please note that you must explicitly return false, since LuaInterface is
111 | -- expecting a boolean return value!
112 | text:SetHandler(function(key)
113 | if key == Keys.Up then
114 | get_history(true)
115 | return true
116 | elseif key == Keys.Down then
117 | get_history(false)
118 | return true
119 | end
120 | return false
121 | end)
122 |
123 | local function write (s)
124 | text:AppendText(s)
125 | end
126 |
127 | list.SelectedIndexChanged:Add(function()
128 | local file = session_file(list.SelectedItem)
129 | if not file or not File.Exists(file) then return end
130 | local txt = readfile(file)
131 | if not txt then
132 | ShowError ("Cannot open '"..file.."'")
133 | return
134 | end
135 | code.Text = txt
136 | end)
137 |
138 | local function load_lua_file (file)
139 | local oldFun = fun
140 | fun = function(file) end
141 | local res,err = pcall(dofile,file)
142 | if not res then -- we have an error!
143 | ShowError(err)
144 | print(err)
145 | end
146 | fun = oldFun
147 | end
148 |
149 | local function load_lua ()
150 | local dlg = OpenFileDialog()
151 | dlg.Filter = "Lua (*.lua)|*.lua"
152 | dlg.InitialDirectory = this_dir
153 | if dlg:ShowDialog() == DialogResult.OK then
154 | load_lua_file(dlg.FileName)
155 | end
156 | end
157 |
158 | local function save_session ()
159 | local dlg = SaveFileDialog()
160 | dlg.Filter = "Lua (*.lua)|*.lua"
161 | dlg.InitialDirectory = this_dir
162 | if dlg:ShowDialog() ~= DialogResult.OK then return end
163 | local f = io.open(dlg.FileName,"w")
164 | f:write(table.concat(lines,'\n'))
165 | f:close()
166 | end
167 |
168 | function clear_code ()
169 | code:Clear()
170 | no_name = true
171 | end
172 |
173 | function delete_list_item ()
174 | local path = session_file(list.SelectedItem)
175 | os.remove(path)
176 | list.Items:Remove(list.SelectedItem)
177 | clear_code()
178 | end
179 |
180 | function save_code ()
181 | local file
182 | if code.Lines.Length == 0 then return end
183 | if not no_name then
184 | file = list.SelectedItem
185 | else -- no name has been assigned, after clearing the code pane
186 | -- try make up an appropriate one!
187 | local firstline = code.Lines[0]
188 | local comment = firstline:match('%s*%-%-%s*(.*)')
189 | if comment then file = comment
190 | else file = "[current]" end
191 | no_name = false
192 | end
193 | local path = session_file(file)
194 | writefile(path,code.Text)
195 | if not list_contains(file) then
196 | add_to_list(file)
197 | else
198 | list.SelectedItem = file
199 | end
200 | return path
201 | end
202 |
203 | local function save_text ()
204 | local dlg = SaveFileDialog()
205 | dlg.Filter = "Text (*.txt)|*.txt"
206 | dlg.InitialDirectory = this_dir
207 | if dlg:ShowDialog() ~= DialogResult.OK then return end
208 | writefile(dlg.FileName,text.Text)
209 | end
210 |
211 | local function save_and_go ()
212 | local file = save_code()
213 | if not file then return end
214 | local res,err = pcall(dofile,file)
215 | --ferr:write(file,'\n')
216 | if not res then
217 | local i1,i2,line = err:find(':(%d+):')
218 | if i1 then
219 | print(err:sub(i2+1))
220 | write '\n> '
221 | code:Focus()
222 | select_line(code,tonumber(line)-1)
223 | return
224 | end
225 | end
226 | write '\n> '
227 | append(lines,'dofile[['..file..']]')
228 | text:Focus()
229 | end
230 |
231 | function fun (fn)
232 | if not fn then -- prompt for a function name
233 | fn = PromptForString("Lua Interface Console","Function name","")
234 | if not fn then return end
235 | end
236 | if list_contains(fn) then
237 | ShowError("'"..fn.."' already exists. Pick another name")
238 | return
239 | end
240 | no_name = false
241 | local txt = "function "..fn.."( )\n\nend\n"
242 | code.Text = txt
243 | add_to_list(fn)
244 | code:Focus()
245 | end
246 |
247 | ---------------------- Main Menu --------------------------------------
248 | local menu = main_menu {
249 | "File",{
250 | "Load Lua(CtrlO)",load_lua,
251 | "Save Session(CtrlS)",save_session,
252 | "Save As Text",save_text,
253 | "E&xit(CtrlX)",function() os.exit(0) end,
254 | },
255 | "Run",{
256 | "Save and Go(F5)",save_and_go,
257 | "Create Function",function() fun() end,
258 | "Delete Item",delete_list_item,
259 | "Clear Code Pane",clear_code,
260 | },
261 | "History", {
262 | "Last(AltUpArrow)", function() get_history(true) end,
263 | "Previous(AltDownArrow)", function() get_history(false) end
264 | }
265 | }
266 |
267 | local function method (obj,fun)
268 | return function()
269 | fun(obj)
270 | end
271 | end
272 |
273 | local popup = popup_menu {
274 | "Copy",method(text,text.Copy),
275 | "Paste",method(text,text.Paste),
276 | "Cut",method(text,text.Cut),
277 | }
278 |
279 | ------------ Managing Command History -----------
280 | local help_idx = 1
281 |
282 | function get_history (up)
283 | call_later(function()
284 | local delta
285 | -- awful hack, cancelling out the last up/down arrow movement!
286 | if up then
287 | delta = -1
288 | else
289 | delta = 1
290 | end
291 | key_sent = true
292 | call_later(function()
293 | help_idx = help_idx + delta
294 | local txt = lines[help_idx]
295 | if not txt then
296 | help_idx = help_idx - delta
297 | return
298 | end
299 | select_line(text)
300 | text.SelectedText = '> '..txt
301 | end)
302 | end)
303 | end
304 |
305 | ------------ Special Key Handling ------------------
306 | local lastLine = -1
307 |
308 | text.KeyDown:Add(function(sender,args)
309 | if args.KeyCode == Keys.Enter then
310 | local lineNo = text:GetLineFromCharIndex(text.SelectionStart)
311 | if lineNo ~= lastLine then -- for some reason, happens twice!
312 | if lineNo >= text.Lines.Length then
313 | lineNo = text.Lines.Length - 1
314 | --ferr:write(lineNo,' ',text.Lines.Length,' goofed\n')
315 | end
316 | do
317 | local line = text.Lines[lineNo]
318 | line = line:gsub('^> ','')
319 | lastLine = lineNo
320 | call_later(function()
321 | eval_lua(line)
322 | append(lines,line)
323 | help_idx = #lines + 1
324 | write '> '
325 | end)
326 | end
327 | end
328 | end
329 | end)
330 |
331 | ----------------------- Ouput Redirection ---------------------------------
332 | function write_out (expand,...)
333 | local t = {...}
334 | local n = #t - 1
335 | for i = 1,n do
336 | write(tostring(t[i]))
337 | if expand then write '\t' end
338 | end
339 | write(tostring(t[n+1]))
340 | end
341 |
342 | function writer (...)
343 | write_out(false,...)
344 | end
345 |
346 | ilua.set_writer(writer)
347 | function print (...)
348 | write_out(true,...)
349 | write '\r\n'
350 | end
351 |
352 | -------- Layout Controls ---------------------------------------------
353 | local form = Form()
354 | form.Menu = menu
355 | form.Text = "LuaInterface GUI Prompt"
356 | form.Size = Size(500,500)
357 | form.Closing:Add(function()
358 | os.exit(0)
359 | end)
360 |
361 | local panel = Panel()
362 | panel.Dock = DockStyle.Top
363 |
364 | local hsplitter = Splitter()
365 | hsplitter.Dock = DockStyle.Left
366 | hsplitter.MinSize = 70
367 |
368 | code.Dock = DockStyle.Fill
369 | code.Height = 70
370 |
371 | list.Dock = DockStyle.Left
372 | list.Width = 70
373 |
374 | panel.Controls:Add(code)
375 | panel.Controls:Add(hsplitter)
376 | panel.Controls:Add(list)
377 |
378 | -- note the particular order!
379 | local splitter = Splitter()
380 | splitter.Dock = DockStyle.Top
381 | splitter.MinSize = 70
382 | splitter.MinExtra = 100
383 | text.Dock = DockStyle.Fill
384 | text.ContextMenu = popup
385 | form.Controls:Add(text)
386 | form.Controls:Add(splitter)
387 | form.Controls:Add(panel)
388 |
389 | -- stuff exported to the interactive console
390 | gettype = luanet.import_type
391 | app = {code=code,text=text, list=list, form=form}
392 | function cd (path)
393 | if not path or #path == 0 then
394 | print(Directory.GetCurrentDirectory())
395 | else
396 | Directory.SetCurrentDirectory(path)
397 | end
398 | end
399 |
400 | write 'Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio\r\n'
401 | write '> '
402 |
403 | if arg[1] and File.Exists(arg[1]) then
404 | load_lua_file(arg[1])
405 | end
406 |
407 | text.WordWrap = true
408 | console = text
409 |
410 | form:ShowDialog()
411 |
412 |
413 |
--------------------------------------------------------------------------------
/samples/lua-gtk.lua:
--------------------------------------------------------------------------------
1 | ---- A simple interactive Console for LuaInterface using Gtk#
2 | require 'CLRPackage'
3 | import ('gtk-sharp','Gtk')
4 | luanet.load_assembly 'gdk-sharp'
5 | luanet.load_assembly 'glib-sharp'
6 | local Gdk = luanet.namespace 'Gdk'
7 | local Glib = luanet.namespace 'GLib'
8 |
9 | local ferr = io.stderr -- for debugging
10 |
11 | --~ Glib.ExceptionManager.UnhandledException:Add(function(ex,what)
12 | --~ ferr:write(tostring(ex),' ',tostring(what),'\n')
13 | --~ ex.ExitApplication = false
14 | --~ end)
15 |
16 | local Up, Down, Return = Gdk.Key.Up, Gdk.Key.Down, Gdk.Key.Return
17 |
18 | Application.Init()
19 |
20 | local win = Window("Gtk# Lua")
21 |
22 | win.DeleteEvent:Add(function()
23 | Application.Quit()
24 | end)
25 |
26 | win:Resize(500,500)
27 |
28 | local buffer
29 | local history = {idx=1}
30 |
31 | function add_history(line)
32 | if line ~= history[#history] then
33 | table.insert(history,line)
34 | history.idx = #history + 1
35 | end
36 | end
37 |
38 | local function clamp(i,s,n)
39 | if i < s then return 1
40 | elseif i > n then return n
41 | else return i
42 | end
43 | end
44 |
45 | function line_range(lno)
46 | lno = lno or buffer.LineCount - 1
47 | local start = buffer:GetIterAtLine(lno-1)
48 | local endi = buffer:GetIterAtLine(lno)
49 | return start,endi
50 | end
51 |
52 | local function set_last_line(text)
53 | if not text then return end
54 | local start = buffer:GetIterAtLine(buffer.LineCount-1)
55 | local endi = buffer.EndIter
56 | start = buffer:Delete(start,endi)
57 | buffer:Insert(start,'> '..text)
58 | end
59 |
60 | -- we need to subclass Gtk.TextView, since we want to trap
61 | -- the up and down keys for accessing command history
62 |
63 | local edit = {}
64 |
65 | function edit:OnKeyPressEvent(event)
66 | local key = event.Key
67 | if key == Up or key == Down then
68 | local delta
69 | if key == Down then
70 | delta = 1
71 | else
72 | delta = -1
73 | end
74 | history.idx = clamp(history.idx + delta,1,#history)
75 | set_last_line(history[history.idx])
76 | return true
77 | else
78 | return self.base:OnKeyPressEvent(event)
79 | end
80 | end
81 |
82 | luanet.make_object(edit,'Gtk.TextView')
83 | buffer = edit.Buffer
84 |
85 |
86 | local function create_tag(colour)
87 | local tag = TextTag(colour)
88 | tag.Foreground = colour
89 | buffer.TagTable:Add(tag)
90 | return {tag}
91 | end
92 |
93 | local plain,err_style = create_tag "#00F" , create_tag "#F00"
94 |
95 | function write(txt,tag)
96 | tag = tag or plain
97 | buffer:InsertWithTags(buffer.EndIter,txt,tag)
98 | end
99 |
100 | local prompt = '> '
101 | write 'Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio\n'
102 | write(prompt)
103 |
104 | function print(...)
105 | local args,n = {...},select('#',...)
106 | for i = 1,n do
107 | write(tostring(args[i])..'\t')
108 | end
109 | write '\n'
110 | end
111 |
112 | local function collect(ok,...)
113 | local args = {...}
114 | args.n = select('#',...)
115 | return ok, args
116 | end
117 |
118 | function eval(s)
119 | if s == 'quit' then Application.Quit() end
120 | local expr = s:match('^%s*=%s+(.+)')
121 | if expr then s = 'return '..expr end
122 | local chunk,err = loadstring(s,'tmp')
123 | local ok,res
124 | if chunk then
125 | ok,res = collect(pcall(chunk))
126 | if not ok then err = res[1] end
127 | end
128 | if err then
129 | write(tostring(err)..'\n',err_style)
130 | elseif res.n > 0 then
131 | print(unpack(res,1,res.n))
132 | _G._ = res[1] -- last expression put into underscore global
133 | end
134 | end
135 |
136 | edit.KeyReleaseEvent:Add(function(obj,e)
137 | local event = e.Event
138 | if event.Key == Return then
139 | local start,endi = line_range()
140 | local stmt = start:GetText(endi)
141 | local i1,i2 = stmt:find(prompt,1,true)
142 | if i1 == 1 then
143 | stmt = stmt:sub(i2+1)
144 | end
145 | stmt = stmt:gsub('\n$','')
146 | eval(stmt)
147 | add_history(stmt)
148 | buffer:InsertAtCursor(prompt)
149 | end
150 | end)
151 |
152 | local sbox = ScrolledWindow()
153 | sbox.VscrollbarPolicy = PolicyType.Always
154 | sbox:Add(edit)
155 | win:Add(sbox)
156 | win:ShowAll()
157 | Application.Run()
158 |
159 |
--------------------------------------------------------------------------------
/samples/lua.lua:
--------------------------------------------------------------------------------
1 | -- lua.lua - Lua 5.1 interpreter (lua.c) reimplemented in Lua.
2 | --
3 | -- WARNING: This is not completed but was quickly done just an experiment.
4 | -- Fix omissions/bugs and test if you want to use this in production.
5 | -- Particularly pay attention to error handling.
6 | --
7 | -- (c) David Manura, 2008-08
8 | -- Licensed under the same terms as Lua itself.
9 | -- Based on lua.c from Lua 5.1.3.
10 | -- Improvements by Shmuel Zeigerman.
11 |
12 | -- Variables analogous to those in luaconf.h
13 | local LUA_INIT = "LUA_INIT"
14 | local LUA_PROGNAME = "lua"
15 | local LUA_PROMPT = "> "
16 | local LUA_PROMPT2 = ">> "
17 | local function LUA_QL(x) return "'" .. x .. "'" end
18 |
19 | local lua51 = _VERSION:match '5%.1$'
20 | -- Variables analogous to those in lua.h
21 | local LUA_RELEASE, LUA_COPYRIGHT, eof_ender
22 | if lua51 then
23 | LUA_RELEASE = "Lua 5.1.4"
24 | LUA_COPYRIGHT = "Copyright (C) 1994-2008 Lua.org, PUC-Rio"
25 | eof_ender = LUA_QL("")
26 | else
27 | LUA_RELEASE = "Lua 5.2.0"
28 | LUA_COPYRIGHT = "Copyright (C) 1994-2011 Lua.org, PUC-Rio"
29 | eof_ender = ''
30 | end
31 | local EXTRA_COPYRIGHT = "lua.lua (c) David Manura, 2008-08"
32 |
33 | -- Note: don't allow user scripts to change implementation.
34 | -- Check for globals with "cat lua.lua | luac -p -l - | grep ETGLOBAL"
35 |
36 | local _G = _G
37 | local assert = assert
38 | local collectgarbage = collectgarbage
39 | local loadfile = loadfile
40 | local loadstring = loadstring or load
41 | local pcall = pcall
42 | local rawget = rawget
43 | local select = select
44 | local tostring = tostring
45 | local type = type
46 | local unpack = unpack or table.unpack
47 | local xpcall = xpcall
48 | local io_stderr = io.stderr
49 | local io_stdout = io.stdout
50 | local io_stdin = io.stdin
51 | local string_format = string.format
52 | local string_sub = string.sub
53 | local os_getenv = os.getenv
54 | local os_exit = os.exit
55 |
56 |
57 | local progname = LUA_PROGNAME
58 |
59 | -- Use external functions, if available
60 | local lua_stdin_is_tty = function() return true end
61 | local setsignal = function() end
62 |
63 | local function print_usage()
64 | io_stderr:write(string_format(
65 | "usage: %s [options] [script [args]].\n" ..
66 | "Available options are:\n" ..
67 | " -e stat execute string " .. LUA_QL("stat") .. "\n" ..
68 | " -l name require library " .. LUA_QL("name") .. "\n" ..
69 | " -i enter interactive mode after executing " ..
70 | LUA_QL("script") .. "\n" ..
71 | " -v show version information\n" ..
72 | " -- stop handling options\n" ..
73 | " - execute stdin and stop handling options\n"
74 | ,
75 | progname))
76 | io_stderr:flush()
77 | end
78 |
79 | local our_tostring = tostring
80 |
81 | local tuple = table.pack or function(...)
82 | return {n=select('#', ...), ...}
83 | end
84 |
85 | local using_lsh,lsh
86 |
87 | local function our_print (...)
88 | local args = tuple(...)
89 | for i = 1,args.n do
90 | io.write(our_tostring(args[i]),'\t')
91 | end
92 | _G._ = args[1]
93 | io.write '\n'
94 | end
95 |
96 | local function saveline(s)
97 | if using_lsh then
98 | lsh.saveline(s)
99 | end
100 | end
101 |
102 | local function getline(prmt)
103 | if using_lsh then
104 | return lsh.readline(prmt)
105 | else
106 | io_stdout:write(prmt)
107 | io_stdout:flush()
108 | return io_stdin:read'*l'
109 | end
110 | end
111 |
112 | local function l_message (pname, msg)
113 | if pname then io_stderr:write(string_format("%s: ", pname)) end
114 | io_stderr:write(string_format("%s\n", msg))
115 | io_stderr:flush()
116 | end
117 |
118 | local function report(status, msg)
119 | if not status and msg ~= nil then
120 | msg = tostring(msg)
121 | --~ msg = (type(msg) == 'string' or type(msg) == 'number') and tostring(msg)
122 | --~ or "(error object is not a string)"
123 | l_message(progname, msg);
124 | end
125 | return status
126 | end
127 |
128 | local function traceback (message)
129 | local tp = type(message)
130 | if tp ~= "string" and tp ~= "number" then return message end
131 | local debug = _G.debug
132 | if type(debug) ~= "table" then return message end
133 | local tb = debug.traceback
134 | if type(tb) ~= "function" then return message end
135 | return tb(message, 2)
136 | end
137 |
138 | local function docall(f, ...)
139 | local tp = {...} -- no need in tuple (string arguments only)
140 | local F = function() return f(unpack(tp)) end
141 | setsignal(true)
142 | local result = tuple(xpcall(F, traceback))
143 | setsignal(false)
144 | -- force a complete garbage collection in case of errors
145 | if not result[1] then collectgarbage("collect") end
146 | return unpack(result, 1, result.n)
147 | end
148 |
149 | function dofile(name)
150 | local f, msg = loadfile(name)
151 | if f then f, msg = docall(f) end
152 | return report(f, msg)
153 | end
154 |
155 | local function dostring(s, name)
156 | local f, msg = loadstring(s, name)
157 | if f then f, msg = docall(f) end
158 | return report(f, msg)
159 | end
160 |
161 | local function dolibrary (name)
162 | return report(docall(_G.require, name))
163 | end
164 |
165 | local function print_version()
166 | l_message(nil, LUA_RELEASE .. " " .. LUA_COPYRIGHT.."\n"..EXTRA_COPYRIGHT)
167 | end
168 |
169 | local function getargs (argv, n)
170 | local arg = {}
171 | for i=1,#argv do arg[i - n] = argv[i] end
172 | if _G.arg then
173 | local i = 0
174 | while _G.arg[i] do
175 | arg[i - n] = _G.arg[i]
176 | i = i - 1
177 | end
178 | end
179 | return arg
180 | end
181 |
182 | local function get_prompt (firstline)
183 | -- use rawget to play fine with require 'strict'
184 | local pmt = rawget(_G, firstline and "_PROMPT" or "_PROMPT2")
185 | local tp = type(pmt)
186 | if tp == "string" or tp == "number" then
187 | return tostring(pmt)
188 | end
189 | return firstline and LUA_PROMPT or LUA_PROMPT2
190 | end
191 |
192 | local function fetchline(firstline)
193 | return getline(get_prompt(firstline))
194 | end
195 |
196 | local function incomplete (msg)
197 | if msg then
198 | if string_sub(msg, -#eof_ender) == eof_ender then
199 | return true
200 | end
201 | end
202 | return false
203 | end
204 |
205 |
206 | local function pushline (firstline)
207 | local fine,b = true
208 | repeat
209 | b = fetchline(firstline)
210 | if not b then return end -- no input
211 | if using_lsh then
212 | fine = lsh.checkline(b)
213 | end
214 | until fine
215 | if firstline and string_sub(b, 1, 1) == '=' then
216 | return "return " .. string_sub(b, 2) -- change '=' to `return'
217 | else
218 | return b
219 | end
220 | end
221 |
222 |
223 | local function loadline ()
224 | local b = pushline(true)
225 | if not b then return -1 end -- no input
226 | local f, msg
227 | while true do -- repeat until gets a complete line
228 | f, msg = loadstring(b, "=stdin")
229 | if not incomplete(msg) then break end -- cannot try to add lines?
230 | local b2 = pushline(false)
231 | if not b2 then -- no more input?
232 | return -1
233 | end
234 | b = b .. "\n" .. b2 -- join them
235 | end
236 |
237 | saveline(b)
238 |
239 | return f, msg
240 | end
241 |
242 |
243 | local function dotty ()
244 | local oldprogname = progname
245 | progname = nil
246 | using_lsh,lsh = false -- pcall(require, 'luaish') blows with LI ??
247 | if using_lsh then
248 | our_tostring = lsh.tostring
249 | else
250 | --print('problem loading luaish:',lsh)
251 | our_tostring = tostring
252 | end
253 | while true do
254 | local result
255 | local status, msg = loadline()
256 | if status == -1 then break end
257 | if status then
258 | result = tuple(docall(status))
259 | status, msg = result[1], result[2]
260 | end
261 | report(status, msg)
262 | if status and result.n > 1 then -- any result to print?
263 | status, msg = pcall(our_print, unpack(result, 2, result.n))
264 | if not status then
265 | l_message(progname, string_format(
266 | "error calling %s (%s)",
267 | LUA_QL("print"), msg))
268 | end
269 | end
270 | end
271 | io_stdout:write"\n"
272 | io_stdout:flush()
273 | progname = oldprogname
274 | end
275 |
276 |
277 | local function handle_script(argv, n)
278 | _G.arg = getargs(argv, n) -- collect arguments
279 | local fname = argv[n]
280 | if fname == "-" and argv[n-1] ~= "--" then
281 | fname = nil -- stdin
282 | end
283 | local status, msg = loadfile(fname)
284 | if status then
285 | status, msg = docall(status, unpack(_G.arg))
286 | end
287 | return report(status, msg)
288 | end
289 |
290 |
291 | local function collectargs (argv, p)
292 | local i = 1
293 | while i <= #argv do
294 | if string_sub(argv[i], 1, 1) ~= '-' then -- not an option?
295 | return i
296 | end
297 | local prefix = string_sub(argv[i], 1, 2)
298 | if prefix == '--' then
299 | if #argv[i] > 2 then return -1 end
300 | return argv[i+1] and i+1 or 0
301 | elseif prefix == '-' then
302 | return i
303 | elseif prefix == '-i' then
304 | if #argv[i] > 2 then return -1 end
305 | p.i = true
306 | p.v = true
307 | elseif prefix == '-v' then
308 | if #argv[i] > 2 then return -1 end
309 | p.v = true
310 | elseif prefix == '-e' then
311 | p.e = true
312 | if #argv[i] == 2 then
313 | i = i + 1
314 | if argv[i] == nil then return -1 end
315 | end
316 | elseif prefix == '-l' then
317 | if #argv[i] == 2 then
318 | i = i + 1
319 | if argv[i] == nil then return -1 end
320 | end
321 | else
322 | return -1 -- invalid option
323 | end
324 | i = i + 1
325 | end
326 | return 0
327 | end
328 |
329 |
330 | local function runargs(argv, n)
331 | local i = 1
332 | while i <= n do if argv[i] then
333 | assert(string_sub(argv[i], 1, 1) == '-')
334 | local c = string_sub(argv[i], 2, 2) -- option
335 | if c == 'e' then
336 | local chunk = string_sub(argv[i], 3)
337 | if chunk == '' then i = i + 1; chunk = argv[i] end
338 | assert(chunk)
339 | if not dostring(chunk, "=(command line)") then return false end
340 | elseif c == 'l' then
341 | local filename = string_sub(argv[i], 3)
342 | if filename == '' then i = i + 1; filename = argv[i] end
343 | assert(filename)
344 | if not dolibrary(filename) then return false end
345 | end
346 | i = i + 1
347 | end end
348 | return true
349 | end
350 |
351 |
352 | local function handle_luainit()
353 | local init = os_getenv(LUA_INIT)
354 | if init == nil then
355 | return -- status OK
356 | elseif string_sub(init, 1, 1) == '@' then
357 | dofile(string_sub(init, 2))
358 | else
359 | dostring(init, "=" .. LUA_INIT)
360 | end
361 | end
362 |
363 |
364 | local import_ = _G.import
365 | if import_ then
366 | lua_stdin_is_tty = import_.lua_stdin_is_tty or lua_stdin_is_tty
367 | setsignal = import_.setsignal or setsignal
368 | LUA_RELEASE = import_.LUA_RELEASE or LUA_RELEASE
369 | LUA_COPYRIGHT = import_.LUA_COPYRIGHT or LUA_COPYRIGHT
370 | _G.import = nil
371 | end
372 |
373 | if _G.arg and _G.arg[0] and #_G.arg[0] > 0 then progname = _G.arg[0] end
374 | local argv = {...}
375 | handle_luainit()
376 | local has = {i=false, v=false, e=false}
377 | local script = collectargs(argv, has)
378 | if script < 0 then -- invalid args?
379 | print_usage()
380 | os_exit(1)
381 | end
382 | if has.v then print_version() end
383 | local status = runargs(argv, (script > 0) and script-1 or #argv)
384 | if not status then os_exit(1) end
385 | if script ~= 0 then
386 | status = handle_script(argv, script)
387 | if not status then os_exit(1) end
388 | else
389 | _G.arg = nil
390 | end
391 | if has.i then
392 | dotty()
393 | elseif script == 0 and not has.e and not has.v then
394 | if lua_stdin_is_tty() then
395 | print_version()
396 | require 'CLRPackage'
397 | import 'System'
398 | dotty()
399 | else dofile(nil) -- executes stdin as a file
400 | end
401 | end
402 |
--------------------------------------------------------------------------------
/samples/nplot1.lua:
--------------------------------------------------------------------------------
1 | require "CLRPackage"
2 | require "CLRForm"
3 | import "System"
4 | import "System.Windows.Forms"
5 | import "System.Drawing"
6 | import 'NPlot.dll'
7 | NPW = CLRPackage('NPlot.dll','NPlot.Windows')
8 |
9 | function doubles(t)
10 | return luanet.make_array(Double,t)
11 | end
12 |
13 | f = Form()
14 |
15 | s = NPW.PlotSurface2D()
16 | s.Dock = DockStyle.Fill
17 | f.Controls:Add(s)
18 |
19 | lp = LinePlot()
20 | lp.AbscissaData = doubles{1,2,3,4}
21 | lp.OrdinateData = doubles{10,25,30,27}
22 |
23 | s:Add(lp)
24 |
25 | f:ShowDialog()
26 |
27 |
--------------------------------------------------------------------------------
/samples/socket.lua:
--------------------------------------------------------------------------------
1 | --require("compat-5.1")
2 |
3 | luanet.load_assembly("System")
4 | Math=luanet.import_type("System.Math")
5 | print(Math.Pow(2,3))
6 |
7 | WebClient=luanet.import_type("System.Net.WebClient")
8 | StreamReader=luanet.import_type("System.IO.StreamReader")
9 |
10 |
11 |
12 |
13 | myWebClient = WebClient()
14 | myStream = myWebClient:OpenRead(arg[1])
15 | sr = StreamReader(myStream)
16 | line=sr:ReadLine()
17 | repeat
18 | print(line)
19 | line=sr:ReadLine()
20 | until not line
21 | myStream:Close()
22 |
--------------------------------------------------------------------------------
/samples/table1.wlua:
--------------------------------------------------------------------------------
1 | -- table1.wlua
2 | require 'CLRPackage'
3 | import "System.Windows.Forms"
4 |
5 | panel = TableLayoutPanel()
6 | panel.RowCount = 2
7 | panel.ColumnCount = 2
8 |
9 | function button(text,callback)
10 | local b = Button()
11 | b.Text = text
12 | panel.Controls:Add(b)
13 | return b
14 | end
15 |
16 | b1 = button "One"
17 | b2 = button "Two"
18 | b3 = button "Three"
19 | b4 = button "Four"
20 |
21 | panel:SetRow(b1,0); panel:SetColumn(b1,0)
22 | panel:SetRow(b2,0); panel:SetColumn(b2,1)
23 | panel:SetRow(b3,1); panel:SetColumn(b3,0)
24 | panel:SetRow(b4,1); panel:SetColumn(b4,1)
25 |
26 | form = Form()
27 | form.Text = "Hello, World!"
28 | panel.Dock = DockStyle.Fill
29 |
30 | form.Controls:Add(panel)
31 | form:ShowDialog()
32 |
--------------------------------------------------------------------------------
/samples/test-com.lua:
--------------------------------------------------------------------------------
1 | require 'com'
2 |
3 | -- http://ss64.com/vb/filesystemobject.html
4 |
5 | fo = com.CreateObject("Scripting.FileSystemObject")
6 | each = luanet.each
7 | print(fo:FileExists 'com.lua')
8 | print 'and'
9 | f = fo:GetFile 'com.lua'
10 | print (f.Name)
11 |
12 | drives = fo.Drives
13 | print(drives.Count)
14 | print(drives)
15 |
16 | -- this is weird: can access as property!
17 | ee = drives.GetEnumerator
18 | while ee:MoveNext() do
19 | -- have to wrap this COM object explicitly!
20 | local drive = com.wrap(ee.Current)
21 | print(drive.DriveLetter)
22 | end
23 |
24 | function com.each(obj)
25 | local e = obj.GetEnumerator
26 | return function()
27 | if e:MoveNext() then
28 | return com.wrap(e.Current)
29 | end
30 | end
31 | end
32 |
33 | for d in com.each(drives) do print(d.DriveType) end
34 |
35 | --print(fo.Drives['C'])
36 |
37 | print(fo:FolderExists 'lua')
38 | print(fo:GetAbsolutePathName 'lua')
39 |
40 | this = fo:GetFolder '..'
41 | for f in com.each(this.SubFolders) do print(f.Name) end
42 |
43 | --~ drive = fo:Drives 'C'
44 | --~ print(drive.AvailableSpace)
45 |
--------------------------------------------------------------------------------
/samples/testbox.wlua:
--------------------------------------------------------------------------------
1 | require "CLRForm"
2 |
3 | text = RichTextBox()
4 | text.Multiline = true
5 | text.Text = [[
6 | here is
7 | a set of lines
8 | for you
9 | ]]
10 |
11 | LuaForm ({text}):ShowDialog()
12 |
--------------------------------------------------------------------------------
/samples/testluaform.lua:
--------------------------------------------------------------------------------
1 | require("CLRPackage")
2 |
3 | Forms = CLRPackage("System.Windows.Forms", "System.Windows.Forms")
4 | Drawing = CLRPackage("System.Drawing", "System.Drawing")
5 | LuaInterface = CLRPackage("LuaInterface", "LuaInterface")
6 | IO = CLRPackage("System.IO", "System.IO")
7 | System = CLRPackage("System", "System")
8 |
9 | Form=Forms.Form
10 | TextBox=Forms.TextBox
11 | Label=Forms.Label
12 | ListBox=Forms.ListBox
13 | Button=Forms.Button
14 | Point=Drawing.Point
15 | Size=Drawing.Size
16 | Lua=LuaInterface.Lua
17 | OpenFileDialog=Forms.OpenFileDialog
18 | File=IO.File
19 | StreamReader=IO.StreamReader
20 | FileMode=IO.FileMode
21 | ScrollBars=Forms.ScrollBars
22 | FormBorderStyle=Forms.FormBorderStyle
23 | FormStartPosition=Forms.FormStartPosition
24 |
25 | function clear_click(sender,args)
26 | code:Clear()
27 | end
28 |
29 | function execute_click(sender,args)
30 | results.Items:Clear()
31 | result=lua:DoString(code.Text)
32 | if result then
33 | for i=0,result.Length-1 do
34 | results.Items:Add(result[i])
35 | end
36 | end
37 | end
38 |
39 | function load_click(sender,args)
40 | open_file:ShowDialog()
41 | file=StreamReader(open_file.FileName)
42 | code.Text=file:ReadToEnd()
43 | file:Close()
44 | end
45 |
46 | form = Form()
47 | code = TextBox()
48 | label1 = Label()
49 | execute = Button()
50 | clear = Button()
51 | results = ListBox()
52 | label2 = Label()
53 | load = Button()
54 | lua = Lua()
55 | --lua:OpenBaseLib() -- steffenj: Open*Lib() functions no longer exist
56 | open_file = OpenFileDialog()
57 |
58 | form:SuspendLayout()
59 |
60 | code.Location = Point(16, 24)
61 | code.Multiline = true
62 | code.Name = "Code"
63 | code.Size = Size(440, 128)
64 | code.ScrollBars = ScrollBars.Vertical
65 | code.TabIndex = 0
66 | code.Text = ""
67 |
68 | label1.Location = Point(16, 8)
69 | label1.Name = "label1"
70 | label1.Size = Size(100, 16)
71 | label1.TabIndex = 1
72 | label1.Text = "Lua Code:"
73 |
74 | execute.Location = Point(96, 160)
75 | execute.Name = "Execute"
76 | execute.TabIndex = 2
77 | execute.Text = "Execute"
78 | execute.Click:Add(execute_click)
79 |
80 | clear.Location = Point(176, 160)
81 | clear.Name = "Clear"
82 | clear.TabIndex = 3
83 | clear.Text = "Clear"
84 | clear.Click:Add(clear_click)
85 |
86 | results.Location = Point(16, 208)
87 | results.Name = "Results"
88 | results.Size = Size(440, 95)
89 | results.TabIndex = 4
90 |
91 | label2.Location = Point(16, 192)
92 | label2.Name = "label2"
93 | label2.Size = Size(100, 16)
94 | label2.TabIndex = 5
95 | label2.Text = "Results:"
96 |
97 | load.Location = Point(16, 160)
98 | load.Name = "Load"
99 | load.TabIndex = 6
100 | load.Text = "Load..."
101 | load.Click:Add(load_click)
102 |
103 | open_file.DefaultExt = "lua"
104 | open_file.Filter = "Lua Scripts|*.lua|All Files|*.*"
105 | open_file.Title = "Pick a File"
106 |
107 | form.AutoScaleBaseSize = Size(5, 13)
108 | form.ClientSize = Size(472, 315)
109 | form.Controls:Add(load)
110 | form.Controls:Add(label2)
111 | form.Controls:Add(results)
112 | form.Controls:Add(clear)
113 | form.Controls:Add(execute)
114 | form.Controls:Add(label1)
115 | form.Controls:Add(code)
116 | form.Name = "MainForm"
117 | form.Text = "LuaNet"
118 | form.FormBorderStyle = FormBorderStyle.Fixed3D
119 | form.StartPosition = FormStartPosition.CenterScreen
120 | form:ResumeLayout(false)
121 |
122 | form:ShowDialog()
123 |
--------------------------------------------------------------------------------
/src/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using System.Runtime.CompilerServices;
4 | using System.Security.Permissions;
5 |
6 | //
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | //
11 | [assembly: AssemblyTitle("LuaInterface")]
12 | [assembly: AssemblyDescription("Bridge between the Lua runtime and the CLR")]
13 | [assembly: AssemblyCopyright("Copyright 2003-2008 Fabio Mascarenhas, Kevin Hester")]
14 | [assembly: CLSCompliant(false)]
15 |
16 | //
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Revision and Build Numbers
25 | // by using the '*' as shown below:
26 |
27 | [assembly: AssemblyVersion("2.0.4.*")]
28 |
29 | //
30 | // In order to sign your assembly you must specify a key to use. Refer to the
31 | // Microsoft .NET Framework documentation for more information on assembly signing.
32 | //
33 | // Use the attributes below to control which key is used for signing.
34 | //
35 | // Notes:
36 | // (*) If no key is specified, the assembly is not signed.
37 | // (*) KeyName refers to a key that has been installed in the Crypto Service
38 | // Provider (CSP) on your machine. KeyFile refers to a file which contains
39 | // a key.
40 | // (*) If the KeyFile and the KeyName values are both specified, the
41 | // following processing occurs:
42 | // (1) If the KeyName can be found in the CSP, that key is used.
43 | // (2) If the KeyName does not exist and the KeyFile does exist, the key
44 | // in the KeyFile is installed into the CSP and used.
45 | // (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
46 | // When specifying the KeyFile, the location of the KeyFile should be
47 | // relative to the project output directory which is
48 | // %Project Directory%\obj\. For example, if your KeyFile is
49 | // located in the project directory, you would specify the AssemblyKeyFile
50 | // attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
51 | // (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
52 | // documentation for more information on this.
53 | //
54 |
55 | // We call native DLLs (lua50) and we don't want to be fucked with or validated
56 | // [assembly: SecurityPermission(RequestMinimum, UnmanagedCode = true)]
57 |
--------------------------------------------------------------------------------
/src/CheckType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 |
5 | namespace LuaInterface
6 | {
7 | /*
8 | * Type checking and conversion functions.
9 | *
10 | * Author: Fabio Mascarenhas
11 | * Version: 1.0
12 | */
13 | class CheckType
14 | {
15 | private ObjectTranslator translator;
16 |
17 | ExtractValue extractNetObject;
18 | Dictionary extractValues = new Dictionary();
19 |
20 | public CheckType(ObjectTranslator translator)
21 | {
22 | this.translator = translator;
23 |
24 | extractValues.Add(typeof(object).TypeHandle.Value.ToInt64(), new ExtractValue(getAsObject));
25 | extractValues.Add(typeof(sbyte).TypeHandle.Value.ToInt64(), new ExtractValue(getAsSbyte));
26 | extractValues.Add(typeof(byte).TypeHandle.Value.ToInt64(), new ExtractValue(getAsByte));
27 | extractValues.Add(typeof(short).TypeHandle.Value.ToInt64(), new ExtractValue(getAsShort));
28 | extractValues.Add(typeof(ushort).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUshort));
29 | extractValues.Add(typeof(int).TypeHandle.Value.ToInt64(), new ExtractValue(getAsInt));
30 | extractValues.Add(typeof(uint).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUint));
31 | extractValues.Add(typeof(long).TypeHandle.Value.ToInt64(), new ExtractValue(getAsLong));
32 | extractValues.Add(typeof(ulong).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUlong));
33 | extractValues.Add(typeof(double).TypeHandle.Value.ToInt64(), new ExtractValue(getAsDouble));
34 | extractValues.Add(typeof(char).TypeHandle.Value.ToInt64(), new ExtractValue(getAsChar));
35 | extractValues.Add(typeof(float).TypeHandle.Value.ToInt64(), new ExtractValue(getAsFloat));
36 | extractValues.Add(typeof(decimal).TypeHandle.Value.ToInt64(), new ExtractValue(getAsDecimal));
37 | extractValues.Add(typeof(bool).TypeHandle.Value.ToInt64(), new ExtractValue(getAsBoolean));
38 | extractValues.Add(typeof(string).TypeHandle.Value.ToInt64(), new ExtractValue(getAsString));
39 | extractValues.Add(typeof(LuaFunction).TypeHandle.Value.ToInt64(), new ExtractValue(getAsFunction));
40 | extractValues.Add(typeof(LuaTable).TypeHandle.Value.ToInt64(), new ExtractValue(getAsTable));
41 | extractValues.Add(typeof(LuaUserData).TypeHandle.Value.ToInt64(), new ExtractValue(getAsUserdata));
42 |
43 | extractNetObject = new ExtractValue(getAsNetObject);
44 | }
45 |
46 | /*
47 | * Checks if the value at Lua stack index stackPos matches paramType,
48 | * returning a conversion function if it does and null otherwise.
49 | */
50 | internal ExtractValue getExtractor(IReflect paramType)
51 | {
52 | return getExtractor(paramType.UnderlyingSystemType);
53 | }
54 | internal ExtractValue getExtractor(Type paramType)
55 | {
56 | if(paramType.IsByRef) paramType=paramType.GetElementType();
57 |
58 | long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64();
59 |
60 | if(extractValues.ContainsKey(runtimeHandleValue))
61 | return extractValues[runtimeHandleValue];
62 | else
63 | return extractNetObject;
64 | }
65 |
66 | internal ExtractValue checkType(IntPtr luaState,int stackPos,Type paramType)
67 | {
68 | LuaTypes luatype = LuaDLL.lua_type(luaState, stackPos);
69 |
70 | if(paramType.IsByRef) paramType=paramType.GetElementType();
71 |
72 | Type underlyingType = Nullable.GetUnderlyingType(paramType);
73 | if (underlyingType != null)
74 | {
75 | paramType = underlyingType; // Silently convert nullable types to their non null requics
76 | }
77 |
78 | long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64();
79 |
80 | if (paramType.Equals(typeof(object)))
81 | return extractValues[runtimeHandleValue];
82 |
83 | //CP: Added support for generic parameters
84 | if (paramType.IsGenericParameter)
85 | {
86 | if (luatype == LuaTypes.LUA_TBOOLEAN)
87 | return extractValues[typeof(bool).TypeHandle.Value.ToInt64()];
88 | else if (luatype == LuaTypes.LUA_TSTRING)
89 | return extractValues[typeof(string).TypeHandle.Value.ToInt64()];
90 | else if (luatype == LuaTypes.LUA_TTABLE)
91 | return extractValues[typeof(LuaTable).TypeHandle.Value.ToInt64()];
92 | else if (luatype == LuaTypes.LUA_TUSERDATA)
93 | return extractValues[typeof(object).TypeHandle.Value.ToInt64()];
94 | else if (luatype == LuaTypes.LUA_TFUNCTION)
95 | return extractValues[typeof(LuaFunction).TypeHandle.Value.ToInt64()];
96 | else if (luatype == LuaTypes.LUA_TNUMBER)
97 | return extractValues[typeof(double).TypeHandle.Value.ToInt64()];
98 | //else // suppress CS0642
99 | ;//an unsupported type was encountered
100 | }
101 |
102 | if (LuaDLL.lua_isnumber(luaState, stackPos))
103 | return extractValues[runtimeHandleValue];
104 |
105 | if (paramType == typeof(bool))
106 | {
107 | if (LuaDLL.lua_isboolean(luaState, stackPos))
108 | return extractValues[runtimeHandleValue];
109 | }
110 | else if (paramType == typeof(string))
111 | {
112 | if (LuaDLL.lua_isstring(luaState, stackPos))
113 | return extractValues[runtimeHandleValue];
114 | else if (luatype == LuaTypes.LUA_TNIL)
115 | return extractNetObject; // kevinh - silently convert nil to a null string pointer
116 | }
117 | else if (paramType == typeof(LuaTable))
118 | {
119 | if (luatype == LuaTypes.LUA_TTABLE)
120 | return extractValues[runtimeHandleValue];
121 | }
122 | else if (paramType == typeof(LuaUserData))
123 | {
124 | if (luatype == LuaTypes.LUA_TUSERDATA)
125 | return extractValues[runtimeHandleValue];
126 | }
127 | else if (paramType == typeof(LuaFunction))
128 | {
129 | if (luatype == LuaTypes.LUA_TFUNCTION)
130 | return extractValues[runtimeHandleValue];
131 | }
132 | else if (typeof(Delegate).IsAssignableFrom(paramType) && luatype == LuaTypes.LUA_TFUNCTION)
133 | {
134 | #if __NOGEN__
135 | translator.throwError(luaState,"Delegates not implemnented");
136 | #else
137 | return new ExtractValue(new DelegateGenerator(translator, paramType).extractGenerated);
138 | #endif
139 | }
140 | else if (paramType.IsInterface && luatype == LuaTypes.LUA_TTABLE)
141 | {
142 | #if __NOGEN__
143 | translator.throwError(luaState,"Interfaces not implemnented");
144 | #else
145 | return new ExtractValue(new ClassGenerator(translator, paramType).extractGenerated);
146 | #endif
147 | }
148 | else if ((paramType.IsInterface || paramType.IsClass) && luatype == LuaTypes.LUA_TNIL)
149 | {
150 | // kevinh - allow nil to be silently converted to null - extractNetObject will return null when the item ain't found
151 | return extractNetObject;
152 | }
153 | else if (LuaDLL.lua_type(luaState, stackPos) == LuaTypes.LUA_TTABLE)
154 | {
155 | if (LuaDLL.luaL_getmetafield(luaState, stackPos, "__index"))
156 | {
157 | object obj = translator.getNetObject(luaState, -1);
158 | LuaDLL.lua_settop(luaState, -2);
159 | if (obj != null && paramType.IsAssignableFrom(obj.GetType()))
160 | return extractNetObject;
161 | }
162 | else
163 | return null;
164 | }
165 | else
166 | {
167 | object obj = translator.getNetObject(luaState, stackPos);
168 | if (obj != null && paramType.IsAssignableFrom(obj.GetType()))
169 | return extractNetObject;
170 | }
171 |
172 | return null;
173 | }
174 |
175 | /*
176 | * The following functions return the value in the Lua stack
177 | * index stackPos as the desired type if it can, or null
178 | * otherwise.
179 | */
180 | private object getAsSbyte(IntPtr luaState,int stackPos)
181 | {
182 | sbyte retVal=(sbyte)LuaDLL.lua_tonumber(luaState,stackPos);
183 | if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
184 | return retVal;
185 | }
186 | private object getAsByte(IntPtr luaState,int stackPos)
187 | {
188 | byte retVal=(byte)LuaDLL.lua_tonumber(luaState,stackPos);
189 | if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
190 | return retVal;
191 | }
192 | private object getAsShort(IntPtr luaState,int stackPos)
193 | {
194 | short retVal=(short)LuaDLL.lua_tonumber(luaState,stackPos);
195 | if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
196 | return retVal;
197 | }
198 | private object getAsUshort(IntPtr luaState,int stackPos)
199 | {
200 | ushort retVal=(ushort)LuaDLL.lua_tonumber(luaState,stackPos);
201 | if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
202 | return retVal;
203 | }
204 | private object getAsInt(IntPtr luaState,int stackPos)
205 | {
206 | int retVal=(int)LuaDLL.lua_tonumber(luaState,stackPos);
207 | if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
208 | return retVal;
209 | }
210 | private object getAsUint(IntPtr luaState,int stackPos)
211 | {
212 | uint retVal=(uint)LuaDLL.lua_tonumber(luaState,stackPos);
213 | if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
214 | return retVal;
215 | }
216 | private object getAsLong(IntPtr luaState,int stackPos)
217 | {
218 | long retVal=(long)LuaDLL.lua_tonumber(luaState,stackPos);
219 | if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
220 | return retVal;
221 | }
222 | private object getAsUlong(IntPtr luaState,int stackPos)
223 | {
224 | ulong retVal=(ulong)LuaDLL.lua_tonumber(luaState,stackPos);
225 | if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
226 | return retVal;
227 | }
228 | private object getAsDouble(IntPtr luaState,int stackPos)
229 | {
230 | double retVal=LuaDLL.lua_tonumber(luaState,stackPos);
231 | if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
232 | return retVal;
233 | }
234 | private object getAsChar(IntPtr luaState,int stackPos)
235 | {
236 | char retVal=(char)LuaDLL.lua_tonumber(luaState,stackPos);
237 | if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
238 | return retVal;
239 | }
240 | private object getAsFloat(IntPtr luaState,int stackPos)
241 | {
242 | float retVal=(float)LuaDLL.lua_tonumber(luaState,stackPos);
243 | if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
244 | return retVal;
245 | }
246 | private object getAsDecimal(IntPtr luaState,int stackPos)
247 | {
248 | decimal retVal=(decimal)LuaDLL.lua_tonumber(luaState,stackPos);
249 | if(retVal==0 && !LuaDLL.lua_isnumber(luaState,stackPos)) return null;
250 | return retVal;
251 | }
252 | private object getAsBoolean(IntPtr luaState,int stackPos)
253 | {
254 | return LuaDLL.lua_toboolean(luaState,stackPos);
255 | }
256 | private object getAsString(IntPtr luaState,int stackPos)
257 | {
258 | string retVal=LuaDLL.lua_tostring(luaState,stackPos);
259 | if(retVal=="" && !LuaDLL.lua_isstring(luaState,stackPos)) return null;
260 | return retVal;
261 | }
262 | private object getAsTable(IntPtr luaState,int stackPos)
263 | {
264 | return translator.getTable(luaState,stackPos);
265 | }
266 | private object getAsFunction(IntPtr luaState,int stackPos)
267 | {
268 | return translator.getFunction(luaState,stackPos);
269 | }
270 | private object getAsUserdata(IntPtr luaState,int stackPos)
271 | {
272 | return translator.getUserData(luaState,stackPos);
273 | }
274 | public object getAsObject(IntPtr luaState,int stackPos)
275 | {
276 | if(LuaDLL.lua_type(luaState,stackPos)==LuaTypes.LUA_TTABLE)
277 | {
278 | if(LuaDLL.luaL_getmetafield(luaState,stackPos,"__index"))
279 | {
280 | if(LuaDLL.luaL_checkmetatable(luaState,-1))
281 | {
282 | LuaDLL.lua_insert(luaState,stackPos);
283 | LuaDLL.lua_remove(luaState,stackPos+1);
284 | }
285 | else
286 | {
287 | LuaDLL.lua_settop(luaState,-2);
288 | }
289 | }
290 | }
291 | object obj=translator.getObject(luaState,stackPos);
292 | return obj;
293 | }
294 | public object getAsNetObject(IntPtr luaState,int stackPos)
295 | {
296 | object obj=translator.getNetObject(luaState,stackPos);
297 | if(obj==null && LuaDLL.lua_type(luaState,stackPos)==LuaTypes.LUA_TTABLE)
298 | {
299 | if(LuaDLL.luaL_getmetafield(luaState,stackPos,"__index"))
300 | {
301 | if(LuaDLL.luaL_checkmetatable(luaState,-1))
302 | {
303 | LuaDLL.lua_insert(luaState,stackPos);
304 | LuaDLL.lua_remove(luaState,stackPos+1);
305 | obj=translator.getNetObject(luaState,stackPos);
306 | }
307 | else
308 | {
309 | LuaDLL.lua_settop(luaState,-2);
310 | }
311 | }
312 | }
313 | return obj;
314 | }
315 | }
316 | }
317 |
--------------------------------------------------------------------------------
/src/LuaBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace LuaInterface
6 | {
7 | ///
8 | /// Base class to provide consistent disposal flow across lua objects. Uses code provided by Yves Duhoux and suggestions by Hans Schmeidenbacher and Qingrui Li
9 | ///
10 | public abstract class LuaBase : IDisposable
11 | {
12 | private bool _Disposed;
13 | protected int _Reference;
14 | protected Lua _Interpreter;
15 |
16 | ~LuaBase()
17 | {
18 | Dispose(false);
19 | }
20 |
21 | public void Dispose()
22 | {
23 | Dispose(true);
24 | GC.SuppressFinalize(this);
25 | }
26 |
27 | public virtual void Dispose(bool disposeManagedResources)
28 | {
29 | if (!_Disposed)
30 | {
31 | if (disposeManagedResources)
32 | {
33 | if (_Reference != 0)
34 | _Interpreter.dispose(_Reference);
35 | }
36 | _Interpreter = null;
37 | _Disposed = true;
38 | }
39 | }
40 |
41 | public override bool Equals(object o)
42 | {
43 | if (o is LuaBase)
44 | {
45 | LuaBase l = (LuaBase)o;
46 | return _Interpreter.compareRef(l._Reference, _Reference);
47 | }
48 | else return false;
49 | }
50 |
51 | public override int GetHashCode()
52 | {
53 | return _Reference;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/LuaException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.Serialization;
3 |
4 | namespace LuaInterface
5 | {
6 | ///
7 | /// Exceptions thrown by the Lua runtime
8 | ///
9 | [Serializable]
10 | public class LuaException : Exception
11 | {
12 | public LuaException()
13 | {}
14 |
15 | public LuaException(string message) : base(message)
16 | {}
17 |
18 | public LuaException(string message, Exception innerException) : base(message, innerException)
19 | {}
20 |
21 | protected LuaException(SerializationInfo info, StreamingContext context) : base(info, context)
22 | {}
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/LuaFunction.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace LuaInterface
6 | {
7 | public class LuaFunction : LuaBase
8 | {
9 | //private Lua interpreter;
10 | internal LuaCSFunction function;
11 | //internal int reference;
12 |
13 | public LuaFunction(int reference, Lua interpreter)
14 | {
15 | _Reference = reference;
16 | this.function = null;
17 | _Interpreter = interpreter;
18 | }
19 |
20 | public LuaFunction(LuaCSFunction function, Lua interpreter)
21 | {
22 | _Reference = 0;
23 | this.function = function;
24 | _Interpreter = interpreter;
25 | }
26 |
27 | //~LuaFunction()
28 | //{
29 | // if (reference != 0)
30 | // interpreter.dispose(reference);
31 | //}
32 |
33 | //bool disposed = false;
34 | //~LuaFunction()
35 | //{
36 | // Dispose(false);
37 | //}
38 |
39 | //public void Dispose()
40 | //{
41 | // Dispose(true);
42 | // GC.SuppressFinalize(this);
43 | //}
44 |
45 | //public virtual void Dispose(bool disposeManagedResources)
46 | //{
47 | // if (!this.disposed)
48 | // {
49 | // if (disposeManagedResources)
50 | // {
51 | // if (_Reference != 0)
52 | // _Interpreter.dispose(_Reference);
53 | // }
54 |
55 | // disposed = true;
56 | // }
57 | //}
58 |
59 |
60 | /*
61 | * Calls the function casting return values to the types
62 | * in returnTypes
63 | */
64 | internal object[] call(object[] args, Type[] returnTypes)
65 | {
66 | return _Interpreter.callFunction(this, args, returnTypes);
67 | }
68 | /*
69 | * Calls the function and returns its return values inside
70 | * an array
71 | */
72 | public object[] Call(params object[] args)
73 | {
74 | return _Interpreter.callFunction(this, args);
75 | }
76 | /*
77 | * Pushes the function into the Lua stack
78 | */
79 | internal void push(IntPtr luaState)
80 | {
81 | if (_Reference != 0)
82 | LuaDLL.lua_getref(luaState, _Reference);
83 | else
84 | _Interpreter.pushCSFunction(function);
85 | }
86 | public override string ToString()
87 | {
88 | return "function";
89 | }
90 | public override bool Equals(object o)
91 | {
92 | if (o is LuaFunction)
93 | {
94 | LuaFunction l = (LuaFunction)o;
95 | if (this._Reference != 0 && l._Reference != 0)
96 | return _Interpreter.compareRef(l._Reference, this._Reference);
97 | else
98 | return this.function == l.function;
99 | }
100 | else return false;
101 | }
102 | public override int GetHashCode()
103 | {
104 | if (_Reference != 0)
105 | return _Reference;
106 | else
107 | return function.GetHashCode();
108 | }
109 | }
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/src/LuaGlobalAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LuaInterface
4 | {
5 | ///
6 | /// Marks a method for global usage in Lua scripts
7 | ///
8 | ///
9 | ///
10 | [AttributeUsage(AttributeTargets.Method)]
11 | // sealed
12 | public class LuaGlobalAttribute : Attribute
13 | {
14 | private string name,descript;
15 | ///
16 | /// An alternative name to use for calling the function in Lua - leave empty for CLR name
17 | ///
18 | public string Name { get { return name; } set { name = value; }}
19 |
20 | ///
21 | /// A description of the function
22 | ///
23 | public string Description { get { return descript; } set { descript = value; }}
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/LuaHideAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LuaInterface
4 | {
5 | ///
6 | /// Marks a method, field or property to be hidden from Lua auto-completion
7 | ///
8 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property)]
9 | public sealed class LuaHideAttribute : Attribute
10 | {}
11 | }
12 |
--------------------------------------------------------------------------------
/src/LuaNetRunner.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using LuaInterface;
3 | using System.Threading;
4 |
5 | /*
6 | * Application to run Lua scripts that can use LuaInterface
7 | * from the console
8 | *
9 | * Author: Fabio Mascarenhas
10 | * Version: 1.0
11 | */
12 | namespace LuaRunner
13 | {
14 | public class LuaNetRunner
15 | {
16 | /*
17 | * Runs the Lua script passed as the first command-line argument.
18 | * It passed all the command-line arguments to the script.
19 | */
20 | [STAThread] // steffenj: testluaform.lua "Load" button complained with an exception that STAThread was missing
21 | public static void Main(string[] args)
22 | {
23 | if(args.Length > 0)
24 | {
25 | // For attaching from the debugger
26 | // Thread.Sleep(20000);
27 |
28 | using (Lua lua = new Lua())
29 | {
30 | //lua.OpenLibs(); // steffenj: Lua 5.1.1 API change (all libs already opened in Lua constructor!)
31 | lua.NewTable("arg");
32 | LuaTable argc = (LuaTable)lua["arg"];
33 | argc[-1] = "LuaRunner";
34 | argc[0] = args[0];
35 | for (int i = 1; i < args.Length; i++)
36 | {
37 | argc[i] = args[i];
38 | }
39 | argc["n"] = args.Length - 1;
40 |
41 | try
42 | {
43 | //Console.WriteLine("DoFile(" + args[0] + ");");
44 | lua.DoFile(args[0]);
45 | }
46 | catch (Exception e)
47 | {
48 | // steffenj: BEGIN error message improved, output is now in decending order of importance (message, where, stacktrace)
49 | // limit size of strack traceback message to roughly 1 console screen height
50 | string trace = e.StackTrace;
51 | if (e.StackTrace.Length > 1300)
52 | trace = e.StackTrace.Substring(0, 1300) + " [...] (traceback cut short)";
53 |
54 | // sjd: make the error message more like standard Lua messages
55 | Console.WriteLine(e.Source + " " + e.Message);
56 | Console.WriteLine("raised a " + e.GetType().ToString());
57 | Console.WriteLine(trace);
58 |
59 | // wait for keypress if there is an error
60 | Console.ReadKey();
61 | // steffenj: END error message improved
62 | }
63 | }
64 | }
65 | else
66 | {
67 | Console.WriteLine("LuaRunner -- runs Lua scripts with CLR access");
68 | Console.WriteLine("Usage: luarunner [{}]");
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/LuaRegistrationHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 | using System.Reflection;
4 |
5 | namespace LuaInterface
6 | {
7 | public static class LuaRegistrationHelper
8 | {
9 | #region Tagged instance methods
10 | ///
11 | /// Registers all public instance methods in an object tagged with as Lua global functions
12 | ///
13 | /// The Lua VM to add the methods to
14 | /// The object to get the methods from
15 | public static void TaggedInstanceMethods(Lua lua, object o)
16 | {
17 | #region Sanity checks
18 | if (lua == null) throw new ArgumentNullException("lua");
19 | if (o == null) throw new ArgumentNullException("o");
20 | #endregion
21 |
22 | foreach (MethodInfo method in o.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public))
23 | {
24 | foreach (LuaGlobalAttribute attribute in method.GetCustomAttributes(typeof(LuaGlobalAttribute), true))
25 | {
26 | if (string.IsNullOrEmpty(attribute.Name))
27 | lua.RegisterFunction(method.Name, o, method); // CLR name
28 | else
29 | lua.RegisterFunction(attribute.Name, o, method); // Custom name
30 | }
31 | }
32 | }
33 | #endregion
34 |
35 | #region Tagged static methods
36 | ///
37 | /// Registers all public static methods in a class tagged with as Lua global functions
38 | ///
39 | /// The Lua VM to add the methods to
40 | /// The class type to get the methods from
41 | public static void TaggedStaticMethods(Lua lua, Type type)
42 | {
43 | #region Sanity checks
44 | if (lua == null) throw new ArgumentNullException("lua");
45 | if (type == null) throw new ArgumentNullException("type");
46 | if (!type.IsClass) throw new ArgumentException("The type must be a class!", "type");
47 | #endregion
48 |
49 | foreach (MethodInfo method in type.GetMethods(BindingFlags.Static | BindingFlags.Public))
50 | {
51 | foreach (LuaGlobalAttribute attribute in method.GetCustomAttributes(typeof(LuaGlobalAttribute), false))
52 | {
53 | if (string.IsNullOrEmpty(attribute.Name))
54 | lua.RegisterFunction(method.Name, null, method); // CLR name
55 | else
56 | lua.RegisterFunction(attribute.Name, null, method); // Custom name
57 | }
58 | }
59 | }
60 | #endregion
61 |
62 | #region Enumeration
63 | ///
64 | /// Registers an enumeration's values for usage as a Lua variable table
65 | ///
66 | /// The enum type to register
67 | /// The Lua VM to add the enum to
68 | [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "The type parameter is used to select an enum type")]
69 | public static void Enumeration(Lua lua)
70 | {
71 | #region Sanity checks
72 | if (lua == null) throw new ArgumentNullException("lua");
73 | #endregion
74 |
75 | Type type = typeof(T);
76 | if (!type.IsEnum) throw new ArgumentException("The type must be an enumeration!");
77 |
78 | string[] names = Enum.GetNames(type);
79 | T[] values = (T[])Enum.GetValues(type);
80 |
81 | lua.NewTable(type.Name);
82 | for (int i = 0; i < names.Length; i++)
83 | {
84 | string path = type.Name + "." + names[i];
85 | lua[path] = values[i];
86 | }
87 | }
88 | #endregion
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/LuaScriptException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LuaInterface
4 | {
5 | ///
6 | /// Exceptions thrown by the Lua runtime because of errors in the script
7 | ///
8 | public class LuaScriptException : LuaException
9 | {
10 | private bool isNet;
11 | ///
12 | /// Returns true if the exception has occured as the result of a .NET exception in user code
13 | ///
14 | public bool IsNetException {
15 | get { return isNet; }
16 | set { isNet = value; }
17 | }
18 |
19 | private readonly string source;
20 |
21 | ///
22 | /// The position in the script where the exception was triggered.
23 | ///
24 | public override string Source { get { return source; } }
25 |
26 | ///
27 | /// Creates a new Lua-only exception.
28 | ///
29 | /// The message that describes the error.
30 | /// The position in the script where the exception was triggered.
31 | public LuaScriptException(string message, string source) : base(message)
32 | {
33 | this.source = source;
34 | }
35 |
36 | ///
37 | /// Creates a new .NET wrapping exception.
38 | ///
39 | /// The .NET exception triggered by user-code.
40 | /// The position in the script where the exception was triggered.
41 | public LuaScriptException(Exception innerException, string source)
42 | : base(innerException.Message, innerException)
43 | {
44 | this.source = source;
45 | this.IsNetException = true;
46 | }
47 |
48 | public override string ToString()
49 | {
50 | // Prepend the error source
51 | return GetType().FullName + ": " + source + Message;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/LuaTable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Collections;
5 |
6 | namespace LuaInterface
7 | {
8 | /*
9 | * Wrapper class for Lua tables
10 | *
11 | * Author: Fabio Mascarenhas
12 | * Version: 1.0
13 | */
14 | public class LuaTable : LuaBase
15 | {
16 | //internal int _Reference;
17 | //private Lua _Interpreter;
18 | public LuaTable(int reference, Lua interpreter)
19 | {
20 | _Reference = reference;
21 | _Interpreter = interpreter;
22 | }
23 |
24 | //bool disposed = false;
25 | //~LuaTable()
26 | //{
27 | // Dispose(false);
28 | //}
29 |
30 | //public void Dispose()
31 | //{
32 | // Dispose(true);
33 | // GC.SuppressFinalize(this);
34 | //}
35 |
36 | //public virtual void Dispose(bool disposeManagedResources)
37 | //{
38 | // if (!this.disposed)
39 | // {
40 | // if (disposeManagedResources)
41 | // {
42 | // if (_Reference != 0)
43 | // _Interpreter.dispose(_Reference);
44 | // }
45 |
46 | // disposed = true;
47 | // }
48 | //}
49 | //~LuaTable()
50 | //{
51 | // _Interpreter.dispose(_Reference);
52 | //}
53 | /*
54 | * Indexer for string fields of the table
55 | */
56 | public object this[string field]
57 | {
58 | get
59 | {
60 | return _Interpreter.getObject(_Reference, field);
61 | }
62 | set
63 | {
64 | _Interpreter.setObject(_Reference, field, value);
65 | }
66 | }
67 | /*
68 | * Indexer for numeric fields of the table
69 | */
70 | public object this[object field]
71 | {
72 | get
73 | {
74 | return _Interpreter.getObject(_Reference, field);
75 | }
76 | set
77 | {
78 | _Interpreter.setObject(_Reference, field, value);
79 | }
80 | }
81 |
82 |
83 | public System.Collections.IDictionaryEnumerator GetEnumerator()
84 | {
85 | return _Interpreter.GetTableDict(this).GetEnumerator();
86 | }
87 |
88 | public ICollection Keys
89 | {
90 | get { return _Interpreter.GetTableDict(this).Keys; }
91 | }
92 |
93 | public ICollection Values
94 | {
95 | get { return _Interpreter.GetTableDict(this).Values; }
96 | }
97 |
98 | /*
99 | * Gets an string fields of a table ignoring its metatable,
100 | * if it exists
101 | */
102 | internal object rawget(string field)
103 | {
104 | return _Interpreter.rawGetObject(_Reference, field);
105 | }
106 |
107 | internal object rawgetFunction(string field)
108 | {
109 | object obj = _Interpreter.rawGetObject(_Reference, field);
110 |
111 | if (obj is LuaCSFunction)
112 | return new LuaFunction((LuaCSFunction)obj, _Interpreter);
113 | else
114 | return obj;
115 | }
116 |
117 | /*
118 | * Pushes this table into the Lua stack
119 | */
120 | internal void push(IntPtr luaState)
121 | {
122 | LuaDLL.lua_getref(luaState, _Reference);
123 | }
124 | public override string ToString()
125 | {
126 | return "table";
127 | }
128 | //public override bool Equals(object o)
129 | //{
130 | // if (o is LuaTable)
131 | // {
132 | // LuaTable l = (LuaTable)o;
133 | // return _Interpreter.compareRef(l._Reference, _Reference);
134 | // }
135 | // else return false;
136 | //}
137 | //public override int GetHashCode()
138 | //{
139 | // return _Reference;
140 | //}
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/src/LuaUserData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace LuaInterface
6 | {
7 | public class LuaUserData : LuaBase
8 | {
9 | //internal int _Reference;
10 | //private Lua _Interpreter;
11 | public LuaUserData(int reference, Lua interpreter)
12 | {
13 | _Reference = reference;
14 | _Interpreter = interpreter;
15 | }
16 | //~LuaUserData()
17 | //{
18 | // if (_Reference != 0)
19 | // _Interpreter.dispose(_Reference);
20 | //}
21 | /*
22 | * Indexer for string fields of the userdata
23 | */
24 | public object this[string field]
25 | {
26 | get
27 | {
28 | return _Interpreter.getObject(_Reference, field);
29 | }
30 | set
31 | {
32 | _Interpreter.setObject(_Reference, field, value);
33 | }
34 | }
35 | /*
36 | * Indexer for numeric fields of the userdata
37 | */
38 | public object this[object field]
39 | {
40 | get
41 | {
42 | return _Interpreter.getObject(_Reference, field);
43 | }
44 | set
45 | {
46 | _Interpreter.setObject(_Reference, field, value);
47 | }
48 | }
49 | /*
50 | * Calls the userdata and returns its return values inside
51 | * an array
52 | */
53 | public object[] Call(params object[] args)
54 | {
55 | return _Interpreter.callFunction(this, args);
56 | }
57 | /*
58 | * Pushes the userdata into the Lua stack
59 | */
60 | internal void push(IntPtr luaState)
61 | {
62 | LuaDLL.lua_getref(luaState, _Reference);
63 | }
64 | public override string ToString()
65 | {
66 | return "userdata";
67 | }
68 | //public override bool Equals(object o)
69 | //{
70 | // if (o is LuaUserData)
71 | // {
72 | // LuaUserData l = (LuaUserData)o;
73 | // return _Interpreter.compareRef(l._Reference, _Reference);
74 | // }
75 | // else return false;
76 | //}
77 | //public override int GetHashCode()
78 | //{
79 | // return _Reference;
80 | //}
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/MethodWrapper.cs:
--------------------------------------------------------------------------------
1 | namespace LuaInterface
2 | {
3 | using System;
4 | using System.IO;
5 | using System.Collections;
6 | using System.Reflection;
7 | using System.Collections.Generic;
8 | using System.Diagnostics;
9 |
10 | /*
11 | * Cached method
12 | */
13 | struct MethodCache
14 | {
15 | private MethodBase _cachedMethod;
16 |
17 | public MethodBase cachedMethod
18 | {
19 | get
20 | {
21 | return _cachedMethod;
22 | }
23 | set
24 | {
25 | _cachedMethod = value;
26 | MethodInfo mi = value as MethodInfo;
27 | if (mi != null)
28 | {
29 | //SJD this is guaranteed to be correct irrespective of actual name used for type..
30 | IsReturnVoid = mi.ReturnType == typeof(void);
31 | }
32 | }
33 | }
34 |
35 | public bool IsReturnVoid;
36 |
37 | // List or arguments
38 | public object[] args;
39 | // Positions of out parameters
40 | public int[] outList;
41 | // Types of parameters
42 | public MethodArgs[] argTypes;
43 | }
44 |
45 | /*
46 | * Parameter information
47 | */
48 | struct MethodArgs
49 | {
50 | // Position of parameter
51 | public int index;
52 | // Type-conversion function
53 | public ExtractValue extractValue;
54 |
55 | public bool isParamsArray;
56 |
57 | public Type paramsArrayType;
58 | }
59 |
60 | /*
61 | * Argument extraction with type-conversion function
62 | */
63 | delegate object ExtractValue(IntPtr luaState, int stackPos);
64 |
65 | /*
66 | * Wrapper class for methods/constructors accessed from Lua.
67 | *
68 | * Author: Fabio Mascarenhas
69 | * Version: 1.0
70 | */
71 | class LuaMethodWrapper
72 | {
73 | private ObjectTranslator _Translator;
74 | private MethodBase _Method;
75 | private MethodCache _LastCalledMethod = new MethodCache();
76 | private string _MethodName;
77 | private MemberInfo[] _Members;
78 | private IReflect _TargetType;
79 | private ExtractValue _ExtractTarget;
80 | private object _Target;
81 | private BindingFlags _BindingType;
82 |
83 | /*
84 | * Constructs the wrapper for a known MethodBase instance
85 | */
86 | public LuaMethodWrapper(ObjectTranslator translator, object target, IReflect targetType, MethodBase method)
87 | {
88 | _Translator = translator;
89 | _Target = target;
90 | _TargetType = targetType;
91 | if (targetType != null)
92 | _ExtractTarget = translator.typeChecker.getExtractor(targetType);
93 | _Method = method;
94 | _MethodName = method.Name;
95 |
96 | if (method.IsStatic)
97 | { _BindingType = BindingFlags.Static; }
98 | else
99 | { _BindingType = BindingFlags.Instance; }
100 | }
101 | /*
102 | * Constructs the wrapper for a known method name
103 | */
104 | public LuaMethodWrapper(ObjectTranslator translator, IReflect targetType, string methodName, BindingFlags bindingType)
105 | {
106 | _Translator = translator;
107 | _MethodName = methodName;
108 | _TargetType = targetType;
109 |
110 | if (targetType != null)
111 | _ExtractTarget = translator.typeChecker.getExtractor(targetType);
112 |
113 | _BindingType = bindingType;
114 |
115 | //CP: Removed NonPublic binding search and added IgnoreCase
116 | _Members = targetType.UnderlyingSystemType.GetMember(methodName, MemberTypes.Method, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase/*|BindingFlags.NonPublic*/);
117 | }
118 |
119 |
120 | ///
121 | /// Convert C# exceptions into Lua errors
122 | ///
123 | /// num of things on stack
124 | /// null for no pending exception
125 | int SetPendingException(Exception e)
126 | {
127 | return _Translator.interpreter.SetPendingException(e);
128 | }
129 |
130 | private static bool IsInteger(double x) {
131 | return Math.Ceiling(x) == x;
132 | }
133 |
134 |
135 | /*
136 | * Calls the method. Receives the arguments from the Lua stack
137 | * and returns values in it.
138 | */
139 | public int call(IntPtr luaState)
140 | {
141 | MethodBase methodToCall = _Method;
142 | object targetObject = _Target;
143 | bool failedCall = true;
144 | int nReturnValues = 0;
145 |
146 | if (!LuaDLL.lua_checkstack(luaState, 5))
147 | throw new LuaException("Lua stack overflow");
148 |
149 | bool isStatic = (_BindingType & BindingFlags.Static) == BindingFlags.Static;
150 |
151 | SetPendingException(null);
152 |
153 | if (methodToCall == null) // Method from name
154 | {
155 | if (isStatic)
156 | targetObject = null;
157 | else
158 | targetObject = _ExtractTarget(luaState, 1);
159 |
160 | //LuaDLL.lua_remove(luaState,1); // Pops the receiver
161 | if (_LastCalledMethod.cachedMethod != null) // Cached?
162 | {
163 | int numStackToSkip = isStatic ? 0 : 1; // If this is an instance invoe we will have an extra arg on the stack for the targetObject
164 | int numArgsPassed = LuaDLL.lua_gettop(luaState) - numStackToSkip;
165 | MethodBase method = _LastCalledMethod.cachedMethod;
166 |
167 | if (numArgsPassed == _LastCalledMethod.argTypes.Length) // No. of args match?
168 | {
169 | if (!LuaDLL.lua_checkstack(luaState, _LastCalledMethod.outList.Length + 6))
170 | throw new LuaException("Lua stack overflow");
171 |
172 | object[] args = _LastCalledMethod.args;
173 |
174 | try
175 | {
176 | for (int i = 0; i < _LastCalledMethod.argTypes.Length; i++)
177 | {
178 | MethodArgs type = _LastCalledMethod.argTypes[i];
179 | object luaParamValue = type.extractValue(luaState, i + 1 + numStackToSkip);
180 | if (_LastCalledMethod.argTypes[i].isParamsArray)
181 | {
182 | args[type.index] = _Translator.tableToArray(luaParamValue,type.paramsArrayType);
183 | }
184 | else
185 | {
186 | args[type.index] = luaParamValue;
187 | }
188 |
189 | if (args[type.index] == null &&
190 | !LuaDLL.lua_isnil(luaState, i + 1 + numStackToSkip))
191 | {
192 | throw new LuaException("argument number " + (i + 1) + " is invalid");
193 | }
194 | }
195 | if ((_BindingType & BindingFlags.Static) == BindingFlags.Static)
196 | {
197 | _Translator.push(luaState, method.Invoke(null, args));
198 | }
199 | else
200 | {
201 | if (_LastCalledMethod.cachedMethod.IsConstructor)
202 | _Translator.push(luaState, ((ConstructorInfo)method).Invoke(args));
203 | else
204 | _Translator.push(luaState, method.Invoke(targetObject,args));
205 | }
206 | failedCall = false;
207 | }
208 | catch (TargetInvocationException e)
209 | {
210 | // Failure of method invocation
211 | return SetPendingException(e.GetBaseException());
212 | }
213 | catch (Exception e)
214 | {
215 | if (_Members.Length == 1) // Is the method overloaded?
216 | // No, throw error
217 | return SetPendingException(e);
218 | }
219 | }
220 | }
221 |
222 | // Cache miss
223 | if (failedCall)
224 | {
225 | // System.Diagnostics.Debug.WriteLine("cache miss on " + methodName);
226 |
227 | // If we are running an instance variable, we can now pop the targetObject from the stack
228 | if (!isStatic)
229 | {
230 | if (targetObject == null)
231 | {
232 | _Translator.throwError(luaState, String.Format("instance method '{0}' requires a non null target object", _MethodName));
233 | LuaDLL.lua_pushnil(luaState);
234 | return 1;
235 | }
236 |
237 | LuaDLL.lua_remove(luaState, 1); // Pops the receiver
238 | }
239 |
240 | bool hasMatch = false;
241 | string candidateName = null;
242 |
243 | foreach (MemberInfo member in _Members)
244 | {
245 | candidateName = member.ReflectedType.Name + "." + member.Name;
246 |
247 | MethodBase m = (MethodInfo)member;
248 |
249 | bool isMethod = _Translator.matchParameters(luaState, m, ref _LastCalledMethod);
250 | if (isMethod)
251 | {
252 | hasMatch = true;
253 | break;
254 | }
255 | }
256 | if (!hasMatch)
257 | {
258 | string msg = (candidateName == null)
259 | ? "invalid arguments to method call"
260 | : ("invalid arguments to method: " + candidateName);
261 |
262 | _Translator.throwError(luaState, msg);
263 | LuaDLL.lua_pushnil(luaState);
264 | return 1;
265 | }
266 | }
267 | }
268 | else // Method from MethodBase instance
269 | {
270 | if (methodToCall.ContainsGenericParameters)
271 | {
272 | // bool isMethod = //* not used
273 | _Translator.matchParameters(luaState, methodToCall, ref _LastCalledMethod);
274 |
275 | if (methodToCall.IsGenericMethodDefinition)
276 | {
277 | //need to make a concrete type of the generic method definition
278 | List typeArgs = new List();
279 |
280 | foreach (object arg in _LastCalledMethod.args)
281 | typeArgs.Add(arg.GetType());
282 |
283 | MethodInfo concreteMethod = (methodToCall as MethodInfo).MakeGenericMethod(typeArgs.ToArray());
284 |
285 | _Translator.push(luaState, concreteMethod.Invoke(targetObject, _LastCalledMethod.args));
286 | failedCall = false;
287 | }
288 | else if (methodToCall.ContainsGenericParameters)
289 | {
290 | _Translator.throwError(luaState, "unable to invoke method on generic class as the current method is an open generic method");
291 | LuaDLL.lua_pushnil(luaState);
292 | return 1;
293 | }
294 | }
295 | else
296 | {
297 | if (!methodToCall.IsStatic && !methodToCall.IsConstructor && targetObject == null)
298 | {
299 | targetObject = _ExtractTarget(luaState, 1);
300 | LuaDLL.lua_remove(luaState, 1); // Pops the receiver
301 | }
302 |
303 | if (!_Translator.matchParameters(luaState, methodToCall, ref _LastCalledMethod))
304 | {
305 | _Translator.throwError(luaState, "invalid arguments to method call");
306 | LuaDLL.lua_pushnil(luaState);
307 | return 1;
308 | }
309 | }
310 | }
311 |
312 | if (failedCall)
313 | {
314 | if (!LuaDLL.lua_checkstack(luaState, _LastCalledMethod.outList.Length + 6))
315 | throw new LuaException("Lua stack overflow");
316 | try
317 | {
318 | if (isStatic)
319 | {
320 | _Translator.push(luaState, _LastCalledMethod.cachedMethod.Invoke(null, _LastCalledMethod.args));
321 | }
322 | else
323 | {
324 | if (_LastCalledMethod.cachedMethod.IsConstructor)
325 | _Translator.push(luaState, ((ConstructorInfo)_LastCalledMethod.cachedMethod).Invoke(_LastCalledMethod.args));
326 | else
327 | _Translator.push(luaState, _LastCalledMethod.cachedMethod.Invoke(targetObject, _LastCalledMethod.args));
328 | }
329 | }
330 | catch (TargetInvocationException e)
331 | {
332 | return SetPendingException(e.GetBaseException());
333 | }
334 | catch (Exception e)
335 | {
336 | return SetPendingException(e);
337 | }
338 | }
339 |
340 | // Pushes out and ref return values
341 | for (int index = 0; index < _LastCalledMethod.outList.Length; index++)
342 | {
343 | nReturnValues++;
344 | _Translator.push(luaState, _LastCalledMethod.args[_LastCalledMethod.outList[index]]);
345 | }
346 |
347 | //by isSingle 2010-09-10 11:26:31
348 | //Desc:
349 | // if not return void,we need add 1,
350 | // or we will lost the function's return value
351 | // when call dotnet function like "int foo(arg1,out arg2,out arg3)" in lua code
352 | if (!_LastCalledMethod.IsReturnVoid && nReturnValues > 0)
353 | {
354 | nReturnValues++;
355 | }
356 |
357 | return nReturnValues < 1 ? 1 : nReturnValues;
358 | }
359 | }
360 |
361 |
362 |
363 |
364 | ///
365 | /// We keep track of what delegates we have auto attached to an event - to allow us to cleanly exit a LuaInterface session
366 | ///
367 | class EventHandlerContainer : IDisposable
368 | {
369 | Dictionary dict = new Dictionary();
370 |
371 | public void Add(Delegate handler, RegisterEventHandler eventInfo)
372 | {
373 | dict.Add(handler, eventInfo);
374 | }
375 |
376 | public void Remove(Delegate handler)
377 | {
378 | bool found = dict.Remove(handler);
379 | Debug.Assert(found);
380 | }
381 |
382 | ///
383 | /// Remove any still registered handlers
384 | ///
385 | public void Dispose()
386 | {
387 | foreach (KeyValuePair pair in dict)
388 | {
389 | pair.Value.RemovePending(pair.Key);
390 | }
391 |
392 | dict.Clear();
393 | }
394 | }
395 |
396 |
397 | /*
398 | * Wrapper class for events that does registration/deregistration
399 | * of event handlers.
400 | *
401 | * Author: Fabio Mascarenhas
402 | * Version: 1.0
403 | */
404 | class RegisterEventHandler
405 | {
406 | object target;
407 | EventInfo eventInfo;
408 | EventHandlerContainer pendingEvents;
409 |
410 | public RegisterEventHandler(EventHandlerContainer pendingEvents, object target, EventInfo eventInfo)
411 | {
412 | this.target = target;
413 | this.eventInfo = eventInfo;
414 | this.pendingEvents = pendingEvents;
415 | }
416 |
417 |
418 | /*
419 | * Adds a new event handler
420 | */
421 | public Delegate Add(LuaFunction function)
422 | {
423 | #if __NOGEN__
424 | //translator.throwError(luaState,"Delegates not implemnented");
425 | return null;
426 | #else
427 | //CP: Fix by Ben Bryant for event handling with one parameter
428 | //link: http://luaforge.net/forum/message.php?msg_id=9266
429 | Delegate handlerDelegate = CodeGeneration.Instance.GetDelegate(eventInfo.EventHandlerType, function);
430 | eventInfo.AddEventHandler(target, handlerDelegate);
431 | pendingEvents.Add(handlerDelegate, this);
432 |
433 | return handlerDelegate;
434 | #endif
435 |
436 |
437 | //MethodInfo mi = eventInfo.EventHandlerType.GetMethod("Invoke");
438 | //ParameterInfo[] pi = mi.GetParameters();
439 | //LuaEventHandler handler=CodeGeneration.Instance.GetEvent(pi[1].ParameterType,function);
440 |
441 | //Delegate handlerDelegate=Delegate.CreateDelegate(eventInfo.EventHandlerType,handler,"HandleEvent");
442 | //eventInfo.AddEventHandler(target,handlerDelegate);
443 | //pendingEvents.Add(handlerDelegate, this);
444 |
445 | //return handlerDelegate;
446 | }
447 |
448 | /*
449 | * Removes an existing event handler
450 | */
451 | public void Remove(Delegate handlerDelegate)
452 | {
453 | RemovePending(handlerDelegate);
454 | pendingEvents.Remove(handlerDelegate);
455 | }
456 |
457 | /*
458 | * Removes an existing event handler (without updating the pending handlers list)
459 | */
460 | internal void RemovePending(Delegate handlerDelegate)
461 | {
462 | eventInfo.RemoveEventHandler(target, handlerDelegate);
463 | }
464 | }
465 |
466 | /*
467 | * Base wrapper class for Lua function event handlers.
468 | * Subclasses that do actual event handling are created
469 | * at runtime.
470 | *
471 | * Author: Fabio Mascarenhas
472 | * Version: 1.0
473 | */
474 | public class LuaEventHandler
475 | {
476 | public LuaFunction handler = null;
477 |
478 | // CP: Fix provided by Ben Bryant for delegates with one param
479 | // link: http://luaforge.net/forum/message.php?msg_id=9318
480 | public void handleEvent(object[] args)
481 | {
482 | handler.Call(args);
483 | }
484 | //public void handleEvent(object sender,object data)
485 | //{
486 | // handler.call(new object[] { sender,data },new Type[0]);
487 | //}
488 | }
489 |
490 | /*
491 | * Wrapper class for Lua functions as delegates
492 | * Subclasses with correct signatures are created
493 | * at runtime.
494 | *
495 | * Author: Fabio Mascarenhas
496 | * Version: 1.0
497 | */
498 | public class LuaDelegate
499 | {
500 | public Type[] returnTypes;
501 | public LuaFunction function;
502 | public LuaDelegate()
503 | {
504 | function = null;
505 | returnTypes = null;
506 | }
507 | public object callFunction(object[] args, object[] inArgs, int[] outArgs)
508 | {
509 | // args is the return array of arguments, inArgs is the actual array
510 | // of arguments passed to the function (with in parameters only), outArgs
511 | // has the positions of out parameters
512 | object returnValue;
513 | int iRefArgs;
514 | object[] returnValues = function.call(inArgs, returnTypes);
515 | if (returnTypes[0] == typeof(void))
516 | {
517 | returnValue = null;
518 | iRefArgs = 0;
519 | }
520 | else
521 | {
522 | returnValue = returnValues[0];
523 | iRefArgs = 1;
524 | }
525 | // Sets the value of out and ref parameters (from
526 | // the values returned by the Lua function).
527 | for (int i = 0; i < outArgs.Length; i++)
528 | {
529 | args[outArgs[i]] = returnValues[iRefArgs];
530 | iRefArgs++;
531 | }
532 | return returnValue;
533 | }
534 | }
535 |
536 | /*
537 | * Static helper methods for Lua tables acting as CLR objects.
538 | *
539 | * Author: Fabio Mascarenhas
540 | * Version: 1.0
541 | */
542 | public class LuaClassHelper
543 | {
544 | /*
545 | * Gets the function called name from the provided table,
546 | * returning null if it does not exist
547 | */
548 | public static LuaFunction getTableFunction(LuaTable luaTable, string name)
549 | {
550 | object funcObj = luaTable.rawget(name);
551 | if (funcObj is LuaFunction)
552 | return (LuaFunction)funcObj;
553 | else
554 | return null;
555 | }
556 | /*
557 | * Calls the provided function with the provided parameters
558 | */
559 | public static object callFunction(LuaFunction function, object[] args, Type[] returnTypes, object[] inArgs, int[] outArgs)
560 | {
561 | // args is the return array of arguments, inArgs is the actual array
562 | // of arguments passed to the function (with in parameters only), outArgs
563 | // has the positions of out parameters
564 | object returnValue;
565 | int iRefArgs;
566 | object[] returnValues = function.call(inArgs, returnTypes);
567 | if (returnTypes[0] == typeof(void))
568 | {
569 | returnValue = null;
570 | iRefArgs = 0;
571 | }
572 | else
573 | {
574 | returnValue = returnValues[0];
575 | iRefArgs = 1;
576 | }
577 | for (int i = 0; i < outArgs.Length; i++)
578 | {
579 | args[outArgs[i]] = returnValues[iRefArgs];
580 | iRefArgs++;
581 | }
582 | return returnValue;
583 | }
584 | }
585 | }
586 |
--------------------------------------------------------------------------------
/src/ProxyType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Reflection;
4 |
5 | namespace LuaInterface
6 | {
7 | ///
8 | /// Summary description for ProxyType.
9 | ///
10 | public class ProxyType : IReflect
11 | {
12 |
13 | Type proxy;
14 |
15 | public ProxyType(Type proxy)
16 | {
17 | this.proxy = proxy;
18 | }
19 |
20 | ///
21 | /// Provide human readable short hand for this proxy object
22 | ///
23 | ///
24 | public override string ToString()
25 | {
26 | return "ProxyType(" + UnderlyingSystemType + ")";
27 | }
28 |
29 |
30 | public Type UnderlyingSystemType
31 | {
32 | get
33 | {
34 | return proxy;
35 | }
36 | }
37 |
38 | public FieldInfo GetField(string name, BindingFlags bindingAttr)
39 | {
40 | return proxy.GetField(name, bindingAttr);
41 | }
42 |
43 | public FieldInfo[] GetFields(BindingFlags bindingAttr)
44 | {
45 | return proxy.GetFields(bindingAttr);
46 | }
47 |
48 | public MemberInfo[] GetMember(string name, BindingFlags bindingAttr)
49 | {
50 | return proxy.GetMember(name, bindingAttr);
51 | }
52 |
53 | public MemberInfo[] GetMembers(BindingFlags bindingAttr)
54 | {
55 | return proxy.GetMembers(bindingAttr);
56 | }
57 |
58 | public MethodInfo GetMethod(string name, BindingFlags bindingAttr)
59 | {
60 | return proxy.GetMethod(name, bindingAttr);
61 | }
62 |
63 | public MethodInfo GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers)
64 | {
65 | return proxy.GetMethod(name, bindingAttr, binder, types, modifiers);
66 | }
67 |
68 | public MethodInfo[] GetMethods(BindingFlags bindingAttr)
69 | {
70 | return proxy.GetMethods(bindingAttr);
71 | }
72 |
73 | public PropertyInfo GetProperty(string name, BindingFlags bindingAttr)
74 | {
75 | return proxy.GetProperty(name, bindingAttr);
76 | }
77 |
78 | public PropertyInfo GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
79 | {
80 | return proxy.GetProperty(name, bindingAttr, binder, returnType, types, modifiers);
81 | }
82 |
83 | public PropertyInfo[] GetProperties(BindingFlags bindingAttr)
84 | {
85 | return proxy.GetProperties(bindingAttr);
86 | }
87 |
88 | public object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters)
89 | {
90 | return proxy.InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters);
91 | }
92 |
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/README.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/stevedonovan/MonoLuaInterface/b923c54ccc36c7d8788ff049e9778bb8e9278668/src/README.txt
--------------------------------------------------------------------------------
/src/config.win:
--------------------------------------------------------------------------------
1 | # .NET build
2 | #LUA_INCLUDE=c:\users\steve\LuaJIT-2.0\src
3 | #LUA_LIB=c:\users\steve\LuaJIT-2.0\src\lua51.dll
4 | #CSC = csc /nologo
5 | #CC=gcc
6 | # Mono build (against 32-bit lua51.dll, note -m32
7 | LUA_INCLUDE=c:\users\steve\lua\lua-5.1.4\src
8 | LUA_LIB=c:\users\steve\lua\lua-5.1.4\src\lua51.dll
9 | CSC=mcs
10 | SHARED=-shared
11 | CC=gcc -m32
12 |
13 |
--------------------------------------------------------------------------------
/src/configure:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | function shell(cmd)
3 | local p = io.popen (cmd..' 2> /dev/null')
4 | local res = p:read()
5 | p:close()
6 | return res
7 | end
8 |
9 | function build_defines(defs)
10 | local res = {}
11 | for d in defs:gmatch '%a+' do
12 | table.insert(res,'-d:__'..d..'__')
13 | end
14 | return table.concat(res,' ')
15 | end
16 |
17 | if arg[1] == '-h' or arg[1] == '--help' then
18 | return print [[
19 | ./configure PARM1=VALUE1, ...
20 | Parameters:
21 | LUA_INCLUDE Lua include directory
22 | On Linux, we look first in /usr/include and then /usr/include/lua5.1
23 | otherwise assume ~/lua-5.1.4/src
24 | DEFINES one or more of lib,dot, embed, Windows, novs, default
25 | lib -> liblua51 (Arch)
26 | lib novs -> liblua (Fedora)
27 | lib dot -> liblua5.1 (Debian/Ubuntu)
28 | dot -> lua5.1 (LuaBinaries)
29 | default is lua51 (PUC build)
30 | Extension is .so (.dll if Windows)
31 | Use embed if luastdcall.c is compiled into your Lua shared library
32 | FLAGS debug or optimize (default optimize)
33 | ]]
34 | end
35 |
36 | for _,a in ipairs(arg) do
37 | local var,val = a:match('([^=]+)=(.+)')
38 | if var then
39 | _G[var] = val
40 | end
41 | end
42 |
43 | local csc, shared
44 | local lua_include=LUA_INCLUDE
45 | local defines=DEFINES
46 | local flags=FLAGS
47 |
48 | if not flags then
49 | flags = 'optimize'
50 | end
51 |
52 | if shell 'which gmcs' then
53 | csc = 'gmcs'
54 | elseif shell 'which mcs' then
55 | csc = 'mcs'
56 | elseif shell 'which cli-csc' then
57 | csc = 'cli-csc'
58 | else
59 | return print 'cannot find C# compiler on your path..'
60 | end
61 |
62 | if not defines then
63 | local possibilities = {
64 | ['lua51'] = 'default',
65 | ['lua5.1'] = 'dot',
66 | ['liblua51'] = 'lib',
67 | ['liblua5.1'] = 'lib dot',
68 | ['liblua'] = 'lib novs',
69 | }
70 |
71 | for lib, defs in pairs(possibilities) do
72 | local fn,err = package.loadlib(lib..'.so','luaL_newstate')
73 | if fn then
74 | defines = defs
75 | break
76 | end
77 | end
78 |
79 | if not defines then
80 | return print 'you did not have a recognized Lua shared library!'
81 | end
82 | end
83 |
84 | local plat = shell 'uname'
85 | if plat == 'Darwin' then
86 | shared = '-dynamiclib -undefined dynamic_lookup'
87 | else
88 | shared = '-shared -fpic'
89 | end
90 |
91 | lua_include = lua_include or shell 'ls /usr/include/lua.h'
92 | if not lua_include then
93 | lua_include = shell 'ls /usr/include/lua5.1/lua.h'
94 | end
95 | if not lua_include then
96 | print 'please check Lua include directory in config.inc'
97 | lua_include = os.getenv('HOME')..'/lua-5.1.4/src'
98 | else
99 | lua_include = lua_include:gsub ('/lua%.h$','')
100 | end
101 |
102 | if defines == 'default' then
103 | defines = nil
104 | end
105 |
106 | print 'writing configuration to config.inc'
107 | local f = io.open('config.inc','w')
108 | f:write('LUA_INCLUDE=',lua_include,'\n')
109 | f:write('CSC=',csc,'\n')
110 | f:write('SHARED=',shared,'\n')
111 | f:write('FLAGS=-',flags,'\n')
112 | if defines then
113 | f:write('DEFINES=',build_defines(defines),'\n')
114 | end
115 | f:close()
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/src/install:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env lua
2 | if arg[1] == '-h' then
3 | print "./install (install-dir or '~/bin') (wrapper or 'luai')"
4 | os.exit(1)
5 | end
6 |
7 | local name = arg[2] or 'luai'
8 | local install_dir = arg[1] or (os.getenv('HOME')..'/bin')
9 |
10 | function shell(cmd)
11 | local p = io.popen (cmd..' 2> /dev/null')
12 | local res = p:read()
13 | p:close()
14 | return res
15 | end
16 |
17 | if not shell('ls '..install_dir) then
18 | print "the target directory does not exist"
19 | os.exit(1)
20 | end
21 |
22 | local cwd = shell 'pwd'
23 | local uname = shell 'uname'
24 | local ld = uname == 'Darwin' and 'DYLD' or 'LD'
25 |
26 | local templ = [[
27 | #!/bin/sh
28 | LUAI=%s/bin
29 | export %s_LIBRARY_PATH=$LUAI
30 | export LUA_PATH=";;$LUAI/lua/?.lua"
31 | /usr/bin/mono $LUAI/luai.exe $*
32 | ]]
33 |
34 | local target = install_dir..'/'..name
35 | local f,err= io.open(target,'w')
36 | if not f then
37 | print ("cannot write "..target.."; you may need to be sudo")
38 | os.exit(1)
39 | end
40 | cwd = cwd:gsub ('/src$','')
41 | local wrapper = templ:format(cwd,ld)
42 | f:write(wrapper)
43 | f:close()
44 | os.execute('chmod +x '..target)
45 |
46 | print("wrapper")
47 | print(wrapper)
48 | print("written to",target)
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/src/luastdcall-unix.h:
--------------------------------------------------------------------------------
1 | #include "lua.h"
2 |
3 | /*
4 | ** stdcall C function
5 | */
6 |
7 | typedef int (*lua_stdcallCFunction) (lua_State *L);
8 |
9 | /*
10 | ** push stdcall C function
11 | */
12 | LUA_API void lua_pushstdcallcfunction(lua_State *L, lua_stdcallCFunction fn);
13 |
14 | /*
15 | ** safe tostring
16 | */
17 | LUA_API void lua_safetostring(lua_State *L,int index,char* buffer);
18 |
19 | /*
20 | ** check metatable
21 | */
22 |
23 | LUA_API int luaL_checkmetatable(lua_State *L,int index);
24 |
25 | LUA_API int luanet_tonetobject(lua_State *L,int index);
26 |
27 | LUA_API void luanet_newudata(lua_State *L,int val);
28 |
29 | LUA_API void *luanet_gettag(void);
30 |
31 | LUA_API int luanet_rawnetobj(lua_State *L,int index);
32 |
33 | LUA_API int luanet_checkudata(lua_State *L,int index,const char *meta);
34 |
--------------------------------------------------------------------------------
/src/luastdcall-windows.h:
--------------------------------------------------------------------------------
1 | #include "lua.h"
2 |
3 | #define LUA_DLLEXPORT __declspec(dllexport)
4 |
5 | /*
6 | ** stdcall C function
7 | */
8 |
9 | typedef int (__stdcall *lua_stdcallCFunction) (lua_State *L);
10 |
11 | /*
12 | ** push stdcall C function
13 | */
14 | LUA_DLLEXPORT void lua_pushstdcallcfunction(lua_State *L, lua_stdcallCFunction fn);
15 |
16 | /*
17 | ** safe tostring
18 | */
19 | LUA_DLLEXPORT void lua_safetostring(lua_State *L,int index,char* buffer);
20 |
21 | /*
22 | ** check metatable
23 | */
24 |
25 | LUA_DLLEXPORT int luaL_checkmetatable(lua_State *L,int index);
26 |
27 | LUA_DLLEXPORT int luanet_tonetobject(lua_State *L,int index);
28 |
29 | LUA_DLLEXPORT void luanet_newudata(lua_State *L,int val);
30 |
31 | LUA_DLLEXPORT void *luanet_gettag(void);
32 |
33 | LUA_DLLEXPORT int luanet_rawnetobj(lua_State *L,int index);
34 |
35 | LUA_DLLEXPORT int luanet_checkudata(lua_State *L,int index,const char *meta);
36 |
--------------------------------------------------------------------------------
/src/luastdcall.c:
--------------------------------------------------------------------------------
1 | // steffenj: replaced all occurances of LUA_DLLEXPORT with LUA_DLLEXPORT due to "macro redefinition" error
2 | // there's probably a "correct" way to solve this but right now I prefer the one that works :)
3 |
4 | #include "lua.h"
5 | #include "lualib.h"
6 | #include "lauxlib.h"
7 | #ifdef _WIN32
8 | #include "luastdcall-windows.h"
9 | #include
10 | BOOL APIENTRY DllMain(HANDLE module, DWORD reason, LPVOID reserved) { return TRUE; }
11 | #else
12 | #define LUA_DLLEXPORT
13 | #include "luastdcall-unix.h"
14 | #endif
15 | #include
16 | #include
17 |
18 | /*
19 | ** stdcall C function support
20 | */
21 |
22 | static int tag = 0;
23 |
24 |
25 | static int stdcall_closure(lua_State *L) {
26 | lua_stdcallCFunction fn = (lua_stdcallCFunction)lua_touserdata(L, lua_upvalueindex(1));
27 | return fn(L);
28 | }
29 |
30 |
31 | LUA_DLLEXPORT void lua_pushstdcallcfunction(lua_State *L,lua_stdcallCFunction fn) {
32 | lua_pushlightuserdata(L, fn);
33 | lua_pushcclosure(L, stdcall_closure, 1);
34 | }
35 |
36 |
37 |
38 | LUA_DLLEXPORT int luaL_checkmetatable(lua_State *L,int index) {
39 | int retVal=0;
40 | if(lua_getmetatable(L,index)!=0) {
41 | lua_pushlightuserdata(L,&tag);
42 | lua_rawget(L,-2);
43 | retVal=!lua_isnil(L,-1);
44 | lua_settop(L,-3);
45 | }
46 | return retVal;
47 | }
48 |
49 | LUA_DLLEXPORT void *luanet_gettag() {
50 | return &tag;
51 | }
52 |
53 |
54 | // Starting with 5.1 the auxlib version of checkudata throws an exception if the type isn't right
55 | // Instead, we want to run our own version that checks the type and just returns null for failure
56 | void *checkudata(lua_State *L, int ud, const char *tname)
57 | {
58 | void *p = lua_touserdata(L, ud);
59 |
60 | if (p != NULL) { /* value is a userdata? */
61 | if (lua_getmetatable(L, ud))
62 | {
63 | int isEqual;
64 |
65 | /* does it have a metatable? */
66 | lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */
67 |
68 | isEqual = lua_rawequal(L, -1, -2);
69 |
70 | lua_pop(L, 2); /* remove both metatables */
71 |
72 | if (isEqual) /* does it have the correct mt? */
73 | return p;
74 | }
75 | }
76 |
77 | return NULL;
78 | }
79 |
80 |
81 | LUA_DLLEXPORT int luanet_tonetobject(lua_State *L,int index) {
82 | int *udata;
83 | if(lua_type(L,index)==LUA_TUSERDATA) {
84 | if(luaL_checkmetatable(L,index)) {
85 | udata=(int*)lua_touserdata(L,index);
86 | if(udata!=NULL) return *udata;
87 | }
88 | udata=(int*)checkudata(L,index,"luaNet_class");
89 | if(udata!=NULL) return *udata;
90 | udata=(int*)checkudata(L,index,"luaNet_searchbase");
91 | if(udata!=NULL) return *udata;
92 | udata=(int*)checkudata(L,index,"luaNet_function");
93 | if(udata!=NULL) return *udata;
94 | }
95 | return -1;
96 | }
97 |
98 | LUA_DLLEXPORT void luanet_newudata(lua_State *L,int val) {
99 | int* pointer=(int*)lua_newuserdata(L,sizeof(int));
100 | *pointer=val;
101 | }
102 |
103 | LUA_DLLEXPORT int luanet_checkudata(lua_State *L,int index,const char *meta) {
104 | int *udata=(int*)checkudata(L,index,meta);
105 | if(udata!=NULL) return *udata;
106 | return -1;
107 | }
108 |
109 | LUA_DLLEXPORT int luanet_rawnetobj(lua_State *L,int index) {
110 | int *udata=lua_touserdata(L,index);
111 | if(udata!=NULL) return *udata;
112 | return -1;
113 | }
114 |
--------------------------------------------------------------------------------
/src/makefile:
--------------------------------------------------------------------------------
1 | include config.inc
2 |
3 | BINDIR=../bin
4 | ASSEMBLY=$(BINDIR)/LuaInterface.dll
5 | RUNNER=$(BINDIR)/luai.exe
6 | STUB=$(BINDIR)/luanet.so
7 |
8 | all: $(ASSEMBLY) $(STUB) $(RUNNER)
9 |
10 | ASSEMBLY_SRC = \
11 | AssemblyInfo.cs LuaException.cs LuaTable.cs \
12 | CheckType.cs LuaFunction.cs LuaUserData.cs \
13 | GenerateEventAssembly.cs LuaGlobalAttribute.cs Metatables.cs \
14 | LuaBase.cs LuaHideAttribute.cs MethodWrapper.cs \
15 | Lua.cs LuaRegistrationHelper.cs ObjectTranslator.cs \
16 | LuaDLL.cs LuaScriptException.cs ProxyType.cs
17 |
18 | $(ASSEMBLY): $(ASSEMBLY_SRC)
19 | $(CSC) $(DEFINES) $(FLAGS) -out:$(ASSEMBLY) $(DEBUG) -t:library $(ASSEMBLY_SRC)
20 |
21 | $(RUNNER): LuaNetRunner.cs
22 | $(CSC) -out:$(RUNNER) $(DEBUG) -r:$(ASSEMBLY) LuaNetRunner.cs
23 |
24 | $(STUB): luastdcall.c
25 | $(CC) $(SHARED) -o $(STUB) $(DEBUG) -I $(LUA_INCLUDE) luastdcall.c $(LUA_LIB)
26 |
27 | clean:
28 | rm $(STUB) $(ASSEMBLY) $(RUNNER)
29 |
--------------------------------------------------------------------------------
/src/makefile.win:
--------------------------------------------------------------------------------
1 | include config.win
2 |
3 | BINDIR=..\bin
4 | ASSEMBLY=$(BINDIR)\LuaInterface.dll
5 | RUNNER=$(BINDIR)\luai.exe
6 | STUB=$(BINDIR)\luanet.dll
7 |
8 | all: $(ASSEMBLY) $(STUB) $(RUNNER)
9 |
10 | ASSEMBLY_SRC = \
11 | AssemblyInfo.cs LuaException.cs LuaTable.cs \
12 | CheckType.cs LuaFunction.cs LuaUserData.cs \
13 | GenerateEventAssembly.cs LuaGlobalAttribute.cs Metatables.cs \
14 | LuaBase.cs LuaHideAttribute.cs MethodWrapper.cs \
15 | Lua.cs LuaRegistrationHelper.cs ObjectTranslator.cs \
16 | LuaDLL.cs LuaScriptException.cs ProxyType.cs
17 |
18 | $(ASSEMBLY): $(ASSEMBLY_SRC)
19 | $(CSC) /define:__Windows__ -out:$(ASSEMBLY) -t:library $(ASSEMBLY_SRC)
20 |
21 | $(RUNNER): LuaNetRunner.cs
22 | $(CSC) -out:$(RUNNER) -r:$(ASSEMBLY) LuaNetRunner.cs
23 |
24 | $(STUB): luastdcall.c
25 | $(CC) $(SHARED) -o $(STUB) -I $(LUA_INCLUDE) luastdcall.c $(LUA_LIB)
26 |
27 | clean:
28 | del $(STUB) $(ASSEMBLY) $(RUNNER)
29 |
--------------------------------------------------------------------------------
/src/rmakefile.win:
--------------------------------------------------------------------------------
1 | include config.win
2 |
3 | BINDIR=..\rbin
4 | ASSEMBLY=$(BINDIR)\LuaInterface.dll
5 | RUNNER=$(BINDIR)\luai.exe
6 | STUB=$(BINDIR)\luanet.dll
7 |
8 | all: $(ASSEMBLY) $(STUB) $(RUNNER)
9 |
10 | ASSEMBLY_SRC = \
11 | AssemblyInfo.cs LuaException.cs LuaTable.cs \
12 | CheckType.cs LuaFunction.cs LuaUserData.cs \
13 | LuaGlobalAttribute.cs Metatables.cs \
14 | LuaBase.cs LuaHideAttribute.cs MethodWrapper.cs \
15 | Lua.cs LuaRegistrationHelper.cs ObjectTranslator.cs \
16 | LuaDLL.cs LuaScriptException.cs ProxyType.cs
17 |
18 | # GenerateEventAssembly.cs
19 |
20 | $(ASSEMBLY): $(ASSEMBLY_SRC)
21 | $(CSC) /define:__Windows__ /define:__NOGEN__ -out:$(ASSEMBLY) -t:library $(ASSEMBLY_SRC)
22 |
23 | $(RUNNER): LuaNetRunner.cs
24 | $(CSC) -out:$(RUNNER) -r:$(ASSEMBLY) LuaNetRunner.cs
25 |
26 | $(STUB): luastdcall.c
27 | $(CC) $(SHARED) -o $(STUB) -I $(LUA_INCLUDE) luastdcall.c $(LUA_LIB)
28 |
29 | clean:
30 | del $(STUB) $(ASSEMBLY) $(RUNNER)
31 |
--------------------------------------------------------------------------------
/tests/CallLua.cs:
--------------------------------------------------------------------------------
1 | /*
2 | Demonstrates using the higher-level LuaInterface API
3 | */
4 |
5 | using System;
6 | using LuaInterface;
7 |
8 | // adding new Lua functions is particularly easy...
9 | public class MyClass {
10 |
11 | [LuaGlobal]
12 | public static double Sqr(double x) {
13 | return x*x;
14 | }
15 |
16 | [LuaGlobal]
17 | public static double Sum(double x, double y) {
18 | return x + y;
19 | }
20 |
21 | // can put into a particular table with a new name
22 | [LuaGlobal(Name="utils.sum",Description="sum a table of numbers")]
23 | public static double SumX(params double[] values) {
24 | double sum = 0.0;
25 | for (int i = 0; i < values.Length; i++)
26 | sum += values[i];
27 | return sum;
28 | }
29 |
30 | public static void Register(Lua L) {
31 | L.NewTable("utils");
32 | LuaRegistrationHelper.TaggedStaticMethods(L,typeof(MyClass));
33 | }
34 |
35 | }
36 |
37 | public class CSharp {
38 | public virtual string MyMethod(string s) {
39 | return s.ToUpper();
40 | }
41 |
42 | protected virtual string Protected(string s) {
43 | return s + "?";
44 | }
45 |
46 | protected virtual bool ProtectedBool() {
47 | return false;
48 | }
49 |
50 | public static string UseMe (CSharp obj, string val) {
51 | Console.WriteLine("calling protected {0} {1}",obj.Protected(val),obj.ProtectedBool());
52 | return obj.MyMethod(val);
53 | }
54 | }
55 |
56 | public class RefParms {
57 | public void Args(out int a, out int b) {
58 | a = 2;
59 | b = 3;
60 | }
61 |
62 | public int ArgsI(out int a, out int b) {
63 | a = 2;
64 | b = 3;
65 | return 1;
66 | }
67 |
68 | public void ArgsVar(params object[] obj) {
69 | int i = (int)obj[0];
70 | Console.WriteLine("cool {0}",i);
71 | }
72 |
73 | }
74 |
75 | public class CallLua {
76 |
77 | public static bool IsInteger(double x) {
78 | return Math.Ceiling(x) == x;
79 | }
80 |
81 |
82 | public static void Main(string[] args) {
83 | Lua L = new Lua();
84 |
85 | // testing out parameters and type coercion for object[] args.
86 | L["obj"] = new RefParms();
87 | dump("void,out,out",L.DoString("return obj:Args()"));
88 | dump("int,out,out",L.DoString("return obj:ArgsI()"));
89 | L.DoString("obj:ArgsVar{1}");
90 | Console.WriteLine("equals {0} {1} {2}",IsInteger(2.3),IsInteger(0),IsInteger(44));
91 | //Environment.Exit(0);
92 |
93 | object[] res = L.DoString("return 20,'hello'","tmp");
94 | Console.WriteLine("returned {0} {1}",res[0],res[1]);
95 |
96 |
97 |
98 | L.DoString("answer = 42");
99 | Console.WriteLine("answer was {0}",L["answer"]);
100 |
101 | MyClass.Register(L);
102 |
103 | L.DoString(@"
104 | print(Sqr(4))
105 | print(Sum(1.2,10))
106 | -- please note that this isn't true varargs syntax!
107 | print(utils.sum {1,5,4.2})
108 | ");
109 |
110 | L.DoString("X = {1,2,3}; Y = {fred='dog',alice='cat'}");
111 |
112 | LuaTable X = (LuaTable)L["X"];
113 | Console.WriteLine("1st {0} 2nd {1}",X[1],X[2]);
114 | // (but no Length defined: an oversight?)
115 | Console.WriteLine("X[4] was nil {0}",X[4] == null);
116 |
117 | // only do this if the table only has string keys
118 | LuaTable Y = (LuaTable)L["Y"];
119 | foreach (string s in Y.Keys)
120 | Console.WriteLine("{0}={1}",s,Y[s]);
121 |
122 | // getting and calling functions by name
123 | LuaFunction f = L.GetFunction("string.gsub");
124 | object[] ans = f.Call("here is the dog's dog","dog","cat");
125 | Console.WriteLine("results '{0}' {1}",ans[0],ans[1]);
126 |
127 | // and it's entirely possible to do these things from Lua...
128 | L["L"] = L;
129 | L.DoString(@"
130 | L:DoString 'print(1,2,3)'
131 | ");
132 |
133 | // it is also possible to override a CLR class in Lua using luanet.make_object.
134 | // This defines a proxy object which will successfully fool any C# code
135 | // receiving it.
136 | object[] R = L.DoString(@"
137 | luanet.load_assembly 'CallLua' -- load this program
138 | local CSharp = luanet.import_type 'CSharp'
139 | local T = {}
140 | function T:MyMethod(s)
141 | return s:lower()
142 | end
143 | function T:Protected(s)
144 | return s:upper()
145 | end
146 | function T:ProtectedBool()
147 | return true
148 | end
149 | luanet.make_object(T,'CSharp')
150 | print(CSharp.UseMe(T,'CoOl'))
151 | io.flush()
152 | return T
153 | ");
154 | // but it's still a table, and there's no way to cast it to CSharp from here...
155 | Console.WriteLine("type of returned value {0}",R[0].GetType());
156 |
157 |
158 | }
159 |
160 | static void dump(string msg, object[] values) {
161 | Console.WriteLine("{0}:",msg);
162 | foreach(object o in values) {
163 | if (o == null) {
164 | Console.WriteLine("\tnull");
165 | } else {
166 | Console.WriteLine("\t({0}) {1}",o.GetType(),o);
167 | }
168 | }
169 | }
170 |
171 |
172 | }
173 |
174 |
--------------------------------------------------------------------------------
/tests/Entity.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace LuaInterface.Tests
6 | {
7 | public class Entity
8 | {
9 | public event EventHandler Clicked;
10 |
11 | protected virtual void OnEntityClicked(EventArgs e)
12 | {
13 | EventHandler handler = Clicked;
14 |
15 | if (handler != null)
16 | {
17 | // Use the () operator to raise the event.
18 | handler(this, e);
19 | }
20 | }
21 |
22 | public Entity()
23 | {
24 |
25 | }
26 |
27 | public void Click()
28 | {
29 | OnEntityClicked(new EventArgs());
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/makefile:
--------------------------------------------------------------------------------
1 | include ../src/config.inc
2 |
3 | BINDIR=../bin
4 | LDPATH=LD_LIBRARY_PATH=$(BINDIR)
5 | ASSEMBLY=LuaInterface.dll
6 | TEST=TestLua.exe
7 | EX=CallLua.exe
8 |
9 | all: $(ASSEMBLY) $(TEST) $(EX) run
10 |
11 | $(TEST): TestLua.cs Entity.cs
12 | $(CSC) -r:$(ASSEMBLY) $^
13 |
14 | $(EX): CallLua.cs
15 | $(CSC) -r:$(ASSEMBLY) $^
16 |
17 | $(ASSEMBLY): $(BINDIR)/$(ASSEMBLY)
18 | cp $< $@
19 |
20 | # to run a CLR program with LuaInterface, then
21 | # 1. LuaInterface.dll must be in same dir, or be in the GAC
22 | # 2. luanet.so and (liblua5.1.so or lua51.so) must be on the shared library path.
23 | run: $(TEST)
24 | $(LDPATH) mono $(EX)
25 | $(LDPATH) mono $(TEST)
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/tests/makefile.win:
--------------------------------------------------------------------------------
1 | include ../src/config.win
2 |
3 | BINDIR=..\bin
4 | ASSEMBLY=LuaInterface.dll
5 | TEST=TestLua.exe
6 | EX=CallLua.exe
7 |
8 | all: $(ASSEMBLY) $(TEST) $(EX) run
9 |
10 | $(TEST): TestLua.cs Entity.cs
11 | $(CSC) -r:$(ASSEMBLY) $^
12 |
13 | $(EX): CallLua.cs
14 | $(CSC) -r:$(ASSEMBLY) $^
15 |
16 | $(ASSEMBLY): $(BINDIR)\$(ASSEMBLY)
17 | copy $<
18 | copy $(BINDIR)\luanet.dll
19 |
20 | run: $(TEST)
21 | $(EX)
22 | $(TEST)
23 |
24 | clean:
25 | del $(ASSEMBLY) $(TEST) $(EX) luanet.dll
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/tests/test.lua:
--------------------------------------------------------------------------------
1 | width=100
2 | height=200
3 | message="Hello World!"
4 | color={r=100,g=20,b=50}
5 | tree={branch1={leaf1=10,leaf2="leaf2"},leaf3="leaf3"}
6 |
7 | function func(x,y)
8 | return x,x+y
9 | end
10 |
--------------------------------------------------------------------------------