diff --git a/parsimony.cabal b/parsimony.cabal
--- a/parsimony.cabal
+++ b/parsimony.cabal
@@ -1,5 +1,5 @@
 name:           parsimony
-version:        1.1
+version:        1.3
 license:        BSD3
 license-file:   LICENSE
 author:         Daan Leijen <daan@cs.uu.nl>, Iavor S. Diatchki <iavor.diatchki@gmail.com>
@@ -11,7 +11,7 @@
 description:
     Parsimony is a generalized and simplified version of the
     industrial-strength parser combinator library Parsec.
-    Like Parsec, it is simple, safe, well documented, convenient, 
+    Like Parsec, it is simple, safe, well documented, convenient,
     with good error messages, and fast.  In addition, Parsimony
     adds support for working with differet types of input such as
     byte strings (for compat input representation) and
@@ -19,7 +19,7 @@
     It also supports working with text in different character
     encodings such as UTF8.
 
-cabal-version: >= 1.2
+cabal-version: >= 1.6
 build-type:     Simple
 
 library
@@ -39,7 +39,12 @@
   build-depends:
     base >= 3 && < 5,
     bytestring,
-    utf8-string
+    text
   GHC-options: -O2 -Wall
+
+source-repository head
+  type:          git
+  location:      git://github.com/yav/parsimony.git
+
 
 
diff --git a/src/Parsimony.hs b/src/Parsimony.hs
--- a/src/Parsimony.hs
+++ b/src/Parsimony.hs
@@ -42,12 +42,13 @@
   , lookAhead, anyToken
 
     -- * Errors 
-  , (<?>), unexpected, empty, parseError, labels 
+  , ParseError, errorPos, (<?>), unexpected, empty, parseError, labels 
 
     -- * Parser State
   , State(..)
   , setState, updateState, mapState
   , getInput, setInput, updateInput
+  , SourcePos(..), SourceName, Line, Column
   , getPosition, setPosition, updatePosition
 
 
@@ -59,4 +60,6 @@
 import Control.Applicative hiding(many)
 import Parsimony.Prim
 import Parsimony.Combinator
+import Parsimony.Error(ParseError, errorPos)
+import Parsimony.Pos(SourcePos(..), SourceName, Line, Column)
 
diff --git a/src/Parsimony/Char.hs b/src/Parsimony/Char.hs
--- a/src/Parsimony/Char.hs
+++ b/src/Parsimony/Char.hs
@@ -39,8 +39,10 @@
 spaces             :: Stream s Char => Parser s ()
 spaces              = skipMany space        <?> "white space"
 
-space, newline, tab :: Stream s Char => Parser s Char
+space              :: Stream s Char => Parser s Char
 space               = satisfy (isSpace)     <?> "space"
+
+newline, tab       :: Stream s Char => Parser s ()
 newline             = char '\n'             <?> "new-line"
 tab                 = char '\t'             <?> "tab"
 
@@ -54,20 +56,21 @@
 hexDigit            = satisfy (isHexDigit)  <?> "hexadecimal digit"
 octDigit            = satisfy (isOctDigit)  <?> "octal digit"
 
-char               :: Stream s Char => Char -> Parser s Char
-char c              = satisfy (==c)  <?> show [c]
+char               :: Stream s Char => Char -> Parser s ()
+char c              = (satisfy (==c) >> return ())  <?> show [c]
 
 anyChar            :: Stream s Char => Parser s Char
 anyChar             = anyToken <?> "a character"
 
 satisfy            :: Stream s Char => (Char -> Bool) -> Parser s Char
-satisfy f           = try $ anyChar >>= \c ->
+satisfy f           = (try $ anyChar >>= \c ->
                               if f c then return c
-                                     else unexpected (show c)
+                                     else unexpected (show c))
+                        <?> ""
 
-string             :: Stream s Char => String -> Parser s String
-string []           = return []
-string s@(c:cs)     = try (char c) >> match show cs anyChar >> return s
+string             :: Stream s Char => String -> Parser s ()
+string []           = return ()
+string (c:cs)       = try (char c) >> match show cs anyChar
 
 
 
diff --git a/src/Parsimony/IO.hs b/src/Parsimony/IO.hs
--- a/src/Parsimony/IO.hs
+++ b/src/Parsimony/IO.hs
@@ -12,102 +12,79 @@
 -----------------------------------------------------------------------------
 
 module Parsimony.IO
-  ( parseFileASCII
-  , parseFileUTF8
-  , parseLargeFileASCII
-  , parseLargeFileUTF8
+  ( parseFile
+  , parseLargeFile
+  , parseBinaryFile
+  , parseLargeBinaryFile
 
-  , uparseFileASCII
-  , uparseFileUTF8
-  , uparseLargeFileASCII
-  , uparseLargeFileUTF8
+  , uparseFile
+  , uparseLargeFile
+  , uparseBinaryFile
+  , uparseLargeBinaryFile
   ) where
 
 import Parsimony.Prim
 import Parsimony.Error
-import Parsimony.Stream
 import Parsimony.Combinator
 import Parsimony.UserState
 
 import qualified Data.ByteString as Strict
 import qualified Data.ByteString.Lazy as Lazy
+import qualified Data.Text as T
+import qualified Data.Text.IO as T
+import qualified Data.Text.Lazy as LT
+import qualified Data.Text.Lazy.IO as LT
 
--- | Parse a file containing ASCII encoded characters.
+-- | Parse a text file in one go.
 -- This functions loads the whole file in memory.
-parseFileASCII :: FilePath
-               -> Parser (ASCII Strict.ByteString) a
-               -> IO (Either ParseError a)
-parseFileASCII f p =
-  do bytes <- Strict.readFile f
-     return $ parseSource p f $ ascii bytes
+parseFile :: FilePath -> Parser T.Text a -> IO (Either ParseError a)
+parseFile f p = parseSource p f `fmap` T.readFile f
 
--- | Parse a file containing UTF8 encoded characters.
--- This functions loads the whole file in memory.
-parseFileUTF8 :: FilePath
-              -> Parser (UTF8 Strict.ByteString) a
-              -> IO (Either ParseError a)
-parseFileUTF8 f p =
-  do bytes <- Strict.readFile f
-     return $ parseSource p f $ utf8 bytes
-      
--- | Parse a file containing ASCII encoded characters.
+-- | Parse a text file in chunks.
 -- This functions loads the file in chunks.
-parseLargeFileASCII :: FilePath
-                    -> Parser (ASCII Lazy.ByteString) a
-                    -> IO (Either ParseError a)
-parseLargeFileASCII f p =
-  do bytes <- Lazy.readFile f
-     return $ parseSource p f $ ascii bytes
+parseLargeFile :: FilePath -> Parser LT.Text a -> IO (Either ParseError a)
+parseLargeFile f p = parseSource p f `fmap` LT.readFile f
 
--- | Parse a file containing UTF8 encoded characters.
+-- | Parse a binary file in one go.
+-- This functions loads the whole file in memory.
+parseBinaryFile :: FilePath -> Parser Strict.ByteString a ->
+                                                IO (Either ParseError a)
+parseBinaryFile f p = parseSource p f `fmap` Strict.readFile f
+
+-- | Parse a text file in chunks.
 -- This functions loads the file in chunks.
-parseLargeFileUTF8 :: FilePath
-                   -> Parser (UTF8 Lazy.ByteString) a
-                   -> IO (Either ParseError a)
-parseLargeFileUTF8 f p =
-  do bytes <- Lazy.readFile f
-     return $ parseSource p f $ utf8 bytes
+parseLargeBinaryFile :: FilePath -> Parser Lazy.ByteString a ->
+                                                    IO (Either ParseError a)
+parseLargeBinaryFile f p = parseSource p f `fmap` Lazy.readFile f
 
+
 -- With user state -------------------------------------------------------------
 
--- | Parse a file containing ASCII encoded characters,
--- using a parser with custom user state.
--- This functions loads the whole file in memory.
-uparseFileASCII :: FilePath
-               -> ParserU u (ASCII Strict.ByteString) a
-               -> u -> IO (Either ParseError a)
-uparseFileASCII f p u =
-  do bytes <- Strict.readFile f
-     return $ uparseSource p u f $ ascii bytes
 
--- | Parse a file containing UTF8 encoded characters,
--- using a parser with custom user state.
+
+-- | Parse a text file in one go, using user state.
 -- This functions loads the whole file in memory.
-uparseFileUTF8 :: FilePath
-              -> ParserU u (UTF8 Strict.ByteString) a
-              -> u -> IO (Either ParseError a)
-uparseFileUTF8 f p u =
-  do bytes <- Strict.readFile f
-     return $ uparseSource p u f $ utf8 bytes
-      
--- | Parse a file containing ASCII encoded characters,
--- using a parser with custom user state.
+uparseFile :: FilePath -> ParserU u T.Text a -> u -> IO (Either ParseError a)
+uparseFile f p u = uparseSource p u f `fmap` T.readFile f
+
+-- | Parse a text file in chunks, using user state.
 -- This functions loads the file in chunks.
-uparseLargeFileASCII :: FilePath
-                    -> ParserU u (ASCII Lazy.ByteString) a
-                    -> u -> IO (Either ParseError a)
-uparseLargeFileASCII f p u =
-  do bytes <- Lazy.readFile f
-     return $ uparseSource p u f $ ascii bytes
+uparseLargeFile :: FilePath -> ParserU u LT.Text a ->
+                                            u -> IO (Either ParseError a)
+uparseLargeFile f p u = uparseSource p u f `fmap` LT.readFile f
 
--- | Parse a file containing UTF8 encoded characters,
--- using a parser with custom user state.
+-- | Parse a binary file in one go, using user state.
+-- This functions loads the whole file in memory.
+uparseBinaryFile :: FilePath -> ParserU u Strict.ByteString a ->
+                                             u -> IO (Either ParseError a)
+uparseBinaryFile f p u = uparseSource p u f `fmap` Strict.readFile f
+
+-- | Parse a text file in chunks, using user state.
 -- This functions loads the file in chunks.
-uparseLargeFileUTF8 :: FilePath
-                   -> ParserU u (UTF8 Lazy.ByteString) a
-                   -> u -> IO (Either ParseError a)
-uparseLargeFileUTF8 f p u =
-  do bytes <- Lazy.readFile f
-     return $ uparseSource p u f $ utf8 bytes
- 
- 
+uparseLargeBinaryFile :: FilePath -> ParserU u Lazy.ByteString a ->
+                                             u -> IO (Either ParseError a)
+uparseLargeBinaryFile f p u = uparseSource p u f `fmap` Lazy.readFile f
+
+
+
+
diff --git a/src/Parsimony/Prim.hs b/src/Parsimony/Prim.hs
--- a/src/Parsimony/Prim.hs
+++ b/src/Parsimony/Prim.hs
@@ -134,7 +134,8 @@
 labels             :: Parser t a -> [String] -> Parser t a
 labels p msgs0      = P $ \s ->
   case unP p s of
-    R c r -> R c (addErr r)
+    R False r -> R False (addErr r)
+    other     -> other
 
   where setExpectErrors err []         = setErrorMessage (Expect "") err
         setExpectErrors err [msg]      = setErrorMessage (Expect msg) err
@@ -272,7 +273,7 @@
 crash :: String -> a
 crash f = error $ f ++ " applied to a parser that accepts the empty string."
 
--- Instances -------------------------------------------------------------------
+-- Instances -----------------------------------------------------------------
 
 instance Functor (Parser t) where
   fmap = liftM
@@ -303,9 +304,12 @@
     -- because then we can quickly move to the second branch, without
     -- having to perform any actual parsing.
     case unP p1 s of
-      R False (Error _) -> unP p2 s
+      R False (Error e) ->
+        case unP p2 s of
+          R c r -> R c $ case r of
+                           Error e2 -> Error (mergeError e e2)
+                           _        -> r
       other             -> other
-
 
 instance MonadPlus (Parser t) where
   mzero   = empty
diff --git a/src/Parsimony/Stream.hs b/src/Parsimony/Stream.hs
--- a/src/Parsimony/Stream.hs
+++ b/src/Parsimony/Stream.hs
@@ -17,10 +17,7 @@
 
 
 
-module Parsimony.Stream
-  ( Token(..), Stream(..)
-  , ASCII, UTF8, ascii, utf8
-  ) where
+module Parsimony.Stream (Token(..), Stream(..)) where
 
 import Parsimony.Prim
 import Parsimony.Pos
@@ -28,8 +25,8 @@
 
 import qualified Data.ByteString as Strict (ByteString,uncons)
 import qualified Data.ByteString.Lazy as Lazy (ByteString,uncons)
-import Data.String.UTF8 (UTF8,UTF8Bytes,fromRep,replacement_char)
-import qualified Data.String.UTF8 as UTF8 (uncons)
+import qualified Data.Text as T
+import qualified Data.Text.Lazy as LT
 import Data.Word (Word8)
 import Numeric (showHex)
 
@@ -83,45 +80,9 @@
 instance Stream Lazy.ByteString Word8 where
   getToken = genToken Lazy.uncons
 
--- Character encodings ---------------------------------------------------------
-
-
--- | The type of ASCII encoded content.
-newtype ASCII content = ASCII content
-
--- | Specify ASCII encoding for some content.
-ascii :: content -> ASCII content
-ascii = ASCII
-
--- | Specify UTF8 encoding for some content.
-utf8 :: content -> UTF8 content
-utf8 = fromRep
-
-instance Stream a Word8 => Stream (ASCII a) Char where
-  getToken (State (ASCII buf) p) =
-    case getToken (State buf p) of
-      Error err           -> Error err
-      Ok w (State b1 p1)  -> Ok (toEnum (fromEnum w)) (State (ASCII b1) p1)
-
-
-instance Stream (UTF8 [Word8]) Char where
-  getToken = genTokenChar
-
-instance Stream (UTF8 Strict.ByteString) Char where
-  getToken = genTokenChar
-
-instance Stream (UTF8 Lazy.ByteString) Char where
-  getToken = genTokenChar
-
-
-{-# INLINE genTokenChar #-}
-genTokenChar :: UTF8Bytes stream ix => PrimParser (UTF8 stream) Char
-genTokenChar (State i p) =
-    case UTF8.uncons i of
-      Just (a,i1)
-        | a /= replacement_char -> Ok a (State i1 (updatePos a p))
-        | otherwise -> Error $ newErrorMessage
-                              (Message "invalid UTF8 character") p
-      Nothing -> eof_err p
+instance Stream T.Text Char where
+  getToken = genToken T.uncons
 
+instance Stream LT.Text Char where
+  getToken = genToken LT.uncons
 
