diff -r 95fb7b66107e Include/compile.h --- a/Include/compile.h Fri Mar 22 00:06:20 2013 +0100 +++ b/Include/compile.h Fri Mar 22 01:52:02 2013 +0100 @@ -53,4 +53,6 @@ PyAPI_FUNC(PyObject*) _Py_Mangle(PyObjec #define Py_file_input 257 #define Py_eval_input 258 +PyAPI_DATA(PyObject*) Py_ASTHook; + #endif /* !Py_COMPILE_H */ diff -r 95fb7b66107e Python/compile.c --- a/Python/compile.c Fri Mar 22 00:06:20 2013 +0100 +++ b/Python/compile.c Fri Mar 22 01:52:02 2013 +0100 @@ -42,6 +42,8 @@ int Py_OptimizeFlag = 0; #define COMP_SETCOMP 2 #define COMP_DICTCOMP 3 +PyObject *Py_ASTHook = NULL; + struct instr { unsigned i_jabs : 1; unsigned i_jrel : 1; @@ -3860,7 +3862,9 @@ assemble_lnotab(struct assembler *a, str d_lineno = i->i_lineno - a->a_lineno; assert(d_bytecode >= 0); +#if 0 assert(d_lineno >= 0); +#endif if(d_bytecode == 0 && d_lineno == 0) return 1; diff -r 95fb7b66107e Python/pythonrun.c --- a/Python/pythonrun.c Fri Mar 22 00:06:20 2013 +0100 +++ b/Python/pythonrun.c Fri Mar 22 01:52:02 2013 +0100 @@ -2072,6 +2072,56 @@ Py_SymtableString(const char *str, const return st; } +static mod_ty +call_ast_hook(mod_ty mod, PyArena *arena, const char *filename, int start) +{ + PyObject *ast, *fileobj, *res; + int mode; + + if (!Py_ASTHook) + return mod; + + if (start == Py_file_input) + mode = 0; /* exec */ + else if (start == Py_eval_input) + mode = 1; /* eval */ + else { + assert(start == Py_single_input); + mode = 2; /* single */ + } + + ast = PyAST_mod2obj(mod); + if (ast == NULL) + return NULL; + + if (filename != NULL) { + fileobj = PyUnicode_DecodeFSDefault(filename); + if (fileobj == NULL) { + Py_DECREF(ast); + return NULL; + } + } + else { + Py_INCREF(Py_None); + fileobj = Py_None; + } + + res = PyObject_CallFunction(Py_ASTHook, "OO", ast, fileobj); + Py_DECREF(ast); + Py_DECREF(fileobj); + if (res == NULL) + return NULL; + + mod = PyAST_obj2mod(res, arena, mode); + Py_DECREF(ast); + if (mod == NULL) + return NULL; + if (!PyAST_Validate(mod)) + return NULL; + + return mod; +} + /* Preferred access to parser is through AST. */ mod_ty PyParser_ASTFromString(const char *s, const char *filename, int start, @@ -2099,7 +2149,10 @@ PyParser_ASTFromString(const char *s, co mod = NULL; } err_free(&err); - return mod; + if (mod == NULL) + return NULL; + + return call_ast_hook(mod, arena, filename, start); } mod_ty @@ -2132,7 +2185,10 @@ PyParser_ASTFromFile(FILE *fp, const cha mod = NULL; } err_free(&err); - return mod; + if (mod == NULL) + return NULL; + + return call_ast_hook(mod, arena, filename, start); } /* Simplified interface to parsefile -- return node or set exception */ diff -r 95fb7b66107e Python/sysmodule.c --- a/Python/sysmodule.c Fri Mar 22 00:06:20 2013 +0100 +++ b/Python/sysmodule.c Fri Mar 22 01:52:02 2013 +0100 @@ -1056,6 +1056,30 @@ PyDoc_STRVAR(sys_clear_type_cache__doc__ "_clear_type_cache() -> None\n\ Clear the internal type lookup cache."); +static PyObject * +sys_setasthook(PyObject *self, PyObject *hook) +{ + if (!PyCallable_Check(hook)) { + PyErr_SetString(PyExc_TypeError, "the argument must be callable"); + return NULL; + } + + Py_XDECREF(Py_ASTHook); + Py_INCREF(hook); + Py_ASTHook = hook; + + + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(setasthook_doc, +"setasthook(function)\n\ +\n\ +Set an hook on the AST compiler." +); + static PyMethodDef sys_methods[] = { /* Might as well keep this in alphabetic order */ @@ -1128,6 +1152,7 @@ static PyMethodDef sys_methods[] = { #endif {"settrace", sys_settrace, METH_O, settrace_doc}, {"gettrace", sys_gettrace, METH_NOARGS, gettrace_doc}, + {"setasthook", sys_setasthook, METH_O, setasthook_doc}, {"call_tracing", sys_call_tracing, METH_VARARGS, call_tracing_doc}, {"_debugmallocstats", sys_debugmallocstats, METH_VARARGS, debugmallocstats_doc},