lua, combining strings with variables inside tables when imported from file - lua

I am having a problem with variables inside tables. this is essential since I use tables as configuration for my program.
so I have tested the following code that works:
> x = "X"
> t = {["ref"]="table with value: "..x}
> print(t["ref"])
table with value: X
> x = "Y"
> t = {["ref"]="table with value: "..x}
> print(t["ref"])
table with value: Y
it however doesn't work without the second > t = ["ref"]="table with value: "..x
now I went to implement this into my main program witch consists of two files, one witch returns the configuration table. And one file with all the functions and stuff. it looks as following
FILE A (main.lua):
testString = "test1"
print(testString)
local CONFIG = require'config'
print(CONIFG[1].test)
testString = "test2"
print(testString)
local CONFIG = require'config'
print(CONIFG[1].test)
FILE B (config.lua):
local CONFIG = {
{["test"]=[[this is a test: ]]..testString}
}
return CONFIG
now when i run file A (a.k.a. main.lua) i get the following output:
test1
this is a test: test1
test2
this is a test: test1
i can't figure out what i am doing wrong here.. i thought it had something to do with that it was a single string so i made testString a table but that gave me the same result...
(that title really seems scary.. sorry)

require, by design, caches the return value. So if you call require with the same string, it will not execute the script again. It will simply return the previously returned value.
require is for loading modules. And modules should not change their return values based on other global state.
The function you're probably looking for is dofile. This will always load and execute the file (but it has none of the path searching properties of require). Alternatively, you can use loadfile to load the file as a function, then execute that function to regenerate the table whenever you want.
Also:
I am having a problem with variables inside tables.
There are no "variables inside tables". Or at least not the way you mean. Expecting a change to a variable to affect some other value is like expecting this:
a = 5
b = a + 5
a = 10
assert(b == 15, "This will never be true.")
When an expression (whether a + 5 or "table with value: " .. x) is evaluated, it results in a value. The resulting value is in no way dependent on any value or variable from the expression that generated it.
That's why you had to regenerate the value; because values don't change just because some variable changes.

Related

LUA indexed table access via named constants

I am using LUA as embedded language on a µC project, so the ressources are limited. To save some cycles and memory I do always only indexed based table access (table[1]) instead og hash-based access (table.someMeaning = 1). This saves a lot of memory.
The clear drawback of this is approach are the magic numbers thrughtout the code.
A Cpp-like preprocessor would help here to replace the number with named-constants.
Is there a good way to achieve this?
A preprocessor in LUA itself, loading the script and editing the chunk and then loading it would be a variant, but I think this exhausts the ressources in the first place ...
So, I found a simple solution: write your own preprocessor in Lua!
It's probably the most easy thing to do.
First, define your symbols globally:
MySymbols = {
FIELD_1 = 1,
FIELD_2 = 2,
FIELD_3 = 3,
}
Then you write your preprocessing function, which basically just replace the strings from MySymbols by their value.
function Preprocess (FilenameIn, FilenameOut)
local FileIn = io.open(FilenameIn, "r")
local FileString = FileIn:read("*a")
for Name, Value in pairs(MySymbols) do
FileString = FileString:gsub(Name, Value)
end
FileIn:close()
local FileOut = io.open(FilenameOut, "w")
FileOut:write(FileString)
FileOut:close()
end
Then, if you try with this input file test.txt:
TEST FIELD_1
TEST FIELD_2
TEST FIELD_3
And call the following function:
Preprocess("test.txt", "test-out.lua")
You will get the fantastic output file:
TEST 1
TEST 2
TEST 3
I let you the joy to integrate it with your scripts/toolchain.
If you want to avoid attributing the number manually, you could just add a wonderful closure:
function MakeCounter ()
local Count = 0
return function ()
Count = Count + 1
return Count
end
end
NewField = MakeCounter()
MySymbols = {
FIELD_1 = NewField(),
FIELD_2 = NewField(),
FIELD_3 = NewField()
}

how can I do this with the variables in lua?

How can I make the 2 "print" give me true?
Code:
Config = {}
Config.option1.general = true
Config.option2.general = false
print(Config.option1.general)
print('Config.'..'option1'..'.general')
Output:
true
Config.option1.general
Excuse me for my ignorance
The objective was to create a function to which you give the option and execute a code with the variables of the corresponding list.
Just create a function that takes as input an option string, and use the string as a key into the Config table:
function getOption (opt)
return Config[opt].general
end
Then you can use the returned value however you like:
> getOption('option1')
true
> print(getOption('option1'))
true
> if (getOption('option1')) then print 'Yay!' else print 'Aw...' end
Yay!
If you want to live dangerously, you can use load to run a chunk of code from a string. Using this feature with user input is begging for security problems, though.
Just write a function that takes a string specifying the option, and use that input to fashion a string representing the chunk. The load function returns a function that has the chunk as its body, so you will need to call that returned function to get the result from the chunk:
function getOption (opt)
local cmd = 'Config.' .. opt .. '.general'
return load('return ' .. cmd)()
end
With getOption('option1'), the cmd string becomes 'Config.option1.general', and this is concatenated with 'return ' to create the chunk 'return Config.option1.general' which is passed to load. The statement load('return Config.option1.general')() calls the function returned by load, and the returned value is returned again from the getOption function.
Sample interaction:
> getOption('option1')
true
> getOption('option2')
false
the first print is collecting a variable and therefore displaying the value of this variable
the second print is already collecting a STRING. A string is a set of characters, they represent only text, and therefore that text will be displayed
for example, imagine that we have a variable test = true
if you do print(test), the value of the variable will be displayed, that is, true. Now, if you get print("test"), the "" means that we are talking about a text "test", not the variable test, so test will be displayed instead of true.
Note that in the second print, 2 dots .. are used, this is called CONCATENATION, it is when we join two or more strings, that is, two or more texts in one
For this reason there is no way you print true on the second print, because you are collecting a STRING with the name of the variable, and not the variable itself

Modify Lua Chunk Environment: Lua 5.2

It is my understanding that in Lua 5.2 that environments are stored in upvalues named _ENV. This has made it really confusing for me to modify the environment of a chunk before running it, but after loading it.
I would like to load a file with some functions and use the chunk to inject those functions into various environments. Example:
chunk = loadfile( "file" )
-- Inject chunk's definitions
chunk._ENV = someTable -- imaginary syntax
chunk( )
chunk._ENV = someOtherTable
chunk( )
Is this possible from within Lua? The only examples I can find of modifying this upvalue are with the C api (another example from C api), but I am trying to do this from within Lua. Is this possible?
Edit: I'm unsure of accepting answers using the debug library. The docs state that the functions may be slow. I'm doing this for efficiency so that entire chunks don't have to be parsed from strings (or a file, even worse) just to inject variable definitions into various environments.
Edit: Looks like this is impossible: Recreating setfenv() in Lua 5.2
Edit: I suppose the best way for me to do this is to bind a C function that can modify the environment. Though this is a much more annoying way of going about it.
Edit: I believe a more natural way to do this would be to load all chunks into separate environments. These can be "inherited" by any other environment by setting a metatable that refers to a global copy of a chunk. This does not require any upvalue modification post-load, but still allows for multiple environments with those function definitions.
The simplest way to allow a chunk to be run in different environments is to make this explicit and have it receive an environment. Adding this line at the top of the chunk achieves this:
_ENV=...
Now you can call chunk(env1) and later chunk(env2) at your pleasure.
There, no debug magic with upvalues.
Although it will be clear if your chunk contains that line, you can add it at load time, by writing a suitable reader function that first sends that line and then the contents of the file.
I do not understand why you want to avoid using the debug library, while you are happy to use a C function (neither is possible in a sandbox.)
It can be done using debug.upvaluejoin:
function newEnvForChunk(chunk, index)
local newEnv = {}
local function source() return newEnv end
debug.upvaluejoin(chunk, 1, source, 1)
if index then setmetatable(newEnv, {__index=index}) end
return newEnv
end
Now load any chunk like this:
local myChunk = load "print(x)"
It will initially inherit the enclosing _ENV. Now give it a new one:
local newEnv = newEnvForChunk(myChunk, _ENV)
and insert a value for 'x':
newEnv.x = 99
Now when you run the chunk, it should see the value for x:
myChunk()
=> 99
If you don't want to modify your chunk (per LHF's great answer) here are two alternatives:
Set up a blank environment, then dynamically change its environment to yours
function compile(code)
local meta = {}
local env = setmetatable({},meta)
return {meta=meta, f=load('return '..code, nil, nil, env)}
end
function eval(block, scope)
block.meta.__index=scope
return block.f()
end
local block = compile('a + b * c')
print(eval(block, {a=1, b=2, c=3})) --> 7
print(eval(block, {a=2, b=3, c=4})) --> 14
Set up a blank environment, and re-set its values with your own each time
function compile(code)
local env = {}
return {env=env, f=load('return '..code, nil, nil, env)}
end
function eval(block, scope)
for k,_ in pairs(block.env) do block.env[k]=nil end
for k,v in pairs(scope) do block.env[k]=v end
return block.f()
end
local block = compile('a + b * c')
print(eval(block, {a=1, b=2, c=3})) --> 7
print(eval(block, {a=2, b=3, c=4})) --> 14
Note that if micro-optimizations matter, the first option is about 2✕ as slow as the _ENV=... answer, while the second options is about 8–9✕ as slow.

Lua create multiple closure instances

I have some lua code in a file. I want to create multiple closure instances of this code, each with a different _ENV upvalue. I can use luaL_loadfile to load the file and set the first upvalue, N times with different tables, to create N instances. But wouldn't this load and compile the file N times?
The lua equivalent of what i want to do is the following, except without the loadfile
func_list = {}
for i = 1, 10 do
local new_env = {hello=i, print=print}
func_list[i] = loadfile("Code.lua", "t", new_env)
end
for i = 1, 10 do
func_list[i]()
end
------ Code.lua ------
print(hello*hello)
is there a better way to do this?
Whenever you load a string/file in Lua, what you get in return is a function to call to actually run the file. What load does for you is just some additional processing to set the _ENV.
However, nothing prevents you from setting _ENV yourself. You could do it with something like this:
-- Code.lua --
_ENV = ...
print(hello * hello)
Then, you could load/compile the file just once, and use multiple instances as such:
local code = loadfile("Code.lua")
env_list = {}
for i = 1, 10 do
local new_env = {hello=i, print=print}
code(new_env)
env_list[i] = new_env
end
If you do not want the user to write _ENV = ... in every file, you could instead load the file into a string, prepend the line yourself and use load to compile the source. But this would not work on compiled files.
Use the IO libraries to load the file into a string, and then call loadstring on it.
Alternatively, just get one chunk and then change it's env prior to executing it

How to set name for function which is in the table

For example, I have a table
table.insert( t, 1, function()
print ("rock");
end );
Is there any way to get function name from this table. I know that I can store name like a key, but what if I want to keep numeric index and also I want to know function name?
Is there any way to do it?
Thanks, on advance.
Say you have this code:
t = {}
x = 5
table.insert(t, 1, x)
t would then be {[1] = 5}. "5" is just a number - it has no name, and isn't associated with the variable "x"; it's a value.
In Lua, functions are treated exactly the same way, as values:
t = {}
x = function() print("test! :D") end
table.insert(t, 1, x)
The value of x is not associated with x in any way, shape, or form. If you want to manually name a function, you can do it by wrapping the function in a table, for example:
t = {}
x = function() print("test! :D") end
table.insert(t, 1, {
name = "MyFunctionName",
func = x
})
That is how you would do it!
...unless..
..you break the rules!
When Lua was developed, the developers realised that the anonymous nature of functions would make productive error messages difficult to produce, if not impossible.
The best thing you'd see would be:
stdin: some error!
stdin: in function 'unknown'
stdin: in function 'unknown'
So, they made it so that when Lua code was parsed, it would record some debug information, to make life easier. To access this information from Lua itself, the debug library is provided.
Be very careful with functions in this library.
You should exert care when using this library. The functions provided here should be used exclusively for debugging and similar tasks, such as profiling. Please resist the temptation to use them as a usual programming tool: they can be very slow. Moreover, several of these functions violate some assumptions about Lua code (e.g., that variables local to a function cannot be accessed from outside or that userdata metatables cannot be changed by Lua code) and therefore can compromise otherwise secure code.
To achieve your desired effect, you must use the debug.getinfo function; an example:
x = function()
print("test!")
print(debug.getinfo(1, "n").name)
end
x() -- prints "test!" followed by "x"
Unfortunately, the form of debug.getinfo that operates directly on a function doesn't fill the name argument (debug.getinfo(x, "n").name == nil) and the version above requires you to run the function.
It seems hopeless!
...unless..
..you really break the rules.
The debug.sethook function allows you to interrupt running Lua code at certain events, and even change things while it's all happening. This, combined with coroutines, allows you to do some interestingly hacky stuff.
Here is an implementation of debug.getfuncname:
function debug.getfuncname(f)
--[[If name found, returns
name source line
If name not found, returns
nil source line
If error, returns
nil nil error
]]
if type(f) == "function" then
local info = debug.getinfo(f, "S")
if not info or not info.what then
return nil, nil, "Invalid function"
elseif info.what == "C" then
-- cannot be called on C functions, as they would execute!
return nil, nil, "C function"
end
--[[Deep magic, look away!]]
local co = coroutine.create(f)
local name, source, linedefined
debug.sethook(co, function(event, line)
local info = debug.getinfo(2, "Sn")
name = info.namewhat ~= "" and info.name or nil
source, linedefined = info.short_src, info.linedefined
coroutine.yield() -- prevent function from executing code
end, "c")
coroutine.resume(co)
return name, source, linedefined
end
return nil, nil, "Not a function"
end
Example usage:
function test()
print("If this prints, stuff went really wrong!")
end
print("Name = ", debug.getfuncname(test))
This function isn't very reliable - it works sometimes, and doesn't others. The debug library is very touchy, so it's to be expected.
Note that you should never use this for actual release code! Only for debugging!
The most extreme case that is still acceptable is logging errors on piece of released software, to help the developer fix issues. No vital code should depend on functions from the debug library.
Good luck!
The function hasn't got any name. If you want you can assign it to a named variable:
theFunction = t[1]
-- Call it:
theFunction()
If what you want is storing a named function to the table, define it beforehand and use its name to store it:
theFunction = function()
print ("rock");
end
table.insert(t, 1, theFunction)
If this is not what you meant, give more details; for example how you would like to access the function. You're question is a bit misty.
The thing is table.insert considers the table as a sequence, only with numeric keys.
If you want to be able to call the function as t.fun() you'll have to use the table as an associative array and hence use a string as key. (BTW any type except nil or NaN are allowed as key)
t={}
t['MyFun']=function print'foo' end
t.myFun() -- uses syntactic sugar for string keys that are valid identifiers.
You might also notice that functions are passed by reference. So all functions are actually anonymous, and are just stored as a value to a certain key or variable.
You can store the names in a separate table.
functions = {}
functionNames = {}
function addFunction(f, name)
table.insert(functions, f)
functionNames[name] = f
end
To get the function, you can use the index. Once you have the function, you can get its name from function_names:
f = functions[3]
name = functionNames[f]
Good luck!

Resources