diff --git a/Earley.cabal b/Earley.cabal
new file mode 100644
--- /dev/null
+++ b/Earley.cabal
@@ -0,0 +1,28 @@
+name:                Earley
+version:             0.6.0
+synopsis:            Parsing all context-free grammars using Earley's algorithm.
+description:         See <https://www.github.com/ollef/Earley> for more
+                     information and
+                     <https://github.com/ollef/Earley/tree/master/examples> for
+                     examples.
+license:             BSD3
+license-file:        LICENSE
+author:              Olle Fredriksson
+maintainer:          fredriksson.olle@gmail.com
+copyright:           (c) 2014-2015 Olle Fredriksson
+category:            Parsing
+build-type:          Simple
+cabal-version:       >=1.10
+
+source-repository    head
+  type:     git
+  location: https://github.com/ollef/Earley.git
+
+library
+  exposed-modules:     Text.Earley.Derived, Text.Earley.Grammar, Text.Earley.Parser Text.Earley
+  -- other-modules:
+  build-depends:       base ==4.8.*, containers >=0.5, kan-extensions >=4.2, ListLike >=4.1
+  -- hs-source-dirs:
+  default-language:    Haskell2010
+  ghc-options:         -Wall -funbox-strict-fields
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2014-2015, Olle Fredriksson
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Olle Fredriksson nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/Text/Earley.hs b/Text/Earley.hs
new file mode 100644
--- /dev/null
+++ b/Text/Earley.hs
@@ -0,0 +1,13 @@
+-- | Parsing all context-free grammars using Earley's algorithm.
+module Text.Earley
+  ( -- * Context-free grammars
+    Prod, satisfy, (<?>), Grammar, rule
+  , -- * Derived operators
+    symbol, namedSymbol, word
+  , -- * Parsing
+    Report(..), Result(..), parser, allParses, fullParses
+  )
+  where
+import Text.Earley.Grammar
+import Text.Earley.Derived
+import Text.Earley.Parser
diff --git a/Text/Earley/Derived.hs b/Text/Earley/Derived.hs
new file mode 100644
--- /dev/null
+++ b/Text/Earley/Derived.hs
@@ -0,0 +1,18 @@
+-- | Derived operators.
+module Text.Earley.Derived where
+import Control.Applicative hiding (many)
+
+import Text.Earley.Grammar
+
+-- | Match a single token.
+symbol :: Eq t => t -> Prod r e t t
+symbol x = satisfy (== x)
+
+-- | Match a single token and give it the name of the token.
+namedSymbol :: Eq t => t -> Prod r t t t
+namedSymbol x = symbol x <?> x
+
+-- | Match a list of tokens in sequence.
+{-# INLINE word #-}
+word :: Eq t => [t] -> Prod r e t [t]
+word = foldr (liftA2 (:) . satisfy . (==)) (pure [])
diff --git a/Text/Earley/Grammar.hs b/Text/Earley/Grammar.hs
new file mode 100644
--- /dev/null
+++ b/Text/Earley/Grammar.hs
@@ -0,0 +1,136 @@
+-- | Context-free grammars.
+{-# LANGUAGE GADTs, RankNTypes #-}
+module Text.Earley.Grammar
+  ( Prod(..)
+  , satisfy
+  , (<?>)
+  , Grammar(..)
+  , rule
+  ) where
+import Control.Applicative
+import Control.Monad
+import Control.Monad.Fix
+
+infixr 0 <?>
+
+-- | A production.
+--
+-- The type parameters are:
+--
+-- @a@: The return type of the production.
+--
+-- @t@: The type of the terminals that the production operates on.
+--
+-- @e@: The type of names, used for example to report expected tokens.
+--
+-- @r@: The type of a non-terminal. This plays a role similar to the @s@ in the
+--      type @ST s a@.  Since the 'parser' function expects the @r@ to be
+--      universally quantified, there is not much to do with this parameter
+--      other than leaving it universally quantified.
+--
+-- As an example, @'Prod' r 'String' 'Char' 'Int'@ is the type of a production that
+-- returns an 'Int', operates on (lists of) characters and reports 'String'
+-- names.
+--
+-- Most of the functionality of 'Prod's is obtained through its instances, e.g.
+-- 'Functor', 'Applicative', and 'Alternative'.
+data Prod r e t a where
+  -- Applicative.
+  Terminal    :: !(t -> Bool) -> !(Prod r e t (t -> b)) -> Prod r e t b
+  NonTerminal :: !(r e t a) -> !(Prod r e t (a -> b)) -> Prod r e t b
+  Pure        :: a -> Prod r e t a
+  -- Monoid/Alternative. We have to special-case 'many' (though it can be done
+  -- with rules) to be able to satisfy the Alternative interface.
+  Plus        :: !(Prod r e t a) -> !(Prod r e t a) -> Prod r e t a
+  Many        :: !(Prod r e t a) -> !(Prod r e t ([a] -> b)) -> Prod r e t b
+  Empty       :: Prod r e t a
+  -- Error reporting.
+  Named       :: !(Prod r e t a) -> e -> Prod r e t a
+
+-- | Match a token that satisfies the given predicate. Returns the matched token.
+{-# INLINE satisfy #-}
+satisfy :: (t -> Bool) -> Prod r e t t
+satisfy p = Terminal p $ Pure id
+
+-- | A named production (used for reporting expected things).
+(<?>) :: Prod r e t a -> e -> Prod r e t a
+(<?>) = Named
+
+instance Monoid (Prod r e t a) where
+  mempty  = empty
+  mappend = (<|>)
+
+instance Functor (Prod r e t) where
+  {-# INLINE fmap #-}
+  fmap f (Terminal b p)    = Terminal b $ fmap (f .) p
+  fmap f (NonTerminal r p) = NonTerminal r $ fmap (f .) p
+  fmap f (Pure x)          = Pure $ f x
+  fmap f (Plus p q)        = Plus (fmap f p) (fmap f q)
+  fmap f (Many p q)        = Many p $ fmap (f .) q
+  fmap _ Empty             = Empty
+  fmap f (Named p n)       = Named (fmap f p) n
+
+instance Applicative (Prod r e t) where
+  pure = Pure
+  {-# INLINE (<*>) #-}
+  Terminal b p    <*> q = Terminal b $ flip <$> p <*> q
+  NonTerminal r p <*> q = NonTerminal r $ flip <$> p <*> q
+  Pure f          <*> q = fmap f q
+  Plus a b        <*> q = a <*> q <|> b <*> q
+  Many a p        <*> q = Many a $ flip <$> p <*> q
+  Empty           <*> _ = Empty
+  Named p n       <*> q = Named (p <*> q) n
+
+instance Alternative (Prod r e t) where
+  empty = Empty
+  Empty     <|> q         = q
+  p         <|> Empty     = p
+  Named p m <|> q         = Named (p <|> q) m
+  p         <|> Named q n = Named (p <|> q) n
+  p         <|> q         = Plus p q
+  many p       = Many p $ Pure id
+  some p       = (:) <$> p <*> many p
+
+-- | A context-free grammar.
+--
+-- The type parameters are:
+--
+-- @a@: The return type of the grammar (often a 'Prod').
+--
+-- @e@: The type of names, used for example to report expected tokens.
+--
+-- @r@: The type of a non-terminal. This plays a role similar to the @s@ in the
+--      type @ST s a@.  Since the 'parser' function expects the @r@ to be
+--      universally quantified, there is not much to do with this parameter
+--      other than leaving it universally quantified.
+--
+-- Most of the functionality of 'Grammar's is obtained through its instances,
+-- e.g.  'Monad' and 'MonadFix'. Note that GHC has syntactic sugar for
+-- 'MonadFix': use @{-\# LANGUAGE RecursiveDo \#-}@ and @mdo@ instead of
+-- @do@.
+data Grammar r e a where
+  RuleBind :: Prod r e t a -> (Prod r e t a -> Grammar r e b) -> Grammar r e b
+  FixBind  :: (a -> Grammar r e a) -> (a -> Grammar r e b) -> Grammar r e b
+  Return   :: a -> Grammar r e a
+
+instance Functor (Grammar r e) where
+  fmap f (RuleBind ps h) = RuleBind ps (fmap f . h)
+  fmap f (FixBind g h)   = FixBind g (fmap f . h)
+  fmap f (Return x)      = Return $ f x
+
+instance Applicative (Grammar r e) where
+  pure  = return
+  (<*>) = ap
+
+instance Monad (Grammar r e) where
+  return = Return
+  RuleBind ps f >>= k = RuleBind ps (f >=> k)
+  FixBind f g   >>= k = FixBind f (g >=> k)
+  Return x      >>= k = k x
+
+instance MonadFix (Grammar r e) where
+  mfix f = FixBind f return
+
+-- | Create a new non-terminal by listing its production rule.
+rule :: Prod r e t a -> Grammar r e (Prod r e t a)
+rule p = RuleBind p return
diff --git a/Text/Earley/Parser.hs b/Text/Earley/Parser.hs
new file mode 100644
--- /dev/null
+++ b/Text/Earley/Parser.hs
@@ -0,0 +1,246 @@
+-- | Parsing.
+{-# LANGUAGE BangPatterns, DeriveFunctor, GADTs, Rank2Types #-}
+module Text.Earley.Parser
+  ( Report(..)
+  , Result(..)
+  , parser
+  , allParses
+  , fullParses
+  ) where
+import Control.Applicative
+import Control.Arrow
+import Control.Monad.Fix
+import Control.Monad.ST.Lazy
+import Data.Functor.Yoneda
+import Data.ListLike(ListLike)
+import qualified Data.ListLike as ListLike
+import Data.STRef.Lazy
+import Text.Earley.Grammar
+
+-------------------------------------------------------------------------------
+-- * Concrete rules and productions
+-------------------------------------------------------------------------------
+-- | The concrete rule type that the parser uses
+data Rule s r e t a = Rule
+  { ruleProd     :: ProdR s r e t a
+  , ruleNullable :: {-# UNPACK #-} !(STRef s (Maybe [a]))
+  , ruleConts    :: {-# UNPACK #-} !(STRef s (Conts s r e t a r))
+  }
+
+type ProdR s r e t a = Prod (Rule s r) e t a
+
+nullable :: Rule s r e t a -> ST s [a]
+nullable r = do
+  mn <- readSTRef $ ruleNullable r
+  case mn of
+    Just xs -> return xs
+    Nothing -> do
+      writeSTRef (ruleNullable r) $ Just mempty
+      res <- nullableProd $ ruleProd r
+      writeSTRef (ruleNullable r) $ Just res
+      return res
+
+nullableProd :: ProdR s r e t a -> ST s [a]
+nullableProd (Terminal _ _)    = return mempty
+nullableProd (NonTerminal r p) = do
+  as <- nullable r
+  concat <$> mapM (\a -> nullableProd $ fmap ($ a) p) as
+nullableProd (Pure a)          = return [a]
+nullableProd (Plus a b)        = mappend <$> nullableProd a <*> nullableProd b
+nullableProd (Many p q)        = do
+  as <- nullableProd $ (:[]) <$> p <|> pure []
+  concat <$> mapM (\a -> nullableProd $ fmap ($ a) q) as
+nullableProd Empty             = return mempty
+nullableProd (Named p _)       = nullableProd p
+
+-------------------------------------------------------------------------------
+-- * States and continuations
+-------------------------------------------------------------------------------
+type Pos = Int
+
+-- | An Earley state with result type @a@.
+data State s r e t a where
+  State :: {-# UNPACK #-} !Pos
+        -> !(ProdR s r e t b)
+        -> {-# UNPACK #-} !(Conts s r e t b a)
+        -> State s r e t a
+  Final :: a -> State s r e t a
+
+-- | A continuation accepting an @a@ and producing a @b@.
+data Cont s r e t a b where
+  Cont      :: {-# UNPACK #-} !Pos
+            -> !(ProdR s r e t (a -> b))
+            -> {-# UNPACK #-} !(Conts s r e t b c)
+            -> Cont s r e t a c
+  FinalCont :: (a -> c) -> Cont s r e t a c
+
+type Conts s r e t a c = STRef s [Cont s r e t a c]
+
+contraMapCont :: (b -> a) -> Cont s r e t a c -> Cont s r e t b c
+contraMapCont f (Cont pos p cs) = (Cont pos $! ((. f) <$> p)) cs
+contraMapCont f (FinalCont g)   = FinalCont (g . f)
+
+contToState :: a -> Cont s r e t a c -> State s r e t c
+contToState a (Cont pos p cs) = State pos (($ a) <$> p) cs
+contToState a (FinalCont f)   = Final (f a)
+
+-- | Strings of non-ambiguous continuations can be optimised by removing
+--   indirections.
+simplifyCont :: Conts s r e t b a -> ST s [Cont s r e t b a]
+simplifyCont cont = readSTRef cont >>= go False
+  where
+    go !_ [Cont _ (Pure f) cont'] = do
+      ks' <- simplifyCont cont'
+      go True $ map (contraMapCont f) ks'
+    go True ks = do
+      writeSTRef cont ks
+      return ks
+    go False ks = return ks
+
+-------------------------------------------------------------------------------
+-- * Grammars
+-------------------------------------------------------------------------------
+-- | Interpret an abstract 'Grammar'.
+grammar :: Grammar (Rule s r) e a -> ST s a
+grammar g = case g of
+  RuleBind p k -> do
+    c  <- newSTRef =<< newSTRef mempty
+    nr <- newSTRef Nothing
+    grammar $ k $ NonTerminal (Rule p nr c) $ Pure id
+  FixBind f k   -> do
+    a <- mfix $ fmap grammar f
+    grammar $ k a
+  Return x      -> return x
+
+-- | Given a grammar, construct an initial state.
+initialState :: ProdR s a e t a -> ST s (State s a e t a)
+initialState r = do
+  rs <- newSTRef [FinalCont id]
+  return $ State (-1) r rs
+
+-------------------------------------------------------------------------------
+-- * Parsing
+-------------------------------------------------------------------------------
+-- | A parsing report, which contains fields that are useful for presenting
+-- errors to the user if a parse is deemed a failure.  Note however that we get
+-- a report even when we successfully parse something.
+data Report e i = Report
+  { position   :: Int -- ^ The final position in the input (0-based) that the
+                      -- parser reached.
+  , expected   :: [e] -- ^ The named productions processed at the final
+                      -- position.
+  , unconsumed :: i   -- ^ The part of the input string that was not consumed,
+                      -- which may be empty.
+  } deriving Show
+
+-- | The result of a parse.
+data Result s e i a
+  = Ended (Report e i)
+    -- ^ The parser ended.
+  | Parsed a Int i (i -> ST s (Result s e i a))
+    -- ^ The parser parsed something, namely an 'a'. The 'Int' is the position
+    -- in the input where it did so, the 'i' is the rest of the input, and the
+    -- function is the parser continuation. This allows incrementally feeding
+    -- the parser more input (e.g. when the 'i' is empty).
+  deriving (Functor)
+
+{-# INLINE uncons #-}
+uncons :: ListLike i t => i -> Maybe (t, i)
+uncons i
+  | ListLike.null i = Nothing
+  | otherwise       = Just (ListLike.head i, ListLike.tail i)
+
+{-# INLINE safeTail #-}
+safeTail :: ListLike i t => i -> i
+safeTail ts'
+  | ListLike.null ts' = ts'
+  | otherwise         = ListLike.tail ts'
+
+{-# SPECIALISE parse :: [State s a e t a] -> [State s a e t a] -> ST s () -> [e] -> Pos -> [t] -> ST s (Result s e [t] a) #-}
+-- | The internal parsing routine
+parse :: ListLike i t
+      => [State s a e t a] -- ^ States to process at this position
+      -> [State s a e t a] -- ^ States to process at the next position
+      -> ST s ()           -- ^ Computation that resets the continuation refs of productions
+      -> [e]               -- ^ Named productions encountered at this position
+      -> Pos               -- ^ The current position in the input string
+      -> i                 -- ^ The input string
+      -> ST s (Result s e i a)
+parse []      []    !reset names !pos   !ts = do
+  reset
+  return $ Ended Report {position = pos, expected = names, unconsumed = ts}
+parse []      !next !reset _names !pos !ts = do
+  reset
+  parse next [] (return ()) [] (pos + 1) (safeTail ts)
+parse (st:ss) !next !reset names !pos !ts = case st of
+  Final a -> return $ Parsed a pos ts $ parse ss next reset names pos
+  State spos pr scont -> case pr of
+    Terminal f p -> case uncons ts of
+      Just (t, _) | f t -> parse ss (State spos (($ t) <$> p) scont : next) reset names pos ts
+      _                 -> parse ss next reset names pos ts
+    NonTerminal r p -> do
+      rkref <- readSTRef $ ruleConts r
+      ks    <- readSTRef rkref
+      writeSTRef rkref (Cont spos p scont : ks)
+      nulls' <- nullable r
+      let notExpanded = null ks
+          p'          = liftYoneda p
+          nulls       = fmap (\a -> State spos (lowerYoneda $ ($ a) <$> p') scont) nulls'
+      if notExpanded then do
+        let st' = State pos (ruleProd r) rkref
+        parse (st' : nulls ++ ss)
+              next
+              ((writeSTRef (ruleConts r) =<< newSTRef mempty) >> reset)
+              names
+              pos
+              ts
+      else
+        parse (nulls ++ ss) next reset names pos ts
+    Pure a | spos /= pos -> do
+      conts <- simplifyCont scont
+      parse (map (contToState a) conts ++ ss) next reset names pos ts
+           | otherwise -> parse ss next reset names pos ts
+
+    Plus p q    -> parse (State spos p scont : State spos q scont : ss) next reset names pos ts
+    Many p q    -> do
+      rkref <- newSTRef [Cont spos (Many p ((\f as a -> f (a : as)) <$> q)) scont]
+      let st' = State pos p rkref
+          nst = State spos (($ []) <$> q) scont
+      parse (st' : nst : ss) next reset names pos ts
+    Empty       -> parse ss next reset names pos ts
+
+    Named pr' n -> parse (State spos pr' scont : ss) next reset (n : names) pos ts
+
+{-# INLINE parser #-}
+-- | Create a parser from the given grammar.
+parser :: ListLike i t
+       => (forall r. Grammar r e (Prod r e t a))
+       -> i
+       -> ST s (Result s e i a)
+parser g xs = do
+  s <- initialState =<< grammar g
+  parse [s] [] (return ()) [] 0 xs
+
+-- | Return all parses from the result of a given parser. The result may
+-- contain partial parses. The 'Int's are the position at which a result was
+-- produced.
+allParses :: (forall s. ST s (Result s e i a)) -> ([(a, Int)], Report e i)
+allParses p = runST $ p >>= go
+  where
+    go :: Result s e i a -> ST s ([(a, Int)], Report e i)
+    go r = case r of
+      Ended report     -> return ([], report)
+      Parsed a pos i k -> fmap (first ((a, pos) :)) $ go =<< k i
+
+{-# INLINE fullParses #-}
+-- | Return all parses that reached the end of the input from the result of a
+--   given parser.
+fullParses :: ListLike i t => (forall s. ST s (Result s e i a)) -> ([a], Report e i)
+fullParses p = runST $ p >>= go
+  where
+    go :: ListLike i t => Result s e i a -> ST s ([a], Report e i)
+    go r = case r of
+      Ended report -> return ([], report)
+      Parsed a _ i k
+        | ListLike.null i -> fmap (first (a :)) $ go =<< k i
+        | otherwise       -> go =<< k i
