From: Robert Bradshaw Date: Sat, 26 Feb 2011 17:50:04 +0000 (-0800) Subject: First pass at struct wrappers. X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=3552114e1b2a21bf2f81f451d50cd48934ea4eb4;p=cython.git First pass at struct wrappers. --- diff --git a/Cython/Compiler/Errors.py b/Cython/Compiler/Errors.py index 401125bb..fc59dfc9 100644 --- a/Cython/Compiler/Errors.py +++ b/Cython/Compiler/Errors.py @@ -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 diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index dbc6d47e..337ae165 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -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 diff --git a/Cython/Compiler/Options.py b/Cython/Compiler/Options.py index f827ce0b..35a7e7ee 100644 --- a/Cython/Compiler/Options.py +++ b/Cython/Compiler/Options.py @@ -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 diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index b78259be..b57d374f 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -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) diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index dcd21613..0d0e5760 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -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