Add reduce and filter
This commit is contained in:
@@ -196,6 +196,33 @@ LISP_FUNC_2(ucl_builtin_mapcar, scope, fun, elems) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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, "Second argument to < must be an integer");
|
||||
|
||||
@@ -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_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_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_print(struct ucl_scope *scope, struct ucl_object *args);
|
||||
|
||||
19
src/lisp.h
19
src/lisp.h
@@ -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)
|
||||
|
||||
// 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
|
||||
|
||||
@@ -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, "nth", ucl_builtin_create(ucl_builtin_nth));
|
||||
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, "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, "while", ucl_special_create(ucl_special_while));
|
||||
|
||||
// TODO:
|
||||
// - reduce
|
||||
// - filter
|
||||
|
||||
if (argc < 2) {
|
||||
while (1) {
|
||||
char *line = readline("> ");
|
||||
|
||||
@@ -29,8 +29,11 @@ void setUp(void) {
|
||||
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, "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, "quote", ucl_special_create(ucl_special_quote));
|
||||
ucl_scope_put(scope, "%", ucl_builtin_create(ucl_builtin_mod));
|
||||
}
|
||||
|
||||
void tearDown(void) {
|
||||
@@ -226,6 +229,16 @@ void test_eval_defun_gc(void) {
|
||||
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) {
|
||||
UNITY_BEGIN();
|
||||
|
||||
@@ -254,6 +267,7 @@ int main(void) {
|
||||
RUN_TEST(test_nth_1);
|
||||
RUN_TEST(test_nth_oob);
|
||||
RUN_TEST(test_eval_defun_gc);
|
||||
RUN_TEST(test_complex);
|
||||
|
||||
return UNITY_END();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user