Skip to content

Instantly share code, notes, and snippets.

@raycmorgan
Created January 14, 2010 07:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raycmorgan/276980 to your computer and use it in GitHub Desktop.
Save raycmorgan/276980 to your computer and use it in GitHub Desktop.
Mustache compiler in JS for JS
var sys = require('sys');
var template ="<html>" +
"<body>" +
"<h1>{{ title }}</h1>" +
"{{# admin }}" +
"If admin {{ name }}" +
"{{/ admin }}" +
"</body>" +
"</html>";
Mu = {
escape: function (val) {
return val.replace(/</, '&lt;');
},
normalize: function (val) {
return val ? val.toString() : '';
},
enumerable: function (env, val, fn) {
if (typeof(val) === 'undefined') {
return '';
}
if (typeof(val) === 'boolean') {
return val ? fn(env) : '';
}
if (val instanceof Array) {
var result = '';
for (var i = 0, len = val.length; i < val.length; i++) {
result += fn(val[i]);
}
return result;
// return val.map(fn).join(''); // One can dreamm.. about 40% slower
}
return val ? fn(val) : '';
}
};
function compilePart(source, begin, end) {
begin = begin || '{{';
end = end || '}}';
var code = [];
var buffer = '';
var rbegin = new RegExp(begin + '$');
var rend = new RegExp(end + '$');
for (var i = 0, len = source.length; i < source.length; i++) {
var letter = source.charAt(i);
buffer += letter;
if (buffer.match(rbegin)) {
if (buffer.length > begin.length) {
buffer = buffer.substring(0, buffer.length - end.length);
code.push('result += "' + buffer + '";');
}
buffer = '';
(function inTag() {
i++;
var buffer = '';
for (; i < source.length; i++) {
var letter = source.charAt(i);
if (letter === ' ') {
continue;
}
if (letter === '#' && buffer === '') {
(function inEnumerableTag() {
i++;
var buffer = '';
for (; i < source.length; i++) {
var letter = source.charAt(i);
if (letter === ' ') {
continue;
}
buffer += letter;
if (buffer.match(rend)) {
buffer = buffer.substring(0, buffer.length - end.length);
(function inEnumerable(varName) {
i++;
var buffer = '';
var regexp = new RegExp('(.*){{ */ *' + varName + ' *}}$');
for (; i < source.length; i++) {
var letter = source.charAt(i);
buffer += letter;
var match = buffer.match(regexp);
if (match) {
code.push(
'result += Mu.enumerable(env, env.' + varName + ', function (env) {',
'var result = "";',
compilePart(match[1], begin, end),
'return result;',
'});'
);
return;
}
}
throw "Unexpected End";
})(buffer);
return;
}
}
})();
return;
}
buffer += letter;
if (buffer.match(rend)) {
buffer = buffer.substring(0, buffer.length - end.length);
code.push("result += Mu.escape(Mu.normalize(env." + buffer + "));");
return;
}
}
throw "Unexpected End";
})();
continue;
}
}
if (buffer) {
code.push('result += "' + buffer + '";');
}
return code.join('');
}
function compile(source) {
source = compilePart(source);
return 'function (env) {\n' +
'var result = "";\n' +
source +
'return result;\n' +
'\n}';
}
var compiled = compile(template);
compiled = eval("(" + compiled + ")");
sys.puts(
compiled(
{
title: "Hello World",
admin: [
{name: "tom"},
{name: "jim"}
]
}
)
);
var d = new Date();
for (var i = 0; i < 1000000; i++) {
compiled(
{
title: "Hello World",
admin: [
{name: "tom"},
{name: "jim"}
]
}
)
}
sys.puts("Time taken: " + ((new Date() - d) / 1000) + "secs");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment