From 1acd9b867c6656ee12733dff52a44f268e020a95 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Wed, 11 Jan 2023 22:59:07 +0100 Subject: [PATCH] Berry add implicit _class parameter to static methods (#17683) * Berry add implicit ``_class`` parameter to static methods * Handle bytecode --- CHANGELOG.md | 1 + lib/libesp32/berry/src/be_bytecode.c | 20 ++++++++++++++++++-- lib/libesp32/berry/src/be_code.c | 10 ++++++++++ lib/libesp32/berry/src/be_code.h | 1 + lib/libesp32/berry/src/be_object.h | 5 +++-- lib/libesp32/berry/src/be_parser.c | 17 +++++++++++++---- lib/libesp32/berry/src/be_solidifylib.c | 8 ++++++-- 7 files changed, 52 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c27879a10..ba3ec5ac0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/lib/libesp32/berry/src/be_bytecode.c b/lib/libesp32/berry/src/be_bytecode.c index 14599441d..a87b28fb8 100644 --- a/lib/libesp32/berry/src/be_bytecode.c +++ b/lib/libesp32/berry/src/be_bytecode.c @@ -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 */ diff --git a/lib/libesp32/berry/src/be_code.c b/lib/libesp32/berry/src/be_code.c index 40e067265..1a890390e 100644 --- a/lib/libesp32/berry/src/be_code.c +++ b/lib/libesp32/berry/src/be_code.c @@ -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 diff --git a/lib/libesp32/berry/src/be_code.h b/lib/libesp32/berry/src/be_code.h index 54d0c317c..cc45d4e06 100644 --- a/lib/libesp32/berry/src/be_code.h +++ b/lib/libesp32/berry/src/be_code.h @@ -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 diff --git a/lib/libesp32/berry/src/be_object.h b/lib/libesp32/berry/src/be_object.h index dbde8317f..ac6e940bf 100644 --- a/lib/libesp32/berry/src/be_object.h +++ b/lib/libesp32/berry/src/be_object.h @@ -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 \ diff --git a/lib/libesp32/berry/src/be_parser.c b/lib/libesp32/berry/src/be_parser.c index 08b64899c..b3988fa60 100644 --- a/lib/libesp32/berry/src/be_parser.c +++ b/lib/libesp32/berry/src/be_parser.c @@ -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); } diff --git a/lib/libesp32/berry/src/be_solidifylib.c b/lib/libesp32/berry/src/be_solidifylib.c index 4cec95f99..9a9f45fe3 100644 --- a/lib/libesp32/berry/src/be_solidifylib.c +++ b/lib/libesp32/berry/src/be_solidifylib.c @@ -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); + } } } }