diff --git a/JustParse.cabal b/JustParse.cabal
new file mode 100644
--- /dev/null
+++ b/JustParse.cabal
@@ -0,0 +1,20 @@
+name:                JustParse
+version:             1.0
+synopsis:            A simple and comprehensive Haskell parsing library
+description:         A simple and comprehensive Haskell parsing library
+homepage:            https://github.com/grantslatton/JustParse
+license:             PublicDomain
+license-file:        LICENSE
+author:              Grant Slatton
+maintainer:          grantslatton@gmail.com
+-- copyright:           
+category:            Text
+build-type:          Simple
+cabal-version:       >=1.8
+
+library
+   exposed-modules: Data.JustParse
+   other-modules: Data.JustParse.Internal, Data.JustParse.Language, Data.JustParse.Common
+  build-depends:       base ==4.6.*
+  hs-source-dirs: src
+  extensions: MultiParamTypeClasses, Rank2Types, FlexibleInstances, FlexibleContexts, Safe
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org>
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/src/Data/JustParse.hs b/src/Data/JustParse.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/JustParse.hs
@@ -0,0 +1,141 @@
+{-|
+Module      : Data.JustParse
+Description : The one-stop import for the library
+Copyright   : Copyright Waived
+License     : PublicDomain
+Maintainer  : grantslatton@gmail.com
+Stability   : experimental
+Portability : portable
+
+A simple and comprehensive Haskell parsing library.
+-} 
+
+{-# LANGUAGE Safe #-}
+module Data.JustParse (
+    -- * Overview
+    -- $overview
+
+    -- * Quickstart Examples
+    -- *** Simple char and string parsing
+    -- $quickstart1
+
+    -- *** Basic combinatorial parsing
+    -- $quickstart2
+
+    -- *** Recursive combinatorial parsing
+    -- $quickstart3
+
+    -- * General Parsing
+    C.Stream(..),
+    C.Result(..),
+    C.Parser( parse ),
+    C.justParse,
+    C.runParser,
+    C.finalize,
+    C.extend,
+    C.isDone,
+    C.isFail,
+    C.isPartial,
+    C.rename,
+    (C.<?>),
+
+    -- * Generic Parsers
+    C.test,
+    C.greedy,
+    C.option,
+    C.satisfy,
+    C.mN,
+    C.many,
+    C.many1,
+    C.manyN,
+    C.atLeast,
+    C.exactly,
+    C.eof,
+    C.oneOf,
+    C.noneOf,
+    C.anyToken,
+    C.lookAhead,
+
+    -- * Char Parsers
+    C.char,
+    C.anyChar,
+    C.ascii,
+    C.latin1,
+    C.control,
+    C.space,
+    C.lower,
+    C.upper,
+    C.alpha,
+    C.alphaNum,
+    C.print,
+    C.digit,
+    C.octDigit,
+    C.hexDigit,
+    C.eol,
+
+    -- * String Parsers
+    C.string,
+
+    -- * Regex Parsers
+    L.regex,
+    L.regex',
+    L.Match(..)
+
+) where
+
+import Data.JustParse.Language as L
+import Data.JustParse.Common as C
+
+-- $overview
+-- 
+-- * Allows for parsing arbitrary 'Stream' types
+-- 
+-- * Makes extensive use of combinators
+-- 
+-- * Returns relatively verbose 'Fail'ure messages.
+-- 
+-- * Allows one to 'rename' a 'Parser'. 
+-- 
+-- * Allows for a parser to return a 'Partial' 'Result'
+-- 
+-- * Non-greedy parsing
+-- 
+-- * Returns a list of all possible parses
+-- 
+-- * Allows for conversion of a 'regex' to a parser
+
+-- $quickstart1
+--
+-- This parser will only accept the string @\"hello world\"@
+--
+-- @
+--p = do                
+--    h \<- char \'h\'                   \-\-Parses the character \'h\'
+--    rest \<- string \"ello world\"     \-\-Parses the string \"ello world\"
+--    exp \<- char \'!\'                 \-\-Parses the character \'!\'
+--    return ([h]++rest++[exp])       \-\-Returns all of the above concatenated together
+-- @
+
+-- $quickstart2
+--
+-- This parser will accept the string @\"hello woooooorld\"@ with any number of @o@\'s.
+-- It returns the number of @o@\'s.
+--
+-- @
+--p = do
+--    first \<- string \"hello w\"         \-\-Parses the string \"hello w\"
+--    os \<- many1 (char \'o\')            \-\-Applies the parser \"char \'o\'\" one or more times
+--    second \<- string \"rld\"            \-\-Parses the string \"rld\"
+--    return (length os)                \-\-Return the number of o\'s parsed
+-- @
+
+-- $quickstart3
+-- 
+-- This parser will turn a string of comma separated values into a list of them
+--
+-- @
+--csv = do  
+--    v \<- greedy (many (noneOf \",\"))       \-\-Parses as many non-comma characters as possible
+--    vs \<- option [] (char \',\' >> csv)     \-\-Optionally parses a comma and a csv, returning the empty list upon failure
+--    return (v:vs)                         \-\-Concatenates and returns the full list
+-- @
diff --git a/src/Data/JustParse/Common.hs b/src/Data/JustParse/Common.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/JustParse/Common.hs
@@ -0,0 +1,284 @@
+{-|
+Module      : Data.JustParse.Common
+Description : Common Parser Combinators
+Copyright   : Copyright Waived
+License     : PublicDomain
+Maintainer  : grantslatton@gmail.com
+Stability   : experimental
+Portability : portable
+
+Many common parsing needs in one place.
+-}
+
+{-# LANGUAGE Safe #-}
+module Data.JustParse.Common (
+-- Parsing
+    Stream(..),
+    Result(..),
+    Parser( parse ),
+    finalize,
+    extend,
+    justParse,
+    runParser,
+    isDone,
+    isFail,
+    isPartial,
+    rename,
+    (<?>),
+
+-- Primitive parsers
+    satisfy,
+    mN,
+
+-- Derived Parsers
+
+-- Generic Parsers
+    test,
+    greedy,
+    option,
+    many,
+    many1,
+    manyN,
+    atLeast,
+    exactly,
+    eof,
+    oneOf,
+    noneOf,
+    anyToken,
+    lookAhead,
+
+-- Char Parsers
+    char,
+    anyChar,
+    ascii,
+    latin1,
+    control,
+    space,
+    lower,
+    upper,
+    alpha,
+    alphaNum,
+    print,
+    digit,
+    octDigit,
+    hexDigit,
+    eol,
+
+-- String Parsers
+    string,
+
+) where
+
+import Prelude hiding ( print, length )
+import Data.JustParse.Internal ( Stream(..), Parser(..), Result(..), extend, finalize, isDone, isPartial, isFail, rename, (<?>) )
+import Data.Monoid ( mempty, Monoid )
+import Data.Maybe ( fromMaybe )
+import Data.List ( minimumBy )
+import Data.Char ( isControl, isSpace, isLower, isUpper, isAlpha, isAlphaNum, isPrint, 
+                   isDigit, isOctDigit, isHexDigit, isLetter, isMark, isNumber, isPunctuation, 
+                   isSymbol, isSeparator, isAscii, isLatin1, isAsciiUpper, isAsciiLower )
+import Data.Ord ( comparing )
+import Control.Monad ( void, (>=>), liftM )
+import Control.Applicative ( (<|>), optional, (<*) )
+
+-- | Supplies the input to the 'Parser'. Returns all 'Result' types, 
+-- including 'Partial' and 'Fail' types.
+runParser :: Parser s a -> s -> [Result s a]
+runParser p = parse p . Just
+
+-- | This is a \"newbie\" command that one should probably only use out of frustration.
+-- It runs the 'Parser' greedily over the input, 'finalize's all the results, and returns
+-- the first successful result. If there are no successful results, it returns Nothing.
+justParse :: Stream s t => Parser s a -> s -> Maybe a
+justParse p s = 
+    case finalize (parse (greedy p) (Just s)) of
+        [] -> Nothing
+        (Done v _:_) -> Just v
+        (Fail m _:_) -> Nothing
+
+-- | Parse a token that satisfies a predicate.
+satisfy :: Stream s t => (t -> Bool) -> Parser s t
+satisfy f = Parser $ \s -> 
+    case s of
+        Nothing -> [Fail ["satisfy"] s]
+        Just s' -> case uncons s' of
+            Nothing -> [Partial $ parse (satisfy f)]
+            Just (x, xs) -> 
+                if f x 
+                    then [Done x (Just xs)]
+                    else [Fail ["satisfy"] s]
+
+-- | Parse from @m@ to @n@ occurences of a 'Parser'. Let @n@ be negative
+-- if one wishes for no upper bound.
+mN :: Int -> Int -> Parser s a -> Parser s [a]
+mN m n p = mN' m n p <?> "mN"
+
+mN' :: Int -> Int -> Parser s a -> Parser s [a]
+mN' _ 0 _ = Parser $ \s -> [Done [] s] 
+mN' m n p = Parser $ \s -> 
+    if m == 0 
+        then Done [] s : (parse p s >>= g)
+        else             parse p s >>= g
+    where
+        m' = if m == 0 then 0 else m-1
+        g (Done a s) = parse (mN' m' (n-1) p) s >>= h a
+        g (Partial p') = [Partial $ p' >=> g]
+        g (Fail m l) = [Fail m l]
+        h a (Done as s) = [Done (a:as) s]
+        h a (Partial p') = [Partial $ p' >=> h a]
+        h a (Fail m l) = [Fail m l]
+
+-- | Return @True@ if the 'Parser' would succeed if one were to apply it,
+-- otherwise, @False@.
+test :: Parser s a -> Parser s Bool
+test p = 
+    do 
+        a <- optional (lookAhead p)
+        case a of
+            Nothing -> return False
+            _ -> return True
+
+-- | Modifies a 'Parser' so that it will ony return the most consumptive
+-- succesful results. If there are no successful results, it will only
+-- return the most consumptive failures. One can use @greedy@ to emulate
+-- parsers from @Parsec@ or @attoparsec@.
+greedy :: Stream s t => Parser s a -> Parser s a
+greedy (Parser p) = Parser $ \s -> g (p s) 
+    where
+        b (Done _ _) = True
+        b (Fail _ _) = True
+        b _ = False
+        f Nothing = 0
+        f (Just s) = length s
+        g [] = []
+        g xs 
+            | all b xs = 
+                let
+                    ds = filter isDone xs
+                    dm = minimum (map (f . leftover) ds)
+                    fs = filter isFail xs
+                    fm = minimum (map (f . leftover) fs)
+                in
+                    if not (null ds)
+                        then filter ((dm==) . f . leftover) ds
+                        else filter ((fm==) . f . leftover) fs
+            | otherwise = [Partial $ \s -> g $ extend s xs] 
+
+-- | Attempts to apply a parser and returns a default value if it fails.
+option :: a -> Parser s a -> Parser s a
+option v p = 
+    do
+        r <- optional p
+        case r of
+            Nothing -> return v
+            Just v' -> return v'
+
+-- | Parse any number of occurences of the 'Parser'. Equivalent to @'mN' 0 (-1)@.
+many :: Parser s a -> Parser s [a]
+many p = rename "many" (mN 0 (-1) p)
+
+-- | Parse one or more occurence of the 'Parser'. Equivalent to @'mN' 1 (-1)@.
+many1 :: Parser s a -> Parser s [a]
+many1 p = rename "many1" (mN 1 (-1) p)
+
+-- | Parse at least @n@ occurences of the 'Parser'. Equivalent to @'mN' n (-1)@.
+manyN :: Int -> Parser s a -> Parser s [a]
+manyN n p = rename "manyN" (mN n (-1) p)
+
+-- | Identical to 'manyN', just a more intuitive name.
+atLeast :: Int -> Parser s a -> Parser s [a]
+atLeast n p = rename "atLeast" (mN n (-1) p)
+
+-- | Parse exactly @n@ occurences of the 'Parser'. Equivalent to @'mN' n n@.
+exactly :: Int -> Parser s a -> Parser s [a]
+exactly n p = rename "exactly" (mN n n p)
+
+-- | Only succeeds when supplied with @Nothing@.
+eof :: (Eq s, Monoid s) => Parser s ()
+eof = Parser $ \s ->
+    case s of
+        Nothing -> [Done () s]
+        Just s' -> 
+            if s' == mempty
+                then [Partial $ parse eof]
+                else [Fail ["eof"] (Just s')]
+
+oneOf :: (Eq t, Stream s t) => [t] -> Parser s t
+oneOf ts = rename "oneOf" (satisfy (`elem` ts))
+
+noneOf :: (Eq t, Stream s t) => [t] -> Parser s t
+noneOf ts = rename "noneOf" (satisfy (not . (`elem` ts)))
+
+-- | Parse a specific token.
+token :: (Eq t, Stream s t) => t -> Parser s t
+token t = rename "token" (satisfy (==t))
+
+anyToken :: Stream s t => Parser s t
+anyToken = rename "anyToken" (satisfy (const True))
+
+-- | Applies the parser and returns its result, but resets
+-- the leftovers as if it consumed nothing.
+lookAhead :: Parser s a -> Parser s a
+lookAhead (Parser p) = rename "lookAhead" $ Parser $ \s -> 
+    let 
+        g (Done a _) = [Done a s]
+        g (Partial p') = [Partial $ p' >=> g]
+        g (Fail m _) = [Fail m s]
+    in
+        p s >>= g
+
+-- | Parse a specic char.
+char :: Stream s Char => Char -> Parser s Char
+char c = rename ("char "++[c]) (token c)
+
+anyChar :: Stream s Char =>  Parser s Char
+anyChar = rename "anyChar" anyToken
+
+ascii :: Stream s Char =>  Parser s Char
+ascii = rename "ascii" (satisfy isAscii)
+
+latin1 :: Stream s Char =>  Parser s Char
+latin1 = rename "latin1" (satisfy isLatin1)
+
+control :: Stream s Char =>  Parser s Char
+control = rename "control" (satisfy isControl)
+
+space :: Stream s Char =>  Parser s Char
+space = rename "space" (satisfy isSpace)
+
+lower :: Stream s Char =>  Parser s Char
+lower = rename "lower" (satisfy isLower)
+
+upper :: Stream s Char =>  Parser s Char
+upper = rename "upper" (satisfy isUpper)
+
+alpha :: Stream s Char =>  Parser s Char
+alpha = rename "alpha" (satisfy isAlpha)
+
+alphaNum :: Stream s Char =>  Parser s Char
+alphaNum = rename "alphaNum" (satisfy isAlphaNum)
+
+print :: Stream s Char =>  Parser s Char
+print = rename "print" (satisfy isPrint)
+
+digit :: Stream s Char =>  Parser s Char
+digit = rename "digit" (satisfy isDigit)
+
+octDigit :: Stream s Char =>  Parser s Char
+octDigit = rename "octDigit" (satisfy isOctDigit)
+
+hexDigit :: Stream s Char =>  Parser s Char
+hexDigit = rename "hexDigit" (satisfy isHexDigit)
+
+-- | Parse a specific string.
+string :: Stream s Char => String -> Parser s String
+string s = rename ("string "++s) (mapM char s)
+
+-- | Parses until a newline, carriage return + newline, or newline + carriage return.
+eol :: Stream s Char => Parser s String
+eol = rename "eol" (string "\r\n" <|> string "\n\r" <|> string "\n")
+
+-- | Makes common types such as Strings into a Stream.
+instance (Eq t) => Stream [t] t where
+    uncons [] = Nothing
+    uncons (x:xs) = Just (x, xs)
diff --git a/src/Data/JustParse/Internal.hs b/src/Data/JustParse/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/JustParse/Internal.hs
@@ -0,0 +1,157 @@
+{-|
+Module      : Data.JustParse.Internal
+Description : The engine behind the JustParse library
+Copyright   : Copyright Waived
+License     : PublicDomain
+Maintainer  : grantslatton@gmail.com
+Stability   : experimental
+Portability : portable
+-}
+
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE Rank2Types #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE Safe #-}
+
+module Data.JustParse.Internal (
+    finalize,
+    extend,
+    Stream (..),
+    Parser (..),
+    Result (..),
+    isDone,
+    isFail,
+    isPartial,
+    rename,
+    (<?>)
+) where
+
+import Prelude hiding ( length )
+import Control.Monad ( MonadPlus, mzero, mplus, (>=>), ap )
+import Control.Applicative ( Alternative, Applicative, pure, (<*>), empty, (<|>) )
+import Data.Monoid ( Monoid, mempty, mappend )
+import Data.List ( intercalate )
+
+-- | A @Stream@ instance has a stream of type @s@, made up of tokens of 
+-- type @t@, which must be determinable by the stream.
+class (Eq s, Monoid s) => Stream s t | s -> t where
+    -- | @uncons@ returns @Nothing@ if the @Stream@ is empty, otherwise it
+    -- returns the first token of the stream, followed by the remainder
+    -- of the stream, wrapped in a @Just@.
+    uncons :: Stream s t => s -> Maybe (t, s)
+    -- | The default @length@ implementation is O(n). If your stream provides
+    -- a more efficient method for determining the length, it is wise to
+    -- override this. The @length@ method is only used by the 'greedy' parser.
+    length :: Stream s t => s -> Int
+    length s = 
+        case uncons s of
+            Nothing -> 0
+            Just (x, xs) -> 1 + length xs
+
+newtype Parser s a = 
+    Parser { 
+        parse :: Maybe s -> [Result s a]
+    }
+
+instance Monoid (Parser s a) where
+    mempty = mzero
+    mappend = mplus
+
+instance Functor (Parser s) where
+    fmap f (Parser p) = Parser $ \s -> map (fmap f) (p s)
+
+instance Applicative (Parser s) where
+    pure = return 
+    (<*>) = ap
+
+instance Alternative (Parser s) where
+    empty = mzero
+    (<|>) = mplus
+
+instance Monad (Parser s) where
+    return v = Parser $ \s -> [Done v s] 
+    (Parser p) >>= f = Parser $ p >=> g
+        where
+            g (Fail m l) = [Fail m l]
+            g (Done a s) = parse (f a) s 
+            g (Partial p) = [Partial $ p >=> g] 
+
+instance MonadPlus (Parser s) where
+    mzero = Parser $ const []
+    mplus (Parser p1) (Parser p2) = Parser (\s -> p1 s ++ p2 s)
+
+data Result s a 
+    -- | A @Partial@ wraps the same function as a Parser. Supply it with a @Just@
+    -- and it will continue parsing, or with a @Nothing@ and it will terminate.
+    =
+    Partial {
+        continue    :: Maybe s -> [Result s a]
+    } |
+    -- | A @Done@ contains the resultant @value@, and the @leftover@ stream, if any.
+    Done {
+        value       :: a,
+        leftover    :: Maybe s
+    } |
+    -- | A @Fail@ contains a stack of error messages, and the @lftover@ stream, if any.
+    Fail {
+        messages    :: [String],
+        leftover    :: Maybe s
+    }
+
+isDone :: Result s a -> Bool
+isDone (Done _ _) = True
+isDone _ = False
+
+isPartial :: Result s a -> Bool
+isPartial (Partial _) = True
+isPartial _ = False
+
+isFail :: Result s a -> Bool
+isFail (Fail _ _) = True
+isFail _ = False
+
+instance Functor (Result s) where
+    fmap f (Partial p) = Partial $ map (fmap f) . p
+    fmap f (Done a s) = Done (f a) s
+    fmap f (Fail m l) = Fail m l
+
+instance Show a => Show (Result s a) where
+    show (Partial _) = "Partial"
+    show (Done a _) = show a
+    show (Fail m l) = "Fail: \nIn: " ++ intercalate "\nIn: " m
+
+-- | @finalize@ takes a list of results (presumably returned from a 'Parser' or 'Partial',
+-- and supplies @Nothing@ to any remaining @Partial@ values, so that only 'Fail' and 'Done'
+-- values remain.
+finalize :: (Eq s, Monoid s) => [Result s a] -> [Result s a]
+finalize = extend Nothing
+
+-- | @extend@ takes a @Maybe s@ as input, and supplies the input to all values
+-- in the 'Result' list. For 'Done' and 'Fail' values, it appends the @stream@ 
+-- to the 'leftover' portion, and for 'Partial' values, it runs the continuation,
+-- adding in any new 'Result' values to the output.
+extend :: (Eq s, Monoid s) => Maybe s -> [Result s a] -> [Result s a]
+extend s rs = rs >>= g --`prnt` (show (map i rs, map i (rs >>= g), h s))
+    where
+        g (Fail m l) = [Fail m (f l s)]
+        g (Partial p) = p s
+        g (Done a s') = [Done a (f s' s)]
+        f Nothing _ = Nothing
+        f (Just s) Nothing = if s == mempty then Nothing else Just s
+        f s s' = mappend s s'
+
+-- | @rename@ pushes a new error message onto the stack in case of failure.
+-- This is particularly useful when debugging a complex 'Parser'.
+rename :: String -> Parser s a -> Parser s a
+rename s p = Parser (map g . parse p)
+    where
+        g v@(Fail m l) = Fail (s:m) l
+        g v = v
+
+
+infixl 0 <?>
+-- | The infix version of 'rename'
+(<?>) :: Parser s a -> String -> Parser s a
+p <?> s = rename s p
diff --git a/src/Data/JustParse/Language.hs b/src/Data/JustParse/Language.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/JustParse/Language.hs
@@ -0,0 +1,169 @@
+{-|
+Module      : Data.JustParse.Language
+Description : Regular Expressions and Grammars in JustParse
+Copyright   : Copyright Waived
+License     : PublicDomain
+Maintainer  : grantslatton@gmail.com
+Stability   : experimental
+Portability : portable
+
+Takes ideas from the field of Formal Languages and imports them into the parsing library.
+-}
+
+{-# LANGUAGE Safe #-}
+module Data.JustParse.Language (
+    Match (..),
+    regex,
+    regex'
+) where
+
+import Data.JustParse.Common ( char, string, many1, digit, Stream, noneOf, oneOf, greedy, many, mN, anyChar, leftover, value, finalize, parse, Result(..), justParse, isFail )
+import Data.JustParse.Internal( Parser (..) )
+import Control.Applicative ( (<|>), optional )
+import Control.Monad ( liftM, mzero )
+import Data.Monoid ( Monoid, mconcat, mempty, mappend )
+import Data.Maybe ( isJust )
+import Data.List ( intercalate )
+
+-- | @regex@ takes a regular expression in the form of a 'String' and,
+-- if the regex is valid, returns a 'Parser' that parses that regex.
+-- If the regex is invalid, it returns a Parser that will only return
+-- 'Fail' with an \"Invalid Regex\" message.
+regex :: Stream s Char => String -> Parser s Match
+regex s 
+    | null r = Parser $ \s -> [Fail ["Invalid Regex"] s]
+    | isFail $ head r = Parser $ \s -> [Fail ["Invalid Regex"] s]
+    | isJust $ leftover $ head r = Parser $ \s -> [Fail ["Invalid Regex"] s]
+    | otherwise = value $ head r
+    where
+        r = finalize (parse (greedy regular) (Just s))
+
+-- | The same as 'regex', but only returns the full matched text.
+regex' :: Stream s Char => String -> Parser s String
+regex' = liftM matched . regex 
+
+-- | The result of a 'regex'
+data Match = 
+    Match {
+        -- | The complete text matched within the regex
+        matched :: String,
+        -- | Any submatches created by using capture groups
+        groups :: [Match]
+    } 
+
+instance Show Match where
+    show = show' ""
+        where
+            show' i (Match m []) = i ++ m
+            show' i (Match m gs) = i ++ m ++ "\n" ++ intercalate "\n" (map (show' ('\t':i)) gs)
+
+-- mconcat makes things very nice for concatenating the results of subregexes
+instance Monoid Match where
+    mempty = Match "" []
+    mappend (Match m g) (Match m' g') = 
+        Match {
+            matched = m ++ m',
+            groups = g ++ g'
+        }
+
+regular :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)
+regular = liftM (liftM mconcat . sequence) (greedy $ many parser)
+
+parser :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)
+parser = character <|> charClass <|> negCharClass <|> question <|> group <|> asterisk <|> plus <|> mn <|> period <|> pipe
+
+parserNP :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)
+parserNP = character <|> charClass <|> negCharClass <|> question <|> group <|> asterisk <|> plus <|> mn <|> period 
+
+restricted :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)
+restricted = character <|> charClass <|> negCharClass <|> group <|> period
+
+unreserved :: Stream s Char => Parser s Char 
+unreserved = (char '\\' >> anyChar ) <|> noneOf "()[]\\*+{}^?:<>|."
+
+character :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)
+character = 
+    do
+        c <- unreserved
+        return $ do
+            c' <- char c
+            return $ Match [c] []
+
+charClass :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)
+charClass = 
+    do
+        char '['
+        c <- greedy (many1 unreserved)
+        char ']'
+        return $ do
+            c' <- oneOf c
+            return $ Match [c'] []
+
+negCharClass :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)
+negCharClass = 
+    do
+        string "[^"
+        c <- greedy (many1 unreserved)
+        char ']'
+        return $ do
+            c' <- noneOf c
+            return $ Match [c'] []
+
+period :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)
+period = 
+    do
+        char '.'
+        return $ do
+            c <- noneOf "\n\r"
+            return $ Match [c] []
+
+
+question :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)
+question = 
+    do
+        p <- restricted
+        char '?'
+        return $ liftM mconcat (mN 0 1 p)
+
+group :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)
+group = 
+    do
+        string "("
+        p <- regular
+        char ')'
+        return $ do
+            r <- p
+            return $ r { groups = [r] } 
+
+asterisk :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)
+asterisk = 
+    do
+        p <- restricted
+        char '*'
+        return $ liftM mconcat (many p)
+
+plus :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)
+plus = 
+    do
+        p <- restricted
+        char '+'
+        return $ liftM mconcat (many1 p)
+
+mn :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)
+mn = 
+    do
+        p <- restricted
+        char '{'
+        l <- optional (many1 digit)
+        char ','
+        r <- optional (many1 digit)
+        char '}'
+        return $ liftM mconcat (mN (maybe 0 read l) (maybe (-1) read r) p)
+
+pipe :: (Stream s0 Char, Stream s1 Char) => Parser s0 (Parser s1 Match)
+pipe = 
+    do
+        p <- parserNP
+        char '|'
+        p' <- parser
+        return $ p <|> p'
