module Language.ClaferT (
ClaferEnv(..),
makeEnv,
getAst,
getIr,
ClaferM,
ClaferT,
CErr(..),
CErrs(..),
ClaferErr,
ClaferErrs,
ClaferSErr,
ClaferSErrs,
ErrPos(..),
PartialErrPos(..),
throwErrs,
throwErr,
catchErrs,
getEnv,
getsEnv,
modifyEnv,
putEnv,
runClafer,
runClaferT,
Throwable(..),
Span(..),
Pos(..)
) where
import Control.Monad.Error
import Control.Monad.State
import Control.Monad.Identity
import Data.List
import Data.Map (Map)
import qualified Data.Map as Map
import Language.Clafer.Common
import Language.Clafer.Front.Absclafer
import Language.Clafer.Intermediate.Tracing
import Language.Clafer.Intermediate.Intclafer
import Language.Clafer.ClaferArgs
data ClaferEnv = ClaferEnv {
args :: ClaferArgs,
modelFrags :: [String],
cAst :: Maybe Module,
cIr :: Maybe (IModule, GEnv, Bool),
frags :: [Pos],
irModuleTrace :: Map Span [Ir],
astModuleTrace :: Map Span [Ast]
} deriving Show
getAst :: (Monad m) => ClaferT m Module
getAst = do
env <- getEnv
case cAst env of
(Just a) -> return a
_ -> throwErr (ClaferErr "No AST. Did you forget to add fragments or parse?" :: CErr Span)
getIr :: (Monad m) => ClaferT m (IModule, GEnv, Bool)
getIr = do
env <- getEnv
case cIr env of
(Just i) -> return i
_ -> throwErr (ClaferErr "No IR. Did you forget to compile?" :: CErr Span)
makeEnv :: ClaferArgs -> ClaferEnv
makeEnv args' = ClaferEnv { args = args'',
modelFrags = [],
cAst = Nothing,
cIr = Nothing,
frags = [],
irModuleTrace = Map.empty,
astModuleTrace = Map.empty}
where
args'' = if (CVLGraph `elem` (mode args') ||
Html `elem` (mode args') ||
Graph `elem` (mode args'))
then args'{keep_unused=True}
else args'
type ClaferM = ClaferT Identity
type ClaferT m = ErrorT ClaferErrs (StateT ClaferEnv m)
type ClaferErr = CErr ErrPos
type ClaferErrs = CErrs ErrPos
type ClaferSErr = CErr Span
type ClaferSErrs = CErrs Span
data CErr p =
ClaferErr {
msg :: String
} |
ParseErr {
pos :: p,
msg :: String
} |
SemanticErr {
pos :: p,
msg :: String
}
deriving Show
data CErrs p =
ClaferErrs {errs :: [CErr p]}
deriving Show
instance Error (CErr p) where
strMsg = ClaferErr
instance Error (CErrs p) where
strMsg m = ClaferErrs [strMsg m]
data ErrPos =
ErrPos {
fragId :: Int,
fragPos :: Pos,
modelPos :: Pos
}
deriving Show
data PartialErrPos =
ErrFragPos {
pFragId :: Int,
pFragPos :: Pos
} |
ErrFragSpan {
pFragId :: Int,
pFragSpan :: Span
} |
ErrModelPos {
pModelPos :: Pos
}
|
ErrModelSpan {
pModelSpan :: Span
}
deriving Show
class ClaferErrPos p where
toErrPos :: Monad m => p -> ClaferT m ErrPos
instance ClaferErrPos Span where
toErrPos = toErrPos . ErrModelSpan
instance ClaferErrPos ErrPos where
toErrPos = return . id
instance ClaferErrPos PartialErrPos where
toErrPos (ErrFragPos frgId frgPos) =
do
f <- getsEnv frags
let pos' = ((Pos 1 1 : f) !! frgId) `addPos` frgPos
return $ ErrPos frgId frgPos pos'
toErrPos (ErrFragSpan frgId (Span frgPos _)) = toErrPos $ ErrFragPos frgId frgPos
toErrPos (ErrModelPos modelPos') =
do
f <- getsEnv frags
let fragSpans = zipWith Span (Pos 1 1 : f) f
case findFrag modelPos' fragSpans of
Just (frgId, Span fragStart _) -> return $ ErrPos frgId (modelPos' `minusPos` fragStart) modelPos'
Nothing -> error $ show modelPos' ++ " not within any frag spans: " ++ show fragSpans
where
findFrag pos'' spans =
find (inSpan pos'' . snd) (zip [0..] spans)
toErrPos (ErrModelSpan (Span modelPos'' _)) = toErrPos $ ErrModelPos modelPos''
class Throwable t where
toErr :: t -> Monad m => ClaferT m ClaferErr
instance ClaferErrPos p => Throwable (CErr p) where
toErr (ClaferErr mesg) = return $ ClaferErr mesg
toErr err =
do
pos' <- toErrPos $ pos err
return $ err{pos = pos'}
throwErrs :: (Monad m, Throwable t) => [t] -> ClaferT m a
throwErrs throws =
do
errors <- mapM toErr throws
throwError $ ClaferErrs errors
throwErr :: (Monad m, Throwable t) => t -> ClaferT m a
throwErr throw = throwErrs [throw]
catchErrs :: Monad m => ClaferT m a -> ([ClaferErr] -> ClaferT m a) -> ClaferT m a
catchErrs e h = e `catchError` (h . errs)
addPos :: Pos -> Pos -> Pos
addPos (Pos l c) (Pos 1 d) = Pos l (c + d 1)
addPos (Pos l _) (Pos m d) = Pos (l + m 1) d
minusPos :: Pos -> Pos -> Pos
minusPos (Pos l c) (Pos 1 d) = Pos l (c d + 1)
minusPos (Pos l c) (Pos m _) = Pos (l m + 1) c
inSpan :: Pos -> Span -> Bool
inSpan pos' (Span start end) = pos' >= start && pos' <= end
getEnv :: Monad m => ClaferT m ClaferEnv
getEnv = get
getsEnv :: Monad m => (ClaferEnv -> a) -> ClaferT m a
getsEnv = gets
modifyEnv :: Monad m => (ClaferEnv -> ClaferEnv) -> ClaferT m ()
modifyEnv = modify
putEnv :: Monad m => ClaferEnv -> ClaferT m ()
putEnv = put
runClaferT :: Monad m => ClaferArgs -> ClaferT m a -> m (Either [ClaferErr] a)
runClaferT args' exec =
mapLeft errs `liftM` evalStateT (runErrorT exec) (makeEnv args')
where
mapLeft :: (a -> c) -> Either a b -> Either c b
mapLeft f (Left l) = Left (f l)
mapLeft _ (Right r) = Right r
runClafer :: ClaferArgs -> ClaferM a -> Either [ClaferErr] a
runClafer args' = runIdentity . runClaferT args'