diff --git a/CHANGELOG.md b/CHANGELOG.md index 26c4ae1f9..3bd18f5d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ## [14.1.0.1] ### Added +- Berry solidification of `bytes` instances ### Breaking Changed diff --git a/lib/libesp32/berry/src/be_byteslib.c b/lib/libesp32/berry/src/be_byteslib.c index 1789dca94..5c50a36ba 100644 --- a/lib/libesp32/berry/src/be_byteslib.c +++ b/lib/libesp32/berry/src/be_byteslib.c @@ -16,28 +16,7 @@ #include "be_constobj.h" #include #include - -#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; +#include "be_byteslib.h" /******************************************************************** ** 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 */ -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 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) { be_raise(vm, "value_error", "operation not allowed on pointer"); } @@ -504,10 +492,14 @@ buf_impl m_read_attributes(bvm *vm, int idx) int32_t signed_size = be_toint(vm, -1); attr.fixed = bfalse; attr.mapped = bfalse; + attr.solidified = bfalse; if (signed_size < 0) { if (signed_size == BYTES_SIZE_MAPPED) { attr.mapped = btrue; } + if (signed_size == BYTES_SIZE_SOLIDIFIED) { + attr.solidified = btrue; + } signed_size = attr.len; attr.fixed = btrue; } @@ -516,10 +508,18 @@ buf_impl m_read_attributes(bvm *vm, int idx) 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 */ /* stack item 1 must contain the instance */ 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); if (attr->bufptr != attr->prev_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) 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 (size > vm->bytesmaxsize) { size = vm->bytesmaxsize; } 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) { 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 */ const char * hex_in = NULL; @@ -713,7 +714,7 @@ buf_impl bytes_check_data(bvm *vm, size_t add_size) { 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"; const uint8_t * pin = in; char * pout = out; @@ -745,7 +746,7 @@ static int m_tostring(bvm *vm) char * hex_out = be_pushbuffer(vm, 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) { 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; 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_remove(vm, -2); /* remove buffer */ @@ -795,7 +796,7 @@ static int m_fromstring(bvm *vm) const char *s = be_tostring(vm, 2); int32_t len = be_strlen(vm, 2); /* calling be_strlen to support null chars in string */ buf_impl attr = bytes_check_data(vm, 0); - check_ptr(vm, &attr); + check_ptr_modifiable(vm, &attr); if (attr.fixed && attr.len != len) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); } @@ -823,7 +824,7 @@ static int m_add(bvm *vm) { int argc = be_top(vm); 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 (argc >= 2 && be_isint(vm, 2)) { int32_t v = be_toint(vm, 2); @@ -949,7 +950,7 @@ static int m_set(bvm *vm) { int argc = be_top(vm); 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)) { int32_t idx = be_toint(vm, 2); int32_t value = be_toint(vm, 3); @@ -985,7 +986,7 @@ static int m_setfloat(bvm *vm) { int argc = be_top(vm); 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))) { int32_t idx = be_toint(vm, 2); float val_f = (float) be_toreal(vm, 3); @@ -1011,7 +1012,7 @@ static int m_addfloat(bvm *vm) { int argc = be_top(vm); 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 (argc >=2 && (be_isint(vm, 2) || be_isreal(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); 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))) { int32_t idx = be_toint(vm, 2); size_t from_len_total; @@ -1084,7 +1085,7 @@ static int m_reverse(bvm *vm) { int argc = be_top(vm); 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 len = attr.len; /* entire len */ @@ -1135,7 +1136,7 @@ static int m_setitem(bvm *vm) { int argc = be_top(vm); 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)) { int index = be_toint(vm, 2); int val = be_toint(vm, 3); @@ -1153,7 +1154,7 @@ static int m_item(bvm *vm) { int argc = be_top(vm); 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 */ int index = be_toint(vm,2); if (index < 0) { @@ -1215,6 +1216,7 @@ static int m_resize(bvm *vm) { int argc = be_top(vm); buf_impl attr = m_read_attributes(vm, 1); + check_ptr_modifiable(vm, &attr); if (argc <= 1 || !be_isint(vm, 2)) { 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) { 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); } attr.len = 0; m_write_attributes(vm, 1, &attr); /* update instance */ @@ -1293,7 +1296,7 @@ static int m_connect(bvm *vm) { int argc = be_top(vm); 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 (argc >= 2 && (be_isbytes(vm, 2) || be_isint(vm, 2) || be_isstring(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 */ buf_impl attr = m_read_attributes(vm, 1); - check_ptr(vm, &attr); + check_ptr_modifiable(vm, &attr); if (attr.fixed && attr.len != bin_len) { 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; buf_impl attr = m_read_attributes(vm, 1); - check_ptr(vm, &attr); + check_ptr_modifiable(vm, &attr); if (attr.fixed && attr.len != bin_len) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); } @@ -1483,6 +1486,18 @@ static int m_is_mapped(bvm *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. * @@ -1497,6 +1512,9 @@ static int m_change_buffer(bvm *vm) int argc = be_top(vm); if (argc >= 2 && be_iscomptr(vm, 2)) { buf_impl attr = m_read_attributes(vm, 1); + if (attr.solidified) { + be_raise(vm, "value_error", BYTES_READ_ONLY_MESSAGE); + } if (!attr.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[] = { { ".p", NULL }, - { ".size", NULL }, { ".len", NULL }, + { ".size", NULL }, { "_buffer", m_buffer }, { "_change_buffer", m_change_buffer }, { "ismapped", m_is_mapped }, + { "isreadonly", m_is_readonly }, { "init", m_init }, { "deinit", m_deinit }, { "tostring", m_tostring }, @@ -1810,14 +1829,18 @@ void be_load_byteslib(bvm *vm) be_regclass(vm, "bytes", members); } #else + +#include "../generate/be_const_bytes_def.h" + /* @const_object_info_begin class be_class_bytes (scope: global, name: bytes) { .p, var - .size, var .len, var + .size, var _buffer, func(m_buffer) _change_buffer, func(m_change_buffer) ismapped, func(m_is_mapped) + isreadonly, func(m_is_readonly) init, func(m_init) deinit, func(m_deinit) tostring, func(m_tostring) diff --git a/lib/libesp32/berry/src/be_byteslib.h b/lib/libesp32/berry/src/be_byteslib.h new file mode 100644 index 000000000..bcf98d125 --- /dev/null +++ b/lib/libesp32/berry/src/be_byteslib.h @@ -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 diff --git a/lib/libesp32/berry/src/be_class.h b/lib/libesp32/berry/src/be_class.h index f80ca8799..12f317b5f 100644 --- a/lib/libesp32/berry/src/be_class.h +++ b/lib/libesp32/berry/src/be_class.h @@ -49,6 +49,16 @@ struct binstance { 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); void be_class_compress(bvm *vm, bclass *c); int be_class_attribute(bvm *vm, bclass *c, bstring *attr); diff --git a/lib/libesp32/berry/src/be_constobj.h b/lib/libesp32/berry/src/be_constobj.h index 34245050a..f478b3150 100644 --- a/lib/libesp32/berry/src/be_constobj.h +++ b/lib/libesp32/berry/src/be_constobj.h @@ -19,6 +19,7 @@ extern "C" { #include "be_class.h" #include "be_string.h" #include "be_module.h" +#include "be_byteslib.h" #ifndef __cplusplus @@ -27,6 +28,25 @@ extern "C" { .type = (_t), \ .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) \ const bcstring be_const_str_##_name = { \ .next = NULL, \ @@ -232,6 +252,27 @@ const bntvmodule_t be_native_module(_module) = { \ .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) \ & (const bmap) { \ be_const_header(BE_MAP), \ @@ -298,6 +339,9 @@ const bntvmodule_t be_native_module(_module) = { \ #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) \ const bcstring be_const_str_##_name = { \ NULL, \ @@ -440,6 +484,7 @@ const bntvmodule_t be_native_module_##_module = { \ /* provide pointers to map and list classes for solidified code */ extern const bclass be_class_list; extern const bclass be_class_map; +extern const bclass be_class_bytes; #ifdef __cplusplus } diff --git a/lib/libesp32/berry/src/be_object.h b/lib/libesp32/berry/src/be_object.h index e386cfa25..d479f9b10 100644 --- a/lib/libesp32/berry/src/be_object.h +++ b/lib/libesp32/berry/src/be_object.h @@ -62,6 +62,7 @@ typedef struct bclosure bclosure; typedef struct bntvclos bntvclos; typedef struct bclass bclass; typedef struct binstance binstance; +typedef struct binstance_arg3 binstance_arg3; typedef struct blist blist; typedef struct bmap bmap; typedef struct bupval bupval; diff --git a/lib/libesp32/berry/src/be_solidifylib.c b/lib/libesp32/berry/src/be_solidifylib.c index 78d5c6b41..5691dce5e 100644 --- a/lib/libesp32/berry/src/be_solidifylib.c +++ b/lib/libesp32/berry/src/be_solidifylib.c @@ -17,6 +17,7 @@ #include "be_decoder.h" #include "be_sys.h" #include "be_mem.h" +#include "be_byteslib.h" #include #include #include @@ -24,6 +25,7 @@ extern const bclass be_class_list; extern const bclass be_class_map; +extern const bclass be_class_bytes; #if BE_USE_SOLIDIFY_MODULE #include @@ -288,20 +290,32 @@ static void m_solidify_bvalue(bvm *vm, bbool str_literal, const bvalue * value, bclass * cl = ins->_class; if (ins->super || ins->sub) { 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 const char * cl_ptr = ""; if (cl == &be_class_map) { cl_ptr = "map"; } - if (cl == &be_class_list) { cl_ptr = "list"; } - logfmt("be_const_simple_instance(be_nested_simple_instance(&be_class_%s, {\n", cl_ptr); - if (cl == &be_class_map) { - logfmt(" be_const_map( * "); + 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_list( * "); + logfmt("be_const_simple_instance(be_nested_simple_instance(&be_class_%s, {\n", cl_ptr); + if (cl == &be_class_map) { + logfmt(" be_const_map( * "); + } else { + logfmt(" be_const_list( * "); + } + m_solidify_bvalue(vm, str_literal, &ins->members[0], prefixname, key, fout); + logfmt(" ) } ))"); } - m_solidify_bvalue(vm, str_literal, &ins->members[0], prefixname, key, fout); - logfmt(" ) } ))"); } } break; diff --git a/lib/libesp32/berry/tools/coc/bytes_build.py b/lib/libesp32/berry/tools/coc/bytes_build.py new file mode 100644 index 000000000..ab266f0af --- /dev/null +++ b/lib/libesp32/berry/tools/coc/bytes_build.py @@ -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 \ No newline at end of file diff --git a/lib/libesp32/berry/tools/coc/coc b/lib/libesp32/berry/tools/coc/coc index b80d0ac08..ffc833433 100755 --- a/lib/libesp32/berry/tools/coc/coc +++ b/lib/libesp32/berry/tools/coc/coc @@ -4,6 +4,7 @@ import re import os from coc_parser import * from str_build import * +from bytes_build import * from block_builder import * from macro_table import * @@ -20,6 +21,7 @@ class builder: self.strmap = {} self.strmap_weak = {} self.strmap_long = {} + self.bytesmap = {} self.macro = macro_table() for path in self.config: @@ -30,6 +32,9 @@ class builder: sb = str_build(self.strmap, self.strmap_weak, self.strmap_long) sb.build(self.output) + + sbytes = bytes_build(self.bytesmap) + sbytes.build(self.output) def parse_file(self, filename): if re.search(r"\.(h|c|cc|cpp)$", filename): @@ -45,6 +50,8 @@ class builder: self.strmap_weak[s] = 0 for s in parser.strtab_long: self.strmap_long[s] = 0 + for s in parser.bintab: + self.bytesmap[s] = 0 for obj in parser.objects: builder = block_builder(obj, self.macro) for s in builder.strtab: diff --git a/lib/libesp32/berry/tools/coc/coc_parser.py b/lib/libesp32/berry/tools/coc/coc_parser.py index 68c81a2ba..7319dc337 100644 --- a/lib/libesp32/berry/tools/coc/coc_parser.py +++ b/lib/libesp32/berry/tools/coc/coc_parser.py @@ -23,10 +23,12 @@ class coc_parser: self.strtab = set() self.strtab_weak = set() self.strtab_long = set() + self.bintab = set() self.text = text self.parsers = { "@const_object_info_begin": self.parse_object, "be_const_str_": self.parse_string, + "be_const_bytes_instance(": self.parse_bin, "be_const_key(": self.parse_string, "be_nested_str(": self.parse_string, "be_const_key_weak(": self.parse_string_weak, @@ -77,6 +79,7 @@ class coc_parser: def parse_word(self): self.skip_space() r = re.match(r"\w+", self.text) + if not r: return None self.text = self.text[r.end(0):] return r[0] @@ -120,6 +123,7 @@ class coc_parser: def parse_string(self): if not self.text[0].isalnum() and self.text[0] != '_': return # do not proceed, maybe false positive in solidify ident = self.parse_word() + if not ident: return literal = unescape_operator(ident) if not literal in self.strtab: self.strtab.add(literal) @@ -128,6 +132,7 @@ class coc_parser: def parse_string_weak(self): if not self.text[0].isalnum() and self.text[0] != '_': return # do not proceed, maybe false positive in solidify ident = self.parse_word() + if not ident: return literal = unescape_operator(ident) if not literal in self.strtab: self.strtab_weak.add(literal) @@ -136,10 +141,19 @@ class coc_parser: def parse_string_long(self): if not self.text[0].isalnum() and self.text[0] != '_': return # do not proceed, maybe false positive in solidify ident = self.parse_word() + if not ident: return literal = unescape_operator(ident) if not literal in self.strtab: 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... #################################################################################