Berry add implicit _class parameter to static methods (#17683)

* Berry add implicit ``_class`` parameter to static methods

* Handle bytecode
This commit is contained in:
s-hadinger 2023-01-11 22:59:07 +01:00 committed by GitHub
parent ef3d30c44f
commit 1acd9b867c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 52 additions and 10 deletions

View File

@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file.
- Berry `bytes()` now evaluates to `false` if empty
- Berry ``crypto.AES_CCM`` (required by Matter protocol)
- ESP32 support for BMPxxx sensors on two I2C busses (#17643)
- Berry add implicit ``_class`` parameter to static methods
### Breaking Changed

View File

@ -206,7 +206,15 @@ static void save_constants(bvm *vm, void *fp, bproto *proto)
bvalue *v = proto->ktab, *end;
save_long(fp, proto->nconst); /* constants count */
for (end = v + proto->nconst; v < end; ++v) {
save_value(vm, fp, v);
if ((v == proto->ktab) && (proto->varg & BE_VA_STATICMETHOD) && (v->type == BE_CLASS)) {
/* implicit `_class` parameter, output nil */
bvalue v_nil;
v_nil.v.i = 0;
v_nil.type = BE_NIL;
save_value(vm, fp, &v_nil);
} else {
save_value(vm, fp, v);
}
}
}
@ -428,7 +436,15 @@ static void load_class(bvm *vm, void *fp, bvalue *v, int version)
be_incrtop(vm);
if (load_proto(vm, fp, (bproto**)&var_toobj(value), -3, version)) {
/* actual method */
bbool is_method = ((bproto*)var_toobj(value))->varg & BE_VA_METHOD;
bproto *proto = (bproto*)var_toobj(value);
bbool is_method = proto->varg & BE_VA_METHOD;
if (!is_method) {
if ((proto->nconst > 0) && (proto->ktab->type == BE_NIL)) {
/* The first argument is nil so we replace with the class as implicit '_class' */
proto->ktab->type = BE_CLASS;
proto->ktab->v.p = c;
}
}
be_class_method_bind(vm, c, name, var_toobj(value), !is_method);
} else {
/* no proto, static member set to nil */

View File

@ -927,4 +927,14 @@ void be_code_raise(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2)
free_expreg(finfo, e2);
}
void be_code_implicit_class(bfuncinfo *finfo, bexpdesc *e, bclass *c)
{
bvalue k;
k.type = BE_CLASS;
k.v.p = c;
int idx = newconst(finfo, &k); /* create new constant */
e->type = ETCONST; /* new type is constant by index */
e->v.idx = setK(idx);
}
#endif

View File

@ -39,5 +39,6 @@ void be_code_import(bfuncinfo *finfo, bexpdesc *m, bexpdesc *v);
int be_code_exblk(bfuncinfo *finfo, int depth);
void be_code_catch(bfuncinfo *finfo, int base, int ecnt, int vcnt, int *jmp);
void be_code_raise(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2);
void be_code_implicit_class(bfuncinfo *finfo, bexpdesc *e, bclass *c);
#endif

View File

@ -43,8 +43,9 @@
#define func_clearstatic(o) ((o)->type &= ~BE_STATIC)
/* values for bproto.varg */
#define BE_VA_VARARG (1 << 0) /* function has variable number of arguments */
#define BE_VA_METHOD (1 << 1) /* function is a method (this is only a hint) */
#define BE_VA_VARARG (1 << 0) /* function has variable number of arguments */
#define BE_VA_METHOD (1 << 1) /* function is a method (this is only a hint) */
#define BE_VA_STATICMETHOD (1 << 2) /* the function is a static method and has the class as implicit '_class' variable */
#define array_count(a) (sizeof(a) / sizeof((a)[0]))
#define bcommon_header \

View File

@ -29,6 +29,7 @@
#define FUNC_METHOD 1
#define FUNC_ANONYMOUS 2
#define FUNC_STATIC 4
#if BE_INTGER_TYPE == 0 /* int */
#define M_IMAX INT_MAX
@ -608,7 +609,7 @@ static void func_varlist(bparser *parser)
/* Parse a function includind arg list and body */
/* Given name and type (function or method) */
/* Returns `bproto` object */
static bproto* funcbody(bparser *parser, bstring *name, int type)
static bproto* funcbody(bparser *parser, bstring *name, bclass *c, int type)
{
bfuncinfo finfo;
bblockinfo binfo;
@ -621,6 +622,14 @@ static bproto* funcbody(bparser *parser, bstring *name, int type)
finfo.proto->varg |= BE_VA_METHOD;
}
func_varlist(parser); /* parse arg list */
if ((type & FUNC_STATIC) && (c != NULL)) { /* If static method, add an implicit local variable `_class` */
bexpdesc e1, e2;
new_var(parser, parser_newstr(parser, "_class"), &e1); /* new implicit variable '_class' */
init_exp(&e2, ETCONST, 0);
be_code_implicit_class(parser->finfo, &e2, c);
be_code_setvar(parser->finfo, &e1, &e2);
finfo.proto->varg |= BE_VA_STATICMETHOD;
}
stmtlist(parser); /* parse statement without final `end` */
end_func(parser); /* close function context */
match_token(parser, KeyEnd); /* skip 'end' */
@ -635,7 +644,7 @@ static void anon_func(bparser *parser, bexpdesc *e)
bstring *name = parser_newstr(parser, "_anonymous_");
/* 'def' ID '(' varlist ')' block 'end' */
scan_next_token(parser); /* skip 'def' */
proto = funcbody(parser, name, FUNC_ANONYMOUS);
proto = funcbody(parser, name, NULL, FUNC_ANONYMOUS);
init_exp(e, ETPROTO, be_code_proto(parser->finfo, proto));
be_stackpop(parser->vm, 1);
}
@ -1371,7 +1380,7 @@ static void def_stmt(bparser *parser)
bfuncinfo *finfo = parser->finfo;
/* 'def' ID '(' varlist ')' block 'end' */
scan_next_token(parser); /* skip 'def' */
proto = funcbody(parser, func_name(parser, &e, 0), 0);
proto = funcbody(parser, func_name(parser, &e, 0), NULL, 0);
be_code_closure(finfo, &e, be_code_proto(finfo, proto));
be_stackpop(parser->vm, 1);
}
@ -1443,7 +1452,7 @@ static void classdef_stmt(bparser *parser, bclass *c, bbool is_static)
scan_next_token(parser); /* skip 'def' */
name = func_name(parser, &e, 1);
check_class_attr(parser, c, name);
proto = funcbody(parser, name, is_static ? 0 : FUNC_METHOD);
proto = funcbody(parser, name, c, is_static ? FUNC_STATIC : FUNC_METHOD);
be_class_method_bind(parser->vm, c, proto->name, proto, is_static);
be_stackpop(parser->vm, 1);
}

View File

@ -282,8 +282,12 @@ static void m_solidify_proto_inner_class(bvm *vm, bbool str_literal, bproto *pr,
if (pr->nconst > 0) {
for (int k = 0; k < pr->nconst; k++) {
if (var_type(&pr->ktab[k]) == BE_CLASS) {
// output the class
m_solidify_subclass(vm, str_literal, (bclass*) var_toobj(&pr->ktab[k]), fout);
if ((k == 0) && (pr->varg & BE_VA_STATICMETHOD)) {
// it is the implicit '_class' variable from a static method, don't dump the class
} else {
// output the class
m_solidify_subclass(vm, str_literal, (bclass*) var_toobj(&pr->ktab[k]), fout);
}
}
}
}