diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f43dd63..9ef55c2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,6 +17,6 @@ jobs: gleam-version: "1.0.0" rebar3-version: "3" # elixir-version: "1.15.4" - - run: gleam format --check src test + - run: gleam format --check - run: gleam deps download - run: gleam test diff --git a/src/party.gleam b/src/party.gleam index 5295a08..62f6645 100644 --- a/src/party.gleam +++ b/src/party.gleam @@ -8,9 +8,9 @@ import gleam/result import gleam/string -/// The custom error type for the parser, +/// The custom error type for the parser, /// which can itself be parameterized by a user-defined error type. -/// The user-defined error type is useful for, for example, +/// The user-defined error type is useful for, for example, /// adding a `int.parse` call into your parser pipeline. /// See `try` for using this feature. pub type ParseError(e) { @@ -23,7 +23,7 @@ pub type Position { Position(row: Int, col: Int) } -/// The parser type, parameterized by the type it parses and +/// The parser type, parameterized by the type it parses and /// the user-defined error type it can return. pub opaque type Parser(a, e) { Parser( @@ -221,6 +221,20 @@ pub fn seq(p: Parser(a, e), q: Parser(b, e)) -> Parser(b, e) { q } +/// A version of `seq` for pleasant interplay with gleam's `use` syntax. +/// example: +/// ``` +/// fn pair() -> Parser(#(String, String), e) { +/// use a <- do(alphanum()) +/// use <- drop(char(",")) +/// use b <- do(alphanum()) +/// return(#(a, b)) +/// } +/// ``` +pub fn drop(p: Parser(a, e), f: fn() -> Parser(b, e)) -> Parser(b, e) { + seq(p, lazy(f)) +} + /// Parse a sequence separated by the given separator parser. pub fn sep(parser: Parser(a, e), by s: Parser(b, e)) -> Parser(List(a), e) { use res <- do(perhaps(sep1(parser, by: s))) @@ -249,7 +263,7 @@ pub fn map(p: Parser(a, e), f: fn(a) -> b) -> Parser(b, e) { } /// Do `p`, the apply `f` to the result if it succeeded. -/// `f` itself can fail with the user-defined error type, +/// `f` itself can fail with the user-defined error type, /// and if it does the result is a `UserError` with the error. pub fn try(p: Parser(a, e), f: fn(a) -> Result(b, e)) -> Parser(b, e) { Parser(fn(source, pos) { @@ -264,7 +278,7 @@ pub fn try(p: Parser(a, e), f: fn(a) -> Result(b, e)) -> Parser(b, e) { }) } -/// Transform the user-defined error type +/// Transform the user-defined error type /// with a user-provided conversion function. pub fn error_map(p: Parser(a, e), f: fn(e) -> f) -> Parser(a, f) { Parser(fn(source, pos) { @@ -348,7 +362,7 @@ pub fn lazy(p: fn() -> Parser(a, e)) -> Parser(a, e) { } /// A monadic bind for pleasant interplay with gleam's `use` syntax. -/// example: +/// example: /// ``` /// fn identifier() -> Parser(String, e) { /// use pos <- do(pos()) diff --git a/test/party_test.gleam b/test/party_test.gleam index 4ba0a94..aa9e4c9 100644 --- a/test/party_test.gleam +++ b/test/party_test.gleam @@ -318,6 +318,16 @@ pub fn do_return_test() { |> should.equal(Ok("aa")) } +pub fn do_drop_return_test() { + { + use a <- party.do(party.char("a")) + use <- party.drop(party.char("*")) + party.return(a <> a) + } + |> party.go("a*") + |> should.equal(Ok("aa")) +} + pub fn fail_test() { party.go(party.fail(), "a") |> should.equal(Error(party.Unexpected(party.Position(1, 1), "a")))