Move Entry.visibility into Binding.* attributes.
authorW. Trevor King <wking@drexel.edu>
Thu, 24 Feb 2011 17:03:13 +0000 (12:03 -0500)
committerW. Trevor King <wking@drexel.edu>
Thu, 24 Feb 2011 18:28:18 +0000 (13:28 -0500)
Cython/Compiler/Binding.py
Cython/Compiler/Code.py
Cython/Compiler/ModuleNode.py
Cython/Compiler/Nodes.py
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/PyrexTypes.py
Cython/Compiler/Symtab.py
Cython/Compiler/TypeSlots.py

index a14cca1750768ef005542708f6853844119f5bc3..f2abd89cab41eaf09db0a6989586ed3276434d19 100644 (file)
@@ -68,5 +68,5 @@ class PythonBinding(CtxAttribute):
       class methods.
     """
     name = None
-    visibility = 'private'
+    visibility = 'public' #private'
     overridable = 0
index 6e87df9d11a5b450297842e0309fc20a0e9ba1c2..e5ff89644de19391bd8025cf17d00f647e29eae3 100644 (file)
@@ -1112,25 +1112,25 @@ class CCodeWriter(object):
         #print "Code.put_var_declaration:", entry.python_binding.name, "definition =", definition ###
         if entry.in_closure:
             return
-        visibility = entry.visibility
-        if visibility == 'private' and not definition:
+        if entry.c_binding.visibility == 'private' and not definition:
             #print "...private and not definition, skipping" ###
             return
-        if not entry.used and visibility == "private":
+        if entry.c_binding.visibility == 'private' and not entry.used:
             #print "not used and private, skipping", entry.c_binding.name ###
             return
         storage_class = ""
-        if visibility == 'extern':
+        if entry.c_source.extern:
             storage_class = Naming.extern_c_macro
-        elif visibility == 'public':
+        elif entry.c_binding.visibility == 'public':
             if not definition:
                 storage_class = Naming.extern_c_macro
-        elif visibility == 'private':
+        elif entry.c_binding.visibility == 'private':
             if static:
                 storage_class = "static"
         if storage_class:
             self.put("%s " % storage_class)
-        if visibility != 'public':
+        if (entry.c_source.extern or
+            entry.c_binding.visibility != 'public'):
             dll_linkage = None
         self.put(entry.type.declaration_code(entry.c_binding.name,
             dll_linkage = dll_linkage))
index 6b1e2ae1b58b3331b87b6609063510a9c6f16916..9d9124f2e882174052bbcf258184d7219a2d75dd 100644 (file)
@@ -98,7 +98,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
     def generate_h_code(self, env, options, result):
         def h_entries(entries, pxd = 0):
             return [entry for entry in entries
-                if entry.visibility == 'public' or pxd and entry.defined_in_pxd]
+                    if (entry.c_binding.visibility == 'public' and
+                        not entry.c_source.extern)
+                    or pxd and entry.defined_in_pxd]
         h_types = h_entries(env.type_entries)
         h_vars = h_entries(env.var_entries)
         h_funcs = h_entries(env.cfunc_entries)
@@ -165,7 +167,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             if entry.c_binding.api:
                 api_funcs.append(entry)
         for entry in env.c_class_entries:
-            if entry.visibility == 'public':
+            if entry.c_binding.visibility == 'public':
                 public_extension_types.append(entry)
             if entry.c_binding.api:
                 has_api_extension_types = 1
@@ -876,11 +878,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         code.putln("")
         name = entry.type.typeobj_cname
         if name:
-            if entry.visibility == 'extern' and not entry.in_cinclude:
+            if entry.c_source.extern and not entry.in_cinclude:
                 code.putln("%s DL_IMPORT(PyTypeObject) %s;" % (
                     Naming.extern_c_macro,
                     name))
-            elif entry.visibility == 'public':
+            elif entry.c_binding.visibility == 'public':
                 code.putln("%s DL_EXPORT(PyTypeObject) %s;" % (
                     Naming.extern_c_macro,
                     name))
@@ -965,8 +967,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
     def generate_cfunction_predeclarations(self, env, code, definition):
         for entry in env.cfunc_entries:
             if entry.inline_func_in_pxd or (not entry.in_cinclude and (definition
-                    or entry.defined_in_pxd or entry.visibility == 'extern')):
-                if entry.visibility in ('public', 'extern'):
+                    or entry.defined_in_pxd or entry.c_source.extern)):
+                if (entry.c_source.extern or
+                    entry.c_binding.visibility == 'public'):
                     dll_linkage = "DL_EXPORT"
                 else:
                     dll_linkage = None
@@ -975,9 +978,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                     type = CPtrType(type)
                 header = type.declaration_code(entry.c_binding.name,
                     dll_linkage = dll_linkage)
-                if entry.visibility == 'private':
+                if entry.c_binding.visibility == 'private':
                     storage_class = "static "
-                elif entry.visibility == 'public':
+                elif (entry.c_binding.visibility == 'public' and
+                      not entry.c_source.extern):
                     storage_class = ""
                 else:
                     storage_class = "%s " % Naming.extern_c_macro
@@ -995,8 +999,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         full_module_name = env.qualified_name
         for entry in env.c_class_entries:
             #print "generate_typeobj_definitions:", entry.python_binding.name
-            #print "...visibility =", entry.visibility
-            if entry.visibility != 'extern':
+            #print "...c_binding.visibility =", entry.c_binding.visibility
+            if not entry.c_source.extern:
                 type = entry.type
                 scope = type.scope
                 if scope: # could be None if there was an error
@@ -1614,7 +1618,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         for suite in TypeSlots.substructures:
             suite.generate_substructure(scope, code)
         code.putln("")
-        if entry.visibility == 'public':
+        if entry.c_binding.visibility == 'public':
             header = "DL_EXPORT(PyTypeObject) %s = {"
         else:
             header = "static PyTypeObject %s = {"
@@ -1868,7 +1872,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             rev_entries = list(env.var_entries)
             rev_entries.reverse()
             for entry in rev_entries:
-                if entry.visibility != 'extern':
+                if not entry.c_source.extern:
                     if entry.type.is_pyobject and entry.used:
                         code.putln("Py_DECREF(%s); %s = 0;" % (
                             code.entry_as_pyobject(entry),
@@ -1991,7 +1995,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         # Generate code to initialise global PyObject *
         # variables to None.
         for entry in env.var_entries:
-            if entry.visibility != 'extern':
+            if not entry.c_source.extern:
                 if entry.type.is_pyobject and entry.used:
                     code.put_init_var_to_py_none(entry, nanny=False)
 
@@ -2045,7 +2049,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         # Generate type import code for extern extension types
         # and type ready code for non-extern ones.
         for entry in env.c_class_entries:
-            if entry.visibility == 'extern':
+            if entry.c_source.extern:
                 self.generate_type_import_code(env, entry.type, entry.pos, code)
             else:
                 self.generate_base_type_import_code(env, entry, code)
@@ -2123,7 +2127,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         typeobj_cname = type.typeobj_cname
         scope = type.scope
         if scope: # could be None if there was an error
-            if entry.visibility != 'extern':
+            if not entry.c_source.extern:
                 for slot in TypeSlots.slot_table:
                     slot.generate_dynamic_init_code(scope, code)
                 code.putln(
index 3a3242cbb03015fe1179a3a18f4d1b9e5285b8e3..6796f26b2c0856cc53c68c9b7823de0e2babba4f 100644 (file)
@@ -1119,9 +1119,14 @@ class CEnumDefItemNode(StatNode):
             if not self.value.type.is_int:
                 self.value = self.value.coerce_to(PyrexTypes.c_int_type, env)
                 self.value.analyse_const_expression(env)
+        visibility = 'private'
+        if enum_entry.c_source.extern:
+            visibility = 'extern'
+        elif enum_entry.c_binding.visibility != 'private':
+            visibility = enum_entry.c_binding.visibility
         entry = env.declare_const(self.name, enum_entry.type,
             self.value, self.pos, cname = self.cname,
-            visibility = enum_entry.visibility)
+            visibility = visibility)
         enum_entry.enum_values.append(entry)
 
 
@@ -1742,7 +1747,6 @@ class CFuncDefNode(FuncDefNode):
     def generate_function_header(self, code, with_pymethdef, with_opt_args = 1, with_dispatch = 1, cname = None):
         arg_decls = []
         type = self.type
-        visibility = self.entry.visibility
         for arg in type.args[:len(type.args)-type.optional_arg_count]:
             arg_decls.append(arg.declaration_code())
         if with_dispatch and self.overridable:
@@ -1756,15 +1760,16 @@ class CFuncDefNode(FuncDefNode):
         if cname is None:
             cname = self.entry.func_cname
         entity = type.function_header_code(cname, ', '.join(arg_decls))
-        if visibility == 'public':
+        if (self.entry.c_binding.visibility == 'public' and
+            not self.entry.c_source.extern):
             dll_linkage = "DL_EXPORT"
         else:
             dll_linkage = None
         header = self.return_type.declaration_code(entity,
             dll_linkage = dll_linkage)
-        if visibility == 'extern':
+        if self.entry.c_source.extern:
             storage_class = "%s " % Naming.extern_c_macro
-        elif visibility == 'public':
+        elif self.entry.c_binding.visibility == 'public':
             storage_class = ""
         else:
             storage_class = "static "
index 8d655890ab7476320995124927dd3a3289971208..1d6eab62ed9b54c0b76845e33d602c5fc59b553d 100644 (file)
@@ -1127,7 +1127,7 @@ property NAME:
     def visit_CNameDeclaratorNode(self, node):
         if node.name in self.seen_vars_stack[-1]:
             entry = self.env_stack[-1].lookup(node.name)
-            if entry is None or entry.visibility != 'extern':
+            if entry is None or not entry.c_source.extern:
                 warning(node.pos, "cdef variable '%s' declared after it is used" % node.name, 2)
         self.visitchildren(node)
         return node
@@ -1138,13 +1138,15 @@ property NAME:
         return None
 
     def create_Property(self, entry):
-        if entry.visibility == 'public':
+        if entry.python_binding.visibility == 'public':
             if entry.type.is_pyobject:
                 template = self.basic_pyobject_property
             else:
                 template = self.basic_property
-        elif entry.visibility == 'readonly':
+        elif entry.python_binding.visibility == 'readonly':
             template = self.basic_property_ro
+        else:
+            raise NotImplementedError('private python methods')
         property = template.substitute({
                 u"ATTR": ExprNodes.AttributeNode(
                     pos=entry.pos,
@@ -1651,7 +1653,7 @@ class DebugTransform(CythonTransform):
             self.nested_funcdefs.append(node)
             return node
 
-        # node.entry.visibility = 'extern'
+        # node.entry.c_source.extern
         if node.py_func is None:
             pf_cname = ''
         else:
index e95b711ef1e04678f915a8c65c9562fae06f12fb..5694f5ef04da641f154ae74aab4f8f9285cdfda8 100755 (executable)
@@ -2019,7 +2019,7 @@ class CStructOrUnionType(CType):
                     self.to_py_function = None
                     self._convert_code = False
                     return False
-            forward_decl = (self.entry.visibility != 'extern')
+            forward_decl = not self.entry.c_source.extern
             self._convert_code = StructUtilityCode(self, forward_decl)
         
         env.use_utility_code(self._convert_code)
index 1cfec0f1d3d675c946cd59b4e3afc3cc1ec6f35b..8344e3ea322abeb5100b2e928a1b4876d54a56ab 100644 (file)
@@ -65,7 +65,6 @@ class Entry(object):
     # type             PyrexType  Type of entity
     # doc              string     Doc string
     # init             string     Initial value
-    # visibility       'private' or 'public' or 'extern'
     # is_builtin       boolean    Is an entry in the Python builtins dict
     # is_cglobal       boolean    Is a C global variable
     # is_pyglobal      boolean    Is a Python module-level variable
@@ -132,7 +131,6 @@ class Entry(object):
     inline_func_in_pxd = False
     borrowed = 0
     init = ""
-    visibility = 'private'
     is_builtin = 0
     is_cglobal = 0
     is_pyglobal = 0
@@ -357,6 +355,15 @@ class Scope(object):
                 error(pos, "'%s' redeclared " % name)
         entry = Entry(name, cname, type, pos = pos)
         entry.in_cinclude = self.in_cinclude
+        if visibility == 'extern':
+            entry.c_source.extern = 1
+            entry.c_binding.visibility = 'public'
+        elif self.outer_scope and visibility not in ('readonly',):
+            entry.c_binding.visibility = visibility
+        else:
+            entry.python_binding.visibility = visibility
+            if entry.python_binding.visibility != 'private':
+                entry.c_binding.visibility = 'public'
         if name:
             entry.qualified_name = self.qualify_name(name)
 #            if name in entries and self.is_cpp():
@@ -365,7 +372,6 @@ class Scope(object):
 #                entries[name] = entry
             entries[name] = entry
         entry.scope = self
-        entry.visibility = visibility
         return entry
 
     def qualify_name(self, name):
@@ -488,10 +494,29 @@ class Scope(object):
                 entry.python_binding.name,
                 ("cdef", "ctypedef")[entry.type.typedef_flag]))
 
-    def check_previous_visibility(self, entry, visibility, pos):
-        if entry.visibility != visibility:
-            error(pos, "'%s' previously declared as '%s'" % (
-                entry.python_binding.name, entry.visibility))
+    def _check_previous_visibility(self, entry, visibility):
+        # Compare the visibility of `entry` with a second
+        # `visibility`.  If there is a difference, return a string
+        # representing the conflicting `entry` visibility, otherwise
+        # return an empty string.
+        if visibility == 'extern':
+            if not entry.c_source.extern:
+                return 'extern'
+        elif self.outer_scope:
+            if visibility != entry.c_binding.visibility:
+                return entry.c_binding.visibility
+        elif visibility != entry.python_binding.visibility:
+            if visibilty != entry.c_binding.visibility:
+                return entry.python_binding.visibility
+
+    def check_previous_visibility(self, entry, visibility, pos,
+                                  type_name=None):
+        vis_diff = self._check_previous_visibility(entry, visibility)
+        if vis_diff:
+            if not type_name:
+                type_name = type(entry)
+            error(pos, "%s '%s' previously declared as '%s'" % (
+                    type_name, entry.python_binding.name, vis_diff))
 
     def declare_enum(self, name, pos, cname, typedef_flag,
             visibility = 'private'):
@@ -586,10 +611,14 @@ class Scope(object):
                 cname = self.mangle(Naming.func_prefix, name)
         entry = self.lookup_here(name)
         if entry:
-            if visibility != 'private' and visibility != entry.visibility:
-                warning(pos, "Function '%s' previously declared as '%s'" % (name, entry.visibility), 1)
+            if visibility != 'private':
+                vis_diff = self._check_previous_visibility(entry, visibility)
+                if vis_diff:
+                    warning(
+                        pos, "Function '%s' previously declared as '%s'" % (
+                            name, vis_diff), 1)
             if not entry.type.same_as(type):
-                if visibility == 'extern' and entry.visibility == 'extern':
+                if visibility == 'extern' and entry.c_source.extern:
                     can_override = False
                     if self.is_cpp():
                         can_override = True
@@ -1120,9 +1149,9 @@ class ModuleScope(Scope):
             entry.defined_in_pxd = 1
         if implementing:   # So that filenames in runtime exceptions refer to
             entry.pos = pos  # the .pyx file and not the .pxd file
-        if visibility != 'private' and entry.visibility != visibility:
-            error(pos, "Class '%s' previously declared as '%s'"
-                % (name, entry.visibility))
+        if visibility != 'private':
+            self.check_previous_visibility(
+                entry, visibility, pos, type_name='Class')
         if api:
             entry.c_binding.api = 1
         if objstruct_cname:
@@ -1193,12 +1222,11 @@ class ModuleScope(Scope):
     def check_c_class(self, entry):
         type = entry.type
         name = entry.python_binding.name
-        visibility = entry.visibility
         # Check defined
         if not type.scope:
             error(entry.pos, "C class '%s' is declared but not defined" % name)
         # Generate typeobj_cname
-        if visibility != 'extern' and not type.typeobj_cname:
+        if not entry.c_source.extern and not type.typeobj_cname:
             type.typeobj_cname = self.mangle(Naming.typeobj_prefix, name)
         ## Generate typeptr_cname
         #type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name)
@@ -1235,7 +1263,11 @@ class ModuleScope(Scope):
             if debug_check_c_classes:
                 print("...entry %s %s" % (entry.python_binding.name, entry))
                 print("......type = ",  entry.type)
-                print("......visibility = ", entry.visibility)
+                print("......extern = ", entry.c_source.extern)
+                print("......c_binding.visibility = ",
+                      entry.c_binding.visibility)
+                print("......python_binding.visibility = ",
+                      entry.python.binding.visibility)
             self.check_c_class(entry)
 
     def check_c_functions(self):
@@ -1245,7 +1277,7 @@ class ModuleScope(Scope):
             if entry.is_cfunction:
                 if (entry.defined_in_pxd
                         and entry.scope is self
-                        and entry.visibility != 'extern'
+                        and not entry.c_source.extern
                         and not entry.in_cinclude
                         and not entry.is_implemented):
                     error(entry.pos, "Non-extern C function '%s' declared but not defined" % name)
@@ -1693,10 +1725,15 @@ class CClassScope(ClassScope):
                 entry.is_variable = 1
                 self.inherited_var_entries.append(entry)
         for base_entry in base_scope.cfunc_entries:
+            visibility = 'private'
+            if base_entry.c_source.extern:
+                visibility = 'extern'
+            elif base_entry.c_binding.visibility != 'private':
+                visibility = base_entry.c_binding.visibility
             entry = self.add_cfunction(
                 base_entry.python_binding.name, base_entry.type,
                 base_entry.pos, adapt(base_entry.c_binding.name),
-                base_entry.visibility, base_entry.func_modifiers)
+                visibility, base_entry.func_modifiers)
             entry.is_inherited = 1
 
 
@@ -1786,10 +1823,15 @@ class CppClassScope(Scope):
                 entry.is_variable = 1
                 self.inherited_var_entries.append(entry)
         for base_entry in base_scope.cfunc_entries:
+            visibility = 'private'
+            if base_entry.c_source.extern:
+                visibility = 'extern'
+            elif base_entry.c_binding.visibility != 'private':
+                visibility = base_entry.c_binding.visibility
             entry = self.declare_cfunction(
                 base_entry.python_binding.name, base_entry.type,
                 base_entry.pos, base_entry.c_binding.name,
-                base_entry.visibility, base_entry.func_modifiers,
+                visibility, base_entry.func_modifiers,
                 utility_code = base_entry.utility_code)
             entry.is_inherited = 1
 
@@ -1801,10 +1843,20 @@ class CppClassScope(Scope):
                     entry.python_binding.name, entry.type.specialize(values),
                     entry.pos, entry.c_binding.name)
             else:
+#                visibility = 'private'
+#                if entry.c_source.extern:
+#                    visibility = 'extern'
+#                elif entry.c_binding.visibility != 'private':
+#                    visibility = entry.c_binding.visibility
 #                scope.declare_var(
 #                    entry.python_binding.name, entry.type.specialize(values),
-#                    entry.pos, entry.c_binding.name, entry.visibility)
+#                    entry.pos, entry.c_binding.name, visibility)
                 for e in entry.all_alternatives():
+#                    visibility = 'private'  # WTK: bug to not use visibility?
+#                    if e.c_source.extern:
+#                        visibility = 'extern'
+#                    elif e.c_binding.visibility != 'private':
+#                        visibility = base_entry.c_binding.visibility
                     scope.declare_cfunction(
                         e.python_binding.name, e.type.specialize(values),
                         e.pos, e.c_binding.name, utility_code = e.utility_code)
index d6bf22e82565fd8c9f3cdbde5fdc3ec862ea40ce..7a96883e80b74acead8852e70b017dea5e86b6bf 100644 (file)
@@ -287,7 +287,7 @@ class GCDependentSlot(InternalMethodSlot):
             parent_type_scope = scope.parent_type.base_type.scope
             if scope.parent_scope is parent_type_scope.parent_scope:
                 entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
-                if entry.visibility != 'extern':
+                if not entry.c_source.extern:
                     return self.slot_code(parent_type_scope)
         return InternalMethodSlot.slot_code(self, scope)
 
@@ -309,7 +309,7 @@ class ConstructorSlot(InternalMethodSlot):
             parent_type_scope = scope.parent_type.base_type.scope
             if scope.parent_scope is parent_type_scope.parent_scope:
                 entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
-                if entry.visibility != 'extern':
+                if not entry.c_source.extern:
                     return self.slot_code(parent_type_scope)
         return InternalMethodSlot.slot_code(self, scope)
 
@@ -468,7 +468,7 @@ def get_base_slot_function(scope, slot):
         parent_slot = slot.slot_code(base_type.scope)
         if parent_slot != '0':
             entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
-            if entry.visibility != 'extern':
+            if not entry.c_source.extern:
                 return parent_slot
     return None