add h_left, h_right, h_middle combinators
This commit is contained in:
parent
6d755efbde
commit
7724ff9e6f
4 changed files with 132 additions and 0 deletions
|
|
@ -4,6 +4,7 @@ PARSERS := \
|
|||
bits \
|
||||
token \
|
||||
whitespace \
|
||||
ignoreseq \
|
||||
ch \
|
||||
action \
|
||||
charset \
|
||||
|
|
|
|||
34
src/hammer.c
34
src/hammer.c
|
|
@ -380,6 +380,37 @@ static void test_whitespace(void) {
|
|||
g_check_parse_failed(whitespace_, "_a", 2);
|
||||
}
|
||||
|
||||
static void test_left(void) {
|
||||
const HParser *left_ = h_left(h_ch('a'), h_ch(' '));
|
||||
|
||||
g_check_parse_ok(left_, "a ", 2, "u0x61");
|
||||
g_check_parse_failed(left_, "a", 1);
|
||||
g_check_parse_failed(left_, " ", 1);
|
||||
g_check_parse_failed(left_, "ab", 2);
|
||||
}
|
||||
|
||||
static void test_right(void) {
|
||||
const HParser *right_ = h_right(h_ch(' '), h_ch('a'));
|
||||
|
||||
g_check_parse_ok(right_, " a", 2, "u0x61");
|
||||
g_check_parse_failed(right_, "a", 1);
|
||||
g_check_parse_failed(right_, " ", 1);
|
||||
g_check_parse_failed(right_, "ba", 2);
|
||||
}
|
||||
|
||||
static void test_middle(void) {
|
||||
const HParser *middle_ = h_middle(h_ch(' '), h_ch('a'), h_ch(' '));
|
||||
|
||||
g_check_parse_ok(middle_, " a ", 3, "u0x61");
|
||||
g_check_parse_failed(middle_, "a", 1);
|
||||
g_check_parse_failed(middle_, " ", 1);
|
||||
g_check_parse_failed(middle_, " a", 2);
|
||||
g_check_parse_failed(middle_, "a ", 2);
|
||||
g_check_parse_failed(middle_, " b ", 3);
|
||||
g_check_parse_failed(middle_, "ba ", 3);
|
||||
g_check_parse_failed(middle_, " ab", 3);
|
||||
}
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
const HParsedToken* upcase(const HParseResult *p) {
|
||||
|
|
@ -600,6 +631,9 @@ void register_parser_tests(void) {
|
|||
g_test_add_func("/core/parser/float32", test_float32);
|
||||
#endif
|
||||
g_test_add_func("/core/parser/whitespace", test_whitespace);
|
||||
g_test_add_func("/core/parser/left", test_left);
|
||||
g_test_add_func("/core/parser/right", test_right);
|
||||
g_test_add_func("/core/parser/middle", test_middle);
|
||||
g_test_add_func("/core/parser/action", test_action);
|
||||
g_test_add_func("/core/parser/not_in", test_not_in);
|
||||
g_test_add_func("/core/parser/end_p", test_end_p);
|
||||
|
|
|
|||
24
src/hammer.h
24
src/hammer.h
|
|
@ -216,6 +216,30 @@ const HParser* h_uint8();
|
|||
*/
|
||||
const HParser* h_whitespace(const HParser* p);
|
||||
|
||||
/**
|
||||
* Given two parsers, p and q, returns a parser that parses them in
|
||||
* sequence but only returns p's result.
|
||||
*
|
||||
* Result token type: p's result type
|
||||
*/
|
||||
const HParser* h_left(const HParser* p, const HParser* q);
|
||||
|
||||
/**
|
||||
* Given two parsers, p and q, returns a parser that parses them in
|
||||
* sequence but only returns q's result.
|
||||
*
|
||||
* Result token type: q's result type
|
||||
*/
|
||||
const HParser* h_right(const HParser* p, const HParser* q);
|
||||
|
||||
/**
|
||||
* Given three parsers, p, x, and q, returns a parser that parses them in
|
||||
* sequence but only returns x's result.
|
||||
*
|
||||
* Result token type: x's result type
|
||||
*/
|
||||
const HParser* h_middle(const HParser* p, const HParser* x, const HParser* q);
|
||||
|
||||
/**
|
||||
* Given another parser, p, and a function f, returns a parser that
|
||||
* applies p, then applies f to everything in the AST of p's result.
|
||||
|
|
|
|||
73
src/parsers/ignoreseq.c
Normal file
73
src/parsers/ignoreseq.c
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#include "parser_internal.h"
|
||||
|
||||
|
||||
//
|
||||
// general case: parse sequence, pick one result
|
||||
//
|
||||
|
||||
typedef struct {
|
||||
const HParser **parsers;
|
||||
size_t count; // how many parsers in 'ps'
|
||||
size_t which; // whose result to return
|
||||
} HIgnoreSeq;
|
||||
|
||||
static HParseResult* parse_ignoreseq(void* env, HParseState *state) {
|
||||
const HIgnoreSeq *seq = (HIgnoreSeq*)env;
|
||||
HParseResult *res = NULL;
|
||||
|
||||
for (size_t i=0; i < seq->count; ++i) {
|
||||
HParseResult *tmp = h_do_parse(seq->parsers[i], state);
|
||||
if (!tmp)
|
||||
return NULL;
|
||||
else if (i == seq->which)
|
||||
res = tmp;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static const HParserVtable ignoreseq_vt = {
|
||||
.parse = parse_ignoreseq,
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// API frontends
|
||||
//
|
||||
|
||||
static const HParser* h_leftright(const HParser* p, const HParser* q, size_t which) {
|
||||
HIgnoreSeq *seq = g_new(HIgnoreSeq, 1);
|
||||
seq->parsers = g_new(const HParser*, 2);
|
||||
seq->parsers[0] = p;
|
||||
seq->parsers[1] = q;
|
||||
seq->count = 2;
|
||||
seq->which = which;
|
||||
|
||||
HParser *ret = g_new(HParser, 1);
|
||||
ret->vtable = &ignoreseq_vt;
|
||||
ret->env = (void*)seq;
|
||||
return ret;
|
||||
}
|
||||
|
||||
const HParser* h_left(const HParser* p, const HParser* q) {
|
||||
return h_leftright(p, q, 0);
|
||||
}
|
||||
|
||||
const HParser* h_right(const HParser* p, const HParser* q) {
|
||||
return h_leftright(p, q, 1);
|
||||
}
|
||||
|
||||
const HParser* h_middle(const HParser* p, const HParser* x, const HParser* q) {
|
||||
HIgnoreSeq *seq = g_new(HIgnoreSeq, 1);
|
||||
seq->parsers = g_new(const HParser*, 3);
|
||||
seq->parsers[0] = p;
|
||||
seq->parsers[1] = x;
|
||||
seq->parsers[2] = q;
|
||||
seq->count = 3;
|
||||
seq->which = 1;
|
||||
|
||||
HParser *ret = g_new(HParser, 1);
|
||||
ret->vtable = &ignoreseq_vt;
|
||||
ret->env = (void*)seq;
|
||||
return ret;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue