本节内容:
9.6.1: Macro-in-Macro
9.6.2: 静态扩展
9.6.3: 构建顺序
9.6.4: 类型参数
Build macros cannot be invoked from a macro context. This means it is impossible to use a macro to create a class which will provide build macros for other classes.
It is also disallowed to invoke expression macros in a macro context.
Prior to Haxe 4, using expression macros inside a macro context was possible. Support was primarily dropped because such code would cause issues with the compiler cache.
静态扩展(第6.3节)和宏的概念有一些冲突:前者需要一个已知类型来确定使用的函数,而宏在类型化简单的语法之前执行。因此毫不奇怪,结合使用这两个特性可能导致问题。Haxe 3.0 会尝试转换 类型化表达式回到一个 语法表达式,并不总是可行,可能丢失一些重要信息。我们建议小心使用。
从 Haxe 3.1.0 以后: 静态扩展和宏的组合在 3.1.0 版本被重构。Haxe编译器甚至不设法寻找宏参数最初的表达式,而是传递一个特殊的 @:this this 表达式。而这个表达式的结构不传达信息,表达式仍然被正确的类型化:
import haxe.macro.Context;
import haxe.macro.Expr;
using Main;
using haxe.macro.Tools;
class Main {
static public function main() {
#if !macro
var a = "foo";
a.test();
#end
}
macro static function test(e:ExprOf<String>) {
trace(e.toString()); // @:this this
// TInst(String,[])
trace(Context.typeof(e));
return e;
}
}
The build order of types is unspecified and this extends to the execution order of build-macros. While certain rules can be determined, we strongly recommend to not rely on the execution order of build-macros. If type building requires multiple passes, this should be reflected directly in the macro code. In order to avoid multiple build-macro executions on the same type, the state can be stored in persistent variables or added as metadata to the type in question:
import haxe.macro.Context;
import haxe.macro.Expr;
#if !macro
@:autoBuild(MyMacro.build())
#end
interface I1 {}
#if !macro
@:autoBuild(MyMacro.build())
#end
interface I2 {}
class C implements I1 implements I2 {}
class MyMacro {
macro static public function build():Array<Field> {
var c = Context.getLocalClass().get();
if (c.meta.has(":processed"))
return null;
c.meta.add(":processed", [], c.pos);
// process here
return null;
}
}
class Main {
static public function main() {}
}
With both interfaces I1
and I2
having :autoBuild
metadata, the build macro is executed twice for class C
. We guard against duplicate processing by adding a custom :processed
metadata to the class, which can be checked during the second macro execution.
官方文档暂无内容