packages feed

commonmark 0.1.1.4 → 0.2

raw patch · 10 files changed

+302/−55 lines, 10 filesdep +tasty-benchdep +unicode-transformsdep −QuickCheckdep −criterionPVP ok

version bump matches the API change (PVP)

Dependencies added: tasty-bench, unicode-transforms

Dependencies removed: QuickCheck, criterion

API changes (from Hackage documentation)

+ Commonmark.Blocks: [linkPos] :: LinkInfo -> !Maybe SourcePos
+ Commonmark.Inlines: LinkInfo :: !Text -> !Text -> !Attributes -> !Maybe SourcePos -> LinkInfo
+ Commonmark.Inlines: [linkAttributes] :: LinkInfo -> !Attributes
+ Commonmark.Inlines: [linkDestination] :: LinkInfo -> !Text
+ Commonmark.Inlines: [linkPos] :: LinkInfo -> !Maybe SourcePos
+ Commonmark.Inlines: [linkTitle] :: LinkInfo -> !Text
+ Commonmark.Inlines: data LinkInfo
+ Commonmark.Inlines: pLink :: ReferenceMap -> Text -> Parsec [Tok] s LinkInfo
+ Commonmark.ReferenceMap: [linkPos] :: LinkInfo -> !Maybe SourcePos
- Commonmark.Blocks: LinkInfo :: !Text -> !Text -> !Attributes -> LinkInfo
+ Commonmark.Blocks: LinkInfo :: !Text -> !Text -> !Attributes -> !Maybe SourcePos -> LinkInfo
- Commonmark.ReferenceMap: LinkInfo :: !Text -> !Text -> !Attributes -> LinkInfo
+ Commonmark.ReferenceMap: LinkInfo :: !Text -> !Text -> !Attributes -> !Maybe SourcePos -> LinkInfo

Files

benchmark/benchmark.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE CPP                 #-} {-# LANGUAGE OverloadedStrings   #-} {-# LANGUAGE ScopedTypeVariables #-}-import Criterion.Main+import Test.Tasty.Bench import Data.Text (Text) import Data.Functor.Identity  -- base >= 4.8 import Commonmark@@ -14,7 +14,7 @@ main :: IO () main = do   sample <- T.replicate 10 <$> TIO.readFile "benchmark/sample.md"-  defaultMainWith defaultConfig+  defaultMain     [ bgroup "tokenize"       [ benchTokenize ("sample.md", sample) ]     , bgroup "parse sample.md"
changelog.md view
@@ -1,5 +1,17 @@ # Changelog for commonmark +## 0.2++* Commonmark.Inlines: export LinkInfo(..) [API change].+* Commonmark.Inlines: export pLink [API chage].+* Comonmark.ReferenceMap: Add linkPos field to LinkInfo [API change].+* Commonmark.Tokens: normalize unicode to NFC before tokenizing (#57).+  Normalization might affect detection of flankingness, recognition+  of reference links, etc.+* Commonmark.Html:  add data-prefix to non-HTML5 attributes, as pandoc does.+* Remove unnecessary build-depends.+* Use lightweight tasty-bench instead of criterion for benchmarks.+ ## 0.1.1.4  * Fix build with GHC 9.0.1 (Simon Jakobi, #72).
commonmark.cabal view
@@ -1,6 +1,6 @@ cabal-version:  2.2 name:           commonmark-version:        0.1.1.4+version:        0.2 synopsis:       Pure Haskell commonmark parser. description:    This library provides the core data types and functions@@ -35,7 +35,7 @@ stability:      experimental author:         John MacFarlane maintainer:     jgm@berkeley.edu-copyright:      2018-2020 John MacFarlane+copyright:      2018-2021 John MacFarlane license:        BSD-3-Clause license-file:   LICENSE build-type:     Simple@@ -60,6 +60,7 @@     , containers     , transformers     , parsec+    , unicode-transforms   exposed-modules:       Commonmark       Commonmark.Parser@@ -74,6 +75,8 @@       Commonmark.SourceMap       Commonmark.Tag       Commonmark.Entity+  if impl(ghc >= 8.10)+    ghc-options:      -Wunused-packages   if impl(ghc >= 8.8)     ghc-options:  -fwrite-ide-info -hiedir=.hie   ghc-options: -Wall -fno-warn-unused-do-bind -funbox-small-strict-fields@@ -86,14 +89,16 @@   hs-source-dirs:       test   ghc-options: -threaded -rtsopts -with-rtsopts=-K40K+  if impl(ghc >= 8.10)+    ghc-options:      -Wunused-packages   build-depends:       base >= 4.9 && <5     , commonmark     , text+    , unicode-transforms     , tasty     , tasty-quickcheck     , tasty-hunit-    , QuickCheck     , parsec   default-language: Haskell2010 @@ -105,9 +110,8 @@        commonmark      , base >= 4.9 && < 5      , text-     , transformers-     , containers-     , bytestring-     , criterion >= 1.0 && < 1.6+     , tasty-bench   ghc-options: -threaded -rtsopts -with-rtsopts=-K10K+  if impl(ghc >= 8.10)+    ghc-options:      -Wunused-packages   default-language: Haskell2010
src/Commonmark/Blocks.hs view
@@ -108,7 +108,7 @@              -> BlockParser m il bl bl processLines specs finalParsers = {-# SCC processLines #-} do   let go = eof <|> (processLine specs >> go) in go-  tree <- (nodeStack <$> getState) >>= collapseNodeStack+  tree <- getState >>= collapseNodeStack . nodeStack   updateState $ \st -> st{ nodeStack = [reverseSubforests tree] }   endContent <- mconcat <$> sequence finalParsers   tree':_ <- nodeStack <$> getState@@ -237,7 +237,7 @@                 else (matched, new:unmatched))        <|> (matched, nd:unmatched) <$ updateState (\st -> st{                                          blockMatched = False })-     else return $! (matched, nd:unmatched)+     else return (matched, nd:unmatched)   {-@@ -404,7 +404,7 @@      go [] = []      go ((!startpos1, !endpos1):(!startpos2, !endpos2):rest)        | endpos1 == startpos2 = go ((startpos1, endpos2):rest)-     go (!x:xs) = x : go xs+     go (x:xs) = x : go xs  -- Add a new node to the block stack.  If current tip can contain -- it, add it there; otherwise, close the tip and repeat til we get@@ -475,10 +475,10 @@          let linkdefs = fromDyn (blockData (rootLabel node))                   undefined :: [((SourceRange, Text), LinkInfo)]          return $! mconcat $ map (\((range, lab), linkinfo) ->-            (ranged range+            ranged range               (addAttributes (linkAttributes linkinfo)                 (referenceLinkDefinition lab (linkDestination linkinfo,-                                            linkTitle linkinfo))))) linkdefs+                                            linkTitle linkinfo)))) linkdefs      , blockFinalize       = defaultFinalizer      } @@ -495,7 +495,7 @@                         many1 (linkReferenceDef (choice $ attributeParsers st)))                   <*> getInput) st "" (getBlockText node)   case res of-        Left _ -> return $! (Just node, Nothing)+        Left _ -> return (Just node, Nothing)         Right (linkdefs, toks') -> do           mapM_             (\((_,lab),linkinfo) ->@@ -523,7 +523,7 @@                    , blockData = toDyn linkdefs                    , blockSpec = refLinkDefSpec                  }}-          return $! (node', Just refnode)+          return (node', Just refnode)  attributeSpec :: (Monad m, IsBlock il bl)               => BlockSpec m il bl@@ -556,7 +556,7 @@          lookAhead (void lineEnd <|> eof)          let oldattrs = fromDyn (blockData (rootLabel n)) mempty :: Attributes          let attrs' = oldattrs <> attrs-         return $! (pos, n{ rootLabel = (rootLabel n){+         return  (pos, n{ rootLabel = (rootLabel n){                           blockData = toDyn attrs' }})      , blockConstructor    = \_ -> return $! mempty      , blockFinalize       = \node parent -> do@@ -617,6 +617,7 @@   guard $ not $ T.all isSpace lab   symbol ':'   optional whitespace+  linkpos <- getPosition   dest <- pLinkDestination   (title, attrs) <- option (mempty, mempty) $ try $ do              tit <- option mempty $ try (whitespace *> pLinkTitle)@@ -624,13 +625,14 @@              as <- option mempty attrParser              skipWhile (hasType Spaces)              lookAhead (void lineEnd <|> eof)-             return $! (tit, as)+             return (tit, as)   endpos <- getPosition   void lineEnd <|> eof-  return $! ((SourceRange [(startpos, endpos)], lab),+  return ((SourceRange [(startpos, endpos)], lab),                 LinkInfo{ linkDestination = unEntity dest                         , linkTitle = unEntity title-                        , linkAttributes = attrs })+                        , linkAttributes = attrs+                        , linkPos = Just linkpos })  atxHeadingSpec :: (Monad m, IsBlock il bl)             => BlockSpec m il bl@@ -677,7 +679,7 @@          let oldAttr = blockAttributes cdata          let toks = getBlockText node          (newtoks, attr) <- parseFinalAttributes True toks-                        <|> (return $! (toks, mempty))+                        <|> (return (toks, mempty))          defaultFinalizer (Node cdata{ blockAttributes = oldAttr <> attr                                      , blockLines = [newtoks] }                                 children) parent@@ -731,7 +733,7 @@          let oldAttr = blockAttributes cdata          let toks = getBlockText node          (newtoks, attr) <- parseFinalAttributes True toks-                        <|> (return $! (toks, mempty))+                        <|> (return (toks, mempty))          defaultFinalizer (Node cdata{ blockAttributes = oldAttr <> attr                                      , blockLines = [newtoks] }                                 children) parent@@ -751,7 +753,7 @@             <*> option [] pAttr') st "heading contents" ts   case res of     Left _         -> mzero-    Right (xs, ys) -> return $! (xs, ys)+    Right (xs, ys) -> return (xs, ys)  blockQuoteSpec :: (Monad m, IsBlock il bl) => BlockSpec m il bl blockQuoteSpec = BlockSpec@@ -773,9 +775,8 @@              pos <- getPosition              _ <- symbol '>'              _ <- gobbleUpToSpaces 1-             return $! (pos, n)-     , blockConstructor    = \node ->-           (blockQuote . mconcat) <$> renderChildren node+             return (pos, n)+     , blockConstructor    = fmap (blockQuote . mconcat) . renderChildren      , blockFinalize       = defaultFinalizer      } @@ -829,7 +830,7 @@                      not (null children)              pos <- getPosition              gobbleSpaces (listItemIndent lidata) <|> 0 <$ lookAhead blankLine-             return $! (pos, node)+             return (pos, node)      , blockConstructor    = fmap mconcat . renderChildren      , blockFinalize       = \(Node cdata children) parent -> do           let lidata = fromDyn (blockData cdata)@@ -866,7 +867,7 @@   numspaces <- try (gobbleUpToSpaces 4 <* notFollowedBy whitespace)            <|> gobbleSpaces 1            <|> 1 <$ lookAhead lineEnd-  return $! (pos, ListItemData{+  return (pos, ListItemData{            listItemType = ty           , listItemIndent = (aftercol - beforecol) + numspaces           , listItemBlanksInside = False@@ -978,7 +979,7 @@              void (gobbleSpaces 4)                <|> try (skipWhile (hasType Spaces) <* lookAhead lineEnd)              pos <- getPosition-             return $! (pos, node)+             return (pos, node)       , blockConstructor    = \node ->              return $! codeBlock mempty (untokenize (getBlockText node))@@ -1020,7 +1021,7 @@               let infotoks = tokenize "info string" info              (content, attrs) <- parseFinalAttributes False infotoks-                                  <|> (return $! (infotoks, mempty))+                                  <|> (return (infotoks, mempty))              addNodeToStack $                 Node (defBlockData fencedCodeSpec){                           blockData = toDyn@@ -1050,7 +1051,7 @@                                    ('`', 3, 0, mempty, mempty)                        pos <- getPosition                        _ <- gobbleUpToSpaces indentspaces-                       return $! (pos, node))+                       return (pos, node))      , blockConstructor    = \node -> do            let ((_, _, _, info, attrs) :: (Char, Int, Int, Text, Attributes)) =                    fromDyn (blockData (rootLabel node)) ('`', 3, 0, mempty, mempty)@@ -1107,7 +1108,7 @@                     return $! (pos', Node ndata{                                     blockData = toDyn (0 :: Int)                                   , blockLines = (toks ++ le) : blockLines ndata-                                  } children)) <|> (return $! (pos, node))+                                  } children)) <|> (return (pos, node))      , blockConstructor    = \node ->              return $! rawBlock (Format "html")                            (untokenize (getBlockText node))
src/Commonmark/Html.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE CPP                        #-}-{-# LANGUAGE BangPatterns               #-} {-# LANGUAGE OverloadedStrings          #-} {-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE FlexibleInstances          #-}@@ -27,6 +26,7 @@                                          singleton) import           Data.Text.Encoding   (encodeUtf8) import qualified Data.ByteString.Char8 as B+import qualified Data.Set as Set import           Text.Printf          (printf) import           Data.Char            (ord, isAlphaNum, isAscii, isSpace) import           Data.Maybe           (fromMaybe)@@ -166,7 +166,7 @@   htmlInline :: Text -> Maybe (Html a) -> Html a-htmlInline tagname mbcontents = HtmlElement InlineElement tagname [] mbcontents+htmlInline tagname = HtmlElement InlineElement tagname []  htmlBlock :: Text -> Maybe (Html a) -> Html a htmlBlock tagname mbcontents = HtmlElement BlockElement tagname [] mbcontents@@ -181,23 +181,244 @@ addAttribute attr (HtmlElement eltType tagname attrs mbcontents) =   HtmlElement eltType tagname (incorporateAttribute attr attrs) mbcontents addAttribute attr (HtmlText t)-  = HtmlElement InlineElement "span" [attr] $ Just (HtmlText t)+  = addAttribute attr $ HtmlElement InlineElement "span" [] $ Just (HtmlText t) addAttribute _ elt = elt  incorporateAttribute :: Attribute -> [Attribute] -> [Attribute] incorporateAttribute (k, v) as =-  case lookup k as of-    Nothing            -> (k, v) : as-    Just v'            -> (if k == "class"+  case lookup k' as of+    Nothing            -> (k', v) : as+    Just v'            -> (if k' == "class"                               then ("class", v <> " " <> v')-                              else (k, v')) :-                          filter (\(x, _) -> x /= k) as+                              else (k', v')) :+                          filter (\(x, _) -> x /= k') as+ where+  k' = if k `Set.member` html5Attributes+            || "data-" `T.isPrefixOf` k+          then k+          else "data-" <> k +html5Attributes :: Set.Set Text+html5Attributes = Set.fromList+  [ "abbr"+  , "accept"+  , "accept-charset"+  , "accesskey"+  , "action"+  , "allow"+  , "allowfullscreen"+  , "allowpaymentrequest"+  , "allowusermedia"+  , "alt"+  , "as"+  , "async"+  , "autocapitalize"+  , "autocomplete"+  , "autofocus"+  , "autoplay"+  , "charset"+  , "checked"+  , "cite"+  , "class"+  , "color"+  , "cols"+  , "colspan"+  , "content"+  , "contenteditable"+  , "controls"+  , "coords"+  , "crossorigin"+  , "data"+  , "datetime"+  , "decoding"+  , "default"+  , "defer"+  , "dir"+  , "dirname"+  , "disabled"+  , "download"+  , "draggable"+  , "enctype"+  , "enterkeyhint"+  , "for"+  , "form"+  , "formaction"+  , "formenctype"+  , "formmethod"+  , "formnovalidate"+  , "formtarget"+  , "headers"+  , "height"+  , "hidden"+  , "high"+  , "href"+  , "hreflang"+  , "http-equiv"+  , "id"+  , "imagesizes"+  , "imagesrcset"+  , "inputmode"+  , "integrity"+  , "is"+  , "ismap"+  , "itemid"+  , "itemprop"+  , "itemref"+  , "itemscope"+  , "itemtype"+  , "kind"+  , "label"+  , "lang"+  , "list"+  , "loading"+  , "loop"+  , "low"+  , "manifest"+  , "max"+  , "maxlength"+  , "media"+  , "method"+  , "min"+  , "minlength"+  , "multiple"+  , "muted"+  , "name"+  , "nomodule"+  , "nonce"+  , "novalidate"+  , "onabort"+  , "onafterprint"+  , "onauxclick"+  , "onbeforeprint"+  , "onbeforeunload"+  , "onblur"+  , "oncancel"+  , "oncanplay"+  , "oncanplaythrough"+  , "onchange"+  , "onclick"+  , "onclose"+  , "oncontextmenu"+  , "oncopy"+  , "oncuechange"+  , "oncut"+  , "ondblclick"+  , "ondrag"+  , "ondragend"+  , "ondragenter"+  , "ondragexit"+  , "ondragleave"+  , "ondragover"+  , "ondragstart"+  , "ondrop"+  , "ondurationchange"+  , "onemptied"+  , "onended"+  , "onerror"+  , "onfocus"+  , "onhashchange"+  , "oninput"+  , "oninvalid"+  , "onkeydown"+  , "onkeypress"+  , "onkeyup"+  , "onlanguagechange"+  , "onload"+  , "onloadeddata"+  , "onloadedmetadata"+  , "onloadend"+  , "onloadstart"+  , "onmessage"+  , "onmessageerror"+  , "onmousedown"+  , "onmouseenter"+  , "onmouseleave"+  , "onmousemove"+  , "onmouseout"+  , "onmouseover"+  , "onmouseup"+  , "onoffline"+  , "ononline"+  , "onpagehide"+  , "onpageshow"+  , "onpaste"+  , "onpause"+  , "onplay"+  , "onplaying"+  , "onpopstate"+  , "onprogress"+  , "onratechange"+  , "onrejectionhandled"+  , "onreset"+  , "onresize"+  , "onscroll"+  , "onsecuritypolicyviolation"+  , "onseeked"+  , "onseeking"+  , "onselect"+  , "onstalled"+  , "onstorage"+  , "onsubmit"+  , "onsuspend"+  , "ontimeupdate"+  , "ontoggle"+  , "onunhandledrejection"+  , "onunload"+  , "onvolumechange"+  , "onwaiting"+  , "onwheel"+  , "open"+  , "optimum"+  , "pattern"+  , "ping"+  , "placeholder"+  , "playsinline"+  , "poster"+  , "preload"+  , "readonly"+  , "referrerpolicy"+  , "rel"+  , "required"+  , "reversed"+  , "role"+  , "rows"+  , "rowspan"+  , "sandbox"+  , "scope"+  , "selected"+  , "shape"+  , "size"+  , "sizes"+  , "slot"+  , "span"+  , "spellcheck"+  , "src"+  , "srcdoc"+  , "srclang"+  , "srcset"+  , "start"+  , "step"+  , "style"+  , "tabindex"+  , "target"+  , "title"+  , "translate"+  , "type"+  , "typemustmatch"+  , "updateviacache"+  , "usemap"+  , "value"+  , "width"+  , "workertype"+  , "wrap"+  ]++ renderHtml :: Html a -> TL.Text renderHtml = {-# SCC renderHtml #-} toLazyText . toBuilder  toBuilder :: Html a -> Builder-toBuilder (HtmlNull) = mempty+toBuilder HtmlNull = mempty toBuilder (HtmlConcat x y) = toBuilder x <> toBuilder y toBuilder (HtmlRaw t) = fromText t toBuilder (HtmlText t) = escapeHtml t
src/Commonmark/Inlines.hs view
@@ -17,8 +17,10 @@   , defaultFormattingSpecs   , BracketedSpec(..)   , defaultBracketedSpecs+  , LinkInfo(..)   , imageSpec   , linkSpec+  , pLink   , pLinkLabel   , pLinkDestination   , pLinkTitle@@ -290,13 +292,13 @@ pLinkSuffix :: IsInline il             => ReferenceMap -> Text -> Parsec [Tok] s (il -> il) pLinkSuffix rm key = do-  LinkInfo target title attrs <- pLink rm key+  LinkInfo target title attrs _mbpos <- pLink rm key   return $! addAttributes attrs . link target title  pImageSuffix :: IsInline il              => ReferenceMap -> Text -> Parsec [Tok] s (il -> il) pImageSuffix rm key = do-  LinkInfo target title attrs <- pLink rm key+  LinkInfo target title attrs _mbpos <- pLink rm key   return $! addAttributes attrs . image target title  ---@@ -408,7 +410,7 @@ withAttributes p = do   x <- p   attrParser <- attributeParser <$> getState-  option x $ (\attr -> addAttributes attr x) <$> attrParser+  option x $ (`addAttributes` x) <$> attrParser  pInline :: (IsInline a, Monad m)         => [InlineParser m a]@@ -426,7 +428,7 @@  rangeFromToks :: [Tok] -> SourcePos -> SourceRange rangeFromToks [] _ = SourceRange mempty-rangeFromToks (!z:zs) !endpos+rangeFromToks (z:zs) !endpos   | sourceLine (tokPos z) == sourceLine endpos     = SourceRange [(tokPos z, endpos)]   | otherwise@@ -436,8 +438,8 @@           case break (hasType LineEnd) ts of              ([], [])     -> []              ([], _:ys)   -> go ys-             (!x:_, [])   -> [(tokPos x, endpos)]-             (!x:_, !y:ys) ->+             (x:_, [])   -> [(tokPos x, endpos)]+             (x:_, y:ys) ->                case ys of                  (Tok _ !pos _ : _) | sourceColumn pos == 1 -> go (x:ys)                  _ -> (tokPos x, tokPos y) : go ys@@ -851,7 +853,7 @@ -- isn't. fixSingleQuote :: Cursor (Chunk a) -> Cursor (Chunk a) fixSingleQuote-  (Cursor (Just (Chunk d@(Delim{ delimType = '\'' }) pos toks)) xs ys) =+  (Cursor (Just (Chunk d@Delim{ delimType = '\'' } pos toks)) xs ys) =   Cursor (Just (Chunk d{ delimCanOpen = False } pos toks)) xs ys fixSingleQuote cursor = cursor @@ -870,7 +872,8 @@   _ <- symbol ')'   return $! LinkInfo { linkDestination = target                     , linkTitle = title-                    , linkAttributes = mempty }+                    , linkAttributes = mempty+                    , linkPos = Nothing }  pLinkDestination :: Monad m => ParsecT [Tok] s m [Tok] pLinkDestination = pAngleDest <|> pNormalDest 0
src/Commonmark/ReferenceMap.hs view
@@ -22,7 +22,11 @@  data LinkInfo = LinkInfo{ linkDestination :: !Text                         , linkTitle       :: !Text-                        , linkAttributes  :: !Attributes }+                        , linkAttributes  :: !Attributes+                        , linkPos         :: !(Maybe SourcePos)+                            -- ^ Position of the reference link definition+                            -- for references links.+                        }      deriving (Show, Typeable)  emptyReferenceMap :: ReferenceMap@@ -35,7 +39,7 @@                 -> ReferenceMap                 -> ReferenceMap insertReference label x (ReferenceMap m) =-  ReferenceMap (M.insertWith (\new old -> old ++ new)+  ReferenceMap (M.insertWith (flip (++))     (T.toCaseFold $! normalizeSpaces label) [toDyn x] m)  -- | Lookup a reference in a reference map.  If there are several
src/Commonmark/TokParsers.hs view
@@ -119,7 +119,7 @@                let newtok = Tok Spaces newpos                       (T.replicate (n - numspaces) " ")                getInput >>= setInput . (newtok:)-               setPosition $ newpos+               setPosition newpos                return $! numspaces)     <|> if requireAll            then mzero
src/Commonmark/Tokens.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE MultiWayIf #-} {-# LANGUAGE BangPatterns #-}  module Commonmark.Tokens@@ -16,6 +15,7 @@ import qualified Data.Text       as T import           Data.Data       (Data, Typeable) import           Text.Parsec.Pos+import           Data.Text.Normalize (normalize, NormalizationMode(NFC))  data Tok = Tok { tokType     :: !TokType                , tokPos      :: !SourcePos@@ -34,7 +34,8 @@ -- | Convert a 'Text' into a list of 'Tok'. The first parameter -- species the source name. tokenize :: String -> Text -> [Tok]-tokenize name = {-# SCC tokenize #-} go (initialPos name) . T.groupBy f+tokenize name =+  {-# SCC tokenize #-} go (initialPos name) . T.groupBy f . normalize NFC   where     -- We group \r\n, consecutive spaces, and consecutive alphanums;     -- everything else gets in a token by itself.
test/test-commonmark.hs view
@@ -12,6 +12,7 @@ import           System.IO             (hSetEncoding, utf8, openFile,                                         IOMode(..)) import qualified Data.Text.Lazy        as TL+import           Data.Text.Normalize   (normalize, NormalizationMode(NFC)) import           Test.Tasty import           Test.Tasty.HUnit import           Test.Tasty.QuickCheck@@ -111,7 +112,7 @@  tokenize_roundtrip :: String -> Bool tokenize_roundtrip s = untokenize (tokenize "source" t) == t-  where t = T.pack s+  where t = normalize NFC $ T.pack s  --- parser for spec test cases