haxe 漫游符号模块

WanderingSymbolsModule.hx
package wanderingSymbolsBonus;
import actions.ActionContainer;
import display.EventParams;
import display.interfaces.IGameAnimation;
import display.interfaces.IGameContainer;
import hxevents.Notifier;
import library.Library;
import modular.IModule;
import net.response.Spin;
import pipes.flow.FlowActors;

using actions.ActionTools;

class WanderingSymbolsModule implements IModule {
	
	/* IModule */
	public function registerFlowActor():Void {
		FlowActors.setActor(Type.getClassName(Type.getClass(this)), this);
	}
	
	public var complete:Notifier = new Notifier();
	
	var response:Spin;
	
	public function setSpinResponse(spin:Spin):Void {
		response = spin;
	}
	/* IModule */
	
	var parent:IGameContainer = null;
	var root = null;
	var libraryName:String;
	var posContainers:Array<Array<IGameContainer>> = [];
	var SYMBOL_MARGIN(get, null):Int = 100;
	
	public var setSymbolStateAtPositionEnd:Notifier = new Notifier();
	public var allMovesSymbolsComplete:Notifier = new Notifier();
	public var moveAnimEnd:Notifier = new Notifier();
	
	public static var WANDERING_SYMBOLS_ID:Map<Int, Int> = [
		0 => 0,
	];
	
	var currentSymbolsPos:Array<Int> = [];
	var newSymbolsPos:Array<Int> = [];
	
	public var remainingWanderingSymbols(get, null):Int;
	
	
	//--------------- show stickyData ------------------
		var showStickyData = {
			stickyPos:[1, 1, 2, 0],
			stickyReels:[1, 0, 0, 4],
			stickySymbolIds:[11804, 11804, 11804, 11804]
		}
	//--------------- show stickyData end ---------------
	
	//--------------- move stickyData -------------------
		var moveStickyData = {
			stickyPos: [1, 2, 1, 0],
			stickyReels: [0, 0, 2, 3],
			stickySymbolIds: [11804, 11804, 11804, 11804]
		}
		
		var moveFromTo = [
			[0, 1, 0, 1],  
			[0, 2, 0, 2],
			[1, 1, 2, 1],
			[4, 0, 3, 0]
		];
	//--------------- move stickyData end ---------------
	
	function get_remainingWanderingSymbols():Int {
		return showStickyData.stickySymbolIds.length;
	}
	
	function shiftShowStickyData():Void {
		showStickyData.stickyPos.shift();
		showStickyData.stickyReels.shift();
		showStickyData.stickySymbolIds.shift();
	}
	
	function shiftMoveStickyData():Void {
		moveStickyData.stickyPos.shift();
		moveStickyData.stickyReels.shift();
		moveStickyData.stickySymbolIds.shift();
		moveFromTo.shift();
	}
	
	public function new(jsonName:String, parantContainer:IGameContainer) {
		libraryName = jsonName;
		parent = parantContainer;
		createRoot();
		init();
		registerFlowActor();
	}
	
	function get_SYMBOL_MARGIN():Int {
		return SYMBOL_MARGIN;
	}
	
	function createRoot():Void {
		root = cast(Library.create(libraryName, "root"), IGameContainer);
		parent.addChild(root);
	}
	
	function init():Void {
		addSymbolsToPosContainers();
	}
	
	function addSymbolsToPosContainers():Void {
		for (child in root.children) {
			if (StringTools.startsWith(child.name, "pos_")) {
				var column:Int = Std.parseInt(child.name.charAt(4));
				if (posContainers[column] == null) posContainers[column] = [];
				posContainers[column].push(cast (child, IGameContainer));
			}
		}
		
		for (column in 0...posContainers.length) {
			for (row in 0...posContainers[column].length) {
				for (symbolId in WANDERING_SYMBOLS_ID.keys()) {
					var wandaringSymbolAnim = cast (Library.create(libraryName, "WanderingSymbol_" + WANDERING_SYMBOLS_ID[symbolId]), IGameAnimation);
					wandaringSymbolAnim.name = Std.string(symbolId);
					posContainers[column][row].addChild(wandaringSymbolAnim);
				}
			}
		}
	}
	
	@:flowExposed
	public function wanderingSymbolNext(state:String, event:String = ""):Notifier {
		var wanderingSymbolNextEnd:Notifier = new Notifier();
		var column:Int = showStickyData.stickyReels[0];
		var row:Int = showStickyData.stickyPos[0];
		var symbolId = showStickyData.stickySymbolIds[0];
		var symbol:IGameAnimation = cast posContainers[column][row].getChildByName(Std.string(symbolId % SYMBOL_MARGIN));
		symbol.forceState(state);
		if (event != "") {
			symbol.events[event].addOnce(function(e:EventParams){
				wanderingSymbolNextEnd.dispatch();
				
			});
		} else {
			wanderingSymbolNextEnd.dispatch();
		}
		shiftShowStickyData();
		return wanderingSymbolNextEnd;
	}
	
	//function setSymbolStateAtPosition(state:String, column:Int, row:Int, symbol:Int, ?animEndNotifier:Notifier = null):Void {
		//var symbol:IGameAnimation = cast posContainers[column][row].getChildByName(Std.string(symbol % SYMBOL_MARGIN));
		//symbol.events["anim_end"].addOnce(function(e:EventParams){
			//animEndNotifier != null ? animEndNotifier.dispatch() : setSymbolStateAtPositionEnd.dispatch();
		//});
		//symbol.forceState(state);
	//}
	
	//function setStateForAllBonusSymbols(state:String, delayBetweenAnims:Float = 0.0, columns:Array<Int>, rows:Array<Int>, symbols:Array<Int>, ?completeNotifier:Notifier = null):Void {
		//var ac:ActionContainer = ActionContainer.get();
		//for (i in 0...symbols.length) {
			//if (i > 0) ac.addDelay(delayBetweenAnims);
			//ac.addFunction(setSymbolStateAtPosition.bind(state, columns[i], rows[i], symbols[i]));
			//if (i == symbols.length - 1) ac.addWaitEvent(setSymbolStateAtPositionEnd);
		//}
		//ac.start(completeNotifier != null ? completeNotifier.dispatch : null);
	//}
	
	//@:flowExposed
	//public function playAnimToAllSymbols(?state:String, ?delayBetweenAnims:Float = 0.0, ?columns:Array<Int>, ?rows:Array<Int>, ?symbols:Array<Int>, ?completeNotifier:Notifier):INotifier {
		//setStateForAllBonusSymbols(state, delayBetweenAnims, columns, rows, symbols, completeNotifier);
		//var a:Notifier = new Notifier();
		//trace("-----------------------------------------------------------------------------------------------------");
		//hide 
		//init 
		//show 
		//shown 
		//win
		//hidden
		//TimeOffset.setDelay(0.1, a.dispatch);
		//return a;
	//}
	
	//public function moveSymbols(allSymbolsMoves:Array<Array<Int>>, symbols:Array<Int>, ?diagonalMotionAllowed:Bool = true):Void {
		//var allSymbolsMovesCopy = allSymbolsMoves.map(function(arr:Array<Int>) { return arr.copy(); });
		//var symbolsToMove = symbols.copy();
		//var symbolMove = allSymbolsMovesCopy[0].copy();
		//var symbolId = symbolsToMove[0];
		//
		//if (!currentAndNewPosAreTheSame(symbolMove)) {
			//moveAnimEnd.addOnce(function(){
				//setSymbolStateAtPosition("hidden",  symbolMove[0], symbolMove[1], symbolId);
				//symbolMove = setNewPosBaseOnDirection(getMoveDirection(symbolMove, diagonalMotionAllowed), symbolMove);
				//allSymbolsMovesCopy[0] = symbolMove;
				//moveSymbols(allSymbolsMovesCopy, symbolsToMove, diagonalMotionAllowed);
			//});
			//setSymbolStateAtPosition(getMoveDirection(symbolMove, diagonalMotionAllowed), symbolMove[0], symbolMove[1], symbolId, moveAnimEnd);
		//} else {
			//setSymbolStateAtPositionEnd.addOnce(function(){
				//allSymbolsMovesCopy.shift();
				//symbolsToMove.shift();
				//if (allSymbolsMovesCopy.length > 0) {
					//moveSymbols(allSymbolsMovesCopy, symbolsToMove, diagonalMotionAllowed);
				//} else {
					//allMovesSymbolsComplete.dispatch();
				//}
			//});
			//setSymbolStateAtPosition("shown", symbolMove[0], symbolMove[1], symbolId);
		//}
	//}
	
	function getMoveDirection(moveFromTo:Array<Int>, diagonalMotionAllowed:Bool = true):String {
		var direction:String = "";																		
		var currentColumnPos:Int = moveFromTo[0];														
		var currentRowPos:Int = moveFromTo[1];															
		var newColumnPos:Int = moveFromTo[2];															
		var newRowPos:Int = moveFromTo[3];
		if (diagonalMotionAllowed) {
			if (currentColumnPos > newColumnPos && currentRowPos == newRowPos) 		direction = "go_w";		
			else if (currentColumnPos < newColumnPos && currentRowPos == newRowPos) direction = "go_e";		
			else if (currentRowPos > newRowPos && currentColumnPos == newColumnPos) direction = "go_n";		
			else if (currentRowPos < newRowPos && currentColumnPos == newColumnPos) direction = "go_s";	
			else if (currentColumnPos > newColumnPos && currentRowPos > newRowPos)	direction = "go_nw";	
			else if (currentColumnPos < newColumnPos && currentRowPos > newRowPos) 	direction = "go_ne";	
			else if (currentColumnPos > newColumnPos && currentRowPos < newRowPos) 	direction = "go_sw";	
			else if (currentColumnPos < newColumnPos && currentRowPos < newRowPos) 	direction = "go_se";
		} else {
			if (currentColumnPos > newColumnPos) 		direction = "go_w";		
			else if (currentColumnPos < newColumnPos)	direction = "go_e";		
			else if (currentRowPos > newRowPos) 		direction = "go_n";		
			else if (currentRowPos < newRowPos) 		direction = "go_s";
		}
		return direction;
	}
	
	function currentAndNewPosAreTheSame(fromToPos:Array<Int>):Bool {
		return fromToPos[0] == fromToPos[2] && fromToPos[1] == fromToPos[3];
	}
	
	function setNewPosBaseOnDirection(direction:String, fromToPos:Array<Int>):Array<Int> {
		switch (direction) {
			case "go_w":
				fromToPos[0] -= 1;
			case "go_e":
				fromToPos[0] += 1;
			case "go_n":
				fromToPos[1] -= 1;
			case "go_s":
				fromToPos[1] += 1;
			case "go_nw":
				fromToPos[0] -= 1;
				fromToPos[1] -= 1;
			case "go_ne":
				fromToPos[0] += 1;
				fromToPos[1] -= 1;
			case "go_sw":
				fromToPos[0] -= 1;
				fromToPos[1] += 1;
			case "go_se":
				fromToPos[0] += 1;
				fromToPos[1] += 1;
		}
		return fromToPos;
	}
	
	//             N 	
	//  		   | 	
	//     NW   )  |  (   NE
	//        )    |    (    
	//      )      |      (    
	// W--)--------O--------(--E 
	//      )      |      (   
	//        )    |    (   
	//     SW   )  |  (   SE 
	//            )|(      
	//   		   |  
	//             S
}

haxe Haxe-OpenFL-Flixel字体嵌入

font embedding
// In project XML add the following line
<assets path="assets/fonts" rename="fonts" if="html5" />

// CREATE Font.hx Class
package;
 
import openfl.text.Font;
import openfl.Assets;
 
class Fonts {
    public static var RALEWAY_EXTRALIGHT(default, null):String;
 
    public static function init():Void {
    #if js
        RALEWAY_EXTRALIGHT = Assets.getFont("fonts/raleway-extralight.ttf").fontName;
    #else
        Font.registerFont(RalewayExtraLight);
        RALEWAY_EXTRALIGHT = (new RalewayExtraLight()).fontName;
    #end
    }
}
 
@:font("assets/fonts/raleway-extralight.ttf")
private class RalewayExtraLight extends Font {}


// In Main.hx use it like so
package;
 
import openfl.display.Sprite;
import openfl.Lib;
import openfl.text.TextField;
import openfl.text.TextFormat;
 
class Main extends Sprite {
    public function new() {
        super();
        Fonts.init();
 
        var tf = new TextFormat(Fonts.RALEWAY_EXTRALIGHT, 32);
        var t = new TextField();
        t.embedFonts = true;
        t.defaultTextFormat = tf;
        t.text = Fonts.RALEWAY_EXTRALIGHT;
        t.width = t.textWidth;
 
        this.addChild(t);
    }
}

haxe JSGenerator.hx

JSGenerator.hx
package amd;

#if macro

import haxe.macro.Type;
import haxe.macro.Expr;
import haxe.macro.*;
import haxe.ds.*;

using Lambda;
using StringTools;

using amd.JsGenerator.StringExtender;

class StringExtender {
	static public function asJSFieldAccess(s:String, api:JSGenApi) {
		return api.isKeyword(s) ? '["' + s + '"]' : "." + s;
	}
	static public function asJSPropertyAccess(s:String, api:JSGenApi) {
		return api.isKeyword(s) ? '"' + s + '"' : s;
	}
	static public function indent(s:String, level:Int) {
		var iStr = '';
		while (level > 0) {
			iStr += '\t';
			level -= 1;
		}
		return s.replace('\n', '\n$iStr');
	}
	static public function dedent(s:String, level:Int) {
		var iStr = '';
		while (level > 0) {
			iStr += '\t';
			level -= 1;
		}
		return s.replace('\n$iStr', '\n');
	}
}

enum Forbidden {
	prototype;
	__proto__;
	constructor;
}

enum StdTypes {
	Int;
	Float;
	Bool;
	Class;
	Enum;
	Dynamic;
}

enum JSTypes {
	Array;
	String;
	Object;
	Date;
	XMLHttpRequest;
	Math;
}

interface IField {
	var name:String;
	var code:String;
	var path:String;
	var isStatic:Bool;
	var dependencies:StringMap<String>;
	public function getCode():String;
}

interface IKlass {
	var name:String;
	var code:String;
	var superClass:String;
	var interfaces:Array<String>;
	var dependencies:StringMap<String>;
	public function getCode():String;
	var members: StringMap<IField>;
}

interface IPackage {
	var name:String;
	var code:String;
	var members: StringMap<IKlass>;
}

class Module {
	public var name:String = "";
	public var path:String = "";
	public var dependencies: StringMap<String> = new StringMap<String>();
	public var code: String = "";
	public var isStatic:Bool = false;

	public var gen:JsGenerator;

	public function new(_gen) {
		gen = _gen;
	}

	function addDependency(dep:String) {
		gen.addDependency(dep, this);
	}

	inline function _print(b:StringBuf, str:String){
		b.add(str);
	}

	inline function _newline(b:StringBuf) {
		b.add(";\n");
	}

	function formatFieldName(name:String):String {
		return gen.api.isKeyword(name) ? '["' + name + '"]' : "." + name;
	}

	public var fieldName(get, never):String;

	function get_fieldName() {
		return name.asJSFieldAccess(gen.api);
	}
}

class Field extends Module implements IField {
	public var fieldAccessName:String;
	public var propertyAccessName:String;

	public function getCode() {
		 return code;
	}

	public function build(f: ClassField, classPath:String) {
		name = f.name;
		path = '$classPath.$name';
		fieldAccessName = name.asJSFieldAccess(gen.api);
		propertyAccessName = name.asJSPropertyAccess(gen.api);
		var e = f.expr();
		if( e == null ) {
			code = 'null';
		} else {
			code = gen.api.generateValue(e);
		}
		for (dep in gen.getDependencies().keys()) {
			addDependency(dep);
		}
	}
}

class Klass extends Module implements IKlass {
	public var members: StringMap<IField> = new StringMap();
	public var init: TypedExpr;

	public var superClass:String = null;
	public var interfaces:Array<String> = new Array();
	public var properties:Array<String> = new Array();

	public function getCode() {
		var t = new haxe.Template('
// Class: ::path::
::if (dependencies.length > 0)::
// Dependencies:
	::foreach dependencies::
//	::__current__::
	::end::
::end::
::if (overrideBase)::::if (useHxClasses)::$$hxClasses["::path::"] = ::className::::end::
::else::var ::className:: = ::if (useHxClasses == true)::$$hxClasses["::path::"] = ::end::::code::;
::if (interfaces != "")::::className::.__interfaces__ = [::interfaces::];
::end::::if (superClass != null)::::className::.__super__ = ::superClass::;
::className::.prototype = $$extend(::superClass::.prototype, {
::else::::className::.prototype = {
::end::::if (propertyString != "")::	"__properties__": {::propertyString::},
::end::::foreach members::	::propertyAccessName::: ::code::,
::end::	__class__: ::className::
}::if (superClass != null)::)::end::;
::className::.__name__ = "::path::";::end::
::foreach statics::::className::::fieldAccessName:: = ::code::;
::end::::if (init != "")::// Initialization Code
::init::::end::
');
		function filterMember(member:IField) {
			var f = new Field(gen);
			f.name = member.name;
			f.fieldAccessName = f.name.asJSFieldAccess(gen.api);
			f.propertyAccessName = f.name.asJSPropertyAccess(gen.api);
			f.isStatic = member.isStatic;
			f.code = member.getCode();
			if (!f.isStatic) {
				f.code = f.code.indent(1);
			}
			return f;
		}

		var initCode = "";
		if (init != null) {
			initCode = gen.api.generateStatement(init);
			initCode = initCode.substring(1, initCode.length - 1).trim().dedent(1);
		}

		var data = {
			overrideBase: Reflect.hasField(JSTypes, name),
			className: name,
			path: path,
			code: code,
			useHxClasses: gen.hasFeature('Type.resolveClass') || gen.hasFeature('Type.resolveEnum'),
			init: initCode,
			dependencies: [for (key in dependencies.keys()) key],
			interfaces: interfaces.join(','),
			superClass: superClass,
			propertyString: [for (prop in properties) '"$prop":"$prop"'].join(','),
			members: [for (member in members.iterator()) filterMember(member)].filter(function(m) { return !m.isStatic; }),
			statics: [for (member in members.iterator()) filterMember(member)].filter(function(m) { return m.isStatic; })
		};
		return t.execute(data);
	}

	public function addField(c: ClassType, f: ClassField) {
		gen.checkFieldName(c, f);
		gen.setContext(path + '.' + f.name);

		if(f.name.indexOf("get_") == 0 || f.name.indexOf("set_") == 0)
		{
			properties.push(f.name);
		}
		switch( f.kind )
		{
			case FVar(r, _):
				if( r == AccResolve ) return;
			default:
		}

		var field = new Field(gen);
		field.build(f, path);
		for (dep in field.dependencies.keys()) {
			addDependency(dep);
		}
		members.set(f.name, field);
	}

	public function addStaticField(c: ClassType, f: ClassField) {
		gen.checkFieldName(c, f);
		gen.setContext(path + '.' + f.name);
		var field = new Field(gen);
		field.build(f, path);
		field.isStatic = true;
		for (dep in field.dependencies.keys()) {
			addDependency(dep);
		}
		members.set(field.name, field);
	}

	public function build(c: ClassType) {
		name = c.name;
		path = gen.getPath(c);

		gen.setContext(path);
		init = c.init;

		if( c.constructor != null ) {
			code = gen.api.generateStatement(c.constructor.get().expr());
		} else {
			code = "function() {}";
		}

		// Add Haxe type metadata
		if( c.interfaces.length > 0 ) {
			interfaces = [for (i in c.interfaces) gen.getTypeFromPath(gen.getPath(i.t.get()))];
		}
		if( c.superClass != null ) {
			gen.hasClassInheritance = true;
			superClass = gen.getTypeFromPath(gen.getPath(c.superClass.t.get()));
		}
		for (dep in gen.getDependencies().keys()) {
			addDependency(dep);
		}

		if (!c.isExtern) {
			for( f in c.fields.get() ) {
				addField(c, f);
			}

			for( f in c.statics.get() ) {
				addStaticField(c, f);
			}
		}
	}
}


class EnumModuleField extends Module implements IField {
	var isFunction:Bool;
	var index:Int;
	var enumName:String;
	var argNames:String;
	public var fieldAccessName:String;

	public function getCode() {
		var t = new haxe.Template('function(::argNames::) { var $$x = [::quoteName::,::index::::if (isFunction)::,::argNames::::end::]; $$x.__enum__ = ::enumName::; return $$x; }::if (!isFunction)::()::end::');

		var data = {
			argNames: argNames,
			index: index,
			isFunction: isFunction,
			enumName: enumName,
			quoteName: gen.api.quoteString(name)
		};

		return t.execute(data);
	}

	public function build(e: EnumField, classPath:String) {
		name = e.name;
		fieldAccessName = name.asJSFieldAccess(gen.api);
		enumName = classPath;
		path = '$classPath.$name';
		index = e.index;

		switch( e.type )
		{
			case TFun(args, _):
				argNames = args.map(function(a) return a.name).join(",");
				isFunction = true;
			default:
				isFunction = false;
				argNames = "";
		}
	}
}


class EnumModule extends Module implements IKlass {
	var names:String;
	var constructs:String;
	public var superClass:String;
	public var interfaces:Array<String> = [];
	public var members:StringMap<IField> = new StringMap();

	public function getCode() {
		var t = new haxe.Template('
// Enum: ::path::
::if (dependencies.length > 0)::
// Dependencies:
	::foreach dependencies::
//	::__current__::
	::end::
::end::
var ::enumName:: = { __ename__ : [::names::], __constructs__ : [::constructs::] };
::if (code != "")::::enumName::.__meta__ = ::code::;::end::
::foreach members::::enumName::::fieldAccessName:: = ::code::;
::end::
');
		function filterMember(member:IField) {
			var f = new EnumModuleField(gen);
			f.name = member.name;
			f.fieldAccessName = f.name.asJSFieldAccess(gen.api);
			f.code = member.getCode();
			return f;
		}

		var data = {
			enumName: name,
			code: code,
			path: path,
			dependencies: [for (key in dependencies.keys()) key],
			names: names,
			constructs: constructs,
			members: [for (member in members.iterator()) filterMember(member)]
		};

		return t.execute(data);
	}

	public function addField(e: EnumType, construct: EnumField) {
		gen.checkFieldName(e, construct);
		gen.setContext(path + '.' + e.name);
		var field = new EnumModuleField(gen);
		field.build(construct, path);

		members.set(construct.name, field);
	}

	public function build(e: EnumType) {
		name = e.name;
		path = gen.getPath(e);
		gen.setContext(path);

		names = path.split(".").map(gen.api.quoteString).join(",");
		constructs = e.names.map(gen.api.quoteString).join(",");

		for( c in e.constructs.keys() ) {
			addField(e, e.constructs.get(c));
		}
		var meta = gen.api.buildMetaData(e);
		if( meta != null ) {
			code = gen.api.generateStatement(meta);
		}
	}
}


class Package extends Module implements IPackage {
	public var isMain:Bool = false;
	public var members: StringMap<IKlass> = new StringMap();

	public function isEmpty():Bool {
		return !members.keys().hasNext() && code == "";
	}

	public function collectDependencies() {
		function hasDependency(key) {
			return ! dependencies.exists(key);
		}

		for( member in members ) {
			for( dep in [for (key in member.dependencies.keys()) key] ) {
				gen.addDependency(dep, this);
				member.dependencies.remove(dep);
			}
		}
	}

	public function getCode() {
		var pre = new haxe.Template('// Package: ::packageName::
define([::dependencyNames::],
	   function (::dependencyVars::) {
');

		//  Collect the package's dependencies into one array
		var allDeps = new StringMap();
		var memberValues = [for (member in members.iterator()) member];
		var depKeys = [for (k in dependencies.keys()) k];

		function formatMember(m: IKlass) {
			var name = m.name;
			var access = m.name.asJSPropertyAccess(gen.api);

			return '$access: $name';
		}

		var data = {
			packageName: name.replace('.', '_'),
			path: path,
			dependencyNames: [for (k in depKeys) gen.api.quoteString(k.replace('.', '_'))].join(', '),
			dependencyVars: [for (k in depKeys) k.replace('.', '_')].join(', '),
			members: [for (member in memberValues) formatMember(member)].join(',\n\t\t'),
			singleMember: ""
		};
		code = pre.execute(data);

		for (member in members) {
			code += member.getCode().indent(1);
		}

		var post:haxe.Template;

		if (memberValues.length == 1) {
			data.singleMember = memberValues[0].name;
			post = new haxe.Template('return ::singleMember::;
});
');
		} else {
			post = new haxe.Template('return {
		::members::
	};
});
');
		}

		code += post.execute(data);
		return code;
	}
}


class MainPackage extends Package {
	public override function getCode() {
		var pre = new haxe.Template('// Package: ::packageName::
require([::dependencyNames::],
	    function (::dependencyVars::) {
');

		//  Collect the package's dependencies into one array
		var allDeps = new StringMap();
		var depKeys = [for (k in dependencies.keys()) k];

		var data = {
			packageName: name.replace('.', '_'),
			path: path,
			dependencyNames: depKeys.map(gen.api.quoteString).join(', '),
			dependencyVars: [for (k in depKeys) k.replace('.', '_')].join(', '),
		};
		var _code = pre.execute(data);

		_code += '\t$code';

		var post = new haxe.Template('
});
');
		_code += post.execute(data);
		return _code;
	}
}


class JsGenerator
{
	public var api : JSGenApi;

	var packages : StringMap<Package>;
	var forbidden : StringMap<Bool>;
	var baseJSModules : haxe.ds.StringMap<Bool>;
	public var currentContext: Array<String>;
	var dependencies: StringMap<String> = new StringMap();
	var assumedFeatures: StringMap<Bool> = new StringMap();

	var curBuf : StringBuf;
	var mainBuf : StringBuf;
	var external : Bool;
	public var hasClassInheritance: Bool = false;

	public function new(api)
	{
		this.api = api;
		mainBuf = new StringBuf();

		curBuf = mainBuf;
		currentContext = [];
		packages = new StringMap<Package>();
		forbidden = new StringMap();
		external = false;

		api.setTypeAccessor(getType);
	}

	public function hasFeature(name:String):Bool {
		var d = Context.definedValue(name);
		if (d != null) {
			return ["false", "no", ""].indexOf(d.toLowerCase()) == -1;
		}

		#if (haxe_ver >= 3.2)
		return api.hasFeature(name);
		#else
		if (!assumedFeatures.exists(name)) {
			Context.warning('Assuming feature "$name" is true until 3.2 is released.', Context.currentPos());
			assumedFeatures.set(name, true);
		}
		return true;
		#end

	}
	public function addDependency(dep:String, ?container:Module) {
		var name = dep;

		if (container == null) {
			dependencies.set(dep, name);
		} else if (! Reflect.hasField(JSTypes, dep)) {
			if (dep != container.path) {
				container.dependencies.set(name, name);
			} else {
			}
		} else {
			return "";
		}
		return name;
	}

	function getType( t : Type )
	{
		var origName = switch(t)
		{
			case TInst(c, _):
				getPath(c.get());
			case TEnum(e, _):
				getPath(e.get());
			case TAbstract(c, _):
				c.get().name;
			default: throw "assert: " + t;
		};

		return getTypeFromPath(origName);
	}

	public function getTypeFromPath(origName: String) {
		if (Reflect.hasField(StdTypes, origName)) {
			addDependency("Std");
		} else {
			addDependency(origName);
		}

		if (Reflect.hasField(JSTypes, origName)) {
			return origName;
		} else {
			return '/* "$origName" */';
		}
	}

	inline function print(str){
		curBuf.add(str);
	}

	public function getPath( t : BaseType ) {
		return (t.pack.length == 0) ? t.name : t.pack.join(".") + "." + t.name;
	}

	public function checkFieldName( c : {pos:Position}, f : {name:String} ) {
		if( forbidden.exists(f.name) )
			Context.error("The field " + f.name + " is not allowed in JS", c.pos);
	}

	public function setContext(ctxt:String) {
		currentContext = [ctxt];
		dependencies = new StringMap<String>();
	}

	public function getDependencies() {
		var depCopy = new StringMap<String>();
		for (key in dependencies.keys()) {
			depCopy.set(key, dependencies.get(key));
		}
		dependencies = new StringMap<String>();
		return depCopy;
	}

	function traverseClass( c : ClassType )
	{
		var pack = new Package(this);
		var kls = new Klass(this);
		api.setCurrentClass(c);
		kls.build(c);

		pack.path = getPath(c);
		pack.name = pack.path;
		if (pack.name == "") {
			pack.name = "core";
		}
		packages.set(pack.path, pack);
		pack.members.set(c.name, kls);
	}

	function traverseEnum( e : EnumType )
	{
		var kls = new EnumModule(this);
		kls.build(e);
		var pack = new Package(this);
		pack.path = getPath(e);
		pack.name = pack.path;
		if (pack.name == "") {
			pack.name = "core";
		}
		packages.set(pack.path, pack);
		pack.members.set(kls.name, kls);
	}

	function traverseType( t : Type )
	{
		switch( t )
		{
			case TInst(c, _):
				var c = c.get();
				if( !c.isExtern || ["Math", "Number"].indexOf(c.name) != -1) {
					traverseClass(c);
				} else {
					var path = getPath(c);
					// Context.warning('Skipping over Extern Class: $path', Context.currentPos());
				}
			case TEnum(r, _):
				var e = r.get();
				if( !e.isExtern ) {
					traverseEnum(e);
				} else {
					var path = getPath(e);
					// Context.warning('Skipping over Extern Enum: $path', Context.currentPos());
				}
			// case TAbstract(a, _):
			// 	var name = a.get().name;
			// 	Context.warning('Skipping over Abstract: $name', Context.currentPos());
			// case TType(tt, _):
			// 	var name = tt.get().name;
			// 	Context.warning('Skipping over Type: $name', Context.currentPos());
			default:
				// Context.error('' + t, Context.currentPos());
		}
	}

	function purgeEmptyPackages() {
		// Dispose of Empty Packages
		var emptyPackages = [for (k in packages.keys()) k].filter(function(pName) { return packages.get(pName).isEmpty(); });
		if (emptyPackages.length > 0) {
			Context.warning('' + emptyPackages + ' are all empty packages.', Context.currentPos());
			for (name in emptyPackages) {
				packages.remove(name);
			}
		}
	}

	function cleanPackageDependencies(message="") {
		// Remove dependencies to non-existent packages
		var packageNames = [for (pack in packages) pack.path];
		for (pack in packages) {
			for (dep in pack.dependencies.keys()) {
				if (packageNames.indexOf(dep) == -1) {
					Context.warning('Removing dependency "$dep" from "${pack.name}".  $message', Context.currentPos());
					pack.dependencies.remove(dep);
				}
			}
		}
	}

	function checkForCyclicPackageDependencies():Array<String> {
		// Check packages for cyclic dependencies
		for( pack in packages.iterator() ) {
			var alreadyChecked = [pack.path];
			var depQueue = [for (dep in pack.dependencies.keys()) {path: dep, depPath: [pack.path]} ];

			while (depQueue.length > 0) {
				var dep = depQueue.shift();

				if (dep.path == pack.path) {
					Context.warning('${pack.name} is cyclically dependent along: ' + dep.depPath.join(' -> '), Context.currentPos());
					return dep.depPath;
				}

				if (alreadyChecked.indexOf(dep.path) != -1) {
					continue;
				}

				if (packages.exists(dep.path)) {
					var depPack = packages.get(dep.path);
					for (packDepKey in depPack.dependencies.keys()) {
						var queueStruct = {path: packDepKey, depPath: dep.depPath.concat([dep.path])}
						if (depQueue.indexOf(queueStruct) == -1) {
							depQueue.push(queueStruct);
						}
					}
				} else {
					Context.error('\tDepends on unknown module "$dep"', Context.currentPos());
				}
				alreadyChecked.push(dep.path);
			}
		}
		return [];
	}

	function joinPackages(a:Package, b:Package):Package {
		Context.warning('Joining packages ${a.path} and ${b.path}', Context.currentPos());
		for (member in a.members.keys()) {
			if (b.members.exists(member)) {
				Context.error('Cannot join packages ${a.path} and ${b.path} because they both have a member named $member.', Context.currentPos());
			}
			b.members.set(member, a.members.get(member));
		}
		b.code += '\n' + a.code;

		b.collectDependencies();
		return b;
	}

	function joinCyclicPackages() {
 		var cyclicPackages = [for (packName in checkForCyclicPackageDependencies()) packages.get(packName)];
		while(cyclicPackages.length != 0) {
			var finalPackage = cyclicPackages.slice(1).fold(joinPackages, cyclicPackages[0]);
			cyclicPackages = cyclicPackages.slice(1);
			for (pack in cyclicPackages) {
				packages.set(pack.path, finalPackage);
				finalPackage.dependencies.remove(pack.path);
			}
			cyclicPackages = [for (packName in checkForCyclicPackageDependencies()) packages.get(packName)];
		}
	}

	function replaceType(f:EReg):String {
		var m = f.matched(1);
		var pack = packages.get(currentContext[0]);
		var memberName = m.substring(m.lastIndexOf('.') + 1);

		if (pack.members.exists(m)) {
			return m; // '(1) -> $m';
		} else if (pack.members.exists(memberName)) {
			return memberName; // '(2) -> $memberName';
		} else if (pack.dependencies.exists(m)) {
			var depPack = packages.get(m);

			if (!depPack.members.exists(memberName)) {
				Context.error('${pack.path} depends on $memberName from package ${depPack.path}, ${depPack.path} contains no member by that name.', Context.currentPos());
			}

			if (depPack.name != m) {
				// When packages are joined, the dependency name doesn't get updated so we do that here.
				pack.dependencies.set(depPack.name, pack.dependencies.get(m));
			}

			if (depPack.members.list().length == 1) {
				var depName = m.replace('.', '_');
				return depName; // '(3) -> $depName';
			} else {
				var depName = depPack.name.replace('.', '_');
				return '$depName.$memberName'; // (4) -> $depName.$memberName';
			}
		} else {
			Context.warning('Assuming "$m" is available in "${pack.name}" scope.', Context.currentPos());
			return m; // '(5) -> $m';
		}
	}

	function replaceTypeComments(pack:Package) {
		var typeFinder = new EReg('\\/\\* "([A-Za-z.]+)" \\*\\/', 'g');

		currentContext = [pack.path];
		pack.code = typeFinder.map(pack.code, replaceType);

		for (klsKey in pack.members.keys() ) {
			var kls = pack.members.get(klsKey);

			currentContext = [pack.path, klsKey];
			for (field in kls.members.iterator()) {
				field.code = typeFinder.map(field.code, replaceType);
			}
			kls.code = typeFinder.map(kls.code, replaceType);
			if (kls.superClass != null) {
				kls.superClass = typeFinder.map(kls.superClass, replaceType);
			}
			kls.interfaces = [for (iface in kls.interfaces) typeFinder.map(iface, replaceType)];
		}
	}

	public function generate()
	{
		// Parse types and build packages
		api.types.map(traverseType);

		// Run through each package, making sure that it has collected the dependencies of it's members.
		for (pack in packages) { pack.collectDependencies(); }

		purgeEmptyPackages();
		cleanPackageDependencies("Assuming a global dependency.");
		joinCyclicPackages();

		// Special case, merge Math into Std
		if (packages.exists('Math') && packages.exists('Std')) {
			var stdPackage = joinPackages(packages.get('Math'), packages.get('Std'));
			packages.set('Math', stdPackage);
			packages.set('Std', stdPackage);
		}

		// Replace type comments
		for( pack in packages.iterator() ) {
			replaceTypeComments(pack);
		}

		var mainPack:MainPackage;
		if(api.main != null) {
			setContext("main");
			mainPack = new MainPackage(this);
			mainPack.name = 'main';
			mainPack.path = 'main';
			mainPack.code = api.generateStatement(api.main);
			for (dep in getDependencies().keys()) {
				addDependency(dep, mainPack);
			}
			packages.set('main', mainPack);
			replaceTypeComments(mainPack);
		}

		cleanPackageDependencies("It has been superceded by another dependency.");

		print("window.$hxClasses = {};");
		print('if (!window.require) alert("You must include an AMD loader such as RequireJS.");\n');

		if (hasFeature("may_print_enum")) {
			print("$estr = function() { return js.Boot.__string_rec(this,''); };\n");
		}

		if (hasClassInheritance) {
			print("function $extend(from, fields) {
	function Inherit() {} Inherit.prototype = from; var proto = new Inherit();
	for (var name in fields) proto[name] = fields[name];
	if( fields.toString !== Object.prototype.toString ) proto.toString = fields.toString;
	return proto;
};\n");
		}

		// Loop through the created packages.
		for( pack in packages.iterator() ) {
			curBuf = new StringBuf();
			var filename = pack.name.replace('.', '_');

			print(pack.getCode());
			// Put it all in a file.
			var filePath = api.outputFile.substring(0, api.outputFile.lastIndexOf("/"));
			filePath += '/$filename.js';
			sys.io.File.saveContent(filePath, curBuf.toString());
		}
		print("\n");

		curBuf = mainBuf;

		if( api.main != null ) {
			print(mainPack.getCode());
		}

		sys.io.File.saveContent(api.outputFile, mainBuf.toString());
	}

	#if macro
	public static function use()
	{
		Compiler.setCustomJSGenerator(function(api) new JsGenerator(api).generate());
	}
	#end

}
#end

haxe RegTest.hx

haxe_output.js
(function () { "use strict";
var RegTest = function() {
	this.ram = new Uint8Array(65536);
};
RegTest.main = function() {
	var foo = new RegTest();
	foo.whatIsR0();
};
RegTest.prototype = {
	whatIsR0: function() {
		console.log("r0 is " + this.ram[123]);
	}
	,get_r0: function() {
		return this.ram[123];
	}
	,set_r0: function(value) {
		return this.ram[123] = value;
	}
};
RegTest.main();
})();
RegisterMacro.hx
package  ;

import haxe.macro.Context;
import haxe.macro.Expr;

class RegisterMacro
{
    macro static public function memoryMappedRegister(fieldName:String,index :Int):Array<Field> {
    	var fields = Context.getBuildFields();
    	
    	var getterName = "get_" + fieldName;
    	var setterName = "set_" + fieldName;
    	var propertyFromMacro = macro : {
    		var $fieldName(get, set) : Int;
    		inline function $getterName() : Int {
    			return ram[ $v{index} ];
            }
    		 inline function $setterName(value:Int) : Int {
                    return ram[$v{index}]=value;
            }
    	};
    	switch (propertyFromMacro) {
    		case TAnonymous(getterFields):
    			fields=fields.concat(getterFields);
    		default:
    			throw 'unreachable';
    	}
	
    return fields;
    }
}
RegTest.hx
import js.html.Uint8Array;

@:build( RegisterMacro.memoryMappedRegister("r0",123) )
class RegTest
{
	var ram : Uint8Array;
	
	public function new() {
		ram = new Uint8Array(65536);
	}
	
	public function whatIsR0() {
		trace("r0 is "+r0);
	}
    
    static function main() {
        var foo = new RegTest();
        foo.whatIsR0();
    }
}

haxe Main.hx

generated.js
(function () { "use strict";
var Main = function() { };
Main.main = function() {
	var tower = { a : 0, b : "", c : 0, d : false, e : [1,2,3], f : { g : []}};
	console.log(tower);
};
Main.main();
})();
StructHelper.hx
#if macro
import haxe.macro.Expr;
import haxe.macro.Context;
import haxe.macro.Type;
using haxe.macro.Tools;
#end

@:dce
class StructHelper {
    public static macro function make(typeExpr:Expr, fieldExprs:Array<Expr>):Expr {
        var type = try
                Context.getType(typeExpr.toString())
            catch (e:Dynamic)
                throw new Error(e.toString(), typeExpr.pos);

        switch (type.follow()) {
            case TAnonymous(_.get() => anon):
                var fieldInits = new Map();
                for (e in fieldExprs) {
                    switch (e) {
                        case macro $i{fieldName} = $value:
                            fieldInits[fieldName] = {expr: value.expr, pos: e.pos};
                        default:
                            throw new Error("Invalid field initialization expression: should be fieldName = value", e.pos);
                    }
                }

                var pos = Context.currentPos();
                var objectDecl = getAnonDefaultValueExpr(anon, pos, fieldInits);
                var objectType = type.toComplexType();
                return macro @:pos(pos) ($objectDecl : $objectType);
            default:
                throw new Error("Make should only be used on structure types", typeExpr.pos);
        }
    }

    #if macro
    static function getDefaultValueExpr(type:Type, pos:Position):Expr {
        var e = switch (type.follow()) {
            case TAbstract(_.get() => {pack: [], name: "Int" | "Float"}, []):
                macro 0;
            case TAbstract(_.get() => {pack: [], name: "Bool"}, []):
                macro false;
            case TInst(_.get() => {pack: [], name: "Array"}, [_]):
                macro [];
            case TInst(_.get() => {pack: [], name: "String"}, []):
                macro "";
            case TAnonymous(_.get() => anon):
                getAnonDefaultValueExpr(anon, pos);
            default:
                throw new Error("Unsupported type for generating default value: " + type.toString(), pos);
        }
        e.pos = pos;
        return e;
    }

    static function getAnonDefaultValueExpr(anon:AnonType, pos:Position, ?fieldInits:Map<String,Expr>):Expr {
        var declFields = [];

        for (field in anon.fields) {
            var fieldValue = null;
            if (fieldInits != null) {
                fieldValue = fieldInits[field.name];
                fieldInits.remove(field.name);
            }

            if (fieldValue == null) {
                if (field.meta.has(":optional"))
                    continue;
                fieldValue = getDefaultValueExpr(field.type, pos);
            }
            declFields.push({field: field.name, expr: fieldValue});
        }

        if (fieldInits != null) {
            for (fieldName in fieldInits.keys())
                throw new Error("Unknown field: " + fieldName, fieldInits[fieldName].pos);
        }

        return {expr: EObjectDecl(declFields), pos: pos};
    }
    #end
}
Main.hx
import StructHelper.make;

typedef A = {
    a:Int,
    b:String,
    c:Float,
    d:Bool,
    e:Array<Int>,
    f:{
        g:Array<Bool>,
        ?h:String,
    },
    ?i:Int,
}

class Main {
    static function main() {
        var tower = make(A, e = [1, 2, 3]);
        trace(tower);
    }
}

haxe gistfile1.hx

gistfile1.hx
package ;

import neko.Lib;
import sys.db.Manager;
import sys.db.Object;
import sys.db.Sqlite;
import sys.db.Types.SDate;
import sys.db.Types.SId;
import sys.db.Types.SNull;
import sys.db.Types.SString;
import sys.db.Types.SText;

/**
 * ...
 * @author 
 */

 // SPOD example - old.haxe.org/manual/spod
 // Neko/SQLite
 
class Main 
{
	
	static function main() 
	{
		// Create the file my-database.sqlite if it doesn't exist and open a SQLite connection to it
		var cnx = Sqlite.open('my-database.sqlite');
		// Initialize the sys.db.Manager that handles the SPOD stuff behind the scenes
		Manager.cnx = cnx;
		// Create the User table in my-database.sqlite if it doesn't exist
		if ( !sys.db.TableCreate.exists(User.manager) ) sys.db.TableCreate.create(User.manager); 		
		
		// create a new user
		var u = new User();
		
		// set some parameters
		u.name = "John Doe";
		u.birthday = Date.now();
		// store it in the db
		u.insert();
		
		// fetch user with id # 1
		var u = User.manager.get(1);
		if ( u == null ) throw "User #1 not found";	
		// trace it
		trace(u.name);		
	}	
}

// User SPOD objcet that extends sys.db.Object
class User extends Object 
{
    public var id : SId; 			// SPOD type for record Id
    public var name : SString<32>;		// SPOD type for strings
    public var birthday : SDate;		// SPOD type for date
    public var phoneNumber : SNull<SText>;	// SPOD tye for nullable variable-lenght text field
}

haxe gistfile1.hx

gistfile1.hx
package ;

import neko.Lib;
import sys.db.Manager;
import sys.db.Object;
import sys.db.Sqlite;
import sys.db.Types.SDate;
import sys.db.Types.SId;
import sys.db.Types.SNull;
import sys.db.Types.SString;
import sys.db.Types.SText;

/**
 * ...
 * @author 
 */

 // SPOD example - old.haxe.org/manual/spod
 // Neko/SQLite
 
class Main 
{
	
	static function main() 
	{
		// Create the file my-database.sqlite if it doesn't exist and open a SQLite connection to it
		var cnx = Sqlite.open('my-database.sqlite');
		// Initialize the sys.db.Manager that handles the SPOD stuff behind the scenes
		Manager.cnx = cnx;
		// Create the User table in my-database.sqlite if it doesn't exist
		if ( !sys.db.TableCreate.exists(User.manager) ) sys.db.TableCreate.create(User.manager); 		
		
		// create a new user
		var u = new User();
		
		// set some parameters
		u.name = "John Doe";
		u.birthday = Date.now();
		// store it in the db
		u.insert();
		
		// fetch user with id # 1
		var u = User.manager.get(1);
		if ( u == null ) throw "User #1 not found";	
		// trace it
		trace(u.name);		
	}	
}

// User SPOD objcet that extends sys.db.Object
class User extends Object 
{
    public var id : SId; 			// SPOD type for record Id
    public var name : SString<32>;		// SPOD type for strings
    public var birthday : SDate;		// SPOD type for date
    public var phoneNumber : SNull<SText>;	// SPOD tye for nullable variable-lenght text field
}

haxe Gen.hx

Gen.hx
package ;

import haxe.macro.*;
import haxe.macro.Type;

using haxe.macro.Tools;

private typedef Accessor = {
  name: String,
  read: Bool,
  field: ClassField,
}

class Gen extends ExampleJSGenerator {
  var accessors:Map<String, Accessor>;
  
  override function getType(t:Type) //just a workaround until this is merged: https://github.com/HaxeFoundation/haxe/pull/3106
    return 
      switch Context.follow(t) {
        case TAbstract(a, _): getPath(a.get());
        default: super.getType(t);
      }
  
  override function genClass(c: ClassType) {
    accessors = new Map();
    for(f in c.fields.get()) 
      switch f.kind {
        case FVar(get, set):
          if (get == AccCall)
            accessors['get_' + f.name] = { read: true, name: f.name, field: null };
          if (set == AccCall)
            accessors['set_' + f.name] = { read: false, name: f.name, field: null };
        default:
      }
      
    for (f in c.fields.get()) 
      if (accessors.exists(f.name))
        accessors[f.name].field = f;
      
    super.genClass(c);
  }
  
  override function genClassField( c : ClassType, p : String, f : ClassField ) {
    switch f.kind {
      case FVar(get, set) if (get == AccCall || set == AccCall):
        var name = f.name;
        
        function makePhysical() {
          var any = false;
          for (kind in 'get,set'.split(',')) 
            switch accessors['${kind}_$name'] {
              case null: 
              case a:
                a = Reflect.copy(a);
                function fixField(t:TypedExpr)
                  return switch t.expr {
                    case TField(owner, FInstance(cl, f)) if (f.get().name == name && owner.expr.equals(TConst(TThis))):
                      t.expr = TField(owner, FDynamic('_' + name));
                      any = true;
                      t;
                    default: t.map(fixField);
                  }
                var expr = fixField(a.field.expr());
                untyped a.field.expr = function () return expr;
                accessors['${kind}_$name'] = a;
            }
            
          if (any) {
            var f = Reflect.copy(f);
            f.name = '_'+name;
            f.kind = FVar(AccNormal, AccNormal);
            genClassField(c, p, f);
          }
        }
        
        function makeAccessors() {
          var first = true;

          print('Object.defineProperty($p.prototype, "$name", {');
          
          for (kind in 'get,set'.split(',')) 
            switch accessors['${kind}_$name'] {
              case null: 
              case { field: accessor }:
                if (first) 
                  first = false;
                else 
                  print(',');
                
                print(' $kind : ');
                genExpr(accessor.expr());
            }            
            
          print('})');
          
          newline();          
        }
        
        switch [get, set] {
          case [AccCall | AccNever, AccCall | AccNever]:
            if (f.meta.has(':isVar')) 
              makePhysical();
            makeAccessors();
          case [AccCall | AccNormal | AccNo, AccCall | AccNormal | AccNo]:
              makePhysical();
            makeAccessors();
          default: 
            throw 'assert';  
        }
        
      case FMethod(_) if (accessors.exists(f.name)):
      
        var accessor = accessors[f.name],
          func = field(f.name);
          
        var field = field(accessor.name);
        
        print('$p.prototype$func = ');
        
        if (accessor.read)
          print('function () { return this$field; }');
        else
          print('function (param) { return this$field = param; }');
          
        newline();        
      default:
        super.genClassField(c, p, f);
    }
  }
  
  static function use() 
    Compiler.setCustomJSGenerator(function(api) new Gen(api).generate());
  
}