Skip to content

Commit

Permalink
✨ separator combinator
Browse files Browse the repository at this point in the history
  • Loading branch information
nabeelvalley committed Jul 19, 2024
1 parent bcbd571 commit 9a762f7
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 27 deletions.
35 changes: 26 additions & 9 deletions src/parz/combinators.gleam
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import gleam/list
import gleam/string
import parz/types.{type Parser, type ParserState, ParserState}
import parz/util.{tap}
Expand Down Expand Up @@ -82,15 +83,6 @@ pub fn between(l: Parser(a), keep: Parser(b), r: Parser(c)) -> Parser(b) {
}
}

pub fn maybe(parser) {
fn(input) {
case parser(input) {
Ok(ok) -> Ok(ok)
Error(_) -> Ok(ParserState("", input))
}
}
}

fn many_rec(
parser: Parser(a),
input,
Expand Down Expand Up @@ -143,3 +135,28 @@ pub fn map(parser: Parser(a), transform) {
}
}
}

pub fn as_list(parser: Parser(a)) {
fn(input) {
case parser(input) {
Error(err) -> Error(err)
Ok(ok) -> Ok(ParserState([ok.matched], ok.remaining))
}
}
}

pub fn separator1(parser: Parser(a), sep: Parser(_)) {
choice([
sequence([as_list(parser), many(right(sep, parser))]) |> map(list.concat),
as_list(parser),
])
}

pub fn separator(parser: Parser(a), sep: Parser(_)) {
fn(input) {
case separator1(parser, sep)(input) {
Error(_) -> Ok(ParserState([], input))
Ok(ok) -> Ok(ok)
}
}
}
70 changes: 52 additions & 18 deletions test/combinators_test.gleam
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import gleeunit/should
import parz.{run}
import parz/combinators.{
between, choice, concat_str, label_error, left, many, many1, map, maybe, right,
sequence,
as_list, between, choice, concat_str, label_error, left, many, many1, map,
right, separator, separator1, sequence,
}
import parz/parsers.{letters, str}
import parz/types.{ParserState}
Expand Down Expand Up @@ -147,22 +147,6 @@ pub fn concat_str_test() {
|> should.be_error
}

pub fn maybe_test() {
let parser = maybe(str("x"))

run(parser, "x")
|> should.be_ok
|> should.equal(ParserState("x", ""))

run(parser, "!")
|> should.be_ok
|> should.equal(ParserState("", "!"))

run(parser, "")
|> should.be_ok
|> should.equal(ParserState("", ""))
}

pub fn label_error_test() {
let message = "Expected [letters]"
let parser =
Expand Down Expand Up @@ -204,3 +188,53 @@ pub fn map_test() {
run(parser, "[hellox")
|> should.be_error
}

pub fn as_list_test() {
let parser = as_list(str("x"))

run(parser, "x")
|> should.be_ok
|> should.equal(ParserState(["x"], ""))

run(parser, "x!")
|> should.be_ok
|> should.equal(ParserState(["x"], "!"))

run(parser, "xx")
|> should.be_ok
|> should.equal(ParserState(["x"], "x"))

run(parser, "[hellox")
|> should.be_error
}

pub fn separator_test() {
let parser = separator(letters(), str(";"))

run(parser, "well;hello;world")
|> should.be_ok
|> should.equal(ParserState(["well", "hello", "world"], ""))

run(parser, "hello!")
|> should.be_ok
|> should.equal(ParserState(["hello"], "!"))

run(parser, "!")
|> should.be_ok
|> should.equal(ParserState([], "!"))
}

pub fn separator1_test() {
let parser = separator1(letters(), str(";"))

run(parser, "well;hello;world")
|> should.be_ok
|> should.equal(ParserState(["well", "hello", "world"], ""))

run(parser, "hello!")
|> should.be_ok
|> should.equal(ParserState(["hello"], "!"))

run(parser, "!")
|> should.be_error
}

0 comments on commit 9a762f7

Please sign in to comment.