Fix handling of delimiters in lambda sections - all spec tests pass woot
diff --git a/lib/mustache.dart b/lib/mustache.dart
index 23b95df..d8ef0ae 100644
--- a/lib/mustache.dart
+++ b/lib/mustache.dart
@@ -27,7 +27,8 @@
       {bool lenient,
        bool htmlEscapeValues,
        String name,
-       PartialResolver partialResolver}) = _Template.fromSource;
+       PartialResolver partialResolver,
+       Delimiters delimiters}) = _Template.fromSource;
   
   String get name;
   String get source;
@@ -124,3 +125,57 @@
 class MustacheMirrorsUsedAnnotation {
   const MustacheMirrorsUsedAnnotation();
 }
+
+
+//FIXME Don't expose this. Just take a string in the api.
+class Delimiters {
+  
+  const Delimiters.standard() : this(
+      _OPEN_MUSTACHE,
+      _OPEN_MUSTACHE,
+      _CLOSE_MUSTACHE,
+      _CLOSE_MUSTACHE);
+  
+  // Assume single space between delimiters.
+  factory Delimiters.fromString(String delimiters) {
+    if (delimiters.length == 3) {
+      return new Delimiters(
+          delimiters.codeUnits[0],
+          null,
+          null,
+          delimiters.codeUnits[2]);
+    
+    } else if (delimiters.length == 5) {
+      return new Delimiters(
+                delimiters.codeUnits[0],
+                delimiters.codeUnits[1],
+                delimiters.codeUnits[3],
+                delimiters.codeUnits[4]);
+    } else {
+      throw 'Invalid delimiter string'; //FIXME
+    }
+  }
+  
+  const Delimiters(this.open, this.openInner, this.closeInner, this.close);
+  
+  final int open;
+  final int openInner;
+  final int closeInner;
+  final int close;
+  
+  String toString() {
+    var value = new String.fromCharCode(open);
+    
+    if (openInner != null)
+      value += new String.fromCharCode(openInner);
+    
+    value += ' ';
+    
+    if (closeInner != null)
+      value += new String.fromCharCode(closeInner);
+    
+    value += new String.fromCharCode(close);
+    
+    return value;
+  }
+}
diff --git a/lib/src/lambda_context.dart b/lib/src/lambda_context.dart
index 84b6d04..af913e5 100644
--- a/lib/src/lambda_context.dart
+++ b/lib/src/lambda_context.dart
@@ -5,9 +5,11 @@
   
   final _Node _node;
   final _Renderer _renderer;
+  final bool _isSection;
   bool _closed = false;
   
-  _LambdaContext(this._node, this._renderer);
+  _LambdaContext(this._node, this._renderer, {bool isSection: true})
+      : _isSection = isSection;
   
   void close() {
     _closed = true;
@@ -58,9 +60,21 @@
   String renderSource(String source) {
     _checkClosed();
     var sink = new StringBuffer();
-    var node = _parse(source, _renderer._lenient, _renderer._templateName);
+    // Lambdas used for sections should parse with the current delimiters.
+    var delimiters = _isSection
+        ? new Delimiters.fromString(_renderer._delimiters)
+        : new Delimiters.standard();
+    var node = _parse(source,
+        _renderer._lenient,
+        _renderer._templateName,
+        delimiters);
     var renderer = new _Renderer.lambda(
-        _renderer, node, source, _renderer._indent, sink);
+        _renderer,
+        node,
+        source,
+        _renderer._indent,
+        sink,
+        _renderer._delimiters);
     renderer.render();
     return sink.toString();
   }
diff --git a/lib/src/scanner.dart b/lib/src/scanner.dart
index 2b8cb38..7edf81f 100644
--- a/lib/src/scanner.dart
+++ b/lib/src/scanner.dart
@@ -1,6 +1,7 @@
 part of mustache;

 

-List<_Token> _scan(String source, bool lenient) => _trim(new _Scanner(source).scan());

+List<_Token> _scan(String source, bool lenient, Delimiters delimiters) 

+  => _trim(new _Scanner(source, null, delimiters).scan());

 

 //FIXME use enums

 const int _TEXT = 1;

@@ -145,18 +146,25 @@
 }

 

 class _Scanner {

-	_Scanner(String source, [this._templateName])

-	 : _r = new _CharReader(source);

+  

+	_Scanner(String source, [this._templateName, Delimiters initial])

+	 : _r = new _CharReader(source),

+	   _openDelimiter = (initial == null) ? _OPEN_MUSTACHE : initial.open,

+	   _openDelimiterInner =

+	     (initial == null) ? _OPEN_MUSTACHE : initial.openInner,

+	   _closeDelimiterInner =

+	     (initial == null) ? _CLOSE_MUSTACHE : initial.closeInner,

+	   _closeDelimiter = (initial == null) ? _CLOSE_MUSTACHE : initial.close;

 

 	final String _templateName;

 	_CharReader _r;

 	List<_Token> _tokens = new List<_Token>();

 

 	// These can be changed by the change delimiter tag.

-	int _openDelimiter = _OPEN_MUSTACHE;

-  int _openDelimiterInner = _OPEN_MUSTACHE;

-  int _closeDelimiterInner = _CLOSE_MUSTACHE;

-  int _closeDelimiter = _CLOSE_MUSTACHE;

+	int _openDelimiter;

+  int _openDelimiterInner;

+  int _closeDelimiterInner;

+  int _closeDelimiter;

 

   List<_Token> scan() {

     while(true) {

@@ -329,19 +337,13 @@
      

      _expect(delimiterInner);

      _expect(delimiter);

-     

-     var value = new String.fromCharCode(_openDelimiter);

-     

-     if (_openDelimiterInner != null)

-       value += new String.fromCharCode(_openDelimiterInner);

-     

-     value += ' ';

-     

-     if (_closeDelimiterInner != null)

-       value += new String.fromCharCode(_closeDelimiterInner);

-     

-     value += new String.fromCharCode(_closeDelimiter);

-     

+    

+     var value = new Delimiters(

+         _openDelimiter,

+         _openDelimiterInner,

+         _closeDelimiterInner,

+         _closeDelimiter).toString();

+          

      _tokens.add(new _Token(_CHANGE_DELIMITER, value, line, col));

 	}

 	

diff --git a/lib/src/template.dart b/lib/src/template.dart
index 1ce4a6d..6172147 100644
--- a/lib/src/template.dart
+++ b/lib/src/template.dart
@@ -35,7 +35,10 @@
 			

 			stack.removeLast();

 

-		} else if (t.type == _COMMENT || t.type == _CHANGE_DELIMITER) {

+		} else if (t.type == _CHANGE_DELIMITER) {

+		  stack.last.children.add(new _Node.fromToken(t));

+		  

+		} else if (t.type == _COMMENT) {

 			// Do nothing

 

 		} else {

@@ -56,23 +59,24 @@
 		}

 }

 

-_Node _parse(String source, bool lenient, String templateName) {

+_Node _parse(String source, bool lenient, String templateName,

+             Delimiters delimiters) {

   if (source == null) throw new ArgumentError.notNull('Template source');

-  var tokens = _scan(source, lenient);

+  var tokens = _scan(source, lenient, delimiters);

   var ast = _parseTokens(tokens, lenient, templateName);

   return ast;

 }

 

-

 class _Template implements Template {

  

   _Template.fromSource(String source, 

        {bool lenient: false,

         bool htmlEscapeValues : true,

         String name,

-        PartialResolver partialResolver})

+        PartialResolver partialResolver,

+        Delimiters delimiters : const Delimiters.standard()})

        :  source = source,

-          _root = _parse(source, lenient, name),

+          _root = _parse(source, lenient, name, delimiters),

           _lenient = lenient,

           _htmlEscapeValues = htmlEscapeValues,

           _name = name,

@@ -95,7 +99,8 @@
 

   void render(values, StringSink sink) {

     var renderer = new _Renderer(_root, sink, values, [values],

-        _lenient, _htmlEscapeValues, _partialResolver, _name, '', source);

+        _lenient, _htmlEscapeValues, _partialResolver, _name, '', source,

+        '{{ }}');

     renderer.render();

   }

 }

@@ -112,7 +117,8 @@
 	    this._partialResolver,

 	    this._templateName,

 	    this._indent,

-	    this._source)

+	    this._source,

+	    this._delimiters)

     : _stack = new List.from(stack); 

 	

 	_Renderer.partial(_Renderer renderer, _Template partial, String indent)

@@ -125,7 +131,8 @@
           renderer._partialResolver,

           renderer._templateName,

           renderer._indent + indent,

-          partial.source);

+          partial.source,

+          '{{ }}');

 

 	 _Renderer.subtree(_Renderer renderer, _Node node, StringSink sink)

        : this(node,

@@ -137,14 +144,16 @@
            renderer._partialResolver,

            renderer._templateName,

            renderer._indent,

-           renderer._source);

+           renderer._source,

+           '{{ }}');

 

 	  _Renderer.lambda(

 	      _Renderer renderer,

 	      _Node node,

 	      String source,

 	      String indent,

-	      StringSink sink)

+	      StringSink sink,

+	      String delimiters)

        : this(node,

            sink,

            renderer._values,

@@ -154,7 +163,8 @@
            renderer._partialResolver,

            renderer._templateName,

            renderer._indent + indent,

-           source);

+           source,

+           delimiters);

 	 

 	final _Node _root;

   final StringSink _sink;

@@ -167,6 +177,8 @@
 	final String _indent;

 	final String _source;

 

+	String _delimiters;

+	

 	void render() {

 	  if (_indent == null || _indent == '') {

 	   _root.children.forEach(_renderNode);

@@ -196,7 +208,7 @@
 	

 	_write(Object output) => _sink.write(output.toString());

 

-	_renderNode(node) {

+	_renderNode(_Node node) {

 		switch (node.type) {

 			case _TEXT:

 				_renderText(node);

@@ -219,7 +231,8 @@
 			case _COMMENT:

 				break; // Do nothing.

 			case _CHANGE_DELIMITER:

-			  break; // Do nothing

+			  _delimiters = node.value;

+			  break;

 			default:

 				throw new UnimplementedError();

 		}

@@ -298,7 +311,7 @@
 		var value = _resolveValue(node.value);

 		

 		if (value is Function) {

-		  var context = new _LambdaContext(node, this);

+		  var context = new _LambdaContext(node, this, isSection: false);

 		  value = value(context);

 		  context.close();

 		}

@@ -355,7 +368,7 @@
 					_templateName, node.line, node.column);

 		

 		} else if (value is Function) {

-      var context = new _LambdaContext(node, this);

+      var context = new _LambdaContext(node, this, isSection: true);

       var output = value(context);

       context.close();        

       _write(output);

@@ -391,7 +404,7 @@
 			}

     

 		} else if (value is Function) {

-      var context = new _LambdaContext(node, this);

+      var context = new _LambdaContext(node, this, isSection: true);

       var output = value(context);

       context.close();        

 

diff --git a/test/mustache_test.dart b/test/mustache_test.dart
index 3af1374..5395336 100644
--- a/test/mustache_test.dart
+++ b/test/mustache_test.dart
@@ -466,6 +466,41 @@
       var output = '<dsfsf dsfsdf dfsdfsd>';
       expect(parse(template).renderString(values), equals(output));      
     });
+
+    test('Alternate Delimiters', () {
+
+      // A lambda's return value should parse with the default delimiters.
+      
+      var template = '{{= | | =}}\nHello, (|&lambda|)!';
+      
+      //function() { return "|planet| => {{planet}}" }
+      var values = {'planet': 'world',
+                    'lambda': (LambdaContext ctx) => ctx.renderSource(
+                        '|planet| => {{planet}}') };
+      
+      var output = 'Hello, (|planet| => world)!';
+      
+      expect(parse(template).renderString(values), equals(output));
+    });
+
+    test('Alternate Delimiters 2', () {
+
+      // Lambdas used for sections should parse with the current delimiters.
+      
+      var template = '{{= | | =}}<|#lambda|-|/lambda|>';
+      
+      //function() { return "|planet| => {{planet}}" }
+      var values = {'planet': 'Earth',
+                    'lambda': (LambdaContext ctx) {
+                      var txt = ctx.source;
+                      return ctx.renderSource('$txt{{planet}} => |planet|$txt');
+                     }
+      };
+      
+      var output = '<-{{planet}} => Earth->';
+      
+      expect(parse(template).renderString(values), equals(output));
+    });
   });
 	
 	group('Other', () {