on master help sign in
WIP: runtime type system
cbf399cAgentM
ProjectM36/Atom.hs+12−1
@@ -8,11 +8,13 @@ import qualified Data.Text as T
8import Data.Time.Calendar (Day)
8import Data.Time.Calendar (Day)
9import Data.Time.Clock
9import Data.Time.Clock
10import Data.ByteString (ByteString)
10import Data.ByteString (ByteString)
11+import qualified Data.Map as M
11
12
12relationForAtom :: Atom -> Either RelationalError Relation
13relationForAtom :: Atom -> Either RelationalError Relation
13relationForAtom (Atom atom) = case cast atom of
14relationForAtom (Atom atom) = case cast atom of
14 Just rel@(Relation _ _) -> Right rel
15 Just rel@(Relation _ _) -> Right rel
15 Nothing -> Left $ AttributeIsNotRelationValuedError ""
16 Nothing -> Left $ AttributeIsNotRelationValuedError ""
17+relationForAtom (ConstructedAtom _ _ _) = Left $ AttributeIsNotRelationValuedError ""
16
18
17atomTypeForProxy :: (Atomable a) => Proxy a -> AtomType
19atomTypeForProxy :: (Atomable a) => Proxy a -> AtomType
18atomTypeForProxy prox = AtomType $ CTR (typeRep prox)
20atomTypeForProxy prox = AtomType $ CTR (typeRep prox)
@@ -70,11 +72,20 @@ intAtom i = Atom i
70
72
71--not safe to use without upfront type-checking
73--not safe to use without upfront type-checking
72castRelation :: Atom -> Relation
74castRelation :: Atom -> Relation
75+castRelation (ConstructedAtom _ _ _) = error "castRelation attempt on ConstructedAtom"
73castRelation (Atom atom) = case cast atom of
76castRelation (Atom atom) = case cast atom of
74 Just rel -> rel
77 Just rel -> rel
75− Nothing -> error "castRelation failure"
78+ Nothing -> error "castRelation attempt on non-relation-typed Atom"
76
79
77unsafeCast :: (Atomable a) => Atom -> a
80unsafeCast :: (Atomable a) => Atom -> a
81+unsafeCast (ConstructedAtom _ _ _) = error "unsafeCast attempt on ConstructedAtom"
78unsafeCast (Atom atom) = case cast atom of
82unsafeCast (Atom atom) = case cast atom of
79 Just x -> x
83 Just x -> x
80 Nothing -> error "unsafeCast failed"
84 Nothing -> error "unsafeCast failed"
85+
86+emptyAtomConstructor :: AtomConstructor
87+emptyAtomConstructor = AtomConstructor M.empty
88+
89+basicAtomTypes :: AtomTypes
90+basicAtomTypes = M.fromList [("Int", (intAtomType, emptyAtomConstructor))]
91+
ProjectM36/AtomType.hsnew file+23
@@ -0,0 +1,23 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module ProjectM36.AtomType where
3+import ProjectM36.Base
4+import ProjectM36.Relation
5+import qualified Data.Text as T
6+import ProjectM36.Error
7+import ProjectM36.Attribute
8+import ProjectM36.Atom
9+import qualified Data.Map as M
10+import qualified Data.Vector as V
11+
12+atomTypesAsRelation :: AtomTypes -> Either RelationalError Relation
13+atomTypesAsRelation aTypes = mkRelationFromTuples attrs tuples
14+ where
15+ attrs = attributesFromList [Attribute "TypeConstructor" stringAtomType,
16+ Attribute "DataConstructors" dConsType]
17+ subAttrs = attributesFromList [Attribute "DataConstructor" stringAtomType]
18+ dConsType = RelationAtomType subAttrs
19+ tuples = map mkTypeConsDescription (M.toList aTypes)
20+ mkTypeConsDescription (tConsName, (_, AtomConstructor dConsMap)) = RelationTuple attrs (V.fromList [stringAtom tConsName, mkDataConsRelation dConsMap])
21+ mkDataConsRelation dConsMap = case mkRelationFromTuples subAttrs $ map (\(dConsName, dConsTypeNames) -> RelationTuple subAttrs (V.singleton $ T.intercalate " " dConsName:dConsTypeNames)) $ M.toList dConsMap of
22+ Left err -> error "mkRelationFromTuples pooped"
23+ Right rel -> Atom rel
ProjectM36/Base.hs+37−4
@@ -56,22 +56,30 @@ instance Atomable Relation
56instance (Atomable a) => Atomable (Maybe a)
56instance (Atomable a) => Atomable (Maybe a)
57
57
58-- | Database atoms are the smallest, undecomposable units of a tuple. Common examples are integers, text, or unique identity keys.
58-- | Database atoms are the smallest, undecomposable units of a tuple. Common examples are integers, text, or unique identity keys.
59−data Atom = forall a. Atomable a => Atom a
59+data Atom = forall a. Atomable a => Atom a |
60−
60+ ConstructedAtom DataConstructorName AtomType [Atom]
61+
61instance Eq Atom where
62instance Eq Atom where
62 (Atom a) == (Atom b) = Just a == cast b
63 (Atom a) == (Atom b) = Just a == cast b
64+ (ConstructedAtom dConsNameA aTypeA atomListA) == (ConstructedAtom dConsNameB aTypeB atomListB) = aTypeA == aTypeB &&
65+ atomListA == atomListB &&
66+ dConsNameA == dConsNameB
67+ _ == _ = False
63
68
64instance Show Atom where
69instance Show Atom where
65 show (Atom atom) = "Atom " ++ show atom
70 show (Atom atom) = "Atom " ++ show atom
71+ show (ConstructedAtom dConsName _ atomList) = unpack dConsName ++ " " ++ L.concat (L.intersperse " " (map show atomList))
66
72
67instance Binary Atom where
73instance Binary Atom where
68 put atom@(Atom val) = put (atomTypeForAtom atom) >> put val
74 put atom@(Atom val) = put (atomTypeForAtom atom) >> put val
75+ put (ConstructedAtom dConsName aType atomList) = put aType >> put dConsName >> put atomList
69 get = do
76 get = do
70 atomtype <- get
77 atomtype <- get
71 --not-so-great for this to be hardcoded here- it would be nicer to have a dispatch table linked to the instances themselves
78 --not-so-great for this to be hardcoded here- it would be nicer to have a dispatch table linked to the instances themselves
72 --http://stackoverflow.com/questions/8101067/binary-instance-for-an-existential
79 --http://stackoverflow.com/questions/8101067/binary-instance-for-an-existential
73 case atomtype of
80 case atomtype of
74 AnyAtomType -> error "unsupported serialization AnyAtomType"
81 AnyAtomType -> error "unsupported serialization AnyAtomType"
82+ caType@(ConstructedAtomType _) -> ConstructedAtom <$> (get :: Get DataConstructorName) <*> pure caType <*> (get :: Get [Atom]) --we really should verify the type with the atoms
75 (RelationAtomType _) -> Atom <$> (get :: Get Relation)
83 (RelationAtomType _) -> Atom <$> (get :: Get Relation)
76 (AtomType cTypeRep) -> if unCTR cTypeRep == typeRep (Proxy :: Proxy Int) then
84 (AtomType cTypeRep) -> if unCTR cTypeRep == typeRep (Proxy :: Proxy Int) then
77 Atom <$> (get :: Get Int)
85 Atom <$> (get :: Get Int)
@@ -92,15 +100,19 @@ instance Binary Atom where
92
100
93instance NFData Atom where
101instance NFData Atom where
94 rnf !(Atom a) = rnf a
102 rnf !(Atom a) = rnf a
103+ rnf !(ConstructedAtom dConsName aType atomList) = rnf (dConsName, atomList, aType)
95
104
96instance Hashable Atom where
105instance Hashable Atom where
97 hashWithSalt salt (Atom a) = hashWithSalt salt a
106 hashWithSalt salt (Atom a) = hashWithSalt salt a
107+ hashWithSalt salt (ConstructedAtom dConsName _ atomList) = salt `hashWithSalt` atomList
108+ `hashWithSalt` dConsName --AtomType is not hashable
98
109
99-- | Return the type of an 'Atom'.
110-- | Return the type of an 'Atom'.
100atomTypeForAtom :: Atom -> AtomType
111atomTypeForAtom :: Atom -> AtomType
101atomTypeForAtom (Atom atom) = case cast atom of
112atomTypeForAtom (Atom atom) = case cast atom of
102 Just (Relation attrs _) -> RelationAtomType attrs
113 Just (Relation attrs _) -> RelationAtomType attrs
103 Nothing -> AtomType $ CTR (typeOf atom)
114 Nothing -> AtomType $ CTR (typeOf atom)
115+atomTypeForAtom (ConstructedAtom _ aType _) = aType
104
116
105instance Binary UTCTime where
117instance Binary UTCTime where
106 put utc = put $ toRational (utcTimeToPOSIXSeconds utc)
118 put utc = put $ toRational (utcTimeToPOSIXSeconds utc)
@@ -113,9 +125,12 @@ instance Binary Day where
113 get = do
125 get = do
114 (y,m,d) <- get :: Get (Integer, Int, Int)
126 (y,m,d) <- get :: Get (Integer, Int, Int)
115 return (fromGregorian y m d)
127 return (fromGregorian y m d)
116−
128+
129+-- I suspect the definition of ConstructedAtomType with its name alone is insufficient to disambiguate the cases; for example, one could create a type named X, remove a type named X, and re-add it using different constructors. However, as long as requests are served from only one DatabaseContext at-a-time, the type name is unambiguous. This will become a problem for time-travel, however.
130+-- | The AtomType must uniquely identify the type of a atom.
117data AtomType = AtomType ConcreteTypeRep |
131data AtomType = AtomType ConcreteTypeRep |
118 RelationAtomType Attributes |
132 RelationAtomType Attributes |
133+ ConstructedAtomType TypeConstructorName |
119 AnyAtomType --wildcard used in Atom Functions
134 AnyAtomType --wildcard used in Atom Functions
120 deriving (Eq,NFData,Generic,Binary,Show)
135 deriving (Eq,NFData,Generic,Binary,Show)
121
136
@@ -124,6 +139,7 @@ isRelationAtomType :: AtomType -> Bool
124isRelationAtomType (RelationAtomType _) = True
139isRelationAtomType (RelationAtomType _) = True
125isRelationAtomType _ = False
140isRelationAtomType _ = False
126
141
142+-- | The AttributeName is the name of an attribute in a relation.
127type AttributeName = StringType
143type AttributeName = StringType
128
144
129-- | A relation's type is composed of attribute names and types.
145-- | A relation's type is composed of attribute names and types.
@@ -256,12 +272,15 @@ data Notification = Notification {
256 }
272 }
257 deriving (Show, Eq, Binary, Generic)
273 deriving (Show, Eq, Binary, Generic)
258
274
275+type AtomTypes = M.Map TypeConstructorName (AtomType, AtomConstructor)
276+
259-- | The DatabaseContext is a snapshot of a database's evolving state and contains everything a database client can change over time.
277-- | The DatabaseContext is a snapshot of a database's evolving state and contains everything a database client can change over time.
260data DatabaseContext = DatabaseContext {
278data DatabaseContext = DatabaseContext {
261 inclusionDependencies :: M.Map IncDepName InclusionDependency,
279 inclusionDependencies :: M.Map IncDepName InclusionDependency,
262 relationVariables :: M.Map RelVarName Relation,
280 relationVariables :: M.Map RelVarName Relation,
263 atomFunctions :: AtomFunctions,
281 atomFunctions :: AtomFunctions,
264− notifications :: Notifications
282+ notifications :: Notifications,
283+ atomTypes :: AtomTypes
265 } deriving (Show, Generic)
284 } deriving (Show, Generic)
266
285
267type IncDepName = StringType
286type IncDepName = StringType
@@ -285,10 +304,24 @@ data DatabaseExpr where
285
304
286 AddNotification :: NotificationName -> RelationalExpr -> RelationalExpr -> DatabaseExpr
305 AddNotification :: NotificationName -> RelationalExpr -> RelationalExpr -> DatabaseExpr
287 RemoveNotification :: NotificationName -> DatabaseExpr
306 RemoveNotification :: NotificationName -> DatabaseExpr
307+
308+ -- this may be generalized to AddAtomFunction in the future
309+ AddAtomConstructor :: TypeConstructorName -> AtomConstructor -> DatabaseExpr
310+ RemoveAtomConstructor :: TypeConstructorName -> DatabaseExpr
311+
312+ -- to implement this, I likely need to implement a DSL for constructing arbitrary functions to operate on atoms at runtime
313+ --AddAtomFunction :: AtomFunction -> DatabaseExpr
314+ --RemoveAtomFunction :: AtomFunctionName -> DatabaseExpr
288
315
289 MultipleExpr :: [DatabaseExpr] -> DatabaseExpr
316 MultipleExpr :: [DatabaseExpr] -> DatabaseExpr
290 deriving (Show, Eq, Binary, Generic)
317 deriving (Show, Eq, Binary, Generic)
291
318
319+type TypeConstructorName = StringType
320+type DataConstructorName = StringType
321+type AtomTypeName = StringType
322+
323+data AtomConstructor = AtomConstructor (M.Map DataConstructorName [AtomTypeName]) deriving (Eq, Show, Binary, Generic)
324+
292type DatabaseState a = State DatabaseContext a
325type DatabaseState a = State DatabaseContext a
293
326
294-- | Restriction predicate are boolean algebra components which, when composed, indicate whether or not a tuple should be retained during a restriction (filtering) operation.
327-- | Restriction predicate are boolean algebra components which, when composed, indicate whether or not a tuple should be retained during a restriction (filtering) operation.
ProjectM36/Client.hs+10−4
@@ -56,7 +56,8 @@ import ProjectM36.TransactionGraph.Persist
56import ProjectM36.Attribute
56import ProjectM36.Attribute
57import ProjectM36.Persist (DiskSync(..))
57import ProjectM36.Persist (DiskSync(..))
58import ProjectM36.Notifications
58import ProjectM36.Notifications
59−import ProjectM36.Server.RemoteCallTypes
59+import ProjectM36.Server.RemoteCallTypes
60+import ProjectM36.AtomType (atomTypesAsRelation)
60import Network.Transport.TCP (createTransport, defaultTCPParameters, encodeEndPointAddress)
61import Network.Transport.TCP (createTransport, defaultTCPParameters, encodeEndPointAddress)
61import Control.Distributed.Process.Node (newLocalNode, initRemoteTable, runProcess, LocalNode, forkProcess)
62import Control.Distributed.Process.Node (newLocalNode, initRemoteTable, runProcess, LocalNode, forkProcess)
62import Control.Distributed.Process.Extras.Internal.Types (whereisRemote)
63import Control.Distributed.Process.Extras.Internal.Types (whereisRemote)
@@ -504,6 +505,11 @@ headName sessionId (InProcessConnection _ _ sessions graphTvar) = do
504 atomically (headNameSTM_ sessionId sessions graphTvar)
505 atomically (headNameSTM_ sessionId sessions graphTvar)
505headName sessionId conn@(RemoteProcessConnection _ _) = remoteCall conn (ExecuteHeadName sessionId)
506headName sessionId conn@(RemoteProcessConnection _ _) = remoteCall conn (ExecuteHeadName sessionId)
506
507
507−
508+atomTypesAsRelation :: SessionId -> Connection -> IO (Either RelationalError Relation)
508−
509+atomTypesAsRelation sessionId (InProcessConnection _ _ sessions) = do
509−
510+ atomically $ do
511+ eSession <- sessionForSessionId sessionId sessions
512+ case eSession of
513+ Left err -> pure (Left err)
514+ Right (Session discon) -> do
515+
ProjectM36/DatabaseContext.hs+2−1
@@ -7,7 +7,8 @@ empty :: DatabaseContext
7empty = DatabaseContext { inclusionDependencies = M.empty,
7empty = DatabaseContext { inclusionDependencies = M.empty,
8 relationVariables = M.empty,
8 relationVariables = M.empty,
9 notifications = M.empty,
9 notifications = M.empty,
10− atomFunctions = HS.empty }
10+ atomFunctions = HS.empty,
11+ atomTypes = M.empty }
11
12
12-- | convert an existing database context into its constituent expression.
13-- | convert an existing database context into its constituent expression.
13databaseContextAsDatabaseContextExpr :: DatabaseContext -> DatabaseExpr
14databaseContextAsDatabaseContextExpr :: DatabaseContext -> DatabaseExpr
ProjectM36/Error.hs+3
@@ -33,6 +33,9 @@ data RelationalError = NoSuchAttributeNamesError (S.Set AttributeName)
33 | NoSuchSession U.UUID
33 | NoSuchSession U.UUID
34 | NoSuchTupleExprFunctionError AtomFunctionName
34 | NoSuchTupleExprFunctionError AtomFunctionName
35 | AtomTypeMismatchError AtomType AtomType
35 | AtomTypeMismatchError AtomType AtomType
36+ | AtomTypeNameInUseError AtomTypeName
37+ | AtomTypeNameNotInUseError AtomTypeName
38+ | InvalidAtomTypeName AtomTypeName
36 | AtomTypeNotSupported AttributeName --used by persistent driver
39 | AtomTypeNotSupported AttributeName --used by persistent driver
37 | AtomOperatorNotSupported T.Text --used by persistent driver
40 | AtomOperatorNotSupported T.Text --used by persistent driver
38 | EmptyTuplesError -- used by persistent driver
41 | EmptyTuplesError -- used by persistent driver
ProjectM36/Relation.hs+1
@@ -271,6 +271,7 @@ matrixRelation attributeCount tupleCount = do
271
271
272
272
273castInt :: Atom -> Int
273castInt :: Atom -> Int
274+castInt (ConstructedAtom _ _ _) = error "castInt attempt on ConstructedAtom"
274castInt (Atom atom) = case cast atom of
275castInt (Atom atom) = case cast atom of
275 Just i -> i
276 Just i -> i
276 Nothing -> error "int cast failure" -- the type checker must ensure this can never occur
277 Nothing -> error "int cast failure" -- the type checker must ensure this can never occur
ProjectM36/Relation/Show/CSV.hs+3−2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE OverloadedStrings #-}
1{-# OPTIONS_GHC -fno-warn-orphans #-}
2{-# OPTIONS_GHC -fno-warn-orphans #-}
2module ProjectM36.Relation.Show.CSV where
3module ProjectM36.Relation.Show.CSV where
3import ProjectM36.Base
4import ProjectM36.Base
@@ -8,8 +9,7 @@ import qualified Data.ByteString.Lazy as BS
8import qualified Data.Vector as V
9import qualified Data.Vector as V
9import ProjectM36.Error
10import ProjectM36.Error
10import qualified Data.Text.Encoding as TE
11import qualified Data.Text.Encoding as TE
11−
12+import qualified Data.Text as T
12−
13
13
14--spit out error for relations without attributes (since relTrue and relFalse cannot be distinguished then as CSV) and for relations with relation-valued attributes
14--spit out error for relations without attributes (since relTrue and relFalse cannot be distinguished then as CSV) and for relations with relation-valued attributes
15relationAsCSV :: Relation -> Either RelationalError BS.ByteString
15relationAsCSV :: Relation -> Either RelationalError BS.ByteString
@@ -39,4 +39,5 @@ instance DefaultOrdered RecordRelationTuple where
39newtype RecordAtom = RecordAtom {unAtom :: Atom}
39newtype RecordAtom = RecordAtom {unAtom :: Atom}
40
40
41instance ToField RecordAtom where
41instance ToField RecordAtom where
42+ toField (RecordAtom (ConstructedAtom dConsName _ atomList)) = TE.encodeUtf8 $ dConsName `T.append` T.intercalate " " (map (\(Atom x) -> toText x) atomList)
42 toField (RecordAtom (Atom atomVal)) = (TE.encodeUtf8 . toText) atomVal
43 toField (RecordAtom (Atom atomVal)) = (TE.encodeUtf8 . toText) atomVal
ProjectM36/Relation/Show/Term.hs+1
@@ -95,6 +95,7 @@ showAtom :: Atom -> StringType
95showAtom (Atom atom) = case cast atom of
95showAtom (Atom atom) = case cast atom of
96 Just rel -> renderTable $ relationAsTable rel
96 Just rel -> renderTable $ relationAsTable rel
97 Nothing -> toText atom
97 Nothing -> toText atom
98+showAtom (ConstructedAtom dConsName _ atoms) = dConsName `T.append` " " `T.append` T.concat (L.intersperse " " (map showAtom atoms))
98
99
99renderTable :: Table -> StringType
100renderTable :: Table -> StringType
100renderTable table = renderHeader table (fst cellLocs) `T.append` renderBody (snd table) cellLocs
101renderTable table = renderHeader table (fst cellLocs) `T.append` renderBody (snd table) cellLocs
ProjectM36/RelationalExpression.hs+34−3
@@ -16,6 +16,8 @@ import qualified Data.Set as S
16import Control.Monad.State hiding (join)
16import Control.Monad.State hiding (join)
17import Data.Maybe
17import Data.Maybe
18import Data.Either
18import Data.Either
19+import Data.Char (isUpper)
20+import qualified Data.Text as T
19
21
20--relvar state is needed in evaluation of relational expression but only as read-only in order to extract current relvar values
22--relvar state is needed in evaluation of relational expression but only as read-only in order to extract current relvar values
21evalRelationalExpr :: RelationalExpr -> DatabaseState (Either RelationalError Relation)
23evalRelationalExpr :: RelationalExpr -> DatabaseState (Either RelationalError Relation)
@@ -117,7 +119,8 @@ emptyDatabaseContext :: DatabaseContext
117emptyDatabaseContext = DatabaseContext { inclusionDependencies = M.empty,
119emptyDatabaseContext = DatabaseContext { inclusionDependencies = M.empty,
118 relationVariables = M.empty,
120 relationVariables = M.empty,
119 atomFunctions = HS.empty,
121 atomFunctions = HS.empty,
120− notifications = M.empty
122+ notifications = M.empty,
123+ atomTypes = M.empty
121 }
124 }
122
125
123basicDatabaseContext :: DatabaseContext
126basicDatabaseContext :: DatabaseContext
@@ -125,14 +128,16 @@ basicDatabaseContext = DatabaseContext { inclusionDependencies = M.empty,
125 relationVariables = M.fromList [("true", relationTrue),
128 relationVariables = M.fromList [("true", relationTrue),
126 ("false", relationFalse)],
129 ("false", relationFalse)],
127 atomFunctions = basicAtomFunctions,
130 atomFunctions = basicAtomFunctions,
128− notifications = M.empty
131+ notifications = M.empty,
132+ atomTypes = basicAtomTypes
129 }
133 }
130
134
131dateExamples :: DatabaseContext
135dateExamples :: DatabaseContext
132dateExamples = DatabaseContext { inclusionDependencies = dateIncDeps,
136dateExamples = DatabaseContext { inclusionDependencies = dateIncDeps,
133 relationVariables = M.union (relationVariables basicDatabaseContext) dateRelVars,
137 relationVariables = M.union (relationVariables basicDatabaseContext) dateRelVars,
134 notifications = M.empty,
138 notifications = M.empty,
135− atomFunctions = basicAtomFunctions}
139+ atomFunctions = basicAtomFunctions,
140+ atomTypes = basicAtomTypes }
136 where
141 where
137 dateRelVars = M.fromList [("S", suppliers),
142 dateRelVars = M.fromList [("S", suppliers),
138 ("P", products),
143 ("P", products),
@@ -327,6 +332,32 @@ evalContextExpr (RemoveNotification notName) = do
327 put $ currentContext { notifications = newNotifications }
332 put $ currentContext { notifications = newNotifications }
328 return Nothing
333 return Nothing
329
334
335+-- | Adds type and data constructors to the database context.
336+-- validate that the type *and* constructor names are unique! not yet implemented!
337+evalContextExpr (AddAtomConstructor tConsName atomConstructor) = do
338+ currentContext <- get
339+ let oldAtomTypes = atomTypes currentContext
340+ if T.length tConsName < 1 || not (isUpper (T.head tConsName)) then
341+ pure $ Just (InvalidAtomTypeName tConsName)
342+ else if M.member tConsName oldAtomTypes then
343+ pure $ Just (AtomTypeNameInUseError tConsName)
344+ else do
345+ let newAtomTypes = M.insert tConsName newType oldAtomTypes
346+ newType = (ConstructedAtomType tConsName, atomConstructor)
347+ put $ currentContext { atomTypes = newAtomTypes }
348+ pure Nothing
349+
350+-- | Removing the atom constructor prevents new atoms of the type from being created. Existing atoms of the type remain. Thus, the atomTypes list in the DatabaseContext need not be all-inclusive.
351+evalContextExpr (RemoveAtomConstructor tConsName) = do
352+ currentContext <- get
353+ let oldAtomTypes = atomTypes currentContext
354+ if M.notMember tConsName oldAtomTypes then
355+ pure $ Just (AtomTypeNameNotInUseError tConsName)
356+ else do
357+ let newAtomTypes = M.delete tConsName oldAtomTypes
358+ put $ currentContext { atomTypes = newAtomTypes }
359+ pure Nothing
360+
330evalContextExpr (MultipleExpr exprs) = do
361evalContextExpr (MultipleExpr exprs) = do
331 --the multiple expressions must pass the same context around- not the old unmodified context
362 --the multiple expressions must pass the same context around- not the old unmodified context
332 evald <- forM exprs evalContextExpr
363 evald <- forM exprs evalContextExpr
TutorialD/Interpreter/DatabaseExpr.hs+21
@@ -26,6 +26,8 @@ databaseExprP = insertP
26 <|> assignP
26 <|> assignP
27 <|> addNotificationP
27 <|> addNotificationP
28 <|> removeNotificationP
28 <|> removeNotificationP
29+ <|> addAtomConstructorP
30+ <|> removeAtomConstructorP
29
31
30assignP :: Parser DatabaseExpr
32assignP :: Parser DatabaseExpr
31assignP = do
33assignP = do
@@ -124,6 +126,25 @@ removeNotificationP = do
124 notName <- identifier
126 notName <- identifier
125 return $ RemoveNotification (T.pack notName)
127 return $ RemoveNotification (T.pack notName)
126
128
129+-- | data Hair = Bald | Color Text
130+addAtomConstructorP :: Parser DatabaseExpr
131+addAtomConstructorP = do
132+ reserved "data"
133+ typeConstructorName <- identifier
134+ reservedOp "="
135+ dataConstructors <- sepBy1 dataConstructorP comma
136+ let aCons = AtomConstructor (M.fromList dataConstructors)
137+ pure (AddAtomConstructor (T.pack typeConstructorName) aCons)
138+
139+dataConstructorP :: Parser (DataConstructorName, [AtomTypeName])
140+dataConstructorP = do
141+ dConsName <- identifier
142+ atomTypeNames <- sepBy (liftM T.pack identifier) spaces
143+ pure (T.pack dConsName, atomTypeNames)
144+
145+removeAtomConstructorP :: Parser DatabaseExpr
146+removeAtomConstructorP = RemoveAtomConstructor <$> liftM T.pack identifier
147+
127databaseExprOpP :: Parser DatabaseExpr
148databaseExprOpP :: Parser DatabaseExpr
128databaseExprOpP = multipleDatabaseExprP
149databaseExprOpP = multipleDatabaseExprP
129
150
TutorialD/Interpreter/RODatabaseContextOperator.hs+4
@@ -21,6 +21,7 @@ data RODatabaseContextOperator where
21 ShowRelationType :: RelationalExpr -> RODatabaseContextOperator
21 ShowRelationType :: RelationalExpr -> RODatabaseContextOperator
22 ShowConstraint :: StringType -> RODatabaseContextOperator
22 ShowConstraint :: StringType -> RODatabaseContextOperator
23 ShowPlan :: DatabaseExpr -> RODatabaseContextOperator
23 ShowPlan :: DatabaseExpr -> RODatabaseContextOperator
24+ ShowTypes :: RODatabaseContextOperator
24 Quit :: RODatabaseContextOperator
25 Quit :: RODatabaseContextOperator
25 deriving (Show)
26 deriving (Show)
26
27
@@ -42,6 +43,9 @@ showPlanP = do
42 expr <- databaseExprP
43 expr <- databaseExprP
43 return $ ShowPlan expr
44 return $ ShowPlan expr
44
45
46+showTypesP :: Parser RODatabaseContextOperator
47+showTypesP = reserved ":showtypes" >> pure ShowTypes
48+
45quitP :: Parser RODatabaseContextOperator
49quitP :: Parser RODatabaseContextOperator
46quitP = do
50quitP = do
47 reservedOp ":quit"
51 reservedOp ":quit"
project-m36.cabal+1
@@ -88,6 +88,7 @@ Library
88 ProjectM36.Relation.Parse.CSV,
88 ProjectM36.Relation.Parse.CSV,
89 ProjectM36.Client,
89 ProjectM36.Client,
90 ProjectM36.Persist,
90 ProjectM36.Persist,
91+ ProjectM36.AtomType,
91 Database.Persist.ProjectM36
92 Database.Persist.ProjectM36
92 GHC-Options: -Wall -rtsopts
93 GHC-Options: -Wall -rtsopts
93 C-sources: ProjectM36/DirectoryFsync.c
94 C-sources: ProjectM36/DirectoryFsync.c