5

I'm using python to implement another programming language named 'foo'. All of foo's code will be translated to python, and will also be run in the same python interpreter, so it will JIT translate to python.

Here is a small piece of foo's code:

function bar(arg1, arg2) {
    while (arg1 > arg2) {
        arg2 += 5;
    }
    return arg2 - arg1;
}

which will translate to :

def _bar(arg1, arg2):
    while arg1 > arg2:
        arg2 += 5
        watchdog.switch()
    watchdog.switch()
    return arg2 - arg1

The 'watchdog' is a greenlet(the generated code is also running in a greenlet context) which will monitor/limit resource usage, since the language will run untrusted code.

As can be seen in the example, before the python code is generated, small changes will be made to the parse tree in order to add watchdog switches and make small changes to function identifiers.

To meet all the requeriments, I must also add traceback/debugging capabilities to the language, so that when the python runtime throws an exception, what the user will see is foo's code traceback(as oposed to showing the generated python code traceback).

Consider that the user creates a file named 'program.foo' with the following contents:

1  function bar() {
2      throw Exception('Some exception message');
3  }
4
5  function foo() {
6      output('invoking function bar');
7      bar();
8  }
9
10 foo();

which will translate to:

def _bar():
    watchdog.switch()
    raise Exception('Some exception message')

def _foo():
    print 'invoking function bar'
    watchdog.switch()
    _bar()

watchdog.switch()
_foo()

Then, the output of 'program.foo' should be something like:

invoking function bar
Traceback (most recent call last):
  File "program.foo", line 10
    foo();
  File "program.foo", line 7, inside function 'foo'
    bar();
  File "program.foo", line 2, inside function 'bar'
    throw Exception('Some exception message');
Exception: Some exception message

Is there an easy way to do that? I would prefer a solution that doesn't involve instrumenting python bytecode, since it is internal to the interpreter implementation, but if there's nothing else, then instrumenting bytecode will also do it.

Thiago Padilha
  • 4,590
  • 5
  • 44
  • 69
  • Does your translation store any kind of mapping between lines of Python code and lines of foo code? You can certainly customise a traceback: IPython has a module called [ultratb](https://github.com/ipython/ipython/blob/master/IPython/core/ultratb.py) for this, although it's fairly long and convoluted, and could do with some cleanup. – Thomas K Mar 09 '12 at 12:40
  • So far it only does translation. But if it is part of a solution I could certainly map lines of python to lines of foo. – Thiago Padilha Mar 09 '12 at 13:03

1 Answers1

2

You could decorate each generated Python function with a decorator which record the context (filename, function, line number, etc.) to a global stack. Then you could derive your own Exception class and catch it at the top level of the interpreter. Finally, you print out what you like, using information from the global debug stack.

Charles Brunet
  • 21,797
  • 24
  • 83
  • 124
  • This seems like a good lead. I can adapt this solution and instead of decorating each function, I will add a function call to record the current foo line before each group of python statements that map to it. But why would I need a custom exception class? Couldn't I just catch any python exception and print the information in the global context stack? – Thiago Padilha Mar 09 '12 at 14:16
  • Off course you can. But declaring your own exception class would allow you to record some custom information into the exception, specific to your problem. – Charles Brunet Mar 09 '12 at 14:51