From e95d3eb797b714c85aef62e08db183e6c1b56293 Mon Sep 17 00:00:00 2001 From: Robert Bradshaw Date: Wed, 28 May 2008 18:09:49 -0700 Subject: [PATCH] Implement "from module [c]import *", some more work on sequence indexing. --- Cython/Compiler/ExprNodes.py | 19 +++-- Cython/Compiler/ModuleNode.py | 153 ++++++++++++++++++++++++++++++++++ Cython/Compiler/Naming.py | 2 + Cython/Compiler/Nodes.py | 45 +++++++--- Cython/Compiler/Parsing.py | 7 +- Cython/Compiler/Symtab.py | 7 +- 6 files changed, 213 insertions(+), 20 deletions(-) diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index c10c1fa6..a614262b 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -1290,12 +1290,10 @@ class IndexNode(ExprNode): self.base.result_code, self.index.result_code) def generate_subexpr_evaluation_code(self, code): - # do not evaluate self.py_index in case we don't need it self.base.generate_evaluation_code(code) self.index.generate_evaluation_code(code) def generate_subexpr_disposal_code(self, code): - # if we used self.py_index, it will be disposed of manually self.base.generate_disposal_code(code) self.index.generate_disposal_code(code) @@ -1344,13 +1342,20 @@ class IndexNode(ExprNode): def generate_deletion_code(self, code): self.generate_subexpr_evaluation_code(code) - self.py_index.generate_evaluation_code(code) - code.put_error_if_neg(self.pos, - "PyObject_DelItem(%s, %s)" % ( + #if self.type.is_pyobject: + if self.index.type.is_int: + function = "PySequence_DelItem" + index_code = self.index.result_code + else: + function = "PyObject_DelItem" + index_code = self.index.py_result() + code.putln( + "if (%s(%s, %s) < 0) %s" % ( + function, self.base.py_result(), - self.py_index.py_result())) + index_code, + code.error_goto(self.pos))) self.generate_subexpr_disposal_code(code) - self.py_index.generate_disposal_code(code) class SliceIndexNode(ExprNode): diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index c86204fb..af059c09 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -230,6 +230,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): self.generate_typeobj_definitions(env, code) self.generate_method_table(env, code) self.generate_filename_init_prototype(code) + if env.has_import_star: + self.generate_import_star(env, code) self.generate_module_init_func(modules[:-1], env, code) code.mark_pos(None) self.generate_module_cleanup_func(env, code) @@ -1429,6 +1431,66 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): def generate_filename_init_prototype(self, code): code.putln(""); code.putln("static void %s(void); /*proto*/" % Naming.fileinit_cname) + + def generate_import_star(self, env, code): + code.putln() + code.putln("char* %s_type_names[] = {" % Naming.import_star) + for name, entry in env.entries.items(): + if entry.is_type: + code.putln('"%s",' % name) + code.putln("0") + code.putln("};") + code.putln() + code.putln("static int %s(PyObject *o, PyObject* py_name, char *name) {" % Naming.import_star_set) + code.putln("char** type_name = %s_type_names;" % Naming.import_star) + code.putln("while (*type_name) {") + code.putln("if (!strcmp(name, *type_name)) {") + code.putln('PyErr_Format(PyExc_TypeError, "Cannot overwrite C type %s", name);') + code.putln('goto bad;') + code.putln("}") + code.putln("type_name++;") + code.putln("}") + old_error_label = code.new_error_label() + code.putln("if (0);") # so the first one can be "else if" + for name, entry in env.entries.items(): + if entry.is_cglobal and entry.used: + code.putln('else if (!strcmp(name, "%s")) {' % name) + if entry.type.is_pyobject: + if entry.type.is_extension_type or entry.type.is_builtin_type: + code.putln("if (!(%s)) %s;" % ( + entry.type.type_test_code("o"), + code.error_goto(entry.pos))) + code.put_var_decref(entry) + code.putln("%s = %s;" % ( + entry.cname, + PyrexTypes.typecast(entry.type, py_object_type, "o"))) + elif entry.type.from_py_function: + rhs = "%s(o)" % entry.type.from_py_function + if entry.type.is_enum: + rhs = typecast(entry.type, c_long_type, rhs) + code.putln("%s = %s; if (%s) %s;" % ( + entry.cname, + rhs, + entry.type.error_condition(entry.cname), + code.error_goto(entry.pos))) + code.putln("Py_DECREF(o);") + else: + code.putln('PyErr_Format(PyExc_TypeError, "Cannot convert Python object %s to %s");' % (name, entry.type)) + code.putln(code.error_goto(entry.pos)) + code.putln("}") + code.putln("else {") + code.putln("if (PyObject_SetAttr(%s, py_name, o) < 0) goto bad;" % Naming.module_cname) + code.putln("}") + code.putln("return 0;") + code.put_label(code.error_label) + # This helps locate the offending name. + code.putln('__Pyx_AddTraceback("%s");' % self.full_module_name); + code.error_label = old_error_label + code.putln("bad:") + code.putln("Py_DECREF(o);") + code.putln("return -1;") + code.putln("}") + code.putln(import_star_utility_code) def generate_module_init_func(self, imported_modules, env, code): code.putln("") @@ -2019,3 +2081,94 @@ bad: return ret; } """] + +import_star_utility_code = """ + +/* import_all_from is an unexposed function from ceval.c */ + +static int +__Pyx_import_all_from(PyObject *locals, PyObject *v) +{ + PyObject *all = PyObject_GetAttrString(v, "__all__"); + PyObject *dict, *name, *value; + int skip_leading_underscores = 0; + int pos, err; + + if (all == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; /* Unexpected error */ + PyErr_Clear(); + dict = PyObject_GetAttrString(v, "__dict__"); + if (dict == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; + PyErr_SetString(PyExc_ImportError, + "from-import-* object has no __dict__ and no __all__"); + return -1; + } + all = PyMapping_Keys(dict); + Py_DECREF(dict); + if (all == NULL) + return -1; + skip_leading_underscores = 1; + } + + for (pos = 0, err = 0; ; pos++) { + name = PySequence_GetItem(all, pos); + if (name == NULL) { + if (!PyErr_ExceptionMatches(PyExc_IndexError)) + err = -1; + else + PyErr_Clear(); + break; + } + if (skip_leading_underscores && + PyString_Check(name) && + PyString_AS_STRING(name)[0] == '_') + { + Py_DECREF(name); + continue; + } + value = PyObject_GetAttr(v, name); + if (value == NULL) + err = -1; + else if (PyDict_CheckExact(locals)) + err = PyDict_SetItem(locals, name, value); + else + err = PyObject_SetItem(locals, name, value); + Py_DECREF(name); + Py_XDECREF(value); + if (err != 0) + break; + } + Py_DECREF(all); + return err; +} + + +static int %s(PyObject* m) { + + int i; + int ret = -1; + PyObject *locals = 0; + PyObject *list = 0; + PyObject *name; + PyObject *item; + + locals = PyDict_New(); if (!locals) goto bad; + if (__Pyx_import_all_from(locals, m) < 0) goto bad; + list = PyDict_Items(locals); if (!list) goto bad; + + for(i=0; i