.. _macros: =========== 精确化 =========== 表达式精确化用于以方便的方式生成 AST 表达式树。 它提供了一组转义序列,以允许不同类型的表达式替换。 在顶层,多个 call 宏支持精确化,这些宏用于生成不同的 AST 对象。 精确化在 daslib/templates_boost 中实现。 -------------- 简单示例 -------------- 让我们回顾一下以下示例:: 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)。 ------------ Quote 宏 ------------ 具体化宏类似于 ``quote`` 表达式,因为参数不经过类型推断。 相反,将生成 ast 树并对其进行作。 ****** qmacro ****** ``qmacro``是最简单的具体化。解析转义序列后,输入按原样返回:: var expr <- qmacro(2+2) print(describe(expr)) prints:: (2+2) ************ qmacro_block ************ ``qmacro_block`` 将一个块作为输入并返回未加引号的块。为了说明 ``qmacro`` 和 ``qmacro_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`` 删除此类装饰。 *********** qmacro_expr *********** ``qmacro_expr`` 将带有单个表达式的块作为输入,并将该表达式作为结果返回。 某些表达式,如 `return` 之类的不能作为调用的参数,因此它们不能直接传递给 ``qmacro``。 解决方法是将它们作为块的第一行传递:: var expr <- qmacro_block() { return 13 } print(describe(expr)) prints:: return 13 *********** qmacro_type *********** ``qmacro_type`` 将类型表达式 (type<...>) 作为输入,并在解析转义序列后将子类型作为 TypeDeclPtr 返回。 请考虑以下示例:: var foo <- typeinfo ast_typedecl(type) var typ <- qmacro_type <| type<$t(foo)?> print(describe(typ)) TypeDeclPtr foo 作为具体化序列传递给 ``qmacro_type`` ,并生成一个新的指针类型。 输出为:: int? *************** qmacro_function *************** ``qmacro_function`` 需要两个参数。第一个是生成的函数名称。第二个是具有函数体和参数的块。 默认情况下,生成的函数仅设置了 `FunctionFlags generated` 标志。 *************** qmacro_variable *************** ``qmacro_variable`` 将变量名称和类型表达式作为输入,并在解析转义序列后将变量作为 VariableDeclPtr 返回:: var vdecl <- qmacro_variable("foo", type) print(describe(vdecl)) prints:: foo:int ---------------- 转义序列 ---------------- 具体化提供了多个转义序列,用于其他模板替换。 ********* $i(ident) ********* ``$i`` 将 ``string`` 或 ``das_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 ************** $f(field-name) ************** ``$f`` 将 ``string`` 或 ``das_string`` 作为参数,并将其替换为字段名称:: var bar = "fieldname" var blk <- qmacro_block() { foo.$f(bar) = 13 } print(describe(blk)) prints:: foo.fieldname = 13 ********* $v(value) ********* ``$v`` 将任何值作为参数,并将其替换为生成该值的表达式。 该值不必是常量表达式,但将在替换表达式之前对表达式进行计算。 将生成适当的 `make` 基础设施:: var t = (1,2.,"3") var expr <- qmacro($v(t)) print(describe(expr)) prints:: (1,2f,"3") 在上面的示例中,元组被替换为生成此元组的表达式。 ************** $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) ***************** $b(array-of-expr) ***************** ``$b`` 将 ``array`` 或 ``das::vector`` 又名 ``dasvector`smart_ptr`Expression`` 作为参数,并按顺序替换为输入数组中的每个表达式:: var qqblk : array 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")) ************* $a(arguments) ************* ``$a`` 将 ``array`` 或 ``das::vector`` 又名 ``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``:: var foo <- [ new Variable(name:="v1", _type<-qmacro_type(type)), new Variable(name:="v2", _type<-qmacro_type(type), 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 } ******** $t(type) ******** ``$t`` 将 ``TypeDeclPtr`` 作为输入,并将其替换为类型表达式。 在以下示例中:: var subtype <- typeinfo ast_typedecl(type) var blk <- qmacro_block() { var a : $t(subtype)? } print(describe(blk)) 我们创建指向子类型的指针:: var a:int? -const ************* $c(call-name) ************* ``$c`` 将 ``string`` 或 ``das_string`` 作为输入,并替换调用表达式名称:: var cll = "somefunnycall" var blk <- qmacro ( $c(cll)(1,2) ) print(describe(blk)) prints:: somefunnycall(1,2)