module Language.ClaferT
( ClaferEnv(..)
, irModuleTrace
, uidIClaferMap
, 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.Except
import Control.Monad.Identity
import Control.Monad.State
import Data.List
import qualified Data.Map as Map
import Language.Clafer.ClaferArgs
import Language.Clafer.Common
import Language.Clafer.Front.AbsClafer
import Language.Clafer.Front.LexClafer
import Language.Clafer.Intermediate.Intclafer
import Language.Clafer.Intermediate.Tracing
data ClaferEnv
= ClaferEnv
{ args :: ClaferArgs
, modelFrags :: [String]
, cAst :: Maybe Module
, cIr :: Maybe (IModule, GEnv, Bool)
, frags :: [Pos]
, astModuleTrace :: Map.Map Span [Ast]
, otherTokens :: [Token]
} deriving Show
irModuleTrace :: ClaferEnv -> Map.Map Span [Ir]
irModuleTrace env = traceIrModule $ getIModule $ cIr env
where
getIModule (Just (imodule, _, _)) = imodule
getIModule Nothing = error "BUG: irModuleTrace: cannot request IR map before desugaring."
uidIClaferMap :: ClaferEnv -> UIDIClaferMap
uidIClaferMap env = createUidIClaferMap $ getIModule $ cIr env
where
getIModule (Just (iModule, _, _)) = iModule
getIModule Nothing = error "BUG: uidIClaferMap: cannot request IClafer map before desugaring."
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 = []
, astModuleTrace = Map.empty
, otherTokens = []
}
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 = ExceptT 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
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 -> return $ ErrPos 1 noPos noPos
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 (runExceptT 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'