WarCraft 3: 13. Текстовые макросы

vJass

Давайте признаем, порой мы мы хотим иметь в распоряжении языка Jass достаточно комплексные возможности, но зачастую, все что нам необходимо, это копирование-вставка-замена кусков кода. По этой причине были реализованы текстовые макросы.
Синтаксис их объявления достаточно прост:
//! textmacro NAME takes argument1, argument2, ..., argument n
// Здесь располагается ваш код
//! endtextmacro
Таким образом, мы объявили некоторый блок кода внутри макроса. теперь мы можем выполнить этот макрос следующим образом:
//! runtextmacro NAME argument1, argument2, ..., argument n
Что приведет к копированию кода внутри блока макроса, на место вызова это макроса.
Например, объявление и выполнение следующего макроса
//! textmacro Increase takes TYPEWORD
function IncreaseStored$TYPEWORD$ takes gamecache g, string m, string l returns nothing
    call Store$TYPEWORD$(g,m,l,GetStored$TYPEWORD$(g,m,l)+1)
endfunction
//! endtextmacro

//! runtextmacro Increase("Integer")
//! runtextmacro Increase("Real")
приведет к генерации следующего кода
function IncreaseStoredInteger takes gamecache g, string m, string l returns nothing
    call StoreInteger(g,m,l,GetStoredInteger(g,m,l)+1)
endfunction
function IncreaseStoredReal takes gamecache g, string m, string l returns nothing
    call StoreReal(g,m,l,GetStoredReal(g,m,l)+1)
endfunction
Как вы можете заметить, внутри блока кода макроса используются специальные разделители $$. Они необходимы, поскольку заменяемое строковое значение может стоять неразрывно к другим символам.
Вам так же необходимо учитывать, что комментарии и строковые литералы не защищены от обработки, препроцессор ориентируется исключительно на разделитель $$, не обращая внимание на смысл выражения.
Если текстовый макрос не подразумевает получение каких-либо аргументов, их можно не указывать:
//! textmacro MSG
call BJDebugMsg("1")
call BJDebugMsg("2")
call BJDebugMsg("3")
//! endtextmacro

function test takes nothing returns nothing
    //! runtextmacro MSG()
    //! runtextmacro MSG()
endfunction
Макросы могут быть использованы вместе с областями и библиотеками, так же они придают языку некоторую фейковую динамику. В качестве простого примера, реализация стека
//! textmacro STACK takes NAME, TYPE, TYPE2STRING
    scope $NAME$
        globals
            private $TYPE$ array V
            private integer N=0
        endglobals
        public function push takes $TYPE$ val returns nothing
            set V[N]=val
            set N=N+1
        endfunction

        public function pop takes nothing returns $TYPE$
            set N=N-1
            return V[N]
        endfunction

        public function print takes nothing returns nothing
         local integer a=N-1
            call BJDebugMsg("Contents of $TYPE$ stack $NAME$:")
            loop
                exitwhen a<0
                call BJDebugMsg(" "+$TYPE2STRING$(V[a]))
                set a=a-1
            endloop
        endfunction
    endscope
//! endtextmacro

//! runtextmacro STACK("StackA","integer","I2S")
//! runtextmacro STACK("StackB","integer","I2S")
//! runtextmacro STACK("StackC","string","")
function Test takes nothing returns nothing
    call StackA_push(4)
    call StackA_push(5)
    call StackB_push(StackA_pop())
    call StackA_push(7)
    call StackA_print()
    call StackB_print()
    call StackC_push("A")
    call StackC_push("B")
    call StackC_push("C")
    call StackC_print()
endfunction
Стоит упомянуть и пару дополнительных возможностей:
  • Для объявления макроса, можно использовать ключевое слово textmacro_once, чей принцип работы аналогичен library_once
  • Для выполнения макроса, вы можете использовать директиву //! runtextmacro optional NAME(arg), что гарантирует отсутствие ошибки компиляции, в случае отсутствия соответствующего макроса

Просмотров: 352

Комментарии пока отсутcтвуют