alright this is probably a stupid mistake but I cant find it.
I am trying to iterate over a treesitter node to find the parent node i need.
local function getParent(node)
local type_text = node:type()
print(type_text, "node type")
if type_text == "variable_declaration" then
return 1
end
print("RUNNING AGAIN?")
getParent(node:parent())
end
local outp = getParent(node_at_cursor, 0)
print(outp, "outp")
the output:
identifier node type 0
RUNNING AGAIN?
variable_list node type 1
RUNNING AGAIN?
assignment_statement node type 2
RUNNING AGAIN?
variable_declaration node type 3
nil outp
i don't understand why the return value is always nil. it clearly stops at some point, i see that from the print statements. The function enters the if block and should return 1.
thank you
You are not returning anything from the recursive call.
local function getParent(node)
local type_text = node:type()
print(type_text, "node type")
if type_text == "variable_declaration" then
return 1
end
print("RUNNING AGAIN?")
return getParent(node:parent())
end
Related
I'm trying to make a OnChange Event Listener, I thought of using coroutines to poll the value in a loop, and see if it changed, so
function Changed(Value)
local StartingValue = Value
while true do
if StartingValue ~= Value then
print(Value)
StartingValue = Value
break
end
end
end
local n = 0
local co = coroutine.wrap(function()
Changed(n)
coroutine.yield()
end)
co()
n = (n + 1)
print("Script ended")
Is the Code I thought of for now, But it gets stuck in the Coroutine.. nothing happens after co()
What's going on?
The function Changed() never returns.
At the very beginning you're assigning the Value to the StartingValue, and the break is inside of the if statement that is only executed when the values are different. But they're not because of that initial assignment. So you have the infinite loop that has no means of ending.
I have created a function that (pseudo)randomly creates a table containing numbers. I then loop this function until at least correct result is found. As soon as I've confirmed that at least one such result exists, I stop the function and return the table.
When I create tables containing small values, there are no issues. However, once the random numbers grow to the range of hundreds, the function begins to return nil, even though the table is true the line before I return it.
local sort = table.sort
local random = math.random
local aMin, aMax = 8, 12
local bMin, bMax = 200, 2000
local function compare( a, b )
return a < b
end
local function getNumbers()
local valid = false
local numbers = {}
-- Generate a random length table, containing random number values.
for i = 1, random( aMin, aMax ) do
numbers[i] = random( bMin, bMax )
end
sort( numbers, compare )
-- See if a specific sequence of numbers exist in the table.
for i = 2, #numbers do
if numbers[i-1]+1 == numbers[i] or numbers[i-1] == numbers[i] then
-- Sequence found, so stop.
valid = true
break
end
end
for i = 1, #numbers-1 do
for j = i+1, #numbers do
if numbers[j] % numbers[i] == 0 and numbers[i] ~= 1 then
valid = true
break
end
end
end
if valid then
print( "Within function:", numbers )
return numbers
else
getNumbers()
end
end
local numbers = getNumbers()
print( "Outside function:", numbers )
This function, to my understanding, is supposed to loop infinitely until I find a valid sequence. The only way that the function can even end, according to my code, is if valid is true.
Sometimes, more often than not, with large numbers the function simply outputs a nil value to the outside of the function. What is going on here?
You're just doing getNumbers() to recurse instead of return getNumbers(). This means that if the recursion gets entered, the final returned value will be nil no matter what else happens.
In the else case of the if valid then, you are not returning anything. You only return anything in the valid case. In the else case, a recursive call may return something, but then you ignore that returned value. The print you see is corresponding to the return from the recursive call; it isn't making it out the original call.
You mean to return getNumbers().
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 am trying to put together a lua script to be called from Redis (via an EVAL call) in order to return every other nth element of a sorted set (nth being the rank in the set, not the score).
There are very few online examples of Lua scripts that can be used to build upon, would anyone be able to point me in the right direction?
local function copyNOtherElements(table, interval, startpos)
local elemno = 1
local rettab = {}
for k, v in ipairs(table) do
if k >= startpos and (k - startpos) % interval == 0 then
rettab[elemno] = v
elemno = elemno + 1
end
end
return rettab
end
Sorry about formatting, typing on a phone. that's assuming the table is a 1 based array
For future readers, adding Redis into the previous answer, and a bit more efficient code to iterate the Nth elements:
local function zrange_pick(zset_key, step, start, stop)
-- The next four lines can be removed along with the start/stop params if not needed as in OP Q.
if start == nil than
start = 0
if end == nil than
end = -1
local set_by_score = redis.call('ZRANGE', zset_key, start, end)
local result = {}
for n = 1, #set_by_score, step do
table.insert(result, set_by_score[n])
end
return result
end