是否可以定义在编译结束时要执行的指令? (水晶郎)

时间:2017-10-31 03:29:54

标签: crystal-lang

假设一个Crystal项目正在使用不同的分片。并且每个分片都希望在整个项目的编译结束时进行清理。是否可以使用宏?

例如:

{% at_end %}
  {% system("rm 'tmp files'") %}
{% end %}

1 个答案:

答案 0 :(得分:0)

如果您需要在多个宏之间共享数据,可以使用HashArray,并通过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节点,从NumberLiteralSymbolLiteral等简单节点到CallDef甚至是{{}等复杂节点{1}}。

ClassDef

最后我创建了一个宏,只需打印(在编译时)macro list {% for elem in STORAGE %} {% puts "Elem: #{elem}" %} {% end %} end 数组的内容。

使用STORAGE

可以做同样的事情
HashLiteral

以与上述相同的方式,您可以使用任何类型的AST节点作为键或值。

请注意,普通代码也可以看到您在宏系统中使用的STORAGE = {} of _ => _ ,并且可能会发生名称冲突(如果用户想要使用常量Constants,那么该怎么办?自己的代码?)。 为了最大限度地减少这种可能性(如果不需要),我建议你将常量放在像STORAGE这样的特殊模块中,或者使用一些复杂的命名模式,如MyShard::MacroStorage::SomeInterestingNodes(&lt; - 这不太可能由用户使用;))