Berry bytes solidification (#21558)

* Berry prepare for bytes() solidification

* Berry solidification of bytes objects

* Berry solidification of `bytes` instances
This commit is contained in:
s-hadinger 2024-06-03 21:14:44 +02:00 committed by GitHub
parent 243411916b
commit a51c511d52
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 250 additions and 50 deletions

View File

@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
## [14.1.0.1] ## [14.1.0.1]
### Added ### Added
- Berry solidification of `bytes` instances
### Breaking Changed ### Breaking Changed

View File

@ -16,28 +16,7 @@
#include "be_constobj.h" #include "be_constobj.h"
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include "be_byteslib.h"
#define BYTES_DEFAULT_SIZE 28 // default pre-reserved size for buffer (keep 4 bytes for len/size)
#define BYTES_OVERHEAD 4 // bytes overhead to be added when allocating (used to store len and size)
#define BYTES_HEADROOM 8 // keep a natural headroom of 8 bytes when resizing
#define BYTES_SIZE_FIXED -1 // if size is -1, then the bytes object cannot be reized
#define BYTES_SIZE_MAPPED -2 // if size is -2, then the bytes object is mapped to a fixed memory region, i.e. cannot be resized
#define BYTES_RESIZE_ERROR "attribute_error"
#define BYTES_RESIZE_MESSAGE "bytes object size if fixed and cannot be resized"
/* be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); */
typedef struct buf_impl {
int32_t size; // size in bytes of the buffer
int32_t len; // current size of the data in buffer. Invariant: len <= size
uint8_t *bufptr; // the actual data
int32_t prev_size; // previous value read from the instance
int32_t prev_len; // previous value read from the instance
uint8_t *prev_bufptr;
bbool fixed; // is size fixed? (actually encoded as negative size)
bbool mapped;
} buf_impl;
/******************************************************************** /********************************************************************
** Base64 lib from https://github.com/Densaugeo/base64_arduino ** Base64 lib from https://github.com/Densaugeo/base64_arduino
@ -481,7 +460,16 @@ static void buf_add_hex(buf_impl* attr, const char *hex, size_t len)
********************************************************************/ ********************************************************************/
/* if the bufptr is null, don't try to dereference and raise an exception instead */ /* if the bufptr is null, don't try to dereference and raise an exception instead */
static void check_ptr(bvm *vm, buf_impl* attr) { static void check_ptr(bvm *vm, const buf_impl* attr) {
if (!attr->bufptr) {
be_raise(vm, "value_error", "operation not allowed on <null> pointer");
}
}
static void check_ptr_modifiable(bvm *vm, const buf_impl* attr) {
if (attr->solidified) {
be_raise(vm, "value_error", BYTES_READ_ONLY_MESSAGE);
}
if (!attr->bufptr) { if (!attr->bufptr) {
be_raise(vm, "value_error", "operation not allowed on <null> pointer"); be_raise(vm, "value_error", "operation not allowed on <null> pointer");
} }
@ -504,10 +492,14 @@ buf_impl m_read_attributes(bvm *vm, int idx)
int32_t signed_size = be_toint(vm, -1); int32_t signed_size = be_toint(vm, -1);
attr.fixed = bfalse; attr.fixed = bfalse;
attr.mapped = bfalse; attr.mapped = bfalse;
attr.solidified = bfalse;
if (signed_size < 0) { if (signed_size < 0) {
if (signed_size == BYTES_SIZE_MAPPED) { if (signed_size == BYTES_SIZE_MAPPED) {
attr.mapped = btrue; attr.mapped = btrue;
} }
if (signed_size == BYTES_SIZE_SOLIDIFIED) {
attr.solidified = btrue;
}
signed_size = attr.len; signed_size = attr.len;
attr.fixed = btrue; attr.fixed = btrue;
} }
@ -516,10 +508,18 @@ buf_impl m_read_attributes(bvm *vm, int idx)
return attr; return attr;
} }
static void m_assert_not_readlonly(bvm *vm, const buf_impl* attr)
{
if (attr->solidified) {
be_raise(vm, "value_error", BYTES_READ_ONLY_MESSAGE);
}
}
/* Write back attributes to the bytes instance, only if values changed after loading */ /* Write back attributes to the bytes instance, only if values changed after loading */
/* stack item 1 must contain the instance */ /* stack item 1 must contain the instance */
void m_write_attributes(bvm *vm, int rel_idx, const buf_impl * attr) void m_write_attributes(bvm *vm, int rel_idx, const buf_impl * attr)
{ {
m_assert_not_readlonly(vm, attr);
int idx = be_absindex(vm, rel_idx); int idx = be_absindex(vm, rel_idx);
if (attr->bufptr != attr->prev_bufptr) { if (attr->bufptr != attr->prev_bufptr) {
be_pushcomptr(vm, attr->bufptr); be_pushcomptr(vm, attr->bufptr);
@ -549,6 +549,7 @@ void m_write_attributes(bvm *vm, int rel_idx, const buf_impl * attr)
// buf_impl * bytes_realloc(bvm *vm, buf_impl *oldbuf, int32_t size) // buf_impl * bytes_realloc(bvm *vm, buf_impl *oldbuf, int32_t size)
void bytes_realloc(bvm *vm, buf_impl * attr, int32_t size) void bytes_realloc(bvm *vm, buf_impl * attr, int32_t size)
{ {
m_assert_not_readlonly(vm, attr);
if (!attr->fixed && size < 4) { size = 4; } if (!attr->fixed && size < 4) { size = 4; }
if (size > vm->bytesmaxsize) { size = vm->bytesmaxsize; } if (size > vm->bytesmaxsize) { size = vm->bytesmaxsize; }
size_t oldsize = attr->bufptr ? attr->size : 0; size_t oldsize = attr->bufptr ? attr->size : 0;
@ -590,7 +591,7 @@ static void bytes_new_object(bvm *vm, size_t size)
static int m_init(bvm *vm) static int m_init(bvm *vm)
{ {
int argc = be_top(vm); int argc = be_top(vm);
buf_impl attr = { 0, 0, NULL, 0, -1, NULL, bfalse, bfalse }; /* initialize prev_values to invalid to force a write at the end */ buf_impl attr = { 0, 0, NULL, 0, -1, NULL, bfalse, bfalse, bfalse }; /* initialize prev_values to invalid to force a write at the end */
/* size cannot be 0, len cannot be negative */ /* size cannot be 0, len cannot be negative */
const char * hex_in = NULL; const char * hex_in = NULL;
@ -713,7 +714,7 @@ buf_impl bytes_check_data(bvm *vm, size_t add_size) {
return attr; return attr;
} }
static size_t tohex(char * out, size_t outsz, const uint8_t * in, size_t insz) { size_t be_bytes_tohex(char * out, size_t outsz, const uint8_t * in, size_t insz) {
static const char * hex = "0123456789ABCDEF"; static const char * hex = "0123456789ABCDEF";
const uint8_t * pin = in; const uint8_t * pin = in;
char * pout = out; char * pout = out;
@ -745,7 +746,7 @@ static int m_tostring(bvm *vm)
char * hex_out = be_pushbuffer(vm, hex_len); char * hex_out = be_pushbuffer(vm, hex_len);
size_t l = be_strlcpy(hex_out, "bytes('", hex_len); size_t l = be_strlcpy(hex_out, "bytes('", hex_len);
l += tohex(&hex_out[l], hex_len - l, attr.bufptr, len); l += be_bytes_tohex(&hex_out[l], hex_len - l, attr.bufptr, len);
if (truncated) { if (truncated) {
l += be_strlcpy(&hex_out[l], "...", hex_len - l); l += be_strlcpy(&hex_out[l], "...", hex_len - l);
} }
@ -767,7 +768,7 @@ static int m_tohex(bvm *vm)
size_t hex_len = len * 2 + 1; size_t hex_len = len * 2 + 1;
char * hex_out = be_pushbuffer(vm, hex_len); char * hex_out = be_pushbuffer(vm, hex_len);
size_t l = tohex(hex_out, hex_len, attr.bufptr, len); size_t l = be_bytes_tohex(hex_out, hex_len, attr.bufptr, len);
be_pushnstring(vm, hex_out, l); /* make escape string from buffer */ be_pushnstring(vm, hex_out, l); /* make escape string from buffer */
be_remove(vm, -2); /* remove buffer */ be_remove(vm, -2); /* remove buffer */
@ -795,7 +796,7 @@ static int m_fromstring(bvm *vm)
const char *s = be_tostring(vm, 2); const char *s = be_tostring(vm, 2);
int32_t len = be_strlen(vm, 2); /* calling be_strlen to support null chars in string */ int32_t len = be_strlen(vm, 2); /* calling be_strlen to support null chars in string */
buf_impl attr = bytes_check_data(vm, 0); buf_impl attr = bytes_check_data(vm, 0);
check_ptr(vm, &attr); check_ptr_modifiable(vm, &attr);
if (attr.fixed && attr.len != len) { if (attr.fixed && attr.len != len) {
be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE);
} }
@ -823,7 +824,7 @@ static int m_add(bvm *vm)
{ {
int argc = be_top(vm); int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 4); /* we reserve 4 bytes anyways */ buf_impl attr = bytes_check_data(vm, 4); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr); check_ptr_modifiable(vm, &attr);
if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); } if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); }
if (argc >= 2 && be_isint(vm, 2)) { if (argc >= 2 && be_isint(vm, 2)) {
int32_t v = be_toint(vm, 2); int32_t v = be_toint(vm, 2);
@ -949,7 +950,7 @@ static int m_set(bvm *vm)
{ {
int argc = be_top(vm); int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */ buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr); check_ptr_modifiable(vm, &attr);
if (argc >=3 && be_isint(vm, 2) && be_isint(vm, 3)) { if (argc >=3 && be_isint(vm, 2) && be_isint(vm, 3)) {
int32_t idx = be_toint(vm, 2); int32_t idx = be_toint(vm, 2);
int32_t value = be_toint(vm, 3); int32_t value = be_toint(vm, 3);
@ -985,7 +986,7 @@ static int m_setfloat(bvm *vm)
{ {
int argc = be_top(vm); int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */ buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr); check_ptr_modifiable(vm, &attr);
if (argc >=3 && be_isint(vm, 2) && (be_isint(vm, 3) || be_isreal(vm, 3))) { if (argc >=3 && be_isint(vm, 2) && (be_isint(vm, 3) || be_isreal(vm, 3))) {
int32_t idx = be_toint(vm, 2); int32_t idx = be_toint(vm, 2);
float val_f = (float) be_toreal(vm, 3); float val_f = (float) be_toreal(vm, 3);
@ -1011,7 +1012,7 @@ static int m_addfloat(bvm *vm)
{ {
int argc = be_top(vm); int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 4); /* we reserve 4 bytes anyways */ buf_impl attr = bytes_check_data(vm, 4); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr); check_ptr_modifiable(vm, &attr);
if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); } if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); }
if (argc >=2 && (be_isint(vm, 2) || be_isreal(vm, 2))) { if (argc >=2 && (be_isint(vm, 2) || be_isreal(vm, 2))) {
float val_f = (float) be_toreal(vm, 2); float val_f = (float) be_toreal(vm, 2);
@ -1040,7 +1041,7 @@ static int m_setbytes(bvm *vm)
{ {
int argc = be_top(vm); int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */ buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr); check_ptr_modifiable(vm, &attr);
if (argc >=3 && be_isint(vm, 2) && (be_isbytes(vm, 3))) { if (argc >=3 && be_isint(vm, 2) && (be_isbytes(vm, 3))) {
int32_t idx = be_toint(vm, 2); int32_t idx = be_toint(vm, 2);
size_t from_len_total; size_t from_len_total;
@ -1084,7 +1085,7 @@ static int m_reverse(bvm *vm)
{ {
int argc = be_top(vm); int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */ buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr); check_ptr_modifiable(vm, &attr);
int32_t idx = 0; /* start from index 0 */ int32_t idx = 0; /* start from index 0 */
int32_t len = attr.len; /* entire len */ int32_t len = attr.len; /* entire len */
@ -1135,7 +1136,7 @@ static int m_setitem(bvm *vm)
{ {
int argc = be_top(vm); int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */ buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr); check_ptr_modifiable(vm, &attr);
if (argc >=3 && be_isint(vm, 2) && be_isint(vm, 3)) { if (argc >=3 && be_isint(vm, 2) && be_isint(vm, 3)) {
int index = be_toint(vm, 2); int index = be_toint(vm, 2);
int val = be_toint(vm, 3); int val = be_toint(vm, 3);
@ -1153,7 +1154,7 @@ static int m_item(bvm *vm)
{ {
int argc = be_top(vm); int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */ buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr); check_ptr_modifiable(vm, &attr);
if (argc >=2 && be_isint(vm, 2)) { /* single byte */ if (argc >=2 && be_isint(vm, 2)) { /* single byte */
int index = be_toint(vm,2); int index = be_toint(vm,2);
if (index < 0) { if (index < 0) {
@ -1215,6 +1216,7 @@ static int m_resize(bvm *vm)
{ {
int argc = be_top(vm); int argc = be_top(vm);
buf_impl attr = m_read_attributes(vm, 1); buf_impl attr = m_read_attributes(vm, 1);
check_ptr_modifiable(vm, &attr);
if (argc <= 1 || !be_isint(vm, 2)) { if (argc <= 1 || !be_isint(vm, 2)) {
be_raise(vm, "type_error", "size must be of type 'int'"); be_raise(vm, "type_error", "size must be of type 'int'");
@ -1237,6 +1239,7 @@ static int m_resize(bvm *vm)
static int m_clear(bvm *vm) static int m_clear(bvm *vm)
{ {
buf_impl attr = m_read_attributes(vm, 1); buf_impl attr = m_read_attributes(vm, 1);
check_ptr_modifiable(vm, &attr);
if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); } if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); }
attr.len = 0; attr.len = 0;
m_write_attributes(vm, 1, &attr); /* update instance */ m_write_attributes(vm, 1, &attr); /* update instance */
@ -1293,7 +1296,7 @@ static int m_connect(bvm *vm)
{ {
int argc = be_top(vm); int argc = be_top(vm);
buf_impl attr = m_read_attributes(vm, 1); buf_impl attr = m_read_attributes(vm, 1);
check_ptr(vm, &attr); check_ptr_modifiable(vm, &attr);
if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); } if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); }
if (argc >= 2 && (be_isbytes(vm, 2) || be_isint(vm, 2) || be_isstring(vm, 2))) { if (argc >= 2 && (be_isbytes(vm, 2) || be_isint(vm, 2) || be_isstring(vm, 2))) {
if (be_isint(vm, 2)) { if (be_isint(vm, 2)) {
@ -1390,7 +1393,7 @@ static int m_fromb64(bvm *vm)
int32_t bin_len = decode_base64_length((unsigned char*)s); /* do a first pass to calculate the buffer size */ int32_t bin_len = decode_base64_length((unsigned char*)s); /* do a first pass to calculate the buffer size */
buf_impl attr = m_read_attributes(vm, 1); buf_impl attr = m_read_attributes(vm, 1);
check_ptr(vm, &attr); check_ptr_modifiable(vm, &attr);
if (attr.fixed && attr.len != bin_len) { if (attr.fixed && attr.len != bin_len) {
be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE);
} }
@ -1429,7 +1432,7 @@ static int m_fromhex(bvm *vm)
int32_t bin_len = (s_len - from) / 2; int32_t bin_len = (s_len - from) / 2;
buf_impl attr = m_read_attributes(vm, 1); buf_impl attr = m_read_attributes(vm, 1);
check_ptr(vm, &attr); check_ptr_modifiable(vm, &attr);
if (attr.fixed && attr.len != bin_len) { if (attr.fixed && attr.len != bin_len) {
be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE);
} }
@ -1483,6 +1486,18 @@ static int m_is_mapped(bvm *vm)
be_return(vm); be_return(vm);
} }
/*
* Returns `btrue` if the buffer is solidified and read only
*
* `isreadonly() -> bool`
*/
static int m_is_readonly(bvm *vm)
{
buf_impl attr = m_read_attributes(vm, 1);
be_pushbool(vm, attr.solidified);
be_return(vm);
}
/* /*
* Change the pointer to a mapped buffer. * Change the pointer to a mapped buffer.
* *
@ -1497,6 +1512,9 @@ static int m_change_buffer(bvm *vm)
int argc = be_top(vm); int argc = be_top(vm);
if (argc >= 2 && be_iscomptr(vm, 2)) { if (argc >= 2 && be_iscomptr(vm, 2)) {
buf_impl attr = m_read_attributes(vm, 1); buf_impl attr = m_read_attributes(vm, 1);
if (attr.solidified) {
be_raise(vm, "value_error", BYTES_READ_ONLY_MESSAGE);
}
if (!attr.mapped) { if (!attr.mapped) {
be_raise(vm, "type_error", "bytes() object must be mapped"); be_raise(vm, "type_error", "bytes() object must be mapped");
} }
@ -1764,11 +1782,12 @@ void be_load_byteslib(bvm *vm)
{ {
static const bnfuncinfo members[] = { static const bnfuncinfo members[] = {
{ ".p", NULL }, { ".p", NULL },
{ ".size", NULL },
{ ".len", NULL }, { ".len", NULL },
{ ".size", NULL },
{ "_buffer", m_buffer }, { "_buffer", m_buffer },
{ "_change_buffer", m_change_buffer }, { "_change_buffer", m_change_buffer },
{ "ismapped", m_is_mapped }, { "ismapped", m_is_mapped },
{ "isreadonly", m_is_readonly },
{ "init", m_init }, { "init", m_init },
{ "deinit", m_deinit }, { "deinit", m_deinit },
{ "tostring", m_tostring }, { "tostring", m_tostring },
@ -1810,14 +1829,18 @@ void be_load_byteslib(bvm *vm)
be_regclass(vm, "bytes", members); be_regclass(vm, "bytes", members);
} }
#else #else
#include "../generate/be_const_bytes_def.h"
/* @const_object_info_begin /* @const_object_info_begin
class be_class_bytes (scope: global, name: bytes) { class be_class_bytes (scope: global, name: bytes) {
.p, var .p, var
.size, var
.len, var .len, var
.size, var
_buffer, func(m_buffer) _buffer, func(m_buffer)
_change_buffer, func(m_change_buffer) _change_buffer, func(m_change_buffer)
ismapped, func(m_is_mapped) ismapped, func(m_is_mapped)
isreadonly, func(m_is_readonly)
init, func(m_init) init, func(m_init)
deinit, func(m_deinit) deinit, func(m_deinit)
tostring, func(m_tostring) tostring, func(m_tostring)

View File

@ -0,0 +1,44 @@
/********************************************************************
** 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
********************************************************************/
#ifndef __BE_BYTESLIB_H
#define __BE_BYTESLIB_H
#include "be_object.h"
#define BYTES_DEFAULT_SIZE 28 /* default pre-reserved size for buffer (keep 4 bytes for len/size) */
#define BYTES_OVERHEAD 4 /* bytes overhead to be added when allocating (used to store len and size) */
#define BYTES_HEADROOM 8 /* keep a natural headroom of 8 bytes when resizing */
#define BYTES_SIZE_FIXED -1 /* if size is -1, then the bytes object cannot be reized */
#define BYTES_SIZE_MAPPED -2 /* if size is -2, then the bytes object is mapped to a fixed memory region, i.e. cannot be resized */
#define BYTES_SIZE_SOLIDIFIED -3 /* is size is -3, then the bytes object is solidified and cannot be resized nor modified */
#define BYTES_RESIZE_ERROR "attribute_error"
#define BYTES_RESIZE_MESSAGE "bytes object size if fixed and cannot be resized"
#define BYTES_READ_ONLY_MESSAGE "bytes object is read only"
/* be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); */
typedef struct buf_impl {
int32_t size; // size in bytes of the buffer
int32_t len; // current size of the data in buffer. Invariant: len <= size
uint8_t *bufptr; // the actual data
int32_t prev_size; // previous value read from the instance
int32_t prev_len; // previous value read from the instance
uint8_t *prev_bufptr;
bbool fixed; // is size fixed? (actually encoded as negative size)
bbool mapped;
bbool solidified;
} buf_impl;
size_t be_bytes_tohex(char * out, size_t outsz, const uint8_t * in, size_t insz);
#if BE_USE_PRECOMPILED_OBJECT
#include "../generate/be_const_bytes.h"
#endif
#endif

View File

@ -49,6 +49,16 @@ struct binstance {
bvalue members[1]; /* members variable data field */ bvalue members[1]; /* members variable data field */
}; };
/* special structure accepting 3 instance variables used only for bytes() solidification */
struct binstance_arg3 {
bcommon_header;
struct binstance *super;
struct binstance *sub;
bclass *_class;
bgcobject *gray; /* for gc gray list */
bvalue members[3]; /* members variable data field */
};
bclass* be_newclass(bvm *vm, bstring *name, bclass *super); bclass* be_newclass(bvm *vm, bstring *name, bclass *super);
void be_class_compress(bvm *vm, bclass *c); void be_class_compress(bvm *vm, bclass *c);
int be_class_attribute(bvm *vm, bclass *c, bstring *attr); int be_class_attribute(bvm *vm, bclass *c, bstring *attr);

View File

@ -19,6 +19,7 @@ extern "C" {
#include "be_class.h" #include "be_class.h"
#include "be_string.h" #include "be_string.h"
#include "be_module.h" #include "be_module.h"
#include "be_byteslib.h"
#ifndef __cplusplus #ifndef __cplusplus
@ -27,6 +28,25 @@ extern "C" {
.type = (_t), \ .type = (_t), \
.marked = GC_CONST .marked = GC_CONST
#define be_define_const_bytes(_name, ...) \
const uint8_t be_const_bin_##_name[] = { __VA_ARGS__ }
#define be_const_bytes_instance(_bytes) { \
.v.c = ( \
& (const binstance_arg3) { \
be_const_header(BE_INSTANCE), \
.super = NULL, \
.sub = NULL, \
._class = (bclass*) &be_class_bytes, \
.members = { \
be_const_comptr(&be_const_bin_##_bytes), \
be_const_int(sizeof(#_bytes) / 2), \
be_const_int(BYTES_SIZE_SOLIDIFIED) \
} \
}), \
.type = BE_INSTANCE \
}
#define be_define_const_str_weak(_name, _s, _len) \ #define be_define_const_str_weak(_name, _s, _len) \
const bcstring be_const_str_##_name = { \ const bcstring be_const_str_##_name = { \
.next = NULL, \ .next = NULL, \
@ -232,6 +252,27 @@ const bntvmodule_t be_native_module(_module) = { \
.members = _members \ .members = _members \
} }
#define be_nested_simple_instance_1_arg(_class_ptr, arg0) \
& (const binstance) { \
be_const_header(BE_INSTANCE), \
.super = NULL, \
.sub = NULL, \
._class = (bclass*) _class_ptr, \
.members = { arg0 } \
}
/* only instances with no super and no sub instance are supported */
/* primarily for `list` and `map`*/
#define be_nested_simple_instance_3_args(_class_ptr, arg0, arg1, arg2) \
& (const binstance_arg3) { \
be_const_header(BE_INSTANCE), \
.super = NULL, \
.sub = NULL, \
._class = (bclass*) _class_ptr, \
.members = { arg0, arg1, arg2 } \
}
#define be_nested_map(_size, _slots) \ #define be_nested_map(_size, _slots) \
& (const bmap) { \ & (const bmap) { \
be_const_header(BE_MAP), \ be_const_header(BE_MAP), \
@ -298,6 +339,9 @@ const bntvmodule_t be_native_module(_module) = { \
#else #else
#define be_define_const_bytes(_name, ...) \
const uint8_t be_const_bin_##_name[] = { __VA_ARGS__ }
#define be_define_const_str_weak(_name, _s, _len) \ #define be_define_const_str_weak(_name, _s, _len) \
const bcstring be_const_str_##_name = { \ const bcstring be_const_str_##_name = { \
NULL, \ NULL, \
@ -440,6 +484,7 @@ const bntvmodule_t be_native_module_##_module = { \
/* provide pointers to map and list classes for solidified code */ /* provide pointers to map and list classes for solidified code */
extern const bclass be_class_list; extern const bclass be_class_list;
extern const bclass be_class_map; extern const bclass be_class_map;
extern const bclass be_class_bytes;
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -62,6 +62,7 @@ typedef struct bclosure bclosure;
typedef struct bntvclos bntvclos; typedef struct bntvclos bntvclos;
typedef struct bclass bclass; typedef struct bclass bclass;
typedef struct binstance binstance; typedef struct binstance binstance;
typedef struct binstance_arg3 binstance_arg3;
typedef struct blist blist; typedef struct blist blist;
typedef struct bmap bmap; typedef struct bmap bmap;
typedef struct bupval bupval; typedef struct bupval bupval;

View File

@ -17,6 +17,7 @@
#include "be_decoder.h" #include "be_decoder.h"
#include "be_sys.h" #include "be_sys.h"
#include "be_mem.h" #include "be_mem.h"
#include "be_byteslib.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
@ -24,6 +25,7 @@
extern const bclass be_class_list; extern const bclass be_class_list;
extern const bclass be_class_map; extern const bclass be_class_map;
extern const bclass be_class_bytes;
#if BE_USE_SOLIDIFY_MODULE #if BE_USE_SOLIDIFY_MODULE
#include <inttypes.h> #include <inttypes.h>
@ -288,12 +290,23 @@ static void m_solidify_bvalue(bvm *vm, bbool str_literal, const bvalue * value,
bclass * cl = ins->_class; bclass * cl = ins->_class;
if (ins->super || ins->sub) { if (ins->super || ins->sub) {
be_raise(vm, "internal_error", "instance must not have a super/sub class"); be_raise(vm, "internal_error", "instance must not have a super/sub class");
} else if (cl->nvar != 1) {
be_raise(vm, "internal_error", "instance must have only one instance variable");
} else if ((cl != &be_class_map && cl != &be_class_list) || 1) { // TODO } else if ((cl != &be_class_map && cl != &be_class_list) || 1) { // TODO
const char * cl_ptr = ""; const char * cl_ptr = "";
if (cl == &be_class_map) { cl_ptr = "map"; } if (cl == &be_class_map) { cl_ptr = "map"; }
if (cl == &be_class_list) { cl_ptr = "list"; } else if (cl == &be_class_list) { cl_ptr = "list"; }
else if (cl == &be_class_bytes) { cl_ptr = "bytes"; }
else { be_raise(vm, "internal_error", "unsupported class"); }
if (cl == &be_class_bytes) {
const void * bufptr = var_toobj(&ins->members[0]);
int32_t len = var_toint(&ins->members[1]);
size_t hex_len = len * 2 + 1;
char * hex_out = be_pushbuffer(vm, hex_len);
be_bytes_tohex(hex_out, hex_len, bufptr, len);
logfmt("be_const_bytes_instance(%s)", hex_out);
be_pop(vm, 1);
} else {
logfmt("be_const_simple_instance(be_nested_simple_instance(&be_class_%s, {\n", cl_ptr); logfmt("be_const_simple_instance(be_nested_simple_instance(&be_class_%s, {\n", cl_ptr);
if (cl == &be_class_map) { if (cl == &be_class_map) {
logfmt(" be_const_map( * "); logfmt(" be_const_map( * ");
@ -304,6 +317,7 @@ static void m_solidify_bvalue(bvm *vm, bbool str_literal, const bvalue * value,
logfmt(" ) } ))"); logfmt(" ) } ))");
} }
} }
}
break; break;
case BE_MAP: case BE_MAP:
m_solidify_map(vm, str_literal, (bmap *) var_toobj(value), prefixname, fout); m_solidify_map(vm, str_literal, (bmap *) var_toobj(value), prefixname, fout);

View File

@ -0,0 +1,41 @@
import json
class bytes_build:
def __init__(self, map):
self.map = map.copy()
def build(self, path):
prefix = path + "/be_const_bytes"
self.writefile(prefix + "_def.h", self.build_bytes_def())
self.writefile(prefix + ".h", self.build_bytes_ext())
def writefile(self, filename, text):
buf = ""
try:
with open(filename) as f:
buf = f.read()
except FileNotFoundError:
pass
if buf != text:
with open(filename, "w") as f:
f.write(text)
def build_bytes_def(self):
ostr = ""
ostr += "/* binary arrays */\n"
ostr += "be_define_const_bytes(,);\n"
for k in self.map:
ostr += "be_define_const_bytes("
ostr += k + ", " + ", ".join( [ "0x" + k[i:i+2] for i in range(0, len(k), 2)] )
ostr += ");\n"
return ostr
def build_bytes_ext(self):
ostr = ""
ostr += "/* extern binary arrays */\n"
ostr += "extern const uint8_t be_const_bin_[];\n"
for k in self.map:
ostr += "extern const uint8_t be_const_bin_" + k + "[];\n"
return ostr

View File

@ -4,6 +4,7 @@ import re
import os import os
from coc_parser import * from coc_parser import *
from str_build import * from str_build import *
from bytes_build import *
from block_builder import * from block_builder import *
from macro_table import * from macro_table import *
@ -20,6 +21,7 @@ class builder:
self.strmap = {} self.strmap = {}
self.strmap_weak = {} self.strmap_weak = {}
self.strmap_long = {} self.strmap_long = {}
self.bytesmap = {}
self.macro = macro_table() self.macro = macro_table()
for path in self.config: for path in self.config:
@ -31,6 +33,9 @@ class builder:
sb = str_build(self.strmap, self.strmap_weak, self.strmap_long) sb = str_build(self.strmap, self.strmap_weak, self.strmap_long)
sb.build(self.output) sb.build(self.output)
sbytes = bytes_build(self.bytesmap)
sbytes.build(self.output)
def parse_file(self, filename): def parse_file(self, filename):
if re.search(r"\.(h|c|cc|cpp)$", filename): if re.search(r"\.(h|c|cc|cpp)$", filename):
# print(f"> parse {filename}") # print(f"> parse {filename}")
@ -45,6 +50,8 @@ class builder:
self.strmap_weak[s] = 0 self.strmap_weak[s] = 0
for s in parser.strtab_long: for s in parser.strtab_long:
self.strmap_long[s] = 0 self.strmap_long[s] = 0
for s in parser.bintab:
self.bytesmap[s] = 0
for obj in parser.objects: for obj in parser.objects:
builder = block_builder(obj, self.macro) builder = block_builder(obj, self.macro)
for s in builder.strtab: for s in builder.strtab:

View File

@ -23,10 +23,12 @@ class coc_parser:
self.strtab = set() self.strtab = set()
self.strtab_weak = set() self.strtab_weak = set()
self.strtab_long = set() self.strtab_long = set()
self.bintab = set()
self.text = text self.text = text
self.parsers = { self.parsers = {
"@const_object_info_begin": self.parse_object, "@const_object_info_begin": self.parse_object,
"be_const_str_": self.parse_string, "be_const_str_": self.parse_string,
"be_const_bytes_instance(": self.parse_bin,
"be_const_key(": self.parse_string, "be_const_key(": self.parse_string,
"be_nested_str(": self.parse_string, "be_nested_str(": self.parse_string,
"be_const_key_weak(": self.parse_string_weak, "be_const_key_weak(": self.parse_string_weak,
@ -77,6 +79,7 @@ class coc_parser:
def parse_word(self): def parse_word(self):
self.skip_space() self.skip_space()
r = re.match(r"\w+", self.text) r = re.match(r"\w+", self.text)
if not r: return None
self.text = self.text[r.end(0):] self.text = self.text[r.end(0):]
return r[0] return r[0]
@ -120,6 +123,7 @@ class coc_parser:
def parse_string(self): def parse_string(self):
if not self.text[0].isalnum() and self.text[0] != '_': return # do not proceed, maybe false positive in solidify if not self.text[0].isalnum() and self.text[0] != '_': return # do not proceed, maybe false positive in solidify
ident = self.parse_word() ident = self.parse_word()
if not ident: return
literal = unescape_operator(ident) literal = unescape_operator(ident)
if not literal in self.strtab: if not literal in self.strtab:
self.strtab.add(literal) self.strtab.add(literal)
@ -128,6 +132,7 @@ class coc_parser:
def parse_string_weak(self): def parse_string_weak(self):
if not self.text[0].isalnum() and self.text[0] != '_': return # do not proceed, maybe false positive in solidify if not self.text[0].isalnum() and self.text[0] != '_': return # do not proceed, maybe false positive in solidify
ident = self.parse_word() ident = self.parse_word()
if not ident: return
literal = unescape_operator(ident) literal = unescape_operator(ident)
if not literal in self.strtab: if not literal in self.strtab:
self.strtab_weak.add(literal) self.strtab_weak.add(literal)
@ -136,10 +141,19 @@ class coc_parser:
def parse_string_long(self): def parse_string_long(self):
if not self.text[0].isalnum() and self.text[0] != '_': return # do not proceed, maybe false positive in solidify if not self.text[0].isalnum() and self.text[0] != '_': return # do not proceed, maybe false positive in solidify
ident = self.parse_word() ident = self.parse_word()
if not ident: return
literal = unescape_operator(ident) literal = unescape_operator(ident)
if not literal in self.strtab: if not literal in self.strtab:
self.strtab_long.add(literal) self.strtab_long.add(literal)
def parse_bin(self):
ident = self.parse_word()
if not ident: return
if not re.fullmatch(r"[0-9A-Za-z]*", ident): return
if not ident in self.bintab:
self.bintab.add(ident)
# print(f"str '{ident}' -> {literal}")
################################################################################# #################################################################################
# Parse a block of definition like module, class... # Parse a block of definition like module, class...
################################################################################# #################################################################################