在 python 中将简单命令转换为 AST
Convert a simple command into an AST in python
我想要 Python 中的函数,将字符串命令转换为 AST(抽象语法树)。
命令的语法如下:
commandName(3, "hello", 5.0, x::int)
命令可以接受任意数量的逗号分隔值,可以是
- 整数
- 字符串
- 花车
- 类型
假设函数被调用convert_to_ast
,那么
convert_to_ast('commandName(3, "hello", 5.0, x::int)')
应该产生以下 AST:
{
'type': 'command',
'name': 'commandName',
'args': [{
'type': 'int',
'value': 3
}, {
'type': 'str',
'value': 'Hello'
}, {
'type': 'float',
'value': 5.0
}, {
'type': 'var',
'kind': 'int',
'name': 'x
}]
看来您可以只评估字符串,然后从那里挑选类型:
>>> items = ast.literal_eval('(404.5, "Hello", 5)')
>>> [{'type': type(item).__name__, 'value': item} for item in items]
[{'type': 'float', 'value': 404.5}, {'type': 'str', 'value': 'Hello'}, {'type': 'int', 'value': 5}]
当然,如果你想做更多有趣的事情,你可以直接访问AST:
>>> ast.dump(ast.parse('(404.5, "Hello", 5)'))
"Module(body=[Expr(value=Tuple(elts=[Num(n=404.5), Str(s='Hello'), Num(n=5)], ctx=Load()))])"
>>> ast.parse('(404.5, "Hello", 5)').body[0].value.elts
[<_ast.Num object at 0x107fa1250>, <_ast.Str object at 0x107fa1290>, <_ast.Num object at 0x107fa12d0>]
对于比解析元组更一般的事情(正如你添加到问题中的那样),我们仍然可以使用 python 的 AST 来解析它(只要你的语法 是 有效 python)。在这种情况下,我们将创建一个 ast.NodeVisitor
,它将提取我们访问我们关心的 python AST 的每个节点的信息。在这种情况下,我们关心 Call
、Num
、Str
和 Name
节点:
import ast
class Parser(ast.NodeVisitor):
def __init__(self):
self.calls = []
self.current_command = None
def visit_Call(self, node):
name = node.func.id
self.current_command = {
'type': 'command',
'name': name,
'args': []
}
self.calls.append(self.current_command)
for arg in node.args:
self.visit(arg)
self.current_command = None
def visit_Num(self, node):
if not self.current_command:
return
args = self.current_command['args']
arg = {
'type': type(node.n).__name__,
'value': node.n
}
args.append(arg)
def visit_Str(self, node):
if not self.current_command:
return
args = self.current_command['args']
arg = {
'type': 'str',
'value': node.s
}
args.append(arg)
def visit_Name(self, node):
if not self.current_command:
return
args = self.current_command['args']
arg = {
'type': 'type',
'kind': node.id
}
args.append(arg)
S = 'commandName(3, "hello", 5.0, int)'
tree = ast.parse(S)
p = Parser()
p.visit(tree)
print p.calls
我想要 Python 中的函数,将字符串命令转换为 AST(抽象语法树)。
命令的语法如下:
commandName(3, "hello", 5.0, x::int)
命令可以接受任意数量的逗号分隔值,可以是
- 整数
- 字符串
- 花车
- 类型
假设函数被调用convert_to_ast
,那么
convert_to_ast('commandName(3, "hello", 5.0, x::int)')
应该产生以下 AST:
{
'type': 'command',
'name': 'commandName',
'args': [{
'type': 'int',
'value': 3
}, {
'type': 'str',
'value': 'Hello'
}, {
'type': 'float',
'value': 5.0
}, {
'type': 'var',
'kind': 'int',
'name': 'x
}]
看来您可以只评估字符串,然后从那里挑选类型:
>>> items = ast.literal_eval('(404.5, "Hello", 5)')
>>> [{'type': type(item).__name__, 'value': item} for item in items]
[{'type': 'float', 'value': 404.5}, {'type': 'str', 'value': 'Hello'}, {'type': 'int', 'value': 5}]
当然,如果你想做更多有趣的事情,你可以直接访问AST:
>>> ast.dump(ast.parse('(404.5, "Hello", 5)'))
"Module(body=[Expr(value=Tuple(elts=[Num(n=404.5), Str(s='Hello'), Num(n=5)], ctx=Load()))])"
>>> ast.parse('(404.5, "Hello", 5)').body[0].value.elts
[<_ast.Num object at 0x107fa1250>, <_ast.Str object at 0x107fa1290>, <_ast.Num object at 0x107fa12d0>]
对于比解析元组更一般的事情(正如你添加到问题中的那样),我们仍然可以使用 python 的 AST 来解析它(只要你的语法 是 有效 python)。在这种情况下,我们将创建一个 ast.NodeVisitor
,它将提取我们访问我们关心的 python AST 的每个节点的信息。在这种情况下,我们关心 Call
、Num
、Str
和 Name
节点:
import ast
class Parser(ast.NodeVisitor):
def __init__(self):
self.calls = []
self.current_command = None
def visit_Call(self, node):
name = node.func.id
self.current_command = {
'type': 'command',
'name': name,
'args': []
}
self.calls.append(self.current_command)
for arg in node.args:
self.visit(arg)
self.current_command = None
def visit_Num(self, node):
if not self.current_command:
return
args = self.current_command['args']
arg = {
'type': type(node.n).__name__,
'value': node.n
}
args.append(arg)
def visit_Str(self, node):
if not self.current_command:
return
args = self.current_command['args']
arg = {
'type': 'str',
'value': node.s
}
args.append(arg)
def visit_Name(self, node):
if not self.current_command:
return
args = self.current_command['args']
arg = {
'type': 'type',
'kind': node.id
}
args.append(arg)
S = 'commandName(3, "hello", 5.0, int)'
tree = ast.parse(S)
p = Parser()
p.visit(tree)
print p.calls