mirror of
https://gitee.com/Lyon1998/pikapython.git
synced 2025-01-29 17:22:56 +08:00
format load_call_arg
use f struct support stack check arg
This commit is contained in:
parent
2bcf0d8eb5
commit
a09d32d6ac
2
port/linux/.vscode/launch.json
vendored
2
port/linux/.vscode/launch.json
vendored
@ -11,7 +11,7 @@
|
||||
"program": "${workspaceFolder}/build/test/pikascript_test",
|
||||
// "program": "${workspaceFolder}/build/boot/demo06-pikamain/pikascript_demo06-pikamain",
|
||||
"args": [
|
||||
"--gtest_filter=vm.fn_pos_kw2"
|
||||
// "--gtest_filter=vm.super_"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
|
@ -500,9 +500,9 @@ PikaObj* newRootObj(char* name, NewFun newObjFun) {
|
||||
if (!logo_printed) {
|
||||
logo_printed = 1;
|
||||
__platform_printf("\r\n");
|
||||
__platform_printf("=========[ POWERED BY ]==========\r\n");
|
||||
__platform_printf("| pikascript.com |\r\n");
|
||||
__platform_printf("=================================\r\n");
|
||||
__platform_printf("~~~/ POWERED BY \\~~~\r\n");
|
||||
__platform_printf("~ pikascript.com ~\r\n");
|
||||
__platform_printf("~~~~~~~~~~~~~~~~~~~~\r\n");
|
||||
}
|
||||
__pikaMain = newObj;
|
||||
return newObj;
|
||||
|
435
src/PikaVM.c
435
src/PikaVM.c
@ -533,11 +533,11 @@ static Arg* VM_instruction_handler_SLC(PikaObj* self,
|
||||
char* data,
|
||||
Arg* arg_ret_reg) {
|
||||
#if PIKA_SYNTAX_SLICE_ENABLE
|
||||
int arg_num_input = VMState_getInputArgNum(vm);
|
||||
if (arg_num_input < 2) {
|
||||
int n_input = VMState_getInputArgNum(vm);
|
||||
if (n_input < 2) {
|
||||
return arg_newNull();
|
||||
}
|
||||
if (arg_num_input == 2) {
|
||||
if (n_input == 2) {
|
||||
Arg* key = stack_popArg_alloc(&vm->stack);
|
||||
Arg* obj = stack_popArg_alloc(&vm->stack);
|
||||
Arg* res = __vm_get(vm, self, key, obj);
|
||||
@ -545,7 +545,7 @@ static Arg* VM_instruction_handler_SLC(PikaObj* self,
|
||||
arg_deinit(obj);
|
||||
return res;
|
||||
}
|
||||
if (arg_num_input == 3) {
|
||||
if (n_input == 3) {
|
||||
Arg* end = stack_popArg_alloc(&vm->stack);
|
||||
Arg* start = stack_popArg_alloc(&vm->stack);
|
||||
Arg* obj = stack_popArg_alloc(&vm->stack);
|
||||
@ -848,9 +848,8 @@ Arg* obj_runMethodArg(PikaObj* self,
|
||||
&run_state);
|
||||
}
|
||||
|
||||
static char* _kw_to_default_all(char* type_list,
|
||||
static char* _kw_to_default_all(FunctionArgsInfo* f,
|
||||
char* arg_name,
|
||||
PikaDict* kw,
|
||||
int* argc,
|
||||
Arg* argv[]) {
|
||||
#if PIKA_NANO
|
||||
@ -859,25 +858,25 @@ static char* _kw_to_default_all(char* type_list,
|
||||
while (strIsContain(arg_name, '=')) {
|
||||
strPopLastToken(arg_name, '=');
|
||||
/* load default arg from kws */
|
||||
if (kw != NULL) {
|
||||
Arg* default_arg = pikaDict_getArg(kw, arg_name);
|
||||
if (f->kw != NULL) {
|
||||
Arg* default_arg = pikaDict_getArg(f->kw, arg_name);
|
||||
if (default_arg != NULL) {
|
||||
argv[(*argc)++] = arg_copy(default_arg);
|
||||
}
|
||||
}
|
||||
arg_name = strPopLastToken(type_list, ',');
|
||||
arg_name = strPopLastToken(f->type_list, ',');
|
||||
}
|
||||
return arg_name;
|
||||
}
|
||||
|
||||
static int _kw_to_pos_one(char* arg_name,
|
||||
PikaDict* kw,
|
||||
static int _kw_to_pos_one(FunctionArgsInfo* f,
|
||||
char* arg_name,
|
||||
int* argc,
|
||||
Arg* argv[]) {
|
||||
if (kw == NULL) {
|
||||
if (f->kw == NULL) {
|
||||
return 0;
|
||||
}
|
||||
Arg* pos_arg = pikaDict_getArg(kw, arg_name);
|
||||
Arg* pos_arg = pikaDict_getArg(f->kw, arg_name);
|
||||
if (pos_arg == NULL) {
|
||||
return 0;
|
||||
}
|
||||
@ -885,18 +884,15 @@ static int _kw_to_pos_one(char* arg_name,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _kw_to_pos_all(char* type_list,
|
||||
PikaDict* kw,
|
||||
int* argc,
|
||||
Arg* argv[],
|
||||
int arg_num_need) {
|
||||
static void _kw_to_pos_all(FunctionArgsInfo* f, int* argc, Arg* argv[]) {
|
||||
int arg_num_need = f->n_positional - f->n_positional_got;
|
||||
if (0 == arg_num_need) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < arg_num_need; i++) {
|
||||
char* arg_name = strPopLastToken(type_list, ',');
|
||||
pika_assert(kw != NULL);
|
||||
Arg* pos_arg = pikaDict_getArg(kw, arg_name);
|
||||
char* arg_name = strPopLastToken(f->type_list, ',');
|
||||
pika_assert(f->kw != NULL);
|
||||
Arg* pos_arg = pikaDict_getArg(f->kw, arg_name);
|
||||
pika_assert(pos_arg != NULL);
|
||||
argv[(*argc)++] = arg_copy(pos_arg);
|
||||
}
|
||||
@ -909,143 +905,237 @@ static void _loadLocalsFromArgv(Args* locals, int argc, Arg* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
static void _type_list_parse(char* type_list,
|
||||
PIKA_BOOL* is_vars,
|
||||
PIKA_BOOL* is_keys,
|
||||
PIKA_BOOL* is_default,
|
||||
int8_t* num_pos,
|
||||
int8_t* num_default) {
|
||||
if (type_list[0] == 0) {
|
||||
*num_pos = 0;
|
||||
static void _type_list_parse(FunctionArgsInfo* f) {
|
||||
if (f->type_list[0] == 0) {
|
||||
f->n_positional = 0;
|
||||
return;
|
||||
}
|
||||
int8_t res = strCountSign(type_list, ',') + 1;
|
||||
int8_t x = strCountSign(type_list, '*');
|
||||
int8_t y = strCountSign(type_list, '=');
|
||||
int8_t res = strCountSign(f->type_list, ',') + 1;
|
||||
int8_t x = strCountSign(f->type_list, '*');
|
||||
int8_t y = strCountSign(f->type_list, '=');
|
||||
/* default */
|
||||
if (y > 0) {
|
||||
res -= y;
|
||||
*is_default = PIKA_TRUE;
|
||||
*num_default = y;
|
||||
f->is_default = PIKA_TRUE;
|
||||
f->n_default = y;
|
||||
}
|
||||
/* vars */
|
||||
if (x == 1) {
|
||||
*is_vars = PIKA_TRUE;
|
||||
*num_pos = res - 1;
|
||||
f->is_vars = PIKA_TRUE;
|
||||
f->n_positional = res - 1;
|
||||
return;
|
||||
}
|
||||
/* kw */
|
||||
if (x == 2) {
|
||||
*is_keys = 1;
|
||||
*num_pos = res - 1;
|
||||
f->is_keys = 1;
|
||||
f->n_positional = res - 1;
|
||||
return;
|
||||
}
|
||||
/* vars and kw */
|
||||
if (x == 3) {
|
||||
*is_vars = PIKA_TRUE;
|
||||
*is_keys = PIKA_TRUE;
|
||||
*num_pos = res - 2;
|
||||
f->is_vars = PIKA_TRUE;
|
||||
f->is_keys = PIKA_TRUE;
|
||||
f->n_positional = res - 2;
|
||||
return;
|
||||
}
|
||||
*num_pos = res;
|
||||
f->n_positional = res;
|
||||
return;
|
||||
}
|
||||
|
||||
static void _kw_push(PikaDict** kw_dict_p,
|
||||
PikaDict** kw_keys_p,
|
||||
Arg* call_arg,
|
||||
int i) {
|
||||
if (NULL == *kw_dict_p) {
|
||||
*kw_dict_p = New_pikaDict();
|
||||
static void _kw_push(FunctionArgsInfo* f, Arg* call_arg, int i) {
|
||||
if (NULL == f->kw) {
|
||||
f->kw = New_pikaDict();
|
||||
}
|
||||
if (NULL == *kw_keys_p) {
|
||||
*kw_keys_p = New_pikaDict();
|
||||
if (NULL == f->kw_keys) {
|
||||
f->kw_keys = New_pikaDict();
|
||||
}
|
||||
arg_setIsKeyword(call_arg, PIKA_FALSE);
|
||||
pikaDict_setArg(*kw_dict_p, call_arg);
|
||||
pikaDict_setArg(f->kw, call_arg);
|
||||
char kw_keys_index_buff[11] = {0};
|
||||
char* kw_keys_index = fast_itoa(kw_keys_index_buff, i);
|
||||
pikaDict_setArg(*kw_keys_p,
|
||||
pikaDict_setArg(f->kw_keys,
|
||||
arg_setInt(NULL, kw_keys_index, arg_getNameHash(call_arg)));
|
||||
}
|
||||
|
||||
#define vars_or_keys_or_default (is_vars || is_keys || is_default)
|
||||
static void _load_call_arg(VMState* vm,
|
||||
Arg* call_arg,
|
||||
FunctionArgsInfo* f,
|
||||
int* i,
|
||||
int* argc,
|
||||
Arg* argv[]) {
|
||||
/* load the kw arg */
|
||||
if (call_arg != NULL && arg_getIsKeyword(call_arg)) {
|
||||
_kw_push(f, call_arg, *i);
|
||||
return;
|
||||
}
|
||||
/* load variable arg */
|
||||
if (f->i_arg > f->n_positional) {
|
||||
if (f->is_vars) {
|
||||
pikaList_append(&(f->tuple)->super, call_arg);
|
||||
/* the append would copy the arg */
|
||||
if (NULL != call_arg) {
|
||||
arg_deinit(call_arg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
char* arg_name = strPopLastToken(f->type_list, ',');
|
||||
/* load default from pos */
|
||||
if (f->i_arg > f->n_positional) {
|
||||
if (f->is_default) {
|
||||
if (arg_name[strlen(arg_name) - 1] == '=') {
|
||||
/* found default arg*/
|
||||
arg_name[strlen(arg_name) - 1] = '\0';
|
||||
arg_setNameHash(call_arg, hash_time33EndWith(arg_name, ':'));
|
||||
argv[(*argc)++] = call_arg;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* load default from kw */
|
||||
arg_name = _kw_to_default_all(f, arg_name, argc, argv);
|
||||
/* load position arg */
|
||||
if (_kw_to_pos_one(f, arg_name, argc, argv)) {
|
||||
/* load pos from kw */
|
||||
(f->n_positional_got)++;
|
||||
/* restore the stack */
|
||||
(*i)--;
|
||||
stack_pushArg(&(vm->stack), call_arg);
|
||||
return;
|
||||
}
|
||||
/*load pos from pos */
|
||||
arg_setNameHash(call_arg, hash_time33EndWith(arg_name, ':'));
|
||||
argv[(*argc)++] = call_arg;
|
||||
(f->n_positional_got)++;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* unpack starred arg */
|
||||
if (call_arg != NULL && arg_getIsStarred(call_arg)) {
|
||||
pika_assert(argType_isObject(arg_getType(call_arg)));
|
||||
PikaObj* obj = arg_getPtr(call_arg);
|
||||
/* clang-format off */
|
||||
PIKA_PYTHON(
|
||||
@l = __len__()
|
||||
)
|
||||
/* clang-format on */
|
||||
const uint8_t bytes[] = {
|
||||
0x08, 0x00, 0x00, 0x00, /* instruct array size */
|
||||
0x00, 0x82, 0x01, 0x00, 0x00, 0x04, 0x09, 0x00, /* instruct
|
||||
array */
|
||||
0x0c, 0x00, 0x00, 0x00, /* const pool size */
|
||||
0x00, 0x5f, 0x5f, 0x6c, 0x65, 0x6e, 0x5f, 0x5f, 0x00,
|
||||
0x40, 0x6c, 0x00, /* const pool */
|
||||
};
|
||||
pikaVM_runByteCode(obj, (uint8_t*)bytes);
|
||||
int len = obj_getInt(obj, "@l");
|
||||
for (int i_star_arg = 0; i_star_arg < len; i_star_arg++) {
|
||||
obj_setInt(obj, "@d", i_star_arg);
|
||||
/* clang-format off */
|
||||
PIKA_PYTHON(
|
||||
@a = __getitem__(@d)
|
||||
)
|
||||
/* clang-format on */
|
||||
const uint8_t bytes[] = {
|
||||
0x0c, 0x00, 0x00, 0x00, /* instruct array size */
|
||||
0x10, 0x81, 0x01, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x04,
|
||||
0x10, 0x00,
|
||||
/* instruct array */
|
||||
0x13, 0x00, 0x00, 0x00, /* const pool size */
|
||||
0x00, 0x40, 0x64, 0x00, 0x5f, 0x5f, 0x67, 0x65, 0x74, 0x69,
|
||||
0x74, 0x65, 0x6d, 0x5f, 0x5f, 0x00, 0x40, 0x61,
|
||||
0x00, /* const pool */
|
||||
};
|
||||
pikaVM_runByteCode(obj, (uint8_t*)bytes);
|
||||
Arg* arg_a = obj_getArg(obj, "@a");
|
||||
_load_call_arg(vm, arg_a, &f, &i_star_arg, &argc, argv);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _get_n_input_with_unpack(VMState* vm) {
|
||||
#if PIKA_NANO_ENABLE
|
||||
return VMState_getInputArgNum(vm);
|
||||
#else
|
||||
int n_input = VMState_getInputArgNum(vm);
|
||||
for (int i = 0; i < n_input; i++) {
|
||||
Arg* arg_check = stack_checkArg(&(vm->stack), i);
|
||||
if (NULL == arg_check) {
|
||||
continue;
|
||||
}
|
||||
if (arg_getIsDoubleStarred(arg_check) || arg_getIsStarred(arg_check)) {
|
||||
n_input--;
|
||||
}
|
||||
}
|
||||
return n_input;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define vars_or_keys_or_default (f.is_vars || f.is_keys || f.is_default)
|
||||
static int VMState_loadArgsFromMethodArg(VMState* vm,
|
||||
PikaObj* method_host_obj,
|
||||
Args* locals,
|
||||
Arg* method_arg,
|
||||
char* method_name,
|
||||
int arg_num_used) {
|
||||
int n_used) {
|
||||
Arg* argv[PIKA_ARG_NUM_MAX] = {0};
|
||||
int argc = 0;
|
||||
char _buffs1[PIKA_LINE_BUFF_SIZE] = {0};
|
||||
char* buffs1 = (char*)_buffs1;
|
||||
char _buffs2[PIKA_LINE_BUFF_SIZE] = {0};
|
||||
char* buffs2 = (char*)_buffs2;
|
||||
int8_t num_pos = 0;
|
||||
int8_t arg_num_default = 0;
|
||||
int8_t arg_num = 0;
|
||||
int8_t arg_num_input = 0;
|
||||
PIKA_BOOL is_vars = PIKA_FALSE;
|
||||
PIKA_BOOL is_keys = PIKA_FALSE;
|
||||
PIKA_BOOL is_default = PIKA_FALSE;
|
||||
ArgType method_type = ARG_TYPE_UNDEF;
|
||||
PikaTuple* tuple = NULL;
|
||||
PikaDict* kw = NULL;
|
||||
PikaDict* kw_keys = NULL;
|
||||
char* var_tuple_name = NULL;
|
||||
char* kw_dict_name = NULL;
|
||||
FunctionArgsInfo f = {0};
|
||||
char* type_list_buff = NULL;
|
||||
/* get method type list */
|
||||
char* type_list =
|
||||
methodArg_getTypeList(method_arg, buffs1, sizeof(_buffs1));
|
||||
if (NULL == type_list) {
|
||||
f.type_list = methodArg_getTypeList(method_arg, buffs1, sizeof(_buffs1));
|
||||
if (NULL == f.type_list) {
|
||||
__platform_printf(
|
||||
"OverflowError: type list is too long, please use bigger "
|
||||
"PIKA_LINE_BUFF_SIZE\r\n");
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
method_type = arg_getType(method_arg);
|
||||
f.method_type = arg_getType(method_arg);
|
||||
|
||||
/* get arg_num_pos */
|
||||
_type_list_parse(type_list, &is_vars, &is_keys, &is_default, &num_pos,
|
||||
&arg_num_default);
|
||||
if (method_type == ARG_TYPE_METHOD_OBJECT) {
|
||||
_type_list_parse(&f);
|
||||
if (f.method_type == ARG_TYPE_METHOD_OBJECT) {
|
||||
/* delete the 'self' */
|
||||
num_pos--;
|
||||
f.n_positional--;
|
||||
}
|
||||
arg_num_input = VMState_getInputArgNum(vm);
|
||||
|
||||
f.n_input = _get_n_input_with_unpack(vm);
|
||||
|
||||
/* check arg num */
|
||||
if (method_type == ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR ||
|
||||
method_type == ARG_TYPE_METHOD_CONSTRUCTOR || is_vars == PIKA_TRUE ||
|
||||
arg_num_used != 0) {
|
||||
if (f.method_type == ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR ||
|
||||
f.method_type == ARG_TYPE_METHOD_CONSTRUCTOR ||
|
||||
f.is_vars == PIKA_TRUE || n_used != 0) {
|
||||
/* skip for constrctor */
|
||||
/* skip for variable args */
|
||||
/* arg_num_used != 0 means it is a factory method */
|
||||
/* n_used != 0 means it is a factory method */
|
||||
} else {
|
||||
/* check position arg num */
|
||||
if (!vars_or_keys_or_default) {
|
||||
if (num_pos != arg_num_input) {
|
||||
if (f.n_positional != f.n_input) {
|
||||
VMState_setErrorCode(vm, PIKA_RES_ERR_INVALID_PARAM);
|
||||
__platform_printf(
|
||||
"TypeError: %s() takes %d positional argument but %d were "
|
||||
"given\r\n",
|
||||
method_name, num_pos, arg_num_input);
|
||||
method_name, f.n_positional, f.n_input);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
#if !PIKA_NANO_ENABLE
|
||||
if (is_default) {
|
||||
int8_t arg_num_min = num_pos;
|
||||
int8_t arg_num_max = num_pos + arg_num_default;
|
||||
if (arg_num_input < arg_num_min || arg_num_input > arg_num_max) {
|
||||
if (f.is_default) {
|
||||
int8_t n_min = f.n_positional;
|
||||
int8_t n_max = f.n_positional + f.n_default;
|
||||
if (f.n_input < n_min || f.n_input > n_max) {
|
||||
VMState_setErrorCode(vm, PIKA_RES_ERR_INVALID_PARAM);
|
||||
__platform_printf(
|
||||
"TypeError: %s() takes from %d to %d positional arguments "
|
||||
"but %d were given\r\n",
|
||||
method_name, arg_num_min, arg_num_max, arg_num_input);
|
||||
method_name, n_min, n_max, f.n_input);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
@ -1053,141 +1143,96 @@ static int VMState_loadArgsFromMethodArg(VMState* vm,
|
||||
}
|
||||
|
||||
if (vars_or_keys_or_default) {
|
||||
arg_num = arg_num_input;
|
||||
f.n_arg = f.n_input;
|
||||
} else {
|
||||
arg_num = num_pos;
|
||||
f.n_arg = f.n_positional;
|
||||
}
|
||||
|
||||
/* create tuple/dict for vars/keys */
|
||||
if (vars_or_keys_or_default) {
|
||||
if (strGetSize(type_list) > sizeof(_buffs2)) {
|
||||
if (strGetSize(f.type_list) > sizeof(_buffs2)) {
|
||||
__platform_printf(
|
||||
"OverFlowError: please use bigger PIKA_LINE_BUFF_SIZE\r\n");
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
type_list_buff = strCopy(buffs2, type_list);
|
||||
uint8_t arg_num_dec_any = strCountSign(type_list_buff, ',') + 1;
|
||||
for (int i = 0; i < arg_num_dec_any; i++) {
|
||||
type_list_buff = strCopy(buffs2, f.type_list);
|
||||
uint8_t n_typelist = strCountSign(type_list_buff, ',') + 1;
|
||||
for (int i = 0; i < n_typelist; i++) {
|
||||
char* arg_def = strPopLastToken(type_list_buff, ',');
|
||||
if (arg_def[0] == '*' && arg_def[1] != '*') {
|
||||
/* get variable tuple name */
|
||||
/* skip the '*' */
|
||||
var_tuple_name = arg_def + 1;
|
||||
f.var_tuple_name = arg_def + 1;
|
||||
/* create tuple */
|
||||
if (NULL == tuple) {
|
||||
tuple = New_pikaTuple();
|
||||
if (NULL == f.tuple) {
|
||||
f.tuple = New_pikaTuple();
|
||||
/* remove the format arg */
|
||||
strPopLastToken(type_list, ',');
|
||||
strPopLastToken(f.type_list, ',');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (arg_def[0] == '*' && arg_def[1] == '*') {
|
||||
/* get keyword dict name */
|
||||
kw_dict_name = arg_def + 2;
|
||||
kw = New_pikaDict();
|
||||
kw_keys = New_pikaDict();
|
||||
/* get kw dict name */
|
||||
f.kw_dict_name = arg_def + 2;
|
||||
f.kw = New_pikaDict();
|
||||
f.kw_keys = New_pikaDict();
|
||||
/* remove the format arg */
|
||||
strPopLastToken(type_list, ',');
|
||||
strPopLastToken(f.type_list, ',');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* load pars */
|
||||
int num_pos_got = 0;
|
||||
for (int i = 0; i < arg_num; i++) {
|
||||
int arg_index = arg_num - i;
|
||||
/* load args */
|
||||
for (int i = 0; i < f.n_arg; i++) {
|
||||
f.i_arg = f.n_arg - i;
|
||||
Arg* call_arg = stack_popArg_alloc(&(vm->stack));
|
||||
/* load the keyword arg */
|
||||
if (call_arg != NULL && arg_getIsKeyword(call_arg)) {
|
||||
_kw_push(&kw, &kw_keys, call_arg, i);
|
||||
continue;
|
||||
}
|
||||
/* load variable arg */
|
||||
if (arg_index > num_pos) {
|
||||
if (is_vars) {
|
||||
pikaList_append(&tuple->super, call_arg);
|
||||
/* the append would copy the arg */
|
||||
if (NULL != call_arg) {
|
||||
arg_deinit(call_arg);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
char* arg_name = strPopLastToken(type_list, ',');
|
||||
/* load default from pos */
|
||||
if (arg_index > num_pos) {
|
||||
if (is_default) {
|
||||
if (arg_name[strlen(arg_name) - 1] == '=') {
|
||||
/* found default arg*/
|
||||
arg_name[strlen(arg_name) - 1] = '\0';
|
||||
arg_setNameHash(call_arg,
|
||||
hash_time33EndWith(arg_name, ':'));
|
||||
argv[argc++] = call_arg;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* load default from kw */
|
||||
arg_name = _kw_to_default_all(type_list, arg_name, kw, &argc, argv);
|
||||
/* load position arg */
|
||||
if (_kw_to_pos_one(arg_name, kw, &argc, argv)) {
|
||||
/* load pos from kw */
|
||||
num_pos_got++;
|
||||
/* restore the stack */
|
||||
i--;
|
||||
stack_pushArg(&(vm->stack), call_arg);
|
||||
continue;
|
||||
}
|
||||
/*load pos from pos */
|
||||
arg_setNameHash(call_arg, hash_time33EndWith(arg_name, ':'));
|
||||
argv[argc++] = call_arg;
|
||||
num_pos_got++;
|
||||
_load_call_arg(vm, call_arg, &f, &i, &argc, argv);
|
||||
}
|
||||
|
||||
/* only default */
|
||||
#if !PIKA_NANO_ENABLE
|
||||
if (strIsContain(type_list, '=')) {
|
||||
char* arg_name = strPopLastToken(type_list, ',');
|
||||
_kw_to_default_all(type_list, arg_name, kw, &argc, argv);
|
||||
if (strIsContain(f.type_list, '=')) {
|
||||
char* arg_name = strPopLastToken(f.type_list, ',');
|
||||
_kw_to_default_all(&f, arg_name, &argc, argv);
|
||||
}
|
||||
/* load kw to pos */
|
||||
_kw_to_pos_all(type_list, kw, &argc, argv, num_pos - num_pos_got);
|
||||
_kw_to_pos_all(&f, &argc, argv);
|
||||
#endif
|
||||
|
||||
if (tuple != NULL) {
|
||||
pikaList_reverse(&tuple->super);
|
||||
if (f.tuple != NULL) {
|
||||
pikaList_reverse(&(f.tuple)->super);
|
||||
/* load variable tuple */
|
||||
PikaObj* New_PikaStdData_Tuple(Args * args);
|
||||
PikaObj* tuple_obj = newNormalObj(New_PikaStdData_Tuple);
|
||||
obj_setPtr(tuple_obj, "list", tuple);
|
||||
obj_setPtr(tuple_obj, "list", f.tuple);
|
||||
Arg* argi =
|
||||
arg_setPtr(NULL, var_tuple_name, ARG_TYPE_OBJECT, tuple_obj);
|
||||
arg_setPtr(NULL, f.var_tuple_name, ARG_TYPE_OBJECT, tuple_obj);
|
||||
argv[argc++] = argi;
|
||||
}
|
||||
|
||||
if (kw != NULL) {
|
||||
if (NULL == kw_dict_name) {
|
||||
kw_dict_name = "__kwargs";
|
||||
if (f.kw != NULL) {
|
||||
if (NULL == f.kw_dict_name) {
|
||||
f.kw_dict_name = "__kwargs";
|
||||
}
|
||||
/* load keyword dict */
|
||||
/* load kw dict */
|
||||
PikaObj* New_PikaStdData_Dict(Args * args);
|
||||
PikaObj* dict_obj = newNormalObj(New_PikaStdData_Dict);
|
||||
obj_setPtr(dict_obj, "dict", kw);
|
||||
obj_setPtr(dict_obj, "_keys", kw_keys);
|
||||
Arg* argi = arg_setPtr(NULL, kw_dict_name, ARG_TYPE_OBJECT, dict_obj);
|
||||
obj_setPtr(dict_obj, "dict", f.kw);
|
||||
obj_setPtr(dict_obj, "_keys", f.kw_keys);
|
||||
Arg* argi = arg_setPtr(NULL, f.kw_dict_name, ARG_TYPE_OBJECT, dict_obj);
|
||||
argv[argc++] = argi;
|
||||
}
|
||||
|
||||
/* load 'self' as the first arg when call object method */
|
||||
if (method_type == ARG_TYPE_METHOD_OBJECT) {
|
||||
if (f.method_type == ARG_TYPE_METHOD_OBJECT) {
|
||||
Arg* call_arg = arg_setRef(NULL, "self", method_host_obj);
|
||||
argv[argc++] = call_arg;
|
||||
}
|
||||
_loadLocalsFromArgv(locals, argc, argv);
|
||||
exit:
|
||||
return arg_num;
|
||||
return f.n_arg;
|
||||
}
|
||||
|
||||
void __vm_List_append(PikaObj* self, Arg* arg) {
|
||||
@ -1210,18 +1255,18 @@ static Arg* _vm_create_list_or_tuple(PikaObj* self,
|
||||
PIKA_BOOL is_list) {
|
||||
#if PIKA_BUILTIN_STRUCT_ENABLE
|
||||
NewFun constructor = is_list ? New_PikaStdData_List : New_PikaStdData_Tuple;
|
||||
uint8_t arg_num = VMState_getInputArgNum(vm);
|
||||
uint8_t n_arg = VMState_getInputArgNum(vm);
|
||||
PikaObj* list = newNormalObj(constructor);
|
||||
__vm_List___init__(list);
|
||||
Stack stack = {0};
|
||||
stack_init(&stack);
|
||||
/* load to local stack to change sort */
|
||||
for (int i = 0; i < arg_num; i++) {
|
||||
for (int i = 0; i < n_arg; i++) {
|
||||
Arg* arg = stack_popArg_alloc(&(vm->stack));
|
||||
pika_assert(arg != NULL);
|
||||
stack_pushArg(&stack, arg);
|
||||
}
|
||||
for (int i = 0; i < arg_num; i++) {
|
||||
for (int i = 0; i < n_arg; i++) {
|
||||
Arg* arg = stack_popArg_alloc(&stack);
|
||||
pika_assert(arg != NULL);
|
||||
__vm_List_append(list, arg);
|
||||
@ -1267,17 +1312,17 @@ static Arg* VM_instruction_handler_DCT(PikaObj* self,
|
||||
char* data,
|
||||
Arg* arg_ret_reg) {
|
||||
#if PIKA_BUILTIN_STRUCT_ENABLE
|
||||
uint8_t arg_num = VMState_getInputArgNum(vm);
|
||||
uint8_t n_arg = VMState_getInputArgNum(vm);
|
||||
PikaObj* dict = newNormalObj(New_PikaStdData_Dict);
|
||||
__vm_Dict___init__(dict);
|
||||
Stack stack = {0};
|
||||
stack_init(&stack);
|
||||
/* load to local stack to change sort */
|
||||
for (int i = 0; i < arg_num; i++) {
|
||||
for (int i = 0; i < n_arg; i++) {
|
||||
Arg* arg = stack_popArg_alloc(&(vm->stack));
|
||||
stack_pushArg(&stack, arg);
|
||||
}
|
||||
for (int i = 0; i < arg_num / 2; i++) {
|
||||
for (int i = 0; i < n_arg / 2; i++) {
|
||||
Arg* key_arg = stack_popArg_alloc(&stack);
|
||||
Arg* val_arg = stack_popArg_alloc(&stack);
|
||||
__vm_Dict_set(dict, val_arg, arg_getStr(key_arg));
|
||||
@ -1374,7 +1419,7 @@ static Arg* VM_instruction_handler_RUN(PikaObj* self,
|
||||
PIKA_BOOL is_temp = PIKA_FALSE;
|
||||
PIKA_BOOL skip_init = PIKA_FALSE;
|
||||
char* sys_out;
|
||||
int arg_num_used = 0;
|
||||
int n_used = 0;
|
||||
arg_newReg(arg_reg1, 64);
|
||||
RunState sub_run_state = {.try_state = vm->run_state->try_state,
|
||||
.try_result = TRY_RESULT_NONE};
|
||||
@ -1432,24 +1477,24 @@ static Arg* VM_instruction_handler_RUN(PikaObj* self,
|
||||
if (NULL == method_host && run_path[0] == '.') {
|
||||
/* get method host obj from stack */
|
||||
Arg* stack_tmp[PIKA_ARG_NUM_MAX] = {0};
|
||||
int arg_num = VMState_getInputArgNum(vm);
|
||||
if (arg_num > PIKA_ARG_NUM_MAX) {
|
||||
int n_arg = VMState_getInputArgNum(vm);
|
||||
if (n_arg > PIKA_ARG_NUM_MAX) {
|
||||
__platform_printf(
|
||||
"[ERROR] Too many args in RUN instruction, please use bigger "
|
||||
"#define PIKA_ARG_NUM_MAX\n");
|
||||
while (1) {
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < arg_num; i++) {
|
||||
for (int i = 0; i < n_arg; i++) {
|
||||
stack_tmp[i] = stack_popArg_alloc(&(vm->stack));
|
||||
}
|
||||
host_arg = stack_tmp[arg_num - 1];
|
||||
host_arg = stack_tmp[n_arg - 1];
|
||||
method_host = _arg_to_obj(host_arg, &is_temp);
|
||||
if (NULL != method_host) {
|
||||
arg_num_used++;
|
||||
n_used++;
|
||||
}
|
||||
/* push back other args to stack */
|
||||
for (int i = arg_num - 2; i >= 0; i--) {
|
||||
for (int i = n_arg - 2; i >= 0; i--) {
|
||||
stack_pushArg(&(vm->stack), stack_tmp[i]);
|
||||
}
|
||||
}
|
||||
@ -1522,8 +1567,8 @@ static Arg* VM_instruction_handler_RUN(PikaObj* self,
|
||||
sub_locals = New_PikaObj();
|
||||
|
||||
/* load args from vmState to sub_local->list */
|
||||
arg_num_used += VMState_loadArgsFromMethodArg(
|
||||
vm, obj_this, sub_locals->list, method, run_path, arg_num_used);
|
||||
n_used += VMState_loadArgsFromMethodArg(vm, obj_this, sub_locals->list,
|
||||
method, run_path, n_used);
|
||||
|
||||
/* load args failed */
|
||||
if (vm->error_code != 0) {
|
||||
@ -1559,7 +1604,7 @@ static Arg* VM_instruction_handler_RUN(PikaObj* self,
|
||||
goto init_exit;
|
||||
}
|
||||
VMState_loadArgsFromMethodArg(vm, new_obj, sub_locals->list, method_arg,
|
||||
"__init__", arg_num_used);
|
||||
"__init__", n_used);
|
||||
/* load args failed */
|
||||
if (vm->error_code != 0) {
|
||||
goto init_exit;
|
||||
@ -1711,7 +1756,7 @@ static Arg* VM_instruction_handler_OUT(PikaObj* self,
|
||||
}
|
||||
ArgType outArg_type = arg_getType(out_arg);
|
||||
if (VMState_getInvokeDeepthNow(vm) > 0) {
|
||||
/* in block, is a keyword arg */
|
||||
/* in block, is a kw arg */
|
||||
arg_setIsKeyword(out_arg, PIKA_TRUE);
|
||||
arg_setName(out_arg, arg_path);
|
||||
Arg* res = arg_copy_noalloc(out_arg, arg_ret_reg);
|
||||
@ -2142,6 +2187,11 @@ exit:
|
||||
}
|
||||
|
||||
static void _OPT_POW(OperatorInfo* op) {
|
||||
if (op->num == 1) {
|
||||
op->res = arg_copy(op->a2);
|
||||
arg_setIsDoubleStarred(op->res, 1);
|
||||
return;
|
||||
}
|
||||
if (op->t1 == ARG_TYPE_INT && op->t2 == ARG_TYPE_INT) {
|
||||
int res = 1;
|
||||
for (int i = 0; i < op->i2; i++) {
|
||||
@ -2218,6 +2268,11 @@ static Arg* VM_instruction_handler_OPT(PikaObj* self,
|
||||
op.res = arg_setInt(op.res, "", op.f1 < op.f2);
|
||||
goto exit;
|
||||
case '*':
|
||||
if (op.num == 1) {
|
||||
op.res = arg_copy(op.a2);
|
||||
arg_setIsStarred(op.res, 1);
|
||||
goto exit;
|
||||
}
|
||||
if ((op.t1 == ARG_TYPE_FLOAT) || op.t2 == ARG_TYPE_FLOAT) {
|
||||
op.res = arg_setFloat(op.res, "", op.f1 * op.f2);
|
||||
goto exit;
|
||||
@ -2494,11 +2549,11 @@ static Arg* VM_instruction_handler_ASS(PikaObj* self,
|
||||
Arg* arg1 = NULL;
|
||||
Arg* arg2 = NULL;
|
||||
Arg* res = NULL;
|
||||
int arg_num = VMState_getInputArgNum(vm);
|
||||
if (arg_num == 1) {
|
||||
int n_arg = VMState_getInputArgNum(vm);
|
||||
if (n_arg == 1) {
|
||||
arg1 = stack_popArg(&vm->stack, ®1);
|
||||
}
|
||||
if (arg_num == 2) {
|
||||
if (n_arg == 2) {
|
||||
arg2 = stack_popArg(&vm->stack, ®2);
|
||||
arg1 = stack_popArg(&vm->stack, ®1);
|
||||
}
|
||||
@ -2507,10 +2562,10 @@ static Arg* VM_instruction_handler_ASS(PikaObj* self,
|
||||
stack_pushArg(&vm->stack, arg_newInt(PIKA_RES_ERR_ASSERT));
|
||||
res = VM_instruction_handler_RIS(self, vm, data, arg_ret_reg);
|
||||
if (vm->run_state->try_state == TRY_STATE_NONE) {
|
||||
if (arg_num == 1) {
|
||||
if (n_arg == 1) {
|
||||
__platform_printf("AssertionError\n");
|
||||
}
|
||||
if (arg_num == 2) {
|
||||
if (n_arg == 2) {
|
||||
__platform_printf("AssertionError: %s\n", arg_getStr(arg2));
|
||||
}
|
||||
}
|
||||
|
19
src/PikaVM.h
19
src/PikaVM.h
@ -83,6 +83,25 @@ struct VMState {
|
||||
RunState* run_state;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int8_t n_positional;
|
||||
int8_t n_positional_got;
|
||||
int8_t n_default;
|
||||
int8_t n_arg;
|
||||
int8_t i_arg;
|
||||
int8_t n_input;
|
||||
PIKA_BOOL is_vars;
|
||||
PIKA_BOOL is_keys;
|
||||
PIKA_BOOL is_default;
|
||||
ArgType method_type;
|
||||
PikaTuple* tuple;
|
||||
PikaDict* kw;
|
||||
PikaDict* kw_keys;
|
||||
char* var_tuple_name;
|
||||
char* kw_dict_name;
|
||||
char* type_list;
|
||||
} FunctionArgsInfo;
|
||||
|
||||
typedef struct OperatorInfo OperatorInfo;
|
||||
struct OperatorInfo {
|
||||
char* opt;
|
||||
|
@ -172,7 +172,9 @@ Arg* arg_loadFile(Arg* self, char* filename);
|
||||
#define ARG_FLAG_SERIALIZED 0x01
|
||||
#define ARG_FLAG_KEYWORD 0x02
|
||||
#define ARG_FLAG_WEAK_REF 0x04
|
||||
#define ARG_FLAG_MAX 0x08
|
||||
#define ARG_FLAG_STARRED 0x08
|
||||
#define ARG_FLAG_DOUBLE_STARRED 0x10
|
||||
#define ARG_FLAG_MAX 0x18
|
||||
|
||||
static inline Arg* arg_getNext(Arg* self) {
|
||||
return self->_.next;
|
||||
@ -190,6 +192,7 @@ static inline uint32_t arg_getSize(Arg* self) {
|
||||
|
||||
static inline uint8_t arg_isSerialized(Arg* self) {
|
||||
pika_assert(NULL != self);
|
||||
pika_assert(self->flag <= ARG_FLAG_MAX);
|
||||
return self->flag & ARG_FLAG_SERIALIZED;
|
||||
}
|
||||
|
||||
@ -199,6 +202,7 @@ static inline void arg_setSerialized(Arg* self, uint8_t serialized) {
|
||||
}
|
||||
|
||||
static inline uint8_t arg_getIsKeyword(Arg* self) {
|
||||
pika_assert(self->flag <= ARG_FLAG_MAX);
|
||||
return self->flag & ARG_FLAG_KEYWORD;
|
||||
}
|
||||
|
||||
@ -208,6 +212,7 @@ static inline void arg_setIsKeyword(Arg* self, uint8_t isKeyword) {
|
||||
}
|
||||
|
||||
static inline uint8_t arg_getIsWeakRef(Arg* self) {
|
||||
pika_assert(self->flag <= ARG_FLAG_MAX);
|
||||
return self->flag & ARG_FLAG_WEAK_REF;
|
||||
}
|
||||
|
||||
@ -217,7 +222,28 @@ static inline void arg_setIsWeakRef(Arg* self, uint8_t isWeakRef) {
|
||||
(self->flag & ~ARG_FLAG_WEAK_REF) | (isWeakRef ? ARG_FLAG_WEAK_REF : 0);
|
||||
}
|
||||
|
||||
static inline void arg_setIsStarred(Arg* self, uint8_t isStarred) {
|
||||
self->flag =
|
||||
(self->flag & ~ARG_FLAG_STARRED) | (isStarred ? ARG_FLAG_STARRED : 0);
|
||||
}
|
||||
|
||||
static inline uint8_t arg_getIsStarred(Arg* self) {
|
||||
pika_assert(self->flag <= ARG_FLAG_MAX);
|
||||
return self->flag & ARG_FLAG_STARRED;
|
||||
}
|
||||
|
||||
static inline void arg_setIsDoubleStarred(Arg* self, uint8_t isDoubleStarred) {
|
||||
self->flag = (self->flag & ~ARG_FLAG_DOUBLE_STARRED) |
|
||||
(isDoubleStarred ? ARG_FLAG_DOUBLE_STARRED : 0);
|
||||
}
|
||||
|
||||
static inline uint8_t arg_getIsDoubleStarred(Arg* self) {
|
||||
pika_assert(self->flag <= ARG_FLAG_MAX);
|
||||
return self->flag & ARG_FLAG_DOUBLE_STARRED;
|
||||
}
|
||||
|
||||
static inline uint8_t* arg_getContent(Arg* self) {
|
||||
pika_assert(self->flag <= ARG_FLAG_MAX);
|
||||
pika_assert(NULL != self);
|
||||
return (arg_isSerialized(self)) ? (self)->content : ((self)->_.buffer);
|
||||
}
|
||||
|
@ -502,6 +502,7 @@ PIKA_RES pikaList_setArg(PikaList* self, int index, Arg* arg) {
|
||||
}
|
||||
|
||||
Arg* pikaList_getArg(PikaList* self, int index) {
|
||||
pika_assert(NULL != self);
|
||||
char buff[11];
|
||||
char* i_str = fast_itoa(buff, index);
|
||||
return args_getArg(&self->super, i_str);
|
||||
|
@ -56,6 +56,26 @@ int32_t stack_popSize(Stack* stack) {
|
||||
return *(stack->sp_size);
|
||||
}
|
||||
|
||||
Arg* stack_checkArg(Stack* stack, int index) {
|
||||
if (stack->top - index <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
int sp_offset = 0;
|
||||
int32_t size = 0;
|
||||
for (int i = 1; i <= index + 1; i++) {
|
||||
size = stack->sp_size[-i];
|
||||
if (size == -1) {
|
||||
sp_offset -= sizeof(Arg*);
|
||||
} else {
|
||||
sp_offset -= size;
|
||||
}
|
||||
}
|
||||
if (size == -1) {
|
||||
return *(Arg**)(stack->sp + sp_offset);
|
||||
}
|
||||
return (Arg*)(stack->sp + sp_offset);
|
||||
}
|
||||
|
||||
int32_t stack_deinit(Stack* stack) {
|
||||
while (stack->top > 0) {
|
||||
int32_t size = stack_popSize(stack);
|
||||
|
@ -42,6 +42,7 @@ int32_t stack_deinit(Stack* stack);
|
||||
|
||||
int32_t stack_pushStr(Stack* stack, char* str);
|
||||
char* stack_popStr(Stack* stack, char* outBuff);
|
||||
Arg* stack_checkArg(Stack* stack, int index);
|
||||
int32_t stack_pushArg(Stack* stack, Arg* arg);
|
||||
Arg* stack_popArg_alloc(Stack* stack);
|
||||
Arg* stack_popArg(Stack* stack, Arg* arg_dict);
|
||||
|
@ -2322,6 +2322,39 @@ TEST(vm, fn_pos_kw2) {
|
||||
obj_deinit(pikaMain);
|
||||
EXPECT_EQ(pikaMemNow(), 0);
|
||||
}
|
||||
|
||||
TEST(vm, fn_star) {
|
||||
/* init */
|
||||
pikaMemInfo.heapUsedMax = 0;
|
||||
PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain);
|
||||
/* run */
|
||||
__platform_printf("BEGIN\r\n");
|
||||
obj_run(pikaMain,
|
||||
"a = (1,2,3)\n"
|
||||
"print(*a)\n");
|
||||
/* collect */
|
||||
/* assert */
|
||||
/* deinit */
|
||||
obj_deinit(pikaMain);
|
||||
EXPECT_EQ(pikaMemNow(), 0);
|
||||
}
|
||||
|
||||
TEST(vm, fn_star_star) {
|
||||
/* init */
|
||||
pikaMemInfo.heapUsedMax = 0;
|
||||
PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain);
|
||||
/* run */
|
||||
__platform_printf("BEGIN\r\n");
|
||||
obj_run(pikaMain,
|
||||
"a = {'a':1,'b':2,'c':3}\n"
|
||||
"print(**a)\n");
|
||||
/* collect */
|
||||
/* assert */
|
||||
/* deinit */
|
||||
obj_deinit(pikaMain);
|
||||
EXPECT_EQ(pikaMemNow(), 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST_END
|
@ -696,4 +696,16 @@ TEST(compiler, bc_fn) {
|
||||
EXPECT_EQ(pikaMemNow(), 0);
|
||||
}
|
||||
|
||||
TEST(compiler, starrd) {
|
||||
char* lines = "@l = __len__()";
|
||||
Parser_linesToArray(lines);
|
||||
EXPECT_EQ(pikaMemNow(), 0);
|
||||
}
|
||||
|
||||
TEST(compiler, starrd_get) {
|
||||
char* lines = "@a = __getitem__(@d)";
|
||||
Parser_linesToArray(lines);
|
||||
EXPECT_EQ(pikaMemNow(), 0);
|
||||
}
|
||||
|
||||
TEST_END
|
@ -5026,6 +5026,23 @@ TEST(parser, multi_from_import_as) {
|
||||
EXPECT_EQ(pikaMemNow(), 0);
|
||||
}
|
||||
|
||||
TEST(parser, print_ssa) {
|
||||
pikaMemInfo.heapUsedMax = 0;
|
||||
Args* buffs = New_strBuff();
|
||||
char* lines = "print(**a)\n";
|
||||
printf("%s\r\n", lines);
|
||||
char* pikaAsm = Parser_linesToAsm(buffs, lines);
|
||||
printf("%s", pikaAsm);
|
||||
EXPECT_STREQ(pikaAsm,
|
||||
"B0\n"
|
||||
"2 REF a\n"
|
||||
"1 OPT **\n"
|
||||
"0 RUN print\n"
|
||||
"B0\n");
|
||||
args_deinit(buffs);
|
||||
EXPECT_EQ(pikaMemNow(), 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST_END
|
@ -61,4 +61,18 @@ TEST(stack, str) {
|
||||
EXPECT_EQ(pikaMemNow(), 0);
|
||||
}
|
||||
|
||||
TEST(stack, get_str) {
|
||||
Stack s;
|
||||
stack_init(&s);
|
||||
stack_pushStr(&s, "abc");
|
||||
stack_pushStr(&s, "123");
|
||||
stack_pushStr(&s, "xyz");
|
||||
EXPECT_STREQ(arg_getStr(stack_checkArg(&s, 0)), "xyz");
|
||||
EXPECT_STREQ(arg_getStr(stack_checkArg(&s, 0)), "xyz");
|
||||
EXPECT_STREQ(arg_getStr(stack_checkArg(&s, 1)), "123");
|
||||
EXPECT_STREQ(arg_getStr(stack_checkArg(&s, 2)), "abc");
|
||||
stack_deinit(&s);
|
||||
EXPECT_EQ(pikaMemNow(), 0);
|
||||
}
|
||||
|
||||
TEST_END
|
Loading…
x
Reference in New Issue
Block a user