2.30. 精确化

表达式精确化用于以方便的方式生成 AST 表达式树。 它提供了一组转义序列,以允许不同类型的表达式替换。 在顶层,多个 call 宏支持精确化,这些宏用于生成不同的 AST 对象。

精确化在 daslib/templates_boost 中实现。

2.30.1. 简单示例

让我们回顾一下以下示例:

var foo = "foo"
var fun <- qmacro_function("madd") <| $ ( a, b ) {
    return $i(foo) * a + b
}
print(describe(fun))

输出将是:

def public madd (  a:auto const;  b:auto const ) : auto {
    return (foo * a) + b
}

这里发生的情况是调用宏 qmacro_function 会生成一个名为 madd 的新函数。 该函数的参数和主体取自块,该块被传递给函数。 转义序列 $i 以字符串的形式获取其参数,并将其转换为标识符 (ExprVar)。

2.30.2. Quote 宏

具体化宏类似于 quote 表达式,因为参数不经过类型推断。 相反,将生成 ast 树并对其进行作。

2.30.2.1. qmacro

``qmacro``是最简单的具体化。解析转义序列后,输入按原样返回:

var expr <- qmacro(2+2)
print(describe(expr))

prints:

(2+2)

2.30.2.2. qmacro_block

qmacro_block 将一个块作为输入并返回未加引号的块。为了说明 qmacroqmacro_block 之间的区别,让我们回顾一下下面的例子:

var blk1 <- qmacro <| $ ( a, b ) { return a+b; }
var blk2 <- qmacro_block <| $ ( a, b ) { return a+b; }
print("{blk1.__rtti}\n{blk2.__rtti}\n")

输出将是:

ExprMakeBlock
ExprBlock

这是因为 block 子表达式是 decorated,即 (ExprMakeBlock(ExprBlock (…))), 和 qmacro_block 删除此类装饰。

2.30.2.3. qmacro_expr

qmacro_expr 将带有单个表达式的块作为输入,并将该表达式作为结果返回。 某些表达式,如 return 之类的不能作为调用的参数,因此它们不能直接传递给 qmacro。 解决方法是将它们作为块的第一行传递:

var expr <- qmacro_block() {
    return 13
}
print(describe(expr))

prints:

return 13

2.30.2.4. qmacro_type

qmacro_type 将类型表达式 (type<…>) 作为输入,并在解析转义序列后将子类型作为 TypeDeclPtr 返回。 请考虑以下示例:

var foo <- typeinfo ast_typedecl(type<int>)
var typ <- qmacro_type <| type<$t(foo)?>
print(describe(typ))

TypeDeclPtr foo 作为具体化序列传递给 qmacro_type ,并生成一个新的指针类型。 输出为:

int?

2.30.2.5. qmacro_function

qmacro_function 需要两个参数。第一个是生成的函数名称。第二个是具有函数体和参数的块。 默认情况下,生成的函数仅设置了 FunctionFlags generated 标志。

2.30.2.6. qmacro_variable

qmacro_variable 将变量名称和类型表达式作为输入,并在解析转义序列后将变量作为 VariableDeclPtr 返回:

var vdecl <- qmacro_variable("foo", type<int>)
print(describe(vdecl))

prints:

foo:int

2.30.3. 转义序列

具体化提供了多个转义序列,用于其他模板替换。

2.30.3.1. $i(ident)

$istringdas_string 作为参数,并用标识符替换它。 在变量声明和使用:

var bus = "bus"
var qb <- qmacro_block() {
    let $i(bus) = "busbus"
    let t = $i(bus)
}
print(describe(qb))

prints:

let  bus:auto const = "busbus"
let  t:auto const = bus

2.30.3.2. $f(field-name)

$fstringdas_string 作为参数,并将其替换为字段名称:

var bar = "fieldname"
var blk <- qmacro_block() {
    foo.$f(bar) = 13
}
print(describe(blk))

prints:

foo.fieldname = 13

2.30.3.3. $v(value)

$v 将任何值作为参数,并将其替换为生成该值的表达式。 该值不必是常量表达式,但将在替换表达式之前对表达式进行计算。 将生成适当的 make 基础设施:

var t = (1,2.,"3")
var expr <- qmacro($v(t))
print(describe(expr))

prints:

(1,2f,"3")

在上面的示例中,元组被替换为生成此元组的表达式。

2.30.3.4. $e(expression)

$e 将任何表达式作为 ExpressionPtr 形式的参数。表达式将按原样替换:

var expr <- quote(2+2)
var qb <- qmacro_block() {
    let foo = $e(expr)
}
print(describe(qb))

prints:

let foo:auto const = (2 + 2)

2.30.3.5. $b(array-of-expr)

$barray<ExpressionPtr>das::vector<ExpressionPtr> 又名 dasvector`smart_ptr`Expression 作为参数,并按顺序替换为输入数组中的每个表达式:

var qqblk : array<ExpressionPtr>
for ( i in range(3) ) {
    qqblk |> emplace_new <| qmacro(print("{$v(i)}\n"))
}
var blk <- qmacro_block() {
    $b(qqblk)
}
print(describe(blk))

prints:

print(string_builder(0, "\n"))
print(string_builder(1, "\n"))
print(string_builder(2, "\n"))

2.30.3.6. $a(arguments)

$aarray<ExpressionPtr>das::vector<ExpressionPtr> 又名 dasvector`smart_ptr`Expression 作为参数,并按顺序将调用参数替换为输入数组中的每个表达式:

var arguments <- [quote(1+2); quote("foo")]
var blk <- qmacro <| somefunnycall(1,$a(arguments),2)
print(describe(blk))

prints:

somefunnycall(1,1 + 2,"foo",2)

请注意函数的其他参数是如何保留的,并且可以同时替换多个参数。

参数可以在函数声明本身中替换。在这种情况下,$a期望 array<VariablePtr>:

var foo <- [
    new Variable(name:="v1", _type<-qmacro_type(type<int>)),
    new Variable(name:="v2", _type<-qmacro_type(type<float>), init<-qmacro(1.2))
]
var fun <- qmacro_function("show") <| $ ( a: int; $a(foo); b : int ) {
    return a + b
}
print(describe(fun))

prints:

def public add ( a:int const; var v1:int; var v2:float = 1.2f; b:int const ) : int {
    return a + b
}

2.30.3.7. $t(type)

$tTypeDeclPtr 作为输入,并将其替换为类型表达式。 在以下示例中:

var subtype <- typeinfo ast_typedecl(type<int>)
var blk <- qmacro_block() {
    var a : $t(subtype)?
}
print(describe(blk))

我们创建指向子类型的指针:

var a:int? -const

2.30.3.8. $c(call-name)

$cstringdas_string 作为输入,并替换调用表达式名称:

var cll = "somefunnycall"
var blk <- qmacro ( $c(cll)(1,2) )
print(describe(blk))

prints:

somefunnycall(1,2)