diff --git a/lib/libesp32/berry/generate/be_fixed_unishox.h b/lib/libesp32/berry/generate/be_fixed_unishox.h new file mode 100644 index 000000000..0fbaafa5b --- /dev/null +++ b/lib/libesp32/berry/generate/be_fixed_unishox.h @@ -0,0 +1,18 @@ +#include "be_constobj.h" + +static be_define_const_map_slots(m_libunishox_map) { + { be_const_key(decompress, -1), be_const_func(be_ntv_unishox_decompress) }, + { be_const_key(compress, -1), be_const_func(be_ntv_unishox_compress) }, +}; + +static be_define_const_map( + m_libunishox_map, + 2 +); + +static be_define_const_module( + m_libunishox, + "unishox" +); + +BE_EXPORT_VARIABLE be_define_const_native_module(unishox); diff --git a/lib/libesp32/berry/src/be_constobj.h b/lib/libesp32/berry/src/be_constobj.h index 2ffe6a0ce..22aefd4cb 100644 --- a/lib/libesp32/berry/src/be_constobj.h +++ b/lib/libesp32/berry/src/be_constobj.h @@ -35,12 +35,17 @@ extern "C" { #define be_const_func(_func) { \ .v.nf = (_func), \ - .type = BE_FUNCTION \ + .type = BE_NTVFUNC \ +} +typedef const void * constptr; +#define be_const_ctype_func(_f, ...) { \ + .v.nf = ((const void*) &(constptr[]) { _f, __VA_ARGS__ }), \ + .type = BE_CTYPE_FUNC \ } #define be_const_static_func(_func) { \ .v.nf = (_func), \ - .type = BE_FUNCTION | BE_FUNC_STATIC \ + .type = BE_NTVFUNC | BE_FUNC_STATIC \ } #define be_const_nil() { \ @@ -251,12 +256,19 @@ const bntvmodule be_native_module(_module) = { \ #define be_const_func(_func) { \ bvaldata(_func), \ - BE_FUNCTION \ + BE_NTVFUNC \ +} + +typedef const void * constptr; +#define be_const_ctype_func(_f, ...) { \ + bvaldata(((const void*) \ + &(constptr[]) { (const void*) _f, __VA_ARGS__ })), \ + BE_CTYPE_FUNC \ } #define be_const_static_func(_func) { \ bvaldata(_func), \ - BE_FUNCTION | BE_FUNC_STATIC \ + BE_NTVFUNC | BE_FUNC_STATIC \ } #define be_const_nil() { \ @@ -349,7 +361,7 @@ const bvector _name = { \ } #define be_define_const_native_module(_module) \ -const bntvmodule be_native_module(_module) = { \ +const bntvmodule be_native_module_##_module = { \ #_module, \ 0, 0, \ (bmodule*)&(m_lib##_module) \ diff --git a/lib/libesp32/berry/src/be_object.c b/lib/libesp32/berry/src/be_object.c index 6c246231c..ed338f790 100644 --- a/lib/libesp32/berry/src/be_object.c +++ b/lib/libesp32/berry/src/be_object.c @@ -20,7 +20,7 @@ const char* be_vtype2str(bvalue *v) case BE_INT: return "int"; case BE_REAL: return "real"; case BE_BOOL: return "bool"; - case BE_CLOSURE: case BE_NTVCLOS: + case BE_CLOSURE: case BE_NTVCLOS: case BE_CTYPE_FUNC: case BE_NTVFUNC: return "function"; case BE_PROTO: return "proto"; case BE_CLASS: return "class"; diff --git a/lib/libesp32/berry/src/be_object.h b/lib/libesp32/berry/src/be_object.h index 31c7714bf..df7c7a9af 100644 --- a/lib/libesp32/berry/src/be_object.h +++ b/lib/libesp32/berry/src/be_object.h @@ -34,6 +34,7 @@ #define BE_NTVFUNC ((0 << 5) | BE_FUNCTION) #define BE_CLOSURE ((1 << 5) | BE_FUNCTION) #define BE_NTVCLOS ((2 << 5) | BE_FUNCTION) +#define BE_CTYPE_FUNC ((3 << 5) | BE_FUNCTION) #define BE_FUNC_STATIC (1 << 7) #define func_isstatic(o) (((o)->type & BE_FUNC_STATIC) != 0) @@ -214,6 +215,7 @@ typedef const char* (*breader)(void*, size_t*); #define var_isclosure(_v) var_istype(_v, BE_CLOSURE) #define var_isntvclos(_v) var_istype(_v, BE_NTVCLOS) #define var_isntvfunc(_v) var_istype(_v, BE_NTVFUNC) +#define var_isctypefunc(_v) var_istype(_v, BE_CTYPEFUNC) #define var_isfunction(_v) (var_basetype(_v) == BE_FUNCTION) #define var_isproto(_v) var_istype(_v, BE_PROTO) #define var_isclass(_v) var_istype(_v, BE_CLASS) @@ -236,6 +238,7 @@ typedef const char* (*breader)(void*, size_t*); #define var_setclosure(_v, _o) var_setobj(_v, BE_CLOSURE, _o) #define var_setntvclos(_v, _o) var_setobj(_v, BE_NTVCLOS, _o) #define var_setntvfunc(_v, _o) { (_v)->v.nf = (_o); var_settype(_v, BE_NTVFUNC); } +#define var_setctypefunc(_v, _o) { (_v)->v.nf = (_o); var_settype(_v, BE_CTYPEFUNC); } #define var_setlist(_v, _o) var_setobj(_v, BE_LIST, _o) #define var_setmap(_v, _o) var_setobj(_v, BE_MAP, _o) #define var_setmodule(_v, _o) var_setobj(_v, BE_MODULE, _o) diff --git a/lib/libesp32/berry/src/be_strlib.c b/lib/libesp32/berry/src/be_strlib.c index abc70b893..1196a5aad 100644 --- a/lib/libesp32/berry/src/be_strlib.c +++ b/lib/libesp32/berry/src/be_strlib.c @@ -87,7 +87,7 @@ static bstring* sim2str(bvm *vm, bvalue *v) case BE_REAL: sprintf(sbuf, "%g", var_toreal(v)); break; - case BE_CLOSURE: case BE_NTVCLOS: case BE_NTVFUNC: + case BE_CLOSURE: case BE_NTVCLOS: case BE_NTVFUNC: case BE_CTYPE_FUNC: sprintf(sbuf, "", var_toobj(v)); break; case BE_CLASS: diff --git a/lib/libesp32/berry/src/be_vm.c b/lib/libesp32/berry/src/be_vm.c index 0ec3524d7..3032fa8ae 100644 --- a/lib/libesp32/berry/src/be_vm.c +++ b/lib/libesp32/berry/src/be_vm.c @@ -462,6 +462,7 @@ BERRY_API bvm* be_vm_new(void) be_loadlibs(vm); vm->compopt = 0; vm->obshook = NULL; + vm->ctypefunc = NULL; #if BE_USE_PERF_COUNTERS vm->counter_ins = 0; vm->counter_enter = 0; @@ -1128,6 +1129,17 @@ newframe: /* a new call frame */ ret_native(vm); break; } + case BE_CTYPE_FUNC: { + if (vm->ctypefunc) { + push_native(vm, var, argc, mode); + const void* args = var_toobj(var); + vm->ctypefunc(vm, args); + ret_native(vm); + } else { + vm_error(vm, "internal_error", "missing ctype_func handler"); + } + break; + } case BE_MODULE: { bvalue attr; var_setstr(&attr, str_literal(vm, "()")); @@ -1257,3 +1269,13 @@ BERRY_API void be_set_obs_hook(bvm *vm, bobshook hook) vm->obshook = hook; } + +BERRY_API void be_set_ctype_func_hanlder(bvm *vm, bctypefunc handler) +{ + vm->ctypefunc = handler; +} + +BERRY_API bctypefunc be_get_ctype_func_hanlder(bvm *vm) +{ + return vm->ctypefunc; +} diff --git a/lib/libesp32/berry/src/be_vm.h b/lib/libesp32/berry/src/be_vm.h index 19d745a7c..35176cead 100644 --- a/lib/libesp32/berry/src/be_vm.h +++ b/lib/libesp32/berry/src/be_vm.h @@ -100,6 +100,7 @@ struct bvm { bmap *ntvclass; /* native class table */ blist *registry; /* registry list */ struct bgc gc; + bctypefunc ctypefunc; /* handler to ctype_func */ bbyte compopt; /* compilation options */ bobshook obshook; #if BE_USE_PERF_COUNTERS diff --git a/lib/libesp32/berry/src/berry.h b/lib/libesp32/berry/src/berry.h index 68f1efd4d..41619aa10 100644 --- a/lib/libesp32/berry/src/berry.h +++ b/lib/libesp32/berry/src/berry.h @@ -409,6 +409,8 @@ enum beobshookevents { BE_OBS_STACK_RESIZE_START, /* Berry stack resized */ }; +typedef int (*bctypefunc)(bvm*, const void*); + /* FFI functions */ #define be_writestring(s) be_writebuffer((s), strlen(s)) #define be_writenewline() be_writebuffer("\n", 1) @@ -550,6 +552,8 @@ BERRY_API void be_vm_delete(bvm *vm); /* Observability hook */ BERRY_API void be_set_obs_hook(bvm *vm, bobshook hook); +BERRY_API void be_set_ctype_func_hanlder(bvm *vm, bctypefunc handler); +BERRY_API bctypefunc be_get_ctype_func_hanlder(bvm *vm); /* code load APIs */ BERRY_API int be_loadbuffer(bvm *vm, diff --git a/lib/libesp32/berry/tools/coc/.gitignore b/lib/libesp32/berry/tools/coc/.gitignore deleted file mode 100644 index be1fbe796..000000000 --- a/lib/libesp32/berry/tools/coc/.gitignore +++ /dev/null @@ -1 +0,0 @@ -coc diff --git a/lib/libesp32/berry/tools/coc/Makefile b/lib/libesp32/berry/tools/coc/Makefile deleted file mode 100644 index 773994b3c..000000000 --- a/lib/libesp32/berry/tools/coc/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -TARGET = coc -CXXFLAGS = -std=c++11 -O2 -CXX = g++ - -OBJS = coc_string.o \ - hash_map.o \ - macro_table.o \ - main.o \ - block_builder.o \ - str_build.o \ - coc_parser.o - -ifeq ($(OS), Windows_NT) # Windows - TARGET := $(TARGET).exe -endif - -all: $(TARGET) - -$(TARGET): $(OBJS) - $(Q) $(CXX) $(OBJS) -o $@ - -$(OBJS): %.o: %.cpp - $(Q) $(CXX) $(CXXFLAGS) -c $< -o $@ - -clean: - $(Q) $(RM) $(OBJS) diff --git a/lib/libesp32/berry/tools/coc/REEADME.md b/lib/libesp32/berry/tools/coc/REEADME.md deleted file mode 100644 index 329c66d46..000000000 --- a/lib/libesp32/berry/tools/coc/REEADME.md +++ /dev/null @@ -1,3 +0,0 @@ -# The Constant Object Compiler (coc) - -The constant object compiler (coc) is a C preprocessor that generates the corresponding C99 code based on the constant object declaration block. diff --git a/lib/libesp32/berry/tools/coc/block_builder.cpp b/lib/libesp32/berry/tools/coc/block_builder.cpp deleted file mode 100755 index bd76cdbf5..000000000 --- a/lib/libesp32/berry/tools/coc/block_builder.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 "block_builder.h" -#include "hash_map.h" -#include "macro_table.h" -#include "object_block.h" -#include -#include - -static bool depend(const object_block *object, const macro_table *macro) -{ - auto it = object->attr.find("depend"); - if (it != object->attr.end()) { - return macro->query(it->second); - } - return true; -} - -block_builder::block_builder(const object_block *object, const macro_table *macro) -{ - m_block.name = object->name; - if (depend(object, macro)) { - m_block.type = object->type; - m_block.attr = object->attr; - - auto it = object->attr.find("name"); - if (it != object->attr.end()) { - m_strtab.push_back(it->second); - } - - for (auto key : object->data_ordered) { - auto second = object->data.at(key); - if (second.depend.empty() || macro->query(second.depend)) { - m_block.data[key] = second.value; - m_strtab.push_back(key); - m_block.data_ordered.push_back(key); /* record insertion order */ - } - } - } -} - -std::string block_builder::block_tostring(const block &block) -{ - std::ostringstream ostr; - if (block.type == "map") { - ostr << map_tostring(block, block.name); - } else if (block.type == "class") { - ostr << class_tostring(block); - } else if (block.type == "vartab") { - ostr << vartab_tostring(block); - } else if (block.type == "module") { - ostr << module_tostring(block); - } - return ostr.str(); -} - -std::string block_builder::class_tostring(const block &block) -{ - bool empty_map = block.data.empty(); - std::ostringstream ostr; - hash_map map(block.data); - std::string map_name(block.name + "_map"); - - if (!empty_map) { - ostr << map_tostring(block, map_name, true) << std::endl; - } - ostr << scope(block) << " be_define_const_class(\n " - << block.name << ",\n " - << map.var_count() << ",\n " - << super(block) << ",\n " - << name(block) << "\n" - ");" << std::endl; - return ostr.str(); -} - -std::string block_builder::map_tostring(const block &block, const std::string &name, bool local) -{ - std::ostringstream ostr; - hash_map map(block.data); - - hash_map::entry_table list = map.entry_list(); - ostr << "static be_define_const_map_slots(" << name << ") {\n"; - for (auto it : list) { - ostr << " { be_const_key(" << it.key << ", " - << it.next << "), " << it.value << " }," << std::endl; - } - ostr << "};\n\n"; - - ostr << (local ? "static" : scope(block)) - << " be_define_const_map(\n " - << name << ",\n " - << list.size() << "\n" - ");" << std::endl; - return ostr.str(); -} - -std::string block_builder::vartab_tostring(const block &block) -{ - std::ostringstream ostr; - struct block idxblk; - std::vector varvec; - int index = 0; - - idxblk = block; - idxblk.data.clear(); - for (auto key : block.data_ordered) { - varvec.push_back(block.data.at(key)); - idxblk.data[key] = "int(" + std::to_string(index++) + ")"; - } - - ostr << map_tostring(idxblk, block.name + "_map", true) << std::endl; - ostr << "static const bvalue __vlist_array[] = {\n"; - for (auto it : varvec) { - ostr << " be_const_" << it << "," << std::endl; - } - ostr << "};\n\n"; - - ostr << "static be_define_const_vector(\n " - << block.name << "_vector,\n " - "__vlist_array,\n " - << varvec.size() << "\n" - ");" << std::endl; - return ostr.str(); -} - -std::string block_builder::module_tostring(const block &block) -{ - std::ostringstream ostr; - std::string name("m_lib" + block.name); - std::string map_name(name + "_map"); - - ostr << map_tostring(block, map_name, true) << std::endl - << "static be_define_const_module(\n " - << name << ",\n " - "\"" << block.name << "\"\n" - ");" << std::endl; - std::string scp = scope(block); - if (scp != "static") { /* extern */ - ostr << "\n" << scp - << " be_define_const_native_module(" - << block.name << ");" << std::endl; - } - return ostr.str(); -} - -std::string block_builder::scope(const block &block) -{ - auto it = block.attr.find("scope"); - return it != block.attr.end() && it->second == "local" ? - "static" : "BE_EXPORT_VARIABLE"; -} - -std::string block_builder::super(const block &block) -{ - auto it = block.attr.find("super"); - return it == block.attr.end() ? "NULL" : "(bclass *)&" + it->second; -} - -std::string block_builder::name(const block &block) -{ - auto it = block.attr.find("name"); - return it == block.attr.end() ? block.name : it->second; -} - -void block_builder::writefile(const std::string &filename, const std::string &text) -{ - std::string pathname(filename); - std::string otext("#include \"be_constobj.h\"\n\n" + text); - - std::ostringstream buf; - std::ifstream fin(pathname); - buf << fin.rdbuf(); - if (buf.str() != otext) { - std::ofstream fout; - fout.open(pathname, std::ios::out); - fout << otext; - fout.close(); - } -} - -void block_builder::dumpfile(const std::string &path) -{ - std::string s = block_tostring(m_block); - auto it = m_block.attr.find("file"); - std::string &name = it != m_block.attr.end() ? it->second : m_block.name; - writefile(path + "/be_fixed_" + name + ".h", s); -} - -const std::vector& block_builder::strtab() const -{ - return m_strtab; -} diff --git a/lib/libesp32/berry/tools/coc/block_builder.h b/lib/libesp32/berry/tools/coc/block_builder.h deleted file mode 100755 index 2811419eb..000000000 --- a/lib/libesp32/berry/tools/coc/block_builder.h +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 __BLOCK_BUILDER_H -#define __BLOCK_BUILDER_H - -#include -#include -#include -#include "object_block.h" - -class macro_table; -class object_block; - -class block_builder { -public: - block_builder(const object_block *object, const macro_table *macro); - void dumpfile(const std::string &path); - const std::vector& strtab() const; - -private: - struct block { - std::string type; - std::string name; - std::map attr; - std::map data; - std::vector data_ordered; /* used to retrieve in insertion order */ - }; - - std::string block_tostring(const block &block); - std::string class_tostring(const block &block); - std::string vartab_tostring(const block &block); - std::string module_tostring(const block &block); - std::string map_tostring(const block &block, const std::string &name, bool local = false); - std::string scope(const block &block); - std::string super(const block &block); - std::string name(const block &block); - void writefile(const std::string &filename, const std::string &text); - -private: - block m_block; - std::vector m_strtab; -}; - -#endif // !__BLOCK_BUILDER_H diff --git a/lib/libesp32/berry/tools/coc/coc_parser.cpp b/lib/libesp32/berry/tools/coc/coc_parser.cpp deleted file mode 100644 index 2bbd69965..000000000 --- a/lib/libesp32/berry/tools/coc/coc_parser.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 "coc_parser.h" -#include - -static inline int _isalnum(int c) -{ - return isalnum(c) || c == '_'; -} - -coc_parser::coc_parser(const std::string &text) -{ - m_ptr = text.c_str(); - while (*m_ptr) { - switch (*m_ptr) { - case '@': - parse_object(); - break; - case 'b': - scan_const_string(); - break; - default: - ++m_ptr; - } - } -} - -const std::vector& coc_parser::objects() const -{ - return m_objects; -} - -const std::vector& coc_parser::strtab() const -{ - return m_strtab; -} - -void coc_parser::scan_const_string() -{ - const char prefix[] = "be_const_str_"; - const size_t len = sizeof(prefix) - 1; - if (!strncmp(m_ptr, prefix, len)) { - m_ptr += len; - const char *p = m_ptr; - while (_isalnum(*m_ptr)) - ++m_ptr; - m_strtab.push_back(std::string(p, m_ptr - p)); - } else { - ++m_ptr; - } -} - -void coc_parser::skip_space() -{ - while (isspace(*m_ptr)) - ++m_ptr; -} - -bool coc_parser::parse_char_base(int c, bool necessary) -{ - bool res = *m_ptr == c; - if (!res && necessary) - throw "error"; - if (res) - ++m_ptr; - return res; -} - -bool coc_parser::parse_char(int c, bool necessary) -{ - skip_space(); - return parse_char_base(c, necessary); -} - -bool coc_parser::parse_char_continue(int c, bool necessary) -{ - int ch; - while (((ch = *m_ptr) == ' ') || ch == '\t') - ++m_ptr; - return parse_char_base(c, necessary); -} - -std::string coc_parser::parse_word() -{ - skip_space(); - const char *p = m_ptr; - if (_isalnum(*m_ptr)) { - while (_isalnum(*(++m_ptr))); - return std::string(p, m_ptr - p); - } - throw "error"; -} - -std::string coc_parser::parse_tocomma() -{ - int c; - skip_space(); - const char *p = m_ptr; - while (((c = *m_ptr) != ',') && !isspace(c)) - ++m_ptr; - if (p == m_ptr) - throw "error"; - return std::string(p, m_ptr - p); -} - -std::string coc_parser::parse_tonewline() -{ - int c; - skip_space(); - const char *p = m_ptr; - while (((c = *m_ptr) != '\r') && c != '\n') - ++m_ptr; - if (p == m_ptr) - throw "error"; - return std::string(p, m_ptr - p); -} - -void coc_parser::parse_object() -{ - const char begin_text[] = "@const_object_info_begin"; - const size_t begin_len = sizeof(begin_text) - 1; - if (!strncmp(m_ptr, begin_text, begin_len)) { - m_ptr += begin_len; - do { - object_block object; - parse_block(&object); - m_objects.push_back(object); - } while (!parse_char('@')); - const char end_text[] = "const_object_info_end"; - const size_t end_len = sizeof(end_text) - 1; - if (strncmp(m_ptr, end_text, end_len)) - throw "error"; - m_ptr += end_len; - } else { - ++m_ptr; - } -} - -void coc_parser::parse_block(object_block *object) -{ - object->type = parse_word(); - object->name = parse_word(); - parse_attr(object); - parse_body(object); -} - -void coc_parser::parse_attr(object_block *object) -{ - skip_char('('); - parse_attr_pair(object); - while (parse_char(',')) { - parse_attr_pair(object); - } - skip_char(')'); -} - -void coc_parser::parse_attr_pair(object_block *object) -{ - std::string key = parse_word(); - skip_char(':'); - std::string value = parse_word(); - object->attr[key] = value; -} - -void coc_parser::parse_body(object_block *object) -{ - skip_char('{'); - if (!parse_char('}')) { - do { - parse_body_item(object); - } while (!parse_char('}')); - } -} - -void coc_parser::parse_body_item(object_block *object) -{ - object_block::data_value value; - std::string key = parse_tocomma(); - parse_char_continue(',', true); - value.value = parse_tocomma(); - if (parse_char_continue(',')) - value.depend = parse_tonewline(); - object->data[key] = value; - object->data_ordered.push_back(key); -} diff --git a/lib/libesp32/berry/tools/coc/coc_parser.h b/lib/libesp32/berry/tools/coc/coc_parser.h deleted file mode 100644 index b17a68a67..000000000 --- a/lib/libesp32/berry/tools/coc/coc_parser.h +++ /dev/null @@ -1,46 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 __COC_PARSER_H -#define __COC_PARSER_H - -#include -#include -#include "object_block.h" - -class coc_parser { -public: - coc_parser(const std::string &text); - const std::vector& objects() const; - const std::vector& strtab() const; - -private: - void scan_const_string(); - void skip_space(); - void skip_char(int c) { - parse_char(c, true); - } - bool parse_char_base(int c, bool necessary); - bool parse_char(int c, bool necessary = false); - bool parse_char_continue(int c, bool necessary = false); - std::string parse_word(); - std::string parse_tocomma(); - std::string parse_tonewline(); - void parse_object(); - void parse_block(object_block *object); - void parse_attr(object_block *object); - void parse_attr_pair(object_block *object); - void parse_body(object_block *object); - void parse_body_item(object_block *object); - -private: - const char *m_ptr; - std::vector m_objects; - std::vector m_strtab; -}; - -#endif // !__COC_PARSER_H diff --git a/lib/libesp32/berry/tools/coc/coc_string.cpp b/lib/libesp32/berry/tools/coc/coc_string.cpp deleted file mode 100644 index 1ae9384ac..000000000 --- a/lib/libesp32/berry/tools/coc/coc_string.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 "coc_string.h" -#include - -namespace coc { - -uint32_t hashcode(const std::string &string) -{ - size_t len = string.size(); - const char *str = string.data(); - uint32_t hash = 2166136261u; - while (len--) - hash = (hash ^ (unsigned char)*str++) * 16777619u; - return hash; -} - -std::string escape_operator(const std::string &string) -{ - int c = string[0]; - if (string == "..") - return "opt_connect"; - if (c == '.') - return "dot_" + string.substr(1); - if (isalpha(c) || c == '_') - return string; - const static std::map tab = { - { "+", "opt_add" }, { "-", "opt_sub" }, - { "*", "opt_mul" }, { "/", "opt_div" }, - { "%", "opt_mod" }, { "&", "opt_and" }, - { "^", "opt_xor" }, { "|", "opt_or" }, - { "<", "opt_lt" }, { ">", "opt_gt" }, - { "<=", "opt_le" }, { ">=", "opt_ge" }, - { "==", "opt_eq" }, { "!=", "opt_neq" }, - { "<<", "opt_shl" }, { ">>", "opt_shr" }, - { "-*", "opt_neg" }, { "~", "opt_flip" }, - { "()", "opt_call" } - }; - auto it = tab.find(string); - return it != tab.end() ? it->second : string; -} - -} diff --git a/lib/libesp32/berry/tools/coc/coc_string.h b/lib/libesp32/berry/tools/coc/coc_string.h deleted file mode 100644 index 5fb63ce2c..000000000 --- a/lib/libesp32/berry/tools/coc/coc_string.h +++ /dev/null @@ -1,18 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 __COC_STRING_H -#define __COC_STRING_H - -#include - -namespace coc { - uint32_t hashcode(const std::string &string); - std::string escape_operator(const std::string &string); -} - -#endif diff --git a/lib/libesp32/berry/tools/coc/hash_map.cpp b/lib/libesp32/berry/tools/coc/hash_map.cpp deleted file mode 100755 index e05ca4677..000000000 --- a/lib/libesp32/berry/tools/coc/hash_map.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 "hash_map.h" -#include "coc_string.h" - -#define is_empty(entry) ((entry).next == NODE_EMPTY) - -hash_map::hash_map() -{ - resize(2); -} - -hash_map::hash_map(std::map map) -{ - resize(2); - for (auto it : map) { - insert(it.first, it.second); - } -} - -hash_map::~hash_map() -{ -} - -void hash_map::resize(size_t size) -{ - entry_table bucket = m_bucket; - m_bucket.resize(size); - /* set all slot to empty */ - for (int i = 0; i < size; ++i) { - m_bucket[i].next = NODE_EMPTY; - } - m_lastfree = size - 1; - for (auto slot : bucket) { - if (!is_empty(slot)) { - insert_p(slot.key, slot.value); - } - } -} - -hash_map::entry* hash_map::findprev(entry *list, entry *slot) -{ - int next; - entry *prev = list; - for (;;) { - next = prev->next; - if (next == NODE_NULL || &m_bucket[next] == slot) { - break; - } - prev = &m_bucket[next]; - } - if (next == NODE_NULL) { - return NULL; - } - return prev; -} - -int hash_map::nextfree() -{ - while (m_lastfree >= 0) { - if (is_empty(m_bucket[m_lastfree])) { - return int(m_lastfree); - } - --m_lastfree; - } - return -1; -} - -hash_map::entry hash_map::find(const std::string &key) -{ - uint32_t hash = coc::hashcode(key); - entry null, *slot = &m_bucket[hash % m_bucket.size()]; - if (is_empty(*slot)) { - return null; - } - while (slot->key != key) { - if (slot->next == NODE_NULL) { - return null; - } - slot = &m_bucket[slot->next]; - } - return *slot; -} - -void hash_map::insert_p(const std::string &key, const std::string value) -{ - entry *slot = &m_bucket[coc::hashcode(key) % m_bucket.size()]; - if (is_empty(*slot)) { /* empty slot */ - slot->next = NODE_NULL; - } else { - int newidx = nextfree(); - /* get the main-slot index */ - entry *mainslot = &m_bucket[coc::hashcode(slot->key) % m_bucket.size()]; - entry *newslot = &m_bucket[newidx]; /* get a free slot index */ - if (mainslot == slot) { /* old is main slot */ - newslot->next = mainslot->next; - mainslot->next = newidx; - slot = newslot; - } else { /* link to list */ - entry *prev = findprev(mainslot, slot); - prev->next = newidx; /* link the previous node */ - *newslot = *slot; /* copy to new slot */ - slot->next = NODE_NULL; - } - } - slot->key = key; - slot->value = value; -} - -void hash_map::insert(const std::string &key, const std::string value) -{ - entry slot = find(key); - if (slot.next == NODE_EMPTY) { /* new entry */ - if (m_count >= m_bucket.size()) { - resize(m_bucket.size() * 2); - } - insert_p(key, value); - ++m_count; - } -} - -hash_map::entry hash_map::entry_modify(entry entry, int *var_count) -{ - entry.key = coc::escape_operator(entry.key); - if (entry.value == "var") { - entry.value = "be_const_var(" - + std::to_string(*var_count) + ")"; - ++(*var_count); - } else { - entry.value = "be_const_" + entry.value; - } - return entry; -} - -hash_map::entry_table hash_map::entry_list() -{ - entry_table list; - int var_count = 0; - - resize(m_count); - for (auto it : m_bucket) { - list.push_back(entry_modify(it, &var_count)); - } - return list; -} - -int hash_map::var_count() -{ - int count = 0; - - resize(m_count); - for (auto it : m_bucket) { - count += it.value == "var" ? 1 : 0; - } - return count; -} diff --git a/lib/libesp32/berry/tools/coc/hash_map.h b/lib/libesp32/berry/tools/coc/hash_map.h deleted file mode 100755 index c1aca3e5b..000000000 --- a/lib/libesp32/berry/tools/coc/hash_map.h +++ /dev/null @@ -1,47 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 __HASH_MAP -#define __HASH_MAP - -#include -#include -#include - -#define NODE_EMPTY -2 -#define NODE_NULL -1 - -class hash_map { -public: - struct entry { - std::string key; - std::string value; - int next = NODE_EMPTY; - }; - typedef std::vector entry_table; - - hash_map(); - hash_map(std::map map); - ~hash_map(); - void insert(const std::string &key, const std::string value); - hash_map::entry find(const std::string &key); - entry_table entry_list(); - int var_count(); - -private: - int nextfree(); - hash_map::entry* findprev(entry *list, entry *slot); - void resize(size_t size); - void insert_p(const std::string &key, const std::string value); - hash_map::entry entry_modify(entry entry, int *var_count); - -private: - size_t m_count = 0, m_lastfree = 0; - entry_table m_bucket; -}; - -#endif // !__HASH_MAP diff --git a/lib/libesp32/berry/tools/coc/macro_table.cpp b/lib/libesp32/berry/tools/coc/macro_table.cpp deleted file mode 100644 index ea6d7bea7..000000000 --- a/lib/libesp32/berry/tools/coc/macro_table.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 "macro_table.h" -#include -#include -#include - -std::string macro_table::readfile(const std::string &filename) -{ - std::ifstream in(filename); - std::ostringstream tmp; - tmp << in.rdbuf(); - return tmp.str(); -} - -int macro_table::parse_value(std::string str) -{ - if (!str.length()) { - return 1; /* defined a macro name but no content, considered true */ - } - if (!(str[0] >= '0' && str[0] <= '9')) { - return 1; - } - return atoi(str.c_str()); -} - -void macro_table::scan_file(const std::string &filename) -{ - std::string str(readfile(filename)); - std::regex reg("(?:\\n|$)\\s*#define\\s+(\\w+)[ \\t]+(\\w+)"); - std::sregex_iterator it(str.begin(), str.end(), reg); - std::sregex_iterator end; - while (it != end) { - m_map[it->str(1)] = parse_value(it->str(2)); - ++it; - } -} - -bool macro_table::query(const std::string &str) const -{ - std::regex reg("(!?)(\\w+)"); - std::match_results res; - if (regex_match(str, res, reg)) { - auto it = m_map.find(res[2]); - int value = it == m_map.end() ? 0 : it->second; - return res[1] == "!" ? value == 0 : value != 0; - } - return 0; -} - -std::map macro_table::table() const -{ - return m_map; -} diff --git a/lib/libesp32/berry/tools/coc/macro_table.h b/lib/libesp32/berry/tools/coc/macro_table.h deleted file mode 100644 index 8999f63e6..000000000 --- a/lib/libesp32/berry/tools/coc/macro_table.h +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 __MACRO_TABLE_H -#define __MACRO_TABLE_H - -#include -#include -#include - -class macro_table { -public: - macro_table() {} - void scan_file(const std::string &filename); - bool query(const std::string &str) const; - std::map table() const; - -private: - std::string readfile(const std::string &filename); - int parse_value(std::string str); - -private: - std::map m_map; -}; - -#endif diff --git a/lib/libesp32/berry/tools/coc/main.cpp b/lib/libesp32/berry/tools/coc/main.cpp deleted file mode 100755 index 0b876ba65..000000000 --- a/lib/libesp32/berry/tools/coc/main.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 "main.h" -#include "block_builder.h" -#include "coc_parser.h" -#include "macro_table.h" -#include "str_build.h" -#include -#include - -void builder::parse_all(const std::string &filename) -{ - size_t pos = filename.find_last_of("."); - std::string ext = pos < filename.size() ? filename.substr(pos) : ""; - if (ext == ".c" || ext == ".cc" || ext == ".cpp") { - std::string text = readfile(filename); - coc_parser parser(text); - push_strtab(parser.strtab()); - for (auto object : parser.objects()) { - block_builder builder(&object, m_macro); - push_strtab(builder.strtab()); - builder.dumpfile(m_output); - } - } -} - -void builder::push_strtab(const std::vector &list) -{ - for (auto s : list) - m_strmap[s] = 0; -} - -std::string builder::readfile(const std::string &filename) -{ - std::ifstream in(filename); - std::ostringstream tmp; - tmp << in.rdbuf(); - return tmp.str(); -} - -#ifndef _MSC_VER -#include -#include -#include -#else -#include -#include -#endif - -#ifndef _MSC_VER -void builder::scandir(const std::string &srcpath) -{ - DIR *dp; - struct dirent *ep; - dp = opendir(srcpath.data()); - if (dp != NULL) { - while ((ep = readdir(dp)) != NULL) { - std::string fname(ep->d_name); - parse_all(srcpath + "/" + fname); - } - closedir(dp); - } -} -#else -void builder::scandir(const std::string &srcpath) -{ - HANDLE find; - WIN32_FIND_DATA data; - find = FindFirstFile((srcpath + "/*").data(), &data); - if (find != INVALID_HANDLE_VALUE) { - do { - std::string fname(data.cFileName); - parse_all(srcpath + "/" + fname); - } while (FindNextFile(find, &data) != 0); - FindClose(find); - } -} -#endif - -void builder::build() -{ - for (auto it : m_input) { - scandir(it); - } - str_build sb(m_strmap); - sb.build(m_output); -} - -builder::builder(int argc, char **argv) -{ - m_state = Input; - for (int i = 1; i < argc; ++i) { - add_arg(argv[i]); - } - m_macro = new macro_table(); - for (auto it : m_config) { - m_macro->scan_file(it); - } -} - -builder::~builder() -{ - delete m_macro; -} - -void builder::add_arg(const std::string &arg) -{ - if (arg == "-i") { - m_state = Input; - } else if (arg == "-o") { - m_state = Output; - } else if (arg == "-c") { - m_state = Config; - } else { - switch (m_state) { - case Output: - m_output = arg; - break; - case Config: - m_config.push_back(arg); - break; - case Input: - default: - m_input.push_back(arg); - break; - } - m_state = Input; - } -} - -int main(int argc, char *argv[]) -{ - builder arg(argc, argv); - arg.build(); - return 0; -} diff --git a/lib/libesp32/berry/tools/coc/main.h b/lib/libesp32/berry/tools/coc/main.h deleted file mode 100644 index bba65d533..000000000 --- a/lib/libesp32/berry/tools/coc/main.h +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 __MAIN_H -#define __MAIN_H - -#include -#include -#include - -class macro_table; - -class builder { -public: - builder(int argc, char **argv); - ~builder(); - void build(); - -private: - void push_strtab(const std::vector& list); - void add_arg(const std::string& arg); - std::string info_block(const std::string &text); - void parse_all(const std::string &filename); - void scandir(const std::string &srcpath); - std::string readfile(const std::string &filename); - -private: - enum arg_state { - Input, - Output, - Config - }; - std::string m_output; - std::vector m_input; - std::vector m_config; - arg_state m_state; - macro_table *m_macro; - std::map m_strmap; -}; - -#endif diff --git a/lib/libesp32/berry/tools/coc/object_block.h b/lib/libesp32/berry/tools/coc/object_block.h deleted file mode 100644 index c437f2b62..000000000 --- a/lib/libesp32/berry/tools/coc/object_block.h +++ /dev/null @@ -1,26 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 __OBJECT_BLOCK_H -#define __OBJECT_BLOCK_H - -#include -#include - -struct object_block { - struct data_value { - std::string value; - std::string depend; - }; - std::string type; - std::string name; - std::map attr; - std::map data; - std::vector data_ordered; /* preserve order of keys */ -}; - -#endif diff --git a/lib/libesp32/berry/tools/coc/str_build.cpp b/lib/libesp32/berry/tools/coc/str_build.cpp deleted file mode 100644 index ebc44301e..000000000 --- a/lib/libesp32/berry/tools/coc/str_build.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 "str_build.h" -#include "coc_string.h" -#include -#include - -str_build::str_build(std::map map) -{ - size_t size = map.size() / 2; - m_count = map.size(); - m_hashtable.resize(size < 4 ? 4 : size); - for (auto it : map) { - make_ceil(it.first, it.second); - } - keywords(); -} - -str_build::~str_build() -{ -} - -void str_build::build(const std::string &path) -{ - std::string prefix(path + "/be_const_strtab"); - writefile(prefix + "_def.h", build_table_def()); - writefile(prefix + ".h", build_table_ext()); -} - -void str_build::keywords() -{ - const int opif = 50; /* note the definition in be_lexer.h */ - const static std::map tab = { - { "if", opif}, { "elif", opif + 1 }, - { "else", opif + 2 }, { "while", opif + 3 }, - { "for", opif + 4 }, { "def", opif + 5 }, - { "end", opif + 6 }, { "class", opif + 7 }, - { "break", opif + 8 }, { "continue", opif + 9 }, - { "return", opif + 10 }, { "true", opif + 11 }, - { "false", opif + 12 }, { "nil", opif + 13 }, - { "var", opif + 14 }, { "do", opif + 15 }, - { "import", opif + 16 }, { "as", opif + 17 }, - { "try", opif + 18 }, { "except", opif + 19 }, - { "raise", opif + 20 }, { "static", opif + 21 } - }; - for (auto it : tab) { - make_ceil(it.first, it.second); - } -} - -void str_build::make_ceil(const std::string &string, int extra) -{ - str_info info; - info.hash = coc::hashcode(string); - info.str = string; - info.extra = extra; - m_hashtable[info.hash % m_hashtable.size()].push_back(info); -} - -void str_build::writefile(const std::string &filename, const std::string &text) -{ - std::ostringstream buf; - std::ifstream fin(filename); - buf << fin.rdbuf(); - if (buf.str() != text) { - std::ofstream fout; - fout.open(filename, std::ios::out); - fout << text; - fout.close(); - } -} - -std::string str_build::build_table_def() -{ - std::ostringstream ostr; - for (auto bucket : m_hashtable) { - size_t size = bucket.size(); - for (size_t i = 0; i < size; ++i) { - str_info info = bucket[i]; - std::string node = coc::escape_operator(info.str); - std::string next = i < size - 1 ? - "&be_const_str_" + coc::escape_operator(bucket[i + 1].str) : - "NULL"; - ostr << "be_define_const_str(" - << node << ", \"" << info.str << "\", " - << info.hash << "u, " << info.extra << ", " - << info.str.size() << ", " << next << ");" - << std::endl; - } - } - ostr << std::endl; - ostr << "static const bstring* const m_string_table[] = {" << std::endl; - size_t size = m_hashtable.size(); - for (size_t i = 0; i < size; ++i) { - auto bucket = m_hashtable[i]; - if (bucket.size()) { - ostr << " (const bstring *)&be_const_str_" - << coc::escape_operator(bucket[0].str); - } else { - ostr << " NULL"; - } - ostr << (i < size - 1 ? "," : "") << std::endl; - } - ostr << "};" << std::endl << std::endl; - ostr << - "static const struct bconststrtab m_const_string_table = {\n" - " .size = " << size << ",\n" << - " .count = " << m_count << ",\n" << - " .table = m_string_table\n" << - "};" << std::endl; - return ostr.str(); -} - -std::string str_build::build_table_ext() -{ - std::ostringstream ostr; - for (auto bucket : m_hashtable) { - for (auto info : bucket) { - ostr << "extern const bcstring be_const_str_" - << coc::escape_operator(info.str) << ";" << std::endl; - } - } - return ostr.str(); -} diff --git a/lib/libesp32/berry/tools/coc/str_build.h b/lib/libesp32/berry/tools/coc/str_build.h deleted file mode 100644 index 3a3527409..000000000 --- a/lib/libesp32/berry/tools/coc/str_build.h +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************** -** Copyright (c) 2018-2020 Guan Wenliang -** 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 __BUILD_MAP_H -#define __BUILD_MAP_H - -#include -#include -#include - -class str_build -{ -public: - str_build(std::map map); - ~str_build(); - void build(const std::string &path); - -private: - void keywords(); - void make_ceil(const std::string &string, int extra = 0); - std::string build_table_def(); - std::string build_table_ext(); - void writefile(const std::string &filename, const std::string &text); - -private: - struct str_info { - uint32_t hash; - std::string str; - int extra; - }; - size_t m_count; - std::vector< std::vector > m_hashtable; -}; - -#endif diff --git a/lib/libesp32/berry/tools/pycoc/coc_parser.py b/lib/libesp32/berry/tools/pycoc/coc_parser.py index c31e35814..728292d84 100644 --- a/lib/libesp32/berry/tools/pycoc/coc_parser.py +++ b/lib/libesp32/berry/tools/pycoc/coc_parser.py @@ -74,12 +74,25 @@ class coc_parser: self.text = self.text[r.end(0):] return r[0] + # parse until the next comma or space (trim preceding spaces before) + # does not skip the comma def parse_tocomma(self): self.skip_space() r = re.match(r"[^,\s]*", self.text) self.text = self.text[r.end(0):] return r[0] + # parse until the next closing parenthesis or a single token if no parenthesis (trim preceding spaces before) + # matches: + # 'int' + # 'func(aa)' + # 'mapped_func(aa,"ee", "aa") + def parse_value(self): + self.skip_space() + r = re.match(r"(\S+\(.*?\))|([^,\s]*)", self.text) + self.text = self.text[r.end(0):] + return r[0] + def parse_tonewline(self): self.skip_space() r = re.match(r"[^\r\n]*", self.text) @@ -105,11 +118,15 @@ class coc_parser: self.strtab.add(literal) # print(f"str '{ident}' -> {literal}") + ################################################################################# + # Parse a block of definition like module, class... + ################################################################################# def parse_block(self): obj = object_block() obj.type = self.parse_word() obj.name = self.parse_word() # print(f"parse_block: type={obj.type} name={obj.name}") + # # ex: 'parse_block: type=module name=gpio' self.parse_attr(obj) self.parse_body(obj) return obj @@ -127,6 +144,9 @@ class coc_parser: value = self.parse_word() obj.attr[key] = value + ################################################################################# + # Parse the body definition of a class, module... + ################################################################################# def parse_body(self, obj): self.skip_char("{") if not self.parse_char("}"): @@ -134,12 +154,16 @@ class coc_parser: self.parse_body_item(obj) if self.parse_char("}"): break + ################################################################################# + # Parse each line item in the module/class/vartab + ################################################################################# def parse_body_item(self, obj): value = data_value() key = self.parse_tocomma() # print(f"Key={key}") - self.parse_char_continue(",", True) - value.value = self.parse_tocomma() + self.parse_char_continue(",", True) # skip the ',' after the key + value.value = self.parse_value() + # print(f"value.value={value.value}") if self.parse_char_continue(","): value.depend = self.parse_tonewline() obj.data[key] = value diff --git a/lib/libesp32/berry/tools/pycoc/hash_map.py b/lib/libesp32/berry/tools/pycoc/hash_map.py index 5686a0342..9d3da5365 100644 --- a/lib/libesp32/berry/tools/pycoc/hash_map.py +++ b/lib/libesp32/berry/tools/pycoc/hash_map.py @@ -111,6 +111,9 @@ class hash_map: self.insert_p(key, value) self.count += 1 + ################################################################################# + # Compute entries in the hash for modules or classes + ################################################################################# # return a list (entiry, var_count) def entry_modify(self, ent, var_count): ent.key = escape_operator(ent.key) @@ -121,6 +124,7 @@ class hash_map: ent.value = "be_const_" + ent.value return (ent, var_count) + # generate the final map def entry_list(self): l = [] var_count = 0 @@ -128,6 +132,9 @@ class hash_map: self.resize(self.count) for it in self.bucket: (ent, var_count) = self.entry_modify(it, var_count) + # print(f"ent={ent} var_count={var_count}") + # # ex: ent= var_count=0 + # # ex: ent= var_count=0 l.append(ent) return l diff --git a/lib/libesp32/berry_mapping/README.md b/lib/libesp32/berry_mapping/README.md index 941a5013b..f9ec646d3 100644 --- a/lib/libesp32/berry_mapping/README.md +++ b/lib/libesp32/berry_mapping/README.md @@ -1,4 +1,4 @@ -# Berry mapping to C functions +# Berry mapping to C functions, aka "ctype functions" This library provides a simplified and semi-automated way to map C functions to Berry functions with minimal effort and minimal code size. @@ -87,7 +87,7 @@ When calling a `C` function, here are the steps applied: Berry type|converted to C type :---|:--- -`int`|`intptr_t`
If a type `r` (real) is expected, the value is silently converted to `breal` +`int`|`intptr_t` (i.e. `int` large enough to hold a pointer.

If a type `r` (real) is expected, the value is silently converted to `breal` `real`|`breal` (either `float` or `double`) `bool`|`intptr_t` with value `1` if `true` or `0` if `false` `string`|`const char*` C string `NULL` terminated (cannot be modified) @@ -111,6 +111,7 @@ Argument type|Berry type expected `c`|`comptr` (native pointer) `.`|**any** - no type checking for this argument `-`|**skip** - skip this argument (handy to discard the `self` implicit argument for methods) +`~`|send the length of the previous bytes() buffer (or raise an exception if no length known) `()`|`instance` deriving from `` (i.e. of this class or any subclass `^^`|`function` which is converted to a `C` callback by calling `cb.make_cb()`. The optional `callback_type` string is passed as second argument to `cb.make_cb()` and Berrt `arg #1` (typically `self`) is passed as 3rd argument
See below for callbacks `[<...>]`|arguments in brackets are optional (note: the closing bracket is not strictly necessary but makes it more readable) @@ -128,12 +129,50 @@ Return type definition|Berry return type :---|:--- `''` (empty string)|`nil` - no return value, equivalent to `C` `void` `i`|`int` -`r`|`real` (warning `intptr_t` and `breal` must be of same size) +`f`|(float) `real` (warning `intptr_t` and `breal` must be of same size) `s`|`string` - `const char*` is converted to `C` string, a copy of the string is made so the original string can be modified `b`|`bool` - any non-zero value is converted to `true` `c`|`comptr` - native pointer `` or ``|Instanciate a new instance for this class, pass the return value as `comptr` (native pointer), and pass a second argument as `comptr(-1)` as a marker for an instance cretion (to distinguish from an simple encapsulation of a pointer) `+` of `=`|Used in class constructor `init()` functions, the return value is passed as `comptr` and stored in the instance variable with name ``. The variables are typically `_p` or `.p`. `=` prefix indicates that a `NULL` value is accepted, while the `+` prefix raises an exception if the function returns `NULL`. This is typically used when encapsulating a pointer to a `C++` object that is not supposed to be `NULL`. +`&`|`bytes()` object, pointer to buffer returned, and size passed with an additional (size_t*) argument after arguments + +## Pre-compiled ctype functions + +It is possible to pre-compile Berry modules or classes that reference directly a ctype function definition. + +Example: + +``` C +/* return type is "i", arg type is "ifs" for int-float-string +int my_ext_func(int x, float s, const char* s) { + /* do whatever */ + return 0; +} + +/* @const_object_info_begin +module my_module (scope: global) { + my_func, ctype_func(my_ext_func, "i", "ifs") +} +@const_object_info_end */ +#include "be_fixed_my_module.h" +``` + +With this scheme, the definition is passed automatically to the ctype handler. +It relies on an extensibility scheme of Berry. + +You need to register the ctype function handler at the launch of the Berry VM: + +``` C +#include "berry.h" +#include "be_mapping.h" + +void berry_launch(boid) +{ + bvm *vm = be_vm_new(); /* Construct a VM */ + be_set_ctype_func_hanlder(berry.vm, be_call_ctype_func); /* register the ctype function handler */ +} +``` ## Callbacks diff --git a/lib/libesp32/berry_mapping/src/be_class_wrapper.c b/lib/libesp32/berry_mapping/src/be_class_wrapper.c index 499c0251e..802ff8230 100644 --- a/lib/libesp32/berry_mapping/src/be_class_wrapper.c +++ b/lib/libesp32/berry_mapping/src/be_class_wrapper.c @@ -151,7 +151,7 @@ int be_find_global_or_module_member(bvm *vm, const char * name) { * '-': skip argument and ignore * '~': send the length of the previous bytes() buffer (or raise an exception if no length known) * 'lv_obj' be_instance of type or subtype - * '^lv_event_cb' callback of a named class - will call `_lvgl.gen_cb(arg_type, closure, self)` and expects a callback address in return + * '^lv_event_cb^' callback of a named class - will call `_lvgl.gen_cb(arg_type, closure, self)` and expects a callback address in return * * Ex: ".ii" takes 3 arguments, first one is any type, followed by 2 ints \*********************************************************************************************/ @@ -399,6 +399,21 @@ static void be_set_ctor_ptr(bvm *vm, void * ptr, const char *name) { } } +/* C arguments are coded as an array of 3 pointers */ +typedef struct ctype_args { + void* func; + const char* return_type; + const char* arg_type; +} ctype_args; + +/*********************************************************************************************\ + * CType handler for Berry +\*********************************************************************************************/ +int be_call_ctype_func(bvm *vm, const void *definition) { + ctype_args* args = (ctype_args*) definition; + return be_call_c_func(vm, args->func, args->return_type, args->arg_type); +} + /*********************************************************************************************\ * Call a C function with auto-mapping * @@ -411,7 +426,7 @@ static void be_set_ctor_ptr(bvm *vm, void * ptr, const char *name) { * Note: the C function mapping supports max 8 arguments and does not directly support * pointers to values (although it is possible to mimick with classes) \*********************************************************************************************/ -int be_call_c_func(bvm *vm, void * func, const char * return_type, const char * arg_type) { +int be_call_c_func(bvm *vm, const void * func, const char * return_type, const char * arg_type) { intptr_t p[8] = {0,0,0,0,0,0,0,0}; int argc = be_top(vm); // Get the number of arguments diff --git a/lib/libesp32/berry_mapping/src/be_mapping.h b/lib/libesp32/berry_mapping/src/be_mapping.h index 6264e1ebb..ac62fd597 100644 --- a/lib/libesp32/berry_mapping/src/be_mapping.h +++ b/lib/libesp32/berry_mapping/src/be_mapping.h @@ -58,7 +58,8 @@ extern int be_find_global_or_module_member(bvm *vm, const char * cl_name); extern bbool be_const_member(bvm *vm, const be_const_member_t * definitions, size_t def_len); 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, void * func, const char * return_type, const char * arg_type); +extern int be_call_c_func(bvm *vm, const void * func, const char * return_type, const char * arg_type); +extern int be_call_ctype_func(bvm *vm, const void *definition); /* handler for Berry vm */ #ifdef __cplusplus } diff --git a/lib/libesp32/berry_tasmota/src/be_unishox_lib.c b/lib/libesp32/berry_tasmota/src/be_unishox_lib.c deleted file mode 100644 index 971f4c9e0..000000000 --- a/lib/libesp32/berry_tasmota/src/be_unishox_lib.c +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************** - * Berry module `unishox` - * - * To use: `import unishox` - * - * Allows to respond to HTTP request - *******************************************************************/ -#include "be_constobj.h" - -#ifdef USE_UNISHOX_COMPRESSION - -extern int be_ntv_unishox_decompress(bvm *vm); -extern int be_ntv_unishox_compress(bvm *vm); - -/******************************************************************** -** Solidified module: unishox -********************************************************************/ -be_local_module(unishox, - "unishox", - be_nested_map(2, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key(decompress, -1), be_const_func(be_ntv_unishox_decompress) }, - { be_const_key(compress, -1), be_const_func(be_ntv_unishox_compress) }, - })) -); -BE_EXPORT_VARIABLE be_define_const_native_module(unishox); - -#endif // USE_UNISHOX_COMPRESSION diff --git a/lib/libesp32/berry_tasmota/src/be_unishox_lib.cpp b/lib/libesp32/berry_tasmota/src/be_unishox_lib.cpp new file mode 100644 index 000000000..af4317987 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/be_unishox_lib.cpp @@ -0,0 +1,83 @@ +/******************************************************************** + * Berry module `unishox` + * + * To use: `import unishox` + * + * Allows to respond to HTTP request + *******************************************************************/ + +#ifdef USE_UNISHOX_COMPRESSION + +#include "be_constobj.h" +#include "be_mapping.h" +#include +#include "unishox.h" + +extern Unishox compressor; + +/*********************************************************************************************\ + * Native functions mapped to Berry functions + * + * import unishox + * + * +\*********************************************************************************************/ +static int be_ntv_unishox_compress(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc == 1 && be_isstring(vm, 1)) { + const char * s = be_tostring(vm, 1); + // do a dry-run to know the compressed size + int32_t compressed_size = compressor.unishox_compress(s, strlen(s), (char*) nullptr, 0); + if (compressed_size < 0) { + be_raise(vm, "internal_error", nullptr); + } + void * buf = be_pushbytes(vm, NULL, compressed_size); + if (compressed_size > 0) { + int32_t ret = compressor.unishox_compress(s, strlen(s), (char*) buf, compressed_size+5); // We expand by 4 the buffer size to avoid an error, but we are sure it will not overflow (see unishox implementation) + if (ret < 0 || ret != compressed_size) { + be_raisef(vm, "internal_error", "unishox size=%i ret=%i", compressed_size, ret); + } + } + be_return(vm); + } + be_raise(vm, "type_error", nullptr); +} + +static int be_ntv_unishox_decompress(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc == 1 && be_isbytes(vm, 1)) { + size_t len; + const void * buf = be_tobytes(vm, 1, &len); + if (len == 0) { + be_pushstring(vm, ""); + } else { + int32_t decomp_size = compressor.unishox_decompress((const char*)buf, len, (char*) nullptr, 0); + if (decomp_size < 0) { + be_raise(vm, "internal_error", nullptr); + } + if (decomp_size == 0) { + be_pushstring(vm, ""); + } else { + void * buf_out = be_pushbuffer(vm, decomp_size); + int32_t ret = compressor.unishox_decompress((const char*)buf, len, (char*) buf_out, decomp_size); + if (ret < 0 || ret != decomp_size) { + be_raisef(vm, "internal_error", "unishox size=%i ret=%i", decomp_size, ret); + } + be_pushnstring(vm, (const char*) buf_out, decomp_size); + } + } + be_return(vm); + } + be_raise(vm, "type_error", nullptr); +} + + +/* @const_object_info_begin +module unishox (scope: global) { + decompress, func(be_ntv_unishox_decompress) + compress, func(be_ntv_unishox_compress) +} +@const_object_info_end */ +#include "be_fixed_unishox.h" + +#endif // USE_UNISHOX_COMPRESSION diff --git a/tasmota/xdrv_52_3_berry_unishox.ino b/tasmota/xdrv_52_3_berry_unishox.ino deleted file mode 100644 index c2ca1b5e7..000000000 --- a/tasmota/xdrv_52_3_berry_unishox.ino +++ /dev/null @@ -1,94 +0,0 @@ -/* - xdrv_52_3_berry_unishox.ino - Berry scripting language, native fucnctions - - Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - - -#ifdef USE_BERRY - -#include - -#ifdef USE_UNISHOX_COMPRESSION - -extern Unishox compressor; - -/*********************************************************************************************\ - * Native functions mapped to Berry functions - * - * import unishox - * - * -\*********************************************************************************************/ -extern "C" { - - int be_ntv_unishox_compress(bvm *vm); - int be_ntv_unishox_compress(bvm *vm) { - int32_t argc = be_top(vm); // Get the number of arguments - if (argc == 1 && be_isstring(vm, 1)) { - const char * s = be_tostring(vm, 1); - // do a dry-run to know the compressed size - int32_t compressed_size = compressor.unishox_compress(s, strlen(s), (char*) nullptr, 0); - if (compressed_size < 0) { - be_raise(vm, "internal_error", nullptr); - } - void * buf = be_pushbytes(vm, NULL, compressed_size); - if (compressed_size > 0) { - int32_t ret = compressor.unishox_compress(s, strlen(s), (char*) buf, compressed_size+5); // We expand by 4 the buffer size to avoid an error, but we are sure it will not overflow (see unishox implementation) - if (ret < 0 || ret != compressed_size) { - be_raisef(vm, "internal_error", "unishox size=%i ret=%i", compressed_size, ret); - } - } - be_return(vm); - } - be_raise(vm, kTypeError, nullptr); - } - - int be_ntv_unishox_decompress(bvm *vm); - int be_ntv_unishox_decompress(bvm *vm) { - int32_t argc = be_top(vm); // Get the number of arguments - if (argc == 1 && be_isbytes(vm, 1)) { - size_t len; - const void * buf = be_tobytes(vm, 1, &len); - if (len == 0) { - be_pushstring(vm, ""); - } else { - int32_t decomp_size = compressor.unishox_decompress((const char*)buf, len, (char*) nullptr, 0); - if (decomp_size < 0) { - be_raise(vm, "internal_error", nullptr); - } - if (decomp_size == 0) { - be_pushstring(vm, ""); - } else { - void * buf_out = be_pushbuffer(vm, decomp_size); - int32_t ret = compressor.unishox_decompress((const char*)buf, len, (char*) buf_out, decomp_size); - if (ret < 0 || ret != decomp_size) { - be_raisef(vm, "internal_error", "unishox size=%i ret=%i", decomp_size, ret); - } - be_pushnstring(vm, (const char*) buf_out, decomp_size); - } - } - be_return(vm); - } - be_raise(vm, kTypeError, nullptr); - } - -} - - -#endif // USE_UNISHOX_COMPRESSION - -#endif // USE_BERRY diff --git a/tasmota/xdrv_52_9_berry.ino b/tasmota/xdrv_52_9_berry.ino index a4a12736e..3435053d5 100644 --- a/tasmota/xdrv_52_9_berry.ino +++ b/tasmota/xdrv_52_9_berry.ino @@ -293,6 +293,7 @@ void BerryInit(void) { be_set_obs_hook(berry.vm, &BerryObservability); /* attach observability hook */ comp_set_named_gbl(berry.vm); /* Enable named globals in Berry compiler */ comp_set_strict(berry.vm); /* Enable strict mode in Berry compiler, equivalent of `import strict` */ + be_set_ctype_func_hanlder(berry.vm, be_call_ctype_func); be_load_custom_libs(berry.vm); // load classes and modules