From 2cf4cd95874af4382a2fdfd67cbb7d3f1ac66658 Mon Sep 17 00:00:00 2001 From: Max Regan Date: Wed, 2 Nov 2022 21:26:52 -0400 Subject: [PATCH] Add 'list' and 'print' builtins --- src/builtins.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++- src/builtins.h | 2 ++ src/evaluate.c | 4 ++++ src/main.c | 18 +++++----------- src/state.c | 3 ++- test/test_e2e.c | 14 ++++++++++++ 6 files changed, 83 insertions(+), 15 deletions(-) diff --git a/src/builtins.c b/src/builtins.c index 27159d7..acdfd9a 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -8,6 +8,7 @@ #include #include #include +#include LISP_FUNC_1(ucl_builtin_type, state, arg) { switch (arg->type) { @@ -21,6 +22,8 @@ LISP_FUNC_1(ucl_builtin_type, state, arg) { return ucl_symbol_create("string"); case UCL_TYPE_ERROR: return ucl_symbol_create("error"); + case UCL_TYPE_BUILTIN: + return ucl_symbol_create("builtin"); case UCL_TYPE_COUNT: assert(0); return NULL; @@ -138,7 +141,9 @@ LISP_FUNC_2(ucl_builtin_concat, state, arg0, arg1) { strcat(outstr, arg0->string); strcat(outstr, arg1->string); - return ucl_string_create(outstr); + struct ucl_object *result = ucl_string_create(outstr); + free(outstr); + return result; } LISP_FUNC_0(ucl_builtin_now_millis_mono, state) { @@ -146,6 +151,47 @@ LISP_FUNC_0(ucl_builtin_now_millis_mono, state) { return NULL; } +static void ucl_print_obj(struct ucl_object *obj) { + switch (obj->type) { + case UCL_TYPE_SYMBOL: + printf("%s", obj->symbol); + break; + case UCL_TYPE_INT: + printf("%d", obj->integer); + break; + case UCL_TYPE_STRING: + printf("\"%s\"", obj->string); + break; + case UCL_TYPE_ERROR: + printf("(error \"%s\")", obj->error); + break; + case UCL_TYPE_BUILTIN: + printf("", obj->builtin); + break; + case UCL_TYPE_CELL: { + int first = true; + printf("%s", "("); + FOREACH_LIST(obj, iter, item) { + if (!first) { + printf(" "); + } + ucl_print_obj(item); + first = false; + } + printf("%s", ")"); + break; + } + case UCL_TYPE_COUNT: + assert(0); + } +} + +LISP_FUNC_1(ucl_builtin_print, state, arg0) { + ucl_print_obj(arg0); + + return ucl_nil_create(); +} + struct ucl_object *ucl_builtin_let(struct ucl_state *state, struct ucl_object *args) { // TODO: Check arguments struct ucl_object *assignments = ucl_car(args); @@ -180,3 +226,12 @@ struct ucl_object *ucl_builtin_let(struct ucl_state *state, struct ucl_object *a ucl_state_delete(let_state); return result; } + +struct ucl_object *ucl_builtin_list(struct ucl_state *state, struct ucl_object *args) { + struct ucl_object *head = ucl_nil_create(); + FOREACH_LIST(args, iter, item) { + ucl_list_append(head, item); + } + + return head; +} diff --git a/src/builtins.h b/src/builtins.h index 800539b..4468a4d 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -63,5 +63,7 @@ struct ucl_object *ucl_builtin_concat(struct ucl_state *state, struct ucl_object struct ucl_object *ucl_builtin_now_millis_mono(struct ucl_state *state, struct ucl_object *args); struct ucl_object *ucl_builtin_let(struct ucl_state *state, struct ucl_object *args); +struct ucl_object *ucl_builtin_list(struct ucl_state *state, struct ucl_object *args); +struct ucl_object *ucl_builtin_print(struct ucl_state *state, struct ucl_object *args); #endif diff --git a/src/evaluate.c b/src/evaluate.c index 03d1fb6..30b302e 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -10,6 +10,10 @@ #include struct ucl_object *ucl_evaluate_list(struct ucl_state *state, struct ucl_object *list) { + if (list->cell.car == NULL) { + return list; + } + // TODO: Recursively eval args struct ucl_object *evaluated_list = ucl_nil_create(); diff --git a/src/main.c b/src/main.c index fb1bbdb..17b24ba 100644 --- a/src/main.c +++ b/src/main.c @@ -12,6 +12,8 @@ int main(int argc, const char **argv) { struct ucl_state *state = ucl_state_create(); ucl_state_put(state, "let", ucl_builtin_create(ucl_builtin_let)); + ucl_state_put(state, "print", ucl_builtin_create(ucl_builtin_print)); + ucl_state_put(state, "list", ucl_builtin_create(ucl_builtin_list)); ucl_state_put(state, "+", ucl_builtin_create(ucl_builtin_add)); ucl_state_put(state, "-", ucl_builtin_create(ucl_builtin_sub)); @@ -31,19 +33,9 @@ int main(int argc, const char **argv) { struct ucl_object *sexp = ucl_parse(argv[1]); struct ucl_object *result = ucl_evaluate(state, ucl_car(sexp)); - switch (result->type) { - case UCL_TYPE_INT: - printf("%d\n", result->integer); - break; - case UCL_TYPE_STRING: - printf("\"%s\"\n", result->string); - break; - case UCL_TYPE_SYMBOL: - printf("%s\n", result->string); - break; - case UCL_TYPE_ERROR: - printf("ERROR: %s\n", result->error); - return 1; + if (result->type == UCL_TYPE_ERROR) { + printf("%s", result->error); + return -1; } return 0; diff --git a/src/state.c b/src/state.c index 1daf50b..94845ae 100644 --- a/src/state.c +++ b/src/state.c @@ -34,7 +34,8 @@ struct ucl_object *ucl_state_get(struct ucl_state *state, const char *name) { struct ucl_object *cell = ucl_state_get_cell(state, name); if (cell == NULL) { if (state->parent == NULL) { - return ucl_error_create("Unknown error"); + // TODO: Include the symbol name + return ucl_error_create("Unbound symbol"); } else { return ucl_state_get(state->parent, name); } diff --git a/test/test_e2e.c b/test/test_e2e.c index e4c858f..923169e 100644 --- a/test/test_e2e.c +++ b/test/test_e2e.c @@ -21,6 +21,7 @@ void setUp(void) { ucl_state_put(state, "let", ucl_builtin_create(ucl_builtin_let)); ucl_state_put(state, "+", ucl_builtin_create(ucl_builtin_add)); ucl_state_put(state, "error", ucl_builtin_create(ucl_builtin_error)); + ucl_state_put(state, "list", ucl_builtin_create(ucl_builtin_list)); } void tearDown(void) { @@ -108,6 +109,18 @@ static void test_eval_nested_error(void) { TEST_ASSERT_OBJ_ERROR(response); } +static void test_eval_list(void) { + response = eval("(list 1 2 3)"); + TEST_ASSERT_OBJ_LIST(response); + TEST_ASSERT_EQUAL(ucl_list_length(response)->integer, 3); + + int i = 1; + FOREACH_LIST(response, iter, item) { + TEST_ASSERT_EQUAL(item->integer, i); + i++; + } +} + int main(void) { UNITY_BEGIN(); @@ -124,6 +137,7 @@ int main(void) { RUN_TEST(test_eval_sym_defined); RUN_TEST(test_eval_sym_undefined); RUN_TEST(test_eval_nested_error); + RUN_TEST(test_eval_list); return UNITY_END(); }