Macros.hx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package hrt.impl;
  2. import haxe.macro.Context;
  3. import haxe.macro.Expr;
  4. class Macros {
  5. #if macro
  6. public static function buildPrefab() {
  7. var fields = Context.getBuildFields();
  8. var toSerialize = [], toCopy = [];
  9. var isRoot = Context.getLocalClass().toString() == "hrt.prefab.Prefab";
  10. var localType = haxe.macro.Tools.TTypeTools.toComplexType(Context.getLocalType());
  11. var changed = false;
  12. for( f in fields ) {
  13. if( f.name == "copy" && !isRoot ) {
  14. // inject auto cast to copy parameter
  15. switch( f.kind ) {
  16. case FFun(f) if( f.args.length == 1 && f.expr != null ):
  17. var name = f.args[0].name;
  18. var expr = f.expr;
  19. f.expr = macro @:pos(f.expr.pos) { var $name : $localType = cast $i{name}; $expr; }
  20. changed = true;
  21. default:
  22. }
  23. }
  24. if( f.meta == null ) continue;
  25. for( m in f.meta ) {
  26. switch( m.name ) {
  27. case ":s":
  28. toSerialize.push(f);
  29. case ":c":
  30. toCopy.push(f.name);
  31. default:
  32. }
  33. }
  34. }
  35. if( toSerialize.length + toCopy.length == 0 )
  36. return changed ? fields : null;
  37. var ser = [], unser = [], copy = [];
  38. var pos = Context.currentPos();
  39. for( f in toSerialize ) {
  40. switch( f.kind ) {
  41. case FProp(_, _, t, e), FVar(t,e):
  42. var name = f.name;
  43. var serCond = null;
  44. if( e == null ) {
  45. var setDef = true;
  46. var c : Constant = switch( t ) {
  47. case null: Context.error("Invalid var decl", f.pos);
  48. case TPath({ pack : [], name : "Int"|"Float" }): CInt("0");
  49. case TPath({ pack : [], name : "Bool" }): CIdent("false");
  50. default: setDef = false; CIdent("null");
  51. }
  52. e = { expr : EConst(c), pos : f.pos };
  53. if( setDef ) {
  54. f.kind = switch( f.kind ) {
  55. case FVar(t,_): FVar(t,e);
  56. case FProp(get,set,t,_): FProp(get,set,t,e);
  57. default: throw "assert";
  58. }
  59. }
  60. } else {
  61. var echeck = e;
  62. if( e.expr.match(EArrayDecl([])) )
  63. serCond = macro @:pos(f.pos) this.$name.length != 0;
  64. }
  65. if( serCond == null ) {
  66. var defVal = e.expr.match(EConst(_) | EBinop(_) | EUnop(_)) ? e : macro @:pos(f.pos) null;
  67. serCond = macro @:pos(pos) this.$name != $defVal;
  68. }
  69. ser.push(macro @:pos(pos) if( $serCond ) obj.$name = this.$name);
  70. unser.push(macro @:pos(pos) this.$name = obj.$name == null ? $e : obj.$name);
  71. copy.push(macro @:pos(pos) this.$name = p.$name);
  72. default:
  73. Context.error("Invalid serialization field", f.pos);
  74. }
  75. }
  76. for( name in toCopy ) {
  77. copy.push(macro @:pos(pos) this.$name = p.$name);
  78. }
  79. if( !isRoot ) {
  80. ser.unshift(macro @:pos(pos) super.saveSerializedFields(obj));
  81. unser.unshift(macro @:pos(pos) super.loadSerializedFields(obj));
  82. copy.unshift(macro @:pos(pos) var p : $localType = cast p);
  83. copy.unshift(macro @:pos(pos) super.copySerializedFields(p));
  84. }
  85. function makeFun(name,block) : Field {
  86. return {
  87. name : name,
  88. kind : FFun({
  89. ret : null,
  90. expr : { expr : EBlock(block), pos : pos },
  91. args : [{ name : "obj", type : macro : Dynamic }],
  92. }),
  93. meta : [{ name : ":noCompletion", pos : pos }],
  94. access : isRoot ? [] : [AOverride],
  95. pos : pos,
  96. };
  97. }
  98. if( toSerialize.length > 0 ) {
  99. fields.push(makeFun("saveSerializedFields",ser));
  100. fields.push(makeFun("loadSerializedFields",unser));
  101. }
  102. fields.push({
  103. name : "copySerializedFields",
  104. kind : FFun({
  105. ret : null,
  106. expr : { expr : EBlock(copy), pos : pos },
  107. args : [{ name : "p", type : macro : hrt.prefab.Prefab }],
  108. }),
  109. meta : [{ name : ":noCompletion", pos : pos }],
  110. access : isRoot ? [] : [AOverride],
  111. pos : pos,
  112. });
  113. return fields;
  114. }
  115. #end
  116. }