mirror of https://github.com/arendst/Tasmota.git
Merge pull request #14521 from s-hadinger/berry_ctype
Berry ctype functions
This commit is contained in:
commit
c0169b92b6
|
@ -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);
|
|
@ -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) \
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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, "<function: %p>", var_toobj(v));
|
||||
break;
|
||||
case BE_CLASS:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
coc
|
|
@ -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)
|
|
@ -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.
|
|
@ -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 <sstream>
|
||||
#include <fstream>
|
||||
|
||||
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<std::string> 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<std::string>& block_builder::strtab() const
|
||||
{
|
||||
return m_strtab;
|
||||
}
|
|
@ -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 <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#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<std::string>& strtab() const;
|
||||
|
||||
private:
|
||||
struct block {
|
||||
std::string type;
|
||||
std::string name;
|
||||
std::map<std::string, std::string> attr;
|
||||
std::map<std::string, std::string> data;
|
||||
std::vector<std::string> 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<std::string> m_strtab;
|
||||
};
|
||||
|
||||
#endif // !__BLOCK_BUILDER_H
|
|
@ -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 <string.h>
|
||||
|
||||
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<object_block>& coc_parser::objects() const
|
||||
{
|
||||
return m_objects;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& 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);
|
||||
}
|
|
@ -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 <string>
|
||||
#include <vector>
|
||||
#include "object_block.h"
|
||||
|
||||
class coc_parser {
|
||||
public:
|
||||
coc_parser(const std::string &text);
|
||||
const std::vector<object_block>& objects() const;
|
||||
const std::vector<std::string>& 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<object_block> m_objects;
|
||||
std::vector<std::string> m_strtab;
|
||||
};
|
||||
|
||||
#endif // !__COC_PARSER_H
|
|
@ -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 <map>
|
||||
|
||||
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<std::string, std::string> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <string>
|
||||
|
||||
namespace coc {
|
||||
uint32_t hashcode(const std::string &string);
|
||||
std::string escape_operator(const std::string &string);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -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<std::string, std::string> 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;
|
||||
}
|
|
@ -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 <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#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<hash_map::entry> entry_table;
|
||||
|
||||
hash_map();
|
||||
hash_map(std::map<std::string, std::string> 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
|
|
@ -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 <regex>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
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<std::string::const_iterator> 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<std::string, int> macro_table::table() const
|
||||
{
|
||||
return m_map;
|
||||
}
|
|
@ -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 <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class macro_table {
|
||||
public:
|
||||
macro_table() {}
|
||||
void scan_file(const std::string &filename);
|
||||
bool query(const std::string &str) const;
|
||||
std::map<std::string, int> table() const;
|
||||
|
||||
private:
|
||||
std::string readfile(const std::string &filename);
|
||||
int parse_value(std::string str);
|
||||
|
||||
private:
|
||||
std::map<std::string, int> m_map;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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 <fstream>
|
||||
#include <sstream>
|
||||
|
||||
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<std::string> &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 <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#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;
|
||||
}
|
|
@ -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 <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
class macro_table;
|
||||
|
||||
class builder {
|
||||
public:
|
||||
builder(int argc, char **argv);
|
||||
~builder();
|
||||
void build();
|
||||
|
||||
private:
|
||||
void push_strtab(const std::vector<std::string>& 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<std::string> m_input;
|
||||
std::vector<std::string> m_config;
|
||||
arg_state m_state;
|
||||
macro_table *m_macro;
|
||||
std::map<std::string, int> m_strmap;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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 <map>
|
||||
#include <string>
|
||||
|
||||
struct object_block {
|
||||
struct data_value {
|
||||
std::string value;
|
||||
std::string depend;
|
||||
};
|
||||
std::string type;
|
||||
std::string name;
|
||||
std::map<std::string, std::string> attr;
|
||||
std::map<std::string, data_value> data;
|
||||
std::vector<std::string> data_ordered; /* preserve order of keys */
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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 <sstream>
|
||||
#include <fstream>
|
||||
|
||||
str_build::str_build(std::map<std::string, int> 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<std::string, int> 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();
|
||||
}
|
|
@ -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 <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class str_build
|
||||
{
|
||||
public:
|
||||
str_build(std::map<std::string, int> 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<str_info> > m_hashtable;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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
|
||||
|
|
|
@ -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=<entry object; key='arg', value='be_const_func(w_webserver_arg)', next=-1> var_count=0
|
||||
# # ex: ent=<entry object; key='check_privileged_access2', value='be_const_func(w_webserver_check_privileged_access_ntv, "b", "")', next=-1> var_count=0
|
||||
l.append(ent)
|
||||
return l
|
||||
|
||||
|
|
|
@ -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`<br>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.<br><br>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)
|
||||
`(<class>)`|`instance` deriving from `<class>` (i.e. of this class or any subclass
|
||||
`^<callback_type>^`|`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<br>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
|
||||
`<class>` or `<module.class>`|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)
|
||||
`+<varable>` of `=<variable>`|Used in class constructor `init()` functions, the return value is passed as `comptr` and stored in the instance variable with name `<variable>`. 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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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 <string.h>
|
||||
#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
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef USE_BERRY
|
||||
|
||||
#include <berry.h>
|
||||
|
||||
#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
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue