First pass at struct wrappers.
authorRobert Bradshaw <robertwb@math.washington.edu>
Sat, 26 Feb 2011 17:50:04 +0000 (09:50 -0800)
committerRobert Bradshaw <robertwb@math.washington.edu>
Sat, 26 Feb 2011 17:50:04 +0000 (09:50 -0800)
Cython/Compiler/Errors.py
Cython/Compiler/Nodes.py
Cython/Compiler/Options.py
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/Symtab.py

index 401125bbe570a05d5f12aa2f33829b57ed545c9b..fc59dfc98de8ddd709639302f2ba4f251256ebd2 100644 (file)
@@ -4,7 +4,7 @@
 
 import sys
 from Cython.Utils import open_new_file
-from DebugFlags import debug_exception_on_error
+import DebugFlags
 import Options
 
 
@@ -156,7 +156,7 @@ def error(position, message):
     if position is None:
         raise InternalError(message)
     err = CompileError(position, message)
-    if debug_exception_on_error: raise Exception(err) # debug
+    if DebugFlags.debug_exception_on_error: raise Exception(err) # debug
     report_error(err)
     return err
 
index dbc6d47e67cf17430efc380cb70630599d515c1c..337ae1656f59273ec6511c89cb4d663f7cc44cb5 100644 (file)
@@ -648,6 +648,9 @@ class CArgDeclNode(Node):
     is_self_arg = 0
     is_type_arg = 0
     is_generic = 1
+    kw_only = 0
+    not_none = 0
+    or_none = 0
     type = None
     name_declarator = None
     default_value = None
@@ -733,6 +736,9 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
 
     child_attrs = []
     arg_name = None   # in case the argument name was interpreted as a type
+    module_path = []
+    is_basic_c_type = False
+    complex = False
 
     def analyse(self, env, could_be_name = False):
         # Return type descriptor.
@@ -1898,6 +1904,9 @@ class DefNode(FuncDefNode):
     entry = None
     acquire_gil = 0
     self_in_stararg = 0
+    star_arg = None
+    starstar_arg = None
+    doc = None
 
     def __init__(self, pos, **kwds):
         FuncDefNode.__init__(self, pos, **kwds)
@@ -3153,6 +3162,7 @@ class CClassDefNode(ClassDefNode):
     objstruct_name = None
     typeobj_name = None
     decorators = None
+    shadow = False
 
     def analyse_declarations(self, env):
         #print "CClassDefNode.analyse_declarations:", self.class_name
@@ -3243,7 +3253,10 @@ class CClassDefNode(ClassDefNode):
             visibility = self.visibility,
             typedef_flag = self.typedef_flag,
             api = self.api,
-            buffer_defaults = buffer_defaults)
+            buffer_defaults = buffer_defaults, 
+            shadow = self.shadow)
+        if self.shadow:
+            home_scope.lookup(self.class_name).as_variable = self.entry
         if home_scope is not env and self.visibility == 'extern':
             env.add_imported_entry(self.class_name, self.entry, self.pos)
         self.scope = scope = self.entry.type.scope
index f827ce0b5e953c387474ab3b3805058c66494e6c..35a7e7ee151642e326165378da53376fb3b4faec 100644 (file)
@@ -50,7 +50,7 @@ init_local_none = True
 embed = None
 
 # Disables function redefinition, allowing all functions to be declared at
-# module creation time. For legacy code only. Needed for some circular imports.
+# module creation time. For legacy code only, needed for some circular imports.
 disable_function_redefinition = False
 
 
index b78259be1e5c103d02e191ecafe334ebefd6ce87..b57d374f2eaf10e1b52f22aa53d6a1b1ca717f51 100644 (file)
@@ -1018,6 +1018,16 @@ property NAME:
         return ATTR
     """, level='c_class')
 
+    repr_tree = TreeFragment(u"""
+def NAME(self):
+    return FORMAT % ATTRS
+    """, level='c_class')
+
+    init_assign = TreeFragment(u"""
+if VAR is not None:
+    ATTR = VAR
+    """, level='c_class')
+    
     def __call__(self, root):
         self.env_stack = [root.scope]
         # needed to determine if a cdef var is declared after it's used.
@@ -1100,6 +1110,116 @@ property NAME:
         node.analyse_declarations(self.env_stack[-1])
         return node
 
+    def visit_CStructOrUnionDefNode(self, node):
+        # Create a shadow node if needed.
+        # We want to use the struct type information (so it can't happen
+        # before this phase) but also create new objects to be declared
+        # (so it can't happen later).
+        # Note that we don't need to return the original node, as it is
+        # never used after this phase.
+        if True: # private (default)
+            return None
+        # cdef struct_type value
+        class_body = [Nodes.CVarDefNode(
+            node.pos,
+            base_type = Nodes.CSimpleBaseTypeNode(node.pos, name=node.name),
+            declarators = [Nodes.CNameDeclaratorNode(node.pos, name='value', cname='value')],
+            visibility = 'private',
+            in_pxd = False)]
+        # setters/getters
+        self_value = ExprNodes.AttributeNode(
+            pos = node.pos,
+            obj = ExprNodes.NameNode(pos=node.pos, name=u"self"),
+            attribute = EncodedString(u"value"))
+        var_entries = node.entry.type.scope.var_entries
+        attributes = []
+        for entry in var_entries:
+            attributes.append(ExprNodes.AttributeNode(pos = entry.pos,
+                                                      obj = self_value,
+                                                      attribute = entry.name))
+        for entry, attr in zip(var_entries, attributes):
+            # TODO: branch on visibility
+            if entry.type.is_pyobject:
+                template = self.basic_pyobject_property
+            else:
+                template = self.basic_property
+            property = template.substitute({
+                    u"ATTR": attr,
+                }, pos = entry.pos).stats[0]
+            property.name = entry.name
+            class_body.append(property)
+        
+        # __init__
+        self_base_type = Nodes.CSimpleBaseTypeNode(node.pos,
+            name = None, module_path = [],
+            is_basic_c_type = 0, signed = 0,
+            complex = 0, longness = 0,
+            is_self_arg = 1, templates = None)
+        init_args = [Nodes.CArgDeclNode(
+            node.pos,
+            base_type = self_base_type,
+            declarator = Nodes.CNameDeclaratorNode(node.pos, name = u"self", cname = None),
+            default = None)]
+        empty_base_type = Nodes.CSimpleBaseTypeNode(node.pos,
+            name = None, module_path = [],
+            is_basic_c_type = 0, signed = 0,
+            complex = 0, longness = 0,
+            is_self_arg = 0, templates = None)
+        init_body = []
+        for entry, attr in zip(var_entries, attributes):
+            # TODO: branch on visibility
+            init_args.append(Nodes.CArgDeclNode(
+                entry.pos,
+                base_type = empty_base_type,
+                declarator = Nodes.CNameDeclaratorNode(entry.pos, name = entry.name, cname = None),
+                default = ExprNodes.NoneNode(entry.pos)))
+            init_body.append(self.init_assign.substitute({
+                    u"VAR": ExprNodes.NameNode(entry.pos, name = entry.name),
+                    u"ATTR": attr,
+                }, pos = entry.pos))
+        init_method = Nodes.DefNode(
+            pos = node.pos,
+            args = init_args,
+            name = u"__init__",
+            decorators = [],
+            body = Nodes.StatListNode(node.pos, stats=init_body))
+        class_body.append(init_method)
+
+        # __str__
+        attr_tuple = ExprNodes.TupleNode(node.pos, args=attributes)
+        format = u"%s(%s)" % (node.entry.type.name, ("%s, " * len(attributes))[:-2])
+        repr_method = self.repr_tree.substitute({
+                u"FORMAT": ExprNodes.StringNode(node.pos, value = EncodedString(format)),
+                u"ATTRS": attr_tuple,
+            }, pos = node.pos).stats[0]
+        repr_method.name = "__str__"
+        class_body.append(repr_method)
+
+        # __repr__
+        format = u"%s(%s)" % (node.entry.type.name, ("%r, " * len(attributes))[:-2])
+        repr_method = self.repr_tree.substitute({
+                u"FORMAT": ExprNodes.StringNode(node.pos, value = EncodedString(format)),
+                u"ATTRS": attr_tuple,
+            }, pos = node.pos).stats[0]
+        repr_method.name = "__repr__"
+        class_body.append(repr_method)
+
+        # Now create the class.
+        shadow = Nodes.CClassDefNode(node.pos,
+            visibility = 'public',
+            module_name = None,
+            class_name = node.name,
+            base_class_module = None,
+            base_class_name = None,
+            decorators = None,
+            body = Nodes.StatListNode(node.pos, stats=class_body),
+            in_pxd = False,
+            doc = None,
+            shadow = True)
+
+        shadow.analyse_declarations(self.env_stack[-1])
+        return self.visit_CClassDefNode(shadow)
+
     # Some nodes are no longer needed after declaration
     # analysis and can be dropped. The analysis was performed
     # on these nodes in a seperate recursive process from the
@@ -1121,9 +1241,6 @@ property NAME:
         else:
             return None
 
-    def visit_CStructOrUnionDefNode(self, node):
-        return None
-
     def visit_CNameDeclaratorNode(self, node):
         if node.name in self.seen_vars_stack[-1]:
             entry = self.env_stack[-1].lookup(node.name)
index dcd21613f034fcc0a90f1af26d78fc0f60f95632..0d0e5760228967750c5521b327d28b5d00c83b89 100644 (file)
@@ -329,7 +329,7 @@ class Scope(object):
         # Return the module-level scope containing this scope.
         return self.outer_scope.builtin_scope()
 
-    def declare(self, name, cname, type, pos, visibility):
+    def declare(self, name, cname, type, pos, visibility, shadow = 0):
         # Create new entry, and add to dictionary if
         # name is not None. Reports a warning if already
         # declared.
@@ -339,7 +339,7 @@ class Scope(object):
             # See http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html#Reserved-Names
             warning(pos, "'%s' is a reserved name in C." % cname, -1)
         entries = self.entries
-        if name and name in entries:
+        if name and name in entries and not shadow:
             if visibility == 'extern':
                 warning(pos, "'%s' redeclared " % name, 0)
             elif visibility != 'ignore':
@@ -352,7 +352,8 @@ class Scope(object):
 #                entries[name].overloaded_alternatives.append(entry)
 #            else:
 #                entries[name] = entry
-            entries[name] = entry
+            if not shadow:
+                entries[name] = entry
         entry.scope = self
         entry.visibility = visibility
         return entry
@@ -373,11 +374,11 @@ class Scope(object):
         return entry
 
     def declare_type(self, name, type, pos,
-            cname = None, visibility = 'private', defining = 1):
+            cname = None, visibility = 'private', defining = 1, shadow = 0):
         # Add an entry for a type definition.
         if not cname:
             cname = name
-        entry = self.declare(name, cname, type, pos, visibility)
+        entry = self.declare(name, cname, type, pos, visibility, shadow)
         entry.is_type = 1
         if defining:
             self.type_entries.append(entry)
@@ -1029,7 +1030,7 @@ class ModuleScope(Scope):
     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,
-        buffer_defaults = None):
+        buffer_defaults = None, shadow = 0):
         # If this is a non-extern typedef class, expose the typedef, but use
         # the non-typedef struct internally to avoid needing forward
         # declarations for anonymous structs.
@@ -1044,7 +1045,7 @@ class ModuleScope(Scope):
         #  Look for previous declaration as a type
         #
         entry = self.lookup_here(name)
-        if entry:
+        if entry and not shadow:
             type = entry.type
             if not (entry.is_type and type.is_extension_type):
                 entry = None # Will cause redeclaration and produce an error
@@ -1060,7 +1061,7 @@ class ModuleScope(Scope):
         #
         #  Make a new entry if needed
         #
-        if not entry:
+        if not entry or shadow:
             type = PyrexTypes.PyExtensionType(name, typedef_flag, base_type, visibility == 'extern')
             type.pos = pos
             type.buffer_defaults = buffer_defaults
@@ -1072,7 +1073,7 @@ class ModuleScope(Scope):
                 type.module_name = self.qualified_name
             type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name)
             entry = self.declare_type(name, type, pos, visibility = visibility,
-                defining = 0)
+                defining = 0, shadow = shadow)
             entry.is_cclass = True
             if objstruct_cname:
                 type.objstruct_cname = objstruct_cname