summaryrefslogtreecommitdiffstats
path: root/Parser
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2008-03-28 12:11:56 (GMT)
committerGeorg Brandl <georg@python.org>2008-03-28 12:11:56 (GMT)
commitfc8eef3c78200593c9c70974e48ab859779c607a (patch)
tree6c1cddba98dad1770c0f22a08d88455d7dc7eeaa /Parser
parentb9803421d231fc66489eafb45f6ae440010cacfc (diff)
downloadcpython-fc8eef3c78200593c9c70974e48ab859779c607a.zip
cpython-fc8eef3c78200593c9c70974e48ab859779c607a.tar.gz
cpython-fc8eef3c78200593c9c70974e48ab859779c607a.tar.bz2
Patch #1810 by Thomas Lee, reviewed by myself:
allow compiling Python AST objects into code objects in compile().
Diffstat (limited to 'Parser')
-rwxr-xr-xParser/asdl_c.py270
1 files changed, 268 insertions, 2 deletions
diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py
index 17d9dfd..4b6b7cf 100755
--- a/Parser/asdl_c.py
+++ b/Parser/asdl_c.py
@@ -73,12 +73,12 @@ def is_simple(sum):
A sum is simple if its types have no fields, e.g.
unaryop = Invert | Not | UAdd | USub
"""
-
for t in sum.types:
if t.fields:
return False
return True
+
class EmitVisitor(asdl.VisitorBase):
"""Visit that emits lines"""
@@ -96,6 +96,7 @@ class EmitVisitor(asdl.VisitorBase):
line = (" " * TABSIZE * depth) + line + "\n"
self.file.write(line)
+
class TypeDefVisitor(EmitVisitor):
def visitModule(self, mod):
for dfn in mod.dfns:
@@ -133,6 +134,7 @@ class TypeDefVisitor(EmitVisitor):
self.emit(s, depth)
self.emit("", depth)
+
class StructVisitor(EmitVisitor):
"""Visitor to generate typdefs for AST."""
@@ -202,6 +204,7 @@ class StructVisitor(EmitVisitor):
self.emit("};", depth)
self.emit("", depth)
+
class PrototypeVisitor(EmitVisitor):
"""Generate function prototypes for the .h file"""
@@ -271,6 +274,7 @@ class PrototypeVisitor(EmitVisitor):
self.emit_function(name, get_c_type(name),
self.get_args(prod.fields), [], union=0)
+
class FunctionVisitor(PrototypeVisitor):
"""Visitor to generate constructor functions for AST."""
@@ -325,6 +329,7 @@ class FunctionVisitor(PrototypeVisitor):
emit("p->%s = %s;" % (argname, argname), 1)
assert not attrs
+
class PickleVisitor(EmitVisitor):
def visitModule(self, mod):
@@ -346,6 +351,181 @@ class PickleVisitor(EmitVisitor):
def visitField(self, sum):
pass
+
+class Obj2ModPrototypeVisitor(PickleVisitor):
+ def visitProduct(self, prod, name):
+ code = "static int obj2ast_%s(PyObject* obj, %s* out, PyArena* arena);"
+ self.emit(code % (name, get_c_type(name)), 0)
+
+ visitSum = visitProduct
+
+
+class Obj2ModVisitor(PickleVisitor):
+ def funcHeader(self, name):
+ ctype = get_c_type(name)
+ self.emit("int", 0)
+ self.emit("obj2ast_%s(PyObject* obj, %s* out, PyArena* arena)" % (name, ctype), 0)
+ self.emit("{", 0)
+ self.emit("PyObject* tmp = NULL;", 1)
+ self.emit("", 0)
+
+ def sumTrailer(self, name):
+ self.emit("", 0)
+ self.emit("tmp = PyObject_Repr(obj);", 1)
+ # there's really nothing more we can do if this fails ...
+ self.emit("if (tmp == NULL) goto failed;", 1)
+ error = "expected some sort of %s, but got %%.400s" % name
+ format = "PyErr_Format(PyExc_TypeError, \"%s\", PyString_AS_STRING(tmp));"
+ self.emit(format % error, 1, reflow=False)
+ self.emit("failed:", 0)
+ self.emit("Py_XDECREF(tmp);", 1)
+ self.emit("return 1;", 1)
+ self.emit("}", 0)
+ self.emit("", 0)
+
+ def simpleSum(self, sum, name):
+ self.funcHeader(name)
+ for t in sum.types:
+ self.emit("if (PyObject_IsInstance(obj, (PyObject*)%s_type)) {" % t.name, 1)
+ self.emit("*out = %s;" % t.name, 2)
+ self.emit("return 0;", 2)
+ self.emit("}", 1)
+ self.sumTrailer(name)
+
+ def buildArgs(self, fields):
+ return ", ".join(fields + ["arena"])
+
+ def complexSum(self, sum, name):
+ self.funcHeader(name)
+ for a in sum.attributes:
+ self.visitAttributeDeclaration(a, name, sum=sum)
+ self.emit("", 0)
+ # XXX: should we only do this for 'expr'?
+ self.emit("if (obj == Py_None) {", 1)
+ self.emit("*out = NULL;", 2)
+ self.emit("return 0;", 2)
+ self.emit("}", 1)
+ for a in sum.attributes:
+ self.visitField(a, name, sum=sum, depth=1)
+ for t in sum.types:
+ self.emit("if (PyObject_IsInstance(obj, (PyObject*)%s_type)) {" % t.name, 1)
+ for f in t.fields:
+ self.visitFieldDeclaration(f, t.name, sum=sum, depth=2)
+ self.emit("", 0)
+ for f in t.fields:
+ self.visitField(f, t.name, sum=sum, depth=2)
+ args = [f.name.value for f in t.fields] + [a.name.value for a in sum.attributes]
+ self.emit("*out = %s(%s);" % (t.name, self.buildArgs(args)), 2)
+ self.emit("if (*out == NULL) goto failed;", 2)
+ self.emit("return 0;", 2)
+ self.emit("}", 1)
+ self.sumTrailer(name)
+
+ def visitAttributeDeclaration(self, a, name, sum=sum):
+ ctype = get_c_type(a.type)
+ self.emit("%s %s;" % (ctype, a.name), 1)
+
+ def visitSum(self, sum, name):
+ if is_simple(sum):
+ self.simpleSum(sum, name)
+ else:
+ self.complexSum(sum, name)
+
+ def visitProduct(self, prod, name):
+ ctype = get_c_type(name)
+ self.emit("int", 0)
+ self.emit("obj2ast_%s(PyObject* obj, %s* out, PyArena* arena)" % (name, ctype), 0)
+ self.emit("{", 0)
+ self.emit("PyObject* tmp = NULL;", 1)
+ for f in prod.fields:
+ self.visitFieldDeclaration(f, name, prod=prod, depth=1)
+ self.emit("", 0)
+ for f in prod.fields:
+ self.visitField(f, name, prod=prod, depth=1)
+ args = [f.name.value for f in prod.fields]
+ self.emit("*out = %s(%s);" % (name, self.buildArgs(args)), 1)
+ self.emit("return 0;", 1)
+ self.emit("failed:", 0)
+ self.emit("Py_XDECREF(tmp);", 1)
+ self.emit("return 1;", 1)
+ self.emit("}", 0)
+ self.emit("", 0)
+
+ def visitFieldDeclaration(self, field, name, sum=None, prod=None, depth=0):
+ ctype = get_c_type(field.type)
+ if field.seq:
+ if self.isSimpleType(field):
+ self.emit("asdl_int_seq* %s;" % field.name, depth)
+ else:
+ self.emit("asdl_seq* %s;" % field.name, depth)
+ else:
+ ctype = get_c_type(field.type)
+ self.emit("%s %s;" % (ctype, field.name), depth)
+
+ def isSimpleSum(self, field):
+ # XXX can the members of this list be determined automatically?
+ return field.type.value in ('expr_context', 'boolop', 'operator',
+ 'unaryop', 'cmpop')
+
+ def isNumeric(self, field):
+ return get_c_type(field.type) in ("int", "bool")
+
+ def isSimpleType(self, field):
+ return self.isSimpleSum(field) or self.isNumeric(field)
+
+ def visitField(self, field, name, sum=None, prod=None, depth=0):
+ ctype = get_c_type(field.type)
+ self.emit("if (PyObject_HasAttrString(obj, \"%s\")) {" % field.name, depth)
+ self.emit("int res;", depth+1)
+ if field.seq:
+ self.emit("Py_ssize_t len;", depth+1)
+ self.emit("Py_ssize_t i;", depth+1)
+ self.emit("tmp = PyObject_GetAttrString(obj, \"%s\");" % field.name, depth+1)
+ self.emit("if (tmp == NULL) goto failed;", depth+1)
+ if field.seq:
+ self.emit("if (!PyList_Check(tmp)) {", depth+1)
+ self.emit("PyErr_Format(PyExc_TypeError, \"%s field \\\"%s\\\" must "
+ "be a list, not a %%.200s\", tmp->ob_type->tp_name);" %
+ (name, field.name),
+ depth+2, reflow=False)
+ self.emit("goto failed;", depth+2)
+ self.emit("}", depth+1)
+ self.emit("len = PyList_GET_SIZE(tmp);", depth+1)
+ if self.isSimpleType(field):
+ self.emit("%s = asdl_int_seq_new(len, arena);" % field.name, depth+1)
+ else:
+ self.emit("%s = asdl_seq_new(len, arena);" % field.name, depth+1)
+ self.emit("if (%s == NULL) goto failed;" % field.name, depth+1)
+ self.emit("for (i = 0; i < len; i++) {", depth+1)
+ self.emit("%s value;" % ctype, depth+2)
+ self.emit("res = obj2ast_%s(PyList_GET_ITEM(tmp, i), &value, arena);" %
+ field.type, depth+2, reflow=False)
+ self.emit("if (res != 0) goto failed;", depth+2)
+ self.emit("asdl_seq_SET(%s, i, value);" % field.name, depth+2)
+ self.emit("}", depth+1)
+ else:
+ self.emit("res = obj2ast_%s(tmp, &%s, arena);" %
+ (field.type, field.name), depth+1)
+ self.emit("if (res != 0) goto failed;", depth+1)
+
+ self.emit("Py_XDECREF(tmp);", depth+1)
+ self.emit("tmp = NULL;", depth+1)
+ self.emit("} else {", depth)
+ if not field.opt:
+ message = "required field \\\"%s\\\" missing from %s" % (field.name, name)
+ format = "PyErr_SetString(PyExc_TypeError, \"%s\");"
+ self.emit(format % message, depth+1, reflow=False)
+ self.emit("return 1;", depth+1)
+ else:
+ if self.isNumeric(field):
+ self.emit("%s = 0;" % field.name, depth+1)
+ elif not self.isSimpleType(field):
+ self.emit("%s = NULL;" % field.name, depth+1)
+ else:
+ raise TypeError("could not determine the default value for %s" % field.name)
+ self.emit("}", depth)
+
+
class MarshalPrototypeVisitor(PickleVisitor):
def prototype(self, sum, name):
@@ -355,6 +535,7 @@ class MarshalPrototypeVisitor(PickleVisitor):
visitProduct = visitSum = prototype
+
class PyTypesDeclareVisitor(PickleVisitor):
def visitProduct(self, prod, name):
@@ -440,6 +621,8 @@ static int add_attributes(PyTypeObject* type, char**attrs, int num_fields)
return result;
}
+/* Conversion AST -> Python */
+
static PyObject* ast2obj_list(asdl_seq *seq, PyObject* (*func)(void*))
{
int i, n = asdl_seq_LEN(seq);
@@ -476,6 +659,57 @@ static PyObject* ast2obj_int(long b)
{
return PyInt_FromLong(b);
}
+
+/* Conversion Python -> AST */
+
+static int obj2ast_object(PyObject* obj, PyObject** out, PyArena* arena)
+{
+ if (obj == Py_None)
+ obj = NULL;
+ if (obj)
+ PyArena_AddPyObject(arena, obj);
+ Py_XINCREF(obj);
+ *out = obj;
+ return 0;
+}
+
+#define obj2ast_identifier obj2ast_object
+#define obj2ast_string obj2ast_object
+
+static int obj2ast_int(PyObject* obj, int* out, PyArena* arena)
+{
+ int i;
+ if (!PyInt_Check(obj) && !PyLong_Check(obj)) {
+ PyObject *s = PyObject_Repr(obj);
+ if (s == NULL) return 1;
+ PyErr_Format(PyExc_ValueError, "invalid integer value: %.400s",
+ PyString_AS_STRING(s));
+ Py_DECREF(s);
+ return 1;
+ }
+
+ i = (int)PyLong_AsLong(obj);
+ if (i == -1 && PyErr_Occurred())
+ return 1;
+ *out = i;
+ return 0;
+}
+
+static int obj2ast_bool(PyObject* obj, bool* out, PyArena* arena)
+{
+ if (!PyBool_Check(obj)) {
+ PyObject *s = PyObject_Repr(obj);
+ if (s == NULL) return 1;
+ PyErr_Format(PyExc_ValueError, "invalid boolean value: %.400s",
+ PyString_AS_STRING(s));
+ Py_DECREF(s);
+ return 1;
+ }
+
+ *out = (obj == Py_True);
+ return 0;
+}
+
""", 0, reflow=False)
self.emit("static int init_types(void)",0)
@@ -523,6 +757,7 @@ static PyObject* ast2obj_int(long b)
(cons.name, cons.name), 1)
self.emit("if (!%s_singleton) return 0;" % cons.name, 1)
+
def parse_version(mod):
return mod.version.value[12:-3]
@@ -562,6 +797,7 @@ class ASTModuleVisitor(PickleVisitor):
def addObj(self, name):
self.emit('if (PyDict_SetItemString(d, "%s", (PyObject*)%s_type) < 0) return;' % (name, name), 1)
+
_SPECIALIZED_SEQUENCES = ('stmt', 'expr')
def find_sequence(fields, doing_specialization):
@@ -587,6 +823,7 @@ class StaticVisitor(PickleVisitor):
def visit(self, object):
self.emit(self.CODE, 0, reflow=False)
+
class ObjVisitor(PickleVisitor):
def func_begin(self, name):
@@ -637,8 +874,12 @@ class ObjVisitor(PickleVisitor):
self.emit("case %s:" % t.name, 2)
self.emit("Py_INCREF(%s_singleton);" % t.name, 3)
self.emit("return %s_singleton;" % t.name, 3)
+ self.emit("default:" % name, 2)
+ self.emit('/* should never happen, but just in case ... */', 3)
+ code = "PyErr_Format(PyExc_SystemError, \"unknown %s found\");" % name
+ self.emit(code, 3, reflow=False)
+ self.emit("return NULL;", 3)
self.emit("}", 1)
- self.emit("return NULL; /* cannot happen */", 1)
self.emit("}", 0)
def visitProduct(self, prod, name):
@@ -712,6 +953,27 @@ PyObject* PyAST_mod2obj(mod_ty t)
init_types();
return ast2obj_mod(t);
}
+
+mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena)
+{
+ mod_ty res;
+ init_types();
+ if (!PyObject_IsInstance(ast, mod_type)) {
+ PyErr_SetString(PyExc_TypeError, "expected either Module, Interactive "
+ "or Expression node");
+ return NULL;
+ }
+ if (obj2ast_mod(ast, &res, arena) != 0)
+ return NULL;
+ else
+ return res;
+}
+
+int PyAST_Check(PyObject* obj)
+{
+ init_types();
+ return PyObject_IsInstance(obj, (PyObject*)AST_type);
+}
"""
class ChainOfVisitors:
@@ -754,6 +1016,8 @@ 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, "int PyAST_Check(PyObject* obj);"
f.close()
if SRC_DIR:
@@ -768,8 +1032,10 @@ def main(srcfile):
v = ChainOfVisitors(
PyTypesDeclareVisitor(f),
PyTypesVisitor(f),
+ Obj2ModPrototypeVisitor(f),
FunctionVisitor(f),
ObjVisitor(f),
+ Obj2ModVisitor(f),
ASTModuleVisitor(f),
PartingShots(f),
)