Tiny AST to code generation thingy

A key feature of Kingston is the pattern matching in kingston.match.

To get an idea of what you can build, let’s create a rudimentary AST to Python code generator. This tends to be a quite daunting exercise.

Imports needed

You will want to import ast, kingston.match.Matcher and kingston.match.TypeMatcher:

>>> import ast
>>> from kingston.match import Matcher, TypeMatcher

Configure a Matcher to convert ast.AST nodes to strings

>>> nodeRep:Matcher[ast.AST, str] = TypeMatcher({
...     ast.Interactive: lambda: '',
...     ast.FunctionDef: lambda node: f"def {node.name}(",
...     ast.arguments: (lambda node: ','.join(arg.arg
...                                          for arg in node.args) +
...                     '):\n'),
...     ast.BinOp: lambda node: '',
...     ast.Constant: lambda node: str(node.value),
...     ast.Return: lambda node: '    return ',
...     ast.Add: lambda: ' + ',
... })

As you can see, this isn’t recursive and will be very primitive. We will borrow ast.walk() for brevity. Note the typing declaration at the top line. This is to be able to use MyPy to type check our matchings. Here the declaration means that the matcher accepts ast.AST nodes as parameters and will return str.

Compile a small AST

>>> topnode = compile("""
... def helo():
...     return 1 + 1
... """, 'examples.ormsnackis', 'single', ast.PyCF_ONLY_AST)

Given the Matcher we just created we could only support the most minimal AST.

Test it

We use the linear list of nodes you get from AST’s walk function to test without too much work:

>>> def test(tree):
...     print(''.join(nodeRep(node) for node in ast.walk(tree)))

>>> if __name__ == '__main__':
...     test(topnode)

Running gives the following output:

$ python examples/ormsnackis.py
def helo():
    return 1 + 1