diff --git a/lib/libesp32/berry/default/be_modtab.c b/lib/libesp32/berry/default/be_modtab.c index 73f8c29df..8275ec739 100644 --- a/lib/libesp32/berry/default/be_modtab.c +++ b/lib/libesp32/berry/default/be_modtab.c @@ -22,6 +22,7 @@ be_extern_native_module(gc); be_extern_native_module(solidify); be_extern_native_module(introspect); be_extern_native_module(strict); +be_extern_native_module(undefined); /* Berry extensions */ #include "be_mapping.h" @@ -104,6 +105,7 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = { #if BE_USE_STRICT_MODULE &be_native_module(strict), #endif + &be_native_module(undefined), /* Berry extensions */ &be_native_module(cb), diff --git a/lib/libesp32/berry/generate/be_fixed_undefined.h b/lib/libesp32/berry/generate/be_fixed_undefined.h new file mode 100644 index 000000000..ab36914dc --- /dev/null +++ b/lib/libesp32/berry/generate/be_fixed_undefined.h @@ -0,0 +1,17 @@ +#include "be_constobj.h" + +static be_define_const_map_slots(m_libundefined_map) { + { be_const_key(_X2Ep, -1), be_const_nil() }, +}; + +static be_define_const_map( + m_libundefined_map, + 1 +); + +static be_define_const_module( + m_libundefined, + "undefined" +); + +BE_EXPORT_VARIABLE be_define_const_native_module(undefined); diff --git a/lib/libesp32/berry/src/be_class.c b/lib/libesp32/berry/src/be_class.c index 0ad035150..225974aff 100644 --- a/lib/libesp32/berry/src/be_class.c +++ b/lib/libesp32/berry/src/be_class.c @@ -12,6 +12,7 @@ #include "be_gc.h" #include "be_vm.h" #include "be_func.h" +#include "be_module.h" #include #define check_members(vm, c) \ @@ -240,12 +241,6 @@ bbool be_class_newobj(bvm *vm, bclass *c, int pos, int argc, int mode) return bfalse; } -/* Default empty constructor */ -static int default_init_native_method(bvm *vm) -{ - be_return_nil(vm); -} - /* Find instance member by name and copy value to `dst` */ /* Do not look into virtual members */ int be_instance_member_simple(bvm *vm, binstance *instance, bstring *name, bvalue *dst) @@ -280,7 +275,7 @@ int be_instance_member(bvm *vm, binstance *instance, bstring *name, bvalue *dst) } else { /* if no method found, try virtual */ /* if 'init' does not exist, create a virtual empty constructor */ if (strcmp(str(name), "init") == 0) { - var_setntvfunc(dst, default_init_native_method); + var_setntvfunc(dst, be_default_init_native_function); return var_primetype(dst); } else { /* get method 'member' */ @@ -297,10 +292,15 @@ int be_instance_member(bvm *vm, binstance *instance, bstring *name, bvalue *dst) *dst = obj->members[dst->v.i]; } type = var_type(dst); - if (type != BE_NIL) { - var_clearstatic(dst); - return type; + if (type == BE_MODULE) { + /* check if the module is named `undefined` */ + bmodule *mod = var_toobj(dst); + if (strcmp(be_module_name(mod), "undefined") == 0) { + return BE_NONE; /* if the return value is module `undefined`, consider it is an error */ + } } + var_clearstatic(dst); + return type; } } } diff --git a/lib/libesp32/berry/src/be_module.c b/lib/libesp32/berry/src/be_module.c index e2b186e9a..935b89bb3 100644 --- a/lib/libesp32/berry/src/be_module.c +++ b/lib/libesp32/berry/src/be_module.c @@ -255,7 +255,7 @@ static void cache_module(bvm *vm, bstring *name) *v = vm->top[-1]; } -/* Try to run '()' function of module. Module is already loaded. */ +/* Try to run 'init(m)' function of module. Module is already loaded. */ static void module_init(bvm *vm) { if (be_ismodule(vm, -1)) { if (be_getmember(vm, -1, "init")) { @@ -318,6 +318,11 @@ int be_module_attr(bvm *vm, bmodule *module, bstring *attr, bvalue *dst) { bvalue *member = be_map_findstr(vm, module->table, attr); if (!member) { /* try the 'member' function */ + /* if 'init' does not exist, don't call member() */ + if (strcmp(str(attr), "init") == 0) { + var_setntvfunc(dst, be_default_init_native_function); + return var_primetype(dst); + } member = be_map_findstr(vm, module->table, str_literal(vm, "member")); if (member && var_basetype(member) == BE_FUNCTION) { bvalue *top = vm->top; @@ -327,9 +332,16 @@ int be_module_attr(bvm *vm, bmodule *module, bstring *attr, bvalue *dst) be_dofunc(vm, top, 1); /* call method 'method' */ vm->top -= 2; *dst = *vm->top; /* copy result to R(A) */ - if (var_basetype(dst) != BE_NIL) { - return var_type(dst); + + int type = var_type(dst); + if (type == BE_MODULE) { + /* check if the module is named `undefined` */ + bmodule *mod = var_toobj(dst); + if (strcmp(be_module_name(mod), "undefined") == 0) { + return BE_NONE; /* if the return value is module `undefined`, consider it is an error */ + } } + return type; } return BE_NONE; } diff --git a/lib/libesp32/berry/src/be_undefinedlib.c b/lib/libesp32/berry/src/be_undefinedlib.c new file mode 100644 index 000000000..7e5ce4495 --- /dev/null +++ b/lib/libesp32/berry/src/be_undefinedlib.c @@ -0,0 +1,34 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang, Stephan Hadinger +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#include "be_object.h" +#include "be_module.h" +#include "be_string.h" +#include "be_vector.h" +#include "be_class.h" +#include "be_debug.h" +#include "be_map.h" +#include "be_vm.h" +#include "be_exec.h" +#include "be_gc.h" +#include + + +#if !BE_USE_PRECOMPILED_OBJECT +be_native_module_attr_table(undefined) { + be_native_module_nil(".p"), /* not needed but can't be empty */ +}; + +be_define_native_module(undefined, NULL); +#else +/* @const_object_info_begin +module undefined (scope: global) { + .p, nil() +} +@const_object_info_end */ +#include "../generate/be_fixed_undefined.h" +#endif diff --git a/lib/libesp32/berry/src/be_vm.c b/lib/libesp32/berry/src/be_vm.c index c60d88c01..2b6113909 100644 --- a/lib/libesp32/berry/src/be_vm.c +++ b/lib/libesp32/berry/src/be_vm.c @@ -1291,6 +1291,18 @@ void be_dofunc(bvm *vm, bvalue *v, int argc) } } +/* Default empty constructor */ +int be_default_init_native_function(bvm *vm) +{ + int argc = be_top(vm); + if (argc >= 1) { + be_pushvalue(vm, 1); + } else { + be_pushnil(vm); + } + be_return(vm); +} + BERRY_API void be_set_obs_hook(bvm *vm, bobshook hook) { (void)vm; /* avoid comiler warning */ diff --git a/lib/libesp32/berry/src/be_vm.h b/lib/libesp32/berry/src/be_vm.h index a2427277a..17a21b6c6 100644 --- a/lib/libesp32/berry/src/be_vm.h +++ b/lib/libesp32/berry/src/be_vm.h @@ -128,6 +128,7 @@ struct bvm { #define BASE_FRAME (1 << 0) #define PRIM_FUNC (1 << 1) +int be_default_init_native_function(bvm *vm); void be_dofunc(bvm *vm, bvalue *v, int argc); bbool be_value2bool(bvm *vm, bvalue *v); bbool be_vm_iseq(bvm *vm, bvalue *a, bvalue *b); diff --git a/lib/libesp32/berry_mapping/src/be_const_members.c b/lib/libesp32/berry_mapping/src/be_const_members.c index 810de4574..01a7b322c 100644 --- a/lib/libesp32/berry_mapping/src/be_const_members.c +++ b/lib/libesp32/berry_mapping/src/be_const_members.c @@ -99,6 +99,20 @@ bbool be_const_module_member(bvm *vm, const be_const_member_t * definitions, siz return be_const_member_dual(vm, definitions, def_len, bfalse); // call for module, non-method } +/* This version raises an exception if the attribute is not found */ +void be_const_module_member_raise(bvm *vm, const be_const_member_t * definitions, size_t def_len) { + if (!be_const_member_dual(vm, definitions, def_len, bfalse)) { + be_module_load(vm, be_newstr(vm, "undefined")); + } +} + bbool be_const_class_member(bvm *vm, const be_const_member_t * definitions, size_t def_len) { return be_const_member_dual(vm, definitions, def_len, btrue); // call for method } + +/* This version raises an exception if the attribute is not found */ +void be_const_class_member_raise(bvm *vm, const be_const_member_t * definitions, size_t def_len) { + if (!be_const_member_dual(vm, definitions, def_len, btrue)) { + be_module_load(vm, be_newstr(vm, "undefined")); + } +} diff --git a/lib/libesp32/berry_mapping/src/be_mapping.h b/lib/libesp32/berry_mapping/src/be_mapping.h index 01aa2e17f..0b0ef2c1e 100644 --- a/lib/libesp32/berry_mapping/src/be_mapping.h +++ b/lib/libesp32/berry_mapping/src/be_mapping.h @@ -100,7 +100,9 @@ extern void be_create_class_wrapper(bvm *vm, const char * class_name, void * ptr extern int be_find_global_or_module_member(bvm *vm, const char * cl_name); extern bbool be_const_module_member(bvm *vm, const be_const_member_t * definitions, size_t def_len); +extern void be_const_module_member_raise(bvm *vm, const be_const_member_t * definitions, size_t def_len); /* raise an exception if not found */ extern bbool be_const_class_member(bvm *vm, const be_const_member_t * definitions, size_t def_len); +extern void be_const_class_member_raise(bvm *vm, const be_const_member_t * definitions, size_t def_len); /* raise an exception if not found */ extern intptr_t be_convert_single_elt(bvm *vm, int idx, const char * arg_type, int *len); extern int be_check_arg_type(bvm *vm, int arg_start, int argc, const char * arg_type, intptr_t p[8]); extern int be_call_c_func(bvm *vm, const void * func, const char * return_type, const char * arg_type); diff --git a/lib/libesp32/berry_tasmota/src/be_ctypes.c b/lib/libesp32/berry_tasmota/src/be_ctypes.c index 7ebe74310..cd7650d41 100644 --- a/lib/libesp32/berry_tasmota/src/be_ctypes.c +++ b/lib/libesp32/berry_tasmota/src/be_ctypes.c @@ -264,8 +264,8 @@ int be_ctypes_member(bvm *vm) { } be_return(vm); } - - be_return_nil(vm); + be_module_load(vm, be_newstr(vm, "undefined")); + be_return(vm); } // setmember takes 3 arguments: diff --git a/lib/libesp32/berry_tasmota/src/be_light_state_class.cpp b/lib/libesp32/berry_tasmota/src/be_light_state_class.cpp index 8c0782ace..5c278dd2d 100644 --- a/lib/libesp32/berry_tasmota/src/be_light_state_class.cpp +++ b/lib/libesp32/berry_tasmota/src/be_light_state_class.cpp @@ -70,11 +70,8 @@ const be_const_member_t light_state_members[] = { extern "C" int light_state_get(bvm *vm); static int light_state_member(bvm *vm) { - if (be_const_class_member(vm, light_state_members, ARRAY_SIZE(light_state_members))) { - be_return(vm); - } else { - be_return_nil(vm); - } + be_const_class_member_raise(vm, light_state_members, ARRAY_SIZE(light_state_members)); + be_return(vm); } #include "be_fixed_be_class_light_state.h" diff --git a/lib/libesp32/berry_tasmota/src/be_zigbee.c b/lib/libesp32/berry_tasmota/src/be_zigbee.c index d0ae432cc..a7efdfa25 100644 --- a/lib/libesp32/berry_tasmota/src/be_zigbee.c +++ b/lib/libesp32/berry_tasmota/src/be_zigbee.c @@ -45,11 +45,8 @@ const be_const_member_t zd_members[] = { }; static int zd_member(bvm *vm) { - if (be_const_class_member(vm, zd_members, ARRAY_SIZE(zd_members))) { - be_return(vm); - } else { - be_return_nil(vm); - } + be_const_class_member_raise(vm, zd_members, ARRAY_SIZE(zd_members)); + be_return(vm); } extern int zc_info(struct bvm *vm); diff --git a/lib/libesp32/berry_tasmota/src/embedded/persist.be b/lib/libesp32/berry_tasmota/src/embedded/persist.be index 164a1dd7b..9a1dbbb84 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/persist.be +++ b/lib/libesp32/berry_tasmota/src/embedded/persist.be @@ -30,7 +30,7 @@ persist_module.init = def (m) # print("Persist init") end - #- virtual member getter, if a key does not exists return `nil`-# + #- virtual member getter, if a key does not exists return `nil` instead of exception -# def member(key) return self._p.find(key) end diff --git a/lib/libesp32_lvgl/lv_binding_berry/src/lv_berry.c b/lib/libesp32_lvgl/lv_binding_berry/src/lv_berry.c index 879c33f55..745e550c5 100644 --- a/lib/libesp32_lvgl/lv_binding_berry/src/lv_berry.c +++ b/lib/libesp32_lvgl/lv_binding_berry/src/lv_berry.c @@ -334,5 +334,6 @@ int lv0_member(bvm *vm) { be_return(vm); } } - be_return_nil(vm); + be_module_load(vm, be_newstr(vm, "undefined")); + be_return(vm); } diff --git a/tasmota/berry/modules/ctypes.be b/tasmota/berry/modules/ctypes.be deleted file mode 100644 index b6a0607df..000000000 --- a/tasmota/berry/modules/ctypes.be +++ /dev/null @@ -1,629 +0,0 @@ -#------------------------------------------------------------- -#- Ctypes for Berry -#- -#- Inspired from Python's ctypes structure -#-------------------------------------------------------------# -import string - -ctypes = module('ctypes') - -#------------------------------------------------------------- -#- Basic types for mapping -#- -#- ints of size 1/2/4 bytes (little endian by default) -#- usigned ints of size 1/2/4 bytes (little endian by default) -#- -#- (Big Endian are negative numbers) -#-------------------------------------------------------------# - -# default is little_endian -ctypes.i32 = 14 -ctypes.i16 = 12 -ctypes.i8 = 11 -ctypes.u32 = 4 -ctypes.u16 = 2 -ctypes.u8 = 1 - -# explicit little endian -ctypes.le_i32 = 14 -ctypes.le_i16 = 12 -ctypes.le_i8 = 11 -ctypes.le_u32 = 4 -ctypes.le_u16 = 2 -ctypes.le_u8 = 1 - -# big endian -ctypes.be_i32 = -14 -ctypes.be_i16 = -12 -ctypes.be_i8 = -11 -ctypes.be_u32 = -4 -ctypes.be_u16 = -2 -ctypes.be_u8 = -1 - -# floating point -ctypes.float = 5 -ctypes.double = 10 - -# pointer -ctypes.ptr32 = 9 -ctypes.ptr64 = -9 - -ctypes.bf_x = 0 # generic bitfield -# bitfields (always unsigned) -ctypes.bf_0 = 100 # serves as base -ctypes.bf_1 = 101 -ctypes.bf_2 = 102 -ctypes.bf_3 = 103 -ctypes.bf_4 = 104 -ctypes.bf_5 = 105 -ctypes.bf_6 = 106 -ctypes.bf_7 = 107 -ctypes.bf_8 = 108 -ctypes.bf_9 = 109 -ctypes.bf_10 = 110 -ctypes.bf_11 = 111 -ctypes.bf_12 = 112 -ctypes.bf_13 = 113 -ctypes.bf_14 = 114 -ctypes.bf_15 = 115 -ctypes.bf_16 = 116 - -ctypes.type_mapping = { - 14: "ctypes_i32", - 12: "ctypes_i16", - 11: "ctypes_i8", - 4: "ctypes_u32", - 2: "ctypes_u16", - 1: "ctypes_u8", - - -14:"ctypes_be_i32", # big endian - -12:"ctypes_be_i16", - -11:"ctypes_be_i8", - -4: "ctypes_be_u32", - -2: "ctypes_be_u16", - -1: "ctypes_be_u8", - - 5: "ctypes_float", - 10: "ctypes_double", - 9: "ctypes_ptr32", - -9: "ctypes_ptr64", - - 0: "ctypes_bf" # bitfield -} - -ctypes.type_to_str = def (type_num) - var type_name = ctypes.type_mapping.find(type_num) - if type_name == nil - return str(type_num) - end - return type_name -end - -def findinlist(l, x) - for i:0..size(l)-1 - if l[i] == x - return i - end - end -end - -#------------------------------------------------------------- -#- 'get_bits' function -#- -#- Reads a bit-field in a `bytes()` object -#- -#- Input: -#- b: bytes() object to read from -#- offset_bytes (int): byte offset in the bytes() object -#- offset_bits (int): bit number to start reading from (0 = LSB) -#- len_bits (int): how many bits to read -#- Output: -#- valuer (int) -#-------------------------------------------------------------# -ctypes.get_bits = def (b, offset_bytes, offset_bits, len_bits) - if !isinstance(b, bytes) raise "value_error", "first argument must be of type 'bytes'" end - if offset_bits < 0 || offset_bits > 7 raise "value_error", "offset_bits must be between 0 and 7" end - if len_bits <= 0 || len_bits > 32 raise "value_error", "length in bits must be between 0 and 32" end - var ret = 0 - - var bit_shift = 0 # bit number to write to - - while (len_bits > 0) - var block_bits = 8 - offset_bits # how many bits to read in the current block (block = byte) - if block_bits > len_bits block_bits = len_bits end - - var mask = ( (1<> offset_bits) << bit_shift) - - # move the input window - bit_shift += block_bits - len_bits -= block_bits - offset_bits = 0 # start at full next byte - offset_bytes += 1 - end - - return ret -end - -ctypes.sort = def (l) - # insertion sort - for i:1..size(l)-1 - var k = l[i] - var j = i - while (j > 0) && (l[j-1] > k) - l[j] = l[j-1] - j -= 1 - end - l[j] = k - end - return l -end - -#------------------------------------------------------------- -#- 'set_bits' function -#- -#- Writes a bit-field in a `bytes()` object -#- -#- Input: -#- b: bytes() object to write to -#- offset_bytes (int): byte offset in the bytes() object -#- offset_bits (int): bit number to start writing to (0 = LSB) -#- len_bits (int): how many bits to write -#- Output: -#- bytes() object modified (by reference) -#-------------------------------------------------------------# -ctypes.set_bits = def (b, offset_bytes, offset_bits, len_bits, val) - if !isinstance(b, bytes) raise "value_error", "first argument must be of type 'bytes'" end - if offset_bits < 0 || offset_bits > 7 raise "value_error", "offset_bits must be between 0 and 7" end - if len_bits <= 0 || len_bits > 32 raise "value_error", "length in bits must be between 0 and 32" end - - while (len_bits > 0) - var block_bits = 8 - offset_bits # how many bits to write in the current block (block = byte) - if block_bits > len_bits block_bits = len_bits end - - var mask_val = (1<>= block_bits - len_bits -= block_bits - offset_bits = 0 # start at full next byte - offset_bytes += 1 - end - return b -end - - -#- print the C types -#1 -ctypes.print_types = def () - print("/********************************************************************") - print(" * Generated code, don't edit") - print(" *******************************************************************/") - print() - print("static const char * be_ctypes_instance_mappings[]; /* forward definition */") - print() -end - -global_classes = [] # track the list of all classes and -global_mappings = [] # mapping to Berry classes, ex: lv_color - -ctypes.print_classes = def (module_name) - # print mappings - if size(global_mappings) > 7 - raise "internal_error", "too many mappings, 7 max" - end - print("static const char * be_ctypes_instance_mappings[] = {") - for n:global_mappings.iter() - print(string.format(" \"%s\",", n)) - end - print(" NULL") - print("};") - print() - - ctypes.sort(global_classes) - - for elt:global_classes - print(string.format("static be_define_ctypes_class(%s, &be_%s, &be_class_ctypes_bytes, \"%s\");", elt, elt, elt)) - end - - print() - print(string.format("void be_load_ctypes_%s_definitions_lib(bvm *vm) {", module_name)) - for elt:global_classes - print(string.format(" ctypes_register_class(vm, &be_class_%s);", elt)) - end - print("}") - print() - print("be_ctypes_class_by_name_t be_ctypes_lvgl_classes[] = {") - for elt:global_classes - print(string.format(" { \"%s\", &be_class_%s },", elt, elt)) - end - print("};") - print("const size_t be_ctypes_lvgl_classes_size = sizeof(be_ctypes_lvgl_classes)/sizeof(be_ctypes_lvgl_classes[0]);") - print() - - print("/********************************************************************/") - print() -end - -#------------------------------------------------------------- -#- 'ctypes.structure' class -#- -#- Parses a ctypes structure descriptor and creates -#- a set of getters and setters -#- -#-------------------------------------------------------------# -class structure - var cur_offset # offset in bytes from buffer start - var bit_offset # are we intra-byte? - var get_closures # - var set_closures # - var size_bytes # size in bytes - var mapping # map to generate C binding - - # init world - def init(mapping, name) - self.cur_offset = 0 - self.bit_offset = 0 - self.size_bytes = 0 # overall size in bytes - self.get_closures = {} - self.set_closures = {} - self.mapping = {} - - # parse mapping - self.parse_mapping(mapping, name) - end - #- iteratively parse mapping - #- - #- if name is not nil, it also outputs a C structure for the mapping - #- - #-------------------------------------------------------------# - def parse_mapping(mapping, name) - for map_line: mapping - self.parse_line(map_line) - end - - # clear any outstanding bitfield - self.align(1) - self.size_bytes = self.cur_offset - - if name != nil - var size_aligned = self.size_bytes - # as a final structure, we align to 2/4 bytesboundaries - if size_aligned >= 3 - size_aligned = ((size_aligned + 3)/4)*4 - end - - print(string.format("const be_ctypes_structure_t be_%s = {", name)) - print(string.format(" %i, /* size in bytes */", size_aligned)) - print(string.format(" %i, /* number of elements */", size(self.mapping))) - print(string.format(" be_ctypes_instance_mappings,")) - print(string.format(" (const be_ctypes_structure_item_t[%i]) {", size(self.mapping))) - # list keys for future binary search - var names = [] - for n:self.mapping.keys() names.push(n) end # convert to list - ctypes.sort(names) - for n:names - var args = self.mapping[n] - print(string.format(" { \"%s\", %i, %i, %i, %s, %i },", n, args[0], args[1], args[2], ctypes.type_to_str(args[3]), args[4])) - end - print("}};") - print() - - # retain class definition - global_classes.push(name) - end - end - - def size() - return self.size_bytes - end - - # parse a single line - def parse_line(map_line) - var type_obj = map_line[0] - var name = map_line[1] - var bits = 0 - if size(map_line) >= 3 bits = map_line[2] end - - if isinstance(type_obj, ctypes.structure) - # nested structure - self.nested(name, type_obj) - end - - var mapping_idx = 0 # mapping starts at 1 - if isinstance(type_obj, list) - # it may be a list to denote a mapping to an instance - var mapping_name = type_obj[1] - if findinlist(global_mappings, mapping_name) == nil - global_mappings.push(mapping_name) - end - mapping_idx = findinlist(global_mappings, mapping_name) + 1 - - type_obj = type_obj[0] # take the simple value of first element in the list - end - - if type(type_obj) == 'int' - # simple attibute - # TODO check actual type - if type_obj > ctypes.bf_0 - # bit field - self.get_bitfield_closure(name, type_obj - ctypes.bf_0, mapping_idx) - elif (type_obj == ctypes.ptr32) || (type_obj == ctypes.ptr64) - # pointer - self.get_ptr_closure(name, type_obj, mapping_idx) - elif (type_obj == ctypes.float) || (type_obj == ctypes.double) - # multi-bytes - self.get_float_closure(name, type_obj, mapping_idx) - else - # multi-bytes - self.get_int_closure(name, type_obj, mapping_idx) - end - end - end - - #- ensure alignment to 1/2/4 bytes -# - def align(n) - if n != 1 && n != 2 && n != 4 raise "value_error", "acceptable values are 1/2/4" end - - #- align to byte boundary if we're in a bitfield -# - if self.bit_offset != 0 - #- we are not byte aligned, let's re-aling -# - self.cur_offset += 1 - self.bit_offset = 0 - end - - #- check 2/4 bytes alignment -# - if self.cur_offset % n != 0 - # we are not aligned with current size - self.cur_offset += n - self.cur_offset % n - end - end - - def nested(name, type_obj) - var sub_size = type_obj.size() - if sub_size <= 0 raise "value_error", "empty sub-structure not supported" end - - # align to appropriate sub-size - var align_size = sub_size - if align_size == 3 || align_size > 4 align_size = 4 end - self.align(align_size) - - var offset = self.cur_offset # var for closure - - # include nested - for subname:type_obj.mapping.keys() - var val = type_obj.mapping[subname] - self.mapping[name+"_"+subname] = [val[0] + offset, val[1], val[2], val[3], val[4]] - end - # self.mapping[name] = [offset << 3, sub_size << 3] - - self.get_closures[name] = def (b, p) return ctypes.nested_buffer(type_obj, offset + p, b) end - # self.set_closures[name] = def (b, p, v) return ctypes.nested_buffer(type_obj, offset + p, b) end - - self.cur_offset += sub_size - end - - def get_int_closure(name, type, instance_mapping) # can be 1/2/4 - #- abs size -# - var size_in_bytes = type < 0 ? - type : type - var signed = size_in_bytes > 10 - var size_in_bytes_le_be = type % 10 # remove sign marker - size_in_bytes = size_in_bytes % 10 # remove sign marker - - self.align(size_in_bytes) # force alignment - var offset = self.cur_offset # prepare variable for capture in closure - - self.mapping[name] = [offset, 0, 0, type, instance_mapping] - - #- add closures -# - if signed - self.get_closures[name] = def (b, p) return b.geti(offset + p, size_in_bytes_le_be) end - else - self.get_closures[name] = def (b, p) return b.get(offset + p, size_in_bytes_le_be) end - end - self.set_closures[name] = def (b, p, v) return b.set(offset+ p, v, size_in_bytes_le_be) end - - self.cur_offset += size_in_bytes # next offset - end - - def get_ptr_closure(name, type, instance_mapping) # can be 1/2/4 - #- actual size -# - import introspect - var size_in_bytes = (type == ctypes.ptr32) ? 4 : 8 - - self.align(size_in_bytes) # force alignment - var offset = self.cur_offset # prepare variable for capture in closure - - self.mapping[name] = [offset, 0, 0, type, instance_mapping] - - #- add closures -# - # TODO no closure yet, anyways need to rethink closures, they are too heavy - # if signed - # self.get_closures[name] = def (b, p) return b.geti(offset + p, size_in_bytes_le_be) end - # else - # self.get_closures[name] = def (b, p) return b.get(offset + p, size_in_bytes_le_be) end - # end - # self.set_closures[name] = def (b, p, v) return b.set(offset+ p, v, size_in_bytes_le_be) end - - self.cur_offset += size_in_bytes # next offset - end - - def get_float_closure(name, type, instance_mapping) # can be 1/2/4 - #- actual size -# - var size_in_bytes = (type == ctypes.float) ? 4 : 8 - - self.align(size_in_bytes) # force alignment - var offset = self.cur_offset # prepare variable for capture in closure - - self.mapping[name] = [offset, 0, 0, type, instance_mapping] - - #- add closures -# - # TODO no closure yet, anyways need to rethink closures, they are too heavy - # if signed - # self.get_closures[name] = def (b, p) return b.geti(offset + p, size_in_bytes_le_be) end - # else - # self.get_closures[name] = def (b, p) return b.get(offset + p, size_in_bytes_le_be) end - # end - # self.set_closures[name] = def (b, p, v) return b.set(offset+ p, v, size_in_bytes_le_be) end - - self.cur_offset += size_in_bytes # next offset - end - - def get_bitfield_closure(name, size_in_bits, instance_mapping) # can be 1..32 - var cur_offset = self.cur_offset # prepare variable for capture in closure - var bit_offset = self.bit_offset - self.mapping[name] = [cur_offset, bit_offset, size_in_bits, 0, instance_mapping] - self.get_closures[name] = def (b, p) return ctypes.get_bits(b, cur_offset + p, bit_offset, size_in_bits) end - self.set_closures[name] = def (b, p, v) return ctypes.set_bits(b, cur_offset+ p, bit_offset, size_in_bits, v) end - - self.cur_offset += (self.bit_offset + size_in_bits) / 8 - self.bit_offset = (self.bit_offset + size_in_bits) % 8 - end -end - -ctypes.structure = structure - -#------------------------------------------------------------- -#- Structured buffer -#- -#- Inspired from Python's ctypes structure -#- -#- This class is a wrapper around `bytes()` object (actually a subclass) -#- providing virtual members mapped to the ctypes structure. -#- -#- Takes as argument a ctypes.structure and an optional bytes() object -#-------------------------------------------------------------# -class buffer : bytes - var _cs # ctypes_structure associated - - def init(cs, b) - if !isinstance(cs, ctypes.structure) raise "value_error", "first argument must be an instance of 'ctypes.structure'" end - self._cs = cs - var size = self._cs.size() # size in bytes of the structure - - super(self, bytes).init(size) # init bytes object with reserved size in memory - - if isinstance(b, bytes) - self..b - end - self.resize(size) # size once for all to the target size and complete with 00s - end - - # accessor for virtual member - def member(name) - return self._cs.get_closures[name](self, 0) - end - - # setter for virtual member - def setmember(name, value) - self._cs.set_closures[name](self, 0, value) - end -end -ctypes.buffer = buffer - -#------------------------------------------------------------- -#- Nested buffer -#- -#- Nested structures are just pointers to the master bytes() object -#-------------------------------------------------------------# -class nested_buffer - var _cs # ctypes.structure instance for this buffer - var _offset # offset un bytes() to the structure - var _bytes # reference to the overall buffer (by reference) - - def init(cs, offset, b) - if !isinstance(cs, ctypes.structure) raise "value_error", "first argument must be an instance of 'ctypes.structure'" end - if type(offset) != 'int' raise "value_error", "second argument must be of type 'int'" end - if !isinstance(b, bytes) raise "value_error", "third argument must be an instance of 'bytes'" end - self._cs = cs - self._offset = offset - self._bytes = b - end - - # accessor for virtual member - def member(name) - return self._cs.get_closures[name](self._bytes, self._offset) - end - - # setter for virtual member - def setmember(name, value) - self._cs.set_closures[name](self._bytes, self._offset, value) - end - - def tostring() - return self._bytes[self._offset..self._offset+self._cs.size()-1].tostring() - end -end -ctypes.nested_buffer = nested_buffer - - -return ctypes - -# ex = [ -# [ctypes.u32, "a"], -# [ctypes.u16, "b"], -# [ctypes.i8, "c"], -# [ctypes.i32, "d"], # should infer an empty byte -# ] - -# cs = ctypes.structure(ex) -# bb = ctypes.buffer(cs, bytes("aabb")) - -# fa = cp.get_int_closure('a', 4) -# fb = cp.get_int_closure('b', 2) -# fc = cp.get_int_closure('c', 1) -# fd = cp.get_int_closure('d', 4) - -# b = bytes("04030201AA55FFFF00010001") - -# cp.get_closures['a'](b) -# cp.get_closures['b'](b) -# cp.get_closures['c'](b) -# cp.get_closures['d'](b) - -# bb = ctypes_buffer(cp, b) - -# bb.a = 0x11223344 -# bb -# bb.a - - -# > bb = ctypes_buffer(cp, b) -# > bb.a -# 16909060 -# > bb.b -# 21930 -# > bb.c -# 255 -# > bb.d -# 16777472 -# > bb.e -# key_error: e -# stack traceback: -# : in native function -# stdin:11: in function `member` -# stdin:1: in function `main` - - -# > bb['a'] -# 16909060 -# > bb['b'] -# 21930 -# > bb['c'] -# 255 -# > bb['d'] -# 16777472 - -#- -> fa(b) -16909060 -> fb(b) -21930 -> fc(b) -255 -> fd(b) -16777472 - --# diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_gpio.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_gpio.ino index bd972e00f..3b616895e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_gpio.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_gpio.ino @@ -40,11 +40,8 @@ extern "C" { // virtual member int gp_member(bvm *vm); int gp_member(bvm *vm) { - if (be_const_module_member(vm, lv_gpio_constants, lv_gpio_constants_size)) { - be_return(vm); - } else { - be_return_nil(vm); - } + be_const_module_member_raise(vm, lv_gpio_constants, lv_gpio_constants_size); + be_return(vm); } int gp_pin_mode(bvm *vm); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webserver.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webserver.ino index d2d1a2077..dd4e8384e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webserver.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webserver.ino @@ -57,12 +57,10 @@ extern "C" { // we did have a match, low == high be_pushint(vm, webserver_constants[constant_idx].value); be_return(vm); - } else if (strcmp(needle, "init")) { - /* don't throw an exception if the 'init' function is requested */ - be_raise(vm, "attribute_error", be_pushfstring(vm, "module 'webserver' has no such attribute '%s'", needle)); } } - be_return_nil(vm); + be_module_load(vm, be_newstr(vm, "undefined")); + be_return(vm); } }