3module TutorialD.Interpreter.RelationalExpr where
5#if MIN_VERSION_megaparsec(7,0,0)
6import Control.Monad.Combinators.Expr
8import Text.Megaparsec.Expr
11import TutorialD.Interpreter.Base
12import TutorialD.Interpreter.Types
13import qualified Data.Text as T
14import qualified Data.Set as S
15import qualified Data.Map as M
16import Data.List (sort)
17import ProjectM36.MiscUtils
20attributeListP :: RelationalMarkerExpr a => Parser (AttributeNamesBase a)
22 (reservedOp "all but" >>
23 InvertedAttributeNames . S.fromList <$> sepBy attributeNameP comma) <|>
24 (reservedOp "all from" >>
25 RelationalExprAttributeNames <$> relExprP) <|>
26 (AttributeNames . S.fromList <$> sepBy attributeNameP comma)
28makeRelationP :: RelationalMarkerExpr a => Parser (RelationalExprBase a)
31 attrExprs <- try (fmap Just makeAttributeExprsP) <|> pure Nothing
32 tupleExprs <- braces (sepBy tupleExprP comma) <|> pure []
33 pure $ MakeRelationFromExprs attrExprs tupleExprs
36--abstract data type parser- in this context, the type constructor must not include any type arguments
38adTypeConstructorP :: Parser TypeConstructor
39adTypeConstructorP = do
40 tConsName <- typeConstructorNameP
41 tConsArgs <- many typeConstructorP
42 pure $ ADTypeConstructor tConsName tConsArgs
44tupleExprP :: RelationalMarkerExpr a => Parser (TupleExprBase a)
47 attrAssocs <- braces (sepBy tupleAtomExprP comma)
48 --detect duplicate attribute names
49 let dupAttrNames = dupes (sort (map fst attrAssocs))
50 if not (null dupAttrNames) then
51 fail ("Attribute names duplicated: " ++ show dupAttrNames)
53 pure (TupleExpr (M.fromList attrAssocs))
55tupleAtomExprP :: RelationalMarkerExpr a => Parser (AttributeName, AtomExprBase a)
57 attributeName <- attributeNameP
59 pure (attributeName, atomExpr)
61projectP :: RelationalMarkerExpr a => Parser (RelationalExprBase a -> RelationalExprBase a)
62projectP = Project <$> braces attributeListP
64renameClauseP :: Parser (T.Text, T.Text)
66 oldAttr <- attributeNameP
68 newAttr <- attributeNameP
69 pure (oldAttr, newAttr)
71renameP :: Parser (RelationalExprBase a -> RelationalExprBase a)
74 renameList <- braces (sepBy renameClauseP comma)
76 [] -> pure (Restrict TruePredicate) --no-op when rename list is empty
78 pure $ \expr -> foldl (\acc (oldAttr, newAttr) -> Rename oldAttr newAttr acc) expr renames
80whereClauseP :: RelationalMarkerExpr a => Parser (RelationalExprBase a -> RelationalExprBase a)
81whereClauseP = reservedOp "where" *> (Restrict <$> restrictionPredicateP)
83groupClauseP :: RelationalMarkerExpr a => Parser (AttributeNamesBase a, T.Text)
85 attrs <- braces attributeListP
87 newAttrName <- attributeNameP
88 pure (attrs, newAttrName)
90groupP :: RelationalMarkerExpr a => Parser (RelationalExprBase a -> RelationalExprBase a)
93 (groupAttrList, groupAttrName) <- parens groupClauseP
94 pure $ Group groupAttrList groupAttrName
96--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.
97ungroupP :: Parser (RelationalExprBase a -> RelationalExprBase a)
100 Ungroup <$> attributeNameP
102extendP :: RelationalMarkerExpr a => Parser (RelationalExprBase a -> RelationalExprBase a)
105 Extend <$> braces extendTupleExpressionP
107semijoinP :: RelationalMarkerExpr a => Parser (RelationalExprBase a -> RelationalExprBase a -> RelationalExprBase a)
109 reservedOp "semijoin" <|> reservedOp "matching"
110 pure (\exprA exprB ->
111 Project (RelationalExprAttributeNames exprA) (Join exprA exprB))
113antijoinP :: RelationalMarkerExpr a => Parser (RelationalExprBase a -> RelationalExprBase a -> RelationalExprBase a)
115 reservedOp "not matching" <|> reservedOp "antijoin"
116 pure (\exprA exprB ->
118 Project (RelationalExprAttributeNames exprA) (Join exprA exprB)))
120relOperators :: RelationalMarkerExpr a => [[Operator Parser (RelationalExprBase a)]]
124 [Postfix whereClauseP],
127 [InfixL (reservedOp "join" >> return Join)],
130 [InfixL (reservedOp "union" >> return Union)],
131 [InfixL (reservedOp "minus" >> return Difference)],
132 [InfixN (reservedOp "=" >> return Equals)],
136relExprP :: RelationalMarkerExpr a => Parser (RelationalExprBase a)
137relExprP = try withMacroExprP <|> makeExprParser relTerm relOperators
139--allow for additional characters
140attributeNameP :: Parser AttributeName
141attributeNameP = uncapitalizedIdentifier
143relVarNameP :: Parser RelVarName
144relVarNameP = uncapitalizedIdentifier
146relVarP :: RelationalMarkerExpr a => Parser (RelationalExprBase a)
147relVarP = RelationVariable <$> relVarNameP <*> parseMarkerP
149relTerm :: RelationalMarkerExpr a => Parser (RelationalExprBase a)
150relTerm = parens relExprP
154restrictionPredicateP :: RelationalMarkerExpr a => Parser (RestrictionPredicateExprBase a)
155restrictionPredicateP = makeExprParser predicateTerm predicateOperators
157 predicateOperators = [
158 [Prefix (reservedOp "not" >> return NotPredicate)],
159 [InfixL (reservedOp "and" >> return AndPredicate)],
160 [InfixL (reservedOp "or" >> return OrPredicate)]
162 predicateTerm = try (parens restrictionPredicateP)
163 <|> try restrictionAtomExprP
164 <|> try restrictionAttributeEqualityP
165 <|> relationalBooleanExprP
167relationalBooleanExprP :: RelationalMarkerExpr a => Parser (RestrictionPredicateExprBase a)
168relationalBooleanExprP =
169 --we can't actually detect if the type is relational boolean, so we just pass it to the next phase
170 RelationalExprPredicate <$> (parens relExprP <|> relTerm)
172restrictionAttributeEqualityP :: RelationalMarkerExpr a => Parser (RestrictionPredicateExprBase a)
173restrictionAttributeEqualityP = do
174 attributeName <- attributeNameP
176 AttributeEqualityPredicate attributeName <$> atomExprP
178restrictionAtomExprP :: RelationalMarkerExpr a=> Parser (RestrictionPredicateExprBase a) --atoms which are of type "boolean"
179restrictionAtomExprP = do
180 _ <- char '^' -- not ideal, but allows me to continue to use a context-free grammar
181 (try (char 't') >> pure TruePredicate) <|> (try (char 'f') >> pure (NotPredicate TruePredicate)) <|> AtomExprPredicate <$> atomExprP
183multiTupleExpressionP :: RelationalMarkerExpr a => Parser [ExtendTupleExprBase a]
184multiTupleExpressionP = sepBy extendTupleExpressionP comma
186extendTupleExpressionP :: RelationalMarkerExpr a => Parser (ExtendTupleExprBase a)
187extendTupleExpressionP = attributeExtendTupleExpressionP
189attributeExtendTupleExpressionP :: RelationalMarkerExpr a => Parser (ExtendTupleExprBase a)
190attributeExtendTupleExpressionP = do
191 newAttr <- attributeNameP
193 AttributeExtendTupleExpr newAttr <$> atomExprP
195atomExprP :: RelationalMarkerExpr a => Parser (AtomExprBase a)
196atomExprP = consumeAtomExprP True
198consumeAtomExprP :: RelationalMarkerExpr a => Bool -> Parser (AtomExprBase a)
199consumeAtomExprP consume = try functionAtomExprP <|>
200 try (parens (constructedAtomExprP True)) <|>
201 constructedAtomExprP consume <|>
202 attributeAtomExprP <|>
206attributeAtomExprP :: Parser (AtomExprBase a)
207attributeAtomExprP = do
209 AttributeAtomExpr <$> attributeNameP
211nakedAtomExprP :: Parser (AtomExprBase a)
212nakedAtomExprP = NakedAtomExpr <$> atomP
214constructedAtomExprP :: RelationalMarkerExpr a => Bool -> Parser (AtomExprBase a)
215constructedAtomExprP consume = do
216 dConsName <- dataConstructorNameP
217 dConsArgs <- if consume then sepBy (consumeAtomExprP False) spaceConsumer else pure []
218 ConstructedAtomExpr dConsName dConsArgs <$> parseMarkerP
220-- used only for primitive type parsing ?
222atomP = stringAtomP <|>
227functionAtomExprP :: RelationalMarkerExpr a => Parser (AtomExprBase a)
229 FunctionAtomExpr <$> uncapitalizedIdentifier <*> parens (sepBy atomExprP comma) <*> parseMarkerP
231relationalAtomExprP :: RelationalMarkerExpr a => Parser (AtomExprBase a)
232relationalAtomExprP = RelationAtomExpr <$> relExprP
234stringAtomP :: Parser Atom
235stringAtomP = TextAtom <$> quotedString
237doubleAtomP :: Parser Atom
238doubleAtomP = DoubleAtom <$> try float
240integerAtomP :: Parser Atom
241integerAtomP = IntegerAtom <$> integer
243boolAtomP :: Parser Atom
245 val <- char 't' <|> char 'f'
246 return $ BoolAtom (val == 't')
248relationAtomExprP :: RelationalMarkerExpr a => Parser (AtomExprBase a)
249relationAtomExprP = RelationAtomExpr <$> makeRelationP
251withMacroExprP :: RelationalMarkerExpr a => Parser (RelationalExprBase a)
254 views <- parens (sepBy1 createViewP comma)
255 With views <$> relExprP
257createViewP :: RelationalMarkerExpr a => Parser (RelVarName, RelationalExprBase a)
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