Advertisement
Masadow

MacroHelper

Mar 13th, 2014
228
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Haxe 6.58 KB | None | 0 0
  1. package beluga.core;
  2.  
  3. import beluga.core.module.Module;
  4. import haxe.io.Bytes;
  5. import haxe.Log;
  6. import haxe.macro.Compiler;
  7. import haxe.macro.Context;
  8. import haxe.macro.Expr;
  9. import haxe.Resource;
  10. import haxe.xml.Fast;
  11. import sys.FileSystem;
  12. import sys.io.File;
  13. import sys.io.Process;
  14.  
  15. typedef ModuleConfig = { name : String, path : String, config : String, tables : Array<String> };
  16.  
  17. /**
  18.  * ...
  19.  * @author Masadow
  20.  */
  21. @:autoBuild(beluga.core.MacroHelper.build())
  22. class MacroHelper
  23. {
  24.     //Macro context only
  25.     public static var installPath;
  26.     // Keep a list of modules to use it in other macros context
  27.     // Need two vars because modulesArray getter would be call in loopFile which result in a compilation error
  28.     // (Since loop file is also available outside of the macro context)
  29.     private static var _modulesArray : Array<String> = null;
  30.  
  31.     macro public static function getModules() : Expr
  32.     {
  33.         if (_modulesArray == null)
  34.             importConfig();
  35.         return Context.makeExpr(_modulesArray, Context.currentPos());
  36.     }
  37.    
  38.     //Need to be there since all loaded modules are referred here
  39.     //Resolve both simple and full path
  40.     public static function getModuleInstanceByName(name : String, key : String = "") : Module {
  41.         var realClass = Type.resolveClass(name + "Impl");
  42.         if (realClass == null)
  43.             realClass = Type.resolveClass("beluga.module." + name.toLowerCase() + "." + name.substr(0, 1).toUpperCase() + name.substr(1).toLowerCase() + "Impl");
  44.         if (realClass == null)
  45.             throw new BelugaException("Module not found " + name);
  46.         return Reflect.callMethod(realClass, "getInstance", [key]);
  47.     }
  48.  
  49.     public static function resolveModel(module : String, name : String) : Class<Dynamic> {
  50.         var realClass = Type.resolveClass("beluga.module." + module + ".model." + name);
  51.         if (realClass == null) {
  52.             throw new BelugaException("Model not found " + name);
  53.         }
  54.         return realClass;
  55.     }
  56.  
  57.     #if macro
  58.     private static function loopFiles(filename : String, output : String) {
  59.  
  60.         //Load configuration
  61.         var file = File.getContent(filename); //Problem, where should we put this configuration file ?
  62.         var xml = Xml.parse(file);            //Is it necessary to let user edit it without recompile its project ? Solution => haxe.Resource
  63.         var fast = new Fast(xml);
  64.         var config : String;
  65.         var modules = new Array<ModuleConfig>();
  66.         var tables = new Array<String>();
  67.  
  68.         // Look for active modules
  69.         for (module in xml.elements()) {
  70.             //Not fully supported, it can leads to mistakes
  71.             //if (module.nodeName == "include") {
  72.                 //var path : String = module.get("path");
  73.                 //var vars = loopFiles(path, output);
  74.                 //modulesFile.concat(vars.modulesFile);
  75.                 //modules.concat(vars.modules);
  76.                 //file += vars.file;
  77.             //}
  78.             //else
  79.             if (module.nodeName == "module") {
  80.                 var name : String = module.get("name");
  81.                 var modulePath = MacroHelper.installPath + "/module/" + name.toLowerCase();
  82.                 var module : String = "beluga.module." + name.toLowerCase();// + "." + name.substr(0, 1).toUpperCase() + name.substr(1) + "Impl";
  83.  
  84.  
  85.                 //Build a list of modules config files
  86.                 config = File.getContent(MacroHelper.installPath + "/module/" + name.toLowerCase() + "/config.xml");
  87.  
  88.                 //Get every single models from the current module
  89.                 tables = new Array<String>();
  90.                 if (!FileSystem.isDirectory(modulePath + "/model")) {
  91.                     throw new BelugaException("Missing model directory from the module " + name);
  92.                 }
  93.                 else {
  94.                     for (model in FileSystem.readDirectory(modulePath + "/model")) {
  95.                         //Do not forget to remove the .hx extension to get the model name
  96.                         tables.push(model.substr(0, model.length - 3));
  97.                     }
  98.                 }
  99.  
  100.                 _modulesArray.push(name);
  101.                 modules.push({name: name, path: module, config: config, tables: tables});
  102.             }
  103.         }
  104.  
  105.         return {
  106.             file : file,
  107.             modules : modules
  108.         }
  109.     }
  110.  
  111.     private static function findBelugaPath() {
  112.         //Call "haxelib path beluga" to get the install path of beluga
  113.         var bytepath = new sys.io.Process("haxelib", ["path", "beluga"]).stdout.readAll();
  114.  
  115.         var path = StringTools.trim(bytepath.readString(0, bytepath.length).split("\n")[0]);
  116.  
  117.         return path + "/beluga";
  118.     }
  119.     #end
  120.  
  121.     private static var cached : Expr = null; //Cache the result
  122.     macro public static function importConfig()
  123.     {
  124.         //Avoid compile error, useless otherwise
  125.         if (_modulesArray == null)
  126.             _modulesArray = new Array<String>();
  127.  
  128.         if (cached != null)
  129.             return cached; //Make sure the method is processed once
  130.  
  131.         var filename = "beluga.xml";
  132.         var pos = Context.currentPos();
  133.  
  134.         //Find the installPath of beluga
  135.         MacroHelper.installPath = findBelugaPath();
  136.         if (MacroHelper.installPath == "") {
  137.             throw new BelugaException("Can't locate haxe installation folder. Make sure HAXE_HOME is set in your env");
  138.         }
  139.  
  140.         var modulesInfo = loopFiles(filename, Compiler.getOutput());
  141.  
  142.         //Load configuration
  143.         var file = File.getContent(filename); //Problem, where should we put this configuration file ?
  144.         var xml = Xml.parse(file);                    //Is it necessary to let user edit it without recompile its project ?
  145.         var fast = new Fast(xml);
  146.         var installPath = fast.hasNode.install ? fast.node.install.att.path : "";
  147.  
  148.         //Add the install path of Beluga to the haxe.Resource to make it globally accessible through macros
  149.         //Not true anymore, it is not accessible through macros, need to be deleted but actually used somewhere else
  150.         //Should add the config file itself instead
  151.         Context.addResource("beluga_config.xml", Bytes.ofString(file)); //Configuration remains accessible and editable
  152.  
  153.         for (module in modulesInfo.modules) {
  154.  
  155.             // Huge constraint :
  156.             // The module is not compiled, which means that if it has a wrong syntax, it won't work without notification
  157.             // Only the package is added to the compile unit
  158.             Compiler.include(module.path); //Provisional, issue #2100 https://github.com/HaxeFoundation/haxe/issues/2100
  159.             //Compiler.addClassPath(module.path);
  160.         }
  161.  
  162.         var configExpr = Context.makeExpr(modulesInfo.file, pos);
  163.         var modulesFile = new Array<{ field : String, expr : Expr }>();
  164.  
  165.         for (module in modulesInfo.modules) {
  166.             var fields = new Array<{field: String, expr: Expr}>();
  167.             for (fieldName in Reflect.fields(module)) {
  168.                 fields.push( {
  169.                     field: fieldName,
  170.                     expr: Context.makeExpr(Reflect.field(module, fieldName), pos)
  171.                 });
  172.             }
  173.             modulesFile.push({
  174.                 field : module.name,
  175.                 expr : { pos: pos, expr: EObjectDecl(fields)}
  176.             });
  177.         }
  178.  
  179.         cached =  {
  180.             expr : EObjectDecl([
  181.                 {
  182.                     field: "modules",
  183.                     expr: { expr: EObjectDecl(modulesFile), pos:pos}
  184.                 }
  185.             ]),
  186.             pos: pos
  187.         }
  188.  
  189.         return cached;
  190.     }  
  191. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement