PROBLEM DESCRIPTION
The following code is a minimal example that replicates a problem I am having. The rFSM library is used, which can be found here: https://github.com/kmarkus/rFSM
There are three lua scripts. The "main", called runscript.lua, which initializes and runs the state machine (SM) that needs to be run, called mainTask.lua, which in turn, uses an auxiliary state machine subTask.lua.
The code flow is the following. We start inside the state machine mainTask.lua and immediately enter the Sim composite state, and then the state evaluate. There, we are calling the function evaluateData which is inside subTask.lua and set the local variable var to false. After this function call, we go to mainTask.lua again, make a transition and end up inside subTask.lua again. There we print the value of var.
Again, schematically: mainTask.lua -> subTask.lua -> mainTask.lua -> subTask.lua.
We expect the value of var to be false. However, as you can see, inside mainTask.lua, we are loading the subTask.lua twice via rfsm.load("subTask.lua"),. This results in having two instances of the auxiliary SM, but I want to have one instead.
The rfsm.load function is
function load(file)
local fsm = dofile(file)
if not is_state(fsm) then
error("rfsm.load: no valid rfsm in file '" .. tostring(file) .. "' found.")
end
return fsm
end
CODE
runscript.lua
-- Set lua path to location of rFSM library
package.path = "/home/anfr/rFSM-master/?.lua;./?.lua";
require 'rfsm';
print('[runscript.lua] Before rfsm.load("mainTask.lua")')
fsm_ = rfsm.load("mainTask.lua")
print('[runscript.lua] Before rfsm.init(fsm_)')
fsm = rfsm.init(fsm_);
print('[runscript.lua] Before rfsm.run(fsm)')
rfsm.run(fsm);
mainTask.lua
local var = true;
return rfsm.state{
Sim = rfsm.composite_state
{
evaluate = rfsm.state {
entry=function()
var = false;
if (evaluateData(var)) then
rfsm.send_events(fsm, "internal_EvaluateDone")
end
end,
},
sub = rfsm.load("subTask.lua"),
rfsm.trans {
src='initial',
tgt='evaluate',
effect=function()
print('[mainTask.lua] initial -> evaluate')
end,
},
rfsm.trans {
src='evaluate',
tgt='sub',
events={'internal_EvaluateDone'},
effect=function()
print('[mainTask.lua] evaluate -> sub with event "internal_EvaluateDone"')
end,
},
}, -- end of Sim
Seq = rfsm.composite_state
{
entry=function()
print('Entry Seq')
end,
exit=function()
print('Exit Seq')
end,
Running = rfsm.composite_state
{
entry=function()
print('Entry Running')
end,
exit=function()
print('Exit Running')
end,
--sub_2 = sub,
sub_2 = rfsm.load("subTask.lua"),
rfsm.trans {
src='initial',
tgt='sub_2',
effect=function()
print('[Seq composite state] initial -> sub_2')
end,
},
},
rfsm.trans {
src='initial',
tgt='Running',
effect=function()
print('[Seq composite state] initial -> Running')
end,
},
}, -- end of Seq
rfsm.trans {
src='initial',
tgt='Sim',
effect=function()
print('[mainTask.lua] initial -> Sim')
end,
},
};
subTask.lua
print("--- start of subTask.lua ---")
local var = true;
function evaluateData(value)
print("[subTask.lua] var before setting in evaluateData is " .. tostring(var));
var = value;
print("[subTask.lua] var after setting in evaluateData is " .. tostring(var))
return true
end
return rfsm.state {
execute = rfsm.state {
entry=function()
print('[subTask.lua] var inside execute is ' .. tostring(var))
end,
},
rfsm.trans {
src='initial',
tgt='execute',
effect=function()
print('[subTask.lua] initial -> execute')
end,
},
},
print("--- end of subTask.lua ---")
LOGS
The following logs show that the second time we enter the auxiliary SM, we use the second instance where the value of var is true (we don't want this).
[runscript.lua] Before rfsm.load("mainTask.lua")
--- start of subTask.lua ---
--- end of subTask.lua ---
--- start of subTask.lua ---
--- end of subTask.lua ---
[runscript.lua] Before rfsm.init(fsm_)
[runscript.lua] Before rfsm.run(fsm)
[mainTask.lua] initial -> Sim
[mainTask.lua] initial -> evaluate
[subTask.lua] var before setting in evaluateData is true
[subTask.lua] var after setting in evaluateData is false
[mainTask.lua] evaluate -> sub with event "internal_EvaluateDone"
[subTask.lua] initial -> execute
[subTask.lua] var inside execute is true
ATTEMPTS FOR A SOLUTION
Attempt 1
This attempt actually works in my local example (not the real system) and uses the commented line
sub_2 = sub. So the idea was to to load the state machine once, and here simply refer to that. I am wondering if the different versions of LUA have an impact on this. Locally I have Lua 5.2, on system Lua 5.1.
Edit
This attempt stops working if I simply add another dummy state inside the Seq composite state. Also there is no dependence on Lua versions.
Attempt 2
Implement a second version of load and use require instead of dofile. Then use this function in those two places inside mainTask.lua.
function load2(file)
local fileWithoutExtension = file:gsub("%.lua", "")
print(fileWithoutExtension)
local fsm = require(fileWithoutExtension)
if not is_state(fsm) then
error("rfsm.load: no valid rfsm in file '" .. tostring(file) .. "' found.")
end
return fsm
end
If I run this I get:
[runscript.lua] Before rfsm.load("mainTask.lua")
subTask
--- start of subTask.lua ---
--- end of subTask.lua ---
subTask
[runscript.lua] Before rfsm.init(fsm_)
lua: /home/anfr/rFSM-master/rfsm.lua:483: bad argument #1 to 'find' (string expected, got table)
stack traceback:
[C]: in function 'find'
/home/anfr/rFSM-master/rfsm.lua:483: in function '__resolve_path'
/home/anfr/rFSM-master/rfsm.lua:511: in function '__resolve_src'
/home/anfr/rFSM-master/rfsm.lua:551: in function 'func'
/home/anfr/rFSM-master/rfsm.lua:272: in function 'f'
/home/anfr/rFSM-master/utils.lua:246: in function 'map'
/home/anfr/rFSM-master/rfsm.lua:268: in function '__mapfsm'
/home/anfr/rFSM-master/rfsm.lua:275: in function 'f'
/home/anfr/rFSM-master/utils.lua:246: in function 'map'
/home/anfr/rFSM-master/rfsm.lua:268: in function '__mapfsm'
/home/anfr/rFSM-master/rfsm.lua:275: in function 'f'
/home/anfr/rFSM-master/utils.lua:246: in function 'map'
/home/anfr/rFSM-master/rfsm.lua:268: in function '__mapfsm'
/home/anfr/rFSM-master/rfsm.lua:283: in function 'mapfsm'
/home/anfr/rFSM-master/rfsm.lua:554: in function 'resolve_trans'
/home/anfr/rFSM-master/rfsm.lua:704: in function 'init'
runscript.lua:9: in main chunk
[C]: in ?
I don't understand why I get a table instead of a string. Unfortunately one needs to navigate in the rFSM lib code to help, but I would appreciate any hints.
Ps: Making the variable var global inside subTask.lua will give the correct behaviour. However I am trying to avoid the unnecessary overhead of loading the same script two times.
I am wondering if the different versions of LUA have an impact on this
All Lua versions have the same semantics of object references assignment.
as you can see, inside mainTask.lua, we are loading the subTask.lua twice via rfsm.load("subTask.lua")
When you use require the same state object is returned.
I don't understand why I get a table instead of a string
The function resolve_trans(fsm) converts .src fields of transitions from stings to objects (tables).
When you resolve the same transition object for the second time, the error is raised because tr.src field is expected to be a string.
Related
I'm learning game development with LÖVE2D and Lua and lately I've been using a state machine class. I haven't coded the class myself, but I've went through the code and I think I pretty much got it, besides this one problem.
The thing is, I'm trying to prompt the class for its current state, just so I can use it inside an if, but no matter what, I cannot get it right.
Here's the relevant code of the class:
StateMachine = Class{}
function StateMachine:init(states)
self.empty = {
render = function() end,
update = function() end,
enter = function() end,
exit = function() end
}
self.states = states or {} -- [name] -> [function that returns states]
self.current = self.empty
end
function StateMachine:change(stateName, enterParams)
assert(self.states[stateName]) -- state must exist!
self.current:exit()
self.current = self.states[stateName]()
self.current:enter(enterParams)
end
What I'm basically trying to do is:
function StateMachine:is(stateName)
if self.current == self.states[stateName] then
-- this never executes
return true
end
return false
end
I've tried changing self.states[stateName] to other things to test it out and also tried printing stuff to the console to see why the comparison is never true. It seems self.current returns a pointer to a table and thus never matches whatever is on the other side of the comparison operator.
Thanks for your help!
self.current is set to the return value of self.states[stateName] in StateMachine:change
function StateMachine:change(stateName, enterParams)
...
self.current = self.states[stateName]() -- note the () indicating the call
This means, unless the return value is self, self.current will not be equal to the function or object self.states[stateName] that it is compared to in StateMachine:is
function StateMachine:is(stateName)
if self.current == self.states[stateName] then -- here we are comparing the function to the return value
I would suggest expanding your state object to have a :getName function that would return the stateName or to store the name in your StateMachine under a key such as currentStateName.
I had the exact same question & I'd like to add--perhaps some of the comments explain this in language I just didn't understand :D--but in the getCurrentState function I created I had to do this:
function StateMachine:getCurrentState()
variable = self.currentStateName
return variable
where ofc variable is just some placeholder. but I had to grab the reference that self.currentStateName was pointing to, otherwise the comparison always failed.
I have a method that builds a Tree from a parent list pointer in lua.
In particular I have this lua table
parents = {2,3,13,5,12,7,11,9,10,11,12,13,14,0}
Along with two functions:
Function 1 (creates the node):
function create_node(parent, i, created, root)
if created[i] ~= nil then
return
end
print(i)
-- print(parent)
-- Create a new node and set created[i]
local new_node = Tree()
new_node.idx = i
created[i] = new_node
-- If 'i' is root, change root pointer and return
if parent[i] == 0 then
root[1] = created[i] -- root[1] denotes root of the tree
return
end
-- If parent is not created, then create parent first
if created[parent[i]] == nil then
create_node(parent, parent[i], created, root )
end
print(i)
-- Find parent pointer
local p = created[parent[i]]
print (p)
if #p.children <=2 then
print(p.idx)
print(created[i].idx)
p.add_child(created[i])
end
end
Function 2 (creates the tree recursively):
I have stopped the loop at one to test the first path from leaf to root i.e 1-2-3-13-14
function read_postorder_parent_tree(parents)
n = #parents
-- Create and array created[] to keep track
-- of created nodes, initialize all entries as None
created = {}
root = {}
for i=1, 1 do
create_node(parents, i, created, root)
end
return root[1]
end
The create_note method uses the below Tree class:
local Tree = torch.class('Tree')
function Tree:__init()
self.parent = nil
self.num_children = 0
self.children = {}
end
function Tree:add_child(c)
print(c)
c.parent = self
self.num_children = self.num_children + 1
self.children[self.num_children] = c
end
Everything works fine but when I call p.add_child(created[i]) the argument is nil why? (why c is nil?) I have already checked that created[i] and p are not nil. How can i solve this and/or why this happening?
This is the error that I get:
./Tree.lua:16: attempt to index local 'c' (a nil value)
stack traceback:
./Tree.lua:16: in function 'add_child'
main.lua:120: in function 'create_node'
main.lua:109: in function 'create_node'
main.lua:109: in function 'create_node'
main.lua:109: in function 'create_node'
main.lua:134: in function 'read_postorder_parent_tree'
main.lua:153: in function 'main'
main.lua:160: in main chunk
[C]: in function 'dofile'
...3rto/torch/install/lib/luarocks/rocks/trepl/scm-1/bin/th:150: in main chunk
[C]: at 0x00405d50
If you define a function in an object-oriented way, you must also call it in the same way.
function Tree:add_child(c)
This declares a function in an object-oriented way using the colon operator. To help you understand what that means, it can be rewritten like this:
Tree.add_child = function(self, c)
As you can see, an implicit self parameter is created to reflect the object the function was called on. However, you call the function via the standard way:
p.add_child(created[i])
Now you can see that what you really did was pass created[i] as self, not as c, which then of course happens to be nil. The standard way to call such a function is also via the colon operator:
p:add_child(created[i])
This implicitly passes p as self to the actual function, and now p will contain the actual argument.
I have this piece of code in C++ and i want to know how can i write some codes that replace switch statement in Lua because i face many problems and i need to use this statement.
int choice;
do// loop
{
cout<<"\n >>> The General Menu <<< \n";
cout << endl;
cout<< " press (1) to Add "<<endl;
cout<< " press (2) to Save "<<endl;
cout<< " press (3) to Quit " << endl;
cout<< endl;
cout<< "Enter your choice please (1/2/3): ";
cin>>choice;
switch(choice)
{
case 1:
add();
break;
case 2:
save();
break;
default:
cout<<" The program has been terminated "<<endl;
cout<<" Thank you! \n";
}
} while (choice != 3);
}
The statement has been used inside a do..while loop.
In general, if you want a switch statement in Lua, what you ought to be doing is building a table. For your simple case of choice that could be 1, 2, or fail, a simple if statement with a few conditions is sufficient. For more complex cases, a table of functions should be employed:
local c_tbl =
{
[1] = add,
[2] = save,
}
local func = c_tbl[choice]
if(func) then
func()
else
print " The program has been terminated."
print " Thank you!";
end
You can use lexical scoping to allow the functions in the table to be able to access local variables, just as if the code was written inline.
Try this one (click here to run the script in a Lua compiler), Hope the code is self-explanatory ;-) and
resembles the same pseudo code format..!!
print("enter your choice : ")
mychoice = io.read()
switch = function (choice)
-- accepts both number as well as string
choice = choice and tonumber(choice) or choice -- returns a number if the choic is a number or string.
-- Define your cases
case =
{
[1] = function ( ) -- case 1 :
print("your choice is Number 1 ") -- code block
end, -- break statement
add = function ( ) -- case 'add' :
print("your choice is string add ") -- code block
end, -- break statement
['+'] = function ( ) -- case '+' :
print("your choice is char + ") -- code block
end, -- break statement
default = function ( ) -- default case
print(" your choice is din't match any of those specified cases")
end, -- u cant exclude end hear :-P
}
-- execution section
if case[choice] then
case[choice]()
else
case["default"]()
end
end
-- Now you can use it as a regular function. Tadaaa..!!
switch(mychoice)
Lua:
if choice == 1
then add()
elseif choice == 2
then save()
else print "The program has been terminated\nThank you!"
end
one more version of switcher (without initializing table as variable):
local case=2;
local result=({[1]="case1", [2]="case2", 3="case3"})[case];
print (result); --> case2
While simply creating a table indexed by cases with functions as elements is most probably the fastest approach, there is this solution I've made which IMO has better code readability:
function switch(element)
local Table = {
["Value"] = element,
["DefaultFunction"] = nil,
["Functions"] = {}
}
Table.case = function(testElement, callback)
Table.Functions[testElement] = callback
return Table
end
Table.default = function(callback)
Table.DefaultFunction = callback
return Table
end
Table.process = function()
local Case = Table.Functions[Table.Value]
if Case then
Case()
elseif Table.DefaultFunction then
Table.DefaultFunction()
end
end
return Table
end
Example Use:
switch(Player:GetName())
.case("Kate", function() print("This player's name rhymes with Fate")end)
.case("Tod", function() print("This player's name rhymes with Cod") end)
.default(function() print("This player's name is not Kate or Tod") end)
.process()
I encountered this issue with functions that would take different parameters - something which the other answers don't handle well.
I solved that with anonymous functions.
-- call the relevant execution based on its opcode
local instructions = {
[01] = function () self:perform_add(table.unpack(valargs)) end,
[02] = function () self:perform_multiply(table.unpack(valargs)) end,
[03] = function () self:perform_store_input(outputargs[1]) end,
[04] = function () self:perform_output(valargs[1]) end,
[05] = function () self:perform_jnz(table.unpack(valargs)) end,
[06] = function () self:perform_jz(table.unpack(valargs)) end,
[07] = function () self:perform_less_than(table.unpack(valargs)) end,
[08] = function () self:perform_equals(table.unpack(valargs)) end,
[99] = function () self:perform_exit() end,
}
local instr = instructions[opcode]
if (instr) then
instr()
else
print("No instruction for opcode " .. opcode)
end
The actions I want to take in my different switch cases are all defined as anonymous functions in a table. The keys used (e.g. 08 here) are the values our variable to switch on might assume (opcode here). The default case of the switch statement happens in my else clause. There is no requirement for a break equivalent - but if you want to have one case continue with the next you would have to call it explicitly.
Reply to comment asking for clarification:
You're right that this example is not complete. You can find my usage here when I did adventofcode 2019 day 7. I can try answer your questions but I never touched lua before, and never after. valargs is a table of arguments because different functions here take different numbers of arguments. But that is not necessarily relevant to the question. Basically, I'm just calling functions here.
In my example, self exists because I defined the functions on a local (and did some weird changes as outlined here). The relevant code parts:
-- a "class"
local IntComputer = {}
function IntComputer:perform_exit()
self.program_ended = true
end
function IntComputer:perform_add(a, b, target)
print(" " .. a .. " + " .. b .. " => " .. target)
self:set_value(target, a+b)
end
If you want switch as a function that is callable, you could use something funny with the callback feature:
(The example below is a switch statement based on the variable type, but you could make the table index into whatever you want to test it for. Just change the return statement of the switch function to not test for type(case))
(This is essentially a lazy table lookup much like Python's dictionary feature but each element is a function)
#!/usr/bin/lua
-- Callback switch statement:
local function switch(a, case)
-- Local variable instead of function(a) on every case:
local value = a
-- Cases list:
local switchcase = {}
-- Cases:
switchcase["string"] = function()
return (tostring(value) .. " is a string")
end
switchcase["number"] = function()
return tostring(value .. " is a number")
end
switchcase["boolean"] = function()
return (tostring(avalue) .. " is a boolean")
end
return switchcase[type(case)](a)
end
local value = 5
print(switch(value,value)) --> 5 is a number
local value = "test"
print(switch(value,value)) --> test is a string
local value = true
print(switch(value,value)) --> true is a boolean
I don't know the performance of this code compared to the two answers given above, but using local variables ought to make it quick enough for repeated use. If you make your switch function in the global scope it could become a standard function for your project to be used.
Here's another fun method using loadstring() and a table lookup.
switch = function(cases,args)
if (cases[args] == nil) then return args else return assert(loadstring ('return ' .. cases[args]))() end
end
local case = 2
local result = switch({
[1] = "2^" .. case,
[2] = string.format("2^%i",case),
[3] = tostring(2^case)
},
case
)
print(result) --> 4
This method is somewhat dangerous to use since loadstring() is similar to Python's eval() function.
I found it ugly to write "function(x)" on every case in the examples provided by the Lua wiki. This is a neat way.
The "default" case is the "return args" part of the function.
I use this code :
while true do local tmpswitch1 = exp ; --[[ switch <exp> do ]]
if tmpswitch1 == exp1 then --[[ case <exp1> : ]]
-- do something
break
end ;if tmpswitch1 == exp2 then --[[ case <exp2> : ]]
-- do something
break
end ; --[[ default : ]]
-- do something
break ; end --[[ switch tmpswitch1 ]]
function case(i,d) return function(t) return t[i] or d end end
x='two'
r=case(x) {
one=1,
two=2,
three=3,
}
case(r,function() print "default" end) {
[1]=function() print "one" end,
[2]=function() print "two" end,
[3]=function() print "three" end,
}()
I need to create a structure. The structure must contain an array of "boolean conditions". Something like this:
function ReturnStructure ()
local structure = {
{A < 10},
{B == "smth"},
{FunctionReturnsTrueOrFalse(params)},
--...
}
return structure
end
structure = ReturnStructure()
print(structure[1][1]) -- prints true or false depending on the value of A
In fact these tables contain true or false, not conditions, because when we call function ReturnStructure and it creates a local table structure, all conditions in the fields will be executed. I want to create a structure whose fields will contain not boolean values, but something that I can execute (when I want to do it) and get a boolean value. I can achieve this by using anonymous functions:
function ReturnStructure ()
local structure = {
{function() return A < 10 end},
{function() return B == "smth" end},
{FunctionReturnsTrueOrFalse, params}, -- I don't call function in this line, a just put its adress and parameters to table.
--...
}
return structure
end
structure = ReturnStructure()
print(structure[1][1]) -- prints function: 0x109bdd0
print(structure[1][1]()) -- prints true or false. I execute condition in this string.
So, there is a code which works as I want it to, but it seems very ugly.
I want to hear some ideas on how to create a simpler and more beautiful table, without printing function () return ... in every field. I think that I should use a simple OOP implementation to create my structure as an object, but I don't know how to do it. I also will be happy to get some references to methods, implementations, articles etc., which can help me to find some ideas.
I want to hear some ideas on how to create a simpler and more beautiful table, without printing function () return ... in every field.
There aren't. If Lua had C#'s lambda syntax, you could write:
local structure = {
() => A < 10,
() => B == "smth",
() => FunctionReturnsTrueOrFalse(params),
But Lua likes to keep things small and simple, to avoid adding size and complexity to the language and its implementation, so we have one syntax for one function type.
You could store them as strings, then compile and run them later, but that's choosing form over function. You don't want to be invoking the compiler unnecessarily.
local structure = {
'A < 10',
'B == "smth"',
'FunctionReturnsTrueOrFalse(params)',
So your original solution is better. I don't particularly like the way that the first two items defer evaluating their arguments, while your third example evaluates the parameters at compile time. It would be more consistent to treat the FunctionReturnsTrueOrFalse the same
local structure = {
function() return A < 10 end,
function() return B == "smth" end,
function() return FunctionReturnsTrueOrFalse(param1) end,
This also means you don't need to put them in tables. Each is just a function you call, which simplifies the calling code as well.
If you really wanted to evaluate FunctionReturnsTrueOrFalse's arguments at compile time, I'd write a utility routine to build a closure from a function and its arguments:
local function bind(f, ...)
local args = {...}
return function() f(unpack(args)) end
end
Then use that to bind the function to its args:
local structure = {
function() return A < 10 end,
function() return B == "smth" end,
bind(FunctionReturnsTrueOrFalse, param1, param2, param3),
Then everything in your table is simply a function so you don't need special handling
function ReturnStructure ()
local structure = {
{'A < 10'},
{'B == "smth"'},
{FunctionReturnsTrueOrFalse, 'parameter'},
}
local function call_me(f, ...)
return (type(f)=='function' and f or
assert((load or loadstring)('return '..f)))(...)
end
return setmetatable({}, {
__index =
function(t,k)
if structure[k] then
return call_me((table.unpack or unpack)(structure[k]))
end
end,
__newindex = function(t,k,v) structure[k] = v end
})
end
A = 2
B = "anything"
function FunctionReturnsTrueOrFalse(par)
return #par > 5
end
structure = ReturnStructure()
print(structure[1]) -- true
print(structure[2]) -- false
print(structure[3]) -- true
structure[4] = {'1==0'}
print(structure[4]) -- false
My game engine pushes a value on to the lua stack as a parameter to a function and then invokes it using lua_pcall. The lua code will run and call additional lua functions. Eventually this lua code will invoke a C function. Is it possible for this function to retrieve the value that was originally pushed on to the stack?
Its like this:
<engine function A>
pushes parameter value X on to stack for lua
<lua func>
<lua func>
<lua func>
<engine function B>
can I extract the values X that was pushed by function A here?
Yes, with a combination of getinfo, getlocal and getupvalue you can get all that information (you can even change those values using set* functions).
Here is a fragment from MobDebug that returns stack information along with a table of locals and upvalues at each level. The variables at each level will be indexed in the same order they appear in the code (starting from parameters). For each get* function you can use their C equivalents (lua_getinfo, lua_getlocal, and lua_getupvalue), but the logic should be exactly the same.
local function stack(start)
local function vars(f)
local func = debug.getinfo(f, "f").func
local i = 1
local locals = {}
while true do
local name, value = debug.getlocal(f, i)
if not name then break end
if string.sub(name, 1, 1) ~= '(' then locals[name] = {value, tostring(value)} end
i = i + 1
end
i = 1
local ups = {}
while func and true do -- check for func as it may be nil for tail calls
local name, value = debug.getupvalue(func, i)
if not name then break end
ups[name] = {value, tostring(value)}
i = i + 1
end
return locals, ups
end
local stack = {}
for i = (start or 0), 100 do
local source = debug.getinfo(i, "Snl")
if not source then break end
table.insert(stack, {
{source.name, source.source, source.linedefined,
source.currentline, source.what, source.namewhat, source.short_src},
vars(i+1)})
if source.what == 'main' then break end
end
return stack
end