#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.regs[EXPR]); TEST_ASSERT_TRUE(am.regs[EXPR]->is_atom); TEST_ASSERT_EQUAL(ATOM_TYPE_INTEGER, am.regs[EXPR]->atom.type); TEST_ASSERT_EQUAL(123, am.regs[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.regs[EXPR]); TEST_ASSERT_TRUE(am.regs[EXPR]->is_atom); TEST_ASSERT_EQUAL(ATOM_TYPE_INTEGER, am.regs[EXPR]->atom.type); TEST_ASSERT_EQUAL(321, am.regs[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.regs[EXPR]); TEST_ASSERT_TRUE(am.regs[EXPR]->is_atom); TEST_ASSERT_EQUAL(ATOM_TYPE_SYMBOL, am.regs[EXPR]->atom.type); TEST_ASSERT_EQUAL(3, am.regs[EXPR]->atom.symbol.len); TEST_ASSERT_EQUAL_MEMORY("foo", am.regs[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.regs[EXPR]); TEST_ASSERT_TRUE(am.regs[EXPR]->is_atom); TEST_ASSERT_EQUAL(ATOM_TYPE_SYMBOL, am.regs[EXPR]->atom.type); TEST_ASSERT_EQUAL(4, am.regs[EXPR]->atom.symbol.len); TEST_ASSERT_EQUAL_MEMORY("quux", am.regs[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.regs[EXPR]); TEST_ASSERT_TRUE(am.regs[EXPR]->is_atom); TEST_ASSERT_EQUAL(ATOM_TYPE_EMPTY_LIST, am.regs[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.regs[EXPR]); TEST_ASSERT_FALSE(am.regs[EXPR]->is_atom); TEST_ASSERT_NOT_NULL(am.regs[EXPR]->pair.car); TEST_ASSERT_TRUE(am.regs[EXPR]->pair.car->is_atom); TEST_ASSERT_EQUAL(ATOM_TYPE_SYMBOL, am.regs[EXPR]->pair.car->atom.type); TEST_ASSERT_EQUAL(3, am.regs[EXPR]->pair.car->atom.symbol.len); TEST_ASSERT_EQUAL_MEMORY( "foo", am.regs[EXPR]->pair.car->atom.symbol.buf, 3); TEST_ASSERT_NOT_NULL(am.regs[EXPR]->pair.cdr); TEST_ASSERT_FALSE(am.regs[EXPR]->pair.cdr->is_atom); TEST_ASSERT_NOT_NULL(am.regs[EXPR]->pair.cdr->pair.car); TEST_ASSERT_TRUE(am.regs[EXPR]->pair.cdr->pair.car->is_atom); TEST_ASSERT_EQUAL( ATOM_TYPE_INTEGER, am.regs[EXPR]->pair.cdr->pair.car->atom.type); TEST_ASSERT_EQUAL(42, am.regs[EXPR]->pair.cdr->pair.car->atom.integer); TEST_ASSERT_NOT_NULL(am.regs[EXPR]->pair.cdr->pair.cdr); TEST_ASSERT_TRUE(am.regs[EXPR]->pair.cdr->pair.cdr->is_atom); TEST_ASSERT_EQUAL( ATOM_TYPE_EMPTY_LIST, am.regs[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.regs[EXPR]); TEST_ASSERT_FALSE(am.regs[EXPR]->is_atom); TEST_ASSERT_NOT_NULL(am.regs[EXPR]->pair.car); TEST_ASSERT_TRUE(am.regs[EXPR]->pair.car->is_atom); TEST_ASSERT_EQUAL(ATOM_TYPE_INTEGER, am.regs[EXPR]->pair.car->atom.type); TEST_ASSERT_EQUAL(1, am.regs[EXPR]->pair.car->atom.integer); TEST_ASSERT_NOT_NULL(am.regs[EXPR]->pair.cdr); TEST_ASSERT_FALSE(am.regs[EXPR]->pair.cdr->is_atom); TEST_ASSERT_NOT_NULL(am.regs[EXPR]->pair.cdr->pair.car); TEST_ASSERT_FALSE(am.regs[EXPR]->pair.cdr->pair.car->is_atom); TEST_ASSERT_NOT_NULL(am.regs[EXPR]->pair.cdr->pair.car->pair.car); TEST_ASSERT_TRUE(am.regs[EXPR]->pair.cdr->pair.car->pair.car->is_atom); TEST_ASSERT_EQUAL( ATOM_TYPE_INTEGER, am.regs[EXPR]->pair.cdr->pair.car->pair.car->atom.type); TEST_ASSERT_EQUAL( 2, am.regs[EXPR]->pair.cdr->pair.car->pair.car->atom.integer); TEST_ASSERT_NOT_NULL(am.regs[EXPR]->pair.cdr->pair.car->pair.cdr); TEST_ASSERT_TRUE(am.regs[EXPR]->pair.cdr->pair.car->pair.cdr->is_atom); TEST_ASSERT_EQUAL( ATOM_TYPE_EMPTY_LIST, am.regs[EXPR]->pair.cdr->pair.car->pair.cdr->atom.type); TEST_ASSERT_NOT_NULL(am.regs[EXPR]->pair.cdr->pair.cdr); TEST_ASSERT_FALSE(am.regs[EXPR]->pair.cdr->pair.cdr->is_atom); TEST_ASSERT_NOT_NULL(am.regs[EXPR]->pair.cdr->pair.cdr->pair.car); TEST_ASSERT_TRUE(am.regs[EXPR]->pair.cdr->pair.cdr->pair.car->is_atom); TEST_ASSERT_EQUAL( ATOM_TYPE_INTEGER, am.regs[EXPR]->pair.cdr->pair.cdr->pair.car->atom.type); TEST_ASSERT_EQUAL( 3, am.regs[EXPR]->pair.cdr->pair.cdr->pair.car->atom.integer); TEST_ASSERT_NOT_NULL(am.regs[EXPR]->pair.cdr->pair.cdr->pair.cdr); TEST_ASSERT_TRUE(am.regs[EXPR]->pair.cdr->pair.cdr->pair.cdr->is_atom); TEST_ASSERT_EQUAL( ATOM_TYPE_EMPTY_LIST, am.regs[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(); }