Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • hammer/hammer
  • mlp/hammer
  • xentrac/hammer
  • pesco/hammer
  • letitiali/hammer
  • nobody/hammer
  • kia/hammer-sandbox
  • vyrus001/hammer
  • denleylam/hammer
9 results
Show changes
#include <glib.h>
#include <stdint.h>
#include <stdlib.h>
#include "glue.h"
#include "hammer.h"
#include "test_suite.h"
......@@ -187,7 +188,7 @@ static void test_charset_bits(void) {
.free = NULL,
};
test_charset_bits__buf[32] = 0xAB;
HCharset cs = new_charset(&alloc);
new_charset(&alloc);
for(size_t i=0; i<32; i++)
g_check_cmp_uint32(test_charset_bits__buf[i], ==, 0);
g_check_cmp_uint32(test_charset_bits__buf[32], ==, 0xAB);
......@@ -270,6 +271,378 @@ static void test_bug_19() {
g_assert_true(1);
}
static void test_flatten_null() {
// h_act_flatten() produces a flat sequence from a nested sequence. it also
// hapens to produce a one-element sequence when given a non-sequence token.
// but given a null token (as from h_epsilon_p() or h_ignore()), it would
// previously segfault.
//
// let's make sure the behavior is consistent and a singular null token
// produces the same thing as a sequence around h_epsilon_p() or h_ignore().
HParser *A = h_many(h_ch('a'));
HParser *B = h_ch('b');
HParser *C = h_sequence(h_ch('c'), NULL);
HParser *V = h_action(h_epsilon_p(), h_act_flatten, NULL);
HParser *W = h_action(B, h_act_flatten, NULL);
HParser *X = h_action(h_sequence(h_ignore(A), NULL), h_act_flatten, NULL);
HParser *Y = h_action(h_sequence(h_epsilon_p(), NULL), h_act_flatten, NULL);
HParser *Z = h_action(h_sequence(A, B, C, NULL), h_act_flatten, NULL);
g_check_parse_match(V, PB_PACKRAT, "", 0, "()");
g_check_parse_match(W, PB_PACKRAT, "b", 1, "(u0x62)");
g_check_parse_match(X, PB_PACKRAT, "", 0, "()");
g_check_parse_match(Y, PB_PACKRAT, "", 0, "()");
g_check_parse_match(Z, PB_PACKRAT, "aabc", 4, "(u0x61 u0x61 u0x62 u0x63)");
#if 0 // XXX ast->bit_length and ast->index are currently not set
// let's also check that position and length info get attached correctly...
HParseResult *p = h_parse(h_sequence(A,V,B, NULL), (uint8_t *)"aaab", 4);
// top-level token
assert(p != NULL);
assert(p->ast != NULL);
g_check_cmp_int64(p->bit_length, ==, 32);
g_check_cmp_size(p->ast->bit_length, ==, 32);
g_check_cmp_size(p->ast->index, ==, 0);
g_check_cmp_int((int)p->ast->bit_offset, ==, 0);
// the empty sequence
HParsedToken *tok = H_INDEX_TOKEN(p->ast, 1);
assert(tok != NULL);
assert(tok->token_type == TT_SEQUENCE);
assert(tok->seq->used == 0);
g_check_cmp_size(tok->bit_length, ==, 0);
g_check_cmp_size(tok->index, ==, 2);
g_check_cmp_int((int)tok->bit_offset, ==, 0);
#endif // 0
}
#if 0 // XXX ast->bit_length and ast->index are currently not set
static void test_ast_length_index() {
HParser *A = h_many(h_ch('a'));
HParser *B = h_ch('b');
HParser *C = h_sequence(h_ch('c'), NULL);
const uint8_t input[] = "aabc";
size_t len = sizeof input - 1; // sans null
HParseResult *p = h_parse(h_sequence(A,B,C, NULL), input, len);
assert(p != NULL);
assert(p->ast != NULL);
// top-level token
g_check_cmp_int64(p->bit_length, ==, (int64_t)(8 * len));
g_check_cmp_size(p->ast->bit_length, ==, 8 * len);
g_check_cmp_size(p->ast->index, ==, 0);
HParsedToken *tok;
// "aa"
tok = H_INDEX_TOKEN(p->ast, 0);
g_check_cmp_size(tok->bit_length, ==, 16);
g_check_cmp_size(tok->index, ==, 0);
// "a", "a"
tok = H_INDEX_TOKEN(p->ast, 0, 0);
g_check_cmp_size(tok->bit_length, ==, 8);
g_check_cmp_size(tok->index, ==, 0);
tok = H_INDEX_TOKEN(p->ast, 0, 1);
g_check_cmp_size(tok->bit_length, ==, 8);
g_check_cmp_size(tok->index, ==, 1);
// "b"
tok = H_INDEX_TOKEN(p->ast, 1);
g_check_cmp_size(tok->bit_length, ==, 8);
g_check_cmp_size(tok->index, ==, 2);
// "c"
tok = H_INDEX_TOKEN(p->ast, 2);
g_check_cmp_size(tok->bit_length, ==, 8);
g_check_cmp_size(tok->index, ==, 3);
tok = H_INDEX_TOKEN(p->ast, 2, 0);
g_check_cmp_size(tok->bit_length, ==, 8);
g_check_cmp_size(tok->index, ==, 3);
}
#endif // 0
static void test_issue91() {
// this ambiguous grammar caused intermittent (?) assertion failures when
// trying to compile with the LALR backend:
//
// assertion "action->type == HLR_SHIFT" failed: file "src/backends/lalr.c",
// line 34, function "follow_transition"
//
// cf. https://gitlab.special-circumstanc.es/hammer/hammer/issues/91
H_RULE(schar, h_ch_range(' ', '~')); /* overlaps digit */
H_RULE(digit, h_ch_range('0', '9'));
H_RULE(digits, h_choice(h_repeat_n(digit, 2), digit, NULL));
H_RULE(p, h_many(h_choice(schar, digits, NULL)));
int r = h_compile(p, PB_LALR, NULL);
g_check_cmp_int(r, ==, -2);
}
// a different instance of issue 91
static void test_issue87() {
HParser *a = h_ch('a');
HParser *a2 = h_ch_range('a', 'a');
HParser *p = h_many(h_many(h_choice(a, a2, NULL)));
int r = h_compile(p, PB_LALR, NULL);
g_check_cmp_int(r, ==, -2);
}
static void test_issue92() {
HParser *a = h_ch('a');
HParser *b = h_ch('b');
HParser *str_a = h_indirect();
HParser *str_b = h_choice(h_sequence(b, str_a, NULL), str_a, NULL);
//h_sequence(h_optional(b), str_a, NULL); // this works
HParser *str_a_ = h_optional(h_sequence(a, str_b, NULL));
HParser *str = str_a;
h_bind_indirect(str_a, str_a_);
/*
* grammar generated from the above:
*
* A -> B -- "augmented" with a fresh start symbol
* B -> C -- B = str_a
* | ""
* C -> "a" D -- C = h_sequence(a, str_b)
* D -> E -- D = str_b
* | B
* E -> "b" B -- E = h_sequence(b, str_a)
*
* transformed to the following "enhanced grammar":
*
* S -> 0B3
* 0B3 -> 0C2
* | ""
* 1B4 -> 1C2
* | ""
* 6B8 -> 6C2
* | "" (*) here
* 0C2 -> "a" 1D7
* 1C2 -> "a" 1D7
* 6C2 -> "a" 1D7
* 1D7 -> 1E5
* | 1B4
* 1E5 -> "b" 6B8
*/
/*
* the following call would cause an assertion failure.
*
* assertion "!h_stringmap_empty(fs)" failed: file
* "src/backends/lalr.c", line 341, function "h_lalr_compile"
*
* the bug happens when trying to compute h_follow() for 6B8 in state 6,
* production "" (*). intermediate results could end up in the memoization
* table and be treated as final by later calls to h_follow(). the problem
* could appear or not depending on the order of nonterminals (i.e. pointers)
* in a hashtable.
*/
int r = h_compile(str, PB_LALR, NULL);
g_check_cmp_int(r, ==, 0);
}
static void test_issue83() {
HParser *p = h_sequence(h_sequence(NULL, NULL), h_nothing_p(), NULL);
/*
* A -> B
* B -> C D
* C -> ""
* D -x
*
* (S) -> 0B1
* 0B1 -> 0C2 2D3
* 0C2 -> "" (*) h_follow()
* 2D3 -x
*/
/*
* similar to issue 91, this would cause the same assertion failure, but for
* a different reason. the follow set of 0C2 above is equal to the first set
* of 2D3, but 2D3 is an empty choice. The first set of an empty choice
* is legitimately empty. the asserting in h_lalr_compile() missed this case.
*/
int r = h_compile(p, PB_LALR, NULL);
g_check_cmp_int(r, ==, 0);
}
/*
* This is Meg's cut-down bug 60 test case
*/
static void test_bug60() {
/* There is probably an even smaller example that shows the issue */
HParser *zed = NULL;
HParser *alpha = NULL;
HParser *vchar = NULL;
HParser *why = NULL;
HParser *plural_zed = NULL;
HParser *plural_zed_zed = NULL;
HParser *a_to_zed = NULL;
HParser *alphas = NULL;
HParser *rule = NULL;
HParser *rulelist = NULL;
HParser *p = NULL;
HParseResult *r = NULL;
int n;
zed = h_ch('z');
vchar = h_ch_range(0x79, 0x7a); /* allows y and z */
alpha = h_ch('a');
why = h_ch('y');
plural_zed = h_sequence(
why,
h_many(h_choice(alpha, vchar, NULL)),
NULL);
plural_zed_zed = h_choice(plural_zed, zed, NULL);
alphas = h_choice(alpha, h_sequence(plural_zed_zed, alpha, NULL), NULL);
a_to_zed = h_sequence(
zed,
h_many(h_sequence(h_many1(alphas), zed, NULL)),
NULL);
rule = h_sequence(a_to_zed, plural_zed_zed, NULL);
rulelist = h_many1(h_choice(
rule,
h_sequence(h_many(alphas), plural_zed_zed, NULL),
NULL));
p = rulelist;
g_check_parse_ok(p, PB_GLR, "ayzza", 5);
g_check_parse_match(p, PB_GLR, "ayzza", 5, "(((u0x61) (u0x79 (u0x7a u0x7a u0x61))))");
}
/*
* This is the original bug60 test case; cut down from an ABNF parser
*/
#define BUG60_ABNF_SCAN_UP_TO 64
static void test_bug60_abnf() {
HParser *newline = NULL;
HParser *alpha = NULL;
HParser *sp = NULL;
HParser *vchar = NULL;
HParser *equal = NULL;
HParser *semicolon = NULL;
HParser *comment = NULL;
HParser *c_nl = NULL;
HParser *c_sp = NULL;
HParser *defined_as = NULL;
HParser *alphas = NULL;
HParser *rule = NULL;
HParser *rulelist = NULL;
HParser *p = NULL;
int i, j, r, s_size;
char *s = NULL;
const char *test_string_template = "x = y z%s;%s\n\n";
char buf_1[BUG60_ABNF_SCAN_UP_TO+1];
char buf_2[2*BUG60_ABNF_SCAN_UP_TO+1];
newline = h_ch('\n');
alpha = h_choice(h_ch_range('A', 'Z'), h_ch_range('a', 'z'), NULL);
sp = h_ch(' ');
vchar = h_ch_range(0x21, 0x7e);
equal = h_ch('=');
semicolon = h_ch(';');
comment = h_sequence(
semicolon,
h_many(h_choice(sp, vchar, NULL)),
newline,
NULL);
c_nl = h_choice(comment, newline, NULL);
c_sp = h_choice(sp, h_sequence(c_nl, sp, NULL), NULL);
defined_as = h_sequence(h_many(c_sp), equal, h_many(c_sp), NULL);
alphas = h_sequence(
alpha,
h_many(h_sequence(h_many1(c_sp), alpha, NULL)),
h_many(c_sp),
NULL);
rule = h_sequence(alpha, defined_as, alphas, c_nl, NULL);
rulelist = h_many1(h_choice(
rule,
h_sequence(h_many(c_sp), c_nl, NULL),
NULL));
p = rulelist;
g_check_compilable(p, PB_GLR, 1);
/* Have a buffer for the string */
s_size = strlen(test_string_template) + 3*BUG60_ABNF_SCAN_UP_TO + 1;
s = malloc(s_size);
g_check_cmp_ptr(s, !=, NULL);
/*
* Try to parse all the different strings according to the template up to
* the scan limit.
*
* Correct behavior: it parses for all values of i, j.
* Bugged behavior: when i % 3 != 0, parse failures begin to occur at
* j == (i / 3) + (i % 3).
*/
for (i = 0; i < BUG60_ABNF_SCAN_UP_TO; ++i) {
memset(buf_1, ' ', i);
buf_1[i] = 0;
for (j = 0; j < 2*BUG60_ABNF_SCAN_UP_TO; ++j) {
memset(buf_2, 'x', j);
buf_2[j] = 0;
snprintf(s, s_size, test_string_template, buf_1, buf_2);
g_check_parse_ok_no_compile(p, s, strlen(s));
}
}
free(s);
}
static void test_bug95_lalr_k_param() {
/*
* The LR backends had been left hardcoded to k = 1 and were ignoring the param value
* This example compiles for LALR(k) where k = 2
* but does not compile for k = 1
* This shows that the parameter is being used rather than ignored.
* The default value of k when the param == NULL is set to k = 1
*/
HParser *a = h_ch('a');
HParser *b = h_ch('b');
HParser *c = h_ch('c');
HParser *B = h_indirect();
HParser *A = h_sequence (a, B, c, NULL);
HParser *B_ = h_choice(B, b, NULL);
h_bind_indirect(B, B_);
HParser *p = A;
if (h_compile(p, PB_LALR, (void *)1) == 0) {
g_test_message("should not compile for lalr(1)");
g_test_fail();
}
g_check_compilable(p, PB_LALR, 2);
g_check_parse_match_no_compile(p, "abc",3, "(u0x61 u0x62 u0x63)");
/* The next test shows that the default works for compile with param == NULL */
/* (default is k = 1) */
g_check_parse_match(h_sequence(a, b, c, NULL), PB_LALR, "abc",3, "(u0x61 u0x62 u0x63)");
}
void register_regression_tests(void) {
g_test_add_func("/core/regression/bug118", test_bug118);
g_test_add_func("/core/regression/seq_index_path", test_seq_index_path);
......@@ -280,4 +653,13 @@ void register_regression_tests(void) {
g_test_add_func("/core/regression/cfg_many_seq", test_cfg_many_seq);
g_test_add_func("/core/regression/charset_bits", test_charset_bits);
g_test_add_func("/core/regression/bug19", test_bug_19);
g_test_add_func("/core/regression/flatten_null", test_flatten_null);
//XXX g_test_add_func("/core/regression/ast_length_index", test_ast_length_index);
g_test_add_func("/core/regression/issue91", test_issue91);
g_test_add_func("/core/regression/issue87", test_issue87);
g_test_add_func("/core/regression/issue92", test_issue92);
g_test_add_func("/core/regression/issue83", test_issue83);
g_test_add_func("/core/regression/bug60", test_bug60);
g_test_add_func("/core/regression/bug60_abnf", test_bug60_abnf);
g_test_add_func("/core/regression/bug95_lalrk_param", test_bug95_lalr_k_param);
}
......@@ -25,6 +25,7 @@ extern void register_parser_tests();
extern void register_grammar_tests();
extern void register_misc_tests();
extern void register_mm_tests();
extern void register_names_tests();
extern void register_benchmark_tests();
extern void register_regression_tests();
......@@ -38,6 +39,7 @@ int main(int argc, char** argv) {
register_grammar_tests();
register_misc_tests();
register_mm_tests();
register_names_tests();
register_regression_tests();
if (g_test_slow() || g_test_perf())
register_benchmark_tests();
......
......@@ -35,6 +35,18 @@
} \
} while(0)
/* Comparison for ptr types; only == and != will work */
#define g_check_cmp_ptr(p1, op, p2) do { \
const void *_p1 = (p1); \
const void *_p2 = (p2); \
if (!(_p1 op _p2)) { \
g_test_message("Check failed: (%s): (%p %s %p)", \
#p1 " " #op " " #p2, \
_p1, #op, _p2); \
g_test_fail(); \
} \
} while (0);
#define g_check_bytes(len, n1, op, n2) do { \
const uint8_t *_n1 = (n1); \
const uint8_t *_n2 = (n2); \
......@@ -56,6 +68,32 @@
} \
} while(0)
#define g_check_maybe_string_eq(n1, n2) do { \
const char *_n1 = (n1); \
const char *_n2 = (n2); \
if (_n1 != _n2 && _n1 != NULL && _n2 != NULL) { \
if (!(strcmp(_n1, _n2) == 0)) { \
g_test_message("Check failed: (%s) (\"%s\" == \"%s\")", \
#n1 " == " #n2, _n1, _n2); \
g_test_fail(); \
} \
} else { \
if (_n1 != NULL || _n2 != NULL) { \
if (_n1 != NULL && _n2 == NULL) { \
g_test_message("Check failed: (%s) (\"%s\" == NULL)", \
#n1 " == " #n2, _n1); \
g_test_fail(); \
} else if (_n1 == NULL && _n2 != NULL) { \
g_test_message("Check failed: (%s) (NULL == \"%s\")", \
#n1 " == " #n2, _n2); \
g_test_fail(); \
} \
/* else both are not-NULL, but point to the same string - succeed */ \
} \
/* else both are NULL, succeed */ \
} \
} while(0)
#define g_check_regular(lang) do { \
if (!lang->isValidRegular(lang->env)) { \
g_test_message("Language is not regular"); \
......@@ -71,24 +109,36 @@
} while(0)
#define g_check_compilable(lang, backend, params) do { \
if (!h_compile(lang, backend, params)) { \
g_test_message("Language is not %s(%s)", #backend, params); \
int r = h_compile((HParser *)(lang), (HParserBackend)(backend), (void *)(params)); \
if (r != 0) { \
g_test_message("Language is not %s(%s)", #backend, #params); \
g_test_fail(); \
} \
} while(0)
#define print_arena_stats(arena) do { \
if (g_test_verbose()) { \
HArenaStats stats; \
h_allocator_stats(arena, &stats); \
g_test_message("Parse used %zd bytes, wasted %zd bytes. " \
"Inefficiency: %5f%%", \
stats.used, stats.wasted, \
stats.wasted * 100. / (stats.used+stats.wasted)); \
} \
} while(0)
#define g_check_parse_failed__m(mm__, parser, backend, input, inp_len) do { \
int skip = h_compile__m(mm__, (HParser *)(parser), (HParserBackend)backend, NULL); \
if(skip != 0) { \
g_test_message("Compile failed"); \
g_test_message("Compile failed on line %d", __LINE__); \
g_test_fail(); \
break; \
} \
HParseResult *result = h_parse__m(mm__, parser, (const uint8_t*)input, inp_len); \
if (NULL != result) { \
h_parse_result_free(result); \
g_test_message("Check failed: shouldn't have succeeded, but did"); \
HParseResult *res = h_parse__m(mm__, parser, (const uint8_t*)input, inp_len); \
if (NULL != res) { \
print_arena_stats(res->arena); \
h_parse_result_free(res); \
g_test_message("Check failed: parse shouldn't have succeeded, but did on line %d", __LINE__); \
g_test_fail(); \
} \
} while(0)
......@@ -96,36 +146,61 @@
#define g_check_parse_failed(p, be, input, len) \
g_check_parse_failed__m(&system_allocator, p, be, input, len)
#define g_check_parse_ok(parser, backend, input, inp_len) do { \
int skip = h_compile((HParser *)(parser), (HParserBackend) backend, NULL); \
#define g_check_parse_failed_no_compile__m(mm__, parser, input, inp_len) do { \
HParseResult *res = h_parse__m(mm__, parser, (const uint8_t*)input, inp_len); \
if (NULL != res) { \
print_arena_stats(res->arena); \
h_parse_result_free(res); \
g_test_message("Check failed: shouldn't have succeeded, but did on ;ine %d", __LINE__); \
g_test_fail(); \
} \
} while(0)
#define g_check_parse_failed_no_compile(p, input, len) \
g_check_parse_failed__m(&system_allocator, p, input, len)
#define g_check_parse_ok__m(mm__, parser, backend, input, inp_len) do { \
int skip = h_compile__m(mm__, (HParser *)(parser), (HParserBackend) backend, NULL); \
if(skip) { \
g_test_message("Compile failed"); \
g_test_fail(); \
break; \
} \
HParseResult *res = h_parse(parser, (const uint8_t*)input, inp_len); \
HParseResult *res = h_parse__m(mm__, parser, (const uint8_t*)input, inp_len); \
if (!res) { \
g_test_message("Parse failed on line %d", __LINE__); \
g_test_fail(); \
} else { \
HArenaStats stats; \
h_allocator_stats(res->arena, &stats); \
g_test_message("Parse used %zd bytes, wasted %zd bytes. " \
"Inefficiency: %5f%%", \
stats.used, stats.wasted, \
stats.wasted * 100. / (stats.used+stats.wasted)); \
print_arena_stats(res->arena); \
h_parse_result_free(res); \
} \
} while(0)
#define g_check_parse_match(parser, backend, input, inp_len, result) do { \
int skip = h_compile((HParser *)(parser), (HParserBackend) backend, NULL); \
#define g_check_parse_ok(p, be, input, len) \
g_check_parse_ok__m(&system_allocator, p, be, input, len)
#define g_check_parse_ok_no_compile__m(mm__, parser, input, inp_len) do { \
HParseResult *res = h_parse__m(mm__, parser, (const uint8_t*)input, inp_len); \
if (!res) { \
g_test_message("Parse failed on line %d", __LINE__); \
g_test_fail(); \
} else { \
print_arena_stats(res->arena); \
h_parse_result_free(res); \
} \
} while(0)
#define g_check_parse_ok_no_compile(p, input, len) \
g_check_parse_ok_no_compile__m(&system_allocator, p, input, len)
#define g_check_parse_match__m(mm__, parser, backend, input, inp_len, result) do { \
int skip = h_compile__m(mm__, (HParser *)(parser), (HParserBackend) backend, NULL); \
if(skip) { \
g_test_message("Compile failed"); \
g_test_fail(); \
break; \
} \
HParseResult *res = h_parse(parser, (const uint8_t*)input, inp_len); \
HParseResult *res = h_parse__m(mm__, (HParser *)(parser), (const uint8_t*)input, inp_len); \
if (!res) { \
g_test_message("Parse failed on line %d", __LINE__); \
g_test_fail(); \
......@@ -133,16 +208,31 @@
char* cres = h_write_result_unamb(res->ast); \
g_check_string(cres, ==, result); \
(&system_allocator)->free(&system_allocator, cres); \
HArenaStats stats; \
h_allocator_stats(res->arena, &stats); \
g_test_message("Parse used %zd bytes, wasted %zd bytes. " \
"Inefficiency: %5f%%", \
stats.used, stats.wasted, \
stats.wasted * 100. / (stats.used+stats.wasted)); \
print_arena_stats(res->arena); \
h_parse_result_free(res); \
} \
} while(0)
#define g_check_parse_match(parser, backend, input, inp_len, result) \
g_check_parse_match__m(&system_allocator, parser, backend, input, inp_len, result)
#define g_check_parse_match_no_compile__m(mm__, parser, input, inp_len, result) do { \
HParseResult *res = h_parse__m(mm__, (HParser *)(parser), (const uint8_t*)input, inp_len); \
if (!res) { \
g_test_message("Parse failed on line %d", __LINE__); \
g_test_fail(); \
} else { \
char* cres = h_write_result_unamb(res->ast); \
g_check_string(cres, ==, result); \
(&system_allocator)->free(&system_allocator, cres); \
print_arena_stats(res->arena); \
h_parse_result_free(res); \
} \
} while(0)
#define g_check_parse_match_no_compile(parser, input, inp_len, result) \
g_check_parse_match_no_compile__m(&system_allocator, parser, input, inp_len, result)
#define g_check_parse_chunks_failed__m(mm__, parser, backend, chunk1, c1_len, chunk2, c2_len) do { \
int skip = h_compile__m(mm__, (HParser *)(parser), (HParserBackend)backend, NULL); \
if(skip) { \
......@@ -154,7 +244,7 @@
} while(0)
#define g_check_parse_chunks_failed___m(mm__, parser, chunk1, c1_len, chunk2, c2_len) do { \
HSuspendedParser *s = h_parse_start__m(mm__, parser); \
HSuspendedParser *s = h_parse_start__m(mm__, (HParser *)(parser)); \
if(!s) { \
g_test_message("Chunk-wise parsing not available"); \
g_test_fail(); \
......@@ -187,7 +277,7 @@
} while(0)
#define g_check_parse_chunks_ok_(parser, chunk1, c1_len, chunk2, c2_len) do { \
HSuspendedParser *s = h_parse_start(parser); \
HSuspendedParser *s = h_parse_start((HParser *)(parser)); \
if(!s) { \
g_test_message("Chunk-wise parsing not available"); \
g_test_fail(); \
......@@ -200,12 +290,7 @@
g_test_message("Parse failed on line %d", __LINE__); \
g_test_fail(); \
} else { \
HArenaStats stats; \
h_allocator_stats(res->arena, &stats); \
g_test_message("Parse used %zd bytes, wasted %zd bytes. " \
"Inefficiency: %5f%%", \
stats.used, stats.wasted, \
stats.wasted * 100. / (stats.used+stats.wasted)); \
print_arena_stats(res->arena); \
h_parse_result_free(res); \
} \
} while(0)
......@@ -221,7 +306,7 @@
} while(0)
#define g_check_parse_chunks_match_(parser, chunk1, c1_len, chunk2, c2_len, result) do { \
HSuspendedParser *s = h_parse_start(parser); \
HSuspendedParser *s = h_parse_start((HParser *)(parser)); \
if(!s) { \
g_test_message("Chunk-wise parsing not available"); \
g_test_fail(); \
......@@ -237,12 +322,98 @@
char* cres = h_write_result_unamb(res->ast); \
g_check_string(cres, ==, result); \
(&system_allocator)->free(&system_allocator, cres); \
HArenaStats stats; \
h_allocator_stats(res->arena, &stats); \
g_test_message("Parse used %zd bytes, wasted %zd bytes. " \
"Inefficiency: %5f%%", \
stats.used, stats.wasted, \
stats.wasted * 100. / (stats.used+stats.wasted)); \
print_arena_stats(res->arena); \
h_parse_result_free(res); \
} \
} while(0)
#define g_check_parse_chunk_failed__m(mm__, parser, backend, chunk1, c1_len) do { \
int skip = h_compile__m(mm__, (HParser *)(parser), (HParserBackend)backend, NULL); \
if(skip) { \
g_test_message("Compile failed"); \
g_test_fail(); \
break; \
} \
g_check_parse_chunk_failed___m(mm__, parser, chunk1, c1_len); \
} while(0)
#define g_check_parse_chunk_failed___m(mm__, parser, chunk1, c1_len) do { \
HSuspendedParser *s = h_parse_start__m(mm__, (HParser *)(parser)); \
if(!s) { \
g_test_message("Chunk-wise parsing not available"); \
g_test_fail(); \
break; \
} \
h_parse_chunk(s, (const uint8_t*)chunk1, c1_len); \
HParseResult *res = h_parse_finish(s); \
if (NULL != res) { \
h_parse_result_free(res); \
g_test_message("Check failed: shouldn't have succeeded, but did"); \
g_test_fail(); \
} \
} while(0)
#define g_check_parse_chunk_failed(p, be, c1, c1_len) \
g_check_parse_chunk_failed__m(&system_allocator, p, be, c1, c1_len)
#define g_check_parse_chunk_failed_(p, c1, c1_len) \
g_check_parse_chunk_failed___m(&system_allocator, p, c1, c1_len)
#define g_check_parse_chunk_ok(parser, backend, chunk1, c1_len) do { \
int skip = h_compile((HParser *)(parser), (HParserBackend)backend, NULL); \
if(skip) { \
g_test_message("Compile failed"); \
g_test_fail(); \
break; \
} \
g_check_parse_chunk_ok_(parser, chunk1, c1_len); \
} while(0)
#define g_check_parse_chunk_ok_(parser, chunk1, c1_len) do { \
HSuspendedParser *s = h_parse_start((HParser *)(parser)); \
if(!s) { \
g_test_message("Chunk-wise parsing not available"); \
g_test_fail(); \
break; \
} \
h_parse_chunk(s, (const uint8_t*)chunk1, c1_len); \
HParseResult *res = h_parse_finish(s); \
if (!res) { \
g_test_message("Parse failed on line %d", __LINE__); \
g_test_fail(); \
} else { \
print_arena_stats(res->arena); \
h_parse_result_free(res); \
} \
} while(0)
#define g_check_parse_chunk_match(parser, backend, chunk1, c1_len, result) do { \
int skip = h_compile((HParser *)(parser), (HParserBackend) backend, NULL); \
if(skip) { \
g_test_message("Compile failed"); \
g_test_fail(); \
break; \
} \
g_check_parse_chunk_match_(parser, chunk1, c1_len, result); \
} while(0)
#define g_check_parse_chunk_match_(parser, chunk1, c1_len, result) do { \
HSuspendedParser *s = h_parse_start((HParser *)(parser)); \
if(!s) { \
g_test_message("Chunk-wise parsing not available"); \
g_test_fail(); \
break; \
} \
h_parse_chunk(s, (const uint8_t*)chunk1, c1_len); \
HParseResult *res = h_parse_finish(s); \
if (!res) { \
g_test_message("Parse failed on line %d", __LINE__); \
g_test_fail(); \
} else { \
char* cres = h_write_result_unamb(res->ast); \
g_check_string(cres, ==, result); \
(&system_allocator)->free(&system_allocator, cres); \
print_arena_stats(res->arena); \
h_parse_result_free(res); \
} \
} while(0)
......@@ -321,7 +492,7 @@
#define g_check_cmp_int64(n1, op, n2) g_check_inttype("%" PRId64, int64_t, n1, op, n2)
#define g_check_cmp_uint32(n1, op, n2) g_check_inttype("%u", uint32_t, n1, op, n2)
#define g_check_cmp_uint64(n1, op, n2) g_check_inttype("%" PRIu64, uint64_t, n1, op, n2)
#define g_check_cmp_ptr(n1, op, n2) g_check_inttype("%p", void *, n1, op, n2)
#define g_check_cmp_size(n1, op, n2) g_check_inttype("%zu", size_t, n1, op, n2)
#define g_check_cmpfloat(n1, op, n2) g_check_inttype("%g", float, n1, op, n2)
#define g_check_cmpdouble(n1, op, n2) g_check_inttype("%g", double, n1, op, n2)
......