cython-devel
changeset 901:193fe7e34b57
cdef public extension type attributes
| author | Robert Bradshaw <robertwb@math.washington.edu> |
|---|---|
| date | Sat Aug 02 16:33:39 2008 -0700 (4 years ago) |
| parents | 6aa240bec787 |
| children | 19282c553659 |
| files | Cython/Compiler/Nodes.py Cython/Compiler/ParseTreeTransforms.py Cython/Compiler/Parsing.py Cython/Compiler/Symtab.py Cython/Compiler/TreeFragment.py |
line diff
1.1 --- a/Cython/Compiler/Nodes.py Sat Aug 02 15:04:53 2008 -0700
1.2 +++ b/Cython/Compiler/Nodes.py Sat Aug 02 16:33:39 2008 -0700
1.3 @@ -624,13 +624,27 @@
1.4 # declarators [CDeclaratorNode]
1.5 # in_pxd boolean
1.6 # api boolean
1.7 + # need_properties [entry]
1.8
1.9 child_attrs = ["base_type", "declarators"]
1.10 + need_properties = []
1.11
1.12 def analyse_declarations(self, env, dest_scope = None):
1.13 if not dest_scope:
1.14 dest_scope = env
1.15 + self.dest_scope = dest_scope
1.16 base_type = self.base_type.analyse(env)
1.17 +
1.18 + if (dest_scope.is_c_class_scope
1.19 + and self.visibility == 'public'
1.20 + and base_type.is_pyobject
1.21 + and (base_type.is_builtin_type or base_type.is_extension_type)):
1.22 + need_property = True
1.23 + visibility = 'private'
1.24 + else:
1.25 + need_property = False
1.26 + visibility = self.visibility
1.27 +
1.28 for declarator in self.declarators:
1.29 name_declarator, type = declarator.analyse(base_type, env)
1.30 if not type.is_complete():
1.31 @@ -653,8 +667,10 @@
1.32 if self.in_pxd and self.visibility != 'extern':
1.33 error(self.pos,
1.34 "Only 'extern' C variable declaration allowed in .pxd file")
1.35 - dest_scope.declare_var(name, type, declarator.pos,
1.36 - cname = cname, visibility = self.visibility, is_cdef = 1)
1.37 + entry = dest_scope.declare_var(name, type, declarator.pos,
1.38 + cname = cname, visibility = visibility, is_cdef = 1)
1.39 + if need_property:
1.40 + self.need_properties.append(entry)
1.41
1.42
1.43 class CStructOrUnionDefNode(StatNode):
2.1 --- a/Cython/Compiler/ParseTreeTransforms.py Sat Aug 02 15:04:53 2008 -0700
2.2 +++ b/Cython/Compiler/ParseTreeTransforms.py Sat Aug 02 16:33:39 2008 -0700
2.3 @@ -301,6 +301,14 @@
2.4
2.5 class AnalyseDeclarationsTransform(CythonTransform):
2.6
2.7 + basic_property = TreeFragment(u"""
2.8 +property NAME:
2.9 + def __get__(self):
2.10 + return ATTR
2.11 + def __set__(self, value):
2.12 + ATTR = value
2.13 + """, level='c_class')
2.14 +
2.15 def __call__(self, root):
2.16 self.env_stack = [root.scope]
2.17 return super(AnalyseDeclarationsTransform, self).__call__(root)
2.18 @@ -325,7 +333,22 @@
2.19 # on these nodes in a seperate recursive process from the
2.20 # enclosing function or module, so we can simply drop them.
2.21 def visit_CVarDefNode(self, node):
2.22 - return None
2.23 + if node.need_properties:
2.24 + # cdef public attributes may need type testing on
2.25 + # assignment, so we create a property accesss
2.26 + # mechanism for them.
2.27 + stats = []
2.28 + for entry in node.need_properties:
2.29 + property = self.basic_property.substitute({
2.30 + u"ATTR": AttributeNode(pos=entry.pos, obj=NameNode(pos=entry.pos, name="self"), attribute=entry.name),
2.31 + }, pos=entry.pos)
2.32 + property.stats[0].name = entry.name
2.33 + property.analyse_declarations(node.dest_scope)
2.34 + self.visit(property)
2.35 + stats.append(property)
2.36 + return StatListNode(pos=node.pos, stats=stats)
2.37 + else:
2.38 + return None
2.39
2.40 class AnalyseExpressionsTransform(CythonTransform):
2.41 def visit_ModuleNode(self, node):
3.1 --- a/Cython/Compiler/Parsing.py Sat Aug 02 15:04:53 2008 -0700
3.2 +++ b/Cython/Compiler/Parsing.py Sat Aug 02 16:33:39 2008 -0700
3.3 @@ -2299,6 +2299,15 @@
3.4 return result
3.5 else:
3.6 return None
3.7 +
3.8 +def p_code(s, level=None):
3.9 + s.add_type_name("object")
3.10 + s.add_type_name("Py_buffer")
3.11 + body = p_statement_list(s, Ctx(level = level), first_statement = 1)
3.12 + if s.sy != 'EOF':
3.13 + s.error("Syntax error in statement [%s,%s]" % (
3.14 + repr(s.sy), repr(s.systring)))
3.15 + return body
3.16
3.17 def p_module(s, pxd, full_module_name):
3.18 s.add_type_name("object")
4.1 --- a/Cython/Compiler/Symtab.py Sat Aug 02 15:04:53 2008 -0700
4.2 +++ b/Cython/Compiler/Symtab.py Sat Aug 02 16:33:39 2008 -0700
4.3 @@ -1457,7 +1457,9 @@
4.4 return entry
4.5
4.6 def declare_property(self, name, doc, pos):
4.7 - entry = self.declare(name, name, py_object_type, pos)
4.8 + entry = self.lookup_here(name)
4.9 + if entry is None:
4.10 + entry = self.declare(name, name, py_object_type, pos)
4.11 entry.is_property = 1
4.12 entry.doc = doc
4.13 entry.scope = PropertyScope(name,
5.1 --- a/Cython/Compiler/TreeFragment.py Sat Aug 02 15:04:53 2008 -0700
5.2 +++ b/Cython/Compiler/TreeFragment.py Sat Aug 02 16:33:39 2008 -0700
5.3 @@ -28,7 +28,7 @@
5.4 raise AssertionError("Not yet supporting any cimports/includes from string code snippets")
5.5 return ModuleScope(module_name, parent_module = None, context = self)
5.6
5.7 -def parse_from_strings(name, code, pxds={}):
5.8 +def parse_from_strings(name, code, pxds={}, level=None):
5.9 """
5.10 Utility method to parse a (unicode) string of code. This is mostly
5.11 used for internal Cython compiler purposes (creating code snippets
5.12 @@ -56,7 +56,10 @@
5.13
5.14 scanner = PyrexScanner(buf, code_source, source_encoding = encoding,
5.15 scope = scope, context = context)
5.16 - tree = Parsing.p_module(scanner, 0, module_name)
5.17 + if level is None:
5.18 + tree = Parsing.p_module(scanner, 0, module_name)
5.19 + else:
5.20 + tree = Parsing.p_code(scanner, level=level)
5.21 return tree
5.22
5.23 class TreeCopier(VisitorTransform):
5.24 @@ -171,7 +174,7 @@
5.25 return lines
5.26
5.27 class TreeFragment(object):
5.28 - def __init__(self, code, name="(tree fragment)", pxds={}, temps=[], pipeline=[]):
5.29 + def __init__(self, code, name="(tree fragment)", pxds={}, temps=[], pipeline=[], level=None):
5.30 if isinstance(code, unicode):
5.31 def fmt(x): return u"\n".join(strip_common_indent(x.split(u"\n")))
5.32
5.33 @@ -180,9 +183,9 @@
5.34 for key, value in pxds.iteritems():
5.35 fmt_pxds[key] = fmt(value)
5.36
5.37 - t = parse_from_strings(name, fmt_code, fmt_pxds)
5.38 - mod = t
5.39 - t = t.body # Make sure a StatListNode is at the top
5.40 + mod = t = parse_from_strings(name, fmt_code, fmt_pxds, level=level)
5.41 + if level is None:
5.42 + t = t.body # Make sure a StatListNode is at the top
5.43 if not isinstance(t, StatListNode):
5.44 t = StatListNode(pos=mod.pos, stats=[t])
5.45 for transform in pipeline:
