diff --git a/CHANGELOG.md b/CHANGELOG.md index 73ce8f94d..23bb2ff87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - Allow acl in mqtt when client certificate is in use with `#define USE_MQTT_CLIENT_CERT` (#22998) - Berry `tasmota.when_network_up()` and simplified Matter using it (#23057) - Berry `introspect.solidified()` to know if a Berry object is solidified or in RAM (#23063) +- Berry `global.undef()` to undefine a global variable ### Breaking Changed diff --git a/lib/libesp32/berry/src/be_api.c b/lib/libesp32/berry/src/be_api.c index 6ccb65c5a..fab94ddcd 100644 --- a/lib/libesp32/berry/src/be_api.c +++ b/lib/libesp32/berry/src/be_api.c @@ -82,8 +82,8 @@ BERRY_API void be_regfunc(bvm *vm, const char *name, bntvfunc f) bstring *s = be_newstr(vm, name); #if !BE_USE_PRECOMPILED_OBJECT int idx = be_builtin_find(vm, s); - be_assert(idx == -1); - if (idx == -1) { /* new function */ + be_assert(idx < 0); + if (idx < 0) { /* new function */ idx = be_builtin_new(vm, s); #else int idx = be_global_find(vm, s); @@ -102,8 +102,8 @@ BERRY_API void be_regclass(bvm *vm, const char *name, const bnfuncinfo *lib) bstring *s = be_newstr(vm, name); #if !BE_USE_PRECOMPILED_OBJECT int idx = be_builtin_find(vm, s); - be_assert(idx == -1); - if (idx == -1) { /* new function */ + be_assert(idx < 0); + if (idx < 0) { /* new function */ idx = be_builtin_new(vm, s); #else int idx = be_global_find(vm, s); @@ -599,7 +599,7 @@ BERRY_API bbool be_getglobal(bvm *vm, const char *name) { int idx = be_global_find(vm, be_newstr(vm, name)); bvalue *top = be_incrtop(vm); - if (idx > -1) { + if (idx >= 0) { *top = *be_global_var(vm, idx); return btrue; } diff --git a/lib/libesp32/berry/src/be_globallib.c b/lib/libesp32/berry/src/be_globallib.c index 6597fe78b..ef247a34d 100644 --- a/lib/libesp32/berry/src/be_globallib.c +++ b/lib/libesp32/berry/src/be_globallib.c @@ -27,10 +27,14 @@ static void dump_map_keys(bvm *vm, bmap *map) bmapiter iter = be_map_iter(); while ((node = be_map_next(map, &iter)) != NULL) { if (var_isstr(&node->key)) { - bstring *s = var_tostr(&node->key); - be_pushstring(vm, str(s)); - be_data_push(vm, -2); - be_pop(vm, 1); + /* check if the global was not undefined/removed */ + int idx = var_toidx(&node->value); + if (idx >= 0) { /* the key is present in global, and the index is valid */ + bstring *s = var_tostr(&node->key); + be_pushstring(vm, str(s)); + be_data_push(vm, -2); + be_pop(vm, 1); + } } } } @@ -49,7 +53,7 @@ static int m_contains(bvm *vm) if (top >= 1 && be_isstring(vm, 1)) { const char * name = be_tostring(vm, 1); int idx = be_global_find(vm, be_newstr(vm, name)); - be_pushbool(vm, idx > -1); + be_pushbool(vm, idx >= 0); be_return(vm); } be_return_nil(vm); @@ -76,12 +80,25 @@ static int m_setglobal(bvm *vm) be_return_nil(vm); } +/* Remove a global variable from global scope */ +/* Internally the global name cannot be removed but it's value is replaced with BE_NONE */ +/* and global function pretend that BE_NONE is equivalent to the name being absent */ +static int m_undef(bvm *vm) +{ + int top = be_top(vm); + if (top >= 1 && be_isstring(vm, 1)) { + be_global_undef(vm, be_newstr(vm, be_tostring(vm, 1))); + } + be_return_nil(vm); +} + #if !BE_USE_PRECOMPILED_OBJECT be_native_module_attr_table(global) { be_native_module_function("()", m_globals), be_native_module_function("contains", m_contains), be_native_module_function("member", m_findglobal), be_native_module_function("setmember", m_setglobal), + be_native_module_function("undef", m_undef), }; be_define_native_module(global, NULL); @@ -92,6 +109,7 @@ module global (scope: global, depend: BE_USE_GLOBAL_MODULE) { contains, func(m_contains) member, func(m_findglobal) setmember, func(m_setglobal) + undef, func(m_undef) } @const_object_info_end */ #include "../generate/be_fixed_global.h" diff --git a/lib/libesp32/berry/src/be_var.c b/lib/libesp32/berry/src/be_var.c index 1a8e5b18c..c243d6747 100644 --- a/lib/libesp32/berry/src/be_var.c +++ b/lib/libesp32/berry/src/be_var.c @@ -67,19 +67,39 @@ static int global_find(bvm *vm, bstring *name) { bvalue *res = be_map_findstr(vm, global(vm).vtab, name); if (res) { - return var_toidx(res) + be_builtin_count(vm); + int idx = var_toidx(res); + if (idx >= 0) { + return idx + be_builtin_count(vm); + } else { + return idx; /* the global does not exist (-1) or was underfined (< -1)*/ + } } return -1; /* not found */ } +bbool be_global_undef(bvm *vm, bstring *name) +{ + int idx = global_find(vm, name); + if (idx >= 0) { + bvalue *desc = be_map_findstr(vm, global(vm).vtab, name); + int index = var_toidx(desc); + var_setint(desc, -index - 2); /* negate the index to mark it as undefined */ + + bvalue* val = be_vector_at(&global(vm).vlist, index); + var_setnil(val); + return btrue; + } + return bfalse; +} + int be_global_find(bvm *vm, bstring *name) { - int res = global_find(vm, name); + int res = global_find(vm, name); /* returns negative if not found, -1 if does not exist, < -1 if existed but undefined */ if (res < 0) { - res = be_builtin_find(vm, name); + res = be_builtin_find(vm, name); /* returns -1 if not found */ } if (res < 0) { - res = global_native_class_find(vm, name); + res = global_native_class_find(vm, name); /* returns -1 if not found */ } return res; } @@ -97,11 +117,18 @@ static int global_new_anonymous(bvm *vm) int be_global_new(bvm *vm, bstring *name) { int idx = global_find(vm, name); - if (idx == -1) { + if (idx < 0) { bvalue *desc; - idx = global_new_anonymous(vm); - desc = be_map_insertstr(vm, global(vm).vtab, name, NULL); - var_setint(desc, idx); + if (idx == -1) { + idx = global_new_anonymous(vm); + desc = be_map_insertstr(vm, global(vm).vtab, name, NULL); + var_setint(desc, idx); + } else { + /* the global exists but was undefined */ + idx = -idx - 2; + desc = be_map_findstr(vm, global(vm).vtab, name); + var_setint(desc, idx); + } idx += be_builtin_count(vm); } return idx; diff --git a/lib/libesp32/berry/src/be_var.h b/lib/libesp32/berry/src/be_var.h index 6b9908a6b..d81623b07 100644 --- a/lib/libesp32/berry/src/be_var.h +++ b/lib/libesp32/berry/src/be_var.h @@ -20,6 +20,7 @@ void be_globalvar_init(bvm *vm); void be_globalvar_deinit(bvm *vm); int be_global_find(bvm *vm, bstring *name); int be_global_new(bvm *vm, bstring *name); +bbool be_global_undef(bvm *vm, bstring *name); bvalue* be_global_var(bvm *vm, int index); void be_global_release_space(bvm *vm); int be_builtin_find(bvm *vm, bstring *name); diff --git a/lib/libesp32/berry/src/be_vm.c b/lib/libesp32/berry/src/be_vm.c index 78fcc486b..dcd2c7d7c 100644 --- a/lib/libesp32/berry/src/be_vm.c +++ b/lib/libesp32/berry/src/be_vm.c @@ -591,7 +591,7 @@ newframe: /* a new call frame */ if (var_isstr(b)) { bstring *name = var_tostr(b); int idx = be_global_find(vm, name); - if (idx > -1) { + if (idx >= 0) { *v = *be_global_var(vm, idx); } else { vm_error(vm, "attribute_error", "'%s' undeclared", str(name));