Здравствуйте, Константин Л., Вы писали:
КЛ>Допустим есть макрос, который должен принимать 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>Значит не во всех случаях. Я в начале сделал так же, но обламался.