Improve parser._readTag()
diff --git a/lib/src/parser.dart b/lib/src/parser.dart
index 2f6a119..e59fde6 100644
--- a/lib/src/parser.dart
+++ b/lib/src/parser.dart
@@ -36,19 +36,6 @@
   static const TagType changeDelimiter = const TagType('changeDelimiter');
 }
 
-const _tagTypeMap = const {
-        '#': TagType.openSection,
-        '^': TagType.openInverseSection,
-        '/': TagType.closeSection,
-        '&': TagType.unescapedVariable,
-        '>': TagType.partial,
-        '!': TagType.comment};
-
-TagType tagTypeFromString(String s) { 
-  var type = _tagTypeMap[s];
-  if (type == null) throw new Exception('Unreachable code.');
-  return type;
-}
 
 class Parser {
   
@@ -81,6 +68,7 @@
     return t;
   }
   
+  //TODO fail on eof unless setting passed.
   //TODO use a sync* generator once landed in Dart 1.10.
   Iterable<Token> _readWhile(bool predicate(Token t)) {
     var list = <Token>[];
@@ -91,6 +79,23 @@
     return list;
   }
   
+  _checkEof() {
+    if (_peek() == null) throw 'End of file!'; //TODO error message;
+  }
+  
+  Token _expect(TokenType type) {
+    var token = _read();
+    if (token == null) throw 'End of file!'; //TODO error message.
+    if (token.type != type) throw 'boom!'; //TODO error message
+    return token;
+  }
+  
+  Token _readIf(TokenType type) {
+    var token = _peek();
+    if (token == null) throw 'End of file!'; //TODO error message.
+    return token.type == type ? _read() : null;
+  }
+  
   // Add a text node to top most section on the stack and merge consecutive
   // text nodes together.
   void _appendTextToken(Token token) {
@@ -325,43 +330,34 @@
   
   final RegExp _validIdentifier = new RegExp(r'^[0-9a-zA-Z\_\-\.]+$');
   
+  static const _tagTypeMap = const {
+          '#': TagType.openSection,
+          '^': TagType.openInverseSection,
+          '/': TagType.closeSection,
+          '&': TagType.unescapedVariable,
+          '>': TagType.partial,
+          '!': TagType.comment};
+  
   //TODO clean up EOF handling.
   Tag _readTag() {
     
-    var open = _read();
+    var open = _expect(TokenType.openDelimiter);
     
-    checkEof() {
-      if (_peek() == null) {
-        throw _error(
-            'Tag not closed before the end of the template.', open.start);
-      }
-    }
- 
-    checkEof();
-    
-    //TODO perhaps handle Eof in readif
-    //TODO _readIf()
-    if (_peek().type == TokenType.whitespace) _read();
-    
-    checkEof();
+    _readIf(TokenType.whitespace);
     
     // A sigil is the character which identifies which sort of tag it is,
     // i.e.  '#', '/', or '>'.
     // Variable tags and triple mustache tags don't have a sigil.
     TagType tagType;
+    
     if (open.value == '{{{') {
       tagType = TagType.tripleMustache;
-    } else if (_peek().type == TokenType.sigil) {
-      tagType = tagTypeFromString(_read().value);
     } else {
-      tagType = TagType.variable;
+      var sigil = _readIf(TokenType.sigil);
+      tagType = sigil == null ? TagType.variable : _tagTypeMap[sigil.value];
     }
-
-    checkEof();
       
-    if (_peek().type == TokenType.whitespace) _read();
-    
-    checkEof();
+    _readIf(TokenType.whitespace);
     
     // TODO split up names here instead of during render.
     // Also check that they are valid token types.
@@ -372,7 +368,8 @@
          .join()
          .trim();
   
-    checkEof();
+    //TODO incorporate this into _readWhile()
+    _checkEof();
     
     // Check to see if tag name is valid.
     if (tagType != TagType.comment) {    
@@ -388,7 +385,7 @@
       }    
     }
     
-    var close = _read();
+    var close = _expect(TokenType.closeDelimiter);
         
     return new Tag(tagType, name, open.start, close.end);
   }