apfl/src/parser_test.c

151 lines
4.3 KiB
C
Raw Normal View History

2021-12-16 22:42:37 +00:00
#include "apfl.h"
#include "test.h"
struct parser_test {
testctx t;
void *source_reader_ctx;
apfl_tokenizer_ptr tokenizer;
apfl_parser_ptr parser;
};
static struct parser_test *
new_parser_test(testctx t, const char *source)
{
struct parser_test *pt = must_alloc(t, sizeof(struct parser_test));
pt->t = t;
if ((pt->source_reader_ctx = apfl_string_source_reader_new(apfl_string_view_from(source))) == NULL) {
test_fatalf(t, "Failed initializing source reader");
}
if ((pt->tokenizer = apfl_tokenizer_new(apfl_string_source_reader, pt->source_reader_ctx)) == NULL) {
test_fatalf(t, "Failed initializing the tokenizer");
}
if ((pt->parser = apfl_parser_new(apfl_tokenizer_as_token_source(pt->tokenizer))) == NULL) {
test_fatalf(t, "Failed initializing the parser");
}
return pt;
}
static void
destroy_parser_test(struct parser_test *pt)
{
apfl_parser_destroy(pt->parser);
apfl_tokenizer_destroy(pt->tokenizer);
apfl_string_source_reader_destroy(pt->source_reader_ctx);
free(pt);
}
static void
expect_eof(struct parser_test *pt)
{
switch (apfl_parser_next(pt->parser)) {
case APFL_PARSE_OK:
test_fatalf(pt->t, "Expected EOF but got an expression");
break;
case APFL_PARSE_EOF:
break;
case APFL_PARSE_ERROR:
test_failf(pt->t, "Got an error instead of an EOF");
apfl_error_print(apfl_parser_get_error(pt->parser), stderr);
test_fatal(pt->t);
break;
}
}
static void
expect_expr(struct parser_test *pt, struct apfl_expr expected)
{
struct apfl_expr expr;
switch (apfl_parser_next(pt->parser)) {
case APFL_PARSE_OK:
expr = apfl_parser_get_expr(pt->parser);
if (!apfl_expr_eq(expr, expected)) {
test_failf(pt->t, "Expected expression differs from actual expression");
test_failf(pt->t, "Expected:");
apfl_expr_print(expected, stderr);
test_failf(pt->t, "Have:");
apfl_expr_print(expr, stderr);
}
apfl_expr_deinit(&expr);
apfl_expr_deinit(&expected);
break;
case APFL_PARSE_EOF:
test_fatalf(pt->t, "Extected an expression but got EOF");
break;
case APFL_PARSE_ERROR:
test_failf(pt->t, "Got an error instead of an EOF");
apfl_error_print(apfl_parser_get_error(pt->parser), stderr);
test_fatal(pt->t);
break;
}
}
static struct apfl_string
new_string(struct parser_test *pt, const char *in)
{
struct apfl_string out = { .bytes = NULL, .len = 0 };
if (!apfl_string_copy(&out, apfl_string_view_from(in))) {
test_fatalf(pt->t, "Failed copying string in new_string");
}
return out;
}
static void *
new_helper(struct parser_test *pt, size_t size, void *data)
{
void *out = must_alloc(pt->t, size);
memcpy(out, data, size);
return out;
}
// Fugly macros to make it a bit easier to create a heap allocated struct value
#define BEGIN_NEW(pt, T) ((T *)new_helper(pt, sizeof(T), &((T)
#define END_NEW )))
TEST(empty, t) {
struct parser_test *pt = new_parser_test(t, "");
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(hello_world, t) {
struct parser_test *pt = new_parser_test(t, "print \"Hello World!\"");
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position.line = 1,
.position.col = 1,
.call = (struct apfl_expr_call) {
.callee = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_VAR,
.position.line = 1,
.position.col = 1,
.var = new_string(pt, "print"),
} END_NEW,
.arguments = (struct apfl_expr_list) {
.len = 1,
.items = BEGIN_NEW(pt, struct apfl_expr_list_item) {
.expand = false,
.expr = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CONSTANT,
.position.line = 1,
.position.col = 7,
.constant.type = APFL_EXPR_CONST_STRING,
.constant.string = new_string(pt, "Hello World!"),
} END_NEW,
} END_NEW,
},
},
});
expect_eof(pt);
destroy_parser_test(pt);
}
TESTS_BEGIN
ADDTEST(empty),
ADDTEST(hello_world),
TESTS_END