Berry extend range(lower, upper, incr) to arbitrary increment (#19120)

This commit is contained in:
s-hadinger 2023-07-15 19:09:52 +02:00 committed by GitHub
parent af27d65a8a
commit 46e17061b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 115 additions and 17 deletions

View File

@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file.
### Changed ### Changed
- ESP32 shutter driver support up to 16 shutters (#18295) - ESP32 shutter driver support up to 16 shutters (#18295)
- Configuration backup and restore now backup and restore ``.xdrvsetXXX`` files too (#18295) - Configuration backup and restore now backup and restore ``.xdrvsetXXX`` files too (#18295)
- Berry extend `range(lower, upper, incr)` to arbitrary increment
### Fixed ### Fixed

View File

@ -11,31 +11,67 @@
static int m_init(bvm *vm) static int m_init(bvm *vm)
{ {
int argc = be_top(vm);
be_pushvalue(vm, 2); be_pushvalue(vm, 2);
be_setmember(vm, 1, "__lower__"); be_setmember(vm, 1, "__lower__");
be_pop(vm, 1); be_pop(vm, 1);
be_pushvalue(vm, 3); be_pushvalue(vm, 3);
be_setmember(vm, 1, "__upper__"); be_setmember(vm, 1, "__upper__");
int incr = 1; /* default increment is '1' */
if (argc >= 4) {
incr = be_toint(vm, 4);
if (incr == 0) { be_raise(vm, "value_error", "increment cannot be zero"); }
}
be_pushint(vm, incr);
be_setmember(vm, 1, "__incr__");
be_return_nil(vm); be_return_nil(vm);
} }
static int m_tostring(bvm *vm) static int m_tostring(bvm *vm)
{ {
be_pushstring(vm, "("); be_getmember(vm, 1, "__incr__");
be_getmember(vm, 1, "__lower__"); int incr = be_toint(vm, -1);
be_tostring(vm, -1);
be_strconcat(vm, -2);
be_pop(vm, 1);
be_pushstring(vm, "..");
be_strconcat(vm, -2);
be_pop(vm, 1);
be_getmember(vm, 1, "__upper__");
be_tostring(vm, -1);
be_strconcat(vm, -2);
be_pop(vm, 1);
be_pushstring(vm, ")");
be_strconcat(vm, -2);
be_pop(vm, 1); be_pop(vm, 1);
if (incr == 1) {
be_pushstring(vm, "(");
be_getmember(vm, 1, "__lower__");
be_tostring(vm, -1);
be_strconcat(vm, -2);
be_pop(vm, 1);
be_pushstring(vm, "..");
be_strconcat(vm, -2);
be_pop(vm, 1);
be_getmember(vm, 1, "__upper__");
be_tostring(vm, -1);
be_strconcat(vm, -2);
be_pop(vm, 1);
be_pushstring(vm, ")");
be_strconcat(vm, -2);
be_pop(vm, 1);
} else {
be_pushstring(vm, "range(");
be_getmember(vm, 1, "__lower__");
be_tostring(vm, -1);
be_strconcat(vm, -2);
be_pop(vm, 1);
be_pushstring(vm, ", ");
be_strconcat(vm, -2);
be_pop(vm, 1);
be_getmember(vm, 1, "__upper__");
be_tostring(vm, -1);
be_strconcat(vm, -2);
be_pop(vm, 1);
be_pushstring(vm, ", ");
be_strconcat(vm, -2);
be_pop(vm, 1);
be_getmember(vm, 1, "__incr__");
be_tostring(vm, -1);
be_strconcat(vm, -2);
be_pop(vm, 1);
be_pushstring(vm, ")");
be_strconcat(vm, -2);
be_pop(vm, 1);
}
be_return(vm); be_return(vm);
} }
@ -51,13 +87,27 @@ static int m_lower(bvm *vm)
be_return(vm); be_return(vm);
} }
static int m_incr(bvm *vm)
{
be_getmember(vm, 1, "__incr__");
be_return(vm);
}
static int m_setrange(bvm *vm) static int m_setrange(bvm *vm)
{ {
int argc = be_top(vm);
be_pushvalue(vm, 2); be_pushvalue(vm, 2);
be_setmember(vm, 1, "__lower__"); be_setmember(vm, 1, "__lower__");
be_pop(vm, 1); be_pop(vm, 1);
be_pushvalue(vm, 3); be_pushvalue(vm, 3);
be_setmember(vm, 1, "__upper__"); be_setmember(vm, 1, "__upper__");
int incr = 1; /* default increment is '1' */
if (argc >= 4) {
incr = be_toint(vm, 4);
if (incr == 0) { be_raise(vm, "value_error", "increment cannot be zero"); }
}
be_pushint(vm, incr);
be_setmember(vm, 1, "__incr__");
be_return_nil(vm); be_return_nil(vm);
} }
@ -68,25 +118,30 @@ static int iter_closure(bvm *vm)
bntvclos *func = var_toobj(vm->cf->func); bntvclos *func = var_toobj(vm->cf->func);
bvalue *uv0 = be_ntvclos_upval(func, 0)->value; bvalue *uv0 = be_ntvclos_upval(func, 0)->value;
bvalue *uv1 = be_ntvclos_upval(func, 1)->value; bvalue *uv1 = be_ntvclos_upval(func, 1)->value;
bvalue *uv2 = be_ntvclos_upval(func, 2)->value;
bint lower = var_toint(uv0); /* upvalue[0] => lower */ bint lower = var_toint(uv0); /* upvalue[0] => lower */
bint upper = var_toint(uv1); /* upvalue[1] => upper */ bint upper = var_toint(uv1); /* upvalue[1] => upper */
if (lower > upper) { bint incr = var_toint(uv2); /* upvalue[2] => incr */
if ((incr > 0 && lower > upper) || (incr < 0 && lower < upper)) {
be_stop_iteration(vm); be_stop_iteration(vm);
} }
var_toint(uv0) = lower + 1; /* set upvale[0] */ var_toint(uv0) = lower + incr; /* set upvale[0] */
be_pushint(vm, lower); /* push the return value */ be_pushint(vm, lower); /* push the return value */
be_return(vm); be_return(vm);
} }
static int m_iter(bvm *vm) static int m_iter(bvm *vm)
{ {
be_pushntvclosure(vm, iter_closure, 2); be_pushntvclosure(vm, iter_closure, 3);
be_getmember(vm, 1, "__lower__"); be_getmember(vm, 1, "__lower__");
be_setupval(vm, -2, 0); be_setupval(vm, -2, 0);
be_pop(vm, 1); be_pop(vm, 1);
be_getmember(vm, 1, "__upper__"); be_getmember(vm, 1, "__upper__");
be_setupval(vm, -2, 1); be_setupval(vm, -2, 1);
be_pop(vm, 1); be_pop(vm, 1);
be_getmember(vm, 1, "__incr__");
be_setupval(vm, -2, 2);
be_pop(vm, 1);
be_return(vm); be_return(vm);
} }
@ -96,6 +151,7 @@ void be_load_rangelib(bvm *vm)
static const bnfuncinfo members[] = { static const bnfuncinfo members[] = {
{ "__lower__", NULL }, { "__lower__", NULL },
{ "__upper__", NULL }, { "__upper__", NULL },
{ "__incr__", NULL },
{ "init", m_init }, { "init", m_init },
{ "tostring", m_tostring }, { "tostring", m_tostring },
{ "lower", m_lower }, { "lower", m_lower },
@ -111,10 +167,12 @@ void be_load_rangelib(bvm *vm)
class be_class_range (scope: global, name: range) { class be_class_range (scope: global, name: range) {
__lower__, var __lower__, var
__upper__, var __upper__, var
__incr__, var
init, func(m_init) init, func(m_init)
tostring, func(m_tostring) tostring, func(m_tostring)
lower, func(m_lower) lower, func(m_lower)
upper, func(m_upper) upper, func(m_upper)
incr, func(m_incr)
setrange, func(m_setrange) setrange, func(m_setrange)
iter, func(m_iter) iter, func(m_iter)
} }

View File

@ -0,0 +1,39 @@
# test for ranges
# expand a range object as list
def expand(iter)
var ret = []
for i: iter
ret.push(i)
end
return ret
end
assert(expand(0..5) == [0, 1, 2, 3, 4, 5])
assert(expand(0..0) == [0])
assert(expand(5..0) == [])
var r = 1..5
assert(r.lower() == 1)
assert(r.upper() == 5)
assert(r.incr() == 1)
assert(expand(range(0,5)) == [0, 1, 2, 3, 4, 5])
assert(expand(range(0,5,2)) == [0, 2, 4])
assert(expand(range(0,5,12)) == [0])
assert(expand(range(0,5,-1)) == [])
assert(expand(range(5,0,-1)) == [5, 4, 3, 2, 1, 0])
assert(expand(range(5,0,-2)) == [5, 3, 1])
assert(expand(range(5,5,-2)) == [5])
assert(expand(range(0,5,-2)) == [])
def assert_value_error(c)
try
compile(c)()
assert(false, 'unexpected execution flow')
except 'value_error' as e, m
end
end
# range with increment zero shoud raise an error
assert_value_error("range(1,2,0)")