Re: Автоматическая перегрузка функций №2 в избранное  msdn  новое всё   Оценить +1123x:) +-   подписка   модер. 
От: _nn_http://our-site.3dn.ru
Дата: 07.04.08 18:47
Здравствуйте, _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: Пока нельзя так, но очень хотелось бы.

Критика приветсвуется
Спасибо.