From 1595a6310d74678c6e0fef12636fd325d80a7e3c Mon Sep 17 00:00:00 2001 From: Max Regan Date: Tue, 15 Nov 2022 22:57:25 -0500 Subject: [PATCH] Minor refactor to parsing and testing cleanup --- src/parse.c | 33 ++++++++----------- src/utility.c | 4 +-- test/test_e2e.c | 73 +++++++++++++----------------------------- test/test_parse.c | 44 ++++++------------------- test/testing_helpers.h | 44 ++++++++++++++++++------- 5 files changed, 81 insertions(+), 117 deletions(-) diff --git a/src/parse.c b/src/parse.c index aa4a320..2f7dc27 100644 --- a/src/parse.c +++ b/src/parse.c @@ -57,7 +57,7 @@ struct ucl_object *ucl_token_next(const char **curr_src) { str[0] = **curr_src; str[1] = '\0'; (*curr_src)++; - return ucl_cell_create(ucl_symbol_create(str), NULL); + return ucl_symbol_create(str); case QUOTE_CHAR: // skip beginning quote (*curr_src)++; @@ -69,20 +69,22 @@ struct ucl_object *ucl_token_next(const char **curr_src) { (*curr_src)++; // -2 for removing start/end quotes str = strndup(start + 1, *curr_src - start - 2); - return ucl_cell_create(ucl_string_create(str), NULL); + // TODO: free + return ucl_string_create(str); case '0'...'9': { // TODO: Add support for negative integers char *end = NULL; long value = strtol(*curr_src, &end, 0); *curr_src = end; - return ucl_cell_create(ucl_int_create(value), NULL); + return ucl_int_create(value); } default: while (!ucl_is_delimiter(**curr_src)) { (*curr_src)++; } + // TODO: Free str = strndup(start, *curr_src - start); - return ucl_cell_create(ucl_symbol_create(str), NULL); + return ucl_symbol_create(str); } } @@ -92,12 +94,12 @@ struct ucl_object *ucl_token_next(const char **curr_src) { } struct ucl_object *ucl_tokenize(const char *source) { - struct ucl_object *tokens = NULL, *curr_token = NULL, **next_token = &tokens; + struct ucl_object *tokens = ucl_nil_create(); + struct ucl_object *curr_token = NULL; const char *curr_src = source; while ((curr_token = ucl_token_next(&curr_src)) != NULL) { - *next_token = curr_token; - next_token = &curr_token->cell.cdr; + ucl_list_append(tokens, curr_token); } return tokens; @@ -197,9 +199,9 @@ static struct ucl_object *ucl_parse_tokens_recursive(struct ucl_object **token_i // parse_tokens_recursive -> error on EOF) struct ucl_object *ucl_parse_tokens(struct ucl_object *tokens) { - struct ucl_object* resultl = NULL; + struct ucl_object* result = ucl_nil_create(); + struct ucl_object* result_tail = result; struct ucl_object** token_iter = &tokens; - struct ucl_object** next_cell = &resultl; while (*token_iter != NULL) { struct ucl_object *new_sexp = ucl_parse_tokens_recursive(token_iter); @@ -207,25 +209,18 @@ struct ucl_object *ucl_parse_tokens(struct ucl_object *tokens) { return new_sexp; } - *next_cell = ucl_cell_create(new_sexp, NULL); - next_cell = &(*next_cell)->cell.cdr; + ucl_list_append(result_tail, new_sexp); } - if (resultl == NULL) { - return ucl_cell_create(NULL, NULL); - } - - return resultl; + return result; } // TODO: Should the parse a single sexp (return the last-parsed position), or // all sexps in the source (return a list of sexps)? struct ucl_object *ucl_parse(const char *source) { struct ucl_object *tokens = ucl_tokenize(source); - if (tokens == NULL) { - tokens = ucl_nil_create(); - } UCL_RET_IF_ERROR(tokens); + struct ucl_object *sexp = ucl_parse_tokens(tokens); if (sexp == NULL) { return ucl_nil_create(); diff --git a/src/utility.c b/src/utility.c index f43c12b..07e436b 100644 --- a/src/utility.c +++ b/src/utility.c @@ -116,7 +116,7 @@ struct ucl_object *ucl_list_append(struct ucl_object *list, struct ucl_object *o if (list->cell.car == NULL) { list->cell.car = obj; - return list; + return NULL; } while (iter->cell.cdr != NULL) { @@ -124,7 +124,7 @@ struct ucl_object *ucl_list_append(struct ucl_object *list, struct ucl_object *o } iter->cell.cdr = ucl_cell_create(obj, NULL); - return list; + return iter->cell.cdr; } void ucl_print_obj(struct ucl_object *obj) { diff --git a/test/test_e2e.c b/test/test_e2e.c index 8f29304..51b660f 100644 --- a/test/test_e2e.c +++ b/test/test_e2e.c @@ -42,23 +42,19 @@ void tearDown(void) { scope = NULL; } - static struct ucl_object *eval (const char *code) { struct ucl_object *sexp = ucl_parse(code); return ucl_evaluate(scope, ucl_car(sexp)); } void test_simple_add(void) { - ucl_scope_put(scope, "+", ucl_builtin_create(ucl_builtin_add)); response = eval("(+ 2 3)"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 5); + TEST_ASSERT_OBJ_INT_V(response, 5); } void test_simple_let(void) { response = eval("(let ((x 2)) (+ x 3))"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 5); + TEST_ASSERT_OBJ_INT_V(response, 5); } void test_let_assignment_error(void) { @@ -68,8 +64,7 @@ void test_let_assignment_error(void) { void test_nested_let(void) { response = eval("(let ((x 2)) (let ((y 5)) (+ x y)))"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 7); + TEST_ASSERT_OBJ_INT_V(response, 7); } void test_nested_let_scope(void) { @@ -79,33 +74,28 @@ void test_nested_let_scope(void) { void test_multi_let(void) { response = eval("(let ((x 2)(y 5)) (+ x y))"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 7); + TEST_ASSERT_OBJ_INT_V(response, 7); } void test_let_return_sym(void) { response = eval("(let ((x 2)) x)"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 2); + TEST_ASSERT_OBJ_INT_V(response, 2); } void test_eval_int(void) { response = eval("2"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 2); + TEST_ASSERT_OBJ_INT_V(response, 2); } void test_eval_string(void) { response = eval("\"foo\""); - TEST_ASSERT_OBJ_STRING(response); - TEST_ASSERT_EQUAL_STRING(response->string, "foo"); + TEST_ASSERT_OBJ_STRING_V(response, "foo"); } void test_eval_sym_defined(void) { ucl_scope_put(scope, "foo", ucl_int_create(2)); response = eval("foo"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 2); + TEST_ASSERT_OBJ_INT_V(response, 2); } void test_eval_sym_undefined(void) { @@ -133,8 +123,7 @@ void test_eval_list(void) { void test_eval_defun(void) { response = eval("(defun foo (a b) (+ a b))"); - TEST_ASSERT_OBJ_SYMBOL(response); - TEST_ASSERT_EQUAL_STRING(response->symbol, "foo"); + TEST_ASSERT_OBJ_SYMBOL_V(response, "foo"); } void test_call_function(void) { @@ -152,44 +141,37 @@ void test_call_function(void) { void test_setq(void) { response = eval("(setq bar 123)"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->symbol, 123); + TEST_ASSERT_OBJ_INT_V(response, 123); response = eval("bar"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->symbol, 123); + TEST_ASSERT_OBJ_INT_V(response, 123); } void test_setq_from_function(void) { response = eval("(defun foo (a) (setq bar a))"); - TEST_ASSERT_OBJ_SYMBOL(response); - TEST_ASSERT_EQUAL_STRING(response->symbol, "foo"); + TEST_ASSERT_OBJ_SYMBOL_V(response, "foo"); response = eval("(foo 2)"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->symbol, 2); + TEST_ASSERT_OBJ_INT_V(response, 2); response = eval("bar"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->symbol, 2); + TEST_ASSERT_OBJ_INT_V(response, 2); } void test_lambda(void) { response = eval("((lambda (x) (+ x 2)) 2)"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 4); + TEST_ASSERT_OBJ_INT_V(response, 4); } void test_mapcar_lambda(void) { response = eval("(car (mapcar (quote (lambda (x) (+ x 2))) (list 5)))"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 7); + TEST_ASSERT_OBJ_INT_V(response, 7); } void test_mapcar_function(void) { @@ -200,36 +182,31 @@ void test_mapcar_function(void) { response = eval("(car (mapcar (quote foo) (list 5)))"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 7); + TEST_ASSERT_OBJ_INT_V(response, 7); } void test_car(void) { response = eval("(car (list 2 3 4))"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 2); + TEST_ASSERT_OBJ_INT_V(response, 2); } void test_cdr(void) { response = eval("(car (cdr (list 2 3 4)))"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 3); + TEST_ASSERT_OBJ_INT_V(response, 3); } void test_nth_0(void) { response = eval("(nth 0 (list 2 3 4))"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 2); + TEST_ASSERT_OBJ_INT_V(response, 2); } void test_nth_1(void) { response = eval("(nth 1 (list 2 3 4))"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 3); + TEST_ASSERT_OBJ_INT_V(response, 3); } void test_nth_oob(void) { @@ -241,16 +218,12 @@ void test_nth_oob(void) { void test_eval_defun_gc(void) { response = eval("(defun foo (a b) (+ a b))"); - TEST_ASSERT_OBJ_SYMBOL(response); - TEST_ASSERT_EQUAL_STRING(response->symbol, "foo"); + TEST_ASSERT_OBJ_SYMBOL_V(response, "foo"); ucl_gc(); - response = eval("(foo 10 15)"); - TEST_ASSERT_OBJ_INT(response); - TEST_ASSERT_EQUAL(response->integer, 25); - + TEST_ASSERT_OBJ_INT_V(response, 25); } int main(void) { diff --git a/test/test_parse.c b/test/test_parse.c index 4c1afbb..cbf0acf 100644 --- a/test/test_parse.c +++ b/test/test_parse.c @@ -43,11 +43,7 @@ static void test_token_next_lparen(void) { const char *curr = input; response = ucl_token_next(&curr); - - TEST_ASSERT_NOT_NULL(response); - TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type); - TEST_ASSERT_EQUAL(UCL_TYPE_SYMBOL, response->cell.car->type); - TEST_ASSERT_EQUAL_STRING("(", response->cell.car->string); + TEST_ASSERT_OBJ_SYMBOL_V(response, "("); TEST_ASSERT_EQUAL('\0', *curr); } @@ -57,10 +53,7 @@ static void test_token_next_rparen(void) { response = ucl_token_next(&curr); - TEST_ASSERT_NOT_NULL(response); - TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type); - TEST_ASSERT_EQUAL(UCL_TYPE_SYMBOL, response->cell.car->type); - TEST_ASSERT_EQUAL_STRING(")", response->cell.car->string); + TEST_ASSERT_OBJ_SYMBOL_V(response, ")"); TEST_ASSERT_EQUAL('\0', *curr); } @@ -70,19 +63,12 @@ static void test_token_next_lrparen(void) { response = ucl_token_next(&curr); - TEST_ASSERT_NOT_NULL(response); - TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type); - TEST_ASSERT_EQUAL(UCL_TYPE_SYMBOL, response->cell.car->type); - TEST_ASSERT_EQUAL_STRING("(", response->cell.car->string); - TEST_ASSERT_EQUAL(')', *curr); + TEST_ASSERT_OBJ_SYMBOL_V(response, "("); ucl_object_delete(response); response = ucl_token_next(&curr); - TEST_ASSERT_NOT_NULL(response); - TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type); - TEST_ASSERT_EQUAL(UCL_TYPE_SYMBOL, response->cell.car->type); - TEST_ASSERT_EQUAL_STRING(")", response->cell.car->string); + TEST_ASSERT_OBJ_SYMBOL_V(response, ")"); TEST_ASSERT_EQUAL('\0', *curr); } @@ -92,10 +78,7 @@ static void test_token_next_string(void) { response = ucl_token_next(&curr); - TEST_ASSERT_NOT_NULL(response); - TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type); - TEST_ASSERT_EQUAL(UCL_TYPE_STRING, response->cell.car->type); - TEST_ASSERT_EQUAL_STRING("foo", response->cell.car->string); + TEST_ASSERT_OBJ_STRING_V(response, "foo"); TEST_ASSERT_EQUAL('\0', *curr); } @@ -105,10 +88,7 @@ static void test_token_next_string_w_whitespace(void) { response = ucl_token_next(&curr); - TEST_ASSERT_NOT_NULL(response); - TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type); - TEST_ASSERT_EQUAL(UCL_TYPE_STRING, response->cell.car->type); - TEST_ASSERT_EQUAL_STRING("foo", response->cell.car->string); + TEST_ASSERT_OBJ_STRING_V(response, "foo"); TEST_ASSERT_EQUAL_STRING(" ", curr); } @@ -118,10 +98,7 @@ static void test_token_next_symbol(void) { response = ucl_token_next(&curr); - TEST_ASSERT_NOT_NULL(response); - TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type); - TEST_ASSERT_EQUAL(UCL_TYPE_SYMBOL, response->cell.car->type); - TEST_ASSERT_EQUAL_STRING("foo", response->cell.car->string); + TEST_ASSERT_OBJ_SYMBOL_V(response, "foo"); TEST_ASSERT_EQUAL_STRING("", curr); } @@ -131,17 +108,14 @@ static void test_token_next_symbol_w_whitespace(void) { response = ucl_token_next(&curr); - TEST_ASSERT_NOT_NULL(response); - TEST_ASSERT_EQUAL(UCL_TYPE_CELL, response->type); - TEST_ASSERT_EQUAL(UCL_TYPE_SYMBOL, response->cell.car->type); - TEST_ASSERT_EQUAL_STRING("foo", response->cell.car->string); + TEST_ASSERT_OBJ_SYMBOL_V(response, "foo"); TEST_ASSERT_EQUAL_STRING(" ", curr); } static void test_tokenize_empty_str(void) { response = ucl_tokenize(""); - TEST_ASSERT_NULL(response); + TEST_ASSERT_NIL(response); } static void test_tokenize_nil(void) { diff --git a/test/testing_helpers.h b/test/testing_helpers.h index bf24627..8f7dcbb 100644 --- a/test/testing_helpers.h +++ b/test/testing_helpers.h @@ -4,26 +4,48 @@ #include #include "uclisp.h" +#include "utility.h" -#define TEST_ASSERT_OBJ_ERROR(obj) \ - TEST_ASSERT_EQUAL(obj->type, UCL_TYPE_ERROR) +#define TEST_ASSERT_OBJ_ERROR(obj) \ + TEST_ASSERT_EQUAL_MESSAGE(UCL_TYPE_ERROR, (obj)->type, "Expected error type") -#define TEST_ASSERT_OBJ_SYMBOL(obj) \ - TEST_ASSERT_EQUAL(obj->type, UCL_TYPE_SYMBOL) +#define TEST_ASSERT_OBJ_SYMBOL(obj) \ + TEST_ASSERT_EQUAL_MESSAGE(UCL_TYPE_SYMBOL, (obj)->type, "Expected symbol type") -#define TEST_ASSERT_OBJ_STRING(obj) \ - TEST_ASSERT_EQUAL(obj->type, UCL_TYPE_STRING) +#define TEST_ASSERT_OBJ_SYMBOL_V(obj, value) \ + do { \ + TEST_ASSERT_NOT_NULL(obj); \ + TEST_ASSERT_EQUAL_MESSAGE(UCL_TYPE_SYMBOL, (obj)->type, "Expected symbol type"); \ + TEST_ASSERT_EQUAL_STRING((obj)->symbol, value); \ + } while (0) -#define TEST_ASSERT_OBJ_INT(obj) \ - TEST_ASSERT_EQUAL(obj->type, UCL_TYPE_INT) +#define TEST_ASSERT_OBJ_STRING(obj) \ + TEST_ASSERT_EQUAL_MESSAGE(UCL_TYPE_STRING, (obj)->type, "Expected string type") -#define TEST_ASSERT_OBJ_LIST(obj) \ - TEST_ASSERT_EQUAL(obj->type, UCL_TYPE_CELL) +#define TEST_ASSERT_OBJ_STRING_V(obj, value) \ + do { \ + TEST_ASSERT_NOT_NULL(obj); \ + TEST_ASSERT_EQUAL_MESSAGE(UCL_TYPE_STRING, (obj)->type, "Expected string type"); \ + TEST_ASSERT_EQUAL_STRING((obj)->string, value); \ + } while (0) + +#define TEST_ASSERT_OBJ_INT(obj) \ + TEST_ASSERT_EQUAL_MESSAGE(UCL_TYPE_INT, (obj)->type, "Expected int type") + +#define TEST_ASSERT_OBJ_INT_V(obj, value) \ + do { \ + TEST_ASSERT_NOT_NULL(obj); \ + TEST_ASSERT_EQUAL_MESSAGE(UCL_TYPE_INT, (obj)->type, "Expected int type"); \ + TEST_ASSERT_EQUAL(value, (obj)->integer); \ + } while (0) + +#define TEST_ASSERT_OBJ_LIST(obj) \ + TEST_ASSERT_EQUAL_MESSAGE(UCL_TYPE_CELL, obj->type, "Expected cell type") #define TEST_ASSERT_LIST_LEN(list, len) \ do { \ TEST_ASSERT_OBJ_LIST(list); \ - TEST_ASSERT_EQUAL(ucl_list_length(list)->integer, len); \ + TEST_ASSERT_EQUAL(len, ucl_list_length(list)->integer); \ } while(0) #define TEST_ASSERT_NIL(obj) \