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

Reply via email to