hedn 0.2.0.1 → 0.3.0.4
raw patch · 13 files changed
Files
- CHANGELOG.md +37/−0
- README.md +1/−2
- example.edn +0/−12
- hedn.cabal +13/−13
- lib/Data/EDN.hs +2/−2
- lib/Data/EDN/AST/Parser.hs +7/−11
- lib/Data/EDN/AST/Printer.hs +12/−2
- lib/Data/EDN/Class.hs +20/−17
- lib/Data/EDN/Class/Parser.hs +15/−4
- lib/Data/EDN/QQ.hs +92/−28
- tests/Data/EDN/AST/Gen.hs +4/−4
- tests/Data/EDN/AST/Test.hs +4/−4
- tests/Data/EDN/Class/Test.hs +8/−2
CHANGELOG.md view
@@ -3,6 +3,38 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [0.3.0.4] - 2021-11-13++- Compatiblity with prettyprinter-1.7.1 deprecactions.++## [0.3.0.3] - 2011-06-19++- GHC 9.0 support.++## [0.3.0.2] - 2020-11-17++- Add liftTyped methods for template-haskell 2.16++## [0.3.0.1] - 2020-03-21++- GHC 8.8 warnings fixed++## [0.3.0.0] - 2019-09-29++### Added++- GHC 8.8 support++### Removed++- GHC 8.0 (Stackage LTS < 11) aren't supported due to upstream changes.+ You can still find a package version combination that'll work for you.++### Changed++- AST Parser `parseText` and EDN `decodeText` no longer rely on MonadFail+ and work in `Either String` instead.+ ## [0.2.0.1] - 2019-02-18 ### Changed@@ -61,6 +93,11 @@ - Use utf8-string parsing for unicode literals. +[0.3.0.4]: https://gitlab.com/dpwiz/hedn/tree/v0.3.0.4+[0.3.0.3]: https://gitlab.com/dpwiz/hedn/tree/v0.3.0.3+[0.3.0.2]: https://gitlab.com/dpwiz/hedn/tree/v0.3.0.2+[0.3.0.1]: https://gitlab.com/dpwiz/hedn/tree/v0.3.0.1+[0.3.0.0]: https://gitlab.com/dpwiz/hedn/tree/v0.3.0.0 [0.2.0.1]: https://gitlab.com/dpwiz/hedn/tree/v0.2.0.1 [0.2.0.0]: https://gitlab.com/dpwiz/hedn/tree/0.2.0.0 [0.1.9.1]: https://gitlab.com/dpwiz/hedn/tree/0.1.9.1
README.md view
@@ -38,8 +38,7 @@ main = do edn <- Text.readFile "example.edn"- value <- EDN.parseText "example.edn" edn- print value+ either error print $ EDN.parseText "example.edn" edn ``` ```haskell
− example.edn
@@ -1,12 +0,0 @@-(#haskell/edn example/kitchensink ; tagged symbol- nil ; ugh..- \space ; character- "dynamic \"typing\"" ; string- {:numbers ; keyword- [42 ; integer- 42.0 ; floating- ] ; Vector- :bools- #{true false} ; Set- } ; Map-) ; List
hedn.cabal view
@@ -1,13 +1,13 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.31.1.+-- This file has been generated from package.yaml by hpack version 0.34.4. -- -- see: https://github.com/sol/hpack ----- hash: 3422cbfa0f065b597c1a18d7b765dcd6ddddbea6b62aceab67212f90c480a468+-- hash: 784b8e18f38a2e70046c5ec03603dd229e8486d61fad1a326af0f647adfa1102 name: hedn-version: 0.2.0.1+version: 0.3.0.4 synopsis: EDN parsing and encoding description: A EDN parsing and encoding library. .@@ -18,13 +18,13 @@ copyright: (c) 2019 Alexander Bondarenko license: BSD3 license-file: LICENSE-tested-with: GHC==8.0.1, GHC==8.2.2, GHC==8.4.4, GHC==8.6.3+tested-with:+ GHC==8.2.2, GHC==8.4.4, GHC==8.6.5, GHC==8.8.3, GHC==8.10.4, GHC==9.0.1, GHC==9.2.1 build-type: Simple extra-source-files: CHANGELOG.md LICENSE README.md- example.edn source-repository head type: git@@ -48,14 +48,14 @@ lib ghc-options: -Wall build-depends:- base >=4.9 && <4.13+ base >=4.9 && <5 , containers >=0.5.7 && <0.7 , deepseq >=1.4 && <2- , deriving-compat >=0.3.6 && <0.6- , megaparsec >=7.0 && <8+ , deriving-compat >=0.3.6 && <0.7+ , megaparsec >=7.0 && <10 , parser-combinators >=1.0 && <2 , prettyprinter >=1.2 && <2- , scientific >=0.3 && <0.4+ , scientific ==0.3.* , template-haskell >=2.11 && <3 , text >=1.2 && <2 , time >=1.6 && <2@@ -77,11 +77,11 @@ tests ghc-options: -Wall build-depends:- base >=4.9 && <4.13+ base >=4.9 && <5 , containers >=0.5.7 && <0.7- , hedgehog >=0.6 && <0.7- , hedn >=0.2 && <1- , megaparsec >=7.0 && <8+ , hedgehog >=0.6 && <2+ , hedn+ , megaparsec >=7.0 && <10 , text >=1.2 && <2 , time >=1.6 && <2 , uuid-types >=1.0 && <2
lib/Data/EDN.hs view
@@ -61,10 +61,10 @@ -- | Decode EDN document into AST and parse value using its 'FromEDN' instance. decodeText- :: (FromEDN a, Monad m)+ :: (FromEDN a) => String -- ^ Source name, for megaparsec error reports -- e.g. @/path/to/file.edn@ or @<stdin>@ -> Text -- ^ EDN document body- -> m a+ -> Either String a decodeText sourceName source = parseText sourceName source >>= fromEDN
lib/Data/EDN/AST/Parser.hs view
@@ -42,17 +42,13 @@ import qualified Data.EDN.AST.Types as EDN parseText- :: Monad m- => String -- ^ Source name, for megaparsec error reports+ :: String -- ^ Source name, for megaparsec error reports -- e.g. @/path/to/file.edn@ or @<stdin>@ -> Text -- ^ EDN document body- -> m TaggedValue-parseText sourceName source =- case P.parse parseDoc sourceName source of- Right tv ->- pure tv- Left err ->- fail (P.errorBundlePretty err)+ -> Either String TaggedValue+parseText sourceName =+ either (Left . P.errorBundlePretty) Right .+ P.parse parseDoc sourceName parseDoc :: Parser TaggedValue parseDoc = do@@ -89,7 +85,7 @@ P.choice [ parseNil , parseBool- , P.try parseNumber+ , parseNumber , parseSymbol , parseCharacter , parseString@@ -189,7 +185,7 @@ plain = P.anySingleBut '"' parseNumber :: Parser Value-parseNumber = P.try parseFloating <|> parseInteger+parseNumber = P.try parseFloating <|> P.try parseInteger where parseFloating = Floating <$> L.floating parseInteger = Integer <$> L.integer
lib/Data/EDN/AST/Printer.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} module Data.EDN.AST.Printer@@ -9,15 +10,24 @@ import Data.Char (ord) import Data.Foldable (toList)+#if MIN_VERSION_base(4,13,0)+#else import Data.Semigroup ((<>))+#endif import Data.Text (Text)-import Data.Text.Prettyprint.Doc (Doc, pretty, (<+>)) import Text.Printf (printf) import qualified Data.Map as Map import qualified Data.Text as Text+#if MIN_VERSION_prettyprinter(1,7,1)+import Prettyprinter (Doc, pretty, (<+>))+import qualified Prettyprinter as PP+import qualified Prettyprinter.Render.Text as PP+#else+import Data.Text.Prettyprint.Doc (Doc, pretty, (<+>)) import qualified Data.Text.Prettyprint.Doc as PP import qualified Data.Text.Prettyprint.Doc.Render.Text as PP+#endif import qualified Data.EDN.AST.Types as EDN
lib/Data/EDN/Class.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedLists #-}@@ -39,7 +40,10 @@ import Control.Applicative ((<|>)) import Data.Map (Map)+#if MIN_VERSION_base(4,12,0)+#else import Data.Semigroup ((<>))+#endif import Data.Set (Set) import Data.Text (Text) import Data.Time (UTCTime, defaultTimeLocale, formatTime, parseTimeM)@@ -169,7 +173,7 @@ | tagNS' == tagNS && tag == tag' -> p v | otherwise ->- fail . Text.unpack $ mconcat+ DP.parserError . Text.unpack $ mconcat [ "unexpected tag. " , "expecting: #" , nsToText tagNS' tag'@@ -177,7 +181,7 @@ , nsToText tagNS tag ] _ ->- fail "expected tagged value"+ DP.parserError "expected tagged value" withNoTag :: (EDN.Value -> DP.Parser a) -> EDN.TaggedValue -> DP.Parser a withNoTag p tv =@@ -185,7 +189,7 @@ EDN.NoTag v -> p v EDN.Tagged tagNS tag _v ->- fail $ "no tag expected, got #" <> Text.unpack (nsToText tagNS tag)+ DP.parserError $ "no tag expected, got #" <> Text.unpack (nsToText tagNS tag) withNil :: DP.Parser a -> EDN.Value -> DP.Parser a withNil p = \case@@ -329,8 +333,8 @@ {-# INLINE parseEDNv #-} -- | Apply appropriate parsers for a value to decode AST.-fromEDN :: (FromEDN a, Monad m) => EDN.TaggedValue -> m a-fromEDN = DP.parseM parseEDN+fromEDN :: (FromEDN a) => EDN.TaggedValue -> Either String a+fromEDN = DP.parseEither parseEDN instance FromEDN EDN.TaggedValue where parseEDN = pure@@ -339,7 +343,7 @@ parseEDNv = pure instance FromEDN Void where- parseEDN = fail "absurd"+ parseEDN _ = DP.parserError "unable to construct Void value" instance FromEDN () where parseEDNv = withNil $ pure ()@@ -387,7 +391,7 @@ vecGet ix v = case v Vector.!? ix of Nothing ->- fail $ unwords+ DP.parserError $ unwords [ "expected vector with at least" , show (succ ix) , "elements"@@ -407,17 +411,16 @@ -- | Get a value from 'EDN.EDNMap' and apply a parser to it mapGetP- :: Monad m- => EDN.TaggedValue -- ^ Map key- -> (EDN.TaggedValue -> m a) -- ^ Parser to apply to a value- -> EDN.EDNMap -- ^ Map with EDN keys and values- -> m a+ :: EDN.TaggedValue -- ^ Map key+ -> (EDN.TaggedValue -> DP.Parser a) -- ^ Parser to apply to a value+ -> EDN.EDNMap -- ^ Map with EDN keys and values+ -> DP.Parser a mapGetP key inner m = case Map.lookup key m of Just tv -> inner tv Nothing ->- fail . Text.unpack $ "key not found: " <> renderText key+ DP.parserError . Text.unpack $ "key not found: " <> renderText key -- | Get a value from 'EDN.EDNMap' for a 'EDN.Keyword' key. mapGetKeyword :: FromEDN a => Text -> EDN.EDNMap -> DP.Parser a@@ -445,21 +448,21 @@ [a, b] -> (,) <$> parseEDN a <*> parseEDN b _ ->- fail "vector of size 2 expected"+ DP.parserError "vector of size 2 expected" instance (FromEDN a, FromEDN b, FromEDN c) => FromEDN (a, b, c) where parseEDNv = withVec $ \case [a, b, c] -> (,,) <$> parseEDN a <*> parseEDN b <*> parseEDN c _ ->- fail "vector of size 3 expected"+ DP.parserError "vector of size 3 expected" instance (FromEDN a, FromEDN b, FromEDN c, FromEDN d) => FromEDN (a, b, c, d) where parseEDNv = withVec $ \case [a, b, c, d] -> (,,,) <$> parseEDN a <*> parseEDN b <*> parseEDN c <*> parseEDN d _ ->- fail "vector of size 3 expected"+ DP.parserError "vector of size 3 expected" instance FromEDN UTCTime where parseEDN tv = parseTaggedUTCTime tv <|> parseUntaggedUTCTime tv@@ -483,7 +486,7 @@ parseUUID t = case UUID.fromText t of Nothing ->- fail "invalid UUID string"+ DP.parserError "invalid UUID string" Just uuid -> pure uuid
lib/Data/EDN/Class/Parser.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE RankNTypes #-} -- | Generic continuation-based parser@@ -10,17 +11,21 @@ , Failure , Expected , Label+ , parserError ) where import Control.Applicative (Alternative(..)) import Control.Monad (MonadPlus(..))+#if MIN_VERSION_base(4,13,0)+#else import Data.Semigroup (Semigroup(..))+#endif import qualified Control.Monad.Fail as Fail import qualified Data.List as List -- | Run a 'Parser' reporting to arbitrary 'Monad' with 'fail'.-parseM :: Monad m => (a -> Parser b) -> a -> m b+parseM :: Fail.MonadFail m => (a -> Parser b) -> a -> m b parseM p v = runParser (p v) (unexpected fail) pure -- | Run a 'Parser' reporting to an 'Either'.@@ -95,9 +100,7 @@ {-# INLINE (<|>) #-} instance Fail.MonadFail Parser where- fail msg =- Parser $ \kf _ks ->- kf mempty msg+ fail = parserError {-# INLINE fail #-} instance Monad Parser where@@ -112,8 +115,11 @@ return = pure {-# INLINE return #-} +#if MIN_VERSION_base(4,12,0)+#else fail = Fail.fail {-# INLINE fail #-}+#endif instance MonadPlus Parser where mzero = fail "mzero"@@ -131,3 +137,8 @@ mappend = (<>) {-# INLINE mappend #-}++parserError :: String -> Parser a+parserError msg = Parser $ \kf _ks ->+ kf mempty msg+{-# INLINE parserError #-}
lib/Data/EDN/QQ.hs view
@@ -1,10 +1,11 @@ {-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-} -- XXX: Lift instances. Don't want to pollute main module with TH shenanigans. {-# OPTIONS_GHC -fno-warn-orphans #-}@@ -19,14 +20,18 @@ ) where import Data.Data (Data)+#if MIN_VERSION_base(4,13,0)+#else import Data.Semigroup ((<>))+#endif import Data.Text (Text) import Data.Typeable (cast) import Language.Haskell.TH.Quote (QuasiQuoter(..))-import Language.Haskell.TH.Syntax (Exp(..), Lift(..), Q, dataToExpQ, loc_filename, qLocation)+import Language.Haskell.TH.Syntax (Exp(..), Lift(..), Q) import qualified Data.Text as Text import qualified Data.Vector as Vector+import qualified Language.Haskell.TH.Syntax as TH import Data.EDN (FromEDN, decodeText, parseText) import Data.EDN.AST.Types (Tagged(..), Value(..))@@ -38,10 +43,14 @@ -- @ edn :: QuasiQuoter edn = ednQQ $ \str -> do- src <- fmap loc_filename qLocation- tv <- parseText src (Text.pack str)- lift tv+ src <- fmap TH.loc_filename TH.qLocation + case parseText src (Text.pack str) of+ Right val ->+ lift val+ Left err ->+ error err+ -- | Quasiquoter for untagged 'Value' wrapped in a List. -- -- @@@ -51,10 +60,17 @@ -- @ ednList :: QuasiQuoter ednList = ednQQ $ \str -> do- src <- fmap loc_filename qLocation- NoTag tv <- parseText src $ "(" <> Text.pack str <> ")"- lift tv+ src <- fmap TH.loc_filename TH.qLocation+ let doc = "(" <> Text.pack str <> ")" + case parseText src doc of+ Right (NoTag tv) ->+ lift tv+ Right Tagged{} ->+ error "unexpected tagged value"+ Left err ->+ error err+ -- | Quasiquoter for untagged 'Value' wrapped in a Vec. -- -- @@@ -64,10 +80,17 @@ -- @ ednVec :: QuasiQuoter ednVec = ednQQ $ \str -> do- src <- fmap loc_filename qLocation- NoTag tv <- parseText src $ "[" <> Text.pack str <> "]"- lift tv+ src <- fmap TH.loc_filename TH.qLocation+ let doc = "[" <> Text.pack str <> "]" + case parseText src doc of+ Right (NoTag tv) ->+ lift tv+ Right Tagged{} ->+ error "unexpected tagged value"+ Left err ->+ error err+ -- | Quasiquoter for untagged 'Value' wrapped in a Set. -- -- @@@ -77,10 +100,17 @@ -- @ ednSet :: QuasiQuoter ednSet = ednQQ $ \str -> do- src <- fmap loc_filename qLocation- NoTag tv <- parseText src $ "#{" <> Text.pack str <> "}"- lift tv+ src <- fmap TH.loc_filename TH.qLocation+ let doc = "#{" <> Text.pack str <> "}" + case parseText src doc of+ Right (NoTag tv) ->+ lift tv+ Right Tagged{} ->+ error "unexpected tagged value"+ Left err ->+ error err+ -- | Quasiquoter for untagged 'Value' wrapped in a Map. -- -- @@@ -90,10 +120,17 @@ -- @ ednMap :: QuasiQuoter ednMap = ednQQ $ \str -> do- src <- fmap loc_filename qLocation- NoTag tv <- parseText src $ "{" <> Text.pack str <> "}"- lift tv+ src <- fmap TH.loc_filename TH.qLocation+ let doc = "{" <> Text.pack str <> "}" + case parseText src doc of+ Right (NoTag tv) ->+ lift tv+ Right Tagged{} ->+ error "unexpected tagged value"+ Left err ->+ error err+ -- | Specializable QuasiQuoter for compile-time decoding. -- -- > ednPerson = fromEDN @Person@@ -103,9 +140,12 @@ -- > theFred = [ednPerson| #myapp/Person { :first "Fred" } |] fromEDN :: forall a. (Lift a, FromEDN a) => QuasiQuoter fromEDN = ednQQ $ \str -> do- src <- fmap loc_filename qLocation- val <- decodeText src (Text.pack str) :: Q a- lift val+ src <- fmap TH.loc_filename TH.qLocation+ case decodeText src (Text.pack str) of+ Left err ->+ error err+ Right (val :: a) ->+ lift val ednQQ :: (String -> Q Exp) -> QuasiQuoter ednQQ qexp = QuasiQuoter@@ -117,12 +157,28 @@ -- XXX: Workaround for Text.pack not present in the same module with Text constructors. -- See https://stackoverflow.com/a/38182444+#if MIN_VERSION_base(4,15,0)+liftData' :: (Data a, TH.Quote m) => a -> m Exp+#else liftData' :: Data a => a -> Q Exp-liftData' = dataToExpQ $ fmap liftText . cast+#endif+liftData' = TH.dataToExpQ $ fmap liftText . cast +#if MIN_VERSION_base(4,15,0)+liftText :: TH.Quote m => Text.Text -> m Exp+#else liftText :: Text.Text -> Q Exp+#endif liftText txt = AppE (VarE 'Text.pack) <$> lift (Text.unpack txt) +#if MIN_VERSION_base(4,15,0)+liftVector :: (Lift a, TH.Quote m) => Vector.Vector a -> m Exp+#else+liftVector :: Lift a => Vector.Vector a -> Q Exp+#endif+liftVector vec =+ AppE (VarE 'Vector.fromList) <$> lift (Vector.toList vec)+ -- XXX: Workaround for undefined toConstr in Data instance for Vector. instance Data a => Lift (Tagged Text a) where lift = \case@@ -135,6 +191,12 @@ val' <- liftData' val pure $ ConE 'Tagged `AppE` tagNS' `AppE` tag' `AppE` val' +#if MIN_VERSION_template_haskell(2,17,0)+ liftTyped = TH.unsafeCodeCoerce . lift+#elif MIN_VERSION_template_haskell(2,16,0)+ liftTyped = TH.unsafeTExpCoerce . lift+#endif+ instance Lift Value where lift = \case Vec items ->@@ -142,6 +204,8 @@ val -> liftData' val -liftVector :: Lift a => Vector.Vector a -> Q Exp-liftVector vec =- AppE (VarE 'Vector.fromList) <$> lift (Vector.toList vec)+#if MIN_VERSION_template_haskell(2,17,0)+ liftTyped = TH.unsafeCodeCoerce . lift+#elif MIN_VERSION_template_haskell(2,16,0)+ liftTyped = TH.unsafeTExpCoerce . lift+#endif
tests/Data/EDN/AST/Gen.hs view
@@ -13,7 +13,7 @@ import qualified Hedgehog.Gen as Gen import qualified Hedgehog.Range as Range -import qualified Data.EDN.AST.Parser as EDN+import qualified Data.EDN.AST.Parser as Parser import qualified Data.EDN.AST.Types as EDN genTaggedValue :: Gen EDN.TaggedValue@@ -40,7 +40,7 @@ withoutTag = EDN.NoTag <$> gen genTagIdent :: Gen Text-genTagIdent = genText EDN.tagChars+genTagIdent = genText Parser.tagChars genValue :: Gen EDN.Value genValue = Gen.recursive Gen.choice atomic collections@@ -93,7 +93,7 @@ <$> genKeywordName genKeywordName :: Gen Text-genKeywordName = genTextInitial EDN.keywordInitialChars EDN.keywordChars+genKeywordName = genTextInitial Parser.keywordInitialChars Parser.keywordChars genSymbol :: Gen EDN.Value genSymbol = EDN.Symbol@@ -101,7 +101,7 @@ <*> genSymbolName genSymbolName :: Gen Text-genSymbolName = genTextInitial EDN.symbolInitialChars EDN.symbolChars+genSymbolName = genTextInitial Parser.symbolInitialChars Parser.symbolChars genSet :: Gen EDN.Value genSet = EDN.mkSet
tests/Data/EDN/AST/Test.hs view
@@ -30,14 +30,14 @@ prop_regr_empty_containers :: Property prop_regr_empty_containers = withTests 1 . property $ do- emptyList <- EDN.parseText "<regr_empty_containers>" "( )"+ emptyList <- either fail pure $ EDN.parseText "<regr_empty_containers>" "( )" emptyList === EDN.NoTag (EDN.List mempty) - emptyVec <- EDN.parseText "<regr_empty_containers>" "[ ]"+ emptyVec <- either fail pure $ EDN.parseText "<regr_empty_containers>" "[ ]" emptyVec === EDN.NoTag (EDN.Vec mempty) - emptySet <- EDN.parseText "<regr_empty_containers>" "#{ }"+ emptySet <- either fail pure $ EDN.parseText "<regr_empty_containers>" "#{ }" emptySet === EDN.NoTag (EDN.Set mempty) - emptyMap <- EDN.parseText "<regr_empty_containers>" "{ }"+ emptyMap <- either fail pure $ EDN.parseText "<regr_empty_containers>" "{ }" emptyMap === EDN.NoTag (EDN.Map mempty)
tests/Data/EDN/Class/Test.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}@@ -34,7 +35,7 @@ codecExample :: forall a. (ToEDN a, FromEDN a, Eq a, Show a) => Text -> a -> Example codecExample encoded value = withTests 1 . property $ do- tripping value toEDN (fromEDN :: EDN.TaggedValue -> Either String a)+ tripping value toEDN fromEDN EDN.renderText (toEDN value) === encoded -- * Atomic types@@ -136,7 +137,11 @@ prop_tagged_utctime :: Example prop_tagged_utctime = codecExample+#if MIN_VERSION_time(1,9,3)+ "#inst \"1985-04-12T23:20:50.52UTC\""+#else "#inst \"1985-04-12T23:20:50.52Z\""+#endif (parseTimeOrError False defaultTimeLocale@@ -179,5 +184,6 @@ prop_unexpected :: Property prop_unexpected = property $ do- uuid <- EDN.decodeText "Test.hs:184" "#uuid \"f81d4fae-7dec-11d0-a765-00a0c91e6bf6\""+ uuid <- either fail pure $+ EDN.decodeText "Test.hs:184" "#uuid \"f81d4fae-7dec-11d0-a765-00a0c91e6bf6\"" uuid === (read "f81d4fae-7dec-11d0-a765-00a0c91e6bf6" :: UUID)