From: Gregory Ewing Date: Wed, 14 May 2008 12:34:23 +0000 (+1200) Subject: Forward declaration of extension class in another module X-Git-Tag: 0.9.8rc1~18 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=4c4f6bdb0cc86ab03d0bef4c3140bae259d13790;p=cython.git Forward declaration of extension class in another module + + - There is now a way of forward-declaring an extension type into + another module. This allows two .pxd files to define extension types + that refer to each other without running into circular import problems. + For example: + + cimport blarg + cdef class blarg.Blarg # Forward declaration + + cdef class Foo: + cdef blarg.Blarg blg --- diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index d668b38e..a843f090 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -571,16 +571,7 @@ class CSimpleBaseTypeNode(CBaseTypeNode): else: type = py_object_type else: - scope = env - for name in self.module_path: - entry = scope.find(name, self.pos) - if entry and entry.as_module: - scope = entry.as_module - else: - if entry: - error(self.pos, "'%s' is not a cimported module" % name) - scope = None - break + scope = env.find_imported_module(self.module_path, self.pos) if scope: if scope.is_c_class_scope: scope = scope.global_scope() @@ -1230,6 +1221,8 @@ class DefNode(FuncDefNode): self.num_required_kw_args = rk self.num_required_args = r + entry = None + def analyse_declarations(self, env): for arg in self.args: base_type = arg.base_type.analyse(env) @@ -2010,7 +2003,14 @@ class CClassDefNode(StatNode, BlockNode): else: self.base_type = base_class_entry.type has_body = self.body is not None - self.entry = env.declare_c_class( + if self.module_name: + module_path = self.module_name.split(".") + home_scope = env.find_imported_module(module_path, self.pos) + if not home_scope: + return + else: + home_scope = env + self.entry = home_scope.declare_c_class( name = self.class_name, pos = self.pos, defining = has_body and self.in_pxd, @@ -2022,6 +2022,8 @@ class CClassDefNode(StatNode, BlockNode): visibility = self.visibility, typedef_flag = self.typedef_flag, api = self.api) + if home_scope is not env and self.visibility == 'extern': + env.add_imported_entry(self.class_name, self.entry, pos) scope = self.entry.type.scope if self.doc and Options.docstrings: diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 485215a7..8127e534 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -420,6 +420,21 @@ class Scope: else: error(pos, "'%s' is not declared" % name) + def find_imported_module(self, path, pos): + # Look up qualified name, must be a module, report error if not found. + # Path is a list of names. + scope = self + for name in path: + entry = scope.find(name, pos) + if not entry: + return None + if entry.as_module: + scope = entry.as_module + else: + error(pos, "'%s' is not a cimported module" % scope.qualified_name) + return None + return scope + def lookup(self, name): # Look up name in this scope or an enclosing one. # Return None if not found.