From dae5622955c74ce35cd9b0675313d523bb38eaa4 Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Sun, 21 May 2017 17:47:19 +0200 Subject: Remove some ancient stupidity --- README.adoc | 7 +++--- ell.c | 76 +++++++++++++++++++++++++++++-------------------------------- 2 files changed, 39 insertions(+), 44 deletions(-) diff --git a/README.adoc b/README.adoc index b507c9f..80360a8 100644 --- a/README.adoc +++ b/README.adoc @@ -48,10 +48,9 @@ Observe that the whole program is enclosed in an implicit pair of `{}` and that Runtime ------- All variables are put in a single global namespace with no further scoping. -When calling a command (which is a list of lists), all arguments are -automatically stored in variables named 0, 1, 2, 3, ... n. They are however -effectively inaccessible and you must rename them first using the `arg` special -form. +Arguments to a block (which is a list of lists) must be assigned to variables +first using the `arg` special form, and that must happen before they get +overriden by execution of a different block. When evaluating a command, the first argument is typically a string with its name and it is resolved as if `set` was called on it. diff --git a/ell.c b/ell.c index 3d9cf1e..d897aa9 100644 --- a/ell.c +++ b/ell.c @@ -625,6 +625,7 @@ parser_run (struct parser *self, const char **e) { struct context { struct item *variables; ///< List of variables struct native_fn *native; ///< Maps strings to C functions + struct item *arguments; ///< Arguments to last executed block char *error; ///< Error information bool error_is_fatal; ///< Whether the error can be catched @@ -654,6 +655,7 @@ context_free (struct context *ctx) { free (iter); } item_free_list (ctx->variables); + item_free_list (ctx->arguments); free (ctx->error); } @@ -733,19 +735,19 @@ set_error (struct context *ctx, const char *format, ...) { } static bool -rename_arguments (struct context *ctx, struct item *names) { - size_t i = 0; +assign_arguments (struct context *ctx, struct item *names) { + struct item *arg = ctx->arguments; for (; names; names = names->next) { if (names->type != ITEM_STRING) return set_error (ctx, "argument names must be strings"); - char buf[64]; - (void) snprintf (buf, sizeof buf, "%zu", i++); - struct item *value = get (ctx, buf); - if (value && !check (ctx, (value = new_clone (value)))) + struct item *value = NULL; + if (arg && !check (ctx, (value = new_clone (arg)))) return false; if (!set (ctx, names->value, value)) return false; + if (arg) + arg = arg->next; } return true; } @@ -770,14 +772,6 @@ execute_args (struct context *ctx, struct item *args, struct item **res) { return true; } -static bool -set_arg (struct context *ctx, size_t arg, struct item *value) { - char buf[64]; - (void) snprintf (buf, sizeof buf, "%zu", arg); - return check (ctx, (value = new_clone (value))) - && set (ctx, buf, value); -} - static bool execute_native (struct context *ctx, const char *name, struct item *args, struct item **result) { @@ -805,16 +799,8 @@ execute_resolved (struct context *ctx, struct item *body, struct item *args, return false; } - // TODO: we should probably maintain arguments in a separate list, - // either that or at least remember the count so that we can reset them - // NOTE: it even seems that storing them as numbers is completely useless - size_t i = 0; - for (struct item *arg = evaluated; arg; arg = arg->next) - if (!set_arg (ctx, i++, arg)) { - item_free_list (evaluated); - return false; - } - item_free_list (evaluated); + item_free_list (ctx->arguments); + ctx->arguments = evaluated; return execute (ctx, body->head, result); } @@ -827,7 +813,7 @@ execute_item (struct context *ctx, struct item *body, struct item **result) { if (!strcmp (name, "quote")) return !args || check (ctx, (*result = new_clone_list (args))); if (!strcmp (name, "arg")) - return rename_arguments (ctx, args); + return assign_arguments (ctx, args); if ((body = get (ctx, name))) return execute_resolved (ctx, body, args, result); return execute_native (ctx, name, args, result); @@ -897,6 +883,28 @@ 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) +static bool +set_single_argument (struct context *ctx, struct item *item) { + struct item *single; + if (!check (ctx, (single = new_clone (item)))) + return false; + item_free_list (ctx->arguments); + ctx->arguments = single; + 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; @@ -914,18 +922,6 @@ new_number (double n) { return item; } -#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 @@ -1001,7 +997,7 @@ defn (fn_for) { (void) result; for (struct item *v = list->head; v; v = v->next) { struct item *res = NULL; - bool ok = set_arg (ctx, 0, v) + bool ok = set_single_argument (ctx, v) && execute (ctx, body->head, &res); item_free_list (res); if (eat_error (ctx, E_BREAK)) @@ -1025,7 +1021,7 @@ defn (fn_map) { struct item *res = NULL, **out = &res; for (struct item *v = values->head; v; v = v->next) { - if (!set_arg (ctx, 0, v) + if (!set_single_argument (ctx, v) || !execute (ctx, body->head, out)) { item_free_list (res); return false; @@ -1046,7 +1042,7 @@ defn (fn_filter) { struct item *res = NULL, **out = &res; for (struct item *v = values->head; v; v = v->next) { struct item *keep = NULL; - if (!set_arg (ctx, 0, v) + if (!set_single_argument (ctx, v) || !execute (ctx, body->head, &keep)) { item_free_list (res); return false; -- cgit v1.2.3-70-g09d2