228 lines
6.7 KiB
C
228 lines
6.7 KiB
C
#include "parse.h"
|
|
#include "unity.h"
|
|
|
|
static am_t am;
|
|
static parse_ctx_t ctx;
|
|
|
|
#define NELEMS(arr) (sizeof(arr) / sizeof(arr[0]))
|
|
|
|
void setUp(void)
|
|
{
|
|
am_init(&am);
|
|
parse_init(&am, &ctx);
|
|
}
|
|
|
|
void tearDown(void)
|
|
{
|
|
}
|
|
|
|
static void test_integer_123(void)
|
|
{
|
|
const token_t token = { .type = TOKEN_TYPE_INTEGER, .integer = 123 };
|
|
|
|
const parse_state_t state = parse_proc(&ctx, &token);
|
|
TEST_ASSERT_EQUAL(PARSE_STATE_DONE, state);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr);
|
|
TEST_ASSERT_TRUE(am.expr->is_atom);
|
|
TEST_ASSERT_EQUAL(ATOM_TYPE_INTEGER, am.expr->atom.type);
|
|
TEST_ASSERT_EQUAL(123, am.expr->atom.integer);
|
|
}
|
|
|
|
static void test_integer_321(void)
|
|
{
|
|
const token_t token = { .type = TOKEN_TYPE_INTEGER, .integer = 321 };
|
|
|
|
const parse_state_t state = parse_proc(&ctx, &token);
|
|
TEST_ASSERT_EQUAL(PARSE_STATE_DONE, state);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr);
|
|
TEST_ASSERT_TRUE(am.expr->is_atom);
|
|
TEST_ASSERT_EQUAL(ATOM_TYPE_INTEGER, am.expr->atom.type);
|
|
TEST_ASSERT_EQUAL(321, am.expr->atom.integer);
|
|
}
|
|
|
|
static void test_symbol_foo(void)
|
|
{
|
|
const token_t token = {
|
|
.type = TOKEN_TYPE_SYMBOL,
|
|
.symbol = { .buf = "foo", .len = 3 },
|
|
};
|
|
|
|
const parse_state_t state = parse_proc(&ctx, &token);
|
|
TEST_ASSERT_EQUAL(PARSE_STATE_DONE, state);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr);
|
|
TEST_ASSERT_TRUE(am.expr->is_atom);
|
|
TEST_ASSERT_EQUAL(ATOM_TYPE_SYMBOL, am.expr->atom.type);
|
|
TEST_ASSERT_EQUAL(3, am.expr->atom.symbol.len);
|
|
TEST_ASSERT_EQUAL_MEMORY("foo", am.expr->atom.symbol.buf, 3);
|
|
}
|
|
|
|
static void test_symbol_quux(void)
|
|
{
|
|
const token_t token = {
|
|
.type = TOKEN_TYPE_SYMBOL,
|
|
.symbol = { .buf = "quux", .len = 4 },
|
|
};
|
|
|
|
const parse_state_t state = parse_proc(&ctx, &token);
|
|
TEST_ASSERT_EQUAL(PARSE_STATE_DONE, state);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr);
|
|
TEST_ASSERT_TRUE(am.expr->is_atom);
|
|
TEST_ASSERT_EQUAL(ATOM_TYPE_SYMBOL, am.expr->atom.type);
|
|
TEST_ASSERT_EQUAL(4, am.expr->atom.symbol.len);
|
|
TEST_ASSERT_EQUAL_MEMORY("quux", am.expr->atom.symbol.buf, 4);
|
|
}
|
|
|
|
static void test_open_paren_close_paren(void)
|
|
{
|
|
// ()
|
|
const token_t tokens[] = {
|
|
{ .type = TOKEN_TYPE_OPEN_PAREN },
|
|
{ .type = TOKEN_TYPE_CLOSE_PAREN },
|
|
};
|
|
parse_state_t state;
|
|
|
|
state = parse_proc(&ctx, tokens + 0);
|
|
TEST_ASSERT_EQUAL(PARSE_STATE_LIST, state);
|
|
state = parse_proc(&ctx, tokens + 1);
|
|
TEST_ASSERT_EQUAL(PARSE_STATE_DONE, state);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr);
|
|
TEST_ASSERT_TRUE(am.expr->is_atom);
|
|
TEST_ASSERT_EQUAL(ATOM_TYPE_EMPTY_LIST, am.expr->atom.type);
|
|
}
|
|
|
|
static void test_open_paren_foo_42_close_paren(void)
|
|
{
|
|
// (foo 1) -> (foo . (1 . ()))
|
|
const token_t tokens[] = {
|
|
{ .type = TOKEN_TYPE_OPEN_PAREN },
|
|
{
|
|
.type = TOKEN_TYPE_SYMBOL,
|
|
.symbol = { .buf = "foo", .len = 3 },
|
|
},
|
|
{ .type = TOKEN_TYPE_INTEGER, .integer = 42 },
|
|
{ .type = TOKEN_TYPE_CLOSE_PAREN },
|
|
};
|
|
parse_state_t state;
|
|
|
|
for (unsigned i = 0; i < NELEMS(tokens) - 1; ++i) {
|
|
state = parse_proc(&ctx, tokens + i);
|
|
TEST_ASSERT_EQUAL(PARSE_STATE_LIST, state);
|
|
}
|
|
state = parse_proc(&ctx, tokens + NELEMS(tokens) - 1);
|
|
TEST_ASSERT_EQUAL(PARSE_STATE_DONE, state);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr);
|
|
TEST_ASSERT_FALSE(am.expr->is_atom);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr->pair.car);
|
|
TEST_ASSERT_TRUE(am.expr->pair.car->is_atom);
|
|
TEST_ASSERT_EQUAL(ATOM_TYPE_SYMBOL, am.expr->pair.car->atom.type);
|
|
TEST_ASSERT_EQUAL(3, am.expr->pair.car->atom.symbol.len);
|
|
TEST_ASSERT_EQUAL_MEMORY("foo", am.expr->pair.car->atom.symbol.buf, 3);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr->pair.cdr);
|
|
TEST_ASSERT_FALSE(am.expr->pair.cdr->is_atom);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr->pair.cdr->pair.car);
|
|
TEST_ASSERT_TRUE(am.expr->pair.cdr->pair.car->is_atom);
|
|
TEST_ASSERT_EQUAL(
|
|
ATOM_TYPE_INTEGER, am.expr->pair.cdr->pair.car->atom.type);
|
|
TEST_ASSERT_EQUAL(42, am.expr->pair.cdr->pair.car->atom.integer);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr->pair.cdr->pair.cdr);
|
|
TEST_ASSERT_TRUE(am.expr->pair.cdr->pair.cdr->is_atom);
|
|
TEST_ASSERT_EQUAL(
|
|
ATOM_TYPE_EMPTY_LIST, am.expr->pair.cdr->pair.cdr->atom.type);
|
|
}
|
|
|
|
static void test_open_paren_1_open_paren_2_close_paren_3_close_paren(void)
|
|
{
|
|
// (1 (2) 3) -> (1 . ((2 . ()) . (3 . ())))
|
|
const token_t tokens[] = {
|
|
{ .type = TOKEN_TYPE_OPEN_PAREN },
|
|
{ .type = TOKEN_TYPE_INTEGER, .integer = 1 },
|
|
{ .type = TOKEN_TYPE_OPEN_PAREN },
|
|
{ .type = TOKEN_TYPE_INTEGER, .integer = 2 },
|
|
{ .type = TOKEN_TYPE_CLOSE_PAREN },
|
|
{ .type = TOKEN_TYPE_INTEGER, .integer = 3 },
|
|
{ .type = TOKEN_TYPE_CLOSE_PAREN },
|
|
};
|
|
parse_state_t state;
|
|
|
|
for (unsigned i = 0; i < NELEMS(tokens) - 1; ++i) {
|
|
state = parse_proc(&ctx, tokens + i);
|
|
TEST_ASSERT_EQUAL(PARSE_STATE_LIST, state);
|
|
}
|
|
state = parse_proc(&ctx, tokens + NELEMS(tokens) - 1);
|
|
TEST_ASSERT_EQUAL(PARSE_STATE_DONE, state);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr);
|
|
TEST_ASSERT_FALSE(am.expr->is_atom);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr->pair.car);
|
|
TEST_ASSERT_TRUE(am.expr->pair.car->is_atom);
|
|
TEST_ASSERT_EQUAL(ATOM_TYPE_INTEGER, am.expr->pair.car->atom.type);
|
|
TEST_ASSERT_EQUAL(1, am.expr->pair.car->atom.integer);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr->pair.cdr);
|
|
TEST_ASSERT_FALSE(am.expr->pair.cdr->is_atom);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr->pair.cdr->pair.car);
|
|
TEST_ASSERT_FALSE(am.expr->pair.cdr->pair.car->is_atom);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr->pair.cdr->pair.car->pair.car);
|
|
TEST_ASSERT_TRUE(am.expr->pair.cdr->pair.car->pair.car->is_atom);
|
|
TEST_ASSERT_EQUAL(
|
|
ATOM_TYPE_INTEGER, am.expr->pair.cdr->pair.car->pair.car->atom.type);
|
|
TEST_ASSERT_EQUAL(
|
|
2, am.expr->pair.cdr->pair.car->pair.car->atom.integer);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr->pair.cdr->pair.car->pair.cdr);
|
|
TEST_ASSERT_TRUE(am.expr->pair.cdr->pair.car->pair.cdr->is_atom);
|
|
TEST_ASSERT_EQUAL(
|
|
ATOM_TYPE_EMPTY_LIST,
|
|
am.expr->pair.cdr->pair.car->pair.cdr->atom.type);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr->pair.cdr->pair.cdr);
|
|
TEST_ASSERT_FALSE(am.expr->pair.cdr->pair.cdr->is_atom);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr->pair.cdr->pair.cdr->pair.car);
|
|
TEST_ASSERT_TRUE(am.expr->pair.cdr->pair.cdr->pair.car->is_atom);
|
|
TEST_ASSERT_EQUAL(
|
|
ATOM_TYPE_INTEGER, am.expr->pair.cdr->pair.cdr->pair.car->atom.type);
|
|
TEST_ASSERT_EQUAL(
|
|
3, am.expr->pair.cdr->pair.cdr->pair.car->atom.integer);
|
|
|
|
TEST_ASSERT_NOT_NULL(am.expr->pair.cdr->pair.cdr->pair.cdr);
|
|
TEST_ASSERT_TRUE(am.expr->pair.cdr->pair.cdr->pair.cdr->is_atom);
|
|
TEST_ASSERT_EQUAL(
|
|
ATOM_TYPE_EMPTY_LIST,
|
|
am.expr->pair.cdr->pair.cdr->pair.cdr->atom.type);
|
|
}
|
|
|
|
static void test_close_paren(void)
|
|
{
|
|
const token_t token = { .type = TOKEN_TYPE_CLOSE_PAREN };
|
|
const parse_state_t state = parse_proc(&ctx, &token);
|
|
TEST_ASSERT_EQUAL(PARSE_STATE_ERROR, state);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
UNITY_BEGIN();
|
|
RUN_TEST(test_integer_123);
|
|
RUN_TEST(test_integer_321);
|
|
RUN_TEST(test_symbol_foo);
|
|
RUN_TEST(test_symbol_quux);
|
|
RUN_TEST(test_open_paren_close_paren);
|
|
RUN_TEST(test_open_paren_foo_42_close_paren);
|
|
RUN_TEST(test_open_paren_1_open_paren_2_close_paren_3_close_paren);
|
|
RUN_TEST(test_close_paren);
|
|
return UNITY_END();
|
|
}
|