Add automatic error collector to the parser

This commit is contained in:
Kirill Andreev 2020-05-08 20:52:58 +04:00
parent 916d9897bd
commit c497da5841
No known key found for this signature in database
GPG Key ID: CF7DA79DE4785A47

View File

@ -141,7 +141,7 @@ field name parser = do
where where
sandbox firstOne tree@ParseTree {ptID, ptRange} = do sandbox firstOne tree@ParseTree {ptID, ptRange} = do
st@Forest {pfGrove = grove, pfRange = rng} <- get st@Forest {pfGrove = grove, pfRange = rng} <- get
let grove' = delete name grove let (errs, grove') = delete name grove
put Forest put Forest
{ pfID = ptID { pfID = ptID
, pfGrove = [(name, tree)] , pfGrove = [(name, tree)]
@ -155,6 +155,8 @@ field name parser = do
, pfRange = if firstOne then diffRange rng ptRange else rng , pfRange = if firstOne then diffRange rng ptRange else rng
} }
for_ errs (tell . pure . unexpected)
return res return res
-- | Variuos error reports. -- | Variuos error reports.
@ -169,6 +171,10 @@ die msg = throwError =<< makeError msg
die' msg rng = throwError =<< makeError' msg rng die' msg rng = throwError =<< makeError' msg rng
complain msg rng = tell . pure =<< makeError' msg rng complain msg rng = tell . pure =<< makeError' msg rng
unexpected :: ParseTree -> Error
unexpected ParseTree { ptSource, ptRange } =
Expected "unexpected" ptSource ptRange
-- | If a parser fails, return stub with error originating here. -- | If a parser fails, return stub with error originating here.
stubbed :: Stubbed a => Text -> Parser a -> Parser a stubbed :: Stubbed a => Text -> Parser a -> Parser a
stubbed msg parser = do stubbed msg parser = do
@ -183,6 +189,8 @@ subtree msg parser = do
then do then do
save <- get save <- get
put ptChildren put ptChildren
rest <- gets pfGrove
collectErrors rest
parser <* put save parser <* put save
else do else do
die msg die msg
@ -237,14 +245,15 @@ runParser (Parser parser) fin = do
either (error . show) (return . fst) res either (error . show) (return . fst) res
-- | Run parser on given file and pretty-print stuff. -- | Run parser on given file and pretty-print stuff.
debugParser :: Parser a -> FilePath -> IO a debugParser :: Show a => Parser a -> FilePath -> IO ()
debugParser parser fin = do debugParser parser fin = do
(res, errs) <- runParser parser fin (res, errs) <- runParser parser fin
putStrLn "Errors:"
for_ errs (print . nest 2 . pp)
putStrLn ""
putStrLn "Result:" putStrLn "Result:"
return res print res
unless (null errs) do
putStrLn ""
putStrLn "Errors:"
for_ errs (print . nest 2 . pp)
-- | Consume next tree if it has give name. Or die. -- | Consume next tree if it has give name. Or die.
token :: Text -> Parser Text token :: Text -> Parser Text
@ -280,12 +289,25 @@ getRange = snd <$> range (return ())
-- --
-- Notice: this works differently from `Prelude.remove`! -- Notice: this works differently from `Prelude.remove`!
-- --
delete :: Eq k => k -> [(k, v)] -> [(k, v)] delete :: Text -> [(Text, ParseTree)] -> ([ParseTree], [(Text, ParseTree)])
delete _ [] = [] delete _ [] = ([], [])
delete k ((k', v) : rest) = delete k ((k', v) : rest) =
if k == k' if k == k'
then rest then (addIfError v [], rest)
else delete k rest else (addIfError v vs, remains)
where
(vs, remains) = delete k rest
addIfError v =
if ptName v == "ERROR"
then (:) v
else id
collectErrors :: [(Text, ParseTree)] -> Parser ()
collectErrors vs =
for_ vs \(_, v) -> do
when (ptName v == "ERROR") do
tell [unexpected v]
-- | Parser negation. -- | Parser negation.
notFollowedBy :: Parser a -> Parser () notFollowedBy :: Parser a -> Parser ()