packages feed

looksee 0.5.3 → 0.6.0

raw patch · 3 files changed

+78/−47 lines, 3 filesdep ~tastydep ~tasty-hunitPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: tasty, tasty-hunit

API changes (from Hackage documentation)

+ Looksee: ReasonExplained :: !Text -> !HideError -> r -> Reason e r
+ Looksee: explainP :: Monad m => (Reason e (Err e) -> Maybe (Text, Bool)) -> ParserT e m a -> ParserT e m a
+ Looksee: instance GHC.Classes.Eq Looksee.HideError
+ Looksee: instance GHC.Classes.Ord Looksee.HideError
+ Looksee: instance GHC.Enum.Bounded Looksee.HideError
+ Looksee: instance GHC.Enum.Enum Looksee.HideError
+ Looksee: instance GHC.Show.Show Looksee.HideError
- Looksee: getErrMessage :: HasErrMessage e => e -> [Text]
+ Looksee: getErrMessage :: HasErrMessage e => (Int -> Text) -> e -> [Text]

Files

looksee.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           looksee-version:        0.5.3+version:        0.6.0 synopsis:       A simple text parser with decent errors description:    Please see the README on GitHub at <https://github.com/ejconlon/looksee#readme> category:       Parsing@@ -17,7 +17,7 @@ license:        BSD3 build-type:     Simple tested-with:-    GHC == 9.6.3+    GHC == 9.6.4 extra-source-files:     README.md @@ -119,8 +119,8 @@     , mtl >=2.2 && <2.4     , recursion-schemes ==5.2.*     , scientific ==0.3.*-    , tasty-    , tasty-hunit+    , tasty >=1.4.3 && <1.5+    , tasty-hunit ==0.10.*     , text >=1.2 && <2.1     , vector >=0.12 && <0.14   default-language: GHC2021
src/Looksee.hs view
@@ -27,6 +27,7 @@   , throwP   , altP   , emptyP+  , explainP   , endP   , optP   , lookP@@ -227,6 +228,10 @@ data InfixPhase = InfixPhaseLeft | InfixPhaseRight | InfixPhaseCont   deriving stock (Eq, Ord, Show, Enum, Bounded) +-- | Whether to hide an underlying error or not+data HideError = HideErrorNo | HideErrorYes+  deriving stock (Eq, Ord, Show, Enum, Bounded)+ -- | Reason for parse failure data Reason e r   = ReasonCustom !e@@ -240,6 +245,7 @@   | ReasonLook r   | ReasonTakeNone   | ReasonEmpty+  | ReasonExplained !Text !HideError r   deriving stock (Eq, Ord, Show, Functor, Foldable, Traversable)  deriveBifunctor ''Reason@@ -485,6 +491,22 @@ emptyP :: (Monad m) => ParserT e m a emptyP = ParserT (\j -> mkErrT ReasonEmpty >>= j . Left) +-- | If things fail and you can give a good message explaining why, this combinator will+-- annotate the error with your explanation. Returning 'True' with message will hide+-- the original error message in textual rendering.+explainP :: (Monad m) => (Reason e (Err e) -> Maybe (Text, Bool)) -> ParserT e m a -> ParserT e m a+explainP f (ParserT g) = ParserT $ \j -> g $ \ea ->+  case ea of+    Left e@(Err (ErrF _ re)) ->+      case f re of+        Nothing -> j ea+        Just (msg, hide) -> do+          sp <- gets stSpan+          let hide' = if hide then HideErrorYes else HideErrorNo+          let e' = Err (ErrF sp (ReasonExplained msg hide' e))+          j (Left e')+    Right _ -> j ea+ -- | Lookahead - rewinds state if the parser succeeds, otherwise throws error lookP :: (Monad m) => ParserT e m a -> ParserT e m a lookP (ParserT g) = ParserT $ \j -> do@@ -1024,62 +1046,71 @@ stripEnd1P :: (Monad m) => ParserT e m a -> ParserT e m a stripEnd1P p = p <* space1P --- | Implement this to format custom errors. The list will be joined with `unlines`.+-- | Implement this to format custom errors. The list will be indented and joined with `unlines`. class HasErrMessage e where-  getErrMessage :: e -> [Text]+  getErrMessage :: (Int -> Text) -> e -> [Text]  instance HasErrMessage Void where-  getErrMessage = absurd+  getErrMessage = const absurd  -- private indent :: Int -> [Text] -> [Text] indent i = let s = T.replicate (2 * i) " " in fmap (s <>)  instance (HasErrMessage e) => HasErrMessage (Err e) where-  getErrMessage (Err (ErrF (Span start end) re)) =-    let pos = "Error in range: (" <> T.pack (show start) <> ", " <> T.pack (show end) <> ")"-        body = case re of-          ReasonCustom e ->-            let hd = "Custom error:"-                tl = indent 1 (getErrMessage e)-            in  hd : tl-          ReasonExpect expected actual ->-            ["Expected text: '" <> expected <> "' but found: '" <> actual <> "'"]-          ReasonDemand expected actual ->-            ["Expected count: " <> T.pack (show expected) <> " but got: " <> T.pack (show actual)]-          ReasonLeftover count ->-            ["Expected end but had leftover count: " <> T.pack (show count)]-          ReasonAlt errs ->-            let hd = "Alternatives:"-                tl = indent 1 $ do-                  (_, e) <- toList errs-                  "Tried:" : indent 1 (getErrMessage e)-            in  hd : tl-          ReasonInfix errs ->-            let hd = "Infix/split failed:"-                tl = indent 1 $ do-                  (i, _, e) <- toList errs-                  let x = "Tried position: " <> T.pack (show i)-                  x : indent 1 (getErrMessage e)-            in  hd : tl-          ReasonFail msg -> ["User reported failure: " <> msg]-          ReasonLabeled lab e ->-            let hd = "Labeled parser: " <> unLabel lab-                tl = indent 1 (getErrMessage e)-            in  hd : tl-          ReasonLook e ->-            let hd = "Error in lookahead:"-                tl = indent 1 (getErrMessage e)-            in  hd : tl-          ReasonTakeNone -> ["Took/dropped no elements"]-          ReasonEmpty -> ["No parse results"]-    in  pos : body+  getErrMessage repPos = go+   where+    go (Err (ErrF (Span start end) re)) =+      let pos = "Error in range " <> repPos start <> "-" <> repPos end <> ":"+          body = case re of+            ReasonCustom e ->+              let hd = "Custom error:"+                  tl = indent 1 (getErrMessage repPos e)+              in  hd : tl+            ReasonExpect expected actual ->+              ["Expected text: '" <> expected <> "' but found: '" <> actual <> "'"]+            ReasonDemand expected actual ->+              ["Expected count: " <> T.pack (show expected) <> " but got: " <> T.pack (show actual)]+            ReasonLeftover count ->+              ["Expected end but had leftover count: " <> T.pack (show count)]+            ReasonAlt errs ->+              let hd = "Alternatives:"+                  tl = indent 1 $ do+                    (_, e) <- toList errs+                    "Tried:" : indent 1 (go e)+              in  hd : tl+            ReasonInfix errs ->+              let hd = "Infix/split failed:"+                  tl = indent 1 $ do+                    (i, _, e) <- toList errs+                    let x = "Tried position: " <> T.pack (show i)+                    x : indent 1 (go e)+              in  hd : tl+            ReasonFail msg -> ["User reported failure: " <> msg]+            ReasonLabeled lab e ->+              let hd = "Label: " <> unLabel lab+                  tl = indent 1 (go e)+              in  hd : tl+            ReasonLook e ->+              let hd = "Error in lookahead:"+                  tl = indent 1 (go e)+              in  hd : tl+            ReasonTakeNone -> ["Took/dropped no elements"]+            ReasonEmpty -> ["No parse results"]+            ReasonExplained msg hide e ->+              case hide of+                HideErrorNo ->+                  let tl = indent 1 (go e)+                  in  msg : tl+                HideErrorYes -> [msg]+      in  pos : body  -- | Create 'Errata' formatting a parse error errataE :: (HasErrMessage e) => FilePath -> (Int -> (E.Line, E.Column)) -> Err e -> [E.Errata] errataE fp mkP e =   let (line, col) = mkP (spanStart (errSpan e))-      msg = getErrMessage e+      repP i = let (l, c) = mkP i in "(" <> T.pack (show l) <> ", " <> T.pack (show c) <> ")"+      msg = getErrMessage repP e       block = E.blockSimple E.basicStyle E.basicPointer fp Nothing (line, col, col + 1, Nothing) (Just (T.unlines msg))   in  [E.Errata Nothing [block] Nothing] 
test/Main.hs view
@@ -791,7 +791,7 @@ main =   defaultMain $     testGroup-      "Looksee"+      "looksee"       [ testBasic       , testSpan       , testSplitBind