From 1de758b6d69dfd9749bcf60be068d388cdebfa94 Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
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-70-g09d2