summaryrefslogtreecommitdiffstats
path: root/lib/handlebars/compiler/compiler.js
diff options
context:
space:
mode:
authorYehuda Katz <wycats@gmail.com>2012-05-28 00:15:52 -0700
committerYehuda Katz <wycats@gmail.com>2012-05-28 00:15:52 -0700
commit8786a6c6e23ec628300ab405fdec71a888eb39e6 (patch)
treec27d5b11d72b50e39415c63d829da4f4dc86a7d5 /lib/handlebars/compiler/compiler.js
parent246325085faec21087ac177acfd9ce1492c88030 (diff)
downloadhandlebars.js-8786a6c6e23ec628300ab405fdec71a888eb39e6.zip
handlebars.js-8786a6c6e23ec628300ab405fdec71a888eb39e6.tar.gz
handlebars.js-8786a6c6e23ec628300ab405fdec71a888eb39e6.tar.bz2
Start doing earlier work on helpers
Diffstat (limited to 'lib/handlebars/compiler/compiler.js')
-rw-r--r--lib/handlebars/compiler/compiler.js155
1 files changed, 127 insertions, 28 deletions
diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js
index 994192b..c36f7e1 100644
--- a/lib/handlebars/compiler/compiler.js
+++ b/lib/handlebars/compiler/compiler.js
@@ -25,7 +25,10 @@ Handlebars.JavaScriptCompiler = function() {};
pushStringParam: 16,
knownHelper: 17,
pushContext: 18,
- lookupOnContext: 19
+ lookupOnContext: 19,
+ resolvePossibleLambda: 20,
+ invokeHelper: 21,
+ pushLiteral: 22
};
Compiler.MULTI_PARAM_OPCODES = {
@@ -44,7 +47,10 @@ Handlebars.JavaScriptCompiler = function() {};
pushStringParam: 1,
knownHelper: 1,
pushContext: 0,
- lookupOnContext: 1
+ lookupOnContext: 1,
+ resolvePossibleLambda: 0,
+ invokeHelper: 2,
+ pushLiteral: 1
};
Compiler.DISASSEMBLE_MAP = {};
@@ -231,9 +237,18 @@ Handlebars.JavaScriptCompiler = function() {};
},
mustache: function(mustache) {
- var params = this.setupStackForMustache(mustache);
+ var id = mustache.id;
+
+ if (!mustache.eligibleHelper) {
+ this.simpleMustache(mustache);
+ } else if (mustache.isHelper) {
+ this.helperMustache(mustache);
+ } else {
+ var params = this.setupStackForMustache(mustache),
+ name = id.parts[0];
- this.opcode('invokeMustache', params.length, mustache.id.original);
+ this.opcode('invokeMustache', params.length, mustache.id.original);
+ }
if(mustache.escaped && !this.options.noEscape) {
this.opcode('appendEscaped');
@@ -242,9 +257,32 @@ Handlebars.JavaScriptCompiler = function() {};
}
},
- ID: function(id) {
+ simpleMustache: function(mustache) {
+ var id = mustache.id;
+
this.addDepth(id.depth);
+ this.opcode('getContext', id.depth);
+
+ if (id.parts.length) {
+ this.opcode('lookupOnContext', id.parts[0]);
+ for(var i=1, l=id.parts.length; i<l; i++) {
+ this.opcode('lookup', id.parts[i]);
+ }
+ } else {
+ this.opcode('pushContext');
+ }
+ this.opcode('resolvePossibleLambda');
+ },
+ helperMustache: function(mustache) {
+ var params = this.setupMustacheParams(mustache),
+ name = mustache.id.parts[0];
+
+ this.opcode('invokeHelper', params.length, name);
+ },
+
+ ID: function(id) {
+ this.addDepth(id.depth);
this.opcode('getContext', id.depth);
var name = id.parts[0];
@@ -282,25 +320,6 @@ Handlebars.JavaScriptCompiler = function() {};
comment: function() {},
// HELPERS
- pushParams: function(params) {
- var i = params.length, param;
-
- while(i--) {
- param = params[i];
-
- if(this.options.stringParams) {
- if(param.depth) {
- this.addDepth(param.depth);
- }
-
- this.opcode('getContext', param.depth || 0);
- this.opcode('pushStringParam', param.string);
- } else {
- this[param.type](param);
- }
- }
- },
-
opcode: function(name, val1, val2, val3) {
this.opcodes.push(Compiler.OPCODE_MAP[name]);
if(val1 !== undefined) { this.opcodes.push(val1); }
@@ -323,17 +342,41 @@ Handlebars.JavaScriptCompiler = function() {};
}
},
- setupStackForMustache: function(mustache) {
- var params = mustache.params;
+ pushParams: function(params) {
+ var i = params.length, param;
+
+ while(i--) {
+ param = params[i];
+ if(this.options.stringParams) {
+ if(param.depth) {
+ this.addDepth(param.depth);
+ }
+
+ this.opcode('getContext', param.depth || 0);
+ this.opcode('pushStringParam', param.string);
+ } else {
+ this[param.type](param);
+ }
+ }
+ },
+
+ setupMustacheParams: function(mustache) {
+ var params = mustache.params;
this.pushParams(params);
if(mustache.hash) {
this.hash(mustache.hash);
} else {
- this.opcode('push', '{}');
+ this.opcode('pushLiteral', '{}');
}
+ return params;
+ },
+
+ setupStackForMustache: function(mustache) {
+ var params = this.setupMustacheParams(mustache);
+
this.ID(mustache.id);
return params;
@@ -547,13 +590,21 @@ Handlebars.JavaScriptCompiler = function() {};
},
lookupOnContext: function(name) {
- this.pushStackLiteral(this.nameLookup('depth' + this.lastContext, name, 'context'));
+ this.pushStack(this.nameLookup('depth' + this.lastContext, name, 'context'));
},
pushContext: function() {
this.pushStackLiteral('depth' + this.lastContext);
},
+ resolvePossibleLambda: function() {
+ this.context.aliases.functionType = '"function"';
+
+ this.replaceStack(function(current) {
+ return "typeof " + current + " === functionType ? " + current + "() : " + current;
+ });
+ },
+
lookupWithHelpers: function(name) {
this.register('foundHelper', this.nameLookup('helpers', name, 'helper'));
this.pushStack("foundHelper || " + this.nameLookup('depth' + this.lastContext, name, 'context'));
@@ -578,6 +629,10 @@ Handlebars.JavaScriptCompiler = function() {};
this.pushStack(name);
},
+ pushLiteral: function(value) {
+ this.pushStackLiteral(value);
+ },
+
// The rules for mustaches are:
//
// If the first parameter resolves to a function, call the function with the remaining parameters
@@ -619,6 +674,50 @@ Handlebars.JavaScriptCompiler = function() {};
});
},
+ invokeHelper: function(paramSize, name) {
+ this.context.aliases.helperMissing = 'helpers.helperMissing';
+
+ var params = [], contexts = [];
+ this.setupParams(paramSize, params, contexts);
+ this.register('foundHelper', this.nameLookup('helpers', name, 'helper'));
+
+ var main = ["depth0"].concat(params).join(", ");
+ var helperMissing = ["depth0", this.quotedString(name)].concat(params).join(", ");
+ this.pushStack("foundHelper ? foundHelper.call(" + main + ") " +
+ ": helperMissing.call(" + helperMissing + ")");
+
+ //this.replaceStack(function(current) {
+ //});
+ },
+
+ // the params and contexts arguments are passed in arrays
+ // to fill in
+ setupParams: function(paramSize, params) {
+ var options = [], contexts = [], param;
+
+ options.push("hash:" + this.popStack());
+
+ for(var i=0; i<paramSize; i++) {
+ param = this.popStack();
+ params.push(param);
+
+ if(this.options.stringParams) {
+ contexts.push(this.popStack());
+ }
+ }
+
+ if (this.options.stringParams) {
+ options.push("contexts:[" + contexts.join(",") + "]");
+ }
+
+ if(this.options.data) {
+ options.push("data:data");
+ }
+
+ params.push("{" + options.join(",") + "}");
+ return params.join(", ");
+ },
+
populateParams: function(paramSize, helperId, options, resolveLambdas, callback) {
var id = this.popStack(), nextStack;
var params = [], contexts = [], param, paramString, stringOptions;