12. Adding a new target languageΒΆ
wrenfold can be extended to target new languages by customizing the code generation step. For a complete demonstration, refer to the c_generation example. This section provides a brief overview.
To begin with, one should subclass the wrenfold.code_generation.BaseGenerator type in python
and implement format_<type name> methods for each of the
syntax tree types.
Most nodes in the syntax tree will have children - for example wrenfold.ast.Add has a
member args that enumerates the operands of an N-ary addition. To facilitate recursive
formatting, the BaseGenerator type provides an overloaded
wrenfold.code_generation.BaseGenerator.format() method that automatically delegates to the
appropriately named formatter on your subclass.
For example, when printing ast.Add we can recurse on add.args:
from wrenfold import ast
from wrenfold.code_generation import BaseGenerator
class CustomGenerator(BaseGenerator):
"""A generator for a new language."""
def format_add(self, add: ast.Add) -> str:
# Calling `format(...)` will automatically delegate to the appropriate overload.
# If the argument is an `ast.Add`, it will recurse back into this method.
return ' + '.join(self.format(x) for x in add.args)
# ... more overloads ...
def format_compare(self, compare: ast.Compare) -> str:
if compare.operation == RelationalOperation.LessThan:
op = '<'
elif compare.operation == RelationalOperation.LessThanOrEqual:
op = '<='
elif compare.operation == RelationalOperation.Equal:
op = '=='
else:
raise NotImplementedError(f"Unknown operation: {compare.operation}")
return f'{self.format(compare.left)} {op} {self.format(compare.right)}'
Note
There is no hard requirement that you use the BaseGenerator infrastructure to implement
code-generation. wrenfold.code_generation.transpile() directly returns the top-level
FunctionDefinition object, which can be traversed by alternative means if desired.
With a BaseGenerator subclass in hand, we can generate code:
def some_symbolic_func(x: type_annotations.FloatScalar):
return x * 2
# Here we replace the built-in generator with `CustomGenerator`:
code = code_generation.generate_function(some_symbolic_func, generator=CustomGenerator())