Здравствуйте, _nn_, Вы писали:
Вторая и улучшенная версия.
C# тест:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ClassLibrary1;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
new Class1().F();
new Class1().F(1);
new Class1().F(2, "a");
new Class1().F(3, "b", 3);
new Class1().F2('q', 5, "d");
new Class1().F2('q', 6, "e", 7.5);
}
}
} |
Nemerle тест:
using System;
using System.Collections.Generic;
using System.Text;
using MacroLibrary1;
using Nemerle.Compiler;
using Nemerle.Compiler.Typedtree;
using Nemerle.Collections;
namespace ClassLibrary1
{
public class Class1
{
// public F(x : int, y : string, z : byte) : void
// public F(x : int, y : string) : void
// public F(x : int) : void
// public F() : void
[DefaultArguments]
public F(x : int = 1, y : string = "a", z : byte = 9) : void
{
System.Console.WriteLine("{0} - {1} - {2}", x, y, z);
}
private FTester() : void
{
F();
F(0);
F(0, "z");
F(0, "z", 10);
}
// public F2(a : char, x : int, y : string, z : double) : void
// public F2(a : char = 'a', x : int, y : string) : void
[DefaultArguments]
public F2(a : char = 'a', x : int = 1, y : string, z : double = 3.3) : void
{
System.Console.WriteLine("{0} - {1} - {2} - {3}", a, x, y, z);
}
private F2Tester() : void
{
// TODO: (1) F2(y = "z");
F2(a = 'x', y = "z", z = 1.0); // 'x' is implied
F2(y = "z", z = 1.0); // 'a' and 'x' are implied
F2('x', 0, "z");
F2('x', 0, "z", 10.0);
}
}
} |
1: На данный момент недоработка.
В следующей версии постараюсь исправить.
Nemerle Макрос:
using Nemerle.Compiler;
using Nemerle.Imperative;
using PT = Nemerle.Compiler.Parsetree;
using TT = Nemerle.Compiler.Typedtree;
namespace MacroLibrary1
{
/// <summary>
/// Converts function with default arguments into overloaded functions.
/// </summary>
///
/// <example> One argument
/// <code>
/// [DefaultArguments]
/// public F(a : int = 1) { ... }
/// =>
/// public F() { F(1); }
/// public F(a : int) { ... }
/// </code>
/// </example>
///
/// <example> More then one argument
/// <code>
/// [DefaultArguments]
/// public F(a : int = 1, b : char = 'a') { ... }
/// =>
/// public F() { F(1, 'a'); }
/// public F(a: int) { F(a, 'a') }
/// public F(a: int, b : char) { ... }
/// </code>
/// </example>
///
/// <example> Breaking the default argument sequence
/// <code>
/// [DefaultArguments]
/// public F(a : int = 1, b : char, c : double = 1.1) { ... }
/// =>
/// public F(a : int, b : char) { F(a, b, 1.1) }
/// public F(a : int = 1, b : char, c : double) { ... }
/// </code>
/// </example>
[Nemerle.MacroUsage(Nemerle.MacroPhase.WithTypedMembers
, Nemerle.MacroTargets.Method)]
public macro DefaultArguments(tb : TypeBuilder, mb : MethodBuilder, params opts : list[PExpr])
{
DefaultArgumentsImpl.DefaultArguments(tb, mb, opts);
}
internal module DefaultArgumentsImpl
{
public DefaultArguments(tb : TypeBuilder
, mb : MethodBuilder
, _ : list[Parsetree.PExpr]) : void
{
def newName(name) { tb.ParsedName.NewName(name) }
def defaultValueToPExpr(l)
{
PT.PExpr.Literal((l.DefaultValueAsTExpr() :> TT.TExpr.Literal).val)
}
// Overloaded methods
def parms = mb.GetParameters();
mutable cur = parms.Length - 1;
foreach(arg in parms.Reverse())
{
// Overload if we have default value
if(arg.HasDefaultValue)
{
def mparms = parms.FirstN(cur)
.Map(p => <[ $(newName(p.name) : name) : $(p.ty : typed) ]>);
def fparms = mparms.Map(PT.Fun_parm);
// Arguments and the default value
def call = mparms + [defaultValueToPExpr(arg)];
tb.Define
(<[ decl:
public $(newName(mb.Name) : name)(..$fparms) : $(mb.ReturnType : typed)
{
this.$(mb.Name : dyn)(..$call)
}
]>);
}
else
break;
// Check for last element
if(cur == 0)
break;
else
--cur;
}
// Check if the sequence was broken, so we need to leave the last argument
def brokenSeq = parms.FirstN(cur).Find(x => x.default_value.IsSome).IsSome;
// Remove the default arguments to avoid ambiguity
parms.LastN(parms.Length - cur - if(brokenSeq && parms.Length > cur) 1 else 0)
// TODO: (1) .Iter(_.default_value = None());
.Iter(x => x.default_value = None());
// Was the default arguments sequence broken
when(brokenSeq)
Message.Hint("Default arguments sequence was broken. " +
"The overload is only by last arguments with default values");
}
}
} |
1: Пока нельзя так, но очень хотелось бы.
Критика приветсвуется 
Спасибо.    | |