Skip to content

Instantly share code, notes, and snippets.

@ccapndave
Created June 4, 2012 10:17
Show Gist options
  • Select an option

  • Save ccapndave/2867627 to your computer and use it in GitHub Desktop.

Select an option

Save ccapndave/2867627 to your computer and use it in GitHub Desktop.
EmberJSGenerator.hx is a straight copy of ExampleJSGenerator, only with the class name changed in .use() and a print() added to the top of generate for testing.
compile.hxml
============
-js bin/embertest.js
-main Main
-cp src
--macro EmberJSGenerator.use()
EmberJSGenerator.hx
===================
package ;
import haxe.macro.Compiler;
import haxe.macro.Context;
import haxe.macro.JSGenApi;
import haxe.macro.Type;
import haxe.macro.Expr;
using Lambda;
class EmberJSGenerator {
var api : JSGenApi;
var buf : StringBuf;
var inits : List<TypedExpr>;
var statics : List<{ c : ClassType, f : ClassField }>;
var packages : Hash<Bool>;
var forbidden : Hash<Bool>;
public function new(api) {
this.api = api;
buf = new StringBuf();
inits = new List();
statics = new List();
packages = new Hash();
forbidden = new Hash();
for( x in ["prototype", "__proto__", "constructor"] )
forbidden.set(x, true);
api.setTypeAccessor(getType);
}
function getType( t : Type ) {
return switch(t) {
case TInst(c, _): getPath(c.get());
case TEnum(e, _): getPath(e.get());
default: throw "assert";
};
}
inline function print(str) {
buf.add(str);
}
inline function newline() {
buf.add(";\n");
}
inline function genExpr(e) {
print(api.generateValue(e));
}
@:macro static function fprint( e : Expr ) {
var pos = haxe.macro.Context.currentPos();
var ret = haxe.macro.Format.format(e);
return { expr : ECall({ expr : EConst(CIdent("print")), pos : pos },[ret]), pos : pos };
}
function field(p) {
return api.isKeyword(p) ? '["' + p + '"]' : "." + p;
}
function genPackage( p : Array<String> ) {
var full = null;
for( x in p ) {
var prev = full;
if( full == null ) full = x else full += "." + x;
if( packages.exists(full) )
continue;
packages.set(full, true);
if( prev == null )
fprint("if(typeof $x=='undefined') $x = {}");
else {
var p = prev + field(x);
fprint("if(!$p) $p = {}");
}
newline();
}
}
function getPath( t : BaseType ) {
return (t.pack.length == 0) ? t.name : t.pack.join(".") + "." + t.name;
}
function checkFieldName( c : ClassType, f : ClassField ) {
if( forbidden.exists(f.name) )
Context.error("The field " + f.name + " is not allowed in JS", c.pos);
}
function genClassField( c : ClassType, p : String, f : ClassField ) {
checkFieldName(c, f);
var field = field(f.name);
fprint("$p.prototype$field = ");
var e = f.expr();
if( e == null )
print("null");
else {
genExpr(e);
}
newline();
}
function genStaticField( c : ClassType, p : String, f : ClassField ) {
checkFieldName(c, f);
var field = field(f.name);
var e = f.expr();
if( e == null ) {
fprint("$p$field = null");
newline();
} else switch( f.kind ) {
case FMethod(_):
fprint("$p$field = ");
genExpr(e);
newline();
default:
statics.add( { c : c, f : f } );
}
}
function genClass( c : ClassType ) {
genPackage(c.pack);
api.setCurrentClass(c);
var p = getPath(c);
fprint("$p = $$hxClasses['$p'] = ");
if( c.constructor != null )
genExpr(c.constructor.get().expr());
else
print("function() { }");
newline();
var name = p.split(".").map(api.quoteString).join(",");
fprint("$p.__name__ = [$name]");
newline();
if( c.superClass != null ) {
var psup = getPath(c.superClass.t.get());
fprint("$p.__super__ = $psup");
newline();
fprint("for(var k in $psup.prototype ) $p.prototype[k] = $psup.prototype[k]");
newline();
}
for( f in c.statics.get() )
genStaticField(c, p, f);
for( f in c.fields.get() ) {
switch( f.kind ) {
case FVar(r, _):
if( r == AccResolve ) continue;
default:
}
genClassField(c, p, f);
}
fprint("$p.prototype.__class__ = $p");
newline();
if( c.interfaces.length > 0 ) {
var me = this;
var inter = c.interfaces.map(function(i) return me.getPath(i.t.get())).join(",");
fprint("$p.__interfaces__ = [$inter]");
newline();
}
}
function genEnum( e : EnumType ) {
genPackage(e.pack);
var p = getPath(e);
var names = p.split(".").map(api.quoteString).join(",");
var constructs = e.names.map(api.quoteString).join(",");
fprint("$p = $$hxClasses['$p'] = { __ename__ : [$names], __constructs__ : [$constructs] }");
newline();
for( c in e.constructs.keys() ) {
var c = e.constructs.get(c);
var f = field(c.name);
fprint("$p$f = ");
switch( c.type ) {
case TFun(args, _):
var sargs = args.map(function(a) return a.name).join(",");
fprint('function($sargs) { var $$x = ["${c.name}",${c.index},$sargs]; $$x.__enum__ = $p; $$x.toString = $$estr; return $$x; }');
default:
print("[" + api.quoteString(c.name) + "," + c.index + "]");
newline();
fprint("$p$f.toString = $$estr");
newline();
fprint("$p$f.__enum__ = $p");
}
newline();
}
var meta = api.buildMetaData(e);
if( meta != null ) {
fprint("$p.__meta__ = ");
genExpr(meta);
newline();
}
}
function genStaticValue( c : ClassType, cf : ClassField ) {
var p = getPath(c);
var f = field(cf.name);
fprint("$p$f = ");
genExpr(cf.expr());
newline();
}
function genType( t : Type ) {
switch( t ) {
case TInst(c, _):
var c = c.get();
if( c.init != null )
inits.add(c.init);
if( !c.isExtern ) genClass(c);
case TEnum(r, _):
var e = r.get();
if( !e.isExtern ) genEnum(e);
default:
}
}
public function generate() {
print("????WHY AM I NOT ENDING UP IN THE GENERATED CODE????");
print("var $_, $hxClasses = $hxClasses || {}, $estr = function() { return js.Boot.__string_rec(this,''); }");
newline();
for( t in api.types )
genType(t);
print("$_ = {}");
newline();
print("js.Boot.__res = {}");
newline();
print("js.Boot.__init()");
newline();
for( e in inits ) {
print(api.generateStatement(e));
newline();
}
for( s in statics ) {
genStaticValue(s.c,s.f);
newline();
}
if( api.main != null ) {
genExpr(api.main);
newline();
}
sys.io.File.saveContent(api.outputFile, buf.toString());
}
#if macro
public static function use() {
Compiler.setCustomJSGenerator(function(api) new EmberJSGenerator(api).generate());
}
#end
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment