mirror of https://github.com/arendst/Tasmota.git
Berry Walrus operator ':=' (#18963)
This commit is contained in:
parent
99a0f2add1
commit
30a65edd7a
|
@ -15,6 +15,7 @@ All notable changes to this project will be documented in this file.
|
|||
- Berry add global function `format` as a simpler syntax to `string.format`
|
||||
- Berry added f-strings as an alternative to string formatting
|
||||
- Matter display the remote Device Name instead of IP address
|
||||
- Berry Walrus operator ':='
|
||||
|
||||
### Breaking Changed
|
||||
|
||||
|
|
|
@ -670,14 +670,15 @@ static void setsfxvar(bfuncinfo *finfo, bopcode op, bexpdesc *e1, int src)
|
|||
|
||||
/* Assign expr e2 to e1 */
|
||||
/* e1 must be in a register and have a valid idx */
|
||||
/* if `keep_reg` is true, do not release registre */
|
||||
/* return 1 if assignment was possible, 0 if type is not compatible */
|
||||
int be_code_setvar(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2)
|
||||
int be_code_setvar(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2, bbool keep_reg)
|
||||
{
|
||||
int src = exp2reg(finfo, e2,
|
||||
e1->type == ETLOCAL ? e1->v.idx : -1); /* Convert e2 to kreg */
|
||||
/* If e1 is a local variable, use the register */
|
||||
|
||||
if (e1->type != ETLOCAL || e1->v.idx != src) {
|
||||
if (!keep_reg && (e1->type != ETLOCAL || e1->v.idx != src)) {
|
||||
free_expreg(finfo, e2); /* free source (checks only ETREG) */ /* TODO e2 is at top */
|
||||
}
|
||||
switch (e1->type) {
|
||||
|
@ -887,7 +888,7 @@ void be_code_import(bfuncinfo *finfo, bexpdesc *m, bexpdesc *v)
|
|||
codeABC(finfo, OP_IMPORT, dst, src, 0);
|
||||
m->type = ETREG;
|
||||
m->v.idx = dst;
|
||||
be_code_setvar(finfo, v, m);
|
||||
be_code_setvar(finfo, v, m, bfalse);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ int be_code_allocregs(bfuncinfo *finfo, int count);
|
|||
void be_code_prebinop(bfuncinfo *finfo, int op, bexpdesc *e);
|
||||
void be_code_binop(bfuncinfo *finfo, int op, bexpdesc *e1, bexpdesc *e2, int dst);
|
||||
int be_code_unop(bfuncinfo *finfo, int op, bexpdesc *e);
|
||||
int be_code_setvar(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2);
|
||||
int be_code_setvar(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2, bbool keep_reg);
|
||||
int be_code_nextreg(bfuncinfo *finfo, bexpdesc *e);
|
||||
int be_code_jump(bfuncinfo *finfo);
|
||||
void be_code_jumpto(bfuncinfo *finfo, int dst);
|
||||
|
|
|
@ -266,7 +266,9 @@ static void hook_callnative(bvm *vm, int mask)
|
|||
be_stack_require(vm, BE_STACK_FREE_MIN + 2);
|
||||
info.type = mask;
|
||||
info.line = cf->lineinfo->linenumber;
|
||||
#if BE_DEBUG_SOURCE_FILE
|
||||
info.source = str(cl->proto->source);
|
||||
#endif
|
||||
info.func_name = str(cl->proto->name);
|
||||
info.data = hb->data;
|
||||
hb->hook(vm, &info);
|
||||
|
|
|
@ -752,7 +752,9 @@ static btokentype lexer_next(blexer *lexer)
|
|||
case '}': next(lexer); return OptRBR;
|
||||
case ',': next(lexer); return OptComma;
|
||||
case ';': next(lexer); return OptSemic;
|
||||
case ':': next(lexer); return OptColon;
|
||||
case ':':
|
||||
next(lexer);
|
||||
return check_next(lexer, '=') ? OptWalrus : OptColon;
|
||||
case '?': next(lexer); return OptQuestion;
|
||||
case '^': return scan_assign(lexer, OptXorAssign, OptBitXor);
|
||||
case '~': next(lexer); return OptFlip;
|
||||
|
|
|
@ -89,7 +89,9 @@ typedef enum {
|
|||
KeyTry, /* keyword try */
|
||||
KeyExcept, /* keyword except */
|
||||
KeyRaise, /* keyword raise */
|
||||
KeyStatic /* keyword static */
|
||||
KeyStatic, /* keyword static */
|
||||
/* Walrus operator */
|
||||
OptWalrus, /* operator, := */
|
||||
} btokentype;
|
||||
|
||||
struct blexerreader {
|
||||
|
|
|
@ -126,9 +126,9 @@ static char* fixpath(bvm *vm, bstring *path, size_t *size)
|
|||
{
|
||||
char *buffer;
|
||||
const char *split, *base;
|
||||
#if BE_DEBUG_SOURCE_FILE
|
||||
bvalue *func = vm->cf->func;
|
||||
bclosure *cl = var_toobj(func);
|
||||
#if BE_DEBUG_SOURCE_FILE
|
||||
if (var_isclosure(func)) {
|
||||
base = str(cl->proto->source); /* get the source file path */
|
||||
} else {
|
||||
|
|
|
@ -80,6 +80,7 @@ typedef struct {
|
|||
static void stmtlist(bparser *parser);
|
||||
static void block(bparser *parser, int type);
|
||||
static void expr(bparser *parser, bexpdesc *e);
|
||||
static void walrus_expr(bparser *parser, bexpdesc *e);
|
||||
static void sub_expr(bparser *parser, bexpdesc *e, int prio);
|
||||
|
||||
static const bbyte binary_op_prio_tab[] = {
|
||||
|
@ -224,17 +225,17 @@ static void end_block(bparser *parser)
|
|||
end_block_ex(parser, -1);
|
||||
}
|
||||
|
||||
#if BE_DEBUG_SOURCE_FILE
|
||||
/* Return the name of the source for this parser, could be `string`,
|
||||
`stdin` or the name of the current function */
|
||||
static bstring* parser_source(bparser *parser)
|
||||
{
|
||||
#if BE_DEBUG_SOURCE_FILE
|
||||
if (parser->finfo) {
|
||||
return parser->finfo->proto->source;
|
||||
}
|
||||
#endif
|
||||
return be_newstr(parser->vm, parser->lexer.fname);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Initialize a function block and create a new `bprotoˋ */
|
||||
static void begin_func(bparser *parser, bfuncinfo *finfo, bblockinfo *binfo)
|
||||
|
@ -368,7 +369,7 @@ static btokentype get_unary_op(bparser *parser)
|
|||
static btokentype get_assign_op(bparser *parser)
|
||||
{
|
||||
btokentype op = next_type(parser);
|
||||
if (op >= OptAssign && op <= OptRsfAssign) {
|
||||
if ((op >= OptAssign && op <= OptRsfAssign) || op == OptWalrus) {
|
||||
return op;
|
||||
}
|
||||
return OP_NOT_ASSIGN;
|
||||
|
@ -631,7 +632,7 @@ static bproto* funcbody(bparser *parser, bstring *name, bclass *c, int type)
|
|||
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);
|
||||
be_code_setvar(parser->finfo, &e1, &e2, bfalse);
|
||||
finfo.proto->varg |= BE_VA_STATICMETHOD;
|
||||
}
|
||||
stmtlist(parser); /* parse statement without final `end` */
|
||||
|
@ -735,7 +736,7 @@ static void map_nextmember(bparser *parser, bexpdesc *l)
|
|||
match_token(parser, OptColon); /* ':' */
|
||||
expr(parser, &e); /* value in `e` */
|
||||
check_var(parser, &e); /* check if value is correct */
|
||||
be_code_setvar(finfo, &v, &e); /* set suffi INDEX value to e */
|
||||
be_code_setvar(finfo, &v, &e, bfalse); /* set suffi INDEX value to e */
|
||||
}
|
||||
|
||||
static void list_expr(bparser *parser, bexpdesc *e)
|
||||
|
@ -892,8 +893,7 @@ static void primary_expr(bparser *parser, bexpdesc *e)
|
|||
switch (next_type(parser)) {
|
||||
case OptLBK: /* '(' expr ')' */
|
||||
scan_next_token(parser); /* skip '(' */
|
||||
/* sub_expr() is more efficient because there is no need to initialize e. */
|
||||
sub_expr(parser, e, ASSIGN_OP_PRIO);
|
||||
expr(parser, e);
|
||||
check_var(parser, e);
|
||||
match_token(parser, OptRBK); /* skip ')' */
|
||||
break;
|
||||
|
@ -1040,7 +1040,7 @@ static void assign_expr(bparser *parser)
|
|||
if (check_newvar(parser, &e)) { /* new variable */
|
||||
new_var(parser, e.v.s, &e);
|
||||
}
|
||||
if (be_code_setvar(parser->finfo, &e, &e1)) {
|
||||
if (be_code_setvar(parser->finfo, &e, &e1, bfalse)) {
|
||||
parser->lexer.linenumber = line;
|
||||
parser_error(parser,
|
||||
"try to assign constant expressions.");
|
||||
|
@ -1125,13 +1125,33 @@ static void sub_expr(bparser *parser, bexpdesc *e, int prio)
|
|||
}
|
||||
}
|
||||
|
||||
static void walrus_expr(bparser *parser, bexpdesc *e)
|
||||
{
|
||||
int line = parser->lexer.linenumber;
|
||||
sub_expr(parser, e, ASSIGN_OP_PRIO); /* left expression */
|
||||
btokentype op = next_type(parser);
|
||||
if (op == OptWalrus) {
|
||||
bexpdesc e1 = *e; /* copy var to e1, e will get the result of expression */
|
||||
scan_next_token(parser); /* skip ':=' */
|
||||
expr(parser, e);
|
||||
if (check_newvar(parser, &e1)) { /* new variable */
|
||||
new_var(parser, e1.v.s, e);
|
||||
}
|
||||
if (be_code_setvar(parser->finfo, &e1, e, btrue /* do not release register */ )) {
|
||||
parser->lexer.linenumber = line;
|
||||
parser_error(parser,
|
||||
"try to assign constant expressions.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse new expression and return value in `e` (overwritten) */
|
||||
/* Initializes an empty expdes and parse subexpr */
|
||||
/* Always allocates a new temp register at top of freereg */
|
||||
static void expr(bparser *parser, bexpdesc *e)
|
||||
{
|
||||
init_exp(e, ETVOID, 0);
|
||||
sub_expr(parser, e, ASSIGN_OP_PRIO);
|
||||
walrus_expr(parser, e);
|
||||
}
|
||||
|
||||
static void expr_stmt(bparser *parser)
|
||||
|
@ -1250,7 +1270,7 @@ static void for_iter(bparser *parser, bstring *var, bexpdesc *it)
|
|||
finfo->binfo->beginpc = finfo->pc;
|
||||
/* itvar = .it() */
|
||||
init_exp(&e, ETLOCAL, new_localvar(parser, var)); /* new itvar */
|
||||
be_code_setvar(finfo, &e, it); /* code function to variable '.it' */
|
||||
be_code_setvar(finfo, &e, it, bfalse); /* code function to variable '.it' */
|
||||
be_code_call(finfo, e.v.idx, 0); /* itvar <- call .it() */
|
||||
stmtlist(parser);
|
||||
}
|
||||
|
@ -1444,7 +1464,7 @@ static void class_static_assignment_expr(bparser *parser, bexpdesc *e, bstring *
|
|||
key.v.s = name;
|
||||
|
||||
be_code_member(parser->finfo, &e1, &key); /* compute member accessor */
|
||||
be_code_setvar(parser->finfo, &e1, &e2); /* set member */
|
||||
be_code_setvar(parser->finfo, &e1, &e2, bfalse); /* set member */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1568,7 +1588,7 @@ static void classstaticclass_stmt(bparser *parser, bclass *c_out, bexpdesc *e_ou
|
|||
key.v.s = name;
|
||||
/* assign the class to the static member */
|
||||
be_code_member(parser->finfo, &e1, &key); /* compute member accessor */
|
||||
be_code_setvar(parser->finfo, &e1, &e_class); /* set member */
|
||||
be_code_setvar(parser->finfo, &e1, &e_class, bfalse); /* set member */
|
||||
} else {
|
||||
parser_error(parser, "class name error");
|
||||
}
|
||||
|
@ -1620,7 +1640,7 @@ static void var_field(bparser *parser)
|
|||
init_exp(&e2, ETNIL, 0);
|
||||
}
|
||||
new_var(parser, name, &e1); /* new variable */
|
||||
be_code_setvar(parser->finfo, &e1, &e2);
|
||||
be_code_setvar(parser->finfo, &e1, &e2, bfalse);
|
||||
}
|
||||
|
||||
static void var_stmt(bparser *parser)
|
||||
|
|
Loading…
Reference in New Issue