2module TutorialDInterpreter where
9import Text.Parsec.String
10import Text.Parsec.Expr
11import Text.Parsec.Language
12import qualified Text.Parsec.Token as Token
13import qualified Data.Set as S
14import qualified Data.HashSet as HS
15import qualified Data.Map as M
16import qualified Data.List as L
17import Control.Applicative (liftA, (<*), (*>))
18import Control.Monad.State
19import System.Console.Readline
22lexer :: Token.TokenParser ()
23lexer = Token.makeTokenParser tutD
24 where tutD = emptyDef {
25 Token.reservedOpNames = ["join", "where", "union", "group", "ungroup"],
26 Token.reservedNames = [],
27 Token.identStart = letter <|> char '_',
28 Token.identLetter = alphaNum <|> char '_'}
30parens = Token.parens lexer
31reservedOp = Token.reservedOp lexer
32reserved = Token.reserved lexer
33braces = Token.braces lexer
34identifier = Token.identifier lexer
35comma = Token.comma lexer
36semi = Token.semi lexer
39attributeList :: Parser [AttributeName]
40attributeList = sepBy identifier comma
42makeRelation :: Parser RelationalExpr
45 attrs <- makeAttributes
46 return $ MakeStaticRelation attrs HS.empty
48--used in relation creation
49makeAttributes :: Parser Attributes
51 attrList <- braces (sepBy attributeAndType comma)
52 return $ M.fromList $ map toAttributeAssocList attrList
54 toAttributeAssocList attr@(Attribute attrName _) = (attrName, attr)
56attributeAndType :: Parser Attribute
58 attrName <- identifier
59 attrTypeName <- identifier
60 --convert type name into type
61 case tutDTypeToAtomType attrTypeName of
62 Just t -> return $ Attribute attrName t
63 Nothing -> fail (attrTypeName ++ " is not a valid type name.")
65tupleP :: Parser RelationTuple
68 attrValues <- braces (sepBy tupleAtomP comma)
69 return $ RelationTuple (M.fromList attrValues)
71tupleAtomP :: Parser (AttributeName, Atom)
73 attributeName <- identifier
74 attrType <- identifier
75 atom <- parens (stringAtomP <|> intAtomP)
76 case tutDTypeToAtomType attrType of
77 Nothing -> fail (attrType ++ " is not a valid type name.")
78 Just typeA -> if typeA == atomTypeForAtom atom then
79 return $ (attributeName, atom)
81 fail "type mismatch in tuple generation"
83--convert Tutorial D type to AtomType
84tutDTypeToAtomType :: String -> Maybe AtomType
85tutDTypeToAtomType tutDType = case tutDType of
86 "char" -> Just StringAtomType
87 "int" -> Just IntAtomType
90atomTypeToTutDType :: AtomType -> Maybe String
91atomTypeToTutDType atomType = case atomType of
92 StringAtomType -> Just "char"
93 IntAtomType -> Just "int"
94 --RelationAtomType rel ->
97relVarP :: Parser RelationalExpr
98relVarP = liftA RelationVariable identifier
100relTerm = parens relExpr
105 attrs <- braces attributeList
106 return $ Project (S.fromList attrs)
108assignP :: Parser DatabaseExpr
110 relVarName <- try $ do
111 relVarName <- identifier
115 return $ Assign relVarName expr
118 oldAttr <- identifier
120 newAttr <- identifier
121 return $ (oldAttr, newAttr)
123renameP :: Parser (RelationalExpr -> RelationalExpr)
126 (oldAttr, newAttr) <- braces renameClause
127 return $ Rename oldAttr newAttr
131 boolExpr <- restrictionPredicateP
132 return $ Restrict boolExpr
135 attrs <- braces attributeList
137 newAttrName <- identifier
138 return $ (attrs, newAttrName)
140groupP :: Parser (RelationalExpr -> RelationalExpr)
143 (groupAttrList, groupAttrName) <- parens groupClause
144 return $ Group (S.fromList groupAttrList) groupAttrName
146--in "Time and Relational Theory" (2014), Date's Tutorial D grammar for ungroup takes one attribute, while in previous books, it take multiple arguments. Let us assume that nested ungroups are the same as multiple attributes.
147ungroupP :: Parser (RelationalExpr -> RelationalExpr)
150 rvaAttrName <- identifier
151 return $ Ungroup rvaAttrName
156 [Postfix whereClauseP],
159 [Infix (reservedOp "join" >> return Join) AssocLeft],
160 [Infix (reservedOp "union" >> return Union) AssocLeft],
161 [Infix (reservedOp "=" >> return Equals) AssocNone]
164relExpr :: Parser RelationalExpr
165relExpr = buildExpressionParser relOperators relTerm
167databaseExpr :: Parser DatabaseExpr
168databaseExpr = insertP
175multipleDatabaseExpr :: Parser DatabaseExpr
176multipleDatabaseExpr = do
177 exprs <- sepBy1 databaseExpr semi
178 return $ MultipleExpr exprs
180insertP :: Parser DatabaseExpr
185 return $ Insert relvar expr
187defineP :: Parser DatabaseExpr
189 relVarName <- try $ do
190 relVarName <- identifier
193 attributes <- makeAttributes
194 return $ Define relVarName attributes
196deleteP :: Parser DatabaseExpr
199 relVarName <- identifier
200 return $ Delete relVarName
202updateP :: Parser DatabaseExpr
205 relVarName <- identifier
206 predicate <- option TruePredicate (reservedOp "where" *> restrictionPredicateP <* spaces)
207 attributeAssignments <- liftM M.fromList $ parens (sepBy attributeAssignment comma)
208 return $ Update relVarName attributeAssignments predicate
210constraintP :: Parser DatabaseExpr
212 reservedOp "constraint"
213 constraintName <- identifier
217 return $ AddInclusionDependency (InclusionDependency constraintName subset superset)
219attributeAssignment :: Parser (String, Atom)
220attributeAssignment = do
221 attrName <- identifier
223 atom <- stringAtomP <|> intAtomP
224 return $ (attrName, atom)
226parseString :: String -> Either RelationalError DatabaseExpr
227parseString str = case parse multipleDatabaseExpr "" str of
228 Left err -> Left $ ParseError (show err)
231data TutorialDOperator where
232 ShowRelation :: RelationalExpr -> TutorialDOperator
233 ShowRelationType :: RelationalExpr -> TutorialDOperator
234 ShowConstraint :: String -> TutorialDOperator
235 Quit :: TutorialDOperator
238typeP :: Parser TutorialDOperator
242 return $ ShowRelationType expr
244showRelP :: Parser TutorialDOperator
248 return $ ShowRelation expr
250quitP :: Parser TutorialDOperator
255showConstraintsP :: Parser TutorialDOperator
258 constraintName <- option "" identifier
259 return $ ShowConstraint constraintName
261interpreterOps :: Parser TutorialDOperator
262interpreterOps = typeP
267showRelationAttributes :: Relation -> String
268showRelationAttributes rel = "{" ++ concat (L.intersperse ", " $ map showAttribute attrs) ++ "}"
270 showAttribute (Attribute name atomType) = name ++ " " ++ case atomTypeToTutDType atomType of
273 attrs = values (attributes rel)
274 values m = map snd (M.toAscList m)
276data TutorialDOperatorResult = QuitResult |
277 DisplayResult String |
278 DisplayErrorResult String |
281evalTutorialDOp :: DatabaseContext -> TutorialDOperator -> TutorialDOperatorResult
282evalTutorialDOp context (ShowRelationType expr) = case runState (typeForRelationalExpr expr) context of
283 (Right rel, _) -> DisplayResult $ showRelationAttributes rel
284 (Left err, _) -> DisplayErrorResult $ show err
286evalTutorialDOp context (ShowRelation expr) = do
287 case runState (evalRelationalExpr expr) context of
288 (Left err, _) -> DisplayErrorResult $ show err
289 (Right rel, _) -> DisplayResult $ showRelation rel
291evalTutorialDOp context (ShowConstraint name) = do
292 DisplayResult $ show filteredDeps
294 deps = inclusionDependencies context
295 filteredDeps = case name of
297 name -> HS.filter (\(InclusionDependency n _ _) -> n == name) deps
299evalTutorialDOp context (Quit) = QuitResult
301example1 = "relA {a,b, c}"
302example2 = "relA join relB"
303example3 = "relA join relB {x,y,z}"
304example4 = "(relA) {x,y,z}"
305example5 = "relA union relB"
306example6 = "rv1 := true"
307example7 = "rv1 := relA union relB"
308example8 = "relA := true; relB := false"
309example9 = "relA := relation { SNO CHAR }"
311interpret :: DatabaseContext -> String -> (Maybe RelationalError, DatabaseContext)
312interpret context tutdstring = case parseString tutdstring of
313 Left err -> (Just err, context)
314 Right parsed -> runState (evalContextExpr parsed) context
316-- for interpreter-specific operations
317interpretOps :: DatabaseContext -> String -> TutorialDOperatorResult
318interpretOps context instring = case parse interpreterOps "" instring of
319 Left err -> NoActionResult
320 Right ops -> evalTutorialDOp context ops
322reprLoop :: DatabaseContext -> IO ()
324 maybeLine <- readline "TutorialD: "
330 case interpretOps context line of
331 QuitResult -> return ()
332 DisplayErrorResult err -> hPutStrLn stderr ("ERR: " ++ err)
333 DisplayResult out -> do
337 let (value, contextup) = interpret context line
339 Nothing -> reprLoop contextup
341 hPutStrLn stderr ("ERR:" ++ show err)
344restrictionPredicateP :: Parser RestrictionPredicateExpr
345restrictionPredicateP = buildExpressionParser predicateOperators predicateTerm
347 predicateOperators = [
348 [Prefix (reservedOp "not" >> return NotPredicate)],
349 [Infix (reservedOp "and" >> return AndPredicate) AssocLeft],
350 [Infix (reservedOp "or" >> return OrPredicate) AssocLeft]
352 predicateTerm = parens restrictionPredicateP
353 <|> try restrictionAttributeEqualityP
354 <|> try relationalBooleanExpr
357relationalBooleanExpr :: Parser RestrictionPredicateExpr
358relationalBooleanExpr = do
360 return $ RelationalExprPredicate relexpr
362restrictionAttributeEqualityP :: Parser RestrictionPredicateExpr
363restrictionAttributeEqualityP = do
364 attributeName <- identifier
366 atom <- stringAtomP <|> intAtomP
367 return $ AttributeEqualityPredicate attributeName atom
369quotedChar = noneOf "\""
370 <|> try (string "\"\"" >> return '"')
372stringAtomP = liftA StringAtom (string "\"" *> many quotedChar <* string "\"")
376 return $ IntAtom (read intstr)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list