3

I want to search for all function calls in a Lua file using python. for example, I have this Lua code:

function displayText (text)
    print(text)
end

sendGreetings = function(sender, reciever) 
    print("Hi " ..reciever.. " greetings from " ..sender.. "!")
end

displayText("Hello, World!")

sendGreetings("Roger", "Michael")

I want my python code to search for function calls in that code and returns a dictionary with the function name and parameters, so the output should be like this:

# {function_name: [param1, param2]}
{"displayText": ["Hello, World!"], "sendGreetings": ["Roger", "Michael"]}

I tried to implement it by using regex but I had all sorts of problems, and inaccurate results. Also, I don't believe there is a Lua parser for Python.

2
  • 2
    Would the functions being called in your Lua code always accept only string arguments? Commented Oct 11, 2021 at 23:39
  • If the pattern for calls is simple, then you can use my ltokenp, at web.tecgraf.puc-rio.br/~lhf/ftp/lua/#ltokenp Commented Oct 12, 2021 at 0:05

1 Answer 1

2

You can use luaparser (pip install luaparser) with recursion to traverse the ast:

import luaparser
from luaparser import ast
class FunCalls:
   def __init__(self):
      self.f_defs, self.f_calls = [], []
   def lua_eval(self, tree):
      #attempts to produce a value for a function parameter. If value is a string or an integer, returns the corresponding Python object. If not, returns a string with the lua code
      if isinstance(tree, (luaparser.astnodes.Number, luaparser.astnodes.String)):
         return tree.n if hasattr(tree, 'n') else tree.s
      return ast.to_lua_source(tree)
   def walk(self, tree):
      to_walk = None
      if isinstance(tree, luaparser.astnodes.Function):
         self.f_defs.append((tree.name.id, [i.id for i in tree.args]))
         to_walk = tree.body
      elif isinstance(tree, luaparser.astnodes.Call):
         self.f_calls.append((tree.func.id, [self.lua_eval(i) for i in tree.args]))
      elif isinstance(tree, luaparser.astnodes.Assign):
         if isinstance(tree.values[0], luaparser.astnodes.AnonymousFunction):
            self.f_defs.append((tree.targets[0].id, [i.id for i in tree.values[0].args]))
      if to_walk is not None:
         for i in ([to_walk] if not isinstance(to_walk, list) else to_walk):
             self.walk(i)
      else:
         for a, b in getattr(tree, '__dict__', {}).items():
            if isinstance(b, list) or 'luaparser.astnodes' in str(b):
               for i in ([b] if not isinstance(b, list) else b):
                   self.walk(i)

Putting it all together:

s = """
function displayText (text)
   print(text)
end

sendGreetings = function(sender, reciever) 
   print("Hi " ..reciever.. " greetings from " ..sender.. "!")
end

displayText("Hello, World!")

sendGreetings("Roger", "Michael")
"""
tree = ast.parse(s)
f = FunCalls()
f.walk(tree)
print(dict(f.f_defs)) #the function definitions with signatures
calls = {a:b for a, b in f.f_calls if any(j == a for j, _ in f.f_defs)}    
print(calls)

Output:

{'displayText': ['text'], 'sendGreetings': ['sender', 'reciever']}
{'displayText': ['Hello, World!'], 'sendGreetings': ['Roger', 'Michael']}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.