Skip to content

Commit

Permalink
Improve documentation: copy over from Parsley (#48)
Browse files Browse the repository at this point in the history
Closes #39 

I've copied over the docs from
[parsley](https://www.javadoc.io/doc/com.github.j-mie6/parsley_2.13/latest/index.html).
I've tried to make sure to adapt it to Haskell properly.
I haven't copied over examples because my HLS was getting upset if I
tried to run examples in comments.

Some modules used to re-export the entire module; I have documented
using explicit exports to make it look nicer, but also re-exported the
module to avoid breaking API -- this will produce warnings for duplicate
exports.
  • Loading branch information
j-mie6 authored Oct 28, 2024
2 parents 39b1ce3 + bd36a7c commit 6ab86b1
Show file tree
Hide file tree
Showing 26 changed files with 3,371 additions and 478 deletions.
2 changes: 1 addition & 1 deletion src/Text/Gigaparsec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ License : BSD-3-Clause
Maintainer : Jamie Willis, Gigaparsec Maintainers
Stability : stable
This object contains the core combinators and parser type: all parsers will require something from
This module contains the core combinators and parser type: all parsers will require something from
within!
@since 0.1.0.0
Expand Down
61 changes: 46 additions & 15 deletions src/Text/Gigaparsec/Combinator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ optionalAs x p = p $> x <|> pure x

-- TODO: collect
{-|
This combinator can eliminate an @Maybe@ from the result of the parser @p@.
This combinator can eliminate a @Maybe@ from the result of the parser @p@.
First parse @p@, if it succeeds returning @Just x@, then return @x@. However,
if @p@ fails, or returned @Nothing@, then this combinator fails.
Expand Down Expand Up @@ -331,7 +331,9 @@ This combinator repeatedly parses a given parser __one__ or more times, returnin
Parses a given parser, @p@, repeatedly until it fails. If @p@ failed having consumed input,
this combinator fails. Otherwise when @p@ fails __without consuming input__, this combinator
will succeed. The parser @p@ must succeed at least once. The number of times @p@ succeeded is returned as the result.
will succeed. The number of times @p@ succeeded is returned as the result.
The parser @p@ must succeed at least once.
==== __Examples__
>>> let p = count1 (string "ab")
Expand All @@ -353,7 +355,7 @@ count1 = somel (flip (const (+ 1))) 0
{-|
This combinator parses __zero__ or more occurrences of @p@, separated by @sep@.
Behaves just like @sepBy1@, except does not require an initial @p@, returning the empty list instead.
Behaves just like 'sepBy1', except does not require an initial @p@, returning the empty list instead.
==== __Examples__
>>> ...
Expand All @@ -379,8 +381,9 @@ This combinator parses __one__ or more occurrences of @p@, separated by @sep@.
First parses a @p@. Then parses @sep@ followed by @p@ until there are no more @sep@s.
The results of the @p@'s, @x1@ through @xn@, are returned as @[x1, .., xn]@.
If @p@ or @sep@ fails having consumed input, the whole parser fails. Requires at least
one @p@ to have been parsed.
If @p@ or @sep@ fails having consumed input, the whole parser fails.
Requires at least one @p@ to have been parsed.
==== __Examples__
>>> ...
Expand All @@ -404,7 +407,7 @@ sepBy1 p sep = p <:> many (sep *> p)
{-|
This combinator parses __zero__ or more occurrences of @p@, separated and optionally ended by @sep@.
Behaves just like @sepEndBy1@, except does not require an initial @p@, returning the empty list instead.
Behaves just like 'sepEndBy1', except does not require an initial @p@, returning the empty list instead.
==== __Examples__
>>> ...
Expand All @@ -430,8 +433,9 @@ This combinator parses __one__ or more occurrences of @p@, separated and optiona
First parses a @p@. Then parses @sep@ followed by @p@ until there are no more: if a final @sep@ exists, this is parsed.
The results of the @p@'s, @x1@ through @xn@, are returned as @[x1, .., xn]@.
If @p@ or @sep@ fails having consumed input, the whole parser fails. Requires at least
one @p@ to have been parsed.
If @p@ or @sep@ fails having consumed input, the whole parser fails.
Requires at least one @p@ to have been parsed.
==== __Examples__
>>> ...
Expand All @@ -455,7 +459,7 @@ sepEndBy1 p sep = let seb1 = p <:> (sep *> (seb1 <|> pure []) <|> pure []) in se
{-|
This combinator parses __zero__ or more occurrences of @p@, separated and ended by @sep@.
Behaves just like @endBy1@, except does not require an initial @p@ and @sep@, returning the empty list instead.
Behaves just like 'endBy1', except does not require an initial @p@ and @sep@, returning the empty list instead.
==== __Examples__
>>> ...
Expand Down Expand Up @@ -483,6 +487,8 @@ Parses @p@ followed by @sep@ one or more times.
The results of the @p@'s, @x1@ through @xn@, are returned as @[x1, .., xn]@.
If @p@ or @sep@ fails having consumed input, the whole parser fails.
Requires at least one @p@ to have been parsed.
==== __Examples__
>>> ...
>>> let args = endBy1 int (string ";\n")
Expand Down Expand Up @@ -530,10 +536,11 @@ manyTill p end = let go = end $> [] <|> p <:> go in go
{-|
This combinator repeatedly parses a given parser __one__ or more times, until the @end@ parser succeeds, collecting the results into a list.
First ensures that trying to parse @end@ fails, then tries to parse @p@. If it succeed then it will repeatedly: try to parse @end@, if it fails
First ensures that trying to parse @end@ fails, then tries to parse @p@. If it succeeds then it will repeatedly: try to parse @end@, if it fails
__without consuming input__, then parses @p@, which must succeed. When @end@ does succeed, this combinator will return all of the results
generated by @p@, @x1@ through @xn@ (with @n >= 1@), in a list: @[x1, .., xn]@. The parser @p@ must succeed at least once
before @end@ succeeds.
generated by @p@, @x1@ through @xn@ (with @n >= 1@), in a list: @[x1, .., xn]@.
The parser @p@ must succeed at least once before @end@ succeeds.
==== __Examples__
This can be useful for scanning comments:
Expand All @@ -550,15 +557,39 @@ Success ['a']
@since 0.1.0.0
-}
someTill :: Parsec a -- ^ @p@, the parser to execute multiple times.
someTill :: Parsec a -- ^ @p@, the parser to execute multiple times, at least once.
-> Parsec end -- ^ @end@, the parser that stops the parsing of @p@.
-> Parsec [a] -- ^ a parser that parses @p@ until @end@ succeeds, returning the list of all the successful results.
someTill p end = notFollowedBy end *> (p <:> manyTill p end)

skipManyTill :: Parsec a -> Parsec end -> Parsec ()
{-|
This combinator repeatedly parses a given parser __zero__ or more times, until the @end@ parser succeeds, discarding any results from @p@.
Behaves like 'manyTill', except the results of parsing @p@ are ignored.
First tries to parse @end@, if it fails __without consuming input__, then parses @p@, which must succeed. This repeats until @end@ succeeds.
When @end@ does succeed (even of the first try), this combinator will discard any results generated by @p@.
-}
skipManyTill :: Parsec a -- ^ @p@, the parser to execute multiple times
-> Parsec end -- ^ @end@, the parser that stops the parsing of @p@
-> Parsec () -- ^ a parser that parses @p@ until @end@ succeeds, returning unit.
skipManyTill p end = void (manyTill p end)

skipSomeTill :: Parsec a -> Parsec end -> Parsec ()
{-|
This combinator repeatedly parses a given parser __one__ or more times, until the @end@ parser succeeds, discarding any results from @p@, and returns unit.
Behaves like 'someTill', except the results of parsing @p@ are ignored.
First ensures that trying to parse @end@ fails, then tries to parse @p@. If it succeeds then it will repeatedly: try to parse @end@, if it fails
__without consuming input__, then parses @p@, which must succeed.
When @end@ does succeed, this combinator will discard any results generated by @p@, returning unit.
The parser @p@ must succeed at least once before @end@ succeeds.
-}
skipSomeTill :: Parsec a -- ^ @p@, the parser to execute multiple times, at least once.
-> Parsec end -- ^ @end@, the parser that stops the parsing of @p@.
-> Parsec () -- ^ a parser that parses @p@ until @end@ succeeds, returning unit.
skipSomeTill p end = void (someTill p end)

-- this is ifP
Expand Down
89 changes: 84 additions & 5 deletions src/Text/Gigaparsec/Combinator/NonEmpty.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
{-# LANGUAGE Safe #-}
{-|
Module : Text.Gigaparsec.Combinator.NonEmpty
Description : This module contains variants of combinators that return non-empty lists of results, modifying the result type to 'NonEmpty'.
License : BSD-3-Clause
Maintainer : Jamie Willis, Gigaparsec Maintainers
Stability : stable
This module contains variants of combinators that return non-empty lists of results, modifying the result type to 'NonEmpty'.
These allow for stronger guarantees of parsed results to be baked into their types.
@since 0.3.0.0
-}
module Text.Gigaparsec.Combinator.NonEmpty (some, someTill, sepBy1, sepEndBy1, endBy1) where

import Text.Gigaparsec (Parsec, liftA2, many, notFollowedBy)
Expand All @@ -16,17 +28,84 @@ infixl 4 <<|>
(<<|>) = liftA2 (<|)
-}

some :: Parsec a -> Parsec (NonEmpty a)
{-|
This combinator repeatedly parses a given parser __one__ or more times, collecting the results into a non-empty list.
Parses a given parser, @p@, repeatedly until it fails. If @p@ failed having consumed input,
this combinator fails.
Otherwise, when @p@ fails __without consuming input__, this combinator
will return all of the results, @x₁@ through @xₙ@ (with @n ≥ 1@), in a non-empty list: @x₁ :| [x₂, .., xₙ]@.
Requires at least one @p@ to have been parsed.
@since 0.3.0.0
-}
some :: Parsec a -- ^ the parser @p@ to execute multiple times
-> Parsec (NonEmpty a) -- ^ a parser that parses @p@ until it fails, returning a non-empty list of the successful results.
some p = p <:|> many p

someTill :: Parsec a -> Parsec end -> Parsec (NonEmpty a)
{-|
This combinator repeatedly parses a given parser __one__ or more times, until the @end@ parser succeeds, collecting the results into a non-empty list.
First ensures that trying to parse @end@ fails, then tries to parse @p@. If it succeeds then it will repeatedly: try to parse @end@, if it fails
__without consuming input__, then parses @p@, which must succeed.
When @end@ does succeed, this combinator will return all of the results
generated by @p@, @x₁@ through @xₙ@ (with @n ≥ 1@), in a non-empty list: @x₁ :| [x₂, .., xₙ]@.
The parser @p@ must succeed at least once before @end@ succeeds.
@since 0.3.0.0
-}
someTill :: Parsec a -- ^ @p@, the parser to execute multiple times, at least once.
-> Parsec end -- ^ @end@, the parser that stops the parsing of @p@.
-> Parsec (NonEmpty a) -- ^ a parser that parses @p@ until @end@ succeeds, returning the non-empty list of all the successful results.
someTill p end = notFollowedBy end *> (p <:|> Combinator.manyTill p end)

sepBy1 :: Parsec a -> Parsec sep -> Parsec (NonEmpty a)
{-|
This combinator parses __one__ or more occurrences of @p@, separated by @sep@.
First parses a @p@. Then parses @sep@ followed by @p@ until there are no more @sep@s.
The results of the @p@'s, @x₁@ through @xₙ@, are returned as @x₁ :| [x₂, .., xₙ]@.
If @p@ or @sep@ fails having consumed input, the whole parser fails.
Requires at least one @p@ to have been parsed.
@since 0.3.0.0
-}
sepBy1 :: Parsec a -- ^ @p@, the parser whose results are collected into a non-empty list.
-> Parsec sep -- ^ @sep@, the delimiter that must be parsed between every @p@.
-> Parsec (NonEmpty a) -- ^ a parser that parses @p@ delimited by @sep@, returning the non-empty list of @p@'s results.
sepBy1 p sep = p <:|> many (sep *> p)

endBy1 :: Parsec a -> Parsec sep -> Parsec (NonEmpty a)
{-|
This combinator parses __one__ or more occurrences of @p@, separated and ended by @sep@.
Parses @p@ followed by @sep@ one or more times.
The results of the @p@'s, @x₁@ through @xₙ@, are returned as @x₁ :| [x₂, .., xₙ]@.
If @p@ or @sep@ fails having consumed input, the whole parser fails.
Requires at least one @p@ to have been parsed.
@since 0.3.0.0
-}
endBy1 :: Parsec a -- ^ @p@, the parser whose results are collected into a non-empty list.
-> Parsec sep -- ^ @sep@, the delimiter that must be parsed between every @p@.
-> Parsec (NonEmpty a) -- ^ a parser that parses @p@ delimited by @sep@, returning the non-empty list of @p@'s results.
endBy1 p sep = some (p <* sep)

sepEndBy1 :: Parsec a -> Parsec sep -> Parsec (NonEmpty a)
{-|
This combinator parses __one__ or more occurrences of @p@, separated and optionally ended by @sep@,
collecting the results in a non-empty list.
First parses a @p@. Then parses @sep@ followed by @p@ until there are no more: if a final @sep@ exists, this is parsed.
The results of the @p@'s, @x₁@ through @xₙ@, are returned as @x₁ :| [x₂, .., xₙ]@.
If @p@ or @sep@ fails having consumed input, the whole parser fails.
Requires at least one @p@ to have been parsed.
@since 0.3.0.0
-}
sepEndBy1 :: Parsec a -- ^ @p@, the parser whose results are collected into a list.
-> Parsec sep -- ^ @sep@, the delimiter that must be parsed between every @p@.
-> Parsec (NonEmpty a) -- ^ a parser that parses @p@ delimited by @sep@, returning the non-empty list of @p@'s results.
sepEndBy1 p sep = NonEmpty.fromList <$> Combinator.sepEndBy1 p sep
Loading

0 comments on commit 6ab86b1

Please sign in to comment.