2module TutorialDInterpreter where
10import RelationStaticOptimizer
12import Text.Parsec.String
13import Text.Parsec.Expr
14import Text.Parsec.Language
15import qualified Text.Parsec.Token as Token
16import qualified Data.Set as S
17import qualified Data.HashSet as HS
18import qualified Data.Map as M
19import qualified Data.List as L
20import Control.Applicative (liftA, (<*), (*>))
21import Control.Monad.State
22import System.Console.Haskeline
24import System.Directory (getHomeDirectory)
26lexer :: Token.TokenParser ()
27lexer = Token.makeTokenParser tutD
28 where tutD = emptyDef {
29 Token.reservedOpNames = ["join", "where", "union", "group", "ungroup"],
30 Token.reservedNames = [],
31 Token.identStart = letter <|> char '_',
32 Token.identLetter = alphaNum <|> char '_' <|> char '#'} -- # needed for Date examples
34parens = Token.parens lexer
35reservedOp = Token.reservedOp lexer
36reserved = Token.reserved lexer
37braces = Token.braces lexer
38identifier = Token.identifier lexer
39comma = Token.comma lexer
40semi = Token.semi lexer
43attributeList :: Parser [AttributeName]
44attributeList = sepBy identifier comma
46makeRelation :: Parser RelationalExpr
49 attrs <- (try makeAttributes <|> return M.empty)
50 if not (M.null attrs) then do
51 return $ MakeStaticRelation attrs emptyTupleSet
53 tuples <- braces (sepBy tupleP comma)
54 return $ MakeStaticRelation (tupleAttributes (head tuples)) (HS.fromList tuples)
56--used in relation creation
57makeAttributes :: Parser Attributes
59 attrList <- braces (sepBy attributeAndType comma)
60 return $ M.fromList $ map toAttributeAssocList attrList
62 toAttributeAssocList attr@(Attribute attrName _) = (attrName, attr)
64attributeAndType :: Parser Attribute
66 attrName <- identifier
67 attrTypeName <- identifier
68 --convert type name into type
69 case tutDTypeToAtomType attrTypeName of
70 Just t -> return $ Attribute attrName t
71 Nothing -> fail (attrTypeName ++ " is not a valid type name.")
73tupleP :: Parser RelationTuple
76 attrValues <- braces (sepBy tupleAtomP comma)
77 return $ RelationTuple (M.fromList attrValues)
79tupleAtomP :: Parser (AttributeName, Atom)
81 attributeName <- identifier
82 attrType <- identifier
83 atom <- parens (stringAtomP <|> intAtomP)
84 case tutDTypeToAtomType attrType of
85 Nothing -> fail (attrType ++ " is not a valid type name.")
86 Just typeA -> if typeA == atomTypeForAtom atom then
87 return $ (attributeName, atom)
89 fail "type mismatch in tuple generation"
91--convert Tutorial D type to AtomType
92tutDTypeToAtomType :: String -> Maybe AtomType
93tutDTypeToAtomType tutDType = case tutDType of
94 "char" -> Just StringAtomType
95 "int" -> Just IntAtomType
98atomTypeToTutDType :: AtomType -> Maybe String
99atomTypeToTutDType atomType = case atomType of
100 StringAtomType -> Just "char"
101 IntAtomType -> Just "int"
102 --RelationAtomType rel ->
105relVarP :: Parser RelationalExpr
106relVarP = liftA RelationVariable identifier
108relTerm = parens relExpr
113 attrs <- braces attributeList
114 return $ Project (S.fromList attrs)
116assignP :: Parser DatabaseExpr
118 relVarName <- try $ do
119 relVarName <- identifier
123 return $ Assign relVarName expr
126 oldAttr <- identifier
128 newAttr <- identifier
129 return $ (oldAttr, newAttr)
131renameP :: Parser (RelationalExpr -> RelationalExpr)
134 (oldAttr, newAttr) <- braces renameClause
135 return $ Rename oldAttr newAttr
139 boolExpr <- restrictionPredicateP
140 return $ Restrict boolExpr
143 attrs <- braces attributeList
145 newAttrName <- identifier
146 return $ (attrs, newAttrName)
148groupP :: Parser (RelationalExpr -> RelationalExpr)
151 (groupAttrList, groupAttrName) <- parens groupClause
152 return $ Group (S.fromList groupAttrList) groupAttrName
154--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.
155ungroupP :: Parser (RelationalExpr -> RelationalExpr)
158 rvaAttrName <- identifier
159 return $ Ungroup rvaAttrName
164 [Postfix whereClauseP],
167 [Infix (reservedOp "join" >> return Join) AssocLeft],
168 [Infix (reservedOp "union" >> return Union) AssocLeft],
169 [Infix (reservedOp "=" >> return Equals) AssocNone]
172relExpr :: Parser RelationalExpr
173relExpr = buildExpressionParser relOperators relTerm
175databaseExpr :: Parser DatabaseExpr
176databaseExpr = insertP
184multipleDatabaseExpr :: Parser DatabaseExpr
185multipleDatabaseExpr = do
186 exprs <- sepBy1 databaseExpr semi
187 return $ MultipleExpr exprs
189insertP :: Parser DatabaseExpr
194 return $ Insert relvar expr
196defineP :: Parser DatabaseExpr
198 relVarName <- try $ do
199 relVarName <- identifier
202 attributes <- makeAttributes
203 return $ Define relVarName attributes
205undefineP :: Parser DatabaseExpr
207 reservedOp "undefine"
208 relVarName <- identifier
209 return $ Undefine relVarName
211deleteP :: Parser DatabaseExpr
214 relVarName <- identifier
215 predicate <- option TruePredicate (reservedOp "where" *> restrictionPredicateP)
216 return $ Delete relVarName predicate
218updateP :: Parser DatabaseExpr
221 relVarName <- identifier
222 predicate <- option TruePredicate (reservedOp "where" *> restrictionPredicateP <* spaces)
223 attributeAssignments <- liftM M.fromList $ parens (sepBy attributeAssignment comma)
224 return $ Update relVarName attributeAssignments predicate
226constraintP :: Parser DatabaseExpr
228 reservedOp "constraint"
229 constraintName <- identifier
233 return $ AddInclusionDependency (InclusionDependency constraintName subset superset)
235attributeAssignment :: Parser (String, Atom)
236attributeAssignment = do
237 attrName <- identifier
239 atom <- stringAtomP <|> intAtomP
240 return $ (attrName, atom)
242parseString :: String -> Either RelationalError DatabaseExpr
243parseString str = case parse multipleDatabaseExpr "" str of
244 Left err -> Left $ ParseError (show err)
247data TutorialDOperator where
248 ShowRelation :: RelationalExpr -> TutorialDOperator
249 ShowRelationType :: RelationalExpr -> TutorialDOperator
250 ShowConstraint :: String -> TutorialDOperator
251 Quit :: TutorialDOperator
254typeP :: Parser TutorialDOperator
258 return $ ShowRelationType expr
260showRelP :: Parser TutorialDOperator
264 return $ ShowRelation expr
266quitP :: Parser TutorialDOperator
271showConstraintsP :: Parser TutorialDOperator
274 constraintName <- option "" identifier
275 return $ ShowConstraint constraintName
277interpreterOps :: Parser TutorialDOperator
278interpreterOps = typeP
283showRelationAttributes :: Relation -> String
284showRelationAttributes rel = "{" ++ concat (L.intersperse ", " $ map showAttribute attrs) ++ "}"
286 showAttribute (Attribute name atomType) = name ++ " " ++ case atomTypeToTutDType atomType of
289 attrs = values (attributes rel)
290 values m = map snd (M.toAscList m)
292data TutorialDOperatorResult = QuitResult |
293 DisplayResult String |
294 DisplayErrorResult String |
297evalTutorialDOp :: DatabaseContext -> TutorialDOperator -> TutorialDOperatorResult
298evalTutorialDOp context (ShowRelationType expr) = case runState (typeForRelationalExpr expr) context of
299 (Right rel, _) -> DisplayResult $ showRelationAttributes rel
300 (Left err, _) -> DisplayErrorResult $ show err
302evalTutorialDOp context (ShowRelation expr) = do
303 case runState (evalRelationalExpr expr) context of
304 (Left err, _) -> DisplayErrorResult $ show err
305 (Right rel, _) -> DisplayResult $ showRelation rel
307evalTutorialDOp context (ShowConstraint name) = do
308 DisplayResult $ show filteredDeps
310 deps = inclusionDependencies context
311 filteredDeps = case name of
313 name -> HS.filter (\(InclusionDependency n _ _) -> n == name) deps
315evalTutorialDOp context (Quit) = QuitResult
317example1 = "relA {a,b, c}"
318example2 = "relA join relB"
319example3 = "relA join relB {x,y,z}"
320example4 = "(relA) {x,y,z}"
321example5 = "relA union relB"
322example6 = "rv1 := true"
323example7 = "rv1 := relA union relB"
324example8 = "relA := true; relB := false"
325example9 = "relA := relation { SNO CHAR }"
327interpret :: DatabaseContext -> String -> (Maybe RelationalError, DatabaseContext)
328interpret context tutdstring = case parseString tutdstring of
329 Left err -> (Just err, context)
330 Right parsed -> runState (evaluator parsed) context
334 optExpr <- applyStaticDatabaseOptimization expr
337 Left err -> return $ Just err
338 Right optExprA -> evalContextExpr optExprA
341interpretNO :: DatabaseContext -> String -> (Maybe RelationalError, DatabaseContext)
342interpretNO context tutdstring = case parseString tutdstring of
343 Left err -> (Just err, context)
344 Right parsed -> runState (evalContextExpr parsed) context
347-- for interpreter-specific operations
348interpretOps :: DatabaseContext -> String -> TutorialDOperatorResult
349interpretOps context instring = case parse interpreterOps "" instring of
350 Left err -> NoActionResult
351 Right ops -> evalTutorialDOp context ops
353reprLoop :: DatabaseContext -> IO ()
355 homeDirectory <- getHomeDirectory
356 let settings = defaultSettings {historyFile = Just (homeDirectory ++ "/.tutd_history")}
357 maybeLine <- runInputT settings $ do
358 getInputLine "TutorialD: "
362 case interpretOps context line of
363 QuitResult -> return ()
364 DisplayErrorResult err -> hPutStrLn stderr ("ERR: " ++ err) >> reprLoop context
365 DisplayResult out -> do
369 let (value, contextup) = interpret context line
371 Nothing -> reprLoop contextup
373 hPutStrLn stderr ("ERR:" ++ show err)
376restrictionPredicateP :: Parser RestrictionPredicateExpr
377restrictionPredicateP = buildExpressionParser predicateOperators predicateTerm
379 predicateOperators = [
380 [Prefix (reservedOp "not" >> return NotPredicate)],
381 [Infix (reservedOp "and" >> return AndPredicate) AssocLeft],
382 [Infix (reservedOp "or" >> return OrPredicate) AssocLeft]
384 predicateTerm = parens restrictionPredicateP
385 <|> try restrictionAttributeEqualityP
386 <|> try relationalBooleanExpr
389relationalBooleanExpr :: Parser RestrictionPredicateExpr
390relationalBooleanExpr = do
392 return $ RelationalExprPredicate relexpr
394restrictionAttributeEqualityP :: Parser RestrictionPredicateExpr
395restrictionAttributeEqualityP = do
396 attributeName <- identifier
398 atom <- stringAtomP <|> intAtomP
399 return $ AttributeEqualityPredicate attributeName atom
401quotedChar = noneOf "\""
402 <|> try (string "\"\"" >> return '"')
404stringAtomP = liftA StringAtom (string "\"" *> many quotedChar <* string "\"")
408 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