Clean up the compiler a bit
This commit is contained in:
@@ -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,44 +578,53 @@ 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 + "); }");
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
populateParams: function(paramSize, helperId, program, inverse, hasHash, callback) {
|
||||
var needsRegister = hasHash || this.options.stringParams || inverse || this.options.data;
|
||||
var id = this.popStack(), nextStack;
|
||||
var params = [], param, stringParam, stringOptions;
|
||||
|
||||
var options = [], contexts = [];
|
||||
|
||||
if (hasHash) {
|
||||
options.push("hash:" + this.popStack());
|
||||
} else {
|
||||
options.push("hash:{}");
|
||||
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, 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);
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user