pass a temporary arena allocator to the continuation in h_bind
This commit is contained in:
parent
7ba5931095
commit
1ce0ef9b8a
3 changed files with 51 additions and 10 deletions
|
|
@ -159,8 +159,13 @@ typedef bool (*HPredicate)(HParseResult *p, void* user_data);
|
||||||
* Type of a parser that depends on the result of a previous parser,
|
* Type of a parser that depends on the result of a previous parser,
|
||||||
* used in h_bind(). The void* argument is passed through from h_bind() and can
|
* used in h_bind(). The void* argument is passed through from h_bind() and can
|
||||||
* be used to arbitrarily parameterize the function further.
|
* be used to arbitrarily parameterize the function further.
|
||||||
|
*
|
||||||
|
* The HAllocator* argument gives access to temporary memory and is to be used
|
||||||
|
* for any allocations inside the function. Specifically, construction of any
|
||||||
|
* HParsers should use the '__m' combinator variants with the given allocator.
|
||||||
|
* Anything allocated thus will be freed by 'h_bind'.
|
||||||
*/
|
*/
|
||||||
typedef HParser* (*HContinuation)(const HParsedToken *x, void *env);
|
typedef HParser* (*HContinuation)(HAllocator *mm__, const HParsedToken *x, void *env);
|
||||||
|
|
||||||
// {{{ Stuff for benchmarking
|
// {{{ Stuff for benchmarking
|
||||||
typedef struct HParserTestcase_ {
|
typedef struct HParserTestcase_ {
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,34 @@ typedef struct {
|
||||||
const HParser *p;
|
const HParser *p;
|
||||||
HContinuation k;
|
HContinuation k;
|
||||||
void *env;
|
void *env;
|
||||||
|
HAllocator *mm__;
|
||||||
} BindEnv;
|
} BindEnv;
|
||||||
|
|
||||||
|
// an HAllocator backed by an HArena
|
||||||
|
typedef struct {
|
||||||
|
HAllocator allocator; // inherit XXX is this the proper way to do it?
|
||||||
|
HArena *arena;
|
||||||
|
} ArenaAllocator;
|
||||||
|
|
||||||
|
void *aa_alloc(HAllocator *allocator, size_t size)
|
||||||
|
{
|
||||||
|
HArena *arena = ((ArenaAllocator *)allocator)->arena;
|
||||||
|
return h_arena_malloc(arena, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *aa_realloc(HAllocator *allocator, void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
HArena *arena = ((ArenaAllocator *)allocator)->arena;
|
||||||
|
assert(0); // XXX realloc for arena allocator
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void aa_free(HAllocator *allocator, void *ptr)
|
||||||
|
{
|
||||||
|
HArena *arena = ((ArenaAllocator *)allocator)->arena;
|
||||||
|
h_arena_free(arena, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
static HParseResult *parse_bind(void *be_, HParseState *state) {
|
static HParseResult *parse_bind(void *be_, HParseState *state) {
|
||||||
BindEnv *be = be_;
|
BindEnv *be = be_;
|
||||||
|
|
||||||
|
|
@ -13,11 +39,20 @@ static HParseResult *parse_bind(void *be_, HParseState *state) {
|
||||||
if(!res)
|
if(!res)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
HParser *kx = be->k(res->ast, be->env);
|
// create a temporary arena allocator for the continuation
|
||||||
if(!kx)
|
HArena *arena = h_new_arena(be->mm__, 0);
|
||||||
return NULL;
|
ArenaAllocator aa = {{aa_alloc, aa_realloc, aa_free}, arena};
|
||||||
|
|
||||||
return h_do_parse(kx, state);
|
HParser *kx = be->k((HAllocator *)&aa, res->ast, be->env);
|
||||||
|
if(!kx) {
|
||||||
|
h_delete_arena(arena);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = h_do_parse(kx, state);
|
||||||
|
|
||||||
|
h_delete_arena(arena);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const HParserVtable bind_vt = {
|
static const HParserVtable bind_vt = {
|
||||||
|
|
@ -40,6 +75,7 @@ HParser *h_bind__m(HAllocator *mm__,
|
||||||
be->p = p;
|
be->p = p;
|
||||||
be->k = k;
|
be->k = k;
|
||||||
be->env = env;
|
be->env = env;
|
||||||
|
be->mm__ = mm__;
|
||||||
|
|
||||||
return h_new_parser(mm__, &bind_vt, be);
|
return h_new_parser(mm__, &bind_vt, be);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -568,7 +568,7 @@ static void test_permutation(gconstpointer backend) {
|
||||||
g_check_parse_failed(po2, be, "ccc", 3);
|
g_check_parse_failed(po2, be, "ccc", 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
static HParser *f_test_bind(const HParsedToken *p, void *env) {
|
static HParser *k_test_bind(HAllocator *mm__, const HParsedToken *p, void *env) {
|
||||||
uint8_t one = (uintptr_t)env;
|
uint8_t one = (uintptr_t)env;
|
||||||
|
|
||||||
assert(p);
|
assert(p);
|
||||||
|
|
@ -581,17 +581,17 @@ static HParser *f_test_bind(const HParsedToken *p, void *env) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(v > 26)
|
if(v > 26)
|
||||||
return h_nothing_p(); // fail
|
return h_nothing_p__m(mm__); // fail
|
||||||
else if(v > 127)
|
else if(v > 127)
|
||||||
return NULL; // equivalent to the above
|
return NULL; // equivalent to the above
|
||||||
else
|
else
|
||||||
return h_ch(one - 1 + v);
|
return h_ch__m(mm__, one - 1 + v);
|
||||||
}
|
}
|
||||||
static void test_bind(gconstpointer backend) {
|
static void test_bind(gconstpointer backend) {
|
||||||
HParserBackend be = (HParserBackend)GPOINTER_TO_INT(backend);
|
HParserBackend be = (HParserBackend)GPOINTER_TO_INT(backend);
|
||||||
const HParser *digit = h_ch_range('0', '9');
|
const HParser *digit = h_ch_range('0', '9');
|
||||||
const HParser *nat = h_many1(digit);
|
const HParser *nat = h_many1(digit);
|
||||||
const HParser *p = h_bind(nat, f_test_bind, (void *)(uintptr_t)'a');
|
const HParser *p = h_bind(nat, k_test_bind, (void *)(uintptr_t)'a');
|
||||||
|
|
||||||
g_check_parse_match(p, be, "1a", 2, "u0x61");
|
g_check_parse_match(p, be, "1a", 2, "u0x61");
|
||||||
g_check_parse_match(p, be, "2b", 2, "u0x62");
|
g_check_parse_match(p, be, "2b", 2, "u0x62");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue