代码之家  ›  专栏  ›  技术社区  ›  dgo.a santervo

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

  •  2
  • dgo.a santervo  · 技术社区  · 7 年前

    假设一个水晶项目使用不同的碎片。每个碎片都希望在整个项目的编译结束时进行清理。可以使用宏吗?

    例如:

    {% at_end %}
      {% system("rm 'tmp files'") %}
    {% end %}
    
    1 回复  |  直到 7 年前
        1
  •  0
  •   bew    6 年前

    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 您在宏系统中使用的代码也可以通过普通代码看到,并且可能会出现名称冲突(如果用户想要使用常量该怎么办 存储 对他自己的代码来说也是如此?)。 为了尽量减少这种可能性(如果不需要的话),我建议您将常数放在一个特殊的模块中,如 MyShard::MacroStorage::SomeInterestingNodes 或者使用一些复杂的命名模式,如 M____ACRO_Storage____01234 (<--这不太可能被用户使用;)