[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