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: