Finish porting circular import patch from Pyrex.
authorRobert Bradshaw <robertwb@math.washington.edu>
Tue, 10 Jun 2008 09:45:57 +0000 (02:45 -0700)
committerRobert Bradshaw <robertwb@math.washington.edu>
Tue, 10 Jun 2008 09:45:57 +0000 (02:45 -0700)
Cython/Compiler/Nodes.py
Cython/Compiler/Parsing.py
Cython/Compiler/Symtab.py

index a843f090aa88daaff0921e277231b5ff29a5434d..256e8f1999bc115fc84dd76b7e154defa164750e 100644 (file)
@@ -3656,8 +3656,8 @@ class CImportStatNode(StatNode):
 class FromCImportStatNode(StatNode):
     #  from ... cimport statement
     #
-    #  module_name     string                  Qualified name of module
-    #  imported_names  [(pos, name, as_name)]  Names to be imported
+    #  module_name     string                        Qualified name of module
+    #  imported_names  [(pos, name, as_name, kind)]  Names to be imported
     
     child_attrs = []
 
@@ -3667,15 +3667,43 @@ class FromCImportStatNode(StatNode):
             return
         module_scope = env.find_module(self.module_name, self.pos)
         env.add_imported_module(module_scope)
-        for pos, name, as_name in self.imported_names:
+        for pos, name, as_name, kind in self.imported_names:
             if name == "*":
                 for local_name, entry in module_scope.entries.items():
                     env.add_imported_entry(local_name, entry, pos)
             else:
-                entry = module_scope.find(name, pos)
+                entry = module_scope.lookup(name)
+                if entry:
+                    if kind and not self.declaration_matches(entry, kind):
+                        entry.redeclared(pos)
+                else:
+                    if kind == 'struct' or kind == 'union':
+                        entry = module_scope.declare_struct_or_union(name,
+                            kind = kind, scope = None, typedef_flag = 0, pos = pos)
+                    elif kind == 'class':
+                        entry = module_scope.declare_c_class(name, pos = pos,
+                            module_name = self.module_name)
+                    else:
+                        error(pos, "Name '%s' not declared in module '%s'"
+                            % (name, self.module_name))
+                        
                 if entry:
                     local_name = as_name or name
                     env.add_imported_entry(local_name, entry, pos)
+    
+    def declaration_matches(self, entry, kind):
+               if not entry.is_type:
+                       return 0
+               type = entry.type
+               if kind == 'class':
+                       if not type.is_extension_type:
+                               return 0
+               else:
+                       if not type.is_struct_or_union:
+                               return 0
+                       if kind <> type.kind:
+                               return 0
+               return 1
 
     def analyse_expressions(self, env):
         pass
index 32ecde7d67eae88b441a4d8c3936a0b7b4be658b..f63076a4846ef97c9eb1f7681e53b8629a871421 100644 (file)
@@ -959,21 +959,21 @@ def p_from_import_statement(s, first_statement = 0):
         s.next()
     else:
         s.error("Expected 'import' or 'cimport'")
+    is_cimport = kind == 'cimport'
     if s.sy == '*':
-#        s.error("'import *' not supported")
-        imported_names = [(s.position(), "*", None)]
+        imported_names = [(s.position(), "*", None, None)]
         s.next()
     else:
-        imported_names = [p_imported_name(s)]
+        imported_names = [p_imported_name(s, is_cimport)]
     while s.sy == ',':
         s.next()
-        imported_names.append(p_imported_name(s))
+        imported_names.append(p_imported_name(s, is_cimport))
     dotted_name = Utils.EncodedString(dotted_name)
     if dotted_name == '__future__':
         if not first_statement:
             s.error("from __future__ imports must occur at the beginning of the file")
         else:
-            for (name_pos, name, as_name) in imported_names:
+            for (name_pos, name, as_name, kind) in imported_names:
                 try:
                     directive = getattr(Future, name)
                 except AttributeError:
@@ -982,7 +982,7 @@ def p_from_import_statement(s, first_statement = 0):
                 s.context.future_directives.add(directive)
         return Nodes.PassStatNode(pos)
     elif kind == 'cimport':
-        for (name_pos, name, as_name) in imported_names:
+        for (name_pos, name, as_name, kind) in imported_names:
             local_name = as_name or name
             s.add_type_name(local_name)
         return Nodes.FromCImportStatNode(pos,
@@ -991,7 +991,7 @@ def p_from_import_statement(s, first_statement = 0):
     else:
         imported_name_strings = []
         items = []
-        for (name_pos, name, as_name) in imported_names:
+        for (name_pos, name, as_name, kind) in imported_names:
             encoded_name = Utils.EncodedString(name)
             imported_name_strings.append(
                 ExprNodes.IdentifierStringNode(name_pos, value = encoded_name))
@@ -1008,11 +1008,17 @@ def p_from_import_statement(s, first_statement = 0):
                 name_list = import_list),
             items = items)
 
-def p_imported_name(s):
+imported_name_kinds = ('class', 'struct', 'union')
+
+def p_imported_name(s, is_cimport):
     pos = s.position()
+    kind = None
+    if is_cimport and s.systring in imported_name_kinds:
+        kind = s.systring
+        s.next()
     name = p_ident(s)
     as_name = p_as_name(s)
-    return (pos, name, as_name)
+    return (pos, name, as_name, kind)
 
 def p_dotted_name(s, as_allowed):
     pos = s.position()
index 26f2335f8b17abf82086a6ff86951386b2797839..313f4fc79c490d48e2d447a46a8b4777e5220c87 100644 (file)
@@ -123,6 +123,9 @@ class Entry:
         self.pos = pos
         self.init = init
         
+    def redeclared(self, pos):
+        error(pos, "'%s' does not match previous declaration" % self.name)
+        error(self.pos, "Previous declaration is here")
         
 class Scope:
     # name              string             Unqualified name
@@ -310,7 +313,8 @@ class Scope:
                 visibility = visibility, defining = scope is not None)
             self.sue_entries.append(entry)
         else:
-            if not (entry.is_type and entry.type.is_struct_or_union):
+            if not (entry.is_type and entry.type.is_struct_or_union
+                    and entry.type.kind == kind):
                 warning(pos, "'%s' redeclared  " % name, 0)
             elif scope and entry.type.scope:
                 warning(pos, "'%s' already defined  (ignoring second definition)" % name, 0)
@@ -902,9 +906,9 @@ class ModuleScope(Scope):
                 return
         self.utility_code_used.append(new_code)
     
-    def declare_c_class(self, name, pos, defining, implementing,
-        module_name, base_type, objstruct_cname, typeobj_cname,
-        visibility, typedef_flag, api):
+    def declare_c_class(self, name, pos, defining = 0, implementing = 0,
+        module_name = None, base_type = None, objstruct_cname = None,
+        typeobj_cname = None, visibility = 'private', typedef_flag = 0, api = 0):
         #
         #  Look for previous declaration as a type
         #