Merge pull request #12954 from s-hadinger/berry_vararg

Berry support for vararg
This commit is contained in:
s-hadinger 2021-08-23 20:21:09 +02:00 committed by GitHub
commit bda28e9981
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 7 deletions

View File

@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
### Added
- Turn HTTP API (command ``SetOption128 1``) default on for backward compatibility
- Support for IEM3155 Wattmeter (#12940)
- Berry support for vararg
### Fixed
- WDT reset on shutters with stepper motors during deceleration (#12849)

View File

@ -528,23 +528,45 @@ static void singlevar(bparser *parser, bexpdesc *var)
}
}
/* parse a vararg argument in the form `def f(a, *b) end` */
/* Munch the '*', read the token, create variable and declare the function as vararg */
static void func_vararg(bparser *parser) {
bexpdesc v;
bstring *str;
match_token(parser, OptMul); /* skip '*' */
str = next_token(parser).u.s;
match_token(parser, TokenId); /* match and skip ID */
new_var(parser, str, &v); /* new variable */
parser->finfo->proto->varg = 1; /* set varg flag */
}
/* Parse function or method definition variable list */
/* Create an implicit local variable for each argument starting at R0 */
/* Update function proto argc to the expected number or arguments */
/* Raise an exception if multiple arguments have the same name */
/* New: vararg support */
static void func_varlist(bparser *parser)
{
bexpdesc v;
bstring *str;
/* '(' [ID {',' ID}] ')' */
/* '(' [ ID {',' ID}] ')' or */
/* '(' '*' ID ')' or */
/* '(' [ ID {',' ID}] ',' '*' ID ')' */
match_token(parser, OptLBK); /* skip '(' */
if (match_id(parser, str) != NULL) {
if (next_type(parser) == OptMul) {
func_vararg(parser);
} else if (match_id(parser, str) != NULL) {
new_var(parser, str, &v); /* new variable */
while (match_skip(parser, OptComma)) { /* ',' */
str = next_token(parser).u.s;
match_token(parser, TokenId); /* match and skip ID */
/* new local variable */
new_var(parser, str, &v);
if (next_type(parser) == OptMul) {
func_vararg(parser);
break;
} else {
str = next_token(parser).u.s;
match_token(parser, TokenId); /* match and skip ID */
/* new local variable */
new_var(parser, str, &v);
}
}
}
match_token(parser, OptRBK); /* skip ')' */

View File

@ -12,6 +12,7 @@
#include "be_class.h"
#include "be_func.h"
#include "be_vector.h"
#include "be_list.h"
#include "be_map.h"
#include "be_module.h"
#include "be_mem.h"
@ -1086,6 +1087,20 @@ newframe: /* a new call frame */
for (; v < end; ++v) { /* set all not provided arguments to nil */
var_setnil(v);
}
if (proto->varg) { /* there are vararg at the last argument, build the list */
/* code below uses mostly low-level calls for performance */
be_stack_require(vm, argc + 2); /* make sure we don't overflow the stack */
bvalue *top_save = vm->top; /* save original stack, we need fresh slots to create the 'list' instance */
vm->top = v; /* move top of stack right after last argument */
be_newobject(vm, "list"); /* this creates 2 objects on stack: list instance, BE_LIST object */
blist *list = var_toobj(vm->top-1); /* get low-level BE_LIST structure */
v = reg + proto->argc - 1; /* last argument */
for (; v < reg + argc; v++) {
be_list_push(vm, list, v); /* push all varargs into list */
}
*(reg + proto->argc - 1) = *(vm->top-2); /* change the vararg argument to now contain the list instance */
vm->top = top_save; /* restore top of stack pointer */
}
goto newframe; /* continue execution of the closure */
}
case BE_NTVCLOS: {

View File

@ -0,0 +1,14 @@
#- vararg -#
def f(a,*b) return b end
assert(f() == [])
assert(f(1) == [])
assert(f(1,2) == [2])
assert(f(1,2,3) == [2, 3])
def g(*a) return a end
assert(g() == [])
assert(g("foo") == ["foo"])
assert(g("foo", nil) == ["foo", nil])
assert(g("foo", nil, 2) == ["foo", nil, 2])

View File

@ -347,7 +347,7 @@ void BrLoad(const char * script_name) {
bool loaded = be_tobool(berry.vm, -2); // did it succeed?
be_pop(berry.vm, 2);
if (loaded) {
AddLog(LOG_LEVEL_INFO, D_LOG_BERRY "sucessfully loaded '%s'", script_name);
AddLog(LOG_LEVEL_INFO, D_LOG_BERRY "successfully loaded '%s'", script_name);
} else {
AddLog(LOG_LEVEL_INFO, D_LOG_BERRY "no '%s'", script_name);
}