can I return from a function a table (or a collection) of the local variables?

Jun 16, 2014 at 5:08 PM
So giving the script:
function f(p1, p2)
    local l1 = p1.Height + p2.Length
    return t
Where t contains p1, p2, l1 values

is there a way to retrieve t or something similar?
Jun 16, 2014 at 8:39 PM
Do you something like this:
function t()
  return {
    p1 = 1,
    p2 = 2,
    f = function f(self)
      self.l = self.p1 + self.p2; 
I am not clear what you want to accomplish?
Jun 16, 2014 at 9:30 PM
I am writing a tiny IDE that I embed into an app. NeoLua works wonders, but I need breakpoints

So I added a function called Break( ), that basically takes the global and put it on a property grid (this is winforms), and then loop DoEvents() while looking for a flag setted by the "Continue"

I though if I could add to the property grid the local variables list it will be more helpful
Jun 16, 2014 at 9:57 PM
Do you want to share the code/project?

Why I asked: at the time I try to figure out how is the best way the debug the scripts. Currently, I am experimenting with trace debugging, that is what you are looking for. A drawback is a big performance loss, but I thing that is okay for the expected result.
May be it helps you, when I force this part a little bit to give a good base for your editor. It is a lot of work to do, and also on the UI site.
Jun 17, 2014 at 2:21 PM
No problem, but you will be disappointed, no big magic here

I have basically 2 buttons in the form: tsbCompile, tsbStop.

Button 1: tsbCompile, and this is the code in the click event
            try {
                if ( _debugStop ) {
                    _debugStop = false;
                _debugStop = false;
                _abortScript = false;
                tsbStop.Enabled = false;
                tsbCompile.Enabled = false;
                tsbCompile.Text = "Run";
                try {
                    Program.Compiler.CompileScript( fctbLua.Text, txtFunctionName.Text, AddToOutput, BreakPoint );
                catch ( AbortScriptException ab ) { }
                catch ( Exception ex ) {
                    MessageBox.Show( "Error: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Information );
            finally {
                pgGlobal.SelectedObject = null;
                tsbStop.Enabled = false;
                tsbCompile.Enabled = true;
                tsbCompile.Text = "Run";
The exception is defined very simple
        class AbortScriptException : Exception { }
pgGlobal is the Property Grid that shows the global environment
fctbLua is the Fast Colored Text Box from this article: (notice that recently I asked the author to add Lua highlighting, and he generously agree... but the highlight does not include your extensions like the foreach, but is open source, so eventyally I'll grab the source and add it)

The click for the tsbStop looks like this:
        private void tsbStop_Click( object sender, EventArgs e ) {
            _abortScript = true;
AddToOutput and Breakpoint are these methods, where txtOutput is just a multiline text box, _debugStop and _abortScript are just flags:
        void AddToOutput( object message ) {

            var objType = message.GetType( ).Name;

            var stringCalculated = message.ToString( );
            if ( objType == "String" ) stringCalculated = message as string;

            txtOutput.SelectionStart = txtOutput.Text.Length;
            txtOutput.SelectionLength = 0;
            txtOutput.AppendText( stringCalculated + "\r\n" );
            txtOutput.SelectionStart = txtOutput.Text.Length;
            txtOutput.SelectionLength = 0;
            txtOutput.ScrollToCaret( );
            Application.DoEvents( );


        void BreakPoint( LuaGlobal global ) {
            pgGlobal.SelectedObject = global;
            _debugStop = true;
            tsbCompile.Enabled = true;
            tsbCompile.Text = "Continue";
            tsbStop.Enabled = true;

            while ( _debugStop ) {
                Application.DoEvents( );
                if ( _abortScript ) throw new AbortScriptException( );

            tsbStop.Enabled = false;
            tsbCompile.Enabled = false;
            tsbCompile.Text = "Run";
            Application.DoEvents( );
The CompileScript looks like this:
        public void CompileScript( string scriptText, string functionName, Scenario scenario, Action<object> message, Action<LuaGlobal> breakFunction ) {
            using ( var lua = new Lua( ) ) {

                var environment = lua.CreateEnvironment();
                environment.RegisterFunction( "Write", message );
                environment.RegisterFunction( "Break", new Action( ( ) => breakFunction( environment ) ) );
                environment.DoChunk( scriptText, "lua script" );

                var funcDelegate = environment[ functionName ] as Func<object, LuaResult>;
                var result = funcDelegate( scenario );

So in the script, I use write instead of print (I didn't want to mess up with your implementation), and Break() will jump to the Breakpoint function where it will look using DoEvents until clicking on the buttons make one of the flags change

So my though was if an call to the breakFunction I can capture somehow the local variables in the script, then I can show them too in the property grid. And if I cannot, then I can add another global function AddToWatch that pass the variable name and the variable it self, and on the C# side keep them in a dictionary for display later

What do you mean with Trace debugging?

Have you look into this?
Jun 17, 2014 at 6:14 PM
Thank you, for your long explaination. Now, I understand what you want to do. Good job.

Some hints:
  1. Do not always recreate the Lua-class. Because, it holds a lot of cached stuff, that was hard to build (reflection cache, type cache, ...). One, should be for your application enough.
  2. It is also possible to override the LuaGlobal, to create a write or break function. If you override the OnPrint you also will not interfere with my implementations.
  3. Yes. This is what I am currently doing. I hope, that a will be done in a cuple of months.
And now the bad news:
At the time there is no easy way for you to get access to the locals. Because, the code is not interpreted it is compiled, and you have to retrieve the values from stack. Without compiler magic is the no easy way.

I hope you are patient.

Because, the trace debugging is what you are looking for, but I have to integrate it in the language. And currently I am a little bit busy with a project on work, and I have no time for a debugging feature. So it will take a while (time see point 3).

A work around might be:

Redefine break (example for override LuaGlobal):
private void LuaBreak(LuaTable t)
And write in the script:
local a = 2;
local b = 1;
break{"a" = a, "b" = b}
Jun 17, 2014 at 6:27 PM
That is what I had in mind. I just wanted to separate the concepts, one thing is to introduce a break point, and another is to watch a variable, so instead of passing the variables as arguments to the break, I would add another function "Watch" that collect a reference to the variables to watch. Since the code is compiled, I still can get a reference. In the script will look like
local a = 2;
local b = 1;
I was also thinking to add an optional parameter to break with the line number so they are "soft" breaks, in other words the editor could have a list of the lines where there is an actual break point, and the function that implements break can decide if it hit a real brreak point and stop or to skip it. This will also allow for "live" follow up. There would be 2 scripts, the one that the user see, and before passing to dochunk one that has a break call in each line. By injecting a break in each line, the debug version of the script will be fully traceable step by step

What is the advantage between overriding LuaGlobal and add a LuaMember vs. just RegisterFunction?
Jun 17, 2014 at 9:21 PM
Your are describing a trace debugger. That is on what I am currently working.
But you will run in the problem, that there is not a concept of references in lua. So, it is not possible to watch a local variable.

I try to speed up my plan and give some early binaries to you. It makes no sense for you to follow your solution, if you can get something out of the box. The best is, that you only need one script, and you just have to turn on/off the debug flag. If you want I can send you the current dll, but this one is not for public or distribution?

LuaMember is late bound and second it is possible to override the value in the script.
Assign print a new function and call it. Then set print to nil and call it again ;).
Jun 18, 2014 at 6:44 AM
Edited Jun 18, 2014 at 6:44 AM
@NeoLithos : I'm interested in this feature of debugging LUA script. If you want, I can test the DLL.

@jorgeleo : In your script, What is variable txtFunctionName.Text? What is it? ( => var result = funcDelegate( scenario );). Fast Colored Text Box is a great control! I didn't know. I will use it in my project with NeoLua. Thanks.
Jun 18, 2014 at 1:44 PM
@NeoLithos : Thank you, but if it is alpha code, I would rather have the code and compile my self. In that way I might be able to help you with bugs or ideas

@PapyRef : txtFunctionName is a text box where the user can type the function they want to execute on the script, it is passed into CompileScript as functionName. The function (in my particular case) might need different parameters, but it allows me to test different parts f the script. Fast Colored Text Box is a great control, I added the language extensions to the control locally, incase that you want this version, I can send you the code and the dll
Jun 18, 2014 at 5:07 PM
Yep, I'm interested by your language extensions for the the Fast Colored Text Box control. You can send me the code.
Jun 18, 2014 at 11:40 PM
Okay, after my short vacation I will start a new branch for the debugging experiment. I have a lot ideas.

I will post the progress in this discussion.
Jun 19, 2014 at 3:30 AM
Another question, kind of belongs here... Do you create an AST? If so can it be accessible? Thinking on ast based syntax highlighting, refactoring like variable rename, etc
Jun 19, 2014 at 10:15 AM
I do not create the parse AST. I create the compile AST, because I optimize and wrap down during the parsing.
  1. I tried for an outer project to combine the AST for parse and the AST for the editor. It is possible, but hard to implement and ends up in a slow parse process. That is ok for compiled languages, but for such a "chunk"-language it will be to slow.
  2. The Lua-Parser stops on the first error. That is not okay (totale scheiße) for syntax-highlighting.
  3. I can give access to the lexer. But for the parser the impact is to high. And I also noticed in a outer language (I support), that you do not need to understand the whole code, for e.g. intellisense or refectoring. I ended up to write a optimized parser for each task. A general propose parser is always a compromise.
  4. I also planning a plugin for vs, to have a nice view on the code.
Jun 20, 2014 at 5:24 PM
Edited Jun 21, 2014 at 3:43 PM
Got you.

Do you have the Lua syntax with your extensions in a Backus-Naur form or similar?
  1. Yes, i agree it would be slow, but both don't need to happen at the same time
  2. Parse recovery points, that is something that cocor would give us
  3. I would write then a separate parser based on the same grammar file, so it does not interfere with your work
  4. Now that gets interesting, if lua can be used with vs shell so it can integrate with other programs like vba editor integrates with office
Jun 23, 2014 at 10:14 PM
Not exactly, but in the documentation there are some snippets they might help you.
If you see commons our something else that will help, let me know. I do not like to have two implementations of the same task, but in this case I do not see any other solution.
Jun 24, 2014 at 7:47 PM
At the bottom there is the document with the extended BNF syntax... I can add the operator priority and your extensions. Thank you
Jun 24, 2014 at 9:26 PM
Edited Jun 24, 2014 at 9:27 PM
You mean the BNF in the Lua-Documentation? I also changed the handling of the prefixes. But, I did this in the code not in a BNF.

So, I also have to figure it out ;). Like you. If you want I can reread your results.
Jul 10, 2014 at 10:28 PM
The version with the traceline debugger will take a little bit longer. Sry, I am currently a little bit busy.

But I will not forget it.