[svn] r6098: nemerle/trunk: macros/core.n ncc/Makefile ncc/hierarchy/BuiltinMethod.n ncc/hierarchy/Extensi...

malekith svnadmin at nemerle.org
Mon Jan 30 15:28:48 CET 2006


Log:
Starting implementation of extension methods.

Author: malekith
Date: Mon Jan 30 15:28:45 2006
New Revision: 6098

Added:
   nemerle/trunk/ncc/hierarchy/ExtensionMethod.n
   nemerle/trunk/ncc/testsuite/negative/extension-methods.n
   nemerle/trunk/ncc/testsuite/positive/extension-methods.n
Modified:
   nemerle/trunk/macros/core.n
   nemerle/trunk/ncc/Makefile
   nemerle/trunk/ncc/hierarchy/BuiltinMethod.n
   nemerle/trunk/ncc/hierarchy/TypeInfo.n
   nemerle/trunk/ncc/typing/Typer2.n

Modified: nemerle/trunk/macros/core.n
==============================================================================
--- nemerle/trunk/macros/core.n	(original)
+++ nemerle/trunk/macros/core.n	Mon Jan 30 15:28:45 2006
@@ -625,6 +625,28 @@
     }
  
   }
+
+
+  [Nemerle.MacroUsage (Nemerle.MacroPhase.WithTypedMembers,
+                       Nemerle.MacroTargets.Parameter)]
+   macro _N_ExtensionMethodOnThisParameter (_tb : TypeBuilder, mb : MethodBuilder, p : ParameterBuilder)
+     syntax ("this")
+   {
+     if (p : object != mb.GetParameters ().Head)
+       Message.Error ("'this' modifier (for extension method) can only be "
+                      "used on the first parameter");
+     else if (!((mb.Attributes %&& NemerleAttributes.Public) &&
+                (mb.Attributes %&& NemerleAttributes.Static)))
+       Message.Error ("extension methods need to be marked public static")
+     else
+       match (p.ty.Fix ()) {
+         | Class (tc, []) =>
+           tc.AddExtensionMethod (mb);
+         | t =>
+           Message.Error ($ "extension methods not yet supported on generic "
+                            "types like $t")
+       }
+   }
 }
 
 namespace Nemerle.Macros

Modified: nemerle/trunk/ncc/Makefile
==============================================================================
--- nemerle/trunk/ncc/Makefile	(original)
+++ nemerle/trunk/ncc/Makefile	Mon Jan 30 15:28:45 2006
@@ -88,6 +88,7 @@
 	generation/DecisionTreeCompiler.n \
 	generation/Typer3.n		 \
 	generation/Typer4.n		 \
+	hierarchy/ExtensionMethod.n      \
 	hierarchy/BuiltinMethod.n        \
 	hierarchy/ClassMembers.n	 \
 	hierarchy/CustomAttribute.n	 \

Modified: nemerle/trunk/ncc/hierarchy/BuiltinMethod.n
==============================================================================
--- nemerle/trunk/ncc/hierarchy/BuiltinMethod.n	(original)
+++ nemerle/trunk/ncc/hierarchy/BuiltinMethod.n	Mon Jan 30 15:28:45 2006
@@ -34,17 +34,25 @@
   class BuiltinMethod : IMethod
   {
     id : int;
-    header : Fun_header;
+    protected header : Fun_header;
     declaring : TypeInfo;
     special_kind : BuiltinMethodKind;
 
+    protected this (parent : TypeInfo, 
+                    kind : BuiltinMethodKind)
+    {
+      id = Util.next_id ();
+      declaring = parent;
+      special_kind = kind;
+    }
+
     internal this (parent : TypeInfo, 
                    name : string, 
                    on_type : TyVar, 
                    kind : BuiltinMethodKind)
     {
-      id = Util.next_id ();
-      declaring = parent;
+      this (parent, kind);
+
       def fp (name, ty) {
         Fun_parm (name = name,
                   ty = ty, 
@@ -61,8 +69,6 @@
            parms = [fp ("left", on_type), fp ("right", on_type)],
            typarms = [],
            tenv = TyVarEnv ());
-
-      special_kind = kind;
     }
     
     public GetKind () : MemberKind
@@ -162,7 +168,7 @@
       get { MemberTypes.Method }
     }
     
-    public IsStatic : bool
+    public virtual IsStatic : bool
     { 
       get { true } 
     }
@@ -173,7 +179,7 @@
       set { ignore (value); }
     }
 
-    public Attributes : NemerleAttributes {
+    public virtual Attributes : NemerleAttributes {
       get { 
         NemerleAttributes.Static | 
         NemerleAttributes.Public

Added: nemerle/trunk/ncc/hierarchy/ExtensionMethod.n
==============================================================================
--- (empty file)
+++ nemerle/trunk/ncc/hierarchy/ExtensionMethod.n	Mon Jan 30 15:28:45 2006
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2006 The University of Wroclaw.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *    3. The name of the University may not be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE UNIVERSITY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using Nemerle.Compiler;
+using Nemerle.Compiler.Typedtree;
+
+namespace Nemerle.Compiler
+{
+  class ExtensionMethod : BuiltinMethod
+  {
+    internal this (parent : TypeInfo,
+                   impl : IMethod)
+    {
+      base (parent, BuiltinMethodKind.ExtensionMethod (impl));
+      //Message.Debug ($"adding extension method $impl to $parent");
+      def h = impl.GetHeader ();
+      assert (h.typarms is []);
+      assert (h.tenv.IsEmpty);
+      header = Fun_header (h.loc, h.name, h.ret_type, h.parms.Tail, [], h.tenv);
+    }
+    
+    public override Attributes : NemerleAttributes {
+      get { 
+        NemerleAttributes.Public
+      }
+    }
+
+    public override IsStatic : bool
+    { 
+      get { false } 
+    }
+    
+  }
+}

Modified: nemerle/trunk/ncc/hierarchy/TypeInfo.n
==============================================================================
--- nemerle/trunk/ncc/hierarchy/TypeInfo.n	(original)
+++ nemerle/trunk/ncc/hierarchy/TypeInfo.n	Mon Jan 30 15:28:45 2006
@@ -67,6 +67,9 @@
       meth : IMethod;
     }
   | ValueTypeConversion
+  | ExtensionMethod {
+      impl : IMethod;
+    }
 }
 
 public interface IMember
@@ -509,6 +512,20 @@
     res.Rev ()
   }
   
+  protected mutable extension_methods : Hashtable [string, list [IMember]];
+  public AddExtensionMethod (based_on : IMethod) : void
+  {
+    when (extension_methods == null)
+      extension_methods = Hashtable ();
+
+    def meth = ExtensionMethod (this, based_on);
+
+    if (extension_methods.Contains (meth.Name))
+      extension_methods [meth.Name] ::= meth
+    else
+      extension_methods [meth.Name] = [meth]
+  }
+  
   /** Look for specified member. 
 
       Semantics of returning base class member is the same as for 
@@ -524,8 +541,16 @@
     else if (special_members.Contains (name))
       special_members [name]
     else {
+      def lookup_impl (ti) {
+        if (ti.extension_methods == null || 
+            !ti.extension_methods.Contains (name))
+          ti.LookupMemberImpl (name)
+        else
+          ti.LookupMemberImpl (name) + ti.extension_methods [name]  
+      }
+      
       def loop (acc, ti : TypeInfo) {
-        def res = ti.LookupMemberImpl (name);
+        def res = lookup_impl (ti);
 
         // filter out members with override specified
         // def res = res.RevFilterWhenNeeded (aint_override);
@@ -535,7 +560,7 @@
         if (ti.IsInterface)
           match (ti.GetDirectSuperTypes ()) {
             | [] =>
-              InternalType.Object_tc.LookupMemberImpl (name) :: acc
+              lookup_impl (InternalType.Object_tc) :: acc
             | ifaces =>
               ifaces.Map (fun (c) {
                 c.tycon.LookupMember (name)
@@ -551,7 +576,7 @@
       if (name == ".ctor")
         // don't recurse
         LookupMemberImpl (name)
-      else
+      else {
         match (loop ([], this)) {
           | [] => []
           | [one] => one
@@ -563,6 +588,7 @@
         }
     }
   }
+  }
 
   /** */
   public abstract GetTydecl () : TypeDeclaration;

Added: nemerle/trunk/ncc/testsuite/negative/extension-methods.n
==============================================================================
--- (empty file)
+++ nemerle/trunk/ncc/testsuite/negative/extension-methods.n	Mon Jan 30 15:28:45 2006
@@ -0,0 +1,17 @@
+#pragma indent
+using System.Console
+
+[Record] \
+class A
+  public v : int
+  public foo () : void
+    Write ("foo()\n")
+
+class B
+  public foo (this a : A, p : int) : void // E: extension methods need to be marked public static
+    Write ($"foo($(a.v),$p)\n")
+
+class C
+  public foo (p : int, this a : A) : void // E: 'this' modifier \(for extension method\) can only be used on the first parameter
+    Write ($"foo($(a.v),$p)\n")
+

Added: nemerle/trunk/ncc/testsuite/positive/extension-methods.n
==============================================================================
--- (empty file)
+++ nemerle/trunk/ncc/testsuite/positive/extension-methods.n	Mon Jan 30 15:28:45 2006
@@ -0,0 +1,26 @@
+#pragma indent
+using System.Console
+
+class A
+  public v : int
+  public this (v : int)
+    this.v = v
+  public foo () : void
+    Write ("foo()\n")
+
+class B
+  public static foo (this a : A, p : int) : void
+    Write ($"foo($(a.v),$p)\n")
+
+def a = A (42)
+a.foo ()
+a.foo (1)
+B.foo (a, 2)
+
+/*
+BEGIN-OUTPUT
+foo()
+foo(42,1)
+foo(42,2)
+END-OUTPUT
+*/

Modified: nemerle/trunk/ncc/typing/Typer2.n
==============================================================================
--- nemerle/trunk/ncc/typing/Typer2.n	(original)
+++ nemerle/trunk/ncc/typing/Typer2.n	Mon Jan 30 15:28:45 2006
@@ -962,6 +962,17 @@
                 ivtc.ty = expr.ty;
                 ivtc
 
+              | TExpr.MethodRef (obj, IMethod where (BuiltinKind = ExtensionMethod (impl)), type_parms, _) as func =>
+                //Message.Debug ($"expand to $impl");
+                def from = impl.DeclaringType.GetMemType ();
+                def fnt = {
+                  def (parms, ret) = func.MType.FunReturnTypeAndParms ().Value;
+                  MType.ConstructFunctionType (obj.Type :: parms, ret)
+                }
+                def fn = TExpr.StaticRef (fnt, from, impl, type_parms);
+                Walk (Context.IsCalledValue,
+                      TExpr.Call (expr.Type, fn, Parm (obj) :: parms, false))
+
               | TExpr.LocalRef (LocalValue where (
                   ValKind = LocalValue.Kind.BlockReturn) as decl) =>
                 BuildBlockReturn (ctx, expr.Type, decl, parms)



More information about the svn mailing list