Lua round-trip?

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Lua round-trip?

Marc Lepage
Hi, suppose I have a file containing data like:

return {

    {
        name='foo',
        val=42,
        onA = function(x)
            return doSomething(x)
        end,
    },

    {
        name='bar',
        val=123,
        onA = function(x)
            return doSomethingElse(x)
        end,
        onB = function(x)
            return doAnotherThing(x)
        end,
    },

}


I want to read in the file, manipulate some of the members (like name, val), and then write it out again. But I want to preserve the functions (onA, onB) as they are.

Any tips for how to do this?

I guess I can easily write out the data structures and known members by just writing them out (since I know them) and then try to grab the raw text of the functions from the original input file and write that out in the appropriate place. Is that a good idea? Maybe the debug library can help?

Suggestions?
Reply | Threaded
Open this post in threaded view
|

Re: Lua round-trip?

Enrico Colombini
On 08/11/2013 17.29, Marc Lepage wrote:
> I want to read in the file, manipulate some of the members (like name,
> val), and then write it out again. But I want to preserve the functions
> (onA, onB) as they are.
>
> Any tips for how to do this?

You could do text substitutions on the source file, e.g. with
string.gsub, rather than (or in addition to) loading it.

--
   Enrico

Reply | Threaded
Open this post in threaded view
|

Re: Lua round-trip?

Thijs Schreijer
In reply to this post by Marc Lepage
If you retain the original code block, you could append code that replaces the values you need updated before returning it.

But I don't know whether it's acceptable for your usecase

Thijs



-------- Oorspronkelijk bericht --------
Van: Marc Lepage <[hidden email]>
Datum:
Aan: Lua mailing list <[hidden email]>
Onderwerp: Lua round-trip?


Hi, suppose I have a file containing data like:

return {

    {
        name='foo',
        val=42,
        onA = function(x)
            return doSomething(x)
        end,
    },

    {
        name='bar',
        val=123,
        onA = function(x)
            return doSomethingElse(x)
        end,
        onB = function(x)
            return doAnotherThing(x)
        end,
    },

}


I want to read in the file, manipulate some of the members (like name, val), and then write it out again. But I want to preserve the functions (onA, onB) as they are.

Any tips for how to do this?

I guess I can easily write out the data structures and known members by just writing them out (since I know them) and then try to grab the raw text of the functions from the original input file and write that out in the appropriate place. Is that a good idea? Maybe the debug library can help?

Suggestions?
Reply | Threaded
Open this post in threaded view
|

Re: Lua round-trip?

Paul E. Merrell, J.D.
In reply to this post by Marc Lepage
On Fri, Nov 8, 2013 at 8:29 AM, Marc Lepage <[hidden email]> wrote:

> I want to read in the file, manipulate some of the members (like name, val),
> and then write it out again. But I want to preserve the functions (onA, onB)
> as they are.
>
> Any tips for how to do this?
>
> I guess I can easily write out the data structures and known members by just
> writing them out (since I know them) and then try to grab the raw text of
> the functions from the original input file and write that out in the
> appropriate place. Is that a good idea? Maybe the debug library can help?

I may be misunderstanding what you're after, but if you rewrite your
script so that each part you want to keep unchanged is assigned to its
own variable in long string format, e.g.,

local bas = [[
onA = function(x)
            return doSomething(x)
        end]]

... in Lua 5.2 you can execute the value stored in bas using load.

And you'd still have the variable name and its value to concatenate
into the string for the new file unchanged.

I'm not certain how to do this in Lua 5.1; I recall that load's
behavior was changed somewhat in 5.2.

Paul

--
[Notice not included in the above original message:  The U.S. National
Security Agency neither confirms nor denies that it intercepted this
message.]

Reply | Threaded
Open this post in threaded view
|

Re: Lua round-trip?

Marc Lepage
Thanks guys.

Another approach I could do is to require some kind of comment demarcation on the extra parts, so they can be preserved. It's just I'd like to avoid that if possible.

What I've got is a description of things with properties and handlers, I want to load it in my editor (I'm writing), edit the properties, and save it back, but keep the handlers (which are functions).

I'm going to take a crack at some kind of solution this weekend, so keep the ideas flowing.


On Fri, Nov 8, 2013 at 1:03 PM, Paul Merrell <[hidden email]> wrote:
On Fri, Nov 8, 2013 at 8:29 AM, Marc Lepage <[hidden email]> wrote:

> I want to read in the file, manipulate some of the members (like name, val),
> and then write it out again. But I want to preserve the functions (onA, onB)
> as they are.
>
> Any tips for how to do this?
>
> I guess I can easily write out the data structures and known members by just
> writing them out (since I know them) and then try to grab the raw text of
> the functions from the original input file and write that out in the
> appropriate place. Is that a good idea? Maybe the debug library can help?

I may be misunderstanding what you're after, but if you rewrite your
script so that each part you want to keep unchanged is assigned to its
own variable in long string format, e.g.,

local bas = [[
onA = function(x)
            return doSomething(x)
        end]]

... in Lua 5.2 you can execute the value stored in bas using load.

And you'd still have the variable name and its value to concatenate
into the string for the new file unchanged.

I'm not certain how to do this in Lua 5.1; I recall that load's
behavior was changed somewhat in 5.2.

Paul

--
[Notice not included in the above original message:  The U.S. National
Security Agency neither confirms nor denies that it intercepted this
message.]


Reply | Threaded
Open this post in threaded view
|

Re: Lua round-trip?

Paul E. Merrell, J.D.
On Fri, Nov 8, 2013 at 11:13 AM, Marc Lepage <[hidden email]> wrote:

> I'm going to take a crack at some kind of solution this weekend, so keep the
> ideas flowing.

I misunderstood and thought you wanted to create a new file each time.
Given that you're writing back to the same file, you could park the
functions in a library file and load the functions using dofile.

Paul


--
[Notice not included in the above original message:  The U.S. National
Security Agency neither confirms nor denies that it intercepted this
message.]

Reply | Threaded
Open this post in threaded view
|

Re: Lua round-trip?

Marc Lepage
OK I looked more closely at the debug API and ran an experiment.

If I have this:

return {

    {
        name='foo',
        val=42,
        onA = function(x)
            return doSomething(x)
        end,
    },

    {
        name='bar',
        val=123,
        onA = function(x)
            return doSomethingElse(x)
        end,
        onB = function(x)
            return doAnotherThing(x)
        end,
    },

}

Then if I store the result in t, and I use debug.getinfo(t[1].onA, 'L'), I get info.activelines containing keys which are the "valid" lines of the function. In this case, they are the two lines containing "return doSomething(x)" and "end,".

If I make the assumption that the first line of the function immediately precedes, then I can tell which are the original source file lines containing the function. I can use those to recover the source code for each function.

I think this would be good enough for my needs.

However, if I provide flag 'S' I get fields 'lastlinedefined' ("end,") and 'linedefined' ("onA = function(x)") which is perfect.

'S' also has fields 'source' and 'short_src' which I thought might contain the actual source code of the function, but they just have the name of the file. Otherwise that would be even more convenient.

So the solution is to use 'S' to get the first and last defined line number for each handler function, then extract them from the original source file when round-tripping.

Thanks!


On Fri, Nov 8, 2013 at 6:39 PM, Paul Merrell <[hidden email]> wrote:
On Fri, Nov 8, 2013 at 11:13 AM, Marc Lepage <[hidden email]> wrote:

> I'm going to take a crack at some kind of solution this weekend, so keep the
> ideas flowing.

I misunderstood and thought you wanted to create a new file each time.
Given that you're writing back to the same file, you could park the
functions in a library file and load the functions using dofile.

Paul


--
[Notice not included in the above original message:  The U.S. National
Security Agency neither confirms nor denies that it intercepted this
message.]


Reply | Threaded
Open this post in threaded view
|

Re: Lua round-trip?

Thijs Schreijer
I think that if you use loadstring then source will actually contain the source code.  See http://www.lua.org/pil/23.1.html 

Not sure though whether it is only that function or the full block passed to loadstring.

Thijs



-------- Oorspronkelijk bericht --------
Van: Marc Lepage <[hidden email]>
Datum:
Aan: Lua mailing list <[hidden email]>
Onderwerp: Re: Lua round-trip?


OK I looked more closely at the debug API and ran an experiment.

If I have this:

return {

    {
        name='foo',
        val=42,
        onA = function(x)
            return doSomething(x)
        end,
    },

    {
        name='bar',
        val=123,
        onA = function(x)
            return doSomethingElse(x)
        end,
        onB = function(x)
            return doAnotherThing(x)
        end,
    },

}

Then if I store the result in t, and I use debug.getinfo(t[1].onA, 'L'), I get info.activelines containing keys which are the "valid" lines of the function. In this case, they are the two lines containing "return doSomething(x)" and "end,".

If I make the assumption that the first line of the function immediately precedes, then I can tell which are the original source file lines containing the function. I can use those to recover the source code for each function.

I think this would be good enough for my needs.

However, if I provide flag 'S' I get fields 'lastlinedefined' ("end,") and 'linedefined' ("onA = function(x)") which is perfect.

'S' also has fields 'source' and 'short_src' which I thought might contain the actual source code of the function, but they just have the name of the file. Otherwise that would be even more convenient.

So the solution is to use 'S' to get the first and last defined line number for each handler function, then extract them from the original source file when round-tripping.

Thanks!


On Fri, Nov 8, 2013 at 6:39 PM, Paul Merrell <[hidden email]> wrote:
On Fri, Nov 8, 2013 at 11:13 AM, Marc Lepage <[hidden email]> wrote:

> I'm going to take a crack at some kind of solution this weekend, so keep the
> ideas flowing.

I misunderstood and thought you wanted to create a new file each time.
Given that you're writing back to the same file, you could park the
functions in a library file and load the functions using dofile.

Paul


--
[Notice not included in the above original message:  The U.S. National
Security Agency neither confirms nor denies that it intercepted this
message.]


Reply | Threaded
Open this post in threaded view
|

Re: Lua round-trip?

Pierre-Yves Gérardy
In reply to this post by Marc Lepage
Another option would be to use dependency injection. Rather than
returning a table, return a function:

    -- file:data.lua
    return function (functions)
        return {

            {
                name='foo',
                val=42,
                onA = functions.onA1,
            },

            {
                name='bar',
                val=123,
                onA = functions.onA2,
                onB = functions.onB2,
            },

        }
    end

in another file, you'll keep the functions in a corresponding table,
and pass it to the return value of

   -- file:functions.lua
    return {onA1 = function()end, onA2=function()end, ...}

then

    -- file:main.lua
    local funcs = require"functions"
    local data1 = require"data"(funcs)
    -- modify data.lua, remove data from package.loaded (or use dofile
instead of require, in whch case you don't need to clean up the package cache)
    local data2 = dofile"data"(funcs)

Another approach (a bit cleaner if you don't use require) :

    -- file:data-bis.lua
    local functions = ... -- a chunk is actually a vararg function.
    return {

        {
            name='foo',
            val=42,
            onA = onA1,
        },

        {
            name='bar',
            val=123,
            onA = onA2,
            onB = onB,
        },

    }

    -- file:main-bis.lua
    functions = require"functions"
    data = loadfile"data-bis.lua"(functions)
    -- etc...

Maybe this would fit your use case?

-- Pierre-Yves