Re[5]: [Nemerle DSL] Описание конечного автомата
От: CodingUnit Россия  
Дата: 24.02.10 20:47
Оценка: 1 (1) +1
Здравствуйте, VladD2, Вы писали:

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


P>>списком состояний, начальным состоянием и функции перехода, заданной:

P>>например,

VD>Для людей важно просто и наглядно задать описание автомата. По сему совершенно не важно чем там в теории определяется автомат. Важно иметь язык который наиболее интуитивно позволит описать этот автомат. Я привел один из возможных языков. Описывать автоматы в виде таблиц очень неудобно. Таблицей можно описать только ДКА. А люди мысленно обычно создают НКА, а НКА не возможно описать с помощью простой матрицы. Спорить на эту тему я не хочу (это не тот форум). Но в принципе такие языки как регулярные выражения и грамматики (BNF, PEG) — это идилальные высокооуровневые языки. Почти для любой задачи можно придумать некоторый высокоуровневый язык который будет лучше любого описания КА. Именно по то этому людям обычно не интересны ДСЛ-и описывающие КА. Но если нужно формировать именно КА, то язык вроде приведенного мной (или использованный в БУ) очень удобен для этого. А разные статистические данные можно генерировать в процессе компиляции макросов. Скажем тот же список переходов в некоторое состояние построить не проблема. Можно даже диаграмму нарисовать.


Вообще комплексную логику на иерархических автоматах можно легко нарисовать, тут таблицы наверное усложнять декларируемость описания автомата, вопрос стоит только как проще и быстрее сделать автомат из описания, без лишней работы, вышеприведенный язык DSL мне кажется более подходит для прикладного применения, с помощью макросов на этапе компиляции можно делать и преобразования и анализ как сказал Владислав, мне кажется очень здесь замечательное применение это анализ автомата и генерация, можно сделать компилируемый автомат который генерирует только последовательность вызовов действий с помощью делегатов на основании иерархии и получает наиболее оптимизированный код, тогда никакие внешние библиотеки не будут нужны, описание автомата просто преобразуется в последовательность вызовов функций комплексной логики, как реакцию на события. Само же описание наверное можно получить из диаграммы, в UML редакторах есть функция экспорта XML, которое можно преобразовать в DSL и так далее.
[Nemerle DSL] Описание конечного автомата
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.02.10 17:13
Оценка: 1 (1)
#Имя: FAQ.nemerle.DSL001
Здравствуйте, CodingUnit, Вы писали:

CU>Задача такова, есть библиотека описания автоматов состояний в коде аналогичным в UML, проблема в том что описание структуры автомата сложно читаемое и создаваемое вручную, хотелось бы автоматизировать этот процессс за счет макросов и DSL, я уже видел решение подобной задачи в Boo, но хотелось бы попробовать сделать такое решение на Nemerle, под нужную библиотеку, там имеются разные процедуры для описания иерархии автомата, хотелось бы например сделать иерархическое визуальное описание иерархии, например:



CU>
CU>[statemachine]
CU>class TestFSM
CU>{

CU>  [state]
CU>  class Top
CU>  {
    
CU>    [state]
CU>    class Start
CU>    {
       
CU>      [state]
CU>      class Sub
CU>      {
CU>       entry() : void
CU>       {
CU>        // действие при входе
CU>       }
CU>       exit() : void
CU>       {
CU>        // действие при выходе
CU>       }
CU>      } 
CU>    }
    
CU>    [state]
CU>    class Next
CU>    {
CU>      transition("Sub",UserEvt) // описание перехода
CU>    }
CU>  }
CU>}
CU>


Примерно ясно. А почему решено именно классами их описывать?

CU>как то так, на Boo там вообще абстрактно описали автомат, типа


CU>
CU>state @Parked:
CU>    when @EngineStarted      >> @IdleInNeutral
    
CU>state @IdleInNeutral:
CU>    when @EngineKilled       >> @Parked
CU>    when @GearEngaged        >> @IdleInGear
    
CU>state @IdleInGear:
CU>    when @GearDisengaged     >> @IdleInNeutral
CU>    when @GasApplied         >> @RacingAlong

CU>state @RacingAlong:
CU>    when @BrakeApplied       >> @IdleInGear
CU>    when @CarCrashedIntoTree >> @CarDestroyed

CU>state @CarDestroyed
CU>


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

Если бы я решал подобную задачу, то скорее всего я выбрал бы следующий подход:
1. Каждый автомат я описывал бы как отдельный класс.
2. Список состояний я описывал бы в метаатрибуте которым помечал бы этот класс.
3. Синтаксис сделал бы похожим на описание локальных функций.
4. Реакции на переходы описывал бы как методы внутри этого класса.

Вот как мог бы выглядеть приведенный выше автомат:
[FsmDef(
{
  state Parked
  {
    | EngineStarted      => IdleInNeutral
  }
      
  state IdleInNeutral
  {
    | EngineKilled       => Parked
    | GearEngaged        => IdleInGear
  }
      
  state IdleInGear
  {
    | GearDisengaged     => IdleInNeutral
    | GasApplied         => RacingAlong
  }

  state RacingAlong
  {
    | BrakeApplied       => IdleInGear
    | CarCrashedIntoTree => CarDestroyed
  }

  state CarDestroyed { }
}
)]
class MyFsm
{
  // обарботчик события перехода 
  EnterIn_IdleInGear_State(previosState : MyFsmState) : void
  {
    ... код обработки 
  }
  ...
}


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


Выше я описал возможный вариант.
Для реализации данного подхода нужно описать и реализовать два макроса:
1. FsmDef — метаатрибут. В нем должна производиться основная работа по построению конечного автомата.
2. state — макрос уровня выражения. Нужен только для того, чтобы немерле мог воспринимать синтаксис описания состояния — "state имяСостояния список состояний".

Вот как могут выглядеть заглушки (т.е. без реализации) этих макросов:
  [Nemerle.MacroUsage(Nemerle.MacroPhase.BeforeTypedMembers, Nemerle.MacroTargets.Class)]
  macro FsmDef(type_builder : TypeBuilder, body)
  {
  }

  macro State(stateName, body)
  syntax("state", stateName, body)
  {
    <[ () ]> // В этом макросе нам ничего делать не надо. Он нужет только чтобы немерле "пропустил" наш синтаксис.
  }


Понимаю, что без опыта создания макросов распознать столь не тривиальную структуру будет не просто. По этому я потратил час, чтобы набросать примерную реализацию макросов. Вот что у меня получилось...
Сами макросы:
using Nemerle;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;
using System.Diagnostics;

namespace MacroLibrary2
{
  [Nemerle.MacroUsage(Nemerle.MacroPhase.BeforeTypedMembers, Nemerle.MacroTargets.Class)]
  macro FsmDef(type_builder : TypeBuilder, body)
  {
    Helper.MakeFsm(type_builder, body);
  }

  macro State(stateName, body)
  syntax("state", stateName, body)
  {
    _ = stateName; // говорим компилятору, что мы намеренно не желаем использовать параметр
    _ = body;      // тоже самое
    <[ () ]> // В этом макросе нам ничего делать не надо. Он нужен только чтобы немерле "пропустил" наш синтаксис.
  }
  
  module Helper
  {
    public MakeFsm(ty : TypeBuilder, body : PExpr) : void
    {
      def makeTransition(transitionDef : MatchCase) : void
      {
          Message.Hint(transitionDef.Location, $"  Events=$(transitionDef.patterns) Transition=$(transitionDef.body)")
      }
    
      def makeSate(stateDef : PExpr) : void
      {   // ncc заворачивает обращение к макросу в конструкцию PExpr.MacroCall...
        | PExpr.MacroCall(name, _, parms) when name.Id == "state" =>
          
          match (parms)
          { // параметры (код передаваемый в них) макроса заворачиваются в SyntaxElement.Expression.
            // Пользователь должен передать два параметра...
            
              // имя и пустую группу...
            | [Expression(<[ $stateName ]>), Expression(<[ { } ]>)] => 
              Message.Hint(stateName.Location, $"Распознано описание состояния '$stateName' (без переходов!)");

              // или имя и список вхождений оператора match который компилятор превращает в полноценный оператор match...              
            | [Expression(<[ $stateName ]>), Expression(<[ match ($_) { ..$transitions } ]>)] =>
              Message.Hint(stateName.Location, $"Распознано описание состояния '$stateName'. Переходы:");
            
              foreach (transitionDef in transitions)
                makeTransition(transitionDef);
                
            | [Expression(<[ $_ ]>), Expression(<[ { $x } ]>)] =>
              Message.Error(x.Location, "Ожидается описание переходов в формате: { | Event => State | Event => State ... }");
              
            | _ => 
              Message.Error(stateDef.Location, 
                "Ожидается описание состояния в формате: state StateName { transitions }"); 
          }
        
        | _ =>
          Message.Error(stateDef.Location, 
            "Ожидается описание состояния в формате: state StateName { transitions }"); 
      }
      
      match (body)
      {
         // описания состояний заключены в группу (фигурные скобки)
        | <[ { ..$states } ]> => // матчим список выражений описывающих состояния
          foreach (state in states) 
            makeSate(state);
            
        | _ => 
          Message.Error(body.Location, 
            "Ожидается список состоянии в формате { state1 state2 ... }"); 
      }
    }
  }
}


Это только код распознавания. В нем нет построения самого КА и генерации кода его реализующего.
Вместо этого я просто выдаю подсказки (которые можно увидеть в окне Output в VS). Так что просто ищи код "Message.Hint" и думай как заменить его на нечто действительно полезное.

Пример использования:
[FsmDef(
{
  state Parked
  {
    | EngineStarted      => IdleInNeutral
  }
      
  state IdleInNeutral
  {
    | EngineKilled       => Parked
    | GearEngaged        => IdleInGear
  }
      
  state IdleInGear
  {
    | GearDisengaged     => IdleInNeutral
    | GasApplied         => RacingAlong
  }

  state RacingAlong
  {
    | BrakeApplied       => IdleInGear
    | CarCrashedIntoTree => CarDestroyed
  }

  state CarDestroyed { }
}
)]
class MyFsm
{
  // обработчик события перехода 
  EnterIn_IdleInGear_State() : void
  {
  }
}
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
nemerle dsl fsm ка дка
Написание DSL на Nemerle и создание Enum в макросах
От: CodingUnit Россия  
Дата: 03.02.10 09:37
Оценка:
Здравствуйте, тут встала проблема написания сложного кода автоматически, за основу взяты макросы Nemerle, при это когда создаются новые ключевые слова их нельзя использовать в пространстве имен или в классе, видимо только в методе, иначе пишется сообщение об ошибке, так ли это?:
namespace TestFSM
{
  // ошибка пишет что требуется тип, макрос определен правильно
  statemachine Test
  {
  }

  class TestClass
  {
    // тоже самое
    statemachine Test
    {
    }
  }
}


Еще встала другая проблема, надо определить во время компиляции в макросе перечисление на основе кода, например так:
[MacroUsage(MacroPhase.BeforeTypedMembers,MacroTargets.Class,Inherited=true)]  
macro statemachine(ty : TypeBuilder)
{

// определяем перечисление, нормально
def stateid=ty.DefineNestedType(<[ decl:
  public enum StateID
  {
  }
  ]>);

..
def states : list[TypeBuilder]= ty.DeclaredNestedTypes; // получаем лист TypeBuilder-ов для внутренних типов

// для каждого типа добавляем имя в качестве константы к перечислению
states.Iter( x => stateid.Define(<[ $(x.Name)]>)); // не компилируется

// также просто если попробовать
stateid.Define(<[decl: | ABC ]>); // компилируется, но при выполнении ничего не происходит, новый член не добавляется
}

stateid.Compile(); // компилируем тип



// при этом если написать сразу список членов, то он определяется правильно:
def stateid=ty.DefineNestedType(<[ decl:
  public enum StateID
  {
  | ABC
  | BCD
  }
  ]>); // если бы была возможность как то в цитату вставить строки с описанием членов


Вопрос такой, как определить перечисление в макросе и добавить как подтип в классе? Как добавить динамически в макросе элементы в список перечисления, есть ли такая возможность?
И последний вопрос, если писать DSL то потребуется много ключевых слов, при этом они как то должны взаимодействовать между собой, проходит синтаксические и семантические проверки, для этого надо чтобы текст разбирался и получалось некое описание на DSL, для этого нужен какой то объект который хранит в себе все состояние описанной структуры, то есть должен быть доступен на этапе компиляции и при вызове макроса через помеченные объекты или описание в методе, добавлять информацию в этот объект, то есть должен создаваться один раз и жить в остальное время. Еще может потребоваться некоторые члены удалять, которые не несут в себе никакой информации для приложения, например классы для описания вложенной иерархии нужные макросу, но ненужные в рантайме, было бы хорошо удалить чтобы они были не видны, но TypeBuilder допускает объявлять члены, но не допускает удалять и многие внутренние поля компилятора read-only, можно ли решить как то эту задачу?
Re: Написание DSL на Nemerle и создание Enum в макросах
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.02.10 12:33
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>namespace TestFSM
CU>{
CU>// ошибка пишет что требуется тип, макрос определен правильно
CU>statemachine Test
CU>{
CU>}


Так, действительно, в текущей версии делать нельзя.

Но можно делать например так:
class Test statemachine
{
}

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

В качестве примерами я написал небольшой макрос "test" который добавляет реализацию метода к классу. Собственно код макроса:
using Nemerle;
using Nemerle.Compiler;

namespace MacroLibrary2
{
  [Nemerle.MacroUsage(
    Nemerle.MacroPhase.BeforeInheritance, 
    Nemerle.MacroTargets.Class // указываем, что макрос - это макроатрибут уровня класса
  )]
  macro @MyTest(type_builder : TypeBuilder) 
    syntax("test") // задаем синтаксис
  {
    Helper.MyTest(type_builder);
  }
  
  module Helper
  {
    public MyTest(type_builder : TypeBuilder) : void
    {
      // добавляем в класс которому применен этот макрос реализацию метода "Test() : void"
      _ = type_builder.DefineWithSource(
        <[ decl:
            public Test() : void 
            {
              System.Console.WriteLine("The test happen! :)");
            }
        ]>);
    }
  }
}

А вот использование этого макроса:
using System;
using System.Console;
using Nemerle.Utility;

using MacroLibrary2;

class A test // собственно вот оно
{
}

module Program
{
  Main() : void
  {
    def a = A();
    a.Test(); // а это использование сгенерированного метода.
    _ = ReadLine();
  }
}
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Написание DSL на Nemerle и создание Enum в макросах
От: CodingUnit Россия  
Дата: 03.02.10 12:46
Оценка:
Здравствуйте, VladD2, Вы писали:


Да генерировать методы легко, хорошо что синтаксис можно добавить после класса, но не могли бы Вы Владислав написать есть ли возможность создать в классе перечисление и добавить в него имена констант на основе динамических данных, как я описал здесь, почему не компилируется определение перечисления и не добавляется даже статическое константное поле в перечисление, есть какие то ограничения у компилятора?:


MacroUsage(MacroPhase.BeforeTypedMembers,MacroTargets.Class,Inherited=true)]  
macro statemachine(ty : TypeBuilder)
{

// определяем перечисление, нормально
def stateid=ty.DefineNestedType(<[ decl:
  public enum StateID
  {
  }
  ]>);

..
def states : list[TypeBuilder]= ty.DeclaredNestedTypes; // получаем лист TypeBuilder-ов для внутренних типов

// для каждого типа добавляем имя в качестве константы к перечислению
states.Iter( x => stateid.Define(<[ | $(x.Name)]>)); // не компилируется

// также просто если попробовать
stateid.Define(<[decl: | ABC ]>); // компилируется, но при выполнении ничего не происходит, новый член не добавляется
}

stateid.Compile(); // компилируем тип




// при этом если написать сразу список членов, то он определяется правильно:
def stateid=ty.DefineNestedType(<[ decl:
  public enum StateID
  {
  | ABC
  | BCD
  }
  ]>); // если бы была возможность как то в цитату вставить строки с описанием членов


И еще вопрос можно ли удалять объявления например подклассов из класса? например убрать объявление SubTest, чтобы он присутствовал во время работы макроса и удалялся из конечного кода?


class Test
{

   class SubTest
   {
   }
}
Re: Написание DSL на Nemerle и создание Enum в макросах
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.02.10 14:36
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>Еще встала другая проблема, надо определить во время компиляции в макросе перечисление на основе кода, например так:

CU>
CU>[MacroUsage(MacroPhase.BeforeTypedMembers,MacroTargets.Class,Inherited=true)]  
CU>macro statemachine(ty : TypeBuilder)
CU>{

CU>// определяем перечисление, нормально
CU>def stateid=ty.DefineNestedType(<[ decl:
CU>  public enum StateID
CU>  {
CU>  }
CU>  ]>);

CU>..
CU>def states : list[TypeBuilder]= ty.DeclaredNestedTypes; // получаем лист TypeBuilder-ов для внутренних типов

CU>// для каждого типа добавляем имя в качестве константы к перечислению
CU>states.Iter( x => stateid.Define(<[ $(x.Name)]>)); // не компилируется

CU>// также просто если попробовать
CU>stateid.Define(<[decl: | ABC ]>); // компилируется, но при выполнении ничего не происходит, новый член не добавляется
CU>}
CU>stateid.Compile(); // компилируем тип
CU>


CU>
CU>// при этом если написать сразу список членов, то он определяется правильно:
CU>def stateid=ty.DefineNestedType(<[ decl:
CU>  public enum StateID
CU>  {
CU>  | ABC
CU>  | BCD
CU>  }
CU>  ]>); // если бы была возможность как то в цитату вставить строки с описанием членов
CU>


CU>Вопрос такой, как определить перечисление в макросе и добавить как подтип в классе?


Что-то вроде этого:
[MacroUsage(MacroPhase.BeforeTypedMembers,MacroTargets.Class,Inherited=true)]  
macro statemachine(ty : TypeBuilder)
{
  // генерируем список определений полей перечисления
  def cases = ty.DeclaredNestedTypes.Map(t => <[ decl: | $(t.ParsedName : name); ]>);

  def enumTypeBuilder = ty.DefineNestedType( // вложенные типы нужно добавлять только с помощью DefineNestedType
    <[ decl:
        public enum StateID
        {
          ..$cases
        }
    ]>, true);
  
  enumTypeBuilder.Compile();
}


CU> Как добавить динамически в макросе элементы в список перечисления, есть ли такая возможность?


Или как показал я, или с помощью методов DefineXxx() класса TypeBuilder.

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


Это все очень сильно зависит от задачи говорить о чем-то в ообщем невозможно.

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


Удалаять нельзя. Но нужную метаинформацию можно описать в другом виде. Например в виде доп-синтаксиса, или в виде мета-атрибутов.

В общем, лучше опиши стоящую задачу (без ее реализации), а мы попробуем как ее лучше реализовать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Написание DSL на Nemerle и создание Enum в макросах
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.02.10 14:39
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>Да генерировать методы легко, хорошо что синтаксис можно добавить после класса, но не могли бы Вы Владислав написать есть ли возможность создать в классе перечисление и добавить в него имена констант на основе динамических данных, как я описал здесь, почему не компилируется определение перечисления и не добавляется даже статическое константное поле в перечисление, есть какие то ограничения у компилятора?


Извиняюсь. Был занят. Ответ на этот вопрос здесь
Автор: VladD2
Дата: 03.02.10
.

CU>И еще вопрос можно ли удалять объявления например подклассов из класса?


Нет. Я бы описал нужные данные в метаатрибуте или расширенном синтаксисе и не стал бы создавать не нужных вложенных типов.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Написание DSL на Nemerle и создание Enum в макросах
От: CodingUnit Россия  
Дата: 03.02.10 15:36
Оценка:
Здравствуйте, VladD2, Вы писали:

CU>>Вопрос такой, как определить перечисление в макросе и добавить как подтип в классе?


VD>Что-то вроде этого:

VD>
VD>[MacroUsage(MacroPhase.BeforeTypedMembers,MacroTargets.Class,Inherited=true)]  
VD>macro statemachine(ty : TypeBuilder)
VD>{
VD>  // генерируем список определений полей перечисления
VD>  def cases = ty.DeclaredNestedTypes.Map(t => <[ decl: | $(t.ParsedName : name); ]>);

VD>  def enumTypeBuilder = ty.DefineNestedType( // вложенные типы нужно добавлять только с помощью DefineNestedType
VD>    <[ decl:
VD>        public enum StateID
VD>        {
VD>          ..$cases
VD>        }
VD>    ]>, true);
  
VD>  enumTypeBuilder.Compile();
VD>}
VD>


спасибо, работает!

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


VD>Это все очень сильно зависит от задачи говорить о чем-то в ообщем невозможно.


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


VD>Удалаять нельзя. Но нужную метаинформацию можно описать в другом виде. Например в виде доп-синтаксиса, или в виде мета-атрибутов.


VD>В общем, лучше опиши стоящую задачу (без ее реализации), а мы попробуем как ее лучше реализовать.


Задача такова, есть библиотека описания автоматов состояний в коде аналогичным в UML, проблема в том что описание структуры автомата сложно читаемое и создаваемое вручную, хотелось бы автоматизировать этот процессс за счет макросов и DSL, я уже видел решение подобной задачи в Boo, но хотелось бы попробовать сделать такое решение на Nemerle, под нужную библиотеку, там имеются разные процедуры для описания иерархии автомата, хотелось бы например сделать иерархическое визуальное описание иерархии, например:


[statemachine]
class TestFSM
{

  [state]
  class Top
  {
    
    [state]
    class Start
    {
       
      [state]
      class Sub
      {
       entry() : void
       {
        // действие при входе
       }
       exit() : void
       {
        // действие при выходе
       }
      } 
    }
    
    [state]
    class Next
    {
      transition("Sub",UserEvt) // описание перехода
    }
  }
}


как то так, на Boo там вообще абстрактно описали автомат, типа

state @Parked:
    when @EngineStarted      >> @IdleInNeutral
    
state @IdleInNeutral:
    when @EngineKilled       >> @Parked
    when @GearEngaged        >> @IdleInGear
    
state @IdleInGear:
    when @GearDisengaged     >> @IdleInNeutral
    when @GasApplied         >> @RacingAlong

state @RacingAlong:
    when @BrakeApplied       >> @IdleInGear
    when @CarCrashedIntoTree >> @CarDestroyed

state @CarDestroyed


хотелось бы что то подобное создать и переводить все это на этапе компиляции в вызовы соответствующих методов в библиотеке автомата для инициализации, главная проблема в легком описании на каком то DSL или псевдоязыке, метааттрибутов, какие могут быть возможнные решения?
Re: [Nemerle DSL] Описание конечного автомата
От: CodingUnit Россия  
Дата: 04.02.10 10:52
Оценка:
Здравствуйте, VladD2, Вы писали:



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


VD>Если бы я решал подобную задачу, то скорее всего я выбрал бы следующий подход:

VD>1. Каждый автомат я описывал бы как отдельный класс.
VD>2. Список состояний я описывал бы в метаатрибуте которым помечал бы этот класс.
VD>3. Синтаксис сделал бы похожим на описание локальных функций.
VD>4. Реакции на переходы описывал бы как методы внутри этого класса.

VD>Вот как мог бы выглядеть приведенный выше автомат:

VD>
VD>


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

CU>>
CU>>[statemachine]
CU>>class TestFSM
CU>>{

CU>>  [state]
CU>>  class Top // самое верхнее состояние
CU>>  {
    
CU>>    [state]
CU>>    class Start // подсостояние Top
CU>>    {
       
CU>>      [state]
CU>>      class Sub1 // подсостояние Start
CU>>      {
            [state]  
            class Sub2 // подсостояние Sub1
            {

            }
CU>>      } 
CU>>    }
    
CU>>    [state]
CU>>    class Next // подсостояние Top
CU>>    {

CU>>    }
CU>>  }
CU>>}
CU>>


графически они выглядят примерно так



В принципе с метаатрибутом описать весь автомат можно, лишь бы это не сложно было сделать, тогда описание будет выглядеть примерно так:
 [FsmDef(
 {
 state Top
  {
        state Start
        {
        | Event1 => Next // переход по событию Event1

           // подостояние 1
           state Sub1
           {
           | entry => {
                      Action1 // действие при входе
                      }
           | exit => Action2 // действие при выходе

            // подсостояние 2            
             state Sub2
             {
             
             }
           }
        } 
       
        state Next
        {
        | Event2 => Start
        }
  }
})]
class MyFsm
{
  // обарботчик события перехода 
  EnterIn_IdleInGear_State(previosState : MyFsmState) : void
  {
    ... код обработки 
  }


сложно ли такую структуру считать в макросе? Там видимо понадобится дополнительный рекурсивный разбор каждого вложенного состояния и создание иерархии, при этом надо как то выделить части | name, и вложенные state. Hадо еще чтобы какой то класс хранил состояние структуру, то есть создавался однократно и использовался как синглтон в дальнейшем. Сложность пока только в том чтобы распознать конструкции | и state на одном уровне, остальное дело техники, не могли бы вы Владислав описать примерно как такое можно сделать, и что такое ..$ в цитате, в прошлом посте оно позволило развернуть лист выражений в цитате? В этих конструкциях match с чем конкретно он сравнивает, после switch такая конструкция выглядит странно, как я понимаю там списки из Expression, то есть он сравнивает списки экземпляров Expression?

VD>

VD> ...
VD>}
VD
VD>Выше я описал возможный вариант.
VD>Для реализации данного подхода нужно описать и реализовать два макроса:
VD>1. FsmDef — метаатрибут. В нем должна производиться основная работа по построению конечного автомата.
VD>2. state — макрос уровня выражения. Нужен только для того, чтобы немерле мог воспринимать синтаксис описания состояния — "state имяСостояния список состояний".

VD>Вот как могут выглядеть заглушки (т.е. без реализации) этих макросов:

VD>
VD>  [Nemerle.MacroUsage(Nemerle.MacroPhase.BeforeTypedMembers, Nemerle.MacroTargets.Class)]
VD>  macro FsmDef(type_builder : TypeBuilder, body)
VD>  {
VD>  }

VD>  macro State(stateName, body)
VD>  syntax("state", stateName, body)
VD>  {
VD>    <[ () ]> // В этом макросе нам ничего делать не надо. Он нужет только чтобы немерле "пропустил" наш синтаксис.
VD>  }
VD>


VD>Понимаю, что без опыта создания макросов распознать столь не тривиальную структуру будет не просто. По этому я потратил час, чтобы набросать примерную реализацию макросов. Вот что у меня получилось...

VD>Сами макросы:
VD>
VD>using Nemerle;
VD>using Nemerle.Compiler;
VD>using Nemerle.Compiler.Parsetree;
VD>using System.Diagnostics;

VD>namespace MacroLibrary2
VD>{
VD>  [Nemerle.MacroUsage(Nemerle.MacroPhase.BeforeTypedMembers, Nemerle.MacroTargets.Class)]
VD>  macro FsmDef(type_builder : TypeBuilder, body)
VD>  {
VD>    Helper.MakeFsm(type_builder, body);
VD>  }

VD>  macro State(stateName, body)
VD>  syntax("state", stateName, body)
VD>  {
VD>    _ = stateName; // говорим компилятору, что мы намеренно не желаем использовать параметр
VD>    _ = body;      // тоже самое
VD>    <[ () ]> // В этом макросе нам ничего делать не надо. Он нужен только чтобы немерле "пропустил" наш синтаксис.
VD>  }
  
VD>  module Helper
VD>  {
VD>    public MakeFsm(ty : TypeBuilder, body : PExpr) : void
VD>    {
VD>      def makeTransition(transitionDef : MatchCase) : void
VD>      {
VD>          Message.Hint(transitionDef.Location, $"  Events=$(transitionDef.patterns) Transition=$(transitionDef.body)")
VD>      }
    
VD>      def makeSate(stateDef : PExpr) : void
VD>      {   // ncc заворачивает обращение к макросу в конструкцию PExpr.MacroCall...
VD>        | PExpr.MacroCall(name, _, parms) when name.Id == "state" =>
          
VD>          match (parms)
VD>          { // параметры (код передаваемый в них) макроса заворачиваются в SyntaxElement.Expression.
VD>            // Пользователь должен передать два параметра...
            
VD>              // имя и пустую группу...
VD>            | [Expression(<[ $stateName ]>), Expression(<[ { } ]>)] => 
VD>              Message.Hint(stateName.Location, $"Распознано описание состояния '$stateName' (без переходов!)");

VD>              // или имя и список вхождений оператора match который компилятор превращает в полноценный оператор match...              
VD>            | [Expression(<[ $stateName ]>), Expression(<[ match ($_) { ..$transitions } ]>)] =>
VD>              Message.Hint(stateName.Location, $"Распознано описание состояния '$stateName'. Переходы:");
            
VD>              foreach (transitionDef in transitions)
VD>                makeTransition(transitionDef);
                
VD>            | [Expression(<[ $_ ]>), Expression(<[ { $x } ]>)] =>
VD>              Message.Error(x.Location, "Ожидается описание переходов в формате: { | Event => State | Event => State ... }");
              
VD>            | _ => 
VD>              Message.Error(stateDef.Location, 
VD>                "Ожидается описание состояния в формате: state StateName { transitions }"); 
VD>          }
        
VD>        | _ =>
VD>          Message.Error(stateDef.Location, 
VD>            "Ожидается описание состояния в формате: state StateName { transitions }"); 
VD>      }
      
VD>      match (body)
VD>      {
VD>         // описания состояний заключены в группу (фигурные скобки)
VD>        | <[ { ..$states } ]> => // матчим список выражений описывающих состояния
VD>          foreach (state in states) 
VD>            makeSate(state);
            
VD>        | _ => 
VD>          Message.Error(body.Location, 
VD>            "Ожидается список состоянии в формате { state1 state2 ... }"); 
VD>      }
VD>    }
VD>  }
VD>}
VD>
Re[2]: [Nemerle DSL] Описание конечного автомата
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.02.10 13:54
Оценка:
Здравствуйте, CodingUnit, Вы писали:

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


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

CU>графически они выглядят примерно так

CU>здесь

CU>В принципе с метаатрибутом описать весь автомат можно, лишь бы это не сложно было сделать, тогда описание будет выглядеть примерно так:


CU>
...
CU>           state Sub1
CU>           {
CU>           | entry => {
CU>                      Action1 // действие при входе
CU>                      }
CU>           | exit => Action2 // действие при выходе
CU>})]
CU>


Так выглядит красивее. Только одно замечание. Вот эти вот "entry" и "exit" ведь к самому автомату отношения не имеют, да? Это ведь реакция?
На мой взгляд лучше не забивать описание автомата действиями которые должны осуществляться при переходах. Действия лучше помещать в методы внутри класса. Метод EnterIn_IdleInGear_State(), который я изобразил в своем примере как раз и был таким действием. Их можно помечать атрибутами или распознавать по имени. В моем случае подразумевалось, что он будет распознаваться оп имени. Можно их описывать и на основании атрибутов. Например, для приведенного выше фрагмента можно описать реакции так:
[OnEnter(State=Sub1)]
{
  Action1 // действие при входе
}

[OnExit(State=Sub1)]
{
  Action2 // действие при выходе
}


Это позволит разгрузить описание самого автомат и иметь интеллисенс (дополнение при вводе, подсветку, хинты, ...) внутри методов.

CU>сложно ли такую структуру считать в макросе?


Макросам без разницы. Они разбирают абстрактный код. Принцип я показал. Если будут какие-то непонимания или вопросы, то можно обращаться сюда или прямо ко мне на Skype (имя в скапе совпадает с ником на форуме).

Естественно, имеет смысл почитать статьи посвященные написанию макросов.

CU> Там видимо понадобится дополнительный рекурсивный разбор каждого вложенного состояния и создание иерархии, при этом надо как то выделить части | name, и вложенные state.


Да, конечно. Вам нужно расширить функцию makeTransition (Ее, собственно, по любому нужно развивать.):
def makeTransition(transitionDef : MatchCase) : void
{
  Message.Hint(transitionDef.Location, $"  Events=$(transitionDef.patterns) Transition=$(transitionDef.body)")
}

В transitionDef.body может находиться произвольный Nemerle-код. Так как мы объявили макрос state, то в transitionDef.body может находиться и он (или даже несколько обращений к нему).

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

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


Это предложение я не понял.
Речь идет о создании объектной модели автомата?
Или о том, что описание одного автомата может использоваться для разных задач?

CU> Сложность пока только в том чтобы распознать конструкции | и state на одном уровне,


Что значит на одном уровне?
Как распознавать state и его вхождения я показал. Вам нужно только немного расширить это распознавание сделав его рекурсивным. Сейчас распознование конструкции "| X => Y" выливается в банальный вывод текста в вывод компилятора:
def makeTransition(transitionDef : MatchCase) : void
{
  Message.Hint(transitionDef.Location, $"  Events=$(transitionDef.patterns) Transition=$(transitionDef.body)")
}

Вам же нужно развить это дело.

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


Это синтаксис квази-цирирования. Оно работает в две стороны (на распознавание и на композицию кода). Конкретно "..$x" позволяет распознать набор повторяющихся участов кода в список или сгенерировать код из списока. Такая конструкция может применятся только в скобках (в данном случсе в фигурных). Более подробно о квази-цитировании написано во второй статье
Автор(ы): Чистяков Владислав Юрьевич
Дата: 18.08.2011
Во второй части статьи о макросах Nemerle речь пойдет о макросах уровня выражения, о макросах, изменяющих синтаксис языка, а также о контексте компиляции, доступном в макросах, и тех возможностях, которые он предоставляет (типизации выражений, получении доступа к описанию типов проекта, информации о методах и т.п.).
курса Макросы Nemerle &mdash; расширенный курс (см. раздел "Работа с квази-цитированием").

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

CU>В этих конструкциях match с чем конкретно он сравнивает, после switch такая конструкция выглядит странно, как я понимаю там списки из Expression, то есть он сравнивает списки экземпляров Expression?


Там список так называемых PExpr. PExpr — это вариантный тип описывающих код немерла. Грубо говоря — это АСТ немерла. Чтобы не нужно было знать все типы данных в него входящий и писать сложный и громоздкий код была придумана система квази-цитирования. В общем, в указанном курсе все это описано.

ЗЫ

Один полезный совет... Чтобы лучше понимать происходящее на работу макросов лучше смотреть из под отладчика. Просто добавьте в некоторый фрагмент кода макроса:
assert2(false);

и скомпилируйте тестовый проект. Когда появится окно ассерат нажмите Retry и вы окажетесь в отладчике (нужно открыть его в отдельной ссесси, не той в котрой идет компиляция). Далее можно будет идти по коду макроса отладчиком и смоетреть значения и тип переменных. Это резко упрощает понимание (особенно чужого кода).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: [Nemerle DSL] Описание конечного автомата
От: CodingUnit Россия  
Дата: 16.02.10 13:56
Оценка:
Здравствуйте, VladD2, Вы писали:

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


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


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


CU>>графически они выглядят примерно так

CU>>здесь

CU>>В принципе с метаатрибутом описать весь автомат можно, лишь бы это не сложно было сделать, тогда описание будет выглядеть примерно так:


CU>>
VD>...
CU>>           state Sub1
CU>>           {
CU>>           | entry => {
CU>>                      Action1 // действие при входе
CU>>                      }
CU>>           | exit => Action2 // действие при выходе
CU>>})]
CU>>


VD>Так выглядит красивее. Только одно замечание. Вот эти вот "entry" и "exit" ведь к самому автомату отношения не имеют, да? Это ведь реакция?

VD>На мой взгляд лучше не забивать описание автомата действиями которые должны осуществляться при переходах. Действия лучше помещать в методы внутри класса. Метод EnterIn_IdleInGear_State(), который я изобразил в своем примере как раз и был таким действием. Их можно помечать атрибутами или распознавать по имени. В моем случае подразумевалось, что он будет распознаваться оп имени. Можно их описывать и на основании атрибутов. Например, для приведенного выше фрагмента можно описать реакции так:
VD>[c#]

Все работает замечательно, на Nemerle можно строить неплохие DSL, но вот беда, почему то не хотят создаваться в цикле объявления событий, то есть создаются правильные PExpr объявления члена класса события, но когда начинается конечная компиляция оказывается что члены поля и методов add,remove генерируются с одинаковыми именами, соответствующих названию в той строчке в которой производилось объявление, например если делаешь так:


// функция которая создает события из описания где то списка событий
def create_events(model)
{
model.Events.Map(x =>
 {
 def ename : string =x.Name; // это имя члена
 <[ decl: public event $(ename : usesite) : EventHandler; ]> // на выходе объявление члена события
 });
}

def defs=create_events(model); // создаем список объявлений
defs.Iter(x => typebuilder.Define(x)); // добавляем в typebuilder


при этом возникает ошибка в духе: _N2_ename_usesite_field duplicated identifier, тоже самое и с методами add,remove, исследовав этот вопрос оказывается когда создается с помощью цитаты объявление события оно всегда использует имя объявления в данном случае текст $(ename : usesite), и с помощью него создает имя членов, видимо подразумевая что событие должно объявлятся с константным именем и всегда разным, но что делать если надо объявить на основе динамических данных? Я решил эту задачу только с помощью специального метода, который берет объявление с помощью цитаты, которое преобразуется в ClassMember.Event и создает новый класс ClassMember.Event заменяя имена на новые и оставляя тела такие же как в старом созданном с помощью цитаты, тогда сообщение об ошибке не возникает, но это не выход, надо видимо чтобы имя полей и методов add,remove, при объявлении квази цитаты использовалось уникальное на основе имени которое берется из выражения, а не на основе текста выражения, это надо править компилятор, где бы найти файл где вся эта логика распознавания цитат реализуется? Может ли помочь наш всемогущий Владислав?
Re[4]: [Nemerle DSL] Описание конечного автомата
От: hardcase Пират http://nemerle.org
Дата: 16.02.10 14:55
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>при этом возникает ошибка в духе: _N2_ename_usesite_field duplicated identifier, тоже самое и с методами add,remove


Вот такой хак насильно изготавливает event-ы:

using Nemerle;
using Nemerle.Compiler;
using PT = Nemerle.Compiler.Parsetree;

namespace MacroLibrary3 {

    [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) {
                BuildEvent(tb, name, <[ System.EventHandler ]>);
            }
        }
        
        private BuildEvent(tb : TypeBuilder, name : string, evt_type : PT.PExpr) : void {
            def evt_field_name = PT.Name("_N_" + name);
            def evt_field = PT.Splicable.Name(evt_field_name);
            def field = <[ decl : private mutable $evt_field : $evt_type; ]>;

            def add_proc = <[ decl :
                private $("add_" + name : usesite)(value : $evt_type) : void {
                    if(null == $(evt_field_name : name)) {
                        $(evt_field_name : name) = value;
                    } else {
                        $(evt_field_name : name) = System.Delegate.Combine($(evt_field_name : name), value) :> $evt_type;
                    }
                }
            ]>;

            def remove_proc = <[ decl :
                private $("remove_" + name : usesite)(value : $evt_type) : void {
                    when(null != $(evt_field_name : name)) {
                        $(evt_field_name : name) = System.Delegate.Remove($(evt_field_name : name), value) :> $evt_type;
                    }
                }
            ]>;

            def evt_mods = Modifiers(NemerleAttributes.Public, []);
            def evt_name = PT.Splicable.Name(PT.Name(name));
            def evt = PT.ClassMember.Event(evt_name, evt_mods, tb.ParsedTypeName, field, add_proc, remove_proc);

            tb.Define(evt);
        }
    }

}



Проблема в том, что несмотря на NemerleAttributes.Public событие остается привытным.

Дойду до дому — повожусь еще.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[4]: [Nemerle DSL] Описание конечного автомата
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.10 15:22
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>при этом возникает ошибка в духе: _N2_ename_usesite_field duplicated identifier, тоже самое и с методами add,remove, исследовав этот вопрос оказывается когда создается с помощью цитаты объявление события оно всегда использует имя объявления в данном случае текст $(ename : usesite), и с помощью него создает имя членов, видимо подразумевая что событие должно объявлятся с константным именем и всегда разным, но что делать если надо объявить на основе динамических данных? Я решил эту задачу только с помощью специального метода, который берет объявление с помощью цитаты, которое преобразуется в ClassMember.Event и создает новый класс ClassMember.Event заменяя имена на новые и оставляя тела такие же как в старом созданном с помощью цитаты, тогда сообщение об ошибке не возникает, но это не выход, надо видимо чтобы имя полей и методов add,remove, при объявлении квази цитаты использовалось уникальное на основе имени которое берется из выражения, а не на основе текста выражения, это надо править компилятор, где бы найти файл где вся эта логика распознавания цитат реализуется? Может ли помочь наш всемогущий Владислав?


А можно прислать мне проект воспроизводящий ошибку? Желательно, чтобы в нем не было ничего лишнего, только описанная проблема. Тогда я постараюсь посмотреть, что происходит, и если получится, поправить баг в компиляторе или объяснить как нужно действовать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: [Nemerle DSL] Описание конечного автомата
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.10 15:43
Оценка:
Здравствуйте, CodingUnit, Вы писали:

Да... Пока я (или кто-то еще) не разобрался в ошибке можно обойти проблему описывая свойство явно. Что-то вроде:
def fieldName = Macros.NewSymbol(field.Name);

tb.Define(<[ decl: private mutable $(fieldName : name) : EventHandler; ]>);

tb.Define(<[ decl: 
  public event $(ename : usesite) : EventHandler
  {
    add    { $(fieldName : name) += value; }
    remove { $(fieldName : name) -= value; } 
  }
]>);
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: [Nemerle DSL] Описание конечного автомата
От: CodingUnit Россия  
Дата: 16.02.10 15:46
Оценка:
Здравствуйте, VladD2, Вы писали:

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


CU>>при этом возникает ошибка в духе: _N2_ename_usesite_field duplicated identifier, тоже самое и с методами add,remove, исследовав этот вопрос оказывается когда создается с помощью цитаты объявление события оно всегда использует имя объявления в данном случае текст $(ename : usesite), и с помощью него создает имя членов, видимо подразумевая что событие должно объявлятся с константным именем и всегда разным, но что делать если надо объявить на основе динамических данных? Я решил эту задачу только с помощью специального метода, который берет объявление с помощью цитаты, которое преобразуется в ClassMember.Event и создает новый класс ClassMember.Event заменяя имена на новые и оставляя тела такие же как в старом созданном с помощью цитаты, тогда сообщение об ошибке не возникает, но это не выход, надо видимо чтобы имя полей и методов add,remove, при объявлении квази цитаты использовалось уникальное на основе имени которое берется из выражения, а не на основе текста выражения, это надо править компилятор, где бы найти файл где вся эта логика распознавания цитат реализуется? Может ли помочь наш всемогущий Владислав?


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


У меня сейчас интеграция вылетела, не хочет переставлятся, нужно будет студию переставлять, сложно будет собрать внятный проект, но описанную проблему легко воспроизвести, достаточно создать макроаттрибут который добавляет члены к классу, далее сделать массив строк имен эвентов и преобразовать в цитатное объявление события так:


void MacroHelper(typebuilder : TypeBuilder)
 {

def create_events(names : list[string])
{
names.Map(x =>
 {
 def ename : string =x; // это имя члена
 <[ decl: public event $(ename : usesite) : EventHandler; ]> // на выходе объявление члена события
 });
}

def names="abc" :: "cda" :: []; // cоздаем массив хотя бы двух имен
def defs=create_events(names); // создаем список объявлений
defs.Iter(x => typebuilder.Define(x)); // добавляем в typebuilder
}


потом добавляем макроаттрибут к какому нибудь классу, и собираем проект с применением макроса и проблема себя проявит сообщением о сдублированных идентификаторов генерируемых компилятором для закрытого поля события и методов add,remove которые все будут именоваться одним именем имеющим в себе название "ename_usesite" по объявлению, кроме как хаком пока такая проблема не решается, хорошо бы глянуть поглубже, если че то не будет работать, то я завтра сделаю проект.
Re[5]: [Nemerle DSL] Описание конечного автомата
От: hardcase Пират http://nemerle.org
Дата: 16.02.10 16:12
Оценка:
Здравствуйте, VladD2, Вы писали:

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


Макрос:
    [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) {
                BuildEvent2(tb, name, <[ System.EventHandler ]>);
            }
        }
        
        private BuildEvent2(tb : TypeBuilder, name : string, evt_type : PT.PExpr) : void {
            tb.Define(<[ decl:
                public event $(name : usesite) : $evt_type;
            ]>);
        }
    }

Использование:
[CreateEvents] class C1 { }


Ошибки вида:
mutable _N__N_event_field_of__name___usesite__3262 : System.EventHandler; redefined in 'C1'
redefinition of method C1.add_(name : usesite)(value : System.EventHandler) : void

Текст (name : usesite) наводит на определенные мысли...
/* иЗвиНите зА неРовнЫй поЧерК */
Re[5]: [Nemerle DSL] Описание конечного автомата
От: hardcase Пират http://nemerle.org
Дата: 16.02.10 16:19
Оценка:
Здравствуйте, VladD2, Вы писали:

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


VD>Да... Пока я (или кто-то еще) не разобрался в ошибке можно обойти проблему описывая свойство явно. Что-то вроде:

VD>
VD>def fieldName = Macros.NewSymbol(field.Name);

VD>tb.Define(<[ decl: private mutable $(fieldName : name) : EventHandler; ]>);

VD>tb.Define(<[ decl: 
VD>  public event $(ename : usesite) : EventHandler
VD>  {
VD>    add    { $(fieldName : name) += value; }
VD>    remove { $(fieldName : name) -= value; } 
VD>  }
VD>]>);
VD>


Судя по всему неправильно формируются имена свойств и add/remove методов. Допилил предыдущий хак до такого вида:
public BuildEvent(tb : TypeBuilder, name : string, evt_type : PT.PExpr) : void {
    def evt_field_name = PT.Name("_" + name);
    def evt_field = PT.Splicable.Name(evt_field_name);
    def field = <[ decl : private mutable $evt_field : $evt_type; ]>;

    def adder = <[ decl :
        ..$(Modifiers(NemerleAttributes.Public | NemerleAttributes.SpecialName, []))
        $("add_" + name : usesite)(value : $evt_type) : void {
            $(evt_field_name : name) = System.Delegate.Combine($(evt_field_name : name), value) :> $evt_type;
        }
    ]>;

    def remover = <[ decl :
        ..$(Modifiers(NemerleAttributes.Public | NemerleAttributes.SpecialName, []))
        $("remove_" + name : usesite)(value : $evt_type) : void {
            $(evt_field_name : name) = System.Delegate.Remove($(evt_field_name : name), value) :> $evt_type;
        }
    ]>;

    def evt_mods = Modifiers(NemerleAttributes.Public, []);
    def evt_name = PT.Splicable.Name(PT.Name(name));
    def evt = PT.ClassMember.Event(evt_name, evt_mods, tb.ParsedTypeName, field, adder, remover);

    tb.Define(evt);
}

К соответствующему свойству для события Foo из класса можно обращаться через подчеркивание: _Foo, операторы += и -= не работают — нужно явно обращаться к add_Foo и remove_Foo.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[6]: [Nemerle DSL] Описание конечного автомата
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.10 17:07
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Текст (name : usesite) наводит на определенные мысли...


Ага. Вот какой код генерируется в итоге (C# by Reflector):
tb.Define(
  new ClassMember.Event(
    new Splicable.Name(new Name(name, ManagerClass.Instance.MacroColors.UseColor, ManagerClass.Instance.MacroColors.UseContext)), 
    new Modifiers(NemerleAttributes.Public, list<PExpr>.Nil._N_constant_object),
    evt_type, 
    new ClassMember.Field(new Splicable.Name(Name.NameInCurrentColor("_N__N_event_field_of__name___usesite__3262", _N_MacroContexts.Get(1, ManagerClass.Instance))), new Modifiers(NemerleAttributes.Mutable | NemerleAttributes.Private, list<PExpr>.Nil._N_constant_object), evt_type),
    new ClassMember.Function(new Splicable.Name(Name.NameInCurrentColor("add_(name : usesite)", _N_MacroContexts.Get(1, ManagerClass.Instance))), 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(Name.NameInCurrentColor("add_(name : usesite)", _N_MacroContexts.Get(1, ManagerClass.Instance))), 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), evt_type), list<PParameter>.Nil._N_constant_object)), list<PExpr>.Nil._N_constant_object, FunBody.Abstract._N_constant_object), 
    new ClassMember.Function(new Splicable.Name(Name.NameInCurrentColor("remove_(name : usesite)", _N_MacroContexts.Get(1, ManagerClass.Instance))), 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(Name.NameInCurrentColor("remove_(name : usesite)", _N_MacroContexts.Get(1, ManagerClass.Instance))), 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), evt_type), list<PParameter>.Nil._N_constant_object)), list<PExpr>.Nil._N_constant_object, FunBody.Abstract._N_constant_object)
  )


Таким образом еще при формировании цитаты формируется некорректный код.
К сожалению искать место в компиляторе которое занимается лифтингом квази-цитат событий не так просто. На это уйдет время.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: [Nemerle DSL] Описание конечного автомата
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.10 18:38
Оценка:
Здравствуйте, VladD2, Вы писали:

В общем, проблема возникает еще при парсинге квази цитаты (см. файл MainParser.n) строка 1619 и далее со строки 1696 и далее:
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();
  ...
      /// 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_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);
      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 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 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)


В случае использования сплайсинга в имени свойства в id находится не имя, а выражение (для приведенного примера — это выражение "(name : usesite)". Оно тупо приводится к строке и далее используется для формирования имени поля, методов add_Xxx и remove_Xxx. Естественно, что в результате получается чушь.

Этот код нужно переписывать, так чтобы вместо генерации имени во время парсига, генерировался бы код который формировал бы имена во время компиляции исходника (т.е. раскрытия макроса в нашем случае).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: [Nemerle DSL] Описание конечного автомата
От: hardcase Пират http://nemerle.org
Дата: 16.02.10 18:45
Оценка:
Здравствуйте, VladD2, Вы писали:

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


VD>В общем, проблема возникает еще при парсинге квази цитаты (см. файл MainParser.n) строка 1619 и далее со строки 1696 и далее:



Я правильно думаю что plain_name должен получаться также как и в parse_property (строка 1340):
def plain_name = match (id) { | Splicable.Name (n) => n.Id | _ => "" };
/* иЗвиНите зА неРовнЫй поЧерК */
Re[9]: [Nemerle DSL] Описание конечного автомата
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.10 19:20
Оценка:
Здравствуйте, hardcase, Вы писали:


H>Я правильно думаю что plain_name должен получаться также как и в parse_property (строка 1340):

H>
H>def plain_name = match (id) { | Splicable.Name (n) => n.Id | _ => "" };
H>


"plain_name" вообще не должно быть. Вместо этого нужно генерировать код который сформирует этот самый plain_name динамически (во время компиляции).

Но что вот как это сделать я пока не понял. Уже устал. Да и задачка получается слишком высшего порядка.

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

Splicable — это вариант который описан следующим образом:
  public variant Splicable : Located
  {
    | Name { body : Parsetree.Name; }
    | Expression
      {
        expr : PExpr;
        [RecordIgnore] public mutable env : GlobalEnv;
        public this(expr : PExpr, env : GlobalEnv) { this.expr = expr; this.env = env; }
        public this(loc : Location, expr : PExpr, env : GlobalEnv)
        {
          this.loc = loc; this.expr = expr; this.env = env;
        }
      }


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

Сплайс вида "$(name : usesite)" на этапе компиляции квази-цитаты преобразуется в:
Splicable.Expression(<[ name : usesite ]>, GlobalEnv(...))

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

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

ЗЫ

Откровенно говоря у меня сейчас ужасный цейтнот, так что заняться в ближайшее время я этим наверно не смогу. Буду рад, если кто-то попытается исправить этот баг.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: [Nemerle DSL] Описание конечного автомата
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.02.10 19:22
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Я правильно думаю что plain_name должен получаться также как и в parse_property (строка 1340):

H>
H>def plain_name = match (id) { | Splicable.Name (n) => n.Id | _ => "" };
H>


Ну, то есть... в двух словах parse_property тоже не рассчитан на сплайснутые имена. В этом случае имя просто становится пустой строкой, что как ты понимаешь, так же не приемлемо.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: [Nemerle DSL] Описание конечного автомата
От: para  
Дата: 20.02.10 11:08
Оценка:
Довольно красиво)
Однако ещё можно задавать автомат(граф) матрицей смежности
Примерно так:
[StateMachine]
class Sm
{
    public States {A, B, C}; //like enum
    public AdjacencyMatrix : bool[,] // извините не знаю, как на немерле двумерный массив объявить
    {
        {0,1,0};
        {0,1,1};
        {1,0,0};
    };

    public DefaultInitialState = State.A;
}

такое можно даже на шарпе написать через дженерики))
Re[2]: [Nemerle DSL] Описание конечного автомата
От: hardcase Пират http://nemerle.org
Дата: 20.02.10 11:14
Оценка:
Здравствуйте, para, Вы писали:

P>Довольно красиво)

P>Однако ещё можно задавать автомат(граф) матрицей смежности

Можно, но только это совершенно не очевидно.
Для 3-4 состояний может еще и можно разобраться, но вот потом......
/* иЗвиНите зА неРовнЫй поЧерК */
Re[3]: [Nemerle DSL] Описание конечного автомата
От: para  
Дата: 20.02.10 12:45
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Можно, но только это совершенно не очевидно.

H>Для 3-4 состояний может еще и можно разобраться, но вот потом......

Это зависит от контекста использования.
Я в принципе то же самое хотел сказать про список смежных вершин.
Более наглядным является диаграмма (Мура), но и она имеет предел понятности.
Матричная запись, как и диаграмма имеют преимущество перед списком:
Видно не только исходящие, но и входящие дуги.

У нас а инсте был один препод (довольно противный), он говорил так:
Матрицы экономят бумагу, но не экономят мозги.
Я придерживаюсь аналогичного мнения про ФП.
Было бы безобразно, зато однообразно)))

ИМХО)
Re[3]: [Nemerle DSL] Описание конечного автомата
От: para  
Дата: 20.02.10 13:28
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Можно, но только это совершенно не очевидно.

H>Для 3-4 состояний может еще и можно разобраться, но вот потом......

А вообще — то, конечный автомат задаётся не списком смежных вершин и не матрицей, а
http://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D0%B5%D1%87%D0%BD%D1%8B%D0%B9_%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82
списком состояний, начальным состоянием и функции перехода, заданной:
например,
1. таблицей переходов,
2. или делегатом

но по п.1 можно автоматически патчить методы на предмет перевода переменной-состояния
Re[4]: [Nemerle DSL] Описание конечного автомата
От: para  
Дата: 20.02.10 13:38
Оценка:
Где входной алфавит это подмножество методов класса
Re[4]: [Nemerle DSL] Описание конечного автомата
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.02.10 13:16
Оценка:
Здравствуйте, para, Вы писали:

P>списком состояний, начальным состоянием и функции перехода, заданной:

P>например,

Для людей важно просто и наглядно задать описание автомата. По сему совершенно не важно чем там в теории определяется автомат. Важно иметь язык который наиболее интуитивно позволит описать этот автомат. Я привел один из возможных языков. Описывать автоматы в виде таблиц очень неудобно. Таблицей можно описать только ДКА. А люди мысленно обычно создают НКА, а НКА не возможно описать с помощью простой матрицы. Спорить на эту тему я не хочу (это не тот форум). Но в принципе такие языки как регулярные выражения и грамматики (BNF, PEG) — это идилальные высокооуровневые языки. Почти для любой задачи можно придумать некоторый высокоуровневый язык который будет лучше любого описания КА. Именно по то этому людям обычно не интересны ДСЛ-и описывающие КА. Но если нужно формировать именно КА, то язык вроде приведенного мной (или использованный в БУ) очень удобен для этого. А разные статистические данные можно генерировать в процессе компиляции макросов. Скажем тот же список переходов в некоторое состояние построить не проблема. Можно даже диаграмму нарисовать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: [Nemerle DSL] Описание конечного автомата
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.02.10 20:57
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>Само же описание наверное можно получить из диаграммы, в UML редакторах есть функция экспорта XML, которое можно преобразовать в DSL и так далее.


Скажу больше. Можно сделать так, чтобы макрос кроме ДСЛ-я мог бы читать и описание из ХМЛ-я (и писать его в ХМЛ). Надо только грамотно спроектировать такой макрос. Тогда можно будет даже сделать весьма навороченное решение которое будет позволять редактировать автомат визуально и по нему генерировать эффективный код.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: [Nemerle DSL] Описание конечного автомата
От: humanist-TPV- Россия www.qarksoft.ru
Дата: 02.06.10 11:27
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>"plain_name" вообще не должно быть. Вместо этого нужно генерировать код который сформирует этот самый plain_name динамически (во время компиляции).

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() которые и использовать для формирования имен соответствующих сущностный.

1) На данный момент проблема не исправлена, может кто-нибудь из гуру Nemerle ей заняться? Хочется в production коде использовать Nemerle, но с такой багой страшно.
2) Поделитесь, пожалуйста, опытные товарищи наиболее критичными проблемами в компиляторе/интеграции для релизной версии 1.0, которые встречались при использовании Nemerle. Интересуют прежде всего проблемы при написании бизнес-логики, DSL и метапрограммирования (это то, для чего я сейчас пытаюсь использовать Nemerle). Проблемы с GUI (asp, WinForms, WPF) пока меня не волнуют, т.к. для этого буду использовать только C#.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[11]: [Nemerle DSL] Описание конечного автомата
От: hardcase Пират http://nemerle.org
Дата: 02.06.10 11:32
Оценка:
Здравствуйте, humanist-TPV-, Вы писали:

HT>1) На данный момент проблема не исправлена, может кто-нибудь из гуру Nemerle ей заняться? Хочется в production коде использовать Nemerle, но с такой багой страшно.


Какая версия компилятора? Проблему с генерированием евентов еще зимой решили.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[11]: [Nemerle DSL] Описание конечного автомата
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.06.10 14:26
Оценка:
Здравствуйте, humanist-TPV-, Вы писали:

VD>>
VD>><[ ("_N_event_field_of_" + name) : usesite ]> // для имени поля 
VD>><[ ("add_" + name) : usesite ]>               // для имени add-ера
VD>><[ ("remove_" + name) : usesite ]>            // для имени remove-ра
VD>>

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

HT>1) На данный момент проблема не исправлена, может кто-нибудь из гуру Nemerle ей заняться? Хочется в production коде использовать Nemerle, но с такой багой страшно.


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

HT>2) Поделитесь, пожалуйста, опытные товарищи наиболее критичными проблемами в компиляторе/интеграции для релизной версии 1.0, которые встречались при использовании Nemerle.

HT>Интересуют прежде всего проблемы при написании бизнес-логики, DSL и метапрограммирования (это то, для чего я сейчас пытаюсь использовать Nemerle). Проблемы с GUI (asp, WinForms, WPF) пока меня не волнуют, т.к. для этого буду использовать только C#.

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

Сам компилятор весьма стабилен. Баги конечно есть, но не критичные. По мере сил они исправляются. Если будет что-то стопорящее работу, то всегда можно обратиться на этот форум. Или предложим обходной маневр, или поправим.

Что касается интеграции, то мелких багов хватает, но они скорее из разряда мелких раздражителей. Опять же если что-то сильно достает, то можно обратиться сюда и мы постараемся поправить. Ну, или (что вообще замечательно) можно поправить самостоятельно и прислать патч.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: [Nemerle DSL] Описание конечного автомата
От: hi_octane Беларусь  
Дата: 02.06.10 15:09
Оценка:
HT>2) Поделитесь, пожалуйста, опытные товарищи наиболее критичными проблемами в компиляторе/интеграции для релизной версии 1.0, которые встречались при использовании Nemerle. Интересуют прежде всего проблемы при написании бизнес-логики, DSL и метапрограммирования (это то, для чего я сейчас пытаюсь использовать Nemerle). Проблемы с GUI (asp, WinForms, WPF) пока меня не волнуют, т.к. для этого буду использовать только C#.
Нижеследующий баг мы тщательно обходили , причём он очень многолик, встречается и в присваивании и в подстановке аргумента в функцию, а один раз лочились из-за него на совсем другом обьекте (со всеми вытекающими в рантайме последствиями):
0001052: Compiler loose a generic type, causing a program to crash.
workaround — параноидально указывать точный тип через ':' при использовании подобных иерархий и внимательно разглядывать тултип при передаче в функцию.
Re[12]: [Nemerle DSL] Описание конечного автомата
От: humanist-TPV- Россия www.qarksoft.ru
Дата: 02.06.10 15:54
Оценка:
Здравствуйте, hardcase, Вы писали:

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


HT>>1) На данный момент проблема не исправлена, может кто-нибудь из гуру Nemerle ей заняться? Хочется в production коде использовать Nemerle, но с такой багой страшно.


H>Какая версия компилятора? Проблему с генерированием евентов еще зимой решили.


Спасибо, оказывается, стояло 2 версии компилятора Снес обе и инсталлировал билд 8879, проблема не проявляется.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[12]: [Nemerle DSL] Описание конечного автомата
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.06.10 15:59
Оценка:
Здравствуйте, hi_octane, Вы писали:

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

_>0001052: Compiler loose a generic type, causing a program to crash.
_>workaround — параноидально указывать точный тип через ':' при использовании подобных иерархий и внимательно разглядывать тултип при передаче в функцию.

А можно пример воспроизводящий баг?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: [Nemerle DSL] Описание конечного автомата
От: humanist-TPV- Россия www.qarksoft.ru
Дата: 02.06.10 16:28
Оценка:
Здравствуйте, VladD2, Вы писали:

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


VD>>>
VD>>><[ ("_N_event_field_of_" + name) : usesite ]> // для имени поля 
VD>>><[ ("add_" + name) : usesite ]>               // для имени add-ера
VD>>><[ ("remove_" + name) : usesite ]>            // для имени remove-ра
VD>>>

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

HT>>1) На данный момент проблема не исправлена, может кто-нибудь из гуру Nemerle ей заняться? Хочется в production коде использовать Nemerle, но с такой багой страшно.


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

Спасибо, оказывается, стояло 2 версии компилятора Снес обе и инсталлировал билд 8879, проблема не проявляется.

HT>>2) Поделитесь, пожалуйста, опытные товарищи наиболее критичными проблемами в компиляторе/интеграции для релизной версии 1.0, которые встречались при использовании Nemerle.

VD>Интересуют прежде всего проблемы при написании бизнес-логики, DSL и метапрограммирования (это то, для чего я сейчас пытаюсь использовать Nemerle). Проблемы с GUI (asp, WinForms, WPF) пока меня не волнуют, т.к. для этого буду использовать только C#.

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


VD>Сам компилятор весьма стабилен. Баги конечно есть, но не критичные. По мере сил они исправляются. Если будет что-то стопорящее работу, то всегда можно обратиться на этот форум. Или предложим обходной маневр, или поправим.


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


Спасибо за оперативную реакцию, пойду дальше немерлить Если дело пойдет, попробую баги постить.
Еще пару вопросов до кучи:
1) Какие на данный момент планы по выходу релиза? В форуме ты как-то говорил, что к лету планируешь зарелизиться.
2) Еще раз хочу актуализировать для себя и сочуствующих:
2.1) Баги лучше куда постить на данный момент?
https://nemerle.org/bugs — этот часто в дауне
http://nemerle.rsdn.ru/bugs/
http://code.google.com/p/nemerle/issues/list

2.2) Доступ на заведение багов как проще всего получить? Можно центролизовано сразу на всех указанных ресурсах (если конечно все реально используются) ?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[13]: [Nemerle DSL] Описание конечного автомата
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.06.10 17:30
Оценка:
Здравствуйте, humanist-TPV-, Вы писали:

HT>Еще пару вопросов до кучи:

HT>1) Какие на данный момент планы по выходу релиза? В форуме ты как-то говорил, что к лету планируешь зарелизиться.

Народ только только сделал поддержку ASP и там багов хватает. Так что в ближайшее время, переведем в статус Бэты 2, а там видно будет.

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

HT>2) Еще раз хочу актуализировать для себя и сочуствующих:

HT>2.1) Баги лучше куда постить на данный момент?
HT>- https://nemerle.org/bugs — этот часто в дауне

Именно сюда. Только без "s" в протоколе: http://nemerle.org/bugs Возможно в нем и дело.
В дауне он не находился с тех пор как переехал на железо РСДН, то есть не меньше двух месяцев.

Если баг критичный, то имеет смысл еще и сюда сообщение добавить со ссылкой на баг и объяснением на русском.

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

HT>- http://code.google.com/p/nemerle/issues/list


Сюда не надо пока. Это вообще какая-то прямая ссылка. По идее на странице Issues стоит редирект на http://nemerle.org/bugs.

HT>2.2) Доступ на заведение багов как проще всего получить? Можно центролизовано сразу на всех указанных ресурсах (если конечно все реально используются) ?


В багтреккере нужно завести логин. Вот если захочется самому баги править, то нужно обратиться ко мне, прислать гуглевый экаунт и я добавляю и поменяю все как надо.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: [Nemerle DSL] Описание конечного автомата
От: hi_octane Беларусь  
Дата: 02.06.10 21:21
Оценка:
_>>Нижеследующий баг мы тщательно обходили , причём он очень многолик, встречается и в присваивании и в подстановке аргумента в функцию, а один раз лочились из-за него на совсем другом обьекте (со всеми вытекающими в рантайме последствиями):
_>>0001052: Compiler loose a generic type, causing a program to crash.
_>>workaround — параноидально указывать точный тип через ':' при использовании подобных иерархий и внимательно разглядывать тултип при передаче в функцию.

VD>А можно пример воспроизводящий баг?


Этот баг уже обсуждался в 2007-м
Автор: hi_octane
Дата: 01.10.07
, в том обсуждении есть пара примеров. Но тогда Дмитрий Иванков почему-то заподозрил в нём фичу и оставил на баге пометку — "фича?".

Самые часто встречающиеся проявления этого бага — из-за того что компилятор некорректно выбирает тип AnyCar[CarBase] вместо AnyCar[TDerived], даже там где пользователь указывает желаемый тип. Ну а от этой тайной подмены уже странности пляшут, да такие, что даже с отладчиком часто нихрена непонятно.
Завтра закину в SVN тесты на его проявления, вот например два из них:

using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.Console;
using System.Linq;

module Program
{
  public class CarBase //базовый класс
  {
    private static mutable globalIndex = 0;
    public index : int;
    
    public this() { globalIndex++; index = globalIndex; }
  }
  
  public class AnyCar[TDerived] : CarBase
    where TDerived : CarBase, new()
  {    
    public static Instance : TDerived = TDerived();//типа синглтон
    
    public static Impossible() : void
    {//тут вообще для неискушённого программиста странное творится - судя по коду используем статический item, но в рантайме он почему-то типа CarBase и один на два разных наследника
        WriteLine(Instance.GetType().Name + " index = " + Instance.index.ToString());//в этой строке отламывается автодополнение, но компилятор работает
    }
  }
  
  public class SmallCar : AnyCar[SmallCar] { } //первый наследник
  
  public class BigCar : AnyCar[BigCar] { } //ещё один 

  Write(car : CarBase) : void
  {
    WriteLine(car.GetType().Name);
  }
  
  Main() : void
  {       
    //первый баг, хорошо тут write, а у нас lock был :)
    Write(SmallCar.Instance);//ожидается SmallCar, получается почему-то CarBase
    Write(BigCar.Instance);//ожидается BigCar, получается опять CarBase
  
    //очень странное поведение - вызывается наследник, но реально управление передаётся в метод AnyCar[CarBase].Impossible()
    SmallCar.Impossible();    
    BigCar.Impossible();
  }
}
nemerle bug generic вывод типов
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.