diff options
author | Přemysl Janouch <p.janouch@gmail.com> | 2017-05-21 09:38:18 +0200 |
---|---|---|
committer | Přemysl Janouch <p.janouch@gmail.com> | 2017-05-21 13:19:48 +0200 |
commit | 0f4ece88675c63060daf1b4f9993a69c6c05a58e (patch) | |
tree | f6826c97a092cc761cce0a4f2cd59cdba3fadebe | |
parent | 1caec277bfff3fe8df9769368d0d84601acd7944 (diff) | |
download | ell-0f4ece88675c63060daf1b4f9993a69c6c05a58e.tar.gz ell-0f4ece88675c63060daf1b4f9993a69c6c05a58e.tar.xz ell-0f4ece88675c63060daf1b4f9993a69c6c05a58e.zip |
Add "break" for breaking out of loops
-rwxr-xr-x | ell.c | 29 |
1 files changed, 25 insertions, 4 deletions
@@ -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) |