Skip to content

Latest commit

 

History

History
104 lines (68 loc) · 3.29 KB

9.6.限制.md

File metadata and controls

104 lines (68 loc) · 3.29 KB

9.6.限制

本节内容:

9.6.1: Macro-in-Macro

9.6.2: 静态扩展

9.6.3: 构建顺序

9.6.4: 类型参数

9.6.1Macro-in-Macro

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.

9.6.2.静态扩展

静态扩展(第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;
  }
}

9.6.3.构建顺序

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.

9.6.4.类型参数

官方文档暂无内容