Implement block parameters

Fixes #907
This commit is contained in:
kpdecker
2014-12-26 00:31:57 -06:00
parent 9e907e6785
commit 396795c983
9 changed files with 247 additions and 51 deletions
+57 -25
View File
@@ -77,10 +77,12 @@ JavaScriptCompiler.prototype = {
this.hashes = [];
this.compileStack = [];
this.inlineStack = [];
this.blockParams = [];
this.compileChildren(environment, options);
this.useDepths = this.useDepths || environment.useDepths || this.options.compat;
this.useBlockParams = this.useBlockParams || environment.useBlockParams;
var opcodes = environment.opcodes,
opcode,
@@ -127,6 +129,9 @@ JavaScriptCompiler.prototype = {
if (this.useDepths) {
ret.useDepths = true;
}
if (this.useBlockParams) {
ret.useBlockParams = true;
}
if (this.options.compat) {
ret.compat = true;
}
@@ -186,6 +191,9 @@ JavaScriptCompiler.prototype = {
var params = ["depth0", "helpers", "partials", "data"];
if (this.useBlockParams || this.useDepths) {
params.push('blockParams');
}
if (this.useDepths) {
params.push('depths');
}
@@ -385,9 +393,7 @@ JavaScriptCompiler.prototype = {
// Looks up the value of `name` on the current context and pushes
// it onto the stack.
lookupOnContext: function(parts, falsy, scoped) {
/*jshint -W083 */
var i = 0,
len = parts.length;
var i = 0;
if (!scoped && this.options.compat && !this.lastContext) {
// The depthed query is expected to handle the undefined logic for the root level that
@@ -397,19 +403,21 @@ JavaScriptCompiler.prototype = {
this.pushContext();
}
for (; i < len; i++) {
this.replaceStack(function(current) {
var lookup = this.nameLookup(current, parts[i], 'context');
// We want to ensure that zero and false are handled properly if the context (falsy flag)
// needs to have the special handling for these values.
if (!falsy) {
return [' != null ? ', lookup, ' : ', current];
} else {
// Otherwise we can use generic falsy handling
return [' && ', lookup];
}
});
}
this.resolvePath('context', parts, i, falsy);
},
// [lookupBlockParam]
//
// On stack, before: ...
// On stack, after: blockParam[name], ...
//
// Looks up the value of `parts` on the given block param and pushes
// it onto the stack.
lookupBlockParam: function(blockParamId, parts) {
this.useBlockParams = true;
this.push(['blockParams[', blockParamId[0], '][', blockParamId[1], ']']);
this.resolvePath('context', parts, 1);
},
// [lookupData]
@@ -426,9 +434,23 @@ JavaScriptCompiler.prototype = {
this.pushStackLiteral('this.data(data, ' + depth + ')');
}
for (var i = 0, len = parts.length; i < len; i++) {
this.resolvePath('data', parts, 0, true);
},
resolvePath: function(type, parts, i, falsy) {
/*jshint -W083 */
var len = parts.length;
for (; i < len; i++) {
this.replaceStack(function(current) {
return [' && ', this.nameLookup(current, parts[i], 'data')];
var lookup = this.nameLookup(current, parts[i], type);
// We want to ensure that zero and false are handled properly if the context (falsy flag)
// needs to have the special handling for these values.
if (!falsy) {
return [' != null ? ', lookup, ' : ', current];
} else {
// Otherwise we can use generic falsy handling
return [' && ', lookup];
}
});
}
},
@@ -661,8 +683,12 @@ JavaScriptCompiler.prototype = {
hash.values[key] = value;
},
pushId: function(type, name) {
if (type === 'PathExpression') {
pushId: function(type, name, child) {
if (type === 'BlockParam') {
this.pushStackLiteral(
'blockParams[' + name[0] + '].path[' + name[1] + ']'
+ (child ? ' + ' + JSON.stringify('.' + child) : ''));
} else if (type === 'PathExpression') {
this.pushString(name);
} else if (type === 'SubExpression') {
this.pushStackLiteral('true');
@@ -693,11 +719,13 @@ JavaScriptCompiler.prototype = {
this.context.environments[index] = child;
this.useDepths = this.useDepths || compiler.useDepths;
this.useBlockParams = this.useBlockParams || compiler.useBlockParams;
} else {
child.index = index;
child.name = 'program' + index;
this.useDepths = this.useDepths || child.useDepths;
this.useBlockParams = this.useBlockParams || child.useBlockParams;
}
}
},
@@ -712,11 +740,12 @@ JavaScriptCompiler.prototype = {
programExpression: function(guid) {
var child = this.environment.children[guid],
useDepths = this.useDepths;
programParams = [child.index, 'data', child.blockParams];
var programParams = [child.index, 'data'];
if (useDepths) {
if (this.useBlockParams || this.useDepths) {
programParams.push('blockParams');
}
if (this.useDepths) {
programParams.push('depths');
}
@@ -943,7 +972,10 @@ JavaScriptCompiler.prototype = {
}
if (this.options.data) {
options.data = "data";
options.data = 'data';
}
if (this.useBlockParams) {
options.blockParams = 'blockParams';
}
return options;
},