diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2024-03-07 19:45:01 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2024-03-07 19:45:01 -0800 |
commit | fe1d0cb216b54a511ab9e3dc4f41b3ce09075997 (patch) | |
tree | 88c81759b5ba2efee3307509d4750523a5769283 /lib.c | |
parent | b5d92c7b65b7c8efd3c62da070b52326989dfe0b (diff) | |
download | txr-fe1d0cb216b54a511ab9e3dc4f41b3ce09075997.tar.gz txr-fe1d0cb216b54a511ab9e3dc4f41b3ce09075997.tar.bz2 txr-fe1d0cb216b54a511ab9e3dc4f41b3ce09075997.zip |
New function: rangeref.
Because ranges can be iterated like sequences, and are
identified as vector-like, they have to support indexing.
However, ranges already have semantics as a function:
with a sequence argument, they slice it.
Let's put the semantics into a function called rangeref,
so it can be coherently documented.
* eval.c (eval_init): Register rangeref intrinsic.
* lib.c (generic_funcall): Range as a function works in
terms of rangeref.
(ref): Handle RNG case via rangeref.
(rangeref): New function.
* lib.h (rangeref): Declared.
* tests/012/seq.tl: New tests.
Diffstat (limited to 'lib.c')
-rw-r--r-- | lib.c | 35 |
1 files changed, 34 insertions, 1 deletions
@@ -8537,7 +8537,7 @@ INLINE val do_generic_funcall(val fun, varg args_in) case 0: callerror(fun, lit("missing required arguments")); case 1: - return sub(args->arg[0], fun->rn.from, fun->rn.to); + return rangeref(fun, args->arg[0]); default: callerror(fun, lit("too many arguments")); } @@ -13288,6 +13288,8 @@ val ref(val seq, val ind) return vecref(seq, ind); case BUF: return buf_get_uchar(seq, ind); + case RNG: + return rangeref(seq, ind); default: type_mismatch(lit("ref: ~s is not a sequence"), seq, nao); } @@ -14039,6 +14041,37 @@ val in_range_star(val range, val num) } } +val rangeref(val range, val ind) +{ + val self = lit("rangeref"); + + if (integerp(ind)) + { + val fr = range->rn.from; + val to = range->rn.to; + val eind = ind; + + if (to != t && to != colon_k) { + val len = minus(to, fr); + + if (minusp(eind)) + eind = plus(eind, len); + + if (minusp(eind) || ge(eind, len)) + goto err; + } else if (minusp(eind)) { + goto err; + } + + return plus(fr, eind); + err: + uw_throwf(error_s, lit("~a: ~s is out of range for ~s"), + self, ind, range, nao); + } + + return sub(ind, range->rn.from, range->rn.to); +} + #if CONFIG_LOCALE_TOLERANCE static void locale_init(void) |