From 63b443ba427b88ed13dc997c287b57dd8745ebac Mon Sep 17 00:00:00 2001 From: James Brock Date: Thu, 10 Nov 2022 00:43:07 +0900 Subject: [PATCH] region docs, inContext example --- CHANGELOG.md | 3 ++- src/Parsing.purs | 26 ++++++++++++++++++++++++++ test/Main.purs | 17 +++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 352fc26..9256025 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,8 @@ New features: Other improvements: -- Better error messages for `manyIndex` (#211 by @jamesbrock) +- Better error messages for `manyIndex` (#211 by @jamesdbrock) +- Docs for `region` (#213 by @jamesdbrock) ## [v10.0.0](https://github.com/purescript-contrib/purescript-parsing/releases/tag/v9.1.0) - 2022-07-18 diff --git a/src/Parsing.purs b/src/Parsing.purs index 1cf290f..ab27a68 100644 --- a/src/Parsing.purs +++ b/src/Parsing.purs @@ -411,6 +411,32 @@ failWithPosition message pos = throwError (ParseError message pos) -- | Contextualize parsing failures inside a region. If a parsing failure -- | occurs, then the `ParseError` will be transformed by each containing -- | `region` as the parser backs out the call stack. +-- | +-- | For example, here’s a helper function `inContext` which uses `region` to +-- | add some string context to the error messages. +-- | +-- | ``` +-- | let +-- | inContext :: forall s m a. (String -> String) -> ParserT s m a -> ParserT s m a +-- | inContext context = region \(ParseError message pos) -> +-- | ParseError (context message) pos +-- | +-- | input = "Tokyo thirty-nine million" +-- | +-- | lmap (parseErrorHuman input 30) $ runParser input do +-- | inContext ("Megacity list: " <> _) do +-- | cityname <- inContext ("city name: " <> _) do +-- | fst <$> match (skipMany letter) +-- | skipSpaces +-- | population <- inContext ("population: " <> _) intDecimal +-- | pure $ Tuple cityname population +-- | ``` +-- | --- +-- | ``` +-- | Megacity list: population: Expected Int at position index:6 (line:1, column:7) +-- | ▼ +-- | Tokyo thirty-nine million +-- | ``` region :: forall m s a. (ParseError -> ParseError) -> ParserT s m a -> ParserT s m a region context p = catchError p $ \err -> throwError $ context err diff --git a/test/Main.purs b/test/Main.purs index d307ac4..62ad146 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -35,6 +35,7 @@ import Effect.Unsafe (unsafePerformEffect) import Node.Process (lookupEnv) import Parsing (ParseError(..), ParseState(..), Parser, ParserT, Position(..), consume, fail, getParserT, initialPos, parseErrorMessage, parseErrorPosition, position, region, runParser) import Parsing.Combinators (advance, between, chainl, chainl1, chainr, chainr1, choice, empty, endBy, endBy1, lookAhead, many, many1, many1Till, many1Till_, manyIndex, manyTill, manyTill_, notFollowedBy, optionMaybe, replicateA, sepBy, sepBy1, sepEndBy, sepEndBy1, skipMany, skipMany1, try, (), (), (<~?>)) +import Parsing.Combinators as Combinators import Parsing.Combinators.Array as Combinators.Array import Parsing.Expr (Assoc(..), Operator(..), buildExprParser) import Parsing.Language (haskellDef, haskellStyle, javaStyle) @@ -702,6 +703,22 @@ main = do , expected: Right false } + do + let + inContext :: forall s m a. (String -> String) -> ParserT s m a -> ParserT s m a + inContext context = region \(ParseError message pos) -> ParseError (context message) pos + input = "Tokyo thirty-nine million" + assertEqual' "region 1" + { actual: runParser input do + inContext ("Megacity list: " <> _) do + cityname <- inContext ("city name: " <> _) do + fst <$> match (Combinators.skipMany letter) + skipSpaces + population <- inContext ("population: " <> _) intDecimal + pure $ Tuple cityname population + , expected: (Left (ParseError "Megacity list: population: Expected Int" (Position { column: 7, index: 6, line: 1 }))) + } + log "\nTESTS number\n" -- assert' "Number.fromString" $ Just infinity == Data.Number.fromString "Infinity"