Add 'list' and 'print' builtins
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
LISP_FUNC_1(ucl_builtin_type, state, arg) {
|
LISP_FUNC_1(ucl_builtin_type, state, arg) {
|
||||||
switch (arg->type) {
|
switch (arg->type) {
|
||||||
@@ -21,6 +22,8 @@ LISP_FUNC_1(ucl_builtin_type, state, arg) {
|
|||||||
return ucl_symbol_create("string");
|
return ucl_symbol_create("string");
|
||||||
case UCL_TYPE_ERROR:
|
case UCL_TYPE_ERROR:
|
||||||
return ucl_symbol_create("error");
|
return ucl_symbol_create("error");
|
||||||
|
case UCL_TYPE_BUILTIN:
|
||||||
|
return ucl_symbol_create("builtin");
|
||||||
case UCL_TYPE_COUNT:
|
case UCL_TYPE_COUNT:
|
||||||
assert(0);
|
assert(0);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -138,7 +141,9 @@ LISP_FUNC_2(ucl_builtin_concat, state, arg0, arg1) {
|
|||||||
strcat(outstr, arg0->string);
|
strcat(outstr, arg0->string);
|
||||||
strcat(outstr, arg1->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) {
|
LISP_FUNC_0(ucl_builtin_now_millis_mono, state) {
|
||||||
@@ -146,6 +151,47 @@ LISP_FUNC_0(ucl_builtin_now_millis_mono, state) {
|
|||||||
return NULL;
|
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) {
|
struct ucl_object *ucl_builtin_let(struct ucl_state *state, struct ucl_object *args) {
|
||||||
// TODO: Check arguments
|
// TODO: Check arguments
|
||||||
struct ucl_object *assignments = ucl_car(args);
|
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);
|
ucl_state_delete(let_state);
|
||||||
return result;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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_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_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
|
#endif
|
||||||
|
|||||||
@@ -10,6 +10,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
struct ucl_object *ucl_evaluate_list(struct ucl_state *state, struct ucl_object *list) {
|
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
|
// TODO: Recursively eval args
|
||||||
struct ucl_object *evaluated_list = ucl_nil_create();
|
struct ucl_object *evaluated_list = ucl_nil_create();
|
||||||
|
|
||||||
|
|||||||
18
src/main.c
18
src/main.c
@@ -12,6 +12,8 @@ int main(int argc, const char **argv) {
|
|||||||
struct ucl_state *state = ucl_state_create();
|
struct ucl_state *state = ucl_state_create();
|
||||||
|
|
||||||
ucl_state_put(state, "let", ucl_builtin_create(ucl_builtin_let));
|
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_add));
|
||||||
ucl_state_put(state, "-", ucl_builtin_create(ucl_builtin_sub));
|
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 *sexp = ucl_parse(argv[1]);
|
||||||
struct ucl_object *result = ucl_evaluate(state, ucl_car(sexp));
|
struct ucl_object *result = ucl_evaluate(state, ucl_car(sexp));
|
||||||
|
|
||||||
switch (result->type) {
|
if (result->type == UCL_TYPE_ERROR) {
|
||||||
case UCL_TYPE_INT:
|
printf("%s", result->error);
|
||||||
printf("%d\n", result->integer);
|
return -1;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -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);
|
struct ucl_object *cell = ucl_state_get_cell(state, name);
|
||||||
if (cell == NULL) {
|
if (cell == NULL) {
|
||||||
if (state->parent == NULL) {
|
if (state->parent == NULL) {
|
||||||
return ucl_error_create("Unknown error");
|
// TODO: Include the symbol name
|
||||||
|
return ucl_error_create("Unbound symbol");
|
||||||
} else {
|
} else {
|
||||||
return ucl_state_get(state->parent, name);
|
return ucl_state_get(state->parent, name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ void setUp(void) {
|
|||||||
ucl_state_put(state, "let", ucl_builtin_create(ucl_builtin_let));
|
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, "+", ucl_builtin_create(ucl_builtin_add));
|
||||||
ucl_state_put(state, "error", ucl_builtin_create(ucl_builtin_error));
|
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) {
|
void tearDown(void) {
|
||||||
@@ -108,6 +109,18 @@ static void test_eval_nested_error(void) {
|
|||||||
TEST_ASSERT_OBJ_ERROR(response);
|
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) {
|
int main(void) {
|
||||||
UNITY_BEGIN();
|
UNITY_BEGIN();
|
||||||
@@ -124,6 +137,7 @@ int main(void) {
|
|||||||
RUN_TEST(test_eval_sym_defined);
|
RUN_TEST(test_eval_sym_defined);
|
||||||
RUN_TEST(test_eval_sym_undefined);
|
RUN_TEST(test_eval_sym_undefined);
|
||||||
RUN_TEST(test_eval_nested_error);
|
RUN_TEST(test_eval_nested_error);
|
||||||
|
RUN_TEST(test_eval_list);
|
||||||
|
|
||||||
return UNITY_END();
|
return UNITY_END();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user