diff options
author | Yehuda Katz <wycats@gmail.com> | 2012-05-26 22:17:22 -0700 |
---|---|---|
committer | Yehuda Katz <wycats@gmail.com> | 2012-05-26 22:17:22 -0700 |
commit | 68c76c9b2eb2fd1cebf5d9fea87f5dfb85b8529d (patch) | |
tree | 2c634a8fdf00a6f33371d1768d1b04b67c11e2e8 /lib/handlebars/compiler/compiler.js | |
parent | facefe8fedd2411bf8ce696b072d15041f0265a0 (diff) | |
download | handlebars.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.js | 160 |
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) { |