Допустим, проект Crystal использует разные осколки. И каждый шард хочет выполнить очистку в конце компиляции всего проекта. Можно ли использовать макросы?
Что-то вроде этого, например:
{% at_end %}
{% system("rm 'tmp files'") %}
{% end %}
Допустим, проект Crystal использует разные осколки. И каждый шард хочет выполнить очистку в конце компиляции всего проекта. Можно ли использовать макросы?
Что-то вроде этого, например:
{% at_end %}
{% system("rm 'tmp files'") %}
{% end %}
Если вам нужно обмениваться данными между несколькими макросами, вы можете использовать Hash
или Array
и получать к ним доступ через Constant
, связанный с которым узел AST доступен из макросов.
Вот пример, демонстрирующий это (в прямом эфире на https://carc.in/#/r/372k а>):
STORAGE = [] of _
macro add(node)
{% STORAGE << node %}
end
macro list
{% for elem in STORAGE %}
{% puts "Elem: #{elem}" %}
{% end %}
end
add 1
add 2
add "hello"
add :world
add({a: 1, b: 2})
add 3 + 4
add a_call(arg1, 2)
list
Важными частями здесь являются:
STORAGE = [] of _
Здесь я объявляю массив определенного типа (что в данном случае не имеет значения, так как доступ к массиву осуществляется только через макросы, вы не можете использовать этот тип (_
) в обычном коде). Макроссистеме нужно только знать, что это массив.
macro add(node)
{% STORAGE << node %}
end
Затем я создаю макрос, который сможет изменять узел AST массива (который имеет тип ArrayLiteral в системе макросов). Обратите внимание, что он позволяет хранить узлы AST любого типа, от простых узлов, таких как NumberLiteral
или SymbolLiteral
, до сложных узлов, таких как Call
, Def
или даже ClassDef
.
macro list
{% for elem in STORAGE %}
{% puts "Elem: #{elem}" %}
{% end %}
end
И, наконец, я создаю макрос, который будет просто печатать (во время компиляции) содержимое массива STORAGE
.
То же самое можно сделать с HashLiteral
:
STORAGE = {} of _ => _
И так же, как описано выше, вы можете использовать любые узлы AST в качестве ключа или значения.
Обратите внимание, что Constants
, который вы используете в системе макросов, также можно увидеть в обычном коде, и возможны конфликты имен (что, если пользователь захочет использовать константу STORAGE
и для своего собственного кода?). Чтобы свести к минимуму эту возможность (если это нежелательно), я предлагаю вам поместить ваши константы в специальный модуль, такой как MyShard::MacroStorage::SomeInterestingNodes
, или использовать какой-нибудь сложный шаблон именования, такой как M____ACRO_Storage____01234
(‹-- это вряд ли будет использоваться пользователем;))
[] of _
в макросе. Как вы об этом узнали? (Спасибо за этот ответ.)
- person dgo.a; 05.12.2017