Introduction

NeoLua is an implementation of the Lua language that totally started from scratch. Currently, the implementation is on the level of Lua 5.2 (http://www.lua.org/manual/5.2/manual.html) with many parts of Lua 5.3. The goal is to follow the reference of the C-Lua implementation and combine this with the full .NET Framework support. That means it should be easy to call .NET functions/classes/interfaces/events from Lua and it should be easy to access variables and functions of Lua from a .NET language (e.g. C#, VB.NET, ...).

NeoLua is implemented in C# and uses the Dynamic Language Runtime. At the time, NeoLua has only one dependency to the .NET framework 4 and it also works under the current mono framework.

Background

The idea of NeoLua was born because I needed Lua as a scripting language in a service application. In the first release, I used LuaInterface. But it turned out that it is really hard to use LuaInterface as a bridge between .NET and C-Lua correctly.

I got a lot of memory leaks! During debugging, I discovered that I did not de-reference the Lua variables correctly and learned that to do this right is really hard.

Principles

What NeoLua is Useful For

Outsource the logic of your application into scripts

Structuring of logic

Build a dynamic configuration system, with functions and variables

As a formula parser

...

So, this could be reliable partner for your compiled .NET application or engine (e.g. Game Engines).

What I Did Not Have In Mind

Compiling libraries

Standalone applications

Advantages of NeoLua

Dynamic access between Lua script and the host application/.NET framework and vice-versa.

NeoLua is based on the DLR. So you get compiled code that is collectable and well-optimized.

It is possible to write strict scripts. Runtime speed is like e.g. C#.

It is compatible with the .NET world (e.g. C#, VB.NET, IronPython, ...).

Full and easy access to the .NET framework or your own libraries (with no stub code).

Drawbacks of NeoLua

Drawbacks of Bridges to C-lua, that are Solved with NeoLua

With C-Lua, you have to deal with two memory managers and so you have to marshal all data between these two worlds. That takes time and there are a lot of pitfalls to get memory leaks.

C-Lua interprets its own bytecode. The code is not compiled to machine code.

Hello World

To get started with NeoLua is very easy. At first, you have to add a reference to the Neo.Lua-Assembly. There are two ways to get NeoLua. First, download it from neolua.codeplex.com.
The second way is to use the nuget package.

Next, create an instance of the Neo.IronLua.Lua (called Lua-Script-Engine) and get a fresh environment to execute Lua code.

Playing with NeoLua

LuaCmd is a interactive program to test NeoLua. Check it out. Just write Lua code and execute it with a empty line.

Running Lua-Snippets

To run a small snippet, just execute it via DoChunk. Scripts can have parameters, like in example a and b. Every script can return values. The return value of scripts are always LuaResult of objects, because in Lua, it is possible to return more than one result.

Values and Types

NeoLua is not a dynamically typed language, it just looks like it is. Variables always have a type (at least System.Object).

NeoLua supports all CLR types. If there is type conversion necessary, it is done automatically. Dynamic types are also supported.

local a = "5"; -- a stringis assigned to a local variable of the type object
local b = {}; -- object assigned with an empty table
b.c = a + 8; -- the variable "a"is converted into an integer and assigned to the dynamic member of a table

A nice feature of NeoLua is strict typing. But more in a later section.

Working with Globals

The environment is a special Lua table. Set or get the variables on the environment and they are accessible in the script-code as global variables.

Methods (Host Application)

The next example defines three members.

a , b are members, they are holding an ordinary integer. And add is holding a function, but this definition is not a method. Because if you try to call the function like a method in e.g. C#, it will throw a NullReferenceException. You must always pass the table as a first parameter to it. To declare a real method, you have to call the explicit method DefineMethod. Lua does not care about the difference, but C# or VB.NET do.

Explicit Typing

A nice feature of NeoLua is its use of strict typing. That means you can give your local variables or parameters a strict type (like in C#). A big advantage of this feature is that the parser can do a lot of stuff during compile time. This will short-cut a lot of the dynamic parts they are normally in a NeoLua script (so the script should run pretty fast).

Globals and Tables cannot have typed dynamic members, they are by implementation always of the type object. One exception is the explicit declarion in a .net class that is inherited from LuaTable.

The code is not the exact code that gets executed, in reality it is a litte bit more complicated, but way more efficient (e.g. Append will only resolve once during runtime, not twice like in this example). If you are interested in how this is done, I can recommend reading the documentation of the DLR.

Same example with strict type:

// define a shortcut to a type, this line is only seen by the parser
const StringBuilder typeof clr.System.Text.StringBuilder;
// create a new instance of StringBuilder
local sb : StringBuilder = StringBuilder();
sb:Append('Hello '):Append('World!');
return sb:ToString();

The third parameter of the CompileChunk function decides if NeoLua should create a Dynamic-Function (false) or Runtime-Function (true). Dynamic functions are available for garbage collection, but they are not debuggable. They are the most efficient choice for small code blocks. A runtime function is compiled in a dynamic assembly in a dynamic type. The assembly/type/function is discarded when the script engine (Lua-Class) is disposed. Runtime-Functions are a good choice for scripts - they are big, often used and need debug information.

Lambda Support

A delegate that is generated by this function has no debug information and no environment. It is not allowed to use global variables or Lua functions/libraries in the code. Only the CLR package is useable. It is always compiled as a dynamic function.

But it is more efficient to use the member call clr.System.Console:WriteLine(). That's because NeoLua creates an instance of the LuaOverloadedMethod-Class to manage the methods behind in the example above.

This is a point you should always have in mind when you use getmember (.) on none .NET members. Classes, interfaces return LuaType. Methods/functions return LuaOverloadedMethod or LuaMethod. And events return LuaEvent.

Complex Example

This example reads Lua script files and executes them once. The example shows how to compile a script and catch exceptions and how to retrieve the stack trace. The stack trace can only be retrieved if the script is compiled with debug information. To turn this switch on, set the second parameter of CompileChunk to true.

Chg: Correction of the arithmetic (it is not full compatible to Lua, but compatible to .net)

Chg: Class part for lua table

0.8.18:

New: rewrite of table package

New: Lexer is public, now

Bug fixing

0.8.17:

Added: require

Bug fixing

0.8.12:

Bug fixing

0.8.9:

Changed: Redesign type system (LuaType, LuaMethod, LuaEvent)

Added: Strict parsing, when it is possible

Added: Operator support

Added: Metatable support

Added: More units tests

Bug fixing

0.8.2:

Add: coroutine package

Add: io package

Next Steps

In the next months, I will stabilize the language before I introduce new features. I hope I get a lot of bug reports. After this, I will investigate debugging/tracing for NeoLua, maybe with the support of the debug package.

I saw that when lua throws an exception (not always) , i can get the Information in the Stacktrace by .GetData

The Problem is that i want the info ,also when the Lua itself is sucessful.

I don't know what you mean with "concept" ,but i'm programming in c# and lua for years.(Lua more casual)

I used LuaInterface before, and there i could always access the current line of the lua source.But as i said i prefer the NeoLua approach, i don't need 100% lua compatibility,because i'm just implementing a Lua Script interface for my own Software, where except of the easy lua scripting possibilities, i mostly need own Methods/Functions written in c#.

the stack trace is only collected, if the function is compiled as a dynamic assembly (Default is dynamic method). And only dynamic assemblies can have debug information, that is defined by the .net framework.

concept = Konzept (I do not know if this works in english). I ment how to implement such a functionality, e.g. how does LuaInterface solve the problem.

The debugger looks good. May be you tie the implementation more to the script. For this is ILuaDebug:CreateChunk very usefull.

Correct, these assemblies are not part of the framework. They are only provided as source code version. That is the reason why I packed these stuff in a seperate assembly.

Thanks for the feedback.

--

If you don't understand something, I can also provide a german version of my writing. Just ask.

NeoLua - its amazingAll stars from me - thanks so much for your work !

I was blinking to Lua sometimes, but the bridges to the native functions are rotten...And than I have a Diagram-Engine (near like Visio..?!) and with simple changes to NET4.0 as target -can now create Shapes with NeoLua-Scripts and so on.- now it's Lua-Time - just play with the capabilitys of Lua.