Здравствуйте, eao197, Вы писали:
E>Может не нужно сразу сложную, а проще что-нибудь, знакомое публике? Например, вот эта задачаАвтор: AndrewVK
Дата: 13.07.05
.
E>Причем интересно как с парсингом XML-я (может быть даже в compile-time), так и создание специализированного DSL на макросах специально для этой задачи.
В общем, я решил попробовать написать такой макрос. Сильно не пинать — первый опыт, можно сказать.
Макрос генерит класс в compile-time в соответствии с постановкой задачи. Конструктор вот только пока что не создаётся (уже домой бежать надо — завтра, надеюсь...). Используется макрос вот так:
using Oyster;
metaclass TestClass {
prop1 : int;
prop2 : string
}
Код макроса (повторяю — писать на Nemerle я пока не умею, так что сильно не ругайте):
using Nemerle.Collections;
namespace Oyster
{
macro metaclass(className, body)
syntax ("metaclass", className, body)
{
// Тут я зачем-то вытаскиваю идентификатор, а потом его снова вставляю в AST.
// Криво (?), но как иначе - не знаю
def className = match (className) { | <[ $(x : name) ]> => x };
// Разбираем "свойства"
def props = match (body) {
| <[ { .. $props } ]> => List.Map(props, fun(prop) { | <[ $(n : name) : $(t : name) ]> => (n, t) })
| _ => []
};
// http://nemerle.org/Defining_types_from_inside_macros
def ctx = Nemerle.Macros.ImplicitCTX();
def builder = ctx.Env.Define(<[ decl: public class $(className : name) {} ]>);
// Добавляем поля для начала.
// Если я тут ничего не верну, то компилятор чего-то на меня обидится :(
List.ForAll(props, fun(n, t) { builder.Define(<[ decl: mutable $(n.NewName("_" + n.Id) : name) : $(t : name) ; ]>); true });
// Добавляем свойства
List.ForAll(props, fun(n, t) {
builder.Define(
<[ decl:
public $(n.NewName(n.Id.Substring(0, 1).ToUpper() + n.Id.Substring(1)) : name) : $(t : name)
{
get { $(n.NewName("_" + n.Id) : name) }
};
]>);
true });
// Добавляем конструктор
// TODO
builder.Compile();
<[ () ]>
}
}