假设一个Crystal项目正在使用不同的分片。并且每个分片都希望在整个项目的编译结束时进行清理。是否可以使用宏?
例如:
{% at_end %}
{% system("rm 'tmp files'") %}
{% end %}
答案 0 :(得分:0)
如果您需要在多个宏之间共享数据,可以使用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
甚至是{{}等复杂节点{1}}。
ClassDef
最后我创建了一个宏,只需打印(在编译时)macro list
{% for elem in STORAGE %}
{% puts "Elem: #{elem}" %}
{% end %}
end
数组的内容。
使用STORAGE
:
HashLiteral
以与上述相同的方式,您可以使用任何类型的AST节点作为键或值。
请注意,普通代码也可以看到您在宏系统中使用的STORAGE = {} of _ => _
,并且可能会发生名称冲突(如果用户想要使用常量Constants
,那么该怎么办?自己的代码?)。
为了最大限度地减少这种可能性(如果不需要),我建议你将常量放在像STORAGE
这样的特殊模块中,或者使用一些复杂的命名模式,如MyShard::MacroStorage::SomeInterestingNodes
(&lt; - 这不太可能由用户使用;))