From 03cd20204ae30ae5db483ba5c1f106f81aba521e Mon Sep 17 00:00:00 2001 From: Sahab Yazdani Date: Wed, 27 Apr 2011 12:25:33 -0400 Subject: [PATCH] Reintroduce compiler --- mustache.js | 236 ++++++++++++++++++++++++++++++--------------------- test/unit.js | 8 +- 2 files changed, 145 insertions(+), 99 deletions(-) diff --git a/mustache.js b/mustache.js index 0b65b62..7dd6033 100644 --- a/mustache.js +++ b/mustache.js @@ -6,14 +6,13 @@ var Mustache = (function(undefined) { var splitFunc = (function() { - // Fix up the stupidness that is IE's split implementation + // fix up the stupidness that is IE's broken String.split implementation + /* Cross-Browser Split 1.0.1 + (c) Steven Levithan ; MIT License + An ECMA-compliant, uniform cross-browser split method + */ var compliantExecNpcg = /()??/.exec("")[1] === undefined; // NPCG: nonparticipating capturing group function capturingSplit(separator) { - // fix up the stupidness that is IE's broken String.split implementation - // originally by Steven Levithan - /* Cross-Browser Split 1.0.1 - (c) Steven Levithan ; MIT License - An ECMA-compliant, uniform cross-browser split method */ var str = this; var limit = undefined; @@ -102,6 +101,8 @@ var Mustache = (function(undefined) { } })(); + function noop() {} + var escapeCompiledRegex; function escape_regex(text) { // thank you Simon Willison @@ -125,7 +126,7 @@ var Mustache = (function(undefined) { } var default_tokenizer = /(\r?\n)|({{![\s\S]*?}})|({{[#\^\/&{>=]?\s*\S*?\s*}?}})|({{=\S*?\s*\S*?=}})/; - function create_parser_context(template, partials, view, send_func, openTag, closeTag) { + function create_parser_context(template, partials, openTag, closeTag) { openTag = openTag || '{{'; closeTag = closeTag || '}}'; @@ -139,15 +140,18 @@ var Mustache = (function(undefined) { tokenizer = new RegExp('(\\r?\\n)|(' + rOTag + '![\\s\\S]*?' + rETag + ')|(' + rOTag + '[#\^\/&{>=]?\\s*\\S*?\\s*}?' + rETag + ')|(' + rOTag + '=\\S*?\\s*\\S*?=' + rETag + ')'); } + var code = []; var context = { template: template || '' , partials: partials || {} - , contextStack: [view || {}] - , user_send_func: send_func , openTag: openTag , closeTag: closeTag , state: 'normal' , pragmas: {} + , code: code + , send_code_func: function(f) { + code.push(f); + } }; // prefilter pragmas @@ -236,59 +240,67 @@ var Mustache = (function(undefined) { prefix = true; } - var res = find_in_stack(get_variable_name(parserContext, token, prefix, postfix), parserContext.contextStack); - if (res!==undefined) { - if (!escape) { - res = escapeHTML('' + res); + var variable = get_variable_name(parserContext, token, prefix, postfix); + parserContext.send_code_func((function(variable, escape) { return function(context, send_func) { + var res = find_in_stack(variable, context); + if (res!==undefined) { + if (!escape) { + res = escapeHTML('' + res); + } + + send_func('' + res); } - - parserContext.user_send_func('' + res); - } + };})(variable, escape)); } function partial(parserContext, token) { - var variable = get_variable_name(parserContext, token, true); + var variable = get_variable_name(parserContext, token, true), + template, program; - var value = find_in_stack(variable, parserContext.contextStack); - if (!parserContext.partials[variable]) { throw new Error('Unknown partial \'' + variable + '\''); } - var new_parser_context = create_parser_context( - parserContext.partials[variable] - , parserContext.partials - , null - , parserContext.user_send_func); + if (!is_function(parserContext.partials[variable])) { + // if the partial has not been compiled yet, do so now - new_parser_context.contextStack = parserContext.contextStack; + template = parserContext.partials[variable]; // remember what the partial was + parserContext.partials[variable] = noop; // avoid infinite recursion + + program = parse(create_parser_context( + template + , parserContext.partials + )); + + parserContext.partials[variable] = function(context, send_func) { + var value = find_in_stack(variable, context); - if (value) { - // TODO: According to mustache-spec, partials do not act as implicit sections - // this behaviour was carried over from janl's mustache and should either - // be discarded or replaced with a pragma - new_parser_context.contextStack.push(value); - } + if (value) { + // TODO: According to mustache-spec, partials do not act as implicit sections + // this behaviour was carried over from janl's mustache and should either + // be discarded or replaced with a pragma + context.push(value); + } - parse(new_parser_context); - - if (value) { - // TODO: See above - new_parser_context.contextStack.pop(); + program(context, send_func); + + if (value) { + // TODO: See above + context.pop(); + } + }; } + + parserContext.send_code_func(function(context, send_func) { parserContext.partials[variable](context, send_func); }); } function section(parserContext) { function create_section_context(template) { var context = create_parser_context(template, parserContext.partials, - null, - parserContext.user_send_func, parserContext.openTag, parserContext.closeTag); - context.contextStack = parserContext.contextStack; - return context; } @@ -306,48 +318,45 @@ var Mustache = (function(undefined) { } } - var s = parserContext.section; - var value = find_in_stack(s.variable, parserContext.contextStack); - var i, n; - var new_parser_context; + var s = parserContext.section, variable = s.variable, template = s.template_buffer.join('') + program = parse(create_section_context(template)); if (s.inverted) { - if (!value || is_array(value) && value.length === 0) { // false or empty list, render it - new_parser_context = create_section_context(s.template_buffer.join('')); - parse(new_parser_context); - } - } else { - if (is_array(value)) { // Enumerable, Let's loop! - new_parser_context = create_section_context(s.template_buffer.join('')); - - for (i=0, n=value.length; i0) { - var optionPairs = suffix.split(','); - var scratch; + optionPairs = suffix.split(','); + scratch; options = {}; - for (var i=0, n=optionPairs.length; ipartial}}', partials ); + var partials = { 'partial' : '{{key}}' }; + Mustache.compile('{{>partial}}', partials ); - //equals(partials['partial'], '{{key}}', 'Partials compiler must be non-destructive'); + equals(partials['partial'], '{{key}}', 'Partials compiler must be non-destructive'); }); test("Basic Variables", function() { @@ -273,7 +273,7 @@ test("'#' (Sections)", function() { ), '\n \n 1\n \n\n \n 2\n \n\n \n 3\n \n', 'Context Nesting' - ); + ); }); test("'^' (Inverted Section)", function() {