aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2017-05-26 01:27:30 +0200
committerPřemysl Janouch <p.janouch@gmail.com>2017-05-26 01:27:30 +0200
commit735dfd026abaeee93c4e9b90db73661076ccafa3 (patch)
tree49e809674195b2699f71d4d0f08712a73b787913
parent4358e6f324a6765b7da69ba28b891584531e710e (diff)
downloadell-735dfd026abaeee93c4e9b90db73661076ccafa3.tar.gz
ell-735dfd026abaeee93c4e9b90db73661076ccafa3.tar.xz
ell-735dfd026abaeee93c4e9b90db73661076ccafa3.zip
Make and/or more useful
Now they follow Scheme, they just aren't special forms here.
-rw-r--r--README.adoc8
-rw-r--r--ell.c33
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 <value>`
+
+Return a boolean with the opposite truthiness.
+
+`and [<body>]...`, `or [<body>]...`
+
+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) {