module AST.Semantics.CheckCall (checkCall, checkEqualityOp,checkTypeof,
checkFFRead,
checkFFWrite,
checkOpen,
checkClose,
checkRead,
checkInput,
checkSizeof) where
import qualified Data.Text as DT
import qualified Data.Map.Strict as Map
import AST.Ast (Ast(..))
import AST.Semantics.Type
import Common.Type.Integer (IntValue(..))
import Data.Char (chr)
import Control.Monad (unless)
import Control.Applicative ((<|>))
type CheckExprFn = CheckEnv -> Ast -> Either String Type
checkCall :: CheckExprFn -> CheckEnv -> Ast -> [Ast] -> Either String Type
checkCall :: CheckExprFn -> CheckEnv -> Ast -> [Ast] -> Either String Type
checkCall CheckExprFn
checker CheckEnv
env (APos Int
_ Int
_ Ast
f) [Ast]
args = CheckExprFn -> CheckEnv -> Ast -> [Ast] -> Either String Type
checkCall CheckExprFn
checker CheckEnv
env Ast
f [Ast]
args
checkCall CheckExprFn
checker CheckEnv
env (ASymbol Text
name) [Ast]
args =
case CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkBuiltinOp CheckExprFn
checker CheckEnv
env Text
name [Ast]
args of
Just Either String Type
result -> Either String Type
result
Maybe (Either String Type)
Nothing -> CheckExprFn -> CheckEnv -> Text -> [Ast] -> Either String Type
checkUserFunc CheckExprFn
checker CheckEnv
env Text
name [Ast]
args
checkCall CheckExprFn
checker CheckEnv
env Ast
expr [Ast]
args = do
funcType <- CheckExprFn
checker CheckEnv
env Ast
expr
case funcType of
TyFunc [Type]
expectedArgs Type
retType ->
CheckExprFn
-> CheckEnv
-> Text
-> [Ast]
-> [Type]
-> Type
-> Either String Type
verifyFuncCall CheckExprFn
checker CheckEnv
env
(String -> Text
DT.pack String
"<anonymous_call>") [Ast]
args [Type]
expectedArgs Type
retType
Type
_ -> String -> Either String Type
forall a b. a -> Either a b
Left (String -> Either String Type) -> String -> Either String Type
forall a b. (a -> b) -> a -> b
$ String
"Error: expression is not a function ("
String -> String -> String
forall a. [a] -> [a] -> [a]
++ Type -> String
typeToString Type
funcType String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
checkBuiltinOp :: CheckExprFn -> CheckEnv -> DT.Text -> [Ast]
-> Maybe (Either String Type)
checkBuiltinOp :: CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkBuiltinOp CheckExprFn
c CheckEnv
e Text
n [Ast]
a =
case CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkMathComp CheckExprFn
c CheckEnv
e Text
n [Ast]
a of
Just Either String Type
res -> Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just Either String Type
res
Maybe (Either String Type)
Nothing -> CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkLogicSpecial CheckExprFn
c CheckEnv
e Text
n [Ast]
a
checkMathComp :: CheckExprFn -> CheckEnv -> DT.Text -> [Ast]
-> Maybe (Either String Type)
checkMathComp :: CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkMathComp CheckExprFn
c CheckEnv
e Text
n [Ast]
a
| Text
n Text -> [Text] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Text]
mathOps = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Type -> Type -> Either String Type
checkBinaryOp CheckExprFn
c CheckEnv
e Text
n [Ast]
a Type
TyInt Type
TyInt
| Text
n Text -> [Text] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Text]
compOps = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Type -> Type -> Either String Type
checkBinaryOp CheckExprFn
c CheckEnv
e Text
n [Ast]
a Type
TyInt Type
TyBool
| Bool
otherwise = Maybe (Either String Type)
forall a. Maybe a
Nothing
where
mathOps :: [Text]
mathOps = (String -> Text) -> [String] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map String -> Text
DT.pack [String
"+", String
"-", String
"*", String
"div", String
"mod"]
compOps :: [Text]
compOps = (String -> Text) -> [String] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map String -> Text
DT.pack [String
"<", String
">", String
"<=", String
">="]
checkPrint :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkPrint :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkPrint CheckExprFn
checker CheckEnv
env [Ast
arg] = do
_ <- CheckExprFn
checker CheckEnv
env Ast
arg
Right TyVoid
checkPrint CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"Function 'print' expects exactly 1 argument"
checkStrictOp :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkStrictOp :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkStrictOp CheckExprFn
checker CheckEnv
env [Ast
left, Ast
right] = do
_ <- CheckExprFn
checker CheckEnv
env Ast
left
_ <- checker env right
Right TyBool
checkStrictOp CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"Strict comparison operator expects 2 arguments"
checkLogicSpecial :: CheckExprFn -> CheckEnv -> DT.Text -> [Ast]
-> Maybe (Either String Type)
checkLogicSpecial :: CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkLogicSpecial CheckExprFn
c CheckEnv
e Text
n [Ast]
a
| Text
n Text -> [Text] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Text]
logicOps = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Type -> Type -> Either String Type
checkBinaryOp CheckExprFn
c CheckEnv
e Text
n [Ast]
a Type
TyBool Type
TyBool
| Text
n Text -> [Text] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Text]
strictOps = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkStrictOp CheckExprFn
c CheckEnv
e [Ast]
a
| Bool
otherwise = CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkKeywordFuncs CheckExprFn
c CheckEnv
e Text
n [Ast]
a
where
logicOps :: [Text]
logicOps = (String -> Text) -> [String] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map String -> Text
DT.pack [String
"&&", String
"||"]
strictOps :: [Text]
strictOps = (String -> Text) -> [String] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map String -> Text
DT.pack [String
"teq?", String
"tneq?"]
checkKeywordFuncs :: CheckExprFn -> CheckEnv -> DT.Text -> [Ast]
-> Maybe (Either String Type)
checkKeywordFuncs :: CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkKeywordFuncs CheckExprFn
c CheckEnv
e Text
n [Ast]
a =
CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkBaseOps CheckExprFn
c CheckEnv
e Text
n [Ast]
a Maybe (Either String Type)
-> Maybe (Either String Type) -> Maybe (Either String Type)
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkSystemOps CheckExprFn
c CheckEnv
e Text
n [Ast]
a Maybe (Either String Type)
-> Maybe (Either String Type) -> Maybe (Either String Type)
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkIOFuncs CheckExprFn
c CheckEnv
e Text
n [Ast]
a Maybe (Either String Type)
-> Maybe (Either String Type) -> Maybe (Either String Type)
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkDataFuncs CheckExprFn
c CheckEnv
e Text
n [Ast]
a
checkBaseOps :: CheckExprFn -> CheckEnv -> DT.Text -> [Ast]
-> Maybe (Either String Type)
checkBaseOps :: CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkBaseOps CheckExprFn
c CheckEnv
e Text
n [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"eq?" Bool -> Bool -> Bool
|| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"neq?" = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkEqualityOp CheckExprFn
c CheckEnv
e [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"!" = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Type -> Type -> Either String Type
checkUnaryOp CheckExprFn
c CheckEnv
e Text
n [Ast]
a Type
TyBool Type
TyBool
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"attr_update" = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkSetField CheckExprFn
c CheckEnv
e [Ast]
a
| Bool
otherwise = Maybe (Either String Type)
forall a. Maybe a
Nothing
checkSystemOps :: CheckExprFn -> CheckEnv -> DT.Text -> [Ast]
-> Maybe (Either String Type)
checkSystemOps :: CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkSystemOps CheckExprFn
c CheckEnv
e Text
n [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"print" = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkPrint CheckExprFn
c CheckEnv
e [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"exit" = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkExit CheckExprFn
c CheckEnv
e [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"typeof" = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkTypeof CheckExprFn
c CheckEnv
e [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"sizeof" = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkSizeof CheckExprFn
c CheckEnv
e [Ast]
a
| Bool
otherwise = Maybe (Either String Type)
forall a. Maybe a
Nothing
checkIOFuncs :: CheckExprFn -> CheckEnv -> DT.Text -> [Ast]
-> Maybe (Either String Type)
checkIOFuncs :: CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkIOFuncs CheckExprFn
c CheckEnv
e Text
n [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"ffread" = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkFFRead CheckExprFn
c CheckEnv
e [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"ffwrite" = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkFFWrite CheckExprFn
c CheckEnv
e [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"open" = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkOpen CheckExprFn
c CheckEnv
e [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"close" = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkClose CheckExprFn
c CheckEnv
e [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"read" = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkRead CheckExprFn
c CheckEnv
e [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"input" = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkInput CheckExprFn
c CheckEnv
e [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"write" = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkWrite CheckExprFn
c CheckEnv
e [Ast]
a
| Bool
otherwise = Maybe (Either String Type)
forall a. Maybe a
Nothing
checkDataFuncs :: CheckExprFn -> CheckEnv -> DT.Text -> [Ast]
-> Maybe (Either String Type)
checkDataFuncs :: CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Maybe (Either String Type)
checkDataFuncs CheckExprFn
c CheckEnv
e Text
n [Ast]
a
| Text
n Text -> [Text] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Text]
castOps = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Type -> Type -> Either String Type
checkUnaryOp CheckExprFn
c CheckEnv
e Text
n [Ast]
a Type
TyInt Type
TyInt
| Text
n Text -> [Text] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Text]
listOps = Either String Type -> Maybe (Either String Type)
forall a. a -> Maybe a
Just (Either String Type -> Maybe (Either String Type))
-> Either String Type -> Maybe (Either String Type)
forall a b. (a -> b) -> a -> b
$ CheckExprFn -> CheckEnv -> Text -> [Ast] -> Either String Type
checkListOps CheckExprFn
c CheckEnv
e Text
n [Ast]
a
| Bool
otherwise = Maybe (Either String Type)
forall a. Maybe a
Nothing
where
castOps :: [Text]
castOps = (String -> Text) -> [String] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map String -> Text
DT.pack [ String
"int8", String
"uint8", String
"int16", String
"uint16"
, String
"int32", String
"uint32", String
"int64", String
"uint64"
, String
"char", String
"uchar" ]
listOps :: [Text]
listOps = (String -> Text) -> [String] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map String -> Text
DT.pack [String
"cons", String
"head", String
"tail", String
"nth", String
"nth_update"]
checkListOps :: CheckExprFn -> CheckEnv -> DT.Text -> [Ast]
-> Either String Type
checkListOps :: CheckExprFn -> CheckEnv -> Text -> [Ast] -> Either String Type
checkListOps CheckExprFn
c CheckEnv
e Text
n [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"cons" = CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkCons CheckExprFn
c CheckEnv
e [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"head" = CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkHead CheckExprFn
c CheckEnv
e [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"tail" = CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkTail CheckExprFn
c CheckEnv
e [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"nth" = CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkNth CheckExprFn
c CheckEnv
e [Ast]
a
| Text
n Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"nth_update" = CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkUpdate CheckExprFn
c CheckEnv
e [Ast]
a
| Bool
otherwise = String -> Either String Type
forall a b. a -> Either a b
Left String
"Unknown list operator"
checkUpdate :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkUpdate :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkUpdate CheckExprFn
checker CheckEnv
env [Ast
lst, Ast
idx, Ast
val] = do
tLst <- CheckExprFn
checker CheckEnv
env Ast
lst
tIdx <- checker env idx
tVal <- checker env val
validateListUpdate tLst tIdx tVal
checkUpdate CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"update expects 3 arguments (list, index, value)"
validateListUpdate :: Type -> Type -> Type -> Either String Type
validateListUpdate :: Type -> Type -> Type -> Either String Type
validateListUpdate (TyList Type
inner) Type
tIdx Type
tVal
| Bool -> Bool
not (Type -> Type -> Bool
areTypesCompatible Type
TyInt Type
tIdx) =
String -> Either String Type
forall a b. a -> Either a b
Left String
"update index must be an integer"
| Type -> Type -> Bool
areTypesCompatible Type
inner Type
tVal = Type -> Either String Type
forall a b. b -> Either a b
Right (Type -> Type
TyList Type
inner)
| Bool
otherwise = String -> Either String Type
forall a b. a -> Either a b
Left (String -> Either String Type) -> String -> Either String Type
forall a b. (a -> b) -> a -> b
$ String
"Type mismatch in list update: expected " String -> String -> String
forall a. [a] -> [a] -> [a]
++
Type -> String
typeToString Type
inner String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" but got " String -> String -> String
forall a. [a] -> [a] -> [a]
++
Type -> String
typeToString Type
tVal
validateListUpdate Type
_ Type
_ Type
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"update expects a list as first argument"
checkExit :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkExit :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkExit CheckExprFn
checker CheckEnv
env [Ast
arg] = do
t <- CheckExprFn
checker CheckEnv
env Ast
arg
unless (areTypesCompatible TyInt t) $ Left "exit expects an integer code"
Right TyVoid
checkExit CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"exit expects 1 argument"
checkCons :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkCons :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkCons CheckExprFn
checker CheckEnv
env [Ast
el, Ast
lst] = do
tEl <- CheckExprFn
checker CheckEnv
env Ast
el
tLst <- checker env lst
case tLst of
TyList Type
inner -> if Type -> Type -> Bool
areTypesCompatible Type
inner Type
tEl
then Type -> Either String Type
forall a b. b -> Either a b
Right Type
tLst
else String -> Either String Type
forall a b. a -> Either a b
Left (String -> Either String Type) -> String -> Either String Type
forall a b. (a -> b) -> a -> b
$ String
"cons type mismatch: " String -> String -> String
forall a. [a] -> [a] -> [a]
++
Type -> String
typeToString Type
tEl String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" vs " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Type -> String
typeToString Type
inner
Type
_ -> String -> Either String Type
forall a b. a -> Either a b
Left String
"cons expects a list as second argument"
checkCons CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"cons expects 2 arguments"
checkHead :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkHead :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkHead CheckExprFn
checker CheckEnv
env [Ast
lst] = do
tLst <- CheckExprFn
checker CheckEnv
env Ast
lst
case tLst of
TyList Type
inner -> Type -> Either String Type
forall a b. b -> Either a b
Right Type
inner
Type
_ -> String -> Either String Type
forall a b. a -> Either a b
Left String
"head expects a list"
checkHead CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"head expects 1 argument"
checkTail :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkTail :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkTail CheckExprFn
checker CheckEnv
env [Ast
lst] = do
tLst <- CheckExprFn
checker CheckEnv
env Ast
lst
case tLst of
TyList Type
_ -> Type -> Either String Type
forall a b. b -> Either a b
Right Type
tLst
Type
_ -> String -> Either String Type
forall a b. a -> Either a b
Left String
"tail expects a list"
checkTail CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"tail expects 1 argument"
checkNth :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkNth :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkNth CheckExprFn
checker CheckEnv
env [Ast
lst, Ast
idx] = do
tLst <- CheckExprFn
checker CheckEnv
env Ast
lst
tIdx <- checker env idx
unless (areTypesCompatible TyInt tIdx) $ Left
"nth index must be an integer"
case tLst of
TyList Type
inner -> Type -> Either String Type
forall a b. b -> Either a b
Right Type
inner
Type
_ -> String -> Either String Type
forall a b. a -> Either a b
Left String
"nth expects a list as first argument"
checkNth CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"nth expects 2 arguments"
checkSetField :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkSetField :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkSetField CheckExprFn
checker CheckEnv
env [Ast
obj, Ast
fieldNameAst, Ast
val] = do
objType <- CheckExprFn
checker CheckEnv
env Ast
obj
case objType of
TyStruct Text
sName -> do
fieldName <- Ast -> Either String Text
extractStringFromAst Ast
fieldNameAst
checkFieldInStruct checker env sName fieldName val
Type
_ -> String -> Either String Type
forall a b. a -> Either a b
Left String
"attr_update expects a structure as first argument"
checkSetField CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"attr_update expects 3 arguments"
checkFieldInStruct :: CheckExprFn -> CheckEnv -> DT.Text -> DT.Text -> Ast
-> Either String Type
checkFieldInStruct :: CheckExprFn
-> CheckEnv -> Text -> Text -> Ast -> Either String Type
checkFieldInStruct CheckExprFn
checker CheckEnv
env Text
sName Text
fieldName Ast
val = do
def <- CheckEnv -> Text -> Either String StructDef
getStructDef CheckEnv
env Text
sName
case Map.lookup fieldName (structFields def) of
Just Type
expectedType ->
CheckExprFn
-> CheckEnv -> Ast -> Type -> Text -> Text -> Either String Type
validateAssignment CheckExprFn
checker CheckEnv
env Ast
val Type
expectedType Text
fieldName Text
sName
Maybe Type
Nothing -> String -> Either String Type
forall a b. a -> Either a b
Left (String -> Either String Type) -> String -> Either String Type
forall a b. (a -> b) -> a -> b
$ String
"Field '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Text -> String
DT.unpack Text
fieldName String -> String -> String
forall a. [a] -> [a] -> [a]
++
String
"' not found in struct '" String -> String -> String
forall a. [a] -> [a] -> [a]
++
Text -> String
DT.unpack Text
sName String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"
validateAssignment :: CheckExprFn -> CheckEnv -> Ast -> Type ->
DT.Text -> DT.Text -> Either String Type
validateAssignment :: CheckExprFn
-> CheckEnv -> Ast -> Type -> Text -> Text -> Either String Type
validateAssignment CheckExprFn
checker CheckEnv
env Ast
val Type
expectedType Text
fieldName Text
sName = do
valType <- CheckExprFn
checker CheckEnv
env Ast
val
if areTypesCompatible expectedType valType
then Right (TyStruct sName)
else Left $ "Type mismatch in field assignment '" ++
DT.unpack fieldName ++ "'. Expected " ++
typeToString expectedType ++ ", got " ++
typeToString valType
extractStringFromAst :: Ast -> Either String DT.Text
(AList [Ast]
chars) =
let extractChar :: Ast -> Maybe Char
extractChar (AInteger (IChar Int8
c)) = Char -> Maybe Char
forall a. a -> Maybe a
Just (Int -> Char
chr (Int8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int8
c))
extractChar Ast
_ = Maybe Char
forall a. Maybe a
Nothing
in case (Ast -> Maybe Char) -> [Ast] -> Maybe String
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM Ast -> Maybe Char
extractChar [Ast]
chars of
Just String
str -> Text -> Either String Text
forall a b. b -> Either a b
Right (String -> Text
DT.pack String
str)
Maybe String
Nothing -> String -> Either String Text
forall a b. a -> Either a b
Left String
"Invalid string format in AST"
extractStringFromAst Ast
_ = String -> Either String Text
forall a b. a -> Either a b
Left String
"Invalid field name format in attr_update"
getStructDef :: CheckEnv -> DT.Text -> Either String StructDef
getStructDef :: CheckEnv -> Text -> Either String StructDef
getStructDef CheckEnv
env Text
name = case Text -> Map Text StructDef -> Maybe StructDef
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Text
name (CheckEnv -> Map Text StructDef
envStructs CheckEnv
env) of
Just StructDef
d -> StructDef -> Either String StructDef
forall a b. b -> Either a b
Right StructDef
d
Maybe StructDef
Nothing -> String -> Either String StructDef
forall a b. a -> Either a b
Left (String -> Either String StructDef)
-> String -> Either String StructDef
forall a b. (a -> b) -> a -> b
$ String
"Error: Undefined struct '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Text -> String
DT.unpack Text
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"
checkBinaryOp :: CheckExprFn -> CheckEnv -> DT.Text -> [Ast]
-> Type -> Type -> Either String Type
checkBinaryOp :: CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Type -> Type -> Either String Type
checkBinaryOp CheckExprFn
checker CheckEnv
env Text
op [Ast]
args Type
inType Type
outType =
case [Ast]
args of
[Ast
left, Ast
right] ->
CheckExprFn
-> CheckEnv
-> Text
-> Ast
-> Ast
-> Type
-> Type
-> Either String Type
validateBinaryOp CheckExprFn
checker CheckEnv
env Text
op Ast
left Ast
right Type
inType Type
outType
[Ast]
_ -> String -> Either String Type
forall a b. a -> Either a b
Left (String -> Either String Type) -> String -> Either String Type
forall a b. (a -> b) -> a -> b
$ String
"Operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Text -> String
DT.unpack Text
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' expects 2 arguments"
validateBinaryOp :: CheckExprFn -> CheckEnv -> DT.Text -> Ast -> Ast
-> Type -> Type -> Either String Type
validateBinaryOp :: CheckExprFn
-> CheckEnv
-> Text
-> Ast
-> Ast
-> Type
-> Type
-> Either String Type
validateBinaryOp CheckExprFn
checker CheckEnv
env Text
op Ast
left Ast
right Type
inType Type
outType = do
tLeft <- CheckExprFn
checker CheckEnv
env Ast
left
tRight <- checker env right
if areTypesCompatible tLeft inType && areTypesCompatible tRight inType
then Right outType
else Left $ binaryOpError op inType tLeft tRight
binaryOpError :: DT.Text -> Type -> Type -> Type -> String
binaryOpError :: Text -> Type -> Type -> Type -> String
binaryOpError Text
op Type
expected Type
actualLeft Type
actualRight =
String
"Operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Text -> String
DT.unpack Text
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' expects (" String -> String -> String
forall a. [a] -> [a] -> [a]
++
Type -> String
typeToString Type
expected String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Type -> String
typeToString Type
expected String -> String -> String
forall a. [a] -> [a] -> [a]
++
String
") but got (" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Type -> String
typeToString Type
actualLeft String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", " String -> String -> String
forall a. [a] -> [a] -> [a]
++
Type -> String
typeToString Type
actualRight String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
checkEqualityOp :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkEqualityOp :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkEqualityOp CheckExprFn
checker CheckEnv
env [Ast]
args =
case [Ast]
args of
[Ast
left, Ast
right] -> do
_ <- CheckExprFn
checker CheckEnv
env Ast
left
_ <- checker env right
Right TyBool
[Ast]
_ -> String -> Either String Type
forall a b. a -> Either a b
Left String
"Equality operator expects 2 arguments"
checkUnaryOp :: CheckExprFn -> CheckEnv -> DT.Text -> [Ast]
-> Type -> Type -> Either String Type
checkUnaryOp :: CheckExprFn
-> CheckEnv -> Text -> [Ast] -> Type -> Type -> Either String Type
checkUnaryOp CheckExprFn
checker CheckEnv
env Text
op [Ast]
args Type
inType Type
outType =
case [Ast]
args of
[Ast
operand] -> do
tOp <- CheckExprFn
checker CheckEnv
env Ast
operand
if areTypesCompatible tOp inType
then Right outType
else Left $ "Operator '" ++ DT.unpack op ++ "' expects " ++
typeToString inType ++" but got "
++ typeToString tOp
[Ast]
_ -> String -> Either String Type
forall a b. a -> Either a b
Left (String -> Either String Type) -> String -> Either String Type
forall a b. (a -> b) -> a -> b
$ String
"Operator '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Text -> String
DT.unpack Text
op String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' expects 1 argument"
checkUserFunc :: CheckExprFn -> CheckEnv -> DT.Text -> [Ast] -> Either String Type
checkUserFunc :: CheckExprFn -> CheckEnv -> Text -> [Ast] -> Either String Type
checkUserFunc CheckExprFn
checker CheckEnv
env Text
name [Ast]
args =
case Text -> Map Text Type -> Maybe Type
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Text
name (CheckEnv -> Map Text Type
envVars CheckEnv
env) of
Just (TyFunc [Type]
argTypes Type
retType) ->
CheckExprFn
-> CheckEnv
-> Text
-> [Ast]
-> [Type]
-> Type
-> Either String Type
verifyFuncCall CheckExprFn
checker CheckEnv
env Text
name [Ast]
args [Type]
argTypes Type
retType
Just Type
_ -> String -> Either String Type
forall a b. a -> Either a b
Left (String -> Either String Type) -> String -> Either String Type
forall a b. (a -> b) -> a -> b
$ String
"'" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Text -> String
DT.unpack Text
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' is not a function"
Maybe Type
Nothing -> String -> Either String Type
forall a b. a -> Either a b
Left (String -> Either String Type) -> String -> Either String Type
forall a b. (a -> b) -> a -> b
$ String
"Undefined function '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Text -> String
DT.unpack Text
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"'"
verifyFuncCall :: CheckExprFn -> CheckEnv -> DT.Text -> [Ast]
-> [Type] -> Type -> Either String Type
verifyFuncCall :: CheckExprFn
-> CheckEnv
-> Text
-> [Ast]
-> [Type]
-> Type
-> Either String Type
verifyFuncCall CheckExprFn
checker CheckEnv
env Text
name [Ast]
args [Type]
expected Type
ret
| [Ast] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Ast]
args Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= [Type] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Type]
expected = Text -> [Type] -> [Ast] -> Either String Type
verifyArgCount Text
name [Type]
expected [Ast]
args
| Bool
otherwise = CheckExprFn
-> CheckEnv
-> Text
-> [Ast]
-> [Type]
-> Type
-> Either String Type
verifyArgTypes CheckExprFn
checker CheckEnv
env Text
name [Ast]
args [Type]
expected Type
ret
verifyArgCount :: DT.Text -> [Type] -> [Ast] -> Either String Type
verifyArgCount :: Text -> [Type] -> [Ast] -> Either String Type
verifyArgCount Text
name [Type]
expected [Ast]
args =
String -> Either String Type
forall a b. a -> Either a b
Left (String -> Either String Type) -> String -> Either String Type
forall a b. (a -> b) -> a -> b
$ String
"Function '" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Text -> String
DT.unpack Text
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' expects " String -> String -> String
forall a. [a] -> [a] -> [a]
++
Int -> String
forall a. Show a => a -> String
show ([Type] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Type]
expected) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" arguments but got "String -> String -> String
forall a. [a] -> [a] -> [a]
++
Int -> String
forall a. Show a => a -> String
show ([Ast] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Ast]
args)
verifyArgTypes :: CheckExprFn -> CheckEnv -> DT.Text -> [Ast]
-> [Type] -> Type -> Either String Type
verifyArgTypes :: CheckExprFn
-> CheckEnv
-> Text
-> [Ast]
-> [Type]
-> Type
-> Either String Type
verifyArgTypes CheckExprFn
checker CheckEnv
env Text
name [Ast]
args [Type]
expected Type
ret = do
checked <- (Ast -> Either String Type) -> [Ast] -> Either String [Type]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM (CheckExprFn
checker CheckEnv
env) [Ast]
args
let errors = ((Type, Type) -> Bool) -> [(Type, Type)] -> [(Type, Type)]
forall a. (a -> Bool) -> [a] -> [a]
filter (\(Type
expect, Type
act) -> Bool -> Bool
not (Type -> Type -> Bool
areTypesCompatible Type
expect Type
act))
([Type] -> [Type] -> [(Type, Type)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Type]
expected [Type]
checked)
if null errors
then Right ret
else Left $ "Argument type mismatch in call to '" ++
DT.unpack name ++ "'"
checkTypeof :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkTypeof :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkTypeof CheckExprFn
checker CheckEnv
env [Ast
arg] = do
_ <- CheckExprFn
checker CheckEnv
env Ast
arg
Right (TyList TyInt)
checkTypeof CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"typeof expects 1 argument"
checkFFRead :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkFFRead :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkFFRead CheckExprFn
checker CheckEnv
env [Ast
path] = do
tPath <- CheckExprFn
checker CheckEnv
env Ast
path
case tPath of
TyList Type
TyInt -> Type -> Either String Type
forall a b. b -> Either a b
Right (Type -> Type
TyList (Type -> Type
TyList Type
TyInt))
Type
_ -> String -> Either String Type
forall a b. a -> Either a b
Left String
"ffread expects a string (path) as argument"
checkFFRead CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"ffread expects 1 argument"
checkFFWrite :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkFFWrite :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkFFWrite CheckExprFn
checker CheckEnv
env [Ast
path, Ast
content] = do
tPath <- CheckExprFn
checker CheckEnv
env Ast
path
tContent <- checker env content
case (tPath, tContent) of
(TyList Type
TyInt, TyList (TyList Type
TyInt)) -> Type -> Either String Type
forall a b. b -> Either a b
Right Type
TyBool
(Type, Type)
_ -> String -> Either String Type
forall a b. a -> Either a b
Left String
"ffwrite expects (path: string, content: [string])"
checkFFWrite CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"ffwrite expects 2 arguments"
checkOpen :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkOpen :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkOpen CheckExprFn
checker CheckEnv
env [Ast
path, Ast
mode] = do
tPath <- CheckExprFn
checker CheckEnv
env Ast
path
tMode <- checker env mode
if areTypesCompatible (TyList TyInt)
tPath && areTypesCompatible TyInt tMode
then Right TyInt
else Left "open expects (path: string, mode: int)"
checkOpen CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"open expects 2 arguments"
checkClose :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkClose :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkClose CheckExprFn
checker CheckEnv
env [Ast
fd] = do
tFd <- CheckExprFn
checker CheckEnv
env Ast
fd
if areTypesCompatible TyInt tFd
then Right TyInt
else Left "close expects an integer file descriptor"
checkClose CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"close expects 1 argument"
checkRead :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkRead :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkRead CheckExprFn
checker CheckEnv
env [Ast
fd, Ast
size] = do
tFd <- CheckExprFn
checker CheckEnv
env Ast
fd
tSize <- checker env size
if areTypesCompatible TyInt tFd && areTypesCompatible TyInt tSize
then Right (TyList TyInt)
else Left "read expects (fd: int, size: int)"
checkRead CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"read expects 2 arguments"
checkInput :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkInput :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkInput CheckExprFn
checker CheckEnv
env [Ast
fd] = do
tFd <- CheckExprFn
checker CheckEnv
env Ast
fd
if areTypesCompatible TyInt tFd
then Right (TyList TyInt)
else Left "input expects an integer file descriptor"
checkInput CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"input expects 1 argument"
checkWrite :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkWrite :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkWrite CheckExprFn
checker CheckEnv
env [Ast
fd, Ast
content] = do
tFd <- CheckExprFn
checker CheckEnv
env Ast
fd
tContent <- checker env content
unless (areTypesCompatible TyInt tFd) $
Left "write expects an integer file descriptor (int) as first argument"
case tContent of
TyList Type
_ -> Type -> Either String Type
forall a b. b -> Either a b
Right Type
TyInt
Type
_ -> String -> Either String Type
forall a b. a -> Either a b
Left String
"write expects a string or list ([char]) as second argument"
checkWrite CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"write expects 2 arguments (fd: int, content: [char])"
checkSizeof :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkSizeof :: CheckExprFn -> CheckEnv -> [Ast] -> Either String Type
checkSizeof CheckExprFn
checker CheckEnv
env [Ast
arg] = do
_ <- CheckExprFn
checker CheckEnv
env Ast
arg
Right TyInt
checkSizeof CheckExprFn
_ CheckEnv
_ [Ast]
_ = String -> Either String Type
forall a b. a -> Either a b
Left String
"sizeof expects 1 argument"