diff --git a/src/hammer.h b/src/hammer.h index 28167e7e58066cff7bc7de2cd6d29c47e0dae4cb..f893f10df4349d2ccc9d3a1c8c8675f60e014c9b 100644 --- a/src/hammer.h +++ b/src/hammer.h @@ -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, * used in h_bind(). The void* argument is passed through from h_bind() and can * 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 typedef struct HParserTestcase_ { diff --git a/src/parsers/bind.c b/src/parsers/bind.c index de0a8ec6374fd2cb32110360d42f77f6a57bebea..efd898105226b0a023e7dd3c1928232d31c8a0ff 100644 --- a/src/parsers/bind.c +++ b/src/parsers/bind.c @@ -4,8 +4,34 @@ typedef struct { const HParser *p; HContinuation k; void *env; + HAllocator *mm__; } 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) { BindEnv *be = be_; @@ -13,11 +39,20 @@ static HParseResult *parse_bind(void *be_, HParseState *state) { if(!res) return NULL; - HParser *kx = be->k(res->ast, be->env); - if(!kx) + // create a temporary arena allocator for the continuation + HArena *arena = h_new_arena(be->mm__, 0); + ArenaAllocator aa = {{aa_alloc, aa_realloc, aa_free}, arena}; + + HParser *kx = be->k((HAllocator *)&aa, res->ast, be->env); + if(!kx) { + h_delete_arena(arena); return NULL; + } + + res = h_do_parse(kx, state); - return h_do_parse(kx, state); + h_delete_arena(arena); + return res; } static const HParserVtable bind_vt = { @@ -40,6 +75,7 @@ HParser *h_bind__m(HAllocator *mm__, be->p = p; be->k = k; be->env = env; + be->mm__ = mm__; return h_new_parser(mm__, &bind_vt, be); } diff --git a/src/t_parser.c b/src/t_parser.c index c16e3840c4d9dced0b63c820f331eda2f50bd429..df9567ed201b1d07d1ebdf9e815fd625ba8de5c8 100644 --- a/src/t_parser.c +++ b/src/t_parser.c @@ -568,7 +568,7 @@ static void test_permutation(gconstpointer backend) { 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; assert(p); @@ -581,17 +581,17 @@ static HParser *f_test_bind(const HParsedToken *p, void *env) { } if(v > 26) - return h_nothing_p(); // fail + return h_nothing_p__m(mm__); // fail else if(v > 127) - return NULL; // equivalent to the above + return NULL; // equivalent to the above else - return h_ch(one - 1 + v); + return h_ch__m(mm__, one - 1 + v); } static void test_bind(gconstpointer backend) { HParserBackend be = (HParserBackend)GPOINTER_TO_INT(backend); const HParser *digit = h_ch_range('0', '9'); 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, "2b", 2, "u0x62");