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

First pass at struct wrappers.

parent d1904794
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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)
......
......@@ -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
......
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