On Mon, Mar 16, 2009 at 3:40 AM, Dag Sverre Seljebotn <[email protected]> wrote: [snip] > > Great that you're making progress. > > Yes, there is something I'd rather tell you about this :-) The transform > works by recursive descent, and when a node type is intercepted, one > needs to actively visit the children as well. > > This is done by self.visitchildren(node); see in visit_FuncDefNode for > an example. Since visitchildren is never called in CVarDefNode, the > children of CVarDefNode are never visited. > > Also, the node will be replaced with whatever it returns. > visit_CVarDefNode returns None so that the entire declaration is removed > from the tree, as it is no longer needed (which is why one isn't > analysing the children as well). > > (Depending on what you need this for, you could be able to extract the > information from the attributes of the enclosing FuncDefNode; I think > there's a Scope there somewhere which you can inspect the entries of.)
Thanks again for the guidance. I have a patch for review -- it involves adding self.visitchildren(node) in some methods and adding a visit_CNameDeclaratorNode() method along with the discussed visit_NameNode() method. It also adds a declareafteruse_T158.pyx file to tests/errors. Let me know if this along the lines of what you were thinking & how it can be improved. (Normally I'd attach this patch to the trac ticket but I thought some feedback would be good.) Kurt
# HG changeset patch # User Kurt Smith <[email protected]> # Date 1237266166 18000 # Node ID 7a7106c2d6265e4382391497bd95adc6c0b9a117 # Parent 20a831e704ada40563fcd6607665bf33b2bb2801 Bug 158 -- raise error if cdef variable declared after it's used. diff -r 20a831e704ad -r 7a7106c2d626 Cython/Compiler/ParseTreeTransforms.py --- a/Cython/Compiler/ParseTreeTransforms.py Sat Mar 14 18:12:20 2009 +0100 +++ b/Cython/Compiler/ParseTreeTransforms.py Tue Mar 17 00:02:46 2009 -0500 @@ -658,6 +658,8 @@ class DecoratorTransform(CythonTransform rhs = decorator_result) return [func_node, reassignment] + +ERR_DEC_AFTER = "cdef variable '%s' declared after it's used." class AnalyseDeclarationsTransform(CythonTransform): basic_property = TreeFragment(u""" @@ -670,14 +672,23 @@ property NAME: def __call__(self, root): self.env_stack = [root.scope] + # needed to determine if a cdef var is declared after it's used. + self.local_scope_stack = [] return super(AnalyseDeclarationsTransform, self).__call__(root) + def visit_NameNode(self, node): + self.local_scope_stack[-1].add(node.name) + return node + def visit_ModuleNode(self, node): + self.local_scope_stack.append(set()) node.analyse_declarations(self.env_stack[-1]) self.visitchildren(node) + self.local_scope_stack.pop() return node def visit_FuncDefNode(self, node): + self.local_scope_stack.append(set()) lenv = node.create_local_scope(self.env_stack[-1]) node.body.analyse_control_flow(lenv) # this will be totally refactored node.declare_arguments(lenv) @@ -692,6 +703,7 @@ property NAME: self.env_stack.append(lenv) self.visitchildren(node) self.env_stack.pop() + self.local_scope_stack.pop() return node # Some nodes are no longer needed after declaration @@ -699,6 +711,8 @@ property NAME: # on these nodes in a seperate recursive process from the # enclosing function or module, so we can simply drop them. def visit_CDeclaratorNode(self, node): + # necessary to ensure that all CNameDeclaratorNodes are visited. + self.visitchildren(node) return node def visit_CTypeDefNode(self, node): @@ -713,7 +727,18 @@ property NAME: def visit_CStructOrUnionDefNode(self, node): return None + def visit_CNameDeclaratorNode(self, node): + if node.name in self.local_scope_stack[-1]: + # cdef variable declared after it's used. + error(node.pos, ERR_DEC_AFTER % node.name) + self.visitchildren(node) + return node + def visit_CVarDefNode(self, node): + + # to ensure all CNameDeclaratorNodes are visited. + self.visitchildren(node) + if node.need_properties: # cdef public attributes may need type testing on # assignment, so we create a property accesss diff -r 20a831e704ad -r 7a7106c2d626 tests/errors/declareafteruse_T158.pyx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/errors/declareafteruse_T158.pyx Tue Mar 17 00:02:46 2009 -0500 @@ -0,0 +1,65 @@ +def mult_decl_test(): + print "%s" % vv + print "%s" % s + cdef str s, vv = "Test" + +def def_test(): + cdef int j = 10 + i[0] = j + cdef int *i = NULL # pointer variables are special case + +cdef cdef_test(): + cdef int j = 10 + i[0] = j + print "%d" % i[0] + cdef int *i = NULL + +cpdef cpdef_test(): + cdef int j = 10 + i[0] = j + print "%d" % i[0] + cdef int *i = NULL + +s.upper() +cdef str s = "Test" + +class Foo(object): + def bar(self, x, y): + cdef unsigned long w = 20 + z = w + t + cdef int t = 10 + +cdef class Foo2(object): + print '%s' % r # check error inside class scope + cdef str r + def bar(self, x, y): + cdef unsigned long w = 20 + self.r = c'r' + print self.r + z = w + g(t) + cdef int t = 10 + +def g(x): + return x + +cdef int d = 20 +baz[0] = d +cdef int *baz + +print var[0][0] +cdef unsigned long long var[100][100] + + +_ERRORS = u""" +4:13: cdef variable 's' declared after it's used. +4:16: cdef variable 'vv' declared after it's used. +9:14: cdef variable 'i' declared after it's used. +15:14: cdef variable 'i' declared after it's used. +21:14: cdef variable 'i' declared after it's used. +24:9: cdef variable 's' declared after it's used. +30:17: cdef variable 't' declared after it's used. +34:13: cdef variable 'r' declared after it's used. +40:17: cdef variable 't' declared after it's used. +47:10: cdef variable 'baz' declared after it's used. +50:24: cdef variable 'var' declared after it's used. +"""
_______________________________________________ Cython-dev mailing list [email protected] http://codespeak.net/mailman/listinfo/cython-dev
