[svn] r6013: nemerle/trunk/ncc: generation/ILEmitter.n generation/Typer3.n generation/Typer4.n misc/Pretty...

malekith svnadmin at nemerle.org
Sat Dec 17 23:09:06 CET 2005


Log:
Properly handle finally clauses in iterators.

Author: malekith
Date: Sat Dec 17 23:09:02 2005
New Revision: 6013

Modified:
   nemerle/trunk/ncc/generation/ILEmitter.n
   nemerle/trunk/ncc/generation/Typer3.n
   nemerle/trunk/ncc/generation/Typer4.n
   nemerle/trunk/ncc/misc/PrettyPrint.n
   nemerle/trunk/ncc/testsuite/positive/yield-tree.n
   nemerle/trunk/ncc/typing/TypedTree.n
   nemerle/trunk/ncc/typing/Typer.n
   nemerle/trunk/ncc/typing/Typer2.n

Modified: nemerle/trunk/ncc/generation/ILEmitter.n
==============================================================================
--- nemerle/trunk/ncc/generation/ILEmitter.n	(original)
+++ nemerle/trunk/ncc/generation/ILEmitter.n	Sat Dec 17 23:09:02 2005
@@ -1166,7 +1166,8 @@
 
 
         /* emit the try/with construction */
-        | TryWith (try_expr, catch_val, catch_expr) =>
+        | TryWith (try_expr, catch_val, catch_expr)
+        | TryFault (try_expr, catch_expr) with catch_val = null =>
           def type_of_try_expr = expr.SystemType;
 
           def ignore_try_with_result = is_void (try_expr.Type);
@@ -1182,6 +1183,10 @@
           unless (try_expr.Throws || ignore_try_with_result)
             _ilg.Emit (OpCodes.Stloc, try_result);
 
+          if (catch_val == null) {
+            _ilg.BeginFaultBlock ();
+            emit (catch_expr);
+          } else {
           _ilg.BeginCatchBlock (catch_val.Type.SystemType);
 
           def catch_val_local_slot = declare_val_local_slot (catch_val);
@@ -1193,6 +1198,7 @@
 
           unless (catch_expr.Throws || ignore_try_with_result)
             _ilg.Emit (OpCodes.Stloc, try_result);
+          }
 
           _ilg.EndExceptionBlock ();
 

Modified: nemerle/trunk/ncc/generation/Typer3.n
==============================================================================
--- nemerle/trunk/ncc/generation/Typer3.n	(original)
+++ nemerle/trunk/ncc/generation/Typer3.n	Sat Dec 17 23:09:02 2005
@@ -430,10 +430,11 @@
     {
       if (hd.usage == FunctionUsage.UsedJustOnce) {
         ClosureRef (hd.decl.DefinedIn)
-      } else if (current_method.name == "_N_yielding_function") {
+      } else if (current_method.is_in_closure_of != 0) {
         // Message.Debug ($ "lookup $(hd.name) from $(current_method.name)");
-        Util.cassert (hd.id == current_method.id ||
-                      current_method.decl.DefinedIn.id == hd.id);
+        Util.cassert (hd.id == current_method.is_in_closure_of ||
+                      (current_method.decl != null && 
+                       current_method.decl.DefinedIn.id == hd.id));
         TExpr.This (local_function_type.GetMemType ())
       } else if (hd.id == current_method.id) {
         PlainRef (current_closure)
@@ -674,7 +675,7 @@
 
           public Dispose () : void
           {
-            this._N_state = -1;
+            foobar
           }
 
           public Reset () : void
@@ -684,23 +685,90 @@
 
           public MoveNext () : bool
           {
+            foobar
           }
         }
       ]>
     }
 
+    static RewriteTryFinally (clo_type : TypeBuilder, fh : Fun_header) : void
+    {
+      mutable dispose_expr = Typer.VoidLiteral ();
+
+      def thisref = TExpr.This (clo_type.GetMemType ());
+
+      def rewrite (expr : TExpr) {
+        | TryFinally (body, handler) =>
+          def fld = clo_type.DefineAndReturn (<[ decl: 
+            mutable $(Macros.NewSymbol ("finally_needed") : name) : bool;
+          ]>) :> IField;
+          fld.HasBeenAssigned = true;
+          fld.HasBeenUsed = true;
+          def fldref = TExpr.FieldMember (InternalType.Boolean, thisref, fld);
+          def for_dispose =
+            TExpr.If (InternalType.Void, fldref, handler, Typer.VoidLiteral ());
+          dispose_expr = TExpr.Sequence (dispose_expr.Type, for_dispose, dispose_expr);
+          
+          BuildRevSequence (
+             [handler, 
+              TExpr.Assign (InternalType.Void, fldref, TExpr.FalseLiteral),
+              body.Walk (rewrite),
+              TExpr.Assign (InternalType.Void, fldref, TExpr.TrueLiteral)])
 
-    SetEnumeratorBody (clo_type : TypeInfo, subst : Subst) : void
+        | _ => null
+      }
+      
+      match (fh.body) {
+        | FunBody.Typed (expr) =>
+          def expr = expr.Walk (rewrite);
+          
+          def dispose_meth =
+            SingleMemberLookup (clo_type, "Dispose") :> IMethod;
+          def dispose_call = 
+            TExpr.Call (InternalType.Void,
+                        TExpr.MethodRef (dispose_meth.GetMemType (),
+                                         thisref, dispose_meth, [], true), 
+                        [], false);
+          def expr = TExpr.TryFault (expr.Type, expr, dispose_call);
+          fh.body = FunBody.Typed (expr);
+          
+          def this_N_state =
+            TExpr.FieldMember (InternalType.Int32, thisref,
+                               SingleMemberLookup (clo_type, "_N_state") :> IField);
+          dispose_expr =
+            TExpr.Sequence (InternalType.Void,
+              TExpr.Assign (InternalType.Void,
+                            this_N_state, 
+                            TExpr.Literal (InternalType.Int32,
+                                           Literal.FromInt (-1))),
+              dispose_expr);
+          dispose_meth.GetHeader ().body = FunBody.Typed (dispose_expr);
+          
+        | _ => Util.ice ()
+      }
+    }
+
+
+    SetEnumeratorBody (clo_type : TypeBuilder, subst : Subst) : void
     {
       match (current_local_fun.body) {
         | FunBody.Typed (DefValIn (_, _, DefValIn (_, _, DefFunctionsIn ([fh], _)))) =>
           def meth = SingleMemberLookup (clo_type, "MoveNext") :> MethodBuilder;
+          RewriteTryFinally (clo_type, fh);
           fh.used_closures = fh.GetParents ();
+          fh.is_in_closure_of = fh.id;
           PrepareForEmission (meth, fh, subst);
           def child = Typer3 (this, meth);
           child.current_subst = subst;
           child.Run ();
 
+          def meth = SingleMemberLookup (clo_type, "Dispose") :> MethodBuilder;
+          meth.GetHeader ().used_closures = fh.GetParents ();
+          meth.GetHeader ().is_in_closure_of = fh.id;
+          def child = Typer3 (this, meth);
+          child.current_subst = subst;
+          child.Run ();
+
           current_local_fun.body = FunBody.Typed (PlainRef (current_closure));
 
         | FunBody.Typed (t)
@@ -784,11 +852,12 @@
                       
         clo_type.MarkWithSpecialName ();
         clo_type.HasBeenUsed = true;
-        clo_type.Compile ();
 
         when (uses_yield)
           SetEnumeratorBody (clo_type, subst);
 
+        clo_type.Compile ();
+
         [TExpr.DefValIn (InternalType.Void, closure_val, ctor_call, null)]
       }
     }
@@ -1612,6 +1681,7 @@
         | Assign
         | Throw
         | TryFinally
+        | TryFault
         | Literal
         | This
         | Base

Modified: nemerle/trunk/ncc/generation/Typer4.n
==============================================================================
--- nemerle/trunk/ncc/generation/Typer4.n	(original)
+++ nemerle/trunk/ncc/generation/Typer4.n	Sat Dec 17 23:09:02 2005
@@ -378,6 +378,7 @@
             exprs.Iter (NoThrowPlease);
             false
 
+          | TryFault (body, handler)
           | TryWith (body, _, handler)
           | TryFinally (body, handler) =>
             when (! allow_try)
@@ -632,6 +633,9 @@
           | TryFinally (body, handler) =>
             TExpr.TryFinally (WalkTry (body), Walk (handler))
 
+          | TryFault (body, handler) =>
+            TExpr.TryFault (WalkTry (body), Walk (handler))
+
           | Goto as g =>
             g.try_block = current_try_block;
             null

Modified: nemerle/trunk/ncc/misc/PrettyPrint.n
==============================================================================
--- nemerle/trunk/ncc/misc/PrettyPrint.n	(original)
+++ nemerle/trunk/ncc/misc/PrettyPrint.n	Sat Dec 17 23:09:02 2005
@@ -1092,6 +1092,13 @@
           append ("throw ");
           recurse (exn)
           
+        | TT.TExpr.TryFault (body, handler) =>
+          append ("try {\n");
+          recurse_and_indent (body);
+          append ("\n" + indentation + "} fault {\n");
+          recurse_and_indent (handler);
+          append ("\n" + indentation + "}")
+        
         | TT.TExpr.TryWith (body /* PExpr */, exn /* LocalValue */, handler /* PExpr */) =>
           append ("try {\n");
           recurse_and_indent (body);

Modified: nemerle/trunk/ncc/testsuite/positive/yield-tree.n
==============================================================================
--- nemerle/trunk/ncc/testsuite/positive/yield-tree.n	(original)
+++ nemerle/trunk/ncc/testsuite/positive/yield-tree.n	Sat Dec 17 23:09:02 2005
@@ -35,3 +35,19 @@
   
 foreach (e in n2)
   System.Console.WriteLine (e)
+
+/*
+BEGIN-OUTPUT
+1
+2
+22
+33
+82
+chinczyk
+due
+ene
+rabe
+zabe
+zlapal
+END-OUTPUT
+*/

Modified: nemerle/trunk/ncc/typing/TypedTree.n
==============================================================================
--- nemerle/trunk/ncc/typing/TypedTree.n	(original)
+++ nemerle/trunk/ncc/typing/TypedTree.n	Sat Dec 17 23:09:02 2005
@@ -223,6 +223,7 @@
     internal mutable children_funs : list [Fun_header] = [];
     internal mutable uses_try_block : bool;
     internal mutable yield_type : TyVar;
+    internal mutable is_in_closure_of : int;
 
     // FIXME: move to hashtables in t3
     internal mutable used_closures : list [Fun_header];
@@ -430,6 +431,7 @@
     | Assign                { target : TExpr; source : TExpr; }
     | DefValIn              { name : LocalValue; val : TExpr; mutable body : TExpr; }
     | Throw                 { exn : TExpr; }
+    | TryFault              { body : TExpr; handler : TExpr; }
     | TryWith               { body : TExpr; exn : LocalValue; handler : TExpr; }
     | TryFinally            { body : TExpr; handler : TExpr; }
     | Literal               { val : Nemerle.Compiler.Literal; }
@@ -879,6 +881,10 @@
           TryFinally (walk (f, body), walk (f, handler))
           
 
+        | TryFault (body, handler) =>
+          TryFault (walk (f, body), walk (f, handler))
+          
+
         | TypeConversion (expr, t, kind) =>
           def expr = null_walk (f, expr);
           if (expr == null) null

Modified: nemerle/trunk/ncc/typing/Typer.n
==============================================================================
--- nemerle/trunk/ncc/typing/Typer.n	(original)
+++ nemerle/trunk/ncc/typing/Typer.n	Sat Dec 17 23:09:02 2005
@@ -629,7 +629,7 @@
     }
 
 
-    static VoidLiteral () : TExpr
+    static internal VoidLiteral () : TExpr
     {
       TExpr.Literal (InternalType.Void, Literal.Void ())
     }
@@ -3243,6 +3243,7 @@
             | _ => "a yet-untyped expression"
           }
 
+        | TExpr.TryFault
         | TExpr.NotNull
         | TExpr.Switch
         | TExpr.DefaultValue

Modified: nemerle/trunk/ncc/typing/Typer2.n
==============================================================================
--- nemerle/trunk/ncc/typing/Typer2.n	(original)
+++ nemerle/trunk/ncc/typing/Typer2.n	Sat Dec 17 23:09:02 2005
@@ -1215,6 +1215,7 @@
         | TExpr.DefaultValue => null
 
        
+        | TExpr.TryFault
         | TExpr.NotNull
         | TExpr.Switch
         | TExpr.MultipleAssign



More information about the svn mailing list