From f2bfd54d6f2acde253ae24805edf116c372bd81e Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 29 Mar 2008 13:24:23 +0000 Subject: Properly check for consistency with the third argument of compile() when compiling an AST node. --- Include/Python-ast.h | 2 +- Lib/test/test_compile.py | 14 ++++++++++++++ Parser/asdl_c.py | 17 ++++++++++++----- Python/Python-ast.c | 15 +++++++++++---- Python/bltinmodule.c | 32 ++++++++++++++++---------------- 5 files changed, 54 insertions(+), 26 deletions(-) diff --git a/Include/Python-ast.h b/Include/Python-ast.h index 8be26f2..f105267 100644 --- a/Include/Python-ast.h +++ b/Include/Python-ast.h @@ -501,5 +501,5 @@ keyword_ty _Py_keyword(identifier arg, expr_ty value, PyArena *arena); alias_ty _Py_alias(identifier name, identifier asname, PyArena *arena); PyObject* PyAST_mod2obj(mod_ty t); -mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena); +mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode); int PyAST_Check(PyObject* obj); diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index ba55dfa..e8695ac 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -441,6 +441,20 @@ if 1: self.assert_(type(ast) == _ast.Module) co2 = compile(ast, '%s3' % fname, 'exec') self.assertEqual(co1, co2) + # the code object's filename comes from the second compilation step + self.assertEqual(co2.co_filename, '%s3' % fname) + + # raise exception when node type doesn't match with compile mode + co1 = compile('print 1', '', 'exec', _ast.PyCF_ONLY_AST) + self.assertRaises(TypeError, compile, co1, '', 'eval') + + # raise exception when node type is no start node + self.assertRaises(TypeError, compile, _ast.If(), '', 'exec') + + # raise exception when node has invalid children + ast = _ast.Module() + ast.body = [_ast.BoolOp()] + self.assertRaises(TypeError, compile, ast, '', 'exec') def test_main(): diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index fa43078..3a0bb95 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -954,13 +954,20 @@ PyObject* PyAST_mod2obj(mod_ty t) return ast2obj_mod(t); } -mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena) +/* mode is 0 for "exec", 1 for "eval" and 2 for "single" input */ +mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode) { mod_ty res; + PyObject *req_type[] = {(PyObject*)Module_type, (PyObject*)Expression_type, + (PyObject*)Interactive_type}; + char *req_name[] = {"Module", "Expression", "Interactive"}; + assert(0 <= mode && mode <= 2); + init_types(); - if (!PyObject_IsInstance(ast, (PyObject*)mod_type)) { - PyErr_SetString(PyExc_TypeError, "expected either Module, Interactive " - "or Expression node"); + + if (!PyObject_IsInstance(ast, req_type[mode])) { + PyErr_Format(PyExc_TypeError, "expected %s node, got %.400s", + req_name[mode], Py_TYPE(ast)->tp_name); return NULL; } if (obj2ast_mod(ast, &res, arena) != 0) @@ -1016,7 +1023,7 @@ def main(srcfile): ) c.visit(mod) print >>f, "PyObject* PyAST_mod2obj(mod_ty t);" - print >>f, "mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena);" + print >>f, "mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);" print >>f, "int PyAST_Check(PyObject* obj);" f.close() diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 085cf61..0703d51 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -5944,13 +5944,20 @@ PyObject* PyAST_mod2obj(mod_ty t) return ast2obj_mod(t); } -mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena) +/* mode is 0 for "exec", 1 for "eval" and 2 for "single" input */ +mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode) { mod_ty res; + PyObject *req_type[] = {(PyObject*)Module_type, (PyObject*)Expression_type, + (PyObject*)Interactive_type}; + char *req_name[] = {"Module", "Expression", "Interactive"}; + assert(0 <= mode && mode <= 2); + init_types(); - if (!PyObject_IsInstance(ast, (PyObject*)mod_type)) { - PyErr_SetString(PyExc_TypeError, "expected either Module, Interactive " - "or Expression node"); + + if (!PyObject_IsInstance(ast, req_type[mode])) { + PyErr_Format(PyExc_TypeError, "expected %s node, got %.400s", + req_name[mode], Py_TYPE(ast)->tp_name); return NULL; } if (obj2ast_mod(ast, &res, arena) != 0) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index fff4fda..bcdcda6 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -466,7 +466,7 @@ builtin_compile(PyObject *self, PyObject *args, PyObject *kwds) char *str; char *filename; char *startstr; - int start; + int mode = -1; int dont_inherit = 0; int supplied_flags = 0; PyCompilerFlags cf; @@ -474,6 +474,7 @@ builtin_compile(PyObject *self, PyObject *args, PyObject *kwds) Py_ssize_t length; static char *kwlist[] = {"source", "filename", "mode", "flags", "dont_inherit", NULL}; + int start[] = {Py_file_input, Py_eval_input, Py_single_input}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oss|ii:compile", kwlist, &cmd, &filename, &startstr, @@ -495,6 +496,18 @@ builtin_compile(PyObject *self, PyObject *args, PyObject *kwds) PyEval_MergeCompilerFlags(&cf); } + if (strcmp(startstr, "exec") == 0) + mode = 0; + else if (strcmp(startstr, "eval") == 0) + mode = 1; + else if (strcmp(startstr, "single") == 0) + mode = 2; + else { + PyErr_SetString(PyExc_ValueError, + "compile() arg 3 must be 'exec', 'eval' or 'single'"); + return NULL; + } + if (PyAST_Check(cmd)) { if (supplied_flags & PyCF_ONLY_AST) { Py_INCREF(cmd); @@ -505,7 +518,7 @@ builtin_compile(PyObject *self, PyObject *args, PyObject *kwds) mod_ty mod; arena = PyArena_New(); - mod = PyAST_obj2mod(cmd, arena); + mod = PyAST_obj2mod(cmd, arena, mode); if (mod == NULL) { PyArena_Free(arena); return NULL; @@ -526,19 +539,6 @@ builtin_compile(PyObject *self, PyObject *args, PyObject *kwds) cf.cf_flags |= PyCF_SOURCE_IS_UTF8; } #endif - /* XXX: is it possible to pass start to the PyAST_ branch? */ - if (strcmp(startstr, "exec") == 0) - start = Py_file_input; - else if (strcmp(startstr, "eval") == 0) - start = Py_eval_input; - else if (strcmp(startstr, "single") == 0) - start = Py_single_input; - else { - PyErr_SetString(PyExc_ValueError, - "compile() arg 3 must be 'exec'" - "or 'eval' or 'single'"); - goto cleanup; - } if (PyObject_AsReadBuffer(cmd, (const void **)&str, &length)) goto cleanup; @@ -547,7 +547,7 @@ builtin_compile(PyObject *self, PyObject *args, PyObject *kwds) "compile() expected string without null bytes"); goto cleanup; } - result = Py_CompileStringFlags(str, filename, start, &cf); + result = Py_CompileStringFlags(str, filename, start[mode], &cf); cleanup: Py_XDECREF(tmp); return result; -- cgit v0.12