Avoid direct references to sexpr in statements

This allows us to avoid creating unnecessary AST nodes and avoids things like isHelper.

Side effect of these changes is that @data functions can now have data parameters passed to them.
This commit is contained in:
kpdecker
2015-01-18 17:27:27 -06:00
parent 999da739a6
commit 884bf15536
10 changed files with 100 additions and 91 deletions
+17 -19
View File
@@ -8,21 +8,25 @@ var AST = {
this.strip = strip;
},
MustacheStatement: function(sexpr, escaped, strip, locInfo) {
MustacheStatement: function(path, params, hash, escaped, strip, locInfo) {
this.loc = locInfo;
this.type = 'MustacheStatement';
this.sexpr = sexpr;
this.path = path;
this.params = params || [];
this.hash = hash;
this.escaped = escaped;
this.strip = strip;
},
BlockStatement: function(sexpr, program, inverse, openStrip, inverseStrip, closeStrip, locInfo) {
BlockStatement: function(path, params, hash, program, inverse, openStrip, inverseStrip, closeStrip, locInfo) {
this.loc = locInfo;
this.type = 'BlockStatement';
this.sexpr = sexpr;
this.path = path;
this.params = params || [];
this.hash = hash;
this.program = program;
this.inverse = inverse;
@@ -31,12 +35,15 @@ var AST = {
this.closeStrip = closeStrip;
},
PartialStatement: function(sexpr, strip, locInfo) {
PartialStatement: function(name, params, hash, strip, locInfo) {
this.loc = locInfo;
this.type = 'PartialStatement';
this.sexpr = sexpr;
this.indent = '';
this.name = name;
this.params = params || [];
this.hash = hash;
this.indent = '';
this.strip = strip;
},
@@ -63,15 +70,6 @@ var AST = {
this.hash = hash;
},
PartialExpression: function(name, params, hash, locInfo) {
this.loc = locInfo;
this.type = 'PartialExpression';
this.name = name;
this.params = params || [];
this.hash = hash;
},
PathExpression: function(data, depth, parts, original, locInfo) {
this.loc = locInfo;
this.type = 'PathExpression';
@@ -121,8 +119,8 @@ var AST = {
// * it is an eligible helper, and
// * it has at least one parameter or hash segment
// TODO: Make these public utility methods
helperExpression: function(sexpr) {
return !!(sexpr.isHelper || sexpr.params.length || sexpr.hash);
helperExpression: function(node) {
return !!(node.type === 'SubExpression' || node.params.length || node.hash);
},
scopedId: function(path) {
+12 -18
View File
@@ -110,28 +110,27 @@ Compiler.prototype = {
},
BlockStatement: function(block) {
var sexpr = block.sexpr,
program = block.program,
var program = block.program,
inverse = block.inverse;
program = program && this.compileProgram(program);
inverse = inverse && this.compileProgram(inverse);
var type = this.classifySexpr(sexpr);
var type = this.classifySexpr(block);
if (type === 'helper') {
this.helperSexpr(sexpr, program, inverse);
this.helperSexpr(block, program, inverse);
} else if (type === 'simple') {
this.simpleSexpr(sexpr);
this.simpleSexpr(block);
// now that the simple mustache is resolved, we need to
// evaluate it by executing `blockHelperMissing`
this.opcode('pushProgram', program);
this.opcode('pushProgram', inverse);
this.opcode('emptyHash');
this.opcode('blockValue', sexpr.path.original);
this.opcode('blockValue', block.path.original);
} else {
this.ambiguousSexpr(sexpr, program, inverse);
this.ambiguousSexpr(block, program, inverse);
// now that the simple mustache is resolved, we need to
// evaluate it by executing `blockHelperMissing`
@@ -147,20 +146,20 @@ Compiler.prototype = {
PartialStatement: function(partial) {
this.usePartial = true;
var params = partial.sexpr.params;
var params = partial.params;
if (params.length > 1) {
throw new Exception('Unsupported number of partial arguments: ' + params.length, partial);
} else if (!params.length) {
params.push({type: 'PathExpression', parts: [], depth: 0});
}
var partialName = partial.sexpr.name.original,
isDynamic = partial.sexpr.name.type === 'SubExpression';
var partialName = partial.name.original,
isDynamic = partial.name.type === 'SubExpression';
if (isDynamic) {
this.accept(partial.sexpr.name);
this.accept(partial.name);
}
this.setupFullMustacheParams(partial.sexpr, undefined, undefined, true);
this.setupFullMustacheParams(partial, undefined, undefined, true);
var indent = partial.indent || '';
if (this.options.preventIndent && indent) {
@@ -173,7 +172,7 @@ Compiler.prototype = {
},
MustacheStatement: function(mustache) {
this.accept(mustache.sexpr);
this.SubExpression(mustache);
if(mustache.escaped && !this.options.noEscape) {
this.opcode('appendEscaped');
@@ -340,11 +339,6 @@ Compiler.prototype = {
pushParam: function(val) {
var value = val.value != null ? val.value : val.original || '';
// Force helper evaluation
if (val.type === 'SubExpression') {
val.isHelper = true;
}
if (this.stringParams) {
if (value.replace) {
value = value
+12 -10
View File
@@ -52,28 +52,29 @@ export function preparePath(data, parts, locInfo) {
return new this.PathExpression(data, depth, dig, original, locInfo);
}
export function prepareMustache(sexpr, open, strip, locInfo) {
export function prepareMustache(path, params, hash, open, strip, locInfo) {
/*jshint -W040 */
// Must use charAt to support IE pre-10
var escapeFlag = open.charAt(3) || open.charAt(2),
escaped = escapeFlag !== '{' && escapeFlag !== '&';
return new this.MustacheStatement(sexpr, escaped, strip, this.locInfo(locInfo));
return new this.MustacheStatement(path, params, hash, escaped, strip, this.locInfo(locInfo));
}
export function prepareRawBlock(openRawBlock, content, close, locInfo) {
/*jshint -W040 */
if (openRawBlock.sexpr.path.original !== close) {
var errorNode = {loc: openRawBlock.sexpr.loc};
if (openRawBlock.path.original !== close) {
var errorNode = {loc: openRawBlock.path.loc};
throw new Exception(openRawBlock.sexpr.path.original + " doesn't match " + close, errorNode);
throw new Exception(openRawBlock.path.original + " doesn't match " + close, errorNode);
}
locInfo = this.locInfo(locInfo);
var program = new this.Program([content], null, {}, locInfo);
return new this.BlockStatement(
openRawBlock.sexpr, program, undefined,
openRawBlock.path, openRawBlock.params, openRawBlock.hash,
program, undefined,
{}, {}, {},
locInfo);
}
@@ -81,10 +82,10 @@ export function prepareRawBlock(openRawBlock, content, close, locInfo) {
export function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) {
/*jshint -W040 */
// When we are chaining inverse calls, we will not have a close path
if (close && close.path && openBlock.sexpr.path.original !== close.path.original) {
var errorNode = {loc: openBlock.sexpr.loc};
if (close && close.path && openBlock.path.original !== close.path.original) {
var errorNode = {loc: openBlock.path.loc};
throw new Exception(openBlock.sexpr.path.original + ' doesn\'t match ' + close.path.original, errorNode);
throw new Exception(openBlock.path.original + ' doesn\'t match ' + close.path.original, errorNode);
}
program.blockParams = openBlock.blockParams;
@@ -108,7 +109,8 @@ export function prepareBlock(openBlock, program, inverseAndProgram, close, inver
}
return new this.BlockStatement(
openBlock.sexpr, program, inverse,
openBlock.path, openBlock.params, openBlock.hash,
program, inverse,
openBlock.strip, inverseStrip, close && close.strip,
this.locInfo(locInfo));
}
+7 -8
View File
@@ -45,7 +45,7 @@ PrintVisitor.prototype.Program = function(program) {
};
PrintVisitor.prototype.MustacheStatement = function(mustache) {
return this.pad('{{ ' + this.accept(mustache.sexpr) + ' }}');
return this.pad('{{ ' + this.SubExpression(mustache) + ' }}');
};
PrintVisitor.prototype.BlockStatement = function(block) {
@@ -53,7 +53,7 @@ PrintVisitor.prototype.BlockStatement = function(block) {
out = out + this.pad('BLOCK:');
this.padding++;
out = out + this.pad(this.accept(block.sexpr));
out = out + this.pad(this.SubExpression(block));
if (block.program) {
out = out + this.pad('PROGRAM:');
this.padding++;
@@ -74,13 +74,12 @@ PrintVisitor.prototype.BlockStatement = function(block) {
};
PrintVisitor.prototype.PartialStatement = function(partial) {
var sexpr = partial.sexpr,
content = 'PARTIAL:' + sexpr.name.original;
if(sexpr.params[0]) {
content += ' ' + this.accept(sexpr.params[0]);
var content = 'PARTIAL:' + partial.name.original;
if(partial.params[0]) {
content += ' ' + this.accept(partial.params[0]);
}
if (sexpr.hash) {
content += ' ' + this.accept(sexpr.hash);
if (partial.hash) {
content += ' ' + this.accept(partial.hash);
}
return this.pad('{{> ' + content + ' }}');
};
+10 -3
View File
@@ -71,17 +71,24 @@ Visitor.prototype = {
},
MustacheStatement: function(mustache) {
this.acceptRequired(mustache, 'sexpr');
this.acceptRequired(mustache, 'path');
this.acceptArray(mustache.params);
this.acceptKey(mustache, 'hash');
},
BlockStatement: function(block) {
this.acceptRequired(block, 'sexpr');
this.acceptRequired(block, 'path');
this.acceptArray(block.params);
this.acceptKey(block, 'hash');
this.acceptKey(block, 'program');
this.acceptKey(block, 'inverse');
},
PartialStatement: function(partial) {
this.acceptRequired(partial, 'sexpr');
this.acceptRequired(partial, 'name');
this.acceptArray(partial.params);
this.acceptKey(partial, 'hash');
},
ContentStatement: function(/* content */) {},