Checking

This commit is contained in:
2024-09-20 16:34:10 +02:00
parent 234ec39985
commit 69b947f966
2 changed files with 97 additions and 4 deletions

View File

@ -1,13 +1,87 @@
module APL.Check (checkExp, Error) where
import APL.AST (Exp (..), VName)
import Control.Monad (ap, liftM)
type Vars = [VName]
varsEmpty :: Vars
varsEmpty = []
type Error = String
newtype CheckM a = CheckM () -- TODO - give this a proper definition.
newtype CheckM a = CheckM (Vars -> Either Error a)
instance Functor CheckM where
fmap = liftM
instance Applicative CheckM where
pure x = CheckM $ \_vars -> Right x
(<*>) = ap
instance Monad CheckM where
CheckM x >>= f = CheckM $ \vars ->
case x vars of
Left err -> Left err
Right x' ->
let CheckM y = f x'
in y vars
elem' :: VName -> [VName] -> Bool
elem' _ [] = False
elem' x (y : ys) = if x == y then True else elem' x ys
askVars :: CheckM Vars
askVars = CheckM $ \vars -> Right vars
varsExtend :: VName -> Vars -> Vars
varsExtend v vars = v : vars
localVars :: (Vars -> Vars) -> CheckM a -> CheckM a
localVars f (CheckM m) = CheckM $ \vars -> m (f vars)
checkBinOp :: Exp -> Exp -> CheckM ()
checkBinOp e1 e2 = do
_ <- check e1
check e2
checkTriOp :: Exp -> Exp -> Exp -> CheckM ()
checkTriOp e1 e2 e3 = do
_ <- check e1
_ <- check e2
check e3
check :: Exp -> CheckM ()
check = undefined
check (CstInt _) = CheckM $ \_vars -> pure ()
check (CstBool _) = CheckM $ \_vars -> pure ()
check (Add e1 e2) = checkBinOp e1 e2
check (Sub e1 e2) = checkBinOp e1 e2
check (Mul e1 e2) = checkBinOp e1 e2
check (Div e1 e2) = checkBinOp e1 e2
check (Pow e1 e2) = checkBinOp e1 e2
check (Eql e1 e2) = checkBinOp e1 e2
check (If e1 e2 e3) = checkTriOp e1 e2 e3
check (Apply e1 e2) = checkBinOp e1 e2
check (TryCatch e1 e2) = checkBinOp e1 e2
check (Print _ e1) = check e1
check (KvGet e1) = check e1
check (KvPut e1 e2) = checkBinOp e1 e2
check (Var v) = do
vars <- askVars
if elem' v vars
then pure ()
else CheckM $ \_vars -> Left $ "Variable not in scope: "++v
check (Let var e1 e2) = do
_ <- check e1
localVars (varsExtend var) $ check e2
check (Lambda var e1) = do
localVars (varsExtend var) $ check e1
runCheck :: CheckM a -> Either Error a
runCheck (CheckM m) = m varsEmpty
checkExp :: Exp -> Maybe Error
checkExp = undefined
checkExp e =
case runCheck $ check e of
Left err -> Just err
_ -> Nothing

View File

@ -23,4 +23,23 @@ tests :: TestTree
tests =
testGroup
"Checking"
[]
[
testPos (CstBool True),
testNeg (Var "x"),
testPos (Let "x" (CstInt 3) (CstInt 5)),
testPos (Let "x" (CstInt 3) (Var "x")),
testNeg (Let "x" (Var "y") (Var "x")),
testNeg (Let "x" (CstInt 3) (Var "y")),
testPos (Add (Sub (CstInt 9) (CstInt 6)) (CstInt 11)),
testPos (Mul (Div (CstInt 9) (CstInt 3)) (CstInt 1)),
testNeg (Add (Add (CstInt 1) (Var "x")) (CstInt 1)),
testPos (If (CstInt 2) (CstInt 2) (CstInt 2)),
testNeg (If (Var "x") (CstInt 2) (CstInt 2)),
testNeg (If (CstInt 2) (Var "x") (CstInt 2)),
testNeg (If (CstInt 2) (CstInt 2) (Var "x")),
testPos (Lambda "x" (CstInt 5)),
testPos (Lambda "x" (Var "x")),
testNeg (Lambda "x" (Var "y")),
testPos (Apply (Lambda "x" (Var "x")) (CstInt 5)),
testNeg (Apply (Lambda "x" (Var "x")) (Var "x"))
]