Re[5]: [Nemerle] Семантический контроль над размерностями
От: Vermicious Knid  
Дата: 05.04.06 12:04
Оценка: 7 (1)
Здравствуйте, Oyster, Вы писали:

O>А ведь ты прав! Очень даже изящное решение получается, спасибо!


Удалил старое сообщение? Видимо заметил пример в конце. Ну да ладно.

O>Интересненько? А точно получится использовать унарный постфиксный (не префиксный) оператор?


Точно. Это в общем-то фича языка — нет разницы между постфиксными и префиксными операторами.

using Nemerle.English;
def yoda = true not;
def reallyObfuscated = yoda !;
def ohmy = 23 ~;


O>Кстати, в таком случае встаёт вопрос генерации макроса внутри макроса чтобы не хардкодить.


Боюсь, что генерация это слишком сложный путь. Одно дело сгенерировать код, а другое дело его скомпилировать. Можно конечно компилировать "настройки" в отдельную сборку и оттуда использовать.

Но есть идея и более простая. И макрос, и оператор можно зарегистрировать вручную через API компилятора(см. модуль MacroRegistry). Макрос это по сути экземпляр некого класса, реализовывающего интерфейс IMacro. Нужно просто написать собственную реализацию IMacro вручную(т.е. не использовать встроенную в компилятор генерацию этого класса), которая в зависимости от того как ее инициализируют будет вести себя как разные макросы(т.е. с разными именами и генерировать различный код).

Вот дамп кода(на псевдо-немерле , выглядит жутко конечно, но понять можно ) методов макро-оператора kg. Кстати стоит обратить внимание, что по сути это вполне обычный макрос, а оператором его делает атрибут сборки. В модуле LibrariesLoader есть функции которые сканируют сборку на предмет нахождения в ней макросов и таких атрибутов, и регистрируют их в MacroRegistry.

Public, Sealed, Macro, SpecialName  My.Phys.kgMacro : System.Object, Nemerle.Compiler.IMacro {
    Private, Static method My.Phys.kgMacro..cctor() : void {
    {
          def customs = typeof (kgMacro).GetCustomAttributes (false);
          foreach (in ((x is MacroUsageAttribute), customs)) my_usage = x;
          keywords = []
    }

    Public, SpecialName method My.Phys.kgMacro.get_IsInherited() : bool {
        my_usage != null && my_usage.Inherited
    }

    Public, SpecialName method My.Phys.kgMacro.get_Keywords() : list[string] {
        keywords
    }

    Public, SpecialName method My.Phys.kgMacro.get_Usage() : Nemerle.MacroUsageAttribute {
        my_usage
    }

    Public, SpecialName method My.Phys.kgMacro.get_IsTailRecursionTransparent() : bool {
        false
    }
    Public method My.Phys.kgMacro.GetName() : string {
        "kg"
    }
    Public method My.Phys.kgMacro.GetNamespace() : string {
        "My.Phys"
    }
    Public method My.Phys.kgMacro.SyntaxExtension() : 
(Nemerle.Compiler.GrammarElement * list[Nemerle.Compiler.Parsetree.SyntaxElement] 
-> list[Nemerle.Compiler.Parsetree.SyntaxElement]) {
        (null, ((Nemerle.Utility.Identity.[list[SyntaxElement], list[SyntaxElement]] () : object) 
:> list[SyntaxElement] -> list[SyntaxElement]))
    }
    Public method My.Phys.kgMacro.Run(_N_944 : Nemerle.Compiler.Typer, parms : 
list[Nemerle.Compiler.Parsetree.SyntaxElement]) : Nemerle.Compiler.Parsetree.PExpr {
        match (parms) {
              | [SyntaxElement.Expression (val)] => 
                <[ do_something_crazy_with_kg ($(val)) ]>
              | _  => 
                  def len = List.Length (parms);
                  def types = parms.ToString (", ");
Message.FatalError ("macro `" + "kg" + "' expects following list of arguments: (" + 
"PExpr" + ") got some " + len.ToString () + " parameters [" + types + "]")
        }
    }
    Public method My.Phys.kgMacro.CallTransform(trans_p : list[Nemerle.Compiler.Parsetree.PExpr]) : 
list[Nemerle.Compiler.Parsetree.SyntaxElement] {
    {
          mutable trans_res = [];
          match (trans_p) {
            | x :: trans_p => 
              {
                trans_res = SyntaxElement.Expression (x) :: trans_res;
                match (trans_p) {
                      | x :: _  => 
                        trans_res = SyntaxElement.Expression (x) :: trans_res
                      | [] => () }
              }
            | [] => ()
        };
          List.Rev (trans_res)
    }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.