packages feed

markup-parse 0.1.1 → 0.1.1.1

raw patch · 7 files changed

+239/−480 lines, 7 filesdep +doctest-paralleldep −html-parsedep −optparse-applicativedep −perfdep ~basedep ~containersPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: doctest-parallel

Dependencies removed: html-parse, optparse-applicative, perf, text

Dependency ranges changed: base, containers

API changes (from Hackage documentation)

- MarkupParse: data Tree a
+ MarkupParse: data () => Tree a
- MarkupParse.FlatParse: data Result e a
+ MarkupParse.FlatParse: data () => Result e a

Files

− app/speed.hs
@@ -1,204 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# OPTIONS_GHC -Wno-unused-do-bind #-}---- | basic measurement and callibration-module Main where--import Data.ByteString qualified as B-import Data.Text.IO qualified as Text-import FlatParse.Basic (byteStringOf, char, satisfy, skipMany)-import FlatParse.Basic qualified as FP-import MarkupParse-import MarkupParse.FlatParse-import Options.Applicative as OA-import Perf-import Text.HTML.Parser qualified as HP-import Text.HTML.Tree qualified as HP-import Prelude--data RunType = RunDefault | RunReduced | RunMarkup | RunWhitespace | RunWrappedQ | RunIsa | RunByteStringOf deriving (Eq, Show)--data SpeedOptions = SpeedOptions-  { speedReportOptions :: ReportOptions,-    speedRunType :: RunType,-    speedFile :: FilePath,-    speedSnippet :: B.ByteString-  }-  deriving (Eq, Show)--parseRun :: OA.Parser RunType-parseRun =-  flag' RunDefault (long "default" <> help "run default performance test")-    <|> flag' RunMarkup (long "markup" <> short 'm' <> help "run markup performance test")-    <|> flag' RunWhitespace (long "whitespace" <> help "run whitespace parsing test")-    <|> flag' RunWrappedQ (long "wrappedQ" <> help "run wrappedQ parsing test")-    <|> flag' RunReduced (long "reduced" <> help "run with reduced result sizes")-    <|> flag' RunByteStringOf (long "bytestringof" <> help "test bytestringof")-    <|> flag' RunIsa (long "isa" <> help "test isa")-    <|> pure RunDefault--speedOptions :: OA.Parser SpeedOptions-speedOptions =-  SpeedOptions-    <$> parseReportOptions-    <*> parseRun-    <*> strOption (value "other/line.svg" <> long "file" <> short 'f' <> help "file to test")-    <*> strOption (value "'wrapped'" <> long "snippet" <> help "snippet to parse")--speedInfo :: ParserInfo SpeedOptions-speedInfo =-  info-    (speedOptions <**> helper)-    (fullDesc <> progDesc "markup-parse benchmarking" <> header "speed tests")--main :: IO ()-main = do-  o <- execParser speedInfo-  let rep = speedReportOptions o-  let r = speedRunType o-  let f = speedFile o-  let snip = speedSnippet o--  case r of-    RunDefault -> do-      bs <- B.readFile f-      t <- Text.readFile f--      reportMainWith rep (show r) $ do-        ts' <- ffap "html-parse tokens" HP.parseTokens t-        _ <- ffap "html-parse tree" (either undefined id . HP.tokensToForest) ts'-        tsHtml <--          warnError-            <$> ffap "tokenize" (tokenize Xml) bs-        _ <--          warnError-            <$> ffap "gather" (gather Xml) tsHtml-        m <--          warnError-            <$> ffap "markup" (markup Xml) bs-        _ <- ffap "normalize" normalize m-        _ <- ffap "markdown" (markdown Compact Xml) m-        pure ()-    RunMarkup -> do-      bs <- B.readFile f-      reportMainWith rep (show r) $ do-        fap "markup" (length . elements . markup_ Xml) bs-    RunWhitespace -> do-      reportMainWith rep (show r) (wsFap " \n\nx")-    RunWrappedQ -> do-      reportMainWith rep (show r) (fapWrappedQ snip)-    RunIsa -> do-      reportMainWith rep (show r) fapIsa-    RunByteStringOf -> do-      reportMainWith rep (show r) fapBSOf-    RunReduced -> do-      bs <- B.readFile f-      t <- Text.readFile f-      let ts' = HP.parseTokens t-      let ts = tokenize_ Xml bs-      let m = markup_ Xml bs-      reportMainWith rep (show r) $ do-        _ <- ffap "html-parse tokens" (length . HP.parseTokens) t-        _ <- ffap "html-parse tree" (either undefined length . HP.tokensToForest) ts'-        _ <- ffap "tokenize" (length . tokenize Xml) bs-        _ <- ffap "gather" (length . elements . gather_ Xml) ts-        _ <- ffap "markup" (length . elements . markup_ Xml) bs-        _ <- ffap "normalize" normalize m-        _ <- ffap "markdown" (markdown Compact Xml) m-        pure ()---- | Consume whitespace.-wsSwitch_ :: FP.Parser e ()-wsSwitch_ =-  $( FP.switch-       [|-         case _ of-           " " -> wsSwitch_-           "\n" -> wsSwitch_-           "\t" -> wsSwitch_-           "\r" -> wsSwitch_-           "\f" -> wsSwitch_-           _ -> pure ()-         |]-   )---- | consume whitespace-wsSatisfy_ :: FP.Parser e ()-wsSatisfy_ = FP.skipMany (FP.satisfy isWhitespace)---- | consume whitespace-wsFusedSatisfy_ :: FP.Parser e ()-wsFusedSatisfy_ = FP.skipMany (FP.fusedSatisfy isWhitespace (const False) (const False) (const False)) >> pure ()---- | consume whitespace-wsSatisfyAscii_ :: FP.Parser e ()-wsSatisfyAscii_ = FP.skipMany (FP.satisfyAscii isWhitespace) >> pure ()--wsFap :: B.ByteString -> PerfT IO [[Double]] ()-wsFap bs = do-  fap "wsFusedSatisfy_" (FP.runParser wsFusedSatisfy_) bs-  fap "ws" (FP.runParser ws) bs-  fap "wss" (FP.runParser wss) bs-  fap "ws_" (FP.runParser ws_) bs-  fap "wsSwitch_" (FP.runParser wsSwitch_) bs-  fap "wsSatisfy_" (FP.runParser wsSatisfy_) bs-  fap "wsSatisfyAscii_" (FP.runParser wsSatisfyAscii_) bs-  pure ()--fapWrappedQ :: B.ByteString -> PerfT IO [[Double]] ()-fapWrappedQ bs = do-  fap "wrappedQ" (FP.runParser wrappedQ) bs-  fap "wrappedQSatisfy" (FP.runParser wrappedQSatisfy) bs-  fap "wrappedQSkipSatisfy" (FP.runParser wrappedQSkipSatisfy) bs-  fap "wrappedQNotA" (FP.runParser wrappedQNotA) bs-  fap "wrappedQCandidate" (FP.runParser wrappedQCandidate) bs-  pure ()--fapIsa :: PerfT IO [[Double]] ()-fapIsa = do-  fap "isa isAttrName" (FP.runParser (isa isAttrName)) "name"-  fap "attrNameP" (FP.runParser attrNameP) "name"-  pure ()--fapBSOf :: PerfT IO [[Double]] ()-fapBSOf = do-  fap "byteStringOf" (FP.runParser (byteStringOf (attrsP Html))) " a=\"a\" b=b c>"-  fap "byteStringOf'" (FP.runParser (byteStringOf' (attrsP Html))) " a=\"a\" b=b c>"-  pure ()--isAttrName :: Char -> Bool-isAttrName x =-  not $-    isWhitespace x-      || (x == '/')-      || (x == '>')-      || (x == '=')--attrNameP :: FP.Parser e B.ByteString-attrNameP = byteStringOf $ some (satisfy isAttrName)--wrappedQSatisfy :: FP.Parser e B.ByteString-wrappedQSatisfy =-  ($(char '"') *> (byteStringOf $ many (satisfy (/= '"'))) <* $(char '"'))-    <|> ($(char '\'') *> (byteStringOf $ many (satisfy (/= '\''))) <* $(char '\''))--wrappedQSkipSatisfy :: FP.Parser e B.ByteString-wrappedQSkipSatisfy =-  ($(char '"') *> (byteStringOf $ skipMany (satisfy (/= '"'))) <* $(char '"'))-    <|> ($(char '\'') *> (byteStringOf $ skipMany (satisfy (/= '\''))) <* $(char '\''))--wrappedQNotA :: FP.Parser e B.ByteString-wrappedQNotA =-  ($(char '"') *> nota '"' <* $(char '"'))-    <|> ($(char '\'') *> nota '\'' <* $(char '\''))--wrappedQCandidate :: FP.Parser e B.ByteString-wrappedQCandidate =-  wrappedSQ' <|> wrappedDQ'--wrappedSQ' :: FP.Parser b B.ByteString-wrappedSQ' = $(char '\'') *> nota '\'' <* $(char '\'')--wrappedDQ' :: FP.Parser b B.ByteString-wrappedDQ' = $(char '"') *> nota '"' <* $(char '"')
markup-parse.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: markup-parse-version: 0.1.1+version: 0.1.1.1 license: BSD-3-Clause license-file: LICENSE copyright: Copyright, Tony Day, 2023-@@ -13,12 +13,15 @@ description:     A markup parser and printer, from and to strict bytestrings, optimised for speed. build-type: Simple-tested-with: GHC == 9.6.2+tested-with:+    , GHC == 9.10.1+    , GHC == 9.6.5+    , GHC == 9.8.2 extra-doc-files:     ChangeLog.md     other/*.html     other/*.svg-    readme.org+    readme.md  source-repository head     type: git@@ -40,69 +43,16 @@         -Wredundant-constraints  common ghc2021-stanza-    if impl ( ghc >= 9.2 )-        default-language: GHC2021--    if impl ( ghc < 9.2 )-        default-language: Haskell2010-        default-extensions:-            BangPatterns-            BinaryLiterals-            ConstrainedClassMethods-            ConstraintKinds-            DeriveDataTypeable-            DeriveFoldable-            DeriveFunctor-            DeriveGeneric-            DeriveLift-            DeriveTraversable-            DoAndIfThenElse-            EmptyCase-            EmptyDataDecls-            EmptyDataDeriving-            ExistentialQuantification-            ExplicitForAll-            FlexibleContexts-            FlexibleInstances-            ForeignFunctionInterface-            GADTSyntax-            GeneralisedNewtypeDeriving-            HexFloatLiterals-            ImplicitPrelude-            InstanceSigs-            KindSignatures-            MonomorphismRestriction-            MultiParamTypeClasses-            NamedFieldPuns-            NamedWildCards-            NumericUnderscores-            PatternGuards-            PolyKinds-            PostfixOperators-            RankNTypes-            RelaxedPolyRec-            ScopedTypeVariables-            StandaloneDeriving-            StarIsType-            TraditionalRecordSyntax-            TupleSections-            TypeApplications-            TypeOperators-            TypeSynonymInstances--    if impl ( ghc < 9.2 ) && impl ( ghc >= 8.10 )-        default-extensions:-            ImportQualifiedPost-            StandaloneKindSignatures+    default-language: GHC2021  library     import: ghc-options-stanza     import: ghc2021-stanza     hs-source-dirs: src     build-depends:-        , base               >=4.7 && <5+        , base               >=4.14 && <5         , bytestring         >=0.11.3 && <0.13-        , containers         >=0.6 && <0.7+        , containers         >=0.6 && <0.8         , deepseq            >=1.4.4 && <1.6         , flatparse          >=0.3.5 && <0.6         , string-interpolate >=0.3 && <0.4@@ -115,6 +65,16 @@         MarkupParse.FlatParse         MarkupParse.Patch +test-suite doctests+    import: ghc2021-stanza+    main-is: doctests.hs+    hs-source-dirs: test+    build-depends:+        , base             >=4.14 && <5+        , doctest-parallel >=0.3 && <0.4+    ghc-options: -threaded+    type: exitcode-stdio-1.0+ test-suite markup-parse-diff     import: ghc-options-exe-stanza     import: ghc-options-stanza@@ -122,29 +82,11 @@     main-is: diff.hs     hs-source-dirs: app     build-depends:-        , base               >=4.7 && <5+        , base               >=4.14 && <5         , bytestring         >=0.11.3 && <0.13         , markup-parse         , string-interpolate >=0.3 && <0.4-        , tasty              >=1.2 && <1.5+        , tasty              >=1.2 && <1.6         , tasty-golden       >=2.3.1.1 && <2.4         , tree-diff          >=0.3 && <0.4-    type: exitcode-stdio-1.0--benchmark markup-parse-speed-    import: ghc-options-exe-stanza-    import: ghc-options-stanza-    import: ghc2021-stanza-    main-is: speed.hs-    hs-source-dirs: app-    build-depends:-        , base                 >=4.7 && <5-        , bytestring           >=0.11.3 && <0.13-        , flatparse            >=0.3.5 && <0.6-        , html-parse           >=0.2 && <0.3-        , markup-parse-        , optparse-applicative >=0.17 && <0.19-        , perf                 >=0.12 && <0.13-        , text                 >=1.2 && <2.2-    ghc-options: -O2     type: exitcode-stdio-1.0
+ readme.md view
@@ -0,0 +1,210 @@++# Table of Contents++1.  [markup-parse](#org813b686)+2.  [Development](#org3d7b96c)+3.  [Main Pipeline types](#orgb8f20ca)+4.  [MarkupParse.Patch](#org3c16287)+5.  [wiki diff test debug](#org25edc96)+6.  [Reference](#org4a018da)+    1.  [Prior Art](#org1ed6bdf)+7.  [Performance](#org9b10723)+    1.  [Profiling](#orgf660933)+++<a id="org813b686"></a>++# markup-parse++[![img](https://img.shields.io/hackage/v/markup-parse.svg)](https://hackage.haskell.org/package/markup-parse)+[![img](https://github.com/tonyday567/markup-parse/workflows/haskell-ci/badge.svg)](https://github.com/tonyday567/markup-parse/actions?query=workflow%3Ahaskell-ci)++`markup-parse` parses and prints a subset of common XML & HTML structured data, from and to strict bytestrings+++<a id="org3d7b96c"></a>++# Development++    :r+    :set prompt "> "+    :set -Wno-type-defaults+    :set -Wno-name-shadowing+    :set -XOverloadedStrings+    :set -XTemplateHaskell+    :set -XQuasiQuotes+    import Control.Monad+    import MarkupParse+    import MarkupParse.FlatParse+    import MarkupParse.Patch+    import Data.ByteString qualified as B+    import Data.ByteString.Char8 qualified as C+    import Data.Map.Strict qualified as Map+    import Data.Function+    import FlatParse.Basic hiding (take)+    import Data.String.Interpolate+    import Data.TreeDiff+    import Control.Monad+    bs <- B.readFile "other/line.svg"+    C.length bs++    Preprocessing library for markup-parse-0.1.1..+    GHCi, version 9.6.2: https://www.haskell.org/ghc/  :? for help+    [1 of 3] Compiling MarkupParse.FlatParse ( src/MarkupParse/FlatParse.hs, interpreted )+    [2 of 3] Compiling MarkupParse      ( src/MarkupParse.hs, interpreted )+    [3 of 3] Compiling MarkupParse.Patch ( src/MarkupParse/Patch.hs, interpreted )+    Ok, three modules loaded.+    g+    Ok, three modules loaded.+    7554+++<a id="orgb8f20ca"></a>++# Main Pipeline types++    :t tokenize Html+    :t gather Html+    :t normalize+    :t degather+    :t detokenize Html+    :t tokenize Html >=> gather Html >=> (normalize >>> pure) >=> degather Html >=> (fmap (detokenize Html) >>> pure)++    tokenize Html :: ByteString -> Warn [Token]+    gather Html :: [Token] -> Warn Markup+    normalize :: Markup -> Markup+    degather :: Standard -> Markup -> Warn [Token]+    detokenize Html :: Token -> ByteString+    tokenize Html >=> gather Html >=> (normalize >>> pure) >=> degather Html >=> (fmap (detokenize Html) >>> pure)+      :: ByteString -> These [MarkupWarning] [ByteString]++Round trip equality++    m = markup_ Xml bs+    m == (markup_ Xml $ markdown_ Compact Xml m)++    True+++<a id="org3c16287"></a>++# MarkupParse.Patch++Obviously, patch doesn&rsquo;t belong here long-term but has been very useful in testing and development.++    showPatch $ patch [1, 2, 3, 5] [0, 1, 2, 4, 6]++    [+0, -3, +4, -5, +6]+++<a id="org25edc96"></a>++# wiki diff test debug++    bs <- B.readFile "other/Parsing - Wikipedia.html"+    m = markup_ Html bs+    m == (markup_ Html $ markdown_ Compact Html m)++    True+++<a id="org4a018da"></a>++# Reference++[HTML Standard](https://html.spec.whatwg.org/#toc-syntax)++[Are (non-void) self-closing tags valid in HTML5? - Stack Overflow](https://stackoverflow.com/questions/3558119/are-non-void-self-closing-tags-valid-in-html5)++[Extensible Markup Language (XML) 1.0 (Fifth Edition)](https://www.w3.org/TR/xml/)+++<a id="org1ed6bdf"></a>++## Prior Art++[html-parse](https://hackage.haskell.org/package/html-parse) is an attoparsec-based parser for HTML. The HTML parsing here has referenced this parsing logic for HTML elements.++[blaze-markup](https://hackage.haskell.org/package/blaze-markup) & [lucid](https://hackage.haskell.org/package/lucid) are HTML DSLs and printers, but not parsers.++[xeno](https://hackage.haskell.org/package/xeno) is an &ldquo;event-based&rdquo; XML parser with a more complicated base markup type.++[XMLParser](https://hackage.haskell.org/package/XMLParser) & [hexml](https://hackage.haskell.org/package/hexml) are parsec-based parsers.+++<a id="org9b10723"></a>++# Performance++The [perf](https://hackage.haskell.org/package/perf) library has been used to measure performance of the library.++\`cabal bench\` runs the default benchmarking:++    cabal bench++    Running 1 benchmarks...+    Benchmark markup-parse-speed: RUNNING...+    label1          label2          old result      new result      change+    +    gather          time            9.33e4          7.73e4          improvement+    html-parse tokenstime            1.21e6          1.17e6+    html-parse tree time            6.61e4          7.59e4          slightly-degraded+    markdown        time            3.75e5          3.92e5+    markup          time            4.72e5          5.20e5          slightly-degraded+    normalize       time            2.80e5          3.04e5          slightly-degraded+    tokenize        time            8.59e5          8.67e5+    Benchmark markup-parse-speed: FINISH+++<a id="orgf660933"></a>++## Profiling++Profiling is used to aid library development:++    cabal configure --enable-library-profiling --enable-executable-profiling -fprof-auto -fprof --write-ghc-environment-files=always --enable-benchmarks -O2++cabal.project.local++    write-ghc-environment-files: always+    ignore-project: False+    flags: +prof +prof-auto+    library-profiling: True+    executable-profiling: True++Profiling slow the main functions significantly:++    ./app/speed -n 1000 --best -c +RTS -s -p -hc -l -RTS+    label1              label2              old_result          new_result          status+    +    gather              time                2.08e4              3.01e4              degraded+    html-parse tokens   time                4.70e5              1.72e6              degraded+    html-parse tree     time                2.30e4              3.85e4              degraded+    markdown            time                3.51e5              5.70e5              degraded+    markup              time                2.10e5              1.05e6              degraded+    normalize           time                8.43e4              1.90e5              degraded+    tokenize            time                1.94e5              1.02e6              degraded+       4,520,989,296 bytes allocated in the heap+       2,668,887,592 bytes copied during GC+         287,122,272 bytes maximum residency (21 sample(s))+           1,572,000 bytes maximum slop+                 560 MiB total memory in use (0 MiB lost due to fragmentation)+    +                                         Tot time (elapsed)  Avg pause  Max pause+      Gen  0      1073 colls,     0 par    0.471s   0.479s     0.0004s    0.0024s+      Gen  1        21 colls,     0 par    2.428s   2.575s     0.1226s    0.3303s+    +      INIT    time    0.007s  (  0.008s elapsed)+      MUT     time    2.142s  (  1.945s elapsed)+      GC      time    1.904s  (  2.071s elapsed)+      RP      time    0.000s  (  0.000s elapsed)+      PROF    time    0.995s  (  0.982s elapsed)+      EXIT    time    0.026s  (  0.000s elapsed)+      Total   time    5.074s  (  5.006s elapsed)+    +      %GC     time       0.0%  (0.0% elapsed)+    +      Alloc rate    2,110,654,040 bytes per MUT second+    +      Productivity  61.8% of total user, 58.5% of total elapsed+
− readme.org
@@ -1,196 +0,0 @@-* markup-parse--[[https://hackage.haskell.org/package/markup-parse][https://img.shields.io/hackage/v/markup-parse.svg]]-[[https://github.com/tonyday567/markup-parse/actions?query=workflow%3Ahaskell-ci][https://github.com/tonyday567/markup-parse/workflows/haskell-ci/badge.svg]]--~markup-parse~ parses and prints a subset of common XML & HTML structured data, from and to strict bytestrings--* Development--#+begin_src haskell :results output :exports both-:r-:set prompt "> "-:set -Wno-type-defaults-:set -Wno-name-shadowing-:set -XOverloadedStrings-:set -XTemplateHaskell-:set -XQuasiQuotes-import Control.Monad-import MarkupParse-import MarkupParse.FlatParse-import MarkupParse.Patch-import Data.ByteString qualified as B-import Data.ByteString.Char8 qualified as C-import Data.Map.Strict qualified as Map-import Data.Function-import FlatParse.Basic hiding (take)-import Data.String.Interpolate-import Data.TreeDiff-import Control.Monad-bs <- B.readFile "other/line.svg"-C.length bs-#+end_src--#+RESULTS:-: Preprocessing library for markup-parse-0.1.1..-: GHCi, version 9.6.2: https://www.haskell.org/ghc/  :? for help-: [1 of 3] Compiling MarkupParse.FlatParse ( src/MarkupParse/FlatParse.hs, interpreted )-: [2 of 3] Compiling MarkupParse      ( src/MarkupParse.hs, interpreted )-: [3 of 3] Compiling MarkupParse.Patch ( src/MarkupParse/Patch.hs, interpreted )-: Ok, three modules loaded.-: g-: Ok, three modules loaded.-: 7554--* Main Pipeline types--#+begin_src haskell :results output :exports both-:t tokenize Html-:t gather Html-:t normalize-:t degather-:t detokenize Html-:t tokenize Html >=> gather Html >=> (normalize >>> pure) >=> degather Html >=> (fmap (detokenize Html) >>> pure)-#+end_src--#+RESULTS:-: tokenize Html :: ByteString -> Warn [Token]-: gather Html :: [Token] -> Warn Markup-: normalize :: Markup -> Markup-: degather :: Standard -> Markup -> Warn [Token]-: detokenize Html :: Token -> ByteString-: tokenize Html >=> gather Html >=> (normalize >>> pure) >=> degather Html >=> (fmap (detokenize Html) >>> pure)-:   :: ByteString -> These [MarkupWarning] [ByteString]--Round trip equality--#+begin_src haskell :results output :exports both-m = markup_ Xml bs-m == (markup_ Xml $ markdown_ Compact Xml m)-#+end_src--#+RESULTS:-: True--* MarkupParse.Patch--Obviously, patch doesn't belong here long-term but has been very useful in testing and development.--#+begin_src haskell :results output :exports both-showPatch $ patch [1, 2, 3, 5] [0, 1, 2, 4, 6]-#+end_src--#+RESULTS:-: [+0, -3, +4, -5, +6]--* wiki diff test debug--#+begin_src haskell :results output :exports both-bs <- B.readFile "other/Parsing - Wikipedia.html"-m = markup_ Html bs-m == (markup_ Html $ markdown_ Compact Html m)-#+end_src--#+RESULTS:-: True--* Reference--[[https://html.spec.whatwg.org/#toc-syntax][HTML Standard]]--[[https://stackoverflow.com/questions/3558119/are-non-void-self-closing-tags-valid-in-html5][Are (non-void) self-closing tags valid in HTML5? - Stack Overflow]]--[[https://www.w3.org/TR/xml/][Extensible Markup Language (XML) 1.0 (Fifth Edition)]]--** Prior Art--[[https://hackage.haskell.org/package/html-parse][html-parse]] is an attoparsec-based parser for HTML. The HTML parsing here has referenced this parsing logic for HTML elements.--[[https://hackage.haskell.org/package/blaze-markup][blaze-markup]] & [[https://hackage.haskell.org/package/lucid][lucid]] are HTML DSLs and printers, but not parsers.--[[https://hackage.haskell.org/package/xeno][xeno]] is an "event-based" XML parser with a more complicated base markup type.--[[https://hackage.haskell.org/package/XMLParser][XMLParser]] & [[https://hackage.haskell.org/package/hexml][hexml]] are parsec-based parsers.--* Performance--The [[https://hackage.haskell.org/package/perf][perf]] library has been used to measure performance of the library.--`cabal bench` runs the default benchmarking:--#+begin_src sh :results output :exports both-cabal bench-#+end_src--#+RESULTS:-#+begin_example-Running 1 benchmarks...-Benchmark markup-parse-speed: RUNNING...-label1          label2          old result      new result      change--gather          time            9.33e4          7.73e4          improvement-html-parse tokenstime            1.21e6          1.17e6-html-parse tree time            6.61e4          7.59e4          slightly-degraded-markdown        time            3.75e5          3.92e5-markup          time            4.72e5          5.20e5          slightly-degraded-normalize       time            2.80e5          3.04e5          slightly-degraded-tokenize        time            8.59e5          8.67e5-Benchmark markup-parse-speed: FINISH-#+end_example--** Profiling--Profiling is used to aid library development:--#+begin_src sh :results output-cabal configure --enable-library-profiling --enable-executable-profiling -fprof-auto -fprof --write-ghc-environment-files=always --enable-benchmarks -O2-#+end_src--cabal.project.local--#+begin_example-write-ghc-environment-files: always-ignore-project: False-flags: +prof +prof-auto-library-profiling: True-executable-profiling: True-#+end_example--Profiling slow the main functions significantly:--#+begin_example-./app/speed -n 1000 --best -c +RTS -s -p -hc -l -RTS-label1              label2              old_result          new_result          status--gather              time                2.08e4              3.01e4              degraded-html-parse tokens   time                4.70e5              1.72e6              degraded-html-parse tree     time                2.30e4              3.85e4              degraded-markdown            time                3.51e5              5.70e5              degraded-markup              time                2.10e5              1.05e6              degraded-normalize           time                8.43e4              1.90e5              degraded-tokenize            time                1.94e5              1.02e6              degraded-   4,520,989,296 bytes allocated in the heap-   2,668,887,592 bytes copied during GC-     287,122,272 bytes maximum residency (21 sample(s))-       1,572,000 bytes maximum slop-             560 MiB total memory in use (0 MiB lost due to fragmentation)--                                     Tot time (elapsed)  Avg pause  Max pause-  Gen  0      1073 colls,     0 par    0.471s   0.479s     0.0004s    0.0024s-  Gen  1        21 colls,     0 par    2.428s   2.575s     0.1226s    0.3303s--  INIT    time    0.007s  (  0.008s elapsed)-  MUT     time    2.142s  (  1.945s elapsed)-  GC      time    1.904s  (  2.071s elapsed)-  RP      time    0.000s  (  0.000s elapsed)-  PROF    time    0.995s  (  0.982s elapsed)-  EXIT    time    0.026s  (  0.000s elapsed)-  Total   time    5.074s  (  5.006s elapsed)--  %GC     time       0.0%  (0.0% elapsed)--  Alloc rate    2,110,654,040 bytes per MUT second--  Productivity  61.8% of total user, 58.5% of total elapsed-#+end_example-
src/MarkupParse.hs view
@@ -457,7 +457,7 @@ -- Markup {elements = [Node {rootLabel = Content "<content>", subForest = []}]} -- -- >>> markup_ Html $ markdown_ Compact Html $ contentRaw "<content>"--- *** Exception: UnclosedTag+-- Markup {elements = *** Exception: UnclosedTag -- ... contentRaw :: ByteString -> Markup contentRaw bs = Markup [pure $ Content bs]
src/MarkupParse/FlatParse.hs view
@@ -57,6 +57,7 @@  -- $setup -- >>> :set -XTemplateHaskell+-- >>> :set -XOverloadedStrings -- >>> import MarkupParse.FlatParse -- >>> import FlatParse.Basic 
+ test/doctests.hs view
@@ -0,0 +1,6 @@+import System.Environment (getArgs)+import Test.DocTest (mainFromCabal)+import Prelude (IO, (=<<))++main :: IO ()+main = mainFromCabal "markup-parse" =<< getArgs