Advertisement
Guest User

Untitled

a guest
Oct 9th, 2018
245
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Haxe 15.11 KB | None | 0 0
  1. package;
  2.  
  3. import haxe.io.Path;
  4. import haxe.macro.Context;
  5. import haxe.macro.Expr.Binop;
  6. import haxe.macro.ExprTools;
  7. import haxe.macro.Type;
  8. import sys.FileSystem;
  9. import sys.io.File;
  10.  
  11. class Generator {
  12.     public static function generate() {
  13.         Context.onGenerate(Generator.onGenerate);
  14.     }
  15.    
  16.     public static function onGenerate(types:Array<Type>):Void {
  17.         FileSystem.createDirectory(Sys.getCwd() + "/bin/generated/include");
  18.         FileSystem.createDirectory(Sys.getCwd() + "/bin/generated/src");
  19.        
  20.         for (t in types) {
  21.             switch(t) {
  22.                 case TInst(c, params):
  23.                     generateClass(c, params);
  24.                 default:
  25.                     //trace(t);  
  26.             }
  27.         }
  28.  
  29.         var libPath:String = HaxeLibHelper.getLibPath("arduino");
  30.        
  31.         var headerFiles = [];
  32.         FileHelper.findFiles(libPath + "\\lib", "h", headerFiles);
  33.         for (h in headerFiles) {
  34.             var p = new Path(h);
  35.             File.copy(h, Sys.getCwd() + "/bin/generated/include/" + p.file + "." + p.ext);
  36.         }
  37.        
  38.         var cppFiles = [];
  39.         FileHelper.findFiles(libPath + "\\lib", "cpp", cppFiles);
  40.         for (c in cppFiles) {
  41.             var p = new Path(c);
  42.             File.copy(c, Sys.getCwd() + "/bin/generated/src/" + p.file + "." + p.ext);
  43.         }
  44.  
  45.         Compiler.compile(Sys.getCwd() + "/bin/generated", true, false, false, libraries);
  46.     }
  47.    
  48.     private static var headers:Array<String> = [];
  49.     private static var externs:Array<String> = [];
  50.     private static var libraries:Array<String> = [];
  51.     private static function generateClass(c:Ref<ClassType>, params:Array<Type>) {
  52.         var classType:ClassType = c.get();
  53.         var fullName = classType.name;
  54.         if (classType.pack.length > 0) {
  55.             fullName = classType.pack.join(".") + "." + fullName;
  56.         }
  57.        
  58.         if (fullName != "Main" && fullName != "test.TestClass1" && fullName != "test.TestClass2" && fullName != "Arduino") {
  59.             return;
  60.         }
  61.  
  62.         headers = [];
  63.        
  64.         if (classType.isExtern == true) {
  65.             return;
  66.         }
  67.        
  68.         var fixedName = StringTools.replace(fullName, ".", "_");
  69.        
  70.         var sb:StringBuf = new StringBuf();
  71.         sb.add("#ifndef " + fixedName + "_h_\n");
  72.         sb.add("#define " + fixedName + "_h_ 1\n\n");
  73.        
  74.         sb.add("%INCLUDES%\n");
  75.        
  76.         sb.add("class " + fixedName + "\n");
  77.         sb.add("{\n");
  78.         sb.add("\tpublic:\n");
  79.        
  80.         var fields:Array<ClassField> = classType.fields.get();
  81.         for (f in fields) {
  82.             switch (f.expr().expr) {
  83.                 case TFunction(tfunc):
  84.                     addIndent(2, sb);
  85.                     sb.add(generateFunctionArgType(tfunc.t));
  86.                     sb.add(" ");
  87.                     sb.add(f.name);
  88.                     sb.add("(");
  89.                    
  90.                     var argList:Array<String> = [];
  91.                     for (arg in tfunc.args) {
  92.                         var argString = generateFunctionArgType(arg.v.t) + " " + arg.v.name;
  93.                         if (arg.value != null) {
  94.                             argString += " = " + printConstant(arg.value);
  95.                         }
  96.                         argList.push(argString);
  97.                     }
  98.                     sb.add(argList.join(", "));
  99.                    
  100.                     sb.add(")\n");
  101.                     tabs = "\t\t";
  102.                     sb.add(printExpr(tfunc.expr));
  103.                     sb.add("\n");
  104.                    
  105.                 default:
  106.                     //trace("NOT IMPL: " + f.expr());
  107.             }
  108.            
  109.             switch (f.kind) {
  110.                 case FVar(read, write):
  111.                     addIndent(2, sb);
  112.                     sb.add(generateFunctionArgType(f.type, true));
  113.                     sb.add(" ");
  114.                     sb.add(f.name);
  115.                     if (f.expr() != null) {
  116.                         sb.add(" = ");
  117.                         sb.add(printExpr(f.expr()));
  118.                     }
  119.                     sb.add(";\n\n");
  120.                 default:
  121.                     //trace("NOT IMPLE: " + f);
  122.             }
  123.         }
  124.  
  125.         var fields:Array<ClassField> = classType.statics.get();
  126.         for (f in fields) {
  127.             if (f.expr() != null) {
  128.                 switch (f.expr().expr) {
  129.                     case TFunction(tfunc):
  130.                         addIndent(2, sb);
  131.                         sb.add("static ");
  132.                         sb.add(generateFunctionArgType(tfunc.t));
  133.                         sb.add(" ");
  134.                         sb.add(f.name);
  135.                         sb.add("(");
  136.                        
  137.                         var argList:Array<String> = [];
  138.                         for (arg in tfunc.args) {
  139.                             var argString = generateFunctionArgType(arg.v.t) + " " + arg.v.name;
  140.                             if (arg.value != null) {
  141.                                 argString += " = " + printConstant(arg.value);
  142.                             }
  143.                             argList.push(argString);
  144.                         }
  145.                         sb.add(argList.join(", "));
  146.                        
  147.                         sb.add(")\n");
  148.                         tabs = "\t\t";
  149.                         sb.add(printExpr(tfunc.expr));
  150.                         sb.add("\n");
  151.                     default:    
  152.                 }
  153.             } else {
  154.                 addIndent(2, sb);
  155.                 sb.add("static ");
  156.                
  157.                 switch(f.type) {
  158.                     case TFun(argString, ret):
  159.                         sb.add(printType(ret, null));
  160.                     default:    
  161.                 }
  162.                
  163.                 sb.add(" ");
  164.                 sb.add(f.name);
  165.                 sb.add("(");
  166.                 sb.add(");\n");
  167.             }
  168.         }
  169.        
  170.         sb.add("};\n");
  171.         sb.add("\n#endif\n");
  172.        
  173.         //trace("\n\n" + sb.toString());
  174.         var content = sb.toString();
  175.         var headersContent = "";
  176.         for (h in headers) {
  177.             headersContent += '#include "${h}"\n';
  178.         }
  179.         content = StringTools.replace(content, "%INCLUDES%", headersContent);
  180.         File.saveContent(Sys.getCwd() + "bin/generated/include/" + fixedName + ".h", content);
  181.     }
  182.    
  183.     private static function generateFunctionArgType(t:Type, isVar:Bool = false):String {
  184.         switch (t) {
  185.             case TAbstract(tt, params):
  186.                 return typeToCpp(tt.toString());
  187.             case TInst(t, params):
  188.                 if (isVar == false) {
  189.                     return StringTools.replace(t.toString(), ".", "_") + "&";
  190.                 } else {
  191.                     return StringTools.replace(t.toString(), ".", "_");
  192.                 }
  193.             case TFun(args, ret):
  194.                 return "Dynamic? ";
  195.             default:
  196.                 trace("NOT IMPL TYPE: " + t.getName());
  197.         }
  198.         return null;
  199.     }
  200.    
  201.     private static function typeToCpp(t:String):String {
  202.         switch (t) {
  203.             case "Int":
  204.                 return "int";
  205.             case "Void":
  206.                 return "void";
  207.             case "Bool":
  208.                 return "bool";
  209.             default:
  210.                 trace("UNKNOWN TYPE: " + t);
  211.         }
  212.        
  213.         return null;
  214.     }
  215.    
  216.     static var tabs:String = "";
  217.     private static function printExpr(e:TypedExpr):String {
  218.         switch (e.expr) {
  219.             case TBlock([]): return '$tabs{\n $tabs}\n';
  220.             case TBlock(el):
  221.                 var old = tabs;
  222.                 tabs += "\t";
  223.                 var s = '$old{\n$tabs' + printExprs(el, ';\n$tabs');
  224.                 tabs = old;
  225.                 s += ';\n$tabs}\n';
  226.                 return s;
  227.             case TVar(v, e):
  228.                 return printType(v.t, v.name) + " " + printVar(v, e);
  229.             case TNew(c, params, el):
  230.                 if (c.get().isExtern == true) {
  231.                     var libName = c.get().name;
  232.                     if (libraries.indexOf(libName) == -1) {
  233.                         libraries.push(libName);
  234.                     }
  235.                 }
  236.                 return '${printClassPath(c)}(${printExprs(el,", ")})';
  237.             case TCall(e, el):
  238.                 return '${printExpr(e)}(${printExprs(el,", ")})';
  239.             case TConst(c):
  240.                 // defo hacky!
  241.                 switch (e.expr) {
  242.                     case TConst(TString(s)):
  243.                         switch(e.t) {
  244.                             case TAbstract(x, _):
  245.                                 if (x.toString() == "Int") {
  246.                                     return s;   // so basically doing some really hack crap here. If you have an untyped static int like:
  247.                                                 // public static inline var LED_BUILTIN:Int = untyped 'LED_BUILTIN';
  248.                                                 // Then the type and the expr dont match (one is string, one is int), so we'll make the
  249.                                                 // awful assumption its supposed to be an int constant... will likely go completely wrong
  250.                                                 // somewhere
  251.                                 }
  252.                             case _:
  253.                         }
  254.                     case _:
  255.                 }
  256.  
  257.                 return printConstant(c);
  258.             case TField(e, FStatic(c, cf)):
  259.                 if (c.get().isExtern == true) {
  260.                     if (c.get().meta.extract(":include") != null && c.get().meta.extract(":include").length > 0) {
  261.                         var include = ExprTools.toString(c.get().meta.extract(":include")[0].params[0]);
  262.                         include = StringTools.replace(include, "\"", "");
  263.                         if (headers.indexOf(include) == -1) {
  264.                             headers.push(include);
  265.                         }
  266.                     }
  267.                     var nativeName:String = "";
  268.                     if (c.get().meta.extract(":native") != null && c.get().meta.extract(":native").length > 0) {
  269.                         nativeName = ExprTools.toString(c.get().meta.extract(":native")[0].params[0]);
  270.                         nativeName = StringTools.replace(nativeName, "\"", "");
  271.                         nativeName += ".";
  272.                     }
  273.                     return nativeName + cf;
  274.                 } else {
  275.                     return printClassPath(c) + "::" + cf;
  276.                 }
  277.             case TField(e, FInstance(c, params, cf)):
  278.                 return printExpr(e) + "." + cf;
  279.             case TLocal(v):
  280.                 return "" + printVar(v, null);
  281.             case TObjectDecl(fields):
  282.                 return "Dynamic()";
  283.             case TTypeExpr(m):
  284.                 trace(">>>>>>>>>------------- " + m);
  285.             case TReturn(e):
  286.                 if (e != null) {
  287.                     return "return " + printExpr(e);
  288.                 } else {
  289.                     return "return";
  290.                 }
  291.             case TIf(econd, eif, null):
  292.                 return 'if (${printExpr(econd)}) ${printExpr(eif)}';
  293.             case TIf(econd, eif, eelse):
  294.                 switch (eif.expr) { // MORE HACK????
  295.                     case TBlock(_):
  296.                         return 'if (${printExpr(econd)}) ${printExpr(eif)} ${tabs}else ${printExpr(eelse)}';
  297.                     case _:
  298.                         return 'if (${printExpr(econd)}) ${printExpr(eif)}; else ${printExpr(eelse)}';
  299.                 }
  300.                 trace(eif);
  301.             case TBinop(op, e1, e2):
  302.                 return '${printExpr(e1)} ${printBinop(op)} ${printExpr(e2)}';
  303.             case TParenthesis(el):
  304.                 return '(${printExpr(el)})';
  305.             default:
  306.                 trace("NOT IMPL: " + e.expr);
  307.         }
  308.        
  309.         return "";
  310.     }
  311.    
  312.     public static function printBinop(op:Binop) return switch(op) {
  313.         case OpAdd: "+";
  314.         case OpMult: "*";
  315.         case OpDiv: "/";
  316.         case OpSub: "-";
  317.         case OpAssign: "=";
  318.         case OpEq: "==";
  319.         case OpNotEq: "!=";
  320.         case OpGt: ">";
  321.         case OpGte: ">=";
  322.         case OpLt: "<";
  323.         case OpLte: "<=";
  324.         case OpAnd: "&";
  325.         case OpOr: "|";
  326.         case OpXor: "^";
  327.         case OpBoolAnd: "&&";
  328.         case OpBoolOr: "||";
  329.         case OpShl: "<<";
  330.         case OpShr: ">>";
  331.         case OpUShr: ">>>";
  332.         case OpMod: "%";
  333.         case OpInterval: "...";
  334.         case OpArrow: "=>";
  335.         case OpAssignOp(op):
  336.             printBinop(op)
  337.             + "=";
  338.     }
  339.    
  340.     public static function printConstant(c:TConstant):String {
  341.         switch (c) {
  342.             case TInt(n):
  343.                 return Std.string(n);
  344.             case TNull:
  345.                 return "NULL";
  346.             case TString(s):
  347.                 return 'String(\"$s\")';
  348.             case TThis:
  349.                 return '(*(this))';
  350.             default:
  351.                 trace("printConstant: " + c);
  352.         }
  353.         return "";
  354.     }
  355.    
  356.     public static function printClassPath(c:Ref<ClassType>):String {
  357.         var s = StringTools.replace(Std.string(c), ".", "_");
  358.         if (headers.indexOf(s + ".h") == -1) {
  359.             headers.push(s + ".h");
  360.         }
  361.         return s;
  362.     }
  363.    
  364.     public static function printVar(v, e):String {
  365.         var s:String = "";
  366.        
  367.         var isFn = false;
  368.         if (e != null) { // hack??
  369.             switch (v.t) {
  370.                 case TFun(args, ret):
  371.                     isFn = true;
  372.                 default:    
  373.             }
  374.         }
  375.        
  376.        
  377.         if (isFn == false) {
  378.             s += v.name;
  379.         }
  380.         if (e != null && e.expr != null) {
  381.             s += " = ";
  382.             s += printExpr(e);
  383.         }
  384.         return s;    
  385.     }
  386.  
  387.     public static function printType(type:Type, name:String):String {
  388.         switch (type) {
  389.             case TAbstract(t, p):
  390.                 return typeToCpp(t.toString());
  391.             case TInst(t, params):
  392.                 return printClassPath(t);
  393.             case TFun(args, ret):
  394.                 return '${printType(ret, null)} (*${name})(${printArgs(args, ", ")})';
  395.             case TDynamic(t):
  396.                 return "Dynamic";
  397.             case TType(t, params):
  398.                 if (params.length > 0) {
  399.                     return printType(params[0], null);
  400.                 } else {
  401.                     return "" + StringTools.replace(Std.string(t), ".", "_") + "";
  402.                 }
  403.             default:
  404.                 trace("UNKNOWN printType: " + type);
  405.                 return "UNKNOWN";
  406.         }
  407.         return "";
  408.     }
  409.    
  410.     public static function printExprs(el:Array<TypedExpr>, sep:String) {
  411.         return el.map(printExpr).join(sep);
  412.     }
  413.    
  414.     public static function printArgs(el:Array<{name:String, opt:Bool, t:Type}>, sep:String) {
  415.         var arr:Array<String> = [];
  416.        
  417.         for (e in el) {
  418.             arr.push(printType(e.t, null));
  419.         }
  420.        
  421.         return arr.join(sep);
  422.     }
  423.    
  424.     private static function addIndent(n:Int, sb:StringBuf) {
  425.         for (i in 0...n) {
  426.             sb.add("\t");
  427.         }
  428.     }
  429. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement