Как добраться до реального типа PExpr?
От: Константин Л. Франция  
Дата: 19.06.07 15:15
Оценка:
Допустим есть макрос, который должен принимать int:



public macro SomeMacro(start, end)
    {        
        match( start, end )
        {
            | (_ is int, _ is int ) => <[]>
            | _ => Message.FatalError("")
        }                  
    
    }


Не хочет.

Так



public macro SomeMacro(start : int, end)


хавает только литералы.

Может быть можно как-то с PExpr.TypedObject пошаманить?

Ведь инфа о реальном типе ноды аст (если там просто переменная) должна быть доступна уже на этапе компиляции?
Re: Как добраться до реального типа PExpr?
От: Иванков Дмитрий Россия  
Дата: 19.06.07 15:28
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>Допустим есть макрос, который должен принимать int:

Можно поподробнее, это должна быть константа времени компиляции или просто при несовпадении типа с int надо получить ошибку?


КЛ>Ведь инфа о реальном типе ноды аст (если там просто переменная) должна быть доступна уже на этапе компиляции?

Вообще говоря нет, пока разворачиваются макросы типизация в процессе.
Если действительно жизненно необходимо получить тип, то можно посмотреть в macros/core.n реализацию макроса lock или foreach.
Re[2]: Как добраться до реального типа PExpr?
От: Константин Л. Франция  
Дата: 19.06.07 15:50
Оценка:
Здравствуйте, Иванков Дмитрий, Вы писали:

ИД>Здравствуйте, Константин Л., Вы писали:


КЛ>>Допустим есть макрос, который должен принимать int:

ИД>Можно поподробнее, это должна быть константа времени компиляции или просто при несовпадении типа с int надо получить ошибку?

с константой все вроде и так понятно, либо явно указываем тип параметра (как в первоначальном моем посте), либо матчим с PExpr.Literal.

Надо "при несовпадении типа с int надо получить ошибку?". Причем compile-time.


КЛ>>Ведь инфа о реальном типе ноды аст (если там просто переменная) должна быть доступна уже на этапе компиляции?

ИД>Вообще говоря нет, пока разворачиваются макросы типизация в процессе.
ИД>Если действительно жизненно необходимо получить тип, то можно посмотреть в macros/core.n реализацию макроса lock или foreach.

и где взять этот core.n?

пс: вроде как ie задавал подобный вопрос, но ответа не получил
Re[3]: Как добраться до реального типа PExpr?
От: Иванков Дмитрий Россия  
Дата: 19.06.07 16:27
Оценка: 3 (1)
Здравствуйте, Константин Л., Вы писали:

КЛ>Надо "при несовпадении типа с 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 или еще какая пакость.
В принципе рабочий способ должен получиться.
Re[4]: Как добраться до реального типа PExpr?
От: Константин Л. Франция  
Дата: 19.06.07 18:57
Оценка:
Здравствуйте, Иванков Дмитрий, Вы писали:

[]

ИД>Грязный способ с ходу такой

ИД>
ИД>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 или еще какая пакость.
ИД>В принципе рабочий способ должен получиться.

быстро посмотрел, вроде как можно
Re[5]: Как добраться до реального типа PExpr?
От: Иванков Дмитрий Россия  
Дата: 19.06.07 20:12
Оценка: 3 (1)
Здравствуйте, Константин Л., Вы писали:

КЛ>Здравствуйте, Иванков Дмитрий, Вы писали:


ИД>>Грязный способ с ходу такой

ИД>>
ИД>>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 не вылез.
Re: Как добраться до реального типа PExpr?
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.06.07 20:42
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>Может быть можно как-то с PExpr.TypedObject пошаманить?


Лучше опиши реальную задачу. А то ты может оказаться, что все намного проще.

PExpr.TypedObject заполняется при типизации. Причем типизация процесс итеративный. Она может откладыватся и в PExpr.TypedObject значения не будет.

Если будет описание задачи, то можно будет подумать, что можно предложить.

Я сам пользуюсь TypedObject в StringTemplate, но у меня точно известно, что то что я типизирую имеет явное описание типа (я работаю с парметрами методов).
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Как добраться до реального типа PExpr?
От: Константин Л. Франция  
Дата: 19.06.07 20:56
Оценка:
Здравствуйте, Иванков Дмитрий, Вы писали:

[]

угу
Re[2]: Как добраться до реального типа PExpr?
От: Константин Л. Франция  
Дата: 19.06.07 21:05
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Константин Л., Вы писали:


КЛ>>Может быть можно как-то с PExpr.TypedObject пошаманить?


VD>Лучше опиши реальную задачу. А то ты может оказаться, что все намного проще.


да попробовал написать свой первый макрос (что-то типа этого здесь
Автор: FDSC
Дата: 25.05.07
), и сразу наткнулся на задание констрейнтов для параметров макроса.

Еще вопрос: почему не компилится это:



macro test( lhs, rhs )
{
   match( lhs, rhs )
   {
      | ( <[$lhs is bla-bla-bla ]>, <[$rhs is bla-bla-bla ]> ) => <[]> //это нет
      | _ => <[]>
   }

   match( lhs, rhs )
   {
      | <[$lhs is bla-bla-bla ]> => <[]> //а это - да
      | _ => <[]>
   }
}
Re[3]: Как добраться до реального типа PExpr?
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.06.07 21:30
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>да попробовал написать свой первый макрос (что-то типа этого здесь
Автор: FDSC
Дата: 25.05.07
), и сразу наткнулся на задание констрейнтов для параметров макроса.


Это не очень конкретно. Вот, например, я тут наклепал макрос в качестве примера к статье:
macro @forEx (expr, step, body)
syntax ("forEx", "(", expr, Optional ("step", step), ")", body) 
{
    def step = if (step == null) <[ 1 ]> else step;
    
    match (expr)
    {
        | <[ $firstExpr <  $maxExpr ]> with gt2 = true
        | <[ $firstExpr <= $maxExpr ]> with gt2 = false => 
            match (firstExpr)
            {
                | <[ $minExpr <  $i ]> with gt1 = true
                | <[ $minExpr <= $i ]> with gt1 = false =>
                    def gt1 = gt1;
                    def gt2 = gt2;
                    match (gt1, gt2)
                    {
                        | (false, false) => <[ for (mutable $i = $minExpr;     $i <= $maxExpr; $i += $step) $body ]>
                        | (true,  false) => <[ for (mutable $i = $minExpr + 1; $i <= $maxExpr; $i += $step) $body ]>
                        | (false, true)  => <[ for (mutable $i = $minExpr + 1; $i <  $maxExpr; $i += $step) $body ]>
                        | (true,  true)  => <[ for (mutable $i = $minExpr;     $i <  $maxExpr; $i += $step) $body ]>
                    }
                    
                | _ => Message.Error(expr.Location, $"Syntax error '$expr'"); <[ () ]>
            }

        | _ => Message.Error(expr.Location, $"Syntax error '$expr'"); <[ () ]>
        
    }

и соответственно применение:
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>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Как добраться до реального типа PExpr?
От: Константин Л. Франция  
Дата: 20.06.07 12:02
Оценка:
Здравствуйте, VladD2, Вы писали:

[]

Кароче, вот что у меня получилось после изучения 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>В общем, я не вижу смысла этого кода. Если нужно (в отладочных целях) просто ничего не делать, то просто нужно нписать () или {}. Но макрос должен что-то возвращать. Если опять таки (в отлдадочных целях) нужно вернуть пустышку, то нужно писать <[ () ]>


ок, загнался
Re[4]: Как добраться до реального типа PExpr?
От: Константин Л. Франция  
Дата: 20.06.07 13:16
Оценка:
Здравствуйте, VladD2, Вы писали:

[]

VD>
VD>macro @forEx (expr, step, body)
VD>syntax ("forEx", "(", expr, Optional ("step", step), ")", body) 
VD>{
VD>    def step = if (step == null) <[ 1 ]> else step;
    
VD>    match (expr)
VD>    {
VD>        | <[ $firstExpr <  $maxExpr ]> with gt2 = true
VD>        | <[ $firstExpr <= $maxExpr ]> with gt2 = false => 
VD[]

VD>


Что это?

[]
Re[4]: Как добраться до реального типа PExpr?
От: WolfHound  
Дата: 20.06.07 14:34
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Это не очень конкретно. Вот, например, я тут наклепал макрос в качестве примера к статье:

А можно узнать зачем такие сложности?
Почему вот так нельзя?
macro @forEx (expr, step, body)
syntax ("forEx", "(", expr, Optional ("step", step), ")", body) 
{
    def step = if (step == null) <[ 1 ]> else step;
    
    match (expr)
    {
    | <[ $minExpr <= $i <= $maxExpr ]> => <[ for (mutable $i = $minExpr;     $i <= $maxExpr; $i += $step) $body ]>
    | <[ $minExpr <  $i <= $maxExpr ]> => <[ for (mutable $i = $minExpr + 1; $i <= $maxExpr; $i += $step) $body ]>
    | <[ $minExpr <  $i <  $maxExpr ]> => <[ for (mutable $i = $minExpr + 1; $i <  $maxExpr; $i += $step) $body ]>
    | <[ $minExpr <= $i <  $maxExpr ]> => <[ for (mutable $i = $minExpr;     $i <  $maxExpr; $i += $step) $body ]>
    | _ => Message.Error(expr.Location, $"Syntax error '$expr'"); <[ () ]>
    }
}


А конструкция
                    def gt1 = gt1;
                    def gt2 = gt2;

Для меня совсем загадка.

Кстати у тебя макрос не правильный код генерит...
Нужно дибо
(false, false)
(true,  false)
(true,  true) 
(false, true)

Либо
$minExpr;    
$minExpr + 1;
$minExpr;
$minExpr + 1;
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[5]: Как добраться до реального типа PExpr?
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.06.07 14:59
Оценка:
Здравствуйте, WolfHound, Вы писали:

VD>>Это не очень конкретно. Вот, например, я тут наклепал макрос в качестве примера к статье:

WH>А можно узнать зачем такие сложности?
WH>Почему вот так нельзя?

Потому что как ты хочешь не работает. Можно сказать — баг.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Как добраться до реального типа PExpr?
От: WolfHound  
Дата: 21.06.07 15:49
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>>>Это не очень конкретно. Вот, например, я тут наклепал макрос в качестве примера к статье:

WH>>А можно узнать зачем такие сложности?
WH>>Почему вот так нельзя?

VD>Потому что как ты хочешь не работает. Можно сказать — баг.


Гм. А у меня работат.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[7]: Как добраться до реального типа PExpr?
От: Сергей Туленцев Россия http://software.tulentsev.com
Дата: 21.06.07 17:47
Оценка:
Здравствуйте, WolfHound, Вы писали:

VD>>Потому что как ты хочешь не работает. Можно сказать — баг.


WH>Гм. А у меня работат.


Если ваша программа заработала с первого раза, обратитесь к системному программисту — он исправит ошибку в компиляторе.


Давно не обновлялся, наверное?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
--
Re[8]: Как добраться до реального типа PExpr?
От: WolfHound  
Дата: 21.06.07 18:03
Оценка:
Здравствуйте, Сергей Туленцев, Вы писали:

СТ>Давно не обновлялся, наверное?

Я использую boot ревизии 7707. Вроде последний. Все работает.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[9]: Как добраться до реального типа PExpr?
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.06.07 13:57
Оценка:
Здравствуйте, WolfHound, Вы писали:

СТ>>Давно не обновлялся, наверное?

WH>Я использую boot ревизии 7707. Вроде последний. Все работает.

Значит не во всех случаях. Я в начале сделал так же, но обламался.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Как добраться до реального типа PExpr?
От: Константин Л. Франция  
Дата: 23.06.07 15:43
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, WolfHound, Вы писали:


СТ>>>Давно не обновлялся, наверное?

WH>>Я использую boot ревизии 7707. Вроде последний. Все работает.

VD>Значит не во всех случаях. Я в начале сделал так же, но обламался.


А по существу
Автор: Константин Л.
Дата: 20.06.07
есть что сказать?
Re[5]: Как добраться до реального типа PExpr?
От: Константин Л. Франция  
Дата: 23.06.07 15:47
Оценка:
Здравствуйте, Константин Л., Вы писали:

fix

КЛ>

КЛ>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);                
        
КЛ>        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()
[]
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.