[svn] r6379: nemerle/trunk/macros/alias.n
d
svnadmin at nemerle.org
Wed Jun 7 22:20:32 CEST 2006
Log:
Add basic support for method aliasing. For now only static methods can be aliased. See source for details.
Author: d
Date: Wed Jun 7 22:20:31 2006
New Revision: 6379
Added:
nemerle/trunk/macros/alias.n
Added: nemerle/trunk/macros/alias.n
==============================================================================
--- (empty file)
+++ nemerle/trunk/macros/alias.n Wed Jun 7 22:20:31 2006
@@ -0,0 +1,203 @@
+/*
+ * 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 SCG = System.Collections.Generic;
+using Nemerle.Collections;
+using Nemerle.Compiler;
+using Nemerle.Compiler.Parsetree;
+
+namespace Nemerle
+{
+ /**
+ * The Alias macro creates aliases for methods with alternative
+ * names/argument count/argument order. The generated code may be
+ * a static or non-static method, or a property. The macro tries
+ * to be "intelligent" in it's choices (which basically means,
+ * that only reasonable possibilities are taken into account).
+ *
+ * TODO: write code for aliasing non-static methods, properties
+ * and fields and handling attributes like public, private,
+ * override etc.
+ *
+ ***** Example #1:
+ *
+ * [Alias (F2, F3 ())]
+ * public static F1 () : int { System.Random ().Next () }
+ *
+ * // generates the following code:
+ *
+ * public F2 : int { get { System.Random.Next () } }
+ * public F3 () : int { System.Random.Next () }
+ *
+ ***** Example #2:
+ *
+ * [Alias (Hd, Head2 (), Head3 (l))]
+ * public static Head (l : list ['a]) : 'a {
+ * match (l) {
+ * | x :: _ => x
+ * | [] => throw System.ArgumentException ("Head called with empty list")
+ * }
+ * }
+ *
+ * // generates the following code:
+ *
+ * public Hd : 'a { get { def l = this; match (l) { ... } } }
+ * public Head2 () : int { def l = this; match (l) { ... } }
+ * public static Head3 (l) : int { match (l) { ... } }
+ *
+ * // where "..." is the code in matching.
+ *
+ ***** Example #3:
+ *
+ * [Alias (Nth (i, l), Lookup (i))]
+ * static Nth (xs : RList ['a], i : int) { some_code }
+ *
+ * // generates the following code:
+ *
+ * static Nth (i : int, xs : RList ['a]) { some_code }
+ * Lookup (i : int) { def xs = this; some_code }
+ *
+ */
+ [Nemerle.MacroUsage (Nemerle.MacroPhase.WithTypedMembers,
+ Nemerle.MacroTargets.Method)]
+ macro Alias (tb : TypeBuilder, meth : MethodBuilder, params opts : list [PExpr]) {
+ def parms = meth.GetParameters ();
+ if (meth.IsStatic)
+ match (parms.Length) {
+ | 0 =>
+ foreach (o in opts) {
+ | <[ $alias_name () ]> => // [Alias (G ())] static F ()
+ tb.Define (<[ decl:
+ public static $(alias_name.ToString () : usesite) ()
+ : $(meth.ReturnType : typed) {
+ $(meth.Body)
+ }
+ ]>)
+ | <[ $_ (.. $_) ]> => // e.g. [Alias (G (x)] static F ()
+ Message.Error ($"Invalid parameter count for alias: $o.")
+ | <[ $alias_name ]> => // [Alias (G)] static F ()
+ tb.Define (<[ decl:
+ public $(alias_name.ToString () : usesite) : $(meth.ReturnType : typed) {
+ get { $(meth.Body) }
+ }
+ ]>)
+ }
+ | 1 =>
+ foreach (o in opts) {
+ | <[ $alias_name () ]> => // [Alias (G ())] static F (x) /* [x] <-> [this] */
+ tb.Define (<[ decl:
+ public $(alias_name.ToString () : usesite) () : $(meth.ReturnType : typed) {
+ def $(parms.Head.name.ToString () : usesite) = this;
+ $(meth.Body)
+ }
+ ]>)
+
+ | <[ $alias_name ($alias_parm) ]> => // [Alias (G (x))] static F (x)
+ def parm = parms.Head;
+ when (parm.name.ToString () != alias_parm.ToString ())
+ Message.Error ($"Invalid parameter name for alias: $o.");
+ tb.Define (<[ decl:
+ static public $(alias_name.ToString () : usesite)
+ ($(parm.name.ToString () : usesite) : $(parm.ty : typed))
+ : $(meth.ReturnType : typed) {
+ $(meth.Body)
+ }
+ ]>)
+
+ | <[ $alias_name ]> => // [Alias (G)] static F (x) /* [x] <-> [this] */
+ tb.Define (<[ decl:
+ public $(alias_name.ToString () : usesite) : $(meth.ReturnType : typed) {
+ get { def $(parms.Head.name.ToString () : usesite) = this; $(meth.Body) }
+ }
+ ]>)
+ }
+ | parms_num =>
+ foreach (o in opts) {
+ | <[ $alias_name (.. $alias_parms) ]> =>
+ match (parms_num - alias_parms.Length) {
+ | 0 => // e.g. [Alias (G (x, y))] static F (x, y)
+ def parm_dict = Hashtable ();
+ List.Iter (parms, p => parm_dict.Add (p.Name.ToString (), p.ty));
+ try {
+ def fparms = List.Map (alias_parms, p => <[ parameter: $(p.ToString () : usesite)
+ : $(parm_dict [p.ToString ()] : typed) ]>);
+ tb.Define (<[ decl:
+ static public $(alias_name.ToString () : usesite) (..$fparms)
+ : $(meth.ReturnType : typed) {
+ $(meth.Body)
+ }
+ ]>)
+ }
+ catch {
+ | _ is SCG.KeyNotFoundException =>
+ Message.Error ($"Invalid parameter name for alias: $o.");
+ }
+ | 1 => // e.g. [Alias (G (x))] static F (x, y) /* [y] <-> [this] */
+ def parm_dict = Hashtable ();
+ List.Iter (parms, p => parm_dict.Add (p.Name.ToString (), p.ty));
+ try {
+ def fparms = List.Map (alias_parms, p => {
+ def ret = <[ parameter: $(p.ToString () : usesite)
+ : $(parm_dict [p.ToString ()] : typed) ]>;
+ parm_dict.Remove ($"$p");
+ ret
+ });
+ def this_def = parm_dict.Fold (<[ () ]>, (k, v, _) =>
+ <[ def $(k : usesite) : $(v : typed) = this ]>);
+ tb.Define (<[ decl:
+ public $(alias_name.ToString () : usesite) (..$fparms)
+ : $(meth.ReturnType : typed) {
+ $this_def;
+ $(meth.Body)
+ }
+ ]>)
+ }
+ catch {
+ | _ is SCG.KeyNotFoundException =>
+ Message.Error ($"Invalid parameter name for alias: $o.");
+ }
+ | _ => Message.Error ($"Invalid parameter count for alias: $o.");
+ }
+ }
+ }
+ else
+ Message.Error ("Sorry, aliasing non-static methods are not yet supported!")
+ /* // Need to add support for
+ *
+ * [Alias (F1, F2 (), F3 (x)] // [x] <-> [this]
+ * F () { ... }
+ *
+ * // and
+ *
+ * [Alias (F1 (x, y), F2 (x, y, z)] // [z] <-> [this]
+ * F (x, y) { ... }
+ *
+ */
+ }
+}
More information about the svn
mailing list