Есть задача. Вполне себе автономная и довольно простая. Так что желающие могут попробовать свои сили в нетривиальном макрососторении и при этом помочь в развитии IDE для Nemerle.
Задача следующая:
Нужно реализовать макрос читающие .resx- и .settings-файлы и генерирующие соответствующие классы-обретки. Для C# генерацией оберток занимаются соответствующие CustomTool-ы (если интересно что это, то где-то на сайте есть статья про них). Немерле подобные подпорки не нужны, так как механизм макросов позволяет реализовать обертки куда интерактивнее и удобнее. Единственная загвоздка — эти макросы нужно вызвать при изменении соответствующих файлов в проекте. Для начала можно просто тупо сбрасывать всю метаинформацию (TypeTree) для проекта если в нем изменился .resx- или .settings-файл. Ну, а макрос пусть будет глобальным, что приведет к генерации оберток при загрузке дерева типов проекта. Мне подобные макросы видятся как-то так:
Эти макросы просто включим в файл Properties\AssemblyInfo.n при создании проекта и получим автоматическую поддержку генерации оберток для настроек и ресурсов (соответствующие файлы уже включаются в проекты типа WinForms).
Задача не сложная и интересная. Единственная проблема, на нее нужно некоторое время. Так что беритесь кто может и имеет желание размяться.
Я могу помочь советом на форуме, по Скайму или Мсн-у.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Есть задача: Реализовать макросы поддрежки .resx и .sett
Здравствуйте, VladD2, Вы писали:
VD>Есть задача. Вполне себе автономная и довольно простая. Так что желающие могут попробовать свои сили в нетривиальном макрососторении и при этом помочь в развитии IDE для Nemerle.
Это уже сделано?
А то у меня после майских праздников будет чуть-чуть времени...
С уважением, Анатолий Попов.
ICQ: 995-908
Re[2]: Есть задача: Реализовать макросы поддрежки .resx и .s
Здравствуйте, Aen Sidhe, Вы писали:
VD>>Есть задача. Вполне себе автономная и довольно простая. Так что желающие могут попробовать свои сили в нетривиальном макрососторении и при этом помочь в развитии IDE для Nemerle.
AS>Это уже сделано?
Ещё нет.
... << RSDN@Home 1.2.0 alpha rev. 771>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: Есть задача: Реализовать макросы поддрежки .resx и .s
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Aen Sidhe, Вы писали:
AS>>Это уже сделано? AS>>А то у меня после майских праздников будет чуть-чуть времени...
VD>Если будет нужна помощь, обращайся ко мне, не стесняйся. Фича нужная.
Спасибо, я сначала покурю доки и цикл статей в RSDN Magazine
С уважением, Анатолий Попов.
ICQ: 995-908
Re[3]: Есть задача: Реализовать макросы поддрежки .resx и .s
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Aen Sidhe, Вы писали:
AS>>Это уже сделано? AS>>А то у меня после майских праздников будет чуть-чуть времени...
VD>Если будет нужна помощь, обращайся ко мне, не стесняйся. Фича нужная.
После прочтения статьи сразу появился вопрос Я не понял как добавить тип в сборку на стадии BeforeInheritance (да и на любой другой, если честно, тоже).
Так, идея как всё реализовать есть. Примерно к выходным сделаю альфу для resx.
Здравствуйте, Aen Sidhe, Вы писали:
AS>После прочтения статьи сразу появился вопрос Я не понял как добавить тип в сборку на стадии BeforeInheritance (да и на любой другой, если честно, тоже).
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Aen Sidhe, Вы писали:
AS>>После прочтения статьи сразу появился вопрос Я не понял как добавить тип в сборку на стадии BeforeInheritance (да и на любой другой, если честно, тоже).
VD>См. метод Define из macro BuildClass () в статье Макросы Nemerle – расширенный курс (Часть 1)
Посмотрел, спасибо. Итак, наклепал простейший макрос. Когда его использую в качестве макроса-выражения всё работает. Как только переделываю в макрос-атрибут — перестаёт. Подозреваю, я опять где-то накосячил, но где — понять не могу
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");
}
}
Здравствуйте, 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();
}
}
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Тоже относится и к другим типам (например, к 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. В сообщениях об ошибках нельзя помещать концы строк. Код:
будет ни чем не хуже.
Но еще раз повторюсь... в сообщениях компилятора нельзя вставлять концы строк. Так что если хочется выдать две строки, то нужно выдать два сообщения об ошибке. Обычно второе (поясняющее) сообщение выдается в виде подсказки (hint-а):
Message.Error($"Error during processing '$path' resourse file: $e.")
AS>Куда их в репозиторий пихать? (логин/пароль у меня есть, если не прибили за давностью
Мне кажется, что это дело должно находиться в составе стандартных макросов. Самому компилятору не мешало бы пользоваться этим макросом.
AS>Не реализовано:
AS>
AS>Поддержка Custom Namespaces. Пока всё сыпется в Top Namespace. AS>
Это отдельная проблема. Сори, что не ответил по Мессенджеру. Был в отпуске.
В двух словах... Все так и есть пока что добавление типов в произвольное пространство имен не реализовано. Есть левый метод, но он (если не ошибаюсь) глючит.
Так что надо просто реализовать данную фунциональность. Сделать это проще всего путем добавления параметра в методы Define и DefineWithSource.
Задача довольно простая для того кто знаком с устройством компилятора, но как всегда все упирается в наличие свободного времени. Если хочешь, то можешь заняться ею. Задача сложная, но интересная... позволяющая понять устройство дерева типов компилятора Немерле. Со своей стороны обещаю любую теоретическую помощь.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Мне кажется, что это дело должно находиться в составе стандартных макросов. Самому компилятору не мешало бы пользоваться этим макросом.
Хорошо бы так же создать макрос для *.settings-файлов. Думаю, все будет очень похоже и даже можно (и нужно) попытаться создать общую реализацию (например, на базе дженериков и/или функций высшего порядка). Ведь разница в основном в средствах чтения данных. В прочем, setting-и должны не только читаться но и изменяться и записываться. Так что может быть обобщенная реализация и не имеет смысла.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>>Мне кажется, что это дело должно находиться в составе стандартных макросов. Самому компилятору не мешало бы пользоваться этим макросом.
VD>То есть в каталоге http://nemerle.org/svn/nemerle/trunk/macros
Пространство имен Nemerle.Rsdn.Macro, при этом, нужно заменить на Nemerle.Resources.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>ЗЫ
VD>Хорошо бы так же создать макрос для *.settings-файлов. Думаю, все будет очень похоже и даже можно (и нужно) попытаться создать общую реализацию (например, на базе дженериков и/или функций высшего порядка). Ведь разница в основном в средствах чтения данных. В прочем, setting-и должны не только читаться но и изменяться и записываться. Так что может быть обобщенная реализация и не имеет смысла.
Ой. Невнимательно посмотрел проект. Оказывается *.settings-файлы уже реализованы. Здорово!
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.