使用 Python 在 Lua 文件中搜索所有函数调用
Search for all function calls in a Lua file using Python
我想使用 python 在 Lua 文件中搜索所有函数调用。
例如,我有这个 Lua 代码:
function displayText (text)
print(text)
end
sendGreetings = function(sender, reciever)
print("Hi " ..reciever.. " greetings from " ..sender.. "!")
end
displayText("Hello, World!")
sendGreetings("Roger", "Michael")
我希望我的 python 代码在该代码中搜索函数调用,并 returns 包含函数名称和参数的字典,因此输出应如下所示:
# {function_name: [param1, param2]}
{"displayText": ["Hello, World!"], "sendGreetings": ["Roger", "Michael"]}
我尝试使用正则表达式来实现它,但我遇到了各种各样的问题,而且结果不准确。另外,我不相信 Python.
有 Lua 解析器
可以使用luaparser
(pip install luaparser
)递归遍历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)
综合起来:
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)
输出:
{'displayText': ['text'], 'sendGreetings': ['sender', 'reciever']}
{'displayText': ['Hello, World!'], 'sendGreetings': ['Roger', 'Michael']}
我想使用 python 在 Lua 文件中搜索所有函数调用。 例如,我有这个 Lua 代码:
function displayText (text)
print(text)
end
sendGreetings = function(sender, reciever)
print("Hi " ..reciever.. " greetings from " ..sender.. "!")
end
displayText("Hello, World!")
sendGreetings("Roger", "Michael")
我希望我的 python 代码在该代码中搜索函数调用,并 returns 包含函数名称和参数的字典,因此输出应如下所示:
# {function_name: [param1, param2]}
{"displayText": ["Hello, World!"], "sendGreetings": ["Roger", "Michael"]}
我尝试使用正则表达式来实现它,但我遇到了各种各样的问题,而且结果不准确。另外,我不相信 Python.
有 Lua 解析器可以使用luaparser
(pip install luaparser
)递归遍历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)
综合起来:
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)
输出:
{'displayText': ['text'], 'sendGreetings': ['sender', 'reciever']}
{'displayText': ['Hello, World!'], 'sendGreetings': ['Roger', 'Michael']}