apfl/src/parser_test.c

1246 lines
49 KiB
C
Raw Normal View History

2021-12-17 20:08:03 +00:00
#include <assert.h>
2021-12-16 22:42:37 +00:00
#include "apfl.h"
2021-12-17 20:08:03 +00:00
#include "resizable.h"
2021-12-16 22:42:37 +00:00
#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 expression");
2021-12-16 22:42:37 +00:00
apfl_error_print(apfl_parser_get_error(pt->parser), stderr);
test_fatal(pt->t);
break;
}
}
2021-12-18 23:27:34 +00:00
static void
expect_error_of_type(struct parser_test *pt, enum apfl_error_type want)
{
struct apfl_error have;
switch (apfl_parser_next(pt->parser)) {
case APFL_PARSE_OK:
test_failf(pt->t, "Expected error but got an OK");
break;
case APFL_PARSE_EOF:
test_fatalf(pt->t, "Expected error but got an EOF");
break;
case APFL_PARSE_ERROR:
have = apfl_parser_get_error(pt->parser);
if (have.type != want) {
test_failf(pt->t, "Expected error of type %s, got this error instead:", apfl_error_type_name(want));
apfl_error_print(have, stderr);
}
break;
}
}
2021-12-16 22:42:37 +00:00
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;
}
2021-12-17 20:08:03 +00:00
static struct apfl_expr_list_item
list_item(bool expand, struct apfl_expr *expr)
{
return (struct apfl_expr_list_item) {
.expand = expand,
.expr = expr,
};
}
2021-12-16 22:42:37 +00:00
// 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 )))
2021-12-17 20:08:03 +00:00
enum listbuilder_cmd {
LISTBUILDER_ADD,
LISTBUILDER_STOP,
};
#define LISTBUILDER_NAME(n) listbuilder_##n
#define LISTBUILDER_ITEM_NAME(n) listbuilder_item_##n
2021-12-17 20:08:03 +00:00
#define MKLISTBUILDER(name, listtype, itemtype, items_memb, len_memb) \
struct LISTBUILDER_ITEM_NAME(name) { \
bool has_item; \
itemtype item; \
}; \
2021-12-17 20:08:03 +00:00
listtype \
LISTBUILDER_NAME(name)( \
struct parser_test *pt, \
struct LISTBUILDER_ITEM_NAME(name) items[] \
) { \
2021-12-17 20:08:03 +00:00
listtype body; \
size_t cap = 0; \
\
apfl_resizable_init((void **)&body.items_memb, &body.len_memb, &cap); \
\
for (items++; items->has_item; items++) { \
2021-12-17 20:08:03 +00:00
if (!apfl_resizable_append( \
sizeof(itemtype), \
(void **)&body.items_memb, \
&body.len, \
&cap, \
&items->item, \
2021-12-17 20:08:03 +00:00
1 \
)) { \
test_fatalf(pt->t, "Failed appending"); \
assert(false); \
} \
} \
\
return body; \
} \
#define LIST_BEGIN(pt, builder) (LISTBUILDER_NAME(builder)(pt, (struct LISTBUILDER_ITEM_NAME(builder)[]) {{.has_item=false
#define LIST_END }, {.has_item = false}}))
#define LIST_ADD }, {.has_item = true, .item =
2021-12-17 20:08:03 +00:00
MKLISTBUILDER(list, struct apfl_expr_list, struct apfl_expr_list_item, items, len)
MKLISTBUILDER(body, struct apfl_expr_body, struct apfl_expr, items, len)
MKLISTBUILDER(dict, struct apfl_expr_dict, struct apfl_expr_dict_pair, items, len)
MKLISTBUILDER(complex_func, struct apfl_expr_complex_func, struct apfl_expr_subfunc, subfuncs, len)
MKLISTBUILDER(params, struct apfl_expr_params, struct apfl_expr_param, params, len)
2021-12-18 15:12:37 +00:00
MKLISTBUILDER(assignable_list, struct apfl_expr_assignable_list, struct apfl_expr_assignable, children, len)
2021-12-17 20:08:03 +00:00
#define POS(l, c) (struct apfl_position) { .line = l, .col = c }
static struct apfl_expr
var(struct parser_test *pt, int line, int col, const char *v)
{
return (struct apfl_expr) {
.type = APFL_EXPR_VAR,
.position = POS(line, col),
.var = new_string(pt, v),
};
}
struct apfl_expr *
new_var(struct parser_test *pt, int line, int col, const char *v)
{
struct apfl_expr expr = var(pt, line, col, v);
return new_helper(pt, sizeof(struct apfl_expr), &expr);
}
static struct apfl_expr
dot(struct parser_test *pt, int line, int col, const char *rhs, struct apfl_expr *lhs)
{
return (struct apfl_expr) {
.type = APFL_EXPR_DOT,
.position = POS(line, col),
.dot.lhs = lhs,
.dot.rhs = new_string(pt, rhs),
};
}
static struct apfl_expr *
new_dot(struct parser_test *pt, int line, int col, const char *rhs, struct apfl_expr *lhs)
{
struct apfl_expr expr = dot(pt, line, col, rhs, lhs);
return new_helper(pt, sizeof(struct apfl_expr), &expr);
}
static struct apfl_expr_const
num_const(apfl_number n)
{
return (struct apfl_expr_const) {
.type = APFL_EXPR_CONST_NUMBER,
.number = n,
};
}
static struct apfl_expr_const
string_const(struct parser_test *pt, const char *s)
{
return (struct apfl_expr_const) {
.type = APFL_EXPR_CONST_STRING,
.string = new_string(pt, s),
};
}
static struct apfl_expr_const
bool_const(bool b)
{
return (struct apfl_expr_const) {
.type = APFL_EXPR_CONST_BOOLEAN,
.boolean = b,
};
}
static struct apfl_expr
const_expr(int line, int col, struct apfl_expr_const constant)
{
return (struct apfl_expr) {
.type = APFL_EXPR_CONSTANT,
.position = POS(line, col),
.constant = constant,
};
}
static struct apfl_expr *
new_const_expr(struct parser_test *pt, int line, int col, struct apfl_expr_const constant)
{
struct apfl_expr expr = const_expr(line, col, constant);
return new_helper(pt, sizeof(struct apfl_expr), &expr);
}
2021-12-16 22:42:37 +00:00
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,
2021-12-17 20:08:03 +00:00
.position = POS(1, 1),
2021-12-16 22:42:37 +00:00
.call = (struct apfl_expr_call) {
2021-12-17 20:08:03 +00:00
.callee = new_var(pt, 1, 1, "print"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD (struct apfl_expr_list_item) {
2021-12-16 22:42:37 +00:00
.expand = false,
.expr = new_const_expr(pt, 1, 7, string_const(pt, "Hello World!")),
2021-12-17 20:08:03 +00:00
},
LIST_END,
},
});
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(empty_function, t) {
struct parser_test *pt = new_parser_test(t, "{}");
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_SIMPLE_FUNC,
.position = POS(1, 1),
.simple_func = LIST_BEGIN(pt, body)
LIST_END,
});
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(empty_list, t) {
struct parser_test *pt = new_parser_test(t, "[]");
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_LIST,
.position = POS(1, 1),
.list = LIST_BEGIN(pt, list)
LIST_END,
});
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(empty_dict, t) {
struct parser_test *pt = new_parser_test(t, "[->]");
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_DICT,
.position = POS(1, 1),
.dict = LIST_BEGIN(pt, dict)
LIST_END,
});
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(simple_dot_access, t) {
struct parser_test *pt = new_parser_test(t, "foo.bar");
expect_expr(pt, dot(pt, 1, 4, "bar", new_var(pt, 1, 1, "foo")));
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(simple_at_access, t) {
struct parser_test *pt = new_parser_test(t, "foo@bar");
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_AT,
.position = POS(1, 4),
.at.lhs = new_var(pt, 1, 1, "foo"),
.at.rhs = new_var(pt, 1, 5, "bar"),
});
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(parens, t) {
// 1 2 3 4
// 12345678901234567890123456789012345678901234567
struct parser_test *pt = new_parser_test(t, "foo (bar baz) (aaa ~bbb (ccc) ~(ddd (eee fff)))");
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(1, 1),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 1, 1, "foo"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(1, 5),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 1, 6, "bar"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 1, 10, "baz")),
LIST_END
},
} END_NEW),
LIST_ADD list_item(false, BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(1, 15),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 1, 16, "aaa"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(true, new_var(pt, 1, 21, "bbb")),
LIST_ADD list_item(false, BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(1, 25),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 1, 26, "ccc"),
.arguments = LIST_BEGIN(pt, list)
LIST_END,
},
} END_NEW),
LIST_ADD list_item(true, BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(1, 32),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 1, 33, "ddd"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(1, 37),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 1, 38, "eee"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 1, 42, "fff")),
LIST_END,
},
} END_NEW),
LIST_END,
},
} END_NEW),
LIST_END,
},
} END_NEW),
LIST_END,
},
});
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(complex_dot_at_access, t) {
// 1 2
// 123456789 01 23456789012345
struct parser_test *pt = new_parser_test(t, "a@b.c@1@\"d\"@(e@(f.g h).i)");
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_AT,
.position = POS(1, 12),
.at = (struct apfl_expr_at) {
.lhs = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_AT,
.position = POS(1, 8),
.at = (struct apfl_expr_at) {
.lhs = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_AT,
.position = POS(1, 6),
.at = (struct apfl_expr_at) {
.lhs = new_dot(pt, 1, 4, "c", BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_AT,
.position = POS(1, 2),
.at = (struct apfl_expr_at) {
.lhs = new_var(pt, 1, 1, "a"),
.rhs = new_var(pt, 1, 3, "b"),
}
} END_NEW),
.rhs = new_const_expr(pt, 1, 7, num_const(1)),
2021-12-17 20:08:03 +00:00
},
} END_NEW,
.rhs = new_const_expr(pt, 1, 9, string_const(pt, "d")),
2021-12-17 20:08:03 +00:00
},
} END_NEW,
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(1, 13),
.call = (struct apfl_expr_call) {
.callee = new_dot(pt, 1, 23, "i", BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_AT,
.position = POS(1, 15),
.at = (struct apfl_expr_at) {
.lhs = new_var(pt, 1, 14, "e"),
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(1, 16),
.call = (struct apfl_expr_call) {
.callee = new_dot(pt, 1, 18, "g",
new_var(pt, 1, 17, "f")
),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD (struct apfl_expr_list_item) {
.expr = new_var(pt, 1, 21, "h"),
.expand = false,
},
LIST_END,
},
} END_NEW,
},
} END_NEW),
.arguments = LIST_BEGIN(pt, list)
LIST_END,
},
} END_NEW,
},
});
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(factorial, t) {
struct parser_test *pt = new_parser_test(t,
// 1 2 3
// 12345678901234567890123456789012
"factorial := {\n"
" 0 -> 1\n"
" n -> * n (factorial (- n 1))\n"
"}\n"
"factorial 10"
);
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_ASSIGNMENT,
.position = POS(1, 11),
.assignment = (struct apfl_expr_assignment) {
.lhs = (struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_VAR,
.var = new_string(pt, "factorial"),
2021-12-16 22:42:37 +00:00
},
2021-12-17 20:08:03 +00:00
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_COMPLEX_FUNC,
.position = POS(1, 14),
.complex_func = LIST_BEGIN(pt, complex_func)
LIST_ADD (struct apfl_expr_subfunc) {
.params = LIST_BEGIN(pt, params)
LIST_ADD (struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_CONSTANT,
.constant = num_const(0),
2021-12-17 20:08:03 +00:00
},
LIST_END,
.body = LIST_BEGIN(pt, body)
LIST_ADD const_expr(2, 10, num_const(1)),
2021-12-17 20:08:03 +00:00
LIST_END
},
LIST_ADD (struct apfl_expr_subfunc) {
.params = LIST_BEGIN(pt, params)
LIST_ADD (struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "n"),
},
LIST_END,
.body = LIST_BEGIN(pt, body)
LIST_ADD (struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(3, 10),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 3, 10, "*"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 3, 12, "n")),
LIST_ADD list_item(false, BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(3, 14),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 3, 15, "factorial"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(3, 25),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 3, 26, "-"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 3, 28, "n")),
LIST_ADD list_item(false, new_const_expr(pt, 3, 30,num_const(1))),
2021-12-17 20:08:03 +00:00
LIST_END,
},
} END_NEW),
LIST_END,
},
} END_NEW),
LIST_END,
},
},
LIST_END
},
LIST_END
} END_NEW
},
});
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(5, 1),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 5, 1, "factorial"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_const_expr(pt, 5, 11, num_const(10))),
2021-12-17 20:08:03 +00:00
LIST_END,
},
});
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(map, t) {
struct parser_test *pt = new_parser_test(t,
// 123456789012345678901234
"map := {\n"
"_ [] -> []\n"
"f [x ~xs] ->\n"
" [(f x) ~(map f xs)]\n"
"}\n"
);
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_ASSIGNMENT,
.position = POS(1, 5),
.assignment = (struct apfl_expr_assignment) {
.lhs = (struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_VAR,
.var = new_string(pt, "map"),
},
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_COMPLEX_FUNC,
.position = POS(1, 8),
.complex_func = LIST_BEGIN(pt, complex_func)
LIST_ADD (struct apfl_expr_subfunc) {
.params = LIST_BEGIN(pt, params)
LIST_ADD (struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "_"),
},
LIST_ADD (struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_LIST,
.list = LIST_BEGIN(pt, params)
LIST_END,
},
LIST_END,
.body = LIST_BEGIN(pt, body)
LIST_ADD (struct apfl_expr) {
.type = APFL_EXPR_LIST,
.position = POS(2, 9),
.list = LIST_BEGIN(pt, list)
LIST_END,
},
LIST_END,
},
LIST_ADD (struct apfl_expr_subfunc) {
.params = LIST_BEGIN(pt, params)
LIST_ADD (struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "f"),
},
LIST_ADD (struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_LIST,
.list = LIST_BEGIN(pt, params)
LIST_ADD (struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "x"),
},
LIST_ADD (struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_EXPAND,
.expand = BEGIN_NEW(pt, struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "xs"),
} END_NEW
},
LIST_END,
},
LIST_END,
.body = LIST_BEGIN(pt, body)
LIST_ADD (struct apfl_expr) {
.type = APFL_EXPR_LIST,
.position = POS(4, 5),
.list = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(4, 6),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 4, 7, "f"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 4, 9, "x")),
LIST_END,
},
} END_NEW),
LIST_ADD list_item(true, BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(4, 13),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 4, 14, "map"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 4, 18, "f")),
LIST_ADD list_item(false, new_var(pt, 4, 20, "xs")),
LIST_END
},
} END_NEW),
LIST_END,
},
LIST_END
},
LIST_END,
} END_NEW,
2021-12-16 22:42:37 +00:00
},
});
expect_eof(pt);
destroy_parser_test(pt);
}
2021-12-18 15:12:37 +00:00
TEST(lists, t) {
struct parser_test *pt = new_parser_test(t,
// 123456789
"[1, 2 3,,# some comment\n"
",4 ~x ]"
);
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_LIST,
.position = POS(1, 1),
.list = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_const_expr(pt, 1, 2, num_const(1))),
LIST_ADD list_item(false, new_const_expr(pt, 1, 5, num_const(2))),
LIST_ADD list_item(false, new_const_expr(pt, 1, 7, num_const(3))),
LIST_ADD list_item(false, new_const_expr(pt, 2, 2, num_const(4))),
LIST_ADD list_item(true, new_var(pt, 2, 5, "x")),
LIST_END,
});
// expect_eof(pt);
destroy_parser_test(pt);
}
TEST(stringification, t) {
struct parser_test *pt = new_parser_test(t, "'hello");
expect_expr(pt, const_expr(1, 1, string_const(pt, "hello")));
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(line_continuation, t) {
struct parser_test *pt = new_parser_test(t,
"foo \\ # A comment\n"
"bar \\\n"
"\\\n"
"baz\n"
"xyz"
);
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(1, 1),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 1, 1, "foo"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 2, 1, "bar")),
LIST_ADD list_item(false, new_var(pt, 4, 1, "baz")),
LIST_END,
},
});
expect_expr(pt, var(pt, 5, 1, "xyz"));
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(dict, t) {
struct parser_test *pt = new_parser_test(t,
// 1 2 3
// 12345678901234567890123456789012
"[ a -> b, 'c -> d\n"
"e ->f g ->h\n"
"(i j) -> [1 2 3],, 42 -> [x -> y]\n"
"true -> false]\n"
);
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_DICT,
.position = POS(1, 1),
.dict = LIST_BEGIN(pt, dict)
LIST_ADD (struct apfl_expr_dict_pair) {
.k = new_var(pt, 1, 3, "a"),
.v = new_var(pt, 1, 8, "b"),
},
LIST_ADD (struct apfl_expr_dict_pair) {
.k = new_const_expr(pt, 1, 11, string_const(pt, "c")),
.v = new_var(pt, 1, 17, "d"),
},
LIST_ADD (struct apfl_expr_dict_pair) {
.k = new_var(pt, 2, 1, "e"),
.v = new_var(pt, 2, 5, "f"),
},
LIST_ADD (struct apfl_expr_dict_pair) {
.k = new_var(pt, 2, 7, "g"),
.v = new_var(pt, 2, 11, "h"),
},
LIST_ADD (struct apfl_expr_dict_pair) {
.k = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(3, 1),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 3, 2, "i"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 3, 4, "j")),
LIST_END,
},
} END_NEW,
.v = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_LIST,
.position = POS(3, 10),
.list = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_const_expr(pt, 3, 11, num_const(1))),
LIST_ADD list_item(false, new_const_expr(pt, 3, 13, num_const(2))),
LIST_ADD list_item(false, new_const_expr(pt, 3, 15, num_const(3))),
LIST_END,
} END_NEW,
},
LIST_ADD (struct apfl_expr_dict_pair) {
.k = new_const_expr(pt, 3, 20, num_const(42)),
.v = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_DICT,
.position = POS(3, 26),
.dict = LIST_BEGIN(pt, dict)
LIST_ADD (struct apfl_expr_dict_pair) {
.k = new_var(pt, 3, 27, "x"),
.v = new_var(pt, 3, 32, "y"),
},
LIST_END,
} END_NEW,
},
LIST_ADD (struct apfl_expr_dict_pair) {
.k = new_const_expr(pt, 4, 1, bool_const(true)),
.v = new_const_expr(pt, 4, 9, bool_const(false)),
},
LIST_END
});
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(assignment, t) {
struct parser_test *pt = new_parser_test(t,
// 123456
"a = b\n"
// 1 2
// 12345678901234567890123456
"foo.bar := bar?pred = baz\n"
// 1 2 3
// 12345678901234567890123456789012345
"[[1 2] ~xs] = bla@(a b) := abc ~xyz\n"
);
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_ASSIGNMENT,
.position = POS(1, 3),
.assignment = (struct apfl_expr_assignment) {
.local = false,
.lhs = (struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_VAR,
.var = new_string(pt, "a"),
},
.rhs = new_var(pt, 1, 5, "b"),
},
});
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_ASSIGNMENT,
.position = POS(2, 9),
.assignment = (struct apfl_expr_assignment) {
.local = true,
.lhs = (struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_DOT,
.dot = (struct apfl_expr_assignable_dot) {
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_VAR,
.var = new_string(pt, "foo"),
} END_NEW,
.rhs = new_string(pt, "bar"),
},
},
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_ASSIGNMENT,
.position = POS(2, 21),
.assignment = (struct apfl_expr_assignment) {
.local = false,
.lhs = (struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_PREDICATE,
.predicate = (struct apfl_expr_assignable_predicate) {
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_VAR,
.var = new_string(pt, "bar"),
} END_NEW,
.rhs = new_var(pt, 2, 16, "pred"),
},
},
.rhs = new_var(pt, 2, 23, "baz"),
},
} END_NEW,
},
});
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_ASSIGNMENT,
.position = POS(3, 13),
.assignment = (struct apfl_expr_assignment) {
.local = false,
.lhs = (struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_LIST,
.list = LIST_BEGIN(pt, assignable_list)
LIST_ADD (struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_LIST,
.list = LIST_BEGIN(pt, assignable_list)
LIST_ADD (struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_CONSTANT,
.constant = num_const(1),
},
LIST_ADD (struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_CONSTANT,
.constant = num_const(2),
},
LIST_END,
},
LIST_ADD (struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_EXPAND,
.expand = BEGIN_NEW(pt, struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_VAR,
.var = new_string(pt, "xs"),
} END_NEW,
},
LIST_END,
},
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_ASSIGNMENT,
.position = POS(3, 25),
.assignment = (struct apfl_expr_assignment) {
.local = true,
.lhs = (struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_AT,
.at = (struct apfl_expr_assignable_at) {
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_VAR,
.var = new_string(pt, "bla"),
} END_NEW,
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(3, 19),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 3, 20, "a"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 3, 22, "b")),
LIST_END,
},
} END_NEW,
},
},
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(3, 28),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 3, 28, "abc"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(true, new_var(pt, 3, 33, "xyz")),
LIST_END,
},
} END_NEW,
},
} END_NEW,
},
});
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(simple_function, t) {
struct parser_test *pt = new_parser_test(t,
// 12345678901
"{{\n"
" }; foo \\\n"
"bar { # comment...\n"
" baz = 10\n"
" a\n"
" b\n"
"}; c}\n"
);
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_SIMPLE_FUNC,
.position = POS(1, 1),
.simple_func = LIST_BEGIN(pt, body)
LIST_ADD (struct apfl_expr) {
.type = APFL_EXPR_SIMPLE_FUNC,
.position = POS(1, 2),
.simple_func = LIST_BEGIN(pt, body)
LIST_END,
},
LIST_ADD (struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(2, 8),
.call = (struct apfl_expr_call) {
.callee = new_var(pt, 2, 8, "foo"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 3, 1, "bar")),
LIST_ADD list_item(false, BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_SIMPLE_FUNC,
.position = POS(3, 5),
.simple_func = LIST_BEGIN(pt, body)
LIST_ADD (struct apfl_expr) {
.type = APFL_EXPR_ASSIGNMENT,
.position = POS(4, 9),
.assignment = (struct apfl_expr_assignment) {
.local = false,
.lhs = (struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_VAR,
.var = new_string(pt, "baz"),
},
.rhs = new_const_expr(pt, 4, 11, num_const(10)),
},
},
LIST_ADD var(pt, 5, 5, "a"),
LIST_ADD var(pt, 6, 5, "b"),
LIST_END,
} END_NEW),
LIST_END,
},
},
LIST_ADD var(pt, 7, 4, "c"),
LIST_END,
});
destroy_parser_test(pt);
}
2021-12-18 16:06:17 +00:00
TEST(complex_function, t) {
struct parser_test *pt = new_parser_test(t,
// 1 2
// 12345678901234567890123456789
"{ a ~b c?d?(e f) -> foo; bar\n"
" baz\n"
"1 [] ->; x [y?x ~ys] ->\n"
" a\n"
" b\n"
" c { x -> y }\n"
" \n"
"}\n"
);
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_COMPLEX_FUNC,
.position = POS(1, 1),
.complex_func = LIST_BEGIN(pt, complex_func)
LIST_ADD {
.params = LIST_BEGIN(pt, params)
LIST_ADD {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "a"),
},
LIST_ADD {
.type = APFL_EXPR_PARAM_EXPAND,
.expand = BEGIN_NEW(pt, struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "b"),
} END_NEW
},
LIST_ADD {
.type = APFL_EXPR_PARAM_PREDICATE,
.predicate = {
.lhs = BEGIN_NEW(pt, struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_PREDICATE,
.predicate = {
.lhs = BEGIN_NEW(pt, struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "c")
} END_NEW,
.rhs = new_var(pt, 1, 10, "d"),
},
} END_NEW,
.rhs = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(1, 12),
.call = {
.callee = new_var(pt, 1, 13, "e"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 1, 15, "f")),
LIST_END,
},
} END_NEW,
},
},
LIST_END,
.body = LIST_BEGIN(pt, body)
LIST_ADD var(pt, 1, 21, "foo"),
LIST_ADD var(pt, 1, 26, "bar"),
LIST_ADD var(pt, 2, 5, "baz"),
LIST_END,
},
LIST_ADD {
.params = LIST_BEGIN(pt, params)
LIST_ADD {
.type = APFL_EXPR_PARAM_CONSTANT,
.constant = num_const(1),
},
LIST_ADD {
.type = APFL_EXPR_PARAM_LIST,
.list = LIST_BEGIN(pt, params)
LIST_END,
},
LIST_END,
.body = LIST_BEGIN(pt, body)
LIST_END,
},
LIST_ADD {
.params = LIST_BEGIN(pt, params)
LIST_ADD {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "x"),
},
LIST_ADD {
.type = APFL_EXPR_PARAM_LIST,
.list = LIST_BEGIN(pt, params)
LIST_ADD {
.type = APFL_EXPR_PARAM_PREDICATE,
.predicate = {
.lhs = BEGIN_NEW(pt, struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "y"),
} END_NEW,
.rhs = new_var(pt, 3, 15, "x"),
},
},
LIST_ADD {
.type = APFL_EXPR_PARAM_EXPAND,
.expand = BEGIN_NEW(pt, struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "ys"),
} END_NEW,
},
LIST_END
},
LIST_END,
.body = LIST_BEGIN(pt, body)
LIST_ADD var(pt, 4, 5, "a"),
LIST_ADD var(pt, 5, 5, "b"),
LIST_ADD {
.type = APFL_EXPR_CALL,
.position = POS(6, 5),
.call = {
.callee = new_var(pt, 6, 5, "c"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_COMPLEX_FUNC,
.position = POS(6, 7),
.complex_func = LIST_BEGIN(pt, complex_func)
LIST_ADD {
.params = LIST_BEGIN(pt, params)
LIST_ADD {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "x"),
},
LIST_END,
.body = LIST_BEGIN(pt, body)
LIST_ADD var(pt, 6, 14, "y"),
LIST_END
}
LIST_END
} END_NEW),
LIST_END,
},
}
LIST_END
},
LIST_END,
});
expect_eof(pt);
destroy_parser_test(pt);
}
2021-12-18 23:27:34 +00:00
TEST(err_empty_assignment, t) {
struct parser_test *pt = new_parser_test(t, "= foo bar");
expect_error_of_type(pt, APFL_ERR_EMPTY_ASSIGNMENT);
destroy_parser_test(pt);
}
TEST(err_mismatching_parens, t) {
struct parser_test *pt = new_parser_test(t, "{[(}");
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_TOKEN);
destroy_parser_test(pt);
}
TEST(err_unclosed_func, t) {
struct parser_test *pt = new_parser_test(t, "{ foo -> bar; baz a; b ->");
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_EOF);
destroy_parser_test(pt);
}
TEST(err_unclosed_paren, t) {
struct parser_test *pt = new_parser_test(t, "(a b.c@d");
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_EOF_AFTER_TOKEN);
destroy_parser_test(pt);
}
TEST(err_assignment_missing_rhs, t) {
struct parser_test *pt = new_parser_test(t, "foo = bar = ;");
expect_error_of_type(pt, APFL_ERR_EMPTY_ASSIGNMENT);
// TODO: Actually kinda weird that we return the same error as in err_empty_assignment.
destroy_parser_test(pt);
}
TEST(err_assignment_invalid_lhs, t) {
struct parser_test *pt = new_parser_test(t, "{foo} = bar");
expect_error_of_type(pt, APFL_ERR_INVALID_ASSIGNMENT_LHS);
destroy_parser_test(pt);
pt = new_parser_test(t, "(a b) = bar");
expect_error_of_type(pt, APFL_ERR_INVALID_ASSIGNMENT_LHS);
destroy_parser_test(pt);
}
TEST(err_fragments_after_mapsto_in_empty_dict, t) {
struct parser_test *pt = new_parser_test(t, "[-> foo]");
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_TOKEN);
destroy_parser_test(pt);
}
TEST(err_fragments_after_mapsto_in_dict, t) {
struct parser_test *pt = new_parser_test(t, "[a -> b, (c d) -> e foo->]");
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_TOKEN);
destroy_parser_test(pt);
}
TEST(err_mapsto_in_list, t) {
struct parser_test *pt = new_parser_test(t, "[a b c -> d]");
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_TOKEN);
destroy_parser_test(pt);
}
TEST(err_expr_in_param, t) {
struct parser_test *pt = new_parser_test(t, "{ foo (bar baz) -> }");
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_EXPRESSION);
destroy_parser_test(pt);
}
TEST(err_statements_before_params, t) {
struct parser_test *pt = new_parser_test(t, "{ a = b = foo bar; 1 \n baz -> }");
expect_error_of_type(pt, APFL_ERR_STATEMENTS_BEFORE_PARAMETERS);
destroy_parser_test(pt);
}
2021-12-16 22:42:37 +00:00
TESTS_BEGIN
ADDTEST(empty),
ADDTEST(hello_world),
2021-12-17 20:08:03 +00:00
ADDTEST(empty_function),
ADDTEST(empty_list),
ADDTEST(empty_dict),
ADDTEST(simple_dot_access),
ADDTEST(simple_at_access),
ADDTEST(parens),
ADDTEST(complex_dot_at_access),
ADDTEST(factorial),
ADDTEST(map),
2021-12-18 15:12:37 +00:00
ADDTEST(lists),
ADDTEST(stringification),
ADDTEST(line_continuation),
ADDTEST(dict),
ADDTEST(assignment),
ADDTEST(simple_function),
2021-12-18 16:06:17 +00:00
ADDTEST(complex_function),
2021-12-18 23:27:34 +00:00
ADDTEST(err_empty_assignment),
ADDTEST(err_mismatching_parens),
ADDTEST(err_unclosed_func),
ADDTEST(err_unclosed_paren),
ADDTEST(err_assignment_missing_rhs),
ADDTEST(err_assignment_invalid_lhs),
ADDTEST(err_fragments_after_mapsto_in_empty_dict),
ADDTEST(err_fragments_after_mapsto_in_dict),
ADDTEST(err_mapsto_in_list),
ADDTEST(err_expr_in_param),
ADDTEST(err_statements_before_params),
2021-12-16 22:42:37 +00:00
TESTS_END