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:
|
2021-12-18 15:09:41 +00:00
|
|
|
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)
|
|
|
|
|
{
|
2022-01-02 16:01:51 +00:00
|
|
|
struct apfl_string out = apfl_string_blank();
|
2021-12-16 22:42:37 +00:00
|
|
|
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
|
2021-12-18 15:34:09 +00:00
|
|
|
#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) \
|
2021-12-18 15:34:09 +00:00
|
|
|
struct LISTBUILDER_ITEM_NAME(name) { \
|
|
|
|
|
bool has_item; \
|
|
|
|
|
itemtype item; \
|
|
|
|
|
}; \
|
2021-12-17 20:08:03 +00:00
|
|
|
listtype \
|
2021-12-18 15:34:09 +00:00
|
|
|
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); \
|
|
|
|
|
\
|
2021-12-18 15:34:09 +00:00
|
|
|
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, \
|
2021-12-18 15:34:09 +00:00
|
|
|
&items->item, \
|
2021-12-17 20:08:03 +00:00
|
|
|
1 \
|
|
|
|
|
)) { \
|
|
|
|
|
test_fatalf(pt->t, "Failed appending"); \
|
|
|
|
|
assert(false); \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
\
|
|
|
|
|
return body; \
|
|
|
|
|
} \
|
|
|
|
|
|
2021-12-18 15:34:09 +00:00
|
|
|
#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);
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-18 15:11:23 +00:00
|
|
|
|
|
|
|
|
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,
|
2021-12-18 15:11:23 +00:00
|
|
|
.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),
|
2021-12-18 15:11:23 +00:00
|
|
|
.rhs = new_const_expr(pt, 1, 7, num_const(1)),
|
2021-12-17 20:08:03 +00:00
|
|
|
},
|
|
|
|
|
} END_NEW,
|
2021-12-18 15:11:23 +00:00
|
|
|
.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,
|
2021-12-18 15:11:23 +00:00
|
|
|
.constant = num_const(0),
|
2021-12-17 20:08:03 +00:00
|
|
|
},
|
|
|
|
|
LIST_END,
|
|
|
|
|
.body = LIST_BEGIN(pt, body)
|
2021-12-18 15:11:23 +00:00
|
|
|
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")),
|
2021-12-18 15:11:23 +00:00
|
|
|
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)
|
2021-12-18 15:11:23 +00:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-05 20:50:50 +00:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
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),
|
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),
|
2022-01-05 20:50:50 +00:00
|
|
|
ADDTEST(err_dict_mapsto_missing),
|
|
|
|
|
ADDTEST(err_dict_mapsto_too_early),
|
2021-12-16 22:42:37 +00:00
|
|
|
TESTS_END
|