@@ -3,8 +3,9 @@ module ProjectM36.AtomType where
33import ProjectM36.Base
44import ProjectM36.Relation
55import ProjectM36.DataTypes.Primitive
6+import qualified ProjectM36.TypeConstructorDef as TCD
67import qualified ProjectM36.TypeConstructor as TC
7−import qualified ProjectM36.DataConstructor as DC
8+import qualified ProjectM36.DataConstructorDef as DCD
89import qualified Data.Text as T
910import ProjectM36.Error
1011import ProjectM36.Attribute
@@ -12,10 +13,12 @@ import ProjectM36.Atom
1213import qualified Data.Vector as V
1314import qualified Data.Set as S
1415import qualified Data.List as L
15−import Data.Maybe (isJust, catMaybes)
16+import Data.Maybe (isJust)
1617import Control.Monad.Writer
18+import qualified Data.Map as M
19+--import Debug.Trace
1720
18−typesAsRelation :: TypeConstructors -> Either RelationalError Relation
21+typesAsRelation :: TypeConstructorMapping -> Either RelationalError Relation
1922typesAsRelation types = mkRelationFromTuples attrs tuples
2023 where
2124 attrs = attributesFromList [Attribute "TypeConstructor" textAtomType,
@@ -24,30 +27,13 @@ typesAsRelation types = mkRelationFromTuples attrs tuples
2427 dConsType = RelationAtomType subAttrs
2528 tuples = map mkTypeConsDescription types
2629
27− mkTypeConsDescription (tCons, dConsList) = RelationTuple attrs (V.fromList [textAtom (TC.name tCons), mkDataConsRelation dConsList])
30+ mkTypeConsDescription (tCons, dConsList) = RelationTuple attrs (V.fromList [textAtom (TCD.name tCons), mkDataConsRelation dConsList])
2831
29− mkDataConsRelation dConsList = case mkRelationFromTuples subAttrs $ map (\dCons -> RelationTuple subAttrs (V.singleton $ textAtom $ T.intercalate " " ((DC.name dCons):(map (T.pack . show) (DC.fields dCons))))) dConsList of
32+ mkDataConsRelation dConsList = case mkRelationFromTuples subAttrs $ map (\dCons -> RelationTuple subAttrs (V.singleton $ textAtom $ T.intercalate " " ((DCD.name dCons):(map (T.pack . show) (DCD.fields dCons))))) dConsList of
3033 Left err -> error ("mkRelationFromTuples pooped " ++ show err)
3134 Right rel -> Atom rel
3235
33−
34−{-
35−-- | Scan all type constructors for the proper data constructor
36−dataConstructorTypeNamesForName :: DataConstructorName -> AtomTypes -> Either RelationalError [AtomTypeName]
37−dataConstructorTypeNamesForName dConsName aTypes = M.foldrWithKey typeFolder defaultErr aTypes
38− where
39− defaultErr = Left (NoSuchDataConstructorError dConsName)
40− typeFolder _ (_, AtomConstructor dConsMap) accum = if isRight accum then
41− accum
42− else
43− case M.lookup dConsName dConsMap of
44− Nothing -> accum
45− Just aTypeNames -> Right (dConsName, aTypeNames)
46−-}
47−-- fix mostly-duplicated fold code
48−
49−
50−findDataConstructor :: DataConstructorName -> TypeConstructors -> Maybe (TypeConstructor, DataConstructor)
36+findDataConstructor :: DataConstructorName -> TypeConstructorMapping -> Maybe (TypeConstructorDef, DataConstructorDef)
5137findDataConstructor dName tConsList = foldr tConsFolder Nothing tConsList
5238 where
5339 tConsFolder (tCons, dConsList) accum = if isJust accum then
@@ -56,60 +42,98 @@ findDataConstructor dName tConsList = foldr tConsFolder Nothing tConsList
5642 case findDCons dConsList of
5743 Just dCons -> Just (tCons, dCons)
5844 Nothing -> Nothing
59− findDCons dConsList = case filter (\dCons -> DC.name dCons == dName) dConsList of
45+ findDCons dConsList = case filter (\dCons -> DCD.name dCons == dName) dConsList of
6046 [] -> Nothing
6147 [dCons] -> Just dCons
6248 _ -> error "More than one data constructor with the same name found"
6349
6450-- | Scan the atom types and return the resultant ConstructedAtomType or error.
6551-- Used in typeFromAtomExpr to validate argument types.
66−atomTypeForDataConstructorName :: DataConstructorName -> [AtomType] -> TypeConstructors -> Either RelationalError AtomType
52+atomTypeForDataConstructorName :: DataConstructorName -> [AtomType] -> TypeConstructorMapping -> Either RelationalError AtomType
6753-- search for the data constructor and resolve the types' names
6854atomTypeForDataConstructorName dConsName atomTypesIn tConsList = do
6955 case findDataConstructor dConsName tConsList of
7056 Nothing -> Left (NoSuchDataConstructorError dConsName)
7157 Just (tCons, dCons) -> do
72− let validation = map (\(aTypeIn, tConsArgIn) -> validAtomTypeWithTypeConstructorArg aTypeIn tConsArgIn tConsList) (zip atomTypesIn (DC.fields dCons))
73− errors = catMaybes validation
74− if length errors /= 0 then
75− Left (head errors)
76− else
77− Right (ConstructedAtomType (TC.name tCons) atomTypesIn)
58+ typeVars <- resolveDataConstructorTypeVars dCons atomTypesIn tConsList
59+ pure (ConstructedAtomType (TCD.name tCons) typeVars)
60+
61+atomTypeForDataConstructorDefArg :: DataConstructorDefArg -> AtomType -> TypeConstructorMapping -> Either RelationalError AtomType
62+atomTypeForDataConstructorDefArg (DataConstructorDefTypeConstructorArg tCons) aType tConss =
63+ case isValidAtomTypeForTypeConstructor aType tCons tConss of
64+ Just err -> Left err
65+ Nothing -> Right aType
66+
67+atomTypeForDataConstructorDefArg (DataConstructorDefTypeVarNameArg _) aType _ = Right aType --any type is OK
7868
79−validAtomTypeWithTypeConstructorArg :: AtomType -> TypeConstructorArg -> TypeConstructors -> Maybe RelationalError
80−validAtomTypeWithTypeConstructorArg aType (TypeConstructorArg tCons) tConsList = validAtomTypeWithTypeConstructor aType tCons tConsList
81−validAtomTypeWithTypeConstructorArg _ (TypeConstructorPolymorphicArg _) _ = Just IncompletelyDefinedAtomTypeWithConstructorError
69+isValidAtomTypeForTypeConstructorArg :: AtomType -> TypeConstructorArg -> TypeConstructorMapping -> Maybe RelationalError
70+isValidAtomTypeForTypeConstructorArg aType (TypeConstructorArg tCons) tConsList = isValidAtomTypeForTypeConstructor aType tCons tConsList
71+isValidAtomTypeForTypeConstructorArg _ (TypeConstructorTypeVarArg _) _ = Nothing
8272
8373--reconcile the atom-in types with the type constructors
84−validAtomTypeWithTypeConstructor :: AtomType -> TypeConstructor -> TypeConstructors -> Maybe RelationalError
85−validAtomTypeWithTypeConstructor aType (PrimitiveTypeConstructor _ expectedAType) _ = if expectedAType /= aType then Just (AtomTypeMismatchError expectedAType aType) else Nothing
74+isValidAtomTypeForTypeConstructor :: AtomType -> TypeConstructor -> TypeConstructorMapping -> Maybe RelationalError
75+isValidAtomTypeForTypeConstructor aType (PrimitiveTypeConstructor _ expectedAType) _ = if expectedAType /= aType then Just (AtomTypeMismatchError expectedAType aType) else Nothing
8676
8777--lookup constructor name and check if the incoming atom types are valid
88−validAtomTypeWithTypeConstructor (ConstructedAtomType tConsName _) (ADTypeConstructor expectedTConsName _) _ = if tConsName /= expectedTConsName then Just (TypeConstructorNameMismatch expectedTConsName tConsName) else Nothing
78+isValidAtomTypeForTypeConstructor (ConstructedAtomType tConsName _) (ADTypeConstructor expectedTConsName _) _ = if tConsName /= expectedTConsName then Just (TypeConstructorNameMismatch expectedTConsName tConsName) else Nothing
8979
90−validAtomTypeWithTypeConstructor aType tCons _ = Just (AtomTypeTypeConstructorReconciliationError aType tCons)
80+isValidAtomTypeForTypeConstructor aType tCons _ = Just (AtomTypeTypeConstructorReconciliationError aType (TC.name tCons))
9181
9282-- | Used to determine if the atom arguments can be used with the data constructor.
93−atomTypeWithDataConstructor :: TypeConstructors -> DataConstructorName -> [AtomType] -> Either RelationalError AtomType
94−atomTypeWithDataConstructor tConss dConsName atomArgTypes = do
83+-- | This is the entry point for type-checking from RelationalExpression.hs.
84+atomTypeForDataConstructor :: TypeConstructorMapping -> DataConstructorName -> [AtomType] -> Either RelationalError AtomType
85+atomTypeForDataConstructor tConss dConsName atomArgTypes = do
9586 --lookup the data constructor
9687 case findDataConstructor dConsName tConss of
9788 Nothing -> Left (NoSuchDataConstructorError dConsName)
9889 Just (tCons, dCons) -> do
99− --match the data constructor arguments to the atom args
100− let validator (tConsArg', aType) = maybe (Right ()) Left (validAtomTypeWithTypeConstructorArg aType tConsArg' tConss)
101− mapM_ validator (zip (DC.fields dCons) atomArgTypes)
102− pure (ConstructedAtomType (TC.name tCons) atomArgTypes)
90+ --validate that the type constructor arguments are fulfilled in the data constructor
91+ typeVars <- resolveDataConstructorTypeVars dCons atomArgTypes tConss
92+ pure (ConstructedAtomType (TCD.name tCons) typeVars)
10393
104−-- check that polymorphic vars on the right also appear on the left
94+-- | Walks the data and type constructors to extract the type variable map.
95+resolveDataConstructorTypeVars :: DataConstructorDef -> [AtomType] -> TypeConstructorMapping -> Either RelationalError TypeVarMap
96+resolveDataConstructorTypeVars dCons aTypeArgs tConss = do
97+ maps <- mapM (\(dCons',aTypeArg) -> resolveDataConstructorArgTypeVars dCons' aTypeArg tConss) (zip (DCD.fields dCons) aTypeArgs)
98+ --if any two maps have the same key and different values- bail!
99+ pure (M.unions maps)
100+
101+-- | Attempt to match the data constructor argument to a type constructor type variable.
102+resolveDataConstructorArgTypeVars :: DataConstructorDefArg -> AtomType -> TypeConstructorMapping -> Either RelationalError TypeVarMap
103+resolveDataConstructorArgTypeVars (DataConstructorDefTypeConstructorArg tCons) aType tConss = resolveTypeConstructorTypeVars tCons aType tConss
104+
105+resolveDataConstructorArgTypeVars (DataConstructorDefTypeVarNameArg pVarName) aType _ = Right (M.singleton pVarName aType)
106+
107+resolveTypeConstructorTypeVars :: TypeConstructor -> AtomType -> TypeConstructorMapping -> Either RelationalError TypeVarMap
108+resolveTypeConstructorTypeVars (PrimitiveTypeConstructor _ pType) aType tConss =
109+ if aType /= pType then
110+ Left (AtomTypeMismatchError pType aType)
111+ else
112+ Right M.empty
113+
114+resolveTypeConstructorTypeVars (ADTypeConstructor tConsName tConsArgs) (ConstructedAtomType tConsName' pVarMap') tConss =
115+ if tConsName /= tConsName' then
116+ Left (TypeConstructorNameMismatch tConsName tConsName')
117+ else
118+ case findTypeConstructor tConsName tConss of
119+ Nothing -> Left (NoSuchTypeConstructorName tConsName)
120+ Just (tConsDef, _) -> let expectedPVars = S.fromList (TCD.typeVars tConsDef)
121+ actualPVars = M.keysSet pVarMap' in
122+ if expectedPVars /= actualPVars then
123+ Left (TypeConstructorTypeVarsMismatch expectedPVars actualPVars)
124+ else
125+ Right (pVarMap')
126+resolveTypeConstructorTypeVars _ _ _ = error "Unhandled type vars"
127+
128+-- check that type vars on the right also appear on the left
105129-- check that the data constructor names are unique
106−validateTypeConstructor :: TypeConstructor -> [DataConstructor] -> [RelationalError]
107−validateTypeConstructor tCons dConsList = execWriter $ do
108− let duplicateDConsNames = dupes (L.sort (map DC.name dConsList))
130+validateTypeConstructorDef :: TypeConstructorDef -> [DataConstructorDef] -> [RelationalError]
131+validateTypeConstructorDef tConsDef dConsList = execWriter $ do
132+ let duplicateDConsNames = dupes (L.sort (map DCD.name dConsList))
109133 mapM_ tell [map DataConstructorNameInUseError duplicateDConsNames]
110− let leftSideVars = TC.polymorphicVariables tCons
111− rightSideVars = concatMap DC.polymorphicVariables dConsList
112− varsDiff = S.difference (S.fromList leftSideVars) (S.fromList rightSideVars)
134+ let leftSideVars = S.fromList (TCD.typeVars tConsDef)
135+ rightSideVars = S.unions (map DCD.typeVars dConsList)
136+ varsDiff = S.difference leftSideVars rightSideVars
113137 mapM_ tell [map DataConstructorUsesUndeclaredTypeVariable (S.toList varsDiff)]
114138 pure ()
115139
@@ -120,24 +144,25 @@ dupes (_:[]) = []
120144dupes (x:y:[]) = if x == y then [x] else []
121145dupes (x:y:xs) = dupes(x:[y]) ++ dupes(xs)
122146
123−atomTypeForTypeConstructor :: TypeConstructor -> TypeConstructors -> Either RelationalError AtomType
124−atomTypeForTypeConstructor tCons tConsList = foldr tConsFolder defaultErr (map fst tConsList)
125− where
126− tConsFolder tCons' accum = if TC.name tCons == TC.name tCons' then do
127− tConsArgTypes <- mapM ((flip atomTypeForTypeConstructorArg) tConsList) (TC.arguments tCons')
128− Right (ConstructedAtomType (TC.name tCons') tConsArgTypes)
129− else
130− accum
131− defaultErr = Left (NoSuchTypeConstructorName (TC.name tCons))
147+-- | Create an atom type iff all type variables are provided.
148+-- Either Int Text -> ConstructedAtomType "Either" {Int , Text}
149+atomTypeForTypeConstructor :: TypeConstructor -> TypeConstructorMapping -> Either RelationalError AtomType
150+atomTypeForTypeConstructor tCons tConss = case findTypeConstructor (TC.name tCons) tConss of
151+ Nothing -> Left (NoSuchTypeConstructorError (TC.name tCons))
152+ Just (tConsDef, _) -> do
153+ tConsArgTypes <- mapM ((flip atomTypeForTypeConstructorArg) tConss) (TC.arguments tCons)
154+ let pVarNames = TCD.typeVars tConsDef
155+ tConsArgs = M.fromList (zip pVarNames tConsArgTypes)
156+ Right (ConstructedAtomType (TC.name tCons) tConsArgs)
132157
133−atomTypeForTypeConstructorArg :: TypeConstructorArg -> TypeConstructors -> Either RelationalError AtomType
134−atomTypeForTypeConstructorArg (TypeConstructorPolymorphicArg _) _ = Left IncompletelyDefinedAtomTypeWithConstructorError
158+atomTypeForTypeConstructorArg :: TypeConstructorArg -> TypeConstructorMapping -> Either RelationalError AtomType
159+atomTypeForTypeConstructorArg (TypeConstructorTypeVarArg _) _ = Left IncompletelyDefinedAtomTypeWithConstructorError
135160atomTypeForTypeConstructorArg (TypeConstructorArg tCons) tConsList = atomTypeForTypeConstructor tCons tConsList
136161
137−findTypeConstructor :: TypeConstructorName -> TypeConstructors -> Maybe (TypeConstructor, [DataConstructor])
162+findTypeConstructor :: TypeConstructorName -> TypeConstructorMapping -> Maybe (TypeConstructorDef, [DataConstructorDef])
138163findTypeConstructor name tConsList = foldr tConsFolder Nothing tConsList
139164 where
140− tConsFolder (tCons, dConsList) accum = if TC.name tCons == name then
165+ tConsFolder (tCons, dConsList) accum = if TCD.name tCons == name then
141166 Just (tCons, dConsList)
142167 else
143168 accum