Search code examples
pythondslabstract-syntax-treetraceback

Customize traceback from exceptions in Python-based DSL


I'm creating a python-based DSL just for fun. Right now, it just compiles text into an AST that executes python code directly. I mean if I write:

a = int(read("input something: "))
b = a**2

It translates this to a tree like:

Program:
  VariableSet a:
    Call:
      VariableGet int
      Call:
        VariableGet read
        Literal("input something: ")
  VariableSet b:
    BinaryExpession **:
       VariableGet a
       Literal(2)

Each of these nodes will be executed with a code like the following:

class VariableSet(object):
    def __init__(self, name, expr):
        self.name = name
        self.expr = expr

    def __call__(self, scope):
        value = self.expr(scope)
        scope.put(self.name, value)
        return value

It does work very well. I wanted that, when some instruction throws an exception, that the exception stack traceback points to the DSL source code, not the python AST code. Right now, all I see is:

Traceback (most recent call last):
  File "parser.py", line 164, in <module>
    parse(data)(scope)  
  File "/home/juanplopes/Projects/my-parser/ast.py", line 158, in __call__
    result = expr(scope)
  File "/home/juanplopes/Projects/my-parser/ast.py", line 63, in __call__
    value = self.expr(scope)
  File "/home/juanplopes/Projects/my-parser/ast.py", line 81, in __call__
    return self.method(scope)(*[arg(scope) for arg in self.args])
  File "/home/juanplopes/Projects/my-parser/ast.py", line 81, in __call__
    return self.method(scope)(*[arg(scope) for arg in self.args])
  File "parser.py", line 153, in read
    raise Exception('some exception')
Exception: some exception

Is there a way to customize how tracebacks are generated in python?


Solution

  • Yes, but it's ugly to do so.

    You might want to look at how it's done in jinja2.

    Jinja is a templating engine. It handles tracebacks so that they point at the template errors.
    Maybe you could transpose this to your code so that it points to the DSL errors.