Implemented a bunch more combinators
This commit is contained in:
parent
0e9bcb31ca
commit
3afe324aaa
5 changed files with 212 additions and 70 deletions
221
src/hammer.c
221
src/hammer.c
|
|
@ -459,28 +459,83 @@ const parser_t* xor(const parser_t* p1, const parser_t* p2) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parser_t* repeat0(const parser_t* p) { return &unimplemented; }
|
typedef struct {
|
||||||
const parser_t* repeat1(const parser_t* p) { return &unimplemented; }
|
const parser_t *p, *sep;
|
||||||
|
size_t count;
|
||||||
|
bool min_p;
|
||||||
const parser_t* repeat_n(const parser_t* p, const size_t n) { return &unimplemented; }
|
} repeat_t;
|
||||||
|
static parse_result_t *parse_many(void* env, parse_state_t *state) {
|
||||||
static parse_result_t* parse_optional(void* env, parse_state_t* state) {
|
repeat_t *env_ = (repeat_t*) env;
|
||||||
input_stream_t bak = state->input_stream;
|
GSequence *seq = g_sequence_new(NULL);
|
||||||
parse_result_t *res0 = do_parse((parser_t*)env, state);
|
size_t count = 0;
|
||||||
if (res0)
|
input_stream_t bak;
|
||||||
return res0;
|
while (env_->min_p || env_->count > count) {
|
||||||
|
bak = state->input_stream;
|
||||||
|
if (count > 0) {
|
||||||
|
parse_result_t *sep = do_parse(env_->sep, state);
|
||||||
|
if (!sep)
|
||||||
|
goto err0;
|
||||||
|
}
|
||||||
|
parse_result_t *elem = do_parse(env_->p, state);
|
||||||
|
if (!elem)
|
||||||
|
goto err0;
|
||||||
|
if (elem->ast)
|
||||||
|
g_sequence_append(seq, (gpointer)elem->ast);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if (count < env_->count)
|
||||||
|
goto err;
|
||||||
|
succ:
|
||||||
|
; // necessary for the label to be here...
|
||||||
|
parsed_token_t *res = a_new(parsed_token_t, 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:
|
||||||
|
g_sequence_free(seq);
|
||||||
state->input_stream = bak;
|
state->input_stream = bak;
|
||||||
parsed_token_t *ast = a_new(parsed_token_t, 1);
|
return NULL;
|
||||||
ast->token_type = TT_NONE;
|
|
||||||
return make_result(state, ast);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const parser_t* optional(const parser_t* p) {
|
const parser_t* many(const parser_t* p) {
|
||||||
parser_t *ret = g_new(parser_t, 1);
|
parser_t *res = g_new(parser_t, 1);
|
||||||
ret->fn = parse_optional;
|
repeat_t *env = g_new(repeat_t, 1);
|
||||||
ret->env = (void*)p;
|
env->p = p;
|
||||||
return ret;
|
env->sep = epsilon_p();
|
||||||
|
env->count = 0;
|
||||||
|
env->min_p = true;
|
||||||
|
res->fn = parse_many;
|
||||||
|
res->env = env;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser_t* many1(const parser_t* p) {
|
||||||
|
parser_t *res = g_new(parser_t, 1);
|
||||||
|
repeat_t *env = g_new(repeat_t, 1);
|
||||||
|
env->p = p;
|
||||||
|
env->sep = epsilon_p();
|
||||||
|
env->count = 1;
|
||||||
|
env->min_p = true;
|
||||||
|
res->fn = parse_many;
|
||||||
|
res->env = env;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser_t* repeat_n(const parser_t* p, const size_t n) {
|
||||||
|
parser_t *res = g_new(parser_t, 1);
|
||||||
|
repeat_t *env = g_new(repeat_t, 1);
|
||||||
|
env->p = p;
|
||||||
|
env->sep = epsilon_p();
|
||||||
|
env->count = n;
|
||||||
|
env->min_p = false;
|
||||||
|
res->fn = parse_many;
|
||||||
|
res->env = env;
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static parse_result_t* parse_ignore(void* env, parse_state_t* state) {
|
static parse_result_t* parse_ignore(void* env, parse_state_t* state) {
|
||||||
|
|
@ -498,11 +553,83 @@ const parser_t* ignore(const parser_t* p) {
|
||||||
ret->env = (void*)p;
|
ret->env = (void*)p;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
const parser_t* list(const parser_t* p, const parser_t* sep) { return &unimplemented; }
|
|
||||||
const parser_t* epsilon_p() { return &unimplemented; }
|
static parse_result_t* parse_optional(void* env, parse_state_t* state) {
|
||||||
|
input_stream_t bak = state->input_stream;
|
||||||
|
parse_result_t *res0 = do_parse((parser_t*)env, state);
|
||||||
|
if (res0)
|
||||||
|
return res0;
|
||||||
|
state->input_stream = bak;
|
||||||
|
parsed_token_t *ast = a_new(parsed_token_t, 1);
|
||||||
|
ast->token_type = TT_NONE;
|
||||||
|
return make_result(state, ast);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser_t* optional(const parser_t* p) {
|
||||||
|
assert_message(p->fn != parse_ignore, "Thou shalt ignore an option, rather than the other way 'round.");
|
||||||
|
parser_t *ret = g_new(parser_t, 1);
|
||||||
|
ret->fn = parse_optional;
|
||||||
|
ret->env = (void*)p;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser_t* sepBy(const parser_t* p, const parser_t* sep) {
|
||||||
|
parser_t *res = g_new(parser_t, 1);
|
||||||
|
repeat_t *env = g_new(repeat_t, 1);
|
||||||
|
env->p = p;
|
||||||
|
env->sep = sep;
|
||||||
|
env->count = 0;
|
||||||
|
env->min_p = true;
|
||||||
|
res->fn = parse_many;
|
||||||
|
res->env = env;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser_t* sepBy1(const parser_t* p, const parser_t* sep) {
|
||||||
|
parser_t *res = g_new(parser_t, 1);
|
||||||
|
repeat_t *env = g_new(repeat_t, 1);
|
||||||
|
env->p = p;
|
||||||
|
env->sep = sep;
|
||||||
|
env->count = 1;
|
||||||
|
env->min_p = true;
|
||||||
|
res->fn = parse_many;
|
||||||
|
res->env = env;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static parse_result_t* parse_epsilon(void* env, parse_state_t* state) {
|
||||||
|
(void)env;
|
||||||
|
parse_result_t* res = a_new(parse_result_t, 1);
|
||||||
|
res->ast = NULL;
|
||||||
|
res->arena = state->arena;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser_t* epsilon_p() {
|
||||||
|
parser_t *res = g_new(parser_t, 1);
|
||||||
|
res->fn = parse_epsilon;
|
||||||
|
res->env = NULL;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
const parser_t* attr_bool(const parser_t* p, attr_bool_t a) { return &unimplemented; }
|
const parser_t* attr_bool(const parser_t* p, attr_bool_t a) { return &unimplemented; }
|
||||||
const parser_t* and(const parser_t* p) { return &unimplemented; }
|
const parser_t* and(const parser_t* p) { return &unimplemented; }
|
||||||
const parser_t* not(const parser_t* p) { return &unimplemented; }
|
|
||||||
|
static parse_result_t* parse_not(void* env, parse_state_t* state) {
|
||||||
|
input_stream_t bak = state->input_stream;
|
||||||
|
if (do_parse((parser_t*)env, state))
|
||||||
|
return NULL;
|
||||||
|
else {
|
||||||
|
state->input_stream = bak;
|
||||||
|
return make_result(state, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parser_t* not(const parser_t* p) {
|
||||||
|
parser_t *res = g_new(parser_t, 1);
|
||||||
|
res->fn = parse_not;
|
||||||
|
res->env = (void*)p;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
static guint cache_key_hash(gconstpointer key) {
|
static guint cache_key_hash(gconstpointer key) {
|
||||||
return djbhash(key, sizeof(parser_cache_key_t));
|
return djbhash(key, sizeof(parser_cache_key_t));
|
||||||
|
|
@ -541,7 +668,7 @@ parse_result_t* parse(const parser_t* parser, const uint8_t* input, size_t lengt
|
||||||
static void test_token(void) {
|
static void test_token(void) {
|
||||||
const parser_t *token_ = token((const uint8_t*)"95\xa2", 3);
|
const parser_t *token_ = token((const uint8_t*)"95\xa2", 3);
|
||||||
|
|
||||||
g_check_parse_ok(token_, "95\xa2", 3, "<39.35.A2>");
|
g_check_parse_ok(token_, "95\xa2", 3, "<39.35.a2>");
|
||||||
g_check_parse_failed(token_, "95", 2);
|
g_check_parse_failed(token_, "95", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -722,22 +849,22 @@ static void test_xor(void) {
|
||||||
g_check_parse_failed(xor_, "a", 1);
|
g_check_parse_failed(xor_, "a", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_repeat0(void) {
|
static void test_many(void) {
|
||||||
const parser_t *repeat0_ = repeat0(choice(ch('a'), ch('b'), NULL));
|
const parser_t *many_ = many(choice(ch('a'), ch('b'), NULL));
|
||||||
|
|
||||||
g_check_parse_ok(repeat0_, "adef", 4, "(s0x61)");
|
g_check_parse_ok(many_, "adef", 4, "(s0x61)");
|
||||||
g_check_parse_ok(repeat0_, "bdef", 4, "(s0x62)");
|
g_check_parse_ok(many_, "bdef", 4, "(s0x62)");
|
||||||
g_check_parse_ok(repeat0_, "aabbabadef", 10, "(s0x61 s0x61 s0x62 s0x62 s0x61 s0x62 s0x61)");
|
g_check_parse_ok(many_, "aabbabadef", 10, "(s0x61 s0x61 s0x62 s0x62 s0x61 s0x62 s0x61)");
|
||||||
g_check_parse_ok(repeat0_, "daabbabadef", 11, "()");
|
g_check_parse_ok(many_, "daabbabadef", 11, "()");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_repeat1(void) {
|
static void test_many1(void) {
|
||||||
const parser_t *repeat1_ = repeat1(choice(ch('a'), ch('b'), NULL));
|
const parser_t *many1_ = many1(choice(ch('a'), ch('b'), NULL));
|
||||||
|
|
||||||
g_check_parse_ok(repeat1_, "adef", 4, "(s0x61)");
|
g_check_parse_ok(many1_, "adef", 4, "(s0x61)");
|
||||||
g_check_parse_ok(repeat1_, "bdef", 4, "(s0x62)");
|
g_check_parse_ok(many1_, "bdef", 4, "(s0x62)");
|
||||||
g_check_parse_ok(repeat1_, "aabbabadef", 10, "(s0x61 s0x61 s0x62 s0x62 s0x61 s0x62 s0x61)");
|
g_check_parse_ok(many1_, "aabbabadef", 10, "(s0x61 s0x61 s0x62 s0x62 s0x61 s0x62 s0x61)");
|
||||||
g_check_parse_failed(repeat1_, "daabbabadef", 11);
|
g_check_parse_failed(many1_, "daabbabadef", 11);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_repeat_n(void) {
|
static void test_repeat_n(void) {
|
||||||
|
|
@ -766,13 +893,13 @@ static void test_ignore(void) {
|
||||||
g_check_parse_failed(ignore_, "ac", 2);
|
g_check_parse_failed(ignore_, "ac", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_list(void) {
|
static void test_sepBy1(void) {
|
||||||
const parser_t *list_ = list(choice(ch('1'), ch('2'), ch('3'), NULL), ch(','));
|
const parser_t *sepBy1_ = sepBy1(choice(ch('1'), ch('2'), ch('3'), NULL), ch(','));
|
||||||
|
|
||||||
g_check_parse_ok(list_, "1,2,3", 5, "(s0x31 s0x32 s0x33)");
|
g_check_parse_ok(sepBy1_, "1,2,3", 5, "(s0x31 s0x32 s0x33)");
|
||||||
g_check_parse_ok(list_, "1,3,2", 5, "(s0x31 s0x33 s0x32)");
|
g_check_parse_ok(sepBy1_, "1,3,2", 5, "(s0x31 s0x33 s0x32)");
|
||||||
g_check_parse_ok(list_, "1,3", 3, "(s0x31 s0x33)");
|
g_check_parse_ok(sepBy1_, "1,3", 3, "(s0x31 s0x33)");
|
||||||
g_check_parse_ok(list_, "3", 1, "(s0x33)");
|
g_check_parse_ok(sepBy1_, "3", 1, "(s0x33)");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_epsilon_p(void) {
|
static void test_epsilon_p(void) {
|
||||||
|
|
@ -806,10 +933,10 @@ static void test_not(void) {
|
||||||
token((const uint8_t*)"++", 2),
|
token((const uint8_t*)"++", 2),
|
||||||
NULL), ch('b'), NULL);
|
NULL), ch('b'), NULL);
|
||||||
|
|
||||||
g_check_parse_ok(not_1, "a+b", 3, "(s0x61 s0x2B s0x62)");
|
g_check_parse_ok(not_1, "a+b", 3, "(s0x61 s0x2b s0x62)");
|
||||||
g_check_parse_failed(not_1, "a++b", 4);
|
g_check_parse_failed(not_1, "a++b", 4);
|
||||||
g_check_parse_ok(not_2, "a+b", 3, "(s0x61 s0x2B s0x62)");
|
g_check_parse_ok(not_2, "a+b", 3, "(s0x61 (s0x2b) s0x62)");
|
||||||
g_check_parse_ok(not_2, "a++b", 4, "(s0x61 <2B.2B> s0x62)");
|
g_check_parse_ok(not_2, "a++b", 4, "(s0x61 <2b.2b> s0x62)");
|
||||||
}
|
}
|
||||||
|
|
||||||
void register_parser_tests(void) {
|
void register_parser_tests(void) {
|
||||||
|
|
@ -838,11 +965,11 @@ void register_parser_tests(void) {
|
||||||
g_test_add_func("/core/parser/butnot", test_butnot);
|
g_test_add_func("/core/parser/butnot", test_butnot);
|
||||||
g_test_add_func("/core/parser/difference", test_difference);
|
g_test_add_func("/core/parser/difference", test_difference);
|
||||||
g_test_add_func("/core/parser/xor", test_xor);
|
g_test_add_func("/core/parser/xor", test_xor);
|
||||||
g_test_add_func("/core/parser/repeat0", test_repeat0);
|
g_test_add_func("/core/parser/many", test_many);
|
||||||
g_test_add_func("/core/parser/repeat1", test_repeat1);
|
g_test_add_func("/core/parser/many1", test_many1);
|
||||||
g_test_add_func("/core/parser/repeat_n", test_repeat_n);
|
g_test_add_func("/core/parser/repeat_n", test_repeat_n);
|
||||||
g_test_add_func("/core/parser/optional", test_optional);
|
g_test_add_func("/core/parser/optional", test_optional);
|
||||||
g_test_add_func("/core/parser/list", test_list);
|
g_test_add_func("/core/parser/sepBy1", test_sepBy1);
|
||||||
g_test_add_func("/core/parser/epsilon_p", test_epsilon_p);
|
g_test_add_func("/core/parser/epsilon_p", test_epsilon_p);
|
||||||
g_test_add_func("/core/parser/attr_bool", test_attr_bool);
|
g_test_add_func("/core/parser/attr_bool", test_attr_bool);
|
||||||
g_test_add_func("/core/parser/and", test_and);
|
g_test_add_func("/core/parser/and", test_and);
|
||||||
|
|
|
||||||
15
src/hammer.h
15
src/hammer.h
|
|
@ -177,10 +177,10 @@ const parser_t* difference(const parser_t* p1, const parser_t* p2);
|
||||||
const parser_t* xor(const parser_t* p1, const parser_t* p2);
|
const parser_t* xor(const parser_t* p1, const parser_t* p2);
|
||||||
|
|
||||||
/* Given a parser, p, this parser succeeds for zero or more repetitions of p. */
|
/* Given a parser, p, this parser succeeds for zero or more repetitions of p. */
|
||||||
const parser_t* repeat0(const parser_t* p);
|
const parser_t* many(const parser_t* p);
|
||||||
|
|
||||||
/* Given a parser, p, this parser succeeds for one or more repetitions of p. */
|
/* Given a parser, p, this parser succeeds for one or more repetitions of p. */
|
||||||
const parser_t* repeat1(const parser_t* p);
|
const parser_t* many1(const parser_t* p);
|
||||||
|
|
||||||
/* Given a parser, p, this parser succeeds for exactly N repetitions of p. */
|
/* Given a parser, p, this parser succeeds for exactly N repetitions of p. */
|
||||||
const parser_t* repeat_n(const parser_t* p, const size_t n);
|
const parser_t* repeat_n(const parser_t* p, const size_t n);
|
||||||
|
|
@ -191,10 +191,15 @@ const parser_t* optional(const parser_t* p);
|
||||||
/* Given a parser, p, this parser succeeds if p succeeds, but doesn't include p's result in the result. */
|
/* Given a parser, p, this parser succeeds if p succeeds, but doesn't include p's result in the result. */
|
||||||
const parser_t* ignore(const parser_t* p);
|
const parser_t* ignore(const parser_t* p);
|
||||||
|
|
||||||
/* Given a parser, p, and a parser for a separator, sep, this parser matches a list of things that p can parse, separated by sep.
|
/* Given a parser, p, and a parser for a separator, sep, this parser matches a (possibly empty) list of things that p can parse, separated by sep.
|
||||||
* For example, if p is repeat1(range('0','9')) and sep is ch(','), list(p, sep) will match a comma-separated list of integers.
|
* For example, if p is repeat1(range('0','9')) and sep is ch(','), sepBy(p, sep) will match a comma-separated list of integers.
|
||||||
*/
|
*/
|
||||||
const parser_t* list(const parser_t* p, const parser_t* sep);
|
const parser_t* sepBy(const parser_t* p, const parser_t* sep);
|
||||||
|
|
||||||
|
/* Given a parser, p, and a parser for a separator, sep, this parser matches a list of things that p can parse, separated by sep. Unlike sepBy, this ensures that the result has at least one element.
|
||||||
|
* For example, if p is repeat1(range('0','9')) and sep is ch(','), sepBy1(p, sep) will match a comma-separated list of integers.
|
||||||
|
*/
|
||||||
|
const parser_t* sepBy1(const parser_t* p, const parser_t* sep);
|
||||||
|
|
||||||
/* This parser always returns a zero length match, i.e., empty string. */
|
/* This parser always returns a zero length match, i.e., empty string. */
|
||||||
const parser_t* epsilon_p();
|
const parser_t* epsilon_p();
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,17 @@
|
||||||
#ifndef HAMMER_INTERNAL__H
|
#ifndef HAMMER_INTERNAL__H
|
||||||
#define HAMMER_INTERNAL__H
|
#define HAMMER_INTERNAL__H
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <err.h>
|
||||||
#include "hammer.h"
|
#include "hammer.h"
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define assert_message(check, message) do { } while(0)
|
||||||
|
#else
|
||||||
|
#define assert_message(check, message) do { \
|
||||||
|
if (!(check)) \
|
||||||
|
errx(1, "Assertation failed (programmer error): %s", message); \
|
||||||
|
} while(0)
|
||||||
|
#endif
|
||||||
#define false 0
|
#define false 0
|
||||||
#define true 1
|
#define true 1
|
||||||
|
|
||||||
|
|
@ -71,4 +80,5 @@ void put_cached(parse_state_t *ps, const parser_t *p, parse_result_t *cached);
|
||||||
guint djbhash(const uint8_t *buf, size_t len);
|
guint djbhash(const uint8_t *buf, size_t len);
|
||||||
char* write_result_unamb(const parsed_token_t* tok);
|
char* write_result_unamb(const parsed_token_t* tok);
|
||||||
void pprint(const parsed_token_t* tok, int indent, int delta);
|
void pprint(const parsed_token_t* tok, int indent, int delta);
|
||||||
|
|
||||||
#endif // #ifndef HAMMER_INTERNAL__H
|
#endif // #ifndef HAMMER_INTERNAL__H
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ static void unamb_sub(const parsed_token_t* tok, struct result_buf *buf) {
|
||||||
append_buf(buf, "<>", 2);
|
append_buf(buf, "<>", 2);
|
||||||
else {
|
else {
|
||||||
for (size_t i = 0; i < tok->bytes.len; i++) {
|
for (size_t i = 0; i < tok->bytes.len; i++) {
|
||||||
const char *HEX = "0123456789ABCDEF";
|
const char *HEX = "0123456789abcdef";
|
||||||
append_buf_c(buf, (i == 0) ? '<': '.');
|
append_buf_c(buf, (i == 0) ? '<': '.');
|
||||||
char c = tok->bytes.token[i];
|
char c = tok->bytes.token[i];
|
||||||
append_buf_c(buf, HEX[(c >> 4) & 0xf]);
|
append_buf_c(buf, HEX[(c >> 4) & 0xf]);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
#define HAMMER_TEST_SUITE__H
|
#define HAMMER_TEST_SUITE__H
|
||||||
|
|
||||||
// Equivalent to g_assert_*, but not using g_assert...
|
// Equivalent to g_assert_*, but not using g_assert...
|
||||||
#define g_check_inttype(fmt, typ, n1, op, n2) { \
|
#define g_check_inttype(fmt, typ, n1, op, n2) do { \
|
||||||
typ _n1 = (n1); \
|
typ _n1 = (n1); \
|
||||||
typ _n2 = (n2); \
|
typ _n2 = (n2); \
|
||||||
if (!(_n1 op _n2)) { \
|
if (!(_n1 op _n2)) { \
|
||||||
|
|
@ -28,9 +28,9 @@
|
||||||
_n1, #op, _n2); \
|
_n1, #op, _n2); \
|
||||||
g_test_fail(); \
|
g_test_fail(); \
|
||||||
} \
|
} \
|
||||||
}
|
} while(0)
|
||||||
|
|
||||||
#define g_check_bytes(len, n1, op, n2) { \
|
#define g_check_bytes(len, n1, op, n2) do { \
|
||||||
const uint8_t *_n1 = (n1); \
|
const uint8_t *_n1 = (n1); \
|
||||||
const uint8_t *_n2 = (n2); \
|
const uint8_t *_n2 = (n2); \
|
||||||
if (!(memcmp(_n1, _n2, len) op 0)) { \
|
if (!(memcmp(_n1, _n2, len) op 0)) { \
|
||||||
|
|
@ -38,37 +38,37 @@
|
||||||
#n1 " " #op " " #n2); \
|
#n1 " " #op " " #n2); \
|
||||||
g_test_fail(); \
|
g_test_fail(); \
|
||||||
} \
|
} \
|
||||||
}
|
} while(0)
|
||||||
|
|
||||||
#define g_check_string(n1, op, n2) { \
|
#define g_check_string(n1, op, n2) do { \
|
||||||
const char *_n1 = (n1); \
|
const char *_n1 = (n1); \
|
||||||
const char *_n2 = (n2); \
|
const char *_n2 = (n2); \
|
||||||
if (!(strcmp(_n1, _n2) op 0)) { \
|
if (!(strcmp(_n1, _n2) op 0)) { \
|
||||||
g_test_message("Check failed: (%s) (%s %s %s)", \
|
g_test_message("Check failed: (%s) (%s %s %s)", \
|
||||||
#n1 " " #op " " #n2, \
|
#n1 " " #op " " #n2, \
|
||||||
_n1, #op, _n2); \
|
_n1, #op, _n2); \
|
||||||
g_test_fail(); \
|
g_test_fail(); \
|
||||||
} \
|
} \
|
||||||
}
|
} while(0)
|
||||||
|
|
||||||
// TODO: replace uses of this with g_check_parse_failed
|
// TODO: replace uses of this with g_check_parse_failed
|
||||||
#define g_check_failed(res) { \
|
#define g_check_failed(res) do { \
|
||||||
const parse_result_t *result = (res); \
|
const parse_result_t *result = (res); \
|
||||||
if (NULL != result) { \
|
if (NULL != result) { \
|
||||||
g_test_message("Check failed: shouldn't have succeeded, but did"); \
|
g_test_message("Check failed: shouldn't have succeeded, but did"); \
|
||||||
g_test_fail(); \
|
g_test_fail(); \
|
||||||
} \
|
} \
|
||||||
}
|
} while(0)
|
||||||
|
|
||||||
#define g_check_parse_failed(parser, input, inp_len) { \
|
#define g_check_parse_failed(parser, input, inp_len) do { \
|
||||||
const parse_result_t *result = parse(parser, (const uint8_t*)input, inp_len); \
|
const parse_result_t *result = parse(parser, (const uint8_t*)input, inp_len); \
|
||||||
if (NULL != result) { \
|
if (NULL != result) { \
|
||||||
g_test_message("Check failed: shouldn't have succeeded, but did"); \
|
g_test_message("Check failed: shouldn't have succeeded, but did"); \
|
||||||
g_test_fail(); \
|
g_test_fail(); \
|
||||||
} \
|
} \
|
||||||
}
|
} while(0)
|
||||||
|
|
||||||
#define g_check_parse_ok(parser, input, inp_len, result) { \
|
#define g_check_parse_ok(parser, input, inp_len, result) do { \
|
||||||
parse_result_t *res = parse(parser, (const uint8_t*)input, inp_len); \
|
parse_result_t *res = parse(parser, (const uint8_t*)input, inp_len); \
|
||||||
if (!res) { \
|
if (!res) { \
|
||||||
g_test_message("Parse failed on line %d", __LINE__); \
|
g_test_message("Parse failed on line %d", __LINE__); \
|
||||||
|
|
@ -83,7 +83,7 @@
|
||||||
stats.used, stats.wasted, \
|
stats.used, stats.wasted, \
|
||||||
stats.wasted * 100. / (stats.used+stats.wasted)); \
|
stats.wasted * 100. / (stats.used+stats.wasted)); \
|
||||||
} \
|
} \
|
||||||
}
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
#define g_check_cmpint(n1, op, n2) g_check_inttype("%d", int, n1, op, n2)
|
#define g_check_cmpint(n1, op, n2) g_check_inttype("%d", int, n1, op, n2)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue