Move classes into separate files
diff --git a/lib/mustache.dart b/lib/mustache.dart
index d8ef0ae..17a8848 100644
--- a/lib/mustache.dart
+++ b/lib/mustache.dart
@@ -5,8 +5,12 @@
 
 part 'src/char_reader.dart';
 part 'src/lambda_context.dart';
+part 'src/node.dart';
+part 'src/parse.dart';
+part 'src/renderer.dart';
 part 'src/scanner.dart';
 part 'src/template.dart';
+part 'src/token.dart';
 
 /// [Mustache template documentation](http://mustache.github.com/mustache.5.html)
 
diff --git a/lib/src/node.dart b/lib/src/node.dart
new file mode 100644
index 0000000..47f468d
--- /dev/null
+++ b/lib/src/node.dart
@@ -0,0 +1,26 @@
+part of mustache;
+
+class _Node {
+  
+  _Node(this.type, this.value, this.line, this.column, {this.indent});
+  
+  _Node.fromToken(_Token token)
+    : type = token.type,
+      value = token.value,
+      line = token.line,
+      column = token.column,
+      indent = token.indent;
+
+  final int type;
+  final String value;
+  final int line;
+  final int column;
+  final String indent;
+  final List<_Node> children = new List<_Node>();
+  
+   //TODO ideally these could be made final.
+   int start;
+   int end;
+  
+  String toString() => '_Node: ${_tokenTypeString(type)}';
+}
diff --git a/lib/src/parse.dart b/lib/src/parse.dart
new file mode 100644
index 0000000..d4dcccf
--- /dev/null
+++ b/lib/src/parse.dart
@@ -0,0 +1,66 @@
+part of mustache;
+
+final RegExp _validTag = new RegExp(r'^[0-9a-zA-Z\_\-\.]+$');
+final RegExp _integerTag = new RegExp(r'^[0-9]+$');
+
+_Node _parse(String source, bool lenient, String templateName,
+             Delimiters delimiters) {
+  if (source == null) throw new ArgumentError.notNull('Template source');
+  var tokens = _scan(source, lenient, delimiters);
+  var ast = _parseTokens(tokens, lenient, templateName);
+  return ast;
+}
+
+_Node _parseTokens(List<_Token> tokens, bool lenient, String templateName) {
+  
+  var stack = new List<_Node>()..add(new _Node(_OPEN_SECTION, 'root', 0, 0));
+  
+  for (var t in tokens) {
+    if (const [_TEXT, _VARIABLE, _UNESC_VARIABLE, _PARTIAL].contains(t.type)) {
+      if (t.type == _VARIABLE || t.type == _UNESC_VARIABLE)
+        _checkTagChars(t, lenient, templateName);
+      stack.last.children.add(new _Node.fromToken(t));
+
+    } else if (t.type == _OPEN_SECTION || t.type == _OPEN_INV_SECTION) {
+      _checkTagChars(t, lenient, templateName);
+      var child = new _Node.fromToken(t);
+      child.start = t.offset;
+      stack.last.children.add(child);
+      stack.add(child);
+
+    } else if (t.type == _CLOSE_SECTION) {
+      _checkTagChars(t, lenient, templateName);
+
+      if (stack.last.value != t.value) {
+        throw new TemplateException(
+          "Mismatched tag, expected: '${stack.last.value}', was: '${t.value}'",
+          templateName, t.line, t.column);
+      }
+
+      stack.last.end = t.offset;
+      
+      stack.removeLast();
+
+    } else if (t.type == _CHANGE_DELIMITER) {
+      stack.last.children.add(new _Node.fromToken(t));
+      
+    } else if (t.type == _COMMENT) {
+      // Do nothing
+
+    } else {
+      //FIXME Use switch with enums so this becomes a compile time error.
+      throw new UnimplementedError();
+    }
+  }
+
+  return stack.last;
+}
+
+_checkTagChars(_Token t, bool lenient, String templateName) {
+    if (!lenient && !_validTag.hasMatch(t.value)) {
+      throw new TemplateException(
+        'Tag contained invalid characters in name, '
+        'allowed: 0-9, a-z, A-Z, underscore, and minus',
+        templateName, t.line, t.column);
+    }
+}
diff --git a/lib/src/renderer.dart b/lib/src/renderer.dart
new file mode 100644
index 0000000..725db8b
--- /dev/null
+++ b/lib/src/renderer.dart
@@ -0,0 +1,370 @@
+part of mustache;
+
+const Object _noSuchProperty = const Object();
+
+class _Renderer {
+  
+  _Renderer(this._root,
+      this._sink,
+      this._values,
+      List stack,
+      this._lenient,
+      this._htmlEscapeValues,
+      this._partialResolver,
+      this._templateName,
+      this._indent,
+      this._source,
+      this._delimiters)
+    : _stack = new List.from(stack); 
+  
+  _Renderer.partial(_Renderer renderer, _Template partial, String indent)
+      : this(partial._root,
+          renderer._sink,
+          renderer._values,
+          renderer._stack,
+          renderer._lenient,
+          renderer._htmlEscapeValues,
+          renderer._partialResolver,
+          renderer._templateName,
+          renderer._indent + indent,
+          partial.source,
+          '{{ }}');
+
+   _Renderer.subtree(_Renderer renderer, _Node node, StringSink sink)
+       : this(node,
+           sink,
+           renderer._values,
+           renderer._stack,
+           renderer._lenient,
+           renderer._htmlEscapeValues,
+           renderer._partialResolver,
+           renderer._templateName,
+           renderer._indent,
+           renderer._source,
+           '{{ }}');
+
+    _Renderer.lambda(
+        _Renderer renderer,
+        _Node node,
+        String source,
+        String indent,
+        StringSink sink,
+        String delimiters)
+       : this(node,
+           sink,
+           renderer._values,
+           renderer._stack,
+           renderer._lenient,
+           renderer._htmlEscapeValues,
+           renderer._partialResolver,
+           renderer._templateName,
+           renderer._indent + indent,
+           source,
+           delimiters);
+   
+  final _Node _root;
+  final StringSink _sink;
+  final _values;
+  final List _stack;
+  final bool _lenient;
+  final bool _htmlEscapeValues;
+  final PartialResolver _partialResolver;
+  final String _templateName;
+  final String _indent;
+  final String _source;
+
+  String _delimiters;
+  
+  void render() {
+    if (_indent == null || _indent == '') {
+     _root.children.forEach(_renderNode);
+    } else {
+      _renderWithIndent();
+    }
+  }
+  
+  void _renderWithIndent() {
+    // Special case to make sure there is not an extra indent after the last
+    // line in the partial file.
+    if (_root.children.isEmpty) return;
+    
+    _write(_indent);
+    
+    for (int i = 0; i < _root.children.length - 1; i++) {
+      _renderNode(_root.children[i]);
+    }
+    
+    var node = _root.children.last;
+    if (node.type != _TEXT) {
+      _renderNode(node);
+    } else {
+      _renderText(node, lastNode: true);
+    }
+  }
+  
+  _write(Object output) => _sink.write(output.toString());
+
+  _renderNode(_Node node) {
+    switch (node.type) {
+      case _TEXT:
+        _renderText(node);
+        break;
+      case _VARIABLE:
+        _renderVariable(node);
+        break;
+      case _UNESC_VARIABLE:
+        _renderVariable(node, escape: false);
+        break;
+      case _OPEN_SECTION:
+        _renderSection(node);
+        break;
+      case _OPEN_INV_SECTION:
+        _renderInvSection(node);
+        break;
+      case _PARTIAL:
+        _renderPartial(node);
+        break;
+      case _COMMENT:
+        break; // Do nothing.
+      case _CHANGE_DELIMITER:
+        _delimiters = node.value;
+        break;
+      default:
+        throw new UnimplementedError();
+    }
+  }
+
+  _renderText(_Node node, {bool lastNode: false}) {
+    var s = node.value;
+    if (s == '') return;
+    if (_indent == null || _indent == '') {
+      _write(s);
+    } else if (lastNode && s.runes.last == _NEWLINE) {
+      s = s.substring(0, s.length - 1);
+      _write(s.replaceAll('\n', '\n$_indent'));
+      _write('\n');
+    } else {
+      _write(s.replaceAll('\n', '\n$_indent'));
+    }
+  }
+
+  // Walks up the stack looking for the variable.
+  // Handles dotted names of the form "a.b.c".
+  _resolveValue(String name) {
+    if (name == '.') {
+      return _stack.last;
+    }
+    var parts = name.split('.');
+    var object = _noSuchProperty;
+    for (var o in _stack.reversed) {
+      object = _getNamedProperty(o, parts[0]);
+      if (object != _noSuchProperty) {
+        break;
+      }
+    }
+    for (int i = 1; i < parts.length; i++) {
+      if (object == null || object == _noSuchProperty) {
+        return _noSuchProperty;
+      }
+      object = _getNamedProperty(object, parts[i]);
+    }
+    return object;
+  }
+  
+  // Returns the property of the given object by name. For a map,
+  // which contains the key name, this is object[name]. For other
+  // objects, this is object.name or object.name(). If no property
+  // by the given name exists, this method returns noSuchProperty.
+  _getNamedProperty(object, name) {
+    
+    var property = null;
+    if (object is Map && object.containsKey(name))
+      return object[name];
+    
+    if (object is List && _integerTag.hasMatch(name))
+      return object[int.parse(name)];
+    
+    if (_lenient && !_validTag.hasMatch(name))
+      return _noSuchProperty;
+    
+    var instance = reflect(object);
+    var field = instance.type.instanceMembers[new Symbol(name)];
+    if (field == null) return _noSuchProperty;
+    
+    var invocation = null;
+    if ((field is VariableMirror) || ((field is MethodMirror) && (field.isGetter))) {
+      invocation = instance.getField(field.simpleName);
+    } else if ((field is MethodMirror) && (field.parameters.length == 0)) {
+      invocation = instance.invoke(field.simpleName, []);
+    }
+    if (invocation == null) {
+      return _noSuchProperty;
+    }
+    return invocation.reflectee;
+  }
+
+  _renderVariable(_Node node, {bool escape : true}) {
+    var value = _resolveValue(node.value);
+    
+    if (value is Function) {
+      var context = new _LambdaContext(node, this, isSection: false);
+      value = value(context);
+      context.close();
+    }
+    
+    if (value == _noSuchProperty) {
+      if (!_lenient)
+        throw new TemplateException(
+          'Value was missing, variable: ${node.value}',
+          _templateName, node.line, node.column);
+    } else {
+      var valueString = (value == null) ? '' : value.toString();
+      var output = !escape || !_htmlEscapeValues
+        ? valueString
+        : _htmlEscape(valueString);
+      _write(output);
+    }
+  }
+
+  _renderSectionWithValue(node, value) {
+    _stack.add(value);
+    node.children.forEach(_renderNode);
+    _stack.removeLast();
+  }
+
+  String _renderSubtree(node) {
+    var sink = new StringBuffer();
+    var renderer = new _Renderer.subtree(this, node, sink);
+    renderer.render();
+    return sink.toString();
+  }
+  
+  _renderSection(_Node node) {
+    var value = _resolveValue(node.value);
+    
+    if (value == null) {
+      // Do nothing.
+    
+    } else if (value is Iterable) {
+      value.forEach((v) => _renderSectionWithValue(node, v));
+    
+    } else if (value is Map) {
+      _renderSectionWithValue(node, value);
+    
+    } else if (value == true) {
+      _renderSectionWithValue(node, value);
+    
+    } else if (value == false) {
+      // Do nothing.
+    
+    } else if (value == _noSuchProperty) {
+      if (!_lenient)
+        throw new TemplateException(
+          'Value was missing, section: ${node.value}',
+          _templateName, node.line, node.column);
+    
+    } else if (value is Function) {
+      var context = new _LambdaContext(node, this, isSection: true);
+      var output = value(context);
+      context.close();        
+      _write(output);
+      
+    } else {
+      throw new TemplateException(
+        'Invalid value type for section, '
+        'section: ${node.value}, '
+        'type: ${value.runtimeType}',
+        _templateName, node.line, node.column);
+    }
+  }
+
+  _renderInvSection(node) {
+    var value = _resolveValue(node.value);
+    
+    if (value == null) {
+      _renderSectionWithValue(node, null);
+    
+    } else if ((value is Iterable && value.isEmpty) || value == false) {
+      _renderSectionWithValue(node, value);
+    
+    } else if (value == true || value is Map || value is Iterable) {
+      // Do nothing.
+    
+    } else if (value == _noSuchProperty) {
+      if (_lenient) {
+        _renderSectionWithValue(node, null);
+      } else {
+        throw new TemplateException(
+            'Value was missing, inverse-section: ${node.value}',
+            _templateName, node.line, node.column);
+      }
+    
+    } else if (value is Function) {
+      var context = new _LambdaContext(node, this, isSection: true);
+      var output = value(context);
+      context.close();        
+
+      //FIXME Poos. I have no idea what this really is for ?????
+      if (output == false) {
+        // FIXME not sure what to output here, result of function or template 
+        // output?
+        _write(output);
+      }
+
+    } else {
+      throw new TemplateException(
+        'Invalid value type for inverse section, '
+        'section: ${node.value}, '
+        'type: ${value.runtimeType}, ',
+        _templateName, node.line, node.column);
+    }
+  }
+
+  _renderPartial(_Node node) {
+    var partialName = node.value;
+    _Template template = _partialResolver == null
+        ? null
+        : _partialResolver(partialName);
+    if (template != null) {
+      var renderer = new _Renderer.partial(this, template, node.indent);
+      renderer.render();      
+    } else if (_lenient) {
+      // do nothing
+    } else {
+      throw new TemplateException(
+          'Partial not found: $partialName',
+          _templateName, node.line, node.column);
+    }
+  }
+
+  static const Map<String,String> _htmlEscapeMap = const {
+    _AMP: '&amp;',
+    _LT: '&lt;',
+    _GT: '&gt;',
+    _QUOTE: '&quot;',
+    _APOS: '&#x27;',
+    _FORWARD_SLASH: '&#x2F;' 
+  };
+  
+  String _htmlEscape(String s) {
+    
+    var buffer = new StringBuffer();
+    int startIndex = 0;
+    int i = 0;
+    for (int c in s.runes) {
+      if (c == _AMP
+          || c == _LT
+          || c == _GT
+          || c == _QUOTE
+          || c == _APOS
+          || c == _FORWARD_SLASH) {
+        buffer.write(s.substring(startIndex, i));
+        buffer.write(_htmlEscapeMap[c]);
+        startIndex = i + 1;
+      }
+      i++;
+    }
+    buffer.write(s.substring(startIndex));
+    return buffer.toString();
+  }
+}
diff --git a/lib/src/scanner.dart b/lib/src/scanner.dart
index 7edf81f..ba7670a 100644
--- a/lib/src/scanner.dart
+++ b/lib/src/scanner.dart
@@ -3,33 +3,6 @@
 List<_Token> _scan(String source, bool lenient, Delimiters delimiters) 

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

 

-//FIXME use enums

-const int _TEXT = 1;

-const int _VARIABLE = 2;

-const int _PARTIAL = 3;

-const int _OPEN_SECTION = 4;

-const int _OPEN_INV_SECTION = 5;

-const int _CLOSE_SECTION = 6;

-const int _COMMENT = 7;

-const int _UNESC_VARIABLE = 8;

-const int _WHITESPACE = 9; // Should be filtered out, before returned by scan.

-const int _LINE_END = 10; // Should be filtered out, before returned by scan.

-const int _CHANGE_DELIMITER = 11;

-

-_tokenTypeString(int type) => [

-	'?', 

-	'Text',

-	'Var',

-	'Par',

-	'Open',

-	'OpenInv',

-	'Close',

-	'Comment',

-	'UnescVar',

-	'Whitespace',

-	'LineEnd',

-	'ChangeDelimiter'][type];

-

 const int _EOF = -1;

 const int _TAB = 9;

 const int _NEWLINE = 10;

@@ -128,23 +101,6 @@
 	return result;

 }

 

-class _Token {

-	_Token(this.type, this.value, this.line, this.column, {this.indent});

-	

-	final int type;

-	final String value;	

-	final int line;

-	final int column;

-	final String indent;

-	

-	// Store offsets to extract text from source for lambdas.

-	// Only used for section, inverse section and close section tags.

-	int offset;

-	

-	toString() => "${_tokenTypeString(type)}: "

-	  "\"${value.replaceAll('\n', '\\n')}\" $line:$column";

-}

-

 class _Scanner {

   

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

diff --git a/lib/src/template.dart b/lib/src/template.dart
index 6172147..82d8fe8 100644
--- a/lib/src/template.dart
+++ b/lib/src/template.dart
@@ -1,72 +1,5 @@
 part of mustache;

 

-const Object _noSuchProperty = const Object();

-

-final RegExp _validTag = new RegExp(r'^[0-9a-zA-Z\_\-\.]+$');

-final RegExp _integerTag = new RegExp(r'^[0-9]+$');

-

-_Node _parseTokens(List<_Token> tokens, bool lenient, String templateName) {

-	

-  var stack = new List<_Node>()..add(new _Node(_OPEN_SECTION, 'root', 0, 0));

-	

-	for (var t in tokens) {

-		if (const [_TEXT, _VARIABLE, _UNESC_VARIABLE, _PARTIAL].contains(t.type)) {

-			if (t.type == _VARIABLE || t.type == _UNESC_VARIABLE)

-			  _checkTagChars(t, lenient, templateName);

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

-

-		} else if (t.type == _OPEN_SECTION || t.type == _OPEN_INV_SECTION) {

-			_checkTagChars(t, lenient, templateName);

-			var child = new _Node.fromToken(t);

-			child.start = t.offset;

-			stack.last.children.add(child);

-			stack.add(child);

-

-		} else if (t.type == _CLOSE_SECTION) {

-			_checkTagChars(t, lenient, templateName);

-

-			if (stack.last.value != t.value) {

-				throw new TemplateException(

-				  "Mismatched tag, expected: '${stack.last.value}', was: '${t.value}'",

-					templateName, t.line, t.column);

-			}

-

-			stack.last.end = t.offset;

-			

-			stack.removeLast();

-

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

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

-		  

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

-			// Do nothing

-

-		} else {

-		  //FIXME Use switch with enums so this becomes a compile time error.

-			throw new UnimplementedError();

-		}

-	}

-

-	return stack.last;

-}

-

-_checkTagChars(_Token t, bool lenient, String templateName) {

-		if (!lenient && !_validTag.hasMatch(t.value)) {

-			throw new TemplateException(

-			  'Tag contained invalid characters in name, '

-				'allowed: 0-9, a-z, A-Z, underscore, and minus',

-				templateName, t.line, t.column);

-		}

-}

-

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

-             Delimiters delimiters) {

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

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

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

-  return ast;

-}

-

 class _Template implements Template {

  

   _Template.fromSource(String source, 

@@ -104,405 +37,3 @@
     renderer.render();

   }

 }

-

-

-class _Renderer {

-  

-	_Renderer(this._root,

-	    this._sink,

-	    this._values,

-	    List stack,

-	    this._lenient,

-	    this._htmlEscapeValues,

-	    this._partialResolver,

-	    this._templateName,

-	    this._indent,

-	    this._source,

-	    this._delimiters)

-    : _stack = new List.from(stack); 

-	

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

-      : this(partial._root,

-          renderer._sink,

-          renderer._values,

-          renderer._stack,

-          renderer._lenient,

-          renderer._htmlEscapeValues,

-          renderer._partialResolver,

-          renderer._templateName,

-          renderer._indent + indent,

-          partial.source,

-          '{{ }}');

-

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

-       : this(node,

-           sink,

-           renderer._values,

-           renderer._stack,

-           renderer._lenient,

-           renderer._htmlEscapeValues,

-           renderer._partialResolver,

-           renderer._templateName,

-           renderer._indent,

-           renderer._source,

-           '{{ }}');

-

-	  _Renderer.lambda(

-	      _Renderer renderer,

-	      _Node node,

-	      String source,

-	      String indent,

-	      StringSink sink,

-	      String delimiters)

-       : this(node,

-           sink,

-           renderer._values,

-           renderer._stack,

-           renderer._lenient,

-           renderer._htmlEscapeValues,

-           renderer._partialResolver,

-           renderer._templateName,

-           renderer._indent + indent,

-           source,

-           delimiters);

-	 

-	final _Node _root;

-  final StringSink _sink;

-  final _values;

-	final List _stack;

-	final bool _lenient;

-	final bool _htmlEscapeValues;

-	final PartialResolver _partialResolver;

-	final String _templateName;

-	final String _indent;

-	final String _source;

-

-	String _delimiters;

-	

-	void render() {

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

-	   _root.children.forEach(_renderNode);

-	  } else {

-	    _renderWithIndent();

-	  }

-	}

-	

-	void _renderWithIndent() {

-	  // Special case to make sure there is not an extra indent after the last

-	  // line in the partial file.

-	  if (_root.children.isEmpty) return;

-	  

-	  _write(_indent);

-	  

-	  for (int i = 0; i < _root.children.length - 1; i++) {

-		  _renderNode(_root.children[i]);

-	  }

-	  

-	  var node = _root.children.last;

-	  if (node.type != _TEXT) {

-	    _renderNode(node);

-	  } else {

-	    _renderText(node, lastNode: true);

-	  }

-	}

-	

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

-

-	_renderNode(_Node node) {

-		switch (node.type) {

-			case _TEXT:

-				_renderText(node);

-				break;

-			case _VARIABLE:

-				_renderVariable(node);

-				break;

-			case _UNESC_VARIABLE:

-				_renderVariable(node, escape: false);

-				break;

-			case _OPEN_SECTION:

-				_renderSection(node);

-				break;

-			case _OPEN_INV_SECTION:

-				_renderInvSection(node);

-				break;

-			case _PARTIAL:

-			  _renderPartial(node);

-			  break;

-			case _COMMENT:

-				break; // Do nothing.

-			case _CHANGE_DELIMITER:

-			  _delimiters = node.value;

-			  break;

-			default:

-				throw new UnimplementedError();

-		}

-	}

-

-	_renderText(_Node node, {bool lastNode: false}) {

-	  var s = node.value;

-	  if (s == '') return;

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

-	    _write(s);

-	  } else if (lastNode && s.runes.last == _NEWLINE) {

-	    s = s.substring(0, s.length - 1);

-	    _write(s.replaceAll('\n', '\n$_indent'));

-	    _write('\n');

-	  } else {

-	    _write(s.replaceAll('\n', '\n$_indent'));

-	  }

-	}

-

-	// Walks up the stack looking for the variable.

-	// Handles dotted names of the form "a.b.c".

-	_resolveValue(String name) {

-		if (name == '.') {

-			return _stack.last;

-		}

-		var parts = name.split('.');

-		var object = _noSuchProperty;

-		for (var o in _stack.reversed) {

-			object = _getNamedProperty(o, parts[0]);

-			if (object != _noSuchProperty) {

-				break;

-			}

-		}

-		for (int i = 1; i < parts.length; i++) {

-			if (object == null || object == _noSuchProperty) {

-				return _noSuchProperty;

-			}

-			object = _getNamedProperty(object, parts[i]);

-		}

-		return object;

-	}

-	

-	// Returns the property of the given object by name. For a map,

-	// which contains the key name, this is object[name]. For other

-	// objects, this is object.name or object.name(). If no property

-	// by the given name exists, this method returns noSuchProperty.

-	_getNamedProperty(object, name) {

-	  

-		var property = null;

-		if (object is Map && object.containsKey(name))

-		  return object[name];

-		

-		if (object is List && _integerTag.hasMatch(name))

-		  return object[int.parse(name)];

-		

-		if (_lenient && !_validTag.hasMatch(name))

-			return _noSuchProperty;

-		

-		var instance = reflect(object);

-		var field = instance.type.instanceMembers[new Symbol(name)];

-		if (field == null) return _noSuchProperty;

-		

-		var invocation = null;

-		if ((field is VariableMirror) || ((field is MethodMirror) && (field.isGetter))) {

-			invocation = instance.getField(field.simpleName);

-		} else if ((field is MethodMirror) && (field.parameters.length == 0)) {

-			invocation = instance.invoke(field.simpleName, []);

-		}

-		if (invocation == null) {

-			return _noSuchProperty;

-		}

-		return invocation.reflectee;

-	}

-

-	_renderVariable(_Node node, {bool escape : true}) {

-		var value = _resolveValue(node.value);

-		

-		if (value is Function) {

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

-		  value = value(context);

-		  context.close();

-		}

-		

-		if (value == _noSuchProperty) {

-			if (!_lenient)

-				throw new TemplateException(

-				  'Value was missing, variable: ${node.value}',

-					_templateName, node.line, node.column);

-		} else {

-			var valueString = (value == null) ? '' : value.toString();

-			var output = !escape || !_htmlEscapeValues

-				? valueString

-				: _htmlEscape(valueString);

-			_write(output);

-		}

-	}

-

-	_renderSectionWithValue(node, value) {

-		_stack.add(value);

-		node.children.forEach(_renderNode);

-		_stack.removeLast();

-	}

-

-	String _renderSubtree(node) {

-	  var sink = new StringBuffer();

-	  var renderer = new _Renderer.subtree(this, node, sink);

-	  renderer.render();

-	  return sink.toString();

-	}

-	

-	_renderSection(_Node node) {

-		var value = _resolveValue(node.value);

-    

-		if (value == null) {

-			// Do nothing.

-		

-		} else if (value is Iterable) {

-			value.forEach((v) => _renderSectionWithValue(node, v));

-		

-		} else if (value is Map) {

-			_renderSectionWithValue(node, value);

-		

-		} else if (value == true) {

-			_renderSectionWithValue(node, value);

-		

-		} else if (value == false) {

-			// Do nothing.

-		

-		} else if (value == _noSuchProperty) {

-			if (!_lenient)

-				throw new TemplateException(

-				  'Value was missing, section: ${node.value}',

-					_templateName, node.line, node.column);

-		

-		} else if (value is Function) {

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

-      var output = value(context);

-      context.close();        

-      _write(output);

-      

-		} else {

-			throw new TemplateException(

-			  'Invalid value type for section, '

-				'section: ${node.value}, '

-        'type: ${value.runtimeType}',

-				_templateName, node.line, node.column);

-		}

-	}

-

-	_renderInvSection(node) {

-		var value = _resolveValue(node.value);

-    

-		if (value == null) {

-			_renderSectionWithValue(node, null);

-		

-		} else if ((value is Iterable && value.isEmpty) || value == false) {

-			_renderSectionWithValue(node, value);

-		

-		} else if (value == true || value is Map || value is Iterable) {

-			// Do nothing.

-		

-		} else if (value == _noSuchProperty) {

-			if (_lenient) {

-				_renderSectionWithValue(node, null);

-			} else {

-				throw new TemplateException(

-				    'Value was missing, inverse-section: ${node.value}',

-				    _templateName, node.line, node.column);

-			}

-    

-		} else if (value is Function) {

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

-      var output = value(context);

-      context.close();        

-

-      //FIXME Poos. I have no idea what this really is for ?????

-      if (output == false) {

-        // FIXME not sure what to output here, result of function or template 

-        // output?

-        _write(output);

-      }

-

-		} else {

-			throw new TemplateException(

-			  'Invalid value type for inverse section, '

-				'section: ${node.value}, '

-				'type: ${value.runtimeType}, ',

-				_templateName, node.line, node.column);

-		}

-	}

-

-  _renderPartial(_Node node) {

-    var partialName = node.value;

-    _Template template = _partialResolver == null

-        ? null

-        : _partialResolver(partialName);

-    if (template != null) {

-      var renderer = new _Renderer.partial(this, template, node.indent);

-      renderer.render();      

-    } else if (_lenient) {

-      // do nothing

-    } else {

-      throw new TemplateException(

-          'Partial not found: $partialName',

-          _templateName, node.line, node.column);

-    }

-  }

-

-  static const Map<String,String> _htmlEscapeMap = const {

-    _AMP: '&amp;',

-    _LT: '&lt;',

-    _GT: '&gt;',

-    _QUOTE: '&quot;',

-    _APOS: '&#x27;',

-    _FORWARD_SLASH: '&#x2F;' 

-  };

-  

-	String _htmlEscape(String s) {

-	  

-		var buffer = new StringBuffer();

-		int startIndex = 0;

-		int i = 0;

-		for (int c in s.runes) {

-			if (c == _AMP

-					|| c == _LT

-					|| c == _GT

-					|| c == _QUOTE

-					|| c == _APOS

-					|| c == _FORWARD_SLASH) {

-				buffer.write(s.substring(startIndex, i));

-				buffer.write(_htmlEscapeMap[c]);

-				startIndex = i + 1;

-			}

-			i++;

-		}

-		buffer.write(s.substring(startIndex));

-		return buffer.toString();

-	}

-}

-

-_visit(_Node root, visitor(_Node n)) {

-	var _stack = new List<_Node>()..add(root);

-	while (!_stack.isEmpty) {

-		var node = _stack.removeLast();

-		_stack.addAll(node.children);

-		visitor(node);

-	}

-}

-

-class _Node {

-	

-  _Node(this.type, this.value, this.line, this.column, {this.indent});

-	

-	_Node.fromToken(_Token token)

-		: type = token.type,

-			value = token.value,

-			line = token.line,

-			column = token.column,

-			indent = token.indent;

-

-	final int type;

-	final String value;

-	final int line;

-	final int column;

-	final String indent;

-	final List<_Node> children = new List<_Node>();

-	

-	 //TODO ideally these could be made final.

-	 int start;

-   int end;

-	

-	String toString() => '_Node: ${_tokenTypeString(type)}';

-}
diff --git a/lib/src/token.dart b/lib/src/token.dart
new file mode 100644
index 0000000..a435455
--- /dev/null
+++ b/lib/src/token.dart
@@ -0,0 +1,45 @@
+part of mustache;
+
+class _Token {
+  _Token(this.type, this.value, this.line, this.column, {this.indent});
+  
+  final int type;
+  final String value; 
+  final int line;
+  final int column;
+  final String indent;
+  
+  // Store offsets to extract text from source for lambdas.
+  // Only used for section, inverse section and close section tags.
+  int offset;
+  
+  toString() => "${_tokenTypeString(type)}: "
+    "\"${value.replaceAll('\n', '\\n')}\" $line:$column";
+}
+
+//FIXME use enums
+const int _TEXT = 1;
+const int _VARIABLE = 2;
+const int _PARTIAL = 3;
+const int _OPEN_SECTION = 4;
+const int _OPEN_INV_SECTION = 5;
+const int _CLOSE_SECTION = 6;
+const int _COMMENT = 7;
+const int _UNESC_VARIABLE = 8;
+const int _WHITESPACE = 9; // Should be filtered out, before returned by scan.
+const int _LINE_END = 10; // Should be filtered out, before returned by scan.
+const int _CHANGE_DELIMITER = 11;
+
+_tokenTypeString(int type) => [
+  '?', 
+  'Text',
+  'Var',
+  'Par',
+  'Open',
+  'OpenInv',
+  'Close',
+  'Comment',
+  'UnescVar',
+  'Whitespace',
+  'LineEnd',
+  'ChangeDelimiter'][type];