symparsec 1.0.0 → 1.0.1
raw patch · 12 files changed
+443/−79 lines, 12 files
Files
- CHANGELOG.md +4/−0
- README.md +39/−47
- src/Symparsec/Internal/List.hs +0/−9
- src/Symparsec/Parser.hs +0/−5
- src/Symparsec/Parser/Common.hs +3/−1
- src/Symparsec/Parser/End.hs +17/−9
- src/Symparsec/Parser/Or.hs +330/−0
- src/Symparsec/Parser/Skip.hs +1/−1
- src/Symparsec/Parser/Take.hs +5/−5
- src/Symparsec/Parser/TakeRest.hs +39/−0
- src/Symparsec/Parsers.hs +2/−0
- symparsec.cabal +3/−2
CHANGELOG.md view
@@ -1,3 +1,7 @@+## 1.0.1 (2024-05-27)+* add `TakeRest` combinator+* re-add `:<|>:` combinator with more accurate behaviour clarification+ ## 1.0.0 (2024-05-25) * small rewrite, changing how `Done` works (now non-consuming) * single all parsers
README.md view
@@ -1,80 +1,72 @@ # Symparsec-Type level string (`Symbol`) parser combinators. Reify to runtime parsers with-guaranteed identical behaviour.+[hackage-parsec]: https://hackage.haskell.org/package/parsec -It's a Parsec-like for `Symbol`s; thus, Symparsec.+Type level string (`Symbol`) parser combinators. A [Parsec][hackage-parsec]-like+for `Symbol`s; thus, Symparsec! With all the features you'd expect: -Previously named symbol-parser.+* define parsers compositionally, largely as you would on the term level+* pretty, detailed parse errors+* decent performance (for simple parsers) -Requires GHC 9.6 for singling parsers.+Parsers may also be reified and used at runtime with _guaranteed identical+behaviour_ via a healthy dose of singletons. -## Features-* Define parsers compositionally, largely as you would on the term level.-* Pretty parse errors.-* Hopefully decent performance.-* Reify parsers to term level with guaranteed identical behaviour via a- healthy dose of singletons.+Requires GHC >= 9.6. ## Examples+Define a type-level parser:+ ```haskell-ghci> import Symparsec-ghci> :k! Run (Drop 3 :*>: Isolate 2 NatDec :<*>: (Drop 3 :*>: NatHex)) "___10___FF"-...-= Right '( '(10, 255), "")+import Symparsec+type PExample = Skip 1 :*>: Isolate 2 NatHex :<*>: (Literal "_" :*>: TakeRest) ``` +Use it to parse a type-level string (in a GHCi session):++```haskell+ghci> :k! Run PExample "xFF_"+Run ...+= Right '( '(255, "etc"), "")+```++Use it to parse a different, term-level string:++```haskell+ghci> import Singleraeh.Demote ( demote )+ghci> run' @PExample demote "abc_123"+Right ((188,"123"),"")+```+ ## Why? Via `GHC.Generics`, we may inspect Haskell data types on the type level. Constructor names are `Symbols`. Ever reify these, then perform some sort of checking or parsing on the term level? Symparsec does the parsing on the type level instead. Catch bugs earlier, get faster runtime. +Also type-level Haskell authors deserve fun libraries too!!+ ## Design ### The parser-A parser is a 4-tuple of:+A parser is a 3-tuple of: -* a consuming character parser; given a character and a state, returns+* a character parser; given a character and a state, returns * `Cont s`: keep going, here's the next state `s`- * `Done r`: parse successful with value `r`+ * `Done r`: parse successful with value `r`, _do not consume character_ * `Err E`: parse error, details in the `E` (a structured error) * an end handler, which takes only a state, and can only return `Done` or `Err`-* an initial "raw" state-* a state initializer, which turns the initial "raw" state into the first state- value (the indirection here assists singling)+* an initial state -Running a parser is simple:+Running such a parser is very simple: * initialize state * parse character by character until end of input, or `Done`/`Err` Parsers may not communicate with the runner any other way. This means no backtracking, chunking etc. This is a conscious decision, made for simplicity.--Note that due to character parsers being consuming, we often need to do a bit of-"internal lookahead", where we check if we expect to consume any more-characters, and if not then emit a `Done`. It also means that non-consuming-parsers such as `Take 0` are invalid for non-empty strings. The state-initializer should be used to catch such cases.--This is a rough overview of parser design. See the code and/or Haddock-documentation for precise details.--### Pitfall: Character parsers always consume-There is no backtracking or lookahead, that you do not implement yourself. This-keeps the parser execution extremely simple, but breaks null parsers such as-`Drop 0`, so these must be handled specially (unless you don't getting mind-stuck type families on misuse).--For concrete examples, see the implementation of `Drop` and `Literal`.--### Pitfall: Not all parsers are definable-* No changing parser state. Thus, parsers such as `Try :: Parser s r -> Parser- (s, [Char]) r` are not definable. _Parsers may not backtrack._- * Combinators such as `<|>` can emulate backtracking, but they are complex and- hard to reason about (they may have bugs!).+We're still able to implement a good handful of parser combinators regardless,+including a limited form of backtracking. -### Feature: Parsers may be reified to use at runtime, with guaranteed same behaviour-TODO+This is a rough overview. See the code & Haddocks for precise details. ## Contributing I would gladly accept further combinators or other suggestions. Please add an
− src/Symparsec/Internal/List.hs
@@ -1,9 +0,0 @@-{-# LANGUAGE UndecidableInstances #-}--module Symparsec.Internal.List where---- | Reverse a type level list.-type Reverse as = Reverse' as '[]-type family Reverse' (as :: [k]) (acc :: [k]) :: [k] where- Reverse' '[] acc = acc- Reverse' (a : as) acc = Reverse' as (a : acc)
src/Symparsec/Parser.hs view
@@ -77,11 +77,6 @@ -> SParser ss sr ('PParser pCh pEnd s0) -- | Parse a 'Char' with the given state.------ The action is always consuming. For this reason, you may need to look ahead--- for the final case, so as to not consume an extra 'Char'. This prevents many--- zero-length parsers. It's a bit weird. See--- 'Data.Type.Symbol.Parser.Parser.Drop' for an example. type ParserCh str s r = Char -> s -> Result str s r type PParserCh s r = ParserCh Symbol s r
src/Symparsec/Parser/Common.hs view
@@ -20,13 +20,15 @@ import Singleraeh.Either -- | Fail with the given message when given any character to parse.+type FailCh name e = Err (EBase name e)+ type FailChSym :: Symbol -> PDoc -> ParserChSym s r data FailChSym name e f type instance App (FailChSym name e) f = FailChSym1 name e f type FailChSym1 :: Symbol -> PDoc -> ParserChSym1 s r data FailChSym1 name e ch s-type instance App (FailChSym1 name e ch) s = Err (EBase name e)+type instance App (FailChSym1 name e ch) s = FailCh name e failChSym :: SSymbol name -> SDoc e -> SParserChSym ss sr (FailChSym name e)
src/Symparsec/Parser/End.hs view
@@ -1,24 +1,32 @@ module Symparsec.Parser.End where import Symparsec.Parser.Common-import DeFun.Core ( Con1, con1 )+import DeFun.Core import Singleraeh.Tuple ( SUnit(..) ) import Singleraeh.Either ( SEither(..) )-import GHC.TypeLits ( symbolSing )-import TypeLevelShow.Doc ( singDoc ) -- | Assert end of symbol, or fail. type End :: PParser () ()-type End = 'PParser- (FailChSym "End" (Text "expected end of string"))- (Con1 Right)- '()+type End = 'PParser EndChSym (Con1 Right) '() sEnd :: SParser SUnit SUnit End-sEnd = SParser (failChSym symbolSing singDoc) (con1 SRight) SUnit+sEnd = SParser sEndChSym (con1 SRight) SUnit --- TODO orphan instance. if I need to, make some dumb type family idk. instance SingParser End where type PS End = SUnit type PR End = SUnit singParser' = sEnd++-- it'd be nice to just reuse FailChSym here but we get told off for writing an+-- orphan instance. fair enough, write this instead+type EndChSym :: ParserChSym s r+data EndChSym f+type instance App EndChSym f = EndChSym1 f++type EndChSym1 :: ParserChSym1 s r+data EndChSym1 ch s+type instance App (EndChSym1 ch) s =+ Err (EBase "End" (Text "expected end of string"))++sEndChSym :: SParserChSym ss rr EndChSym+sEndChSym = Lam2 $ \_ch _s -> SErr singE
+ src/Symparsec/Parser/Or.hs view
@@ -0,0 +1,330 @@+{-# LANGUAGE UndecidableInstances #-}++module Symparsec.Parser.Or where++import Symparsec.Parser+import TypeLevelShow.Doc+import GHC.TypeLits hiding ( ErrorMessage(..) )+import DeFun.Core+import Singleraeh.Tuple+import Singleraeh.Either+import Singleraeh.List++{- | Limited parser choice. Try left; if it fails, backtrack and try right.+ However, _the right choice must consume at least as much as the left+ choice._ If it doesn't, then even if the right parser succeeds, it+ will emit an error.++This behaviour is due to the parser runner not supporting backtracking. We can+emulate it by storing a record of the characters parsed so far, and "replaying"+these on the right parser if the left parser fails. If the right parser ends+before we finish replaying, we will have consumed extra characters that we can't+ask the runner to revert.++For example, @Literal "abcd" :<|>: Literal "ab"@ is bad. An input of @abcX@ will+trigger the consumption error.++I can't think of another way to implement this with the current parser design. I+think it's the best we have. A more complex parser design may permit changing+internal running state, so we could save and load state (this would permit a+@Try p@ parser). But that's scary. And you're better off designing your+type-level string schemas to permit non-backtracking parsing anyway...++Also problematic is that we never emit a left parser error, so errors can+degrade. Perhaps your string was one character off a successful left parse; but+if it fails, you won't see that error.+-}+infixl 3 :<|>:+type (:<|>:)+ :: PParser sl rl+ -> PParser sr rr+ -> PParser (OrS sl sr) (Either rl rr)+type family pl :<|>: pr where+ 'PParser plCh plEnd s0l :<|>: 'PParser prCh prEnd s0r =+ Or' plCh plEnd s0l prCh prEnd s0r++type Or' plCh plEnd s0l prCh prEnd s0r = 'PParser+ (OrChSym plCh prCh s0r)+ (OrEndSym plEnd prCh prEnd s0r)+ (Left '(s0l, '[]))++type SOrS ssl ssr = SEither (STuple2 ssl (SList SChar)) ssr+type OrS sl sr = Either (sl, [Char]) sr+type SPOr ssl srl ssr srr plCh plEnd s0l prCh prEnd s0r =+ SParser (SOrS ssl ssr) (SEither srl srr) (Or' plCh plEnd s0l prCh prEnd s0r)++sOr+ :: SParser ssl srl ('PParser plCh plEnd s0l)+ -> SParser ssr srr ('PParser prCh prEnd s0r)+ -> SPOr ssl srl ssr srr plCh plEnd s0l prCh prEnd s0r+sOr (SParser plCh plEnd s0l) (SParser prCh prEnd s0r) = SParser+ (sOrChSym plCh prCh s0r)+ (sOrEndSym plEnd prCh prEnd s0r)+ (SLeft (STuple2 s0l SNil))++instance+ ( pl ~ 'PParser plCh plEnd s0l+ , pr ~ 'PParser prCh prEnd s0r+ , SingParser pl+ , SingParser pr+ ) => SingParser (Or' plCh plEnd s0l prCh prEnd s0r) where+ type PS (Or' plCh plEnd s0l prCh prEnd s0r) = SOrS+ (PS ('PParser plCh plEnd s0l))+ (PS ('PParser prCh prEnd s0r))+ type PR (Or' plCh plEnd s0l prCh prEnd s0r) = SEither+ (PR ('PParser plCh plEnd s0l))+ (PR ('PParser prCh prEnd s0r))+ singParser' = sOr (singParser @pl) (singParser @pr)++type OrCh+ :: ParserChSym sl rl+ -> ParserChSym sr rr+ -> sr+ -> PParserCh (OrS sl sr) (Either rl rr)+type family OrCh plCh prCh sr ch s where+ -- | parsing left+ OrCh plCh prCh s0r ch (Left '(sl, chs)) =+ OrChL prCh s0r ch chs (plCh @@ ch @@ sl)++ -- | parsing right (after left failed and was successfully replayed)+ OrCh plCh prCh _ ch (Right sr) =+ OrChR (prCh @@ ch @@ sr)++type OrChL+ :: ParserChSym sr rr+ -> sr+ -> Char+ -> [Char]+ -> PResult sl rl+ -> PResult (Either (sl, [Char]) sr) (Either rl rr)+type family OrChL prCh s0r chLast chs resl where+ -- | left parser OK, continue+ OrChL _ _ chLast chs (Cont sl) = Cont (Left '(sl, chLast : chs))++ -- | left parser OK, done+ OrChL _ _ _ _ (Done rl) = Done (Left rl)++ -- | left parser failed: ignore, replay consumed characters on right parser+ OrChL prCh s0r chLast chs (Err _ ) =+ OrChLReplay prCh chLast (Reverse chs) (Cont s0r)++type OrChLReplay+ :: ParserChSym sr rr+ -> Char+ -> [Char]+ -> PResult sr rr+ -> PResult (Either (sl, [Char]) sr) (Either rl rr)+type family OrChLReplay prCh chLast chs resr where+ -- | right parser OK, keep replaying+ OrChLReplay prCh chLast (ch : chs) (Cont sr) =+ OrChLReplay prCh chLast chs (prCh @@ ch @@ sr)+ --+ -- | right parser OK, final replay char+ OrChLReplay prCh chLast '[] (Cont sr) = OrChR (prCh @@ chLast @@ sr)++ -- | right parser fail: wrap error+ OrChLReplay prCh chLast chs (Err er) = Err (EOrR er)++ -- | right parser done but still replaying! no choice but to error out+ OrChLReplay prCh chLast chs (Done rr) = Err EOrStillReplaying+ -- Done (Right rr) -- TODO++sOrChLReplay+ :: SParserChSym ssr srr prCh+ -> SChar chLast+ -> SList SChar chs+ -> SResult ssr srr resr+ -> SResult (SOrS ssl ssr) (SEither srl srr)+ (OrChLReplay prCh chLast chs resr)+sOrChLReplay prCh chLast chs resr =+ case chs of+ SCons ch chs' ->+ case resr of+ SCont sr ->+ sOrChLReplay prCh chLast chs' (prCh @@ ch @@ sr)+ SDone _rr -> SErr eOrStillReplaying+ SErr er -> SErr $ eOrR er+ SNil ->+ case resr of+ SCont sr -> sOrChR (prCh @@ chLast @@ sr)+ SDone _rr -> SErr eOrStillReplaying+ SErr er -> SErr $ eOrR er++type EOrR er = EIn "Or(R)" er+eOrR :: SE er -> SE (EOrR er)+eOrR er = SEIn symbolSing er++type EOrStillReplaying = EBase "Or"+ (Text "right parser much consume at least as much as the failed left parser")+eOrStillReplaying :: SE EOrStillReplaying+eOrStillReplaying = singE++type family OrChR resr where+ OrChR (Cont sr) = Cont (Right sr)+ OrChR (Done rr) = Done (Right rr)+ OrChR (Err er) = Err (EOrR er)++sOrChR+ :: SResult ssr srr resr+ -> SResult (SOrS ssl ssr) (SEither srl srr) (OrChR resr)+sOrChR = \case+ SCont sr -> SCont $ SRight sr+ SDone rr -> SDone $ SRight rr+ SErr er -> SErr $ eOrR er++type OrEnd+ :: ParserEndSym sl rl+ -> ParserChSym sr rr+ -> ParserEndSym sr rr+ -> sr+ -> PParserEnd (Either (sl, [Char]) sr) (Either rl rr)+type family OrEnd plEnd prCh prEnd sr res where+ -- | input ended during left parser+ OrEnd plEnd prCh prEnd s0r (Left '(sl, chs)) =+ OrEndL prCh prEnd s0r chs (plEnd @@ sl)++ -- | input ended during right parser: call right end+ OrEnd plEnd prCh prEnd _ (Right sr) = OrEndR (prEnd @@ sr)++type OrEndR :: PResultEnd rr -> PResultEnd (Either rl rr)+type family OrEndR resr where+ OrEndR (Right rr) = Right (Right rr)+ OrEndR (Left er) = Left (EOrR er)++sOrEndR+ :: SResultEnd srr resr+ -> SResultEnd (SEither srl srr) (OrEndR resr)+sOrEndR = \case+ SRight rr -> SRight $ SRight rr+ SLeft er -> SLeft $ eOrR er++type OrEndL+ :: ParserChSym sr rr+ -> ParserEndSym sr rr+ -> sr+ -> [Char]+ -> Either PE rl+ -> Either PE (Either rl rr)+type family OrEndL prCh prEnd s0r chs resl where+ -- | input ended during left parser and left end succeeeded: phew+ OrEndL prCh prEnd s0r chs (Right rl) = Right (Left rl)++ -- | input ended during left parser and left end failed. replay on right,+ -- then eventually call right end+ OrEndL prCh prEnd s0r chs (Left el) =+ OrEndLReplay prCh prEnd (Reverse chs) (Cont s0r)++sOrEndL+ :: SParserChSym ssr srr prCh+ -> SParserEndSym ssr srr prEnd+ -> ssr s0r+ -> SList SChar chs+ -> SResultEnd srl resl+ -> SResultEnd (SEither srl srr) (OrEndL prCh prEnd s0r chs resl)+sOrEndL prCh prEnd s0r chs = \case+ SRight rl -> SRight $ SLeft rl+ SLeft _el -> sOrEndLReplay prCh prEnd (sReverse chs) (SCont s0r)++type OrEndLReplay+ :: ParserChSym sr rr+ -> ParserEndSym sr rr+ -> [Char]+ -> PResult sr rr+ -> Either PE (Either rl rr)+type family OrEndLReplay prCh prEnd chs resr where+ -- | right parser OK, keep replaying+ OrEndLReplay prCh prEnd (ch : chs) (Cont sr) =+ OrEndLReplay prCh prEnd chs (prCh @@ ch @@ sr)++ -- | replay complete+ OrEndLReplay prCh prEnd '[] resr = OrEndLReplay' prEnd resr++ -- | right parser fail: wrap error+ OrEndLReplay prCh prEnd chs (Err er) = Left (EOrR er)++ -- | right parser done but still replaying! no choice but to error out+ OrEndLReplay prCh prEnd chs (Done rr) = Left EOrStillReplaying+ -- Right (Right rr) TODO++sOrEndLReplay+ :: SParserChSym ssr srr prCh+ -> SParserEndSym ssr srr prEnd+ -> SList SChar chs+ -> SResult ssr srr resr+ -> SResultEnd (SEither srl srr) (OrEndLReplay prCh prEnd chs resr)+sOrEndLReplay prCh prEnd chs resr =+ case chs of+ SCons ch chs' ->+ case resr of+ SCont sr ->+ sOrEndLReplay prCh prEnd chs' (prCh @@ ch @@ sr)+ SErr er -> SLeft $ eOrR er+ SDone _rr -> SLeft eOrStillReplaying+ SNil ->+ case resr of+ SCont sr -> sOrEndR $ prEnd @@ sr+ SDone rr -> SRight $ SRight rr+ SErr er -> SLeft $ eOrR er++type family OrEndLReplay' prEnd resr where+ OrEndLReplay' prEnd (Cont sr) = OrEndR (prEnd @@ sr)+ OrEndLReplay' prEnd (Done rr) = Right (Right rr)+ OrEndLReplay' prEnd (Err er) = Left (EOrR er)++type OrChSym+ :: ParserChSym sl rl+ -> ParserChSym sr rr+ -> sr+ -> ParserChSym (OrS sl sr) (Either rl rr)+data OrChSym plCh prCh s0r f+type instance App (OrChSym plCh prCh s0r) f = OrChSym1 plCh prCh s0r f++type OrChSym1+ :: ParserChSym sl rl+ -> ParserChSym sr rr+ -> sr+ -> ParserChSym1 (OrS sl sr) (Either rl rr)+data OrChSym1 plCh prCh sr ch s+type instance App (OrChSym1 plCh prCh sr ch) s = OrCh plCh prCh sr ch s++sOrChSym+ :: SParserChSym ssl srl plCh+ -> SParserChSym ssr srr prCh+ -> ssr s0r+ -> SParserChSym (SOrS ssl ssr) (SEither srl srr) (OrChSym plCh prCh s0r)+sOrChSym plCh prCh s0r = Lam2 $ \ch -> \case+ SLeft (STuple2 sl chs) -> sOrChL prCh s0r ch chs (plCh @@ ch @@ sl)+ SRight sr -> sOrChR (prCh @@ ch @@ sr)++sOrChL+ :: SParserChSym ssr srr prCh+ -> ssr s0r+ -> SChar chLast+ -> SList SChar chs+ -> SResult ssl srl resl+ -> SResult (SOrS ssl ssr) (SEither srl srr) (OrChL prCh s0r chLast chs resl)+sOrChL prCh s0r chLast chs = \case+ SCont sl -> SCont $ SLeft $ STuple2 sl $ SCons chLast chs+ SDone rl -> SDone $ SLeft rl+ SErr _el -> sOrChLReplay prCh chLast (sReverse chs) (SCont s0r)++type OrEndSym+ :: ParserEndSym sl rl+ -> ParserChSym sr rr+ -> ParserEndSym sr rr+ -> sr+ -> ParserEndSym (Either (sl, [Char]) sr) (Either rl rr)+data OrEndSym plEnd prCh prEnd s0r s+type instance App (OrEndSym plEnd prCh prEnd s0r) s =+ OrEnd plEnd prCh prEnd s0r s++sOrEndSym+ :: SParserEndSym ssl srl plEnd+ -> SParserChSym ssr srr prCh+ -> SParserEndSym ssr srr prEnd+ -> ssr s0r+ -> SParserEndSym (SOrS ssl ssr) (SEither srl srr)+ (OrEndSym plEnd prCh prEnd s0r)+sOrEndSym plEnd prCh prEnd s0r = Lam $ \case+ SLeft (STuple2 sl chs) -> sOrEndL prCh prEnd s0r chs (plEnd @@ sl)+ SRight sr -> sOrEndR $ prEnd @@ sr
src/Symparsec/Parser/Skip.hs view
@@ -50,7 +50,7 @@ SkipEnd n = Left (ESkipPastEnd n) type ESkipPastEnd n = EBase "Skip"- ( Text "tried to drop "+ ( Text "tried to skip " :<>: Text (ShowNatDec n) :<>: Text " chars from empty string") eSkipPastEnd :: SNat n -> SE (ESkipPastEnd n) eSkipPastEnd n = withKnownSymbol (sShowNatDec n) singE
src/Symparsec/Parser/Take.hs view
@@ -21,7 +21,7 @@ type TakeS = (Natural, [Char]) sTake :: SNat n -> SParser STakeS SSymbol (Take n)-sTake n = SParser takeChSym takeEndSym (STuple2 n SNil)+sTake n = SParser sTakeChSym sTakeEndSym (STuple2 n SNil) instance KnownNat n => SingParser (Take n) where type PS (Take n) = STakeS@@ -37,8 +37,8 @@ data TakeChSym f type instance App TakeChSym f = TakeChSym1 f -takeChSym :: SParserChSym STakeS SSymbol TakeChSym-takeChSym = Lam2 $ \ch (STuple2 n chs) ->+sTakeChSym :: SParserChSym STakeS SSymbol TakeChSym+sTakeChSym = Lam2 $ \ch (STuple2 n chs) -> case testEquality n (SNat @0) of Just Refl -> SDone $ revCharsToSymbol chs Nothing ->@@ -64,8 +64,8 @@ data TakeEndSym s type instance App TakeEndSym s = TakeEnd s -takeEndSym :: SParserEndSym STakeS SSymbol TakeEndSym-takeEndSym = Lam $ \(STuple2 n chs) ->+sTakeEndSym :: SParserEndSym STakeS SSymbol TakeEndSym+sTakeEndSym = Lam $ \(STuple2 n chs) -> case testEquality n (SNat @0) of Just Refl -> SRight $ revCharsToSymbol chs Nothing -> unsafeCoerce $ SLeft $ eTakeEnd n
+ src/Symparsec/Parser/TakeRest.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE UndecidableInstances #-}++module Symparsec.Parser.TakeRest where++import Symparsec.Parser.Common+import Singleraeh.Symbol ( RevCharsToSymbol, revCharsToSymbol )+import Singleraeh.List ( SList(..) )+import Singleraeh.Either ( SEither(..) )+import GHC.TypeLits hiding ( ErrorMessage(..) )+import DeFun.Core++-- | Return the remaining input string.+type TakeRest = 'PParser TakeRestChSym TakeRestEndSym '[]++sTakeRest :: SParser (SList SChar) SSymbol TakeRest+sTakeRest = SParser sTakeRestChSym sTakeRestEndSym SNil++instance SingParser TakeRest where+ type PS TakeRest = SList SChar+ type PR TakeRest = SSymbol+ singParser' = sTakeRest++type TakeRestChSym :: ParserChSym [Char] Symbol+data TakeRestChSym f+type instance App TakeRestChSym f = TakeRestChSym1 f++type TakeRestChSym1 :: ParserChSym1 [Char] Symbol+data TakeRestChSym1 ch chs+type instance App (TakeRestChSym1 ch) chs = Cont (ch : chs)++sTakeRestChSym :: SParserChSym (SList SChar) SSymbol TakeRestChSym+sTakeRestChSym = Lam2 $ \ch chs -> SCont $ SCons ch chs++type TakeRestEndSym :: ParserEndSym [Char] Symbol+data TakeRestEndSym chs+type instance App TakeRestEndSym chs = Right (RevCharsToSymbol chs)++sTakeRestEndSym :: SParserEndSym (SList SChar) SSymbol TakeRestEndSym+sTakeRestEndSym = Lam $ \chs -> SRight $ revCharsToSymbol chs
src/Symparsec/Parsers.hs view
@@ -15,6 +15,7 @@ -- * Positional -- $positional , Take+ , TakeRest , Skip , End , Isolate@@ -40,6 +41,7 @@ import Symparsec.Parser.Literal import Symparsec.Parser.End import Symparsec.Parser.Take+import Symparsec.Parser.TakeRest --import Symparsec.Parser.Or -- $binary-combinators
symparsec.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: symparsec-version: 1.0.0+version: 1.0.1 synopsis: Type level string parser combinators description: Please see README.md. category: Types, Data@@ -30,7 +30,6 @@ library exposed-modules: Symparsec- Symparsec.Internal.List Symparsec.Parser Symparsec.Parser.Common Symparsec.Parser.End@@ -38,8 +37,10 @@ Symparsec.Parser.Literal Symparsec.Parser.Natural Symparsec.Parser.Natural.Digits+ Symparsec.Parser.Or Symparsec.Parser.Skip Symparsec.Parser.Take+ Symparsec.Parser.TakeRest Symparsec.Parser.Then Symparsec.Parser.Then.VoidLeft Symparsec.Parser.Then.VoidRight