From c24e27f0b8b995bd67d9c3b91fdeae077e2b771c Mon Sep 17 00:00:00 2001 From: steve-chavez Date: Tue, 8 Aug 2023 14:15:55 -0500 Subject: [PATCH] feat: add sepby1 combinator `sepby1` is a common reusable combinator in Haskell Parsec. This adds `mpc_sepby1(mpc_fold_t f, mpc_parser_t *sep, mpc_parser_t *a)` according to Haskell's implementation: https://hackage.haskell.org/package/parsec-3.1.16.1/docs/src/Text.Parsec.Combinator.html#sepBy1 Reuses existing `mpc_and`, `mpc_many`, and `mpcf_snd_free`. --- README.md | 8 ++++++++ mpc.c | 6 ++++++ mpc.h | 2 ++ tests/core.c | 13 +++++++++++++ 4 files changed, 29 insertions(+) diff --git a/README.md b/README.md index 6ccc3ef..824aaa2 100644 --- a/README.md +++ b/README.md @@ -356,6 +356,14 @@ Runs `a` one or more times until it fails. Results are combined with fold functi * * * +```c +mpc_parser_t *mpc_sepby1(mpc_fold_t f, mpc_parser_t *sep, mpc_parser_t *a); +``` + +Runs `a` one or more times, separated by `sep`. Results are combined with fold function `f`. + +* * * + ```c mpc_parser_t *mpc_count(int n, mpc_fold_t f, mpc_parser_t *a, mpc_dtor_t da); ``` diff --git a/mpc.c b/mpc.c index c545557..fc560bf 100644 --- a/mpc.c +++ b/mpc.c @@ -2120,6 +2120,12 @@ mpc_parser_t *mpc_tok_braces(mpc_parser_t *a, mpc_dtor_t ad) { return mpc_tok_ mpc_parser_t *mpc_tok_brackets(mpc_parser_t *a, mpc_dtor_t ad) { return mpc_tok_between(a, ad, "{", "}"); } mpc_parser_t *mpc_tok_squares(mpc_parser_t *a, mpc_dtor_t ad) { return mpc_tok_between(a, ad, "[", "]"); } +mpc_parser_t *mpc_sepby1(mpc_fold_t f, mpc_parser_t *sep, mpc_parser_t *a) { + return mpc_and(2, f, + a, mpc_many(f, mpc_and(2, mpcf_snd_free, sep, mpc_copy(a), free)), + free); +} + /* ** Regular Expression Parsers */ diff --git a/mpc.h b/mpc.h index 545b35e..49a08ee 100644 --- a/mpc.h +++ b/mpc.h @@ -220,6 +220,8 @@ mpc_parser_t *mpc_tok_braces(mpc_parser_t *a, mpc_dtor_t ad); mpc_parser_t *mpc_tok_brackets(mpc_parser_t *a, mpc_dtor_t ad); mpc_parser_t *mpc_tok_squares(mpc_parser_t *a, mpc_dtor_t ad); +mpc_parser_t *mpc_sepby1(mpc_fold_t f, mpc_parser_t *sep, mpc_parser_t *a); + /* ** Common Function Parameters */ diff --git a/tests/core.c b/tests/core.c index 52463e1..35e1411 100644 --- a/tests/core.c +++ b/tests/core.c @@ -242,6 +242,18 @@ void test_eoi(void) { } +void test_sepby(void) { + mpc_parser_t* CommaSepIdent = mpc_sepby1(mpcf_strfold, mpc_char(','), mpc_ident()); + + PT_ASSERT(mpc_test_fail(CommaSepIdent, "", "", streq, free, strprint)); + PT_ASSERT(mpc_test_pass(CommaSepIdent, "one", "one", streq, free, strprint)); + PT_ASSERT(mpc_test_pass(CommaSepIdent, "one,", "one", streq, free, strprint)); + PT_ASSERT(mpc_test_pass(CommaSepIdent, "one,two,", "onetwo", streq, free, strprint)); + PT_ASSERT(mpc_test_pass(CommaSepIdent, "one,two,three", "onetwothree", streq, free, strprint)); + + mpc_delete(CommaSepIdent); +} + void suite_core(void) { pt_add_test(test_ident, "Test Ident", "Suite Core"); pt_add_test(test_maths, "Test Maths", "Suite Core"); @@ -251,4 +263,5 @@ void suite_core(void) { pt_add_test(test_reader, "Test Reader", "Suite Core"); pt_add_test(test_tokens, "Test Tokens", "Suite Core"); pt_add_test(test_eoi, "Test EOI", "Suite Core"); + pt_add_test(test_sepby, "Test SepBy", "Suite Core"); }