mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-25 03:36:42 +00:00
Berry extend range(lower, upper, incr)
to arbitrary increment (#19120)
This commit is contained in:
parent
af27d65a8a
commit
46e17061b2
@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file.
|
||||
### Changed
|
||||
- ESP32 shutter driver support up to 16 shutters (#18295)
|
||||
- Configuration backup and restore now backup and restore ``.xdrvsetXXX`` files too (#18295)
|
||||
- Berry extend `range(lower, upper, incr)` to arbitrary increment
|
||||
|
||||
### Fixed
|
||||
|
||||
|
@ -11,31 +11,67 @@
|
||||
|
||||
static int m_init(bvm *vm)
|
||||
{
|
||||
int argc = be_top(vm);
|
||||
be_pushvalue(vm, 2);
|
||||
be_setmember(vm, 1, "__lower__");
|
||||
be_pop(vm, 1);
|
||||
be_pushvalue(vm, 3);
|
||||
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);
|
||||
}
|
||||
|
||||
static int m_tostring(bvm *vm)
|
||||
{
|
||||
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_getmember(vm, 1, "__incr__");
|
||||
int incr = be_toint(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);
|
||||
}
|
||||
|
||||
@ -51,13 +87,27 @@ static int m_lower(bvm *vm)
|
||||
be_return(vm);
|
||||
}
|
||||
|
||||
static int m_incr(bvm *vm)
|
||||
{
|
||||
be_getmember(vm, 1, "__incr__");
|
||||
be_return(vm);
|
||||
}
|
||||
|
||||
static int m_setrange(bvm *vm)
|
||||
{
|
||||
int argc = be_top(vm);
|
||||
be_pushvalue(vm, 2);
|
||||
be_setmember(vm, 1, "__lower__");
|
||||
be_pop(vm, 1);
|
||||
be_pushvalue(vm, 3);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -68,25 +118,30 @@ static int iter_closure(bvm *vm)
|
||||
bntvclos *func = var_toobj(vm->cf->func);
|
||||
bvalue *uv0 = be_ntvclos_upval(func, 0)->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 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);
|
||||
}
|
||||
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_return(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_setupval(vm, -2, 0);
|
||||
be_pop(vm, 1);
|
||||
be_getmember(vm, 1, "__upper__");
|
||||
be_setupval(vm, -2, 1);
|
||||
be_pop(vm, 1);
|
||||
be_getmember(vm, 1, "__incr__");
|
||||
be_setupval(vm, -2, 2);
|
||||
be_pop(vm, 1);
|
||||
be_return(vm);
|
||||
}
|
||||
|
||||
@ -96,6 +151,7 @@ void be_load_rangelib(bvm *vm)
|
||||
static const bnfuncinfo members[] = {
|
||||
{ "__lower__", NULL },
|
||||
{ "__upper__", NULL },
|
||||
{ "__incr__", NULL },
|
||||
{ "init", m_init },
|
||||
{ "tostring", m_tostring },
|
||||
{ "lower", m_lower },
|
||||
@ -111,10 +167,12 @@ void be_load_rangelib(bvm *vm)
|
||||
class be_class_range (scope: global, name: range) {
|
||||
__lower__, var
|
||||
__upper__, var
|
||||
__incr__, var
|
||||
init, func(m_init)
|
||||
tostring, func(m_tostring)
|
||||
lower, func(m_lower)
|
||||
upper, func(m_upper)
|
||||
incr, func(m_incr)
|
||||
setrange, func(m_setrange)
|
||||
iter, func(m_iter)
|
||||
}
|
||||
|
39
lib/libesp32/berry/tests/range.be
Normal file
39
lib/libesp32/berry/tests/range.be
Normal 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)")
|
Loading…
x
Reference in New Issue
Block a user