mirror of https://github.com/arendst/Tasmota.git
Berry add implicit _class parameter to static methods (#17683)
* Berry add implicit ``_class`` parameter to static methods * Handle bytecode
This commit is contained in:
parent
ef3d30c44f
commit
1acd9b867c
|
@ -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 `bytes()` now evaluates to `false` if empty
|
||||||
- Berry ``crypto.AES_CCM`` (required by Matter protocol)
|
- Berry ``crypto.AES_CCM`` (required by Matter protocol)
|
||||||
- ESP32 support for BMPxxx sensors on two I2C busses (#17643)
|
- ESP32 support for BMPxxx sensors on two I2C busses (#17643)
|
||||||
|
- Berry add implicit ``_class`` parameter to static methods
|
||||||
|
|
||||||
### Breaking Changed
|
### Breaking Changed
|
||||||
|
|
||||||
|
|
|
@ -206,7 +206,15 @@ static void save_constants(bvm *vm, void *fp, bproto *proto)
|
||||||
bvalue *v = proto->ktab, *end;
|
bvalue *v = proto->ktab, *end;
|
||||||
save_long(fp, proto->nconst); /* constants count */
|
save_long(fp, proto->nconst); /* constants count */
|
||||||
for (end = v + proto->nconst; v < end; ++v) {
|
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);
|
be_incrtop(vm);
|
||||||
if (load_proto(vm, fp, (bproto**)&var_toobj(value), -3, version)) {
|
if (load_proto(vm, fp, (bproto**)&var_toobj(value), -3, version)) {
|
||||||
/* actual method */
|
/* 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);
|
be_class_method_bind(vm, c, name, var_toobj(value), !is_method);
|
||||||
} else {
|
} else {
|
||||||
/* no proto, static member set to nil */
|
/* no proto, static member set to nil */
|
||||||
|
|
|
@ -927,4 +927,14 @@ void be_code_raise(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2)
|
||||||
free_expreg(finfo, 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
|
#endif
|
||||||
|
|
|
@ -39,5 +39,6 @@ void be_code_import(bfuncinfo *finfo, bexpdesc *m, bexpdesc *v);
|
||||||
int be_code_exblk(bfuncinfo *finfo, int depth);
|
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_catch(bfuncinfo *finfo, int base, int ecnt, int vcnt, int *jmp);
|
||||||
void be_code_raise(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2);
|
void be_code_raise(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2);
|
||||||
|
void be_code_implicit_class(bfuncinfo *finfo, bexpdesc *e, bclass *c);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,8 +43,9 @@
|
||||||
#define func_clearstatic(o) ((o)->type &= ~BE_STATIC)
|
#define func_clearstatic(o) ((o)->type &= ~BE_STATIC)
|
||||||
|
|
||||||
/* values for bproto.varg */
|
/* values for bproto.varg */
|
||||||
#define BE_VA_VARARG (1 << 0) /* function has variable number of arguments */
|
#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_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 array_count(a) (sizeof(a) / sizeof((a)[0]))
|
||||||
|
|
||||||
#define bcommon_header \
|
#define bcommon_header \
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
#define FUNC_METHOD 1
|
#define FUNC_METHOD 1
|
||||||
#define FUNC_ANONYMOUS 2
|
#define FUNC_ANONYMOUS 2
|
||||||
|
#define FUNC_STATIC 4
|
||||||
|
|
||||||
#if BE_INTGER_TYPE == 0 /* int */
|
#if BE_INTGER_TYPE == 0 /* int */
|
||||||
#define M_IMAX INT_MAX
|
#define M_IMAX INT_MAX
|
||||||
|
@ -608,7 +609,7 @@ static void func_varlist(bparser *parser)
|
||||||
/* Parse a function includind arg list and body */
|
/* Parse a function includind arg list and body */
|
||||||
/* Given name and type (function or method) */
|
/* Given name and type (function or method) */
|
||||||
/* Returns `bproto` object */
|
/* 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;
|
bfuncinfo finfo;
|
||||||
bblockinfo binfo;
|
bblockinfo binfo;
|
||||||
|
@ -621,6 +622,14 @@ static bproto* funcbody(bparser *parser, bstring *name, int type)
|
||||||
finfo.proto->varg |= BE_VA_METHOD;
|
finfo.proto->varg |= BE_VA_METHOD;
|
||||||
}
|
}
|
||||||
func_varlist(parser); /* parse arg list */
|
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` */
|
stmtlist(parser); /* parse statement without final `end` */
|
||||||
end_func(parser); /* close function context */
|
end_func(parser); /* close function context */
|
||||||
match_token(parser, KeyEnd); /* skip 'end' */
|
match_token(parser, KeyEnd); /* skip 'end' */
|
||||||
|
@ -635,7 +644,7 @@ static void anon_func(bparser *parser, bexpdesc *e)
|
||||||
bstring *name = parser_newstr(parser, "_anonymous_");
|
bstring *name = parser_newstr(parser, "_anonymous_");
|
||||||
/* 'def' ID '(' varlist ')' block 'end' */
|
/* 'def' ID '(' varlist ')' block 'end' */
|
||||||
scan_next_token(parser); /* skip 'def' */
|
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));
|
init_exp(e, ETPROTO, be_code_proto(parser->finfo, proto));
|
||||||
be_stackpop(parser->vm, 1);
|
be_stackpop(parser->vm, 1);
|
||||||
}
|
}
|
||||||
|
@ -1371,7 +1380,7 @@ static void def_stmt(bparser *parser)
|
||||||
bfuncinfo *finfo = parser->finfo;
|
bfuncinfo *finfo = parser->finfo;
|
||||||
/* 'def' ID '(' varlist ')' block 'end' */
|
/* 'def' ID '(' varlist ')' block 'end' */
|
||||||
scan_next_token(parser); /* skip 'def' */
|
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_code_closure(finfo, &e, be_code_proto(finfo, proto));
|
||||||
be_stackpop(parser->vm, 1);
|
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' */
|
scan_next_token(parser); /* skip 'def' */
|
||||||
name = func_name(parser, &e, 1);
|
name = func_name(parser, &e, 1);
|
||||||
check_class_attr(parser, c, name);
|
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_class_method_bind(parser->vm, c, proto->name, proto, is_static);
|
||||||
be_stackpop(parser->vm, 1);
|
be_stackpop(parser->vm, 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -282,8 +282,12 @@ static void m_solidify_proto_inner_class(bvm *vm, bbool str_literal, bproto *pr,
|
||||||
if (pr->nconst > 0) {
|
if (pr->nconst > 0) {
|
||||||
for (int k = 0; k < pr->nconst; k++) {
|
for (int k = 0; k < pr->nconst; k++) {
|
||||||
if (var_type(&pr->ktab[k]) == BE_CLASS) {
|
if (var_type(&pr->ktab[k]) == BE_CLASS) {
|
||||||
// output the class
|
if ((k == 0) && (pr->varg & BE_VA_STATICMETHOD)) {
|
||||||
m_solidify_subclass(vm, str_literal, (bclass*) var_toobj(&pr->ktab[k]), fout);
|
// 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue