From 5ab0081f4796dc053d5c3df2e8b790e8227870bc Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Tue, 24 Aug 2021 22:44:33 +0200 Subject: [PATCH] Berry upgrade to latest changes --- lib/libesp32/Berry/src/be_api.c | 28 ++-- lib/libesp32/Berry/src/be_bytecode.c | 82 +++++++---- lib/libesp32/Berry/src/be_class.c | 26 +++- lib/libesp32/Berry/src/be_code.c | 15 +- lib/libesp32/Berry/src/be_debug.c | 4 +- lib/libesp32/Berry/src/be_module.c | 46 +++++- lib/libesp32/Berry/src/be_module.h | 4 +- lib/libesp32/Berry/src/be_parser.c | 8 ++ lib/libesp32/Berry/src/be_string.c | 1 - lib/libesp32/Berry/src/be_vm.c | 133 ++++-------------- .../Berry/tools/grammar/berry.bytecode | 28 ++-- tasmota/xdrv_52_3_berry_lvgl.ino | 4 +- tasmota/xdrv_52_3_berry_webserver.ino | 5 +- 13 files changed, 197 insertions(+), 187 deletions(-) diff --git a/lib/libesp32/Berry/src/be_api.c b/lib/libesp32/Berry/src/be_api.c index ea78283dc..d883c08d7 100644 --- a/lib/libesp32/Berry/src/be_api.c +++ b/lib/libesp32/Berry/src/be_api.c @@ -608,23 +608,18 @@ BERRY_API bbool be_getbuiltin(bvm *vm, const char *name) BERRY_API bbool be_setmember(bvm *vm, int index, const char *k) { - int res = BE_NIL; bvalue *o = be_indexof(vm, index); + bvalue *v = be_indexof(vm, -1); if (var_isinstance(o)) { bstring *key = be_newstr(vm, k); - bvalue *v = be_indexof(vm, -1); binstance *obj = var_toobj(o); - res = be_instance_setmember(vm, obj, key, v); + return be_instance_setmember(vm, obj, key, v); } else if (var_ismodule(o)) { bstring *key = be_newstr(vm, k); bmodule *mod = var_toobj(o); - bvalue *v = be_module_bind(vm, mod, key); - if (v) { - *v = *be_indexof(vm, -1); - return btrue; - } + return be_module_setmember(vm, mod, key, v); } - return res != BE_NIL; + return bfalse; } BERRY_API bbool be_copy(bvm *vm, int index) @@ -650,16 +645,15 @@ static int ins_member(bvm *vm, int index, const char *k, bbool onlyins) if (var_isinstance(o)) { binstance *obj = var_toobj(o); type = be_instance_member(vm, obj, be_newstr(vm, k), top); - if (type == BE_NONE) { - type = BE_NIL; - } + } else if (var_isclass(o) && !onlyins) { + bclass *cl = var_toobj(o); + type = be_class_member(vm, cl, be_newstr(vm, k), top); } else if (var_ismodule(o) && !onlyins) { bmodule *module = var_toobj(o); - bvalue *v = be_module_attr(vm, module, be_newstr(vm, k)); - if (v != NULL) { - *top = *v; - type = v->type; - } + type = be_module_attr(vm, module, be_newstr(vm, k), top); + } + if (type == BE_NONE) { + type = BE_NIL; } return type; } diff --git a/lib/libesp32/Berry/src/be_bytecode.c b/lib/libesp32/Berry/src/be_bytecode.c index e6d69a0dd..0e0cbf723 100644 --- a/lib/libesp32/Berry/src/be_bytecode.c +++ b/lib/libesp32/Berry/src/be_bytecode.c @@ -23,7 +23,7 @@ #define MAGIC_NUMBER1 0xBE #define MAGIC_NUMBER2 0xCD #define MAGIC_NUMBER3 0xFE -#define BYTECODE_VERSION 1 +#define BYTECODE_VERSION 2 #define USE_64BIT_INT (BE_INTGER_TYPE == 2 \ || BE_INTGER_TYPE == 1 && LONG_MAX == 9223372036854775807L) @@ -179,12 +179,18 @@ static void save_value(bvm *vm, void *fp, bvalue *v) } } -static void save_bytecode(void *fp, bproto *proto) +static void save_bytecode(bvm *vm, void *fp, bproto *proto) { + int forbid_gbl = comp_is_named_gbl(vm); binstruction *code = proto->code, *end; save_long(fp, (uint32_t)proto->codesize); for (end = code + proto->codesize; code < end; ++code) { save_long(fp, (uint32_t)*code); + if (forbid_gbl) { /* we are saving only named globals, so make sure we don't save OP_GETGBL or OP_SETGBL */ + if ((uint32_t)*code == OP_GETGBL || (uint32_t)*code == OP_SETGBL) { + be_raise(vm, "internal_error", "GETGBL/SETGBL found when saving with named globals"); + } + } } } @@ -223,7 +229,9 @@ static void save_proto(bvm *vm, void *fp, bproto *proto) save_string(fp, proto->source); /* source */ save_byte(fp, proto->argc); /* argc */ save_byte(fp, proto->nstack); /* nstack */ - save_bytecode(fp, proto); /* bytecode */ + save_byte(fp, proto->varg); /* varg */ + save_byte(fp, 0x00); /* reserved */ + save_bytecode(vm, fp, proto); /* bytecode */ save_constants(vm, fp, proto); /* constant */ save_proto_table(vm, fp, proto); /* proto table */ save_upvals(fp, proto); /* upvals description table */ @@ -253,8 +261,13 @@ static void save_globals(bvm *vm, void *fp) static void save_global_info(bvm *vm, void *fp) { save_long(fp, be_builtin_count(vm)); - save_long(fp, be_global_count(vm)); - save_globals(vm, fp); + if (comp_is_named_gbl(vm)) { + /* named globals only so no need to save current globals */ + save_long(fp, 0); + } else { + save_long(fp, be_global_count(vm)); + save_globals(vm, fp); + } } void be_bytecode_save(bvm *vm, const char *filename, bproto *proto) @@ -273,7 +286,7 @@ void be_bytecode_save(bvm *vm, const char *filename, bproto *proto) #endif /* BE_USE_BYTECODE_SAVER */ #if BE_USE_BYTECODE_LOADER -static void load_proto(bvm *vm, void *fp, bproto **proto, int info); +static void load_proto(bvm *vm, void *fp, bproto **proto, int info, int version); static uint8_t load_byte(void *fp) { @@ -313,9 +326,13 @@ static int load_head(void *fp) res = buffer[0] == MAGIC_NUMBER1 && buffer[1] == MAGIC_NUMBER2 && buffer[2] == MAGIC_NUMBER3 && - buffer[3] == BYTECODE_VERSION && + buffer[3] <= BYTECODE_VERSION && buffer[4] == vm_sizeinfo(); - return res; + if (res) { + return buffer[3]; + } else { + return 0; + } } bbool be_bytecode_check(const char *path) @@ -385,7 +402,7 @@ static bstring* cache_string(bvm *vm, void *fp) return str; } -static void load_class(bvm *vm, void *fp, bvalue *v) +static void load_class(bvm *vm, void *fp, bvalue *v, int version) { int nvar, count; bclass *c = be_newclass(vm, NULL, NULL); @@ -399,7 +416,7 @@ static void load_class(bvm *vm, void *fp, bvalue *v) value = vm->top; var_setproto(value, NULL); be_incrtop(vm); - load_proto(vm, fp, (bproto**)&var_toobj(value), -3); + load_proto(vm, fp, (bproto**)&var_toobj(value), -3, version); be_method_bind(vm, c, name, var_toobj(value)); be_stackpop(vm, 2); /* pop the cached string and proto */ } @@ -410,13 +427,13 @@ static void load_class(bvm *vm, void *fp, bvalue *v) } } -static void load_value(bvm *vm, void *fp, bvalue *v) +static void load_value(bvm *vm, void *fp, bvalue *v, int version) { switch (load_byte(fp)) { case BE_INT: var_setint(v, load_int(fp)); break; case BE_REAL: var_setreal(v, load_real(fp)); break; case BE_STRING: var_setstr(v, load_string(vm, fp)); break; - case BE_CLASS: load_class(vm, fp, v); break; + case BE_CLASS: load_class(vm, fp, v, version); break; default: break; } } @@ -449,7 +466,7 @@ static void load_bytecode(bvm *vm, void *fp, bproto *proto, int info) } } -static void load_constant(bvm *vm, void *fp, bproto *proto) +static void load_constant(bvm *vm, void *fp, bproto *proto, int version) { int size = (int)load_long(fp); /* nconst */ if (size) { @@ -458,12 +475,12 @@ static void load_constant(bvm *vm, void *fp, bproto *proto) proto->ktab = v; proto->nconst = size; for (end = v + size; v < end; ++v) { - load_value(vm, fp, v); + load_value(vm, fp, v, version); } } } -static void load_proto_table(bvm *vm, void *fp, bproto *proto) +static void load_proto_table(bvm *vm, void *fp, bproto *proto, int version) { int size = (int)load_long(fp); /* proto count */ if (size) { @@ -472,7 +489,7 @@ static void load_proto_table(bvm *vm, void *fp, bproto *proto) proto->ptab = p; proto->nproto = size; while (size--) { - load_proto(vm, fp, p++, -1); + load_proto(vm, fp, p++, -1, version); } } } @@ -492,16 +509,20 @@ static void load_upvals(bvm *vm, void *fp, bproto *proto) } } -static void load_proto(bvm *vm, void *fp, bproto **proto, int info) +static void load_proto(bvm *vm, void *fp, bproto **proto, int info, int version) { *proto = be_newproto(vm); (*proto)->name = load_string(vm, fp); (*proto)->source = load_string(vm, fp); (*proto)->argc = load_byte(fp); (*proto)->nstack = load_byte(fp); + if (version > 1) { + (*proto)->varg = load_byte(fp); + load_byte(fp); /* discard reserved byte */ + } load_bytecode(vm, fp, *proto, info); - load_constant(vm, fp, *proto); - load_proto_table(vm, fp, *proto); + load_constant(vm, fp, *proto, version); + load_proto_table(vm, fp, *proto, version); load_upvals(vm, fp, *proto); } @@ -510,7 +531,7 @@ void load_global_info(bvm *vm, void *fp) int i; int bcnt = (int)load_long(fp); /* builtin count */ int gcnt = (int)load_long(fp); /* global count */ - if (bcnt != be_builtin_count(vm)) { + if (bcnt > be_builtin_count(vm)) { bytecode_error(vm, be_pushfstring(vm, "inconsistent number of builtin objects.")); } @@ -530,15 +551,18 @@ bclosure* be_bytecode_load(bvm *vm, const char *filename) if (fp == NULL) { bytecode_error(vm, be_pushfstring(vm, "can not open file '%s'.", filename)); - } else if (load_head(fp)) { - bclosure *cl = be_newclosure(vm, 0); - var_setclosure(vm->top, cl); - be_stackpush(vm); - load_global_info(vm, fp); - load_proto(vm, fp, &cl->proto, -1); - be_stackpop(vm, 2); /* pop the closure and list */ - be_fclose(fp); - return cl; + } else { + int version = load_head(fp); + if (version) { + bclosure *cl = be_newclosure(vm, 0); + var_setclosure(vm->top, cl); + be_stackpush(vm); + load_global_info(vm, fp); + load_proto(vm, fp, &cl->proto, -1, version); + be_stackpop(vm, 2); /* pop the closure and list */ + be_fclose(fp); + return cl; + } } bytecode_error(vm, be_pushfstring(vm, "invalid bytecode file '%s'.", filename)); diff --git a/lib/libesp32/Berry/src/be_class.c b/lib/libesp32/Berry/src/be_class.c index 4bd264446..b8e3ea2fb 100644 --- a/lib/libesp32/Berry/src/be_class.c +++ b/lib/libesp32/Berry/src/be_class.c @@ -241,20 +241,38 @@ bbool be_class_newobj(bvm *vm, bclass *c, bvalue *reg, int argc, int mode) /* Input: none of `obj`, `name` and `dst` may not be NULL */ /* Returns the type of the member or BE_NONE if member not found */ /* TODO need to support synthetic members */ -int be_instance_member(bvm *vm, binstance *obj, bstring *name, bvalue *dst) +int be_instance_member(bvm *vm, binstance *instance, bstring *name, bvalue *dst) { int type; be_assert(name != NULL); - obj = instance_member(vm, obj, name, dst); + binstance * obj = instance_member(vm, instance, name, dst); type = var_type(dst); if (obj && type == MT_VARIABLE) { *dst = obj->members[dst->v.i]; } if (obj) { return type; - } else { - return BE_NONE; + } else { /* if no method found, try virtual */ + /* get method 'member' */ + obj = instance_member(vm, instance, str_literal(vm, "member"), vm->top); + if (obj && basetype(var_type(vm->top)) == BE_FUNCTION) { + bvalue *top = vm->top; + var_setinstance(&top[1], instance); + var_setstr(&top[2], name); + vm->top += 3; /* prevent gc collection results */ + be_dofunc(vm, top, 2); /* call method 'member' */ + vm->top -= 3; + *dst = *vm->top; /* copy result to R(A) */ + if (obj && var_type(dst) == MT_VARIABLE) { + *dst = obj->members[dst->v.i]; + } + type = var_type(dst); + if (type != BE_NIL) { + return type; + } + } } + return BE_NONE; } int be_class_member(bvm *vm, bclass *obj, bstring *name, bvalue *dst) diff --git a/lib/libesp32/Berry/src/be_code.c b/lib/libesp32/Berry/src/be_code.c index e9d0e4d9f..cf1a265b3 100644 --- a/lib/libesp32/Berry/src/be_code.c +++ b/lib/libesp32/Berry/src/be_code.c @@ -251,7 +251,7 @@ static int newconst(bfuncinfo *finfo, bvalue *k) } /* Find constant by value and return constant number, or -1 if constant does not exist */ -/* The search is linear and lilited to 50 elements for performance reasons */ +/* The search is linear and limited to 100 elements for performance reasons */ static int findconst(bfuncinfo *finfo, bexpdesc *e) { int i, count = be_vector_count(&finfo->kvec); @@ -260,7 +260,7 @@ static int findconst(bfuncinfo *finfo, bexpdesc *e) * so only search the constant table for the * previous value. **/ - count = count < 50 ? count : 50; + count = count < 100 ? count : 100; for (i = 0; i < count; ++i) { bvalue *k = be_vector_at(&finfo->kvec, i); switch (e->type) { @@ -746,10 +746,12 @@ int be_code_proto(bfuncinfo *finfo, bproto *proto) void be_code_closure(bfuncinfo *finfo, bexpdesc *e, int idx) { - int reg = e->type == ETGLOBAL ? finfo->freereg: e->v.idx; + int reg = (e->type == ETGLOBAL || e->type == ETNGLOBAL) ? finfo->freereg: e->v.idx; code_closure(finfo, idx, reg); - if (e->type == ETGLOBAL) { /* store to grobal R(A) -> G(Bx) */ + if (e->type == ETGLOBAL) { /* store to global R(A) -> G(Bx) */ codeABx(finfo, OP_SETGBL, reg, e->v.idx); + } else if (e->type == ETNGLOBAL) { /* store R(A) -> GLOBAL[RK(B)] */ + codeABC(finfo, OP_SETNGBL, reg, e->v.idx, 0); } } @@ -841,9 +843,12 @@ void be_code_class(bfuncinfo *finfo, bexpdesc *dst, bclass *c) src = newconst(finfo, &var); /* allocate a new constant and return kreg */ if (dst->type == ETLOCAL) { /* if target is a local variable, just assign */ codeABx(finfo, OP_LDCONST, dst->v.idx, src); - } else { /* otherwise set as global with same name as class name */ + } else if (dst->type == ETGLOBAL) { /* otherwise set as global with same name as class name */ codeABx(finfo, OP_LDCONST, finfo->freereg, src); codeABx(finfo, OP_SETGBL, finfo->freereg, dst->v.idx); + } else if (dst->type == ETNGLOBAL) { + codeABx(finfo, OP_LDCONST, finfo->freereg, src); + codeABC(finfo, OP_SETNGBL, finfo->freereg, dst->v.idx, 0); } codeABx(finfo, OP_CLASS, 0, src); /* emit CLASS opcode to register class */ } diff --git a/lib/libesp32/Berry/src/be_debug.c b/lib/libesp32/Berry/src/be_debug.c index 0b1cd914b..33db01d36 100644 --- a/lib/libesp32/Berry/src/be_debug.c +++ b/lib/libesp32/Berry/src/be_debug.c @@ -62,7 +62,7 @@ void be_print_inst(binstruction ins, int pc) case OP_OR: case OP_XOR: case OP_SHL: case OP_SHR: logbuf("%s\tR%d\t%c%d\t%c%d", opc2str(op), IGET_RA(ins), isKB(ins) ? 'K' : 'R', IGET_RKB(ins) & KR_MASK, - isKB(ins) ? 'K' : 'R', IGET_RKC(ins) & KR_MASK); + isKC(ins) ? 'K' : 'R', IGET_RKC(ins) & KR_MASK); break; case OP_GETNGBL: case OP_SETNGBL: logbuf("%s\tR%d\t%c%d", opc2str(op), IGET_RA(ins), @@ -116,7 +116,7 @@ void be_print_inst(binstruction ins, int pc) case OP_RAISE: logbuf("%s\t%d\t%c%d\t%c%d", opc2str(op), IGET_RA(ins), isKB(ins) ? 'K' : 'R', IGET_RKB(ins) & KR_MASK, - isKB(ins) ? 'K' : 'R', IGET_RKC(ins) & KR_MASK); + isKC(ins) ? 'K' : 'R', IGET_RKC(ins) & KR_MASK); break; case OP_EXBLK: if (IGET_RA(ins)) { diff --git a/lib/libesp32/Berry/src/be_module.c b/lib/libesp32/Berry/src/be_module.c index 096a7c826..4cbc86a95 100644 --- a/lib/libesp32/Berry/src/be_module.c +++ b/lib/libesp32/Berry/src/be_module.c @@ -299,22 +299,58 @@ void be_module_delete(bvm *vm, bmodule *module) be_free(vm, module, sizeof(bmodule)); } -bvalue* be_module_attr(bvm *vm, bmodule *module, bstring *attr) +int be_module_attr(bvm *vm, bmodule *module, bstring *attr, bvalue *dst) { - return be_map_findstr(vm, module->table, attr); + bvalue *member = be_map_findstr(vm, module->table, attr); + if (!member) { /* try the 'member' function */ + member = be_map_findstr(vm, module->table, str_literal(vm, "member")); + if (member && var_basetype(member) == BE_FUNCTION) { + bvalue *top = vm->top; + top[0] = *member; + var_setstr(&top[1], attr); + vm->top += 2; /* prevent collection results */ + be_dofunc(vm, top, 1); /* call method 'method' */ + vm->top -= 2; + *dst = *vm->top; /* copy result to R(A) */ + if (var_basetype(dst) != BE_NIL) { + return var_type(dst); + } + } + return BE_NONE; + } else { + *dst = *member; + return var_type(dst); + } } -bvalue* be_module_bind(bvm *vm, bmodule *module, bstring *attr) +bbool be_module_setmember(bvm *vm, bmodule *module, bstring *attr, bvalue *src) { + assert(src); bmap *attrs = module->table; if (!gc_isconst(attrs)) { bvalue *v = be_map_findstr(vm, attrs, attr); if (v == NULL) { v = be_map_insertstr(vm, attrs, attr, NULL); } - return v; + if (v) { + *v = *src; + return btrue; + } + } else { + /* if not writable, try 'setmember' */ + int type = be_module_attr(vm, module, str_literal(vm, "setmember"), vm->top); + if (type == BE_FUNCTION) { + bvalue *top = vm->top; + // top[0] already has 'member' + var_setstr(&top[1], attr); /* attribute name */ + top[2] = *src; /* new value */ + vm->top += 3; /* prevent collection results */ + be_dofunc(vm, top, 2); /* call method 'setmember' */ + vm->top -= 3; + return btrue; + } } - return NULL; + return bfalse; } const char* be_module_name(bmodule *module) diff --git a/lib/libesp32/Berry/src/be_module.h b/lib/libesp32/Berry/src/be_module.h index 1a95df59b..4f9b869de 100644 --- a/lib/libesp32/Berry/src/be_module.h +++ b/lib/libesp32/Berry/src/be_module.h @@ -34,8 +34,8 @@ typedef struct bmodule { bmodule* be_module_new(bvm *vm); void be_module_delete(bvm *vm, bmodule *module); int be_module_load(bvm *vm, bstring *path); -bvalue* be_module_attr(bvm *vm, bmodule *module, bstring *attr); -bvalue* be_module_bind(bvm *vm, bmodule *module, bstring *attr); +int be_module_attr(bvm *vm, bmodule *module, bstring *attr, bvalue *dst); +bbool be_module_setmember(bvm *vm, bmodule *module, bstring *attr, bvalue *src); const char* be_module_name(bmodule *module); bbool be_module_setname(bmodule *module, bstring *name); diff --git a/lib/libesp32/Berry/src/be_parser.c b/lib/libesp32/Berry/src/be_parser.c index 1f38f48e2..b04b24383 100644 --- a/lib/libesp32/Berry/src/be_parser.c +++ b/lib/libesp32/Berry/src/be_parser.c @@ -461,6 +461,14 @@ static void new_var(bparser *parser, bstring *name, bexpdesc *var) push_error(parser, "too many global variables (in '%s')", str(name)); } + if (comp_is_named_gbl(parser->vm)) { + /* change to ETNGLBAL */ + bexpdesc key; + init_exp(&key, ETSTRING, 0); + key.v.s = name; + init_exp(var, ETNGLOBAL, 0); + var->v.idx = be_code_nglobal(parser->finfo, &key); + } } } diff --git a/lib/libesp32/Berry/src/be_string.c b/lib/libesp32/Berry/src/be_string.c index d9685968f..b6890a937 100644 --- a/lib/libesp32/Berry/src/be_string.c +++ b/lib/libesp32/Berry/src/be_string.c @@ -55,7 +55,6 @@ int be_eqstr(bstring *s1, bstring *s2) blstring *ls2 = cast(blstring*, s2); return ls1->llen == ls2->llen && !strcmp(lstr(ls1), lstr(ls2)); } - // TODO one is long const and the other is long string /* const short strings */ if (gc_isconst(s1) || gc_isconst(s2)) { /* one of the two string is short const */ if (cast(bcstring*, s1)->hash && cast(bcstring*, s2)->hash) { diff --git a/lib/libesp32/Berry/src/be_vm.c b/lib/libesp32/Berry/src/be_vm.c index 370a7997c..49e20517f 100644 --- a/lib/libesp32/Berry/src/be_vm.c +++ b/lib/libesp32/Berry/src/be_vm.c @@ -275,26 +275,10 @@ static void obj_method(bvm *vm, bvalue *o, bstring *attr, bvalue *dst) } } -static int obj_attribute(bvm *vm, bvalue *o, bvalue *c, bvalue *dst) +static int obj_attribute(bvm *vm, bvalue *o, bstring *attr, bvalue *dst) { - bvalue instance = *o; /* save instance to send it later to member */ - bstring *attr = var_tostr(c); binstance *obj = var_toobj(o); int type = be_instance_member(vm, obj, attr, dst); - if (type == BE_NONE) { /* if no method found, try virtual */ - /* get method 'member' */ - int type2 = be_instance_member(vm, obj, str_literal(vm, "member"), vm->top); - if (basetype(type2) == BE_FUNCTION) { - bvalue *top = vm->top; - top[1] = instance; /* move instance to argv[0] */ - top[2] = *c; /* move method name to argv[1] */ - vm->top += 3; /* prevent collection results */ - be_dofunc(vm, top, 2); /* call method 'member' */ - vm->top -= 3; - *dst = *vm->top; /* copy result to R(A) */ - type = var_type(dst); - } - } if (type == BE_NONE) { vm_error(vm, "attribute_error", "the '%s' object has no attribute '%s'", @@ -316,6 +300,19 @@ static int class_attribute(bvm *vm, bvalue *o, bvalue *c, bvalue *dst) return type; } +static int module_attribute(bvm *vm, bvalue *o, bvalue *c, bvalue *dst) +{ + bstring *attr = var_tostr(c); + bmodule *module = var_toobj(o); + int type = be_module_attr(vm, module, attr, dst); + if (type == BE_NONE) { + vm_error(vm, "attribute_error", + "module '%s' has no member '%s'", + be_module_name(module), str(attr)); + } + return type; +} + static bbool object_eqop(bvm *vm, const char *op, bbool iseq, bvalue *a, bvalue *b) { @@ -529,12 +526,8 @@ newframe: /* a new call frame */ bvalue *b = RKB(); if (var_isstr(b)) { bstring *name = var_tostr(b); - int idx = be_global_find(vm, name); - if (idx > -1) { - *be_global_var(vm, idx) = *v; - } else { - vm_error(vm, "attribute_error", "'%s' undeclared", str(name)); - } + int idx = be_global_new(vm, name); + *be_global_var(vm, idx) = *v; } else { vm_error(vm, "internal_error", "global name must be a string"); } @@ -793,35 +786,14 @@ newframe: /* a new call frame */ opcase(GETMBR): { bvalue *a = RA(), *b = RKB(), *c = RKC(); if (var_isinstance(b) && var_isstr(c)) { - obj_attribute(vm, b, c, a); + obj_attribute(vm, b, var_tostr(c), a); reg = vm->reg; } else if (var_isclass(b) && var_isstr(c)) { class_attribute(vm, b, c, a); reg = vm->reg; } else if (var_ismodule(b) && var_isstr(c)) { - bstring *attr = var_tostr(c); - bmodule *module = var_toobj(b); - bvalue *v = be_module_attr(vm, module, attr); - if (v) { - *a = *v; - } else { - bvalue *member = be_module_attr(vm, module, str_literal(vm, "member")); - var_setnil(a); - if (member && var_basetype(member) == BE_FUNCTION) { - bvalue *top = vm->top; - top[0] = *member; - top[1] = *c; /* move name to argv[0] */ - vm->top += 2; /* prevent collection results */ - be_dofunc(vm, top, 1); /* call method 'method' */ - vm->top -= 2; - *a = *vm->top; /* copy result to R(A) */ - } - if (var_basetype(a) == BE_NIL) { - vm_error(vm, "attribute_error", - "module '%s' has no attribute '%s'", - be_module_name(module), str(attr)); - } - } + module_attribute(vm, b, c, a); + reg = vm->reg; } else { attribute_error(vm, "attribute", b, c); } @@ -830,49 +802,23 @@ newframe: /* a new call frame */ opcase(GETMET): { bvalue *a = RA(), *b = RKB(), *c = RKC(); if (var_isinstance(b) && var_isstr(c)) { - bvalue self = *b; - bstring *attr = var_tostr(c); binstance *obj = var_toobj(b); - int type = obj_attribute(vm, b, c, a); + int type = obj_attribute(vm, b, var_tostr(c), a); reg = vm->reg; if (basetype(type) == BE_FUNCTION) { /* check if the object is a superinstance, if so get the lowest possible subclass */ while (obj->sub) { obj = obj->sub; } - var_setobj(&self, var_type(&self), obj); /* replace superinstance by lowest subinstance */ - a[1] = self; + var_setinstance(&a[1], obj); /* replace superinstance by lowest subinstance */ } else { vm_error(vm, "attribute_error", "class '%s' has no method '%s'", - str(be_instance_name(obj)), str(attr)); + str(be_instance_name(obj)), str(var_tostr(c))); } } else if (var_ismodule(b) && var_isstr(c)) { - bstring *attr = var_tostr(c); - bmodule *module = var_toobj(b); - bvalue *src = be_module_attr(vm, module, attr); - if (src) { - var_settype(a, NOT_METHOD); - a[1] = *src; - } else { - bvalue *member = be_module_attr(vm, module, str_literal(vm, "member")); - var_setnil(a); - if (member && var_basetype(member) == BE_FUNCTION) { - bvalue *top = vm->top; - top[0] = *member; - top[1] = *c; /* move name to argv[0] */ - vm->top += 2; /* prevent collection results */ - be_dofunc(vm, top, 1); /* call method 'method' */ - vm->top -= 2; - var_settype(a, NOT_METHOD); - a[1] = *vm->top; /* copy result to R(A) */ - } - if (var_basetype(a) == BE_NIL) { - vm_error(vm, "attribute_error", - "module '%s' has no method '%s'", - be_module_name(module), str(attr)); - } - } + module_attribute(vm, b, c, &a[1]); + var_settype(a, NOT_METHOD); } else { attribute_error(vm, "method", b, c); } @@ -903,23 +849,10 @@ newframe: /* a new call frame */ if (var_ismodule(a) && var_isstr(b)) { bmodule *obj = var_toobj(a); bstring *attr = var_tostr(b); - bvalue tmp = *c; /* stack may change */ - bvalue *v = be_module_bind(vm, obj, attr); - if (v != NULL) { - *v = tmp; - dispatch(); - } - /* if it failed, try 'setmeemner' */ - bvalue *member = be_module_attr(vm, obj, str_literal(vm, "setmember")); - if (member && var_basetype(member) == BE_FUNCTION) { - bvalue *top = vm->top; - top[0] = *member; - top[1] = *b; /* move name to argv[0] */ - top[2] = tmp; /* move value to argv[1] */ - vm->top += 3; /* prevent collection results */ - be_dofunc(vm, top, 2); /* call method 'setmember' */ - vm->top -= 3; + if (be_module_setmember(vm, obj, attr, c)) { dispatch(); + } else { + // fall through exception below } } attribute_error(vm, "writable attribute", a, b); @@ -1118,14 +1051,10 @@ newframe: /* a new call frame */ break; } case BE_MODULE: { - bmodule *f = var_toobj(var); - bvalue *member = be_module_attr(vm, f, str_literal(vm, "()")); - if (member && var_basetype(member) == BE_FUNCTION) { - *var = *member; - goto recall; /* call '()' method */ - } else { - call_error(vm, var); - } + bvalue attr; + var_setstr(&attr, str_literal(vm, "()")); + module_attribute(vm, var, &attr, var); /* exception if not found */ + goto recall; /* call '()' method */ break; } default: diff --git a/lib/libesp32/Berry/tools/grammar/berry.bytecode b/lib/libesp32/Berry/tools/grammar/berry.bytecode index 9e150635d..2c265fb5c 100755 --- a/lib/libesp32/Berry/tools/grammar/berry.bytecode +++ b/lib/libesp32/Berry/tools/grammar/berry.bytecode @@ -4,18 +4,13 @@ -- description -- -- a double dash ('--') start a line comment. --- a: n means that the size of entity 'a' is 'n' bytes. --- 'a: .n means that the size of entity 'a' is 'n' bits. --- a: --- b means that the entity 'a' is realized by the 'b' structure. --- a: --- b --- c 'b' and 'c' are arranged in a compact order (one byte alignment). +-- a: b means that the entity 'a' is realized by the 'b' structure. +-- a: b c 'b' and 'c' are arranged in a compact order (one byte alignment). -- [a] means that structure 'a' can be repeated 0 to any times. -- [a](b) means that structure 'a' can be repeated 'b' times. -- a | b means that the entity can be implemented by structure 'a' or 'b'. --- a -> b is equivalent to 'a: --- b'. +-- N a number indicates the byte count of the field (eg. 'a: 1'). +-- .N means the number of bits in the field (eg. 'a: .1'). -- only the first entity is a file entity (the root). ------------------------------------------------------------------------------- @@ -26,7 +21,7 @@ bytecode_file: -- little endian header: 8 magic_number: 3 -- 0xbecdfe (berry code file) - version: 1 -- update with file structure definition + version: 2 -- update with file structure definition integer_size: .1 float_size: .1 -- reserved space @@ -35,7 +30,7 @@ main_function -> function global_desc: builtin_count: 4 - global_count: 4 + global_count: 4 -- excluding builtins global_name -> [ string ](global_count) @@ -48,7 +43,8 @@ function: string argc: 1 -- arguments count nstack: 1 -- number of stack size by this function - extra: 2 -- extra data + varg: 1 + extra: 1 -- extra data bytecode: code_size: 4 code_array -> [ -- bytecode array @@ -62,7 +58,7 @@ function: [function](proto_count) upval_table: upval_count: 1 - upvals -> [ + upvals: [ instack: 1 index: 1 ](upval_count) @@ -82,7 +78,7 @@ class: string member_count: 4 -- number of member variables method_count: 4 -- number of method - method_table -> [ + method_table: [ string -- method name function -- method function body ](method_count) @@ -92,5 +88,5 @@ class: nil: 1 boolean: 1 -integer: 4 or 8 -float: 4 or 8 +integer: 4 | 8 +float: 4 | 8 diff --git a/tasmota/xdrv_52_3_berry_lvgl.ino b/tasmota/xdrv_52_3_berry_lvgl.ino index 2e6c302c3..30daf6fb3 100644 --- a/tasmota/xdrv_52_3_berry_lvgl.ino +++ b/tasmota/xdrv_52_3_berry_lvgl.ino @@ -809,12 +809,10 @@ extern "C" { // all good be_return(vm); - } else { - be_return_nil(vm); } } } - be_raise(vm, "attribute_error", "module 'lvgl' has no such attribute"); + be_return_nil(vm); } /*********************************************************************************************\ diff --git a/tasmota/xdrv_52_3_berry_webserver.ino b/tasmota/xdrv_52_3_berry_webserver.ino index fb98e0ce3..2faa223ba 100644 --- a/tasmota/xdrv_52_3_berry_webserver.ino +++ b/tasmota/xdrv_52_3_berry_webserver.ino @@ -57,9 +57,12 @@ extern "C" { // we did have a match, low == high be_pushint(vm, webserver_constants[constant_idx].value); be_return(vm); + } else if (strcmp(needle, "init")) { + /* don't throw an exception if the 'init' function is requested */ + be_raise(vm, "attribute_error", be_pushfstring(vm, "module 'webserver' has no such attribute '%s'", needle)); } } - be_raise(vm, "attribute_error", "module 'webserver' has no such attribute"); + be_return_nil(vm); } }