Commit 3552114e authored by Robert Bradshaw's avatar Robert Bradshaw

First pass at struct wrappers.

parent d1904794
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
import sys import sys
from Cython.Utils import open_new_file from Cython.Utils import open_new_file
from DebugFlags import debug_exception_on_error import DebugFlags
import Options import Options
...@@ -156,7 +156,7 @@ def error(position, message): ...@@ -156,7 +156,7 @@ def error(position, message):
if position is None: if position is None:
raise InternalError(message) raise InternalError(message)
err = CompileError(position, 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) report_error(err)
return err return err
......
...@@ -648,6 +648,9 @@ class CArgDeclNode(Node): ...@@ -648,6 +648,9 @@ class CArgDeclNode(Node):
is_self_arg = 0 is_self_arg = 0
is_type_arg = 0 is_type_arg = 0
is_generic = 1 is_generic = 1
kw_only = 0
not_none = 0
or_none = 0
type = None type = None
name_declarator = None name_declarator = None
default_value = None default_value = None
...@@ -733,6 +736,9 @@ class CSimpleBaseTypeNode(CBaseTypeNode): ...@@ -733,6 +736,9 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
child_attrs = [] child_attrs = []
arg_name = None # in case the argument name was interpreted as a type 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): def analyse(self, env, could_be_name = False):
# Return type descriptor. # Return type descriptor.
...@@ -1898,6 +1904,9 @@ class DefNode(FuncDefNode): ...@@ -1898,6 +1904,9 @@ class DefNode(FuncDefNode):
entry = None entry = None
acquire_gil = 0 acquire_gil = 0
self_in_stararg = 0 self_in_stararg = 0
star_arg = None
starstar_arg = None
doc = None
def __init__(self, pos, **kwds): def __init__(self, pos, **kwds):
FuncDefNode.__init__(self, pos, **kwds) FuncDefNode.__init__(self, pos, **kwds)
...@@ -3153,6 +3162,7 @@ class CClassDefNode(ClassDefNode): ...@@ -3153,6 +3162,7 @@ class CClassDefNode(ClassDefNode):
objstruct_name = None objstruct_name = None
typeobj_name = None typeobj_name = None
decorators = None decorators = None
shadow = False
def analyse_declarations(self, env): def analyse_declarations(self, env):
#print "CClassDefNode.analyse_declarations:", self.class_name #print "CClassDefNode.analyse_declarations:", self.class_name
...@@ -3243,7 +3253,10 @@ class CClassDefNode(ClassDefNode): ...@@ -3243,7 +3253,10 @@ class CClassDefNode(ClassDefNode):
visibility = self.visibility, visibility = self.visibility,
typedef_flag = self.typedef_flag, typedef_flag = self.typedef_flag,
api = self.api, 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': if home_scope is not env and self.visibility == 'extern':
env.add_imported_entry(self.class_name, self.entry, self.pos) env.add_imported_entry(self.class_name, self.entry, self.pos)
self.scope = scope = self.entry.type.scope self.scope = scope = self.entry.type.scope
......
...@@ -50,7 +50,7 @@ init_local_none = True ...@@ -50,7 +50,7 @@ init_local_none = True
embed = None embed = None
# Disables function redefinition, allowing all functions to be declared at # 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 disable_function_redefinition = False
......
...@@ -1018,6 +1018,16 @@ property NAME: ...@@ -1018,6 +1018,16 @@ property NAME:
return ATTR return ATTR
""", level='c_class') """, 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): def __call__(self, root):
self.env_stack = [root.scope] self.env_stack = [root.scope]
# needed to determine if a cdef var is declared after it's used. # needed to determine if a cdef var is declared after it's used.
...@@ -1100,6 +1110,116 @@ property NAME: ...@@ -1100,6 +1110,116 @@ property NAME:
node.analyse_declarations(self.env_stack[-1]) node.analyse_declarations(self.env_stack[-1])
return node 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 # Some nodes are no longer needed after declaration
# analysis and can be dropped. The analysis was performed # analysis and can be dropped. The analysis was performed
# on these nodes in a seperate recursive process from the # on these nodes in a seperate recursive process from the
...@@ -1121,9 +1241,6 @@ property NAME: ...@@ -1121,9 +1241,6 @@ property NAME:
else: else:
return None return None
def visit_CStructOrUnionDefNode(self, node):
return None
def visit_CNameDeclaratorNode(self, node): def visit_CNameDeclaratorNode(self, node):
if node.name in self.seen_vars_stack[-1]: if node.name in self.seen_vars_stack[-1]:
entry = self.env_stack[-1].lookup(node.name) entry = self.env_stack[-1].lookup(node.name)
......
...@@ -329,7 +329,7 @@ class Scope(object): ...@@ -329,7 +329,7 @@ class Scope(object):
# Return the module-level scope containing this scope. # Return the module-level scope containing this scope.
return self.outer_scope.builtin_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 # Create new entry, and add to dictionary if
# name is not None. Reports a warning if already # name is not None. Reports a warning if already
# declared. # declared.
...@@ -339,7 +339,7 @@ class Scope(object): ...@@ -339,7 +339,7 @@ class Scope(object):
# See http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html#Reserved-Names # 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) warning(pos, "'%s' is a reserved name in C." % cname, -1)
entries = self.entries entries = self.entries
if name and name in entries: if name and name in entries and not shadow:
if visibility == 'extern': if visibility == 'extern':
warning(pos, "'%s' redeclared " % name, 0) warning(pos, "'%s' redeclared " % name, 0)
elif visibility != 'ignore': elif visibility != 'ignore':
...@@ -352,6 +352,7 @@ class Scope(object): ...@@ -352,6 +352,7 @@ class Scope(object):
# entries[name].overloaded_alternatives.append(entry) # entries[name].overloaded_alternatives.append(entry)
# else: # else:
# entries[name] = entry # entries[name] = entry
if not shadow:
entries[name] = entry entries[name] = entry
entry.scope = self entry.scope = self
entry.visibility = visibility entry.visibility = visibility
...@@ -373,11 +374,11 @@ class Scope(object): ...@@ -373,11 +374,11 @@ class Scope(object):
return entry return entry
def declare_type(self, name, type, pos, 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. # Add an entry for a type definition.
if not cname: if not cname:
cname = name cname = name
entry = self.declare(name, cname, type, pos, visibility) entry = self.declare(name, cname, type, pos, visibility, shadow)
entry.is_type = 1 entry.is_type = 1
if defining: if defining:
self.type_entries.append(entry) self.type_entries.append(entry)
...@@ -1029,7 +1030,7 @@ class ModuleScope(Scope): ...@@ -1029,7 +1030,7 @@ class ModuleScope(Scope):
def declare_c_class(self, name, pos, defining = 0, implementing = 0, def declare_c_class(self, name, pos, defining = 0, implementing = 0,
module_name = None, base_type = None, objstruct_cname = None, module_name = None, base_type = None, objstruct_cname = None,
typeobj_cname = None, visibility = 'private', typedef_flag = 0, api = 0, 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 # If this is a non-extern typedef class, expose the typedef, but use
# the non-typedef struct internally to avoid needing forward # the non-typedef struct internally to avoid needing forward
# declarations for anonymous structs. # declarations for anonymous structs.
...@@ -1044,7 +1045,7 @@ class ModuleScope(Scope): ...@@ -1044,7 +1045,7 @@ class ModuleScope(Scope):
# Look for previous declaration as a type # Look for previous declaration as a type
# #
entry = self.lookup_here(name) entry = self.lookup_here(name)
if entry: if entry and not shadow:
type = entry.type type = entry.type
if not (entry.is_type and type.is_extension_type): if not (entry.is_type and type.is_extension_type):
entry = None # Will cause redeclaration and produce an error entry = None # Will cause redeclaration and produce an error
...@@ -1060,7 +1061,7 @@ class ModuleScope(Scope): ...@@ -1060,7 +1061,7 @@ class ModuleScope(Scope):
# #
# Make a new entry if needed # 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 = PyrexTypes.PyExtensionType(name, typedef_flag, base_type, visibility == 'extern')
type.pos = pos type.pos = pos
type.buffer_defaults = buffer_defaults type.buffer_defaults = buffer_defaults
...@@ -1072,7 +1073,7 @@ class ModuleScope(Scope): ...@@ -1072,7 +1073,7 @@ class ModuleScope(Scope):
type.module_name = self.qualified_name type.module_name = self.qualified_name
type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name) type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name)
entry = self.declare_type(name, type, pos, visibility = visibility, entry = self.declare_type(name, type, pos, visibility = visibility,
defining = 0) defining = 0, shadow = shadow)
entry.is_cclass = True entry.is_cclass = True
if objstruct_cname: if objstruct_cname:
type.objstruct_cname = objstruct_cname type.objstruct_cname = objstruct_cname
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment