module Camfort.Specification.Stencils.CheckBackend where
import Camfort.Specification.Stencils.Syntax
import Camfort.Specification.Stencils.Model
import qualified Camfort.Specification.Stencils.Grammar as SYN
type ErrorMsg = String
class SynToAst s t | s -> t where
synToAst :: (?renv :: RegionEnv) => s -> Either ErrorMsg t
instance SynToAst SYN.Specification (Either RegionEnv SpecDecls) where
synToAst (SYN.SpecDec spec vars) = do
spec' <- synToAst spec
return $ Right [(vars, spec')]
synToAst (SYN.RegionDec rvar region) = do
spec' <- synToAst region
return $ Left [(rvar, spec')]
instance SynToAst SYN.Spec Specification where
synToAst (SYN.Spatial mods r) = do
(modLinear, approx) <- synToAst mods
r' <- synToAst r
let s' = Spatial r'
return $ Specification $ addLinearity modLinear $
case approx of
Just SYN.AtMost -> Bound Nothing (Just s')
Just SYN.AtLeast -> Bound (Just s') Nothing
Nothing -> Exact s'
where
addLinearity Linear appr = Once appr
addLinearity NonLinear appr = Mult appr
instance SynToAst SYN.Region RegionSum where
synToAst = dnf
dnf :: (?renv :: RegionEnv) => SYN.Region -> Either ErrorMsg RegionSum
dnf (SYN.And r1 r2) = do
r1' <- dnf r1
r2' <- dnf r2
return $ Sum $ unSum r1' >>= (\(Product ps1) ->
unSum r2' >>= (\(Product ps2) ->
return $ Product $ ps1 ++ ps2))
dnf (SYN.Or r1 r2) = do
r1' <- dnf r1
r2' <- dnf r2
return $ Sum $ unSum r1' ++ unSum r2'
dnf (SYN.Forward dep dim reflx) = return $ Sum [Product [Forward dep dim reflx]]
dnf (SYN.Backward dep dim reflx) = return $ Sum [Product [Backward dep dim reflx]]
dnf (SYN.Centered dep dim reflx) = return $ Sum [Product [Centered dep dim reflx]]
dnf (SYN.Var v) =
case lookup v ?renv of
Nothing -> Left $ "Error: region " ++ v ++ " is not in scope."
Just rs -> return rs
instance SynToAst [SYN.Mod]
(Linearity, Maybe SYN.Mod) where
synToAst mods = return (linearity, approx)
where
linearity = if SYN.ReadOnce `elem` mods then Linear else NonLinear
approx = find' isApprox mods
isApprox SYN.AtMost = Just SYN.AtMost
isApprox SYN.AtLeast = Just SYN.AtLeast
isApprox _ = Nothing
find' :: Eq a => (a -> Maybe b) -> [a] -> Maybe b
find' p [] = Nothing
find' p (x : xs) =
case p x of
Nothing -> find' p xs
Just b -> Just b