Skip to content

Commit 034a9bb

Browse files
committed
combine field attributes and directive arguments
1 parent c0e1bfd commit 034a9bb

File tree

2 files changed

+23
-95
lines changed

2 files changed

+23
-95
lines changed

persistent/Database/Persist/Quasi/Internal/ModelParser.hs

Lines changed: 21 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ data SourceLoc = SourceLoc
257257
}
258258
deriving (Show, Lift)
259259

260-
-- | An attribute of an entity field definition.
260+
-- | An attribute of an entity field definition or a directive.
261261
--
262262
-- @since 2.17.1.0
263263
data Attribute
@@ -268,17 +268,6 @@ data Attribute
268268
Quotation Text
269269
deriving (Eq, Ord, Show)
270270

271-
-- | An argument to an entity field directive.
272-
--
273-
-- @since 2.17.1.0
274-
data DirectiveArgument
275-
= -- This is too unstructured. We should rework directive parsing and make this smarter.
276-
DText Text
277-
| DParenthetical Text
278-
| -- | Quoted directive arguments are deprecated since 2.17.1.0.
279-
DQuotation Text
280-
deriving (Eq, Ord, Show)
281-
282271
-- | The name of an entity block or extra block.
283272
--
284273
-- @since 2.17.1.0
@@ -309,7 +298,7 @@ attributeContent = \case
309298
--
310299
-- @since 2.17.1.0
311300
directiveContent :: Directive -> [Text]
312-
directiveContent d = directiveArgumentContent <$> directiveArguments d
301+
directiveContent d = [directiveNameContent $ directiveName d] <> (attributeContent <$> directiveAttributes d)
313302

314303
entityFieldContent :: EntityField -> [Text]
315304
entityFieldContent f =
@@ -321,6 +310,9 @@ entityFieldContent f =
321310
blockKeyContent :: BlockKey -> Text
322311
blockKeyContent (BlockKey t) = t
323312

313+
directiveNameContent :: DirectiveName -> Text
314+
directiveNameContent (DirectiveName t) = t
315+
324316
-- | Generates the field name of an EntityField, accompanied by
325317
-- its strictness sigil, if one is present.
326318
-- This is only needed temporarily, and can eventually be refactored away.
@@ -343,7 +335,7 @@ commentContent = \case
343335
DocComment s -> s
344336

345337
quotedAttributeErrorMessage :: String
346-
quotedAttributeErrorMessage = "Unexpected quotation mark in entity field attribute"
338+
quotedAttributeErrorMessage = "Unexpected quotation mark in field or directive attribute"
347339

348340
attribute :: Parser Attribute
349341
attribute = do
@@ -663,6 +655,9 @@ data FieldStrictness = Strict | Lazy
663655
newtype FieldName = FieldName Text
664656
deriving (Show)
665657

658+
newtype DirectiveName = DirectiveName Text
659+
deriving (Show)
660+
666661
data EntityField = EntityField
667662
{ entityFieldDocCommentBlock :: Maybe DocCommentBlock
668663
, entityFieldStrictness :: Maybe FieldStrictness
@@ -675,7 +670,8 @@ data EntityField = EntityField
675670

676671
data Directive = Directive
677672
{ directiveDocCommentBlock :: Maybe DocCommentBlock
678-
, directiveArguments :: [DirectiveArgument]
673+
, directiveName :: DirectiveName
674+
, directiveAttributes :: [Attribute]
679675
, directivePos :: SourcePos
680676
}
681677
deriving (Show)
@@ -831,100 +827,32 @@ entityField = do
831827
, entityFieldPos = pos
832828
}
833829

834-
directiveName :: Parser String
835-
directiveName =
836-
label "directive name" $
837-
choice
838-
[ string "deriving"
839-
, directiveName'
840-
]
830+
directiveNameP :: Parser DirectiveName
831+
directiveNameP = label "directive name" $
832+
DirectiveName . Text.pack <$> choice
833+
[ string "deriving"
834+
, directiveName'
835+
]
841836
where
842837
directiveName' = do
843838
fl <- upperChar
844839
rl <- many alphaNumChar
845840
pure (fl : rl)
846841

847-
quotedArgumentErrorMessage :: String
848-
quotedArgumentErrorMessage = "Unexpected quotation mark in directive argument"
849-
850-
-- Parses an argument to an entity definition directive. It's somewhat naive about it,
851-
-- and we should refine this in the future.
852-
directiveArgument :: Parser DirectiveArgument
853-
directiveArgument = do
854-
quotedArgumentErrorLevel <- asks psQuotedArgumentErrorLevel
855-
tryOrReport
856-
quotedArgumentErrorLevel
857-
"Quoted directive arguments are deprecated since 2.17.1.0, and will be removed in or after 2.18.0.0"
858-
isQuotedArgumentError
859-
directiveArgument'
860-
(DQuotation . Text.pack <$> quotation)
861-
where
862-
isQuotedArgumentError (FancyError _ s) = s == Set.singleton (ErrorFail quotedArgumentErrorMessage)
863-
isQuotedArgumentError _ = False
864-
parentheticalInner = do
865-
str <- parenthetical'
866-
pure . init . drop 1 $ str
867-
directiveArgument' = do
868-
q <- lookAhead (optional $ char '"')
869-
case q of
870-
Just _ -> fail quotedArgumentErrorMessage
871-
Nothing ->
872-
choice
873-
[ DParenthetical . Text.pack . init . drop 1 <$> L.lexeme spaceConsumer parenthetical'
874-
, DText . Text.pack <$> some directiveArgumentChar
875-
]
876-
-- This big random-looking character class is a sign that the parser is too lax.
877-
-- When we improve directive parsing, we'll eliminate this.
878-
-- Note that this character class is not identical to the class parsed by the top-level function `contentChar`.
879-
directiveArgumentChar =
880-
choice
881-
[ alphaNumChar
882-
, char '.'
883-
, char '['
884-
, char ']'
885-
, char '('
886-
, char ')'
887-
, char '_'
888-
, char '\''
889-
, char '!'
890-
, char '~'
891-
, char '-'
892-
, char ':'
893-
, char ','
894-
, char '='
895-
, char '"'
896-
, char '\''
897-
, do
898-
backslash <- char '\\'
899-
nextChar <- lookAhead anySingle
900-
if nextChar == '(' || nextChar == ')'
901-
then single nextChar
902-
else pure backslash
903-
]
904-
905-
-- | Converts a directive argument into a Text representation for second-stage
906-
-- parsing or presentation to the user
907-
--
908-
-- @since 2.17.1.0
909-
directiveArgumentContent :: DirectiveArgument -> Text
910-
directiveArgumentContent = \case
911-
DText t -> t
912-
DParenthetical t -> t
913-
DQuotation t -> t
914-
915842
directive :: Parser Member
916843
directive = do
917844
dcb <- getDcb
918845
pos <- getSourcePos
919-
dn <- L.lexeme spaceConsumer directiveName
920-
args <- some $ L.lexeme spaceConsumer directiveArgument
846+
dn <- L.lexeme spaceConsumer directiveNameP
847+
args <- some $ L.lexeme spaceConsumer attribute
921848
_ <- setLastDocumentablePosition
922849
lookAhead (void newline <|> eof)
923850
pure $
924851
MemberDirective
925852
Directive
926853
{ directiveDocCommentBlock = dcb
927-
, directiveArguments = DText (Text.pack dn) : args
854+
, directiveName = dn
855+
, directiveAttributes = args
928856
, directivePos = pos
929857
}
930858

persistent/test/Database/Persist/QuasiSpec.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ spec = describe "Quasi" $ do
436436
it "rejects quoted attributes" $
437437
evaluate (unboundEntityDef user)
438438
`shouldErrorWithMessage`
439-
"2:14:\n |\n2 | name String \"Maybe\"\n | ^\nUnexpected quotation mark in entity field attribute\n"
439+
"2:14:\n |\n2 | name String \"Maybe\"\n | ^\nUnexpected quotation mark in field or directive attribute\n"
440440

441441
describe "and the definition has quotation marks in the type" $ do
442442
let definitionsWithTypeLevelString = T.pack "User\n name \"String\"\n deriving Show"
@@ -464,7 +464,7 @@ spec = describe "Quasi" $ do
464464
it "rejects quoted arguments" $
465465
evaluate (unboundEntityDef user)
466466
`shouldErrorWithMessage`
467-
"3:11:\n |\n3 | deriving \"Show\"\n | ^\nUnexpected quotation mark in directive argument\n"
467+
"3:11:\n |\n3 | deriving \"Show\"\n | ^\nUnexpected quotation mark in field or directive attribute\n"
468468

469469
describe "parse" $ do
470470
let

0 commit comments

Comments
 (0)