Add 'list' and 'print' builtins

This commit is contained in:
2022-11-02 21:26:52 -04:00
parent 3b7bef779b
commit 2cf4cd9587
6 changed files with 83 additions and 15 deletions

View File

@@ -8,6 +8,7 @@
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
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("<builtin %p>", 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;
}

View File

@@ -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

View File

@@ -10,6 +10,10 @@
#include <string.h>
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();

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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();
}