✅ Checking
This commit is contained in:
@ -1,13 +1,87 @@
|
|||||||
module APL.Check (checkExp, Error) where
|
module APL.Check (checkExp, Error) where
|
||||||
|
|
||||||
import APL.AST (Exp (..), VName)
|
import APL.AST (Exp (..), VName)
|
||||||
|
import Control.Monad (ap, liftM)
|
||||||
|
|
||||||
|
type Vars = [VName]
|
||||||
|
|
||||||
|
varsEmpty :: Vars
|
||||||
|
varsEmpty = []
|
||||||
|
|
||||||
type Error = String
|
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 :: 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 :: Exp -> Maybe Error
|
||||||
checkExp = undefined
|
checkExp e =
|
||||||
|
case runCheck $ check e of
|
||||||
|
Left err -> Just err
|
||||||
|
_ -> Nothing
|
||||||
|
@ -23,4 +23,23 @@ tests :: TestTree
|
|||||||
tests =
|
tests =
|
||||||
testGroup
|
testGroup
|
||||||
"Checking"
|
"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"))
|
||||||
|
]
|
||||||
|
Reference in New Issue
Block a user