diff options
author | tomhuda <tomhuda@tilde.io> | 2012-05-28 17:35:21 -0700 |
---|---|---|
committer | tomhuda <tomhuda@tilde.io> | 2012-05-28 17:35:21 -0700 |
commit | 727eb26cb6a9e89ab08596dedbabcec0becb4d75 (patch) | |
tree | 1e9d19609bc1088196cd3646d1746cf427ab120d /lib/handlebars/compiler/compiler.js | |
parent | 175c6fae0f704b2f1088728136e238186fbb1cf3 (diff) | |
download | handlebars.js-727eb26cb6a9e89ab08596dedbabcec0becb4d75.zip handlebars.js-727eb26cb6a9e89ab08596dedbabcec0becb4d75.tar.gz handlebars.js-727eb26cb6a9e89ab08596dedbabcec0becb4d75.tar.bz2 |
Remove unneeded code and add docs
There were a few operations that are no longer
needed, so remove them. Also document all
operations.
Diffstat (limited to 'lib/handlebars/compiler/compiler.js')
-rw-r--r-- | lib/handlebars/compiler/compiler.js | 382 |
1 files changed, 213 insertions, 169 deletions
diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js index 74b0b0b..cab5b30 100644 --- a/lib/handlebars/compiler/compiler.js +++ b/lib/handlebars/compiler/compiler.js @@ -240,21 +240,7 @@ Handlebars.JavaScriptCompiler = function() {}; ID: function(id) { this.addDepth(id.depth); this.opcode('getContext', id.depth); - - 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); - } + this.opcode('lookupOnContext', id.parts[0]); for(var i=1, l=id.parts.length; i<l; i++) { this.opcode('lookup', id.parts[i]); @@ -361,14 +347,6 @@ Handlebars.JavaScriptCompiler = function() {}; } return params; - }, - - setupStackForMustache: function(mustache) { - var params = this.setupMustacheParams(mustache); - - this.ID(mustache.id); - - return params; } }; @@ -525,6 +503,15 @@ Handlebars.JavaScriptCompiler = function() {}; } }, + // [blockValue] + // + // On stack, before: hash, inverse, program, value + // On stack, after: return value of blockHelperMissing + // + // The purpose of this opcode is to take a block of the form + // `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and + // replace it on the stack with the result of properly + // invoking blockHelperMissing. blockValue: function() { this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing'; @@ -537,6 +524,12 @@ Handlebars.JavaScriptCompiler = function() {}; }); }, + // [ambiguousBlockValue] + // + // On stack, before: hash, inverse, program, value + // Compiler value, before: lastHelper=value of last found helper, if any + // On stack, after, if no lastHelper: same as [blockValue] + // On stack, after, if lastHelper: value ambiguousBlockValue: function() { this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing'; @@ -549,10 +542,25 @@ Handlebars.JavaScriptCompiler = function() {}; this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }"); }, + // [appendContent] + // + // On stack, before: ... + // On stack, after: ... + // + // Appends the string value of `content` to the current buffer appendContent: function(content) { this.source.push(this.appendToBuffer(this.quotedString(content))); }, + // [append] + // + // On stack, before: value, ... + // On stack, after: ... + // + // Coerces `value` to a String and appends it to the current buffer. + // + // If `value` is truthy, or 0, it is coerced into a string and appended + // Otherwise, the empty string is appended append: function() { var local = this.popStack(); this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }"); @@ -561,6 +569,12 @@ Handlebars.JavaScriptCompiler = function() {}; } }, + // [appendEscaped] + // + // On stack, before: value, ... + // On stack, after: ... + // + // Escape `value` and append it to the buffer appendEscaped: function() { var opcode = this.nextOpcode(), extra = ""; this.context.aliases.escapeExpression = 'this.escapeExpression'; @@ -573,24 +587,47 @@ Handlebars.JavaScriptCompiler = function() {}; this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")" + extra)); }, + // [getContext] + // + // On stack, before: ... + // On stack, after: ... + // Compiler value, after: lastContext=depth + // + // Set the value of the `lastContext` compiler value to the depth getContext: function(depth) { if(this.lastContext !== depth) { this.lastContext = depth; } }, - knownHelper: function(name) { - this.pushStackLiteral(this.nameLookup('helpers', name, 'helper')); - }, - + // [lookupOnContext] + // + // On stack, before: ... + // On stack, after: currentContext[name], ... + // + // Looks up the value of `name` on the current context and pushes + // it onto the stack. lookupOnContext: function(name) { this.pushStack(this.nameLookup('depth' + this.lastContext, name, 'context')); }, + // [pushContext] + // + // On stack, before: ... + // On stack, after: currentContext, ... + // + // Pushes the value of the current context onto the stack. pushContext: function() { this.pushStackLiteral('depth' + this.lastContext); }, + // [resolvePossibleLambda] + // + // On stack, before: value, ... + // On stack, after: resolved value, ... + // + // If the `value` is a lambda, replace it on the stack by + // the return value of the lambda resolvePossibleLambda: function() { this.context.aliases.functionType = '"function"'; @@ -599,57 +636,72 @@ Handlebars.JavaScriptCompiler = function() {}; }); }, - lookupWithHelpers: function(name) { - var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); - this.register('foundHelper', helperName); - this.pushStack("foundHelper || " + this.nameLookup('depth' + this.lastContext, name, 'context')); - }, - + // [lookup] + // + // On stack, before: value, ... + // On stack, after: value[name], ... + // + // Replace the value on the stack with the result of looking + // up `name` on `value` lookup: function(name) { this.replaceStack(function(current) { return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context'); }); }, + // [pushStringParam] + // + // On stack, before: ... + // On stack, after: string, currentContext, ... + // + // This opcode is designed for use in string mode, which + // provides the string value of a parameter along with its + // depth rather than resolving it immediately. pushStringParam: function(string) { this.pushStackLiteral('depth' + this.lastContext); this.pushString(string); }, + // [pushString] + // + // On stack, before: ... + // On stack, after: quotedString(string), ... + // + // Push a quoted version of `string` onto the stack pushString: function(string) { this.pushStackLiteral(this.quotedString(string)); }, - push: function(name) { - this.pushStack(name); + // [push] + // + // On stack, before: ... + // On stack, after: expr, ... + // + // Push an expression onto the stack + push: function(expr) { + this.pushStack(expr); }, + // [pushLiteral] + // + // On stack, before: ... + // On stack, after: value, ... + // + // Pushes a value onto the stack. This operation prevents + // the compiler from creating a temporary variable to hold + // it. pushLiteral: function(value) { this.pushStackLiteral(value); }, - // The rules for mustaches containing a block are: + // [pushProgram] // - // 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; - - 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 + "); }"); - }); - }, - + // On stack, before: ... + // On stack, after: program(guid), ... + // + // Push a program expression onto the stack. This takes + // a compile-time guid and converts it into a runtime-accessible + // expression. pushProgram: function(guid) { if (guid != null) { this.pushStackLiteral(this.programExpression(guid)); @@ -658,6 +710,15 @@ Handlebars.JavaScriptCompiler = function() {}; } }, + // [invokeHelper] + // + // On stack, before: hash, inverse, program, params..., ... + // On stack, after: result of helper invocation + // + // Pops off the helper's parameters, invokes the helper, + // and pushes the helper's return value onto the stack. + // + // If the helper is not found, `helperMissing` is called. invokeHelper: function(paramSize, name) { this.context.aliases.helperMissing = 'helpers.helperMissing'; @@ -669,11 +730,30 @@ Handlebars.JavaScriptCompiler = function() {}; helper.helperMissingParams + ")"); }, + // [invokeKnownHelper] + // + // On stack, before: hash, inverse, program, params..., ... + // On stack, after: result of helper invocation + // + // This operation is used when the helper is known to exist, + // so a `helperMissing` fallback is not required. invokeKnownHelper: function(paramSize, name) { var helper = this.setupHelper(paramSize, name); this.pushStack(helper.name + ".call(" + helper.callParams + ")"); }, + // [invokeAmbiguous] + // + // On stack, before: hash, inverse, program, params..., ... + // On stack, after: result of disambiguation + // + // This operation is used when an expression like `{{foo}}` + // is provided, but we don't know at compile-time whether it + // is a helper or a path. + // + // This operation emits more code than the other options, + // and can be avoided by passing the `knownHelpers` and + // `knownHelpersOnly` flags at compile-time. invokeAmbiguous: function(name) { this.context.aliases.functionType = '"function"'; @@ -690,119 +770,15 @@ Handlebars.JavaScriptCompiler = function() {}; this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '() : ' + nextStack + '; }'); }, - setupHelper: function(paramSize, name) { - var params = []; - this.setupParams(paramSize, params); - var foundHelper = this.nameLookup('helpers', name, 'helper'); - - return { - params: params, - name: foundHelper, - callParams: ["depth0"].concat(params).join(", "), - helperMissingParams: ["depth0", this.quotedString(name)].concat(params).join(", ") - }; - }, - - // the params and contexts arguments are passed in arrays - // to fill in - setupParams: function(paramSize, params) { - var options = [], contexts = [], param, inverse, program; - - options.push("hash:" + this.popStack()); - - inverse = this.popStack(); - program = this.popStack(); - - // Avoid setting fn and inverse if neither are set. This allows - // helpers to do a check for `if (options.fn)` - if (program || inverse) { - if (!program) { - this.context.aliases.self = "this"; - program = "self.noop"; - } - - if (!inverse) { - this.context.aliases.self = "this"; - inverse = "self.noop"; - } - - options.push("inverse:" + inverse); - options.push("fn:" + program); - } - - 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; - - 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"); - } - - this.register("params", "{" + options.join(",") + "}"); - - params.push("params"); - - if (this.usingKnownHelper) { - this.pushStack(id + ".call(" + ["depth0"].concat(params).join(", ") + ")"); - } else { - this.findAndCallHelper(params, id, helperId || id, resolveLambdas, callback); - } - }, - - 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(", "); - - nextStack = this.nextStack(); - var condition = resolveLambdas ? "" : "foundHelper && "; - - this.source.push("if(" + condition + "typeof " + id + " === functionType) { " + - nextStack + " = " + id + ".call(" + paramString + "); }"); - - callback.call(this, nextStack, helperMissingString, id); - }, - - invokePartial: function(context) { - var params = [this.nameLookup('partials', context, 'partial'), "'" + context + "'", this.popStack(), "helpers", "partials"]; + // [invokePartial] + // + // On stack, before: context, ... + // On stack after: result of partial invocation + // + // This operation pops off a context, invokes a partial with that context, + // and pushes the result of the invocation back. + invokePartial: function(name) { + var params = [this.nameLookup('partials', name, 'partial'), "'" + name + "'", this.popStack(), "helpers", "partials"]; if (this.options.data) { params.push("data"); @@ -812,6 +788,13 @@ Handlebars.JavaScriptCompiler = function() {}; this.pushStack("self.invokePartial(" + params.join(", ") + ");"); }, + // [assignToHash] + // + // On stack, before: value, hash, ... + // On stack, after: hash, ... + // + // Pops a value and hash off the stack, assigns `hash[key] = value` + // and pushes the hash back onto the stack. assignToHash: function(key) { var value = this.popStack(); var hash = this.topStack(); @@ -934,6 +917,67 @@ Handlebars.JavaScriptCompiler = function() {}; .replace(/"/g, '\\"') .replace(/\n/g, '\\n') .replace(/\r/g, '\\r') + '"'; + }, + + setupHelper: function(paramSize, name) { + var params = []; + this.setupParams(paramSize, params); + var foundHelper = this.nameLookup('helpers', name, 'helper'); + + return { + params: params, + name: foundHelper, + callParams: ["depth0"].concat(params).join(", "), + helperMissingParams: ["depth0", this.quotedString(name)].concat(params).join(", ") + }; + }, + + // the params and contexts arguments are passed in arrays + // to fill in + setupParams: function(paramSize, params) { + var options = [], contexts = [], param, inverse, program; + + options.push("hash:" + this.popStack()); + + inverse = this.popStack(); + program = this.popStack(); + + // Avoid setting fn and inverse if neither are set. This allows + // helpers to do a check for `if (options.fn)` + if (program || inverse) { + if (!program) { + this.context.aliases.self = "this"; + program = "self.noop"; + } + + if (!inverse) { + this.context.aliases.self = "this"; + inverse = "self.noop"; + } + + options.push("inverse:" + inverse); + options.push("fn:" + program); + } + + 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(", "); } }; |