Partial merge of trunk progress. Some tests still fail.
[cython.git] / Cython / Compiler / ParseTreeTransforms.py
index f99f699988b606db73cf0431befbd7fef08eb083..a660db1337a90edea8309db24639188cebec3831 100644 (file)
@@ -11,11 +11,12 @@ import Naming
 import ExprNodes
 import Nodes
 import Options
+import Builtin
 
 from Cython.Compiler.Visitor import VisitorTransform, TreeVisitor
 from Cython.Compiler.Visitor import CythonTransform, EnvTransform, ScopeTrackingTransform
 from Cython.Compiler.ModuleNode import ModuleNode
-from Cython.Compiler.UtilNodes import LetNode, LetRefNode
+from Cython.Compiler.UtilNodes import LetNode, LetRefNode, ResultRefNode
 from Cython.Compiler.TreeFragment import TreeFragment, TemplateTransform
 from Cython.Compiler.StringEncoding import EncodedString
 from Cython.Compiler.Errors import error, warning, CompileError, InternalError
@@ -193,9 +194,8 @@ class PostParse(ScopeTrackingTransform):
         collector = YieldNodeCollector()
         collector.visitchildren(node.result_expr)
         if collector.yields or isinstance(node.result_expr, ExprNodes.YieldExprNode):
-            body = ExprNodes.YieldExprNode(
-                node.result_expr.pos, arg=node.result_expr)
-            body = Nodes.ExprStatNode(node.result_expr.pos, expr=body)
+            body = Nodes.ExprStatNode(
+                node.result_expr.pos, expr=node.result_expr)
         else:
             body = Nodes.ReturnStatNode(
                 node.result_expr.pos, value=node.result_expr)
@@ -552,7 +552,7 @@ class PxdPostParse(CythonTransform, SkipDeclarations):
         if isinstance(node, Nodes.CFuncDefNode):
             if u'inline' in node.modifiers and self.scope_type == 'pxd':
                 node.inline_in_pxd = True
-                if node.visibility != 'private':
+                if node.c_visibility != 'private':
                     err = self.ERR_NOGO_WITH_INLINE % node.visibility
                 elif node.api:
                     err = self.ERR_NOGO_WITH_INLINE % 'api'
@@ -898,81 +898,55 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations):
         return self.visit_Node(node)
 
 class WithTransform(CythonTransform, SkipDeclarations):
-
-    # EXCINFO is manually set to a variable that contains
-    # the exc_info() tuple that can be generated by the enclosing except
-    # statement.
-    template_without_target = TreeFragment(u"""
-        MGR = EXPR
-        EXIT = MGR.__exit__
-        MGR.__enter__()
-        EXC = True
-        try:
-            try:
-                EXCINFO = None
-                BODY
-            except:
-                EXC = False
-                if not EXIT(*EXCINFO):
-                    raise
-        finally:
-            if EXC:
-                EXIT(None, None, None)
-    """, temps=[u'MGR', u'EXC', u"EXIT"],
-    pipeline=[NormalizeTree(None)])
-
-    template_with_target = TreeFragment(u"""
-        MGR = EXPR
-        EXIT = MGR.__exit__
-        VALUE = MGR.__enter__()
-        EXC = True
-        try:
-            try:
-                EXCINFO = None
-                TARGET = VALUE
-                BODY
-            except:
-                EXC = False
-                if not EXIT(*EXCINFO):
-                    raise
-        finally:
-            if EXC:
-                EXIT(None, None, None)
-            MGR = EXIT = VALUE = EXC = None
-
-    """, temps=[u'MGR', u'EXC', u"EXIT", u"VALUE"],
-    pipeline=[NormalizeTree(None)])
-
     def visit_WithStatNode(self, node):
-        # TODO: Cleanup badly needed
-        TemplateTransform.temp_name_counter += 1
-        handle = "__tmpvar_%d" % TemplateTransform.temp_name_counter
-
-        self.visitchildren(node, ['body'])
-        excinfo_temp = ExprNodes.NameNode(node.pos, name=handle)#TempHandle(Builtin.tuple_type)
-        if node.target is not None:
-            result = self.template_with_target.substitute({
-                u'EXPR' : node.manager,
-                u'BODY' : node.body,
-                u'TARGET' : node.target,
-                u'EXCINFO' : excinfo_temp
-                }, pos=node.pos)
-        else:
-            result = self.template_without_target.substitute({
-                u'EXPR' : node.manager,
-                u'BODY' : node.body,
-                u'EXCINFO' : excinfo_temp
-                }, pos=node.pos)
-
-        # Set except excinfo target to EXCINFO
-        try_except = result.stats[-1].body.stats[-1]
-        try_except.except_clauses[0].excinfo_target = ExprNodes.NameNode(node.pos, name=handle)
-#            excinfo_temp.ref(node.pos))
-
-#        result.stats[-1].body.stats[-1] = TempsBlockNode(
-#            node.pos, temps=[excinfo_temp], body=try_except)
-
-        return result
+        self.visitchildren(node, 'body')
+        pos = node.pos
+        body, target, manager = node.body, node.target, node.manager
+        node.target_temp = ExprNodes.TempNode(pos, type=PyrexTypes.py_object_type)
+        if target is not None:
+            node.has_target = True
+            body = Nodes.StatListNode(
+                pos, stats = [
+                    Nodes.WithTargetAssignmentStatNode(
+                        pos, lhs = target, rhs = node.target_temp),
+                    body
+                    ])
+            node.target = None
+
+        excinfo_target = ResultRefNode(
+            pos=pos, type=Builtin.tuple_type, may_hold_none=False)
+        except_clause = Nodes.ExceptClauseNode(
+            pos, body = Nodes.IfStatNode(
+                pos, if_clauses = [
+                    Nodes.IfClauseNode(
+                        pos, condition = ExprNodes.NotNode(
+                            pos, operand = ExprNodes.WithExitCallNode(
+                                pos, with_stat = node,
+                                args = excinfo_target)),
+                        body = Nodes.ReraiseStatNode(pos),
+                        ),
+                    ],
+                else_clause = None),
+            pattern = None,
+            target = None,
+            excinfo_target = excinfo_target,
+            )
+
+        node.body = Nodes.TryFinallyStatNode(
+            pos, body = Nodes.TryExceptStatNode(
+                pos, body = body,
+                except_clauses = [except_clause],
+                else_clause = None,
+                ),
+            finally_clause = Nodes.ExprStatNode(
+                pos, expr = ExprNodes.WithExitCallNode(
+                    pos, with_stat = node,
+                    args = ExprNodes.TupleNode(
+                        pos, args = [ExprNodes.NoneNode(pos) for _ in range(3)]
+                        ))),
+            handle_error_case = False,
+            )
+        return node
 
     def visit_ExprNode(self, node):
         # With statements are never inside expressions.
@@ -1124,7 +1098,7 @@ if VALUE is not None:
             if not lenv.lookup_here(var):   # don't redeclare args
                 type = type_node.analyse_as_type(lenv)
                 if type:
-                    lenv.declare_var(var, type, type_node.pos)
+                    lenv.declare_var(name = var, type = type, pos = type_node.pos)
                 else:
                     error(type_node.pos, "Not a type")
         node.body.analyse_declarations(lenv)
@@ -1212,7 +1186,7 @@ if VALUE is not None:
             arg = copy.deepcopy(arg_template)
             arg.declarator.name = entry.name
             init_method.args.append(arg)
-            
+
         # setters/getters
         for entry, attr in zip(var_entries, attributes):
             # TODO: branch on visibility
@@ -1225,7 +1199,7 @@ if VALUE is not None:
                 }, pos = entry.pos).stats[0]
             property.name = entry.name
             wrapper_class.body.stats.append(property)
-            
+
         wrapper_class.analyse_declarations(self.env_stack[-1])
         return self.visit_CClassDefNode(wrapper_class)
 
@@ -1253,7 +1227,7 @@ if VALUE is not None:
     def visit_CNameDeclaratorNode(self, node):
         if node.name in self.seen_vars_stack[-1]:
             entry = self.env_stack[-1].lookup(node.name)
-            if (entry is None or entry.visibility != 'extern'
+            if (entry is None or entry.c_visibility != 'extern'
                 and not entry.scope.is_c_class_scope):
                 warning(node.pos, "cdef variable '%s' declared after it is used" % node.name, 2)
         self.visitchildren(node)
@@ -1272,6 +1246,10 @@ if VALUE is not None:
                 template = self.basic_property
         elif entry.visibility == 'readonly':
             template = self.basic_property_ro
+        else:
+            error(entry.pos,
+                  "python methods may not have '%s' Python visibility" %
+                  entry.visibility)
         property = template.substitute({
                 u"ATTR": ExprNodes.AttributeNode(pos=entry.pos,
                                                  obj=ExprNodes.NameNode(pos=entry.pos, name="self"),
@@ -1553,29 +1531,39 @@ class CreateClosureClasses(CythonTransform):
                                                    PyrexTypes.c_void_ptr_type,
                                                    '__pyx_generator_body_t')
         klass.declare_var(pos=pos, name='body', cname='body',
-                          type=body_type, is_cdef=True)
+                          visibility='private', type=body_type, is_cdef=True)
         klass.declare_var(pos=pos, name='is_running', cname='is_running', type=PyrexTypes.c_int_type,
                           is_cdef=True)
         klass.declare_var(pos=pos, name='resume_label', cname='resume_label', type=PyrexTypes.c_int_type,
                           is_cdef=True)
+        klass.declare_var(pos=pos, name='exc_type', cname='exc_type',
+                          type=PyrexTypes.py_object_type, is_cdef=True)
+        klass.declare_var(pos=pos, name='exc_value', cname='exc_value',
+                          type=PyrexTypes.py_object_type, is_cdef=True)
+        klass.declare_var(pos=pos, name='exc_traceback', cname='exc_traceback',
+                          type=PyrexTypes.py_object_type, is_cdef=True)
 
         import TypeSlots
-        e = klass.declare_pyfunction('send', pos)
+        e = klass.declare_pyfunction(name='send', pos=pos)
         e.func_cname = '__Pyx_Generator_Send'
         e.signature = TypeSlots.binaryfunc
 
-        e = klass.declare_pyfunction('close', pos)
+        e = klass.declare_pyfunction(name='close', pos=pos)
         e.func_cname = '__Pyx_Generator_Close'
         e.signature = TypeSlots.unaryfunc
 
-        e = klass.declare_pyfunction('throw', pos)
+        e = klass.declare_pyfunction(name='throw', pos=pos)
         e.func_cname = '__Pyx_Generator_Throw'
         e.signature = TypeSlots.pyfunction_signature
 
-        e = klass.declare_var('__iter__', PyrexTypes.py_object_type, pos, visibility='public')
+        e = klass.declare_var(
+            name='__iter__', type=PyrexTypes.py_object_type,
+            c_visibility='public', pos=pos)
         e.func_cname = 'PyObject_SelfIter'
 
-        e = klass.declare_var('__next__', PyrexTypes.py_object_type, pos, visibility='public')
+        e = klass.declare_var(
+            name='__next__', type=PyrexTypes.py_object_type,
+            c_visibility='public', pos=pos)
         e.func_cname = '__Pyx_Generator_Next'
 
         self.generator_class = entry.type