Add reduce and filter

This commit is contained in:
2022-11-16 22:55:06 -05:00
parent 1f7034c0c2
commit a093fb0b9c
5 changed files with 64 additions and 5 deletions

View File

@@ -196,6 +196,33 @@ LISP_FUNC_2(ucl_builtin_mapcar, scope, fun, elems) {
return result; return result;
} }
LISP_FUNC_2(ucl_builtin_filter, scope, predicate, elems) {
// TODO: Support arbitrary number of 'elems' lists
struct ucl_object *result = ucl_nil_create();
struct ucl_object *result_tail = result;
FOREACH_LIST(elems, iter, elem) {
struct ucl_object *form = ucl_tuple_create(predicate, elem);
struct ucl_object *value = ucl_evaluate(scope, form);
UCL_RET_IF_ERROR(value);
if (ucl_truthy_bool(value)) {
result_tail = ucl_list_append(result_tail, elem);
}
}
return result;
}
LISP_FUNC_3(ucl_builtin_reduce, scope, fun, elems, initial_value) {
// TODO: Support arbitrary number of 'elems' lists
struct ucl_object *result = initial_value;
FOREACH_LIST(elems, iter, elem) {
struct ucl_object *form = ucl_tuple_create(fun, elem);
ucl_list_append(form, result);
result = ucl_evaluate(scope, form);
UCL_RET_IF_ERROR(result);
}
return result;
}
LISP_FUNC_2(ucl_builtin_equal, scope, arg0, arg1) { LISP_FUNC_2(ucl_builtin_equal, scope, arg0, arg1) {
return ucl_equal(arg0, arg1); return ucl_equal(arg0, arg1);
} }
@@ -212,7 +239,6 @@ LISP_FUNC_2(ucl_builtin_ge, scope, arg0, arg1) {
return ucl_predicate(arg0->integer > arg1->integer); return ucl_predicate(arg0->integer > arg1->integer);
} }
LISP_FUNC_2(ucl_builtin_lt, scope, arg0, arg1) { LISP_FUNC_2(ucl_builtin_lt, scope, arg0, arg1) {
UCL_COND_OR_RET_ERROR(arg0->type == UCL_TYPE_INT, "First argument to < must be an integer"); UCL_COND_OR_RET_ERROR(arg0->type == UCL_TYPE_INT, "First argument to < must be an integer");
UCL_COND_OR_RET_ERROR(arg0->type == UCL_TYPE_INT, "Second argument to < must be an integer"); UCL_COND_OR_RET_ERROR(arg0->type == UCL_TYPE_INT, "Second argument to < must be an integer");

View File

@@ -32,6 +32,8 @@ struct ucl_object *ucl_builtin_cdr(struct ucl_scope *scope, struct ucl_object *a
struct ucl_object *ucl_builtin_nth(struct ucl_scope *scope, struct ucl_object *args); struct ucl_object *ucl_builtin_nth(struct ucl_scope *scope, struct ucl_object *args);
struct ucl_object *ucl_builtin_list(struct ucl_scope *scope, struct ucl_object *args); struct ucl_object *ucl_builtin_list(struct ucl_scope *scope, struct ucl_object *args);
struct ucl_object *ucl_builtin_mapcar(struct ucl_scope *scope, struct ucl_object *args); struct ucl_object *ucl_builtin_mapcar(struct ucl_scope *scope, struct ucl_object *args);
struct ucl_object *ucl_builtin_filter(struct ucl_scope *scope, struct ucl_object *args);
struct ucl_object *ucl_builtin_reduce(struct ucl_scope *scope, struct ucl_object *args);
struct ucl_object *ucl_builtin_append(struct ucl_scope *scope, struct ucl_object *args); struct ucl_object *ucl_builtin_append(struct ucl_scope *scope, struct ucl_object *args);
struct ucl_object *ucl_builtin_print(struct ucl_scope *scope, struct ucl_object *args); struct ucl_object *ucl_builtin_print(struct ucl_scope *scope, struct ucl_object *args);

View File

@@ -46,4 +46,23 @@
} \ } \
static struct ucl_object *func_name##_impl(struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name) static struct ucl_object *func_name##_impl(struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name)
// TODO: Unroll the args more efficiently, this is O(n^2)
#define LISP_FUNC_3(func_name, scope_name, arg0_name, arg1_name, arg2_name) \
static struct ucl_object *func_name##_impl(struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name, struct ucl_object *arg2_name); \
struct ucl_object *func_name(struct ucl_scope *scope, struct ucl_object *args) { \
struct ucl_object *len_obj = ucl_list_length(args); \
if (len_obj->type != UCL_TYPE_INT) { \
return NULL; \
} \
if (len_obj->integer != 3) { \
return NULL; \
} \
struct ucl_object *arg0 = ucl_list_nth(args, 0); \
struct ucl_object *arg1 = ucl_list_nth(args, 1); \
struct ucl_object *arg2 = ucl_list_nth(args, 2); \
return func_name##_impl(scope_name, arg0, arg1, arg2); \
} \
static struct ucl_object *func_name##_impl(struct ucl_scope *scope, struct ucl_object *arg0_name, struct ucl_object *arg1_name, struct ucl_object *arg2_name)
#endif #endif

View File

@@ -60,6 +60,8 @@ int main(int argc, const char **argv) {
ucl_scope_put(scope, "cdr", ucl_builtin_create(ucl_builtin_cdr)); ucl_scope_put(scope, "cdr", ucl_builtin_create(ucl_builtin_cdr));
ucl_scope_put(scope, "nth", ucl_builtin_create(ucl_builtin_nth)); ucl_scope_put(scope, "nth", ucl_builtin_create(ucl_builtin_nth));
ucl_scope_put(scope, "mapcar", ucl_builtin_create(ucl_builtin_mapcar)); ucl_scope_put(scope, "mapcar", ucl_builtin_create(ucl_builtin_mapcar));
ucl_scope_put(scope, "filter", ucl_builtin_create(ucl_builtin_filter));
ucl_scope_put(scope, "reduce", ucl_builtin_create(ucl_builtin_reduce));
ucl_scope_put(scope, "equal", ucl_builtin_create(ucl_builtin_equal)); ucl_scope_put(scope, "equal", ucl_builtin_create(ucl_builtin_equal));
ucl_scope_put(scope, "append", ucl_builtin_create(ucl_builtin_append)); ucl_scope_put(scope, "append", ucl_builtin_create(ucl_builtin_append));
@@ -67,10 +69,6 @@ int main(int argc, const char **argv) {
ucl_scope_put(scope, "dolist", ucl_special_create(ucl_special_dolist)); ucl_scope_put(scope, "dolist", ucl_special_create(ucl_special_dolist));
ucl_scope_put(scope, "while", ucl_special_create(ucl_special_while)); ucl_scope_put(scope, "while", ucl_special_create(ucl_special_while));
// TODO:
// - reduce
// - filter
if (argc < 2) { if (argc < 2) {
while (1) { while (1) {
char *line = readline("> "); char *line = readline("> ");

View File

@@ -29,8 +29,11 @@ void setUp(void) {
ucl_scope_put(scope, "cdr", ucl_builtin_create(ucl_builtin_cdr)); ucl_scope_put(scope, "cdr", ucl_builtin_create(ucl_builtin_cdr));
ucl_scope_put(scope, "nth", ucl_builtin_create(ucl_builtin_nth)); ucl_scope_put(scope, "nth", ucl_builtin_create(ucl_builtin_nth));
ucl_scope_put(scope, "mapcar", ucl_builtin_create(ucl_builtin_mapcar)); ucl_scope_put(scope, "mapcar", ucl_builtin_create(ucl_builtin_mapcar));
ucl_scope_put(scope, "filter", ucl_builtin_create(ucl_builtin_filter));
ucl_scope_put(scope, "reduce", ucl_builtin_create(ucl_builtin_reduce));
ucl_scope_put(scope, "lambda", ucl_special_create(ucl_special_lambda)); ucl_scope_put(scope, "lambda", ucl_special_create(ucl_special_lambda));
ucl_scope_put(scope, "quote", ucl_special_create(ucl_special_quote)); ucl_scope_put(scope, "quote", ucl_special_create(ucl_special_quote));
ucl_scope_put(scope, "%", ucl_builtin_create(ucl_builtin_mod));
} }
void tearDown(void) { void tearDown(void) {
@@ -226,6 +229,16 @@ void test_eval_defun_gc(void) {
TEST_ASSERT_OBJ_INT_V(response, 25); TEST_ASSERT_OBJ_INT_V(response, 25);
} }
void test_complex(void) {
response = eval("(defun sum (elems) (reduce (quote +) elems 0))");
TEST_ASSERT_OBJ_SYMBOL_V(response, "sum");
response = eval("(sum (filter (quote (lambda (x) (% x 2))) (list 1 2 3 4 5)))");
TEST_ASSERT_OBJ_INT_V(response, 9);
}
int main(void) { int main(void) {
UNITY_BEGIN(); UNITY_BEGIN();
@@ -254,6 +267,7 @@ int main(void) {
RUN_TEST(test_nth_1); RUN_TEST(test_nth_1);
RUN_TEST(test_nth_oob); RUN_TEST(test_nth_oob);
RUN_TEST(test_eval_defun_gc); RUN_TEST(test_eval_defun_gc);
RUN_TEST(test_complex);
return UNITY_END(); return UNITY_END();
} }