Add support for hash args in the tokenizer and parser

This commit is contained in:
tomhuda
2011-03-03 21:33:28 -08:00
parent 51d2543ba1
commit e0aa705f71
6 changed files with 81 additions and 4 deletions
+5
View File
@@ -52,6 +52,11 @@ var Handlebars = require("handlebars");
this.string = string;
};
Handlebars.AST.HashNode = function(pairs) {
this.type = "hash";
this.pairs = pairs;
};
Handlebars.AST.IdNode = function(parts) {
this.type = "ID";
this.original = parts.join("/");
+13
View File
@@ -89,6 +89,19 @@ Handlebars.PrintVisitor.prototype.partial = function(partial) {
return this.pad("{{> " + content + " }}");
};
Handlebars.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(", ") + "}";
};
Handlebars.PrintVisitor.prototype.STRING = function(string) {
return '"' + string.string + '"';
};
+22
View File
@@ -87,6 +87,10 @@ describe "Parser" do
string.inspect
end
def hash(*pairs)
"HASH{" + pairs.map {|k,v| "#{k}=#{v}" }.join(", ") + "}"
end
def id(id)
"ID:#{id}"
end
@@ -112,6 +116,24 @@ describe "Parser" do
ast_for("{{foo bar}}").should == program { mustache id("foo"), id("bar") }
end
it "parses mustaches with hash arguments" do
ast_for("{{foo bar=baz}}").should == program do
mustache id("foo"), hash(["bar", "ID:baz"])
end
ast_for("{{foo bar=baz bat=bam}}").should == program do
mustache id("foo"), hash(["bar", "ID:baz"], ["bat", "ID:bam"])
end
ast_for("{{foo bar=baz bat=\"bam\"}}").should == program do
mustache id("foo"), hash(["bar", "ID:baz"], ["bat", "\"bam\""])
end
ast_for("{{foo omg bar=baz bat=\"bam\"}}").should == program do
mustache id("foo"), id("omg"), hash(["bar", id("baz")], ["bat", string("bam")])
end
end
it "parses mustaches with string parameters" do
ast_for("{{foo bar \"baz\" }}").should == program { mustache id("foo"), id("bar"), string("baz")}
end
+22 -2
View File
@@ -12,8 +12,10 @@ describe "Tokenizer" do
out = []
while token = lexer.lex
result = parser.terminals_[token]
break if !result || result == "EOF"
# p token
result = parser.terminals_[token] || token
# p result
break if !result || result == "EOF" || result == "INVALID"
out << Token.new(result, lexer.yytext)
end
@@ -163,6 +165,24 @@ describe "Tokenizer" do
result[2].should be_token("STRING", %{bar"baz})
end
it "tokenizes hash arguments" do
result = tokenize("{{ foo bar=baz }}")
result.should match_tokens %w(OPEN ID ID EQUALS ID CLOSE)
result = tokenize("{{ foo bar baz=bat }}")
result.should match_tokens %w(OPEN ID ID ID EQUALS ID CLOSE)
result = tokenize("{{ foo bar baz=\"bat\" }}")
result.should match_tokens %w(OPEN ID ID ID EQUALS STRING CLOSE)
result = tokenize("{{ foo bar baz=\"bat\" bam=wot }}")
result.should match_tokens %w(OPEN ID ID ID EQUALS STRING ID EQUALS ID CLOSE)
result = tokenize("{{foo omg bar=baz bat=\"bam\"}}")
result.should match_tokens %w(OPEN ID ID ID EQUALS ID ID EQUALS STRING CLOSE)
result[2].should be_token("ID", "omg")
end
it "does not time out in a mustache with a single } followed by EOF" do
Timeout.timeout(1) { tokenize("{{foo}").should match_tokens(%w(OPEN ID)) }
end
+2 -1
View File
@@ -16,6 +16,7 @@
<mu>"{{!".*?"}}" { yytext = yytext.substr(3,yyleng-5); this.begin("INITIAL"); return 'COMMENT'; }
<mu>"{{" { return 'OPEN'; }
<mu>"=" { return 'EQUALS'; }
<mu>"."/[} ] { return 'ID'; }
<mu>".." { return 'ID'; }
<mu>[/.] { return 'SEP'; }
@@ -23,7 +24,7 @@
<mu>"}}}" { this.begin("INITIAL"); return 'CLOSE'; }
<mu>"}}" { this.begin("INITIAL"); return 'CLOSE'; }
<mu>'"'("\\"["]|[^"])*'"' { yytext = yytext.substr(1,yyleng-2).replace(/\\"/g,'"'); return 'STRING'; }
<mu>[a-zA-Z0-9_]+/[} /.] { return 'ID'; }
<mu>[a-zA-Z0-9_]+/[=} /.] { return 'ID'; }
<mu>. { return 'INVALID'; }
<INITIAL,mu><<EOF>> { return 'EOF'; }
+17 -1
View File
@@ -54,7 +54,9 @@ simpleInverse
;
inMustache
: path params { $$ = [$1].concat($2) }
: path params hash { $$ = [$1].concat($2).concat([$3]) }
| path params { $$ = [$1].concat($2) }
| path hash { $$ = [$1].concat([$2]) }
| path { $$ = [$1] }
;
@@ -68,6 +70,20 @@ param
| STRING { $$ = new yy.StringNode($1) }
;
hash
: hashSegments { $$ = new yy.HashNode($1) }
;
hashSegments
: hashSegments hashSegment { $1.push($2); $$ = $1 }
| hashSegment { $$ = [$1] }
;
hashSegment
: ID EQUALS path { $$ = [$1, $3] }
| ID EQUALS STRING { $$ = [$1, new yy.StringNode($3)] }
;
path
: pathSegments { $$ = new yy.IdNode($1) }
;