From 1de758b6d69dfd9749bcf60be068d388cdebfa94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Thu, 25 May 2017 13:52:41 +0200 Subject: Replace for/break with a try/throw mechanism --- ell.c | 47 ++++++----------------------------------------- greet.ell | 8 ++++++++ 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/ell.c b/ell.c index 9eefbc9..b50d15e 100644 --- a/ell.c +++ b/ell.c @@ -852,18 +852,6 @@ set_single_argument (struct context *ctx, struct item *item) { return true; } -#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 struct item * new_number (double n) { char *s; @@ -946,31 +934,6 @@ defn (fn_if) { return true; } -defn (fn_for) { - struct item *list = args, *body; - if (!list || list->type != ITEM_LIST) - return set_error (ctx, "first argument must be a list"); - if (!(body = list->next) || body->type != ITEM_LIST) - return set_error (ctx, "second argument must be a function"); - - (void) result; - for (struct item *v = list->head; v; v = v->next) { - struct item *res = NULL; - bool ok = set_single_argument (ctx, 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) @@ -1214,8 +1177,12 @@ init_runtime_library (struct context *ctx) { const char *definition; ///< The defining script } functions[] = { { "unless", "arg _cond _body; if (not (@_cond)) @_body" }, - { "filter", "arg _body _list; map {" - "arg _item; if (@_body @_item) { @_item } } @_list" }, + { "filter", "arg _body _list;" + "map { arg _i; if (@_body @_i) { @_i } } @_list" }, + { "for", "arg _list _body;" + "try { map {arg _i; @_body @_i } @_list" + "} { arg _e; if (ne? @_e _break) { throw @e } }" }, + { "break", "throw _break" }, // TODO: we should be able to apply them to all arguments { "ne?", "arg _ne1 _ne2; not (eq? @_ne1 @_ne2)" }, { "ge?", "arg _ge1 _ge2; not (lt? @_ge1 @_ge2)" }, @@ -1251,8 +1218,6 @@ init_runtime_library (struct context *ctx) { && native_register (ctx, "set", fn_set) && native_register (ctx, "list", fn_list) && native_register (ctx, "if", fn_if) - && native_register (ctx, "for", fn_for) - && native_register (ctx, "break", fn_break) && native_register (ctx, "map", fn_map) && native_register (ctx, "print", fn_print) && native_register (ctx, "..", fn_concatenate) diff --git a/greet.ell b/greet.ell index b53f21d..3bfad4e 100644 --- a/greet.ell +++ b/greet.ell @@ -2,10 +2,18 @@ set greet { arg _name print 'hello ' @_name '\n' } +set decr { + arg _name + set @_name (- @@_name 1) +} + +set limit 2 for (map { arg _x; .. @_x ! } [ world creator + 'darkness, my old friend' ]) { arg _whom greet @_whom + if (= 0 (decr limit)) { break } } -- cgit v1.2.3