Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create Lua function from string

Tags:

lua

I am creating functions (of x) from a string in Lua. The code I am using is

function fcreate(fs)
 return assert(loadstring("return function (x) return " .. fs.." end"))()
end

This works for globals, e.g.

u=fcreate("math.sin(x)")

does the right thing.

However, it does not seem to like local variables. So

local c=1
u=fcreate("math.sin(x)+c")

will not work because c is local.

Is this fixable?

like image 595
John Smith Avatar asked Dec 05 '22 15:12

John Smith


2 Answers

"loadstring does not compile with lexical scoping", so no, it can't see locals outside the loadstring call.


Is this fixable?

That depends. Why are you using loadstring in the first place? Lua supports closures as first class values, so I can't see from your example why you'd need loadstring.

Your example:

u = fcreate("math.sin(x)+c")

Can be rewritten without the need for loadstring or your fcreate function:

u = function(x) return math.sin(x)+c end

Which of course is the same as:

function u(x) return math.sin(x) + c end

I can see a case for loadstring if you have user-configurable expressions that you wanted to compile into some other function, but your case with the local c suggests that's not the case. Are you trying to make some kinda of home-rolled lamda syntax?

like image 136
Mud Avatar answered Jan 26 '23 01:01

Mud


Can't be done in any reasonable way. For an example of why, look at this:

function makefunction(name)
    local a = 1
    local b = 2
    local c = 3
    -- ...
    return assert(loadstring("return " .. name))
end

local a = 4
local func = makefunction("a")
print(func())

If this worked, what is printed? 1 or 4? Does it capture the variable from the place where the function was loaded, even though that function doesn't exist anymore? Or does it look it up from the place where it was called?

The first would mean that the function is lexically scoped wherever it's created. Being able to access the variable after the function has exited means that the variable would need to be promoted into an upvalue dynamically, which is not something that Lua can do at the moment. As it is now, Lua can see every access to a local variable during compilation, so it knows which variables to turn into upvalues (at a performance hit) and which to keep as locals.

The second would mean that variable accesses inside a loadstring'd function would work completely different than every other access in Lua: Lua uses lexical scoping, not dynamic scoping. It'd be a huge implementation change in Lua, and an extremely inconsistent one.

So, neither is supported. You can control the environment of a dynamically loaded function, using setfenv in Lua 5.1 or the env parameter of load(...) in Lua 5.2, but neither of those let you access local variables automatically.

like image 45
John Calsbeek Avatar answered Jan 25 '23 23:01

John Calsbeek