Skip to content

Commit

Permalink
Merge branch 'master' of git://github.com/ciscoheat/erazor
Browse files Browse the repository at this point in the history
Conflicts:
	src/erazor/macro/Build.hx
  • Loading branch information
clemos committed Oct 9, 2012
2 parents a4cfead + 701f126 commit 88c6770
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 54 deletions.
107 changes: 55 additions & 52 deletions src/erazor/macro/Build.hx
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,23 @@ typedef PosInfo =
min:Int
}

class Build
class Build
{
static function buildTemplate():Array<Field>
{
#if display
return null;
#else
var cls = Context.getLocalClass().get();

if (cls.superClass.t.toString() != "erazor.macro.Template")
{
//if someone is extending an already created macro template, it doesn't make sense for build() to execute
return null;
}

var params = cls.superClass.params[0];

//getting the class parameter and transforming it into a ComplexType
var t = switch(Context.parse("{var _:" + typeToString(params, cls.pos) + ";}", cls.pos).expr)
{
Expand All @@ -49,7 +49,7 @@ class Build
}
default:null;
};

for (meta in cls.meta.get())
{
switch(meta.name)
Expand All @@ -64,18 +64,18 @@ class Build
var srcLocation = Context.resolvePath(cls.module.split(".").join("/") + ".hx");
var path = srcLocation.split("/");
path.pop();

var templatePath = getString(meta.params[0]);
templatePath = path.join("/") + "/" + templatePath;

if (! FileSystem.exists(templatePath)) throw new Error("File " + templatePath + " not found.", meta.params[0].pos);
var contents = File.getContent(templatePath);
var pos = Context.makePosition( { min:0, max:contents.length, file:templatePath } );

return build(contents, pos, t);
}
}

throw new Error("No :template meta or :includeTemplate meta were found", cls.pos);
#end
}
Expand All @@ -98,12 +98,12 @@ class Build
throw new Error("String type was expected", e.pos);
return ret;
}
static function typeToString(type:Type, ?pos:Position):Null<String>

static function typeToString(type:Type, pos:Position):Null<String>
{
if (type == null)
return null;

return switch(type)
{
case TMono( t ):
Expand All @@ -120,32 +120,32 @@ class Build
for (a in a.get().fields)
{
if (first) first = false; else sbuf.add(", ");

var first = a.name.charCodeAt(0);
if (first >= 'A'.code && first <= 'Z'.code)
{
Context.warning("Capitalized variables won't behave correctly inside an erazor macro context.", pos);
}

sbuf.add(a.name);
sbuf.add(" : ");
sbuf.add(typeToString(a.type, pos));
}
sbuf.add(" }");

sbuf.toString();
case TDynamic( t ):
if (t != null)
"Dynamic<" + typeToString(t, pos) + ">";
else
"Dynamic";
//#if haxe_209
case TLazy( f ): typeToString(f());
//#end
#if haxe_209
case TLazy( f ): typeToString(f(), pos);
#end
}
}
static function args(args:Array<Type>, pos):String

static function args(args:Array<Type>, pos):String
{
if (args.length > 0)
{
Expand All @@ -161,22 +161,22 @@ class Build
{
pos = Context.currentPos();
}

// Parse the template into TBlocks for the HTemplateParser
var parsedBlocks = null;
try
{
parsedBlocks = new Parser().parseWithPosition(template);
}

//if a ParserError is found, bubble up but add the correct macro position to it.
catch (e:ParserError)
{
var pos = Context.getPosInfos(pos);
pos.min += e.pos;
throw new Error("Parser error: \"" + e.toString() + "\"", Context.makePosition(pos));
}

var buildedBlocks = new StringBuf();
buildedBlocks.add("{");
var builder = new ScriptBuilder('__b__');
Expand All @@ -187,19 +187,19 @@ class Build
buildedBlocks.add(builder.blockToString(block.block));
}
buildedBlocks.add("}");

var posInfo = Context.getPosInfos(pos);
var min = posInfo.min;
var blockPos = parsedBlocks.map(function(block) return { file:posInfo.file, min:min + block.start, max:min + block.start + block.length } ).array();
blockPos.reverse();

// Make a hscript with the buffer as context.
var script = buildedBlocks.toString();

//trace(script);
// Call macro string -> macro parser
var expr = Context.parse(script, Context.makePosition({min:0, max:0, file:"_internal_"}));

// Change all top-level var use to use the context's
// And change the parsed script to take off all no-ops and set the right position values
var contextVar = "__context__";
Expand All @@ -213,23 +213,24 @@ class Build
defVars.set("true", true);
defVars.set("false", true);
expr = changeExpr(expr, { expr:EConst(CIdent(contextVar)), pos:pos }, [defVars], {info:null, carry:0, blockPos:blockPos});

var fields = [];
var executeBlock = [];
var bvar = switch(Context.parse("{var __b__ = new StringBuf();}", pos).expr)

var bvar = switch(Context.parse("{var __b__ = new StringBuf();}", pos).expr)
{
case EBlock(b): b[0];
default:throw "assert";
};

//var __b__ = new StringBuf();
executeBlock.push(bvar);
//the executed script
executeBlock.push(expr);
executeBlock.push(Context.parse("return __b__.toString()", pos));

//return new execute() field

fields.push({
name:"execute",
doc:null,
Expand All @@ -248,35 +249,35 @@ class Build
pos:pos,
meta:[]
});

return fields;
}

//this internal function will traverse the AST and add a __context__ field access to any undeclared variable
//it will also correctly set the position information for all constant types. This could also be extended to set the correct
//position to any expression, but the most common error will most likely be in the constants part. (e.g. wrong variable name, etc)
static function changeExpr(e:Null<Expr>, contextExpr:Expr, declaredVars:Array<Hash<Bool>>, curPosInfo:{info:PosInfo, carry:Int, blockPos:Array<PosInfo>}, ?inCase = false, ?isType = false):Null<Expr>
{
if (e == null)
return null;

function _recurse(e:Expr)
{
return changeExpr(e, contextExpr, declaredVars, curPosInfo);
}

function pos(lastPos:Position)
{
var info = curPosInfo.info;
var pos = Context.getPosInfos(lastPos);
var len = pos.max - pos.min;

var min = pos.min - curPosInfo.carry;
var ret = Context.makePosition( { file: info.file, min:min, max:min + len } );

return ret;
}

return switch(e.expr)
{
case EConst( c ):
Expand All @@ -287,12 +288,12 @@ class Build
{
addVar(s, declaredVars);
{expr:EConst(c), pos:pos(e.pos) };
} else if (s == "__blockbegin__")
} else if (s == "__blockbegin__")
{
var info = curPosInfo.blockPos.pop();
var pos = Context.getPosInfos(e.pos);
curPosInfo.info = info;

curPosInfo.carry = pos.max - info.min - 3;
{expr:EConst(CIdent("null")), pos:e.pos };
} else if (!isType && !lookupVar(s, declaredVars)) {
Expand All @@ -309,7 +310,7 @@ class Build
case EParenthesis( e1 ): { expr:EParenthesis(changeExpr(e1, contextExpr, declaredVars, curPosInfo, inCase, isType)), pos:pos(e.pos) };
case EObjectDecl( fields ): { expr:EObjectDecl(fields.map(function(f) return { field:f.field, expr:_recurse(f.expr) } ).array()), pos:pos(e.pos) };
case EArrayDecl( values ): { expr:EArrayDecl(values.map(_recurse).array()), pos:pos(e.pos) };
case ECall( e1, params):
case ECall( e1, params):
//we need to check if we find the expression __b__.add()
//in order to not mess with the positions
switch(e1.expr)
Expand All @@ -321,30 +322,30 @@ class Build
{
var p = Context.getPosInfos(e1.pos);
curPosInfo.carry += (p.max - p.min) + 2;

var ret = { expr:ECall(e1, params.map(function(e) return changeExpr(e, contextExpr, declaredVars, curPosInfo, inCase)).array()), pos:e.pos };
curPosInfo.carry += 3;
ret;
}
}
default:
}

{ expr:ECall(_recurse(e1), params.map(function(e) return changeExpr(e, contextExpr, declaredVars, curPosInfo, inCase)).array()), pos:pos(e.pos) };
case ENew( t, params ): { expr:ENew(t, params.map(_recurse).array()), pos:pos(e.pos)};
case EUnop( op, postFix, e1 ): { expr:EUnop(op, postFix, _recurse(e1)), pos:pos(e.pos) };
case EVars( vars): { expr:EVars(vars.map(function(v) {
addVar(v.name, declaredVars);
return { name:v.name, type:v.type, expr:_recurse(v.expr) };
}).array()), pos:pos(e.pos) };
case EFunction( name, f ):
case EFunction( name, f ):
addVar(name, declaredVars);
declaredVars.push(new Hash());
for (arg in f.args)
{
addVar(arg.name, declaredVars);
}

var ret = { expr:EFunction(name, { args:f.args, ret:f.ret, expr:_recurse(f.expr), params:f.params } ), pos:pos(e.pos) };
declaredVars.pop();
ret;
Expand All @@ -354,7 +355,7 @@ class Build
declaredVars.pop();
ret;
case EFor( it, expr ): { expr:EFor(_recurse(it), _recurse(expr)), pos:pos(e.pos) };
case EIn( e1, e2 ):
case EIn( e1, e2 ):
switch(e1.expr)
{
case EConst(c):
Expand All @@ -365,7 +366,7 @@ class Build
}
default:
}

{ expr:EIn(_recurse(e1), _recurse(e2)), pos:pos(e.pos) };
case EIf( econd, eif, eelse): { expr:EIf(_recurse(econd), _recurse(eif), _recurse(eelse)), pos:pos(e.pos) };
case EWhile( econd, e1, normalWhile ): { expr:EWhile(_recurse(econd), _recurse(e1), normalWhile), pos:pos(e.pos) };
Expand All @@ -391,23 +392,25 @@ class Build
case EDisplay( e, isCall ): { expr:EDisplay(_recurse(e), isCall), pos:pos(e.pos) };
case EDisplayNew( t ): e;
case ETernary( econd, eif, eelse ): { expr:ETernary(_recurse(econd), _recurse(eif), _recurse(eelse)), pos:pos(e.pos) };
default: throw "Not implemented";
#if haxe_209
case ECheckType( e, t ): { expr:ECheckType(_recurse(e), t), pos:pos(e.pos) };
#end
}
}

static function addVar(name:String, declaredVars:Array<Hash<Bool>>):Void
{
declaredVars[declaredVars.length - 1].set(name, true);
}

static function lookupVar(name:String, declaredVars:Array<Hash<Bool>>):Bool
{
for (v in declaredVars)
{
if (v.exists(name))
return true;
}

return false;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/erazor/macro/Template.hx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ class Template<T>
{
public function new()
{

}

#if display
public function execute(context:T):String
{
Expand Down

0 comments on commit 88c6770

Please sign in to comment.