Merge pull request #15802 from s-hadinger/berry_member_undefined

Berry virtual member can return nil
This commit is contained in:
s-hadinger 2022-06-15 22:12:09 +02:00 committed by GitHub
commit 46fa84de9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 120 additions and 665 deletions

View File

@ -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),

View File

@ -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);

View File

@ -12,6 +12,7 @@
#include "be_gc.h"
#include "be_vm.h"
#include "be_func.h"
#include "be_module.h"
#include <string.h>
#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,13 +292,18 @@ 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) {
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;
}
}
}
}
return BE_NONE;
}

View File

@ -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,10 +332,17 @@ 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;
}
*dst = *member;

View File

@ -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 <string.h>
#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

View File

@ -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 */

View File

@ -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);

View File

@ -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"));
}
}

View File

@ -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);

View File

@ -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:

View File

@ -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_const_class_member_raise(vm, light_state_members, ARRAY_SIZE(light_state_members));
be_return(vm);
} else {
be_return_nil(vm);
}
}
#include "be_fixed_be_class_light_state.h"

View File

@ -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_const_class_member_raise(vm, zd_members, ARRAY_SIZE(zd_members));
be_return(vm);
} else {
be_return_nil(vm);
}
}
extern int zc_info(struct bvm *vm);

View File

@ -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

View File

@ -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);
}

View File

@ -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<<block_bits) - 1) << offset_bits
# print(string.format("mask = %02X", mask))
ret = ret | ( ((b[offset_bytes] & mask) >> 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) - 1 # mask to the n bits to get for this block
var mask_b_inv = 0xFF - (mask_val << offset_bits)
b[offset_bytes] = (b[offset_bytes] & mask_b_inv) | ((val & mask_val) << offset_bits)
# move the input window
val >>= 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:
# <native>: 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
-#

View File

@ -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_const_module_member_raise(vm, lv_gpio_constants, lv_gpio_constants_size);
be_return(vm);
} else {
be_return_nil(vm);
}
}
int gp_pin_mode(bvm *vm);

View File

@ -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);
}
}