apfl/src/parser_test.c

1470 lines
58 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 "alloc.h"
2021-12-16 22:42:37 +00:00
#include "test.h"
struct parser_test {
testctx t;
struct apfl_allocator allocator;
2021-12-16 22:42:37 +00:00
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 apfl_allocator allocator = test_allocator(t);
2021-12-16 22:42:37 +00:00
struct parser_test *pt = must_alloc(t, sizeof(struct parser_test));
pt->t = t;
pt->allocator = allocator;
if ((pt->source_reader_ctx = apfl_string_source_reader_new(allocator, apfl_string_view_from(source))) == NULL) {
2021-12-16 22:42:37 +00:00
test_fatalf(t, "Failed initializing source reader");
}
if ((pt->tokenizer = apfl_tokenizer_new(allocator, apfl_string_source_reader, pt->source_reader_ctx)) == NULL) {
2021-12-16 22:42:37 +00:00
test_fatalf(t, "Failed initializing the tokenizer");
}
if ((pt->parser = apfl_parser_new(allocator, apfl_tokenizer_as_token_source(pt->tokenizer))) == NULL) {
2021-12-16 22:42:37 +00:00
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(pt->allocator, &expr);
apfl_expr_deinit(pt->allocator, &expected);
2021-12-16 22:42:37 +00:00
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;
}
}
Implement mark&sweep garbage collection and bytecode compilation Instead of the previous refcount base garbage collection, we're now using a basic tri-color mark&sweep collector. This is done to support cyclical value relationships in the future (functions can form cycles, all values implemented up to this point can not). The collector maintains a set of roots and a set of objects (grouped into blocks). The GC enabled objects are no longer allocated manually, but will be allocated by the GC. The GC also wraps an allocator, this way the GC knows, if we ran out of memory and will try to get out of this situation by performing a full collection cycle. The tri-color abstraction was chosen for two reasons: - We don't have to maintain a list of objects that need to be marked, we can simply grab the next grey one. - It should allow us to later implement incremental collection (right now we only do a stop-the-world collection). This also switches to a bytecode based evaluation of the code: We no longer directly evaluate the AST, but first compile it into a series of instructions, that are evaluated in a separate step. This was done in preparation for inplementing functions: We only need to turn a function body into instructions instead of evaluating the node again with each call of the function. Also, since an instruction list is implemented as a GC object, this then removes manual memory management of the function body and it's child nodes. Since the GC and the bytecode go hand in hand, this was done in one (giant) commit. As a downside, we've now lost the ability do do list matching on assignments. I've already started to work on implementing this in the new architecture, but left it out of this commit, as it's already quite a large commit :)
2022-04-11 20:24:22 +00:00
static struct apfl_string
2021-12-16 22:42:37 +00:00
new_string(struct parser_test *pt, const char *in)
{
Implement mark&sweep garbage collection and bytecode compilation Instead of the previous refcount base garbage collection, we're now using a basic tri-color mark&sweep collector. This is done to support cyclical value relationships in the future (functions can form cycles, all values implemented up to this point can not). The collector maintains a set of roots and a set of objects (grouped into blocks). The GC enabled objects are no longer allocated manually, but will be allocated by the GC. The GC also wraps an allocator, this way the GC knows, if we ran out of memory and will try to get out of this situation by performing a full collection cycle. The tri-color abstraction was chosen for two reasons: - We don't have to maintain a list of objects that need to be marked, we can simply grab the next grey one. - It should allow us to later implement incremental collection (right now we only do a stop-the-world collection). This also switches to a bytecode based evaluation of the code: We no longer directly evaluate the AST, but first compile it into a series of instructions, that are evaluated in a separate step. This was done in preparation for inplementing functions: We only need to turn a function body into instructions instead of evaluating the node again with each call of the function. Also, since an instruction list is implemented as a GC object, this then removes manual memory management of the function body and it's child nodes. Since the GC and the bytecode go hand in hand, this was done in one (giant) commit. As a downside, we've now lost the ability do do list matching on assignments. I've already started to work on implementing this in the new architecture, but left it out of this commit, as it's already quite a large commit :)
2022-04-11 20:24:22 +00:00
struct apfl_string out = apfl_string_blank();
if (!apfl_string_copy(pt->allocator, &out, apfl_string_view_from(in))) {
2021-12-16 22:42:37 +00:00
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 = ALLOC_BYTES(pt->allocator, size);
2021-12-16 22:42:37 +00:00
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,
};
}
static struct apfl_expr_assignable_list_item
assignable_list_item(bool expand, struct apfl_expr_assignable assignable)
{
return (struct apfl_expr_assignable_list_item) {
.expand = expand,
.assignable = assignable,
};
}
static struct apfl_expr_params_item
params_item(bool expand, struct apfl_expr_param param)
{
return (struct apfl_expr_params_item) {
.expand = expand,
.param = param,
};
}
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
#define LISTBUILDER_FILL_LIST(pt, itemtype, items, list_items, list_len, cap) \
apfl_resizable_init((void **)&list_items, &list_len, &cap); \
2021-12-17 20:08:03 +00:00
\
for (items++; items->has_item; items++) { \
if (!apfl_resizable_append( \
pt->allocator, \
sizeof(itemtype), \
(void **)&list_items, \
&list_len, \
&cap, \
&items->item, \
1 \
)) { \
test_fatalf(pt->t, "Failed appending"); \
assert(false); \
2021-12-17 20:08:03 +00:00
} \
} \
#define MKLISTBUILDER(name, listtype, itemtype, items_memb) \
struct LISTBUILDER_ITEM_NAME(name) { \
bool has_item; \
itemtype item; \
}; \
listtype \
LISTBUILDER_NAME(name)( \
struct parser_test *pt, \
struct LISTBUILDER_ITEM_NAME(name) items[] \
) { \
listtype list; \
size_t cap = 0; \
\
LISTBUILDER_FILL_LIST(pt, itemtype, items, list.items_memb, list.len, cap) \
\
return list; \
} \
#define MKCAPLISTBUILDER(name, listtype, itemtype, items_memb) \
struct LISTBUILDER_ITEM_NAME(name) { \
bool has_item; \
itemtype item; \
}; \
listtype \
LISTBUILDER_NAME(name)( \
struct parser_test *pt, \
struct LISTBUILDER_ITEM_NAME(name) items[] \
) { \
listtype list; \
\
LISTBUILDER_FILL_LIST(pt, itemtype, items, list.items_memb, list.len, list.cap) \
\
return list; \
} \
#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)
2022-04-11 20:44:04 +00:00
MKCAPLISTBUILDER(body, struct apfl_expr_body, struct apfl_expr, items)
MKCAPLISTBUILDER(dict, struct apfl_expr_dict, struct apfl_expr_dict_pair, items)
MKCAPLISTBUILDER(complex_func, struct apfl_expr_complex_func, struct apfl_expr_subfunc, subfuncs)
MKCAPLISTBUILDER(params, struct apfl_expr_params, struct apfl_expr_params_item, params)
MKLISTBUILDER(assignable_list, struct apfl_expr_assignable_list, struct apfl_expr_assignable_list_item, items)
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);
}
static struct apfl_expr_assignable
assignable_var(struct parser_test *pt, const char *name)
{
return (struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER,
.var_or_member = {
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR,
.var = new_string(pt, name),
},
};
}
static struct apfl_expr_assignable *
new_assignable_var(struct parser_test *pt, const char *name)
{
struct apfl_expr_assignable assignable = assignable_var(pt, name);
return new_helper(pt, sizeof(struct apfl_expr_assignable), &assignable);
}
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),
2022-04-11 20:44:04 +00:00
.simple_func = LIST_BEGIN(pt, body)
LIST_END,
2021-12-17 20:08:03 +00:00
});
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 = assignable_var(pt, "factorial"),
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 params_item(false, (struct apfl_expr_param) {
2021-12-17 20:08:03 +00:00
.type = APFL_EXPR_PARAM_CONSTANT,
.constant = num_const(0),
}),
2021-12-17 20:08:03 +00:00
LIST_END,
2022-04-11 20:44:04 +00:00
.body = LIST_BEGIN(pt, body)
LIST_ADD const_expr(2, 10, num_const(1)),
2022-04-11 20:44:04 +00:00
LIST_END
2021-12-17 20:08:03 +00:00
},
LIST_ADD (struct apfl_expr_subfunc) {
.params = LIST_BEGIN(pt, params)
LIST_ADD params_item(false, (struct apfl_expr_param) {
2021-12-17 20:08:03 +00:00
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "n"),
}),
2021-12-17 20:08:03 +00:00
LIST_END,
2022-04-11 20:44:04 +00:00
.body = LIST_BEGIN(pt, body)
2021-12-17 20:08:03 +00:00
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,
},
},
2022-04-11 20:44:04 +00:00
LIST_END
2021-12-17 20:08:03 +00:00
},
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 = assignable_var(pt, "map"),
2021-12-17 20:08:03 +00:00
.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 params_item(false, (struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_BLANK,
}),
LIST_ADD params_item(false, (struct apfl_expr_param) {
2021-12-17 20:08:03 +00:00
.type = APFL_EXPR_PARAM_LIST,
.list = LIST_BEGIN(pt, params)
LIST_END,
}),
2021-12-17 20:08:03 +00:00
LIST_END,
2022-04-11 20:44:04 +00:00
.body = LIST_BEGIN(pt, body)
2021-12-17 20:08:03 +00:00
LIST_ADD (struct apfl_expr) {
.type = APFL_EXPR_LIST,
.position = POS(2, 9),
.list = LIST_BEGIN(pt, list)
LIST_END,
},
2022-04-11 20:44:04 +00:00
LIST_END,
2021-12-17 20:08:03 +00:00
},
LIST_ADD (struct apfl_expr_subfunc) {
.params = LIST_BEGIN(pt, params)
LIST_ADD params_item(false, (struct apfl_expr_param) {
2021-12-17 20:08:03 +00:00
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "f"),
}),
LIST_ADD params_item(false, (struct apfl_expr_param) {
2021-12-17 20:08:03 +00:00
.type = APFL_EXPR_PARAM_LIST,
.list = LIST_BEGIN(pt, params)
LIST_ADD params_item(false, (struct apfl_expr_param) {
2021-12-17 20:08:03 +00:00
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "x"),
}),
LIST_ADD params_item(true, (struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "xs"),
}),
2021-12-17 20:08:03 +00:00
LIST_END,
}),
2021-12-17 20:08:03 +00:00
LIST_END,
2022-04-11 20:44:04 +00:00
.body = LIST_BEGIN(pt, body)
2021-12-17 20:08:03 +00:00
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,
},
2022-04-11 20:44:04 +00:00
LIST_END
2021-12-17 20:08:03 +00:00
},
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 = assignable_var(pt, "a"),
2021-12-18 15:12:37 +00:00
.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_VAR_OR_MEMBER,
.var_or_member = {
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_DOT,
.dot = {
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable_var_or_member) {
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR,
.var = new_string(pt, "foo"),
} END_NEW,
.rhs = new_string(pt, "bar"),
},
2021-12-18 15:12:37 +00:00
},
},
.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 = new_assignable_var(pt, "bar"),
2021-12-18 15:12:37 +00:00
.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 assignable_list_item(false, (struct apfl_expr_assignable) {
2021-12-18 15:12:37 +00:00
.type = APFL_EXPR_ASSIGNABLE_LIST,
.list = LIST_BEGIN(pt, assignable_list)
LIST_ADD assignable_list_item(false, (struct apfl_expr_assignable) {
2021-12-18 15:12:37 +00:00
.type = APFL_EXPR_ASSIGNABLE_CONSTANT,
.constant = num_const(1),
}),
LIST_ADD assignable_list_item(false, (struct apfl_expr_assignable) {
2021-12-18 15:12:37 +00:00
.type = APFL_EXPR_ASSIGNABLE_CONSTANT,
.constant = num_const(2),
}),
2021-12-18 15:12:37 +00:00
LIST_END,
}),
LIST_ADD assignable_list_item(true, assignable_var(pt, "xs")),
2021-12-18 15:12:37 +00:00
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_VAR_OR_MEMBER,
.var_or_member = {
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_AT,
.at = {
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable_var_or_member) {
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_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,
},
}
2021-12-18 15:12:37 +00:00
},
.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),
2022-04-11 20:44:04 +00:00
.simple_func = LIST_BEGIN(pt, body)
2021-12-18 15:12:37 +00:00
LIST_ADD (struct apfl_expr) {
.type = APFL_EXPR_SIMPLE_FUNC,
.position = POS(1, 2),
2022-04-11 20:44:04 +00:00
.simple_func = LIST_BEGIN(pt, body)
LIST_END,
2021-12-18 15:12:37 +00:00
},
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),
2022-04-11 20:44:04 +00:00
.simple_func = LIST_BEGIN(pt, body)
2021-12-18 15:12:37 +00:00
LIST_ADD (struct apfl_expr) {
.type = APFL_EXPR_ASSIGNMENT,
.position = POS(4, 9),
.assignment = (struct apfl_expr_assignment) {
.local = false,
.lhs = assignable_var(pt, "baz"),
2021-12-18 15:12:37 +00:00
.rhs = new_const_expr(pt, 4, 11, num_const(10)),
},
},
LIST_ADD var(pt, 5, 5, "a"),
LIST_ADD var(pt, 6, 5, "b"),
2022-04-11 20:44:04 +00:00
LIST_END,
2021-12-18 15:12:37 +00:00
} END_NEW),
LIST_END,
},
},
LIST_ADD var(pt, 7, 4, "c"),
2022-04-11 20:44:04 +00:00
LIST_END,
2021-12-18 15:12:37 +00:00
});
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 params_item(false, (struct apfl_expr_param) {
2021-12-18 16:06:17 +00:00
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "a"),
}),
LIST_ADD params_item(true, (struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "b"),
}),
LIST_ADD params_item(false, (struct apfl_expr_param) {
2021-12-18 16:06:17 +00:00
.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,
},
}),
2021-12-18 16:06:17 +00:00
LIST_END,
2022-04-11 20:44:04 +00:00
.body = LIST_BEGIN(pt, body)
2021-12-18 16:06:17 +00:00
LIST_ADD var(pt, 1, 21, "foo"),
LIST_ADD var(pt, 1, 26, "bar"),
LIST_ADD var(pt, 2, 5, "baz"),
2022-04-11 20:44:04 +00:00
LIST_END,
2021-12-18 16:06:17 +00:00
},
LIST_ADD {
.params = LIST_BEGIN(pt, params)
LIST_ADD params_item(false, (struct apfl_expr_param) {
2021-12-18 16:06:17 +00:00
.type = APFL_EXPR_PARAM_CONSTANT,
.constant = num_const(1),
}),
LIST_ADD params_item(false, (struct apfl_expr_param) {
2021-12-18 16:06:17 +00:00
.type = APFL_EXPR_PARAM_LIST,
.list = LIST_BEGIN(pt, params)
LIST_END,
}),
2021-12-18 16:06:17 +00:00
LIST_END,
2022-04-11 20:44:04 +00:00
.body = LIST_BEGIN(pt, body)
LIST_END,
2021-12-18 16:06:17 +00:00
},
LIST_ADD {
.params = LIST_BEGIN(pt, params)
LIST_ADD params_item(false, (struct apfl_expr_param) {
2021-12-18 16:06:17 +00:00
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "x"),
}),
LIST_ADD params_item(false, (struct apfl_expr_param) {
2021-12-18 16:06:17 +00:00
.type = APFL_EXPR_PARAM_LIST,
.list = LIST_BEGIN(pt, params)
LIST_ADD params_item(false, (struct apfl_expr_param) {
2021-12-18 16:06:17 +00:00
.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 params_item(true, (struct apfl_expr_param) {
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "ys"),
}),
2021-12-18 16:06:17 +00:00
LIST_END
}),
2021-12-18 16:06:17 +00:00
LIST_END,
2022-04-11 20:44:04 +00:00
.body = LIST_BEGIN(pt, body)
2021-12-18 16:06:17 +00:00
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 params_item(false, (struct apfl_expr_param) {
2021-12-18 16:06:17 +00:00
.type = APFL_EXPR_PARAM_VAR,
.var = new_string(pt, "x"),
}),
2021-12-18 16:06:17 +00:00
LIST_END,
2022-04-11 20:44:04 +00:00
.body = LIST_BEGIN(pt, body)
2021-12-18 16:06:17 +00:00
LIST_ADD var(pt, 6, 14, "y"),
2022-04-11 20:44:04 +00:00
LIST_END,
2021-12-18 16:06:17 +00:00
}
LIST_END
} END_NEW),
LIST_END,
},
}
2022-04-11 20:44:04 +00:00
LIST_END,
2021-12-18 16:06:17 +00:00
},
LIST_END,
});
expect_eof(pt);
destroy_parser_test(pt);
}
2022-01-06 21:50:14 +00:00
TEST(function_calls, t) {
struct parser_test *pt = new_parser_test(t,
"foo\n"
"(foo)\n"
"foo bar\n"
"(foo bar)\n"
"((foo bar))\n"
"foo bar ~baz\n"
);
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_VAR,
.position = POS(1, 1),
.var = new_string(pt, "foo"),
});
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(2, 1),
.call = {
.callee = new_var(pt, 2, 2, "foo"),
.arguments = LIST_BEGIN(pt, list)
LIST_END,
},
});
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(3, 1),
.call = {
.callee = new_var(pt, 3, 1, "foo"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 3, 5, "bar")),
LIST_END,
},
});
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(4, 1),
.call = {
.callee = new_var(pt, 4, 2, "foo"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 4, 6, "bar")),
LIST_END,
},
});
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(5, 1),
.call = {
.callee = BEGIN_NEW(pt, struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(5, 2),
.call = {
.callee = new_var(pt, 5, 3, "foo"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 5, 7, "bar")),
LIST_END,
},
} END_NEW,
.arguments = LIST_BEGIN(pt, list)
LIST_END
},
});
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_CALL,
.position = POS(6, 1),
.call = {
.callee = new_var(pt, 6, 1, "foo"),
.arguments = LIST_BEGIN(pt, list)
LIST_ADD list_item(false, new_var(pt, 6, 5, "bar")),
LIST_ADD list_item(true, new_var(pt, 6, 10, "baz")),
LIST_END,
},
});
expect_eof(pt);
destroy_parser_test(pt);
}
TEST(member_assignment_with_predicate, t) {
struct parser_test *pt = new_parser_test(t, "a.b@c?d?e = f");
expect_expr(pt, (struct apfl_expr) {
.type = APFL_EXPR_ASSIGNMENT,
.position = POS(1, 11),
.assignment = {
.lhs = {
.type = APFL_EXPR_ASSIGNABLE_PREDICATE,
.predicate = {
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_PREDICATE,
.predicate = {
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable) {
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER,
.var_or_member = {
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_AT,
.at = {
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable_var_or_member) {
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_DOT,
.dot = {
.lhs = BEGIN_NEW(pt, struct apfl_expr_assignable_var_or_member) {
.type = APFL_EXPR_ASSIGNABLE_VAR_OR_MEMBER_VAR,
.var = new_string(pt, "a"),
} END_NEW,
.rhs = new_string(pt, "b"),
},
} END_NEW,
.rhs = new_var(pt, 1, 5, "c"),
},
},
} END_NEW,
.rhs = new_var(pt, 1, 7, "d"),
}
} END_NEW,
.rhs = new_var(pt, 1, 9, "e"),
},
},
.rhs = new_var(pt, 1, 13, "f")
}
});
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);
}
TEST(err_dict_mapsto_missing, t) {
struct parser_test *pt = new_parser_test(t, "[foo -> bar, baz wtf -> xyu]");
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_TOKEN);
destroy_parser_test(pt);
}
TEST(err_dict_mapsto_too_early, t) {
struct parser_test *pt = new_parser_test(t, "[foo -> bar -> baz]");
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_TOKEN);
destroy_parser_test(pt);
}
TEST(err_assign_multiple_expands_per_level, t) {
struct parser_test *pt = new_parser_test(t, "[~foo ~bar] = baz");
expect_error_of_type(pt, APFL_ERR_ONLY_ONE_EXPAND_ALLOWED);
destroy_parser_test(pt);
}
TEST(err_assign_multiple_expands_per_level_nested, t) {
struct parser_test *pt = new_parser_test(t, "[1 [~foo ~bar]] = baz");
expect_error_of_type(pt, APFL_ERR_ONLY_ONE_EXPAND_ALLOWED);
destroy_parser_test(pt);
}
TEST(err_params_multiple_expands, t) {
struct parser_test *pt = new_parser_test(t, "{ ~foo ~bar -> baz }");
expect_error_of_type(pt, APFL_ERR_ONLY_ONE_EXPAND_ALLOWED);
destroy_parser_test(pt);
}
TEST(err_params_multiple_expands_nested, t) {
struct parser_test *pt = new_parser_test(t, "{ 1 [~foo ~bar] -> baz }");
expect_error_of_type(pt, APFL_ERR_ONLY_ONE_EXPAND_ALLOWED);
destroy_parser_test(pt);
}
TEST(err_unexpected_expression_in_member_assignable, t) {
struct parser_test *pt = new_parser_test(t, "(foo).bar = 123");
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_EXPR_IN_MEMBER_ACCESS);
destroy_parser_test(pt);
}
TEST(err_unexpected_constant_in_member_assignable, t) {
struct parser_test *pt = new_parser_test(t, "nil.bar = 456");
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_CONSTANT_IN_MEMBER_ACCESS);
destroy_parser_test(pt);
}
TEST(err_unexpected_assignment_member_access, t) {
struct parser_test *pt = new_parser_test(t, "[1 2 3]@bar = 456");
expect_error_of_type(pt, APFL_ERR_UNEXPECTED_TOKEN);
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),
2022-01-06 21:50:14 +00:00
ADDTEST(function_calls),
ADDTEST(member_assignment_with_predicate),
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),
ADDTEST(err_dict_mapsto_missing),
ADDTEST(err_dict_mapsto_too_early),
ADDTEST(err_assign_multiple_expands_per_level),
ADDTEST(err_assign_multiple_expands_per_level_nested),
ADDTEST(err_params_multiple_expands),
ADDTEST(err_params_multiple_expands_nested),
ADDTEST(err_unexpected_expression_in_member_assignable),
ADDTEST(err_unexpected_constant_in_member_assignable),
ADDTEST(err_unexpected_assignment_member_access),
2021-12-16 22:42:37 +00:00
TESTS_END