[svn] r5992: nemerle/trunk: boot/Nemerle.Compiler.dll boot/Nemerle.Macros.dll boot/Nemerle.dll boot/ncc.ex...

malekith svnadmin at nemerle.org
Sun Dec 4 12:47:52 CET 2005


Log:
Yield implementation: the simplest example seems to work. Moving local variables to the class level and this-masquarading doesn't yet work.

Author: malekith
Date: Sun Dec  4 12:47:27 2005
New Revision: 5992

Added:
   nemerle/trunk/ncc/testsuite/negative/yield.n
   nemerle/trunk/ncc/testsuite/negative/yield2.n
   nemerle/trunk/ncc/testsuite/positive/yield.n
Modified:
   nemerle/trunk/boot/Nemerle.Compiler.dll
   nemerle/trunk/boot/Nemerle.Macros.dll
   nemerle/trunk/boot/Nemerle.dll
   nemerle/trunk/boot/ncc.exe
   nemerle/trunk/macros/core.n
   nemerle/trunk/ncc/external/InternalTypes.n
   nemerle/trunk/ncc/generation/Typer3.n
   nemerle/trunk/ncc/generation/Typer4.n
   nemerle/trunk/ncc/hierarchy/ClassMembers.n
   nemerle/trunk/ncc/misc/PrettyPrint.n
   nemerle/trunk/ncc/typing/TypedTree.n
   nemerle/trunk/ncc/typing/Typer.n
   nemerle/trunk/ncc/typing/Typer2.n

Modified: nemerle/trunk/boot/Nemerle.Compiler.dll
==============================================================================
Binary files. No diff available.

Modified: nemerle/trunk/boot/Nemerle.Macros.dll
==============================================================================
Binary files. No diff available.

Modified: nemerle/trunk/boot/Nemerle.dll
==============================================================================
Binary files. No diff available.

Modified: nemerle/trunk/boot/ncc.exe
==============================================================================
Binary files. No diff available.

Modified: nemerle/trunk/macros/core.n
==============================================================================
--- nemerle/trunk/macros/core.n	(original)
+++ nemerle/trunk/macros/core.n	Sun Dec  4 12:47:27 2005
@@ -132,6 +132,14 @@
     <[ dont_use_me ($expr) ]>
   }
   
+  
+  /// Yet another syntax extender.
+  macro @yield (expr = null)
+    syntax ("yield", expr)
+  {
+    <[ dont_use_me ($expr) ]>
+  }
+  
   /** specialized macro for [if] condition with good warning messages,
       it performs typing of given expressions to check their type
       correctness

Modified: nemerle/trunk/ncc/external/InternalTypes.n
==============================================================================
--- nemerle/trunk/ncc/external/InternalTypes.n	(original)
+++ nemerle/trunk/ncc/external/InternalTypes.n	Sun Dec  4 12:47:27 2005
@@ -383,6 +383,7 @@
   public mutable Nemerle_list_tc : TypeInfo;
   public mutable IEnumerable_tc : TypeInfo;
   public mutable Generic_IEnumerable_tc : TypeInfo;
+  public mutable Generic_IEnumerator_tc : TypeInfo;
   public mutable DllImport_tc : TypeInfo;
   public mutable Serializable_tc : TypeInfo;    
 
@@ -527,6 +528,7 @@
     ValueType_tc = lookup ("System.ValueType"); ValueType = MType.Class (ValueType_tc, []);
     IEnumerable_tc = lookup ("System.Collections.IEnumerable");
     Generic_IEnumerable_tc = lookup ("System.Collections.Generic.IEnumerable");
+    Generic_IEnumerator_tc = lookup ("System.Collections.Generic.IEnumerator");
     DllImport_tc = lookup ("System.Runtime.InteropServices.DllImportAttribute");
     Serializable_tc = lookup ("System.SerializableAttribute");    
     IObjectReference = MType.Class (lookup ("System.Runtime.Serialization.IObjectReference"), []);

Modified: nemerle/trunk/ncc/generation/Typer3.n
==============================================================================
--- nemerle/trunk/ncc/generation/Typer3.n	(original)
+++ nemerle/trunk/ncc/generation/Typer3.n	Sun Dec  4 12:47:27 2005
@@ -230,7 +230,7 @@
     }
 
 
-    static SingleMemberLookup (tb : TypeInfo, name : string) : IMember
+    static internal SingleMemberLookup (tb : TypeInfo, name : string) : IMember
     {
       match (tb.LookupMember (name)) {
         | [mem] => mem
@@ -1575,7 +1575,6 @@
         | DefFunctionsIn
         | Match
         | SelfTailCall 
-        | Yield
         | Block =>
           Util.cassert (Message.SeenError);
           null

Modified: nemerle/trunk/ncc/generation/Typer4.n
==============================================================================
--- nemerle/trunk/ncc/generation/Typer4.n	(original)
+++ nemerle/trunk/ncc/generation/Typer4.n	Sun Dec  4 12:47:27 2005
@@ -309,7 +309,6 @@
           | DefFunctionsIn
           | Match
           | Block
-          | Yield
           | SelfTailCall =>
             Util.cassert (Message.SeenError);
             false

Modified: nemerle/trunk/ncc/hierarchy/ClassMembers.n
==============================================================================
--- nemerle/trunk/ncc/hierarchy/ClassMembers.n	(original)
+++ nemerle/trunk/ncc/hierarchy/ClassMembers.n	Sun Dec  4 12:47:27 2005
@@ -598,6 +598,8 @@
 
   internal mutable overridden_method : IMethod;
 
+  internal yield_stuff : option [PT.PExpr * list [PT.Fun_parm]] = None ();
+
   is_var_args : bool;
 
   public GetMethodBase () : MethodBase
@@ -710,7 +712,7 @@
       when (t is <[ _ ]>)
         Message.Error (t.Location, "type inference on global methods is not yet supported");
       def ty = par.MonoBindType (tenv', t);
-      types_to_check = ty :: types_to_check;
+      types_to_check ::= ty;
       ty
     }
 
@@ -846,8 +848,21 @@
         | (x, _) => x
       };
 
+    def ret_type = bind (f.header.ret_type);
+    match (ret_type.Fix ()) {
+      | Class (tc, [_])
+        when tc.Equals (InternalType.Generic_IEnumerator_tc) =>
+        match (f.header.ret_type) {
+          | <[ $_ [ $t ] ]> =>
+            // we need it at the parsetree level
+            yield_stuff = Some ((t, f.header.parms));
+          | _ => {}
+        }
+      | _ => {}
+    }
+
     fun_header = Fun_header (
-      ret_type = bind (f.header.ret_type),
+      ret_type = ret_type,
       typarms = typarms,
       name = this.name,
       parms = parms,

Modified: nemerle/trunk/ncc/misc/PrettyPrint.n
==============================================================================
--- nemerle/trunk/ncc/misc/PrettyPrint.n	(original)
+++ nemerle/trunk/ncc/misc/PrettyPrint.n	Sun Dec  4 12:47:27 2005
@@ -1048,12 +1048,6 @@
           recurse_and_indent (body);
 
 
-        | TT.TExpr.Yield (body) =>
-          append ("yield (");
-          recurse (body);
-          append (")");
-
-
         | TT.TExpr.Goto (id, t) =>
           append ($ "goto l$id [$t];");
           

Added: nemerle/trunk/ncc/testsuite/negative/yield.n
==============================================================================
--- (empty file)
+++ nemerle/trunk/ncc/testsuite/negative/yield.n	Sun Dec  4 12:47:27 2005
@@ -0,0 +1,9 @@
+using System.Collections.Generic;
+
+class D
+{
+  public GetEnumerator () : string
+  {
+    yield "foo"; // E: yield used in a function returning string
+  }
+}

Added: nemerle/trunk/ncc/testsuite/negative/yield2.n
==============================================================================
--- (empty file)
+++ nemerle/trunk/ncc/testsuite/negative/yield2.n	Sun Dec  4 12:47:27 2005
@@ -0,0 +1,9 @@
+using System.Collections.Generic;
+
+class D
+{
+  public GetEnumerator () : IEnumerator [int]
+  {
+    yield "foo"; // E: expected int, got string in assigned value
+  }
+}

Added: nemerle/trunk/ncc/testsuite/positive/yield.n
==============================================================================
--- (empty file)
+++ nemerle/trunk/ncc/testsuite/positive/yield.n	Sun Dec  4 12:47:27 2005
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+
+class C : IEnumerable [int] 
+{
+  public GetEnumerator () : IEnumerator [int]
+  {
+    yield 42;
+    yield 13;
+    yield 77;
+  }
+}
+
+foreach (e in C ())
+  System.Console.WriteLine (e);
+
+foreach (e in C ())
+  System.Console.WriteLine (e);
+
+/*
+BEGIN-OUTPUT
+42
+13
+77
+42
+13
+77
+END-OUTPUT
+*/

Modified: nemerle/trunk/ncc/typing/TypedTree.n
==============================================================================
--- nemerle/trunk/ncc/typing/TypedTree.n	(original)
+++ nemerle/trunk/ncc/typing/TypedTree.n	Sun Dec  4 12:47:27 2005
@@ -447,13 +447,12 @@
     | StaticEventRef        { from : MType.Class; ev : IEvent; }
     | ConstantObjectRef     { from : MType.Class; mem : IField; }
     | Block                 { jump_out : LocalValue; body : TExpr; }
-    | Yield                 { expr : TExpr; }
     | Delayed               { susp : Typer.DelayedTyping; }
     | Error
 
     // invalid after T3
     | DefFunctionsIn        { funs : list [Fun_header]; mutable body : TExpr; }
-    | Match                 { expr : TExpr; cases : list [Match_case]; }
+    | Match                 { expr : TExpr; mutable cases : list [Match_case]; }
     | SelfTailCall          { parms : list [Parm]; }
     | LocalFunRef           { decl : LocalValue; type_parms : list [TyVar]; }
     
@@ -752,7 +751,6 @@
         | StaticPropertyRef
         | EventMember
         | Block
-        | Yield
         | StaticEventRef =>
           // this is supposed to be run after Typer2
           Message.Warning (expr.loc, 

Modified: nemerle/trunk/ncc/typing/Typer.n
==============================================================================
--- nemerle/trunk/ncc/typing/Typer.n	(original)
+++ nemerle/trunk/ncc/typing/Typer.n	Sun Dec  4 12:47:27 2005
@@ -66,13 +66,20 @@
     locals_stack : Stack [LocalContext];
     mutable skip_n_return : bool;
     
+    mutable inside_yielding_function : bool;
+    yield_stuff : option [PT.PExpr * list [PT.Fun_parm]];
+    mutable yield_labels : list [int] = [];
+
     #region Toplevel typing
+    class SwitchToYielding : System.Exception { }
+    
     // FIXME: copy doc from TypeMethod
     /** Walk through method body typing it. */
     public this (m : MethodBuilder)
     {
       solver = Passes.Solver;
       current_type = m.DeclaringType;
+      yield_stuff = m.yield_stuff;
       parent_typer = None ();
       env = current_type.GlobalEnv;
       current_fun = m.GetHeader ();
@@ -80,6 +87,10 @@
       messenger = solver.CurrentMessenger;
       locals_stack = Stack ();
 
+      inside_yielding_function =
+        m.Name == "MoveNext" && 
+        current_type.LookupMember ("_N_current") is [_];
+
       local_context = LocalContext.Empty;
 
       assert (solver.IsTopLevel);
@@ -101,6 +112,16 @@
           mutable typer_done = false;
           assert (messenger.IsTopLevel);
 
+          def put_in_error_mode () {
+            solver.Unwind ();
+            messenger.Cleanup ();
+            assert (!messenger.InErrorMode);
+            assert (messenger.IsTopLevel);
+            messenger.InErrorMode = true;
+            local_context = LocalContext.Empty;
+            assert (!typer_done);
+          }
+
           try {
             messenger.Cleanup ();
             messenger.InErrorMode = false;
@@ -122,18 +143,23 @@
           } catch {
             | _ is RestartInErrorMode =>
               def errcnt = Message.ErrorCount;
-              solver.Unwind ();
-              messenger.Cleanup ();
-              assert (!messenger.InErrorMode);
-              assert (messenger.IsTopLevel);
-              messenger.InErrorMode = true;
-              local_context = LocalContext.Empty;
-
-              assert (!typer_done);
+              put_in_error_mode ();
               RunTyper ();
 
               when (errcnt == Message.ErrorCount)
                 Util.ice ($"hidden errors compiling $m");
+                
+            | _ is SwitchToYielding =>
+              def errcnt = Message.ErrorCount;
+              // just in case
+              put_in_error_mode ();
+              m.Body = MakeEnumeratorClass (m.Body);
+              when (errcnt == Message.ErrorCount)
+                RunTyper ();
+              when (errcnt == Message.ErrorCount) {
+                RunSecondPass (m);
+                MaybeDumpTypedTree ();
+              }
           }
         })
       } finally {
@@ -257,10 +283,7 @@
               MakeImplicitBlockJumpOut ("_N_return", current_fun.ret_type);
           def e' = TypeExpr (e);
           messenger.CleanLocalError ();
-          def ret_type =
-            if (UsedYield) InternalType.Void
-            else current_fun.ret_type;
-          def e' = AddCastTo (e', ret_type, "function return type");
+          def e' = AddCastTo (e', current_fun.ret_type, "function return type");
           def e' =
             if (skip_n_return) e' 
             else TExpr.Block (e'.Type, local, e');
@@ -277,7 +300,13 @@
 
     RunSecondPass (meth : MethodBuilder) : void
     {
-      def t2 = Typer2 (current_type, meth, UsedYield);
+      when (inside_yielding_function)
+        match (current_fun.body) {
+          | FunBody.Typed (t) => AddYieldStateMachine (t)
+          | _ => Util.ice ()
+        }
+
+      def t2 = Typer2 (current_type, meth);
       t2.Run ();
       def t3 = Typer3 (meth);
       t3.Run ();
@@ -2982,6 +3011,10 @@
               PopLocals ();
             }
           } else if (ns.Equals (yield_macro)) {
+            when (! inside_yielding_function) {
+              _ = GetYieldStuff ();
+              throw SwitchToYielding ();
+            }
             _ = Expect (expected, InternalType.Void, "yield ``result''");
             HandleYield (expr)
           } else null
@@ -2993,48 +3026,130 @@
     
 
     #region yield handling
-    GetYieldType () : TyVar
+    MakeEnumeratorClass (body : PT.PExpr) : PT.PExpr
+    {
+      def (yield_type, parms) = GetYieldStuff ();
+      def this_type = Util.ExprOfQid (current_type.FullName);
+      def all_parms = <[ parameter: _N_this : $this_type ]> :: parms;
+
+      def pt = <[ decl:
+        class $(Macros.NewSymbol ("Enumerator") : name) :
+          System.Collections.IEnumerator,
+          System.Collections.Generic.IEnumerator [$yield_type]
+        {
+          mutable _N_current : $yield_type;
+          mutable _N_state : int;
+
+          public Current : $yield_type
+          {
+            get { _N_current }
+          }
+
+          public MoveNext () : bool
+          {
+            _N_MoveNext_exit : {
+              match (_N_state) {
+                // AddYieldStateMachine will add something here
+                | 0 => {}
+                | _ => _N_MoveNext_exit (false)
+              }
+              {
+                $body;
+                false
+              }
+            }
+          }
+
+          public Dispose () : void
+          {
+            _N_state = -1;
+          }
+
+          public Reset () : void
+          {
+            throw System.NotSupportedException ();
+          }
+
+          public this (.. $all_parms)
+          {
+          }
+        }
+      ]>;
+
+      def tb = current_type.DefineNestedType (pt);
+      
+      def ctor_assigns =
+        all_parms.Map (fun (fp) {
+          when (fp.ty is <[ ref $_ ]> || fp.ty is <[ out $_ ]>)
+            ReportError (messenger, 
+                         "ref/out parameters not allowed in functions "
+                         "using ``yield''");
+          tb.Define (<[ decl: mutable $(fp.name) : $(fp.ty) ]>);
+          <[ this . $(fp.name) = $(fp.name.GetName () : name) ]>
+        });
+        
+      def meth = Typer3.SingleMemberLookup (tb, ".ctor") :> MethodBuilder;
+      meth.Body = <[ { .. $ctor_assigns } ]>;
+
+      tb.Compile ();
+
+      def parm_refs = 
+        <[ this ]> :: parms.Map (fun (fp) { <[ $(fp.name.GetName () : name) ]> });
+
+      <[ $(Util.ExprOfQid (tb.FullName)) (.. $parm_refs) ]>
+    }
+
+
+    GetYieldStuff () : PT.PExpr * list [PT.Fun_parm]
     {
       match (parent_typer) {
-        | Some (t) => t.GetYieldType ()
+        | Some (t) => t.GetYieldStuff ()
+        | None =>
+          match (yield_stuff) {
+            | Some (x) => x
         | None =>
-          match (current_fun.ret_type.Fix ()) {
-            | Class (tc, [t])
-              when tc.Equals (InternalType.Generic_IEnumerable_tc) =>
-              t
-            | t =>
               ReportError (messenger,
-                           $ "yield used in a function returning $t (it "
+                           $ "yield used in a function returning "
+                             "$(current_fun.ret_type) (it "
                              "should be System.Collections.Generic."
                              "IEnumerable[T])");
-              InternalType.Object
+              (<[ object ]>, [])
           }
       }
     }
 
     HandleYield (expr : PT.PExpr) : TExpr
     {
-      when (solver.IsTopLevel)
-        UsedYield = true;
-      TExpr.Yield (InternalType.Void,
-                   AddCastTo (TypeExpr (expr), GetYieldType (), "yielded expression"))
-    }
+      Util.cassert (solver.IsTopLevel);
+      def label_no = Util.next_id ();
+      yield_labels ::= label_no;
+      def label =
+        TExpr.Label (InternalType.Void, label_no, VoidLiteral ());
+      def state_no = yield_labels.Length;
 
-    UsedYield : bool
+      TypeExpr (<[ 
     {
-      mutable used_yield : bool;
-
-      get {
-        match (parent_typer) {
-          | Some (t) => t.UsedYield
-          | None => used_yield
+          $(This () : typed) . _N_current = $expr;
+          $(This () : typed) . _N_state = $(state_no : int);
+          _N_MoveNext_exit (true);
+          $(label : typed)
         }
+      ]>)
       }
-      set {
-        match (parent_typer) {
-          | Some (t) => t.UsedYield = value
-          | None => used_yield = value
-        }
+
+    AddYieldStateMachine (e : TExpr) : void
+    {
+      match (e) {
+        | Block (_, Block (_, Sequence (Match as m, _))) =>
+          mutable cnt = 1;
+          def cases = yield_labels.Rev ().Map (fun (id) {
+            def cntpat = Pattern.Literal (InternalType.Int32, Literal.FromInt (cnt));
+            cnt++;
+            def yes = TExpr.Literal (InternalType.Boolean, Literal.Bool (true));
+            Match_case ([(cntpat, yes, [])], TExpr.Goto (m.Type, id, 1), false)
+          });
+          m.cases = cases + m.cases;
+        | _ => Util.ice ($ "e = $e")
       }
     }
     #endregion
@@ -3139,7 +3254,6 @@
         | TExpr.Goto
         | TExpr.Label
         | TExpr.Block
-        | TExpr.Yield
         | TExpr.MultipleAssign
         | TExpr.MethodAddress => 
           $ "!!!shouldn't happen: $(expr.GetType())!!!"

Modified: nemerle/trunk/ncc/typing/Typer2.n
==============================================================================
--- nemerle/trunk/ncc/typing/Typer2.n	(original)
+++ nemerle/trunk/ncc/typing/Typer2.n	Sun Dec  4 12:47:27 2005
@@ -42,7 +42,6 @@
     mutable current_fun : Fun_header;
     current_type : TypeBuilder;
     messenger : Messenger;
-    used_yield : bool;
 
     [System.Flags]
     enum Context {
@@ -61,13 +60,12 @@
       | TopLevel           = IsTail %| AllowGoto %| AllowTry
     }
     
-    public this (ty : TypeBuilder, fn : MethodBuilder, used_yield : bool)
+    public this (ty : TypeBuilder, fn : MethodBuilder)
     {
       current_fun = fn.GetHeader ();
       current_fun.usage = FunctionUsage.Used;
       top_level_fun = fn;
       current_type = ty;
-      this.used_yield = used_yield;
 
       messenger = Passes.Solver.CurrentMessenger;
     }
@@ -168,13 +166,11 @@
             | _ => false
           }
         | TExpr.StaticRef (Class (tc, _) as from, meth is IMethod, typarms) =>
-          !used_yield &&
           meth.GetHeader ().id == current_fun.id &&
           tc.GetMemType ().Equals (from) &&
           AreSelfMethodTyParms (meth, typarms)
           
         | TExpr.MethodRef (th, meth : IMethod, typarms, _) =>
-          !used_yield &&
           meth.GetHeader ().id == current_fun.id &&
           Unfold (th) is TExpr.This &&
           AreSelfMethodTyParms (meth, typarms)
@@ -659,12 +655,6 @@
     }
 
 
-    [Nemerle.NotImplemented]
-    static ExpandYield (expr : TExpr) : TExpr
-    {
-    }
-
-
     /* block (foo) {
          ...
          when (...) foo (33);
@@ -1203,10 +1193,6 @@
           Walk (ctx, ExpandBlock (b))
 
 
-        | TExpr.Yield (e) =>
-          Walk (ctx, ExpandYield (e))
-
-
         | TExpr.If (cond, e1, e2) =>
           TExpr.If (Walk (cond), Walk (ctx, e1), Walk (ctx, e2))
 



More information about the svn mailing list