Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get name of argument of function in lua

Tags:

lua

When call a lua function like

PrintMe(MyVariableName)

I would like to be able to actually print "MyVariableName" and not it's value(well, for demo purposes).

Obviously I could just pass the string but that requires extra quotes and I also would like to print it's value.

e.g.,

MyVariable = 4
PrintVariable(MyVariable)

Would print "MyVariable is 4" or whatever

I do not want to have to duplicate the name and variable like

PrintVariable(MyVariable, "MyVariable")

as this is unnecessary duplication.

Can lua handle it?

What I'm doing now is passing the variable name in quotes and using loadstring to get the value but I would like to just pass the variable directly without the extra unnecessary quotes(which I thought debug.getlocal did but it ends up returning the value instead of the name).


Here is mock example

function printme1(var, val)
    print(var.." = "..val)
end

function printme2(v)
    local r
    loadstring("r = "..v)() -- equivalent to r = a but must be used since v is a string representing a and not the object a
    print(v.." = "..tostring(r))
end

function printme3(v)
    -- unknown
end

a = 3

printme1("a", a)
printme2("a")
printme3(a) 

In this case all 3 should print the same thing. printme3 obviously is the most convenient.

like image 835
Uiy Avatar asked Sep 16 '25 05:09

Uiy


1 Answers

You can't say PrintVariable(MyVariable), because Lua gives you no way of determining which variable (if any; a constant could have been used) was used to pass an argument to your function. However, you can say PrintVariable('MyVariable') then used the debug API to look for a local variable in the caller's scope which has that name:

function PrintVariable(name)
  -- default to showing the global with that name, if any
  local value = _G[name]

  -- see if we can find a local in the caller's scope with that name
  for i=1,math.huge do
    local localname, localvalue = debug.getlocal(2,i,1)
    if not localname then
      break -- no more locals to check
    elseif localname == name then
      value = localvalue
    end
  end

  if value then
    print(string.format("%s = %s", name, tostring(value)))
  else
    print(string.format("No variable named '%s' found.", name))
  end
end

Now you can say:

PrintVariable('MyVariable')

While in this case will print "MyVariable = 4".


Not, if you really want to do this without the quotes, you could check the caller's locals for variables that have a supplied value, but that's occasionally going to give you the wrong variable name if there is more than one variable in the caller's scope with a given value. With that said, here's how you'd do that:

function PrintVariable(value)
  local name

  -- see if we can find a local in the caller's scope with the given value
  for i=1,math.huge do
    local localname, localvalue = debug.getlocal(2,i,1)
    if not localname then
      break
    elseif localvalue == value then
      name = localname
    end
  end

  -- if we couldn't find a local, check globals
  if not name then
    for globalname, globalvalue in pairs(_G) do
      if globalvalue == value then
        name = globalname
      end
    end
  end

  if name then
    print(string.format("%s = %s", name, tostring(value)))
  else
    print(string.format("No variable found for the value '%s'.", tostring(value)))
  end
end

Now you can say PrintVariable(MyVariable), but if there happened to be another variable in the caller's scope with the value 4, and it occurred before MyVariable, it's that variable name that will be printed.

like image 190
Mud Avatar answered Sep 19 '25 16:09

Mud