Reputation: 1065
I would like a function in Python that converts a string command into an AST (Abstract Syntax Tree).
The syntax for the command is as follows:
commandName(3, "hello", 5.0, x::int)
A command can accept any number of comma separated values that can be either
Suppose the function is called convert_to_ast
, then
convert_to_ast('commandName(3, "hello", 5.0, x::int)')
Should yield the following 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
}]
Upvotes: 0
Views: 780
Reputation: 310307
Seems like you could just evaluate the string and then pick off the types from there:
>>> 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}]
Of course, if you want to do more interesting things, you can access the AST directly:
>>> 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>]
For a more general thing than parsing a tuple (as you've added to the question), we still can use python's AST to parse this (as long as your syntax is valid python). In this case, we'll create an ast.NodeVisitor
which will pull out the information that we as it visits each node of the python AST that we care about. In this case, we care about Call
, Num
, Str
and Name
nodes:
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
Upvotes: 5