Macro With Context

宏定义如下:

// macro_definition.cj
macro package macro_definition

import std.ast.*

public macro Outter(input: Tokens): Tokens {
    return input
}

public macro Inner(input: Tokens): Tokens {
    assertParentContext("Outter")
    return input
}

宏调用如下:

// macro_call.cj
package macro_calling

import macro_definition.*

main() {
    @Outter var a = 0
    @Inner var b = 0 // error: The macro call 'Inner' should with the surround code contains a call 'Outter'.
}

编译命令如下:

# 先编译宏定义文件
cjc macro_definition.cj --compile-macro

# 编译使用宏的文件
cjc macro_call.cj -o demo

如上代码所示,Inner 宏在定义时使用了 assertParentContext 函数用于检查其在调用阶段是否位于 Outter 宏中,在代码示例的宏调用场景下,由于 OutterInner 在调用时不存在这样的嵌套关系,因此编译器将报告一个错误。

宏定义如下:

// macro_definition.cj
macro package macro_definition

import std.ast.*

public macro Outter(input: Tokens): Tokens {
    let messages = getChildMessages("Inner")
    for (m in messages) {
        let value1 = m.getString("key1") // get value: "value1"
        let value2 = m.getString("key2") // get value: "value2"
        println("value1: ${value1}  value2: ${value2}")
    }
    return input
}

public macro Inner(input: Tokens): Tokens {
    assertParentContext("Outter")
    setItem("key1", "value1")
    setItem("key2", "value2")
    return input
}

宏调用如下:

// macro_call.cj
import std.ast.*

import macro_definition.*

main() {
    @Outter(
        @Inner var cnt = 0
    )
    println(cnt)
}

编译命令如下:

# 先编译宏定义文件
cjc macro_definition.cj --compile-macro

# 编译使用宏的文件
cjc macro_call.cj -o demo

编译阶段输出:

value1: value1  value2: value2

在上面的代码中,内层宏 Inner 通过 setItem 向外层宏发送信息;Outter 宏通过 getChildMessages 函数接收到 Inner 发送的一组信息对象(Outter 中可以调用多次 Inner);最后通过该信息对象的 getString 函数接收对应的值。