Only provide aliases for multiple use calls

Fixes #903
This commit is contained in:
kpdecker
2014-11-08 18:53:43 -06:00
parent 8dfeabdd16
commit ac208b1bcd
+39 -26
View File
@@ -20,9 +20,7 @@ JavaScriptCompiler.prototype = {
}
},
depthedLookup: function(name) {
this.aliases.lookup = 'this.lookup';
return ['lookup(depths, "', name, '")'];
return [this.aliasable('this.lookup'), '(depths, "', name, '")'];
},
compilerInfo: function() {
@@ -171,9 +169,18 @@ JavaScriptCompiler.prototype = {
}
// Generate minimizer alias mappings
//
// When using true SourceNodes, this will update all references to the given alias
// as the source nodes are reused in situ. For the non-source node compilation mode,
// aliases will not be used, but this case is already being run on the client and
// we aren't concern about minimizing the template size.
var aliasCount = 0;
for (var alias in this.aliases) {
if (this.aliases.hasOwnProperty(alias)) {
varDeclarations += ', ' + alias + '=' + this.aliases[alias];
var node = this.aliases[alias];
if (this.aliases.hasOwnProperty(alias) && node.children && node.referenceCount > 1) {
varDeclarations += ', alias' + (++aliasCount) + '=' + alias;
node.children[0] = 'alias' + aliasCount;
}
}
@@ -264,15 +271,14 @@ JavaScriptCompiler.prototype = {
// replace it on the stack with the result of properly
// invoking blockHelperMissing.
blockValue: function(name) {
this.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
var params = [this.contextName(0)];
var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),
params = [this.contextName(0)];
this.setupParams(name, 0, params);
var blockName = this.popStack();
params.splice(1, 0, blockName);
this.push(this.source.functionCall('blockHelperMissing', 'call', params));
this.push(this.source.functionCall(blockHelperMissing, 'call', params));
},
// [ambiguousBlockValue]
@@ -282,10 +288,9 @@ JavaScriptCompiler.prototype = {
// On stack, after, if no lastHelper: same as [blockValue]
// On stack, after, if lastHelper: value
ambiguousBlockValue: function() {
this.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
// We're being a bit cheeky and reusing the options value from the prior exec
var params = [this.contextName(0)];
var blockHelperMissing = this.aliasable('helpers.blockHelperMissing'),
params = [this.contextName(0)];
this.setupParams('', 0, params, true);
this.flushInline();
@@ -295,7 +300,7 @@ JavaScriptCompiler.prototype = {
this.pushSource([
'if (!', this.lastHelper, ') { ',
current, ' = ', this.source.functionCall('blockHelperMissing', 'call', params),
current, ' = ', this.source.functionCall(blockHelperMissing, 'call', params),
'}']);
},
@@ -347,9 +352,8 @@ JavaScriptCompiler.prototype = {
//
// Escape `value` and append it to the buffer
appendEscaped: function() {
this.aliases.escapeExpression = 'this.escapeExpression';
this.pushSource(this.appendToBuffer(['escapeExpression(', this.popStack(), ')']));
this.pushSource(this.appendToBuffer(
[this.aliasable('this.escapeExpression'), '(', this.popStack(), ')']));
},
// [getContext]
@@ -438,9 +442,7 @@ JavaScriptCompiler.prototype = {
// If the `value` is a lambda, replace it on the stack by
// the return value of the lambda
resolvePossibleLambda: function() {
this.aliases.lambda = 'this.lambda';
this.push(['lambda(', this.popStack(), ', ', this.contextName(0), ')']);
this.push([this.aliasable('this.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']);
},
// [pushStringParam]
@@ -546,15 +548,13 @@ JavaScriptCompiler.prototype = {
//
// If the helper is not found, `helperMissing` is called.
invokeHelper: function(paramSize, name, isSimple) {
this.aliases.helperMissing = 'helpers.helperMissing';
var nonHelper = this.popStack();
var helper = this.setupHelper(paramSize, name);
var simple = isSimple ? [helper.name, ' || '] : '';
this.push(
this.source.functionCall(
['('].concat(simple, nonHelper, ' || ', 'helperMissing)'),
['('].concat(simple, nonHelper, ' || ', this.aliasable('helpers.helperMissing'), ')'),
'call',
helper.callParams));
},
@@ -584,8 +584,6 @@ JavaScriptCompiler.prototype = {
// and can be avoided by passing the `knownHelpers` and
// `knownHelpersOnly` flags at compile-time.
invokeAmbiguous: function(name, helperCall) {
this.aliases.functionType = '"function"';
this.aliases.helperMissing = 'helpers.helperMissing';
this.useRegister('helper');
var nonHelper = this.popStack();
@@ -596,9 +594,10 @@ JavaScriptCompiler.prototype = {
var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
this.push([
'((helper = (helper = ', helperName, ' || ', nonHelper, ') != null ? helper : helperMissing',
'((helper = (helper = ', helperName, ' || ', nonHelper, ') != null ? helper : ',
this.aliasable('helpers.helperMissing'),
(helper.paramsInit ? ['),(', helper.paramsInit] : []), '),',
'(typeof helper === functionType ? ',
'(typeof helper === ', this.aliasable('"function"'), ' ? ',
this.source.functionCall('helper','call', helper.callParams), ' : helper))'
]);
},
@@ -865,6 +864,20 @@ JavaScriptCompiler.prototype = {
return this.source.objectLiteral(obj);
},
aliasable: function(name) {
var ret = this.aliases[name];
if (ret) {
ret.referenceCount++;
return ret;
}
ret = this.aliases[name] = this.source.wrap(name);
ret.aliasable = true;
ret.referenceCount = 1;
return ret;
},
setupHelper: function(paramSize, name, blockHelper) {
var params = [],
paramsInit = this.setupParams(name, paramSize, params, blockHelper);