aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2017-05-21 09:38:18 +0200
committerPřemysl Janouch <p.janouch@gmail.com>2017-05-21 13:19:48 +0200
commit0f4ece88675c63060daf1b4f9993a69c6c05a58e (patch)
treef6826c97a092cc761cce0a4f2cd59cdba3fadebe
parent1caec277bfff3fe8df9769368d0d84601acd7944 (diff)
downloadell-0f4ece88675c63060daf1b4f9993a69c6c05a58e.tar.gz
ell-0f4ece88675c63060daf1b4f9993a69c6c05a58e.tar.xz
ell-0f4ece88675c63060daf1b4f9993a69c6c05a58e.zip
Add "break" for breaking out of loops
-rwxr-xr-xell.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/ell.c b/ell.c
index f5b1924..b4f5f2b 100755
--- a/ell.c
+++ b/ell.c
@@ -858,9 +858,10 @@ execute_statement
item_free_list (*result);
*result = NULL;
- // In that case, `error' is NULL and there's nothing else to do anyway
- if (!ctx->memory_failure) {
- // This creates some form of a stack trace
+ // In that case, `error' is NULL and there's nothing else to do anyway.
+ // Errors starting with an underscore are exceptions and would not work
+ // with stack traces generated this way.
+ if (!ctx->memory_failure && ctx->error[0] != '_') {
char *tmp = ctx->error;
set_error (ctx, "%s -> %s", name, tmp);
free (tmp);
@@ -885,12 +886,26 @@ execute (struct context *ctx, struct item *body, struct item **result) {
#define defn(name) static bool name \
(struct context *ctx, struct item *args, struct item **result)
+#define E_BREAK "_break"
+
+static bool
+eat_error (struct context *ctx, const char *name) {
+ if (!ctx->error || strcmp (ctx->error, name))
+ return false;
+
+ free (ctx->error);
+ ctx->error = NULL;
+ return true;
+}
+
static bool
truthy (struct item *item) {
return item
&& ((item->type == ITEM_STRING && item->len != 0) || item->head);
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
defn (fn_set) {
struct item *name = args;
if (!name || name->type != ITEM_STRING)
@@ -946,7 +961,6 @@ defn (fn_if) {
return true;
}
-// TODO: how to break out of the loop? Catchable error? Special value?
defn (fn_for) {
struct item *list = args, *body;
if (!list || list->type != ITEM_LIST)
@@ -960,12 +974,18 @@ defn (fn_for) {
bool ok = set_arg (ctx, 0, v)
&& execute (ctx, body->head, &res);
item_free_list (res);
+ if (eat_error (ctx, E_BREAK))
+ break;
if (!ok)
return false;
}
return true;
}
+defn (fn_break) {
+ (void) args; (void) result; return set_error (ctx, E_BREAK);
+}
+
defn (fn_map) {
struct item *body = args, *values;
if (!body || body->type != ITEM_LIST)
@@ -1054,6 +1074,7 @@ init_native_library (void)
&& native_register ("list", fn_list)
&& native_register ("if", fn_if)
&& native_register ("for", fn_for)
+ && native_register ("break", fn_break)
&& native_register ("map", fn_map)
&& native_register ("filter", fn_filter)
&& native_register ("print", fn_print)