From: Nathaniel Wesley Filardo Date: Mon, 4 Feb 2013 20:25:57 +0000 (-0500) Subject: Update to new parser & trifecta packages X-Git-Url: https://hydra-www.ietfng.org/gitweb/?a=commitdiff_plain;h=c8476f21a8975e14f78277cb0346c80acd36acb2;p=dyna2 Update to new parser & trifecta packages --- diff --git a/Makefile b/Makefile index 9b6d20b..38e17e7 100644 --- a/Makefile +++ b/Makefile @@ -5,13 +5,14 @@ all: build upstream: git submodule init git submodule update external/ekmett-parsers external/ekmett-trifecta - (cd external/ekmett-parsers; cabal install --user) - (cd external/ekmett-trifecta; cabal install --user) + cabal install --user --enable-tests --only-dependencies \ + external/ekmett-parsers external/ekmett-trifecta . + cabal install --user external/ekmett-parsers external/ekmett-trifecta deps: - (cabal install --enable-tests --only-dependencies) + cabal install --user --enable-tests --only-dependencies . -build: deps +build: cabal configure --user --enable-tests cabal build cabal test diff --git a/README.md b/README.md index 80d5a2b..da964dc 100644 --- a/README.md +++ b/README.md @@ -24,18 +24,13 @@ First, ensure that you have GHC 7.6 or later. (Though in a pinch, if you're only interested in the frontend stuff and the Python backend, apparently as early as 7.0 continues to be servicable.) -Then, sadly, I have to ask you to build some upstream packages out of their -repositories. I thought they were going to be released "soon" when I -switched to these later versions, but it hasn't happened yet: - - make upstream - Build K3, if that's your thing, which requires OCaml: git submodule update external/damsl-k3 (cd external/damsl-k3; make) -Then fetch, build, and install any dependencies +Then fetch, build, and install any dependencies (for the moment, we seem to +be doing OK with vanilla upstreams!) make deps diff --git a/dyna.cabal b/dyna.cabal index 2311069..442b372 100644 --- a/dyna.cabal +++ b/dyna.cabal @@ -29,31 +29,33 @@ Library Exposed-Modules: Dyna.Analysis.ANF, + Dyna.Analysis.Base, Dyna.Analysis.Mode, - Dyna.Backend.K3.AST, - Dyna.Backend.K3.Automation, - Dyna.Backend.K3.Render, + Dyna.Main.BackendDefn, + Dyna.Main.Driver, + Dyna.Main.Exception, Dyna.ParserHS.Parser, - Dyna.XXX.HList, - Dyna.XXX.THTuple, Dyna.XXX.Trifecta - Build-Depends: base >=4, + Build-Depends: ansi-wl-pprint >= 0.6, + base >=4, bytestring >=0.9, charset >=0.3, containers >=0.4, ghc-prim >= 0.3, + HUnit >=1.2, mtl >=2.1, - parsers >=0.2, + parsers >=0.5, reducers >=3.0, semigroups >=0.8, tagged >= 0.4.4, template-haskell, - trifecta >=0.90, + trifecta >= 1.0, unification-fd, unordered-containers>=0.2, utf8-string >=0.3, - wl-pprint-extras >=3.0 + wl-pprint-extras >=3.0, + wl-pprint-terminfo >=3.0 Executable drepl Default-Language: Haskell2010 @@ -62,18 +64,19 @@ Executable drepl ghc-options: -Wall -main-is Dyna.REPL - Build-Depends: base >=4, + Build-Depends: ansi-wl-pprint >= 0.6, + base >=4, bytestring >=0.9, charset >=0.3, containers >=0.4, haskeline >=0.6, mtl >=2.1, - parsers >=0.2, + parsers >=0.5, process >=1.1, reducers >=3.0, semigroups >=0.8, tagged >= 0.4.4, - trifecta >=0.90, + trifecta >= 1.0, unification-fd, unordered-containers>=0.2, utf8-string >=0.3, @@ -89,19 +92,20 @@ Executable dyna ghc-options: -Wall -main-is Dyna.Main.Driver - Build-Depends: base >=4, + Build-Depends: ansi-wl-pprint >= 0.6, + base >=4, bytestring >=0.9, charset >=0.3, containers >=0.4, haskeline >=0.6, HUnit >=1.2, mtl >=2.1, - parsers >=0.2, + parsers >=0.5, process >=1.1, reducers >=3.0, semigroups >=0.8, tagged >= 0.4.4, - trifecta >=0.90, + trifecta >= 1.0, unification-fd, unordered-containers>=0.2, utf8-string >=0.3, @@ -118,14 +122,15 @@ Test-suite dyna-selftests ghc-options: -Wall -main-is Dyna.Main.TestsDriver - Build-Depends: base >=4, + Build-Depends: ansi-wl-pprint >= 0.6, + base >=4, bytestring >=0.9, charset >=0.3, containers >=0.4, ghc-prim >= 0.3, HUnit >=1.2, mtl >=2.1, - parsers >=0.2, + parsers >=0.5, process >=1.1, reducers >=3.0, semigroups >=0.8, @@ -135,12 +140,10 @@ Test-suite dyna-selftests test-framework-hunit >=0.2, test-framework-th >=0.2, test-framework-golden >= 1.1, - trifecta >=0.90, + trifecta >= 1.0, unification-fd, unordered-containers>=0.2, utf8-string >=0.3, wl-pprint-extras >=3.0 - Other-Modules: Dyna.Backend.K3.Examples - Main-Is: Dyna/Main/TestsDriver.hs diff --git a/external/ekmett-parsers b/external/ekmett-parsers index 82505d7..c707806 160000 --- a/external/ekmett-parsers +++ b/external/ekmett-parsers @@ -1 +1 @@ -Subproject commit 82505d74430677c92aedcd3e71ececf491e859b3 +Subproject commit c707806109119e3f54c3064039a4ee2624f18ff1 diff --git a/external/ekmett-trifecta b/external/ekmett-trifecta index 0725065..fd1aa5e 160000 --- a/external/ekmett-trifecta +++ b/external/ekmett-trifecta @@ -1 +1 @@ -Subproject commit 0725065a6f9a7e6e1732cd3a9f326f410b73f312 +Subproject commit fd1aa5e853dd5e015e5df841507ae532558b13d1 diff --git a/src/Dyna/Main/Driver.hs b/src/Dyna/Main/Driver.hs index 7bbb8d8..576a25b 100644 --- a/src/Dyna/Main/Driver.hs +++ b/src/Dyna/Main/Driver.hs @@ -15,22 +15,24 @@ import Control.Applicative ((<*)) import Control.Exception import Control.Monad import Data.Char -import qualified Data.Map as M -import qualified Data.Maybe as MA -import qualified Data.Set as S +import qualified Data.Map as M +import qualified Data.Maybe as MA +import qualified Data.Set as S import Dyna.Analysis.Aggregation import Dyna.Analysis.ANF import Dyna.Analysis.RuleMode import Dyna.Backend.Python import Dyna.Main.BackendDefn import Dyna.Main.Exception -import qualified Dyna.ParserHS.Parser as P +import qualified Dyna.ParserHS.Parser as P import System.Console.GetOpt import System.Environment import System.Exit import System.IO import Text.PrettyPrint.Free -import qualified Text.Trifecta as T +import qualified Text.PrettyPrint.ANSI.Leijen as PPA +import qualified Text.Trifecta as T +import qualified Text.Trifecta.Result as TR ------------------------------------------------------------------------}}} -- Dumping {{{ @@ -211,8 +213,8 @@ processFile fileName = bracket openOut hClose go parse = do pr <- T.parseFromFileEx (P.dlines <* T.eof) fileName case pr of - T.Failure td -> dynacUserErr $ align ("Parser error" `above` td) - T.Success rs -> return rs + TR.Failure td -> dynacUserANSIErr $ PPA.align ("Parser error" PPA.<$> td) + TR.Success rs -> return rs ------------------------------------------------------------------------}}} -- Main {{{ diff --git a/src/Dyna/Main/Exception.hs b/src/Dyna/Main/Exception.hs index a21b700..e9fee66 100644 --- a/src/Dyna/Main/Exception.hs +++ b/src/Dyna/Main/Exception.hs @@ -13,6 +13,7 @@ import Control.Exception import qualified Data.Typeable as DT import qualified System.Console.Terminfo.PrettyPrint as TP import qualified Text.PrettyPrint.Free as PP +import qualified Text.PrettyPrint.ANSI.Leijen as PPA ------------------------------------------------------------------------}}} -- Dyna Compiler Exceptions {{{ @@ -21,6 +22,9 @@ data DynacException = -- | The user program contains an error UserProgramError (PP.Doc TP.Effect) + -- | Same as 'UserProgramError' but with ANSI documentation + | UserProgramANSIError PPA.Doc + -- | Something went wrong when trying to understand arguments | InvocationError (PP.Doc TP.Effect) @@ -42,6 +46,9 @@ dynacUserErr = throw . UserProgramError dynacSorry = throw . Sorry dynacPanic = throw . Panic +dynacUserANSIErr :: PPA.Doc -> a +dynacUserANSIErr = throw . UserProgramANSIError + dynacThrow :: DynacException -> a dynacThrow = throw diff --git a/src/Dyna/ParserHS/Parser.hs b/src/Dyna/ParserHS/Parser.hs index d68b925..3734d53 100644 --- a/src/Dyna/ParserHS/Parser.hs +++ b/src/Dyna/ParserHS/Parser.hs @@ -47,6 +47,7 @@ import qualified Data.HashSet as H import Data.Semigroup ((<>)) import Data.Monoid (mempty) import Text.Parser.Expression +import Text.Parser.LookAhead import Text.Parser.Token.Highlight import Text.Parser.Token.Style import Text.Trifecta @@ -213,7 +214,8 @@ dynaCommentStyle = CommentStyle } newtype DynaLanguage m a = DL { unDL :: m a } - deriving (Functor,Applicative,Alternative,Monad,MonadPlus,Parsing,CharParsing) + deriving (Functor,Applicative,Alternative,Monad,MonadPlus, + Parsing,CharParsing,LookAheadParsing) instance MonadTrans DynaLanguage where lift = DL @@ -249,7 +251,8 @@ nullaryStar :: DeltaParsing m => m (Spanned Term) nullaryStar = spanned $ flip TFunctor [] <$> (bsf $ string "*") <* (notFollowedBy $ char '(') -term :: DeltaParsing m => m (Spanned Term) +term :: (DeltaParsing m, LookAheadParsing m) + => m (Spanned Term) term = token $ choice [ parens tfexpr , spanned $ TVar <$> (bsf $ ident dynaVarStyle) @@ -276,7 +279,8 @@ term = token $ choice -- | Sometimes we require that a character not be followed by whitespace -- and satisfy some additional predicate before we pass it off to some other parser. -thenAny :: (TokenParsing m, Monad m) => m a -> m Char +thenAny :: (Monad m, TokenParsing m, LookAheadParsing m) + => m a -> m Char thenAny p = anyChar -- some character <* lookAhead (notFollowedBy someSpace) -- not followed by space <* lookAhead p -- and not follwed by the request @@ -286,12 +290,14 @@ thenAny p = anyChar -- some character -- by itself as being counted as an operator; the dot operator is required -- to have not-a-space following (to avoid confusion with the end-of-rule -- marker, which is taken to be "dot space" or "dot eof"). -dotOper :: (Monad m, TokenParsing m) => m [Char] +dotOper :: (Monad m, TokenParsing m, LookAheadParsing m) + => m [Char] dotOper = try (lookAhead (thenAny anyChar) *> identNL dynaDotOperStyle) -- | A "comma operator" is a comma necessarily followed by something that -- would continue to be an operator (i.e. punctuation). -commaOper :: (Monad m, TokenParsing m) => m [Char] +commaOper :: (Monad m, TokenParsing m, LookAheadParsing m) + => m [Char] commaOper = try ( lookAhead (thenAny $ _styleLetter dynaCommaOperStyle) *> identNL dynaCommaOperStyle) @@ -316,7 +322,8 @@ bf f = do -- -- XXX timv suggests that this should be assocnone for binops as a quick -- fix. Eventually we should still do this properly. -termETable :: DeltaParsing m => [[Operator m (Spanned Term)]] +termETable :: (DeltaParsing m, LookAheadParsing m) + => [[Operator m (Spanned Term)]] termETable = [ [ Prefix $ uf (spanned $ bsf $ symbol "new") ] , [ Prefix $ uf (spanned $ bsf $ ident dynaPfxOperStyle) ] , [ Infix (bf (spanned $ bsf $ ident dynaOperStyle)) AssocLeft ] @@ -324,7 +331,8 @@ termETable = [ [ Prefix $ uf (spanned $ bsf $ symbol "new") ] , [ Infix (bf (spanned $ bsf $ commaOper)) AssocRight ] ] -tlexpr :: DeltaParsing m => m (Spanned Term) +tlexpr :: (DeltaParsing m, LookAheadParsing m) + => m (Spanned Term) tlexpr = buildExpressionParser termETable term "Limited Expression" fullETable :: DeltaParsing m => [[Operator m (Spanned Term)]] @@ -333,16 +341,17 @@ fullETable = [ [ Infix (bf (spanned $ bsf $ symbol "is" )) AssocNone ] , [ Infix (bf (spanned $ bsf $ symbol "whenever")) AssocNone ] ] -tfexpr :: DeltaParsing m => m (Spanned Term) +tfexpr :: (DeltaParsing m, LookAheadParsing m) => m (Spanned Term) tfexpr = buildExpressionParser fullETable tlexpr "Expression" -dterm :: DeltaParsing m => m (Spanned Term) +dterm :: (DeltaParsing m, LookAheadParsing m) => m (Spanned Term) dterm = unDL term ------------------------------------------------------------------------}}} -- Rules {{{ -parseRule :: (MonadState RuleIx m, DeltaParsing m) => m Rule +parseRule :: (MonadState RuleIx m, DeltaParsing m, LookAheadParsing m) + => m Rule parseRule = choice [ -- HEAD AGGR TFEXPR . try $ rule <*> term @@ -361,31 +370,31 @@ parseRule = choice [ ] <* optional (char '.') -drule :: (DeltaParsing m) => m (Spanned Rule) +drule :: (DeltaParsing m, LookAheadParsing m) => m (Spanned Rule) drule = evalStateT (unDL (spanned parseRule)) 0 ------------------------------------------------------------------------}}} -- Lines {{{ -dpragma :: DeltaParsing m => m (Spanned Term) +dpragma :: (DeltaParsing m, LookAheadParsing m) => m (Spanned Term) dpragma = symbol ":-" *> whiteSpace *> tlexpr <* whiteSpace <* optional (char '.') -progline :: (MonadState RuleIx m, DeltaParsing m) => m (Spanned Line) +progline :: (MonadState RuleIx m, DeltaParsing m, LookAheadParsing m) + => m (Spanned Line) progline = whiteSpace *> spanned (choice [ LRule <$> spanned parseRule , LPragma <$> dpragma ]) -dline :: (DeltaParsing m) => m (Spanned Line) +dline :: (DeltaParsing m, LookAheadParsing m) => m (Spanned Line) dline = evalStateT (unDL (progline <* optional whiteSpace)) 0 --- XXX This is not prepared for parser-altering pragmas. We will have to --- fix that. -dlines :: DeltaParsing m => m [Spanned Line] +-- XXX This is not prepared for parser-altering pragmas. +dlines :: (DeltaParsing m, LookAheadParsing m) => m [Spanned Line] dlines = evalStateT (unDL (many (progline <* optional whiteSpace))) 0 ------------------------------------------------------------------------}}} diff --git a/src/Dyna/ParserHS/Selftest.hs b/src/Dyna/ParserHS/Selftest.hs index c1f0121..8b431cb 100644 --- a/src/Dyna/ParserHS/Selftest.hs +++ b/src/Dyna/ParserHS/Selftest.hs @@ -143,7 +143,7 @@ case_colonFunctor = e @=? (term pvv) case_failIncompleteExpr :: Assertion case_failIncompleteExpr = checkParseFail dterm "foo +" - "(interactive):1:5: error: expected: \"(\",\n end of input\nfoo + " + "(interactive):1:5: error: expected: \"(\",\nend of input\nfoo + \n ^ " ------------------------------------------------------------------------}}} -- Annotations {{{ @@ -191,13 +191,15 @@ case_ruleSimple = e @=? (progline sr) sr = "goal += 1." -- XXX for some reason parser is fine with "1." but not "0." --- This is almost surely a bug upstream +-- This is almost surely a bug upstream; it's fixed in parsers +-- c707806109119e3f54c3064039a4ee2624f18ff1, but that isn't yet cut into a +-- release. +-- -- case_ruleSimple0 :: Assertion -- case_ruleSimple0 = e @=? (progline sr) -- where -- e = LRule (Rule 0 (TFunctor "goal" [] :~ Span (Columns 0 0) (Columns 5 5) sr) -- "+=" --- [] -- (_tNumeric (Left 0) :~ Span (Columns 8 8) (Columns 9 9) sr) -- :~ ts) -- :~ ts diff --git a/src/Dyna/REPL.hs b/src/Dyna/REPL.hs index 137c6d9..ffa3866 100644 --- a/src/Dyna/REPL.hs +++ b/src/Dyna/REPL.hs @@ -4,11 +4,14 @@ module Dyna.REPL where import Control.Applicative ((<*)) import Control.Monad.Trans (liftIO) import System.Console.Haskeline -import Text.PrettyPrint.Free -import Text.Trifecta +import System.IO +import System.Process +import qualified Text.PrettyPrint.ANSI.Leijen as PPA +import Text.Trifecta as T +import Text.Trifecta.Result as TR -import qualified Dyna.ParserHS.Parser as DP --- import qualified Dyna.NormalizeParse as DNP +import qualified Dyna.ParserHS.Parser as DP +-- import qualified Dyna.NormalizeParse as DNP import Dyna.XXX.Trifecta main :: IO () @@ -36,5 +39,5 @@ main = do loop failure td = do - liftIO $ displayLn td + liftIO $ PPA.hPutDoc stdout td loop diff --git a/src/Dyna/XXX/Trifecta.hs b/src/Dyna/XXX/Trifecta.hs index 2330913..bacbf2c 100644 --- a/src/Dyna/XXX/Trifecta.hs +++ b/src/Dyna/XXX/Trifecta.hs @@ -10,16 +10,16 @@ module Dyna.XXX.Trifecta ( import Control.Applicative import Control.Monad (when) import qualified Data.ByteString.UTF8 as BU -import Data.Char -import Data.List (foldl') import Data.Monoid (mempty) import Data.HashSet as HashSet (member) import qualified Data.Semigroup.Reducer as R +import qualified Data.Int as I import Text.Parser.Token.Highlight import Text.Trifecta import Text.Trifecta.Delta - +import Text.Trifecta.Result import qualified Text.PrettyPrint.Free as PP +import qualified Text.PrettyPrint.ANSI.Leijen as PPA -- import Debug.Trace @@ -46,55 +46,10 @@ identNL s = try $ do stringLiteralSQ :: TokenParsing m => m String stringLiteralSQ = token (highlight StringLiteral lit) where lit = Prelude.foldr (maybe id (:)) "" - <$> between (char '\'') (char '\'' "end of string") (many stringChar) + <$> between (char '\'') (char '\'' "end of string") (many $ Just <$> characterChar) "string" - stringChar = Just <$> stringLetter - <|> stringEscape - "string character" - stringLetter = satisfy (\c -> (c /= '\'') && (c /= '\\') && (c > '\026')) - -- XXX That is, charLetter - - stringEscape = highlight EscapeCode $ char '\\' *> esc where - esc = Nothing <$ escapeGap - <|> Nothing <$ escapeEmpty - <|> Just <$> escapeCode - escapeEmpty = char '&' - escapeGap = skipSome space *> (char '\\' "end of string gap") {-# INLINE stringLiteralSQ #-} --- XXX Duplicated from Text.Parser.Token -escapeCode :: TokenParsing m => m Char -escapeCode = (charEsc <|> charNum <|> charAscii <|> charControl) "escape code" - where - charControl = (\c -> toEnum (fromEnum c - fromEnum 'A')) <$> (char '^' *> upper) - charNum = toEnum . fromInteger <$> num where - num = decimal - <|> (char 'o' *> number 8 octDigit) - <|> (char 'x' *> number 16 hexDigit) - charEsc = choice $ parseEsc <$> escMap - parseEsc (c,code) = code <$ char c - escMap = zip ("abfnrtv\\\"\'") ("\a\b\f\n\r\t\v\\\"\'") - charAscii = choice $ parseAscii <$> asciiMap - parseAscii (asc,code) = try $ code <$ string asc - asciiMap = zip (ascii3codes ++ ascii2codes) (ascii3 ++ ascii2) - ascii2codes, ascii3codes :: [String] - ascii2codes = [ "BS","HT","LF","VT","FF","CR","SO" - , "SI","EM","FS","GS","RS","US","SP"] - ascii3codes = ["NUL","SOH","STX","ETX","EOT","ENQ","ACK" - ,"BEL","DLE","DC1","DC2","DC3","DC4","NAK" - ,"SYN","ETB","CAN","SUB","ESC","DEL"] - ascii2, ascii3 :: [Char] - ascii2 = ['\BS','\HT','\LF','\VT','\FF','\CR','\SO','\SI' - ,'\EM','\FS','\GS','\RS','\US','\SP'] - ascii3 = ['\NUL','\SOH','\STX','\ETX','\EOT','\ENQ','\ACK' - ,'\BEL','\DLE','\DC1','\DC2','\DC3','\DC4','\NAK' - ,'\SYN','\ETB','\CAN','\SUB','\ESC','\DEL'] - --- XXX Duplicated from Text.Parser.Token -number :: TokenParsing m => Integer -> m Char -> m Integer -number base baseDigit = - foldl' (\x d -> base*x + toInteger (digitToInt d)) 0 <$> some baseDigit - ------------------------------------------------------------------------}}} -- pureSpanned {{{ @@ -115,7 +70,7 @@ triInteract :: (Monad m, Show a) => (Parser a) -- ^ Parser -> (m (Maybe String)) -- ^ Continuation callback -> (a -> m b) -- ^ Success callback - -> (TermDoc -> m b) -- ^ Failure callback + -> (PPA.Doc -> m b) -- ^ Failure callback -> String -- ^ Initial input -> m b triInteract p c s f i = loop (feed (BU.fromString i) $ stepParser (release dd *> p) dd mempty) @@ -138,6 +93,24 @@ triInteract p c s f i = loop (feed (BU.fromString i) $ stepParser (release dd *> -- results in the lie of "(interactive)". In any case, this function is -- here as a placeholder for doing the right thing. prettySpanLoc :: Span -> PP.Doc e -prettySpanLoc (Span s e l) = PP.pretty s PP.<> PP.char '-' PP.<> PP.pretty e +prettySpanLoc (Span s e _) = doPretty s PP.<> PP.char '-' PP.<> doPretty e + where + -- This is pretty from the Pretty Delta instance of Text.Trifecta.Delta + -- stripped of its ANSI commands so that it works with + -- Text.PrettyPrint.Free. Le sigh! XXX + doPretty d = case d of + Columns c _ -> k f 0 c + Tab x y _ -> k f 0 (nextTab x + y) + Lines l c _ _ -> k f l c + Directed fn l c _ _ -> k fn l c + where + k :: BU.ByteString -> I.Int64 -> I.Int64 -> PP.Doc e + k fn ln cn = PP.pretty fn + PP.<> PP.char ':' + PP.<> PP.pretty (ln+1) + PP.<> PP.char ':' + PP.<> PP.pretty (cn+1) + f :: BU.ByteString + f = "(interactive)" ------------------------------------------------------------------------}}} diff --git a/src/Dyna/XXX/TrifectaTest.hs b/src/Dyna/XXX/TrifectaTest.hs index 38f863f..d2da3c4 100644 --- a/src/Dyna/XXX/TrifectaTest.hs +++ b/src/Dyna/XXX/TrifectaTest.hs @@ -7,6 +7,8 @@ import Data.ByteString (ByteString) import Data.Monoid (mempty) import Test.HUnit import Text.Trifecta +import Text.Trifecta.Result +import qualified Text.PrettyPrint.ANSI.Leijen as PPA unsafeFS :: Result t -> t unsafeFS (Success a) = a @@ -14,7 +16,15 @@ unsafeFS (Failure td) = error $ "Errors: " ++ show td unsafeFF :: String -> Result t -> Assertion unsafeFF _ (Success _) = error $ "Unexpected success" -unsafeFF e (Failure td) = e @=? show td +unsafeFF e (Failure td) = e @=? flip PPA.displayS "" + (filterSD $ PPA.renderCompact td) + where + -- strip out any ANSI BS + filterSD PPA.SEmpty = PPA.SEmpty + filterSD (PPA.SChar c x) = PPA.SChar c (filterSD x) + filterSD (PPA.SText i s x) = PPA.SText i s (filterSD x) + filterSD (PPA.SLine i x) = PPA.SLine i (filterSD x) + filterSD (PPA.SSGR _ x) = filterSD x unsafeParse :: (Show a) => (Parser a) -> ByteString -> a unsafeParse p = unsafeFS . parseByteString (p <* eof) mempty