Здравствуйте, VladD2, Вы писали:
VD>А можно ли как-то в генерируемом классе использовать другие макросы?
Макросы внутри кода функций однозначно использовать можно. Насчет совсем других макросов я не знаю, надо поинтересоваться на досуге.
VD>Ведь реализация свойств по полям уже реализована в макросе Nemerle.Utility.Accessor. А реализация конструктора для всех полей в макросе Record.
Record это только для публичных полей(т.е. строго говоря для описания конструкторов структур). Accessor у меня использовать не получилось. Он его почему-то не опознает. Возможно это из-за того, что он обычно выполняется на более раннем этапе компиляции, или по другим причинам. Нужно спросить разработчиков языка.
VD>Так что если бы эти макросы можно было бы задействовать, то осталось бы только сформировать класс и список полей. Если при этом вынести в универсальный модуль такую байду как выскребание описания свойств, то код такого макроса был бы совсем небольшим и весьма понятным.
В универсальный модуль можно вынести. Есть еще пара мест где код можно упростить. Собственно местами я сделал лишнее и не заметил как можно сократить составление списка свойств. Если бы Accessor работал, то код выглядел бы так:
using Nemerle.Compiler;
using Nemerle.Collections;
using Nemerle.Macros;
namespace Oyster
{
macro metaclass(className, body)
syntax ("metaclass", className, body)
{
def ctx = ImplicitCTX();
def builder = ctx.Env.Define(<[ decl: public class $(className.ToString() : usesite) {} ]>);
mutable constrParams = [];
mutable constrCode = [];
match (body)
{
| <[ { .. $props } ]> =>
foreach(<[ $(n : name) : $(t : name) ]> in props)
{
builder.Define(<[ decl:
[Nemerle.Utility.Accessor]
mutable $(n : name) : $(t : name) ;
]>);
def paramType = ctx.BindType(<[ $(t : name) ]>);
constrParams = <[ parameter: $(n : name) : $(paramType : typed) ]> :: constrParams;
constrCode = <[ this.$(n.NewName("_" + n.Id) : name) = $(n : name); ]> :: constrCode;
}
| _ => Message.FatalError($"Invalid metaclass syntax, expected properties definition, got $body");
}
builder.Define(<[ decl: public this(.. $(constrParams.Reverse())) { .. $constrCode } ]>);
builder.Compile();
<[ () ]>
}
}
А вообще-то и неупрощенный код это всего полсотни строчек. И учитывая, что он делает работу сразу трех макросов это очень хороший результат. Но насчет выноса частоиспользуемых вещей в универсальный модуль ты пожалуй прав. Я сам думал над этим неоднократно.