script: fix call/dip, add fold/each/unit/cons/cat
This commit is contained in:
parent
053359aaf1
commit
f62dbe9546
139
plugins/script
139
plugins/script
|
@ -929,37 +929,83 @@ defn (fn_drop)
|
||||||
defn (fn_swap)
|
defn (fn_swap)
|
||||||
{
|
{
|
||||||
check_stack (2);
|
check_stack (2);
|
||||||
struct item *first = pop (ctx);
|
|
||||||
struct item *second = pop (ctx);
|
struct item *second = pop (ctx);
|
||||||
push (ctx, first);
|
struct item *first = pop (ctx);
|
||||||
push (ctx, second);
|
push (ctx, second);
|
||||||
|
push (ctx, first);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
defn (fn_call)
|
defn (fn_call)
|
||||||
{
|
{
|
||||||
check_stack (1);
|
check_stack (1);
|
||||||
struct item *item = pop (ctx);
|
struct item *script = pop (ctx);
|
||||||
bool success;
|
bool success = check_type (ctx, script, ITEM_LIST)
|
||||||
// XXX: this behaves differently from if/map/filter
|
&& execute (ctx, get_list (script));
|
||||||
if (item->type == ITEM_LIST)
|
item_free (script);
|
||||||
success = execute (ctx, get_list (item));
|
|
||||||
else
|
|
||||||
success = execute (ctx, item);
|
|
||||||
item_free (item);
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
defn (fn_dip)
|
defn (fn_dip)
|
||||||
{
|
{
|
||||||
check_stack (2);
|
check_stack (2);
|
||||||
struct item *item = pop (ctx);
|
struct item *script = pop (ctx);
|
||||||
if (!fn_call (ctx))
|
struct item *item = pop (ctx);
|
||||||
{
|
bool success = check_type (ctx, script, ITEM_LIST)
|
||||||
|
&& execute (ctx, get_list (script));
|
||||||
|
if (success)
|
||||||
|
push (ctx, item);
|
||||||
|
else
|
||||||
item_free (item);
|
item_free (item);
|
||||||
|
item_free (script);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
defn (fn_unit)
|
||||||
|
{
|
||||||
|
check_stack (1);
|
||||||
|
struct item *item = pop (ctx);
|
||||||
|
push (ctx, new_list (item));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
defn (fn_cons)
|
||||||
|
{
|
||||||
|
check_stack (2);
|
||||||
|
struct item *list = pop (ctx);
|
||||||
|
struct item *item = pop (ctx);
|
||||||
|
bool success = check_type (ctx, list, ITEM_LIST);
|
||||||
|
item->next = get_list (list);
|
||||||
|
((struct item_list *) list)->head = item;
|
||||||
|
if (success)
|
||||||
|
push (ctx, list);
|
||||||
|
else
|
||||||
|
item_free (list);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
defn (fn_cat)
|
||||||
|
{
|
||||||
|
check_stack (2);
|
||||||
|
struct item *scnd = pop (ctx);
|
||||||
|
struct item *frst = pop (ctx);
|
||||||
|
if (!check_type (ctx, frst, ITEM_LIST)
|
||||||
|
|| !check_type (ctx, scnd, ITEM_LIST))
|
||||||
|
{
|
||||||
|
item_free (frst);
|
||||||
|
item_free (scnd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
push (ctx, item);
|
|
||||||
|
// XXX: we shouldn't have to do this in O(n)
|
||||||
|
struct item **tail = &((struct item_list *) frst)->head;
|
||||||
|
while (*tail)
|
||||||
|
tail = &(*tail)->next;
|
||||||
|
*tail = get_list (scnd);
|
||||||
|
push (ctx, frst);
|
||||||
|
|
||||||
|
((struct item_list *) scnd)->head = NULL;
|
||||||
|
item_free (scnd);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1054,7 +1100,7 @@ defn (fn_try)
|
||||||
bool success = false;
|
bool success = false;
|
||||||
if (!check_type (ctx, try, ITEM_LIST)
|
if (!check_type (ctx, try, ITEM_LIST)
|
||||||
|| !check_type (ctx, catch, ITEM_LIST))
|
|| !check_type (ctx, catch, ITEM_LIST))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (!execute (ctx, get_list (try)))
|
if (!execute (ctx, get_list (try)))
|
||||||
{
|
{
|
||||||
|
@ -1163,6 +1209,59 @@ fail:
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defn (fn_fold)
|
||||||
|
{
|
||||||
|
check_stack (3);
|
||||||
|
struct item *op = pop (ctx);
|
||||||
|
struct item *null = pop (ctx);
|
||||||
|
struct item *list = pop (ctx);
|
||||||
|
bool success = false;
|
||||||
|
if (!check_type (ctx, op, ITEM_LIST)
|
||||||
|
|| !check_type (ctx, list, ITEM_LIST))
|
||||||
|
{
|
||||||
|
item_free (null);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
push (ctx, null);
|
||||||
|
for (struct item *iter = get_list (list); iter; iter = iter->next)
|
||||||
|
{
|
||||||
|
push (ctx, new_clone (iter));
|
||||||
|
if (!execute (ctx, get_list (op)))
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
success = true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
item_free (op);
|
||||||
|
item_free (list);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
defn (fn_each)
|
||||||
|
{
|
||||||
|
check_stack (2);
|
||||||
|
struct item *op = pop (ctx);
|
||||||
|
struct item *list = pop (ctx);
|
||||||
|
bool success = false;
|
||||||
|
if (!check_type (ctx, op, ITEM_LIST)
|
||||||
|
|| !check_type (ctx, list, ITEM_LIST))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
for (struct item *iter = get_list (list); iter; iter = iter->next)
|
||||||
|
{
|
||||||
|
push (ctx, new_clone (iter));
|
||||||
|
if (!execute (ctx, get_list (op)))
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
success = true;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
item_free (op);
|
||||||
|
item_free (list);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
// - - Arithmetic - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - Arithmetic - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
// XXX: why not a `struct item_string *` argument?
|
// XXX: why not a `struct item_string *` argument?
|
||||||
|
@ -1534,16 +1633,13 @@ item_list_to_str (const struct item *script, struct buffer *buf)
|
||||||
|
|
||||||
// TODO: implement more functions; try to avoid writing it in C
|
// TODO: implement more functions; try to avoid writing it in C
|
||||||
//
|
//
|
||||||
// ? fold
|
|
||||||
// join { list delim -- string } -- string join -> script this
|
// join { list delim -- string } -- string join -> script this
|
||||||
//
|
//
|
||||||
// concat { list list -- list } -- join two lists
|
|
||||||
// -, /, %, ** -- arithmetic
|
// -, /, %, ** -- arithmetic
|
||||||
// >, !=, <=, >= -- comparison
|
// >, !=, <=, >= -- comparison
|
||||||
// first -- first character of a string, first element in a list
|
// first -- first character of a string, first element in a list
|
||||||
// rest -- [1:] of a string, the "tail" in a list
|
// rest -- [1:] of a string, the "tail" in a list
|
||||||
// at { value index -- sub-value } -- get n-th subvalue of a string/list
|
// at { value index -- sub-value } -- get n-th subvalue of a string/list
|
||||||
// cons { item value } -- prepend an item to the list/string
|
|
||||||
// <each> step { value program } -- foreach
|
// <each> step { value program } -- foreach
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1577,6 +1673,13 @@ init_runtime_library (void)
|
||||||
// List processing
|
// List processing
|
||||||
register_handler ("map", fn_map);
|
register_handler ("map", fn_map);
|
||||||
register_handler ("filter", fn_filter);
|
register_handler ("filter", fn_filter);
|
||||||
|
register_handler ("fold", fn_fold);
|
||||||
|
register_handler ("each", fn_each);
|
||||||
|
|
||||||
|
// List manipulation
|
||||||
|
register_handler ("unit", fn_unit);
|
||||||
|
register_handler ("cons", fn_cons);
|
||||||
|
register_handler ("cat", fn_cat);
|
||||||
|
|
||||||
// Arithmetic operations
|
// Arithmetic operations
|
||||||
register_handler ("*", fn_times);
|
register_handler ("*", fn_times);
|
||||||
|
|
Loading…
Reference in New Issue