Создание event-ов в макросах
От: hardcase Пират http://nemerle.org
Дата: 20.02.10 10:12
Оценка:
Ноги растут примерно отсюда
Автор: hardcase
Дата: 16.02.10
.

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

VD>По уму имя поля, add-ера и remove-ера нужно формировать динамически.

VD>Посему для формирования имен поля, add-ера и remove-ера нужно сформировать экзепляры Splicable.Expression() которые будут содержать код из имени свойства плюс дополнительный код модифицирующий имя так чтобы из него получались требуемые имена.

VD>Сплайс вида "$(name : usesite)" на этапе компиляции квази-цитаты преобразуется в:

VD>
VD>Splicable.Expression(<[ name : usesite ]>, GlobalEnv(...))
VD>

VD>Думается, что нужно разобрать выражение <[ name : usesite ]> "на запчасти" и вцепить из него выржение (в данном случае "name"), тип (в данном случае "usesite") и сформировать новые выражение которое будут выглядеть как-то так:
VD>
VD><[ ("_N_event_field_of_" + name) : usesite ]> // для имени поля 
VD><[ ("add_" + name) : usesite ]>               // для имени add-ера
VD><[ ("remove_" + name) : usesite ]>            // для имени remove-ра
VD>

VD>ну, и далее сформировать на их основе новые варианты Splicable.Expression() которые и использовать для формирования имен соответствующих сущностный.

Попробовал написать патч, решающий эту проблему. На "запчасти" разбираю сплайс-выражение таким вот образом:
AddSplicableNamePrefix(prefix : string, id : Splicable, loc : Location) : Splicable
{
  match(id)
  {
    | Splicable.Name(body) => MkSplicableName(prefix + body.Id, loc)
    | Splicable.HalfId(pref) => Splicable.HalfId(loc, Name(prefix + pref.Id, loc, pref.color, pref.context))
    | Splicable.Expression(expr) as id =>
      def new_expr = match(expr)
      {
        | PExpr.TypeEnforcement(expr, ty) =>
            <[ ($(prefix : string) + $expr.ToString()) : $ty ]>
        | _ =>   
            <[ ($(prefix : string) + $expr.ToString()) : usesite ]>
      }
      Splicable.Expression(loc, new_expr, id.env)
  }
}

Т.е. тупо преобразую исходное выражение в строку, и добавляю префикс ("add_", "remove_", или "_N_event_field_of_").

Соответственно переправил метод parse_event в файле MainParser.n (закомментированые строчки — оригинал):

parse_event (mutable loc : Location, mods : Modifiers,
             mutable customs : list [Token.SquareGroup]) : ClassMember
{
  def id = get_splicable_id ();
  def ret_type = parse_return_type(false, Location.Default);
  loc += ret_type.Location;
  //def plain_name = id.ToString();
  def val_n = MkSplicableName("value", loc.AsGenerated());
  mutable remove = null;
  mutable add = null;
  
  match (peek_token ())
  {
    | Token.BracesGroup as group =>
      shift ();
      take_attributes_out (ref customs, System.AttributeTargets.Event, true, mods);

      foreach (Token.LooseGroup (toks) in group)
      {
        push_stream (toks);
        mutable mycustoms = get_customs ();
        def mymods = get_modifiers ();

        match (get_token ())
        {
          | Token.Identifier (i) as nametok =>
            def genLoc = nametok.Location.AsGenerated();
            match (i)
            {
              | "remove" | "add" =>
                if (i == "remove")
                  unless (remove == null)
                    Message.Error (nametok.Location, "event cannot have multiple remove methods");
                else
                  unless (add == null)
                    Message.Error (nametok.Location, "event cannot have multiple add methods");

                def method_atts = Modifiers (mymods, []);                           
                take_attributes_out (ref mycustoms, System.AttributeTargets.Method, false, method_atts);
                parse_top_extensions (method_atts, MacroTargets.Method);                    

                def par_atts = Modifiers (NemerleAttributes.None, []);
                take_attributes_out (ref mycustoms, System.AttributeTargets.Parameter, true, par_atts);
                def method_parms = [PParameter (val_n, ret_type, par_atts)];
                
                def bodyBracesGroup = TryPeekBracesGroup();
                def (kind, body) = parse_accessor_body (method_parms, []);
                //def name = MkSplicableName(i + "_" + plain_name, plain_name, genLoc);
                def name = AddSplicableNamePrefix(i + "_", id, genLoc);
                def fh = PFunHeader (genLoc, name, PExpr.Void (), method_parms);
                def method = ClassMember.Function (CombineLocations(nametok, bodyBracesGroup), 
                               name, method_atts, fh, kind, body);
                method.ParsedBody = body;
                InitBodyLocations(method, bodyBracesGroup);
                method._env = env;
                if (i == "remove")
                  remove = method;
                else
                  add = method;

              | _ =>
                def fieldName = MkSplicableName(i, nametok.Location);
                def ty = parse_return_type(false, Location.Default);
                def attrs = Modifiers (mymods, []);
                take_attributes_out (ref mycustoms, System.AttributeTargets.Field, true, attrs);
                def f = ClassMember.Field (nametok.Location.Combine(ty.Location), fieldName, attrs, ty);
                def embed = PExpr.Quoted (genLoc, SyntaxElement.ClassMember (f));
                mods.AddCustomAttribute(<[ $(MkNameGenerated("Nemerle") : name).InternalMacros.EventEmbeddedField($embed) ]>);
            }

          | x => Error (x, "expecting event accessor"); 
        }
        pop_stream ("property member");
      }
      when (add == null || remove == null)
        Message.Error (loc, "both of event accessors `add' and 'remove' must be specified");
      
      ClassMember.Event (loc + group.Location, id, mods, ret_type, null, add, remove)
      
    | Token.EndOfGroup =>
      // first take out event attributes (those without target also get here)
      take_attributes_out (ref customs, System.AttributeTargets.Event, false, mods);
      
      /// auto-generated field
      //def fieldName = "_N_event_field_of_" + plain_name;
      def fmods = NemerleAttributes.Private %| NemerleAttributes.Mutable;
      //def doRenaming = !Manager.IsIntelliSenseMode;
      def generatedLoc = loc.AsGenerated();
      //def field_name = if (doRenaming) MkTempName(fieldName, generatedLoc) else MkName(fieldName, generatedLoc);
      def field_name = AddSplicableNamePrefix("_N_event_field_of_", id, generatedLoc);
      def field_attrs = Modifiers (fmods, []);
      take_attributes_out (ref customs, System.AttributeTargets.Field, false, field_attrs);
      //def field = ClassMember.Field (generatedLoc, Splicable.Name (field_name), field_attrs, ret_type);
      def field = ClassMember.Field (generatedLoc, field_name, field_attrs, ret_type);
      field.ParsedType = ret_type;

      def method_atts = Modifiers (mods.Attributes, []);                                         
      take_attributes_out (ref customs, System.AttributeTargets.Method, true, method_atts);

      def method_parms = [PParameter (val_n, ret_type, Modifiers ())];

      //def name = MkSplicableName("add_" + plain_name, generatedLoc);
      def name = AddSplicableNamePrefix("add_", id, generatedLoc);
      def fh = PFunHeader (generatedLoc, name, PExpr.Void (generatedLoc), method_parms);
      // funbody is filled during typing
      add = ClassMember.Function (generatedLoc, name, method_atts, fh, [], null);
      add._env = env;

      //def name = MkSplicableName("remove_" + plain_name, generatedLoc);
      def name = AddSplicableNamePrefix("remove_", id, generatedLoc);
      def fh = PFunHeader (generatedLoc, name, PExpr.Void (generatedLoc), method_parms);
      remove = ClassMember.Function (generatedLoc, name, method_atts, fh, [], null);
      remove._env = env;

      ClassMember.Event (loc, id, mods, ret_type, field, add, remove)
      
    | t => Error (t, "expecting `;' or `{ }' in event declaration"); null
  }
}


Сей грубый способ формирования имен методов и поля в принципе работает, для макроса вида
using Nemerle;
using Nemerle.Compiler;
using PT = Nemerle.Compiler.Parsetree;

namespace Lib {

    [MacroUsage(MacroPhase.BeforeTypedMembers, MacroTargets.Class)]
    public macro CreateEvents(tb : TypeBuilder) {
        Helper.CreateEvents(tb, [ "Foo", "Bar" ]);
    }

    module Helper {
        public CreateEvents(tb :TypeBuilder, events : list[string]) : void {
            foreach(name in events) {
                tb.Define(<[ decl:
                    public event $(name : usesite) : System.EventHandler;
                ]>);
            }
        }
    }
}


Рефлектор показал (id — это текущий name в foreach-е):

       tb.Define(
new ClassMember.Event(
    new Splicable.Name(new Name(id, ManagerClass.Instance.MacroColors.UseColor, ManagerClass.Instance.MacroColors.UseContext)),
    
    new Modifiers(NemerleAttributes.Public, list<PExpr>.Nil._N_constant_object),
    
    new PExpr.Member(
        new PExpr.Ref(Name.NameInCurrentColor("System", _N_MacroContexts.Get(1, ManagerClass.Instance))),
        new Splicable.Name(Name.NameInCurrentColor("EventHandler", _N_MacroContexts.Get(1, ManagerClass.Instance)))),
    
    new ClassMember.Field(
        new Splicable.Name(new Name("_N_event_field_of_" + id.ToString(), ManagerClass.Instance.MacroColors.UseColor, ManagerClass.Instance.MacroColors.UseContext)),
        new Modifiers(NemerleAttributes.Mutable | NemerleAttributes.Private, list<PExpr>.Nil._N_constant_object),
        new PExpr.Member(
            new PExpr.Ref(Name.NameInCurrentColor("System", _N_MacroContexts.Get(1, ManagerClass.Instance))),
            new Splicable.Name(Name.NameInCurrentColor("EventHandler", _N_MacroContexts.Get(1, ManagerClass.Instance))))),
    
    new ClassMember.Function(
        new Splicable.Name(new Name("add_" + id.ToString(), ManagerClass.Instance.MacroColors.UseColor, ManagerClass.Instance.MacroColors.UseContext)),
        new Modifiers(NemerleAttributes.Public, list<PExpr>.Nil._N_constant_object),
        new PFunHeader(
            new Typarms(list<Splicable>.Nil._N_constant_object, list<Constraint>.Nil._N_constant_object),
            new Splicable.Name(new Name("add_" + id.ToString(), ManagerClass.Instance.MacroColors.UseColor, ManagerClass.Instance.MacroColors.UseContext)),
            new PExpr.Void(),
            new list<PParameter>.Cons(
                new PParameter(
                    new Splicable.Name(Name.NameInCurrentColor("value", _N_MacroContexts.Get(1, ManagerClass.Instance))),
                    new Modifiers(NemerleAttributes.None, list<PExpr>.Nil._N_constant_object),
                    new PExpr.Member(
                        new PExpr.Ref(Name.NameInCurrentColor("System", _N_MacroContexts.Get(1, ManagerClass.Instance))),
                        new Splicable.Name(Name.NameInCurrentColor("EventHandler", _N_MacroContexts.Get(1, ManagerClass.Instance))))),
                list<PParameter>.Nil._N_constant_object)),
        list<PExpr>.Nil._N_constant_object,
        FunBody.Abstract._N_constant_object),
            
    new ClassMember.Function(
        new Splicable.Name(new Name("remove_" + id.ToString(), ManagerClass.Instance.MacroColors.UseColor, ManagerClass.Instance.MacroColors.UseContext)),
        new Modifiers(NemerleAttributes.Public, list<PExpr>.Nil._N_constant_object),
        new PFunHeader(
            new Typarms(list<Splicable>.Nil._N_constant_object, list<Constraint>.Nil._N_constant_object),
            new Splicable.Name(new Name("remove_" + id.ToString(), ManagerClass.Instance.MacroColors.UseColor, ManagerClass.Instance.MacroColors.UseContext)),
            new PExpr.Void(),
            new list<PParameter>.Cons(
                new PParameter(
                    new Splicable.Name(Name.NameInCurrentColor("value", _N_MacroContexts.Get(1, ManagerClass.Instance))),
                    new Modifiers(NemerleAttributes.None, list<PExpr>.Nil._N_constant_object),
                    new PExpr.Member(
                        new PExpr.Ref(Name.NameInCurrentColor("System", _N_MacroContexts.Get(1, ManagerClass.Instance))),
                        new Splicable.Name(Name.NameInCurrentColor("EventHandler", _N_MacroContexts.Get(1, ManagerClass.Instance))))),
                list<PParameter>.Nil._N_constant_object)),
        list<PExpr>.Nil._N_constant_object,
        FunBody.Abstract._N_constant_object)));


Т.е. вроде бы то что нужно... проблема возникает при компиляции.
Для построенных таким макросом событий
[CreateEvents] class C1 { }

компилятор 4 раза жалуется на value (видимо для каждого аксессора для двух эвентов Foo и Bar):
event-macro.n:3:2:3:14: ←[01;31merror←[0m: unbound name `value'
event-macro.n:3:2:3:14: ←[01;31merror←[0m: unbound name `value'
event-macro.n:3:2:3:14: ←[01;31merror←[0m: unbound name `value'
event-macro.n:3:2:3:14: ←[01;31merror←[0m: unbound name `value'

В остальном все тесты компилятора проходят.

События с фиксированным именем, вида
tb.Define(<[ decl:
    public event OnDoSomething : System.EventHandler;
]>);

создаются нормально.
/* иЗвиНите зА неРовнЫй поЧерК */
Re: Создание event-ов в макросах
От: hardcase Пират http://nemerle.org
Дата: 20.02.10 12:55
Оценка:
Здравствуйте, hardcase, Вы писали:

H> ... дофига ....



Может быть проблема в "контекстах":

new Splicable.Name(new Name("remove_" + id.ToString(), ManagerClass.Instance.MacroColors.UseColor, ManagerClass.Instance.MacroColors.UseContext))


против

new Splicable.Name(Name.NameInCurrentColor("value", _N_MacroContexts.Get(1, ManagerClass.Instance)))



Какой они физический смысл несут?
/* иЗвиНите зА неРовнЫй поЧерК */
Re[2]: Создание event-ов в макросах
От: hardcase Пират http://nemerle.org
Дата: 21.02.10 12:11
Оценка: 129 (1)
Баг с созданием событий пофиксил, патч и тесты залил в репозиторий.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[3]: Создание event-ов в макросах
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.02.10 15:21
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Баг с созданием событий пофиксил, патч и тесты залил в репозиторий.


Здорово! С почином!

И пара замечаний.

1. В коде не нужно оставлять закомментированным старый (удаленный) код. Об удалении функций лучше писать в комментариях к комиту в SVN.

2. Нужно придерживаться соглашений по форматированию кода RSDN. В частности, фигурные скобки нужно начинать с новой строки. Отступы в коде делать двумя пробелами (1 табуляция = 2 пробела).

3. Ты убрал одну существенную функциональность. Поле, автоматически генерируемое для свойства, при компиляции переименовывалось, чтобы случайно не совпасть с именем другой переменной или чтобы нельзя было обратиться к нему по имени из конечной программы.

4. В позитивных тестах нужно делать проверки. О том как работать с тестами можно прочесть здесь
Автор: VladD2
Дата: 02.02.10
.

Все вышеуказанное я пофиксил.

Но в целом ты молодец! Задача была не из легких.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Создание event-ов в макросах
От: hardcase Пират http://nemerle.org
Дата: 21.02.10 20:41
Оценка:
Здравствуйте, VladD2, Вы писали:


VD>Здорово! С почином!


Спасибо.

VD>1. В коде не нужно оставлять закомментированным старый (удаленный) код. Об удалении функций лучше писать в комментариях к комиту в SVN.


Замечание понятно, причиной тому была та самая "существенная функциональность", которую я отключил: я не совсем понял логики переименования. Потому и прежний код оставил.

VD>2. Нужно придерживаться соглашений по форматированию кода RSDN. В частности, фигурные скобки нужно начинать с новой строки. Отступы в коде делать двумя пробелами (1 табуляция = 2 пробела).


Сложно, блин, особенно когда есть собственный давно выработанный стиль.

VD>4. В позитивных тестах нужно делать проверки. О том как работать с тестами можно прочесть здесь
Автор: VladD2
Дата: 02.02.10
.


Заметку читал, просто как-то упустил из виду — пытался просто заставить компилироваться.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[5]: Создание event-ов в макросах
От: VladD2 Российская Империя www.nemerle.org
Дата: 23.02.10 12:42
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Замечание понятно, причиной тому была та самая "существенная функциональность", которую я отключил: я не совсем понял логики переименования. Потому и прежний код оставил.


Дык все и так увидят удаление. Лучше уж тогда написать комментарий. Мол не полня, что за фигня... Поправьте если что...

H>Сложно, блин, особенно когда есть собственный давно выработанный стиль.


Сам к некоторым аспектам долго привыкал. Но код должен быть единобразным. РСДН-овские правила проверены годами и понятны очень многим.

H>Заметку читал, просто как-то упустил из виду — пытался просто заставить компилироваться.


Проблема в том, что скомпилироваться может и не верный код, ну, или код может скомпилироваться в неверный мсил. Суть позитивных тестов в том, что мы проверяем конечный результат — поведение скомпилированной программы. Это гарантирует верность семантики.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Создание event-ов в макросах
От: Аноним  
Дата: 24.02.10 15:19
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Ноги растут примерно отсюда
Автор: hardcase
Дата: 16.02.10
.


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


VD>>По уму имя поля, add-ера и remove-ера нужно формировать динамически.

VD>>Посему для формирования имен поля, add-ера и remove-ера нужно сформировать экзепляры Splicable.Expression() которые будут содержать код из имени свойства плюс дополнительный код модифицирующий имя так чтобы из него получались требуемые имена.


H>Попробовал написать патч, решающий эту проблему. На "запчасти" разбираю сплайс-выражение таким вот образом:

H>
H>AddSplicableNamePrefix(prefix : string, id : Splicable, loc : Location) : Splicable
H>{
H>  match(id)
H>  {
H>    | Splicable.Name(body) => MkSplicableName(prefix + body.Id, loc)
H>    | Splicable.HalfId(pref) => Splicable.HalfId(loc, Name(prefix + pref.Id, loc, pref.color, pref.context))
H>    | Splicable.Expression(expr) as id =>
H>      def new_expr = match(expr)
H>      {
H>        | PExpr.TypeEnforcement(expr, ty) =>
H>            <[ ($(prefix : string) + $expr.ToString()) : $ty ]>
H>        | _ =>   
H>            <[ ($(prefix : string) + $expr.ToString()) : usesite ]>
H>      }
H>      Splicable.Expression(loc, new_expr, id.env)
H>  }
H>}
H>

H>Т.е. тупо преобразую исходное выражение в строку, и добавляю префикс ("add_", "remove_", или "_N_event_field_of_").

Я тоже исследовал проблему и пытался решить ее, сравнивая логику формирования имен getter setter свойств с методами эвентов, оказывается что имена методов для свойств объявленных с помощью читат с Expression внутри Splicable, то есть сложные имена при парсинге просто опускаются и остаются как get_ и set_, пустые имена получаются так:
1340: def plain_name = match (id) { | Splicable.Name (n) => n.Id | _ => "" };
потом когда объявление созданное цитатой добавляется в TypeBuilder с помощью Define, там есть фикс который имена get_ и set_ преобразуется в нормальные с именем объявленного свойства, уже по имеющимся данным имени готового свойства, мне кажется этот вариант более верный, то есть имена должны создаваться когда уже известно значение того самого Expression в сплайсе объявления имени эвента, на этапе парсинга такой информации нет, мы можем оперировать только экспрешенами, а они могут быть совершенно разными и не всегда это PExpr.TypeEnforcement он может быть получается и из других экспрешенов таких как вызов функции и других, например создание так:
<[ decl: public event $(Name(evt) : name) EventHandler; ]> я думаю просто складывать это не универсальный вариант, там значения может быть понадобится кэшировать чтобы избежать двойного раскрытия сплайса и сложения в двух методах, также накладывать ограничение только на объявления типа TypeEnforcement не хорошо, ведь программист не ограничен как задавать имена эвентов в сплайс выражении, может быть стоит действительно сделать как в свойствах, то есть цитатные имена методов при парсинге оставлять пустыми add_ remove_ а когда они добавляются в TypeBuilder то создавать им наглядные имена, чем просто приведенные из строки экспрешена, которые для других выражений могут дать ту же ошибку из за повторяемости в циклах, надеюсь в эти объявления используются только в Define TypeBuilder, и сопутствующих, если где то еще то надо вставить код и туда, при этом для сплайсов не Expression, и объявление без сплайса будет проходить нормально. Вообще все же кажется более правильнее создавать имена для сопутствующих методов сплайс выражений не при парсинге, а после раскрытия выражения цитаты, то есть либо или при лифтинге выражения, либо при создании ClassMember.Event в конструкторе, либо в TypeBuilder.Define, при лифтинге создавать я не разобрался пока выше моего понимания, а в конструкторе или в Define как в свойстве получается и более безопасно, потому что не зависимы от выражения в сплайсе объявления имени, а создаем тогда когда значение имени эвента уже известно. При этом в парсере вставляется строчка def plain_name = match (id) { | Splicable.Name (n) => n.Id | _ => "" }; то есть имена add_ и remove_

вместо старой, а в TypeBuilder вставляется код, рядом с таким же для свойства:

public DefineAndReturn (f : PT.ClassMember) : MemberBuilder
{
..
match (f) 
{
| Event(add=a,field=fld,remove=r) with name=f.Name =>
        when (a.Name=="add_" && r.Name=="remove_") // проверяем что было создано в парсере с помощью сплайс цитаты
         {
         a.name=PT.Splicable.Name(PT.Name($"add_$name")); // создаем имена
         r.name=PT.Splicable.Name(PT.Name($"remove_$name"));
         fld.name=PT.Splicable.Name(PT.Name($"event_field_of_$name"));
         }
}
..
}



Этот вариант у меня готов, если сообщество немерлистов примет такой вариант, то думаю его можно будет оставить и я сделаю коммит.
Re[7]: Создание event-ов в макросах
От: CodingUnit Россия  
Дата: 24.02.10 15:47
Оценка:
Предыдущий пост мой, у меня этот вариант готов, если сообщество немерлистов примет такой вариант, то думаю его можно будет оставить и я сделаю коммит.
Re[8]: Создание event-ов в макросах
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.02.10 16:36
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>Предыдущий пост мой, у меня этот вариант готов, если сообщество немерлистов примет такой вариант, то думаю его можно будет оставить и я сделаю коммит.


Дык вроде то что залит и так должен работать. Мне в нем не нравится dyn, так как он связывает имена динамически. Но все же...

Для начала имеет смысл написать тесты которые бы не проходили в данном варианте. А там уже думать. Мне текущее решение нравится больше, так как оно более чистое. Но если есть веские аргументы против...
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Создание event-ов в макросах
От: seregaa Ниоткуда http://blogtani.ru
Дата: 24.02.10 17:09
Оценка:
Здравствуйте, VladD2, Вы писали:

H>>Сложно, блин, особенно когда есть собственный давно выработанный стиль.

VD>Сам к некоторым аспектам долго привыкал. Но код должен быть единобразным. РСДН-овские правила проверены годами и понятны очень многим.

Влад, а что делать с тем, что в интеграции используется другой стиль? Например отступы преимущественно отформатировны табами.
Мобильная версия сайта RSDN — http://rsdn.org/forum/rsdn/6938747
Автор: sergeya
Дата: 19.10.17
Re[7]: Создание event-ов в макросах
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.02.10 17:20
Оценка:
Здравствуйте, seregaa, Вы писали:

S>Влад, а что делать с тем, что в интеграции используется другой стиль? Например отступы преимущественно отформатировны табами.


Это где это?

Может речь о C#-проектах? Пробелы — это соглашение для немерла. Так уж начала поляки писать. А в шарпе всегда были табы. В принципе в соглашениях РСНД-а табы предпочитаются. Но так уж сложилось для немерловых файлов.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Создание event-ов в макросах
От: seregaa Ниоткуда http://blogtani.ru
Дата: 24.02.10 17:25
Оценка:
Здравствуйте, VladD2, Вы писали:

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


S>>Влад, а что делать с тем, что в интеграции используется другой стиль? Например отступы преимущественно отформатировны табами.


VD>Это где это?


VD>Может речь о C#-проектах? Пробелы — это соглашение для немерла. Так уж начала поляки писать. А в шарпе всегда были табы. В принципе в соглашениях РСНД-а табы предпочитаются. Но так уж сложилось для немерловых файлов.


Да, я о c# проектах. Ok, пусть будут табы — мне тоже такой стиль более по душе.
Мобильная версия сайта RSDN — http://rsdn.org/forum/rsdn/6938747
Автор: sergeya
Дата: 19.10.17
Re[7]: Создание event-ов в макросах
От: CodingUnit Россия  
Дата: 24.02.10 17:26
Оценка: 43 (1)
Здравствуйте, seregaa, Вы писали:

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


H>>>Сложно, блин, особенно когда есть собственный давно выработанный стиль.

VD>>Сам к некоторым аспектам долго привыкал. Но код должен быть единобразным. РСДН-овские правила проверены годами и понятны очень многим.

S>Влад, а что делать с тем, что в интеграции используется другой стиль? Например отступы преимущественно отформатировны табами.


Я занимаюсь форматированием, уже перевел ее на асинхронный движок, большинство проблем исправлено, но есть еще небольшие проблемы, с разными объявлениями, пока не исправил не выкладываю, сейчас отступы сделаны через табы но они распознаются как два пробела, что то исправить проблем не составит, и надо доделать разбивку отступов вокруг операторов и тп, потом заведу особую ветку связанную с релизом движка форматирования, тогда будете присылать замечания по форматированию, пока работаем.
Я постараюсь написать такой код чтобы не работало объявление эвента и сформулировать недостаток такого подхода, мне все же не нравится когда выражение отличное от PExpr.TypeEnforcement преобразуется сразу в строку и используется в названиях, это как то не чисто, C# здесь более гигиеничен, и не факт что не возникнут проблемы с этими самими именами для каких то мудреных экспрешенов в названиях, а так хорошо что какой то вариант появился рабочий замены бага. У меня вопрос могут такие декларации эвента в цитате использоваться где то без вызова метода Define/DefineWithReturn, если нет то не проще ли действительно исследовать имена и присваивать уже там, чем мучить парсер?
Re[8]: Создание event-ов в макросах
От: CodingUnit Россия  
Дата: 24.02.10 17:41
Оценка:
Здравствуйте, CodingUnit, Вы писали:

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


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


H>>>>Сложно, блин, особенно когда есть собственный давно выработанный стиль.

VD>>>Сам к некоторым аспектам долго привыкал. Но код должен быть единобразным. РСДН-овские правила проверены годами и понятны очень многим.

S>>Влад, а что делать с тем, что в интеграции используется другой стиль? Например отступы преимущественно отформатировны табами.


CU>Я занимаюсь форматированием, уже перевел ее на асинхронный движок, большинство проблем исправлено, но есть еще небольшие проблемы, с разными объявлениями, пока не исправил не выкладываю, сейчас отступы сделаны через табы но они распознаются как два пробела, что то исправить проблем не составит, и надо доделать разбивку отступов вокруг операторов и тп, потом заведу особую ветку связанную с релизом движка форматирования, тогда будете присылать замечания по форматированию, пока работаем.


Еще вопрос к Владу, возникла такая интересная ошибка при форматировании для объявления surroundwith, посмотрел оказывается там при исследовании выражения вызова вышеназванного макроса получается что слово surroundwith лексером распознается как Token.Identifier а не Token.Keyword, который он ищет для проверки синтаксиса макроса и после этого возникает ошибка форматирования, здесь может быть дело в том что лексер пока не знает такого имени макроса, то есть ему нужна информация от парсинга макроса, в этом ли дело? Обязательно ли сначала строить дерево типов всего проекта чтобы начать форматирование, тогда форматирование может не работать для файлов открытых без проекта?
Еще есть интересная проблема для сгенерированных объявлений, например yield, тогда у парсера практически нет никакой информации о том что было в исходном файле, тогда надо форматировать по исходным токенам лексера, может быть сделать такой дополнительный шаг в форматировании для объявлений неизвестных, неуспевших просканироваться Intellisense интеграции, информацию которой он использует в форматировании выражений и типов и с помощью только информации лексера форматировать выражения которые сгенерированы, зная их расположение в документе?
Re[8]: Создание event-ов в макросах
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.02.10 18:36
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>Я занимаюсь форматированием, уже перевел ее на асинхронный движок, большинство проблем исправлено, но есть еще небольшие проблемы, с разными объявлениями, пока не исправил не выкладываю, сейчас отступы сделаны через табы но они распознаются как два пробела, что то исправить проблем не составит, и надо доделать разбивку отступов вокруг операторов и тп, потом заведу особую ветку связанную с релизом движка форматирования, тогда будете присылать замечания по форматированию, пока работаем.


Отлично! Надеюсь до релиза это дело заработает. Ну, и надеюсь, что ты доведешь код форматирования до рабочего состояния. А то у нас что не фича, то начата и брошена автором.

CU>Я постараюсь написать такой код чтобы не работало объявление эвента и сформулировать недостаток такого подхода, мне все же не нравится когда выражение отличное от PExpr.TypeEnforcement преобразуется сразу в строку и используется в названиях, это как то не чисто,


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

CU>C# здесь более гигиеничен,


Что? Этого высказывания я вообще не понял. В шарпе нет макросов.

CU>и не факт что не возникнут проблемы с этими самими именами для каких то мудреных экспрешенов в названиях, а так хорошо что какой то вариант появился рабочий замены бага.


Дык, я и говорю. Нужны юскейся. Тогда можно будет или доработать текущую схему, или понять в чем она ущербна.
Пока что я вижу, что текущая схема довольно гибка. А предложенная тобой — нет, так как переименованием заведует компилятор, а не макрос. Со свойством все несколько проще, так как там нужно давать имена гетарам и сетерам которые даются по четкой схеме. А вот с событиями не все так просто. Там еще нужно вводить переменную. Какое имя давать ей? Пустое? А как потом понять какое имя требовалось? В общем, одни вопросы.

CU> У меня вопрос могут такие декларации эвента в цитате использоваться где то без вызова метода Define/DefineWithReturn, если нет то не проще ли действительно исследовать имена и присваивать уже там, чем мучить парсер?


Потенциально конечно могут. Но тут не это главное. Главное, что так имя может сформировать макрос. Компилятор тут будет не причем. А в твоем варианте уже компилятор будет отчевать за имена. Как я уже говорил, если для геттеров и сеттеров это нормально, то для переменных уже нет.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Создание event-ов в макросах
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.02.10 18:44
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>Еще вопрос к Владу, возникла такая интересная ошибка при форматировании для объявления surroundwith, посмотрел оказывается там при исследовании выражения вызова вышеназванного макроса получается что слово surroundwith лексером распознается как Token.Identifier а не Token.Keyword, который он ищет для проверки синтаксиса макроса и после этого возникает ошибка форматирования, здесь может быть дело в том что лексер пока не знает такого имени макроса, то есть ему нужна информация от парсинга макроса, в этом ли дело? Обязательно ли сначала строить дерево типов всего проекта чтобы начать форматирование, тогда форматирование может не работать для файлов открытых без проекта?


Без проекта конечно ключевые слова могут не распознаваться. Ведь без проекта у нас нет списка сборок (в том числе макро-сборок) которые используются в исходнике.

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

CU>Еще есть интересная проблема для сгенерированных объявлений, например yield, тогда у парсера практически нет никакой информации о том что было в исходном файле, тогда надо форматировать по исходным токенам лексера, может быть сделать такой дополнительный шаг в форматировании для объявлений неизвестных, неуспевших просканироваться Intellisense интеграции, информацию которой он использует в форматировании выражений и типов и с помощью только информации лексера форматировать выражения которые сгенерированы, зная их расположение в документе?


Я плохо понял смысл предложения. Уж больно оно большое. Можно все тоже самое изложить проще?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Создание event-ов в макросах
От: CodingUnit Россия  
Дата: 24.02.10 19:21
Оценка:
Здравствуйте, VladD2, Вы писали:

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


CU>>Еще вопрос к Владу, возникла такая интересная ошибка при форматировании для объявления surroundwith, посмотрел оказывается там при исследовании выражения вызова вышеназванного макроса получается что слово surroundwith лексером распознается как Token.Identifier а не Token.Keyword, который он ищет для проверки синтаксиса макроса и после этого возникает ошибка форматирования, здесь может быть дело в том что лексер пока не знает такого имени макроса, то есть ему нужна информация от парсинга макроса, в этом ли дело? Обязательно ли сначала строить дерево типов всего проекта чтобы начать форматирование, тогда форматирование может не работать для файлов открытых без проекта?


VD>Без проекта конечно ключевые слова могут не распознаваться. Ведь без проекта у нас нет списка сборок (в том числе макро-сборок) которые используются в исходнике.


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

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


CU>>Еще есть интересная проблема для сгенерированных объявлений, например yield, тогда у парсера практически нет никакой информации о том что было в исходном файле, тогда надо форматировать по исходным токенам лексера, может быть сделать такой дополнительный шаг в форматировании для объявлений неизвестных, неуспевших просканироваться Intellisense интеграции, информацию которой он использует в форматировании выражений и типов и с помощью только информации лексера форматировать выражения которые сгенерированы, зная их расположение в документе?


VD>Я плохо понял смысл предложения. Уж больно оно большое. Можно все тоже самое изложить проще?

Я нашел такой эффект, сделал функцию которая создает итератор через слово yield, и он отказался его форматировать, хотя код простой, посмотрел поглубже оказалось что заместо всего блока с yield получается какой то мудреный код сгенерированный компилятором, форматирование сгенерированных объявлений (те которых нет в исходнике) я убрал, весь блок пропускается, и участок остается без форматирования, здесь я понял что нужно форматировать тогда по токенам с помощью информации лексера, которая одна только может дать понятие что хранится в документе, тогда наверное правильно было бы сделать так что если объявление сгенерировано, то произвести его специальный анализ и форматирование с помощью информации лексера, а не пропускать, тогда форматирование должно быть корректным.
По поводу того чтобы сначала парсить есть еще проблема, у меня на ноутбуке проект компилятора очень долго сканируется Intellisense, невыносимо и жутко жрет процессор, если запускать форматирование с принудительным парсингом то это может занять продолжительное время, Intellisense производит полную компиляцию при анализе или только парсинг, может сделать какой то облегченный вариант сканирования, чтобы быстрее сканировалось с минимумом нужной информации модулю форматирования? C# Intellisense вообще летает.
Re[11]: Создание event-ов в макросах
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.02.10 19:36
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>Тогда получается надо распознавать слово как есть, если есть информация от парсера то использовать ее, если нет, то пытаться сделать по стандартным правилам, скобки на своих местах и тп, или наверное лучше все таки если есть возможность распарсить если есть проект то сначала принудительно парсить, если нет то есть открыт файл без проекта, то уже пользоваться стандартными правилами для ключевых слов и макросов, за точность гарантий здесь не будет с макросами.


Меня лично устроил бы вариант форматирования только на основании токенов.

Но можно конечно и смотреть есть ли информация от парсера и типизатора и если есть, то выполнять расширенное форматирование, а если нет, то по токенам.


VD>>Я плохо понял смысл предложения. Уж больно оно большое. Можно все тоже самое изложить проще?

CU>Я нашел такой эффект, сделал функцию которая создает итератор через слово yield, и он отказался его форматировать, хотя код простой, посмотрел поглубже оказалось что заместо всего блока с yield получается какой то мудреный код сгенерированный компилятором,

Это код конечного автомата. Но ты можешь пользоваться исходным кодом метода доступным чере свойство ClassMember.Function.ParsedBody.

Собственно только его и нужно анализировать. Код из ClassMember.Body может быть изменен макросами до неузнаваемости.

CU> форматирование сгенерированных объявлений (те которых нет в исходнике) я убрал, весь блок пропускается, и участок остается без форматирования, здесь я понял что нужно форматировать тогда по токенам с помощью информации лексера, которая одна только может дать понятие что хранится в документе, тогда наверное правильно было бы сделать так что если объявление сгенерировано, то произвести его специальный анализ и форматирование с помощью информации лексера, а не пропускать, тогда форматирование должно быть корректным.


Ну, я уже сказал, что если пользоваться ClassMember.Function.ParsedBody, а не ClassMember.Body, то такой проблемы быть не должно, но у меня есть одни вопрос.
А какие проблемы возникают если форматировать только по токенам (т.е. без анализа кода вообще?). Ну, по крайней мере когда речь идет о коде методов?

CU>По поводу того чтобы сначала парсить есть еще проблема, у меня на ноутбуке проект компилятора очень долго сканируется Intellisense, невыносимо и жутко жрет процессор, если запускать форматирование с принудительным парсингом то это может занять продолжительное время, Intellisense производит полную компиляцию при анализе или только парсинг, может сделать какой то облегченный вариант сканирования, чтобы быстрее сканировалось с минимумом нужной информации модулю форматирования? C# Intellisense вообще летает.


По идее компиляция одного метода не должна особо тормозить. Но если ух хочется линейной и высокой скорости, то имеет смысл подумать о форматировании только на основании токенов. Уж этот вариант будет летать как трофейный мессершмит.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Создание event-ов в макросах
От: CodingUnit Россия  
Дата: 24.02.10 19:54
Оценка:
Здравствуйте, VladD2, Вы писали:

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


CU>>Я постараюсь написать такой код чтобы не работало объявление эвента и сформулировать недостаток такого подхода, мне все же не нравится когда выражение отличное от PExpr.TypeEnforcement преобразуется сразу в строку и используется в названиях, это как то не чисто,


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


CU>>C# здесь более гигиеничен,


VD>Что? Этого высказывания я вообще не понял. В шарпе нет макросов.


Здесь я имел в виду, что он более просто создает имена, информация строки из экспрешена исходного кода в коде IL метода сборки может отпугнуть.

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

VD>Пока что я вижу, что текущая схема довольно гибка. А предложенная тобой — нет, так как переименованием заведует компилятор, а не макрос. Со свойством все несколько проще, так как там нужно давать имена гетарам и сетерам которые даются по четкой схеме. А вот с событиями не все так просто. Там еще нужно вводить переменную. Какое имя давать ей? Пустое? А как потом понять какое имя требовалось? В общем, одни вопросы.

Вообщем там просто, если объявление создано не с помощью цитаты, то оно просто генерируется по имени как есть, если с помощью цитаты, то имена скрытого поля и методов add remove, создаются по умолчанию то есть типа event_field_of и add_ remove_, при этом выражение обязательно должно пройти через метод DefineWithReturn TypeBuilder, объявление квазицитатой события, как я понимаю не имеет смысла без вышеназванного метода, где можно его перехватить и правильно обработать, как это делается со свойствами,

CU>> У меня вопрос могут такие декларации эвента в цитате использоваться где то без вызова метода Define/DefineWithReturn, если нет то не проще ли действительно исследовать имена и присваивать уже там, чем мучить парсер?


VD>Потенциально конечно могут. Но тут не это главное. Главное, что так имя может сформировать макрос. Компилятор тут будет не причем. А в твоем варианте уже компилятор будет отчевать за имена. Как я уже говорил, если для геттеров и сеттеров это нормально, то для переменных уже нет.

Все же по правильному наверное где то на последних этапах создавать дополнительные члены, при этом имена не должны пересекаться с чем то, информация о экспрешенах в именах методов и поля избыточна, методы по тупому должны создаваться на конечных этапах добавления метода к классу когда имя события уже известно, это было бы правильно, для обычных объявлений в момент парсинга можно установить им имена сначала. Если событие может создаться в обход метода DefineWithReturn то можно создавать add и remove в конструкторе ClassMember.Event, наверное самый гибкий вариант. Ладно еще этот вопрос исследую и тогда можно будет более точно сказать как лучше устроить.
Re[10]: Создание event-ов в макросах
От: hardcase Пират http://nemerle.org
Дата: 24.02.10 20:27
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>Вообщем там просто, если объявление создано не с помощью цитаты, то оно просто генерируется по имени как есть, если с помощью цитаты, то имена скрытого поля и методов add remove, создаются по умолчанию то есть типа event_field_of и add_ remove_, при этом выражение обязательно должно пройти через метод DefineWithReturn TypeBuilder, объявление квазицитатой события, как я понимаю не имеет смысла без вышеназванного метода, где можно его перехватить и правильно обработать, как это делается со свойствами,


Код разбора объявления event-а в обычном коде и квази-цитировании унифицирован в методе parse_event.
Только если для нормального event-а в конечном счете генерируется IL, то разобранный квази-цитированный event затем сериализуется в код, собирающий его же самого.
Выражение, которое передается в качестве имени в любом случае должно иметь строковое представление (как иначе к нему можно будет обращаться?) — это суть имени. Таким образом, я сделал допущение, что выражение можно будет безопасно свернуть в строку и далее присобачить к нему префикс. Образно говоря, я поднял ToString существовавший до того эпистемологическим уровнем повыше (а ведь не хотел умничать).
По поводу dyn. Если в том коде использовать usesite, то компилятор будет для полученного имени будет формировать контекст, который не будет совпадать с контекстом, где будут объявлены аргументы value (сам я сути не вкурил, это домыслы — см. дизассемблерный листинг). Возможно где-то внутри банально проверяется равенство ссылок контекстов. Я считаю, что в данном случае dyn использовать безопасно (хоть и не шибко красиво), так как он фигурирует не внутри алгоритмического кода, но лишь для объявлений.
/* иЗвиНите зА неРовнЫй поЧерК */
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.