module AST.Semantics.Type (
Type(..),
StructDef(..),
CheckEnv(..),
emptyEnv,
parseType,
typeToString,
areTypesCompatible,
) where
import qualified Data.Text as DT
import qualified Data.Map.Strict as Map
data Type
= TyInt
| TyBool
| TyVoid
| TyList Type
| TyFunc [Type] Type
| TyStruct DT.Text
| TyAuto
deriving (Int -> Type -> ShowS
[Type] -> ShowS
Type -> String
(Int -> Type -> ShowS)
-> (Type -> String) -> ([Type] -> ShowS) -> Show Type
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Type -> ShowS
showsPrec :: Int -> Type -> ShowS
$cshow :: Type -> String
show :: Type -> String
$cshowList :: [Type] -> ShowS
showList :: [Type] -> ShowS
Show, Type -> Type -> Bool
(Type -> Type -> Bool) -> (Type -> Type -> Bool) -> Eq Type
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Type -> Type -> Bool
== :: Type -> Type -> Bool
$c/= :: Type -> Type -> Bool
/= :: Type -> Type -> Bool
Eq)
data StructDef = StructDef
{ StructDef -> Text
structName :: DT.Text
, StructDef -> Map Text Type
structFields :: Map.Map DT.Text Type
} deriving (Int -> StructDef -> ShowS
[StructDef] -> ShowS
StructDef -> String
(Int -> StructDef -> ShowS)
-> (StructDef -> String)
-> ([StructDef] -> ShowS)
-> Show StructDef
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> StructDef -> ShowS
showsPrec :: Int -> StructDef -> ShowS
$cshow :: StructDef -> String
show :: StructDef -> String
$cshowList :: [StructDef] -> ShowS
showList :: [StructDef] -> ShowS
Show)
data CheckEnv = CheckEnv
{ CheckEnv -> Map Text Type
envVars :: Map.Map DT.Text Type
, CheckEnv -> Map Text StructDef
envStructs :: Map.Map DT.Text StructDef
} deriving (Int -> CheckEnv -> ShowS
[CheckEnv] -> ShowS
CheckEnv -> String
(Int -> CheckEnv -> ShowS)
-> (CheckEnv -> String) -> ([CheckEnv] -> ShowS) -> Show CheckEnv
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CheckEnv -> ShowS
showsPrec :: Int -> CheckEnv -> ShowS
$cshow :: CheckEnv -> String
show :: CheckEnv -> String
$cshowList :: [CheckEnv] -> ShowS
showList :: [CheckEnv] -> ShowS
Show)
emptyEnv :: CheckEnv
emptyEnv :: CheckEnv
emptyEnv = Map Text Type -> Map Text StructDef -> CheckEnv
CheckEnv Map Text Type
forall k a. Map k a
Map.empty Map Text StructDef
forall k a. Map k a
Map.empty
parseType :: DT.Text -> Type
parseType :: Text -> Type
parseType Text
t
| Text
t Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"int" = Type
TyInt
| Text
t Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"char" = Type
TyInt
| Text
t Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"bool" = Type
TyBool
| Text
t Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"void" Bool -> Bool -> Bool
|| Text
t Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"Void" = Type
TyVoid
| Text
t Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== String -> Text
DT.pack String
"auto" = Type
TyAuto
| Text -> Text -> Bool
DT.isPrefixOf (String -> Text
DT.pack String
"[") Text
t Bool -> Bool -> Bool
&& Text -> Text -> Bool
DT.isSuffixOf (String -> Text
DT.pack String
"]") Text
t =
let inner :: Text
inner = HasCallStack => Text -> Text
Text -> Text
DT.init (HasCallStack => Text -> Text
Text -> Text
DT.tail Text
t)
in Type -> Type
TyList (Text -> Type
parseType Text
inner)
| Bool
otherwise = Text -> Type
TyStruct Text
t
typeToString :: Type -> String
typeToString :: Type -> String
typeToString Type
TyInt = String
"int"
typeToString Type
TyBool = String
"bool"
typeToString Type
TyVoid = String
"void"
typeToString Type
TyAuto = String
"auto"
typeToString (TyList Type
t) = String
"[" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Type -> String
typeToString Type
t String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"]"
typeToString (TyStruct Text
n) = Text -> String
DT.unpack Text
n
typeToString (TyFunc [Type]
args Type
ret) =
String
"(" String -> ShowS
forall a. [a] -> [a] -> [a]
++ [String] -> String
unwords ((Type -> String) -> [Type] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Type -> String
typeToString [Type]
args) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" -> " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Type -> String
typeToString Type
ret String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
")"
areTypesCompatible :: Type -> Type -> Bool
areTypesCompatible :: Type -> Type -> Bool
areTypesCompatible Type
TyAuto Type
_ = Bool
True
areTypesCompatible Type
_ Type
TyAuto = Bool
True
areTypesCompatible Type
TyInt Type
TyInt = Bool
True
areTypesCompatible Type
TyBool Type
TyBool = Bool
True
areTypesCompatible Type
TyVoid Type
TyVoid = Bool
True
areTypesCompatible (TyList Type
a) (TyList Type
b) = Type -> Type -> Bool
areTypesCompatible Type
a Type
b
areTypesCompatible (TyStruct Text
a) (TyStruct Text
b) = Text
a Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== Text
b
areTypesCompatible (TyFunc [Type]
args1 Type
ret1) (TyFunc [Type]
args2 Type
ret2) =
[Type] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Type]
args1 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]
args2 Bool -> Bool -> Bool
&&
[Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and ((Type -> Type -> Bool) -> [Type] -> [Type] -> [Bool]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Type -> Type -> Bool
areTypesCompatible [Type]
args1 [Type]
args2) Bool -> Bool -> Bool
&&
Type -> Type -> Bool
areTypesCompatible Type
ret1 Type
ret2
areTypesCompatible Type
_ Type
_ = Bool
False