From 6af4e67309cfa30850b40d67bd24a2f730dca35c Mon Sep 17 00:00:00 2001 From: Max Regan Date: Mon, 7 Nov 2022 09:18:59 -0500 Subject: [PATCH] Add boolean, comparison, and equality functions --- src/builtins.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/builtins.h | 8 ++++++++ src/main.c | 17 +++++++++++++---- src/special.c | 22 ++++++++++++++++++++++ src/special.h | 2 ++ src/utility.c | 48 +++++++++++++++++++++++++++++++++++++++++++----- src/utility.h | 2 ++ 7 files changed, 133 insertions(+), 9 deletions(-) diff --git a/src/builtins.c b/src/builtins.c index cdc76f2..53fb57a 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -194,3 +194,46 @@ LISP_FUNC_2(ucl_builtin_mapcar, state, fun, elems) { } return result; } + +LISP_FUNC_2(ucl_builtin_equal, state, arg0, arg1) { + return ucl_equal(arg0, arg1); +} + +LISP_FUNC_2(ucl_builtin_gt, state, 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"); + return ucl_predicate(arg0->integer > arg1->integer); +} + +LISP_FUNC_2(ucl_builtin_ge, state, 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"); + return ucl_predicate(arg0->integer > arg1->integer); +} + + +LISP_FUNC_2(ucl_builtin_lt, state, 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"); + return ucl_predicate(arg0->integer < arg1->integer); +} + +LISP_FUNC_2(ucl_builtin_le, state, 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"); + return ucl_predicate(arg0->integer < arg1->integer); +} + +LISP_FUNC_2(ucl_builtin_num_eq, state, 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"); + return ucl_predicate(arg0->integer == arg1->integer); +} + +LISP_FUNC_2(ucl_builtin_xor, state, arg0, arg1) { + return ucl_predicate(ucl_truthy_bool(arg0) || ucl_truthy_bool(arg1)); +} + +LISP_FUNC_1(ucl_builtin_not, state, arg0) { + return ucl_predicate(!ucl_truthy_bool(arg0)); +} diff --git a/src/builtins.h b/src/builtins.h index 1b4053b..05de882 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -15,8 +15,16 @@ struct ucl_object *ucl_builtin_sub(struct ucl_state *state, struct ucl_object *a struct ucl_object *ucl_builtin_mul(struct ucl_state *state, struct ucl_object *args); struct ucl_object *ucl_builtin_div(struct ucl_state *state, struct ucl_object *args); struct ucl_object *ucl_builtin_mod(struct ucl_state *state, struct ucl_object *args); +struct ucl_object *ucl_builtin_gt(struct ucl_state *state, struct ucl_object *args); +struct ucl_object *ucl_builtin_ge(struct ucl_state *state, struct ucl_object *args); +struct ucl_object *ucl_builtin_lt(struct ucl_state *state, struct ucl_object *args); +struct ucl_object *ucl_builtin_le(struct ucl_state *state, struct ucl_object *args); +struct ucl_object *ucl_builtin_num_eq(struct ucl_state *state, struct ucl_object *args); struct ucl_object *ucl_builtin_concat(struct ucl_state *state, struct ucl_object *args); +struct ucl_object *ucl_builtin_not(struct ucl_state *state, struct ucl_object *args); +struct ucl_object *ucl_builtin_xor(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_car(struct ucl_state *state, struct ucl_object *args); diff --git a/src/main.c b/src/main.c index 95ac9c4..35f4aba 100644 --- a/src/main.c +++ b/src/main.c @@ -20,6 +20,8 @@ int main(int argc, const char **argv) { ucl_state_put(state, "setq", ucl_special_create(ucl_special_setq)); ucl_state_put(state, "progn", ucl_special_create(ucl_special_progn)); ucl_state_put(state, "quote", ucl_special_create(ucl_special_quote)); + ucl_state_put(state, "and", ucl_special_create(ucl_special_and)); + ucl_state_put(state, "or", ucl_special_create(ucl_special_or)); // TODO: // - iteration @@ -35,6 +37,13 @@ int main(int argc, const char **argv) { ucl_state_put(state, "*", ucl_builtin_create(ucl_builtin_mul)); ucl_state_put(state, "/", ucl_builtin_create(ucl_builtin_div)); ucl_state_put(state, "%", ucl_builtin_create(ucl_builtin_mod)); + ucl_state_put(state, ">", ucl_builtin_create(ucl_builtin_gt)); + ucl_state_put(state, ">=", ucl_builtin_create(ucl_builtin_ge)); + ucl_state_put(state, "<", ucl_builtin_create(ucl_builtin_lt)); + ucl_state_put(state, "<=", ucl_builtin_create(ucl_builtin_le)); + ucl_state_put(state, "=", ucl_builtin_create(ucl_builtin_num_eq)); + ucl_state_put(state, "not", ucl_builtin_create(ucl_builtin_not)); + ucl_state_put(state, "xor", ucl_builtin_create(ucl_builtin_xor)); // TODO: // - Floats or nah? @@ -52,10 +61,9 @@ int main(int argc, const char **argv) { ucl_state_put(state, "cdr", ucl_builtin_create(ucl_builtin_cdr)); ucl_state_put(state, "nth", ucl_builtin_create(ucl_builtin_nth)); ucl_state_put(state, "mapcar", ucl_builtin_create(ucl_builtin_mapcar)); + ucl_state_put(state, "equal", ucl_builtin_create(ucl_builtin_mapcar)); // TODO: - // - equality - // - map // - reduce // - booleans (e.g. not) @@ -66,6 +74,9 @@ int main(int argc, const char **argv) { size_t len = 0; ssize_t lineSize = 0; lineSize = getline(&line, &len, stdin); + if (lineSize == -1) { + return 0; + } struct ucl_object *sexp = ucl_parse(line); struct ucl_object *result = ucl_evaluate(state, ucl_car(sexp)); @@ -86,5 +97,3 @@ int main(int argc, const char **argv) { return 0; } } - -// '(let (()) (defun foo (a b) (+ a b)) (foo 1 2))' diff --git a/src/special.c b/src/special.c index e82ac50..f528096 100644 --- a/src/special.c +++ b/src/special.c @@ -105,3 +105,25 @@ struct ucl_object *ucl_special_progn(struct ucl_state *state, struct ucl_object struct ucl_object *ucl_special_quote(struct ucl_state *state, struct ucl_object *args) { return ucl_car(args); } + +struct ucl_object *ucl_special_and(struct ucl_state *state, struct ucl_object *args) { + struct ucl_object *value = ucl_t_create(); + FOREACH_LIST(args, iter, form) { + value = ucl_evaluate(state, form); + if (!ucl_truthy_bool(value)) { + return value; + } + } + return value; +} + +struct ucl_object *ucl_special_or(struct ucl_state *state, struct ucl_object *args) { + struct ucl_object *value = ucl_nil_create(); + FOREACH_LIST(args, iter, form) { + value = ucl_evaluate(state, form); + if (ucl_truthy_bool(value)) { + return value; + } + } + return value; +} diff --git a/src/special.h b/src/special.h index b052e03..dea0988 100644 --- a/src/special.h +++ b/src/special.h @@ -10,5 +10,7 @@ struct ucl_object *ucl_special_lambda(struct ucl_state *state, struct ucl_object struct ucl_object *ucl_special_setq(struct ucl_state *state, struct ucl_object *args); struct ucl_object *ucl_special_progn(struct ucl_state *state, struct ucl_object *args); struct ucl_object *ucl_special_quote(struct ucl_state *state, struct ucl_object *args); +struct ucl_object *ucl_special_and(struct ucl_state *state, struct ucl_object *args); +struct ucl_object *ucl_special_or(struct ucl_state *state, struct ucl_object *args); #endif diff --git a/src/utility.c b/src/utility.c index ef11613..75291fd 100644 --- a/src/utility.c +++ b/src/utility.c @@ -86,16 +86,22 @@ struct ucl_object *ucl_list_nth(struct ucl_object *list, int n) { return node->cell.car; } -struct ucl_object *ucl_truthy(struct ucl_object *obj) { +bool ucl_truthy_bool(struct ucl_object *obj) { // TODO: Implement me better if (obj->type == UCL_TYPE_INT) { - return ucl_predicate(obj->integer); + return obj->integer; } else if (obj->type == UCL_TYPE_SYMBOL) { - return ucl_predicate(true); + return true; } else if (obj->type == UCL_TYPE_CELL) { - return ucl_predicate(obj->cell.car != NULL); + return obj->cell.car != NULL; } - return ucl_error_create("Unimplemented function 'ucl_truthy'"); + + assert(0); + return false; +} + +struct ucl_object *ucl_truthy(struct ucl_object *obj) { + return ucl_predicate(ucl_truthy_bool(obj)); } struct ucl_object *ucl_tuple_create(struct ucl_object *obj0, struct ucl_object *obj1) { @@ -166,3 +172,35 @@ struct ucl_object *ucl_progn(struct ucl_state *state, struct ucl_object *forms) return (result == NULL) ? ucl_nil_create() : result; } + + +struct ucl_object *ucl_equal( + struct ucl_object *arg0, struct ucl_object *arg1) { + if (arg0->type != arg1->type) { + return ucl_nil_create(); + } + + switch (arg0->type) { + case UCL_TYPE_INT: + return ucl_predicate(arg0->integer == arg1->integer); + case UCL_TYPE_SYMBOL: + return ucl_predicate(!strcmp(arg0->symbol, arg1->symbol)); + case UCL_TYPE_CELL: { + struct ucl_object *car_equal = ucl_equal(arg0->cell.car, arg1->cell.car); + if (!ucl_truthy(car_equal)) { + return car_equal; + } + return ucl_equal(arg0->cell.cdr, arg1->cell.cdr); + } + case UCL_TYPE_BUILTIN: + return ucl_predicate(arg0->special == arg1->builtin); + case UCL_TYPE_SPECIAL: + return ucl_predicate(arg0->special == arg1->builtin); + case UCL_TYPE_STRING: + return ucl_predicate(!strcmp(arg0->string, arg1->string)); + case UCL_TYPE_ERROR: + case UCL_TYPE_COUNT: + return ucl_error_create(""); + } + +} diff --git a/src/utility.h b/src/utility.h index 11706f3..2d55427 100644 --- a/src/utility.h +++ b/src/utility.h @@ -9,6 +9,8 @@ struct ucl_object *ucl_nil_create(); struct ucl_object *ucl_t_create(); struct ucl_object *ucl_predicate(bool value); struct ucl_object *ucl_truthy(struct ucl_object *arg); +bool ucl_truthy_bool(struct ucl_object *arg); +struct ucl_object *ucl_equal(struct ucl_object *arg0, struct ucl_object *arg1); struct ucl_object* ucl_car(struct ucl_object *list); struct ucl_object* ucl_cdr(struct ucl_object *list);