summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/handlebars/compiler/ast.js27
-rw-r--r--lib/handlebars/compiler/compiler.js39
-rw-r--r--lib/handlebars/compiler/javascript-compiler.js2
-rw-r--r--lib/handlebars/compiler/printer.js20
-rw-r--r--lib/handlebars/compiler/visitor.js9
-rw-r--r--spec/ast.js18
-rw-r--r--spec/parser.js88
-rw-r--r--spec/string-params.js12
-rw-r--r--spec/subexpressions.js4
-rw-r--r--spec/visitor.js4
-rw-r--r--src/handlebars.yy4
11 files changed, 103 insertions, 124 deletions
diff --git a/lib/handlebars/compiler/ast.js b/lib/handlebars/compiler/ast.js
index 44b26ec..287a9e5 100644
--- a/lib/handlebars/compiler/ast.js
+++ b/lib/handlebars/compiler/ast.js
@@ -92,11 +92,11 @@ var AST = {
this.pairs = pairs;
},
- IdNode: function(parts, locInfo) {
+ PathNode: function(data, parts, locInfo) {
this.loc = locInfo;
- this.type = "ID";
+ this.type = 'PathExpression';
- var original = "",
+ var original = '',
dig = [],
depth = 0,
depthString = '';
@@ -105,10 +105,10 @@ var AST = {
var part = parts[i].part;
original += (parts[i].separator || '') + part;
- if (part === ".." || part === "." || part === "this") {
+ if (part === '..' || part === '.' || part === 'this') {
if (dig.length > 0) {
- throw new Exception("Invalid path: " + original, this);
- } else if (part === "..") {
+ throw new Exception('Invalid path: ' + original, this);
+ } else if (part === '..') {
depth++;
depthString += '../';
} else {
@@ -119,25 +119,14 @@ var AST = {
}
}
- this.original = original;
+ this.data = data;
+ this.original = (data ? '@' : '') + original;
this.parts = dig;
- this.string = dig.join('.');
this.depth = depth;
- this.idName = depthString + this.string;
// an ID is simple if it only has one part, and that part is not
// `..` or `this`.
this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
-
- this.stringModeValue = this.string;
- },
-
- DataNode: function(id, locInfo) {
- this.loc = locInfo;
- this.type = "DATA";
- this.id = id;
- this.stringModeValue = id.stringModeValue;
- this.idName = '@' + id.stringModeValue;
},
StringNode: function(string, locInfo) {
diff --git a/lib/handlebars/compiler/compiler.js b/lib/handlebars/compiler/compiler.js
index a5acb64..ea65583 100644
--- a/lib/handlebars/compiler/compiler.js
+++ b/lib/handlebars/compiler/compiler.js
@@ -212,7 +212,7 @@ Compiler.prototype = {
this.opcode('pushProgram', sexpr, program);
this.opcode('pushProgram', sexpr, inverse);
- this.ID(id);
+ this.accept(id);
this.opcode('invokeAmbiguous', sexpr, name, isBlock);
},
@@ -220,10 +220,8 @@ Compiler.prototype = {
simpleSexpr: function(sexpr) {
var id = sexpr.id;
- if (id.type === 'DATA') {
- this.DATA(id);
- } else if (id.parts.length) {
- this.ID(id);
+ if (id.parts.length) {
+ this.accept(id);
} else {
// Simplified ID for `this`
this.addDepth(id.depth);
@@ -246,7 +244,7 @@ Compiler.prototype = {
} else {
id.falsy = true;
- this.ID(id);
+ this.accept(id);
this.opcode('invokeHelper', sexpr, params.length, id.original, id.isSimple);
}
},
@@ -265,7 +263,7 @@ Compiler.prototype = {
this.opcode('popHash', hash);
},
- ID: function(id) {
+ PathExpression: function(id) {
this.addDepth(id.depth);
this.opcode('getContext', id, id.depth);
@@ -273,16 +271,14 @@ Compiler.prototype = {
if (!name) {
// Context reference, i.e. `{{foo .}}` or `{{foo ..}}`
this.opcode('pushContext', id);
+ } else if (id.data) {
+ this.options.data = true;
+ this.opcode('lookupData', id, id.depth, id.parts);
} else {
this.opcode('lookupOnContext', id, id.parts, id.falsy, id.isScoped);
}
},
- DATA: function(data) {
- this.options.data = true;
- this.opcode('lookupData', data, data.id.depth, data.id.parts);
- },
-
StringLiteral: function(string) {
this.opcode('pushString', string, string.value);
},
@@ -338,14 +334,20 @@ Compiler.prototype = {
},
pushParam: function(val) {
- var stringModeValue = val.stringModeValue || (val.value != null ? val.value : '');
+ var value = val.value != null ? val.value : val.original || '';
if (this.stringParams) {
+ if (value.replace) {
+ value = value
+ .replace(/^(\.?\.\/)*/g, '')
+ .replace(/\//g, '.');
+ }
+
if(val.depth) {
this.addDepth(val.depth);
}
this.opcode('getContext', val, val.depth || 0);
- this.opcode('pushStringParam', val, stringModeValue, val.type);
+ this.opcode('pushStringParam', val, value, val.type);
if (val.type === 'sexpr') {
// Subexpressions get evaluated and passed in
@@ -354,7 +356,14 @@ Compiler.prototype = {
}
} else {
if (this.trackIds) {
- this.opcode('pushId', val, val.type, val.idName || stringModeValue);
+ value = val.original || value;
+ if (value.replace) {
+ value = value
+ .replace(/^\.\//g, '')
+ .replace(/^\.$/g, '');
+ }
+
+ this.opcode('pushId', val, val.type, value);
}
this.accept(val);
}
diff --git a/lib/handlebars/compiler/javascript-compiler.js b/lib/handlebars/compiler/javascript-compiler.js
index 639aa41..2916a32 100644
--- a/lib/handlebars/compiler/javascript-compiler.js
+++ b/lib/handlebars/compiler/javascript-compiler.js
@@ -659,7 +659,7 @@ JavaScriptCompiler.prototype = {
},
pushId: function(type, name) {
- if (type === 'ID' || type === 'DATA') {
+ if (type === 'PathExpression') {
this.pushString(name);
} else if (type === 'sexpr') {
this.pushStackLiteral('true');
diff --git a/lib/handlebars/compiler/printer.js b/lib/handlebars/compiler/printer.js
index c86f7fa..05e8ee7 100644
--- a/lib/handlebars/compiler/printer.js
+++ b/lib/handlebars/compiler/printer.js
@@ -107,6 +107,12 @@ PrintVisitor.prototype.sexpr = function(sexpr) {
return this.accept(sexpr.id) + " " + params + hash;
};
+PrintVisitor.prototype.PathExpression = function(id) {
+ var path = id.parts.join('/');
+ return (id.data ? '@' : '') + 'PATH:' + path;
+};
+
+
PrintVisitor.prototype.hash = function(hash) {
var pairs = hash.pairs;
var joinedPairs = [], left, right;
@@ -131,17 +137,3 @@ PrintVisitor.prototype.NumberLiteral = function(number) {
PrintVisitor.prototype.BooleanLiteral = function(bool) {
return "BOOLEAN{" + bool.value + "}";
};
-
-PrintVisitor.prototype.ID = function(id) {
- var path = id.parts.join("/");
- if(id.parts.length > 1) {
- return "PATH:" + path;
- } else {
- return "ID:" + path;
- }
-};
-
-PrintVisitor.prototype.DATA = function(data) {
- return "@" + this.accept(data.id);
-};
-
diff --git a/lib/handlebars/compiler/visitor.js b/lib/handlebars/compiler/visitor.js
index a2ad7bb..e191bbd 100644
--- a/lib/handlebars/compiler/visitor.js
+++ b/lib/handlebars/compiler/visitor.js
@@ -45,6 +45,8 @@ Visitor.prototype = {
this.accept(sexpr.hash);
},
+ PathExpression: function(id) {},
+
hash: function(hash) {
var pairs = hash.pairs;
@@ -53,14 +55,9 @@ Visitor.prototype = {
}
},
- DATA: function(data) {
- this.accept(data.id);
- },
-
StringLiteral: function(string) {},
NumberLiteral: function(number) {},
- BooleanLiteral: function(bool) {},
- ID: function(id) {}
+ BooleanLiteral: function(bool) {}
};
export default Visitor;
diff --git a/spec/ast.js b/spec/ast.js
index dc6e136..064bf64 100644
--- a/spec/ast.js
+++ b/spec/ast.js
@@ -81,24 +81,24 @@ describe('ast', function() {
testLocationInfoStorage(block);
});
});
- describe('IdNode', function() {
+ describe('PathNode', function() {
it('should throw on invalid path', function() {
shouldThrow(function() {
- new handlebarsEnv.AST.IdNode([
+ new handlebarsEnv.AST.PathNode(false, [
{part: 'foo'},
{part: '..'},
{part: 'bar'}
], {start: {line: 1, column: 1}});
}, Handlebars.Exception, "Invalid path: foo.. - 1:1");
shouldThrow(function() {
- new handlebarsEnv.AST.IdNode([
+ new handlebarsEnv.AST.PathNode(false, [
{part: 'foo'},
{part: '.'},
{part: 'bar'}
], {start: {line: 1, column: 1}});
}, Handlebars.Exception, "Invalid path: foo. - 1:1");
shouldThrow(function() {
- new handlebarsEnv.AST.IdNode([
+ new handlebarsEnv.AST.PathNode(false, [
{part: 'foo'},
{part: 'this'},
{part: 'bar'}
@@ -107,7 +107,7 @@ describe('ast', function() {
});
it('stores location info', function(){
- var idNode = new handlebarsEnv.AST.IdNode([], LOCATION_INFO);
+ var idNode = new handlebarsEnv.AST.PathNode(false, [], LOCATION_INFO);
testLocationInfoStorage(idNode);
});
});
@@ -160,14 +160,6 @@ describe('ast', function() {
});
});
- describe("DataNode", function(){
-
- it('stores location info', function(){
- var data = new handlebarsEnv.AST.DataNode("YES", LOCATION_INFO);
- testLocationInfoStorage(data);
- });
- });
-
describe("PartialNode", function(){
it('stores location info', function(){
var pn = new handlebarsEnv.AST.PartialNode('so_partial', {}, LOCATION_INFO);
diff --git a/spec/parser.js b/spec/parser.js
index f2b6e41..b25f222 100644
--- a/spec/parser.js
+++ b/spec/parser.js
@@ -10,19 +10,19 @@ describe('parser', function() {
}
it('parses simple mustaches', function() {
- equals(ast_for('{{foo}}'), "{{ ID:foo [] }}\n");
- equals(ast_for('{{foo?}}'), "{{ ID:foo? [] }}\n");
- equals(ast_for('{{foo_}}'), "{{ ID:foo_ [] }}\n");
- equals(ast_for('{{foo-}}'), "{{ ID:foo- [] }}\n");
- equals(ast_for('{{foo:}}'), "{{ ID:foo: [] }}\n");
+ equals(ast_for('{{foo}}'), "{{ PATH:foo [] }}\n");
+ equals(ast_for('{{foo?}}'), "{{ PATH:foo? [] }}\n");
+ equals(ast_for('{{foo_}}'), "{{ PATH:foo_ [] }}\n");
+ equals(ast_for('{{foo-}}'), "{{ PATH:foo- [] }}\n");
+ equals(ast_for('{{foo:}}'), "{{ PATH:foo: [] }}\n");
});
it('parses simple mustaches with data', function() {
- equals(ast_for("{{@foo}}"), "{{ @ID:foo [] }}\n");
+ equals(ast_for("{{@foo}}"), "{{ @PATH:foo [] }}\n");
});
it('parses simple mustaches with data paths', function() {
- equals(ast_for("{{@../foo}}"), "{{ @ID:foo [] }}\n");
+ equals(ast_for("{{@../foo}}"), "{{ @PATH:foo [] }}\n");
});
it('parses mustaches with paths', function() {
@@ -30,54 +30,54 @@ describe('parser', function() {
});
it('parses mustaches with this/foo', function() {
- equals(ast_for("{{this/foo}}"), "{{ ID:foo [] }}\n");
+ equals(ast_for("{{this/foo}}"), "{{ PATH:foo [] }}\n");
});
it('parses mustaches with - in a path', function() {
- equals(ast_for("{{foo-bar}}"), "{{ ID:foo-bar [] }}\n");
+ equals(ast_for("{{foo-bar}}"), "{{ PATH:foo-bar [] }}\n");
});
it('parses mustaches with parameters', function() {
- equals(ast_for("{{foo bar}}"), "{{ ID:foo [ID:bar] }}\n");
+ equals(ast_for("{{foo bar}}"), "{{ PATH:foo [PATH:bar] }}\n");
});
it('parses mustaches with string parameters', function() {
- equals(ast_for("{{foo bar \"baz\" }}"), '{{ ID:foo [ID:bar, "baz"] }}\n');
+ equals(ast_for("{{foo bar \"baz\" }}"), '{{ PATH:foo [PATH:bar, "baz"] }}\n');
});
it('parses mustaches with NUMBER parameters', function() {
- equals(ast_for("{{foo 1}}"), "{{ ID:foo [NUMBER{1}] }}\n");
+ equals(ast_for("{{foo 1}}"), "{{ PATH:foo [NUMBER{1}] }}\n");
});
it('parses mustaches with BOOLEAN parameters', function() {
- equals(ast_for("{{foo true}}"), "{{ ID:foo [BOOLEAN{true}] }}\n");
- equals(ast_for("{{foo false}}"), "{{ ID:foo [BOOLEAN{false}] }}\n");
+ equals(ast_for("{{foo true}}"), "{{ PATH:foo [BOOLEAN{true}] }}\n");
+ equals(ast_for("{{foo false}}"), "{{ PATH:foo [BOOLEAN{false}] }}\n");
});
it('parses mutaches with DATA parameters', function() {
- equals(ast_for("{{foo @bar}}"), "{{ ID:foo [@ID:bar] }}\n");
+ equals(ast_for("{{foo @bar}}"), "{{ PATH:foo [@PATH:bar] }}\n");
});
it('parses mustaches with hash arguments', function() {
- equals(ast_for("{{foo bar=baz}}"), "{{ ID:foo [] HASH{bar=ID:baz} }}\n");
- equals(ast_for("{{foo bar=1}}"), "{{ ID:foo [] HASH{bar=NUMBER{1}} }}\n");
- equals(ast_for("{{foo bar=true}}"), "{{ ID:foo [] HASH{bar=BOOLEAN{true}} }}\n");
- equals(ast_for("{{foo bar=false}}"), "{{ ID:foo [] HASH{bar=BOOLEAN{false}} }}\n");
- equals(ast_for("{{foo bar=@baz}}"), "{{ ID:foo [] HASH{bar=@ID:baz} }}\n");
+ equals(ast_for("{{foo bar=baz}}"), "{{ PATH:foo [] HASH{bar=PATH:baz} }}\n");
+ equals(ast_for("{{foo bar=1}}"), "{{ PATH:foo [] HASH{bar=NUMBER{1}} }}\n");
+ equals(ast_for("{{foo bar=true}}"), "{{ PATH:foo [] HASH{bar=BOOLEAN{true}} }}\n");
+ equals(ast_for("{{foo bar=false}}"), "{{ PATH:foo [] HASH{bar=BOOLEAN{false}} }}\n");
+ equals(ast_for("{{foo bar=@baz}}"), "{{ PATH:foo [] HASH{bar=@PATH:baz} }}\n");
- equals(ast_for("{{foo bar=baz bat=bam}}"), "{{ ID:foo [] HASH{bar=ID:baz, bat=ID:bam} }}\n");
- equals(ast_for("{{foo bar=baz bat=\"bam\"}}"), '{{ ID:foo [] HASH{bar=ID:baz, bat="bam"} }}\n');
+ equals(ast_for("{{foo bar=baz bat=bam}}"), "{{ PATH:foo [] HASH{bar=PATH:baz, bat=PATH:bam} }}\n");
+ equals(ast_for("{{foo bar=baz bat=\"bam\"}}"), '{{ PATH:foo [] HASH{bar=PATH:baz, bat="bam"} }}\n');
- equals(ast_for("{{foo bat='bam'}}"), '{{ ID:foo [] HASH{bat="bam"} }}\n');
+ equals(ast_for("{{foo bat='bam'}}"), '{{ PATH:foo [] HASH{bat="bam"} }}\n');
- equals(ast_for("{{foo omg bar=baz bat=\"bam\"}}"), '{{ ID:foo [ID:omg] HASH{bar=ID:baz, bat="bam"} }}\n');
- equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=1}}"), '{{ ID:foo [ID:omg] HASH{bar=ID:baz, bat="bam", baz=NUMBER{1}} }}\n');
- equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=true}}"), '{{ ID:foo [ID:omg] HASH{bar=ID:baz, bat="bam", baz=BOOLEAN{true}} }}\n');
- equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=false}}"), '{{ ID:foo [ID:omg] HASH{bar=ID:baz, bat="bam", baz=BOOLEAN{false}} }}\n');
+ equals(ast_for("{{foo omg bar=baz bat=\"bam\"}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam"} }}\n');
+ equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=1}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=NUMBER{1}} }}\n');
+ equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=true}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{true}} }}\n');
+ equals(ast_for("{{foo omg bar=baz bat=\"bam\" baz=false}}"), '{{ PATH:foo [PATH:omg] HASH{bar=PATH:baz, bat="bam", baz=BOOLEAN{false}} }}\n');
});
it('parses contents followed by a mustache', function() {
- equals(ast_for("foo bar {{baz}}"), "CONTENT[ \'foo bar \' ]\n{{ ID:baz [] }}\n");
+ equals(ast_for("foo bar {{baz}}"), "CONTENT[ \'foo bar \' ]\n{{ PATH:baz [] }}\n");
});
it('parses a partial', function() {
@@ -87,15 +87,15 @@ describe('parser', function() {
});
it('parses a partial with context', function() {
- equals(ast_for("{{> foo bar}}"), "{{> PARTIAL:foo ID:bar }}\n");
+ equals(ast_for("{{> foo bar}}"), "{{> PARTIAL:foo PATH:bar }}\n");
});
it('parses a partial with hash', function() {
- equals(ast_for("{{> foo bar=bat}}"), "{{> PARTIAL:foo HASH{bar=ID:bat} }}\n");
+ equals(ast_for("{{> foo bar=bat}}"), "{{> PARTIAL:foo HASH{bar=PATH:bat} }}\n");
});
it('parses a partial with context and hash', function() {
- equals(ast_for("{{> foo bar bat=baz}}"), "{{> PARTIAL:foo ID:bar HASH{bat=ID:baz} }}\n");
+ equals(ast_for("{{> foo bar bat=baz}}"), "{{> PARTIAL:foo PATH:bar HASH{bat=PATH:baz} }}\n");
});
it('parses a partial with a complex name', function() {
@@ -111,47 +111,47 @@ describe('parser', function() {
});
it('parses an inverse section', function() {
- equals(ast_for("{{#foo}} bar {{^}} baz {{/foo}}"), "BLOCK:\n ID:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n");
+ equals(ast_for("{{#foo}} bar {{^}} baz {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n");
});
it('parses an inverse (else-style) section', function() {
- equals(ast_for("{{#foo}} bar {{else}} baz {{/foo}}"), "BLOCK:\n ID:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n");
+ equals(ast_for("{{#foo}} bar {{else}} baz {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]\n");
});
it('parses multiple inverse sections', function() {
- equals(ast_for("{{#foo}} bar {{else if bar}}{{else}} baz {{/foo}}"), "BLOCK:\n ID:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n BLOCK:\n ID:if [ID:bar]\n PROGRAM:\n {{^}}\n CONTENT[ ' baz ' ]\n");
+ equals(ast_for("{{#foo}} bar {{else if bar}}{{else}} baz {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n BLOCK:\n PATH:if [PATH:bar]\n PROGRAM:\n {{^}}\n CONTENT[ ' baz ' ]\n");
});
it('parses empty blocks', function() {
- equals(ast_for("{{#foo}}{{/foo}}"), "BLOCK:\n ID:foo []\n PROGRAM:\n");
+ equals(ast_for("{{#foo}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n");
});
it('parses empty blocks with empty inverse section', function() {
- equals(ast_for("{{#foo}}{{^}}{{/foo}}"), "BLOCK:\n ID:foo []\n PROGRAM:\n {{^}}\n");
+ equals(ast_for("{{#foo}}{{^}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n");
});
it('parses empty blocks with empty inverse (else-style) section', function() {
- equals(ast_for("{{#foo}}{{else}}{{/foo}}"), "BLOCK:\n ID:foo []\n PROGRAM:\n {{^}}\n");
+ equals(ast_for("{{#foo}}{{else}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n");
});
it('parses non-empty blocks with empty inverse section', function() {
- equals(ast_for("{{#foo}} bar {{^}}{{/foo}}"), "BLOCK:\n ID:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n");
+ equals(ast_for("{{#foo}} bar {{^}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n");
});
it('parses non-empty blocks with empty inverse (else-style) section', function() {
- equals(ast_for("{{#foo}} bar {{else}}{{/foo}}"), "BLOCK:\n ID:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n");
+ equals(ast_for("{{#foo}} bar {{else}}{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n");
});
it('parses empty blocks with non-empty inverse section', function() {
- equals(ast_for("{{#foo}}{{^}} bar {{/foo}}"), "BLOCK:\n ID:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n");
+ equals(ast_for("{{#foo}}{{^}} bar {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n");
});
it('parses empty blocks with non-empty inverse (else-style) section', function() {
- equals(ast_for("{{#foo}}{{else}} bar {{/foo}}"), "BLOCK:\n ID:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n");
+ equals(ast_for("{{#foo}}{{else}} bar {{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]\n");
});
it('parses a standalone inverse section', function() {
- equals(ast_for("{{^foo}}bar{{/foo}}"), "BLOCK:\n ID:foo []\n {{^}}\n CONTENT[ 'bar' ]\n");
+ equals(ast_for("{{^foo}}bar{{/foo}}"), "BLOCK:\n PATH:foo []\n {{^}}\n CONTENT[ 'bar' ]\n");
});
it('throws on old inverse section', function() {
shouldThrow(function() {
@@ -160,11 +160,11 @@ describe('parser', function() {
});
it('parses block with block params', function() {
- equals(ast_for("{{#foo as |bar baz|}}content{{/foo}}"), "BLOCK:\n ID:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
+ equals(ast_for("{{#foo as |bar baz|}}content{{/foo}}"), "BLOCK:\n PATH:foo []\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
});
it('parses inverse block with block params', function() {
- equals(ast_for("{{^foo as |bar baz|}}content{{/foo}}"), "BLOCK:\n ID:foo []\n {{^}}\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
+ equals(ast_for("{{^foo as |bar baz|}}content{{/foo}}"), "BLOCK:\n PATH:foo []\n {{^}}\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]\n");
});
it("raises if there's a Parse error", function() {
diff --git a/spec/string-params.js b/spec/string-params.js
index 52ea5a8..4704a84 100644
--- a/spec/string-params.js
+++ b/spec/string-params.js
@@ -58,7 +58,7 @@ describe('string params mode', function() {
var helpers = {
tomdale: function(desire, noun, trueBool, falseBool, options) {
equal(options.types[0], 'StringLiteral', "the string type is passed");
- equal(options.types[1], 'ID', "the expression type is passed");
+ equal(options.types[1], 'PathExpression', "the expression type is passed");
equal(options.types[2], 'BooleanLiteral', "the expression type is passed");
equal(desire, "need", "the string form is passed for strings");
equal(noun, "dad.joke", "the string form is passed for expressions");
@@ -78,10 +78,10 @@ describe('string params mode', function() {
var helpers = {
tomdale: function(exclamation, options) {
equal(exclamation, 'he.says');
- equal(options.types[0], 'ID');
+ equal(options.types[0], 'PathExpression');
equal(options.hashTypes.desire, 'StringLiteral');
- equal(options.hashTypes.noun, 'ID');
+ equal(options.hashTypes.noun, 'PathExpression');
equal(options.hashTypes.bool, 'BooleanLiteral');
equal(options.hash.desire, 'need');
equal(options.hash.noun, 'dad.joke');
@@ -102,7 +102,7 @@ describe('string params mode', function() {
var helpers = {
tomdale: function(exclamation, options) {
equal(exclamation, "he.says");
- equal(options.types[0], "ID");
+ equal(options.types[0], 'PathExpression');
equal(options.contexts.length, 1);
equal(options.hashContexts.noun, context);
@@ -165,8 +165,8 @@ describe('string params mode', function() {
var helpers = {
foo: function(bar, options) {
- equal(bar, 'bar');
- equal(options.types[0], 'DATA');
+ equal(bar, '@bar');
+ equal(options.types[0], 'PathExpression');
return 'Foo!';
}
};
diff --git a/spec/subexpressions.js b/spec/subexpressions.js
index 5c9fdfc..d892bb5 100644
--- a/spec/subexpressions.js
+++ b/spec/subexpressions.js
@@ -171,13 +171,13 @@ describe('subexpressions', function() {
equals(a, 'foo');
equals(options.types.length, 2, "string params for outer helper processed correctly");
equals(options.types[0], 'sexpr', "string params for outer helper processed correctly");
- equals(options.types[1], 'ID', "string params for outer helper processed correctly");
+ equals(options.types[1], 'PathExpression', "string params for outer helper processed correctly");
return a + b;
},
blorg: function(a, options) {
equals(options.types.length, 1, "string params for inner helper processed correctly");
- equals(options.types[0], 'ID', "string params for inner helper processed correctly");
+ equals(options.types[0], 'PathExpression', "string params for inner helper processed correctly");
return a;
}
};
diff --git a/spec/visitor.js b/spec/visitor.js
index e6f80f3..66c3b68 100644
--- a/spec/visitor.js
+++ b/spec/visitor.js
@@ -29,8 +29,8 @@ describe('Visitor', function() {
visitor.BooleanLiteral = function(bool) {
equal(bool.value, true);
};
- visitor.ID = function(id) {
- equal(id.original, 'foo.bar');
+ visitor.PathExpression = function(id) {
+ equal(/foo\.bar$/.test(id.original), true);
};
visitor.ContentStatement = function(content) {
equal(content.value, ' ');
diff --git a/src/handlebars.yy b/src/handlebars.yy
index 0bd6fde..fb0837a 100644
--- a/src/handlebars.yy
+++ b/src/handlebars.yy
@@ -114,11 +114,11 @@ helperName
;
dataName
- : DATA path -> new yy.DataNode($2, yy.locInfo(@$))
+ : DATA pathSegments -> new yy.PathNode(true, $2, yy.locInfo(@$))
;
path
- : pathSegments -> new yy.IdNode($1, yy.locInfo(@$))
+ : pathSegments -> new yy.PathNode(false, $1, yy.locInfo(@$))
;
pathSegments