+parseIRCMessage :: String -> Either [Error] IRCMessage
+parseIRCMessage s = case runParser parsePrefix (fromString s) of
+ ([(prefix, rest):_], _)
+ = case parse parseReply rest of
+ Left e = case parseCmd rest of
+ Left e2 = Left $ e2 ++ e
+ Right cmd = Right {IRCMessage | irc_prefix=prefix, irc_command=Right cmd}
+ Right repl = Right {IRCMessage | irc_prefix=prefix, irc_command=Left repl}
+ (_, es) = Left ["couldn't parse prefix":es]
+
+parsePrefix :: Parser Char (Maybe (Either IRCUser String))
+parsePrefix = optional (pToken ':' >>| parseEither parseUser parseHost) <* pToken ' '
+
+pOne [] = (Left ["Expected an argument"], [])
+pOne [a:as] = (Right a, as)
+
+generic gIRCParse a :: [String] -> (Either [Error] a, [String])
+gIRCParse{|UNIT|} a = (Right UNIT, a)
+gIRCParse{|String|} as = pOne as
+gIRCParse{|Int|} as = appFst (fmap toInt) $ pOne as
+gIRCParse{|EITHER|} lp rp as = case lp as of
+ (Right a, rest) = (Right $ LEFT a, rest)
+ (Left e1, _) = case rp as of
+ (Right a, rest) = (Right $ RIGHT a, rest)
+ (Left e2, _) = (Left $ e1 ++ e2, [])
+gIRCParse{|OBJECT|} p as = appFst (fmap OBJECT) $ p as
+gIRCParse{|CONS of d|} p [] = (Left ["Expected a cmd constructor: " +++ d.gcd_name], [])
+gIRCParse{|CONS of d|} p [a:as]
+| a <> d.gcd_name = (Left ["Wrong constructor. expected: " +++ d.gcd_name +++ ", got: " +++ a], [])
+= case p as of
+ (Right a, rest) = (Right $ CONS a, rest)
+ (Left e, _) = (Left e, [])
+gIRCParse{|PAIR|} pl pr as = case pl as of
+ (Right a1, rest) = case pr rest of
+ (Right a2, rest) = (Right $ PAIR a1 a2, rest)
+ (Left e, _) = (Left e, [])
+ (Left e, _) = (Left e, [])
+gIRCParse{|[]|} pl as = case pl as of
+ (Right e, rest) = case gIRCParse{|*->*|} pl rest of
+ (Right es, rest) = (Right [e:es], rest)
+ (Left e, _) = (Left e, [])
+ (Left e, _) = (Right [], as)
+gIRCParse{|Maybe|} pm as
+ = appFst (either (const $ Right Nothing) $ Right o Just) $ pm as
+
+derive gIRCParse (,), (,,), IRCCommand
+
+parseCmd :: [Char] -> Either [Error] IRCCommand
+parseCmd cs = fst $ gIRCParse{|*|} $ argfun $ split " " $ toString cs
+ where
+ argfun :: [String] -> [String]
+ argfun [] = []
+ argfun [x:xs]
+ # x = trim x
+ | x.[0] == ':' = [jon " " $ [x:map rtrim xs]]
+ | otherwise = [x:argfun xs]
+
+parseReply :: Parser Char IRCNumReply
+parseReply = (toString <$> pSome pDigit)
+ >>= \rep->pMiddle
+ >>= \recipient->spaceParser >>| (toString <$> pSome (pNoneOf illegal))
+ >>= \msg->pure {IRCNumReply|irc_reply=fs rep,irc_recipient=recipient,irc_message=msg}
+ where
+ fs :: String -> IRCReplies
+ fs s = fromInt $ toInt s
+//