Extracted out common error handling and result patching code
This commit is contained in:
parent
44440c8347
commit
6d755efbde
1 changed files with 35 additions and 37 deletions
72
src/hammer.c
72
src/hammer.c
|
|
@ -35,14 +35,43 @@ static guint djbhash(const uint8_t *buf, size_t len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// short-hand for constructing HCachedResult's
|
// short-hand for constructing HCachedResult's
|
||||||
static HCachedResult *cached_result(const HParseState *state, HParseResult *result)
|
static HCachedResult *cached_result(const HParseState *state, HParseResult *result) {
|
||||||
{
|
|
||||||
HCachedResult *ret = a_new(HCachedResult, 1);
|
HCachedResult *ret = a_new(HCachedResult, 1);
|
||||||
ret->result = result;
|
ret->result = result;
|
||||||
ret->input_stream = state->input_stream;
|
ret->input_stream = state->input_stream;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Really library-internal tool to perform an uncached parse, and handle any common error-handling.
|
||||||
|
static inline HParseResult* perform_lowlevel_parse(HParseState *state, const HParser *parser) {
|
||||||
|
HParseResult *tmp_res;
|
||||||
|
if (parser) {
|
||||||
|
HInputStream bak = state->input_stream;
|
||||||
|
tmp_res = parser->vtable->parse(parser->env, state);
|
||||||
|
if (tmp_res) {
|
||||||
|
tmp_res->arena = state->arena;
|
||||||
|
if (!state->input_stream.overrun) {
|
||||||
|
tmp_res->bit_length = ((state->input_stream.index - bak.index) << 3);
|
||||||
|
if (state->input_stream.endianness & BIT_BIG_ENDIAN)
|
||||||
|
tmp_res->bit_length += state->input_stream.bit_offset - bak.bit_offset;
|
||||||
|
else
|
||||||
|
tmp_res->bit_length += bak.bit_offset - state->input_stream.bit_offset;
|
||||||
|
} else
|
||||||
|
tmp_res->bit_length = 0;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
tmp_res = NULL;
|
||||||
|
if (state->input_stream.overrun)
|
||||||
|
return NULL; // overrun is always failure.
|
||||||
|
#ifdef CONSISTENCY_CHECK
|
||||||
|
if (!tmp_res) {
|
||||||
|
state->input_stream = INVALID;
|
||||||
|
state->input_stream.input = key->input_pos.input;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return tmp_res;
|
||||||
|
}
|
||||||
|
|
||||||
HParserCacheValue* recall(HParserCacheKey *k, HParseState *state) {
|
HParserCacheValue* recall(HParserCacheKey *k, HParseState *state) {
|
||||||
HParserCacheValue *cached = g_hash_table_lookup(state->cache, k);
|
HParserCacheValue *cached = g_hash_table_lookup(state->cache, k);
|
||||||
HRecursionHead *head = g_hash_table_lookup(state->recursion_heads, k);
|
HRecursionHead *head = g_hash_table_lookup(state->recursion_heads, k);
|
||||||
|
|
@ -60,9 +89,7 @@ HParserCacheValue* recall(HParserCacheKey *k, HParseState *state) {
|
||||||
if (g_slist_find(head->eval_set, k->parser)) {
|
if (g_slist_find(head->eval_set, k->parser)) {
|
||||||
// Something is in the cache, and the key parser is in the eval set. Remove the key parser from the eval set of the head.
|
// Something is in the cache, and the key parser is in the eval set. Remove the key parser from the eval set of the head.
|
||||||
head->eval_set = g_slist_remove_all(head->eval_set, k->parser);
|
head->eval_set = g_slist_remove_all(head->eval_set, k->parser);
|
||||||
HParseResult *tmp_res = k->parser->vtable->parse(k->parser->env, state);
|
HParseResult *tmp_res = perform_lowlevel_parse(state, k->parser);
|
||||||
if (tmp_res)
|
|
||||||
tmp_res->arena = state->arena;
|
|
||||||
// we know that cached has an entry here, modify it
|
// we know that cached has an entry here, modify it
|
||||||
if (!cached)
|
if (!cached)
|
||||||
cached = a_new(HParserCacheValue, 1);
|
cached = a_new(HParserCacheValue, 1);
|
||||||
|
|
@ -106,13 +133,8 @@ HParseResult* grow(HParserCacheKey *k, HParseState *state, HRecursionHead *head)
|
||||||
|
|
||||||
// reset the eval_set of the head of the recursion at each beginning of growth
|
// reset the eval_set of the head of the recursion at each beginning of growth
|
||||||
head->eval_set = head->involved_set;
|
head->eval_set = head->involved_set;
|
||||||
HParseResult *tmp_res;
|
HParseResult *tmp_res = perform_lowlevel_parse(state, k->parser);
|
||||||
if (k->parser) {
|
|
||||||
tmp_res = k->parser->vtable->parse(k->parser->env, state);
|
|
||||||
if (tmp_res)
|
|
||||||
tmp_res->arena = state->arena;
|
|
||||||
} else
|
|
||||||
tmp_res = NULL;
|
|
||||||
if (tmp_res) {
|
if (tmp_res) {
|
||||||
if ((old_res->ast->index < tmp_res->ast->index) ||
|
if ((old_res->ast->index < tmp_res->ast->index) ||
|
||||||
(old_res->ast->index == tmp_res->ast->index && old_res->ast->bit_offset < tmp_res->ast->bit_offset)) {
|
(old_res->ast->index == tmp_res->ast->index && old_res->ast->bit_offset < tmp_res->ast->bit_offset)) {
|
||||||
|
|
@ -173,31 +195,7 @@ HParseResult* h_do_parse(const HParser* parser, HParseState *state) {
|
||||||
dummy->value_type = PC_LEFT; dummy->left = base;
|
dummy->value_type = PC_LEFT; dummy->left = base;
|
||||||
g_hash_table_replace(state->cache, key, dummy);
|
g_hash_table_replace(state->cache, key, dummy);
|
||||||
// parse the input
|
// parse the input
|
||||||
HParseResult *tmp_res;
|
HParseResult *tmp_res = perform_lowlevel_parse(state, parser);
|
||||||
if (parser) {
|
|
||||||
HInputStream bak = state->input_stream;
|
|
||||||
tmp_res = parser->vtable->parse(parser->env, state);
|
|
||||||
if (tmp_res) {
|
|
||||||
tmp_res->arena = state->arena;
|
|
||||||
if (!state->input_stream.overrun) {
|
|
||||||
tmp_res->bit_length = ((state->input_stream.index - bak.index) << 3);
|
|
||||||
if (state->input_stream.endianness & BIT_BIG_ENDIAN)
|
|
||||||
tmp_res->bit_length += state->input_stream.bit_offset - bak.bit_offset;
|
|
||||||
else
|
|
||||||
tmp_res->bit_length += bak.bit_offset - state->input_stream.bit_offset;
|
|
||||||
} else
|
|
||||||
tmp_res->bit_length = 0;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
tmp_res = NULL;
|
|
||||||
if (state->input_stream.overrun)
|
|
||||||
return NULL; // overrun is always failure.
|
|
||||||
#ifdef CONSISTENCY_CHECK
|
|
||||||
if (!tmp_res) {
|
|
||||||
state->input_stream = INVALID;
|
|
||||||
state->input_stream.input = key->input_pos.input;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// the base variable has passed equality tests with the cache
|
// the base variable has passed equality tests with the cache
|
||||||
g_queue_pop_head(state->lr_stack);
|
g_queue_pop_head(state->lr_stack);
|
||||||
// setupLR, used below, mutates the LR to have a head if appropriate, so we check to see if we have one
|
// setupLR, used below, mutates the LR to have a head if appropriate, so we check to see if we have one
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue