diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2023-03-26 16:07:12 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2023-03-26 16:07:12 -0700 |
commit | d152f874b7096d6642a00b8237a94b6fd9991c00 (patch) | |
tree | b626dd5e301ebd3981b6bc43f676d7a0a37e0154 | |
parent | df916c063942c031c394a38a0c89f1537c742a9b (diff) | |
download | txr-d152f874b7096d6642a00b8237a94b6fd9991c00.tar.gz txr-d152f874b7096d6642a00b8237a94b6fd9991c00.tar.bz2 txr-d152f874b7096d6642a00b8237a94b6fd9991c00.zip |
range/range*: connect with non-arithmetic ranges
* eval.c (range_func_fstep, range_func_fstep_inf,
range_func_iter, range_star_func_fstep,
range_star_func_iter: New static functions.
(range, range*): Analyze inputs and use the new functions
for non-numeric ranges.
-rw-r--r-- | eval.c | 172 |
1 files changed, 165 insertions, 7 deletions
@@ -5935,14 +5935,96 @@ static val range_func(val env, val lcons) return nil; } +static val range_func_fstep(val env, val lcons) +{ + us_cons_bind (from, to_step, env); + us_cons_bind (to, stepfn, to_step); + val next = funcall1(stepfn, from); + us_rplaca(lcons, from); + + if (equal(from, to)) + { + us_rplacd(lcons, nil); + return nil; + } + + us_rplacd(lcons, make_lazy_cons(us_lcons_fun(lcons))); + us_rplaca(env, next); + return nil; +} + +static val range_func_fstep_inf(val env, val lcons) +{ + us_cons_bind (from, stepfn, env); + val next = funcall1(stepfn, from); + us_rplaca(lcons, from); + us_rplacd(lcons, make_lazy_cons(us_lcons_fun(lcons))); + us_rplaca(env, next); + return nil; +} + +static val range_func_iter(val env, val lcons) +{ + us_cons_bind (iter, step, env); + val next = iter_item(iter); + + us_rplaca(lcons, next); + + while (plusp(step)) { + iter = iter_step(iter); + step = minus(step, one); + } + + if (!iter_more(iter)) { + us_rplacd(lcons, nil); + return nil; + } + + us_rplacd(lcons, make_lazy_cons(us_lcons_fun(lcons))); + us_rplaca(env, iter); + return nil; +} + static val range(val from_in, val to_in, val step_in) { + val self = lit("range"); val from = default_arg(from_in, zero); val to = default_null_arg(to_in); - val step = default_arg(step_in, if3(to && gt(from, to), negone, one)); - val env = cons(from, cons(to, step)); - return make_lazy_cons(func_f1(env, range_func)); + switch (type(from)) { + case NUM: + case BGNUM: + case FLNUM: + case CHR: + case RNG: + { + val step = default_arg(step_in, if3(to && gt(from, to), negone, one)); + val env = cons(from, cons(to, step)); + return make_lazy_cons(func_f1(env, range_func)); + } + default: + { + val step = default_arg(step_in, one); + + if (functionp(step)){ + if (missingp(to_in)) { + val env = cons(from, step); + return make_lazy_cons(func_f1(env, range_func_fstep_inf)); + } else { + val env = cons(from, cons(to, step)); + return make_lazy_cons(func_f1(env, range_func_fstep)); + } + } else if (integerp(step) && plusp(step)) { + val iter = iter_begin(rcons(from, to)); + val env = cons(iter, step); + return if2(iter_more(iter), + make_lazy_cons(func_f1(env, range_func_iter))); + } else { + uw_throwf(error_s, lit("~s: step must be positive integer, not ~s"), + self, step, nao); + } + } + } } static val range_star_func(val env, val lcons) @@ -5969,18 +6051,94 @@ static val range_star_func(val env, val lcons) return nil; } +static val range_star_func_fstep(val env, val lcons) +{ + us_cons_bind (from, to_step, env); + us_cons_bind (to, stepfn, to_step); + val next = funcall1(stepfn, from); + us_rplaca(lcons, from); + + if (equal(next, to)) + { + us_rplacd(lcons, nil); + return nil; + } + + us_rplacd(lcons, make_lazy_cons(us_lcons_fun(lcons))); + us_rplaca(env, next); + return nil; +} + +static val range_star_func_iter(val env, val lcons) +{ + us_cons_bind (iter, prev_step, env); + us_cons_bind (prev, step, prev_step); + val next = nil; + us_rplaca(lcons, prev); + + while (plusp(step)) { + if (iter_more(iter)) + next = iter_item(iter); + iter = iter_step(iter); + step = minus(step, one); + } + + if (!iter_more(iter)) { + us_rplacd(lcons, nil); + return nil; + } + + us_rplaca(prev_step, next); + us_rplacd(lcons, make_lazy_cons(us_lcons_fun(lcons))); + us_rplaca(env, iter); + return nil; +} + static val range_star(val from_in, val to_in, val step_in) { + val self = lit("range*"); val from = default_arg(from_in, zero); val to = default_null_arg(to_in); if (eql(from, to)) { return nil; - } else { - val step = default_arg(step_in, if3(to && gt(from, to), negone, one)); - val env = cons(from, cons(to, step)); + } else switch (type(from)) { + case NUM: + case BGNUM: + case FLNUM: + case CHR: + case RNG: + { + val step = default_arg(step_in, if3(to && gt(from, to), negone, one)); + val env = cons(from, cons(to, step)); + return make_lazy_cons(func_f1(env, range_star_func)); + } + default: + { + val step = default_arg(step_in, one); - return make_lazy_cons(func_f1(env, range_star_func)); + if (functionp(step)){ + if (missingp(to_in)) { + val env = cons(from, step); + return make_lazy_cons(func_f1(env, range_func_fstep_inf)); + } else { + val env = cons(from, cons(to, step)); + return make_lazy_cons(func_f1(env, range_star_func_fstep)); + } + } else if (integerp(step) && plusp(step)) { + val iter = iter_begin(rcons(from, to)); + if (iter_more(iter)) { + val next = iter_item(iter); + val nxiter = iter_step(iter); + val env = cons(nxiter, cons(next, step)); + return make_lazy_cons(func_f1(env, range_star_func_iter)); + } + return nil; + } else { + uw_throwf(error_s, lit("~s: step must be positive integer, not ~s"), + self, step, nao); + } + } } } |