From 735dfd026abaeee93c4e9b90db73661076ccafa3 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Fri, 26 May 2017 01:27:30 +0200
Subject: Make and/or more useful
Now they follow Scheme, they just aren't special forms here.
---
README.adoc | 8 ++++++++
ell.c | 33 +++++++++++++++++++++++----------
2 files changed, 31 insertions(+), 10 deletions(-)
diff --git a/README.adoc b/README.adoc
index b68b948..792429d 100644
--- a/README.adoc
+++ b/README.adoc
@@ -129,6 +129,14 @@ Execute the body and pass any error to the handler instead of propagating it.
Throw an error. Messages starting on an underscore don't generate backtraces.
+`not `
+
+Return a boolean with the opposite truthiness.
+
+`and []...`, `or []...`
+
+Short-circuit evaluation, trying to return whatever the bodies result in.
+
`+`, `-`, `*`, `/`
Arithmetic operations on floating point numbers.
diff --git a/ell.c b/ell.c
index 99b0867..da3fb72 100644
--- a/ell.c
+++ b/ell.c
@@ -839,7 +839,7 @@ execute_item (struct context *ctx, struct item *body, struct item **result) {
struct item *args = body->next;
if (body->type == ITEM_STRING) {
const char *name = body->value;
- // TODO: these could be just regular handlers, only top priority
+ // These could be just regular handlers, only top priority
if (!strcmp (name, "quote"))
return !args || check (ctx, (*result = new_clone_list (args)));
if (!strcmp (name, "arg"))
@@ -1168,19 +1168,32 @@ defn (fn_not) {
return check (ctx, (*result = new_boolean (!truthy (args))));
}
-// TODO: "and" and "or" should be short-circuiting special forms
defn (fn_and) {
- bool res = true;
- for (; args; args = args->next)
- res &= truthy (args);
- return check (ctx, (*result = new_boolean (res)));
+ if (!args)
+ return check (ctx, (*result = new_boolean (true)));
+ for (; args; args = args->next) {
+ item_free_list (*result);
+ *result = NULL;
+
+ if (!execute_any (ctx, args, result))
+ return false;
+ if (!truthy (*result))
+ return check (ctx, (*result = new_boolean (false)));
+ }
+ return true;
}
defn (fn_or) {
- bool res = false;
- for (; args; args = args->next)
- res |= truthy (args);
- return check (ctx, (*result = new_boolean (res)));
+ for (; args; args = args->next) {
+ if (!execute_any (ctx, args, result))
+ return false;
+ if (truthy (*result))
+ return true;
+
+ item_free_list (*result);
+ *result = NULL;
+ }
+ return check (ctx, (*result = new_boolean (false)));
}
defn (fn_eq) {
--
cgit v1.2.3-70-g09d2