grammatical-parsers 0.4.1 → 0.4.1.1
raw patch · 5 files changed
+118/−4 lines, 5 filesdep ~checkersPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: checkers
API changes (from Hackage documentation)
Files
- CHANGELOG.md +4/−0
- grammatical-parsers.cabal +3/−2
- src/Text/Grampa/ContextFree/Memoizing.hs +1/−1
- src/Text/Grampa/ContextFree/SortedMemoizing.hs +1/−1
- test/README.lhs +109/−0
CHANGELOG.md view
@@ -1,3 +1,7 @@+Version 0.4.1.1+---------------+* Fixed the doctests after cabal get+ Version 0.4.1 --------------- * Adjustments for monoid-subclasses-1.0
grammatical-parsers.cabal view
@@ -1,5 +1,5 @@ name: grammatical-parsers-version: 0.4.1+version: 0.4.1.1 synopsis: parsers that combine into grammars description: /Gram/matical-/pa/rsers, or Grampa for short, is a library of parser types whose values are meant to be assigned@@ -60,7 +60,7 @@ build-depends: base >=4.9 && < 5, containers >= 0.5.7.0 && < 0.7, monoid-subclasses < 1.1, parsers < 0.13, rank2classes >= 1.0.2 && < 1.4, grammatical-parsers,- QuickCheck >= 2 && < 3, checkers >= 0.4.6 && < 0.5, size-based < 0.2,+ QuickCheck >= 2 && < 3, checkers >= 0.4.6 && < 0.6, size-based < 0.2, testing-feat >= 1.1 && < 1.2, tasty >= 0.7, tasty-quickcheck >= 0.7 main-is: Test.hs@@ -73,6 +73,7 @@ hs-source-dirs: test default-language: Haskell2010 main-is: Doctest.hs+ other-modules: README ghc-options: -threaded -pgmL markdown-unlit build-depends: base, rank2classes, grammatical-parsers, parsers, doctest >= 0.8 build-tool-depends: markdown-unlit:markdown-unlit >= 0.5 && < 0.6
src/Text/Grampa/ContextFree/Memoizing.hs view
@@ -13,7 +13,7 @@ import Data.List (genericLength, maximumBy, nub) import Data.Semigroup (Semigroup(..)) import Data.Monoid (Monoid(mappend, mempty))-import Data.Monoid.Cancellative (LeftReductiveMonoid, isPrefixOf)+import Data.Monoid.Cancellative (isPrefixOf) import Data.Monoid.Null (MonoidNull(null)) import Data.Monoid.Factorial (FactorialMonoid, length, splitPrimePrefix) import Data.Monoid.Textual (TextualMonoid)
src/Text/Grampa/ContextFree/SortedMemoizing.hs view
@@ -12,7 +12,7 @@ import Data.List.NonEmpty (NonEmpty((:|))) import Data.Semigroup (Semigroup(..)) import Data.Monoid (Monoid(mappend, mempty))-import Data.Monoid.Cancellative (LeftReductiveMonoid, isPrefixOf)+import Data.Monoid.Cancellative (isPrefixOf) import Data.Monoid.Null (MonoidNull(null)) import Data.Monoid.Factorial (FactorialMonoid, splitPrimePrefix) import Data.Monoid.Textual (TextualMonoid)
+ test/README.lhs view
@@ -0,0 +1,109 @@+Grammatical Parsers+===================++Behold, yet another parser combinator library in Haskell. Except this one is capable of working with grammars rather than mere parsers. A more in-depth description is available in the [paper](../Grampa.lhs.pdf) from Haskell Symposium 2017, what follows is a short tutorial.++You can apply the usual+[Applicative](http://hackage.haskell.org/package/base/docs/Control-Applicative.html#t:Applicative),+[Alternative](http://hackage.haskell.org/package/base/docs/Control-Applicative.html#t:Alternative), and+[Monad](http://hackage.haskell.org/package/base/docs/Control-Monad.html#t:Monad) operators to combine primitive parsers+into larger ones. The combinators from the [parsers](http://hackage.haskell.org/package/parsers) library type classes+are also available. Here are some typical imports you may need:++~~~ {.haskell}+{-# LANGUAGE RecordWildCards, ScopedTypeVariables, TemplateHaskell #-}+module README where+import Control.Applicative+import Data.Char (isDigit)+import Data.Functor.Classes (Show1, showsPrec1)+import Text.Grampa+import Text.Grampa.ContextFree.LeftRecursive (Parser)+import qualified Rank2.TH+~~~++What puts this library apart from most is that these parsers are *grammatical*, just as the library name says. Instead+of writing the parser definitions as top-level bindings, you can and should group them into a grammar record definition,+like this:++~~~ {.haskell}+arithmetic :: GrammarBuilder Arithmetic g Parser String+arithmetic Arithmetic{..} = Arithmetic{+ sum= product+ <|> string "-" *> (negate <$> product)+ <|> (+) <$> sum <* string "+" <*> product+ <|> (-) <$> sum <* string "-" <*> product,+ product= factor+ <|> (*) <$> product <* string "*" <*> factor+ <|> div <$> product <* string "/" <*> factor,+ factor= read <$> number+ <|> string "(" *> sum <* string ")",+ number= takeCharsWhile1 isDigit <?> "number"}+~~~++What on Earth for? One good reason is that these parser definitions can then be left-recursive, which is normally a+death knell for parser libraries. There are other benefits like memoization and grammar composability, and the main+downside is the obligation to declare the grammar record:++~~~ {.haskell}+data Arithmetic f = Arithmetic{sum :: f Int,+ product :: f Int,+ factor :: f Int,+ number :: f String}+~~~++and to make it an instance of several rank 2 type classes:++~~~ {.haskell}+$(Rank2.TH.deriveAll ''Arithmetic)+~~~++Optionally, you may also be inclined to declare a proper ``Show`` instance, as it's often handy:++~~~ {.haskell}+instance Show1 f => Show (Arithmetic f) where+ show Arithmetic{..} =+ "Arithmetic{\n sum=" ++ showsPrec1 0 sum+ (",\n product=" ++ showsPrec1 0 factor+ (",\n factor=" ++ showsPrec1 0 factor+ (",\n number=" ++ showsPrec1 0 number "}")))+~~~++Once that's done, use [fixGrammar](http://hackage.haskell.org/package/grammatical-parsers/docs/Text-Grampa.html#v:fixGrammar) to, well, fix the grammar++~~~ {.haskell}+grammar = fixGrammar arithmetic+~~~++and then [parseComplete](http://hackage.haskell.org/package/grammatical-parsers/docs/Text-Grampa.html#v:parseComplete)+or [parsePrefix](http://hackage.haskell.org/package/grammatical-parsers/docs/Text-Grampa.html#v:parsePrefix) to parse+some input.++~~~ {.haskell}+-- |+-- >>> parseComplete grammar "42"+-- Arithmetic{+-- sum=Compose (Right [42]),+-- product=Compose (Right [42]),+-- factor=Compose (Right [42]),+-- number=Compose (Right ["42"])}+-- >>> parseComplete grammar "1+2*3"+-- Arithmetic{+-- sum=Compose (Right [7]),+-- product=Compose (Left (ParseFailure 1 ["endOfInput"])),+-- factor=Compose (Left (ParseFailure 1 ["endOfInput"])),+-- number=Compose (Left (ParseFailure 1 ["endOfInput"]))}+-- >>> parsePrefix grammar "1+2*3 apples"+-- Arithmetic{+-- sum=Compose (Compose (Right [("+2*3 apples",1),("*3 apples",3),(" apples",7)])),+-- product=Compose (Compose (Right [("+2*3 apples",1)])),+-- factor=Compose (Compose (Right [("+2*3 apples",1)])),+-- number=Compose (Compose (Right [("+2*3 apples","1")]))}+~~~++To see more grammar examples, go straight to the+[examples](https://github.com/blamario/grampa/tree/master/grammatical-parsers/examples) directory that builds up several+smaller grammars and combines them all together in the+[Combined](https://github.com/blamario/grampa/blob/master/grammatical-parsers/examples/Combined.hs) module.++For more conventional tastes there are monolithic examples of+[Lua](https://github.com/blamario/language-lua2/blob/master/src/Language/Lua/Grammar.hs) and [Oberon](http://hackage.haskell.org/package/language-oberon) grammars as well.