Макросы для WPF
От: WolfHound  
Дата: 09.04.10 12:09
Оценка: 125 (2)
Раз уж я написал макру то зачем добру пропадать?...
Залил в http://code.google.com/p/nemerle/source/browse/nemerle/trunk/snippets/Nemerle.WPF/
Если у кого есть жилание развивать это дело до полноценного решения то нужно завести аккаунт на гугле поросить Влада чтобы добавил вас в коммитеры.
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: Макросы для WPF
От: seregaa Ниоткуда http://blogtani.ru
Дата: 09.04.10 12:12
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Если у кого есть жилание развивать это дело до полноценного решения то нужно завести аккаунт на гугле поросить Влада чтобы добавил вас в коммитеры.


А если кто то решит допилить поддержку WPF проектов студией, то здесь — http://rsdn.ru/forum/prj.nemerle/3768282.1.aspx
Автор: seregaa
Дата: 09.04.10
вводная по текущим проблемам и возможным способам их разрешения.
Мобильная версия сайта RSDN — http://rsdn.org/forum/rsdn/6938747
Автор: sergeya
Дата: 19.10.17
Re: Макросы для WPF
От: _FRED_ Черногория
Дата: 13.04.10 10:37
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Раз уж я написал макру то зачем добру пропадать?...

WH>Залил в http://code.google.com/p/nemerle/source/browse/nemerle/trunk/snippets/Nemerle.WPF/
WH>Если у кого есть жилание развивать это дело до полноценного решения то нужно завести аккаунт на гугле поросить Влада чтобы добавил вас в коммитеры.

Вот что у меня получилось. Сначала, про использование:

  // Переименовал - ИМХО, нет  необходимости в сокращениях
  [DependencyProperty(Metadata = FrameworkPropertyMetadata("a", (d, e) => { }, (d, b) => b))]
  public DependencyProperty1 : string { get { } set { } }

  // ReadOnly задаётся отдельно через параметр, а не выводится, 
  // как я ранее предлагал из спецификаторов видимости,
  // ибо только путает. (1*)
  // Теперь так: Access Modifier на свойстве имеет право быть любым, хоть пропущенным,
  // модификаторы на акессорах не допускаются
  // В случае наличия параметра IsReadOnly: set-акессор будет private
  // Можно задавать так: просто IsReadOnly или IsReadOnly = true|false (2*)
  [DependencyProperty(IsReadOnly)]
  public DependencyProperty2 : string { get { } set { } }

  // Attached-свойства объявляются как Get- методы без тела,
  // имя должно начинаться с "Get" - это хоть и договорённость, 
  // но достаточно общепринятая, что бы быть захардкоженой :о)
  // Соответственно, параметр должен быть строго один (3*)
  // Макросом добавляется соответствующий set-метод, его видимость или такая же, 
  // как у Get или private, если макросу сказано IsReadOnly
  [DependencyProperty(IsReadOnly, ValidateCallback = value => value > 0)]
  internal static GetDependencyProperty3(_ : DependencyObject) : int;

  // Имя параметра можно или опустить, как показано в примере выше (4*), или указать явно
  [DependencyProperty]
  public static GetDependencyProperty4(item : DependencyObject) : int;


Пока не перечитал все статьи по макросам, так что можно и не отвечать, попробую сам разобраться со сложностями, но они такие:
(1*) — Не придумал, как добавлять к свойству акессоры, если их нет
(2*) — Не придумал, как узнать тип PExpr (надо просто знать, что тип bool) тогда можно было бы понимать такое: "IsReadOnly = 3 < 5"
(3*) — Не придумал, как узнать тип параметра и установить, является ли он наследником нужного мне типа
(4*) — Не придумал, как узнать, что имя параметра является автосгенерированным и как изменить его (имя) на то, которое нужно мне в таком случае.

Реализация получилась такой:

using Nemerle;
using Nemerle.Collections;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;
using Nemerle.Compiler.Typedtree;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;

namespace Nemerle.WPF
{
  [MacroUsage(MacroPhase.BeforeInheritance, MacroTargets.Property, Inherited = false, AllowMultiple = false)]
  public macro DependencyProperty(typeBuilder : TypeBuilder, property : ParsedProperty, params options : list[PExpr]) {
    DependencyPropertyImpl.Implement(typeBuilder, property, options);
  }

  [MacroUsage(MacroPhase.BeforeInheritance, MacroTargets.Method, Inherited = false, AllowMultiple = false)]
  public macro DependencyProperty(typeBuilder : TypeBuilder, method : ParsedMethod, params options : list[PExpr]) {
    DependencyPropertyImpl.Implement(typeBuilder, method, options);
  }

  internal module DependencyPropertyImpl
  {
    private PropertyFieldName(propertyName : string) : string {
      propertyName + "Property";
    }

    private PropertyKeyFieldName(propertyName : string) : string {
      propertyName + "PropertyKey";
    }

    private PropertyFieldName(propertyName : string, readOnly : bool) : string {
      if(readOnly) {
        PropertyKeyFieldName(propertyName)
      } else {
        PropertyFieldName(propertyName)
      }//if
    }

    private GetOptions(propertyType : PExpr, options : list[PExpr]) : PExpr * PExpr * bool {
      def check(item, value) { // Check, that option specified once
        match(value) {
          | null => item;
          | _ => Message.Error(item.Location, $"Duplicated option: \"$item\"."); null;
        }//match
      }

      mutable metadata, validate, isReadOnly;
      foreach(item in options) {
        | <[ Metadata = $value ]> => metadata = check(value, metadata)
        | <[ ValidateCallback = $value ]> => validate = check(<[ System.Windows.ValidateValueCallback(value => $value(value :> $propertyType)) ]>, validate)
        | <[ IsReadOnly = $value ]> => match(value) {
           | <[ true ]> | <[ false ]> => isReadOnly = check(value, isReadOnly)
           | _ => Message.Error(value.Location, $"Unsupported expression: \"$(value)\". Boolean expected.");
          }//match
        | <[ IsReadOnly ]> => isReadOnly = check(<[ true ]>, isReadOnly)
        | _ => Message.Error(item.Location, $"Invalid option: \"$item\".")
      }//for

      def readOnly = match(isReadOnly) {
        | <[ true ]> => true
        | _ => /* false, null */ false
      }//match

      (metadata ?? <[ System.Windows.PropertyMetadata() ]>, validate ?? <[ null ]>, readOnly)
    }

    private DeclareFields(typeBuilder : TypeBuilder, propertyName : string, propertyType : PExpr, access : NemerleAttributes, options : list[PExpr]) : bool {
      def (metadata, validate, readOnly) = GetOptions(propertyType, options);
      def args = [<[ $(propertyName : string) ]>, <[ typeof($propertyType) ]>, <[ typeof($(typeBuilder.ParsedTypeName)) ]>, metadata, validate];
      def name = PropertyFieldName(propertyName);
      def define(property) {
        property.Attributes |= access & NemerleAttributes.AccessModifiers;
        typeBuilder.Define(property);
      }
      if(readOnly) {
        def nameKey = PropertyKeyFieldName(propertyName);
        typeBuilder.Define(<[decl:
          private static $(nameKey : dyn) : DependencyPropertyKey = DependencyProperty.RegisterReadOnly(..$args);
        ]>);
        define(<[decl:
          static $(name : dyn) : DependencyProperty = $(nameKey : dyn).DependencyProperty;
        ]>)
      } else {
        define(<[decl:
          static $(name : dyn) : DependencyProperty = DependencyProperty.Register(..$args);
        ]>)
      }//if
      readOnly
    }

    private MakeGetValue(@this : PExpr, propertyName : string, propertyType : PExpr) : PExpr {
      def name = PropertyFieldName(propertyName);
      <[ $(@this).GetValue($(name : dyn)) :> $propertyType ]>;
    }

    private MakeSetValue(@this : PExpr, propertyName : string, readOnly : bool) : PExpr {
      def name = PropertyFieldName(propertyName, readOnly);
      <[ $(@this).SetValue($(name : dyn), $("value" : dyn)) ]>
    }

    private GetSetterAccessModifiers(readOnly : bool, getterAccessModifiers : NemerleAttributes) : NemerleAttributes {
      match(readOnly) {
        | true => NemerleAttributes.Private
        | _ => getterAccessModifiers & NemerleAttributes.AccessModifiers
      }//match
    }

    private CheckArgumentNull(argument : PExpr) : PExpr {
      <[
        when($(argument) == null) {
          throw ArgumentNullException();
        }//when
      ]>
    }

    public Implement(typeBuilder : TypeBuilder, property : ClassMember.Property, options : list[PExpr]) : void {
      def redundant = property.Attributes & ~NemerleAttributes.AccessModifiers;
      when(redundant != 0) {
        Message.Error(property.Location, $"Unsupported dependency property attributes: \"$redundant\". Only access modifiers allowed.");
      }//when

      def propertyType = property.prop_ty;

      def accessor(accessor) {
        | Some(fn) => fn
        | _ => Message.Error(property.Location, "Both getter and setter should be specified for dependency property."); null
      }
      def getter = accessor(property.get);
      def setter = accessor(property.set);

      def checkAccessorAttributes(accessor) {
        when(accessor.Attributes %&& NemerleAttributes.AccessModifiers) {
          Message.Error(accessor.Location, "Property accessors can not contains access modifiers.")
        }//when
      }
      checkAccessorAttributes(getter);
      checkAccessorAttributes(setter);
      def propertyAccess = property.Attributes & NemerleAttributes.AccessModifiers;

      def readOnly = DeclareFields(typeBuilder, property.Name, propertyType, propertyAccess, options);
      getter.Body = MakeGetValue(<[ this ]>, property.Name, propertyType);
      setter.Attributes |= GetSetterAccessModifiers(readOnly, propertyAccess);
      setter.Body = MakeSetValue(<[ this ]>, property.Name, readOnly);
    }

    public Implement(typeBuilder : TypeBuilder, method : ClassMember.Function, options : list[PExpr]) : void {
      when(!(method.Attributes %&& NemerleAttributes.Static)) {
        Message.Error(method.Location, "Attached property method should be static.");
      }//when

      def redundant = method.Attributes & ~(NemerleAttributes.AccessModifiers | NemerleAttributes.Static);
      when(redundant != 0) {
        Message.Error(method.Location, $"Unsupported dependency property attributes: \"$redundant\". Only access modifiers and $(NemerleAttributes.Static) allowed.");
      }//when

      def GetMethodPrefix = "Get";
      def SetMethodPrefix = "Set";

      def getterName = method.Name;
      when(String.IsNullOrEmpty(getterName) || getterName.Length <= GetMethodPrefix.Length || !getterName.StartsWith(GetMethodPrefix)) {
        Message.Error(method.Location, "Dependency property name should be 'Get<DependencyPropertyName>'.");
      }//when

      def parameters = method.header.Parameters;
      when(parameters.Length != 1) {
        Message.Error(method.Location, "Attached property method should have exactly one parameter of type 'DependencyObject' or derived.");
      }//when
      def parameter = parameters.Head;

      def propertyName = getterName.Substring(GetMethodPrefix.Length);
      def setterName = SetMethodPrefix + propertyName;
      def propertyType = method.header.ReturnType;

      def parameterName = parameter.Name;
      def parameterType = parameter.Type;
      def propertyAccess = method.Attributes & NemerleAttributes.AccessModifiers;

      def readOnly = DeclareFields(typeBuilder, propertyName, propertyType, propertyAccess, options);

      method.Body = <[
        $(CheckArgumentNull(<[ $(parameterName : dyn) ]>));
        $(MakeGetValue(<[ $(parameterName : dyn) ]>, propertyName, propertyType));
      ]>;

      def setter = <[decl:
        static $(setterName : dyn)($(parameterName : dyn) : $(parameterType), value : $(propertyType)) : void {
          $(CheckArgumentNull(<[ $(parameterName : dyn) ]>));
          $(MakeSetValue(<[ $(parameterName : dyn) ]>, propertyName, readOnly));
        }
      ]>;
      setter.Attributes |= GetSetterAccessModifiers(readOnly, propertyAccess);
      typeBuilder.Define(setter);
    }
  }
}


Вопросы по стилистике такие:

Какие соглашения на счёт того, ставить точку с запятой в конце выражения или нет?
Почему не приняты (или я ошибся) проверки аргументов на null? Пару раз из-за этого долго и мучительно разбирался с неинформативными сообщениями компилятора об ошибках (могу подробно описать).
Что предпочтительней и когда использщовать if/else или match (когда, конечно, нету разницы)?
И прочее — есть ли в каком виде документ по принятому оформлению (кроме исходников компилятора ?)

Гугловый экаунт указан в профиле (e-mail) — я так понимаю именно он нужен для получния доступа на коммит?
Help will always be given at Hogwarts to those who ask for it.
Re[2]: Макросы для WPF
От: _FRED_ Черногория
Дата: 13.04.10 10:43
Оценка:
Здравствуйте, _FRED_, Вы писали:

И самое главное:

_FR>    private CheckArgumentNull(argument : PExpr) : PExpr {
_FR>      <[
_FR>        when($(argument) == null) {
_FR>          throw ArgumentNullException(/* !!! */);
_FR>        }//when
_FR>      ]>
_FR>    }


Как тут вывести имя аргумента (видимо, argument.ToString())? Эх, "интуитивно" не удалось, надо браться за раздаточный материал
Help will always be given at Hogwarts to those who ask for it.
Re[3]: Макросы для WPF
От: hardcase Пират http://nemerle.org
Дата: 13.04.10 10:57
Оценка: 24 (1) +1
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, _FRED_, Вы писали:


_FR>И самое главное:


_FR>
_FR>>    private CheckArgumentNull(argument : PExpr) : PExpr {
_FR>>      <[
_FR>>        when($(argument) == null) {
_FR>>          throw ArgumentNullException(/* !!! */);
_FR>>        }//when
_FR>>      ]>
_FR>>    }
_FR>


_FR>Как тут вывести имя аргумента (видимо, argument.ToString())? Эх, "интуитивно" не удалось, надо браться за раздаточный материал

Для проверки на null есть метаатрибут [NotNull]:
using Nemerle.Assertions;

...

Foo([NotNull] x : object) : void {
}


В этом же пространстве имен есть макросы для проверки инвариант:
Foo(x : int) : void
    requires x > 0      // перед выполнением тела
{
...
}


mutable x : int = ... ;

Foo(i : int) : void
    enshures x < 100    // после выполнения тела
{
  x += i
}


Их также можно применять к классам.

Design by contract macros.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[4]: Макросы для WPF
От: _FRED_ Черногория
Дата: 13.04.10 10:59
Оценка:
Здравствуйте, hardcase, Вы писали:

_FR>>Как тут вывести имя аргумента (видимо, argument.ToString())? Эх, "интуитивно" не удалось, надо браться за раздаточный материал

H>Для проверки на null есть метаатрибут [NotNull]:
H>В этом же пространстве имен есть макросы для проверки инвариант:

Ух ты, а мне почему-то казалось чт это что-то недоделанное и не рабочее
Help will always be given at Hogwarts to those who ask for it.
Re[2]: Макросы для WPF
От: VladD2 Российская Империя www.nemerle.org
Дата: 14.04.10 01:05
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Пока не перечитал все статьи по макросам, так что можно и не отвечать, попробую сам разобраться со сложностями, но они такие:

_FR>(1*) — Не придумал, как добавлять к свойству акессоры, если их нет

Пока никак. Ошибка дизайна. Я над этим работаю. Скоро будет можно.

_FR>(2*) — Не придумал, как узнать тип PExpr (надо просто знать, что тип bool) тогда можно было бы понимать такое: "IsReadOnly = 3 < 5"


Не очень ясно что за PExpr. Хорошо бы на примере. Если это просто код описывающий тип, ну типа bool, то можно его типизирвоать внучную:
typer.BindFixedType(pExpr)

Если это сложное выражение, то его можно попытаться типизировать так:
typer.TypeExpr(pExpr)


_FR>(3*) — Не придумал, как узнать тип параметра и установить, является ли он наследником нужного мне типа

На стадии ВизТайпедМемберс типы будут доступны напрямую. На предыдущих стадиях можно связывать типы вручнуб с помощью BindFixedType, о котором я уже упомянал.

_FR>(4*) — Не придумал, как узнать, что имя параметра является автосгенерированным


У объектов которые сгенерированы в свойстве Location свойство IsGenerated выставлено в true.

_FR>и как изменить его (имя) на то, которое нужно мне в таком случае.


Опять же чтобы ответит на вопрос нужно понимать контекст.

_FR>Какие соглашения на счёт того, ставить точку с запятой в конце выражения или нет?


В общем, их нет. Но я обычно придерживаюсь следующего соглашения.

Если выражение не возвращает значение, например "def ..." ставлю ";" даже если он оканчивается блоком.

Не ставлю ";" если выражение возвращает значение.

Не ставлю ";" после блоков (аз исключением, того если это def ...).

Кстати, блок надо ставить только если в этом есть необходимость (т.е. есть несколько выражений). В ином случае фигурные скобки опускаются.

_FR>Почему не приняты (или я ошибся) проверки аргументов на null? Пару раз из-за этого долго и мучительно разбирался с неинформативными сообщениями компилятора об ошибках (могу подробно описать).


По лени и безграмотности. Для этих целей даже есть макра [NotNull].

_FR>Что предпочтительней и когда использщовать if/else или match (когда, конечно, нету разницы)?


То что понятнее. Обычно if/else лучше передает суть в случае выбора по булеву условию, а матч хорош когда нужно именно сопоставить что-то с образцами.

_FR>И прочее — есть ли в каком виде документ по принятому оформлению (кроме исходников компилятора ?)


К сожалению — нет. nn хотел такое дело набросать, но я не видел сделал он что-то или нет.

_FR>Гугловый экаунт указан в профиле (e-mail) — я так понимаю именно он нужен для получния доступа на коммит?


Да, он тоже пойдет. Только там букв много . Лучше пришли мне его на мыло.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Макросы для WPF
От: _FRED_ Черногория
Дата: 15.04.10 07:42
Оценка:
Здравствуйте, VladD2, Вы писали:

_FR>>(2*) — Не придумал, как узнать тип PExpr (надо просто знать, что тип bool) тогда можно было бы понимать такое: "IsReadOnly = 3 < 5"

VD>Не очень ясно что за PExpr.

Это тип переменной. То есть параметры (опции) указываются так:
[DependencyProperty(IsReadOnly = (3 < 5))]
public DependencyProperty2 : string { get { } set { } }

затем матчатся так:

      mutable metadata, validate, isReadOnly;
      foreach(item in options) {
        | …
        | <[ IsReadOnly = $value ]> => … // Вот здесь "value" имеет тип PExpr, требуется узнать тип выражения
        | …
      }//for

VD>Если это сложное выражение, то его можно попытаться типизировать так:
VD>typer.TypeExpr(pExpr)


Что за typer? Я так понимаю
Автор: VladD2
Дата: 08.04.10
, что это "Nemerle.Macros.ImplicitCTX()"? Но такое выражение у меня не работает: у типа Macros в пространстве имён Nemerle нет метода ImplicitCTX().

_FR>>(3*) — Не придумал, как узнать тип параметра и установить, является ли он наследником нужного мне типа

VD>На стадии ВизТайпедМемберс типы будут доступны напрямую.

Эта стадия не подходит.

VD>На предыдущих стадиях можно связывать типы вручнуб с помощью BindFixedType, о котором я уже упомянал.


Попробую, но что-то не ясно, как сравнить FixrdType и Type.

_FR>>(4*) — Не придумал, как узнать, что имя параметра является автосгенерированным

VD>У объектов которые сгенерированы в свойстве Location свойство IsGenerated выставлено в true.

Вот такое объявление:
[DependencyProperty]
public static GetDependencyProperty3(_ : DependencyObject) : int;

в макросе MacroPhase.BeforeInheritance получаю параметр так:
      def parameters = method.header.Parameters;
      when(parameters.Length != 1) {
        Message.Error(method.Location, "Attached property method should have exactly one parameter of type 'DependencyObject' or derived.");
      }//when
      def parameter = parameters.Head;

далее:
      Message.Hint($"parameter.Name = $(parameter.Name).");
      Message.Hint($"parameter.IsGenerated = $(parameter.IsGenerated).");
      Message.Hint($"parameter.Location.IsGenerated = $(parameter.Location.IsGenerated).");
      Message.Hint($"parameter.Location.IsGeneratedOrEmpty = $(parameter.Location.IsGeneratedOrEmpty).");
      Message.Hint($"parameter.NameLocation.IsGenerated = $(parameter.NameLocation.IsGenerated).");
      Message.Hint($"parameter.NameLocation.IsGeneratedOrEmpty = $(parameter.NameLocation.IsGeneratedOrEmpty).");
      Message.Hint($"parameter.PName.IsGenerated = $(parameter.PName.IsGenerated).");
      Message.Hint($"parameter.PName.Location.IsGenerated = $(parameter.PName.Location.IsGenerated).");
      Message.Hint($"parameter.PName.Location.IsGeneratedOrEmpty = $(parameter.PName.Location.IsGeneratedOrEmpty).");

И получаю:
Warning: hint: parameter.Name = _N_wildcard_2775.
Warning: hint: parameter.IsGenerated = False.
Warning: hint: parameter.Location.IsGenerated = False.
Warning: hint: parameter.Location.IsGeneratedOrEmpty = False.
Warning: hint: parameter.NameLocation.IsGenerated = False.
Warning: hint: parameter.NameLocation.IsGeneratedOrEmpty = False.
Warning: hint: parameter.PName.IsGenerated = False.
Warning: hint: parameter.PName.Location.IsGenerated = False.
Warning: hint: parameter.PName.Location.IsGeneratedOrEmpty = False.



А мне бы хотелось, что бы в случае, когда пользователь имя явно не указал, вместо "_N_wildcard_2775" подставить своё имя, например, "value". Но не понятно, как имя изменить и как определить, что оно автоматическое?

VD>Кстати, блок надо ставить только если в этом есть необходимость (т.е. есть несколько выражений). В ином случае фигурные скобки опускаются.


Ну дело ваше Я конечно же перед комитом лишние блоки уберу и коменты в конце блока (a-la "}//match") тоже удалю.

Так же, чего очень не хватает, так это знать, к каким членам аргументов макроса на какой фазе мы имеем дело. Например, хочу узнать, к extension-ли методу применён макрос? А не могу Почему-то на фазе MacroPhase.BeforeInheritance свойство Builder в "method : ClassMember.Function" пустое, а в билдере как раз есть методы управлением этим делом

Сделать же метод методом-расширением возможно с помощью method.AddCustomAttribute(<[ Nemerle.Internal.ExtensionAttribute() ]>);, но вот узнать, является ли метод расширением нельзя: method.GetCustomAttributes() возвращает пустой список

Для написания макросов же необходим документ, в котором говорилось бы, какими методами\свойствами передаваемых аргументов можно пользоваться, а то отладка этого дела (то есть узнавание что есть, а что нет через принты) занимает непростительно много времени.
Help will always be given at Hogwarts to those who ask for it.
Re[4]: Макросы для WPF
От: hardcase Пират http://nemerle.org
Дата: 15.04.10 11:21
Оценка:
Здравствуйте, _FRED_, Вы писали:


_FR>А мне бы хотелось, что бы в случае, когда пользователь имя явно не указал, вместо "_N_wildcard_2775" подставить своё имя, например, "value". Но не понятно, как имя изменить и как определить, что оно автоматическое?


using Nemerle;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;


  [MacroUsage(MacroPhase.BeforeInheritance, MacroTargets.Method)]
  public macro Macro1(tb : TypeBuilder, m : ParsedMethod)
  {
    Impl.DoWork(tb, m)
  }
  
  
  module Impl {
  
    public DoWork(_ : TypeBuilder, m : ClassMember.Function) : void {
      match(m.header.Parameters) {
        | single :: [] when single.PName.ParcedId == "_" =>
          Message.Hint("Automatic wildecard rename.");
          m.header.Parameters = PParameter(Splicable.Name(Name("value", single.PName.Location, single.PName.color, single.PName.context)), single.modifiers, single.ParsedType) :: [];

        | single :: [] =>
          Message.Hint($"Single parameter $single found no need to rename.");

        | _ => 
          Message.FatalError("Single parameter required.");
      }
    }
  
  }


Использование:
  [MacroLibrary1.Macro1]
  Foo(_ : string) : void { WriteLine(value) }



З.Ы. Макрос отлаживать можно подставив (только осторожно) следующее:
_ = System.Diagnostics.Debugger.Launch();
/* иЗвиНите зА неРовнЫй поЧерК */
Re[4]: Макросы для WPF
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.04.10 12:10
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, VladD2, Вы писали:


_FR>>>(2*) — Не придумал, как узнать тип PExpr (надо просто знать, что тип bool) тогда можно было бы понимать такое: "IsReadOnly = 3 < 5"

VD>>Не очень ясно что за PExpr.

Узнать не сложно. Достаточно типизировать выражение.

Вот только я не очень понимаю зачем? Не уж то параметр с именем IsReadOnly может иметь не булев тип?

Кроме того я не понимаю какой смысл в выражении "3 < 5". Какие выражения будут встречаться в реальном коде?

_FR>Что за typer? Я так понимаю
Автор: VladD2
Дата: 08.04.10
, что это "Nemerle.Macros.ImplicitCTX()"?


Да. Ты правильно понял.

_FR>Но такое выражение у меня не работает: у типа Macros в пространстве имён Nemerle нет метода ImplicitCTX().


Это ImplicitCTX — это макрос доступный в теле макросов или если перед его использованием вызвали DefineCTX().

Сделай поиск по коду каталога macros.

_FR>Попробую, но что-то не ясно, как сравнить FixrdType и Type.


Это просто не надо делать. Сравнивать нужно только FixrdType и VarType. Откуда взялся Type? И правильно ли я понял, что речь идет о System.Type?

...
_FR>И получаю:
_FR>
_FR>Warning: hint: parameter.Name = _N_wildcard_2775.
_FR>Warning: hint: parameter.IsGenerated = False.
_FR>

_FR>

_FR>А мне бы хотелось, что бы в случае, когда пользователь имя явно не указал, вместо "_N_wildcard_2775" подставить своё имя, например, "value". Но не понятно, как имя изменить и как определить, что оно автоматическое?


Понятно. Это все же код полученный путем парсинга исходного файла. У его все локешноы корректные.
Если тебе нужно распознать именно вилдкард, то можешь просто проверять префикс "_N_" и сравнивать длину имени с позицией заданной в локешное (там она будет один символ, так как исходное имя "_").

_FR>Так же, чего очень не хватает, так это знать, к каким членам аргументов макроса на какой фазе мы имеем дело. Например, хочу узнать, к extension-ли методу применён макрос? А не могу Почему-то на фазе MacroPhase.BeforeInheritance свойство Builder в "method : ClassMember.Function" пустое, а в билдере как раз есть методы управлением этим делом


На этой файзе типы еще не связаны.
А зачем может понадобиться информация является ли метод методом-расширением?

_FR>Сделать же метод методом-расширением возможно с помощью method.AddCustomAttribute(<[ Nemerle.Internal.ExtensionAttribute() ]>);, но вот узнать, является ли метод расширением нельзя: method.GetCustomAttributes() возвращает пустой список


Я погляжу что там и как и отвечу позже.

_FR>Для написания макросов же необходим документ, в котором говорилось бы, какими методами\свойствами передаваемых аргументов можно пользоваться, а то отладка этого дела (то есть узнавание что есть, а что нет через принты) занимает непростительно много времени.


В одной из моих статей (расширенный курс) об этом рассказывается.

В двух словах все что связано с типами доступно только на стадии ВизТайпедМемберс.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Макросы для WPF
От: _FRED_ Черногория
Дата: 15.04.10 12:22
Оценка:
Здравствуйте, VladD2, Вы писали:

_FR>>>>(2*) — Не придумал, как узнать тип PExpr (надо просто знать, что тип bool) тогда можно было бы понимать такое: "IsReadOnly = 3 < 5"

VD>>>Не очень ясно что за PExpr.
VD>Узнать не сложно. Достаточно типизировать выражение.
VD>Вот только я не очень понимаю зачем? Не уж то параметр с именем IsReadOnly может иметь не булев тип?
VD>Кроме того я не понимаю какой смысл в выражении "3 < 5". Какие выражения будут встречаться в реальном коде?

Например, сравнение двух констант

_FR>>Попробую, но что-то не ясно, как сравнить FixrdType и Type.


VD>Это просто не надо делать. Сравнивать нужно только FixrdType и VarType. Откуда взялся Type? И правильно ли я понял, что речь идет о System.Type?


Да, System.Type. Требуется проверить, что макрос объявлен в типе, который унаследован от DependencyObject. Затем, если метаданные не указаны и тип унаследован от UIElement, то по дефолту создавать UIPropertyMetadata, а если от FrameworkElement, то FrameworkPropertyMetadata. Так же первым параметром метода (в макросе на метод) должен быть тип, унаследованный от DependencyObject. Это, конечно, не очень критично, но хотелось бы.

VD>Понятно. Это все же код полученный путем парсинга исходного файла. У его все локешноы корректные.


Мне тут уже выше показали, буду пробовать.

_FR>>Так же, чего очень не хватает, так это знать, к каким членам аргументов макроса на какой фазе мы имеем дело. Например, хочу узнать, к extension-ли методу применён макрос? А не могу Почему-то на фазе MacroPhase.BeforeInheritance свойство Builder в "method : ClassMember.Function" пустое, а в билдере как раз есть методы управлением этим делом


VD>На этой файзе типы еще не связаны.

VD>А зачем может понадобиться информация является ли метод методом-расширением?

Очень удобно методы-аккесоры аттачед-свойств делать методами\расширениями. Но не всегда :о)) Поэтому хотелось бы, если Get-метод объявлен как метод-расширение, то и создаваемый макросом Set-акессор так же делать расширением. Между прочим, почему Немерле использует свой ExtensionAttribut и не позволяет иметь не-паблик методы-расширения?

_FR>>Сделать же метод методом-расширением возможно с помощью method.AddCustomAttribute(<[ Nemerle.Internal.ExtensionAttribute() ]>);, но вот узнать, является ли метод расширением нельзя: method.GetCustomAttributes() возвращает пустой список


VD>Я погляжу что там и как и отвечу позже.


Спасибо! Кстати, мне оказалась достаточной фаза BeforeTypedMembers, но на сколько она лучше — ещё не успел изучить :о)

_FR>>Для написания макросов же необходим документ, в котором говорилось бы, какими методами\свойствами передаваемых аргументов можно пользоваться, а то отладка этого дела (то есть узнавание что есть, а что нет через принты) занимает непростительно много времени.


VD>В одной из моих статей (расширенный курс) об этом рассказывается.


Да, уже начал читать, многие вопросы отпадают — то что я просил как раз всё понятно расскано

VD>В двух словах все что связано с типами доступно только на стадии ВизТайпедМемберс.


Буду пытаться понять
Help will always be given at Hogwarts to those who ask for it.
Re[4]: Макросы для WPF
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.04.10 13:13
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Сделать же метод методом-расширением возможно с помощью method.AddCustomAttribute(<[ Nemerle.Internal.ExtensionAttribute() ]>);, но вот узнать, является ли метод расширением нельзя: method.GetCustomAttributes() возвращает пустой список


К сожалнию, на сегодня узнать это до стадии ВизТайпедМемберс невозможно. Да и на ней не факт, что получится.

Проблема как всегда в халтуре. Парсинг "this" реализован макро-атрибутом "_N_ExtensionMethodOnThisParameter" для параметра который отрабатывает на стадии WithTypedMembers.

В общем, это можно признать багом. Так что надо фиксить.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Макросы для WPF
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.04.10 13:23
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Например, сравнение двух констант


А есть в этом смысл?

В общем, TypeExpr() тебе поможет.

_FR>Да, System.Type. Требуется проверить, что макрос объявлен в типе, который унаследован от DependencyObject. Затем, если метаданные не указаны и тип унаследован от UIElement, то по дефолту создавать UIPropertyMetadata, а если от FrameworkElement, то FrameworkPropertyMetadata. Так же первым параметром метода (в макросе на метод) должен быть тип, унаследованный от DependencyObject. Это, конечно, не очень критично, но хотелось бы.


Очень советую прочитать четвертую часть
Автор(ы): Владислав Юрьевич Чистяков
Дата: 03.09.2009
В данной части статьи рассказывается о том, как работает система вывода типов Nemerle, о том, как с ней могут взаимодействовать макросы Nemerle, и что это дает
Расширенного курса по макрам. Там этот вопрос освещается.

Вкратце, DependencyObject нужно получать через немерловый интерфейс (например, через <[ ttype: ...DependencyObject ]> и проверять с помощью метода TryRequire().

А про System.Type в макросах нужно вообще забыть. Как будто нет его.

_FR>Очень удобно методы-аккесоры аттачед-свойств делать методами\расширениями. Но не всегда :о)) Поэтому хотелось бы, если Get-метод объявлен как метод-расширение, то и создаваемый макросом Set-акессор так же делать расширением.\\\\\


А может лучше его всегда делать методом-расшерением?

Кстати, а зачем там вообще методы? Это же вроде свойства?

_FR> Между прочим, почему Немерле использует свой ExtensionAttribut и не позволяет иметь не-паблик методы-расширения?


Это подстраховка на случай если используется .net 2.0.

_FR>Спасибо! Кстати, мне оказалась достаточной фаза BeforeTypedMembers, но на сколько она лучше — ещё не успел изучить :о)


Чем на более ранней стадии может отработать макрос, тем лучше, так как плодами его работы смогут воспользоваться макры следующих стадий.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Макросы для WPF
От: _FRED_ Черногория
Дата: 15.04.10 13:44
Оценка:
Здравствуйте, VladD2, Вы писали:

_FR>>Очень удобно методы-аккесоры аттачед-свойств делать методами\расширениями. Но не всегда :о)) Поэтому хотелось бы, если Get-метод объявлен как метод-расширение, то и создаваемый макросом Set-акессор так же делать расширением.\\\\\


VD>А может лучше его всегда делать методом-расшерением?


Нет, все не имеет смысла. Ниже объясню почему.

VD>Кстати, а зачем там вообще методы? Это же вроде свойства?


Методы используются для attached-свойств, то есть свойств, которые не являются частью интерфейса объекта, а являются "прикрепляемыми". По сути, любому объекту можно назначить любое свойство, но всяким визульным дизайнерам и прочим внешним сервисам удобно различать свойства самого объекта (свойства, объявленные самим объектом) и свойства, которые объявлены в одном месте, а используются для тех же объектов. Такие прикрепляемые свойства реализуются посредством не экземплярного свойства (в котором есть this), а с помощью статического метода Get<Name>/Set<Name>, первым параметром в который приходит объект, к которому свойство следует применить. Запутал, да..? Может, так:

Attached иначе называются "прикрепляемыми". Прикрепляемые свойства описываются так:
<PropertyType> Get<PropertyName>(DependencyObject+ obj);
Set<PropertyName>(DependencyObject+ obj, <PropertyType> value);

то есть их можно "снаружи" прикрепить к любому (почти) объекту. Иногда имена таких свойств достаточно информативны и не дублируются, например:
class WatermarkService
{
  public static object GetWatermark(TextBox obj) { }
  public static SetWatermark(TextBox obj, object value) { }
}

и очень удобно сделать метода-акессоры к свойству расширениями. Но некоторые свойства имеют более общеупотребительные имена:

class RadioButtonListBoxExtensions
{
  public static object GetItemValue(FrameworkElement obj) { }
  public static SetItemValue(FrameworkElement obj, object value) { }
}

и тут без имени класса не понятно, о каком таком ItemValue речь, а переносить в имя свойства часть имени класса мне кажется здесь излишне. Поэтому иногда нужно extension, а иногда нет.

_FR>> Между прочим, почему Немерле использует свой ExtensionAttribut и не позволяет иметь не-паблик методы-расширения?


VD>Это подстраховка на случай если используется .net 2.0.


_FR>>Спасибо! Кстати, мне оказалась достаточной фаза BeforeTypedMembers, но на сколько она лучше — ещё не успел изучить :о)


VD>Чем на более ранней стадии может отработать макрос, тем лучше, так как плодами его работы смогут воспользоваться макры следующих стадий.
Help will always be given at Hogwarts to those who ask for it.
Re[8]: Макросы для WPF
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.04.10 15:41
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Нет, все не имеет смысла. Ниже объясню почему...


В общих чертах ясно. Откровенно говоря дизайн в ВПФ так себе...

А может для всех этих свойств генерировать полноценные свойства? Или код распухнет?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Макросы для WPF (с другой стороны)
От: MxMsk Португалия  
Дата: 01.04.11 06:22
Оценка: +1
Здравствуйте, WolfHound, Вы писали:

WH>Раз уж я написал макру то зачем добру пропадать?...

WH>Если у кого есть жилание развивать это дело до полноценного решения то нужно завести аккаунт на гугле поросить Влада чтобы добавил вас в коммитеры.
Еще когда всё это было на стадии обсуждения, что-то не давало мне покоя в этом решении. И вот вчера, когда Влад вывел на экран то, как выглядит применение этих макросов, я понял, что мне не нравится. Зашли не с той стороны! Нужно не из обычных свойств генерировать DependencyProperty, а, наоборот, из DependencyProrperty (или DependencyProrpertyKey) генерировать CLR-свойства (или Get/Set методы).

На количество кода это не повлияет, зато:
  1. Параметры свойства будут нагляднее — их не будут заменять никакие элементы языка.
  2. Не будет хаков по части объявления attached свойств.
  3. Не потребуется специальный макрос для AddOwner.
  4. Макрос перестанет зависеть от параметров конструктора DependencyProperty. Разве что только по части типа значения свойства.

Для WPF идентификаторы важнее (вспомним OverrideMetadata), а добавление в классы обычных свойств называется не иначе, как создание CLR Wrapper. Странно генерить исходник из его обертки

Но вот беда! Nemerle я не не знаю (пока). Так что это только предложение к обсуждению
Re[2]: Макросы для WPF (с другой стороны)
От: _FRED_ Черногория
Дата: 01.04.11 06:46
Оценка:
Здравствуйте, MxMsk, Вы писали:

WH>>Раз уж я написал макру то зачем добру пропадать?...

WH>>Если у кого есть жилание развивать это дело до полноценного решения то нужно завести аккаунт на гугле поросить Влада чтобы добавил вас в коммитеры.
MM>Еще когда всё это было на стадии обсуждения, что-то не давало мне покоя в этом решении. И вот вчера, когда Влад вывел на экран то, как выглядит применение этих макросов, я понял, что мне не нравится. Зашли не с той стороны! Нужно не из обычных свойств генерировать DependencyProperty, а, наоборот, из DependencyProrperty (или DependencyProrpertyKey) генерировать CLR-свойства (или Get/Set методы).

Это менее универсально, ибо не редко на свойства нужно навешать атрибутов (с соответствующим AttributeTarget), а вот навешивать атрибуты на поля не приходится.
Help will always be given at Hogwarts to those who ask for it.
Re[2]: Макросы для WPF (с другой стороны)
От: _FRED_ Черногория
Дата: 01.04.11 06:51
Оценка:
Здравствуйте, MxMsk, Вы писали:

MM>Но вот беда! Nemerle я не не знаю (пока). Так что это только предложение к обсуждению


А вообще, я пока написанный WolfHound-ом макрос дополнять не взялся, тоже на Немерле не писал ничего Что было неясно спрашивал — отвечали очень оперативно :о))
Help will always be given at Hogwarts to those who ask for it.
Re[3]: Макросы для WPF (с другой стороны)
От: BogdanMart Украина  
Дата: 01.04.11 08:57
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, MxMsk, Вы писали:


_FR>Это менее универсально, ибо не редко на свойства нужно навешать атрибутов (с соответствующим AttributeTarget), а вот навешивать атрибуты на поля не приходится.


Наверно надо два механизма.
Re[4]: Макросы для WPF (с другой стороны)
От: _FRED_ Черногория
Дата: 01.04.11 09:02
Оценка:
Здравствуйте, BogdanMart, Вы писали:

_FR>>Это менее универсально, ибо не редко на свойства нужно навешать атрибутов (с соответствующим AttributeTarget), а вот навешивать атрибуты на поля не приходится.


BM>Наверно надо два механизма.


Да в случае полей проблем всё равно будет не меньше да всё те же: попробовали бы что ли пример набросать, как оно должно выглядеть, сразу стало бы понятненько.
Help will always be given at Hogwarts to those who ask for it.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.