Здравствуйте, Oyster, Вы писали:
O>В общем, я решил попробовать написать такой макрос. Сильно не пинать — первый опыт, можно сказать.
Очень неплохо для первого опыта. Хотя и не без ляпов конечно.

Сразу становится понятно, что Nemerle достаточно простой в освоении язык.
O>Конструктор вот только пока что не создаётся (уже домой бежать надо — завтра, надеюсь...).
С конструктором вообще и параметрами функций там все не так просто. В общем я добавил создание конструктора и упростил/улучшил некоторые моменты. Вот пример того, как это все работает:
using Oyster;
using Nemerle.IO;
metaclass zuper
{
test : int;
anotherProperty : string;
}
def z = zuper(1, "crazy test");
printf("%d %s\n", z.Test, z.AnotherProperty);
Вот улучшенный код(комментировать было лень, да и код в общем недалеко ушел):
using Nemerle.Collections;
using Nemerle.Macros;
using PT = Nemerle.Compiler.Parsetree;
namespace Oyster
{
macro metaclass(className, body)
syntax ("metaclass", className, body)
{
def props = match (body) {
| <[ { .. $props } ]> =>
props.Map(fun(_) { | <[ $(n : name) : $(t : name) ]> => (n, t) })
| _ => []
};
def ctx = ImplicitCTX();
def builder = ctx.Env.Define(<[ decl: public class $(className.ToString() : usesite) {} ]>);
mutable constrParams = [] : list[PT.Fun_parm];
mutable constrCode = [] : list[PT.PExpr];
foreach((n, t) in props)
{
def prop = n.NewName("_" + n.Id);
def accessor = n.NewName(n.Id.Substring(0, 1).ToUpper() + n.Id.Substring(1));
builder.Define(<[ decl: mutable $(prop : name) : $(t : name) ; ]>);
builder.Define(
<[ decl:
public $(accessor : name) : $(t : name)
{
get { $(prop : name) }
};
]>);
def paramType = ctx.BindType(<[ $(t : name) ]>);
constrParams = <[ parameter: $(n : name) : $(paramType : typed) ]> :: constrParams;
constrCode = <[ this.$(prop : name) = $(n : name); ]> :: constrCode;
}
builder.Define(
<[ decl:
public this(.. $(constrParams.Reverse())) { .. $constrCode }
]>);
builder.Compile();
<[ () ]>
}
}