Convert children to nested functions. Reuse identifiers by closure where possible.
This commit is contained in:
@@ -315,12 +315,14 @@ Handlebars.JavaScriptCompiler = function() {};
|
||||
},
|
||||
// END PUBLIC API
|
||||
|
||||
compile: function(environment, options, asObject) {
|
||||
compile: function(environment, options, context, asObject) {
|
||||
this.environment = environment;
|
||||
this.options = options || {};
|
||||
|
||||
this.context = {
|
||||
aliases: {},
|
||||
this.name = this.environment.name;
|
||||
this.isChild = !!context;
|
||||
this.context = context || {
|
||||
programs: [],
|
||||
aliases: { self: 'this' },
|
||||
registers: {list: []}
|
||||
};
|
||||
@@ -330,7 +332,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
||||
this.stackSlot = 0;
|
||||
this.stackVars = [];
|
||||
|
||||
this.compileChildren(environment, options, asObject);
|
||||
this.compileChildren(environment, options);
|
||||
|
||||
var opcodes = environment.opcodes, opcode, name, declareName, declareVal;
|
||||
|
||||
@@ -380,9 +382,13 @@ Handlebars.JavaScriptCompiler = function() {};
|
||||
preamble: function() {
|
||||
var out = [];
|
||||
|
||||
var copies = "helpers = helpers || Handlebars.helpers;";
|
||||
if(this.environment.usePartial) { copies = copies + " partials = partials || Handlebars.partials;"; }
|
||||
out.push(copies);
|
||||
if (!this.isChild) {
|
||||
var copies = "helpers = helpers || Handlebars.helpers;";
|
||||
if(this.environment.usePartial) { copies = copies + " partials = partials || Handlebars.partials;"; }
|
||||
out.push(copies);
|
||||
} else {
|
||||
out.push('');
|
||||
}
|
||||
|
||||
out.push("var buffer = " + this.initializeBuffer() + ", currentContext = context");
|
||||
|
||||
@@ -393,25 +399,33 @@ Handlebars.JavaScriptCompiler = function() {};
|
||||
},
|
||||
|
||||
createFunctionContext: function(asObject) {
|
||||
var locals = this.stackVars.concat(this.context.registers.list);
|
||||
var locals = this.stackVars;
|
||||
if (!this.isChild) {
|
||||
locals = locals.concat(this.context.registers.list);
|
||||
}
|
||||
|
||||
if(locals.length > 0) {
|
||||
this.source[1] = this.source[1] + ", " + locals.join(", ");
|
||||
}
|
||||
|
||||
// Generate minimizer alias mappings
|
||||
var aliases = []
|
||||
for (var alias in this.context.aliases) {
|
||||
this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
|
||||
if (!this.isChild) {
|
||||
var aliases = []
|
||||
for (var alias in this.context.aliases) {
|
||||
this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
|
||||
}
|
||||
}
|
||||
|
||||
this.source[1] = this.source[1] + ";";
|
||||
|
||||
// Merge children
|
||||
if (!this.isChild) {
|
||||
this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
|
||||
}
|
||||
|
||||
this.source.push("return buffer;");
|
||||
|
||||
var params = ["Handlebars", "context", "helpers", "partials"];
|
||||
|
||||
if(this.options.data) { params.push("data"); }
|
||||
var params = this.isChild ? ["context", "data"] : ["Handlebars", "context", "helpers", "partials", "data"];
|
||||
|
||||
for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
|
||||
params.push("depth" + this.environment.depths.list[i]);
|
||||
@@ -422,24 +436,11 @@ Handlebars.JavaScriptCompiler = function() {};
|
||||
if (asObject) {
|
||||
params.push(this.source.join("\n "));
|
||||
|
||||
return {
|
||||
fn: Function.apply(this, params),
|
||||
children: this.environment.children
|
||||
};
|
||||
return Function.apply(this, params);
|
||||
} else {
|
||||
var functionSource = 'function(' + params.join(',') + ') {\n ' + this.source.join("\n ") + '}';
|
||||
|
||||
var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n ' + this.source.join("\n ") + '}';
|
||||
Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n");
|
||||
|
||||
var script = ['{\n fn: ', functionSource, ',\n children: [\n '],
|
||||
children = this.environment.children;
|
||||
for (var i = 0, len = children.length; i < len; i++) {
|
||||
script.push(children[i]);
|
||||
if (i < len-1) { script.push(',\n'); }
|
||||
}
|
||||
script.push('\n ]\n}');
|
||||
|
||||
return script.join('');
|
||||
return functionSource;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -582,7 +583,7 @@ Handlebars.JavaScriptCompiler = function() {};
|
||||
},
|
||||
|
||||
invokePartial: function(context) {
|
||||
this.pushStack("this.invokePartial(" + this.nameLookup('partials', context, 'partial') + ", '" + context + "', " + this.popStack() + ", helpers, partials);");
|
||||
this.pushStack("self.invokePartial(" + this.nameLookup('partials', context, 'partial') + ", '" + context + "', " + this.popStack() + ", helpers, partials);");
|
||||
},
|
||||
|
||||
assignToHash: function(key) {
|
||||
@@ -596,29 +597,27 @@ Handlebars.JavaScriptCompiler = function() {};
|
||||
|
||||
compiler: JavaScriptCompiler,
|
||||
|
||||
compileChildren: function(environment, options, asObject) {
|
||||
compileChildren: function(environment, options) {
|
||||
var children = environment.children, child, compiler;
|
||||
var compiled = [];
|
||||
|
||||
for(var i=0, l=children.length; i<l; i++) {
|
||||
child = children[i];
|
||||
compiler = new this.compiler();
|
||||
|
||||
compiled[i] = compiler.compile(child, options, asObject);
|
||||
this.context.programs.push(''); // Placeholder to prevent name conflicts for nested children
|
||||
var index = this.context.programs.length;
|
||||
child.index = index;
|
||||
child.name = 'program' + index;
|
||||
this.context.programs[index] = compiler.compile(child, options, this.context);
|
||||
}
|
||||
|
||||
environment.rawChildren = children;
|
||||
environment.children = compiled;
|
||||
},
|
||||
|
||||
programExpression: function(guid) {
|
||||
|
||||
var programParams = [guid, "helpers", "partials"];
|
||||
if(guid == null) { return "self.noop"; }
|
||||
|
||||
var depths = this.environment.rawChildren[guid].depths.list;
|
||||
|
||||
if(this.options.data) { programParams.push("data"); }
|
||||
var child = this.environment.children[guid],
|
||||
depths = child.depths.list;
|
||||
var programParams = [child.index, child.name, "data"];
|
||||
|
||||
for(var i=0, l = depths.length; i<l; i++) {
|
||||
depth = depths[i];
|
||||
@@ -627,18 +626,10 @@ Handlebars.JavaScriptCompiler = function() {};
|
||||
else { programParams.push("depth" + (depth - 1)); }
|
||||
}
|
||||
|
||||
if(!this.environment.usePartial) {
|
||||
if(programParams[3]) {
|
||||
programParams[2] = "null";
|
||||
} else {
|
||||
programParams.pop();
|
||||
}
|
||||
}
|
||||
|
||||
if(depths.length === 0) {
|
||||
return "self.program(" + programParams.join(", ") + ")";
|
||||
} else {
|
||||
programParams[0] = "this.children[" + guid + "]";
|
||||
programParams.shift();
|
||||
return "self.programWithDepth(" + programParams.join(", ") + ")";
|
||||
}
|
||||
},
|
||||
@@ -704,7 +695,7 @@ Handlebars.precompile = function(string, options) {
|
||||
Handlebars.compile = function(string, options) {
|
||||
var ast = Handlebars.parse(string);
|
||||
var environment = new Handlebars.Compiler().compile(ast, options);
|
||||
var templateSpec = new Handlebars.JavaScriptCompiler().compile(environment, options, true);
|
||||
var templateSpec = new Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
|
||||
return Handlebars.template(templateSpec);
|
||||
};
|
||||
|
||||
|
||||
+10
-30
@@ -3,66 +3,46 @@ var Handlebars = require("./base");
|
||||
// BEGIN(BROWSER)
|
||||
Handlebars.VM = {
|
||||
template: function(templateSpec) {
|
||||
// Setup all children
|
||||
for (var i = 0, len = templateSpec.children.length; i < len; i++) {
|
||||
templateSpec.children[i] = Handlebars.VM.template(templateSpec.children[i]);
|
||||
}
|
||||
|
||||
// Just add water
|
||||
var container = {
|
||||
escapeExpression: Handlebars.Utils.escapeExpression,
|
||||
invokePartial: Handlebars.VM.invokePartial,
|
||||
programs: [],
|
||||
program: function(i, helpers, partials, data) {
|
||||
program: function(i, fn, data) {
|
||||
var programWrapper = this.programs[i];
|
||||
if(data) {
|
||||
return Handlebars.VM.program(this.children[i], helpers, partials, data);
|
||||
return Handlebars.VM.program(fn, data);
|
||||
} else if(programWrapper) {
|
||||
return programWrapper;
|
||||
} else {
|
||||
programWrapper = this.programs[i] = Handlebars.VM.program(this.children[i], helpers, partials);
|
||||
programWrapper = this.programs[i] = Handlebars.VM.program(fn);
|
||||
return programWrapper;
|
||||
}
|
||||
},
|
||||
programWithDepth: Handlebars.VM.programWithDepth,
|
||||
noop: Handlebars.VM.noop
|
||||
};
|
||||
container.render = templateSpec.fn;
|
||||
container.children = templateSpec.children;
|
||||
|
||||
return function(context, options, $depth) {
|
||||
return function(context, options) {
|
||||
options = options || {};
|
||||
var args = [Handlebars, context, options.helpers, options.partials, options.data];
|
||||
var depth = Array.prototype.slice.call(arguments, 2);
|
||||
args = args.concat(depth);
|
||||
return container.render.apply(container, args);
|
||||
return templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
|
||||
};
|
||||
},
|
||||
|
||||
programWithDepth: function(fn, helpers, partials, data, $depth) {
|
||||
var args = Array.prototype.slice.call(arguments, 4);
|
||||
programWithDepth: function(fn, data, $depth) {
|
||||
var args = Array.prototype.slice.call(arguments, 2);
|
||||
|
||||
return function(context, options) {
|
||||
options = options || {};
|
||||
|
||||
options = {
|
||||
helpers: options.helpers || helpers,
|
||||
partials: options.partials || partials,
|
||||
data: options.data || data
|
||||
};
|
||||
|
||||
return fn.apply(this, [context, options].concat(args));
|
||||
return fn.apply(this, [context, options.data || data].concat(args));
|
||||
};
|
||||
},
|
||||
program: function(fn, helpers, partials, data) {
|
||||
program: function(fn, data) {
|
||||
return function(context, options) {
|
||||
options = options || {};
|
||||
|
||||
return fn(context, {
|
||||
helpers: options.helpers || helpers,
|
||||
partials: options.partials || partials,
|
||||
data: options.data || data
|
||||
});
|
||||
return fn(context, options.data || data);
|
||||
};
|
||||
},
|
||||
noop: function() { return ""; },
|
||||
|
||||
Reference in New Issue
Block a user