Здравствуйте, Константин Л., Вы писали:
КЛ>Допустим есть макрос, который должен принимать int:
Можно поподробнее, это должна быть константа времени компиляции или просто при несовпадении типа с int надо получить ошибку?
КЛ>Ведь инфа о реальном типе ноды аст (если там просто переменная) должна быть доступна уже на этапе компиляции?
Вообще говоря нет, пока разворачиваются макросы типизация в процессе.
Если действительно жизненно необходимо получить тип, то можно посмотреть в macros/core.n реализацию макроса lock или foreach.
Здравствуйте, Иванков Дмитрий, Вы писали:
ИД>Здравствуйте, Константин Л., Вы писали:
КЛ>>Допустим есть макрос, который должен принимать int: ИД>Можно поподробнее, это должна быть константа времени компиляции или просто при несовпадении типа с int надо получить ошибку?
с константой все вроде и так понятно, либо явно указываем тип параметра (как в первоначальном моем посте), либо матчим с PExpr.Literal.
Надо "при несовпадении типа с int надо получить ошибку?". Причем compile-time.
КЛ>>Ведь инфа о реальном типе ноды аст (если там просто переменная) должна быть доступна уже на этапе компиляции? ИД>Вообще говоря нет, пока разворачиваются макросы типизация в процессе. ИД>Если действительно жизненно необходимо получить тип, то можно посмотреть в macros/core.n реализацию макроса lock или foreach.
и где взять этот core.n?
пс: вроде как ie задавал подобный вопрос, но ответа не получил
Здравствуйте, Константин Л., Вы писали:
КЛ>Надо "при несовпадении типа с int надо получить ошибку?". Причем compile-time.
Простой вариант — сделать некую конструкцию, которая не скомпилируется для не int.
Скажем просто в генерируемом коде сделать приведение/указание типа
macro f(x)
{
<[ _ = $x : int ]>
}
хотя не совсем то, тут проверяется только приводимость, а не совпадение.
Грязный способ с ходу такой
macro f (x)
{
<[
{ _ = $x : int; //x приводится к int
mutable y;
_ = y == $x; //тип y теперь совпадает с типом x, чистый хак =)
y = 1 : int; //int приводится к x
}
]>
}
Над красивым надо подумать, может быть удастся обойтись без большого шаманства с типизацией (сложный это процесс) и странных конструкций
КЛ>и где взять этот core.n?
В исходниках компилятора, прямая ссылка
В макросе lock как раз проверяется что лочится класс, а не void, int или еще какая пакость.
В принципе рабочий способ должен получиться.
ИД>macro f (x)
ИД>{
ИД> <[
ИД> { _ = $x : int; //x приводится к int
ИД> mutable y;
ИД> _ = y == $x; //тип y теперь совпадает с типом x, чистый хак =)
ИД> y = 1 : int; //int приводится к x
ИД> }
ИД> ]>
ИД>}
ИД>
вот тут не понял,
1. y == $x. Вроде как просто сравниваются значения?
2. _ = — результат сравнения?
Почему вдруг y должен совпадать с типом х
ИД>Над красивым надо подумать, может быть удастся обойтись без большого шаманства с типизацией (сложный это процесс) и странных конструкций
КЛ>>и где взять этот core.n?
ИД>В исходниках компилятора, прямая ссылка ИД>В макросе lock как раз проверяется что лочится класс, а не void, int или еще какая пакость. ИД>В принципе рабочий способ должен получиться.
Здравствуйте, Константин Л., Вы писали:
КЛ>Здравствуйте, Иванков Дмитрий, Вы писали:
ИД>>Грязный способ с ходу такой ИД>>
ИД>>macro f (x)
ИД>>{
ИД>> <[
ИД>> { _ = $x : int; //x приводится к int
ИД>> mutable y;
ИД>> _ = y == $x; //тип y теперь совпадает с типом x, чистый хак =)
ИД>> y = 1 : int; //int приводится к x
ИД>> }
ИД>> ]>
ИД>>}
ИД>>
КЛ>вот тут не понял,
КЛ>Почему вдруг y должен совпадать с типом х
Потому что это хак =)
Работает примерно так:
1) x приводитя к int
2) для оператора == и != вывод типов более агрессивен, т.е сразу полагаем что x и y одного (еще неизвестного) типа
3) int приводится к x, т.е. и x и y — int
Полагаться на это не стоит =)
КЛ>1. y == $x. Вроде как просто сравниваются значения?
Да, просто чтобы сказать, что есть оператор ==
КЛ>2. _ = — результат сравнения?
_ = ... — вычислить ... и "присвоить в никуда", т.е. игнорировать, это чтобы warning про неиспользованный bool не вылез.
Здравствуйте, Константин Л., Вы писали:
КЛ>Может быть можно как-то с PExpr.TypedObject пошаманить?
Лучше опиши реальную задачу. А то ты может оказаться, что все намного проще.
PExpr.TypedObject заполняется при типизации. Причем типизация процесс итеративный. Она может откладыватся и в PExpr.TypedObject значения не будет.
Если будет описание задачи, то можно будет подумать, что можно предложить.
Я сам пользуюсь TypedObject в StringTemplate, но у меня точно известно, что то что я типизирую имеет явное описание типа (я работаю с парметрами методов).
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Константин Л., Вы писали:
КЛ>>Может быть можно как-то с PExpr.TypedObject пошаманить?
VD>Лучше опиши реальную задачу. А то ты может оказаться, что все намного проще.
да попробовал написать свой первый макрос (что-то типа этого здесь
forEx (0 <= i < 10 step 2)
forEx (0 <= k <= 2)
WriteLine($"i=$i k=$k");
Можешь на его примере объяснить, что ты хотел бы получить?
КЛ>Еще вопрос: почему не компилится это:
КЛ>
КЛ>macro test( lhs, rhs )
КЛ>{
КЛ> match( lhs, rhs )
КЛ> {
КЛ> | ( <[$lhs is bla-bla-bla ]>, <[$rhs is bla-bla-bla ]> ) => <[]> // это попытка возвратить пустоту
КЛ> | _ => <[]>
КЛ> } // причем значение не испоьзуется. match в дамнном случае выражение!
КЛ> match( lhs, rhs )
КЛ> {
КЛ> | <[$lhs is bla-bla-bla ]> => <[]> // и здесь ерунда.
КЛ> | _ => <[]>
КЛ> }
КЛ>}
КЛ>
В общем, я не вижу смысла этого кода. Если нужно (в отладочных целях) просто ничего не делать, то просто нужно нписать () или {}. Но макрос должен что-то возвращать. Если опять таки (в отлдадочных целях) нужно вернуть пустышку, то нужно писать <[ () ]>
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Кароче, вот что у меня получилось после изучения lockMacro:
namespace MacroLibrary1
{
public macro MyTestMacro(start, end, body)
syntax ("from", start, "to", end, body)
{
def typer = Nemerle.Macros.ImplicitCTX() : Nemerle.Compiler.Typer;
def ts = typer.TypeExpr(start);
def te = typer.TypeExpr(end);
//KL: for help
//def ts = typer.TypeExpr(start) : Nemerle.Compiler.Typedtree.TExpr;
//def tyVar = ts.Type : Nemerle.Compiler.TyVar;
//def hint = tyVar.Hint : option[MType];
//def startTypeInfo = hint.Value.TypeInfo;
//def endTypeInfo = typer.TypeExpr(end).Type.Hint.Value.TypeInfo;
//def endType = endTypeInfo.SystemType;
typer.DelayMacro( fun (fail_loud)
{
match (ts.Type.Hint, te.Type.Hint)
{
| (Some(Nemerle.Compiler.MType.Class(cs, _)), Some(Nemerle.Compiler.MType.Class(ce, _)))
when( !cs.IsValueType && !ce.IsValueType ) =>
when (fail_loud)
Message.Error (start.Location, $"'$start, $end' is not a reference type as required by the lock expression");
None()
| (None, _) => when (fail_loud)
Message.Error (start.Location, "compiler was unable to analyze type start,end");
None()
| (_, None) => when (fail_loud)
Message.Error (start.Location, "compiler was unable to analyze type start,end");
None()
| _ =>
def startType = ts.Type.Hint.Value.TypeInfo.SystemType;
def endType = te.Type.Hint.Value.TypeInfo.SystemType;
when( startType.Equals(typeof(int)) && endType.Equals(typeof(int)) )
{
def result =
<[
when( $start >= $end ) throw System.ArgumentException();
for (mutable var = $start; var <= $end; var++)
{
$body
}
]>;
Nemerle.Imperative.Return( Some( result ) );
}
Message.Error (start.Location, "start & end must be System.Int32");
None()
}
});
}
}
module Program
{
Main() : void
{
def a = [1,2];
def func() { 10; };
from 1 to 10 //ok
{
WriteLine("Hi!");
}
def i = 10;
from 1 to i //ok
{
WriteLine("Hi!");
}
from 1 to a //Errors: start & end must be System.Int32; typing fails on delayed macro
{
WriteLine("Hi!");
}
from 1 to func //internal compiler error: got some unknown exception of type System.NullReferenceException
{
WriteLine("Hi!");
}
from 1 to func() //ok
{
WriteLine("Hi!");
}
}
}
Похоже, что выделенная ветка вообще никогда не вызывается.
КЛ>>Еще вопрос: почему не компилится это:
[]
VD>В общем, я не вижу смысла этого кода. Если нужно (в отладочных целях) просто ничего не делать, то просто нужно нписать () или {}. Но макрос должен что-то возвращать. Если опять таки (в отлдадочных целях) нужно вернуть пустышку, то нужно писать <[ () ]>
Здравствуйте, VladD2, Вы писали:
VD>Это не очень конкретно. Вот, например, я тут наклепал макрос в качестве примера к статье:
А можно узнать зачем такие сложности?
Почему вот так нельзя?
Здравствуйте, WolfHound, Вы писали:
VD>>Это не очень конкретно. Вот, например, я тут наклепал макрос в качестве примера к статье: WH>А можно узнать зачем такие сложности? WH>Почему вот так нельзя?
Потому что как ты хочешь не работает. Можно сказать — баг.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>>>Это не очень конкретно. Вот, например, я тут наклепал макрос в качестве примера к статье: WH>>А можно узнать зачем такие сложности? WH>>Почему вот так нельзя?
VD>Потому что как ты хочешь не работает. Можно сказать — баг.
Гм. А у меня работат.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, WolfHound, Вы писали:
СТ>>>Давно не обновлялся, наверное? WH>>Я использую boot ревизии 7707. Вроде последний. Все работает.
VD>Значит не во всех случаях. Я в начале сделал так же, но обламался.
КЛ>Кароче, вот что у меня получилось после изучения lockMacro:
КЛ>
[skipped]
КЛ> def startType = ts.Type.Hint.Value.TypeInfo.SystemType;
КЛ> def endType = te.Type.Hint.Value.TypeInfo.SystemType;
КЛ> when( startType.Equals(typeof(int)) && endType.Equals(typeof(int)) )
[skipped]
КЛ> def func() { 10; };
КЛ> from 1 to func //internal compiler error: got some unknown exception of type System.NullReferenceException
КЛ> {
КЛ> WriteLine("Hi!");
КЛ> }
[skipped]
КЛ>
"ICE" вылезает потому что te.Type.Hint.Value.TypeInfo == null (знать не хочу почему )
В то время как te.Type.Hint.Value.SystemType содержит адекватное значение, а также кажется есть и повыше в иерархии такая информация.
Подумалось что в такие кишки залезать не стоит, а стоит лишь потребовать совпадения типов, во как
using Nemerle.Utility;
using Nemerle.Compiler;
namespace MacroLibrary1
{
public macro MyTestMacro(start, end, body)
syntax ("from", start, "to", end, body)
{
def typer = Nemerle.Macros.ImplicitCTX() : Nemerle.Compiler.Typer;
def ts = typer.TypeExpr(start);
def te = typer.TypeExpr(end);
when (!ts.Type.Unify (Nemerle.Macros.Manager ().InternalType.Int32))
Message.Error ("Need int for start");
when (!te.Type.Unify (Nemerle.Macros.Manager ().InternalType.Int32))
Message.Error ("Need int for end");
<[
when( $start >= $end )
throw System.ArgumentException();
for (mutable var = $start; var <= $end; var++) {
$body
}
]>;
}
}
Здравствуйте, Константин Л., Вы писали:
КЛ>а как их можно отлаживать, кроме как аттачиться к ncc в процессе компиляции macro assembly?
Компиляция сборки макроса как раз не при чем, разве что стоит с ключиком -g собирать макрос.
А дальше собственно надо аттачится к ncc в процессе компиляции основного приложения, иначе никак, макросы с компилятором взаимодействую очень тесно.
Ну и там как-то добавить в референсы сборку с макросом чтоли, в общем если все сложится, то можно и брейкпойнты в макросе ставить и в watch что-то будет видно
А вот как лучше всего подцеплятся к ncc не знаю, в форуме интеграции все еще не ответили, точно описать шаманства с которыми работаю не смогу
(сейчас есть симлинк папки с библиотеками компилера в другую, к параметрам ncc добавлен -nostdmacros -r symlink\Nemerle.Macros.dll, как-то так выглядит мой винегрет)
Здравствуйте, Константин Л., Вы писали:
КЛ>а как их можно отлаживать, кроме как аттачиться к ncc в процессе компиляции macro assembly?
1. Прописать в качестве отлаживаемого ехе-шника ncc.exe, задать ему в качестве параметров файл (*.n) использующий макрос и подключить сборку с макросом. Все это подробно описано в Макросы Nemerle – расширенный курс (Часть 1)
Здравствуйте, WolfHound, Вы писали:
WH>А конструкция WH>
WH> def gt1 = gt1;
WH> def gt2 = gt2;
WH>
WH>Для меня совсем загадка.
Это в отладочных целях. Такой прием позволяет видеть значения переменных в отладчике. Дело в том, что там появляется замыкание и переменные альфа-переименовываются, а такой прием позволяет создать локальные перменные с исходными именами. Джит в релизе из выкидывает.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>PExpr.TypedObject заполняется при типизации. Причем типизация процесс итеративный. Она может откладыватся и в PExpr.TypedObject значения не будет.
Я это дело немножко подкрутил, теперь по идее это поле должно быть заполнено даже после отложенной типизации. Но понятное дело на 100% уверенности нет.
Если нам не помогут, то мы тоже никого не пощадим.