Merge branch 'refactor-parser' of github.com:mmun/handlebars.js into mmun-refactor-parser

Conflicts:
	lib/handlebars/compiler/ast.js
	spec/ast.js
	src/handlebars.yy
This commit is contained in:
kpdecker
2014-08-23 16:29:22 -05:00
9 changed files with 229 additions and 257 deletions
+13 -35
View File
@@ -68,17 +68,9 @@ describe('ast', function() {
});
});
describe('BlockNode', function() {
it('should throw on mustache mismatch (old sexpr-less version)', function() {
shouldThrow(function() {
var mustacheNode = new handlebarsEnv.AST.MustacheNode([{ original: 'foo'}], null, '{{', {});
new handlebarsEnv.AST.BlockNode(mustacheNode, {}, {}, {path: {original: 'bar'}});
}, Handlebars.Exception, "foo doesn't match bar");
});
it('should throw on mustache mismatch', function() {
shouldThrow(function() {
var sexprNode = new handlebarsEnv.AST.SexprNode([{ original: 'foo'}], null);
var mustacheNode = new handlebarsEnv.AST.MustacheNode(sexprNode, null, '{{', {});
new handlebarsEnv.AST.BlockNode(mustacheNode, {}, {}, {path: {original: 'bar'}}, {first_line: 2, first_column: 2});
handlebarsEnv.parse("\n {{#foo}}{{/bar}}")
}, Handlebars.Exception, "foo doesn't match bar - 2:2");
});
@@ -197,32 +189,11 @@ describe('ast', function() {
testLocationInfoStorage(pn);
});
});
describe("ProgramNode", function(){
describe("storing location info", function(){
it("stores when `inverse` argument isn't passed", function(){
var pn = new handlebarsEnv.AST.ProgramNode(false, [], LOCATION_INFO);
testLocationInfoStorage(pn);
});
it("stores when `inverse` or `stripInverse` arguments passed", function(){
var pn = new handlebarsEnv.AST.ProgramNode(false, [], {strip: {}}, undefined, LOCATION_INFO);
testLocationInfoStorage(pn);
var clone = {
strip: {},
firstLine: 0,
lastLine: 0,
firstColumn: 0,
lastColumn: 0
};
pn = new handlebarsEnv.AST.ProgramNode(false, [], {strip: {}}, [ clone ], LOCATION_INFO);
testLocationInfoStorage(pn);
// Assert that the newly created ProgramNode has the same location
// information as the inverse
testLocationInfoStorage(pn.inverse);
});
describe('ProgramNode', function(){
it('storing location info', function(){
var pn = new handlebarsEnv.AST.ProgramNode([], {}, LOCATION_INFO);
testLocationInfoStorage(pn);
});
});
@@ -265,11 +236,18 @@ describe('ast', function() {
testColumns(blockHelperNode, 3, 7, 8, 23);
});
it('correctly records the line numbers the program of a block helper', function(){
var blockHelperNode = statements[7],
program = blockHelperNode.program;
testColumns(program, 3, 5, 8, 5);
});
it('correctly records the line numbers of an inverse of a block helper', function(){
var blockHelperNode = statements[7],
inverse = blockHelperNode.inverse;
testColumns(inverse, 5, 6, 13, 0);
testColumns(inverse, 5, 7, 5, 0);
});
});
+2 -2
View File
@@ -41,7 +41,7 @@ describe('compiler', function() {
});
it('can utilize AST instance', function() {
equal(Handlebars.compile(new Handlebars.AST.ProgramNode(true, [ new Handlebars.AST.ContentNode("Hello")]))(), 'Hello');
equal(Handlebars.compile(new Handlebars.AST.ProgramNode([ new Handlebars.AST.ContentNode("Hello")], {}))(), 'Hello');
});
it("can pass through an empty string", function() {
@@ -60,7 +60,7 @@ describe('compiler', function() {
});
it('can utilize AST instance', function() {
equal(/return "Hello"/.test(Handlebars.precompile(new Handlebars.AST.ProgramNode(true, [ new Handlebars.AST.ContentNode("Hello")]))), true);
equal(/return "Hello"/.test(Handlebars.precompile(new Handlebars.AST.ProgramNode([ new Handlebars.AST.ContentNode("Hello")]), {})), true);
});
it("can pass through an empty string", function() {
+6 -3
View File
@@ -121,11 +121,11 @@ describe('parser', function() {
});
it('parses empty blocks with empty inverse section', function() {
equals(ast_for("{{#foo}}{{^}}{{/foo}}"), "BLOCK:\n {{ ID:foo [] }}\n PROGRAM:\n");
equals(ast_for("{{#foo}}{{^}}{{/foo}}"), "BLOCK:\n {{ ID: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");
equals(ast_for("{{#foo}}{{else}}{{/foo}}"), "BLOCK:\n {{ ID:foo [] }}\n PROGRAM:\n {{^}}\n");
});
it('parses non-empty blocks with empty inverse section', function() {
@@ -147,6 +147,9 @@ describe('parser', function() {
it('parses a standalone inverse section', function() {
equals(ast_for("{{^foo}}bar{{/foo}}"), "BLOCK:\n {{ ID:foo [] }}\n {{^}}\n CONTENT[ 'bar' ]\n");
});
it('parses a standalone inverse section', function() {
equals(ast_for("{{else foo}}bar{{/foo}}"), "BLOCK:\n {{ ID:foo [] }}\n {{^}}\n CONTENT[ 'bar' ]\n");
});
it("raises if there's a Parse error", function() {
shouldThrow(function() {
@@ -184,7 +187,7 @@ describe('parser', function() {
describe('externally compiled AST', function() {
it('can pass through an already-compiled AST', function() {
equals(ast_for(new Handlebars.AST.ProgramNode(false, [ new Handlebars.AST.ContentNode("Hello")])), "CONTENT[ \'Hello\' ]\n");
equals(ast_for(new Handlebars.AST.ProgramNode([ new Handlebars.AST.ContentNode("Hello")])), "CONTENT[ \'Hello\' ]\n");
});
});
});
+4 -4
View File
@@ -237,10 +237,10 @@ describe('Tokenizer', function() {
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'CLOSE', 'CONTENT', 'OPEN_ENDBLOCK', 'ID', 'CLOSE']);
});
it('tokenizes inverse sections as "OPEN_INVERSE CLOSE"', function() {
shouldMatchTokens(tokenize("{{^}}"), ['OPEN_INVERSE', 'CLOSE']);
shouldMatchTokens(tokenize("{{else}}"), ['OPEN_INVERSE', 'CLOSE']);
shouldMatchTokens(tokenize("{{ else }}"), ['OPEN_INVERSE', 'CLOSE']);
it('tokenizes inverse sections as "INVERSE"', function() {
shouldMatchTokens(tokenize("{{^}}"), ['INVERSE']);
shouldMatchTokens(tokenize("{{else}}"), ['INVERSE']);
shouldMatchTokens(tokenize("{{ else }}"), ['INVERSE']);
});
it('tokenizes inverse sections with ID as "OPEN_INVERSE ID CLOSE"', function() {