2module TutorialDInterpreter where
11import Text.Parsec.String
12import Text.Parsec.Expr
13import Text.Parsec.Language
14import qualified Text.Parsec.Token as Token
15import qualified Data.Set as S
16import qualified Data.HashSet as HS
17import qualified Data.Map as M
18import qualified Data.List as L
19import Control.Applicative (liftA, (<*), (*>))
20import Control.Monad.State
21import System.Console.Readline
24lexer :: Token.TokenParser ()
25lexer = Token.makeTokenParser tutD
26 where tutD = emptyDef {
27 Token.reservedOpNames = ["join", "where", "union", "group", "ungroup"],
28 Token.reservedNames = [],
29 Token.identStart = letter <|> char '_',
30 Token.identLetter = alphaNum <|> char '_'}
32parens = Token.parens lexer
33reservedOp = Token.reservedOp lexer
34reserved = Token.reserved lexer
35braces = Token.braces lexer
36identifier = Token.identifier lexer
37comma = Token.comma lexer
38semi = Token.semi lexer
41attributeList :: Parser [AttributeName]
42attributeList = sepBy identifier comma
44makeRelation :: Parser RelationalExpr
47 attrs <- (try makeAttributes <|> return M.empty)
48 if not (M.null attrs) then do
49 return $ MakeStaticRelation attrs emptyTupleSet
51 tuples <- braces (sepBy tupleP comma)
52 return $ MakeStaticRelation (tupleAttributes (head tuples)) (HS.fromList tuples)
54--used in relation creation
55makeAttributes :: Parser Attributes
57 attrList <- braces (sepBy attributeAndType comma)
58 return $ M.fromList $ map toAttributeAssocList attrList
60 toAttributeAssocList attr@(Attribute attrName _) = (attrName, attr)
62attributeAndType :: Parser Attribute
64 attrName <- identifier
65 attrTypeName <- identifier
66 --convert type name into type
67 case tutDTypeToAtomType attrTypeName of
68 Just t -> return $ Attribute attrName t
69 Nothing -> fail (attrTypeName ++ " is not a valid type name.")
71tupleP :: Parser RelationTuple
74 attrValues <- braces (sepBy tupleAtomP comma)
75 return $ RelationTuple (M.fromList attrValues)
77tupleAtomP :: Parser (AttributeName, Atom)
79 attributeName <- identifier
80 attrType <- identifier
81 atom <- parens (stringAtomP <|> intAtomP)
82 case tutDTypeToAtomType attrType of
83 Nothing -> fail (attrType ++ " is not a valid type name.")
84 Just typeA -> if typeA == atomTypeForAtom atom then
85 return $ (attributeName, atom)
87 fail "type mismatch in tuple generation"
89--convert Tutorial D type to AtomType
90tutDTypeToAtomType :: String -> Maybe AtomType
91tutDTypeToAtomType tutDType = case tutDType of
92 "char" -> Just StringAtomType
93 "int" -> Just IntAtomType
96atomTypeToTutDType :: AtomType -> Maybe String
97atomTypeToTutDType atomType = case atomType of
98 StringAtomType -> Just "char"
99 IntAtomType -> Just "int"
100 --RelationAtomType rel ->
103relVarP :: Parser RelationalExpr
104relVarP = liftA RelationVariable identifier
106relTerm = parens relExpr
111 attrs <- braces attributeList
112 return $ Project (S.fromList attrs)
114assignP :: Parser DatabaseExpr
116 relVarName <- try $ do
117 relVarName <- identifier
121 return $ Assign relVarName expr
124 oldAttr <- identifier
126 newAttr <- identifier
127 return $ (oldAttr, newAttr)
129renameP :: Parser (RelationalExpr -> RelationalExpr)
132 (oldAttr, newAttr) <- braces renameClause
133 return $ Rename oldAttr newAttr
137 boolExpr <- restrictionPredicateP
138 return $ Restrict boolExpr
141 attrs <- braces attributeList
143 newAttrName <- identifier
144 return $ (attrs, newAttrName)
146groupP :: Parser (RelationalExpr -> RelationalExpr)
149 (groupAttrList, groupAttrName) <- parens groupClause
150 return $ Group (S.fromList groupAttrList) groupAttrName
152--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.
153ungroupP :: Parser (RelationalExpr -> RelationalExpr)
156 rvaAttrName <- identifier
157 return $ Ungroup rvaAttrName
162 [Postfix whereClauseP],
165 [Infix (reservedOp "join" >> return Join) AssocLeft],
166 [Infix (reservedOp "union" >> return Union) AssocLeft],
167 [Infix (reservedOp "=" >> return Equals) AssocNone]
170relExpr :: Parser RelationalExpr
171relExpr = buildExpressionParser relOperators relTerm
173databaseExpr :: Parser DatabaseExpr
174databaseExpr = insertP
181multipleDatabaseExpr :: Parser DatabaseExpr
182multipleDatabaseExpr = do
183 exprs <- sepBy1 databaseExpr semi
184 return $ MultipleExpr exprs
186insertP :: Parser DatabaseExpr
191 return $ Insert relvar expr
193defineP :: Parser DatabaseExpr
195 relVarName <- try $ do
196 relVarName <- identifier
199 attributes <- makeAttributes
200 return $ Define relVarName attributes
202deleteP :: Parser DatabaseExpr
205 relVarName <- identifier
206 return $ Delete relVarName
208updateP :: Parser DatabaseExpr
211 relVarName <- identifier
212 predicate <- option TruePredicate (reservedOp "where" *> restrictionPredicateP <* spaces)
213 attributeAssignments <- liftM M.fromList $ parens (sepBy attributeAssignment comma)
214 return $ Update relVarName attributeAssignments predicate
216constraintP :: Parser DatabaseExpr
218 reservedOp "constraint"
219 constraintName <- identifier
223 return $ AddInclusionDependency (InclusionDependency constraintName subset superset)
225attributeAssignment :: Parser (String, Atom)
226attributeAssignment = do
227 attrName <- identifier
229 atom <- stringAtomP <|> intAtomP
230 return $ (attrName, atom)
232parseString :: String -> Either RelationalError DatabaseExpr
233parseString str = case parse multipleDatabaseExpr "" str of
234 Left err -> Left $ ParseError (show err)
237data TutorialDOperator where
238 ShowRelation :: RelationalExpr -> TutorialDOperator
239 ShowRelationType :: RelationalExpr -> TutorialDOperator
240 ShowConstraint :: String -> TutorialDOperator
241 Quit :: TutorialDOperator
244typeP :: Parser TutorialDOperator
248 return $ ShowRelationType expr
250showRelP :: Parser TutorialDOperator
254 return $ ShowRelation expr
256quitP :: Parser TutorialDOperator
261showConstraintsP :: Parser TutorialDOperator
264 constraintName <- option "" identifier
265 return $ ShowConstraint constraintName
267interpreterOps :: Parser TutorialDOperator
268interpreterOps = typeP
273showRelationAttributes :: Relation -> String
274showRelationAttributes rel = "{" ++ concat (L.intersperse ", " $ map showAttribute attrs) ++ "}"
276 showAttribute (Attribute name atomType) = name ++ " " ++ case atomTypeToTutDType atomType of
279 attrs = values (attributes rel)
280 values m = map snd (M.toAscList m)
282data TutorialDOperatorResult = QuitResult |
283 DisplayResult String |
284 DisplayErrorResult String |
287evalTutorialDOp :: DatabaseContext -> TutorialDOperator -> TutorialDOperatorResult
288evalTutorialDOp context (ShowRelationType expr) = case runState (typeForRelationalExpr expr) context of
289 (Right rel, _) -> DisplayResult $ showRelationAttributes rel
290 (Left err, _) -> DisplayErrorResult $ show err
292evalTutorialDOp context (ShowRelation expr) = do
293 case runState (evalRelationalExpr expr) context of
294 (Left err, _) -> DisplayErrorResult $ show err
295 (Right rel, _) -> DisplayResult $ showRelation rel
297evalTutorialDOp context (ShowConstraint name) = do
298 DisplayResult $ show filteredDeps
300 deps = inclusionDependencies context
301 filteredDeps = case name of
303 name -> HS.filter (\(InclusionDependency n _ _) -> n == name) deps
305evalTutorialDOp context (Quit) = QuitResult
307example1 = "relA {a,b, c}"
308example2 = "relA join relB"
309example3 = "relA join relB {x,y,z}"
310example4 = "(relA) {x,y,z}"
311example5 = "relA union relB"
312example6 = "rv1 := true"
313example7 = "rv1 := relA union relB"
314example8 = "relA := true; relB := false"
315example9 = "relA := relation { SNO CHAR }"
317interpret :: DatabaseContext -> String -> (Maybe RelationalError, DatabaseContext)
318interpret context tutdstring = case parseString tutdstring of
319 Left err -> (Just err, context)
320 Right parsed -> runState (evalContextExpr parsed) context
322-- for interpreter-specific operations
323interpretOps :: DatabaseContext -> String -> TutorialDOperatorResult
324interpretOps context instring = case parse interpreterOps "" instring of
325 Left err -> NoActionResult
326 Right ops -> evalTutorialDOp context ops
328reprLoop :: DatabaseContext -> IO ()
330 maybeLine <- readline "TutorialD: "
336 case interpretOps context line of
337 QuitResult -> return ()
338 DisplayErrorResult err -> hPutStrLn stderr ("ERR: " ++ err)
339 DisplayResult out -> do
343 let (value, contextup) = interpret context line
345 Nothing -> reprLoop contextup
347 hPutStrLn stderr ("ERR:" ++ show err)
350restrictionPredicateP :: Parser RestrictionPredicateExpr
351restrictionPredicateP = buildExpressionParser predicateOperators predicateTerm
353 predicateOperators = [
354 [Prefix (reservedOp "not" >> return NotPredicate)],
355 [Infix (reservedOp "and" >> return AndPredicate) AssocLeft],
356 [Infix (reservedOp "or" >> return OrPredicate) AssocLeft]
358 predicateTerm = parens restrictionPredicateP
359 <|> try restrictionAttributeEqualityP
360 <|> try relationalBooleanExpr
363relationalBooleanExpr :: Parser RestrictionPredicateExpr
364relationalBooleanExpr = do
366 return $ RelationalExprPredicate relexpr
368restrictionAttributeEqualityP :: Parser RestrictionPredicateExpr
369restrictionAttributeEqualityP = do
370 attributeName <- identifier
372 atom <- stringAtomP <|> intAtomP
373 return $ AttributeEqualityPredicate attributeName atom
375quotedChar = noneOf "\""
376 <|> try (string "\"\"" >> return '"')
378stringAtomP = liftA StringAtom (string "\"" *> many quotedChar <* string "\"")
382 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