parent utils
object list

var root name 'list

eval
    .initialize();
.

method range
    arg x, y;
    var i, l;

    l = [];
    for i in [ x .. y ]
        l = [@l, i];
    return l;
.


method to_string
    arg l, sep;
    var r, e;

    if (!l)
      return "";
    r = tostr(l[1]);
    for e in (delete(l, 1)) 
       r = r + sep + tostr(e);
    return r;
.

method to_english
    arg l, [rest];
    var empty, and, sep;

    empty = [@rest, "nothing"][1];
    switch (listlen(l)) {
        case 0: 
            return empty;
        case 1: 
            return l[1];
    }
    and = [@rest, " and ", " and "][2];
    sep = [@rest, ", ", ", ", ", "][3];
    return .to_string(delete(l, listlen(l)), sep) + and + l[listlen(l)];
.

method map
    arg l, method, [args];
    var r, e;

    r = [];
    for e in (l)
        r = [@r, e.(method)(@args)];
    return r;
.

method map_on
    arg l, object, method, [args];
    var r, e;

    r = [];
    for e in (l)
        r = [@r, object.(method)(e, @args)];
    return r;
.

method filter
    arg l, method, [args];
    var r, e;

    r = [];
    for e in (l) {
        if (e.(method)(@args))
            r = [@r, e];
    }
    return r;
.

method filter_on
    arg l, object, method, [args];
    var r, e;

    r = [];
    for e in (l) {
        if (object.(method)(e, @args))
            r = [@r, e];
    }
    return r;
.

method sort
    arg lst;

    return ._sort( lst, 1, listlen( lst));
.

method _sort
    arg lst, x, y;
    var p, i, j;

    switch (y - x + 1) {
        case 0,1:
            return lst;
        case 2:
            if (lst[x] <= lst[y])
                return lst;
            p = lst[x];
            lst = replace( lst, x, lst[y]);
            lst = replace( lst, y, p);
            return lst;
        case 3:
            if (lst[x] <= lst[x+1]) {
                if (lst[x+1] <= lst[y]) ;
            else if (lst[x] <= lst[y]) {
                p = lst[x+1];
                lst = replace( lst, x+1, lst[y]);
                lst = replace( lst, y, p);
            } else {
                p = lst[x];
                lst = replace( lst, x, lst[y]);
                lst = replace( lst, y, lst[x+1]);
                lst = replace( lst, x+1, p);
            }
            } else if (lst[x] <= lst[y]) {
      p = lst[x];
      lst = replace( lst, x, lst[x+1]);
      lst = replace( lst, x+1, p);
   } else if (lst[x+1] <= lst[y]) {
      p = lst[x];
      lst = replace( lst, x, lst[x+1]);
      lst = replace( lst, x+1, lst[y]);
      lst = replace( lst, y, p);
   } else {
      p = lst[x];
      lst = replace( lst, x, lst[y]);
      lst = replace( lst, y, p);
   }
   return lst;
}
p = lst[x];
i = x;
j = y;
while (1) {
   while (i < j && p <= lst[j])
      j = j - 1;
   if (i == j)
      break;
   lst = replace( lst, i, lst[j]);
   i = i + 1;
   while (i < j && p >= lst[i])
      i = i + 1;
   if (i == j)
      break;
   lst = replace( lst, j, lst[i]);
   j = j - 1;
}
lst = replace( lst, i, p);
lst = ._sort( lst, x, i - 1);
lst = ._sort( lst, i + 1, y);
return lst;
.

method range
    arg x, y;
    var l, e;

    l = [];
    for e in [x..y]
        l = l + [e];
    return l;
.

nethod random
    arg lst;
    var x, y, l, p;

    l = listlen(lst);
    for x in [1 .. l - 1] {
        y = random(l - x) + x;
        p = lst[x];
        lst = replace(lst, x, lst[y]);
        lst = replace(lst, y, p);
    }
    return lst;
.

method columnize
    arg l, n, [rest];
    var sep, len, width, ret, line, i;

    sep = [@rest, "   "][1];
    len = [@rest, 78, 78][2];
    width = (len - (n-1) * strlen(sep)) / n;
    ret = [];
    while (l) {
        line = pad(l[1], width);
        for i in [2..n]
            if (i > listlen(l))
                line = line + sep + pad("", width);
            else
                line = line + sep + pad(l[i], width);
       ret = [@ret, line];
      l = n >= listlen(l) ? [] | sublist(l, n + 1);
    }
    return ret;
.

method map_tostr
    arg l;
    var n;

    for n in [ 1 .. listlen(l) ]
        l = replace(l, n, tostr(l[n]));
    return l;
.

method english_vr_object_list
    arg l, [otherargs];
    var n;

    for n in [ 1 .. listlen(l) ]
        l = replace(l, n, l[n].vr_name() + " (" + toliteral(l[n].name()) +")");
    return .to_english(l, @otherargs);
.