summaryrefslogtreecommitdiffstats
path: root/lib/handlebars/compiler/compiler.js
diff options
context:
space:
mode:
authorYehuda Katz <wycats@gmail.com>2012-05-26 22:17:22 -0700
committerYehuda Katz <wycats@gmail.com>2012-05-26 22:17:22 -0700
commit68c76c9b2eb2fd1cebf5d9fea87f5dfb85b8529d (patch)
tree2c634a8fdf00a6f33371d1768d1b04b67c11e2e8 /lib/handlebars/compiler/compiler.js
parentfacefe8fedd2411bf8ce696b072d15041f0265a0 (diff)
downloadhandlebars.js-68c76c9b2eb2fd1cebf5d9fea87f5dfb85b8529d.zip
handlebars.js-68c76c9b2eb2fd1cebf5d9fea87f5dfb85b8529d.tar.gz
handlebars.js-68c76c9b2eb2fd1cebf5d9fea87f5dfb85b8529d.tar.bz2
Clean up the compiler a bit
Diffstat (limited to 'lib/handlebars/compiler/compiler.js')
-rw-r--r--lib/handlebars/compiler/compiler.js160
1 files changed, 91 insertions, 69 deletions
diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js
index 8fccc90..994192b 100644
--- a/lib/handlebars/compiler/compiler.js
+++ b/lib/handlebars/compiler/compiler.js
@@ -22,15 +22,18 @@ Handlebars.JavaScriptCompiler = function() {};
invokePartial: 12,
push: 13,
assignToHash: 15,
- pushStringParam: 16
+ pushStringParam: 16,
+ knownHelper: 17,
+ pushContext: 18,
+ lookupOnContext: 19
};
Compiler.MULTI_PARAM_OPCODES = {
appendContent: 1,
getContext: 1,
- lookupWithHelpers: 2,
+ lookupWithHelpers: 1,
lookup: 1,
- invokeMustache: 3,
+ invokeMustache: 2,
pushString: 1,
truthyOrFallback: 1,
functionOrFallback: 1,
@@ -38,7 +41,10 @@ Handlebars.JavaScriptCompiler = function() {};
invokePartial: 1,
push: 1,
assignToHash: 1,
- pushStringParam: 1
+ pushStringParam: 1,
+ knownHelper: 1,
+ pushContext: 0,
+ lookupOnContext: 1
};
Compiler.DISASSEMBLE_MAP = {};
@@ -227,7 +233,7 @@ Handlebars.JavaScriptCompiler = function() {};
mustache: function(mustache) {
var params = this.setupStackForMustache(mustache);
- this.opcode('invokeMustache', params.length, mustache.id.original, !!mustache.hash);
+ this.opcode('invokeMustache', params.length, mustache.id.original);
if(mustache.escaped && !this.options.noEscape) {
this.opcode('appendEscaped');
@@ -241,7 +247,20 @@ Handlebars.JavaScriptCompiler = function() {};
this.opcode('getContext', id.depth);
- this.opcode('lookupWithHelpers', id.parts[0] || null, id.isScoped || false);
+ var name = id.parts[0];
+
+ if (!name) {
+ this.opcode('pushContext');
+ } else if (!id.isScoped && this.options.knownHelpers[name]) {
+ this.declare('usingKnownHelper', true);
+ this.opcode('knownHelper', name);
+ } else if (id.isScoped || this.options.knownHelpersOnly) {
+ this.declare('usingKnownHelper', false);
+ this.opcode('lookupOnContext', name);
+ } else {
+ this.declare('usingKnownHelper', false);
+ this.opcode('lookupWithHelpers', name);
+ }
for(var i=1, l=id.parts.length; i<l; i++) {
this.opcode('lookup', id.parts[i]);
@@ -311,6 +330,8 @@ Handlebars.JavaScriptCompiler = function() {};
if(mustache.hash) {
this.hash(mustache.hash);
+ } else {
+ this.opcode('push', '{}');
}
this.ID(mustache.id);
@@ -521,23 +542,21 @@ Handlebars.JavaScriptCompiler = function() {};
}
},
- lookupWithHelpers: function(name, isScoped) {
- if(name) {
- this.usingKnownHelper = false;
+ knownHelper: function(name) {
+ this.pushStackLiteral(this.nameLookup('helpers', name, 'helper'));
+ },
- var toPush;
- if (!isScoped && this.options.knownHelpers[name]) {
- this.usingKnownHelper = true;
- this.pushStackLiteral(this.nameLookup('helpers', name, 'helper'));
- } else if (isScoped || this.options.knownHelpersOnly) {
- this.pushStackLiteral(this.nameLookup('depth' + this.lastContext, name, 'context'));
- } else {
- this.register('foundHelper', this.nameLookup('helpers', name, 'helper'));
- this.pushStack("foundHelper || " + this.nameLookup('depth' + this.lastContext, name, 'context'));
- }
- } else {
- this.pushStackLiteral('depth' + this.lastContext);
- }
+ lookupOnContext: function(name) {
+ this.pushStackLiteral(this.nameLookup('depth' + this.lastContext, name, 'context'));
+ },
+
+ pushContext: function() {
+ this.pushStackLiteral('depth' + this.lastContext);
+ },
+
+ lookupWithHelpers: function(name) {
+ this.register('foundHelper', this.nameLookup('helpers', name, 'helper'));
+ this.pushStack("foundHelper || " + this.nameLookup('depth' + this.lastContext, name, 'context'));
},
lookup: function(name) {
@@ -559,43 +578,52 @@ Handlebars.JavaScriptCompiler = function() {};
this.pushStack(name);
},
- invokeMustache: function(paramSize, original, hasHash) {
- this.populateParams(paramSize, this.quotedString(original), null, null, hasHash, function(nextStack, helperMissingString, id) {
- if (!this.usingKnownHelper) {
- this.context.aliases.helperMissing = 'helpers.helperMissing';
- this.context.aliases.undef = 'void 0';
- this.source.push("else if(" + id + "=== undef) { " + nextStack + " = helperMissing.call(" + helperMissingString + "); }");
- if (nextStack !== id) {
- this.source.push("else { " + nextStack + " = " + id + "; }");
- }
+ // The rules for mustaches are:
+ //
+ // If the first parameter resolves to a function, call the function with the remaining parameters
+ // If the first parameter resolves to undefined, call helperMissing with the string form of the
+ // first parameter and the remaining parameters
+ // Otherwise, if there is only one parameter, the expression evaluates to the value of the first
+ // parameter
+ invokeMustache: function(paramSize, original) {
+ this.populateParams(paramSize, this.quotedString(original), [], true, function(nextStack, helperMissingString, id) {
+ this.context.aliases.helperMissing = 'helpers.helperMissing';
+ this.context.aliases.undef = 'void 0';
+
+ this.source.push("else if(" + id + "=== undef) { " + nextStack + " = helperMissing.call(" + helperMissingString + "); }");
+ if (nextStack !== id) {
+ this.source.push("else { " + nextStack + " = " + id + "; }");
}
});
},
- invokeProgram: function(guid, paramSize, hasHash) {
- var inverse = this.programExpression(this.inverse);
- var mainProgram = this.programExpression(guid);
+ // The rules for mustaches containing a block are:
+ //
+ // If the first parameter resolves to a function, call the function with the remaining parameters
+ // Otherwise, invoke blockHelperMissing with the string form of the first parameter and the
+ // remaining parameters.
+ invokeProgram: function(guid, paramSize) {
+ var options = [], program, inverse;
- this.populateParams(paramSize, null, mainProgram, inverse, hasHash, function(nextStack, helperMissingString, id) {
- if (!this.usingKnownHelper) {
- this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
- this.source.push("else { " + nextStack + " = blockHelperMissing.call(" + helperMissingString + "); }");
- }
+ if (inverse = this.programExpression(this.inverse)) {
+ options.push("inverse:" + inverse);
+ }
+
+ if (program = this.programExpression(guid)) {
+ options.push("fn:" + program);
+ }
+
+ this.populateParams(paramSize, null, options, false, function(nextStack, helperMissingString) {
+ this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
+ this.source.push("else { " + nextStack + " = blockHelperMissing.call(" + helperMissingString + "); }");
});
},
- populateParams: function(paramSize, helperId, program, inverse, hasHash, callback) {
- var needsRegister = hasHash || this.options.stringParams || inverse || this.options.data;
+ populateParams: function(paramSize, helperId, options, resolveLambdas, callback) {
var id = this.popStack(), nextStack;
- var params = [], param, stringParam, stringOptions;
-
- var options = [], contexts = [];
+ var params = [], contexts = [], param, paramString, stringOptions;
- if (hasHash) {
- options.push("hash:" + this.popStack());
- } else {
- options.push("hash:{}");
- }
+ options.push("hash:" + this.popStack());
for(var i=0; i<paramSize; i++) {
param = this.popStack();
@@ -610,14 +638,6 @@ Handlebars.JavaScriptCompiler = function() {};
options.push("contexts:[" + contexts.join(",") + "]");
}
- if (program) {
- options.push("fn:" + program);
- }
-
- if (inverse) {
- options.push("inverse:" + inverse);
- }
-
if(this.options.data) {
options.push("data:data");
}
@@ -626,25 +646,27 @@ Handlebars.JavaScriptCompiler = function() {};
params.push("params");
- this.populateCall(params, id, helperId || id, callback, program);
+ if (this.usingKnownHelper) {
+ this.pushStack(id + ".call(" + ["depth0"].concat(params).join(", ") + ")");
+ } else {
+ this.findAndCallHelper(params, id, helperId || id, resolveLambdas, callback);
+ }
},
- populateCall: function(params, id, helperId, callback, program) {
+ findAndCallHelper: function(params, id, helperId, resolveLambdas, callback) {
+ this.useRegister('foundHelper');
+ this.context.aliases.functionType = '"function"';
+
var paramString = ["depth0"].concat(params).join(", "), nextStack;
var helperMissingString = ["depth0"].concat(helperId).concat(params).join(", ");
- if (this.usingKnownHelper) {
- nextStack = this.pushStack(id + ".call(" + paramString + ")");
- } else {
- this.useRegister('foundHelper');
+ nextStack = this.nextStack();
+ var condition = resolveLambdas ? "" : "foundHelper && ";
+
+ this.source.push("if(" + condition + "typeof " + id + " === functionType) { " +
+ nextStack + " = " + id + ".call(" + paramString + "); }");
- nextStack = this.nextStack();
- this.context.aliases.functionType = '"function"';
- var condition = program ? "foundHelper && " : "";
- this.source.push("if(" + condition + "typeof " + id + " === functionType) { " + nextStack + " = " + id + ".call(" + paramString + "); }");
- }
callback.call(this, nextStack, helperMissingString, id);
- this.usingKnownHelper = false;
},
invokePartial: function(context) {