on master help sign in
.ghci+1−1
since splitsnapshots
unifiedsplit
@@ -1,4 +1,4 @@
1−:set -fwarn-unused-binds -fwarn-unused-imports -fwarn-orphans
1+:set -Wunused-binds -Wunused-imports -Worphans
2:set -isrc
2:set -isrc
3:load Main
3:load Main
4
4
.github/workflows/ci.ymlnew file+33
@@ -0,0 +1,33 @@
1+name: ci
2+on:
3+ push:
4+ pull_request:
5+ schedule:
6+ - cron: '0 3 * * 6' # 3am Saturday
7+jobs:
8+ test:
9+ runs-on: ${{ matrix.os }}
10+
11+ strategy:
12+ fail-fast: false
13+ matrix:
14+ os: [ubuntu-latest]
15+ ghc: ['9.6', '9.4', '9.2', '9.0', '8.10', '8.8']
16+ include:
17+ - os: windows-latest
18+ - os: macOS-latest
19+
20+ steps:
21+ - run: git config --global core.autocrlf false
22+ - uses: actions/checkout@v2
23+ - uses: haskell/actions/setup@v2
24+ id: setup-haskell
25+ with:
26+ ghc-version: ${{ matrix.ghc }}
27+ - run: cabal v2-freeze --enable-tests
28+ - uses: actions/cache@v2
29+ with:
30+ path: ${{ steps.setup-haskell.outputs.cabal-store }}
31+ key: ${{ runner.os }}-${{ matrix.ghc }}-${{ hashFiles('cabal.project.freeze') }}
32+ restore-keys: ${{ runner.os }}-${{ matrix.ghc }}-
33+ - uses: ndmitchell/neil@master
.travis.ymldeleted−12
@@ -1,12 +0,0 @@
1−sudo: required
2−env:
3−- GHCVER=7.10
4−- GHCVER=8.0
5−- GHCVER=8.2
6−- GHCVER=8.4
7−- GHCVER=8.6
8−- GHCVER=head
9−
10−script:
11−- curl -sSL https://raw.github.com/ndmitchell/neil/master/travis.sh | sh
12−- sh afl.sh
LICENSE+1−1
@@ -1,4 +1,4 @@
1−Copyright Neil Mitchell 2016-2019.
1+Copyright Neil Mitchell 2016-2023.
2
2
3Licensed under either of:
3Licensed under either of:
4
4
README.md+1−1
@@ -1,4 +1,4 @@
1−# Hexml [![Hackage version](https://img.shields.io/hackage/v/hexml.svg?label=Hackage)](https://hackage.haskell.org/package/hexml) [![Stackage version](https://www.stackage.org/package/hexml/badge/nightly?label=Stackage)](https://www.stackage.org/package/hexml) [![Linux build status](https://img.shields.io/travis/ndmitchell/hexml/master.svg?label=Linux%20build)](https://travis-ci.org/ndmitchell/hexml) [![Windows build status](https://img.shields.io/appveyor/ci/ndmitchell/hexml/master.svg?label=Windows%20build)](https://ci.appveyor.com/project/ndmitchell/hexml)
1+# Hexml [![Hackage version](https://img.shields.io/hackage/v/hexml.svg?label=Hackage)](https://hackage.haskell.org/package/hexml) [![Stackage version](https://www.stackage.org/package/hexml/badge/nightly?label=Stackage)](https://www.stackage.org/package/hexml) [![Build status](https://img.shields.io/github/actions/workflow/status/ndmitchell/hexml/ci.yml?branch=master)](https://github.com/ndmitchell/hexml/actions)
2
2
3An XML DOM-style parser, that only parses a subset of XML, but is designed to be fast. In particular:
3An XML DOM-style parser, that only parses a subset of XML, but is designed to be fast. In particular:
4
4
appveyor.ymldeleted−5
@@ -1,5 +0,0 @@
1−build: off
2−cache: "c:\\sr -> appveyor.yml"
3−
4−test_script:
5−- ps: Invoke-Expression (Invoke-WebRequest 'https://raw.githubusercontent.com/ndmitchell/neil/master/appveyor.ps1')
gen/Lib.hs+3−3
@@ -10,7 +10,7 @@ module Lib(
10import Control.Monad.Extra
10import Control.Monad.Extra
11import Control.Monad.Trans.Writer
11import Control.Monad.Trans.Writer
12import Data.Maybe
12import Data.Maybe
13−import Data.List
13+import Data.List.Extra
14import Data.Bits
14import Data.Bits
15import Data.Monoid
15import Data.Monoid
16import Numeric
16import Numeric
@@ -67,7 +67,7 @@ choices :: [Parser o ()] -> Parser o ()
67choices = foldr1 choice
67choices = foldr1 choice
68
68
69optional :: Parser o () -> Parser o ()
69optional :: Parser o () -> Parser o ()
70−optional x = choice x $ return ()
70+optional x = choice x $ pure ()
71
71
72
72
73---------------------------------------------------------------------
73---------------------------------------------------------------------
@@ -106,7 +106,7 @@ charSetC sets =
106 ,\x -> fromMaybe ("table[(int) *p] & " ++ showBit (bit $ fromJust $ elemIndex x hard)) $ simple x)
106 ,\x -> fromMaybe ("table[(int) *p] & " ++ showBit (bit $ fromJust $ elemIndex x hard)) $ simple x)
107 where
107 where
108 showBit x = "0x" ++ showHex (x :: Int) ""
108 showBit x = "0x" ++ showHex (x :: Int) ""
109− disp c = showBit $ foldr (.|.) 0 [bit i | (i, h) <- zip [0..] hard, fromCharSet h c]
109+ disp c = showBit $ foldr (.|.) 0 [bit i | (i, h) <- zipFrom 0 hard, fromCharSet h c]
110
110
111 hard = nub $ filter (isNothing . simple) sets
111 hard = nub $ filter (isNothing . simple) sets
112
112
gen/Main.hs+2−2
@@ -28,13 +28,13 @@ main = do
28
28
29writeFileChanged :: FilePath -> String -> IO ()
29writeFileChanged :: FilePath -> String -> IO ()
30writeFileChanged file new = do
30writeFileChanged file new = do
31− old <- ifM (doesFileExist file) (readFile' file) (return "")
31+ old <- ifM (doesFileExist file) (readFile' file) (pure "")
32 when (old /= new) $
32 when (old /= new) $
33 writeFile file new
33 writeFile file new
34
34
35buildRule :: [FilePath] -> [FilePath] -> IO () -> IO ()
35buildRule :: [FilePath] -> [FilePath] -> IO () -> IO ()
36buildRule from to act = do
36buildRule from to act = do
37− let modTime x = ifM (doesFileExist x) (Just <$> getModificationTime x) (return Nothing)
37+ let modTime x = ifM (doesFileExist x) (Just <$> getModificationTime x) (pure Nothing)
38 from <- mapM modTime from
38 from <- mapM modTime from
39 to <- mapM modTime to
39 to <- mapM modTime to
40 when (any isNothing (from ++ to) || maximum from >= minimum to)
40 when (any isNothing (from ++ to) || maximum from >= minimum to)
hexml.cabal+2−2
@@ -8,13 +8,13 @@ license-file: LICENSE
8category: XML
8category: XML
9author: Neil Mitchell <ndmitchell@gmail.com>
9author: Neil Mitchell <ndmitchell@gmail.com>
10maintainer: Neil Mitchell <ndmitchell@gmail.com>
10maintainer: Neil Mitchell <ndmitchell@gmail.com>
11−copyright: Neil Mitchell 2016-2019
11+copyright: Neil Mitchell 2016-2023
12synopsis: XML subset DOM parser
12synopsis: XML subset DOM parser
13description:
13description:
14 An XML DOM-style parser, that only parses a subset of XML, but is designed to be fast.
14 An XML DOM-style parser, that only parses a subset of XML, but is designed to be fast.
15homepage: https://github.com/ndmitchell/hexml#readme
15homepage: https://github.com/ndmitchell/hexml#readme
16bug-reports: https://github.com/ndmitchell/hexml/issues
16bug-reports: https://github.com/ndmitchell/hexml/issues
17−tested-with: GHC==8.6.5, GHC==8.4.4, GHC==8.2.2, GHC==8.0.2, GHC==7.10.3
17+tested-with: GHC==9.6, GHC==9.4, GHC==9.2, GHC==9.0, GHC==8.10, GHC==8.8
18extra-doc-files:
18extra-doc-files:
19 README.md
19 README.md
20 CHANGES.txt
20 CHANGES.txt
src/Main.hs+4−4
@@ -44,12 +44,12 @@ main = do
44 attributes (head $ children doc) === [Attribute "id" "1", Attribute "extra" "2"]
44 attributes (head $ children doc) === [Attribute "id" "1", Attribute "extra" "2"]
45 map (`attributeBy` "id") (childrenBy doc "test") === map (fmap (Attribute "id")) [Just "1", Just "2", Just "4", Nothing]
45 map (`attributeBy` "id") (childrenBy doc "test") === map (fmap (Attribute "id")) [Just "1", Just "2", Just "4", Nothing]
46
46
47− Right _ <- return $ parse $ "<test " <> BS.unwords [BS.pack $ "x" ++ show i ++ "='value'" | i <- [1..10000]] <> " />"
47+ Right _ <- pure $ parse $ "<test " <> BS.unwords [BS.pack $ "x" ++ show i ++ "='value'" | i <- [1..10000]] <> " />"
48− Right _ <- return $ parse $ BS.unlines $ replicate 10000 "<test x='value' />"
48+ Right _ <- pure $ parse $ BS.unlines $ replicate 10000 "<test x='value' />"
49
49
50 let attrs = ["usd:jpy","test","extra","more","stuff","jpy:usd","xxx","xxxx"]
50 let attrs = ["usd:jpy","test","extra","more","stuff","jpy:usd","xxx","xxxx"]
51− Right doc <- return $ parse $ "<test " <> BS.unwords [x <> "='" <> x <> "'" | x <- attrs] <> ">middle</test>"
51+ Right doc <- pure $ parse $ "<test " <> BS.unwords [x <> "='" <> x <> "'" | x <- attrs] <> ">middle</test>"
52− [c] <- return $ childrenBy doc "test"
52+ [c] <- pure $ childrenBy doc "test"
53 forM_ attrs $ \a -> attributeBy c a === Just (Attribute a a)
53 forM_ attrs $ \a -> attributeBy c a === Just (Attribute a a)
54 forM_ ["missing","gone","nothing"] $ \a -> attributeBy c a === Nothing
54 forM_ ["missing","gone","nothing"] $ \a -> attributeBy c a === Nothing
55 putStrLn "\nSuccess"
55 putStrLn "\nSuccess"
src/Text/XML/Hexml.hs+9−9
@@ -90,11 +90,11 @@ parse src = do
90 if err /= nullPtr then do
90 if err /= nullPtr then do
91 bs <- BS.packCString =<< hexml_document_error doc
91 bs <- BS.packCString =<< hexml_document_error doc
92 hexml_document_free doc
92 hexml_document_free doc
93− return $ Left bs
93+ pure $ Left bs
94 else do
94 else do
95 node <- hexml_document_node doc
95 node <- hexml_document_node doc
96 doc <- newForeignPtr hexml_document_free_funptr doc
96 doc <- newForeignPtr hexml_document_free_funptr doc
97− return $ Right $ Node src0 doc node
97+ pure $ Right $ Node src0 doc node
98
98
99-- | Given a node, rerender it to something with an equivalent parse tree.
99-- | Given a node, rerender it to something with an equivalent parse tree.
100-- Mostly useful for debugging - if you want the real source document use 'outer' instead.
100-- Mostly useful for debugging - if you want the real source document use 'outer' instead.
@@ -103,7 +103,7 @@ render (Node src doc n) = unsafePerformIO $ withForeignPtr doc $ \d -> do
103 i <- hexml_node_render d n nullPtr 0
103 i <- hexml_node_render d n nullPtr 0
104 res <- BS.create (fromIntegral i) $ \ptr -> void $ hexml_node_render d n (castPtr ptr) i
104 res <- BS.create (fromIntegral i) $ \ptr -> void $ hexml_node_render d n (castPtr ptr) i
105 touchBS src
105 touchBS src
106− return res
106+ pure res
107
107
108applyStr :: BS.ByteString -> Str -> BS.ByteString
108applyStr :: BS.ByteString -> Str -> BS.ByteString
109applyStr bs Str{..} = BS.take (fromIntegral strLength) $ BS.drop (fromIntegral strStart) bs
109applyStr bs Str{..} = BS.take (fromIntegral strLength) $ BS.drop (fromIntegral strStart) bs
@@ -118,7 +118,7 @@ attrPeek :: BS.ByteString -> ForeignPtr CDocument -> Ptr CAttr -> Attribute
118attrPeek src doc a = unsafePerformIO $ withForeignPtr doc $ \_ -> do
118attrPeek src doc a = unsafePerformIO $ withForeignPtr doc $ \_ -> do
119 name <- applyStr src <$> peekElemOff (castPtr a) 0
119 name <- applyStr src <$> peekElemOff (castPtr a) 0
120 val <- applyStr src <$> peekElemOff (castPtr a) 1
120 val <- applyStr src <$> peekElemOff (castPtr a) 1
121− return $ Attribute name val
121+ pure $ Attribute name val
122
122
123-- | Get the name of a node, e.g. @\<test /\>@ produces @\"test\"@.
123-- | Get the name of a node, e.g. @\<test /\>@ produces @\"test\"@.
124name :: Node -> BS.ByteString
124name :: Node -> BS.ByteString
@@ -142,7 +142,7 @@ outer = nodeBS 2
142contents :: Node -> [Either BS.ByteString Node]
142contents :: Node -> [Either BS.ByteString Node]
143contents n@(Node src _ _) = f (strStart inner) outers
143contents n@(Node src _ _) = f (strStart inner) outers
144 where
144 where
145− f i [] = string i (strEnd inner) ++ []
145+ f i [] = string i (strEnd inner)
146 f i ((x, n):xs) = string i (strStart x) ++ Right n : f (strEnd x) xs
146 f i ((x, n):xs) = string i (strStart x) ++ Right n : f (strEnd x) xs
147
147
148 string start end | start == end = []
148 string start end | start == end = []
@@ -156,7 +156,7 @@ children (Node src doc n) = unsafePerformIO $ withForeignPtr doc $ \d ->
156 alloca $ \count -> do
156 alloca $ \count -> do
157 res <- hexml_node_children d n count
157 res <- hexml_node_children d n count
158 count <- fromIntegral <$> peek count
158 count <- fromIntegral <$> peek count
159− return [Node src doc $ plusPtr res $ i*szNode | i <- [0..count-1]]
159+ pure [Node src doc $ plusPtr res $ i*szNode | i <- [0..count-1]]
160
160
161-- | Get the attributes of this node.
161-- | Get the attributes of this node.
162attributes :: Node -> [Attribute]
162attributes :: Node -> [Attribute]
@@ -164,7 +164,7 @@ attributes (Node src doc n) = unsafePerformIO $ withForeignPtr doc $ \d ->
164 alloca $ \count -> do
164 alloca $ \count -> do
165 res <- hexml_node_attributes d n count
165 res <- hexml_node_attributes d n count
166 count <- fromIntegral <$> peek count
166 count <- fromIntegral <$> peek count
167− return [attrPeek src doc $ plusPtr res $ i*szAttr | i <- [0..count-1]]
167+ pure [attrPeek src doc $ plusPtr res $ i*szAttr | i <- [0..count-1]]
168
168
169-- | Get the direct children of this node which have a specific name.
169-- | Get the direct children of this node which have a specific name.
170-- A more efficient version of:
170-- A more efficient version of:
@@ -177,7 +177,7 @@ childrenBy (Node src doc n) str = go nullPtr
177 BS.unsafeUseAsCStringLen str $ \(bs, len) -> do
177 BS.unsafeUseAsCStringLen str $ \(bs, len) -> do
178 r <- hexml_node_child d n old bs $ fromIntegral len
178 r <- hexml_node_child d n old bs $ fromIntegral len
179 touchBS src
179 touchBS src
180− return $ if r == nullPtr then [] else Node src doc r : go r
180+ pure $ if r == nullPtr then [] else Node src doc r : go r
181
181
182-- | Get the first attribute of this node which has a specific name, if there is one.
182-- | Get the first attribute of this node which has a specific name, if there is one.
183-- A more efficient version of:
183-- A more efficient version of:
@@ -188,7 +188,7 @@ attributeBy (Node src doc n) str = unsafePerformIO $ withForeignPtr doc $ \d ->
188 BS.unsafeUseAsCStringLen str $ \(bs, len) -> do
188 BS.unsafeUseAsCStringLen str $ \(bs, len) -> do
189 r <- hexml_node_attribute d n bs $ fromIntegral len
189 r <- hexml_node_attribute d n bs $ fromIntegral len
190 touchBS src
190 touchBS src
191− return $ if r == nullPtr then Nothing else Just $ attrPeek src doc r
191+ pure $ if r == nullPtr then Nothing else Just $ attrPeek src doc r
192
192
193-- | Find the starting location of a node, the @<@ character.
193-- | Find the starting location of a node, the @<@ character.
194-- The first character will be reported as @(line 1,column 1)@, because thats
194-- The first character will be reported as @(line 1,column 1)@, because thats