module Helium.CodeGeneration.DerivingEq(dataDictionary) where
import qualified Helium.Syntax.UHA_Syntax as UHA
import Helium.Syntax.UHA_Utils
import Helium.CodeGeneration.CoreUtils
import Lvm.Core.Expr
import Lvm.Core.Utils
import Lvm.Common.Id
import Helium.Utils.Utils
dataDictionary :: UHA.Declaration -> CoreDecl
dataDictionary (UHA.Declaration_Data _ _ (UHA.SimpleType_SimpleType _ name names) constructors _) =
DeclValue
{ declName = idFromString ("$dictEq" ++ getNameName name)
, declAccess = public
, valueEnc = Nothing
, valueValue = eqFunction names constructors
, declCustoms = [ custom "type" ("DictEq" ++ getNameName name) ]
}
where
dataDictionary _ = error "pattern match failure in CodeGeneration.Deriving.dataDictionary"
eqFunction :: [UHA.Name] -> [UHA.Constructor] -> Expr
eqFunction names constructors =
let
body =
Let (Strict (Bind fstArg (Var fstArg)))
(Let (Strict (Bind sndArg (Var sndArg)))
(Match fstArg
(map makeAlt constructors)))
in
foldr Lam body (map idFromName names ++ [fstArg, sndArg])
fstArg, sndArg :: Id
[fstArg, sndArg] = map idFromString ["$fstArg", "$sndArg"]
makeAlt :: UHA.Constructor -> Alt
makeAlt constructor =
Alt (PatCon (ConId ident) vs)
(Match sndArg
[ Alt (PatCon (ConId ident) ws)
( if null types then Con (ConId (idFromString "True"))
else
foldr1 andCore [ Ap (Ap (eqFunForType tp) (Var v)) (Var w)
| (v, w, tp) <- zip3 vs ws types
]
)
, Alt PatDefault (Con (ConId (idFromString "False")))
])
where
(ident, types) = nameAndTypes constructor
vs = [ idFromString ("$v"++show i) | i <- [0..length types1] ]
ws = [ idFromString ("$w"++show i) | i <- [0..length types1] ]
andCore x y = Ap (Ap (Var (idFromString "&&")) x) y
nameAndTypes :: UHA.Constructor -> (Id, [UHA.Type])
nameAndTypes c =
case c of
UHA.Constructor_Constructor _ n ts -> (idFromName n, map annotatedTypeToType ts )
UHA.Constructor_Infix _ t1 n t2 -> (idFromName n, map annotatedTypeToType [t1, t2])
UHA.Constructor_Record _ _ _ -> error "pattern match failure in CodeGeneration.DerivingEq.nameAndTypes"
where
annotatedTypeToType :: UHA.AnnotatedType -> UHA.Type
annotatedTypeToType (UHA.AnnotatedType_AnnotatedType _ _ t) = t
eqFunForType :: UHA.Type -> Expr
eqFunForType t =
case t of
UHA.Type_Variable _ n -> Var (idFromName n)
UHA.Type_Constructor _ n -> var ("$dictEq" ++ show n)
UHA.Type_Application _ _ f xs -> foldl Ap (eqFunForType f) (map eqFunForType xs)
UHA.Type_Parenthesized _ ty -> eqFunForType ty
_ -> internalError "DerivingEq" "eqFunForType" "unsupported type"