summaryrefslogtreecommitdiffstats
path: root/lib/handlebars
diff options
context:
space:
mode:
Diffstat (limited to 'lib/handlebars')
-rw-r--r--lib/handlebars/ast.js53
-rw-r--r--lib/handlebars/handlebars_lexer.js71
-rw-r--r--lib/handlebars/jison_ext.js58
-rw-r--r--lib/handlebars/printer.js92
4 files changed, 274 insertions, 0 deletions
diff --git a/lib/handlebars/ast.js b/lib/handlebars/ast.js
new file mode 100644
index 0000000..d37d378
--- /dev/null
+++ b/lib/handlebars/ast.js
@@ -0,0 +1,53 @@
+var ProgramNode = function(statements, inverse) {
+ this.type = "program";
+ this.statements = statements;
+ this.inverse = inverse;
+};
+
+var MustacheNode = function(params) {
+ this.type = "mustache";
+ this.id = params[0];
+ this.params = params.slice(1);
+};
+
+var PartialNode = function(id) {
+ this.type = "partial";
+ this.id = id;
+};
+
+var BlockNode = function(mustache, program) {
+ this.type = "block";
+ this.mustache = mustache;
+ this.program = program;
+};
+
+var ContentNode = function(string) {
+ this.type = "content";
+ this.string = string;
+}
+
+var IdNode = function(id) {
+ this.type = "ID"
+ this.id = id;
+}
+
+StringNode = function(string) {
+ this.type = "STRING";
+ this.string = string;
+}
+
+CommentNode = function(comment) {
+ this.type = "comment";
+ this.comment = comment;
+}
+
+if(exports) {
+ exports.ProgramNode = ProgramNode;
+ exports.MustacheNode = MustacheNode;
+ exports.ContentNode = ContentNode;
+ exports.IdNode = IdNode;
+ exports.StringNode = StringNode;
+ exports.PartialNode = PartialNode;
+ exports.CommentNode = CommentNode;
+ exports.BlockNode = BlockNode;
+}
diff --git a/lib/handlebars/handlebars_lexer.js b/lib/handlebars/handlebars_lexer.js
new file mode 100644
index 0000000..f92fc17
--- /dev/null
+++ b/lib/handlebars/handlebars_lexer.js
@@ -0,0 +1,71 @@
+if(require) {
+ var Lexer = require("handlebars/jison_ext").Lexer
+}
+
+var HandlebarsLexer = function() {
+ this.state = "CONTENT";
+};
+HandlebarsLexer.prototype = new Lexer;
+
+HandlebarsLexer.prototype.lex = function() {
+ if(this.input === "") return;
+
+ this.setupLex();
+
+ var lookahead = this.peek(2);
+ var result = '';
+
+ if(this.state == "MUSTACHE") {
+ // chomp optional whitespace
+ while(this.peek() === " ") { this.readchar(); }
+
+ if(this.peek(2) === "}}") {
+ this.state = "CONTENT"
+ this.getchar(2);
+
+ if(this.peek() == "}") this.getchar();
+ return "CLOSE";
+ } else if(this.peek() === '"') {
+ this.getchar();
+ while(this.peek() !== '"') { this.getchar() }
+ this.getchar();
+ return "STRING";
+ } else {
+ while(this.peek().match(/[A-Za-z]/)) { this.getchar() }
+ return "ID"
+ }
+ } else if(lookahead == "{{") {
+ this.state = "MUSTACHE";
+ this.getchar(2);
+
+ var peek = this.peek();
+
+ if(peek === ">") {
+ this.getchar();
+ return "OPEN_PARTIAL";
+ } else if(peek === "#") {
+ this.getchar();
+ return "OPEN_BLOCK";
+ } else if(peek === "/") {
+ this.getchar();
+ return "OPEN_ENDBLOCK";
+ } else if(peek === "^") {
+ this.getchar();
+ return "OPEN_INVERSE"
+ } else if(peek === "!") {
+ this.getchar();
+ this.setupLex();
+ while(this.peek(2) !== "}}") { this.getchar(); };
+ this.readchar(2);
+ this.state = "CONTENT"
+ return "COMMENT";
+ } else {
+ return "OPEN";
+ }
+ } else {
+ while(this.peek(2) !== "{{" && this.peek(2) !== "") { result = result + this.getchar(); }
+ return "CONTENT"
+ }
+};
+
+if(exports) { exports.Lexer = HandlebarsLexer; }
diff --git a/lib/handlebars/jison_ext.js b/lib/handlebars/jison_ext.js
new file mode 100644
index 0000000..0608034
--- /dev/null
+++ b/lib/handlebars/jison_ext.js
@@ -0,0 +1,58 @@
+var Lexer = function() {};
+
+Lexer.prototype = {
+ setInput: function(input) {
+ this.input = input;
+ this.yylineno = 0;
+ },
+
+ setupLex: function() {
+ this.yyleng = 0;
+ this.yytext = '';
+ },
+
+ getchar: function(n) {
+ n = n || 1;
+ var char = "";
+
+ for(var i=0; i<n; i++) {
+ char += this.input[0];
+ this.yytext += this.input[0];
+ this.yyleng++;
+
+ if(char === "\n") this.yylineno++;
+
+ this.input = this.input.slice(1);
+ }
+ return char;
+ },
+
+ readchar: function(n) {
+ n = n || 1;
+ var char;
+
+ for(var i=0; i<n; i++) {
+ char = this.input[i];
+ if(char === "\n") this.yylineno++;
+ }
+
+ this.input = this.input.slice(n);
+ },
+
+ peek: function(n) {
+ return this.input.slice(0, n || 1);
+ }
+};
+
+var Visitor = function() {};
+
+Visitor.prototype = {
+ accept: function(object) {
+ return this[object.type](object);
+ }
+}
+
+if(exports) {
+ exports.Lexer = Lexer;
+ exports.Visitor = Visitor;
+}
diff --git a/lib/handlebars/printer.js b/lib/handlebars/printer.js
new file mode 100644
index 0000000..542cfcf
--- /dev/null
+++ b/lib/handlebars/printer.js
@@ -0,0 +1,92 @@
+if(exports) { var Visitor = require("handlebars/jison_ext").Visitor }
+
+PrintVisitor = function() { this.padding = 0; };
+PrintVisitor.prototype = new Visitor;
+
+PrintVisitor.prototype.pad = function(string, newline) {
+ var out = "";
+
+ for(var i=0,l=this.padding; i<l; i++) {
+ out = out + " ";
+ }
+
+ out = out + string;
+
+ if(newline !== false) { out = out + "\n" }
+ return out;
+};
+
+PrintVisitor.prototype.program = function(program) {
+ var out = this.pad("PROGRAM:"),
+ statements = program.statements,
+ inverse = program.inverse;
+
+ this.padding++;
+
+ for(var i=0, l=statements.length; i<l; i++) {
+ out = out + this.accept(statements[i]);
+ }
+
+ this.padding--;
+
+ if(inverse) {
+ out = out + this.pad("{{^}}");
+
+ this.padding++;
+
+ for(var i=0, l=inverse.length; i<l; i++) {
+ out = out + this.accept(inverse[i]);
+ }
+ }
+
+ this.padding--;
+
+ return out;
+};
+
+PrintVisitor.prototype.block = function(block) {
+ var out = "";
+
+ out = out + this.pad("BLOCK:");
+ this.padding++;
+ out = out + this.accept(block.mustache);
+ out = out + this.accept(block.program);
+ this.padding--;
+
+ return out;
+};
+
+PrintVisitor.prototype.mustache = function(mustache) {
+ var params = mustache.params, paramStrings = [];
+
+ for(var i=0, l=params.length; i<l; i++) {
+ paramStrings.push(this.accept(params[i]));
+ }
+
+ var params = "[" + paramStrings.join(", ") + "]";
+ return this.pad("{{ " + this.accept(mustache.id) + " " + params + "}}");
+};
+
+PrintVisitor.prototype.partial = function(partial) {
+ return this.pad("{{> " + this.accept(partial.id) + " }}");
+};
+
+PrintVisitor.prototype.STRING = function(string) {
+ return string.string;
+};
+
+PrintVisitor.prototype.ID = function(id) {
+ return "ID:" + id.id;
+};
+
+PrintVisitor.prototype.content = function(content) {
+ return this.pad("CONTENT[ '" + content.string + "' ]");
+};
+
+PrintVisitor.prototype.comment = function(comment) {
+ return this.pad("{{! '" + comment.comment + "' }}");
+}
+
+if(exports) {
+ exports.PrintVisitor = PrintVisitor;
+}