mirror of https://github.com/arendst/Tasmota.git
Berry upgrade to latest changes
This commit is contained in:
parent
228593c092
commit
5ab0081f47
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue