Skip to content

Commit

Permalink
Add undefined and null literal support
Browse files Browse the repository at this point in the history
This adds the UndefinedLiteral and NullLiteral to AST.

Fixes #990
  • Loading branch information
kpdecker committed Apr 8, 2015
1 parent 81a4d50 commit 2d149e7
Show file tree
Hide file tree
Showing 12 changed files with 65 additions and 2 deletions.
8 changes: 8 additions & 0 deletions docs/compiler-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,14 @@ interface NumberLiteral <: Literal {
value: number;
original: number;
}

interface UndefinedLiteral <: Literal {
type: "UndefinedLiteral";
}

interface NullLiteral <: Literal {
type: "NullLiteral";
}
```


Expand Down
12 changes: 12 additions & 0 deletions lib/handlebars/compiler/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,18 @@ var AST = {
this.value = bool === 'true';
},

UndefinedLiteral: function(locInfo) {
this.loc = locInfo;
this.type = 'UndefinedLiteral';
this.original = this.value = undefined;
},

NullLiteral: function(locInfo) {
this.loc = locInfo;
this.type = 'NullLiteral';
this.original = this.value = null;
},

Hash: function(pairs, locInfo) {
this.loc = locInfo;
this.type = 'Hash';
Expand Down
8 changes: 8 additions & 0 deletions lib/handlebars/compiler/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,14 @@ Compiler.prototype = {
this.opcode('pushLiteral', bool.value);
},

UndefinedLiteral: function() {
this.opcode('pushLiteral', 'undefined');
},

NullLiteral: function() {
this.opcode('pushLiteral', 'null');
},

Hash: function(hash) {
var pairs = hash.pairs, i, l;

Expand Down
8 changes: 8 additions & 0 deletions lib/handlebars/compiler/printer.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ PrintVisitor.prototype.BooleanLiteral = function(bool) {
return "BOOLEAN{" + bool.value + "}";
};

PrintVisitor.prototype.UndefinedLiteral = function() {
return 'UNDEFINED';
};

PrintVisitor.prototype.NullLiteral = function() {
return 'NULL';
};

PrintVisitor.prototype.Hash = function(hash) {
var pairs = hash.pairs;
var joinedPairs = [];
Expand Down
2 changes: 2 additions & 0 deletions lib/handlebars/compiler/visitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ Visitor.prototype = {
StringLiteral: function(/* string */) {},
NumberLiteral: function(/* number */) {},
BooleanLiteral: function(/* bool */) {},
UndefinedLiteral: function(/* literal */) {},
NullLiteral: function(/* literal */) {},

Hash: function(hash) {
this.acceptArray(hash.pairs);
Expand Down
10 changes: 10 additions & 0 deletions spec/basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ describe("basic context", function() {
shouldCompileTo('val: {{{val1/val2}}}', {val1: {val2: false}}, 'val: false');
});

it('should handle undefined and null', function() {
shouldCompileTo('{{awesome undefined null}}',
{
awesome: function(_undefined, _null, options) {
return (_undefined === undefined) + ' ' + (_null === null) + ' ' + (typeof options);
}
},
'true true object');
});

it("newlines", function() {
shouldCompileTo("Alan's\nTest", {}, "Alan's\nTest");
shouldCompileTo("Alan's\rTest", {}, "Alan's\rTest");
Expand Down
2 changes: 1 addition & 1 deletion spec/javascript-compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('javascript-compiler api', function() {
// Tests nameLookup dot vs. bracket behavior. Bracket is required in certain cases
// to avoid errors in older browsers.
it('should handle reserved words', function() {
shouldCompileTo("{{foo}} {{~null~}}", { foo: "food" }, "food");
shouldCompileTo("{{foo}} {{~[null]~}}", { foo: "food" }, "food");
});
});
describe('#compilerInfo', function() {
Expand Down
4 changes: 4 additions & 0 deletions spec/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ describe('parser', function() {
equals(ast_for("{{foo false}}"), "{{ PATH:foo [BOOLEAN{false}] }}\n");
});

it('parses mustaches with undefined and null parameters', function() {
equals(ast_for("{{foo undefined null}}"), "{{ PATH:foo [UNDEFINED, NULL] }}\n");
});

it('parses mutaches with DATA parameters', function() {
equals(ast_for("{{foo @bar}}"), "{{ PATH:foo [@PATH:bar] }}\n");
});
Expand Down
7 changes: 7 additions & 0 deletions spec/tokenizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,13 @@ describe('Tokenizer', function() {
shouldBeToken(result[2], "BOOLEAN", "false");
});

it('tokenizes undefined and null', function() {
var result = tokenize('{{ foo undefined null }}');
shouldMatchTokens(result, ['OPEN', 'ID', 'UNDEFINED', 'NULL', 'CLOSE']);
shouldBeToken(result[2], 'UNDEFINED', 'undefined');
shouldBeToken(result[3], 'NULL', 'null');
});

it('tokenizes hash arguments', function() {
var result = tokenize("{{ foo bar=baz }}");
shouldMatchTokens(result, ['OPEN', 'ID', 'ID', 'EQUALS', 'ID', 'CLOSE']);
Expand Down
2 changes: 1 addition & 1 deletion spec/visitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('Visitor', function() {
// Simply run the thing and make sure it does not fail and that all of the
// stub methods are executed
var visitor = new Handlebars.Visitor();
visitor.accept(Handlebars.parse('{{foo}}{{#foo (bar 1 "1" true) foo=@data}}{{!comment}}{{> bar }} {{/foo}}'));
visitor.accept(Handlebars.parse('{{foo}}{{#foo (bar 1 "1" true undefined null) foo=@data}}{{!comment}}{{> bar }} {{/foo}}'));
});

it('should traverse to stubs', function() {
Expand Down
2 changes: 2 additions & 0 deletions src/handlebars.l
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ ID [^\s!"#%-,\.\/;->@\[-\^`\{-~]+/{LOOKAHEAD}
<mu>"@" return 'DATA';
<mu>"true"/{LITERAL_LOOKAHEAD} return 'BOOLEAN';
<mu>"false"/{LITERAL_LOOKAHEAD} return 'BOOLEAN';
<mu>"undefined"/{LITERAL_LOOKAHEAD} return 'UNDEFINED';
<mu>"null"/{LITERAL_LOOKAHEAD} return 'NULL';
<mu>\-?[0-9]+(?:\.[0-9]+)?/{LITERAL_LOOKAHEAD} return 'NUMBER';
<mu>"as"\s+"|" return 'OPEN_BLOCK_PARAMS';
<mu>"|" return 'CLOSE_BLOCK_PARAMS';
Expand Down
2 changes: 2 additions & 0 deletions src/handlebars.yy
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ partial
param
: helperName -> $1
| sexpr -> $1
| UNDEFINED -> new yy.UndefinedLiteral(yy.locInfo(@$))
| NULL -> new yy.NullLiteral(yy.locInfo(@$))
;

sexpr
Expand Down

0 comments on commit 2d149e7

Please sign in to comment.