diff --git a/Text/Trifecta/Diagnostic.hs b/Text/Trifecta/Diagnostic.hs
--- a/Text/Trifecta/Diagnostic.hs
+++ b/Text/Trifecta/Diagnostic.hs
@@ -1,6 +1,7 @@
 module Text.Trifecta.Diagnostic 
   ( Diagnostic(..)
   , tellDiagnostic
+  , MonadDiagnostic(..)
   , DiagnosticLevel(..)
   , Renderable(..)
   , Source
@@ -11,5 +12,6 @@
   ) where
 
 import Text.Trifecta.Diagnostic.Prim
+import Text.Trifecta.Diagnostic.Class
 import Text.Trifecta.Diagnostic.Level
 import Text.Trifecta.Diagnostic.Rendering
diff --git a/Text/Trifecta/Diagnostic/Class.hs b/Text/Trifecta/Diagnostic/Class.hs
new file mode 100644
--- /dev/null
+++ b/Text/Trifecta/Diagnostic/Class.hs
@@ -0,0 +1,33 @@
+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies, FlexibleContexts, UndecidableInstances #-}
+module Text.Trifecta.Diagnostic.Class
+  ( MonadDiagnostic(..)
+  ) where
+
+import Control.Monad.Trans.Class
+import Control.Monad.Trans.State.Lazy as Lazy
+import Control.Monad.Trans.State.Strict as Strict
+import Text.Trifecta.Diagnostic.Prim
+
+class Monad m => MonadDiagnostic e m | m -> e where
+  record  :: Diagnostic e -> m a
+  fatal   :: e -> m a -- consuming error
+  err     :: e -> m a -- non-consuming error
+  warn    :: e -> m ()
+  note    :: e -> m ()
+  verbose :: Int -> e -> m ()
+
+instance MonadDiagnostic e m => MonadDiagnostic e (Lazy.StateT s m) where
+  record    = lift . record
+  fatal     = lift . fatal
+  err       = lift . err
+  warn      = lift . warn
+  note      = lift . note
+  verbose n = lift . verbose n
+
+instance MonadDiagnostic e m => MonadDiagnostic e (Strict.StateT s m) where
+  record    = lift . record
+  fatal     = lift . fatal
+  err       = lift . err
+  warn      = lift . warn
+  note      = lift . note
+  verbose n = lift . verbose n
diff --git a/Text/Trifecta/Parser.hs b/Text/Trifecta/Parser.hs
--- a/Text/Trifecta/Parser.hs
+++ b/Text/Trifecta/Parser.hs
@@ -5,6 +5,11 @@
   , module Text.Trifecta.Parser.Combinators
   , module Text.Trifecta.Parser.Token
   , module Text.Trifecta.Parser.Result
+  -- * traditional numeric literals that would be in Token
+  , decimal
+  , hexadecimal
+  , octal
+  -- * expressive diagnostics
   , caret
   , careted
   , span
@@ -16,6 +21,7 @@
 import Text.Trifecta.Parser.Class
 import Text.Trifecta.Parser.Char
 import Text.Trifecta.Parser.Combinators
+import Text.Trifecta.Parser.Literals
 import Text.Trifecta.Parser.Token
 import Text.Trifecta.Parser.Result
 
diff --git a/Text/Trifecta/Parser/Literals.hs b/Text/Trifecta/Parser/Literals.hs
new file mode 100644
--- /dev/null
+++ b/Text/Trifecta/Parser/Literals.hs
@@ -0,0 +1,212 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Text.Trifecta.Parser.Literals
+-- Copyright   :  (c) Edward Kmett 2011,
+--                (c) Daan Leijen 1999-2001
+-- License     :  BSD3
+-- 
+-- Maintainer  :  ekmett@gmail.com
+-- Stability   :  provisional
+-- Portability :  non-portable
+-- 
+-----------------------------------------------------------------------------
+module Text.Trifecta.Parser.Literals
+  ( charLiteral'
+  , stringLiteral'
+  , natural'
+  , integer'
+  , double'
+  , naturalOrDouble'
+  , decimal
+  , hexadecimal
+  , octal
+  ) where
+
+import Data.Char (digitToInt)
+import Control.Applicative
+import Text.Trifecta.Parser.Class
+import Text.Trifecta.Parser.Char
+import Text.Trifecta.Parser.Combinators
+
+-- | This parser parses a single literal character. Returns the
+-- literal character value. This parsers deals correctly with escape
+-- sequences. The literal character is parsed according to the grammar
+-- rules defined in the Haskell report (which matches most programming
+-- languages quite closely). 
+--
+-- This parser does NOT swallow trailing whitespace. 
+charLiteral' :: MonadParser m => m Char
+charLiteral' = between (char '\'') (char '\'' <?> "end of character") characterChar
+          <?> "character" 
+
+characterChar, charEscape, charLetter :: MonadParser m => m Char
+characterChar = charLetter <|> charEscape
+            <?> "literal character"
+charEscape = char '\\' *> escapeCode
+charLetter = satisfy (\c -> (c /= '\'') && (c /= '\\') && (c > '\026'))
+
+-- | This parser parses a literal string. Returns the literal
+-- string value. This parsers deals correctly with escape sequences and
+-- gaps. The literal string is parsed according to the grammar rules
+-- defined in the Haskell report (which matches most programming
+-- languages quite closely). 
+--
+-- This parser does NOT swallow trailing whitespace
+stringLiteral' :: MonadParser m => m String
+stringLiteral' = lit where
+  lit = foldr (maybe id (:)) "" <$> between (char '"') (char '"' <?> "end of string") (many stringChar) 
+    <?> "literal string"
+  stringChar = Just <$> stringLetter 
+           <|> stringEscape 
+       <?> "string character"
+  stringLetter    = satisfy (\c -> (c /= '"') && (c /= '\\') && (c > '\026'))
+
+  stringEscape = char '\\' *> esc where
+    esc = Nothing <$ escapeGap 
+      <|> Nothing <$ escapeEmpty 
+      <|> Just <$> escapeCode
+  escapeEmpty = char '&'
+  escapeGap = do skipSome space
+                 char '\\' <?> "end of string gap"
+
+escapeCode :: MonadParser m => m Char
+escapeCode = (charEsc <|> charNum <|> charAscii <|> charControl) <?> "escape code"
+  where 
+  charControl = (\c -> toEnum (fromEnum c - fromEnum 'A')) <$> (char '^' *> upper)
+  charNum     = toEnum . fromInteger <$> num where
+    num = decimal 
+      <|> (char 'o' *> number 8 octDigit)
+      <|> (char 'x' *> number 16 hexDigit)
+  charEsc = choice $ parseEsc <$> escMap
+  parseEsc (c,code) = code <$ char c
+  escMap = zip ("abfnrtv\\\"\'") ("\a\b\f\n\r\t\v\\\"\'")
+  charAscii = choice $ parseAscii <$> asciiMap
+  parseAscii (asc,code) = try $ code <$ string asc
+  asciiMap = zip (ascii3codes ++ ascii2codes) (ascii3 ++ ascii2)
+  ascii2codes, ascii3codes :: [String]
+  ascii2codes = [ "BS","HT","LF","VT","FF","CR","SO"
+                , "SI","EM","FS","GS","RS","US","SP"]
+  ascii3codes = ["NUL","SOH","STX","ETX","EOT","ENQ","ACK"
+                ,"BEL","DLE","DC1","DC2","DC3","DC4","NAK"
+                ,"SYN","ETB","CAN","SUB","ESC","DEL"]
+  ascii2, ascii3 :: [Char]
+  ascii2 = ['\BS','\HT','\LF','\VT','\FF','\CR','\SO','\SI'
+           ,'\EM','\FS','\GS','\RS','\US','\SP']
+  ascii3 = ['\NUL','\SOH','\STX','\ETX','\EOT','\ENQ','\ACK'
+           ,'\BEL','\DLE','\DC1','\DC2','\DC3','\DC4','\NAK'
+           ,'\SYN','\ETB','\CAN','\SUB','\ESC','\DEL']
+  
+
+-- | This lexeme parser parses a natural number (a positive whole
+-- number). Returns the value of the number. The number can be
+-- specified in 'decimal', 'hexadecimal' or
+-- 'octal'. The number is parsed according to the grammar
+-- rules in the Haskell report. 
+--
+-- This parser does NOT swallow trailing whitespace. 
+natural' :: MonadParser m => m Integer
+natural' = nat <?> "natural"
+
+number :: MonadParser m => Integer -> m Char -> m Integer
+number base baseDigit = do
+  digits <- some baseDigit
+  return $! foldl (\x d -> base*x + toInteger (digitToInt d)) 0 digits
+
+-- | This lexeme parser parses an integer (a whole number). This parser
+-- is like 'natural' except that it can be prefixed with
+-- sign (i.e. \'-\' or \'+\'). Returns the value of the number. The
+-- number can be specified in 'decimal', 'hexadecimal'
+-- or 'octal'. The number is parsed according
+-- to the grammar rules in the Haskell report. 
+--
+-- This parser does NOT swallow trailing whitespace. 
+--
+-- Also, unlike the 'integer' parser, this parser does not admit spaces
+-- between the sign and the number.
+        
+integer' :: MonadParser m => m Integer
+integer' = int <?> "integer"
+
+sign :: MonadParser m => m (Integer -> Integer)
+sign = negate <$ char '-'
+   <|> id <$ char '+'
+   <|> pure id
+
+int :: MonadParser m => m Integer
+int = {-lexeme-} sign <*> nat
+nat, zeroNumber :: MonadParser m => m Integer
+nat = zeroNumber <|> decimal
+zeroNumber = char '0' *> (hexadecimal <|> octal <|> decimal <|> return 0) <?> ""
+
+-- | This parser parses a floating point value. Returns the value
+-- of the number. The number is parsed according to the grammar rules
+-- defined in the Haskell report. 
+--
+-- This parser does NOT swallow trailing whitespace. 
+
+double' :: MonadParser m => m Double
+double' = floating <?> "double"
+
+floating :: MonadParser m => m Double
+floating = decimal >>= fractExponent
+
+fractExponent :: MonadParser m => Integer -> m Double
+fractExponent n = (\fract expo -> (fromInteger n + fract) * expo) <$> fraction <*> option 1.0 exponent'
+              <|> (fromInteger n *) <$> exponent' where
+  fraction = foldr op 0.0 <$> (char '.' *> (some digit <?> "fraction"))
+  op d f = (f + fromIntegral (digitToInt d))/10.0
+  exponent' = do
+       _ <- oneOf "eE"
+       f <- sign
+       e <- decimal <?> "exponent"
+       return (power (f e))
+    <?> "exponent"
+  power e  
+    | e < 0     = 1.0/power(-e)
+    | otherwise = fromInteger (10^e)
+
+-- | This parser parses either 'natural' or a 'float'.
+-- Returns the value of the number. This parsers deals with
+-- any overlap in the grammar rules for naturals and floats. The number
+-- is parsed according to the grammar rules defined in the Haskell report. 
+--
+-- This parser does NOT swallow trailing whitespace. 
+
+naturalOrDouble' :: MonadParser m => m (Either Integer Double)
+naturalOrDouble' = natDouble <?> "number"
+
+natDouble, zeroNumFloat, decimalFloat :: MonadParser m => m (Either Integer Double)
+natDouble 
+    = char '0' *> zeroNumFloat
+  <|> decimalFloat
+zeroNumFloat
+    = Left <$> (hexadecimal <|> octal)
+  <|> decimalFloat
+  <|> fractFloat 0
+  <|> return (Left 0)
+decimalFloat = do 
+  n <- decimal
+  option (Left n) (fractFloat n)
+
+fractFloat :: MonadParser m => Integer -> m (Either Integer Double)
+fractFloat n = Right <$> fractExponent n
+
+-- | Parses a positive whole number in the decimal system. Returns the
+-- value of the number. 
+
+decimal :: MonadParser m => m Integer
+decimal = number 10 digit
+
+-- | Parses a positive whole number in the hexadecimal system. The number
+-- should be prefixed with \"0x\" or \"0X\". Returns the value of the
+-- number. 
+
+hexadecimal :: MonadParser m => m Integer
+hexadecimal = oneOf "xX" *> number 16 hexDigit
+
+-- | Parses a positive whole number in the octal system. The number
+-- should be prefixed with \"0o\" or \"0O\". Returns the value of the
+-- number. 
+
+octal :: MonadParser m => m Integer
+octal = oneOf "oO" *> number 8 octDigit
diff --git a/Text/Trifecta/Parser/Token/Combinators.hs b/Text/Trifecta/Parser/Token/Combinators.hs
--- a/Text/Trifecta/Parser/Token/Combinators.hs
+++ b/Text/Trifecta/Parser/Token/Combinators.hs
@@ -17,9 +17,6 @@
   , integer
   , double
   , naturalOrDouble
-  , decimal
-  , hexadecimal
-  , octal
   , symbol
   , symbolic
   , parens
@@ -36,11 +33,11 @@
   , commaSep1
   ) where
 
-import Data.Char (digitToInt)
 import Data.ByteString as Strict hiding (map, zip, foldl, foldr)
 import Control.Applicative
 import Text.Trifecta.Parser.Class
 import Text.Trifecta.Parser.Char
+import Text.Trifecta.Parser.Literals
 import Text.Trifecta.Parser.Combinators
 import Text.Trifecta.Parser.Token.Class
 
@@ -50,14 +47,7 @@
 -- rules defined in the Haskell report (which matches most programming
 -- languages quite closely). 
 charLiteral :: MonadTokenParser m => m Char
-charLiteral = lexeme (between (char '\'') (char '\'' <?> "end of character") characterChar)
-          <?> "character" 
-
-characterChar, charEscape, charLetter :: MonadTokenParser m => m Char
-characterChar = charLetter <|> charEscape
-            <?> "literal character"
-charEscape = char '\\' *> escapeCode
-charLetter = satisfy (\c -> (c /= '\'') && (c /= '\\') && (c > '\026'))
+charLiteral = lexeme charLiteral'
 
 -- | This lexeme parser parses a literal string. Returns the literal
 -- string value. This parsers deals correctly with escape sequences and
@@ -66,49 +56,7 @@
 -- languages quite closely). 
 
 stringLiteral :: MonadTokenParser m => m String
-stringLiteral = lexeme lit where
-  lit = foldr (maybe id (:)) "" <$> between (char '"') (char '"' <?> "end of string") (many stringChar) 
-    <?> "literal string"
-  stringChar = Just <$> stringLetter 
-           <|> stringEscape 
-       <?> "string character"
-  stringLetter    = satisfy (\c -> (c /= '"') && (c /= '\\') && (c > '\026'))
-
-  stringEscape = char '\\' *> esc where
-    esc = Nothing <$ escapeGap 
-      <|> Nothing <$ escapeEmpty 
-      <|> Just <$> escapeCode
-  escapeEmpty = char '&'
-  escapeGap = do skipSome space
-                 char '\\' <?> "end of string gap"
-
-escapeCode :: MonadTokenParser m => m Char
-escapeCode = (charEsc <|> charNum <|> charAscii <|> charControl) <?> "escape code"
-  where 
-  charControl = (\c -> toEnum (fromEnum c - fromEnum 'A')) <$> (char '^' *> upper)
-  charNum     = toEnum . fromInteger <$> num where
-    num = decimal 
-      <|> (char 'o' *> number 8 octDigit)
-      <|> (char 'x' *> number 16 hexDigit)
-  charEsc = choice $ parseEsc <$> escMap
-  parseEsc (c,code) = code <$ char c
-  escMap = zip ("abfnrtv\\\"\'") ("\a\b\f\n\r\t\v\\\"\'")
-  charAscii = choice $ parseAscii <$> asciiMap
-  parseAscii (asc,code) = try $ code <$ string asc
-  asciiMap = zip (ascii3codes ++ ascii2codes) (ascii3 ++ ascii2)
-  ascii2codes, ascii3codes :: [String]
-  ascii2codes = [ "BS","HT","LF","VT","FF","CR","SO"
-                , "SI","EM","FS","GS","RS","US","SP"]
-  ascii3codes = ["NUL","SOH","STX","ETX","EOT","ENQ","ACK"
-                ,"BEL","DLE","DC1","DC2","DC3","DC4","NAK"
-                ,"SYN","ETB","CAN","SUB","ESC","DEL"]
-  ascii2, ascii3 :: [Char]
-  ascii2 = ['\BS','\HT','\LF','\VT','\FF','\CR','\SO','\SI'
-           ,'\EM','\FS','\GS','\RS','\US','\SP']
-  ascii3 = ['\NUL','\SOH','\STX','\ETX','\EOT','\ENQ','\ACK'
-           ,'\BEL','\DLE','\DC1','\DC2','\DC3','\DC4','\NAK'
-           ,'\SYN','\ETB','\CAN','\SUB','\ESC','\DEL']
-  
+stringLiteral = lexeme stringLiteral'
 
 -- | This lexeme parser parses a natural number (a positive whole
 -- number). Returns the value of the number. The number can be
@@ -117,12 +65,7 @@
 -- rules in the Haskell report. 
 
 natural :: MonadTokenParser m => m Integer
-natural = lexeme nat <?> "natural"
-
-number :: MonadTokenParser m => Integer -> m Char -> m Integer
-number base baseDigit = do
-  digits <- some baseDigit
-  return $! foldl (\x d -> base*x + toInteger (digitToInt d)) 0 digits
+natural = lexeme natural'
 
 -- | This lexeme parser parses an integer (a whole number). This parser
 -- is like 'natural' except that it can be prefixed with
@@ -133,41 +76,18 @@
         
 integer :: MonadTokenParser m => m Integer
 integer = lexeme int <?> "integer"
-
-sign :: MonadTokenParser m => m (Integer -> Integer)
-sign = negate <$ char '-'
-   <|> id <$ char '+'
-   <|> pure id
-
-nat, int, zeroNumber :: MonadTokenParser m => m Integer
-nat = zeroNumber <|> decimal
-int = lexeme sign <*> nat
-zeroNumber = char '0' *> (hexadecimal <|> octal <|> decimal <|> return 0) <?> ""
+  where
+  sign = negate <$ char '-'
+    <|> id <$ char '+'
+    <|> pure id
+  int = lexeme sign <*> natural'
 
 -- | This lexeme parser parses a floating point value. Returns the value
 -- of the number. The number is parsed according to the grammar rules
 -- defined in the Haskell report. 
 
 double :: MonadTokenParser m => m Double
-double = lexeme floating <?> "double"
-
-floating :: MonadTokenParser m => m Double
-floating = decimal >>= fractExponent
-
-fractExponent :: MonadTokenParser m => Integer -> m Double
-fractExponent n = (\fract expo -> (fromInteger n + fract) * expo) <$> fraction <*> option 1.0 exponent'
-              <|> (fromInteger n *) <$> exponent' where
-  fraction = foldr op 0.0 <$> (char '.' *> (some digit <?> "fraction"))
-  op d f = (f + fromIntegral (digitToInt d))/10.0
-  exponent' = do
-       _ <- oneOf "eE"
-       f <- sign
-       e <- decimal <?> "exponent"
-       return (power (f e))
-    <?> "exponent"
-  power e  
-    | e < 0     = 1.0/power(-e)
-    | otherwise = fromInteger (10^e)
+double = lexeme double'
 
 -- | This lexeme parser parses either 'natural' or a 'float'.
 -- Returns the value of the number. This parsers deals with
@@ -175,43 +95,7 @@
 -- is parsed according to the grammar rules defined in the Haskell report. 
 
 naturalOrDouble :: MonadTokenParser m => m (Either Integer Double)
-naturalOrDouble = lexeme natDouble <?> "number"
-
-natDouble , zeroNumFloat, decimalFloat :: MonadTokenParser m => m (Either Integer Double)
-natDouble 
-    = char '0' *> zeroNumFloat
-  <|> decimalFloat
-zeroNumFloat
-    = Left <$> (hexadecimal <|> octal)
-  <|> decimalFloat
-  <|> fractFloat 0
-  <|> return (Left 0)
-decimalFloat = do 
-  n <- decimal
-  option (Left n) (fractFloat n)
-
-fractFloat :: MonadTokenParser m => Integer -> m (Either Integer Double)
-fractFloat n = Right <$> fractExponent n
-
--- | Parses a positive whole number in the decimal system. Returns the
--- value of the number. 
-
-decimal :: MonadTokenParser m => m Integer
-decimal = number 10 digit
-
--- | Parses a positive whole number in the hexadecimal system. The number
--- should be prefixed with \"0x\" or \"0X\". Returns the value of the
--- number. 
-
-hexadecimal :: MonadTokenParser m => m Integer
-hexadecimal = oneOf "xX" *> number 16 hexDigit
-
--- | Parses a positive whole number in the octal system. The number
--- should be prefixed with \"0o\" or \"0O\". Returns the value of the
--- number. 
-
-octal :: MonadTokenParser m => m Integer
-octal = oneOf "oO" *> number 8 octDigit
+naturalOrDouble = lexeme naturalOrDouble'
 
 -- | Lexeme parser @symbol s@ parses 'string' @s@ and skips
 -- trailing white space. 
@@ -230,7 +114,6 @@
 
 parens :: MonadTokenParser m => m a -> m a
 parens = between (symbolic '(') (symbolic ')')
-
 
 -- | Lexeme parser @braces p@ parses @p@ enclosed in braces (\'{\' and
 -- \'}\'), returning the value of @p@. 
diff --git a/trifecta.cabal b/trifecta.cabal
--- a/trifecta.cabal
+++ b/trifecta.cabal
@@ -1,6 +1,6 @@
 name:          trifecta
 category:      Text, Parsing, Diagnostics, Pretty Printer, Logging
-version:       0.19
+version:       0.20
 license:       BSD3
 cabal-version: >= 1.6
 license-file:  LICENSE
@@ -37,6 +37,7 @@
     Text.Trifecta.Rope.Strand
     Text.Trifecta.Diagnostic
     Text.Trifecta.Diagnostic.Prim
+    Text.Trifecta.Diagnostic.Class
     Text.Trifecta.Diagnostic.Level
     Text.Trifecta.Diagnostic.Err
     Text.Trifecta.Diagnostic.Err.State
@@ -46,13 +47,14 @@
     Text.Trifecta.Diagnostic.Rendering.Fixit
     Text.Trifecta.Diagnostic.Rendering.Span
     Text.Trifecta.Parser
-    Text.Trifecta.Parser.It
     Text.Trifecta.Parser.Char
-    Text.Trifecta.Parser.Expr
     Text.Trifecta.Parser.Class
+    Text.Trifecta.Parser.Combinators
+    Text.Trifecta.Parser.Expr
+    Text.Trifecta.Parser.It
+    Text.Trifecta.Parser.Literals
     Text.Trifecta.Parser.Prim
     Text.Trifecta.Parser.Result
-    Text.Trifecta.Parser.Combinators
     Text.Trifecta.Parser.Step
     Text.Trifecta.Parser.Token
     Text.Trifecta.Parser.Token.Class
