Phase 3: End-of-line and inline block comment parsing
- Add pEndComment parser for -- end-of-line comments - Add pInlineComment parser for [- ... -] block comments - Update pText to stop before -- and [- sequences using notFollowedBy - Add tests for both comment types (2 new tests, 19 total)
This commit is contained in:
+18
-2
@@ -111,6 +111,8 @@ pStepBlock = do
|
||||
pStepItem :: Parser StepItem
|
||||
pStepItem =
|
||||
pLineBreak
|
||||
P.<|> P.try pInlineComment
|
||||
P.<|> P.try pEndComment
|
||||
P.<|> P.try pRecipeRef
|
||||
P.<|> P.try pIngredient
|
||||
P.<|> P.try pCookware
|
||||
@@ -250,6 +252,20 @@ readMaybeDouble t = case reads (T.unpack t) of
|
||||
[(n, "")] -> Just n
|
||||
_ -> Nothing
|
||||
|
||||
-- | Inline block comment: [- comment text -]
|
||||
pInlineComment :: Parser StepItem
|
||||
pInlineComment = do
|
||||
_ <- P.string "[-"
|
||||
content <- P.manyTill P.anyChar (P.try (P.string "-]"))
|
||||
return (StepComment (T.pack content))
|
||||
|
||||
-- | End-of-line comment: -- rest of line
|
||||
pEndComment :: Parser StepItem
|
||||
pEndComment = do
|
||||
_ <- P.string "--"
|
||||
content <- P.many (P.noneOf "\n")
|
||||
return (StepEndComment (T.strip (T.pack content)))
|
||||
|
||||
-- | Cookware: #name or #multi word name{}
|
||||
pCookware :: Parser StepItem
|
||||
pCookware = P.char '#' *> (StepCookware . Cookware . T.pack <$> pNameWithBraces)
|
||||
@@ -279,10 +295,10 @@ pTimer = do
|
||||
Just q -> return (Duration (quantityAmount q) (quantityUnit q))
|
||||
Nothing -> P.parserFail ("invalid duration: " <> content)
|
||||
|
||||
-- | Plain text (everything up to a special character or newline).
|
||||
-- | Plain text (everything up to a special character, newline, or comment start).
|
||||
pText :: Parser StepItem
|
||||
pText = do
|
||||
chars <- P.many1 (P.noneOf ['\\', '\n', '@', '#', '~'])
|
||||
chars <- P.many1 (P.notFollowedBy (P.string "--") *> P.notFollowedBy (P.string "[-") *> P.noneOf ['\\', '\n', '@', '#', '~'])
|
||||
return (StepText (T.pack chars))
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
@@ -259,6 +259,40 @@ spec = do
|
||||
}
|
||||
parseCookFile input `shouldBe` expected
|
||||
|
||||
describe "Comments" $ do
|
||||
it "parses an end-of-line comment within a step" $ do
|
||||
let input = "Mash until smooth -- alternatively, boil 'em first"
|
||||
case parseCookFile input of
|
||||
Left err -> expectationFailure ("parse failed: " <> err)
|
||||
Right recipe -> do
|
||||
let body = NE.toList (sectionBody (NE.head (recipeSections recipe)))
|
||||
case body of
|
||||
[SecStep (Step items)] -> do
|
||||
let expected =
|
||||
[ StepText "Mash until smooth "
|
||||
, StepEndComment "alternatively, boil 'em first"
|
||||
]
|
||||
items `shouldBe` expected
|
||||
other -> expectationFailure ("expected single SecStep, got " <> show other)
|
||||
|
||||
it "parses an inline block comment" $ do
|
||||
let input = "Slowly add @milk{4%cup} [- TODO change units to litres -], keep mixing"
|
||||
case parseCookFile input of
|
||||
Left err -> expectationFailure ("parse failed: " <> err)
|
||||
Right recipe -> do
|
||||
let body = NE.toList (sectionBody (NE.head (recipeSections recipe)))
|
||||
case body of
|
||||
[SecStep (Step items)] -> do
|
||||
let expected =
|
||||
[ StepText "Slowly add "
|
||||
, StepIngredient (Ingredient "milk" (Just (Quantity 4 (Just "cup") False)) Nothing)
|
||||
, StepText " "
|
||||
, StepComment " TODO change units to litres "
|
||||
, StepText ", keep mixing"
|
||||
]
|
||||
items `shouldBe` expected
|
||||
other -> expectationFailure ("expected single SecStep, got " <> show other)
|
||||
|
||||
describe "EasyPancakes example" $ do
|
||||
let pancakeInput =
|
||||
"-- TODO add source\n"
|
||||
|
||||
Reference in New Issue
Block a user