Skip to content

Commit

Permalink
Merge pull request #906 from mmun/block-params
Browse files Browse the repository at this point in the history
Add parser support for block params
  • Loading branch information
kpdecker committed Nov 13, 2014
2 parents b3b5b35 + b8a9f72 commit bf99352
Show file tree
Hide file tree
Showing 9 changed files with 51 additions and 12 deletions.
3 changes: 2 additions & 1 deletion lib/handlebars/compiler/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ function LocationInfo(locInfo) {
}

var AST = {
ProgramNode: function(statements, strip, locInfo) {
ProgramNode: function(statements, blockParams, strip, locInfo) {
LocationInfo.call(this, locInfo);
this.type = "program";
this.statements = statements;
this.blockParams = blockParams;
this.strip = strip;
},

Expand Down
4 changes: 3 additions & 1 deletion lib/handlebars/compiler/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function prepareRawBlock(openRawBlock, content, close, locInfo) {
throw new Exception(openRawBlock.sexpr.id.original + " doesn't match " + close, errorNode);
}

var program = new this.ProgramNode([content], {}, locInfo);
var program = new this.ProgramNode([content], null, {}, locInfo);

return new this.BlockNode(openRawBlock.sexpr, program, undefined, undefined, locInfo);
}
Expand All @@ -40,6 +40,8 @@ export function prepareBlock(openBlock, program, inverseAndProgram, close, inver
throw new Exception(openBlock.sexpr.id.original + ' doesn\'t match ' + close.path.original, errorNode);
}

program.blockParams = openBlock.blockParams;

// Safely handle a chained inverse that does not have a non-conditional inverse
// (i.e. both inverseAndProgram AND close are undefined)
if (!close) {
Expand Down
9 changes: 9 additions & 0 deletions lib/handlebars/compiler/printer.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ PrintVisitor.prototype.program = function(program) {
statements = program.statements,
i, l;

if (program.blockParams) {
var blockParams = "BLOCK PARAMS: [";
for(i=0, l=program.blockParams.length; i<l; i++) {
blockParams += " " + program.blockParams[i];
}
blockParams += " ]";
out += this.pad(blockParams);
}

for(i=0, l=statements.length; i<l; i++) {
out = out + this.accept(statements[i]);
}
Expand Down
2 changes: 1 addition & 1 deletion spec/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ describe('ast', function() {

describe('ProgramNode', function(){
it('storing location info', function(){
var pn = new handlebarsEnv.AST.ProgramNode([], {}, LOCATION_INFO);
var pn = new handlebarsEnv.AST.ProgramNode([], null, {}, LOCATION_INFO);
testLocationInfoStorage(pn);
});
});
Expand Down
4 changes: 2 additions & 2 deletions spec/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('compiler', function() {
});

it('can utilize AST instance', function() {
equal(Handlebars.compile(new Handlebars.AST.ProgramNode([ new Handlebars.AST.ContentNode("Hello")], {}))(), 'Hello');
equal(Handlebars.compile(new Handlebars.AST.ProgramNode([ new Handlebars.AST.ContentNode("Hello")], null, {}))(), 'Hello');
});

it("can pass through an empty string", function() {
Expand All @@ -60,7 +60,7 @@ describe('compiler', function() {
});

it('can utilize AST instance', function() {
equal(/return "Hello"/.test(Handlebars.precompile(new Handlebars.AST.ProgramNode([ new Handlebars.AST.ContentNode("Hello")]), {})), true);
equal(/return "Hello"/.test(Handlebars.precompile(new Handlebars.AST.ProgramNode([ new Handlebars.AST.ContentNode("Hello")]), null, {})), true);
});

it("can pass through an empty string", function() {
Expand Down
10 changes: 9 additions & 1 deletion spec/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ describe('parser', function() {
}, Error);
});

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");
});

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");
});

it("raises if there's a Parse error", function() {
shouldThrow(function() {
ast_for("foo{{^}}bar");
Expand Down Expand Up @@ -193,7 +201,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([ new Handlebars.AST.ContentNode("Hello")])), "CONTENT[ \'Hello\' ]\n");
equals(ast_for(new Handlebars.AST.ProgramNode([new Handlebars.AST.ContentNode("Hello")], null)), "CONTENT[ \'Hello\' ]\n");
});
});
});
14 changes: 14 additions & 0 deletions spec/tokenizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -399,4 +399,18 @@ describe('Tokenizer', function() {
var result = tokenize("{{foo (bar (lol true) false) (baz 1) (blah 'b') (blorg \"c\")}}");
shouldMatchTokens(result, ['OPEN', 'ID', 'OPEN_SEXPR', 'ID', 'OPEN_SEXPR', 'ID', 'BOOLEAN', 'CLOSE_SEXPR', 'BOOLEAN', 'CLOSE_SEXPR', 'OPEN_SEXPR', 'ID', 'NUMBER', 'CLOSE_SEXPR', 'OPEN_SEXPR', 'ID', 'STRING', 'CLOSE_SEXPR', 'OPEN_SEXPR', 'ID', 'STRING', 'CLOSE_SEXPR', 'CLOSE']);
});

it('tokenizes block params', function() {
var result = tokenize("{{#foo as |bar|}}");
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);

var result = tokenize("{{#foo as |bar baz|}}");
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);

var result = tokenize("{{#foo as | bar baz |}}");
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);

var result = tokenize("{{#foo as as | bar baz |}}");
shouldMatchTokens(result, ['OPEN_BLOCK', 'ID', 'ID', 'OPEN_BLOCK_PARAMS', 'ID', 'ID', 'CLOSE_BLOCK_PARAMS', 'CLOSE']);
});
});
4 changes: 3 additions & 1 deletion src/handlebars.l
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function strip(start, end) {
LEFT_STRIP "~"
RIGHT_STRIP "~"

LOOKAHEAD [=~}\s\/.)]
LOOKAHEAD [=~}\s\/.)|]
LITERAL_LOOKAHEAD [~}\s)]

/*
Expand Down Expand Up @@ -103,6 +103,8 @@ ID [^\s!"#%-,\.\/;->@\[-\^`\{-~]+/{LOOKAHEAD}
<mu>"true"/{LITERAL_LOOKAHEAD} return 'BOOLEAN';
<mu>"false"/{LITERAL_LOOKAHEAD} return 'BOOLEAN';
<mu>\-?[0-9]+(?:\.[0-9]+)?/{LITERAL_LOOKAHEAD} return 'NUMBER';
<mu>"as"\s+"|" return 'OPEN_BLOCK_PARAMS';
<mu>"|" return 'CLOSE_BLOCK_PARAMS';
<mu>{ID} return 'ID';
Expand Down
13 changes: 8 additions & 5 deletions src/handlebars.yy
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ root
;

program
: statement* -> new yy.ProgramNode(yy.prepareProgram($1), {}, @$)
: statement* -> new yy.ProgramNode(yy.prepareProgram($1), null, {}, @$)
;

statement
Expand Down Expand Up @@ -39,11 +39,11 @@ block
;

openBlock
: OPEN_BLOCK sexpr CLOSE -> { sexpr: $2, strip: yy.stripFlags($1, $3) }
: OPEN_BLOCK sexpr blockParams? CLOSE -> { sexpr: $2, blockParams: $3, strip: yy.stripFlags($1, $4) }
;

openInverse
: OPEN_INVERSE sexpr CLOSE -> { sexpr: $2, strip: yy.stripFlags($1, $3) }
: OPEN_INVERSE sexpr blockParams? CLOSE -> { sexpr: $2, blockParams: $3, strip: yy.stripFlags($1, $4) }
;

openInverseChain
Expand All @@ -57,7 +57,7 @@ inverseAndProgram
inverseChain
: openInverseChain program inverseChain? {
var inverse = yy.prepareBlock($1, $2, $3, $3, false, @$),
program = new yy.ProgramNode(yy.prepareProgram([inverse]), {}, @$);
program = new yy.ProgramNode(yy.prepareProgram([inverse]), null, {}, @$);

program.inverse = inverse;

Expand Down Expand Up @@ -104,6 +104,10 @@ hashSegment
: ID EQUALS param -> [$1, $3]
;

blockParams
: OPEN_BLOCK_PARAMS ID+ CLOSE_BLOCK_PARAMS -> $2
;

partialName
: path -> new yy.PartialNameNode($1, @$)
| STRING -> new yy.PartialNameNode(new yy.StringNode($1, @$), @$)
Expand All @@ -122,4 +126,3 @@ pathSegments
: pathSegments SEP ID { $1.push({part: $3, separator: $2}); $$ = $1; }
| ID -> [{part: $1}]
;

0 comments on commit bf99352

Please sign in to comment.