replace-megaparsec 1.0.0.0 → 1.0.1.0
raw patch · 6 files changed
+74/−51 lines, 6 filesdep ~basePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base
API changes (from Hackage documentation)
Files
- README.md +32/−12
- replace-megaparsec.cabal +29/−28
- src/Replace/Megaparsec.hs +7/−5
- tests/TestByteString.hs +2/−2
- tests/TestString.hs +2/−2
- tests/TestText.hs +2/−2
README.md view
@@ -1,5 +1,9 @@ # replace-megaparsec +[](https://hackage.haskell.org/package/replace-megaparsec)+[](http://stackage.org/nightly/package/replace-megaparsec)+[](http://stackage.org/lts/package/replace-megaparsec)+ __replace-megaparsec__ is for finding text patterns, and also editing and replacing the found patterns. This activity is traditionally done with regular expressions,@@ -27,7 +31,7 @@ ## Why would we want to do pattern matching and substitution with parsers instead of regular expressions? -* Parsers have a nicer syntax than+* Haskell parsers have a nicer syntax than [regular expressions](https://en.wikipedia.org/wiki/Regular_expression), which are notoriously [difficult to read](https://en.wikipedia.org/wiki/Write-only_language).@@ -37,7 +41,7 @@ can construct typed data structures based on the capture groups, guaranteeing no disagreement between the pattern rules and the rules that we're using to build data structures based on the pattern matches.- + For example, consider scanning a string for numbers. A lot of different things can look like a number, and can have leading plus or minus signs, or be in scientific notation, or@@ -53,10 +57,16 @@ [regular](https://en.wikipedia.org/wiki/Chomsky_hierarchy#The_hierarchy) grammers. Parsers are able pattern-match with context-free grammers, and- even context-sensitive or Turing-complete grammers, if needed. See below for+ even context-sensitive or Turing grammers, if needed. See below for an example of lifting a `Parser` into a `State` monad for context-sensitive pattern-matching. + The replacement expression for a traditional regular expression-based+ substitution command is usually just a simple string template in which+ the *Nth* “capture group” can be inserted with the syntax `\N`. With+ this library, instead of a template, we get+ an `editor` function which can perform any computation, including IO.+ ## Examples Try the examples in `ghci` by@@ -78,13 +88,13 @@ and deconstruct the string of text by separating it into sections which match the pattern, and sections which don't match. -#### Pattern-match, capture only the parsed result+#### Pattern match, capture only the parsed result Separate the input string into sections which can be parsed as a hexadecimal number with a prefix `"0x"`, and sections which can't. ```haskell-let hexparser = string "0x" >> hexadecimal :: Parsec Void String Integer+let hexparser = chunk "0x" >> hexadecimal :: Parsec Void String Integer parseTest (sepCap hexparser) "0xA 000 0xFFFF" ``` ```haskell@@ -97,7 +107,7 @@ the parsed number. ```haskell-let hexparser = string "0x" >> hexadecimal :: Parsec Void String Integer+let hexparser = chunk "0x" >> hexadecimal :: Parsec Void String Integer parseTest (findAll hexparser) "0xA 000 0xFFFF" ``` ```haskell@@ -110,7 +120,7 @@ parses as a hexadecimal number. ```haskell-let hexparser = string "0x" >> hexadecimal :: Parsec Void String Integer+let hexparser = chunk "0x" >> hexadecimal :: Parsec Void String Integer parseTest (findAllCap hexparser) "0xA 000 0xFFFF" ``` ```haskell@@ -143,10 +153,10 @@ Replace all carriage-return-newline instances with newline. ```haskell-streamEdit crlf (const "\n") "1\r\n\r\n2"+streamEdit (chunk "\r\n") (const "\n") "1\r\n2\r\n" ``` ```haskell-"1\n\n2"+"1\n2\n" ``` #### Pattern match and edit the matches@@ -160,14 +170,16 @@ "IBM 9000" ``` -#### Pattern match and edit the matches+#### Pattern match and maybe edit the matches, or maybe leave them alone Find all of the string sections *`s`* which can be parsed as a hexadecimal number *`r`*,-and if *`r≤16`*, then replace *`s`* with a decimal number.+and if *`r≤16`*, then replace *`s`* with a decimal number. Uses the+[`match`](https://hackage.haskell.org/package/megaparsec/docs/Text-Megaparsec.html#v:match)+combinator. ```haskell-let hexparser = string "0x" >> hexadecimal :: Parsec Void String Integer+let hexparser = chunk "0x" >> hexadecimal :: Parsec Void String Integer streamEdit (match hexparser) (\(s,r) -> if r <= 16 then show r else s) "0xA 000 0xFFFF" ``` ```haskell@@ -214,3 +226,11 @@ <http://hackage.haskell.org/package/pcre-utils> <http://hackage.haskell.org/package/template>++## Motivation++I wanted to scan a Markdown document and find tokens inside backticks that+look like a Haskell identifier, then look up the identifier in Hoogle to+see if it has a definition in __base__, and if so, insert a Hackage link+for the identifier into the Markdown. I couldn't find a simple and+obvious way to do that with any existing technology.
replace-megaparsec.cabal view
@@ -1,5 +1,5 @@ name: replace-megaparsec-version: 1.0.0.0+version: 1.0.1.0 cabal-version: 1.18 synopsis: Stream editing with parsers homepage: https://github.com/jamesdbrock/replace-megaparsec@@ -25,39 +25,40 @@ library hs-source-dirs: src -- rely on megaparsec for version bounds- build-depends: base+ build-depends: base >= 4.0 && < 5.0 , megaparsec default-language: Haskell2010 exposed-modules: Replace.Megaparsec+ ghc-options: -O2 -Wall test-suite test-string- type: detailed-0.9- test-module: TestString- hs-source-dirs: tests- default-language: Haskell2010- build-depends: base >=4.12 && < 5.0- , replace-megaparsec- , megaparsec- , Cabal+ type: detailed-0.9+ test-module: TestString+ hs-source-dirs: tests+ default-language: Haskell2010+ build-depends: base >= 4.0 && < 5.0+ , replace-megaparsec+ , megaparsec+ , Cabal test-suite test-text- type: detailed-0.9- test-module: TestText- hs-source-dirs: tests- default-language: Haskell2010- build-depends: base >=4.12 && < 5.0- , replace-megaparsec- , megaparsec- , Cabal- , text+ type: detailed-0.9+ test-module: TestText+ hs-source-dirs: tests+ default-language: Haskell2010+ build-depends: base >= 4.0 && < 5.0+ , replace-megaparsec+ , megaparsec+ , Cabal+ , text test-suite test-bytestring- type: detailed-0.9- test-module: TestByteString- hs-source-dirs: tests- default-language: Haskell2010- build-depends: base >=4.12 && < 5.0- , replace-megaparsec- , megaparsec- , Cabal- , bytestring+ type: detailed-0.9+ test-module: TestByteString+ hs-source-dirs: tests+ default-language: Haskell2010+ build-depends: base >= 4.0 && < 5.0+ , replace-megaparsec+ , megaparsec+ , Cabal+ , bytestring
src/Replace/Megaparsec.hs view
@@ -48,7 +48,6 @@ import Data.Void-import Data.Maybe import Data.Bifunctor import Data.Functor.Identity import Data.Proxy@@ -112,7 +111,7 @@ offset1 <- getOffset x <- p offset2 <- getOffset- when (offset1 == offset2) empty+ when (offset1 >= offset2) empty return x -- |@@ -163,14 +162,17 @@ -- a “way to run a parser”, like 'Text.Megaparsec.parse' -- or 'Text.Megaparsec.runParserT'. ----- === Access the matched section of text in the editor+-- === Access the matched section of text in the `editor` -- -- If you want access to the matched string in the @editor@ function,--- then combine the pattern parser @sep@ with 'Text.Megaparsec.match', like+-- then combine the pattern parser @sep@ with 'Text.Megaparsec.match'.+-- This will effectively change the type of the `editor`+-- to `(s,a) -> m s`, and then we can write `editor` like: -- -- @ -- let editor (matchString,parseResult) = return matchString--- in streamEditT ('Text.Megaparsec.match' sep) editor inputstring+--+-- streamEditT ('Text.Megaparsec.match' sep) editor inputString -- @ -- -- === Type constraints
tests/TestByteString.hs view
@@ -67,11 +67,11 @@ -- but if we use the Text.Megaparsec.Byte.Lexer.float, then it consumes -- the "E" and the exponent. Whatever, doesn't really matter for this test. m <- fromIntegral <$> decimal- string "E"+ chunk "E" e <- decimal return (m, e) offsetA :: Parser Int-offsetA = getOffset <* string "A"+offsetA = getOffset <* chunk "A"
tests/TestString.hs view
@@ -59,11 +59,11 @@ scinum :: Parser (Double, Integer) scinum = do m <- some digitChar- string "E"+ chunk "E" e <- some digitChar return (read m, read e) offsetA :: Parser Int-offsetA = getOffset <* string "A"+offsetA = getOffset <* chunk "A"
tests/TestText.hs view
@@ -62,11 +62,11 @@ scinum :: Parser (Double, Integer) scinum = do m <- some digitChar- string "E"+ chunk "E" e <- some digitChar return (read m, read e) offsetA :: Parser Int-offsetA = getOffset <* string "A"+offsetA = getOffset <* chunk "A"