module Helium.Parser.LexerMonad
( LexerMonad
, getPos, incPos, nextPos, addPos
, openBracket, closeBracket, checkBracketsAtEOF
, lexerError, lexerWarning
, runLexerMonad
, getOpts
) where
import Helium.Main.Args
import Helium.Parser.LexerMessage
import Text.ParserCombinators.Parsec.Pos
type Bracket = (SourcePos, Char)
newtype LexerMonad a =
LM ([Option] -> SourcePos -> [Bracket] ->
Either LexerError (a, [LexerWarning], SourcePos, [Bracket]))
unLM :: LexerMonad t -> [Option] -> SourcePos -> [Bracket]
-> Either LexerError (t, [LexerWarning], SourcePos, [Bracket])
unLM (LM x) = x
bindLM :: LexerMonad a -> (a -> LexerMonad b) -> LexerMonad b
bindLM (LM f) g =
LM (\opts pos brackets ->
case f opts pos brackets of
Left err -> Left err
Right (a, warnings, pos2, brackets2) ->
case unLM (g a) opts pos2 brackets2 of
Left err -> Left err
Right (b, moreWarnings, pos3, brackets3) ->
Right (b, warnings ++ moreWarnings, pos3, brackets3))
returnLM :: a -> LexerMonad a
returnLM x = LM (\_ pos brackets -> Right (x, [], pos, brackets))
instance Monad LexerMonad where
(>>=) = bindLM
return = returnLM
runLexerMonad :: [Option] -> String -> LexerMonad a -> Either LexerError (a, [LexerWarning])
runLexerMonad opts fileName (LM f) =
case f opts (initialPos fileName) [] of
Left err -> Left err
Right (a, warnings, _, _) -> Right (a, keepOneTabWarning warnings)
getOpts :: LexerMonad [Option]
getOpts = LM (\opts pos brackets -> Right (opts, [], pos, brackets))
getPos :: LexerMonad SourcePos
getPos = LM (\_ pos brackets -> Right (pos, [], pos, brackets))
incPos :: Int -> LexerMonad ()
incPos i = LM (\_ pos brackets -> Right ((), [], addPos i pos, brackets))
nextPos :: Char -> LexerMonad ()
nextPos c = LM (\_ pos brackets -> Right ( (), [], updatePosChar pos c, brackets ))
lexerError :: LexerErrorInfo -> SourcePos -> LexerMonad a
lexerError err pos =
LM (\_ _ _ -> Left (LexerError pos err))
lexerWarning :: LexerWarningInfo -> SourcePos -> LexerMonad ()
lexerWarning warning warningPos =
LM (\_ pos brackets ->
Right ((), [LexerWarning warningPos warning], pos, brackets))
addPos :: Int -> SourcePos -> SourcePos
addPos i pos = incSourceColumn pos i
openBracket :: Char -> LexerMonad ()
openBracket c = LM (\_ pos brackets ->
Right ( (), [], pos, (pos, c) : brackets ))
closeBracket :: Char -> LexerMonad ()
closeBracket c = LM (\_ pos brackets ->
case brackets of
[] -> Left (LexerError pos (TooManyClose c))
(pos2, c2):rest
| matchBracket c2 c ->
Right ((), [], pos, rest)
| otherwise ->
Left (LexerError pos (UnexpectedClose c pos2 c2))
)
checkBracketsAtEOF :: LexerMonad ()
checkBracketsAtEOF = LM (\_ pos brackets ->
case brackets of
[] -> Right ((), [], pos, [])
_ -> Left (LexerError pos (StillOpenAtEOF brackets))
)
matchBracket :: Char -> Char -> Bool
matchBracket '(' ')' = True
matchBracket '[' ']' = True
matchBracket '{' '}' = True
matchBracket _ _ = False