Berry upgrade to latest changes

This commit is contained in:
Stephan Hadinger 2021-08-24 22:44:33 +02:00
parent 228593c092
commit 5ab0081f47
13 changed files with 197 additions and 187 deletions

View File

@ -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) BERRY_API bbool be_setmember(bvm *vm, int index, const char *k)
{ {
int res = BE_NIL;
bvalue *o = be_indexof(vm, index); bvalue *o = be_indexof(vm, index);
bvalue *v = be_indexof(vm, -1);
if (var_isinstance(o)) { if (var_isinstance(o)) {
bstring *key = be_newstr(vm, k); bstring *key = be_newstr(vm, k);
bvalue *v = be_indexof(vm, -1);
binstance *obj = var_toobj(o); 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)) { } else if (var_ismodule(o)) {
bstring *key = be_newstr(vm, k); bstring *key = be_newstr(vm, k);
bmodule *mod = var_toobj(o); bmodule *mod = var_toobj(o);
bvalue *v = be_module_bind(vm, mod, key); return be_module_setmember(vm, mod, key, v);
if (v) {
*v = *be_indexof(vm, -1);
return btrue;
}
} }
return res != BE_NIL; return bfalse;
} }
BERRY_API bbool be_copy(bvm *vm, int index) 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)) { if (var_isinstance(o)) {
binstance *obj = var_toobj(o); binstance *obj = var_toobj(o);
type = be_instance_member(vm, obj, be_newstr(vm, k), top); type = be_instance_member(vm, obj, be_newstr(vm, k), top);
if (type == BE_NONE) { } else if (var_isclass(o) && !onlyins) {
type = BE_NIL; bclass *cl = var_toobj(o);
} type = be_class_member(vm, cl, be_newstr(vm, k), top);
} else if (var_ismodule(o) && !onlyins) { } else if (var_ismodule(o) && !onlyins) {
bmodule *module = var_toobj(o); bmodule *module = var_toobj(o);
bvalue *v = be_module_attr(vm, module, be_newstr(vm, k)); type = be_module_attr(vm, module, be_newstr(vm, k), top);
if (v != NULL) { }
*top = *v; if (type == BE_NONE) {
type = v->type; type = BE_NIL;
}
} }
return type; return type;
} }

View File

@ -23,7 +23,7 @@
#define MAGIC_NUMBER1 0xBE #define MAGIC_NUMBER1 0xBE
#define MAGIC_NUMBER2 0xCD #define MAGIC_NUMBER2 0xCD
#define MAGIC_NUMBER3 0xFE #define MAGIC_NUMBER3 0xFE
#define BYTECODE_VERSION 1 #define BYTECODE_VERSION 2
#define USE_64BIT_INT (BE_INTGER_TYPE == 2 \ #define USE_64BIT_INT (BE_INTGER_TYPE == 2 \
|| BE_INTGER_TYPE == 1 && LONG_MAX == 9223372036854775807L) || 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; binstruction *code = proto->code, *end;
save_long(fp, (uint32_t)proto->codesize); save_long(fp, (uint32_t)proto->codesize);
for (end = code + proto->codesize; code < end; ++code) { for (end = code + proto->codesize; code < end; ++code) {
save_long(fp, (uint32_t)*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_string(fp, proto->source); /* source */
save_byte(fp, proto->argc); /* argc */ save_byte(fp, proto->argc); /* argc */
save_byte(fp, proto->nstack); /* nstack */ 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_constants(vm, fp, proto); /* constant */
save_proto_table(vm, fp, proto); /* proto table */ save_proto_table(vm, fp, proto); /* proto table */
save_upvals(fp, proto); /* upvals description 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) static void save_global_info(bvm *vm, void *fp)
{ {
save_long(fp, be_builtin_count(vm)); save_long(fp, be_builtin_count(vm));
save_long(fp, be_global_count(vm)); if (comp_is_named_gbl(vm)) {
save_globals(vm, fp); /* 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) 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 */ #endif /* BE_USE_BYTECODE_SAVER */
#if BE_USE_BYTECODE_LOADER #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) static uint8_t load_byte(void *fp)
{ {
@ -313,9 +326,13 @@ static int load_head(void *fp)
res = buffer[0] == MAGIC_NUMBER1 && res = buffer[0] == MAGIC_NUMBER1 &&
buffer[1] == MAGIC_NUMBER2 && buffer[1] == MAGIC_NUMBER2 &&
buffer[2] == MAGIC_NUMBER3 && buffer[2] == MAGIC_NUMBER3 &&
buffer[3] == BYTECODE_VERSION && buffer[3] <= BYTECODE_VERSION &&
buffer[4] == vm_sizeinfo(); buffer[4] == vm_sizeinfo();
return res; if (res) {
return buffer[3];
} else {
return 0;
}
} }
bbool be_bytecode_check(const char *path) bbool be_bytecode_check(const char *path)
@ -385,7 +402,7 @@ static bstring* cache_string(bvm *vm, void *fp)
return str; 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; int nvar, count;
bclass *c = be_newclass(vm, NULL, NULL); bclass *c = be_newclass(vm, NULL, NULL);
@ -399,7 +416,7 @@ static void load_class(bvm *vm, void *fp, bvalue *v)
value = vm->top; value = vm->top;
var_setproto(value, NULL); var_setproto(value, NULL);
be_incrtop(vm); 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_method_bind(vm, c, name, var_toobj(value));
be_stackpop(vm, 2); /* pop the cached string and proto */ 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)) { switch (load_byte(fp)) {
case BE_INT: var_setint(v, load_int(fp)); break; case BE_INT: var_setint(v, load_int(fp)); break;
case BE_REAL: var_setreal(v, load_real(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_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; 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 */ int size = (int)load_long(fp); /* nconst */
if (size) { if (size) {
@ -458,12 +475,12 @@ static void load_constant(bvm *vm, void *fp, bproto *proto)
proto->ktab = v; proto->ktab = v;
proto->nconst = size; proto->nconst = size;
for (end = v + size; v < end; ++v) { 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 */ int size = (int)load_long(fp); /* proto count */
if (size) { if (size) {
@ -472,7 +489,7 @@ static void load_proto_table(bvm *vm, void *fp, bproto *proto)
proto->ptab = p; proto->ptab = p;
proto->nproto = size; proto->nproto = size;
while (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 = be_newproto(vm);
(*proto)->name = load_string(vm, fp); (*proto)->name = load_string(vm, fp);
(*proto)->source = load_string(vm, fp); (*proto)->source = load_string(vm, fp);
(*proto)->argc = load_byte(fp); (*proto)->argc = load_byte(fp);
(*proto)->nstack = 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_bytecode(vm, fp, *proto, info);
load_constant(vm, fp, *proto); load_constant(vm, fp, *proto, version);
load_proto_table(vm, fp, *proto); load_proto_table(vm, fp, *proto, version);
load_upvals(vm, fp, *proto); load_upvals(vm, fp, *proto);
} }
@ -510,7 +531,7 @@ void load_global_info(bvm *vm, void *fp)
int i; int i;
int bcnt = (int)load_long(fp); /* builtin count */ int bcnt = (int)load_long(fp); /* builtin count */
int gcnt = (int)load_long(fp); /* global 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, bytecode_error(vm, be_pushfstring(vm,
"inconsistent number of builtin objects.")); "inconsistent number of builtin objects."));
} }
@ -530,15 +551,18 @@ bclosure* be_bytecode_load(bvm *vm, const char *filename)
if (fp == NULL) { if (fp == NULL) {
bytecode_error(vm, be_pushfstring(vm, bytecode_error(vm, be_pushfstring(vm,
"can not open file '%s'.", filename)); "can not open file '%s'.", filename));
} else if (load_head(fp)) { } else {
bclosure *cl = be_newclosure(vm, 0); int version = load_head(fp);
var_setclosure(vm->top, cl); if (version) {
be_stackpush(vm); bclosure *cl = be_newclosure(vm, 0);
load_global_info(vm, fp); var_setclosure(vm->top, cl);
load_proto(vm, fp, &cl->proto, -1); be_stackpush(vm);
be_stackpop(vm, 2); /* pop the closure and list */ load_global_info(vm, fp);
be_fclose(fp); load_proto(vm, fp, &cl->proto, -1, version);
return cl; be_stackpop(vm, 2); /* pop the closure and list */
be_fclose(fp);
return cl;
}
} }
bytecode_error(vm, be_pushfstring(vm, bytecode_error(vm, be_pushfstring(vm,
"invalid bytecode file '%s'.", filename)); "invalid bytecode file '%s'.", filename));

View File

@ -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 */ /* Input: none of `obj`, `name` and `dst` may not be NULL */
/* Returns the type of the member or BE_NONE if member not found */ /* Returns the type of the member or BE_NONE if member not found */
/* TODO need to support synthetic members */ /* 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; int type;
be_assert(name != NULL); be_assert(name != NULL);
obj = instance_member(vm, obj, name, dst); binstance * obj = instance_member(vm, instance, name, dst);
type = var_type(dst); type = var_type(dst);
if (obj && type == MT_VARIABLE) { if (obj && type == MT_VARIABLE) {
*dst = obj->members[dst->v.i]; *dst = obj->members[dst->v.i];
} }
if (obj) { if (obj) {
return type; return type;
} else { } else { /* if no method found, try virtual */
return BE_NONE; /* 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) int be_class_member(bvm *vm, bclass *obj, bstring *name, bvalue *dst)

View File

@ -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 */ /* 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) static int findconst(bfuncinfo *finfo, bexpdesc *e)
{ {
int i, count = be_vector_count(&finfo->kvec); 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 * so only search the constant table for the
* previous value. * previous value.
**/ **/
count = count < 50 ? count : 50; count = count < 100 ? count : 100;
for (i = 0; i < count; ++i) { for (i = 0; i < count; ++i) {
bvalue *k = be_vector_at(&finfo->kvec, i); bvalue *k = be_vector_at(&finfo->kvec, i);
switch (e->type) { 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) 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); 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); 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 */ src = newconst(finfo, &var); /* allocate a new constant and return kreg */
if (dst->type == ETLOCAL) { /* if target is a local variable, just assign */ if (dst->type == ETLOCAL) { /* if target is a local variable, just assign */
codeABx(finfo, OP_LDCONST, dst->v.idx, src); 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_LDCONST, finfo->freereg, src);
codeABx(finfo, OP_SETGBL, finfo->freereg, dst->v.idx); 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 */ codeABx(finfo, OP_CLASS, 0, src); /* emit CLASS opcode to register class */
} }

View File

@ -62,7 +62,7 @@ void be_print_inst(binstruction ins, int pc)
case OP_OR: case OP_XOR: case OP_SHL: case OP_SHR: 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), 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_RKB(ins) & KR_MASK,
isKB(ins) ? 'K' : 'R', IGET_RKC(ins) & KR_MASK); isKC(ins) ? 'K' : 'R', IGET_RKC(ins) & KR_MASK);
break; break;
case OP_GETNGBL: case OP_SETNGBL: case OP_GETNGBL: case OP_SETNGBL:
logbuf("%s\tR%d\t%c%d", opc2str(op), IGET_RA(ins), 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: case OP_RAISE:
logbuf("%s\t%d\t%c%d\t%c%d", opc2str(op), IGET_RA(ins), 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_RKB(ins) & KR_MASK,
isKB(ins) ? 'K' : 'R', IGET_RKC(ins) & KR_MASK); isKC(ins) ? 'K' : 'R', IGET_RKC(ins) & KR_MASK);
break; break;
case OP_EXBLK: case OP_EXBLK:
if (IGET_RA(ins)) { if (IGET_RA(ins)) {

View File

@ -299,22 +299,58 @@ void be_module_delete(bvm *vm, bmodule *module)
be_free(vm, module, sizeof(bmodule)); 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; bmap *attrs = module->table;
if (!gc_isconst(attrs)) { if (!gc_isconst(attrs)) {
bvalue *v = be_map_findstr(vm, attrs, attr); bvalue *v = be_map_findstr(vm, attrs, attr);
if (v == NULL) { if (v == NULL) {
v = be_map_insertstr(vm, attrs, attr, 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) const char* be_module_name(bmodule *module)

View File

@ -34,8 +34,8 @@ typedef struct bmodule {
bmodule* be_module_new(bvm *vm); bmodule* be_module_new(bvm *vm);
void be_module_delete(bvm *vm, bmodule *module); void be_module_delete(bvm *vm, bmodule *module);
int be_module_load(bvm *vm, bstring *path); int be_module_load(bvm *vm, bstring *path);
bvalue* be_module_attr(bvm *vm, bmodule *module, bstring *attr); int be_module_attr(bvm *vm, bmodule *module, bstring *attr, bvalue *dst);
bvalue* be_module_bind(bvm *vm, bmodule *module, bstring *attr); bbool be_module_setmember(bvm *vm, bmodule *module, bstring *attr, bvalue *src);
const char* be_module_name(bmodule *module); const char* be_module_name(bmodule *module);
bbool be_module_setname(bmodule *module, bstring *name); bbool be_module_setname(bmodule *module, bstring *name);

View File

@ -461,6 +461,14 @@ static void new_var(bparser *parser, bstring *name, bexpdesc *var)
push_error(parser, push_error(parser,
"too many global variables (in '%s')", str(name)); "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);
}
} }
} }

View File

@ -55,7 +55,6 @@ int be_eqstr(bstring *s1, bstring *s2)
blstring *ls2 = cast(blstring*, s2); blstring *ls2 = cast(blstring*, s2);
return ls1->llen == ls2->llen && !strcmp(lstr(ls1), lstr(ls2)); return ls1->llen == ls2->llen && !strcmp(lstr(ls1), lstr(ls2));
} }
// TODO one is long const and the other is long string
/* const short strings */ /* const short strings */
if (gc_isconst(s1) || gc_isconst(s2)) { /* one of the two string is short const */ if (gc_isconst(s1) || gc_isconst(s2)) { /* one of the two string is short const */
if (cast(bcstring*, s1)->hash && cast(bcstring*, s2)->hash) { if (cast(bcstring*, s1)->hash && cast(bcstring*, s2)->hash) {

View File

@ -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); binstance *obj = var_toobj(o);
int type = be_instance_member(vm, obj, attr, dst); 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) { if (type == BE_NONE) {
vm_error(vm, "attribute_error", vm_error(vm, "attribute_error",
"the '%s' object has no attribute '%s'", "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; 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, static bbool object_eqop(bvm *vm,
const char *op, bbool iseq, bvalue *a, bvalue *b) const char *op, bbool iseq, bvalue *a, bvalue *b)
{ {
@ -529,12 +526,8 @@ newframe: /* a new call frame */
bvalue *b = RKB(); bvalue *b = RKB();
if (var_isstr(b)) { if (var_isstr(b)) {
bstring *name = var_tostr(b); bstring *name = var_tostr(b);
int idx = be_global_find(vm, name); int idx = be_global_new(vm, name);
if (idx > -1) { *be_global_var(vm, idx) = *v;
*be_global_var(vm, idx) = *v;
} else {
vm_error(vm, "attribute_error", "'%s' undeclared", str(name));
}
} else { } else {
vm_error(vm, "internal_error", "global name must be a string"); vm_error(vm, "internal_error", "global name must be a string");
} }
@ -793,35 +786,14 @@ newframe: /* a new call frame */
opcase(GETMBR): { opcase(GETMBR): {
bvalue *a = RA(), *b = RKB(), *c = RKC(); bvalue *a = RA(), *b = RKB(), *c = RKC();
if (var_isinstance(b) && var_isstr(c)) { if (var_isinstance(b) && var_isstr(c)) {
obj_attribute(vm, b, c, a); obj_attribute(vm, b, var_tostr(c), a);
reg = vm->reg; reg = vm->reg;
} else if (var_isclass(b) && var_isstr(c)) { } else if (var_isclass(b) && var_isstr(c)) {
class_attribute(vm, b, c, a); class_attribute(vm, b, c, a);
reg = vm->reg; reg = vm->reg;
} else if (var_ismodule(b) && var_isstr(c)) { } else if (var_ismodule(b) && var_isstr(c)) {
bstring *attr = var_tostr(c); module_attribute(vm, b, c, a);
bmodule *module = var_toobj(b); reg = vm->reg;
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));
}
}
} else { } else {
attribute_error(vm, "attribute", b, c); attribute_error(vm, "attribute", b, c);
} }
@ -830,49 +802,23 @@ newframe: /* a new call frame */
opcase(GETMET): { opcase(GETMET): {
bvalue *a = RA(), *b = RKB(), *c = RKC(); bvalue *a = RA(), *b = RKB(), *c = RKC();
if (var_isinstance(b) && var_isstr(c)) { if (var_isinstance(b) && var_isstr(c)) {
bvalue self = *b;
bstring *attr = var_tostr(c);
binstance *obj = var_toobj(b); 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; reg = vm->reg;
if (basetype(type) == BE_FUNCTION) { if (basetype(type) == BE_FUNCTION) {
/* check if the object is a superinstance, if so get the lowest possible subclass */ /* check if the object is a superinstance, if so get the lowest possible subclass */
while (obj->sub) { while (obj->sub) {
obj = obj->sub; obj = obj->sub;
} }
var_setobj(&self, var_type(&self), obj); /* replace superinstance by lowest subinstance */ var_setinstance(&a[1], obj); /* replace superinstance by lowest subinstance */
a[1] = self;
} else { } else {
vm_error(vm, "attribute_error", vm_error(vm, "attribute_error",
"class '%s' has no method '%s'", "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)) { } else if (var_ismodule(b) && var_isstr(c)) {
bstring *attr = var_tostr(c); module_attribute(vm, b, c, &a[1]);
bmodule *module = var_toobj(b); var_settype(a, NOT_METHOD);
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));
}
}
} else { } else {
attribute_error(vm, "method", b, c); attribute_error(vm, "method", b, c);
} }
@ -903,23 +849,10 @@ newframe: /* a new call frame */
if (var_ismodule(a) && var_isstr(b)) { if (var_ismodule(a) && var_isstr(b)) {
bmodule *obj = var_toobj(a); bmodule *obj = var_toobj(a);
bstring *attr = var_tostr(b); bstring *attr = var_tostr(b);
bvalue tmp = *c; /* stack may change */ if (be_module_setmember(vm, obj, attr, c)) {
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;
dispatch(); dispatch();
} else {
// fall through exception below
} }
} }
attribute_error(vm, "writable attribute", a, b); attribute_error(vm, "writable attribute", a, b);
@ -1118,14 +1051,10 @@ newframe: /* a new call frame */
break; break;
} }
case BE_MODULE: { case BE_MODULE: {
bmodule *f = var_toobj(var); bvalue attr;
bvalue *member = be_module_attr(vm, f, str_literal(vm, "()")); var_setstr(&attr, str_literal(vm, "()"));
if (member && var_basetype(member) == BE_FUNCTION) { module_attribute(vm, var, &attr, var); /* exception if not found */
*var = *member; goto recall; /* call '()' method */
goto recall; /* call '()' method */
} else {
call_error(vm, var);
}
break; break;
} }
default: default:

View File

@ -4,18 +4,13 @@
-- description -- description
-- --
-- a double dash ('--') start a line comment. -- a double dash ('--') start a line comment.
-- a: n means that the size of entity 'a' is 'n' bytes. -- a: b means that the entity 'a' is realized by the 'b' structure.
-- 'a: .n means that the size of entity 'a' is 'n' bits. -- 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] 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 structure 'a' can be repeated 'b' times.
-- a | b means that the entity can be implemented by structure 'a' or 'b'. -- a | b means that the entity can be implemented by structure 'a' or 'b'.
-- a -> b is equivalent to 'a: -- N a number indicates the byte count of the field (eg. 'a: 1').
-- b'. -- .N means the number of bits in the field (eg. 'a: .1').
-- only the first entity is a file entity (the root). -- only the first entity is a file entity (the root).
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -26,7 +21,7 @@ bytecode_file: -- little endian
header: 8 header: 8
magic_number: 3 -- 0xbecdfe (berry code file) magic_number: 3 -- 0xbecdfe (berry code file)
version: 1 -- update with file structure definition version: 2 -- update with file structure definition
integer_size: .1 integer_size: .1
float_size: .1 float_size: .1
-- reserved space -- reserved space
@ -35,7 +30,7 @@ main_function -> function
global_desc: global_desc:
builtin_count: 4 builtin_count: 4
global_count: 4 global_count: 4 -- excluding builtins
global_name -> [ global_name -> [
string string
](global_count) ](global_count)
@ -48,7 +43,8 @@ function:
string string
argc: 1 -- arguments count argc: 1 -- arguments count
nstack: 1 -- number of stack size by this function nstack: 1 -- number of stack size by this function
extra: 2 -- extra data varg: 1
extra: 1 -- extra data
bytecode: bytecode:
code_size: 4 code_size: 4
code_array -> [ -- bytecode array code_array -> [ -- bytecode array
@ -62,7 +58,7 @@ function:
[function](proto_count) [function](proto_count)
upval_table: upval_table:
upval_count: 1 upval_count: 1
upvals -> [ upvals: [
instack: 1 instack: 1
index: 1 index: 1
](upval_count) ](upval_count)
@ -82,7 +78,7 @@ class:
string string
member_count: 4 -- number of member variables member_count: 4 -- number of member variables
method_count: 4 -- number of method method_count: 4 -- number of method
method_table -> [ method_table: [
string -- method name string -- method name
function -- method function body function -- method function body
](method_count) ](method_count)
@ -92,5 +88,5 @@ class:
nil: 1 nil: 1
boolean: 1 boolean: 1
integer: 4 or 8 integer: 4 | 8
float: 4 or 8 float: 4 | 8

View File

@ -809,12 +809,10 @@ extern "C" {
// all good // all good
be_return(vm); be_return(vm);
} else {
be_return_nil(vm);
} }
} }
} }
be_raise(vm, "attribute_error", "module 'lvgl' has no such attribute"); be_return_nil(vm);
} }
/*********************************************************************************************\ /*********************************************************************************************\

View File

@ -57,9 +57,12 @@ extern "C" {
// we did have a match, low == high // we did have a match, low == high
be_pushint(vm, webserver_constants[constant_idx].value); be_pushint(vm, webserver_constants[constant_idx].value);
be_return(vm); 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);
} }
} }