diff --git a/Text/Parser/Char.hs b/Text/Parser/Char.hs
--- a/Text/Parser/Char.hs
+++ b/Text/Parser/Char.hs
@@ -12,7 +12,6 @@
 -- |
 -- Module      :  Text.Parser.Char
 -- Copyright   :  (c) Edward Kmett 2011
---                (c) Daan Leijen 1999-2001
 -- License     :  BSD3
 --
 -- Maintainer  :  ekmett@gmail.com
@@ -23,9 +22,9 @@
 --
 -----------------------------------------------------------------------------
 module Text.Parser.Char
-  ( CharParsing(..)
-  -- * Character parsers
-  , oneOf       -- :: CharParsing m => [Char] -> m Char
+  (
+  -- * Combinators
+    oneOf       -- :: CharParsing m => [Char] -> m Char
   , noneOf      -- :: CharParsing m => [Char] -> m Char
   , oneOfSet    -- :: CharParsing m => CharSet -> m Char
   , noneOfSet   -- :: CharParsing m => CharSet -> m Char
@@ -40,17 +39,8 @@
   , digit       -- :: CharParsing m => m Char
   , hexDigit    -- :: CharParsing m => m Char
   , octDigit    -- :: CharParsing m => m Char
-  , decimal     -- :: CharParsing m => m Integer
-  , hexadecimal -- :: CharParsing m => m Integer
-  , octal       -- :: CharParsing m => m Integer
-  -- ** Internal parsers
-  , charLiteral'
-  , characterChar
-  , stringLiteral'
-  , natural'
-  , integer'
-  , double'
-  , naturalOrDouble'
+  -- * Class
+  , CharParsing(..)
   ) where
 
 import Control.Applicative
@@ -143,20 +133,17 @@
 
 -- | Parses a letter or digit (a character between \'0\' and \'9\').
 -- Returns the parsed character.
-
 alphaNum :: CharParsing m => m Char
 alphaNum = satisfy isAlphaNum <?> "letter or digit"
 {-# INLINE alphaNum #-}
 
 -- | Parses a letter (an upper case or lower case character). Returns the
 -- parsed character.
-
 letter :: CharParsing m => m Char
 letter = satisfy isAlpha <?> "letter"
 {-# INLINE letter #-}
 
 -- | Parses a digit. Returns the parsed character.
-
 digit :: CharParsing m => m Char
 digit = satisfy isDigit <?> "digit"
 {-# INLINE digit #-}
@@ -264,188 +251,4 @@
   notChar = lift . notChar
   anyChar = lift anyChar
   string  = lift . string
-
-
--- | 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' :: CharParsing m => m Char
-charLiteral' = between (char '\'') (char '\'' <?> "end of character") characterChar
-          <?> "character"
-
-characterChar, charEscape, charLetter :: CharParsing 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' :: CharParsing m => m String
-stringLiteral' = Prelude.foldr (maybe id (:)) "" <$>
-  between (char '"') (char '"' <?> "end of string") (many stringChar) <?> 
-  "literal string" where
-  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 :: CharParsing 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 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' :: CharParsing m => m Integer
-natural' = nat <?> "natural"
-
-number :: CharParsing 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 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' :: CharParsing m => m Integer
-integer' = int <?> "integer"
-
-sign :: CharParsing m => m (Integer -> Integer)
-sign = negate <$ char '-'
-   <|> id <$ char '+'
-   <|> pure id
-
-int :: CharParsing m => m Integer
-int = {-lexeme-} sign <*> nat
-nat, zeroNumber :: CharParsing 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' :: CharParsing m => m Double
-double' = floating <?> "double"
-
-floating :: CharParsing m => m Double
-floating = decimal >>= fractExponent
-
-fractExponent :: CharParsing m => Integer -> m Double
-fractExponent n = (\fract expo -> (fromInteger n + fract) * expo) <$> fraction <*> option 1.0 exponent'
-              <|> (fromInteger n *) <$> exponent' where
-  fraction = Prelude.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 'double'.
--- 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' :: CharParsing m => m (Either Integer Double)
-naturalOrDouble' = natDouble <?> "number"
-
-natDouble, zeroNumFloat, decimalFloat :: CharParsing 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 :: CharParsing 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 :: CharParsing m => m Integer
-decimal = number 10 digit
-
--- | Parses a positive whole number in the hexadecimal system. The number
--- should be prefixed with \"x\" or \"X\". Returns the value of the
--- number.
-
-hexadecimal :: CharParsing m => m Integer
-hexadecimal = oneOf "xX" *> number 16 hexDigit
-
--- | Parses a positive whole number in the octal system. The number
--- should be prefixed with \"o\" or \"O\". Returns the value of the
--- number.
-
-octal :: CharParsing m => m Integer
-octal = oneOf "oO" *> number 8 octDigit
 
diff --git a/Text/Parser/Combinators.hs b/Text/Parser/Combinators.hs
--- a/Text/Parser/Combinators.hs
+++ b/Text/Parser/Combinators.hs
@@ -22,9 +22,9 @@
 --
 -----------------------------------------------------------------------------
 module Text.Parser.Combinators
-  ( Parsing(..)
-  -- * Alternative Parser combinators
-  , choice
+  (
+  -- * Parsing Combinators
+    choice
   , option
   , optional -- from Control.Applicative, parsec optionMaybe
   , skipOptional -- parsec optional
@@ -43,6 +43,8 @@
   , chainl1
   , chainr1
   , manyTill
+  -- * Parsing Class
+  , Parsing(..)
   ) where
 
 import Data.Traversable (sequenceA)
@@ -59,7 +61,6 @@
 import Control.Monad.Trans.Identity
 import Data.Monoid
 
-
 -- | @choice ps@ tries to apply the parsers in the list @ps@ in order,
 -- until one of them succeeds. Returns the value of the succeeding
 -- parser.
@@ -315,4 +316,3 @@
   lookAhead = IdentityT . lookAhead . runIdentityT
   unexpected = lift . unexpected
   eof = lift eof
-
diff --git a/Text/Parser/Token.hs b/Text/Parser/Token.hs
--- a/Text/Parser/Token.hs
+++ b/Text/Parser/Token.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# OPTIONS_GHC -fspec-constr -fspec-constr-count=8 #-}
 -----------------------------------------------------------------------------
 -- |
@@ -15,40 +16,53 @@
 -- > idStyle    = haskellIdentifierStyle { styleReserved = ... }
 -- > identifier = ident haskellIdentifierStyle
 -- > reserved   = reserve haskellIdentifierStyle
+--
 -----------------------------------------------------------------------------
 module Text.Parser.Token
-  ( TokenParsing(..)
-  -- * Token Parsers
-  , whiteSpace
-  , token
-  , charLiteral
-  , stringLiteral
-  , natural
-  , integer
-  , double
-  , naturalOrDouble
-  , symbol
-  , symbolic
-  , parens
-  , braces
-  , angles
-  , brackets
-  , comma
-  , colon
-  , dot
-  , semiSep
-  , semiSep1
-  , commaSep
-  , commaSep1
+  (
+  -- * Token Parsing
+    whiteSpace      -- :: TokenParsing m => m ()
+  , token           -- :: TokenParsing m => m a -> m a
+  , charLiteral     -- :: TokenParsing m => m Char
+  , stringLiteral   -- :: TokenParsing m => m String
+  , natural         -- :: TokenParsing m => m Integer
+  , integer         -- :: TokenParsing m => m Integer
+  , double          -- :: TokenParsing m => m Double
+  , naturalOrDouble -- :: TokenParsing m => m (Either Integer Double)
+  , symbol          -- :: TokenParsing m => String -> m String
+  , symbolic        -- :: TokenParsing m => Char -> m Char
+  , parens          -- :: TokenParsing m => m a -> m a
+  , braces          -- :: TokenParsing m => m a -> m a
+  , angles          -- :: TokenParsing m => m a -> m a
+  , brackets        -- :: TokenParsing m => m a -> m a
+  , comma           -- :: TokenParsing m => m Char
+  , colon           -- :: TokenParsing m => m Char
+  , dot             -- :: TokenParsing m => m Char
+  , semiSep         -- :: TokenParsing m => m a -> m [a]
+  , semiSep1        -- :: TokenParsing m => m a -> m [a]
+  , commaSep        -- :: TokenParsing m => m a -> m [a]
+  , commaSep1       -- :: TokenParsing m => m a -> m [a]
+  -- ** Token Parsing Class
+  , TokenParsing(..)
+  -- ** Token Parsing Transformers
+  , Unspaced(..)
+  , Unhighlighted(..)
+  -- ** /Non-Token/ Parsers
+  , decimal       -- :: TokenParsing m => m Integer
+  , hexadecimal   -- :: TokenParsing m => m Integer
+  , octal         -- :: TokenParsing m => m Integer
+  , characterChar -- :: TokenParsing m => m Char
+  , integer'      -- :: TokenParsing m => m Integer
   -- * Identifiers
   , IdentifierStyle(..)
-  , liftIdentifierStyle
-  , ident
-  , reserve
+  , liftIdentifierStyle -- :: (MonadTrans t, Monad m) =>
+                        --    IdentifierStyle m -> IdentifierStyle (t m)
+  , ident           -- :: TokenParsing m => IdentifierStyle m -> m String
+  , reserve         -- :: TokenParsing m => IdentifierStyle m -> String -> m ()
   ) where
 
 import Control.Applicative
-import Control.Monad (when)
+import Control.Monad (MonadPlus(..), when)
 import Control.Monad.Trans.Class
 import Control.Monad.Trans.State.Lazy as Lazy
 import Control.Monad.Trans.State.Strict as Strict
@@ -59,12 +73,15 @@
 import Control.Monad.Trans.Reader
 import Control.Monad.Trans.Identity
 import Data.Char
-import Data.HashSet as HashSet
+import qualified Data.HashSet as HashSet
+import Data.HashSet (HashSet)
+import Data.List (foldl')
 import Data.Monoid
-import Text.Parser.Combinators
 import Text.Parser.Char
+import Text.Parser.Combinators
+import Text.Parser.Token.Highlight
 
--- | Skip zero or more bytes worth of white space. More complex parsers are‗
+-- | Skip zero or more bytes worth of white space. More complex parsers are
 -- free to consider comments as white space.
 whiteSpace :: TokenParsing m => m ()
 whiteSpace = someSpace <|> return ()
@@ -83,6 +100,7 @@
 -- > mainParser  = sum <$ whiteSpace <*> many (token digit) <* eof
 token :: TokenParsing m => m a -> m a
 token p = p <* whiteSpace
+{-# INLINE token #-}
 
 -- | This token parser parses a single literal character. Returns the
 -- literal character value. This parsers deals correctly with escape
@@ -90,7 +108,10 @@
 -- rules defined in the Haskell report (which matches most programming
 -- languages quite closely).
 charLiteral :: TokenParsing m => m Char
-charLiteral = token charLiteral'
+charLiteral = token (highlight CharLiteral lit) where
+  lit = between (char '\'') (char '\'' <?> "end of character") characterChar
+    <?> "character"
+{-# INLINE charLiteral #-}
 
 -- | This token parser parses a literal string. Returns the literal
 -- string value. This parsers deals correctly with escape sequences and
@@ -99,8 +120,24 @@
 -- languages quite closely).
 
 stringLiteral :: TokenParsing m => m String
-stringLiteral = token stringLiteral'
+stringLiteral = token (highlight StringLiteral lit) where
+  lit = Prelude.foldr (maybe id (:)) ""
+    <$> between (char '"') (char '"' <?> "end of string") (many stringChar)
+    <?> "string"
+  stringChar = Just <$> stringLetter
+           <|> stringEscape
+       <?> "string character"
+  stringLetter    = satisfy (\c -> (c /= '"') && (c /= '\\') && (c > '\026'))
 
+  stringEscape = highlight EscapeCode $ char '\\' *> esc where
+    esc = Nothing <$ escapeGap
+      <|> Nothing <$ escapeEmpty
+      <|> Just <$> escapeCode
+  escapeEmpty = char '&'
+  escapeGap = do skipSome space
+                 char '\\' <?> "end of string gap"
+{-# INLINE stringLiteral #-}
+
 -- | This token parser parses a natural number (a positive whole
 -- number). Returns the value of the number. The number can be
 -- specified in 'decimal', 'hexadecimal' or
@@ -109,6 +146,7 @@
 
 natural :: TokenParsing m => m Integer
 natural = token natural'
+{-# INLINE natural #-}
 
 -- | This token parser parses an integer (a whole number). This parser
 -- is like 'natural' except that it can be prefixed with
@@ -118,19 +156,20 @@
 -- to the grammar rules in the Haskell report.
 
 integer :: TokenParsing m => m Integer
-integer = token int <?> "integer"
+integer = token (token (highlight Operator sgn <*> natural')) <?> "integer"
   where
-  sign = negate <$ char '-'
+  sgn = negate <$ char '-'
     <|> id <$ char '+'
     <|> pure id
-  int = token sign <*> natural'
+{-# INLINE integer #-}
 
 -- | This token 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 :: TokenParsing m => m Double
-double = token double'
+double = token (highlight Number floating <?> "double")
+{-# INLINE double #-}
 
 -- | This token parser parses either 'natural' or a 'float'.
 -- Returns the value of the number. This parsers deals with
@@ -138,61 +177,71 @@
 -- is parsed according to the grammar rules defined in the Haskell report.
 
 naturalOrDouble :: TokenParsing m => m (Either Integer Double)
-naturalOrDouble = token naturalOrDouble'
+naturalOrDouble = token (highlight Number natDouble <?> "number")
+{-# INLINE naturalOrDouble #-}
 
 -- | Token parser @symbol s@ parses 'string' @s@ and skips
 -- trailing white space.
 
 symbol :: TokenParsing m => String -> m String
-symbol name = token (string name)
+symbol name = token (highlight Symbol (string name))
+{-# INLINE symbol #-}
 
 -- | Token parser @symbolic s@ parses 'char' @s@ and skips
 -- trailing white space.
 
 symbolic :: TokenParsing m => Char -> m Char
-symbolic name = token (char name)
+symbolic name = token (highlight Symbol (char name))
+{-# INLINE symbolic #-}
 
 -- | Token parser @parens p@ parses @p@ enclosed in parenthesis,
 -- returning the value of @p@.
 
 parens :: TokenParsing m => m a -> m a
 parens = nesting . between (symbolic '(') (symbolic ')')
+{-# INLINE parens #-}
 
 -- | Token parser @braces p@ parses @p@ enclosed in braces (\'{\' and
 -- \'}\'), returning the value of @p@.
 
 braces :: TokenParsing m => m a -> m a
 braces = nesting . between (symbolic '{') (symbolic '}')
+{-# INLINE braces #-}
 
 -- | Token parser @angles p@ parses @p@ enclosed in angle brackets (\'\<\'
 -- and \'>\'), returning the value of @p@.
 
 angles :: TokenParsing m => m a -> m a
 angles = nesting . between (symbolic '<') (symbolic '>')
+{-# INLINE angles #-}
 
 -- | Token parser @brackets p@ parses @p@ enclosed in brackets (\'[\'
 -- and \']\'), returning the value of @p@.
 
 brackets :: TokenParsing m => m a -> m a
 brackets = nesting . between (symbolic '[') (symbolic ']')
+{-# INLINE brackets #-}
 
 -- | Token parser @comma@ parses the character \',\' and skips any
 -- trailing white space. Returns the string \",\".
 
 comma :: TokenParsing m => m Char
 comma = symbolic ','
+{-# INLINE comma #-}
 
 -- | Token parser @colon@ parses the character \':\' and skips any
 -- trailing white space. Returns the string \":\".
 
 colon :: TokenParsing m => m Char
 colon = symbolic ':'
+{-# INLINE colon #-}
 
 -- | Token parser @dot@ parses the character \'.\' and skips any
 -- trailing white space. Returns the string \".\".
 
 dot :: TokenParsing m => m Char
 dot = symbolic '.'
+{-# INLINE dot #-}
 
 -- | Token parser @semiSep p@ parses /zero/ or more occurrences of @p@
 -- separated by 'semi'. Returns a list of values returned by
@@ -200,12 +249,14 @@
 
 semiSep :: TokenParsing m => m a -> m [a]
 semiSep p = sepBy p semi
+{-# INLINE semiSep #-}
 
 -- | Token parser @semiSep1 p@ parses /one/ or more occurrences of @p@
 -- separated by 'semi'. Returns a list of values returned by @p@.
 
 semiSep1 :: TokenParsing m => m a -> m [a]
 semiSep1 p = sepBy1 p semi
+{-# INLINE semiSep1 #-}
 
 -- | Token parser @commaSep p@ parses /zero/ or more occurrences of
 -- @p@ separated by 'comma'. Returns a list of values returned
@@ -213,6 +264,7 @@
 
 commaSep :: TokenParsing m => m a -> m [a]
 commaSep p = sepBy p comma
+{-# INLINE commaSep #-}
 
 -- | Token parser @commaSep1 p@ parses /one/ or more occurrences of
 -- @p@ separated by 'comma'. Returns a list of values returned
@@ -220,6 +272,7 @@
 
 commaSep1 :: TokenParsing m => m a -> m [a]
 commaSep1 p = sepBy p comma
+{-# INLINE commaSep1 #-}
 
 class CharParsing m => TokenParsing m where
   -- | Usually, someSpace consists of /one/ or more occurrences of a 'space'.
@@ -239,53 +292,66 @@
   semi :: m Char
   semi = (satisfy (';'==) <?> ";") <* (someSpace <|> pure ())
 
+  -- | Tag a region of parsed text with a bit of semantic information.
+  -- Most parsers won't use this, but it is indispensible for highlighters.
+  highlight :: Highlight -> m a -> m a
+  highlight _ a = a
+
 instance TokenParsing m => TokenParsing (Lazy.StateT s m) where
   nesting (Lazy.StateT m) = Lazy.StateT $ nesting . m
   someSpace = lift someSpace
   semi      = lift semi
-
+  highlight h (Lazy.StateT m) = Lazy.StateT $ highlight h . m
 
 instance TokenParsing m => TokenParsing (Strict.StateT s m) where
   nesting (Strict.StateT m) = Strict.StateT $ nesting . m
   someSpace = lift someSpace
   semi      = lift semi
+  highlight h (Strict.StateT m) = Strict.StateT $ highlight h . m
 
 instance TokenParsing m => TokenParsing (ReaderT e m) where
   nesting (ReaderT m) = ReaderT $ nesting . m
   someSpace = lift someSpace
   semi      = lift semi
+  highlight h (ReaderT m) = ReaderT $ highlight h . m
 
 instance (TokenParsing m, Monoid w) => TokenParsing (Strict.WriterT w m) where
   nesting (Strict.WriterT m) = Strict.WriterT $ nesting m
   someSpace = lift someSpace
   semi      = lift semi
+  highlight h (Strict.WriterT m) = Strict.WriterT $ highlight h m
 
 instance (TokenParsing m, Monoid w) => TokenParsing (Lazy.WriterT w m) where
   nesting (Lazy.WriterT m) = Lazy.WriterT $ nesting m
   someSpace = lift someSpace
   semi      = lift semi
+  highlight h (Lazy.WriterT m) = Lazy.WriterT $ highlight h m
 
 instance (TokenParsing m, Monoid w) => TokenParsing (Lazy.RWST r w s m) where
   nesting (Lazy.RWST m) = Lazy.RWST $ \r s -> nesting (m r s)
   someSpace = lift someSpace
   semi      = lift semi
+  highlight h (Lazy.RWST m) = Lazy.RWST $ \r s -> highlight h (m r s)
 
 instance (TokenParsing m, Monoid w) => TokenParsing (Strict.RWST r w s m) where
   nesting (Strict.RWST m) = Strict.RWST $ \r s -> nesting (m r s)
   someSpace = lift someSpace
   semi      = lift semi
+  highlight h (Strict.RWST m) = Strict.RWST $ \r s -> highlight h (m r s)
 
 instance TokenParsing m => TokenParsing (IdentityT m) where
   nesting = IdentityT . nesting . runIdentityT
   someSpace = lift someSpace
   semi      = lift semi
-
+  highlight h = IdentityT . highlight h . runIdentityT
 
 data IdentifierStyle m = IdentifierStyle
   { styleName              :: String
   , styleStart             :: m Char
   , styleLetter            :: m Char
   , styleReserved          :: HashSet String
+  , styleHighlight         :: Highlight
+  , styleReservedHighlight :: Highlight
   }
 
 -- | Lift an identifier style into a monad transformer
@@ -294,16 +360,209 @@
   s { styleStart  = lift (styleStart s)
     , styleLetter = lift (styleLetter s)
     }
+{-# INLINE liftIdentifierStyle #-}
 
 -- | parse a reserved operator or identifier using a given style
 reserve :: TokenParsing m => IdentifierStyle m -> String -> m ()
 reserve s name = token $ try $ do
-   _ <- string name
+   _ <- highlight (styleReservedHighlight s) $ string name
    notFollowedBy (styleLetter s) <?> "end of " ++ show name
+{-# INLINE reserve #-}
 
 -- | parse an non-reserved identifier or symbol
 ident :: TokenParsing m => IdentifierStyle m -> m String
 ident s = token $ try $ do
-  name <- (:) <$> styleStart s <*> many (styleLetter s) <?> styleName s
-  when (member name (styleReserved s)) $ unexpected $ "reserved " ++ styleName s ++ " " ++ show name
+  name <- highlight (styleHighlight s)
+          ((:) <$> styleStart s <*> many (styleLetter s) <?> styleName s)
+  when (HashSet.member name (styleReserved s)) $ unexpected $ "reserved " ++ styleName s ++ " " ++ show name
   return name
+{-# INLINE ident #-}
+
+-- * Utilities
+
+
+-- | This parser parses a character literal without the surrounding quotation marks.
+--
+-- This parser does NOT swallow trailing whitespace
+
+characterChar :: TokenParsing m => m Char
+
+charEscape, charLetter :: TokenParsing m => m Char
+characterChar = charLetter <|> charEscape <?> "literal character"
+{-# INLINE characterChar #-}
+
+charEscape = highlight EscapeCode $ char '\\' *> escapeCode
+{-# INLINE charEscape #-}
+
+charLetter = satisfy (\c -> (c /= '\'') && (c /= '\\') && (c > '\026'))
+{-# INLINE charLetter #-}
+
+-- | 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
+
+escapeCode :: TokenParsing 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 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' :: TokenParsing m => m Integer
+natural' = highlight Number nat <?> "natural"
+
+number :: TokenParsing m => Integer -> m Char -> m Integer
+number base baseDigit =
+  foldl' (\x d -> base*x + toInteger (digitToInt d)) 0 <$> some baseDigit
+
+-- | This 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' :: TokenParsing m => m Integer
+integer' = int <?> "integer"
+{-# INLINE integer' #-}
+
+sign :: TokenParsing m => m (Integer -> Integer)
+sign = highlight Operator
+     $ negate <$ char '-'
+   <|> id <$ char '+'
+   <|> pure id
+
+int :: TokenParsing m => m Integer
+int = {-token-} sign <*> highlight Number nat
+nat, zeroNumber :: TokenParsing m => m Integer
+nat = zeroNumber <|> decimal
+zeroNumber = char '0' *> (hexadecimal <|> octal <|> decimal <|> return 0) <?> ""
+
+floating :: TokenParsing m => m Double
+floating = decimal >>= fractExponent
+{-# INLINE floating #-}
+
+fractExponent :: TokenParsing m => Integer -> m Double
+fractExponent n = (\fract expo -> (fromInteger n + fract) * expo) <$> fraction <*> option 1.0 exponent'
+              <|> (fromInteger n *) <$> exponent' where
+  fraction = Prelude.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)
+
+natDouble, zeroNumFloat, decimalFloat :: TokenParsing 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 :: TokenParsing m => Integer -> m (Either Integer Double)
+fractFloat n = Right <$> fractExponent n
+{-# INLINE fractFloat #-}
+
+-- | Parses a positive whole number in the decimal system. Returns the
+-- value of the number.
+--
+-- This parser does NOT swallow trailing whitespace
+
+decimal :: TokenParsing m => m Integer
+decimal = number 10 digit
+{-# INLINE decimal #-}
+
+-- | Parses a positive whole number in the hexadecimal system. The number
+-- should be prefixed with \"x\" or \"X\". Returns the value of the
+-- number.
+--
+-- This parser does NOT swallow trailing whitespace
+
+hexadecimal :: TokenParsing m => m Integer
+hexadecimal = oneOf "xX" *> number 16 hexDigit
+{-# INLINE hexadecimal #-}
+
+-- | Parses a positive whole number in the octal system. The number
+-- should be prefixed with \"o\" or \"O\". Returns the value of the
+-- number.
+--
+-- This parser does NOT swallow trailing whitespace
+
+octal :: TokenParsing m => m Integer
+octal = oneOf "oO" *> number 8 octDigit
+{-# INLINE octal #-}
+
+-- | This is a parser transformer you can use to disable syntax highlighting
+-- over a range of text you are parsing.
+newtype Unhighlighted m a = Unhighlighted { runUnhighlighted :: m a }
+  deriving (Functor,Applicative,Alternative,Monad,MonadPlus,Parsing,CharParsing)
+
+instance MonadTrans Unhighlighted where
+  lift = Unhighlighted
+
+instance TokenParsing m => TokenParsing (Unhighlighted m) where
+  nesting (Unhighlighted m) = Unhighlighted (nesting m)
+  someSpace = lift someSpace
+  semi      = lift semi
+  highlight _ m = m
+
+-- | This is a parser transformer you can use to disable the automatic trailing
+-- space consumption of a Token parser.
+newtype Unspaced m a = Unspaced { runUnspaced :: m a }
+  deriving (Functor,Applicative,Alternative,Monad,MonadPlus,Parsing,CharParsing)
+
+instance MonadTrans Unspaced where
+  lift = Unspaced
+
+instance TokenParsing m => TokenParsing (Unspaced m) where
+  nesting (Unspaced m) = Unspaced (nesting m)
+  someSpace = empty
+  semi      = lift semi
+  highlight h (Unspaced m) = Unspaced (highlight h m)
diff --git a/Text/Parser/Token/Highlight.hs b/Text/Parser/Token/Highlight.hs
new file mode 100644
--- /dev/null
+++ b/Text/Parser/Token/Highlight.hs
@@ -0,0 +1,45 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Text.Parser.Token.Highlight
+-- Copyright   :  (C) 2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- Highlighting isn't strictly a parsing concern, but it makes more sense
+-- to annotate a parser with highlighting information than to require
+-- someone to completely reimplement all of the combinators to add
+-- this functionality later when they need it.
+--
+----------------------------------------------------------------------------
+module Text.Parser.Token.Highlight
+  ( Highlight(..)
+  ) where
+
+data Highlight
+  = EscapeCode
+  | Number
+  | Comment
+  | CharLiteral
+  | StringLiteral
+  | Constant
+  | Statement
+  | Special
+  | Symbol
+  | Identifier
+  | ReservedIdentifier
+  | Operator
+  | ReservedOperator
+  | Constructor
+  | ReservedConstructor
+  | ConstructorOperator
+  | ReservedConstructorOperator
+  | BadInput
+  | Unbound
+  | Layout
+  | MatchedSymbols
+  | LiterateComment
+  | LiterateSyntax
+  deriving (Eq,Ord,Show,Read,Enum,Bounded)
diff --git a/Text/Parser/Token/Style.hs b/Text/Parser/Token/Style.hs
--- a/Text/Parser/Token/Style.hs
+++ b/Text/Parser/Token/Style.hs
@@ -21,9 +21,9 @@
   , javaCommentStyle
   , haskellCommentStyle
   , buildSomeSpaceParser
-  -- * identifier styles
+  -- * Identifier Styles
   , emptyIdents, haskellIdents, haskell98Idents
-  -- * operator styles
+  -- * Operator Styles
   , emptyOps, haskellOps, haskell98Ops
   ) where
 
@@ -34,6 +34,7 @@
 import Text.Parser.Combinators
 import Text.Parser.Char
 import Text.Parser.Token
+import Text.Parser.Token.Highlight
 import Data.List (nub)
 
 data CommentStyle = CommentStyle
@@ -84,6 +85,8 @@
   , styleStart    = styleLetter emptyOps
   , styleLetter   = oneOf ":!#$%&*+./<=>?@\\^|-~"
   , styleReserved = mempty
+  , styleHighlight = Operator
+  , styleReservedHighlight = ReservedOperator
   }
 haskell98Ops = emptyOps
   { styleReserved = set ["::","..","=","\\","|","<-","->","@","~","=>"]
@@ -96,6 +99,8 @@
   , styleStart    = letter <|> char '_'
   , styleLetter   = alphaNum <|> oneOf "_'"
   , styleReserved = set []
+  , styleHighlight = Identifier
+  , styleReservedHighlight = ReservedIdentifier
   }
 
 haskell98Idents = emptyIdents
diff --git a/parsers.cabal b/parsers.cabal
--- a/parsers.cabal
+++ b/parsers.cabal
@@ -1,6 +1,6 @@
 name:          parsers
 category:      Text, Parsing
-version:       0.1
+version:       0.2
 license:       BSD3
 cabal-version: >= 1.6
 license-file:  LICENSE
@@ -28,6 +28,7 @@
     Text.Parser.Expression
     Text.Parser.Token
     Text.Parser.Token.Style
+    Text.Parser.Token.Highlight
 
   ghc-options: -Wall
 
