From f65548f1c41751ac6bfd43296af4274d07740048 Mon Sep 17 00:00:00 2001 From: "Elf M. Sternberg" Date: Mon, 10 Jun 2013 15:55:27 -0700 Subject: [PATCH] Needed if I'm ever going to make this NPM-able. --- .gitignore | 1 - lib/engine.js | 32 ++ lib/lexer.js | 823 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/parser.js | 159 ++++++++++ lib/tumble.js | 20 ++ 5 files changed, 1034 insertions(+), 1 deletion(-) create mode 100644 lib/engine.js create mode 100644 lib/lexer.js create mode 100644 lib/parser.js create mode 100644 lib/tumble.js diff --git a/.gitignore b/.gitignore index e19f199..e7ee1d2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,4 @@ *.orig npm-debug.log node_modules/* -lib/ tmp/ diff --git a/lib/engine.js b/lib/engine.js new file mode 100644 index 0000000..9ac237f --- /dev/null +++ b/lib/engine.js @@ -0,0 +1,32 @@ +// Generated by CoffeeScript 1.6.1 +(function() { + var exports, fromFile, fs, parse, render, tumble; + + tumble = require('./lexer').parse; + + parse = require('./parser'); + + fs = require('fs'); + + render = function(str, options, callback) { + try { + return callback(null, parse(tumble(str), options)); + } catch (err) { + return callback(err, null); + } + }; + + fromFile = function(path, options, callback) { + return fs.readFile(path, 'utf8', function(err, str) { + if (err) { + return callback(err); + } + return render(str, options, callback); + }); + }; + + fromFile.render = render; + + exports = fromFile; + +}).call(this); diff --git a/lib/lexer.js b/lib/lexer.js new file mode 100644 index 0000000..89973a5 --- /dev/null +++ b/lib/lexer.js @@ -0,0 +1,823 @@ +module.exports = (function() { + /* + * Generated by PEG.js 0.7.0. + * + * http://pegjs.majda.cz/ + */ + + function peg$subclass(child, parent) { + function ctor() { this.constructor = child; } + ctor.prototype = parent.prototype; + child.prototype = new ctor(); + } + + function SyntaxError(expected, found, offset, line, column) { + function buildMessage(expected, found) { + function stringEscape(s) { + function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); } + + return s + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\x08/g, '\\b') + .replace(/\t/g, '\\t') + .replace(/\n/g, '\\n') + .replace(/\f/g, '\\f') + .replace(/\r/g, '\\r') + .replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) + .replace(/[\x10-\x1F\x80-\xFF]/g, function(ch) { return '\\x' + hex(ch); }) + .replace(/[\u0180-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); }) + .replace(/[\u1080-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); }); + } + + var expectedDesc, foundDesc; + + switch (expected.length) { + case 0: + expectedDesc = "end of input"; + break; + + case 1: + expectedDesc = expected[0]; + break; + + default: + expectedDesc = expected.slice(0, -1).join(", ") + + " or " + + expected[expected.length - 1]; + } + + foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input"; + + return "Expected " + expectedDesc + " but " + foundDesc + " found."; + } + + this.expected = expected; + this.found = found; + this.offset = offset; + this.line = line; + this.column = column; + + this.name = "SyntaxError"; + this.message = buildMessage(expected, found); + } + + peg$subclass(SyntaxError, Error); + + function parse(input) { + var options = arguments.length > 1 ? arguments[1] : {}, + + peg$startRuleFunctions = { document: peg$parsedocument }, + peg$startRuleFunction = peg$parsedocument, + + peg$c0 = [], + peg$c1 = function(ps) { return { unit: "block", name: "document", content: ps }; }, + peg$c2 = "tag_start", + peg$c3 = null, + peg$c4 = ":", + peg$c5 = "\":\"", + peg$c6 = function(b, n) { return {type: b, name: n }; }, + peg$c7 = "/", + peg$c8 = "\"/\"", + peg$c9 = "tagname", + peg$c10 = /^[a-zA-Z]/, + peg$c11 = "[a-zA-Z]", + peg$c12 = function(t) { return t.join(''); }, + peg$c13 = "", + peg$c14 = /^[a-zA-Z:\/]/, + peg$c15 = "[a-zA-Z:\\/]", + peg$c16 = "{", + peg$c17 = "\"{\"", + peg$c18 = "}", + peg$c19 = "\"}\"", + peg$c20 = "\n", + peg$c21 = "\"\\n\"", + peg$c22 = "\r\n", + peg$c23 = "\"\\r\\n\"", + peg$c24 = "\r", + peg$c25 = "\"\\r\"", + peg$c26 = "\u2028", + peg$c27 = "\"\\u2028\"", + peg$c28 = "\u2029", + peg$c29 = "\"\\u2029\"", + peg$c30 = "any character", + peg$c31 = function(c) {return c}, + peg$c32 = function(bs) { return { unit: 'text', content: bs.join('') } }, + peg$c33 = "variable", + peg$c34 = function(t) { return { unit: 'variable', name: t }; }, + peg$c35 = function(t, ps, n) { return (t.type == n.type) && (t.name == n.name) }, + peg$c36 = function(t, ps, n) { return {unit: 'block', type:t.type, name:t.name, content: ps } }, + + peg$currPos = 0, + peg$reportedPos = 0, + peg$cachedPos = 0, + peg$cachedPosDetails = { line: 1, column: 1, seenCR: false }, + peg$maxFailPos = 0, + peg$maxFailExpected = [], + peg$silentFails = 0, + + peg$result; + + if ("startRule" in options) { + if (!(options.startRule in peg$startRuleFunctions)) { + throw new Error("Can't start parsing from rule \"" + options.startRule + "\"."); + } + + peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; + } + + function text() { + return input.substring(peg$reportedPos, peg$currPos); + } + + function offset() { + return peg$reportedPos; + } + + function line() { + return peg$computePosDetails(peg$reportedPos).line; + } + + function column() { + return peg$computePosDetails(peg$reportedPos).column; + } + + function peg$computePosDetails(pos) { + function advance(details, startPos, endPos) { + var p, ch; + + for (p = startPos; p < endPos; p++) { + ch = input.charAt(p); + if (ch === "\n") { + if (!details.seenCR) { details.line++; } + details.column = 1; + details.seenCR = false; + } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") { + details.line++; + details.column = 1; + details.seenCR = true; + } else { + details.column++; + details.seenCR = false; + } + } + } + + if (peg$cachedPos !== pos) { + if (peg$cachedPos > pos) { + peg$cachedPos = 0; + peg$cachedPosDetails = { line: 1, column: 1, seenCR: false }; + } + advance(peg$cachedPosDetails, peg$cachedPos, pos); + peg$cachedPos = pos; + } + + return peg$cachedPosDetails; + } + + function peg$fail(expected) { + if (peg$currPos < peg$maxFailPos) { return; } + + if (peg$currPos > peg$maxFailPos) { + peg$maxFailPos = peg$currPos; + peg$maxFailExpected = []; + } + + peg$maxFailExpected.push(expected); + } + + function peg$cleanupExpected(expected) { + var i = 0; + + expected.sort(); + + while (i < expected.length) { + if (expected[i - 1] === expected[i]) { + expected.splice(i, 1); + } else { + i++; + } + } + } + + function peg$parsedocument() { + var s0, s1, s2; + + s0 = peg$currPos; + s1 = []; + s2 = peg$parsepart(); + while (s2 !== null) { + s1.push(s2); + s2 = peg$parsepart(); + } + if (s1 !== null) { + peg$reportedPos = s0; + s1 = peg$c1(s1); + } + if (s1 === null) { + peg$currPos = s0; + s0 = s1; + } else { + s0 = s1; + } + + return s0; + } + + function peg$parsepart() { + var s0; + + s0 = peg$parseblock(); + if (s0 === null) { + s0 = peg$parsevariable(); + if (s0 === null) { + s0 = peg$parsetext(); + } + } + + return s0; + } + + function peg$parsetag_start() { + var s0, s1, s2, s3, s4, s5; + + peg$silentFails++; + s0 = peg$currPos; + s1 = peg$parseld(); + if (s1 !== null) { + s2 = peg$parsetagname(); + if (s2 !== null) { + if (input.charCodeAt(peg$currPos) === 58) { + s3 = peg$c4; + peg$currPos++; + } else { + s3 = null; + if (peg$silentFails === 0) { peg$fail(peg$c5); } + } + if (s3 !== null) { + s4 = peg$parsetagname(); + if (s4 !== null) { + s5 = peg$parserd(); + if (s5 !== null) { + peg$reportedPos = s0; + s1 = peg$c6(s2,s4); + if (s1 === null) { + peg$currPos = s0; + s0 = s1; + } else { + s0 = s1; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + peg$silentFails--; + if (s0 === null) { + s1 = null; + if (peg$silentFails === 0) { peg$fail(peg$c2); } + } + + return s0; + } + + function peg$parsetag_end() { + var s0, s1, s2, s3, s4, s5, s6; + + s0 = peg$currPos; + s1 = peg$parseld(); + if (s1 !== null) { + if (input.charCodeAt(peg$currPos) === 47) { + s2 = peg$c7; + peg$currPos++; + } else { + s2 = null; + if (peg$silentFails === 0) { peg$fail(peg$c8); } + } + if (s2 !== null) { + s3 = peg$parsetagname(); + if (s3 !== null) { + if (input.charCodeAt(peg$currPos) === 58) { + s4 = peg$c4; + peg$currPos++; + } else { + s4 = null; + if (peg$silentFails === 0) { peg$fail(peg$c5); } + } + if (s4 !== null) { + s5 = peg$parsetagname(); + if (s5 !== null) { + s6 = peg$parserd(); + if (s6 !== null) { + peg$reportedPos = s0; + s1 = peg$c6(s3,s5); + if (s1 === null) { + peg$currPos = s0; + s0 = s1; + } else { + s0 = s1; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + + return s0; + } + + function peg$parsetagname() { + var s0, s1, s2; + + peg$silentFails++; + s0 = peg$currPos; + s1 = []; + if (peg$c10.test(input.charAt(peg$currPos))) { + s2 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s2 = null; + if (peg$silentFails === 0) { peg$fail(peg$c11); } + } + if (s2 !== null) { + while (s2 !== null) { + s1.push(s2); + if (peg$c10.test(input.charAt(peg$currPos))) { + s2 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s2 = null; + if (peg$silentFails === 0) { peg$fail(peg$c11); } + } + } + } else { + s1 = peg$c3; + } + if (s1 !== null) { + peg$reportedPos = s0; + s1 = peg$c12(s1); + } + if (s1 === null) { + peg$currPos = s0; + s0 = s1; + } else { + s0 = s1; + } + peg$silentFails--; + if (s0 === null) { + s1 = null; + if (peg$silentFails === 0) { peg$fail(peg$c9); } + } + + return s0; + } + + function peg$parsetag() { + var s0, s1, s2, s3, s4, s5, s6; + + s0 = peg$currPos; + s1 = peg$parseld(); + if (s1 !== null) { + s2 = []; + s3 = peg$currPos; + s4 = peg$currPos; + peg$silentFails++; + s5 = peg$parserd(); + peg$silentFails--; + if (s5 === null) { + s4 = peg$c13; + } else { + peg$currPos = s4; + s4 = peg$c3; + } + if (s4 !== null) { + s5 = peg$currPos; + peg$silentFails++; + s6 = peg$parseeol(); + peg$silentFails--; + if (s6 === null) { + s5 = peg$c13; + } else { + peg$currPos = s5; + s5 = peg$c3; + } + if (s5 !== null) { + if (peg$c14.test(input.charAt(peg$currPos))) { + s6 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s6 = null; + if (peg$silentFails === 0) { peg$fail(peg$c15); } + } + if (s6 !== null) { + s4 = [s4, s5, s6]; + s3 = s4; + } else { + peg$currPos = s3; + s3 = peg$c3; + } + } else { + peg$currPos = s3; + s3 = peg$c3; + } + } else { + peg$currPos = s3; + s3 = peg$c3; + } + if (s3 !== null) { + while (s3 !== null) { + s2.push(s3); + s3 = peg$currPos; + s4 = peg$currPos; + peg$silentFails++; + s5 = peg$parserd(); + peg$silentFails--; + if (s5 === null) { + s4 = peg$c13; + } else { + peg$currPos = s4; + s4 = peg$c3; + } + if (s4 !== null) { + s5 = peg$currPos; + peg$silentFails++; + s6 = peg$parseeol(); + peg$silentFails--; + if (s6 === null) { + s5 = peg$c13; + } else { + peg$currPos = s5; + s5 = peg$c3; + } + if (s5 !== null) { + if (peg$c14.test(input.charAt(peg$currPos))) { + s6 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s6 = null; + if (peg$silentFails === 0) { peg$fail(peg$c15); } + } + if (s6 !== null) { + s4 = [s4, s5, s6]; + s3 = s4; + } else { + peg$currPos = s3; + s3 = peg$c3; + } + } else { + peg$currPos = s3; + s3 = peg$c3; + } + } else { + peg$currPos = s3; + s3 = peg$c3; + } + } + } else { + s2 = peg$c3; + } + if (s2 !== null) { + s3 = peg$parserd(); + if (s3 !== null) { + s1 = [s1, s2, s3]; + s0 = s1; + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + + return s0; + } + + function peg$parseld() { + var s0; + + if (input.charCodeAt(peg$currPos) === 123) { + s0 = peg$c16; + peg$currPos++; + } else { + s0 = null; + if (peg$silentFails === 0) { peg$fail(peg$c17); } + } + + return s0; + } + + function peg$parserd() { + var s0; + + if (input.charCodeAt(peg$currPos) === 125) { + s0 = peg$c18; + peg$currPos++; + } else { + s0 = null; + if (peg$silentFails === 0) { peg$fail(peg$c19); } + } + + return s0; + } + + function peg$parseeol() { + var s0; + + if (input.charCodeAt(peg$currPos) === 10) { + s0 = peg$c20; + peg$currPos++; + } else { + s0 = null; + if (peg$silentFails === 0) { peg$fail(peg$c21); } + } + if (s0 === null) { + if (input.substr(peg$currPos, 2) === peg$c22) { + s0 = peg$c22; + peg$currPos += 2; + } else { + s0 = null; + if (peg$silentFails === 0) { peg$fail(peg$c23); } + } + if (s0 === null) { + if (input.charCodeAt(peg$currPos) === 13) { + s0 = peg$c24; + peg$currPos++; + } else { + s0 = null; + if (peg$silentFails === 0) { peg$fail(peg$c25); } + } + if (s0 === null) { + if (input.charCodeAt(peg$currPos) === 8232) { + s0 = peg$c26; + peg$currPos++; + } else { + s0 = null; + if (peg$silentFails === 0) { peg$fail(peg$c27); } + } + if (s0 === null) { + if (input.charCodeAt(peg$currPos) === 8233) { + s0 = peg$c28; + peg$currPos++; + } else { + s0 = null; + if (peg$silentFails === 0) { peg$fail(peg$c29); } + } + } + } + } + } + + return s0; + } + + function peg$parsetext() { + var s0, s1, s2, s3, s4; + + s0 = peg$currPos; + s1 = []; + s2 = peg$currPos; + s3 = peg$currPos; + peg$silentFails++; + s4 = peg$parsetag(); + peg$silentFails--; + if (s4 === null) { + s3 = peg$c13; + } else { + peg$currPos = s3; + s3 = peg$c3; + } + if (s3 !== null) { + if (input.length > peg$currPos) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = null; + if (peg$silentFails === 0) { peg$fail(peg$c30); } + } + if (s4 !== null) { + peg$reportedPos = s2; + s3 = peg$c31(s4); + if (s3 === null) { + peg$currPos = s2; + s2 = s3; + } else { + s2 = s3; + } + } else { + peg$currPos = s2; + s2 = peg$c3; + } + } else { + peg$currPos = s2; + s2 = peg$c3; + } + if (s2 !== null) { + while (s2 !== null) { + s1.push(s2); + s2 = peg$currPos; + s3 = peg$currPos; + peg$silentFails++; + s4 = peg$parsetag(); + peg$silentFails--; + if (s4 === null) { + s3 = peg$c13; + } else { + peg$currPos = s3; + s3 = peg$c3; + } + if (s3 !== null) { + if (input.length > peg$currPos) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = null; + if (peg$silentFails === 0) { peg$fail(peg$c30); } + } + if (s4 !== null) { + peg$reportedPos = s2; + s3 = peg$c31(s4); + if (s3 === null) { + peg$currPos = s2; + s2 = s3; + } else { + s2 = s3; + } + } else { + peg$currPos = s2; + s2 = peg$c3; + } + } else { + peg$currPos = s2; + s2 = peg$c3; + } + } + } else { + s1 = peg$c3; + } + if (s1 !== null) { + peg$reportedPos = s0; + s1 = peg$c32(s1); + } + if (s1 === null) { + peg$currPos = s0; + s0 = s1; + } else { + s0 = s1; + } + + return s0; + } + + function peg$parsevariable() { + var s0, s1, s2, s3; + + peg$silentFails++; + s0 = peg$currPos; + s1 = peg$parseld(); + if (s1 !== null) { + s2 = peg$parsetagname(); + if (s2 !== null) { + s3 = peg$parserd(); + if (s3 !== null) { + peg$reportedPos = s0; + s1 = peg$c34(s2); + if (s1 === null) { + peg$currPos = s0; + s0 = s1; + } else { + s0 = s1; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + peg$silentFails--; + if (s0 === null) { + s1 = null; + if (peg$silentFails === 0) { peg$fail(peg$c33); } + } + + return s0; + } + + function peg$parseblock() { + var s0, s1, s2, s3, s4; + + s0 = peg$currPos; + s1 = peg$parsetag_start(); + if (s1 !== null) { + s2 = []; + s3 = peg$parsepart(); + while (s3 !== null) { + s2.push(s3); + s3 = peg$parsepart(); + } + if (s2 !== null) { + s3 = peg$parsetag_end(); + if (s3 !== null) { + peg$reportedPos = peg$currPos; + s4 = peg$c35(s1,s2,s3); + if (s4) { + s4 = peg$c13; + } else { + s4 = peg$c3; + } + if (s4 !== null) { + peg$reportedPos = s0; + s1 = peg$c36(s1,s2,s3); + if (s1 === null) { + peg$currPos = s0; + s0 = s1; + } else { + s0 = s1; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + } else { + peg$currPos = s0; + s0 = peg$c3; + } + + return s0; + } + + peg$result = peg$startRuleFunction(); + + if (peg$result !== null && peg$currPos === input.length) { + return peg$result; + } else { + peg$cleanupExpected(peg$maxFailExpected); + peg$reportedPos = Math.max(peg$currPos, peg$maxFailPos); + + throw new SyntaxError( + peg$maxFailExpected, + peg$reportedPos < input.length ? input.charAt(peg$reportedPos) : null, + peg$reportedPos, + peg$computePosDetails(peg$reportedPos).line, + peg$computePosDetails(peg$reportedPos).column + ); + } + } + + return { + SyntaxError: SyntaxError, + parse : parse + }; +})(); diff --git a/lib/parser.js b/lib/parser.js new file mode 100644 index 0000000..a5f8b34 --- /dev/null +++ b/lib/parser.js @@ -0,0 +1,159 @@ +// Generated by CoffeeScript 1.6.1 +(function() { + var Contexter, util, _; + + _ = require('underscore'); + + util = require('util'); + + Contexter = (function() { + + function Contexter(content) { + this.content = content; + this.stack = [this.content]; + this.templates = {}; + this.depth = 0; + } + + Contexter.prototype.has_any = function(name) { + return _.find(this.stack, function(o) { + return _.has(o, name); + }); + }; + + Contexter.prototype.has_any_one = function(name) { + var p; + p = this.has_any(name); + if (p) { + return p[name]; + } else { + return null; + } + }; + + Contexter.prototype.has = function(name) { + if (this.stack[0][name] != null) { + return this.stack[0][name]; + } else { + return null; + } + }; + + Contexter.prototype.get = function(name, alt) { + var p; + if (alt == null) { + alt = ''; + } + p = this.has_any_one(name); + if (p && (_.isString(p) || _.isNumber(p))) { + return p; + } + return this.render(name); + }; + + Contexter.prototype.once = function(obj, cb) { + var r; + this.stack.unshift(obj); + this.depth++; + if (this.depth > 10) { + throw new Error('recursion-error'); + } + r = cb(this); + this.stack.shift(); + this.depth--; + return r; + }; + + Contexter.prototype["if"] = function(name, cb) { + var p; + p = this.has_any_one(name); + if (p) { + return cb(this); + } else { + return ''; + } + }; + + Contexter.prototype.block = function(name, cb) { + var p; + p = this.has_any_one(name); + if (p && _.isObject(p)) { + return this.once(p, cb); + } else { + return ''; + } + }; + + Contexter.prototype.many = function(name, cb) { + var ps, + _this = this; + ps = this.has(name); + if (!(ps && _.isArray(ps))) { + return ""; + } + return (_.map(ps, function(p) { + return _this.once(p, cb); + })).join(''); + }; + + Contexter.prototype.template = function(name, cb) { + this.templates[name] = cb; + return ""; + }; + + Contexter.prototype.render = function(name) { + if ((this.templates[name] != null) && _.isFunction(this.templates[name])) { + return this.templates[name](this); + } else { + return ""; + } + }; + + return Contexter; + + })(); + + module.exports = function(ast, data) { + var cmd, context, o; + context = new Contexter(data); + cmd = function(o) { + switch (o.unit) { + case 'variable': + return function(context) { + return context.get(o.name); + }; + case 'text': + return function(context) { + return o.content; + }; + case 'block': + return function(context) { + return context[o.type](o.name, function(context) { + var p; + return ((function() { + var _i, _len, _ref, _results; + _ref = o.content; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + p = _ref[_i]; + _results.push(cmd(p)(context)); + } + return _results; + })()).join(""); + }); + }; + } + }; + return ((function() { + var _i, _len, _ref, _results; + _ref = ast.content; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + o = _ref[_i]; + _results.push(cmd(o)(context)); + } + return _results; + })()).join(""); + }; + +}).call(this); diff --git a/lib/tumble.js b/lib/tumble.js new file mode 100644 index 0000000..8b381e5 --- /dev/null +++ b/lib/tumble.js @@ -0,0 +1,20 @@ +// Generated by CoffeeScript 1.6.1 +(function() { + var engine, lexer, parse; + + lexer = require('./lexer'); + + parse = require('./parser'); + + engine = require('./engine'); + + module.exports = { + tumble: lexer.parse, + parse: parse, + render: function(str, data) { + return parse(lexer.parse(str), data); + }, + engine: engine + }; + +}).call(this);