summaryrefslogtreecommitdiffstats
path: root/lib/handlebars/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'lib/handlebars/compiler')
-rw-r--r--lib/handlebars/compiler/ast.js25
-rw-r--r--lib/handlebars/compiler/compiler.js118
-rw-r--r--lib/handlebars/compiler/helpers.js8
-rw-r--r--lib/handlebars/compiler/javascript-compiler.js4
-rw-r--r--lib/handlebars/compiler/printer.js33
-rw-r--r--lib/handlebars/compiler/visitor.js21
6 files changed, 104 insertions, 105 deletions
diff --git a/lib/handlebars/compiler/ast.js b/lib/handlebars/compiler/ast.js
index 7530074..2439571 100644
--- a/lib/handlebars/compiler/ast.js
+++ b/lib/handlebars/compiler/ast.js
@@ -66,17 +66,10 @@ var AST = {
SexprNode: function(rawParams, hash, locInfo) {
this.loc = locInfo;
- this.type = "sexpr";
- this.hash = hash;
-
- this.id = rawParams[0];
+ this.type = 'SubExpression';
+ this.path = rawParams[0];
this.params = rawParams.slice(1);
- },
-
- HashNode: function(pairs, locInfo) {
- this.loc = locInfo;
- this.type = "hash";
- this.pairs = pairs;
+ this.hash = hash;
},
PathNode: function(data, parts, locInfo) {
@@ -128,6 +121,18 @@ var AST = {
this.loc = locInfo;
this.type = 'BooleanLiteral';
this.value = bool === 'true';
+ },
+
+ HashNode: function(pairs, locInfo) {
+ this.loc = locInfo;
+ this.type = 'Hash';
+ this.pairs = pairs;
+ },
+ HashPair: function(key, value, locInfo) {
+ this.loc = locInfo;
+ this.type = 'HashPair';
+ this.key = key;
+ this.value = value;
}
};
diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js
index 5dbbfc4..e73ce37 100644
--- a/lib/handlebars/compiler/compiler.js
+++ b/lib/handlebars/compiler/compiler.js
@@ -11,16 +11,16 @@ function helperExpr(sexpr) {
return !!(sexpr.isHelper || sexpr.params.length || sexpr.hash);
}
-function scopedId(id) {
- return (/^\.|this\b/).test(id.original);
+function scopedId(path) {
+ return (/^\.|this\b/).test(path.original);
}
// an ID is simple if it only has one part, and that part is not
// `..` or `this`.
-function simpleId(id) {
- var part = id.parts[0];
+function simpleId(path) {
+ var part = path.parts[0];
- return id.parts.length === 1 && !scopedId(id) && !id.depth;
+ return path.parts.length === 1 && !scopedId(path) && !path.depth;
}
export function Compiler() {}
@@ -147,7 +147,7 @@ Compiler.prototype = {
this.opcode('pushProgram', block, program);
this.opcode('pushProgram', block, inverse);
this.opcode('emptyHash', block);
- this.opcode('blockValue', block, sexpr.id.original);
+ this.opcode('blockValue', block, sexpr.path.original);
} else {
this.ambiguousSexpr(sexpr, program, inverse);
@@ -163,7 +163,7 @@ Compiler.prototype = {
},
PartialStatement: function(partial) {
- var partialName = partial.sexpr.id.original;
+ var partialName = partial.sexpr.path.original;
this.usePartial = true;
if (partial.sexpr.hash) {
@@ -194,7 +194,7 @@ Compiler.prototype = {
},
MustacheStatement: function(mustache) {
- this.sexpr(mustache.sexpr);
+ this.accept(mustache.sexpr);
if(mustache.escaped && !this.options.noEscape) {
this.opcode('appendEscaped', mustache);
@@ -211,91 +211,67 @@ Compiler.prototype = {
CommentStatement: function() {},
- sexpr: function(sexpr) {
+ SubExpression: function(sexpr) {
var type = this.classifySexpr(sexpr);
- if (type === "simple") {
+ if (type === 'simple') {
this.simpleSexpr(sexpr);
- } else if (type === "helper") {
+ } else if (type === 'helper') {
this.helperSexpr(sexpr);
} else {
this.ambiguousSexpr(sexpr);
}
},
ambiguousSexpr: function(sexpr, program, inverse) {
- var id = sexpr.id,
- name = id.parts[0],
+ var path = sexpr.path,
+ name = path.parts[0],
isBlock = program != null || inverse != null;
- this.opcode('getContext', sexpr, id.depth);
+ this.opcode('getContext', sexpr, path.depth);
this.opcode('pushProgram', sexpr, program);
this.opcode('pushProgram', sexpr, inverse);
- this.accept(id);
+ this.accept(path);
this.opcode('invokeAmbiguous', sexpr, name, isBlock);
},
simpleSexpr: function(sexpr) {
- var id = sexpr.id;
-
- if (id.parts.length) {
- this.accept(id);
- } else {
- // Simplified ID for `this`
- this.addDepth(id.depth);
- this.opcode('getContext', sexpr, id.depth);
- this.opcode('pushContext', sexpr);
- }
-
+ this.accept(sexpr.path);
this.opcode('resolvePossibleLambda', sexpr);
},
helperSexpr: function(sexpr, program, inverse) {
var params = this.setupFullMustacheParams(sexpr, program, inverse),
- id = sexpr.id,
- name = id.parts[0];
+ path = sexpr.path,
+ name = path.parts[0];
if (this.options.knownHelpers[name]) {
this.opcode('invokeKnownHelper', sexpr, params.length, name);
} else if (this.options.knownHelpersOnly) {
throw new Exception("You specified knownHelpersOnly, but used the unknown helper " + name, sexpr);
} else {
- id.falsy = true;
-
- this.accept(id);
- this.opcode('invokeHelper', sexpr, params.length, id.original, simpleId(id));
- }
- },
-
- hash: function(hash) {
- var pairs = hash.pairs, i, l;
-
- this.opcode('pushHash', hash);
+ path.falsy = true;
- for(i=0, l=pairs.length; i<l; i++) {
- this.pushParam(pairs[i][1]);
+ this.accept(path);
+ this.opcode('invokeHelper', sexpr, params.length, path.original, simpleId(path));
}
- while(i--) {
- this.opcode('assignToHash', hash, pairs[i][0]);
- }
- this.opcode('popHash', hash);
},
- PathExpression: function(id) {
- this.addDepth(id.depth);
- this.opcode('getContext', id, id.depth);
+ PathExpression: function(path) {
+ this.addDepth(path.depth);
+ this.opcode('getContext', path, path.depth);
- var name = id.parts[0];
+ var name = path.parts[0];
if (!name) {
// Context reference, i.e. `{{foo .}}` or `{{foo ..}}`
- this.opcode('pushContext', id);
- } else if (id.data) {
+ this.opcode('pushContext', path);
+ } else if (path.data) {
this.options.data = true;
- this.opcode('lookupData', id, id.depth, id.parts);
+ this.opcode('lookupData', path, path.depth, path.parts);
} else {
- this.opcode('lookupOnContext', id, id.parts, id.falsy, scopedId(id));
+ this.opcode('lookupOnContext', path, path.parts, path.falsy, scopedId(path));
}
},
@@ -311,6 +287,20 @@ Compiler.prototype = {
this.opcode('pushLiteral', bool, bool.value);
},
+ Hash: function(hash) {
+ var pairs = hash.pairs, i, l;
+
+ this.opcode('pushHash', hash);
+
+ for (i=0, l=pairs.length; i<l; i++) {
+ this.pushParam(pairs[i].value);
+ }
+ while (i--) {
+ this.opcode('assignToHash', hash, pairs[i].key);
+ }
+ this.opcode('popHash', hash);
+ },
+
// HELPERS
opcode: function(name, node) {
this.opcodes.push({ opcode: name, args: slice.call(arguments, 2), loc: node.loc });
@@ -328,19 +318,19 @@ Compiler.prototype = {
classifySexpr: function(sexpr) {
// a mustache is an eligible helper if:
// * its id is simple (a single part, not `this` or `..`)
- var isHelper = helperExpr(sexpr);
+ var isHelper = helperExpr(sexpr);
// if a mustache is an eligible helper but not a definite
// helper, it is ambiguous, and will be resolved in a later
// pass or at runtime.
- var isEligible = isHelper || simpleId(sexpr.id);
+ var isEligible = isHelper || simpleId(sexpr.path);
- var options = this.options;
+ var options = this.options;
// if ambiguous, we can possibly resolve the ambiguity now
// An eligible helper is one that does not have a complex path, i.e. `this.foo`, `../foo` etc.
if (isEligible && !isHelper) {
- var name = sexpr.id.parts[0];
+ var name = sexpr.path.parts[0];
if (options.knownHelpers[name]) {
isHelper = true;
@@ -349,9 +339,9 @@ Compiler.prototype = {
}
}
- if (isHelper) { return "helper"; }
- else if (isEligible) { return "ambiguous"; }
- else { return "simple"; }
+ if (isHelper) { return 'helper'; }
+ else if (isEligible) { return 'ambiguous'; }
+ else { return 'simple'; }
},
pushParams: function(params) {
@@ -364,7 +354,7 @@ Compiler.prototype = {
var value = val.value != null ? val.value : val.original || '';
// Force helper evaluation
- if (val.type === 'sexpr') {
+ if (val.type === 'SubExpression') {
val.isHelper = true;
}
@@ -381,10 +371,10 @@ Compiler.prototype = {
this.opcode('getContext', val, val.depth || 0);
this.opcode('pushStringParam', val, value, val.type);
- if (val.type === 'sexpr') {
+ if (val.type === 'SubExpression') {
// Subexpressions get evaluated and passed in
// in string params mode.
- this.sexpr(val);
+ this.accept(val);
}
} else {
if (this.trackIds) {
@@ -409,7 +399,7 @@ Compiler.prototype = {
this.opcode('pushProgram', sexpr, inverse);
if (sexpr.hash) {
- this.hash(sexpr.hash);
+ this.accept(sexpr.hash);
} else {
this.opcode('emptyHash', sexpr);
}
diff --git a/lib/handlebars/compiler/helpers.js b/lib/handlebars/compiler/helpers.js
index 023566b..f75c10b 100644
--- a/lib/handlebars/compiler/helpers.js
+++ b/lib/handlebars/compiler/helpers.js
@@ -26,10 +26,10 @@ export function stripComment(comment) {
export function prepareRawBlock(openRawBlock, content, close, locInfo) {
/*jshint -W040 */
- if (openRawBlock.sexpr.id.original !== close) {
+ if (openRawBlock.sexpr.path.original !== close) {
var errorNode = {loc: openRawBlock.sexpr.loc};
- throw new Exception(openRawBlock.sexpr.id.original + " doesn't match " + close, errorNode);
+ throw new Exception(openRawBlock.sexpr.path.original + " doesn't match " + close, errorNode);
}
var program = new this.ProgramNode([content], null, {}, locInfo);
@@ -40,10 +40,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.id.original !== close.path.original) {
+ if (close && close.path && openBlock.sexpr.path.original !== close.path.original) {
var errorNode = {loc: openBlock.sexpr.loc};
- throw new Exception(openBlock.sexpr.id.original + ' doesn\'t match ' + close.path.original, errorNode);
+ throw new Exception(openBlock.sexpr.path.original + ' doesn\'t match ' + close.path.original, errorNode);
}
program.blockParams = openBlock.blockParams;
diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js
index 2916a32..cde2ab5 100644
--- a/lib/handlebars/compiler/javascript-compiler.js
+++ b/lib/handlebars/compiler/javascript-compiler.js
@@ -460,7 +460,7 @@ JavaScriptCompiler.prototype = {
// If it's a subexpression, the string result
// will be pushed after this opcode.
- if (type !== 'sexpr') {
+ if (type !== 'SubExpression') {
if (typeof string === 'string') {
this.pushString(string);
} else {
@@ -661,7 +661,7 @@ JavaScriptCompiler.prototype = {
pushId: function(type, name) {
if (type === 'PathExpression') {
this.pushString(name);
- } else if (type === 'sexpr') {
+ } else if (type === 'SubExpression') {
this.pushStackLiteral('true');
} else {
this.pushStackLiteral('null');
diff --git a/lib/handlebars/compiler/printer.js b/lib/handlebars/compiler/printer.js
index 05e8ee7..b549d61 100644
--- a/lib/handlebars/compiler/printer.js
+++ b/lib/handlebars/compiler/printer.js
@@ -75,7 +75,7 @@ PrintVisitor.prototype.BlockStatement = function(block) {
PrintVisitor.prototype.PartialStatement = function(partial) {
var sexpr = partial.sexpr,
- content = 'PARTIAL:' + sexpr.id.original;
+ content = 'PARTIAL:' + sexpr.path.original;
if(sexpr.params[0]) {
content += ' ' + this.accept(sexpr.params[0]);
}
@@ -93,7 +93,7 @@ PrintVisitor.prototype.CommentStatement = function(comment) {
return this.pad("{{! '" + comment.value + "' }}");
};
-PrintVisitor.prototype.sexpr = function(sexpr) {
+PrintVisitor.prototype.SubExpression = function(sexpr) {
var params = sexpr.params, paramStrings = [], hash;
for(var i=0, l=params.length; i<l; i++) {
@@ -104,7 +104,7 @@ PrintVisitor.prototype.sexpr = function(sexpr) {
hash = sexpr.hash ? " " + this.accept(sexpr.hash) : "";
- return this.accept(sexpr.id) + " " + params + hash;
+ return this.accept(sexpr.path) + " " + params + hash;
};
PrintVisitor.prototype.PathExpression = function(id) {
@@ -113,19 +113,6 @@ PrintVisitor.prototype.PathExpression = function(id) {
};
-PrintVisitor.prototype.hash = function(hash) {
- var pairs = hash.pairs;
- var joinedPairs = [], left, right;
-
- for(var i=0, l=pairs.length; i<l; i++) {
- left = pairs[i][0];
- right = this.accept(pairs[i][1]);
- joinedPairs.push( left + "=" + right );
- }
-
- return "HASH{" + joinedPairs.join(", ") + "}";
-};
-
PrintVisitor.prototype.StringLiteral = function(string) {
return '"' + string.value + '"';
};
@@ -137,3 +124,17 @@ PrintVisitor.prototype.NumberLiteral = function(number) {
PrintVisitor.prototype.BooleanLiteral = function(bool) {
return "BOOLEAN{" + bool.value + "}";
};
+
+PrintVisitor.prototype.Hash = function(hash) {
+ var pairs = hash.pairs;
+ var joinedPairs = [], left, right;
+
+ for (var i=0, l=pairs.length; i<l; i++) {
+ joinedPairs.push(this.accept(pairs[i]));
+ }
+
+ return 'HASH{' + joinedPairs.join(', ') + '}';
+};
+PrintVisitor.prototype.HashPair = function(pair) {
+ return pair.key + '=' + this.accept(pair.value);
+};
diff --git a/lib/handlebars/compiler/visitor.js b/lib/handlebars/compiler/visitor.js
index e191bbd..c0cfab6 100644
--- a/lib/handlebars/compiler/visitor.js
+++ b/lib/handlebars/compiler/visitor.js
@@ -35,29 +35,32 @@ Visitor.prototype = {
ContentStatement: function(content) {},
CommentStatement: function(comment) {},
- sexpr: function(sexpr) {
+ SubExpression: function(sexpr) {
var params = sexpr.params, paramStrings = [], hash;
- this.accept(sexpr.id);
+ this.accept(sexpr.path);
for(var i=0, l=params.length; i<l; i++) {
this.accept(params[i]);
}
this.accept(sexpr.hash);
},
- PathExpression: function(id) {},
+ PathExpression: function(path) {},
- hash: function(hash) {
+ StringLiteral: function(string) {},
+ NumberLiteral: function(number) {},
+ BooleanLiteral: function(bool) {},
+
+ Hash: function(hash) {
var pairs = hash.pairs;
for(var i=0, l=pairs.length; i<l; i++) {
- this.accept(pairs[i][1]);
+ this.accept(pairs[i]);
}
},
-
- StringLiteral: function(string) {},
- NumberLiteral: function(number) {},
- BooleanLiteral: function(bool) {}
+ HashPair: function(pair) {
+ this.accept(pair.value);
+ }
};
export default Visitor;