Есть задача: Реализовать макросы поддрежки .resx и .settings
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.02.08 00:30
Оценка:
Есть задача. Вполне себе автономная и довольно простая. Так что желающие могут попробовать свои сили в нетривиальном макрососторении и при этом помочь в развитии IDE для Nemerle.

Задача следующая:

Нужно реализовать макрос читающие .resx- и .settings-файлы и генерирующие соответствующие классы-обретки. Для C# генерацией оберток занимаются соответствующие CustomTool-ы (если интересно что это, то где-то на сайте есть статья про них). Немерле подобные подпорки не нужны, так как механизм макросов позволяет реализовать обертки куда интерактивнее и удобнее. Единственная загвоздка — эти макросы нужно вызвать при изменении соответствующих файлов в проекте. Для начала можно просто тупо сбрасывать всю метаинформацию (TypeTree) для проекта если в нем изменился .resx- или .settings-файл. Ну, а макрос пусть будет глобальным, что приведет к генерации оберток при загрузке дерева типов проекта. Мне подобные макросы видятся как-то так:
[assembly: Nemerle.Resources(relative\path_to\Resources.resx)]
[assembly: Nemerle.Settings(relative\path_to\Settings.settings)]

Эти макросы просто включим в файл Properties\AssemblyInfo.n при создании проекта и получим автоматическую поддержку генерации оберток для настроек и ресурсов (соответствующие файлы уже включаются в проекты типа WinForms).

Задача не сложная и интересная. Единственная проблема, на нее нужно некоторое время. Так что беритесь кто может и имеет желание размяться.
Я могу помочь советом на форуме, по Скайму или Мсн-у.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Есть задача: Реализовать макросы поддрежки .resx и .sett
От: Aen Sidhe Россия Просто блог
Дата: 25.04.08 18:52
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Есть задача. Вполне себе автономная и довольно простая. Так что желающие могут попробовать свои сили в нетривиальном макрососторении и при этом помочь в развитии IDE для Nemerle.


Это уже сделано?
А то у меня после майских праздников будет чуть-чуть времени...
С уважением, Анатолий Попов.
ICQ: 995-908
Re[2]: Есть задача: Реализовать макросы поддрежки .resx и .s
От: IT Россия linq2db.com
Дата: 26.04.08 18:57
Оценка: +1
Здравствуйте, Aen Sidhe, Вы писали:

VD>>Есть задача. Вполне себе автономная и довольно простая. Так что желающие могут попробовать свои сили в нетривиальном макрососторении и при этом помочь в развитии IDE для Nemerle.


AS>Это уже сделано?


Ещё нет.
... << RSDN@Home 1.2.0 alpha rev. 771>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: Есть задача: Реализовать макросы поддрежки .resx и .s
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.05.08 10:11
Оценка:
Здравствуйте, Aen Sidhe, Вы писали:

AS>Это уже сделано?

AS>А то у меня после майских праздников будет чуть-чуть времени...

Если будет нужна помощь, обращайся ко мне, не стесняйся. Фича нужная.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Есть задача: Реализовать макросы поддрежки .resx и .s
От: Aen Sidhe Россия Просто блог
Дата: 04.05.08 10:13
Оценка:
Здравствуйте, VladD2, Вы писали:

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


AS>>Это уже сделано?

AS>>А то у меня после майских праздников будет чуть-чуть времени...

VD>Если будет нужна помощь, обращайся ко мне, не стесняйся. Фича нужная.


Спасибо, я сначала покурю доки и цикл статей в RSDN Magazine
С уважением, Анатолий Попов.
ICQ: 995-908
Re[3]: Есть задача: Реализовать макросы поддрежки .resx и .s
От: Aen Sidhe Россия Просто блог
Дата: 13.05.08 11:13
Оценка:
Здравствуйте, VladD2, Вы писали:

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


AS>>Это уже сделано?

AS>>А то у меня после майских праздников будет чуть-чуть времени...

VD>Если будет нужна помощь, обращайся ко мне, не стесняйся. Фича нужная.


После прочтения статьи сразу появился вопрос Я не понял как добавить тип в сборку на стадии BeforeInheritance (да и на любой другой, если честно, тоже).

Так, идея как всё реализовать есть. Примерно к выходным сделаю альфу для resx.
С уважением, Анатолий Попов.
ICQ: 995-908
nemerle macro
Re[4]: Есть задача: Реализовать макросы поддрежки .resx и .s
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.05.08 13:06
Оценка:
Здравствуйте, Aen Sidhe, Вы писали:

AS>После прочтения статьи сразу появился вопрос Я не понял как добавить тип в сборку на стадии BeforeInheritance (да и на любой другой, если честно, тоже).


См. метод Define из macro BuildClass () в статье Макросы Nemerle – расширенный курс (Часть 1)
Автор(ы): Чистяков Влад (VladD2)
Дата: 24.04.2007
Статься задумана как углубленное описание самой малоосвещенной части языка программирования Nemerle – его макросистемы. В первой части статьи будет описан процесс компиляции и освещены его особенности. Рассказано о том, что же такое макросы, каких типов они бывают, и как с ними бороться.
Во второй части будут даны примеры каждого из видов макросов и советы, где и как их применять.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
nemerle macro
Re[5]: Есть задача: Реализовать макросы поддрежки .resx и .s
От: Aen Sidhe Россия Просто блог
Дата: 13.05.08 21:19
Оценка:
Здравствуйте, VladD2, Вы писали:

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


AS>>После прочтения статьи сразу появился вопрос Я не понял как добавить тип в сборку на стадии BeforeInheritance (да и на любой другой, если честно, тоже).


VD>См. метод Define из macro BuildClass () в статье Макросы Nemerle – расширенный курс (Часть 1)
Автор(ы): Чистяков Влад (VladD2)
Дата: 24.04.2007
Статься задумана как углубленное описание самой малоосвещенной части языка программирования Nemerle – его макросистемы. В первой части статьи будет описан процесс компиляции и освещены его особенности. Рассказано о том, что же такое макросы, каких типов они бывают, и как с ними бороться.
Во второй части будут даны примеры каждого из видов макросов и советы, где и как их применять.


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

Сборка с макросом:
using Nemerle.Compiler;
using Nemerle;
using System.IO.Path;
using ResXReader = System.Resources.ResXResourceReader;

namespace Nemerle.Rsdn.Macro
{
  //[MacroUsage(MacroPhase.BeforeInheritance, MacroTargets.Assembly)]
  public macro Resource(path : string)
  {
    def ctx = Nemerle.Macros.ImplicitCTX ();
    when(ctx.IsMainPass)
      using(def reader = ResXReader(path))
      {
        def builder = ctx.Env.Define (
        <[ decl:
          internal module $(GetFileNameWithoutExtension(path) : usesite)
          {
            
          }
        ]>);
        builder.Compile();
      }
    <[ () ]>
  }
}


Тестовое приложение:
using System;
using System.Console;
using Nemerle.Utility;
//[assembly: Nemerle.Rsdn.Macro.Resource("Resource1.resx")]

module Program
{
  Main() : void
  {
    Nemerle.Rsdn.Macro.Resource("Resource1.resx");
  }
}
С уважением, Анатолий Попов.
ICQ: 995-908
nemerle macro
Re[6]: Есть задача: Реализовать макросы поддрежки .resx и .s
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.05.08 11:19
Оценка:
Здравствуйте, Aen Sidhe, Вы писали:

AS>Посмотрел, спасибо. Итак, наклепал простейший макрос. Когда его использую в качестве макроса-выражения всё работает. Как только переделываю в макрос-атрибут — перестаёт. Подозреваю, я опять где-то накосячил, но где — понять не могу


Закоментируй строчку:

AS> when(ctx.IsMainPass)


В макроатрибутах она не имеет смысла. По идее IsMainPass должен выдавать true внутри макроатрибута, но почему-то во время компиляции он это не делает.

ЗЫ

Кстати чтобы упростить себе жизнь, код макросов лучше переносить в отдельный модуль. В нем будет работать интеллисенс.
Вот, например, код тестового проекта что я создал.
Макрос:
using Nemerle;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;
using System.Console;
using System.IO.Path;
using ResXReader = System.Resources.ResXResourceReader;

namespace AssemblyLevelMacro
{
  [MacroUsage(MacroPhase.BeforeInheritance, MacroTargets.Assembly)]
  public macro Resource(path : string)
  {
    ResourceHelper.Resource(path, Nemerle.Macros.ImplicitCTX(), Nemerle.Macros.Manager());
  }
  
  public module ResourceHelper
  {
    public Resource(path : string, typer : Typer, manager : ManagerClass) : void
    {
      _ = manager;
      def ctx = typer;
      //System.Diagnostics.Trace.Assert(false); // А так можно отлаживать компилятор :). Жмешь во время компиляции на Retry и ты внутри этого кода.
      _ = ctx.IsMainPass;
      //when(ctx.IsMainPass)
        using(def reader = ResXReader(path))
        {
          def builder = ctx.Env.Define (
          <[ decl:
            internal module $(GetFileNameWithoutExtension(path) : usesite)
            {
              public Test() : void { WriteLine("Привет из мира макроатрибутов! ;)") }
            }
          ]>);
          builder.Compile();
        }
    }
  }
}

Код теста:
using System;
using System.Console;
using Nemerle.Utility;
using AssemblyLevelMacro;

[assembly: AssemblyLevelMacro.Resource(@"c:\x.txt")]

module Program
{
  Main() : void
  {
    x.Test();
    _ = ReadLine();
  }
}
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
nemerle macro макроатрибут macroattribute
Re: .resx
От: Aen Sidhe Россия Просто блог
Дата: 19.05.08 17:10
Оценка: 144 (4)
Доброго времени суток.

Пинайте.

Хелпер:
using Nemerle;
using Nemerle.Collections;
using Nemerle.Compiler;

using System.IO.Path;
using DictionaryEntry = System.Collections.DictionaryEntry;
using ResXReader = System.Resources.ResXResourceReader;

namespace Nemerle.Rsdn.Macro
{
  internal module MacroHelper
  {
    public Resource(path : string, _ : string, context : Typer) : void
    {
      def types = Hashtable();
      def getType(name)
      {
        when (!types.ContainsKey(name))
          types.Add(name, context.Manager.Lookup(name).GetMemType());
          
        types[name];
      }
      
      using(def reader = ResXReader(path))
      {
        def className = GetFileNameWithoutExtension(path);
        def builder = context.Env.Define (
        <[ decl:
          internal module  $(className: usesite)
          {
            private mutable _resourceManager : $(getType("System.Resources.ResourceManager") : typed);
            public ResourceManager : $(getType("System.Resources.ResourceManager") : typed)
            {
              get 
              {
                when (object.ReferenceEquals(_resourceManager, null)) 
                {
                    def temp 
                      : $(getType("System.Resources.ResourceManager") : typed) 
                      = System.Resources.ResourceManager($(className : string), typeof($(className: usesite)).Assembly);
                      
                    _resourceManager = temp;
                }
                _resourceManager;
              }
            }
            
            private mutable _resourceCulture : $(getType("System.Globalization.CultureInfo") : typed);
            public ResourceCulture : $(getType("System.Globalization.CultureInfo") : typed)
            {
              get { _resourceCulture; } 
              set { _resourceCulture = value; }
            }
          }
        ]>);
        
        foreach(d :> DictionaryEntry in reader)
        {
          def typeName = d.Value.GetType().FullName;
          def key = d.Key.ToString();
          
          match(d.Value)
          {
            | _ is string => 
                builder.Define(
                <[ decl: 
                  public $(d.Key.ToString() : usesite) : $(getType(typeName) : typed)
                  {
                    get
                    {
                      ResourceManager.GetString($(key : string), _resourceCulture);
                    }
                  }
                ]>);
            | _ => 
                builder.Define(
                <[ decl: 
                  public $(d.Key.ToString() : usesite) : $(getType(typeName) : typed)
                  {
                    get
                    {
                      def temp = ResourceManager.GetObject($(key : string), _resourceCulture);
                      temp :> $(getType(typeName) : typed);
                    }
                  }
                ]>);
          }
        }
        
        builder.Compile();
      }
    }
  }
}


Макрос:

namespace Nemerle.Rsdn.Macro
{
  [MacroUsage(MacroPhase.BeforeInheritance, MacroTargets.Assembly)]
  public macro Resource(path : string, @namespace : string = null)
  {
    MacroHelper.Resource(path, @namespace, Nemerle.Macros.ImplicitCTX());
  }
}


Использование (пока обработки ошибок нет — Resourse1.resx должен быть в папке с этим файлом):
using System;
using System.Console;
using Nemerle.Utility;

[assembly: Nemerle.Rsdn.Macro.Resource("Resource1.resx")]

module Program
{
  Main() : void
  {
    WriteLine(typeof(Resource1).FullName);
    _ = ReadKey();
  }
}
С уважением, Анатолий Попов.
ICQ: 995-908
Re: Макросы поддрежки .resx и .settings
От: Aen Sidhe Россия Просто блог
Дата: 22.05.08 20:49
Оценка: 96 (1)
Доброго времени суток.

Бета обоих макросов с поддержкой обработки ошибок.

здесь (~300 кб)

В архиве проект с макросами, тестовый проект с различными ресурсами и сеттингами.

Куда их в репозиторий пихать? (логин/пароль у меня есть, если не прибили за давностью

Не реализовано:

С уважением, Анатолий Попов.
ICQ: 995-908
.net nemerle macro resx settings
Re[2]: Макросы поддрежки .resx и .settings
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.06.08 15:09
Оценка:
Здравствуйте, Aen Sidhe, Вы писали:

Несколько замечаний...

1. Зачем каждый раз вызывать:
>$(getType("System.Resources.ResourceManager")
дублируя код? Лучше один раз объявить переменную и использовать ее.
def resManType = getType("System.Resources.ResourceManager");
private mutable _resourceManager : $(resManType : typed);
public ResourceManager : $(resManType : typed)
{
  get 
  {
    when (object.ReferenceEquals(_resourceManager, null)) 
    {
        def temp : $(resManType : typed) 
          = System.Resources.ResourceManager($(className : string), typeof($(className: usesite)).Assembly);

Тоже относится и к другим типам (например, к CultureInfo).

2. На счет пути. Если я правильно все понял, то путь получается относительно текущего каталога. Это неправильно.
Надо вычислять путь относительно файла в котором описан вызов макроса. Получить путь к можно через локешон. Для этого макрос нужно изменит примерно следующим образом:
using System.IO.Path;
...
  [MacroUsage(MacroPhase.BeforeInheritance, MacroTargets.Assembly)]
  public macro Resource(path : PExpr, @namespace : string = null, @public : bool = false)
  {
    match (path)
    {
      | PExpr.Literal(Literal.String(val)) =>
        def fullPath = Combine(GetDirectoryName(path.Location.File), val);
        ResourceHelper.Resource(fullPath, @namespace, @public, Nemerle.Macros.ImplicitCTX())

      | _ =>  Message.Error ("The first argument of Resource macro should be string contains relative "
                             "(from file which contains this macro) or full path to resource file.");
    }
    ;
  }

Естествнно, что данный match можно поместить ResourceHelper.Resource().

3. В сообщениях об ошибках нельзя помещать концы строк. Код:
Message.Error(string.Format($"$path isn't valid resource file.{0}$e", System.Environment.NewLine));

приведет к проблемам при работе из под интеграции.

Ну, и уж совсем не ясно зачем вообще нужно использовать в данном случае string.Format (тем более вместе с $-строкой). Тоже самое может выглядеть так:
Message.Error($"$path isn't valid resource file.$(System.Environment.NewLine)$e");

К тому же практически все средства вывода информации прекрасно работают с одним лишь \n. Так что так:
Message.Error($"$path isn't valid resource file.\n$e");

будет ни чем не хуже.
Но еще раз повторюсь... в сообщениях компилятора нельзя вставлять концы строк. Так что если хочется выдать две строки, то нужно выдать два сообщения об ошибке. Обычно второе (поясняющее) сообщение выдается в виде подсказки (hint-а):
Message.Error($"'$path' isn't valid resource file.");
Message.Hint(e);

В прочем, в данном случае лучше как-то так:
Message.Error($"Error during processing '$path' resourse file: $e.")



AS>Куда их в репозиторий пихать? (логин/пароль у меня есть, если не прибили за давностью


Мне кажется, что это дело должно находиться в составе стандартных макросов. Самому компилятору не мешало бы пользоваться этим макросом.

AS>Не реализовано:


AS>

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

Так что надо просто реализовать данную фунциональность. Сделать это проще всего путем добавления параметра в методы Define и DefineWithSource.

Задача довольно простая для того кто знаком с устройством компилятора, но как всегда все упирается в наличие свободного времени. Если хочешь, то можешь заняться ею. Задача сложная, но интересная... позволяющая понять устройство дерева типов компилятора Немерле. Со своей стороны обещаю любую теоретическую помощь.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Макросы поддрежки .resx и .settings
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.06.08 15:16
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Мне кажется, что это дело должно находиться в составе стандартных макросов. Самому компилятору не мешало бы пользоваться этим макросом.


То есть в каталоге http://nemerle.org/svn/nemerle/trunk/macros

ЗЫ

Хорошо бы так же создать макрос для *.settings-файлов. Думаю, все будет очень похоже и даже можно (и нужно) попытаться создать общую реализацию (например, на базе дженериков и/или функций высшего порядка). Ведь разница в основном в средствах чтения данных. В прочем, setting-и должны не только читаться но и изменяться и записываться. Так что может быть обобщенная реализация и не имеет смысла.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Макросы поддрежки .resx и .settings
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.06.08 15:19
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>>Мне кажется, что это дело должно находиться в составе стандартных макросов. Самому компилятору не мешало бы пользоваться этим макросом.


VD>То есть в каталоге http://nemerle.org/svn/nemerle/trunk/macros


Пространство имен Nemerle.Rsdn.Macro, при этом, нужно заменить на Nemerle.Resources.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Макросы поддрежки .resx и .settings
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.06.08 16:17
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>ЗЫ


VD>Хорошо бы так же создать макрос для *.settings-файлов. Думаю, все будет очень похоже и даже можно (и нужно) попытаться создать общую реализацию (например, на базе дженериков и/или функций высшего порядка). Ведь разница в основном в средствах чтения данных. В прочем, setting-и должны не только читаться но и изменяться и записываться. Так что может быть обобщенная реализация и не имеет смысла.


Ой. Невнимательно посмотрел проект. Оказывается *.settings-файлы уже реализованы. Здорово!
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Макросы поддрежки .resx и .settings
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.06.08 16:21
Оценка:
Здравствуйте, Aen Sidhe, Вы писали:

getType(name) стоит вынести в метод, так как он дублируется в двух файлах.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Макросы поддрежки .resx и .settings
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.06.08 16:27
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>getType(name) стоит вынести в метод, так как он дублируется в двух файлах.


Кстати его лучше реализовать так:
def getType(name)
{
  match (types.TryGetValue(name))
  {
    | (value, true) => value
    | _ => 
      def value = context.Manager.Lookup(name).GetMemType();
      types.Add(name, value);
      value
  }
}


Код будет практически аналогичный, но работать он будет быстрее, так как не будет лишних поисков по хэш-таблице.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Макросы поддрежки .resx и .settings
От: Aen Sidhe Россия Просто блог
Дата: 04.06.08 16:45
Оценка:
Здравствуйте, VladD2, Вы писали:

Ок. Займусь на следующих выходных — пока нет времени
С уважением, Анатолий Попов.
ICQ: 995-908
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.