Refactor ALL the things!
This commit is contained in:
parent
6a2f10df0c
commit
f2def8fa05
28 changed files with 930 additions and 855 deletions
145
src/parsers/many.c
Normal file
145
src/parsers/many.c
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
#include "parser_internal.h"
|
||||
|
||||
// TODO: split this up.
|
||||
typedef struct {
|
||||
const HParser *p, *sep;
|
||||
size_t count;
|
||||
bool min_p;
|
||||
} HRepeat;
|
||||
|
||||
static HParseResult *parse_many(void* env, HParseState *state) {
|
||||
HRepeat *env_ = (HRepeat*) env;
|
||||
HCountedArray *seq = h_carray_new_sized(state->arena, (env_->count > 0 ? env_->count : 4));
|
||||
size_t count = 0;
|
||||
HInputStream bak;
|
||||
while (env_->min_p || env_->count > count) {
|
||||
bak = state->input_stream;
|
||||
if (count > 0) {
|
||||
HParseResult *sep = h_do_parse(env_->sep, state);
|
||||
if (!sep)
|
||||
goto err0;
|
||||
}
|
||||
HParseResult *elem = h_do_parse(env_->p, state);
|
||||
if (!elem)
|
||||
goto err0;
|
||||
if (elem->ast)
|
||||
h_carray_append(seq, (void*)elem->ast);
|
||||
count++;
|
||||
}
|
||||
if (count < env_->count)
|
||||
goto err;
|
||||
succ:
|
||||
; // necessary for the label to be here...
|
||||
HParsedToken *res = a_new(HParsedToken, 1);
|
||||
res->token_type = TT_SEQUENCE;
|
||||
res->seq = seq;
|
||||
return make_result(state, res);
|
||||
err0:
|
||||
if (count >= env_->count) {
|
||||
state->input_stream = bak;
|
||||
goto succ;
|
||||
}
|
||||
err:
|
||||
state->input_stream = bak;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const HParserVtable many_vt = {
|
||||
.parse = parse_many,
|
||||
};
|
||||
|
||||
const HParser* h_many(const HParser* p) {
|
||||
HParser *res = g_new(HParser, 1);
|
||||
HRepeat *env = g_new(HRepeat, 1);
|
||||
env->p = p;
|
||||
env->sep = h_epsilon_p();
|
||||
env->count = 0;
|
||||
env->min_p = true;
|
||||
res->vtable = &many_vt;
|
||||
res->env = env;
|
||||
return res;
|
||||
}
|
||||
|
||||
const HParser* h_many1(const HParser* p) {
|
||||
HParser *res = g_new(HParser, 1);
|
||||
HRepeat *env = g_new(HRepeat, 1);
|
||||
env->p = p;
|
||||
env->sep = h_epsilon_p();
|
||||
env->count = 1;
|
||||
env->min_p = true;
|
||||
res->vtable = &many_vt;
|
||||
res->env = env;
|
||||
return res;
|
||||
}
|
||||
|
||||
const HParser* h_repeat_n(const HParser* p, const size_t n) {
|
||||
HParser *res = g_new(HParser, 1);
|
||||
HRepeat *env = g_new(HRepeat, 1);
|
||||
env->p = p;
|
||||
env->sep = h_epsilon_p();
|
||||
env->count = n;
|
||||
env->min_p = false;
|
||||
res->vtable = &many_vt;
|
||||
res->env = env;
|
||||
return res;
|
||||
}
|
||||
|
||||
const HParser* h_sepBy(const HParser* p, const HParser* sep) {
|
||||
HParser *res = g_new(HParser, 1);
|
||||
HRepeat *env = g_new(HRepeat, 1);
|
||||
env->p = p;
|
||||
env->sep = sep;
|
||||
env->count = 0;
|
||||
env->min_p = true;
|
||||
res->vtable = &many_vt;
|
||||
res->env = env;
|
||||
return res;
|
||||
}
|
||||
|
||||
const HParser* h_sepBy1(const HParser* p, const HParser* sep) {
|
||||
HParser *res = g_new(HParser, 1);
|
||||
HRepeat *env = g_new(HRepeat, 1);
|
||||
env->p = p;
|
||||
env->sep = sep;
|
||||
env->count = 1;
|
||||
env->min_p = true;
|
||||
res->vtable = &many_vt;
|
||||
res->env = env;
|
||||
return res;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const HParser *length;
|
||||
const HParser *value;
|
||||
} HLenVal;
|
||||
|
||||
static HParseResult* parse_length_value(void *env, HParseState *state) {
|
||||
HLenVal *lv = (HLenVal*)env;
|
||||
HParseResult *len = h_do_parse(lv->length, state);
|
||||
if (!len)
|
||||
return NULL;
|
||||
if (len->ast->token_type != TT_UINT)
|
||||
errx(1, "Length parser must return an unsigned integer");
|
||||
// TODO: allocate this using public functions
|
||||
HRepeat repeat = {
|
||||
.p = lv->value,
|
||||
.sep = h_epsilon_p(),
|
||||
.count = len->ast->uint,
|
||||
.min_p = false
|
||||
};
|
||||
return parse_many(&repeat, state);
|
||||
}
|
||||
|
||||
static const HParserVtable length_value_vt = {
|
||||
.parse = parse_length_value,
|
||||
};
|
||||
|
||||
const HParser* h_length_value(const HParser* length, const HParser* value) {
|
||||
HParser *res = g_new(HParser, 1);
|
||||
res->vtable = &length_value_vt;
|
||||
HLenVal *env = g_new(HLenVal, 1);
|
||||
env->length = length;
|
||||
env->value = value;
|
||||
res->env = (void*)env;
|
||||
return res;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue