Merge pull request #14521 from s-hadinger/berry_ctype

Berry ctype functions
This commit is contained in:
s-hadinger 2022-01-19 23:06:14 +01:00 committed by GitHub
commit c0169b92b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 245 additions and 1392 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1 +0,0 @@
coc

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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