module Text.LaTeX.Base.Parser
( parseLaTeX
, ParseError (..)
) where
import Text.LaTeX.Base.Syntax
import Text.Parsec
import Text.Parsec.Text
import Control.Applicative hiding ((<|>),many)
import Data.Monoid
import Data.String
import Data.Text
p_Comm :: Parser LaTeX
p_Comm = do
char '\\'
str <- many1 alphaNum
args <- try (string "{}" >> return [])
<|> (many1 p_Arg)
return $ TeXComm str args
p_CommS :: Parser LaTeX
p_CommS = do
char '\\'
TeXCommS <$> many1 alphaNum
p_Env :: Parser LaTeX
p_Env = do
string "\\begin{"
str <- many1 alphaNum
char '}'
args <- many p_Arg
ls <- manyTill p_TeXU $ try $ string $ "\\end{" ++ str ++ "}"
return $ TeXEnv str args $ mconcat ls
p_Math :: Parser LaTeX
p_Math = do
char '$'
TeXMath . mconcat <$> manyTill p_TeXU (char '$')
p_NewLine :: Parser LaTeX
p_NewLine = do
string "\\\\"
fmap TeXNewLine $ (char '*' >> return True) <|> return False
p_RawG :: [Char] -> Parser LaTeX
p_RawG xs = TeXRaw . fromString <$> manyTill anyChar (lookAhead $ (oneOf xs >> return mempty) <|> p_TeXURaw)
p_Raw :: Parser LaTeX
p_Raw = p_RawG []
p_RawNC :: Parser LaTeX
p_RawNC = p_RawG ","
p_TeXU :: Parser LaTeX
p_TeXU = choice $ try <$> [p_NewLine , p_Math , p_Env , p_Comm , p_CommS , p_Raw]
p_TeXURaw :: Parser LaTeX
p_TeXURaw = choice $ try <$> [p_NewLine , p_Math , p_Env , p_Comm , p_CommS]
p_TeX :: Parser LaTeX
p_TeX = mconcat <$> many p_TeXU
p_TeXUNC :: Parser LaTeX
p_TeXUNC = choice $ try <$> [p_NewLine , p_Math , p_Env , p_Comm , p_CommS , p_RawNC]
p_TeXNC :: Parser LaTeX
p_TeXNC = mconcat <$> many p_TeXUNC
p_SimpleArg :: (Char,Char) -> (LaTeX -> TeXArg) -> Parser TeXArg
p_SimpleArg (c1,c2) f = do
char c1
fmap (f . mconcat) $ manyTill (p_TeXURaw <|> p_RawG [c2]) $ char c2
p_MultiArg :: (Char,Char) -> ([LaTeX] -> TeXArg) -> Parser TeXArg
p_MultiArg (c1,c2) f = do
char c1
fmap f $ sepBy1 (mconcat <$> manyTill p_TeXUNC (char c2)) $ char ','
p_Opt :: Parser TeXArg
p_Opt = p_SimpleArg ('[',']') OptArg
p_MOpt :: Parser TeXArg
p_MOpt = p_MultiArg ('[',']') MOptArg
p_Fix :: Parser TeXArg
p_Fix = p_SimpleArg ('{','}') FixArg
p_Sym :: Parser TeXArg
p_Sym = p_SimpleArg ('<','>') SymArg
p_MSym :: Parser TeXArg
p_MSym = p_MultiArg ('<','>') MSymArg
p_Arg :: Parser TeXArg
p_Arg = choice $ try <$> [ p_MOpt , p_MSym , p_Opt , p_Fix , p_Sym ]
parseLaTeX :: Text -> Either ParseError LaTeX
parseLaTeX = parse (p_TeX >>= \l -> eof >> return l) "LaTeX input"