@@ -3,8 +3,9 @@ module ProjectM36.AtomType where
3import ProjectM36.Base
3import ProjectM36.Base
4import ProjectM36.Relation
4import ProjectM36.Relation
5import ProjectM36.DataTypes.Primitive
5import ProjectM36.DataTypes.Primitive
6+import qualified ProjectM36.TypeConstructorDef as TCD
6import qualified ProjectM36.TypeConstructor as TC
7import qualified ProjectM36.TypeConstructor as TC
7−import qualified ProjectM36.DataConstructor as DC
8+import qualified ProjectM36.DataConstructorDef as DCD
8import qualified Data.Text as T
9import qualified Data.Text as T
9import ProjectM36.Error
10import ProjectM36.Error
10import ProjectM36.Attribute
11import ProjectM36.Attribute
@@ -12,10 +13,12 @@ import ProjectM36.Atom
12import qualified Data.Vector as V
13import qualified Data.Vector as V
13import qualified Data.Set as S
14import qualified Data.Set as S
14import qualified Data.List as L
15import qualified Data.List as L
15−import Data.Maybe (isJust, catMaybes)
16+import Data.Maybe (isJust)
16import Control.Monad.Writer
17import Control.Monad.Writer
18+import qualified Data.Map as M
18−typesAsRelation :: TypeConstructors -> Either RelationalError Relation
21+typesAsRelation :: TypeConstructorMapping -> Either RelationalError Relation
19typesAsRelation types = mkRelationFromTuples attrs tuples
22typesAsRelation types = mkRelationFromTuples attrs tuples
21 attrs = attributesFromList [Attribute "TypeConstructor" textAtomType,
24 attrs = attributesFromList [Attribute "TypeConstructor" textAtomType,
@@ -24,30 +27,13 @@ typesAsRelation types = mkRelationFromTuples attrs tuples
24 dConsType = RelationAtomType subAttrs
27 dConsType = RelationAtomType subAttrs
25 tuples = map mkTypeConsDescription types
28 tuples = map mkTypeConsDescription types
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])
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
30 Left err -> error ("mkRelationFromTuples pooped " ++ show err)
33 Left err -> error ("mkRelationFromTuples pooped " ++ show err)
31 Right rel -> Atom rel
34 Right rel -> Atom rel
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
39− defaultErr = Left (NoSuchDataConstructorError dConsName)
40− typeFolder _ (_, AtomConstructor dConsMap) accum = if isRight accum then
43− case M.lookup dConsName dConsMap of
45− Just aTypeNames -> Right (dConsName, aTypeNames)
47−-- fix mostly-duplicated fold code
50−findDataConstructor :: DataConstructorName -> TypeConstructors -> Maybe (TypeConstructor, DataConstructor)
36+findDataConstructor :: DataConstructorName -> TypeConstructorMapping -> Maybe (TypeConstructorDef, DataConstructorDef)
51findDataConstructor dName tConsList = foldr tConsFolder Nothing tConsList
37findDataConstructor dName tConsList = foldr tConsFolder Nothing tConsList
53 tConsFolder (tCons, dConsList) accum = if isJust accum then
39 tConsFolder (tCons, dConsList) accum = if isJust accum then
@@ -56,60 +42,98 @@ findDataConstructor dName tConsList = foldr tConsFolder Nothing tConsList
56 case findDCons dConsList of
42 case findDCons dConsList of
57 Just dCons -> Just (tCons, dCons)
43 Just dCons -> Just (tCons, dCons)
58 Nothing -> Nothing
44 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
60 [] -> Nothing
46 [] -> Nothing
61 [dCons] -> Just dCons
47 [dCons] -> Just dCons
62 _ -> error "More than one data constructor with the same name found"
48 _ -> error "More than one data constructor with the same name found"
64-- | Scan the atom types and return the resultant ConstructedAtomType or error.
50-- | Scan the atom types and return the resultant ConstructedAtomType or error.
65-- Used in typeFromAtomExpr to validate argument types.
51-- Used in typeFromAtomExpr to validate argument types.
66−atomTypeForDataConstructorName :: DataConstructorName -> [AtomType] -> TypeConstructors -> Either RelationalError AtomType
52+atomTypeForDataConstructorName :: DataConstructorName -> [AtomType] -> TypeConstructorMapping -> Either RelationalError AtomType
67-- search for the data constructor and resolve the types' names
53-- search for the data constructor and resolve the types' names
68atomTypeForDataConstructorName dConsName atomTypesIn tConsList = do
54atomTypeForDataConstructorName dConsName atomTypesIn tConsList = do
69 case findDataConstructor dConsName tConsList of
55 case findDataConstructor dConsName tConsList of
70 Nothing -> Left (NoSuchDataConstructorError dConsName)
56 Nothing -> Left (NoSuchDataConstructorError dConsName)
71 Just (tCons, dCons) -> do
57 Just (tCons, dCons) -> do
72− let validation = map (\(aTypeIn, tConsArgIn) -> validAtomTypeWithTypeConstructorArg aTypeIn tConsArgIn tConsList) (zip atomTypesIn (DC.fields dCons))
58+ typeVars <- resolveDataConstructorTypeVars dCons atomTypesIn tConsList
73− errors = catMaybes validation
74− if length errors /= 0 then
77− Right (ConstructedAtomType (TC.name tCons) atomTypesIn)
59+ pure (ConstructedAtomType (TCD.name tCons) typeVars)
61+atomTypeForDataConstructorDefArg :: DataConstructorDefArg -> AtomType -> TypeConstructorMapping -> Either RelationalError AtomType
62+atomTypeForDataConstructorDefArg (DataConstructorDefTypeConstructorArg tCons) aType tConss =
63+ case isValidAtomTypeForTypeConstructor aType tCons tConss of
65+ Nothing -> Right aType
67+atomTypeForDataConstructorDefArg (DataConstructorDefTypeVarNameArg _) aType _ = Right aType --any type is OK
79−validAtomTypeWithTypeConstructorArg :: AtomType -> TypeConstructorArg -> TypeConstructors -> Maybe RelationalError
69+isValidAtomTypeForTypeConstructorArg :: AtomType -> TypeConstructorArg -> TypeConstructorMapping -> Maybe RelationalError
80−validAtomTypeWithTypeConstructorArg aType (TypeConstructorArg tCons) tConsList = validAtomTypeWithTypeConstructor aType tCons tConsList
70+isValidAtomTypeForTypeConstructorArg aType (TypeConstructorArg tCons) tConsList = isValidAtomTypeForTypeConstructor aType tCons tConsList
81−validAtomTypeWithTypeConstructorArg _ (TypeConstructorPolymorphicArg _) _ = Just IncompletelyDefinedAtomTypeWithConstructorError
71+isValidAtomTypeForTypeConstructorArg _ (TypeConstructorTypeVarArg _) _ = Nothing
83--reconcile the atom-in types with the type constructors
73--reconcile the atom-in types with the type constructors
84−validAtomTypeWithTypeConstructor :: AtomType -> TypeConstructor -> TypeConstructors -> Maybe RelationalError
74+isValidAtomTypeForTypeConstructor :: AtomType -> TypeConstructor -> TypeConstructorMapping -> Maybe RelationalError
85−validAtomTypeWithTypeConstructor aType (PrimitiveTypeConstructor _ expectedAType) _ = if expectedAType /= aType then Just (AtomTypeMismatchError expectedAType aType) else Nothing
75+isValidAtomTypeForTypeConstructor aType (PrimitiveTypeConstructor _ expectedAType) _ = if expectedAType /= aType then Just (AtomTypeMismatchError expectedAType aType) else Nothing
87--lookup constructor name and check if the incoming atom types are valid
77--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
90−validAtomTypeWithTypeConstructor aType tCons _ = Just (AtomTypeTypeConstructorReconciliationError aType tCons)
80+isValidAtomTypeForTypeConstructor aType tCons _ = Just (AtomTypeTypeConstructorReconciliationError aType (TC.name tCons))
92-- | Used to determine if the atom arguments can be used with the data constructor.
82-- | Used to determine if the atom arguments can be used with the data constructor.
83+-- | This is the entry point for type-checking from RelationalExpression.hs.
93−atomTypeWithDataConstructor :: TypeConstructors -> DataConstructorName -> [AtomType] -> Either RelationalError AtomType
84+atomTypeForDataConstructor :: TypeConstructorMapping -> DataConstructorName -> [AtomType] -> Either RelationalError AtomType
94−atomTypeWithDataConstructor tConss dConsName atomArgTypes = do
85+atomTypeForDataConstructor tConss dConsName atomArgTypes = do
95 --lookup the data constructor
86 --lookup the data constructor
96 case findDataConstructor dConsName tConss of
87 case findDataConstructor dConsName tConss of
97 Nothing -> Left (NoSuchDataConstructorError dConsName)
88 Nothing -> Left (NoSuchDataConstructorError dConsName)
98 Just (tCons, dCons) -> do
89 Just (tCons, dCons) -> do
99− --match the data constructor arguments to the atom args
90+ --validate that the type constructor arguments are fulfilled in the data constructor
100− let validator (tConsArg', aType) = maybe (Right ()) Left (validAtomTypeWithTypeConstructorArg aType tConsArg' tConss)
91+ typeVars <- resolveDataConstructorTypeVars dCons atomArgTypes tConss
101− mapM_ validator (zip (DC.fields dCons) atomArgTypes)
102− pure (ConstructedAtomType (TC.name tCons) atomArgTypes)
92+ pure (ConstructedAtomType (TCD.name tCons) typeVars)
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!
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
105+resolveDataConstructorArgTypeVars (DataConstructorDefTypeVarNameArg pVarName) aType _ = Right (M.singleton pVarName aType)
107+resolveTypeConstructorTypeVars :: TypeConstructor -> AtomType -> TypeConstructorMapping -> Either RelationalError TypeVarMap
108+resolveTypeConstructorTypeVars (PrimitiveTypeConstructor _ pType) aType tConss =
109+ if aType /= pType then
110+ Left (AtomTypeMismatchError pType aType)
114+resolveTypeConstructorTypeVars (ADTypeConstructor tConsName tConsArgs) (ConstructedAtomType tConsName' pVarMap') tConss =
115+ if tConsName /= tConsName' then
116+ Left (TypeConstructorNameMismatch tConsName tConsName')
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)
126+resolveTypeConstructorTypeVars _ _ _ = error "Unhandled type vars"
104−-- check that polymorphic vars on the right also appear on the left
128+-- check that type vars on the right also appear on the left
105-- check that the data constructor names are unique
129-- check that the data constructor names are unique
106−validateTypeConstructor :: TypeConstructor -> [DataConstructor] -> [RelationalError]
130+validateTypeConstructorDef :: TypeConstructorDef -> [DataConstructorDef] -> [RelationalError]
107−validateTypeConstructor tCons dConsList = execWriter $ do
131+validateTypeConstructorDef tConsDef dConsList = execWriter $ do
108− let duplicateDConsNames = dupes (L.sort (map DC.name dConsList))
132+ let duplicateDConsNames = dupes (L.sort (map DCD.name dConsList))
109 mapM_ tell [map DataConstructorNameInUseError duplicateDConsNames]
133 mapM_ tell [map DataConstructorNameInUseError duplicateDConsNames]
110− let leftSideVars = TC.polymorphicVariables tCons
134+ let leftSideVars = S.fromList (TCD.typeVars tConsDef)
111− rightSideVars = concatMap DC.polymorphicVariables dConsList
135+ rightSideVars = S.unions (map DCD.typeVars dConsList)
112− varsDiff = S.difference (S.fromList leftSideVars) (S.fromList rightSideVars)
136+ varsDiff = S.difference leftSideVars rightSideVars
113 mapM_ tell [map DataConstructorUsesUndeclaredTypeVariable (S.toList varsDiff)]
137 mapM_ tell [map DataConstructorUsesUndeclaredTypeVariable (S.toList varsDiff)]
@@ -120,24 +144,25 @@ dupes (_:[]) = []
120dupes (x:y:[]) = if x == y then [x] else []
144dupes (x:y:[]) = if x == y then [x] else []
121dupes (x:y:xs) = dupes(x:[y]) ++ dupes(xs)
145dupes (x:y:xs) = dupes(x:[y]) ++ dupes(xs)
147+-- | Create an atom type iff all type variables are provided.
148+-- Either Int Text -> ConstructedAtomType "Either" {Int , Text}
123−atomTypeForTypeConstructor :: TypeConstructor -> TypeConstructors -> Either RelationalError AtomType
149+atomTypeForTypeConstructor :: TypeConstructor -> TypeConstructorMapping -> Either RelationalError AtomType
124−atomTypeForTypeConstructor tCons tConsList = foldr tConsFolder defaultErr (map fst tConsList)
150+atomTypeForTypeConstructor tCons tConss = case findTypeConstructor (TC.name tCons) tConss of
125− where
151+ Nothing -> Left (NoSuchTypeConstructorError (TC.name tCons))
126− tConsFolder tCons' accum = if TC.name tCons == TC.name tCons' then do
152+ Just (tConsDef, _) -> do
127− tConsArgTypes <- mapM ((flip atomTypeForTypeConstructorArg) tConsList) (TC.arguments tCons')
153+ tConsArgTypes <- mapM ((flip atomTypeForTypeConstructorArg) tConss) (TC.arguments tCons)
154+ let pVarNames = TCD.typeVars tConsDef
155+ tConsArgs = M.fromList (zip pVarNames tConsArgTypes)
128− Right (ConstructedAtomType (TC.name tCons') tConsArgTypes)
156+ Right (ConstructedAtomType (TC.name tCons) tConsArgs)
131− defaultErr = Left (NoSuchTypeConstructorName (TC.name tCons))
133−atomTypeForTypeConstructorArg :: TypeConstructorArg -> TypeConstructors -> Either RelationalError AtomType
158+atomTypeForTypeConstructorArg :: TypeConstructorArg -> TypeConstructorMapping -> Either RelationalError AtomType
134−atomTypeForTypeConstructorArg (TypeConstructorPolymorphicArg _) _ = Left IncompletelyDefinedAtomTypeWithConstructorError
159+atomTypeForTypeConstructorArg (TypeConstructorTypeVarArg _) _ = Left IncompletelyDefinedAtomTypeWithConstructorError
135atomTypeForTypeConstructorArg (TypeConstructorArg tCons) tConsList = atomTypeForTypeConstructor tCons tConsList
160atomTypeForTypeConstructorArg (TypeConstructorArg tCons) tConsList = atomTypeForTypeConstructor tCons tConsList
137−findTypeConstructor :: TypeConstructorName -> TypeConstructors -> Maybe (TypeConstructor, [DataConstructor])
162+findTypeConstructor :: TypeConstructorName -> TypeConstructorMapping -> Maybe (TypeConstructorDef, [DataConstructorDef])
138findTypeConstructor name tConsList = foldr tConsFolder Nothing tConsList
163findTypeConstructor name tConsList = foldr tConsFolder Nothing tConsList
140− tConsFolder (tCons, dConsList) accum = if TC.name tCons == name then
165+ tConsFolder (tCons, dConsList) accum = if TCD.name tCons == name then
141 Just (tCons, dConsList)
166 Just (tCons, dConsList)