mini 2.1.0.0 → 2.2.0.0
raw patch · 6 files changed
+707/−5 lines, 6 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Mini.Data.Map: instance Mini.Hash.Class.Hashable a => Mini.Hash.Class.Hashable (Mini.Data.Map.Map k a)
+ Mini.Data.Map: instance (Mini.Hash.Class.Hashable k, Mini.Hash.Class.Hashable a) => Mini.Hash.Class.Hashable (Mini.Data.Map.Map k a)
+ Mini.Hash.Class: instance (Mini.Hash.Class.Hashable a, Mini.Hash.Class.Hashable b) => Mini.Hash.Class.Hashable (Data.Either.Either a b)
+ Mini.Hash.Class: instance (Mini.Hash.Class.Hashable a, Mini.Hash.Class.Hashable b) => Mini.Hash.Class.Hashable (a, b)
+ Mini.Hash.Class: instance Mini.Hash.Class.Hashable a => Mini.Hash.Class.Hashable (GHC.Base.NonEmpty a)
+ Mini.Hash.Class: instance Mini.Hash.Class.Hashable a => Mini.Hash.Class.Hashable (GHC.Maybe.Maybe a)
+ Mini.String.URI: instance Mini.Hash.Class.Hashable Mini.String.URI.Address
+ Mini.String.URI: instance Mini.Hash.Class.Hashable Mini.String.URI.Authority
+ Mini.String.URI: instance Mini.Hash.Class.Hashable Mini.String.URI.Fragment
+ Mini.String.URI: instance Mini.Hash.Class.Hashable Mini.String.URI.Host
+ Mini.String.URI: instance Mini.Hash.Class.Hashable Mini.String.URI.Path
+ Mini.String.URI: instance Mini.Hash.Class.Hashable Mini.String.URI.Port
+ Mini.String.URI: instance Mini.Hash.Class.Hashable Mini.String.URI.Query
+ Mini.String.URI: instance Mini.Hash.Class.Hashable Mini.String.URI.Scheme
+ Mini.String.URI: instance Mini.Hash.Class.Hashable Mini.String.URI.Segment
+ Mini.String.URI: instance Mini.Hash.Class.Hashable Mini.String.URI.URI
+ Mini.String.URI: instance Mini.Hash.Class.Hashable Mini.String.URI.UserInfo
+ Mini.String.URI: instance Mini.Hash.Class.Hashable Mini.String.URI.Version
+ Mini.String.XML: Attributes :: Map Key Value -> Attributes
+ Mini.String.XML: CData :: String -> CData
+ Mini.String.XML: Comment :: String -> Comment
+ Mini.String.XML: Document :: [Misc] -> Element -> [Misc] -> Document
+ Mini.String.XML: EType :: String -> EType
+ Mini.String.XML: Element :: EType -> Attributes -> [Node] -> Element
+ Mini.String.XML: Instruction :: String -> Instruction
+ Mini.String.XML: Key :: String -> Key
+ Mini.String.XML: MiscComment :: Comment -> Misc
+ Mini.String.XML: MiscPI :: PI -> Misc
+ Mini.String.XML: MiscSpace :: Space -> Misc
+ Mini.String.XML: NodeCData :: CData -> Node
+ Mini.String.XML: NodeComment :: Comment -> Node
+ Mini.String.XML: NodeElement :: Element -> Node
+ Mini.String.XML: NodePI :: PI -> Node
+ Mini.String.XML: PI :: Target -> Maybe Instruction -> PI
+ Mini.String.XML: Space :: String -> Space
+ Mini.String.XML: Target :: String -> Target
+ Mini.String.XML: Value :: String -> Value
+ Mini.String.XML: data Document
+ Mini.String.XML: data Element
+ Mini.String.XML: data Misc
+ Mini.String.XML: data Node
+ Mini.String.XML: data PI
+ Mini.String.XML: decode :: forall (m :: Type -> Type). Monad m => ParserT Char m Char
+ Mini.String.XML: document :: forall (m :: Type -> Type). Monad m => ParserT Char m Document
+ Mini.String.XML: encode :: Char -> String
+ Mini.String.XML: instance GHC.Classes.Eq Mini.String.XML.Attributes
+ Mini.String.XML: instance GHC.Classes.Eq Mini.String.XML.CData
+ Mini.String.XML: instance GHC.Classes.Eq Mini.String.XML.Comment
+ Mini.String.XML: instance GHC.Classes.Eq Mini.String.XML.Document
+ Mini.String.XML: instance GHC.Classes.Eq Mini.String.XML.EType
+ Mini.String.XML: instance GHC.Classes.Eq Mini.String.XML.Element
+ Mini.String.XML: instance GHC.Classes.Eq Mini.String.XML.Instruction
+ Mini.String.XML: instance GHC.Classes.Eq Mini.String.XML.Key
+ Mini.String.XML: instance GHC.Classes.Eq Mini.String.XML.Misc
+ Mini.String.XML: instance GHC.Classes.Eq Mini.String.XML.Node
+ Mini.String.XML: instance GHC.Classes.Eq Mini.String.XML.PI
+ Mini.String.XML: instance GHC.Classes.Eq Mini.String.XML.Space
+ Mini.String.XML: instance GHC.Classes.Eq Mini.String.XML.Target
+ Mini.String.XML: instance GHC.Classes.Eq Mini.String.XML.Value
+ Mini.String.XML: instance GHC.Classes.Ord Mini.String.XML.Attributes
+ Mini.String.XML: instance GHC.Classes.Ord Mini.String.XML.CData
+ Mini.String.XML: instance GHC.Classes.Ord Mini.String.XML.Comment
+ Mini.String.XML: instance GHC.Classes.Ord Mini.String.XML.Document
+ Mini.String.XML: instance GHC.Classes.Ord Mini.String.XML.EType
+ Mini.String.XML: instance GHC.Classes.Ord Mini.String.XML.Element
+ Mini.String.XML: instance GHC.Classes.Ord Mini.String.XML.Instruction
+ Mini.String.XML: instance GHC.Classes.Ord Mini.String.XML.Key
+ Mini.String.XML: instance GHC.Classes.Ord Mini.String.XML.Misc
+ Mini.String.XML: instance GHC.Classes.Ord Mini.String.XML.Node
+ Mini.String.XML: instance GHC.Classes.Ord Mini.String.XML.PI
+ Mini.String.XML: instance GHC.Classes.Ord Mini.String.XML.Space
+ Mini.String.XML: instance GHC.Classes.Ord Mini.String.XML.Target
+ Mini.String.XML: instance GHC.Classes.Ord Mini.String.XML.Value
+ Mini.String.XML: instance GHC.Show.Show Mini.String.XML.Attributes
+ Mini.String.XML: instance GHC.Show.Show Mini.String.XML.CData
+ Mini.String.XML: instance GHC.Show.Show Mini.String.XML.Comment
+ Mini.String.XML: instance GHC.Show.Show Mini.String.XML.Document
+ Mini.String.XML: instance GHC.Show.Show Mini.String.XML.EType
+ Mini.String.XML: instance GHC.Show.Show Mini.String.XML.Element
+ Mini.String.XML: instance GHC.Show.Show Mini.String.XML.Instruction
+ Mini.String.XML: instance GHC.Show.Show Mini.String.XML.Key
+ Mini.String.XML: instance GHC.Show.Show Mini.String.XML.Misc
+ Mini.String.XML: instance GHC.Show.Show Mini.String.XML.Node
+ Mini.String.XML: instance GHC.Show.Show Mini.String.XML.PI
+ Mini.String.XML: instance GHC.Show.Show Mini.String.XML.Space
+ Mini.String.XML: instance GHC.Show.Show Mini.String.XML.Target
+ Mini.String.XML: instance GHC.Show.Show Mini.String.XML.Value
+ Mini.String.XML: instance Mini.Hash.Class.Hashable Mini.String.XML.Attributes
+ Mini.String.XML: instance Mini.Hash.Class.Hashable Mini.String.XML.CData
+ Mini.String.XML: instance Mini.Hash.Class.Hashable Mini.String.XML.Comment
+ Mini.String.XML: instance Mini.Hash.Class.Hashable Mini.String.XML.Document
+ Mini.String.XML: instance Mini.Hash.Class.Hashable Mini.String.XML.EType
+ Mini.String.XML: instance Mini.Hash.Class.Hashable Mini.String.XML.Element
+ Mini.String.XML: instance Mini.Hash.Class.Hashable Mini.String.XML.Instruction
+ Mini.String.XML: instance Mini.Hash.Class.Hashable Mini.String.XML.Key
+ Mini.String.XML: instance Mini.Hash.Class.Hashable Mini.String.XML.Misc
+ Mini.String.XML: instance Mini.Hash.Class.Hashable Mini.String.XML.Node
+ Mini.String.XML: instance Mini.Hash.Class.Hashable Mini.String.XML.PI
+ Mini.String.XML: instance Mini.Hash.Class.Hashable Mini.String.XML.Space
+ Mini.String.XML: instance Mini.Hash.Class.Hashable Mini.String.XML.Target
+ Mini.String.XML: instance Mini.Hash.Class.Hashable Mini.String.XML.Value
+ Mini.String.XML: newtype Attributes
+ Mini.String.XML: newtype CData
+ Mini.String.XML: newtype Comment
+ Mini.String.XML: newtype EType
+ Mini.String.XML: newtype Instruction
+ Mini.String.XML: newtype Key
+ Mini.String.XML: newtype Space
+ Mini.String.XML: newtype Target
+ Mini.String.XML: newtype Value
Files
- CHANGELOG.md +13/−0
- mini.cabal +2/−1
- src/Mini/Data/Map.hs +2/−3
- src/Mini/Hash/Class.hs +28/−0
- src/Mini/String/URI.hs +49/−1
- src/Mini/String/XML.hs +613/−0
CHANGELOG.md view
@@ -4,6 +4,19 @@ (!) Breaking change ``` +2.2.0.0 [2026-09-30]+--------------------+```+ Create Mini.String.XML+ hash(class): Add Hashable instance for pairs+ hash(class): Add Hashable instance for Maybe+ hash(class): Add Hashable instance for Either+ hash(class): Add Hashable instance for NonEmpty+ string(uri): Format+ string(uri): Add Hashable instances+(!) data(map): Fix Hashable instance+```+ 2.1.0.0 [2026-09-07] -------------------- ```
mini.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: mini-version: 2.1.0.0+version: 2.2.0.0 license: MIT license-file: LICENSE author: Victor Wallsten <victor.wallsten@protonmail.com>@@ -49,6 +49,7 @@ Mini.Random.SplitMix Mini.String.URI Mini.String.UTF8+ Mini.String.XML Mini.Transformers.Class Mini.Transformers.Either Mini.Transformers.Maybe
src/Mini/Data/Map.hs view
@@ -105,7 +105,6 @@ Show, Traversable, compare,- concatMap, const, error, flip,@@ -181,8 +180,8 @@ instance (Ord k) => Monoid (Map k a) where mempty = E -instance (Hashable a) => Hashable (Map k a) where- toBytes = concatMap toBytes+instance (Hashable k, Hashable a) => Hashable (Map k a) where+ toBytes = foldrWith (\k a b -> toBytes k <> toBytes a <> b) [] -- | Primitive recursion on maps (internally structured as trees) map
src/Mini/Hash/Class.hs view
@@ -24,6 +24,11 @@ Int64, Int8, )+import Data.List.NonEmpty (+ NonEmpty (+ (:|)+ ),+ ) import Data.Word ( Word, Word16,@@ -40,8 +45,16 @@ import Prelude ( Bool, Char,+ Either (+ Left,+ Right+ ), Enum, Integral,+ Maybe (+ Just,+ Nothing+ ), concatMap, div, fmap,@@ -52,6 +65,7 @@ take, ($), (.),+ (<>), ) -- Classes@@ -105,8 +119,22 @@ instance Hashable Word64 where toBytes = finiteBitsIntegralToBytes +instance (Hashable a) => Hashable (Maybe a) where+ toBytes Nothing = []+ toBytes (Just a) = toBytes a++instance (Hashable a, Hashable b) => Hashable (Either a b) where+ toBytes (Left a) = toBytes a+ toBytes (Right b) = toBytes b++instance (Hashable a, Hashable b) => Hashable (a, b) where+ toBytes (a, b) = toBytes a <> toBytes b+ instance (Hashable a) => Hashable [a] where toBytes = concatMap toBytes++instance (Hashable a) => Hashable (NonEmpty a) where+ toBytes (a :| as) = toBytes a <> toBytes as instance (Hashable a) => Hashable (Array i a) where toBytes = concatMap toBytes
src/Mini/String/URI.hs view
@@ -96,6 +96,10 @@ import Data.Word ( Word8, )+import Mini.Hash.Class (+ Hashable,+ toBytes,+ ) import qualified Mini.String.UTF8 as UTF8 ( decode, encode,@@ -177,6 +181,14 @@ <> maybe "" (("?" <>) . show) q <> maybe "" (("#" <>) . show) f +instance Hashable URI where+ toBytes (URI s a p q f) =+ toBytes s+ <> toBytes a+ <> toBytes p+ <> toBytes q+ <> toBytes f+ -- | The authority component of a URI data Authority = -- | without the leading @"\/\/"@@@ -189,6 +201,9 @@ <> show h <> maybe "" ((":" <>) . show) p +instance Hashable Authority where+ toBytes (Authority u h p) = toBytes u <> toBytes h <> toBytes p+ -- | The host component of an authority data Host = IPv4 Address@@ -203,6 +218,12 @@ show (IPvF v a) = "v" <> show v <> "." <> show a show (RegName a) = show a +instance Hashable Host where+ toBytes (IPv4 a) = toBytes a+ toBytes (IPv6 a) = toBytes a+ toBytes (IPvF v a) = toBytes v <> toBytes a+ toBytes (RegName a) = toBytes a+ -- | The path component of a URI data Path = Path@@ -219,6 +240,9 @@ <> intercalate "/" (fmap show segs) <> bool "" "/" t +instance Hashable Path where+ toBytes (Path l segs t) = toBytes l <> toBytes segs <> toBytes t+ -- | The address of a host newtype Address = Address String deriving (Eq, Ord)@@ -226,6 +250,9 @@ instance Show Address where show (Address a) = a +instance Hashable Address where+ toBytes (Address a) = toBytes a+ -- | The fragment component of a URI newtype Fragment = -- | without the leading @"#"@@@ -235,6 +262,9 @@ instance Show Fragment where show (Fragment f) = f +instance Hashable Fragment where+ toBytes (Fragment f) = toBytes f+ -- | The port component of an authority newtype Port = -- | without the leading @":"@@@ -244,6 +274,9 @@ instance Show Port where show (Port p) = p +instance Hashable Port where+ toBytes (Port p) = toBytes p+ -- | The query component of a URI newtype Query = -- | without the leading @"?"@@@ -253,6 +286,9 @@ instance Show Query where show (Query q) = q +instance Hashable Query where+ toBytes (Query q) = toBytes q+ -- | The scheme component of a URI newtype Scheme = -- | without the trailing @":"@@@ -262,6 +298,9 @@ instance Show Scheme where show (Scheme s) = s +instance Hashable Scheme where+ toBytes (Scheme s) = toBytes s+ -- | A segment of a path newtype Segment = -- | without any delimiting @"\/"@@@ -271,6 +310,9 @@ instance Show Segment where show (Segment s) = s +instance Hashable Segment where+ toBytes (Segment s) = toBytes s+ -- | The userinfo component of an authority newtype UserInfo = -- | without the trailing @"\@"@@@ -280,6 +322,9 @@ instance Show UserInfo where show (UserInfo u) = u +instance Hashable UserInfo where+ toBytes (UserInfo u) = toBytes u+ -- | The version of a future IP newtype Version = -- | without the leading @"v"@ and trailing @"."@@@ -289,6 +334,9 @@ instance Show Version where show (Version v) = v +instance Hashable Version where+ toBytes (Version v) = toBytes v+ -- Parsers -- | Parse an absolute URI (a generic URI without a fragment)@@ -342,7 +390,7 @@ encode :: Char -> String encode = concatMap (('%' :) . twoDigitHex) . UTF8.encode where- twoDigitHex w = [hex $ w `shiftR` 4, hex $ w .&. 0x0f]+ twoDigitHex w = [hex $ w `shiftR` 4, hex $ w .&. 0x0F] hex n = toEnum . fromEnum . (+ n) . bool 0x37 0x30 $ n <= 9 -- | Parse a percent-encoded octet sequence in UTF-8 format into a character
+ src/Mini/String/XML.hs view
@@ -0,0 +1,613 @@+-- | XML 1.0 (Fifth Edition): <https://www.w3.org/TR/2008/REC-xml-20081126>+module Mini.String.XML (+ -- * Types+ Document (+ Document+ ),+ Element (+ Element+ ),+ Node (+ NodeCData,+ NodeComment,+ NodeElement,+ NodePI+ ),+ Misc (+ MiscComment,+ MiscPI,+ MiscSpace+ ),+ PI (+ PI+ ),+ Attributes (+ Attributes+ ),+ EType (+ EType+ ),+ CData (+ CData+ ),+ Key (+ Key+ ),+ Value (+ Value+ ),+ Comment (+ Comment+ ),+ Target (+ Target+ ),+ Instruction (+ Instruction+ ),+ Space (+ Space+ ),++ -- * Parsers+ document,++ -- * Encoding+ encode,+ decode,+) where++import Control.Applicative (+ empty,+ many,+ optional,+ some,+ (<|>),+ )+import Data.Bits (+ shiftL,+ )+import Data.Bool (+ bool,+ )+import Data.Char (+ digitToInt,+ )+import Mini.Data.Map (+ Map,+ )+import qualified Mini.Data.Map as Map (+ foldrWith,+ insert,+ member,+ )+import Mini.Hash.Class (+ Hashable,+ toBytes,+ )+import Mini.Transformers.Parser (+ ParserT,+ accept,+ noneOf,+ oneOf,+ reject,+ sat,+ string,+ symbol,+ till,+ )+import Prelude (+ Char,+ Eq,+ Maybe,+ Monad,+ Ord,+ Show,+ String,+ concatMap,+ dropWhile,+ foldl,+ fromEnum,+ maybe,+ mempty,+ null,+ pure,+ show,+ toEnum,+ ($),+ (&&),+ (*),+ (*>),+ (+),+ (.),+ (<$),+ (<$>),+ (<*),+ (<*>),+ (<=),+ (<>),+ (==),+ (>=),+ (>>=),+ (||),+ )++-- Types++-- | An XML document+data Document = Document [Misc] Element [Misc]+ deriving (Eq, Ord)++instance Show Document where+ show (Document ms e ms') = concatMap show ms <> show e <> concatMap show ms'++instance Hashable Document where+ toBytes = toBytes . show++-- | An element+data Element = Element EType Attributes [Node]+ deriving (Eq, Ord)++instance Show Element where+ show (Element t as ns) =+ "<"+ <> show t+ <> show as+ <> bool+ ( ">"+ <> concatMap show ns+ <> "</"+ <> show t+ <> ">"+ )+ ("/>")+ (null ns)++instance Hashable Element where+ toBytes = toBytes . show++-- | An element node+data Node+ = NodeCData CData+ | NodeComment Comment+ | NodeElement Element+ | NodePI PI+ deriving (Eq, Ord)++instance Show Node where+ show (NodeCData cd) = show cd+ show (NodeComment c) = show c+ show (NodeElement e) = show e+ show (NodePI p) = show p++instance Hashable Node where+ toBytes = toBytes . show++-- | A miscellaneous component+data Misc+ = MiscComment Comment+ | MiscPI PI+ | MiscSpace Space+ deriving (Eq, Ord)++instance Show Misc where+ show (MiscComment c) = show c+ show (MiscPI p) = show p+ show (MiscSpace s) = show s++instance Hashable Misc where+ toBytes = toBytes . show++-- | Element attributes+newtype Attributes = Attributes (Map Key Value)+ deriving (Eq, Ord)++-- | Values are shown within double quotes+instance Show Attributes where+ show (Attributes as) =+ Map.foldrWith+ (\k v b -> " " <> show k <> "=\"" <> show v <> "\"" <> b)+ []+ as++instance Hashable Attributes where+ toBytes = toBytes . show++-- | A processing instruction+data PI = PI Target (Maybe Instruction)+ deriving (Eq, Ord)++instance Show PI where+ show (PI t i) = "<?" <> show t <> maybe "" ((' ' :) . show) i <> "?>"++instance Hashable PI where+ toBytes = toBytes . show++-- | An element type+newtype EType = EType String+ deriving (Eq, Ord)++instance Show EType where+ show (EType t) = t++instance Hashable EType where+ toBytes = toBytes . show++-- | Character data+newtype CData = CData String+ deriving (Eq, Ord)++-- | Encodes @<&@ into predefined entities+instance Show CData where+ show (CData cd) = concatMap enc cd+ where+ enc '&' = "&"+ enc '<' = "<"+ enc c = [c]++instance Hashable CData where+ toBytes = toBytes . show++-- | An attribute key+newtype Key = Key String+ deriving (Eq, Ord)++instance Show Key where+ show (Key k) = k++instance Hashable Key where+ toBytes = toBytes . show++-- | An attribute value+newtype Value+ = -- | without the surrounding quotes+ Value String+ deriving (Eq, Ord)++-- | Encodes @<&"@ into predefined entities+instance Show Value where+ show (Value v) = concatMap enc v+ where+ enc '&' = "&"+ enc '<' = "<"+ enc '"' = """+ enc c = [c]++instance Hashable Value where+ toBytes = toBytes . show++-- | A comment+newtype Comment+ = -- | without the leading @"<!--"@ and trailing @"-->"@+ Comment String+ deriving (Eq, Ord)++instance Show Comment where+ show (Comment c) = "<!--" <> c <> "-->"++instance Hashable Comment where+ toBytes = toBytes . show++-- | A PI target+newtype Target = Target String+ deriving (Eq, Ord)++instance Show Target where+ show (Target t) = t++instance Hashable Target where+ toBytes = toBytes . show++-- | A PI instruction+newtype Instruction = Instruction String+ deriving (Eq, Ord)++instance Show Instruction where+ show (Instruction i) = i++instance Hashable Instruction where+ toBytes = toBytes . show++-- | Miscellaneous whitespace+newtype Space = Space String+ deriving (Eq, Ord)++instance Show Space where+ show (Space s) = s++instance Hashable Space where+ toBytes = toBytes . show++-- Parsers++-- | Parse an XML document.+--+-- Enforces well-formedness constraints /Element Type Match/, /Unique Att Spec/,+-- and /Legal Character/.+--+-- Rejects documents containing a document type declaration or non-predefined+-- entity references.+--+-- Normalizes line breaks according to section 2.11 /End-of-Line Handling/.+--+-- Decodes predefined entity references and numeric references.+document :: (Monad m) => ParserT Char m Document+document = Document <$> prolog <*> element <*> many misc++-- Encoding++-- | Turn a character into a predefined or decimal reference+encode :: Char -> String+encode '&' = "&"+encode '<' = "<"+encode '>' = ">"+encode '"' = """+encode '\'' = "'"+encode c = "&#" <> show (fromEnum c) <> ";"++-- | Parse a predefined or numeric reference into a legal character+decode :: (Monad m) => ParserT Char m Char+decode = symbol '&' *> (entityRef <|> charRef) <* symbol ';'+ where+ entityRef =+ ('&' <$ string "amp")+ <|> ('<' <$ string "lt")+ <|> ('>' <$ string "gt")+ <|> ('"' <$ string "quot")+ <|> ('\'' <$ string "apos")+ charRef = symbol '#' *> (dec <|> hex)+ dec =+ some (oneOf ['0' .. '9'])+ >>= ( \n ->+ bool+ empty+ (pure $ toEnum n)+ $ isLegal n+ )+ . foldl (\b a -> digitToInt a + b * 10) 0+ . dropWhile (== '0')+ hex =+ (symbol 'x' *> some (oneOf $ ['0' .. '9'] <> ['a' .. 'f'] <> ['A' .. 'F']))+ >>= ( \n ->+ bool+ empty+ (pure $ toEnum n)+ $ isLegal n+ )+ . foldl (\b a -> digitToInt a + (b `shiftL` 4)) 0+ . dropWhile (== '0')+ isLegal =+ ( \n ->+ n == 0x9+ || n == 0xA+ || n == 0xD+ || n >= 0x20 && n <= 0xD7FF+ || n >= 0xE000 && n <= 0xFFFD+ || n >= 0x10000 && n <= 0x10FFFF+ )+ . fromEnum++-- Helpers++char :: (Monad m) => ParserT Char m Char+char =+ ('\n' <$ string "\r\n")+ <|> ('\n' <$ symbol '\r')+ <|> ( sat $+ ( \n ->+ n == 0x9+ || n == 0xA+ || n >= 0x20 && n <= 0xD7FF+ || n >= 0xE000 && n <= 0xFFFD+ || n >= 0x10000 && n <= 0x10FFFF+ )+ . fromEnum+ )++space :: (Monad m) => ParserT Char m Space+space =+ Space+ <$> ( some . sat $+ (\n -> n == 0x20 || n == 0x9 || n == 0xD || n == 0xA) . fromEnum+ )++nameStartChar :: (Monad m) => ParserT Char m Char+nameStartChar =+ symbol ':'+ <|> oneOf ['A' .. 'Z']+ <|> symbol '_'+ <|> oneOf ['a' .. 'z']+ <|> sat+ ( ( \n ->+ n >= 0xC0 && n <= 0xD6+ || n >= 0xD8 && n <= 0xF6+ || n >= 0xF8 && n <= 0x2FF+ || n >= 0x370 && n <= 0x37D+ || n >= 0x37F && n <= 0x1FFF+ || n >= 0x200C && n <= 0x200D+ || n >= 0x2070 && n <= 0x218F+ || n >= 0x2C00 && n <= 0x2FEF+ || n >= 0x3001 && n <= 0xD7FF+ || n >= 0xF900 && n <= 0xFDCF+ || n >= 0xFDF0 && n <= 0xFFFD+ || n >= 0x10000 && n <= 0xEFFFF+ )+ . fromEnum+ )++nameChar :: (Monad m) => ParserT Char m Char+nameChar =+ nameStartChar+ <|> symbol '-'+ <|> symbol '.'+ <|> oneOf ['0' .. '9']+ <|> sat+ ( ( \n ->+ n == 0xB7+ || n >= 0x0300 && n <= 0x036F+ || n >= 0x203F && n <= 0x2040+ )+ . fromEnum+ )++name :: (Monad m) => ParserT Char m String+name = (:) <$> nameStartChar <*> many nameChar++value :: (Monad m) => ParserT Char m Value+value =+ Value+ <$> ( (doubleQuoted $ many (noneOf "<&\"" <|> decode))+ <|> (singleQuoted $ many (noneOf "<&'" <|> decode))+ )++cData :: (Monad m) => ParserT Char m CData+cData = CData <$> (some $ reject (string "]]>") *> exclude "<&")++comment :: (Monad m) => ParserT Char m Comment+comment =+ Comment+ <$> ( string "<!--"+ *> many (reject (string "--") *> char)+ <* string "-->"+ )++pi :: (Monad m) => ParserT Char m PI+pi =+ PI+ <$> (string "<?" *> target)+ <*> optional+ (Instruction <$> (space *> many (reject (string "?>") *> char)))+ <* string "?>"++target :: (Monad m) => ParserT Char m Target+target = Target <$> (reject (oneOf "Xx" *> oneOf "Mm" *> oneOf "Ll") *> name)++cdSect :: (Monad m) => ParserT Char m CData+cdSect = CData <$> (string "<![CDATA[" *> (char `till` string "]]>"))++-- NOTE: rejecting doctypedecl+prolog :: (Monad m) => ParserT Char m [Misc]+prolog = optional xmlDecl *> many misc++xmlDecl :: (Monad m) => ParserT Char m ()+xmlDecl =+ ()+ <$ ( string "<?xml"+ *> versionInfo+ *> optional encodingDecl+ *> optional sdDecl+ *> optional space+ *> string "?>"+ )++versionInfo :: (Monad m) => ParserT Char m ()+versionInfo =+ ()+ <$ ( space+ *> string "version"+ *> eq+ *> (doubleQuoted versionNum <|> singleQuoted versionNum)+ )++eq :: (Monad m) => ParserT Char m Char+eq = optional space *> symbol '=' <* optional space++versionNum :: (Monad m) => ParserT Char m ()+versionNum = () <$ (string "1." *> some (oneOf ['0' .. '9']))++misc :: (Monad m) => ParserT Char m Misc+misc =+ (MiscComment <$> comment)+ <|> (MiscPI <$> pi)+ <|> (MiscSpace <$> space)++sdDecl :: (Monad m) => ParserT Char m ()+sdDecl =+ ()+ <$ ( space+ *> string "standalone"+ *> eq+ *> ( doubleQuoted (string "yes" <|> string "no")+ <|> singleQuoted (string "yes" <|> string "no")+ )+ )++element :: (Monad m) => ParserT Char m Element+element = do+ t <- symbol '<' *> (EType <$> name)+ as <- attributes+ (Element t as [] <$ string "/>")+ <|> ( do+ ns <- symbol '>' *> nodes+ t' <-+ string "</"+ *> (EType <$> name)+ <* optional space+ <* symbol '>'+ bool+ empty+ (pure $ Element t as ns)+ $ t == t'+ )++attributes :: (Monad m) => ParserT Char m Attributes+attributes = (many (space *> attribute) <* optional space) >>= go mempty+ where+ go t ((k, v) : as) = bool (go (Map.insert k v t) as) empty $ k `Map.member` t+ go t [] = pure $ Attributes t++attribute :: (Monad m) => ParserT Char m (Key, Value)+attribute = (,) <$> (Key <$> name) <* eq <*> value++nodes :: (Monad m) => ParserT Char m [Node]+nodes = go <$> many node+ where+ go (NodeCData (CData cd) : NodeCData (CData cd') : rest) =+ NodeCData (CData $ cd <> cd') : go rest+ go (n : ns) = n : go ns+ go [] = []++node :: (Monad m) => ParserT Char m Node+node =+ ( NodeCData+ <$> ( cData+ <|> (CData <$> (pure <$> decode))+ <|> cdSect+ )+ )+ <|> (NodeComment <$> comment)+ <|> (NodeElement <$> element)+ <|> (NodePI <$> pi)++encodingDecl :: (Monad m) => ParserT Char m ()+encodingDecl =+ ()+ <$ ( space+ *> string "encoding"+ *> eq+ *> (doubleQuoted encName <|> singleQuoted encName)+ )++encName :: (Monad m) => ParserT Char m ()+encName =+ ()+ <$ ( (:)+ <$> oneOf (['A' .. 'Z'] <> ['a' .. 'z'])+ <*> many+ ( oneOf+ ( ['A' .. 'Z']+ <> ['a' .. 'z']+ <> ['0' .. '9']+ <> "._-"+ )+ )+ )++doubleQuoted :: (Monad m) => ParserT Char m a -> ParserT Char m a+doubleQuoted p = symbol '"' *> p <* symbol '"'++singleQuoted :: (Monad m) => ParserT Char m a -> ParserT Char m a+singleQuoted p = symbol '\'' *> p <* symbol '\''++exclude :: (Monad m) => String -> ParserT Char m Char+exclude str = accept (noneOf str) *> char