UpstandingHackers / hammer

Parser combinators for binary formats, in C. Yes, in C. What? Don't look at me like that.
GNU General Public License v2.0
430 stars 40 forks source link

Add monadic bind combinator h_bind #129

Closed pesco closed 9 years ago

pesco commented 9 years ago

See declarations/docs below. There's obviously a bit of a near-name-clash with h_bind_indirect - I'll leave it to you to decide whether anything needs to be done about that.

One item of note is the HArena wrapped in an HAllocator I made so I can have parsers, via the __m function variants, allocated in a temporary arena that I destroy before leaving the outer parser. Consider h_bind(p, k, NULL); Obviously I don't want allocations from the second argument to stick around after the continuation has run, so k is passed an ArenaAllocator (as a pointer to HAllocator) that it is supposed to use.

Please have a look how I extend the HAllocator struct to add the pointer to the HArena. I'm fuzzy on whether this trick is portable.

This arena allocator could be useful to users in other circumstances so maybe we should expose it; it's private to the h_bind implementation right now.

/**
 * 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)(HAllocator *mm__, const HParsedToken *x, void *env);

/**
 * Monadic bind for HParsers, i.e.:
 * Sequencing where later parsers may depend on the result(s) of earlier ones.
 *
 * Run p and call the result x. Then run k(env,x).  Fail if p fails or if
 * k(env,x) fails or if k(env,x) is NULL.
 *
 * Result: the result of k(x,env).
 */
HAMMER_FN_DECL(HParser*, h_bind, const HParser *p, HContinuation k, void *env);