/* * This file is part of the PikaPython project. * http://github.com/pikastech/pikapython * * MIT License * * Copyright (c) 2021 lyon liang6516@outlook.com * Copyright (c) 2023 Gorgon Meducer embedded_zhuroan@hotmail.com * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "PikaObj.h" #include #include "BaseObj.h" #include "PikaCompiler.h" #include "PikaParser.h" #include "PikaPlatform.h" #include "dataArg.h" #include "dataArgs.h" #include "dataMemory.h" #include "dataQueue.h" #include "dataString.h" #include "dataStrs.h" #if __linux #include "signal.h" #include "termios.h" #include "unistd.h" #endif extern volatile VMState g_PikaVMState; volatile PikaObjState g_PikaObjState = { .helpModulesCmodule = NULL, .inRootObj = pika_false, #if PIKA_GC_MARK_SWEEP_ENABLE .objCnt = 0, .objCntMax = 0, .objCntLastGC = 0, .gcChain = NULL, .markSweepBusy = 0, #endif }; extern volatile PikaObj* __pikaMain; static volatile ShellConfig g_REPL; PikaObj* New_PikaStdData_Dict(Args* args); PikaObj* New_PikaStdData_dict_keys(Args* args); PikaObj* New_PikaStdData_List(Args* args); PikaObj* New_PikaStdData_Tuple(Args* args); void PikaStdData_Tuple___init__(PikaObj* self); void PikaStdData_List___init__(PikaObj* self); void PikaStdData_List_append(PikaObj* self, Arg* arg); void PikaStdData_Dict_set(PikaObj* self, char* key, Arg* value); void PikaStdData_Dict___init__(PikaObj* self); void _mem_cache_deinit(void); void _VMEvent_deinit(void); void pikaGC_markObj(PikaGC* gc, PikaObj* self); void _pikaGC_mark(PikaGC* gc); void obj_dump(PikaObj* self); void Locals_deinit(PikaObj* self); #if __linux static void disable_raw_mode(void); #endif static enum shellCTRL __obj_shellLineHandler_REPL(PikaObj* self, char* input_line, ShellConfig* shell); static const uint64_t __talbe_fast_atoi[][10] = { {0, 1e0, 2e0, 3e0, 4e0, 5e0, 6e0, 7e0, 8e0, 9e0}, {0, 1e1, 2e1, 3e1, 4e1, 5e1, 6e1, 7e1, 8e1, 9e1}, {0, 1e2, 2e2, 3e2, 4e2, 5e2, 6e2, 7e2, 8e2, 9e2}, {0, 1e3, 2e3, 3e3, 4e3, 5e3, 6e3, 7e3, 8e3, 9e3}, {0, 1e4, 2e4, 3e4, 4e4, 5e4, 6e4, 7e4, 8e4, 9e4}, {0, 1e5, 2e5, 3e5, 4e5, 5e5, 6e5, 7e5, 8e5, 9e5}, {0, 1e6, 2e6, 3e6, 4e6, 5e6, 6e6, 7e6, 8e6, 9e6}, {0, 1e7, 2e7, 3e7, 4e7, 5e7, 6e7, 7e7, 8e7, 9e7}, {0, 1e8, 2e8, 3e8, 4e8, 5e8, 6e8, 7e8, 8e8, 9e8}, {0, 1e9, 2e9, 3e9, 4e9, 5e9, 6e9, 7e9, 8e9, 9e9}, }; int64_t fast_atoi(char* src) { const char* p = src; uint16_t size = strGetSize(src); p = p + size - 1; if (*p) { int64_t s = 0; const uint64_t* n = __talbe_fast_atoi[0]; while (p != src) { s += n[(*p - '0')]; n += 10; p--; } if (*p == '-') { return -s; } return s + n[(*p - '0')]; } return 0; } PIKA_RES fast_atoi_safe(char* src, int64_t* out) { // Check is digit char* p = src; while (*p) { if (*p < '0' || *p > '9') { return PIKA_RES_ERR_INVALID_PARAM; } p++; } *out = fast_atoi(src); return PIKA_RES_OK; } static uint16_t const str100p[100] = { 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930, 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931, 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932, 0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933, 0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934, 0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935, 0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936, 0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937, 0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938, 0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939, }; char* fast_itoa(char* buf, uint32_t val) { char* p = &buf[10]; *p = '\0'; while (val >= 100) { uint32_t const old = val; p -= 2; val /= 100; pika_platform_memcpy(p, &str100p[old - (val * 100)], sizeof(uint16_t)); } p -= 2; pika_platform_memcpy(p, &str100p[val], sizeof(uint16_t)); return &p[val < 10]; } static int32_t obj_deinit_no_del(PikaObj* self) { /* free the list */ Locals_deinit(self); args_deinit_ex(self->list, pika_true); #if PIKA_KERNAL_DEBUG_ENABLE if (NULL != self->aName) { arg_deinit(self->aName); } #endif /* remove self from gc chain */ obj_removeGcChain(self); /* free the pointer */ pikaFree(self, sizeof(PikaObj)); if (self == (PikaObj*)__pikaMain) { __pikaMain = NULL; } return 0; } int obj_GC(PikaObj* self) { if (!obj_checkAlive(self)) { return 0; } if (obj_getFlag(self, OBJ_FLAG_IN_DEL)) { /* in __del__, skip gc */ return 0; } obj_refcntDec(self); int ref_cnt = obj_refcntNow(self); if (ref_cnt <= 0) { obj_deinit(self); } return 0; } int32_t obj_deinit(PikaObj* self) { pikaGC_lock(); pika_bool bisRoot = pika_false; #if PIKA_KERNAL_DEBUG_ENABLE self->isAlive = pika_false; #endif Arg* del = obj_getMethodArgWithFullPath(self, "__del__"); if (NULL != del) { obj_setFlag(self, OBJ_FLAG_IN_DEL); Arg* aRes = obj_runMethodArg0(self, del); if (NULL != aRes) { arg_deinit(aRes); } } extern volatile PikaObj* __pikaMain; if (self == (PikaObj*)__pikaMain) { bisRoot = pika_true; _mem_cache_deinit(); #if PIKA_EVENT_ENABLE _VMEvent_deinit(); #endif if (NULL != g_PikaObjState.helpModulesCmodule) { arg_deinit(g_PikaObjState.helpModulesCmodule); g_PikaObjState.helpModulesCmodule = NULL; } } int32_t ret = obj_deinit_no_del(self); pikaGC_unlock(); if (bisRoot) { pikaGC_markSweep(); shConfig_deinit((ShellConfig*)&g_REPL); #if __linux disable_raw_mode(); pika_GIL_deinit(); #endif } return ret; } PIKA_RES obj_setInt(PikaObj* self, char* argPath, int64_t val) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { /* [error] object no found */ return PIKA_RES_ERR_ARG_NO_FOUND; } char* name = strPointToLastToken(argPath, '.'); args_setInt(obj->list, name, val); return PIKA_RES_OK; } PIKA_RES obj_setPtr(PikaObj* self, char* argPath, void* pointer) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { /* [error] object no found */ return PIKA_RES_ERR_ARG_NO_FOUND; } char* name = strPointToLastToken(argPath, '.'); args_setPtr(obj->list, name, pointer); return PIKA_RES_OK; } PIKA_RES obj_setRef(PikaObj* self, char* argPath, PikaObj* pointer) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { /* [error] object no found */ return PIKA_RES_ERR_ARG_NO_FOUND; } char* name = strPointToLastToken(argPath, '.'); args_setRef(obj->list, name, pointer); return PIKA_RES_OK; } PIKA_RES obj_setFloat(PikaObj* self, char* argPath, pika_float value) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { /* [error] object no found */ return PIKA_RES_ERR_ARG_NO_FOUND; } char* name = strPointToLastToken(argPath, '.'); args_setFloat(obj->list, name, value); return PIKA_RES_OK; } PIKA_RES obj_setStr(PikaObj* self, char* argPath, char* str) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { return PIKA_RES_ERR_ARG_NO_FOUND; } char* name = strPointToLastToken(argPath, '.'); return args_setStr(obj->list, name, str); } PIKA_RES obj_setNone(PikaObj* self, char* argPath) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { return PIKA_RES_ERR_ARG_NO_FOUND; } char* name = strPointToLastToken(argPath, '.'); args_setNone(obj->list, name); return PIKA_RES_OK; } PIKA_RES obj_setBytes(PikaObj* self, char* argPath, uint8_t* src, size_t size) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { return PIKA_RES_ERR_ARG_NO_FOUND; } char* name = strPointToLastToken(argPath, '.'); args_setBytes(obj->list, name, src, size); return PIKA_RES_OK; } int64_t obj_getInt(PikaObj* self, char* argPath) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { return _PIKA_INT_ERR; } char* argName = strPointToLastToken(argPath, '.'); int64_t res = args_getInt(obj->list, argName); return res; } pika_bool obj_getBool(PikaObj* self, char* argPath) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { return pika_false; } char* argName = strPointToLastToken(argPath, '.'); pika_bool res = args_getBool(obj->list, argName); return res; } Arg* obj_getArg(PikaObj* self, char* argPath) { pika_assert(obj_checkAlive(self)); pika_bool is_temp = pika_false; PikaObj* obj = obj_getHostObjWithIsTemp(self, argPath, &is_temp); if (NULL == obj) { return NULL; } Arg* res = NULL; char* argName = strPointToLastToken(argPath, '.'); res = args_getArg(obj->list, argName); if (is_temp) { obj_setArg(self, "_buf", res); res = obj_getArg(self, "_buf"); obj_deinit(obj); } return res; } uint8_t* obj_getBytes(PikaObj* self, char* argPath) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { return NULL; } char* argName = strPointToLastToken(argPath, '.'); return args_getBytes(obj->list, argName); } size_t obj_getBytesSize(PikaObj* self, char* argPath) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { return 0; } char* argName = strPointToLastToken(argPath, '.'); return args_getBytesSize(obj->list, argName); } size_t obj_loadBytes(PikaObj* self, char* argPath, uint8_t* out_buff) { size_t size_mem = obj_getBytesSize(self, argPath); void* src = obj_getBytes(self, argPath); if (0 == size_mem) { return 0; } if (NULL == src) { return 0; } pika_platform_memcpy(out_buff, src, size_mem); return size_mem; } void obj_setName(PikaObj* self, char* name) { #if !PIKA_KERNAL_DEBUG_ENABLE return; #else if (strEqu(name, "self")) { return; } if (NULL != self->aName) { if (!strstr(self->name, name)) { self->aName = arg_strAppend(self->aName, "|"); self->aName = arg_strAppend(self->aName, name); } } else { self->aName = arg_newStr(name); } self->name = arg_getStr(self->aName); #endif } static PIKA_RES _obj_setArg(PikaObj* self, char* argPath, Arg* arg, uint8_t is_copy) { pika_assert(obj_checkAlive(self)); /* setArg would copy arg */ PikaObj* host = obj_getHostObj(self, argPath); PikaObj* oNew = NULL; pika_bool bNew = pika_false; if (NULL == host) { /* object no found */ return PIKA_RES_ERR_ARG_NO_FOUND; } char* sArgName = strPointToLastToken(argPath, '.'); Arg* aNew; if (is_copy) { aNew = arg_copy(arg); } else { aNew = arg; } aNew = arg_setName(aNew, sArgName); if (arg_isObject(aNew)) { oNew = arg_getPtr(aNew); bNew = pika_true; pika_assert(obj_checkAlive(oNew)); #if PIKA_KERNAL_DEBUG_ENABLE if (host != oNew) { /* skip self ref */ oNew->parent = host; } #endif obj_setName(oNew, sArgName); } #if 0 if (argType_isObjectMethodActive(arg_getType(arg))) { PikaObj* host_self = methodArg_getHostObj(arg); obj_refcntInc(host_self); } #endif args_setArg(host->list, aNew); /* enable mark sweep to collect this object */ if (bNew) { /* only enable mark sweep after setArg */ obj_enableGC(oNew); } return PIKA_RES_OK; } PIKA_RES obj_setArg(PikaObj* self, char* argPath, Arg* arg) { return _obj_setArg(self, argPath, arg, 1); }; PIKA_RES obj_setArg_noCopy(PikaObj* self, char* argPath, Arg* arg) { return _obj_setArg(self, argPath, arg, 0); } PIKA_RES obj_setObj(PikaObj* self, char* argPath, PikaObj* obj) { Arg* arg = arg_newObj(obj); return obj_setArg_noCopy(self, argPath, arg); } void* obj_getPtr(PikaObj* self, char* argPath) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { return NULL; } char* argName = strPointToLastToken(argPath, '.'); void* res = args_getPtr(obj->list, argName); return res; } pika_float obj_getFloat(PikaObj* self, char* argPath) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { return -999.999; } char* argName = strPointToLastToken(argPath, '.'); pika_float res = args_getFloat(obj->list, argName); return res; } char* obj_getStr(PikaObj* self, char* argPath) { PikaObj* obj = obj_getHostObj(self, argPath); if (NULL == obj) { return NULL; } char* argName = strPointToLastToken(argPath, '.'); char* res = args_getStr(obj->list, argName); return res; } PikaObj* obj_newObjFromConstructor(PikaObj* context, char* name, NewFun constructor) { PikaObj* self = constructor(NULL); self->constructor = constructor; self->refcnt = 1; return self; } static PikaObj* _pika_new_obj_with_args(PikaObj* (*constructor)(), void (*init_func)(PikaObj*), int num_args, va_list args) { PikaObj* obj = newNormalObj(constructor); init_func(obj); if (constructor == New_PikaStdData_Tuple || constructor == New_PikaStdData_List) { for (int i = 0; i < num_args; i++) { Arg* arg = va_arg(args, Arg*); if (num_args == 1 && NULL == arg) { /* empty tuple */ return obj; } pikaList_append(obj, arg); } } else if (constructor == New_PikaStdData_Dict) { if (num_args == 1) { /* empty dict */ return obj; } for (int i = 0; i + 1 < num_args; i += 2) { Arg* aKey = va_arg(args, Arg*); char* sKey = arg_getStr(aKey); Arg* value = va_arg(args, Arg*); pikaDict_set(obj, sKey, value); arg_deinit(aKey); } } return obj; } PikaObj* _pika_tuple_new(int num_args, ...) { va_list args; va_start(args, num_args); PikaObj* tuple = _pika_new_obj_with_args( New_PikaStdData_Tuple, PikaStdData_Tuple___init__, num_args, args); va_end(args); return tuple; } PikaObj* _pika_list_new(int num_args, ...) { va_list args; va_start(args, num_args); PikaObj* list = _pika_new_obj_with_args( New_PikaStdData_List, PikaStdData_List___init__, num_args, args); va_end(args); return list; } PikaObj* _pika_dict_new(int num_args, ...) { va_list args; va_start(args, num_args); PikaObj* dict = _pika_new_obj_with_args( New_PikaStdData_Dict, PikaStdData_Dict___init__, num_args, args); va_end(args); return dict; } NativeProperty* obj_getProp(PikaObj* self) { Arg* aProp = obj_getArg(self, "@p_"); PikaObj* class_obj = NULL; if (NULL == aProp) { if (NULL != self->constructor) { class_obj = obj_getClassObj(self); aProp = obj_getArg(class_obj, "@p_"); } } NativeProperty* prop = NULL; if (aProp == NULL) { goto __exit; } if (arg_getType(aProp) != ARG_TYPE_POINTER) { goto __exit; } prop = (NativeProperty*)arg_getPtr(aProp); __exit: if (NULL != class_obj) { obj_deinit_no_del(class_obj); } return prop; } Arg* _obj_getPropArg(PikaObj* obj, char* name) { NativeProperty* prop = obj_getProp(obj); Hash method_hash = hash_time33(name); Arg* aMethod = NULL; while (1) { if (prop == NULL) { break; } int size = prop->methodGroupCount; pika_assert(size >= 0); /* binary search */ if (size == 0) { goto __next; } #if !PIKA_NANO_ENABLE if (size > 16) { int left = 0; int right = size - 1; int mid = 0; while (1) { if (left > right) { break; } mid = (right + left) >> 1; Arg* prop_this = (Arg*)(prop->methodGroup + mid); if (prop_this->name_hash == method_hash) { aMethod = prop_this; goto __exit; } else if (prop_this->name_hash < method_hash) { left = mid + 1; } else { right = mid - 1; } } goto __next; } #endif for (int i = 0; i < (int)prop->methodGroupCount; i++) { Arg* prop_this = (Arg*)(prop->methodGroup + i); if (prop_this->name_hash == method_hash) { aMethod = prop_this; goto __exit; } } goto __next; __next: prop = (NativeProperty*)prop->super; } __exit: return aMethod; } Arg* _obj_getMethodArg(PikaObj* obj, char* methodName, Arg* arg_reg) { Arg* aMethod = NULL; aMethod = obj_getArg(obj, methodName); if (NULL != aMethod) { aMethod = arg_copy_noalloc(aMethod, arg_reg); goto __exit; } aMethod = _obj_getPropArg(obj, methodName); __exit: return aMethod; } Arg* _obj_getMethodArgWithFullPath(PikaObj* obj, char* methodPath, Arg* arg_reg) { char* methodName = strPointToLastToken(methodPath, '.'); return _obj_getMethodArg(obj, methodName, arg_reg); } Arg* obj_getMethodArgWithFullPath(PikaObj* obj, char* methodPath) { return _obj_getMethodArgWithFullPath(obj, methodPath, NULL); } Arg* obj_getMethodArgWithFullPath_noalloc(PikaObj* obj, char* methodPath, Arg* arg_reg) { return _obj_getMethodArgWithFullPath(obj, methodPath, arg_reg); } Arg* obj_getMethodArg(PikaObj* obj, char* methodName) { return _obj_getMethodArg(obj, methodName, NULL); } Arg* obj_getMethodArg_noalloc(PikaObj* obj, char* methodName, Arg* arg_reg) { return _obj_getMethodArg(obj, methodName, arg_reg); } NewFun obj_getClass(PikaObj* obj) { return (NewFun)obj->constructor; } PikaObj* obj_getClassObj(PikaObj* obj) { NewFun classPtr = obj_getClass(obj); if (NULL == classPtr) { return NULL; } PikaObj* classObj = obj_newObjFromConstructor(obj, "", classPtr); return classObj; } void* getNewClassObjFunByName(PikaObj* obj, char* name) { char* classPath = name; /* init the subprocess */ void* newClassObjFun = args_getPtr(obj->list, classPath); return newClassObjFun; } PikaObj* removeMethodInfo(PikaObj* thisClass) { #if PIKA_METHOD_CACHE_ENABLE #else args_removeArg(thisClass->list, args_getArg(thisClass->list, "@p_")); #endif return thisClass; } PikaObj* newNormalObj(NewFun newObjFun) { PikaObj* thisClass = obj_newObjFromConstructor(NULL, "", newObjFun); obj_setFlag(thisClass, OBJ_FLAG_ALREADY_INIT); return removeMethodInfo(thisClass); } #ifdef __linux #include #include #include #include #define ECHOFLAGS (ECHO | ECHOE | ECHOK | ECHONL) static int set_disp_mode(int fd, int option) { int err; struct termios term; if (tcgetattr(fd, &term) == -1) { perror("Cannot get the attribution of the terminal"); return 1; } if (option) term.c_lflag |= ECHOFLAGS; else term.c_lflag &= ~ECHOFLAGS; err = tcsetattr(fd, TCSAFLUSH, &term); if (err == -1) { perror("Cannot set the attribution of the terminal"); return 1; } return 0; } #endif static volatile uint8_t logo_printed = 0; #if __linux struct termios original_termios; static void enable_raw_mode(void) { struct termios raw; tcgetattr(STDIN_FILENO, &original_termios); raw = original_termios; raw.c_lflag &= ~(ECHO | ICANON); tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw); } static void disable_raw_mode(void) { tcsetattr(STDIN_FILENO, TCSAFLUSH, &original_termios); printf("\n"); } static void signal_handler(int sig) { if (sig == SIGSEGV) { printf("Segmentation fault"); } else if (sig == SIGINT) { printf("Ctrl+C"); } else if (sig == SIGTERM) { printf("SIGTERM"); } else if (sig == SIGHUP) { printf("SIGHUP"); } else if (sig == SIGABRT) { printf("Aborted"); } disable_raw_mode(); exit(1); } #endif extern volatile PikaObj* __pikaMain; PikaObj* newRootObj(char* name, NewFun newObjFun) { g_PikaObjState.inRootObj = pika_true; #if PIKA_POOL_ENABLE mem_pool_init(); #endif #ifdef __linux signal(SIGTERM, signal_handler); signal(SIGHUP, signal_handler); signal(SIGSEGV, signal_handler); signal(SIGABRT, signal_handler); signal(SIGQUIT, signal_handler); signal(SIGTRAP, signal_handler); signal(SIGHUP, signal_handler); enable_raw_mode(); #endif PikaObj* newObj = newNormalObj(newObjFun); if (!logo_printed) { logo_printed = 1; pika_platform_printf("\r\n"); pika_platform_printf("~~~/ POWERED BY \\~~~\r\n"); pika_platform_printf("~ pikapython.com ~\r\n"); pika_platform_printf("~~~~~~~~~~~~~~~~~~~~\r\n"); } if (NULL != __pikaMain) { pika_platform_printf("Error: root object already exists\r\n"); pika_platform_panic_handle(); return NULL; } __pikaMain = newObj; obj_setName(newObj, name); g_PikaObjState.inRootObj = pika_false; return newObj; } Arg* arg_newMetaObj(NewFun new_obj_fun) { Arg* arg_new = New_arg(NULL); /* m means meta-object */ arg_new = arg_setPtr(arg_new, "", ARG_TYPE_OBJECT_META, (void*)new_obj_fun); return arg_new; } Arg* arg_newDirectObj(NewFun new_obj_fun) { PikaObj* newObj = newNormalObj(new_obj_fun); Arg* arg_new = arg_newPtr(ARG_TYPE_OBJECT_NEW, newObj); return arg_new; } Arg* obj_newObjInPackage(NewFun new_obj_fun) { return arg_newDirectObj(new_obj_fun); } static PikaObj* _obj_initMetaObj(PikaObj* obj, char* name) { PikaObj* res = NULL; NewFun constructor = (NewFun)getNewClassObjFunByName(obj, name); Args buffs = {0}; PikaObj* thisClass; PikaObj* oNew; if (NULL == constructor) { /* no such object */ res = NULL; goto __exit; } thisClass = obj_newObjFromConstructor(obj, name, constructor); oNew = removeMethodInfo(thisClass); obj_setName(oNew, name); obj_runNativeMethod(oNew, "__init__", NULL); args_setPtrWithType(obj->list, name, ARG_TYPE_OBJECT, oNew); res = obj_getPtr(obj, name); // pikaGC_enable(res); goto __exit; __exit: strsDeinit(&buffs); return res; } PikaObj* _arg_to_obj(Arg* self, pika_bool* pIsTemp) { if (NULL == self) { return NULL; } if (arg_isObject(self)) { return arg_getPtr(self); } #if !PIKA_NANO_ENABLE if (arg_getType(self) == ARG_TYPE_STRING) { PikaObj* New_PikaStdData_String(Args * args); PikaObj* obj = newNormalObj(New_PikaStdData_String); obj_setStr(obj, "str", arg_getStr(self)); if (NULL != pIsTemp) { *pIsTemp = pika_true; } return obj; } if (arg_getType(self) == ARG_TYPE_BYTES) { PikaObj* New_PikaStdData_ByteArray(Args * args); PikaObj* obj = newNormalObj(New_PikaStdData_ByteArray); obj_setArg(obj, "raw", self); if (NULL != pIsTemp) { *pIsTemp = pika_true; } return obj; } #endif return NULL; } static PikaObj* _obj_getObjDirect(PikaObj* self, char* name, pika_bool* pIsTemp) { *pIsTemp = pika_false; if (NULL == self) { return NULL; } /* finded object, check type*/ Arg* aObj = args_getArg(self->list, name); ArgType type = ARG_TYPE_NONE; if (NULL == aObj) { aObj = _obj_getPropArg(self, name); } if (NULL == aObj) { return NULL; } type = arg_getType(aObj); /* found meta Object */ if (type == ARG_TYPE_OBJECT_META) { return _obj_initMetaObj(self, name); } /* found Objcet */ if (argType_isObject(type)) { return arg_getPtr(aObj); } #if !PIKA_NANO_ENABLE /* found class */ if (type == ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR || type == ARG_TYPE_METHOD_CONSTRUCTOR) { *pIsTemp = pika_true; PikaObj* oMethodArgs = New_TinyObj(NULL); Arg* aClsObj = obj_runMethodArg(self, oMethodArgs, aObj); obj_deinit(oMethodArgs); Args* args = New_args(NULL); if (type == ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR) { obj_runNativeMethod(arg_getPtr(aClsObj), "__init__", args); } PikaObj* res = arg_getPtr(aClsObj); arg_deinit(aClsObj); args_deinit(args); return res; } #endif return _arg_to_obj(aObj, pIsTemp); } static PikaObj* _obj_getObjWithKeepDeepth(PikaObj* self, char* objPath, pika_bool* pIsTemp, int32_t keepDeepth) { char objPath_buff[PIKA_PATH_BUFF_SIZE]; char* objPath_ptr = objPath_buff; pika_assert(NULL != objPath); if ('.' == objPath[0] && '\0' == objPath[1]) { return self; } pika_assert(strGetSize(objPath) < PIKA_PATH_BUFF_SIZE); strcpy(objPath_buff, objPath); int32_t token_num = strGetTokenNum(objPath, '.'); PikaObj* objThis = self; PikaObj* objNext = NULL; pika_bool bThisIsTemp = pika_false; for (int32_t i = 0; i < token_num - keepDeepth; i++) { char* token = strPopFirstToken(&objPath_ptr, '.'); objNext = _obj_getObjDirect(objThis, token, pIsTemp); if (objNext == NULL) { objThis = NULL; goto __exit; } if (bThisIsTemp) { if (*pIsTemp == pika_false) { obj_refcntInc(objNext); *pIsTemp = pika_true; } obj_deinit(objThis); } pika_assert_obj_alive(objNext); objThis = objNext; bThisIsTemp = *pIsTemp; } goto __exit; __exit: if (NULL != objThis) { pika_assert(obj_checkAlive(objThis)); } return objThis; } PikaObj* obj_getObj(PikaObj* self, char* objPath) { pika_assert(NULL != objPath); pika_bool is_temp = pika_false; return _obj_getObjWithKeepDeepth(self, objPath, &is_temp, 0); } PikaObj* obj_getHostObj(PikaObj* self, char* objPath) { pika_assert(NULL != objPath); pika_bool is_temp = pika_false; return _obj_getObjWithKeepDeepth(self, objPath, &is_temp, 1); } PikaObj* obj_getHostObjWithIsTemp(PikaObj* self, char* objPath, pika_bool* pIsTemp) { return _obj_getObjWithKeepDeepth(self, objPath, pIsTemp, 1); } Method methodArg_getPtr(Arg* method_arg) { MethodProp* method_store = (MethodProp*)arg_getContent(method_arg); return (Method)method_store->ptr; } Arg* _get_return_arg(PikaObj* locals); NativeProperty* methodArg_toProp(Arg* method_arg) { pika_assert(arg_getType(method_arg) == ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR); PikaObj* locals = New_TinyObj(NULL); MethodProp* method_store = (MethodProp*)arg_getContent(method_arg); Method fMethod = (Method)method_store->ptr; fMethod(NULL, locals->list); Arg* aReturn = _get_return_arg(locals); if (arg_getType(aReturn) == ARG_TYPE_OBJECT_NEW) { arg_setType(aReturn, ARG_TYPE_OBJECT); } PikaObj* obj = arg_getPtr(aReturn); NativeProperty* prop = obj_getProp(obj); arg_deinit(aReturn); obj_deinit(locals); return prop; } char* methodArg_getTypeList(Arg* method_arg, char* buffs, size_t size) { pika_assert(arg_isCallable(method_arg)); MethodProp* prop = (MethodProp*)arg_getContent(method_arg); if (NULL != prop->type_list) { pika_assert(strGetSize(prop->type_list) < size); return strcpy(buffs, prop->type_list); } char* method_dec = methodArg_getDec(method_arg); pika_assert(strGetSize(method_dec) <= size); if (strGetSize(method_dec) > size) { pika_platform_printf( "OverFlowError: please use bigger PIKA_LINE_BUFF_SIZE\r\n"); while (1) { } } char* res = strCut(buffs, method_dec, '(', ')'); return res; } MethodProp* methodArg_getProp(Arg* method_arg) { return (MethodProp*)arg_getContent(method_arg); } PikaObj* methodArg_getHostObj(Arg* method_arg) { pika_assert(argType_isObjectMethodActive(arg_getType(method_arg))); MethodProp* prop = (MethodProp*)arg_getContent(method_arg); return prop->host_obj; } Arg* methodArg_active(Arg* method_arg) { pika_assert(arg_getType(method_arg) == ARG_TYPE_METHOD_NATIVE); Arg* aActive = New_arg(NULL); MethodPropNative* propNative = (MethodPropNative*)arg_getContent(method_arg); MethodProp prop = {0}; /* active the method */ pika_platform_memcpy(&prop, propNative, sizeof(MethodPropNative)); aActive = arg_setStruct(aActive, "", (uint8_t*)&prop, sizeof(MethodProp)); arg_setType(aActive, ARG_TYPE_METHOD_NATIVE_ACTIVE); return aActive; } Arg* methodArg_setHostObj(Arg* method_arg, PikaObj* host_obj) { if (!argType_isObjectMethod(arg_getType(method_arg))) { return method_arg; } if (arg_getType(method_arg) == ARG_TYPE_METHOD_NATIVE) { method_arg = methodArg_active(method_arg); } MethodProp* prop = (MethodProp*)arg_getContent(method_arg); if (prop->host_obj == NULL) { prop->host_obj = host_obj; #if 0 obj_refcntInc(host_obj); #endif return method_arg; } return method_arg; } char* methodArg_getName(Arg* method_arg, char* buffs, size_t size) { MethodProp* method_store = (MethodProp*)arg_getContent(method_arg); if (NULL != method_store->name) { return strcpy(buffs, method_store->name); } char* method_dec = methodArg_getDec(method_arg); pika_assert(strGetSize(method_dec) <= size); char* res = strGetFirstToken(buffs, method_dec, '('); return res; } char* _find_super_class_name(ByteCodeFrame* bcframe, int32_t pc_start); Arg* methodArg_super(Arg* aThis, NativeProperty** p_prop) { Arg* aSuper = NULL; PikaObj* builtins = NULL; ArgType type = arg_getType(aThis); *p_prop = NULL; if (!argType_isConstructor(type)) { aSuper = NULL; goto __exit; } if (type == ARG_TYPE_METHOD_CONSTRUCTOR) { builtins = obj_getBuiltins(); MethodProp* method_store = (MethodProp*)arg_getContent(aThis); ByteCodeFrame* bcframe = method_store->bytecode_frame; int32_t pc = (uintptr_t)method_store->ptr - (uintptr_t)bcframe->instruct_array.content_start; char* sSuper = _find_super_class_name(bcframe, pc); /* map TinyObj to object */ if (strEqu(sSuper, "TinyObj")) { sSuper = "object"; } PikaObj* context = method_store->def_context; aSuper = obj_getMethodArgWithFullPath(context, sSuper); if (NULL == aSuper) { aSuper = obj_getMethodArgWithFullPath(builtins, sSuper); } goto __exit; } if (type == ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR) { NativeProperty* prop = methodArg_toProp(aThis); *p_prop = prop; arg_deinit(aThis); aSuper = NULL; goto __exit; } __exit: if (NULL != builtins) { obj_deinit(builtins); } if (NULL != aSuper) { arg_deinit(aThis); } return aSuper; } Method obj_getNativeMethod(PikaObj* self, char* method_name) { Arg* method_arg = obj_getMethodArgWithFullPath(self, method_name); if (NULL == method_arg) { return NULL; } Method res = methodArg_getPtr(method_arg); arg_deinit(method_arg); return res; } ByteCodeFrame* methodArg_getBytecodeFrame(Arg* method_arg) { MethodProp* method_store = (MethodProp*)arg_getContent(method_arg); return method_store->bytecode_frame; } char* methodArg_getDec(Arg* method_arg) { MethodProp* method_store = (MethodProp*)arg_getContent(method_arg); return method_store->declareation; } PikaObj* methodArg_getDefContext(Arg* method_arg) { MethodProp* method_store = (MethodProp*)arg_getContent(method_arg); return method_store->def_context; } void _update_proxy(PikaObj* self, char* name) { #if PIKA_NANO_ENABLE return; #endif if (name[0] != '_' || name[1] != '_') { return; } if (!obj_getFlag(self, OBJ_FLAG_PROXY_GETATTRIBUTE)) { if (strEqu(name, "__getattribute__")) { obj_setFlag(self, OBJ_FLAG_PROXY_GETATTRIBUTE); return; } } if (!obj_getFlag(self, OBJ_FLAG_PROXY_GETATTR)) { if (strEqu(name, "__getattr__")) { obj_setFlag(self, OBJ_FLAG_PROXY_GETATTR); return; } } if (!obj_getFlag(self, OBJ_FLAG_PROXY_SETATTR)) { if (strEqu(name, "__setattr__")) { obj_setFlag(self, OBJ_FLAG_PROXY_SETATTR); return; } } if (!obj_getFlag(self, OBJ_FLAG_PROXY_METHOD)) { if (strEqu(name, "__proxy__")) { obj_setFlag(self, OBJ_FLAG_PROXY_METHOD); return; } } } static void obj_saveMethodInfo(PikaObj* self, MethodInfo* tInfo) { Arg* aMethod = New_arg(NULL); MethodProp tProp = { .ptr = tInfo->ptr, .type_list = tInfo->typelist, .name = tInfo->name, .bytecode_frame = tInfo->bytecode_frame, .def_context = tInfo->def_context, .declareation = tInfo->dec, // const .host_obj = NULL, }; char* name = tInfo->name; if (NULL == tInfo->name) { char name_buff[PIKA_LINE_BUFF_SIZE / 2] = {0}; name = strGetFirstToken(name_buff, tInfo->dec, '('); } /* the first arg_value */ aMethod = arg_setStruct(aMethod, name, &tProp, sizeof(tProp)); pika_assert(NULL != aMethod); arg_setType(aMethod, tInfo->type); _update_proxy(self, name); args_setArg(self->list, aMethod); } static int32_t __class_defineMethodWithType(PikaObj* self, char* declareation, char* name, char* typelist, Method method_ptr, ArgType method_type, PikaObj* def_context, ByteCodeFrame* bytecode_frame) { int32_t res = 0; Args buffs = {0}; PikaObj* method_host = self; MethodInfo method_info = {0}; if (NULL == method_host) { /* no found method object */ res = 1; goto __exit; } method_info.dec = declareation; method_info.name = name; method_info.ptr = (void*)method_ptr; method_info.type = method_type; method_info.def_context = def_context; method_info.bytecode_frame = bytecode_frame; method_info.typelist = typelist; obj_saveMethodInfo(method_host, &method_info); res = 0; goto __exit; __exit: strsDeinit(&buffs); return res; } /* define a constructor method */ int32_t class_defineConstructor(PikaObj* self, char* name, char* typelist, Method methodPtr) { return __class_defineMethodWithType(self, NULL, name, typelist, methodPtr, ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR, NULL, NULL); } /* define a native method as default */ int32_t class_defineMethod(PikaObj* self, char* name, char* typelist, Method methodPtr) { return __class_defineMethodWithType(self, NULL, name, typelist, methodPtr, ARG_TYPE_METHOD_NATIVE, NULL, NULL); } /* define object method, object method is which startwith (self) */ int32_t class_defineRunTimeConstructor(PikaObj* self, char* declareation, Method methodPtr, PikaObj* def_context, ByteCodeFrame* bytecode_frame) { return __class_defineMethodWithType(self, declareation, NULL, NULL, methodPtr, ARG_TYPE_METHOD_CONSTRUCTOR, def_context, bytecode_frame); } /* define object method, object method is which startwith (self) */ int32_t class_defineObjectMethod(PikaObj* self, char* declareation, Method methodPtr, PikaObj* def_context, ByteCodeFrame* bytecode_frame) { return __class_defineMethodWithType(self, declareation, NULL, NULL, methodPtr, ARG_TYPE_METHOD_OBJECT, def_context, bytecode_frame); } /* define a static method as default */ int32_t class_defineStaticMethod(PikaObj* self, char* declareation, Method methodPtr, PikaObj* def_context, ByteCodeFrame* bytecode_frame) { return __class_defineMethodWithType(self, declareation, NULL, NULL, methodPtr, ARG_TYPE_METHOD_STATIC, def_context, bytecode_frame); } int32_t obj_removeArg(PikaObj* self, char* argPath) { PikaObj* objHost = obj_getHostObj(self, argPath); char* argName; int32_t res; int32_t err = 0; if (NULL == objHost) { /* [error] object no found */ err = 1; goto __exit; } argName = strPointToLastToken(argPath, '.'); res = args_removeArg(objHost->list, args_getArg(objHost->list, argName)); if (1 == res) { /*[error] not found arg*/ err = 2; goto __exit; } goto __exit; __exit: return err; } pika_bool obj_isArgExist(PikaObj* self, char* argPath) { if (NULL == argPath) { return 0; } PikaObj* obj_host = obj_getHostObj(self, argPath); if (obj_host == NULL) { return pika_false; } int32_t res = 0; char* argName; Arg* arg; pika_assert(NULL != obj_host); argName = strPointToLastToken(argPath, '.'); arg = args_getArg(obj_host->list, argName); if (NULL == arg) { /* no found arg */ res = 0; goto __exit; } /* found arg */ res = 1; goto __exit; __exit: return res; } pika_bool obj_isMethodExist(PikaObj* self, char* method) { Arg* arg = obj_getMethodArg(self, method); if (NULL == arg) { return pika_false; } arg_deinit(arg); return pika_true; } VMParameters* obj_run(PikaObj* self, char* cmd) { return pikaVM_run(self, cmd); } PIKA_RES obj_runNativeMethod(PikaObj* self, char* method_name, Args* args) { Method native_method = obj_getNativeMethod(self, method_name); if (NULL == native_method) { return PIKA_RES_ERR_ARG_NO_FOUND; } native_method(self, args); return PIKA_RES_OK; } static void __clearBuff(ShellConfig* shell) { memset(shell->lineBuff, 0, PIKA_LINE_BUFF_SIZE); shell->line_curpos = 0; shell->line_position = 0; } enum PIKA_SHELL_STATE { PIKA_SHELL_STATE_NORMAL, PIKA_SHELL_STATE_WAIT_SPEC_KEY, PIKA_SHELL_STATE_WAIT_FUNC_KEY, }; static void _obj_runChar_beforeRun(PikaObj* self, ShellConfig* shell) { /* create the line buff for the first time */ shell->inBlock = pika_false; shell->stat = PIKA_SHELL_STATE_NORMAL; shell->line_position = 0; shell->line_curpos = 0; __clearBuff(shell); pika_platform_printf("%s", shell->prefix); } static void _putc_cmd(char KEY_POS, int pos) { const char cmd[] = {0x1b, 0x5b, KEY_POS, 0x00}; for (int i = 0; i < pos; i++) { pika_platform_printf((char*)cmd); } } #if PIKA_SHELL_FILTER_ENABLE typedef enum { __FILTER_NO_RESULT, __FILTER_FAIL_DROP_ONE, __FILTER_SUCCESS_GET_ALL_PEEKED, __FILTER_SUCCESS_DROP_ALL_PEEKED } FilterReturn; pika_bool _filter_msg_hi_pika_handler(FilterItem* msg, PikaObj* self, ShellConfig* shell) { pika_platform_printf("Yes, I am here\r\n"); return pika_true; } pika_bool _filter_msg_bye_pika_handler(FilterItem* msg, PikaObj* self, ShellConfig* shell) { pika_platform_printf("OK, see you\r\n"); return pika_true; } #define __MSG_DECLARE #include "__default_filter_msg_table.h" static const FilterItem g_default_filter_messages[] = { #define __MSG_TABLE #include "__default_filter_msg_table.h" }; static FilterReturn _do_message_filter(PikaObj* self, ShellConfig* shell, FilterItem* msg, uint_fast16_t count) { pika_assert(NULL != msg); pika_assert(count > 0); ByteQueue* queue = &shell->filter_fifo.queue; FilterReturn result = __FILTER_FAIL_DROP_ONE; do { do { if (msg->ignore_mask & shell->filter_fifo.ignore_mask) { /* this message should be ignored */ break; } if (NULL == msg->message) { break; } uint_fast16_t message_size = msg->size; if (!message_size) { break; } byteQueue_resetPeek(queue); /* do message comparison */ uint8_t* src = (uint8_t*)msg->message; if (msg->is_case_insensitive) { do { uint8_t byte; if (!byteQueue_peekOne(queue, &byte)) { result = __FILTER_NO_RESULT; break; } char letter = *src++; if (letter >= 'A' && letter <= 'Z') { letter += 'a' - 'A'; } if (byte >= 'A' && byte <= 'Z') { byte += 'a' - 'A'; } if (letter != byte) { break; } } while (--message_size); } else { do { uint8_t byte; if (!byteQueue_peekOne(queue, &byte)) { result = __FILTER_NO_RESULT; break; } if (*src++ != byte) { break; } } while (--message_size); } if (0 == message_size) { /* message match */ if (NULL != msg->handler) { if (!msg->handler(msg, self, shell)) { break; } } /* message is handled */ if (msg->is_visible) { return __FILTER_SUCCESS_GET_ALL_PEEKED; } return __FILTER_SUCCESS_DROP_ALL_PEEKED; } } while (0); msg++; } while (--count); return result; } #ifndef dimof #define dimof(__array) (sizeof(__array) / sizeof(__array[0])) #endif int16_t _do_stream_filter(PikaObj* self, ShellConfig* shell) { ByteQueue* queue = &shell->filter_fifo.queue; FilterReturn result = _do_message_filter(self, shell, (FilterItem*)g_default_filter_messages, dimof(g_default_filter_messages)); int16_t drop_count = 0; switch (result) { case __FILTER_NO_RESULT: break; case __FILTER_FAIL_DROP_ONE: drop_count = 1; break; case __FILTER_SUCCESS_DROP_ALL_PEEKED: byteQueue_dropAllPeeked(queue); return 0; case __FILTER_SUCCESS_GET_ALL_PEEKED: drop_count = byteQueue_getPeekedNumber(queue); return drop_count; } /* user registered message filter */ if (NULL != shell->messages && shell->message_count) { result = _do_message_filter(self, shell, shell->messages, shell->message_count); switch (result) { case __FILTER_NO_RESULT: break; case __FILTER_FAIL_DROP_ONE: drop_count = 1; break; case __FILTER_SUCCESS_DROP_ALL_PEEKED: byteQueue_dropAllPeeked(&shell->filter_fifo.queue); return 0; case __FILTER_SUCCESS_GET_ALL_PEEKED: drop_count = byteQueue_getPeekedNumber(&shell->filter_fifo.queue); return drop_count; } } return drop_count; } #endif #if PIKA_SHELL_HISTORY_ENABLE ShellHistory* shHistory_create(int max_size) { ShellHistory* self = (ShellHistory*)pikaMalloc(sizeof(ShellHistory)); self->max_size = max_size; self->current = -1; self->count = 0; self->last_offset = 0; self->cached_current = 0; self->history = (char**)pikaMalloc(max_size * sizeof(char*)); return self; } void shHistory_destroy(ShellHistory* self) { for (int i = 0; i < self->count; i++) { pikaFree(self->history[i], strGetSize(self->history[i]) + 1); } pikaFree(self->history, sizeof(char*) * self->max_size); pikaFree(self, sizeof(ShellHistory)); } void shHistory_add(ShellHistory* self, char* command) { if (self->count == self->max_size) { pikaFree(self->history[0], strGetSize(self->history[0]) + 1); pika_platform_memmove(self->history, self->history + 1, (self->max_size - 1) * sizeof(char*)); self->count--; } /* filter for empty command */ if (self->count > 0 && self->history[self->count - 1][0] == '\0') { pikaFree(self->history[self->count - 1], strGetSize(self->history[self->count - 1]) + 1); self->count--; } /* filter for same command */ if (self->count > 0 && strEqu(self->history[self->count - 1], command)) { return; } self->history[self->count] = pikaMalloc(strGetSize(command) + 1); pika_platform_memcpy(self->history[self->count], command, strGetSize(command) + 1); self->count++; self->current = self->count - 1; self->last_offset = 0; } char* shHistory_get(ShellHistory* self, int offset) { int actual_offset = offset + self->last_offset; int index = self->current + actual_offset; if (index < 0 || index >= self->count) { return NULL; } self->last_offset = actual_offset; return self->history[index]; } char* shHistory_getPrev(ShellHistory* self) { return shHistory_get(self, -1); } char* shHistory_getNext(ShellHistory* self) { return shHistory_get(self, 1); } #endif #define PIKA_BACKSPACE() pika_platform_printf(" \b") #if __linux #define PIKA_BACKSPACE_FORCE() printf("\b \b") #else #define PIKA_BACKSPACE_FORCE() pika_platform_printf("\b \b") #endif static void handle_history_navigation(char inputChar, ShellConfig* shell, pika_bool bIsUp) { #if PIKA_SHELL_HISTORY_ENABLE if (NULL == shell->history) { shell->history = shHistory_create(PIKA_SHELL_HISTORY_NUM); } if (0 == shell->history->cached_current) { /* save the current line */ shHistory_add(shell->history, shell->lineBuff); shell->history->cached_current = 1; } char* history_line = bIsUp ? shHistory_getPrev(shell->history) : shHistory_getNext(shell->history); if (NULL == history_line) { return; } /* move to the last position */ for (int i = 0; i < shell->line_position - shell->line_curpos; i++) { _putc_cmd(PIKA_KEY_RIGHT, 1); } /* clear the current line */ for (int i = 0; i < shell->line_position; i++) { PIKA_BACKSPACE_FORCE(); } pika_platform_memcpy(shell->lineBuff, history_line, strGetSize(history_line) + 1); /* show the previous line */ pika_platform_printf("%s", shell->lineBuff); shell->line_position = strGetSize(history_line); shell->line_curpos = shell->line_position; #endif return; } enum shellCTRL _inner_do_obj_runChar(PikaObj* self, char inputChar, ShellConfig* shell) { char* input_line = NULL; enum shellCTRL ctrl = SHELL_CTRL_CONTINUE; if (inputChar == 0x7F) { inputChar = '\b'; } if (g_REPL.no_echo == pika_false) { #if __linux printf("%c", inputChar); #elif !(defined(_WIN32)) pika_platform_printf("%c", inputChar); #endif } if (inputChar == '\n' && shell->lastChar == '\r') { ctrl = SHELL_CTRL_CONTINUE; goto __exit; } if (inputChar == 0x1b) { shell->stat = PIKA_SHELL_STATE_WAIT_SPEC_KEY; ctrl = SHELL_CTRL_CONTINUE; goto __exit; } if (shell->stat == PIKA_SHELL_STATE_WAIT_SPEC_KEY) { if (inputChar == 0x5b) { shell->stat = PIKA_SHELL_STATE_WAIT_FUNC_KEY; ctrl = SHELL_CTRL_CONTINUE; goto __exit; } else { shell->stat = PIKA_SHELL_STATE_NORMAL; } } if (shell->stat == PIKA_SHELL_STATE_WAIT_FUNC_KEY) { shell->stat = PIKA_SHELL_STATE_NORMAL; if (inputChar == PIKA_KEY_LEFT) { if (shell->line_curpos) { shell->line_curpos--; } else { pika_platform_printf(" "); } ctrl = SHELL_CTRL_CONTINUE; goto __exit; } if (inputChar == PIKA_KEY_RIGHT) { if (shell->line_curpos < shell->line_position) { // pika_platform_printf("%c", // shell->lineBuff[shell->line_curpos]); shell->line_curpos++; } else { pika_platform_printf("\b"); } ctrl = SHELL_CTRL_CONTINUE; goto __exit; } if (inputChar == PIKA_KEY_UP) { _putc_cmd(PIKA_KEY_DOWN, 1); ctrl = SHELL_CTRL_CONTINUE; handle_history_navigation(inputChar, shell, pika_true); goto __exit; } if (inputChar == PIKA_KEY_DOWN) { ctrl = SHELL_CTRL_CONTINUE; handle_history_navigation(inputChar, shell, pika_false); goto __exit; } } if (inputChar == '\b') { if (shell->line_curpos == 0) { #if __linux printf(" "); #else pika_platform_printf(" "); #endif ctrl = SHELL_CTRL_CONTINUE; goto __exit; } PIKA_BACKSPACE(); shell->line_position--; shell->line_curpos--; pika_platform_memmove(shell->lineBuff + shell->line_curpos, shell->lineBuff + shell->line_curpos + 1, shell->line_position - shell->line_curpos); shell->lineBuff[shell->line_position] = 0; if (shell->line_curpos != shell->line_position) { /* update screen */ pika_platform_printf("%s", shell->lineBuff + shell->line_curpos); pika_platform_printf(" "); _putc_cmd(PIKA_KEY_LEFT, shell->line_position - shell->line_curpos + 1); } ctrl = SHELL_CTRL_CONTINUE; goto __exit; } if ((inputChar != '\r') && (inputChar != '\n')) { if (shell->line_position + 1 >= PIKA_LINE_BUFF_SIZE) { pika_platform_printf( "\r\nError: line buff overflow, please use bigger " "'PIKA_LINE_BUFF_SIZE'\r\n"); ctrl = SHELL_CTRL_EXIT; __clearBuff(shell); goto __exit; } if ('\0' != inputChar) { pika_platform_memmove(shell->lineBuff + shell->line_curpos + 1, shell->lineBuff + shell->line_curpos, shell->line_position - shell->line_curpos); shell->lineBuff[shell->line_position + 1] = 0; if (shell->line_curpos != shell->line_position) { pika_platform_printf("%s", shell->lineBuff + shell->line_curpos + 1); _putc_cmd(PIKA_KEY_LEFT, shell->line_position - shell->line_curpos); } shell->lineBuff[shell->line_curpos] = inputChar; shell->line_position++; shell->line_curpos++; } ctrl = SHELL_CTRL_CONTINUE; goto __exit; } if ((inputChar == '\r') || (inputChar == '\n')) { #if !(defined(__linux) || defined(_WIN32) || PIKA_SHELL_NO_NEWLINE) pika_platform_printf("\r\n"); #endif #if PIKA_SHELL_HISTORY_ENABLE if (NULL == shell->history) { shell->history = shHistory_create(PIKA_SHELL_HISTORY_NUM); } if (shell->lineBuff[0] != '\0') { shHistory_add(shell->history, shell->lineBuff); } shell->history->last_offset = 0; shell->history->cached_current = 0; #endif /* still in block */ if (shell->blockBuffName != NULL && shell->inBlock) { /* load new line into buff */ Args buffs = {0}; char _n = '\n'; strAppendWithSize(shell->lineBuff, &_n, 1); char* shell_buff_new = strsAppend(&buffs, obj_getStr(self, shell->blockBuffName), shell->lineBuff); obj_setStr(self, shell->blockBuffName, shell_buff_new); strsDeinit(&buffs); /* go out from block */ if ((shell->lineBuff[0] != ' ') && (shell->lineBuff[0] != '\t')) { shell->inBlock = pika_false; input_line = obj_getStr(self, shell->blockBuffName); ctrl = shell->handler(self, input_line, shell); __clearBuff(shell); pika_platform_printf(">>> "); goto __exit; } else { pika_platform_printf("... "); } __clearBuff(shell); ctrl = SHELL_CTRL_CONTINUE; goto __exit; } /* go in block */ if (shell->blockBuffName != NULL && 0 != strGetSize(shell->lineBuff)) { if (shell->lineBuff[strGetSize(shell->lineBuff) - 1] == ':') { shell->inBlock = pika_true; char _n = '\n'; strAppendWithSize(shell->lineBuff, &_n, 1); obj_setStr(self, shell->blockBuffName, shell->lineBuff); __clearBuff(shell); pika_platform_printf("... "); ctrl = SHELL_CTRL_CONTINUE; goto __exit; } } shell->lineBuff[shell->line_position] = '\0'; ctrl = shell->handler(self, shell->lineBuff, shell); if (SHELL_CTRL_EXIT != ctrl) { pika_platform_printf("%s", shell->prefix); } __clearBuff(shell); goto __exit; } __exit: shell->lastChar = inputChar; return ctrl; } PIKA_WEAK enum shellCTRL _do_obj_runChar(PikaObj* self, char inputChar, ShellConfig* shell) { #if PIKA_SHELL_FILTER_ENABLE ByteQueue* queue = &(shell->filter_fifo.queue); /* validation */ if (NULL == queue->buffer) { /* need initialize first */ byteQueue_init(queue, &shell->filter_fifo.buffer, sizeof(shell->filter_fifo.buffer), pika_false); } pika_bool result = byteQueue_writeOne(queue, inputChar); (void)result; pika_assert(result != pika_false); int16_t byte_count; do { if (0 == byteQueue_peekAvailableCount(queue)) { break; } byte_count = _do_stream_filter(self, shell); int16_t n = byte_count; while (n--) { result = byteQueue_readOne(queue, (uint8_t*)&inputChar); pika_assert(pika_false != result); if (SHELL_CTRL_EXIT == _inner_do_obj_runChar(self, inputChar, shell)) { return SHELL_CTRL_EXIT; } } } while (byte_count); return SHELL_CTRL_CONTINUE; #else return _inner_do_obj_runChar(self, inputChar, shell); #endif } enum shellCTRL obj_runChar(PikaObj* self, char inputChar) { ShellConfig* shell = args_getHeapStruct(self->list, "@shcfg"); if (NULL == shell) { /* init the shell */ ShellConfig newShell = {0}; newShell.prefix = ">>> "; newShell.blockBuffName = "@sh1"; newShell.handler = __obj_shellLineHandler_REPL; args_setHeapStruct(self->list, "@shcfg", newShell, shConfig_deinit); shell = args_getHeapStruct(self->list, "@shcfg"); _obj_runChar_beforeRun(self, shell); } return _do_obj_runChar(self, inputChar, shell); } static void _save_file(char* file_name, uint8_t* buff, size_t size) { pika_platform_printf("[ Info] Saving file to '%s'...\r\n", file_name); FILE* fp = pika_platform_fopen(file_name, "wb+"); if (NULL == fp) { pika_platform_printf("[ Error] Open file '%s' error!\r\n", file_name); pika_platform_fclose(fp); } else { if (pika_platform_fwrite(buff, 1, size, fp) != size) { pika_platform_printf("[ Error] Failed to write to '%s'...\r\n", file_name); pika_platform_fclose(fp); pika_platform_printf("[ Info] Removing '%s'...\r\n", file_name); pika_platform_remove(file_name); return; } else { pika_platform_printf("[ Info] Writing %d bytes to '%s'...\r\n", (int)(size), file_name); } pika_platform_fclose(fp); pika_platform_printf("[ OK ] Writing to '%s' succeed!\r\n", file_name); } } char _await_getchar(sh_getchar fn_getchar) { pika_GIL_EXIT(); char ret = fn_getchar(); pika_GIL_ENTER(); return ret; } #define PIKA_MAGIC_CODE_LEN 4 /* return file size */ uint32_t _pikaShell_recv_file_direct(ShellConfig* cfg, uint8_t* magic_code, uint8_t** pbuff) { uint32_t size = 0; for (int i = 0; i < 4; i++) { uint8_t* size_byte = (uint8_t*)&size; size_byte[i] = cfg->fn_getchar(); } if (magic_code[3] == 'o') { size += sizeof(uint32_t) * 2; } uint8_t* buff = pikaMalloc(size); /* save magic code and size */ memcpy(buff, magic_code, PIKA_MAGIC_CODE_LEN); memcpy(buff + PIKA_MAGIC_CODE_LEN, &size, sizeof(size)); for (uint32_t i = sizeof(uint32_t) * 2; i < size; i++) { buff[i] = cfg->fn_getchar(); } *pbuff = buff; return size; } /* return file size */ PIKA_WEAK uint32_t _pikaShell_recv_file(ShellConfig* cfg, uint8_t* magic_code, uint8_t** pbuff) { return _pikaShell_recv_file_direct(cfg, magic_code, pbuff); } void _do_pikaScriptShell(PikaObj* self, ShellConfig* cfg) { /* init the shell */ _obj_runChar_beforeRun(self, cfg); /* getchar and run */ char inputChar[2] = {0}; while (1) { inputChar[1] = inputChar[0]; inputChar[0] = _await_getchar(cfg->fn_getchar); #if !PIKA_NANO_ENABLE /* run python script */ if (inputChar[0] == '!' && inputChar[1] == '#') { /* #! xxx */ /* start */ char* buff = pikaMalloc(PIKA_READ_FILE_BUFF_SIZE); char input[2] = {0}; int buff_i = 0; pika_bool is_exit = pika_false; pika_bool is_first_line = pika_true; while (1) { input[1] = input[0]; input[0] = cfg->fn_getchar(); if (input[0] == '!' && input[1] == '#') { buff[buff_i - 1] = 0; for (int i = 0; i < 4; i++) { /* eat 'pika' */ cfg->fn_getchar(); } break; } if ('\r' == input[0]) { continue; } if (is_first_line) { if ('\n' == input[0]) { is_first_line = pika_false; } continue; } buff[buff_i++] = input[0]; } /* end */ pika_platform_printf( "\r\n=============== [Code] ===============\r\n"); size_t len = strGetSize(buff); for (size_t i = 0; i < len; i++) { if (buff[i] == '\r') { continue; } if (buff[i] == '\n') { pika_platform_printf("\r\n"); continue; } pika_platform_printf("%c", buff[i]); } pika_platform_printf("\r\n"); pika_platform_printf("=============== [File] ===============\r\n"); pika_platform_printf( "[ Info] File buff used: %d/%d (%0.2f%%)\r\n", (int)len, (int)PIKA_READ_FILE_BUFF_SIZE, ((float)len / (float)PIKA_READ_FILE_BUFF_SIZE)); #if PIKA_SHELL_SAVE_FILE_ENABLE _save_file(PIKA_SHELL_SAVE_FILE_PATH, (uint8_t*)buff, len); #endif pika_platform_printf("=============== [ Run] ===============\r\n"); obj_run(self, (char*)buff); if (NULL != strstr(buff, "exit()")) { is_exit = pika_true; } pikaFree(buff, PIKA_READ_FILE_BUFF_SIZE); if (is_exit) { return; } pika_platform_printf("%s", cfg->prefix); continue; } /* run xx.py.o */ if (inputChar[0] == 'p' && inputChar[1] == 0x0f) { uint8_t magic_code[PIKA_MAGIC_CODE_LEN] = {0x0f, 'p', 0x00, 0x00}; for (int i = 0; i < 2; i++) { /* eat 'yo' */ magic_code[2 + i] = cfg->fn_getchar(); } uint8_t* recv = NULL; uint32_t size = 0; if (magic_code[2] == 'y' && magic_code[3] == 'a') { size = _pikaShell_recv_file(cfg, magic_code, &recv); } else { size = _pikaShell_recv_file_direct(cfg, magic_code, &recv); } pika_platform_printf( "\r\n=============== [File] ===============\r\n"); pika_platform_printf("[ Info] Recived size: %d\r\n", size); if (magic_code[3] == 'o') { #if PIKA_SHELL_SAVE_BYTECODE_ENABLE _save_file(PIKA_SHELL_SAVE_BYTECODE_PATH, (uint8_t*)recv, size); #endif pika_platform_printf( "=============== [ RUN] ===============\r\n"); pikaVM_runByteCodeInconstant(self, recv); pikaFree(recv, size); // pika_platform_printf("%s", cfg->prefix); // continue; //! Return for example like lvgl handler to continue. return; } if (magic_code[3] == 'a') { _save_file(PIKA_SHELL_SAVE_APP_PATH, (uint8_t*)recv, size); pika_platform_printf( "=============== [REBOOT] ===============\r\n"); pika_platform_reboot(); pikaFree(recv, size); return; } } #endif if (SHELL_CTRL_EXIT == _do_obj_runChar(self, inputChar[0], cfg)) { break; } } } void _temp__do_pikaScriptShell(PikaObj* self, ShellConfig* shell) { /* init the shell */ _obj_runChar_beforeRun(self, shell); /* getchar and run */ while (1) { char inputChar = shell->fn_getchar(); if (SHELL_CTRL_EXIT == _do_obj_runChar(self, inputChar, shell)) { break; } } } static enum shellCTRL __obj_shellLineHandler_REPL(PikaObj* self, char* input_line, ShellConfig* shell) { /* exit */ if (strEqu("exit()", input_line)) { /* exit pika shell */ return SHELL_CTRL_EXIT; } /* run single line */ pikaVM_run_ex_cfg cfg = {0}; cfg.in_repl = pika_true; pikaVM_run_ex(self, input_line, &cfg); return SHELL_CTRL_CONTINUE; } static volatile ShellConfig g_REPL = { .handler = __obj_shellLineHandler_REPL, .prefix = ">>> ", .blockBuffName = "@sh0", #if PIKA_SHELL_HISTORY_ENABLE .history = NULL, #endif .no_echo = PIKA_SHELL_NO_ECHO, }; void pikaScriptShell_withGetchar(PikaObj* self, sh_getchar getchar_fn) { g_REPL.fn_getchar = getchar_fn; _do_pikaScriptShell(self, (ShellConfig*)&g_REPL); } int shConfig_deinit(ShellConfig* self) { #if PIKA_SHELL_HISTORY_ENABLE if (NULL != self->history) { shHistory_destroy(self->history); self->history = NULL; } #endif return 0; } char pika_repl_getchar(void) { char c = 0; pika_platform_repl_recv((uint8_t*)&c, 1, PIKA_TIMEOUT_FOREVER); return c; } void pikaPythonShell(PikaObj* self) { pikaScriptShell_withGetchar(self, pika_repl_getchar); } void pikaShellSetEcho(pika_bool enable_echo) { if (enable_echo) { g_REPL.no_echo = pika_false; } else { g_REPL.no_echo = pika_true; } } void obj_setErrorCode(PikaObj* self, int32_t errCode) { pika_assert(NULL != self->vmFrame); self->vmFrame->error.code = errCode; } void method_returnBytes(Args* args, uint8_t* val) { args_pushArg_name(args, "@rt", arg_newBytes(val, PIKA_BYTES_DEFAULT_SIZE)); } void method_returnStr(Args* args, char* val) { args_pushArg_name(args, "@rt", arg_newStr(val)); } void method_returnInt(Args* args, int64_t val) { args_pushArg_name(args, "@rt", arg_newInt(val)); } void method_returnBool(Args* args, pika_bool val) { if (val == _PIKA_BOOL_ERR) { return; } args_pushArg_name(args, "@rt", arg_newBool(val)); } void method_returnFloat(Args* args, pika_float val) { args_pushArg_name(args, "@rt", arg_newFloat(val)); } void method_returnPtr(Args* args, void* val) { args_pushArg_name(args, "@rt", arg_newPtr(ARG_TYPE_POINTER, val)); } void method_returnObj(Args* args, void* val) { if (NULL == val) { args_pushArg_name(args, "@rt", arg_newNone()); return; } ArgType type; PikaObj* obj = (PikaObj*)val; if (obj_getFlag(obj, OBJ_FLAG_ALREADY_INIT)) { type = ARG_TYPE_OBJECT; } else { type = ARG_TYPE_OBJECT_NEW; } args_pushArg_name(args, "@rt", arg_newPtr(type, val)); } void method_returnArg(Args* args, Arg* arg) { args_pushArg_name(args, "@rt", arg); } int64_t method_getInt(Args* args, char* argName) { return args_getInt(args, argName); } pika_float method_getFloat(Args* args, char* argName) { return args_getFloat(args, argName); } char* method_getStr(Args* args, char* argName) { return args_getStr(args, argName); } #if PIKA_GC_MARK_SWEEP_ENABLE PikaObj* pikaGC_getLast(PikaObj* self) { PikaObj* obj = g_PikaObjState.gcChain; PikaObj* last = NULL; while (NULL != obj) { if (obj == self) { return last; } last = obj; obj = obj->gcNext; } return NULL; } void pikaGC_clean(PikaGC* gc) { PikaObj* obj = g_PikaObjState.gcChain; while (NULL != obj) { obj_clearFlag(obj, OBJ_FLAG_GC_MARKED); // obj->gcRoot = NULL; obj = obj->gcNext; } } uint32_t pikaGC_count(void) { uint32_t count = 0; PikaObj* obj = g_PikaObjState.gcChain; while (NULL != obj) { count++; obj = obj->gcNext; } return count; } uint32_t pikaGC_countMarked(void) { uint32_t count = 0; PikaObj* obj = g_PikaObjState.gcChain; while (NULL != obj) { if (obj_getFlag(obj, OBJ_FLAG_GC_MARKED)) { count++; } obj = obj->gcNext; } return count; } uint32_t pikaGC_printFreeList(void) { uint32_t count = 0; PikaObj* obj = g_PikaObjState.gcChain; pika_platform_printf("-----\r\n"); while (NULL != obj) { if (!obj_getFlag(obj, OBJ_FLAG_GC_MARKED)) { count++; pika_platform_printf("gc free: "); obj_dump(obj); } obj = obj->gcNext; } pika_platform_printf("-----\r\n"); return count; } void obj_dump(PikaObj* self) { #if PIKA_KERNAL_DEBUG_ENABLE pika_platform_printf("[\033[32m%s\033[0m]", self->name); #endif pika_platform_printf(" \033[36m@%p\033[0m", self); pika_platform_printf("\r\n"); } uint32_t pikaGC_markSweepOnce(PikaGC* gc) { _pikaGC_mark(gc); uint32_t count = 0; PikaObj* freeList[16] = {0}; PikaObj* obj = g_PikaObjState.gcChain; while (NULL != obj) { if (!obj_getFlag(obj, OBJ_FLAG_GC_MARKED)) { if (count > dimof(freeList) - 1) { break; } freeList[count] = obj; count++; } obj = obj->gcNext; } if (count > 0) { // pikaGC_markDump(); // pikaGC_printFreeList(); for (uint32_t i = 0; i < count; i++) { pika_platform_printf("GC Free:"); obj_dump(freeList[i]); } for (uint32_t i = 0; i < count; i++) { obj_GC(freeList[i]); } } return count; } int32_t _pikaGC_markHandler(Arg* argEach, void* context) { PikaGC* gc = (PikaGC*)context; if (arg_isObject(argEach)) { PikaObj* obj = (PikaObj*)arg_getPtr(argEach); #if PIKA_KERNAL_DEBUG_ENABLE obj->gcRoot = (void*)gc->oThis; #endif pikaGC_markObj(gc, obj); } return 0; } void pikaGC_markObj(PikaGC* gc, PikaObj* self) { gc->oThis = self; gc->markDeepth++; if (NULL == self) { goto __exit; } if (obj_getFlag(self, OBJ_FLAG_GC_MARKED)) { goto __exit; } obj_setFlag(self, OBJ_FLAG_GC_MARKED); if (NULL != gc->onMarkObj) { gc->onMarkObj(gc); } args_foreach(self->list, _pikaGC_markHandler, gc); if (self->constructor == New_PikaStdData_Dict) { Args* dict = _OBJ2DICT(self); if (NULL == dict) { goto __exit; } args_foreach(dict, _pikaGC_markHandler, (void*)gc); goto __exit; } if (self->constructor == New_PikaStdData_List || self->constructor == New_PikaStdData_Tuple) { Args* list = _OBJ2LIST(self); if (NULL == list) { goto __exit; } args_foreach(list, _pikaGC_markHandler, (void*)gc); goto __exit; } __exit: gc->markDeepth--; return; } void _pikaGC_mark(PikaGC* gc) { pikaGC_clean(gc); PikaObj* root = g_PikaObjState.gcChain; while (NULL != root) { if (obj_getFlag(root, OBJ_FLAG_GC_ROOT)) { pikaGC_markObj(gc, root); } root = root->gcNext; } } void pikaGC_mark(void) { PikaGC gc = {0}; _pikaGC_mark(&gc); } int _pikaGC_markDumpHandler(PikaGC* gc) { for (uint32_t i = 0; i < gc->markDeepth - 1; i++) { pika_platform_printf(" |"); } if (gc->markDeepth != 1) { pika_platform_printf("- "); } obj_dump(gc->oThis); return 0; } #endif pika_bool obj_checkAlive(PikaObj* self) { #if !PIKA_GC_MARK_SWEEP_ENABLE return pika_true; #else pika_bool ret = pika_false; if (NULL == g_PikaObjState.gcChain) { ret = pika_false; goto __exit; } PikaObj* obj = g_PikaObjState.gcChain; while (NULL != obj) { if (obj == self) { ret = pika_true; goto __exit; } obj = obj->gcNext; } __exit: #if PIKA_KERNAL_DEBUG_ENABLE if (ret == pika_true) { self->isAlive = ret; } #endif return ret; #endif } uint32_t pikaGC_markSweep(void) { #if !PIKA_GC_MARK_SWEEP_ENABLE return 0; #else PikaGC gc = {0}; uint32_t count = 0; if (pikaGC_islock()) { return 0; } pikaGC_lock(); while (pikaGC_markSweepOnce(&gc) != 0) { count++; }; if (count > 0) { // pikaGC_markDump(); } /* update gc state */ g_PikaObjState.objCntLastGC = g_PikaObjState.objCnt; pikaGC_unlock(); return count; #endif } void pikaGC_markDump(void) { #if !PIKA_GC_MARK_SWEEP_ENABLE return; #else PikaGC gc = {0}; pika_platform_printf( "\033[32m" "========= PIKA GC DUMP =========\r\n" "\033[0m"); gc.onMarkObj = _pikaGC_markDumpHandler; _pikaGC_mark(&gc); #endif } void pikaGC_checkThreshold(void) { #if !PIKA_GC_MARK_SWEEP_ENABLE return; #else if (g_PikaObjState.objCnt > g_PikaObjState.objCntLastGC + PIKA_GC_MARK_SWEEP_THRESHOLD) { pikaGC_markSweep(); } #endif } void pikaGC_append(PikaObj* self) { #if !PIKA_GC_MARK_SWEEP_ENABLE return; #else g_PikaObjState.objCnt++; if (g_PikaObjState.objCntMax < g_PikaObjState.objCnt) { g_PikaObjState.objCntMax = g_PikaObjState.objCnt; } /* gc single chain */ if (NULL == g_PikaObjState.gcChain) { g_PikaObjState.gcChain = self; return; } /* append to head of gc chain */ self->gcNext = g_PikaObjState.gcChain; g_PikaObjState.gcChain = self; #endif } void obj_removeGcChain(PikaObj* self) { #if !PIKA_GC_MARK_SWEEP_ENABLE return; #else g_PikaObjState.objCnt--; PikaObj* last = pikaGC_getLast(self); if (NULL == last) { /* remove head */ g_PikaObjState.gcChain = self->gcNext; return; } last->gcNext = self->gcNext; #endif } void obj_enableGC(PikaObj* self) { #if !PIKA_GC_MARK_SWEEP_ENABLE return; #else obj_clearFlag(self, OBJ_FLAG_GC_ROOT); #endif } void pikaGC_lock(void) { #if !PIKA_GC_MARK_SWEEP_ENABLE return; #else g_PikaObjState.markSweepBusy++; #endif } void pikaGC_unlock(void) { #if !PIKA_GC_MARK_SWEEP_ENABLE return; #else g_PikaObjState.markSweepBusy--; #endif } pika_bool pikaGC_islock(void) { #if !PIKA_GC_MARK_SWEEP_ENABLE return pika_false; #else return g_PikaObjState.markSweepBusy > 0; #endif } PikaObj* New_PikaObj(Args* args) { PikaObj* self = pikaMalloc(sizeof(PikaObj)); /* List */ self->list = New_args(NULL); self->refcnt = 0; self->constructor = New_PikaObj; self->flag = 0; self->vmFrame = NULL; #if PIKA_GC_MARK_SWEEP_ENABLE self->gcNext = NULL; obj_setFlag(self, OBJ_FLAG_GC_ROOT); #endif #if PIKA_KERNAL_DEBUG_ENABLE self->aName = NULL; self->name = "PikaObj"; self->parent = NULL; self->isAlive = pika_true; #endif #if PIKA_GC_MARK_SWEEP_ENABLE && PIKA_KERNAL_DEBUG_ENABLE self->gcRoot = NULL; #endif /* append to gc chain */ pikaGC_append(self); pikaGC_checkThreshold(); return self; } Arg* arg_setObj(Arg* self, char* name, PikaObj* obj) { return arg_setPtr(self, name, ARG_TYPE_OBJECT, obj); } Arg* arg_setRef(Arg* self, char* name, PikaObj* obj) { pika_assert(NULL != obj); obj_refcntInc(obj); return arg_setObj(self, name, obj); } Arg* arg_setWeakRef(Arg* self, char* name, PikaObj* obj) { pika_assert(NULL != obj); return arg_setPtr(self, name, ARG_TYPE_OBJECT_WEAK, obj); } int32_t obj_newDirectObj(PikaObj* self, char* objName, NewFun newFunPtr) { Arg* aNewObj = arg_newDirectObj(newFunPtr); aNewObj = arg_setName(aNewObj, objName); obj_setName(arg_getPtr(aNewObj), objName); arg_setType(aNewObj, ARG_TYPE_OBJECT); // pikaGC_enable(arg_getPtr(aNewObj)); obj_setArg_noCopy(self, objName, aNewObj); return 0; } int32_t obj_newHostObj(PikaObj* self, char* objName) { Args buffs = {0}; size_t tokenCnt = strCountSign(objName, '.'); if (0 == tokenCnt) { return 0; } PikaObj* this = self; objName = strsCopy(&buffs, objName); for (int i = 0; i < tokenCnt; i++) { char* name = strsPopToken(&buffs, &objName, '.'); if (!obj_isArgExist(this, name)) { obj_newDirectObj(this, name, New_TinyObj); this = obj_getObj(this, name); } } strsDeinit(&buffs); return 0; } int32_t obj_newMetaObj(PikaObj* self, char* objName, NewFun newFunPtr) { /* add meta Obj, no inited */ Arg* aMetaObj = arg_newMetaObj(newFunPtr); aMetaObj = arg_setName(aMetaObj, objName); args_setArg(self->list, aMetaObj); return 0; } static void _append_help(char* name) { if (NULL == g_PikaObjState.helpModulesCmodule) { g_PikaObjState.helpModulesCmodule = arg_newStr(""); } Arg* _help = g_PikaObjState.helpModulesCmodule; _help = arg_strAppend(_help, name); _help = arg_strAppend(_help, "\r\n"); g_PikaObjState.helpModulesCmodule = _help; } int32_t obj_newObj(PikaObj* self, char* objName, char* className, NewFun newFunPtr) { /* before init root object */ if (g_PikaObjState.inRootObj) { _append_help(objName); } return obj_newMetaObj(self, objName, newFunPtr); } PikaObj* obj_importModuleWithByteCode(PikaObj* self, char* name, uint8_t* byteCode) { if (!obj_isArgExist((PikaObj*)__pikaMain, name)) { /* import to main module context */ obj_newHostObj((PikaObj*)__pikaMain, name); obj_newDirectObj((PikaObj*)__pikaMain, name, New_TinyObj); PikaObj* module_obj = obj_getObj((PikaObj*)__pikaMain, name); pikaVM_runBytecode_ex_cfg cfg = {0}; cfg.globals = module_obj; cfg.locals = module_obj; cfg.name = name; cfg.vm_thread = self->vmFrame->vm_thread; cfg.is_const_bytecode = pika_true; pikaVM_runByteCode_ex(module_obj, byteCode, &cfg); } if (self != (PikaObj*)__pikaMain) { /* import to other module context */ Arg* aModule = obj_getArg((PikaObj*)__pikaMain, name); PikaObj* oModule = arg_getPtr(aModule); obj_newHostObj(self, name); obj_setArg(self, name, aModule); arg_setIsWeakRef(obj_getArg(self, name), pika_true); pika_assert(arg_isObject(aModule)); /* decrase refcnt to avoid circle reference */ obj_refcntDec(oModule); } return self; } PikaObj* obj_importModuleWithByteCodeFrame(PikaObj* self, char* name, ByteCodeFrame* byteCode_frame) { PikaObj* New_PikaStdLib_SysObj(Args * args); obj_newDirectObj(self, name, New_PikaStdLib_SysObj); pikaVM_runByteCodeFrame(obj_getObj(self, name), byteCode_frame); return self; } int obj_linkLibraryFile(PikaObj* self, char* input_file_name) { obj_newMetaObj(self, "@lib", New_LibObj); LibObj* lib = obj_getObj(self, "@lib"); return LibObj_loadLibraryFile(lib, input_file_name); } PikaObj* obj_linkLibrary(PikaObj* self, uint8_t* library_bytes) { obj_newMetaObj(self, "@lib", New_LibObj); LibObj* lib = obj_getObj(self, "@lib"); LibObj_loadLibrary(lib, library_bytes); return self; } void obj_printModules(PikaObj* self) { LibObj* lib = obj_getObj(self, "@lib"); if (lib == NULL) { pika_platform_printf( "Error: Not found LibObj, please execute obj_linkLibrary()\r\n"); return; } pika_platform_printf(arg_getStr((Arg*)g_PikaObjState.helpModulesCmodule)); LibObj_printModules(lib); } PikaObj* obj_linkLibObj(PikaObj* self, LibObj* library) { obj_setRef(self, "@lib", library); return self; } LibObj* pika_getLibObj(void) { // Ensure __pikaMain exists if (__pikaMain == NULL) { return NULL; } // Cast __pikaMain to PikaObj and fetch library PikaObj* self = (PikaObj*)__pikaMain; return obj_getPtr(self, "@lib"); } uint8_t* pika_getByteCodeFromModule(char* module_name) { // Check if module_name is not NULL pika_assert(NULL != module_name); // Fetch library using pika_getLibObj LibObj* lib = pika_getLibObj(); // Exit if there's no library if (NULL == lib) { return NULL; } // Fetch the module from the library PikaObj* module = LibObj_getModule(lib, module_name); // Check if module exists if (NULL == module) { return NULL; } // Return bytecode of the module return obj_getPtr(module, "bytecode"); } int obj_runModule(PikaObj* self, char* module_name) { uint8_t* bytecode = pika_getByteCodeFromModule(module_name); if (NULL == bytecode) { return 1; } PikaVMThread* vm_thread = pikaVMThread_require(); pikaVM_runBytecode_ex_cfg cfg = {0}; cfg.globals = self; cfg.locals = self; cfg.name = module_name; cfg.vm_thread = vm_thread; cfg.is_const_bytecode = pika_true; pikaVM_runByteCode_ex(self, bytecode, &cfg); return 0; } PikaObj* obj_runFile(PikaObj* self, char* file_name) { return pikaVM_runFile(self, file_name); } PikaObj* obj_runSingleFile(PikaObj* self, char* file_name) { return pikaVM_runSingleFile(self, file_name); } int obj_importModule(PikaObj* self, char* module_name) { if (NULL == module_name) { return -1; } /* import bytecode of the module */ uint8_t* bytecode = pika_getByteCodeFromModule(module_name); if (NULL == bytecode) { return -1; } obj_importModuleWithByteCode(self, module_name, bytecode); return 0; } PikaObj* arg_getObj(Arg* self) { return (PikaObj*)arg_getPtr(self); } char* obj_toStr(PikaObj* self) { /* check method arg */ Arg* aMethod = obj_getMethodArgWithFullPath(self, "__str__"); if (NULL != aMethod) { Arg* aStr = obj_runMethodArg0(self, aMethod); char* str_res = obj_cacheStr(self, arg_getStr(aStr)); arg_deinit(aStr); return str_res; } /* normal object */ Args buffs = {0}; char* str_res = strsFormat(&buffs, PIKA_SPRINTF_BUFF_SIZE, "", self); obj_setStr(self, "@res_str", str_res); strsDeinit(&buffs); return obj_getStr(self, "@res_str"); } void pika_eventListener_registEventHandler(PikaEventListener* self, uintptr_t eventId, PikaObj* eventHandleObj) { Args buffs = {0}; char* event_name = strsFormat(&buffs, PIKA_SPRINTF_BUFF_SIZE, "%ld", eventId); obj_newDirectObj(self, event_name, New_TinyObj); PikaObj* event_item = obj_getObj(self, event_name); obj_setRef(event_item, "eventHandleObj", eventHandleObj); strsDeinit(&buffs); } PIKA_RES obj_setEventCallback(PikaObj* self, uintptr_t eventId, Arg* eventCallback, PikaEventListener* listener) { obj_setArg(self, "eventCallBack", eventCallback); if (argType_isObjectMethodActive(arg_getType(eventCallback))) { PikaObj* method_self = methodArg_getHostObj(eventCallback); obj_setRef(self, "eventCallBackHost", method_self); } pika_eventListener_registEventHandler(listener, eventId, self); return PIKA_RES_OK; } void pika_eventListener_registEventCallback(PikaEventListener* listener, uintptr_t eventId, Arg* eventCallback) { pika_assert(NULL != listener); char hash_str[32] = {0}; pika_sprintf(hash_str, "C%d", eventId); obj_newDirectObj(listener, hash_str, New_TinyObj); PikaObj* oHandle = obj_getPtr(listener, hash_str); obj_setEventCallback(oHandle, eventId, eventCallback, listener); } Args buffs = {0}; void pika_eventListener_removeEvent(PikaEventListener* self, uintptr_t eventId) { char* event_name = strsFormat(&buffs, PIKA_SPRINTF_BUFF_SIZE, "%ld", eventId); obj_removeArg(self, event_name); strsDeinit(&buffs); } PikaObj* pika_eventListener_getEventHandleObj(PikaEventListener* self, uintptr_t eventId) { Args buffs = {0}; char* event_name = strsFormat(&buffs, PIKA_SPRINTF_BUFF_SIZE, "%ld", eventId); PikaObj* event_item = obj_getObj(self, event_name); PikaObj* eventHandleObj = obj_getPtr(event_item, "eventHandleObj"); strsDeinit(&buffs); return eventHandleObj; } void pika_eventListener_init(PikaEventListener** p_self) { *p_self = newNormalObj(New_TinyObj); } void pika_eventListener_deinit(PikaEventListener** p_self) { if (NULL != *p_self) { obj_deinit(*p_self); *p_self = NULL; } } Arg* pika_runFunction0_ex(PikaObj* host, Arg* functionArg) { obj_setArg(host, "@f", functionArg); /* clang-format off */ PIKA_PYTHON( @r = @f() ) /* clang-format on */ const uint8_t bytes[] = { 0x08, 0x00, 0x00, 0x00, /* instruct array size */ 0x00, 0x82, 0x01, 0x00, 0x00, 0x04, 0x04, 0x00, /* instruct array */ 0x07, 0x00, 0x00, 0x00, /* const pool size */ 0x00, 0x40, 0x66, 0x00, 0x40, 0x72, 0x00, /* const pool */ }; Arg* res = pikaVM_runByteCodeReturn(host, bytes, "@r"); arg_deinit(functionArg); return res; } Arg* pika_runFunction1_ex(PikaObj* host, Arg* functionArg, Arg* arg1) { obj_setArg(host, "@d", arg1); obj_setArg(host, "@f", functionArg); /* clang-format off */ PIKA_PYTHON( @r = @f(@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, 0x07, 0x00, /* instruct array */ 0x0a, 0x00, 0x00, 0x00, /* const pool size */ 0x00, 0x40, 0x64, 0x00, 0x40, 0x66, 0x00, 0x40, 0x72, 0x00, /* const pool */ }; Arg* res = pikaVM_runByteCodeReturn(host, bytes, "@r"); arg_deinit(arg1); arg_deinit(functionArg); return res; } Arg* pika_runFunction2_ex(PikaObj* host, Arg* functionArg, Arg* arg1, Arg* arg2) { obj_setArg(host, "@d", arg1); obj_setArg(host, "@e", arg2); obj_setArg(host, "@f", functionArg); /* clang-format off */ PIKA_PYTHON( @r = @f(@d, @e) ) /* clang-format on */ const uint8_t bytes[] = { 0x10, 0x00, 0x00, 0x00, /* instruct array size */ 0x10, 0x81, 0x01, 0x00, 0x10, 0x01, 0x04, 0x00, 0x00, 0x02, 0x07, 0x00, 0x00, 0x04, 0x0a, 0x00, /* instruct array */ 0x0d, 0x00, 0x00, 0x00, /* const pool size */ 0x00, 0x40, 0x64, 0x00, 0x40, 0x65, 0x00, 0x40, 0x66, 0x00, 0x40, 0x72, 0x00, /* const pool */ }; Arg* res = pikaVM_runByteCodeReturn(host, bytes, "@r"); arg_deinit(arg1); arg_deinit(arg2); arg_deinit(functionArg); return res; } Arg* pika_runFunction0(Arg* functionArg) { PikaObj* locals = New_TinyObj(NULL); Arg* res = pika_runFunction0_ex(locals, functionArg); obj_deinit(locals); return res; } Arg* pika_runFunction1(Arg* functionArg, Arg* arg1) { PikaObj* locals = New_TinyObj(NULL); Arg* res = pika_runFunction1_ex(locals, functionArg, arg1); obj_deinit(locals); return res; } Arg* pika_runFunction2(Arg* functionArg, Arg* arg1, Arg* arg2) { PikaObj* locals = New_TinyObj(NULL); Arg* res = pika_runFunction2_ex(locals, functionArg, arg1, arg2); obj_deinit(locals); return res; } Arg* obj_runMethod0(PikaObj* self, char* methodName) { Arg* aMethod = obj_getMethodArg(self, methodName); if (NULL == aMethod) { return NULL; } Arg* aRes = pika_runFunction0_ex(self, aMethod); return aRes; } Arg* obj_runMethod1(PikaObj* self, char* methodName, Arg* arg1) { Arg* aMethod = obj_getMethodArg(self, methodName); if (NULL == aMethod) { return NULL; } Arg* aRes = pika_runFunction1_ex(self, aMethod, arg1); return aRes; } Arg* obj_runMethod2(PikaObj* self, char* methodName, Arg* arg1, Arg* arg2) { Arg* aMethod = obj_getMethodArg(self, methodName); if (NULL == aMethod) { return NULL; } Arg* aRes = pika_runFunction2_ex(self, aMethod, arg1, arg2); return aRes; } Arg* obj_runMethodArg0(PikaObj* self, Arg* methodArg) { return pika_runFunction0_ex(self, methodArg); } Arg* obj_runMethodArg1(PikaObj* self, Arg* methodArg, Arg* arg1) { return pika_runFunction1_ex(self, methodArg, arg1); } Arg* obj_runMethodArg2(PikaObj* self, Arg* methodArg, Arg* arg1, Arg* arg2) { return pika_runFunction2_ex(self, methodArg, arg1, arg2); } Arg* __eventListener_runEvent(PikaEventListener* listener, uintptr_t eventId, Arg* eventData) { PikaObj* handler = pika_eventListener_getEventHandleObj(listener, eventId); pika_debug("event handler: %p", handler); if (NULL == handler) { pika_platform_printf( "Error: can not find event handler by id: [0x%02x]\r\n", eventId); return NULL; } Arg* eventCallBack = obj_getArg(handler, "eventCallBack"); pika_debug("run event handler: %p", handler); Arg* res = pika_runFunction1(arg_copy(eventCallBack), arg_copy(eventData)); return res; } void pika_debug_bytes(uint8_t* buff, size_t len) { pika_debug_raw("["); for (size_t i = 0; i < len; i++) { pika_debug_raw("0x%02X", buff[i]); if (i < len - 1) { pika_debug_raw(","); } } pika_debug_raw("]\n"); } static void _thread_event(void* arg) { pika_assert(_VM_is_first_lock()); while (1) { pika_GIL_ENTER(); #if PIKA_EVENT_ENABLE if (g_PikaVMState.event_thread_exit) { g_PikaVMState.event_thread_exit_done = 1; break; } #endif _VMEvent_pickupEvent(); pika_GIL_EXIT(); pika_platform_thread_yield(); } pika_GIL_EXIT(); } PIKA_RES _do_pika_eventListener_send(PikaEventListener* self, uintptr_t eventId, Arg* eventData, int eventSignal, PIKA_BOOL pickupWhenNoVM) { #if !PIKA_EVENT_ENABLE pika_platform_printf("PIKA_EVENT_ENABLE is not enable"); while (1) { }; #else if (NULL != eventData && !_VM_is_first_lock()) { #if PIKA_EVENT_THREAD_ENABLE _VM_lock_init(); #else pika_platform_printf( "Error: can not send arg event data without thread support\r\n"); arg_deinit(eventData); return PIKA_RES_ERR_RUNTIME_ERROR; #endif } if (NULL == eventData) { // for event signal if (PIKA_RES_OK != __eventListener_pushSignal(self, eventId, eventSignal)) { return PIKA_RES_ERR_RUNTIME_ERROR; } } /* using multi thread */ if (pika_GIL_isInit()) { /* python thread is running */ /* wait python thread get first lock */ while (1) { if (_VM_is_first_lock()) { break; } if (g_PikaVMState.vm_cnt == 0) { break; } if (pika_GIL_getBareLock() == 0) { break; } pika_platform_thread_yield(); } pika_GIL_ENTER(); #if PIKA_EVENT_THREAD_ENABLE if (!g_PikaVMState.event_thread) { // avoid _VMEvent_pickupEvent() in _time.c as soon as // possible g_PikaVMState.event_thread = pika_platform_thread_init( "pika_event", _thread_event, NULL, PIKA_EVENT_THREAD_STACK_SIZE, PIKA_THREAD_PRIO, PIKA_THREAD_TICK); pika_debug("event thread init"); } #endif if (NULL != eventData) { if (PIKA_RES_OK != __eventListener_pushEvent(self, eventId, eventData)) { goto __gil_exit; } } if (pickupWhenNoVM) { int vmCnt = _VMEvent_getVMCnt(); if (0 == vmCnt) { /* no vm running, pick up event imediately */ pika_debug("vmCnt: %d, pick up imediately", vmCnt); _VMEvent_pickupEvent(); } } __gil_exit: pika_GIL_EXIT(); } return (PIKA_RES)0; #endif } PIKA_RES pika_eventListener_send(PikaEventListener* self, uintptr_t eventId, Arg* eventData) { return _do_pika_eventListener_send(self, eventId, eventData, 0, pika_false); } PIKA_RES pika_eventListener_sendSignal(PikaEventListener* self, uintptr_t eventId, int eventSignal) { return _do_pika_eventListener_send(self, eventId, NULL, eventSignal, pika_false); } Arg* pika_eventListener_sendSignalAwaitResult(PikaEventListener* self, uintptr_t eventId, int eventSignal) { /* * Await result from event. * need implement `pika_platform_thread_delay()` to support thread switch */ #if !PIKA_EVENT_ENABLE pika_platform_printf("PIKA_EVENT_ENABLE is not enable"); while (1) { }; #else extern volatile VMState g_PikaVMState; int tail = g_PikaVMState.cq.tail; pika_eventListener_sendSignal(self, eventId, eventSignal); while (1) { Arg* res = g_PikaVMState.cq.res[tail]; pika_platform_thread_yield(); if (NULL != res) { return res; } } #endif } Arg* pika_eventListener_syncSendAwaitResult(PikaEventListener* self, uintptr_t eventId, Arg* eventData) { return __eventListener_runEvent(self, eventId, eventData); } PIKA_RES pika_eventListener_syncSend(PikaEventListener* self, uintptr_t eventId, Arg* eventData) { Arg* res = __eventListener_runEvent(self, eventId, eventData); PIKA_RES ret = PIKA_RES_OK; if (NULL == res) { ret = PIKA_RES_ERR_RUNTIME_ERROR; } else { arg_deinit(res); } arg_deinit(eventData); return ret; } PIKA_RES pika_eventListener_syncSendSignal(PikaEventListener* self, uintptr_t eventId, int eventSignal) { Arg* eventData = arg_newInt(eventSignal); PIKA_RES res = pika_eventListener_syncSend(self, eventId, eventData); return res; } Arg* pika_eventListener_syncSendSignalAwaitResult(PikaEventListener* self, uintptr_t eventId, int eventSignal) { Arg* eventData = arg_newInt(eventSignal); Arg* ret = pika_eventListener_syncSendAwaitResult(self, eventId, eventData); arg_deinit(eventData); return ret; } /* print major version info */ void pika_printVersion(void) { pika_platform_printf("pikascript-core==v%d.%d.%d (%s)\r\n", PIKA_VERSION_MAJOR, PIKA_VERSION_MINOR, PIKA_VERSION_MICRO, PIKA_EDIT_TIME); } void pika_getVersion(char* buff) { pika_sprintf(buff, "%d.%d.%d", PIKA_VERSION_MAJOR, PIKA_VERSION_MINOR, PIKA_VERSION_MICRO); } void* obj_getStruct(PikaObj* self, char* name) { pika_assert(self != NULL); return args_getStruct(self->list, name); } char* obj_cacheStr(PikaObj* self, char* str) { pika_assert(self != NULL); return args_cacheStr(self->list, str); } void _obj_updateProxyFlag(PikaObj* self) { if (!obj_getFlag(self, OBJ_FLAG_PROXY_GETATTRIBUTE)) { if (NULL != _obj_getPropArg(self, "__getattribute__")) { obj_setFlag(self, OBJ_FLAG_PROXY_GETATTRIBUTE); } } if (!obj_getFlag(self, OBJ_FLAG_PROXY_GETATTR)) { if (NULL != _obj_getPropArg(self, "__getattr__")) { obj_setFlag(self, OBJ_FLAG_PROXY_GETATTR); } } if (!obj_getFlag(self, OBJ_FLAG_PROXY_SETATTR)) { if (NULL != _obj_getPropArg(self, "__setattr__")) { obj_setFlag(self, OBJ_FLAG_PROXY_SETATTR); } } }; void builtins_remove(PikaObj* self, char* argPath) { obj_setErrorCode(self, 0); int32_t res = obj_removeArg(self, argPath); if (1 == res) { obj_setSysOut(self, "[error] del: object no found."); obj_setErrorCode(self, 1); return; } if (2 == res) { obj_setSysOut(self, "[error] del: arg not match."); obj_setErrorCode(self, 2); return; } } Arg* _type(Arg* arg); Arg* builtins_type(PikaObj* self, Arg* arg) { #if PIKA_NANO_ENABLE pika_platform_printf("PIKA_NANO_ENABLE is not enable"); return NULL; #else if (NULL == arg) { obj_setSysOut(self, "[error] type: arg no found."); obj_setErrorCode(self, 1); return NULL; } return _type(arg); #endif } pika_float builtins_float(PikaObj* self, Arg* arg) { ArgType type = arg_getType(arg); if (ARG_TYPE_INT == type) { return (pika_float)arg_getInt(arg); } if (ARG_TYPE_FLOAT == type) { return (pika_float)arg_getFloat(arg); } if (ARG_TYPE_STRING == type) { return strtod(arg_getStr(arg), NULL); } if (ARG_TYPE_BOOL == type) { return (pika_float)arg_getBool(arg); } obj_setSysOut(self, "[error] convert to pika_float type failed."); obj_setErrorCode(self, 1); return _PIKA_FLOAT_ERR; } PIKA_RES _transeInt(Arg* arg, int base, int64_t* res) { ArgType type = arg_getType(arg); if (ARG_TYPE_INT == type) { *res = arg_getInt(arg); return PIKA_RES_OK; } if (ARG_TYPE_BOOL == type) { *res = (int64_t)arg_getBool(arg); return PIKA_RES_OK; } if (ARG_TYPE_FLOAT == type) { *res = (int64_t)arg_getFloat(arg); return PIKA_RES_OK; } if (ARG_TYPE_STRING == type) { char* end = NULL; char* str = arg_getStr(arg); *res = strtoll(str, &end, base); if (NULL != end && strGetSize(end) != 0) { return PIKA_RES_ERR_INVALID_PARAM; } return PIKA_RES_OK; } if (ARG_TYPE_BYTES == type) { size_t size = arg_getBytesSize(arg); if (size != 1) { return PIKA_RES_ERR_INVALID_PARAM; } uint8_t val = *arg_getBytes(arg); *res = val; return PIKA_RES_OK; } return PIKA_RES_ERR_INVALID_PARAM; } PIKA_RES _transeBool(Arg* arg, pika_bool* res) { int64_t iRes = 0; if (arg_getType(arg) == ARG_TYPE_BOOL) { *res = arg_getBool(arg); return PIKA_RES_OK; } if (arg_getType(arg) == ARG_TYPE_NONE) { *res = pika_false; return PIKA_RES_OK; } if (arg_getType(arg) == ARG_TYPE_STRING || arg_getType(arg) == ARG_TYPE_BYTES) { if (arg_getStr(arg)[0] == '\0') { *res = pika_false; return PIKA_RES_OK; } *res = pika_true; return PIKA_RES_OK; } if (arg_isObject(arg)) { int64_t len = obj_getSize(arg_getObj(arg)); if (len < 0) { *res = pika_true; return PIKA_RES_OK; } if (len == 0) { *res = pika_false; return PIKA_RES_OK; } *res = pika_true; return PIKA_RES_OK; } if (_transeInt(arg, 10, &iRes) == PIKA_RES_OK) { *res = iRes ? pika_true : pika_false; return PIKA_RES_OK; } return PIKA_RES_ERR_INVALID_PARAM; } Arg* builtins_int(PikaObj* self, Arg* arg, PikaTuple* base) { int64_t res = 0; int64_t iBase = 10; if (pikaTuple_getSize(base) > 0) { if (arg_getType(arg) != ARG_TYPE_STRING && arg_getType(arg) != ARG_TYPE_BYTES) { obj_setSysOut(self, "TypeError: int() can't convert non-string with " "explicit base"); obj_setErrorCode(self, 1); return NULL; } iBase = (int64_t)pikaTuple_getInt(base, 0); } if (_transeInt(arg, iBase, &res) == PIKA_RES_OK) { return arg_newInt(res); } obj_setSysOut(self, "ValueError: invalid literal for int(): '%s'", arg_getStr(arg)); obj_setErrorCode(self, 1); return NULL; } pika_bool builtins_bool(PikaObj* self, Arg* arg) { pika_bool res = 0; if (_transeBool(arg, &res) == PIKA_RES_OK) { return res; } obj_setSysOut(self, "ValueError: invalid literal for bool()"); obj_setErrorCode(self, 1); return _PIKA_BOOL_ERR; } char* builtins_str(PikaObj* self, Arg* arg) { pika_assert(NULL != arg); pika_assert(NULL != self); // if (arg_getType(arg) == ARG_TYPE_BYTES) { // return obj_cacheStr(self, (char*)arg_getBytes(arg)); // } Arg* arg_str = arg_toStrArg(arg); if (NULL == arg_str) { obj_setSysOut(self, "Error: convert to str type failed."); obj_setErrorCode(self, 1); return NULL; } char* str = obj_cacheStr(self, arg_getStr(arg_str)); arg_deinit(arg_str); return str; } PikaObj* New_builtins_RangeObj(Args* args); Arg* builtins_iter(PikaObj* self, Arg* arg) { pika_assert(NULL != arg); /* object */ pika_bool bIsTemp = pika_false; PikaObj* oArg = _arg_to_obj(arg, &bIsTemp); pika_assert(NULL != oArg); NewFun _clsptr = (NewFun)oArg->constructor; if (_clsptr == New_builtins_RangeObj) { /* found RangeObj, return directly */ return arg_copy(arg); } /* clang-format off */ PIKA_PYTHON( @res_iter = __iter__() ) /* clang-format on */ const uint8_t bytes[] = { 0x08, 0x00, 0x00, 0x00, /* instruct array size */ 0x00, 0x82, 0x01, 0x00, 0x00, 0x04, 0x0a, 0x00, /* instruct array */ 0x14, 0x00, 0x00, 0x00, /* const pool size */ 0x00, 0x5f, 0x5f, 0x69, 0x74, 0x65, 0x72, 0x5f, 0x5f, 0x00, 0x40, 0x72, 0x65, 0x73, 0x5f, 0x69, 0x74, 0x65, 0x72, 0x00, /* const pool */ }; Arg* res = pikaVM_runByteCodeReturn(oArg, (uint8_t*)bytes, "@res_iter"); if (bIsTemp) { obj_refcntDec(oArg); } return res; } Arg* builtins_range(PikaObj* self, PikaTuple* ax) { /* set template arg to create rangeObj */ Arg* aRangeObj = arg_newDirectObj(New_builtins_RangeObj); PikaObj* oRangeObj = arg_getPtr(aRangeObj); RangeData tRangeData = {0}; if (pikaTuple_getSize(ax) == 1) { int start = 0; int end = arg_getInt(pikaTuple_getArg(ax, 0)); tRangeData.start = start; tRangeData.end = end; tRangeData.step = 1; } else if (pikaTuple_getSize(ax) == 2) { int start = arg_getInt(pikaTuple_getArg(ax, 0)); int end = arg_getInt(pikaTuple_getArg(ax, 1)); tRangeData.start = start; tRangeData.end = end; tRangeData.step = 1; } else if (pikaTuple_getSize(ax) == 3) { int start = arg_getInt(pikaTuple_getArg(ax, 0)); int end = arg_getInt(pikaTuple_getArg(ax, 1)); int step = arg_getInt(pikaTuple_getArg(ax, 2)); tRangeData.start = start; tRangeData.end = end; tRangeData.step = step; } tRangeData.i = tRangeData.start; obj_setStruct(oRangeObj, "_", tRangeData); return aRangeObj; } Arg* builtins___getitem__(PikaObj* self, Arg* obj, Arg* key) { return _vm_get(NULL, self, key, obj); } Arg* builtins___setitem__(PikaObj* self, Arg* obj, Arg* key, Arg* val) { ArgType obj_type = arg_getType(obj); if (ARG_TYPE_STRING == obj_type) { int index = arg_getInt(key); char* str_val = arg_getStr(val); char* str_pyload = arg_getStr(obj); str_pyload[index] = str_val[0]; return arg_newStr(str_pyload); } if (ARG_TYPE_BYTES == obj_type) { int index = arg_getInt(key); uint8_t byte_val = 0; if (ARG_TYPE_BYTES == arg_getType(val)) { uint8_t* bytes_val = arg_getBytes(val); byte_val = bytes_val[0]; } if (ARG_TYPE_INT == arg_getType(val)) { byte_val = arg_getInt(val); } uint8_t* bytes_pyload = arg_getBytes(obj); size_t bytes_len = arg_getBytesSize(obj); bytes_pyload[index] = byte_val; return arg_newBytes(bytes_pyload, bytes_len); } if (argType_isObject(obj_type)) { PikaObj* arg_obj = arg_getPtr(obj); obj_setArg(arg_obj, "__key", key); obj_setArg(arg_obj, "__val", val); /* clang-format off */ PIKA_PYTHON( __setitem__(__key, __val) ) /* clang-format on */ const uint8_t bytes[] = { 0x0c, 0x00, 0x00, 0x00, /* instruct array size */ 0x10, 0x81, 0x01, 0x00, 0x10, 0x01, 0x07, 0x00, 0x00, 0x02, 0x0d, 0x00, /* instruct array */ 0x19, 0x00, 0x00, 0x00, /* const pool size */ 0x00, 0x5f, 0x5f, 0x6b, 0x65, 0x79, 0x00, 0x5f, 0x5f, 0x76, 0x61, 0x6c, 0x00, 0x5f, 0x5f, 0x73, 0x65, 0x74, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x5f, 0x00, /* const pool */ }; pikaVM_runByteCode(arg_obj, (uint8_t*)bytes); return arg_newRef(arg_obj); } return NULL; } pika_bool arg_isList(Arg* arg) { if (!arg_isObject(arg)) { return pika_false; } return arg_getObj(arg)->constructor == New_PikaStdData_List; } pika_bool arg_isDict(Arg* arg) { if (!arg_isObject(arg)) { return pika_false; } return arg_getObj(arg)->constructor == New_PikaStdData_Dict; } pika_bool arg_isTuple(Arg* arg) { if (!arg_isObject(arg)) { return pika_false; } return arg_getObj(arg)->constructor == New_PikaStdData_Tuple; } int64_t obj_getSize(PikaObj* arg_obj) { Arg* aRes = obj_runMethod0(arg_obj, "__len__"); if (NULL == aRes) { return -1; } int64_t res = arg_getInt(aRes); arg_deinit(aRes); return res; } int builtins_len(PikaObj* self, Arg* arg) { if (ARG_TYPE_STRING == arg_getType(arg)) { return strGetSize(arg_getStr(arg)); } if (ARG_TYPE_BYTES == arg_getType(arg)) { return arg_getBytesSize(arg); } if (arg_isObject(arg)) { PikaObj* arg_obj = arg_getPtr(arg); return obj_getSize(arg_obj); } obj_setErrorCode(self, 1); __platform_printf("[Error] len: arg type not support\r\n"); return -1; } Arg* builtins_list(PikaObj* self, PikaTuple* val) { #if PIKA_BUILTIN_STRUCT_ENABLE if (1 == pikaTuple_getSize(val)) { Arg* aInput = pikaTuple_getArg(val, 0); if (!arg_isIterable(aInput)) { obj_setErrorCode(self, 1); obj_setSysOut(self, "Error: input arg must be iterable"); return NULL; } obj_setArg(self, "__list", aInput); /* clang-format off */ PIKA_PYTHON( @res_list = [] for __item in __list: @res_list.append(__item) del __item del __list ) /* clang-format on */ const uint8_t bytes[] = { 0x40, 0x00, 0x00, 0x00, /* instruct array size */ 0x00, 0x95, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x10, 0x81, 0x0b, 0x00, 0x00, 0x02, 0x12, 0x00, 0x00, 0x04, 0x17, 0x00, 0x00, 0x82, 0x1b, 0x00, 0x00, 0x04, 0x28, 0x00, 0x00, 0x0d, 0x28, 0x00, 0x00, 0x07, 0x2f, 0x00, 0x11, 0x81, 0x28, 0x00, 0x01, 0x02, 0x31, 0x00, 0x00, 0x86, 0x42, 0x00, 0x00, 0x8c, 0x17, 0x00, 0x00, 0x8c, 0x28, 0x00, 0x00, 0x8c, 0x0b, 0x00, /* instruct array */ 0x45, 0x00, 0x00, 0x00, /* const pool size */ 0x00, 0x40, 0x72, 0x65, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x00, 0x5f, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x00, 0x69, 0x74, 0x65, 0x72, 0x00, 0x24, 0x6c, 0x30, 0x00, 0x24, 0x6c, 0x30, 0x2e, 0x5f, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x00, 0x32, 0x00, 0x40, 0x72, 0x65, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x00, 0x2d, 0x31, 0x00, /* const pool */ }; return pikaVM_runByteCodeReturn(self, (uint8_t*)bytes, "@res_list"); } return arg_newObj(New_pikaListFrom(NULL)); #else obj_setErrorCode(self, 1); obj_setSysOut(self, "[Error] built-in list is not enabled."); return arg_newNull(); #endif } Arg* builtins_dict(PikaObj* self, PikaTuple* val) { #if PIKA_BUILTIN_STRUCT_ENABLE return arg_newObj(New_PikaDict()); #else obj_setErrorCode(self, 1); obj_setSysOut(self, "[Error] built-in dist is not enabled."); return arg_newNull(); #endif } Arg* builtins_tuple(PikaObj* self, PikaTuple* val) { #if PIKA_BUILTIN_STRUCT_ENABLE Arg* tuple = builtins_list(self, val); if (NULL == tuple) { return NULL; } PikaObj* oTuple = arg_getObj(tuple); oTuple->constructor = New_PikaStdData_Tuple; return tuple; #else obj_setErrorCode(self, 1); obj_setSysOut(self, "[Error] built-in tuple is not enabled."); return arg_newNull(); #endif } char* builtins_hex(PikaObj* self, int val) { char buff[PIKA_SPRINTF_BUFF_SIZE] = {0}; if (val >= 0) { __platform_sprintf(buff, "0x%02x", val); } else { __platform_sprintf(buff, "-0x%02x", -val); } /* load the string from stack to heap */ obj_setStr(self, "__buf", buff); return obj_getStr(self, "__buf"); } int builtins_ord(PikaObj* self, char* val) { return (int)val[0]; } char* builtins_chr(PikaObj* self, int val) { char buff[PIKA_SPRINTF_BUFF_SIZE] = {0}; char to_str[] = "0"; to_str[0] = val; __platform_sprintf(buff, "%s", to_str); /* load the string from stack to heap */ obj_setStr(self, "__buf", buff); return obj_getStr(self, "__buf"); } Arg* builtins_bytes(PikaObj* self, Arg* val) { ArgType type = arg_getType(val); if (ARG_TYPE_INT == type) { int size = arg_getInt(val); /* src is NULL so the bytes are all '\0' */ Arg* bytes = arg_newBytes(NULL, size); return bytes; } if (ARG_TYPE_BYTES == type) { return arg_copy(val); } if (ARG_TYPE_STRING == type) { int size = strGetSize(arg_getStr(val)); Arg* bytes = arg_newBytes((uint8_t*)arg_getStr(val), size); return bytes; } #if !PIKA_NANO_ENABLE if (argType_isObject(type)) { PikaObj* obj = arg_getPtr(val); PikaObj* New_PikaStdData_List(Args * args); PikaObj* New_PikaStdData_Tuple(Args * args); if (obj->constructor == New_PikaStdData_List || obj->constructor == New_PikaStdData_Tuple) { Arg* bytes = arg_newBytes(NULL, pikaList_getSize(obj)); uint8_t* bytes_raw = arg_getBytes(bytes); for (size_t i = 0; i < pikaList_getSize(obj); i++) { bytes_raw[i] = (uint8_t)pikaList_getInt(obj, i); } return bytes; } } #endif obj_setErrorCode(self, 1); obj_setSysOut(self, "Error: input arg type not supported."); return arg_newNone(); } void builtins_print(PikaObj* self, PikaTuple* val, PikaDict* ops) { int arg_size = pikaTuple_getSize(val); pika_assert(arg_size >= 0); char* end = pikaDict_getStr(ops, "end"); if (NULL == end) { /* default */ end = "\r\n"; } if (arg_size == 1) { arg_print(pikaTuple_getArg(val, 0), pika_false, end); return; } Arg* print_out_arg = NULL; pika_bool is_get_print = pika_false; for (int i = 0; i < arg_size; i++) { Arg* arg = pikaTuple_getArg(val, i); Arg* item_arg_str = arg_toStrArg(arg); if (NULL != item_arg_str) { is_get_print = PIKA_TRUE; if (NULL == print_out_arg) { print_out_arg = arg_newStr(""); } print_out_arg = arg_strAppend(print_out_arg, arg_getStr(item_arg_str)); if (i < arg_size - 1) { print_out_arg = arg_strAppend(print_out_arg, " "); } arg_deinit(item_arg_str); } } if (PIKA_TRUE == is_get_print) { __platform_printf("%s%s", arg_getStr(print_out_arg), end); } if (NULL != print_out_arg) { arg_deinit(print_out_arg); } } char* builtins_cformat(PikaObj* self, char* fmt, PikaTuple* var) { #if PIKA_SYNTAX_FORMAT_ENABLE Args buffs = {0}; pikaMemMaxReset(); char* res = strsFormatList(&buffs, fmt, var); obj_setStr(self, "_buf", res); res = obj_getStr(self, "_buf"); strsDeinit(&buffs); return res; #else obj_setErrorCode(self, 1); obj_setSysOut(self, "[Error] PIKA_SYNTAX_FORMAT_ENABLE is not enabled."); return NULL; #endif } int builtins_id(PikaObj* self, Arg* obj) { uintptr_t ptr = 0; if (arg_isObject(obj)) { ptr = (uintptr_t)arg_getPtr(obj); } else { ptr = (uintptr_t)obj; } return ptr & (0x7FFFFFFF); } int PikaStdData_FILEIO_init(PikaObj* self, char* path, char* mode); PikaObj* New_PikaStdData_FILEIO(Args* args); PikaObj* builtins_open(PikaObj* self, char* path, char* mode) { #if PIKA_FILEIO_ENABLE PikaObj* file = newNormalObj(New_PikaStdData_FILEIO); if (0 != PikaStdData_FILEIO_init(file, path, mode)) { obj_setErrorCode(self, 1); obj_setSysOut(self, "[Error] open: can not open file."); obj_deinit(file); return NULL; } return file; #else obj_setErrorCode(self, 1); obj_setSysOut(self, "[Error] PIKA_FILEIO_ENABLE is not enabled."); return NULL; #endif } /* __dir_each */ int32_t __dir_each(Arg* argEach, void* context) { if (argType_isCallable(arg_getType(argEach))) { char name_buff[PIKA_LINE_BUFF_SIZE] = {0}; char* method_name = methodArg_getName(argEach, name_buff, sizeof(name_buff)); Arg* arg_str = arg_newStr(method_name); PikaList* list = args_getPtr(context, "_list"); pikaList_append(list, arg_str); } return 0; } PikaObj* builtins_dir(PikaObj* self, Arg* arg) { if (!arg_isObject(arg)) { obj_setErrorCode(self, 1); obj_setSysOut(self, "[Error] dir: not support type."); return NULL; } PikaObj* obj = arg_getPtr(arg); PikaObj* New_PikaStdData_List(Args * args); PikaObj* list = New_PikaList(); Args* context = New_args(NULL); args_setPtr(context, "_list", list); args_foreach(obj->list, __dir_each, context); args_deinit(context); return list; } void builtins_exec(PikaObj* self, char* code) { #if PIKA_EXEC_ENABLE obj_run(self, code); #else obj_setErrorCode(self, 1); obj_setSysOut(self, "[Error] PIKA_EXEC_ENABLE is not enabled."); #endif } Arg* builtins_getattr(PikaObj* self, PikaObj* obj, char* name) { if (NULL == obj) { obj_setErrorCode(self, 1); obj_setSysOut(self, "[Error] getattr: can not get attr of NULL."); return NULL; } Arg* aRes = obj_getArg(obj, name); if (NULL == aRes) { aRes = obj_getMethodArgWithFullPath(obj, name); } if (NULL != aRes) { aRes = methodArg_setHostObj(aRes, obj); if (arg_getType(aRes) != ARG_TYPE_METHOD_NATIVE_ACTIVE) { aRes = arg_copy(aRes); } } return aRes; } void builtins_setattr(PikaObj* self, PikaObj* obj, char* name, Arg* val) { if (NULL == obj) { obj_setErrorCode(self, 1); obj_setSysOut(self, "[Error] setattr: obj is null."); goto __exit; } obj_setArg(obj, name, val); __exit: return; } void builtins_exit(PikaObj* self) { pika_vm_exit(); } int builtins_hasattr(PikaObj* self, PikaObj* obj, char* name) { if (NULL == obj) { obj_setErrorCode(self, 1); obj_setSysOut(self, "[Error] hasattr: obj is null."); return 0; } if (obj_isArgExist(obj, name)) { return 1; } Arg* method = obj_getMethodArgWithFullPath(obj, name); if (NULL != method) { arg_deinit(method); return 1; } return 0; } Arg* builtins_eval(PikaObj* self, char* code) { Args buffs = {0}; char* cmd = strsAppend(&buffs, "@res = ", code); obj_run(self, cmd); Arg* res = arg_copy(obj_getArg(self, "@res")); strsDeinit(&buffs); obj_removeArg(self, "@res"); return res; } static enum shellCTRL __obj_shellLineHandler_input(PikaObj* self, char* input_line, struct ShellConfig* cfg) { cfg->context = arg_newStr(input_line); return SHELL_CTRL_EXIT; } Arg* _type(Arg* arg) { Arg* result; PikaObj* oBuiltins = NULL; ArgType type = arg_getType(arg); oBuiltins = obj_getBuiltins(); if (ARG_TYPE_INT == type) { result = arg_copy(obj_getMethodArgWithFullPath(oBuiltins, "int")); goto __exit; } if (ARG_TYPE_FLOAT == type) { result = arg_copy(obj_getMethodArgWithFullPath(oBuiltins, "float")); goto __exit; } if (ARG_TYPE_STRING == type) { result = arg_copy(obj_getMethodArgWithFullPath(oBuiltins, "str")); goto __exit; } if (ARG_TYPE_BOOL == type) { result = arg_copy(obj_getMethodArgWithFullPath(oBuiltins, "bool")); goto __exit; } if (ARG_TYPE_BYTES == type) { result = arg_copy(obj_getMethodArgWithFullPath(oBuiltins, "bytes")); goto __exit; } if (argType_isObject(type)) { PikaObj* obj = arg_getPtr(arg); NewFun clsptr = obj_getClass(obj); PikaObj* New_PikaStdData_List(Args * args); if (clsptr == New_PikaStdData_List) { result = arg_copy(obj_getMethodArgWithFullPath(oBuiltins, "list")); goto __exit; } PikaObj* New_PikaStdData_Dict(Args * args); if (clsptr == New_PikaStdData_Dict) { result = arg_copy(obj_getMethodArgWithFullPath(oBuiltins, "dict")); goto __exit; } PikaObj* New_PikaStdData_Tuple(Args * args); if (clsptr == New_PikaStdData_Tuple) { result = arg_copy(obj_getMethodArgWithFullPath(oBuiltins, "tuple")); goto __exit; } #if PIKA_TYPE_FULL_FEATURE_ENABLE Arg* aMethod = obj_getArg(obj, "__class__"); if (NULL != aMethod) { result = arg_copy(aMethod); goto __exit; } #endif result = arg_newStr(""); goto __exit; } if (ARG_TYPE_OBJECT_META == type) { result = arg_newStr(""); goto __exit; } if (ARG_TYPE_METHOD_OBJECT == type) { result = arg_newStr(""); goto __exit; } if (ARG_TYPE_METHOD_STATIC == type) { result = arg_newStr(""); goto __exit; } if (ARG_TYPE_NONE == type) { result = arg_newStr(""); goto __exit; } result = arg_newStr(""); __exit: if (NULL != oBuiltins) { obj_deinit(oBuiltins); } return result; } pika_bool _isinstance(Arg* aObj, Arg* classinfo) { pika_bool res = pika_false; Arg* aObjType = NULL; aObjType = _type(aObj); NativeProperty* objProp = NULL; while (1) { if (arg_getPtr(aObjType) == arg_getPtr(classinfo)) { res = pika_true; goto __exit; } Arg* aObjSuper = methodArg_super(aObjType, &objProp); if ((NULL == aObjSuper) && (NULL == objProp)) { res = pika_false; goto __exit; } aObjType = aObjSuper; if (NULL != objProp) { if (!(arg_getType(classinfo) == ARG_TYPE_METHOD_NATIVE_CONSTRUCTOR)) { res = pika_false; goto __exit; } NativeProperty* classProp = methodArg_toProp(classinfo); while (1) { if (objProp == classProp) { res = pika_true; goto __exit; } if (objProp->super == NULL) { res = pika_false; goto __exit; } objProp = (NativeProperty*)objProp->super; } } if (NULL == aObjType) { res = pika_false; goto __exit; } } __exit: if (NULL != aObjType) { arg_deinit(aObjType); } return res; } char* builtins_input(PikaObj* self, PikaTuple* info) { struct ShellConfig cfg = { .prefix = "", .context = NULL, .handler = __obj_shellLineHandler_input, .fn_getchar = __platform_getchar, }; if (pikaTuple_getSize(info) > 0) { __platform_printf("%s", pikaTuple_getStr(info, 0)); } _temp__do_pikaScriptShell(self, &cfg); char* res = obj_cacheStr(self, arg_getStr(cfg.context)); arg_deinit(cfg.context); return res; } extern volatile PikaObj* __pikaMain; void builtins_help(PikaObj* self, char* name) { if (strEqu(name, "modules")) { obj_printModules((PikaObj*)__pikaMain); return; } pika_platform_printf( "Warning: help() only support help('modules') now.\r\n"); } void builtins_reboot(PikaObj* self) { pika_platform_reboot(); } void builtins_clear(PikaObj* self) { pika_platform_clear(); } void builtins_gcdump(PikaObj* self) { pikaGC_markDump(); } Arg* builtins_abs(PikaObj* self, Arg* val) { ArgType type = arg_getType(val); if (type == ARG_TYPE_INT) { int64_t v = arg_getInt(val); if (v < 0) { v = -v; } return arg_newInt(v); } if (type == ARG_TYPE_FLOAT) { pika_float v = arg_getFloat(val); if (v < 0) { v = -v; } return arg_newFloat(v); } obj_setSysOut(self, "TypeError: bad operand type for abs()"); obj_setErrorCode(self, PIKA_RES_ERR_INVALID_PARAM); return NULL; } PikaObj* New_PikaStdData_Tuple(Args* args); /* clang-format off */ PIKA_PYTHON( @res_max = @list[0] for @item in @list: if @item > @res_max: @res_max = @item ) /* clang-format on */ const uint8_t bc_max[] = { 0x4c, 0x00, 0x00, 0x00, /* instruct array size */ 0x10, 0x81, 0x01, 0x00, 0x10, 0x05, 0x07, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x04, 0x09, 0x00, 0x10, 0x81, 0x01, 0x00, 0x00, 0x02, 0x12, 0x00, 0x00, 0x04, 0x17, 0x00, 0x00, 0x82, 0x1b, 0x00, 0x00, 0x04, 0x28, 0x00, 0x00, 0x0d, 0x28, 0x00, 0x00, 0x07, 0x2e, 0x00, 0x11, 0x81, 0x28, 0x00, 0x11, 0x01, 0x09, 0x00, 0x01, 0x08, 0x30, 0x00, 0x01, 0x07, 0x32, 0x00, 0x02, 0x81, 0x28, 0x00, 0x02, 0x04, 0x09, 0x00, 0x00, 0x86, 0x34, 0x00, 0x00, 0x8c, 0x17, 0x00, /* instruct array */ 0x37, 0x00, 0x00, 0x00, /* const pool size */ 0x00, 0x40, 0x6c, 0x69, 0x73, 0x74, 0x00, 0x30, 0x00, 0x40, 0x72, 0x65, 0x73, 0x5f, 0x6d, 0x61, 0x78, 0x00, 0x69, 0x74, 0x65, 0x72, 0x00, 0x24, 0x6c, 0x30, 0x00, 0x24, 0x6c, 0x30, 0x2e, 0x5f, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x5f, 0x00, 0x40, 0x69, 0x74, 0x65, 0x6d, 0x00, 0x32, 0x00, 0x3e, 0x00, 0x31, 0x00, 0x2d, 0x31, 0x00, /* const pool */ }; /* clang-format off */ PIKA_PYTHON( @res_max = @list[0] for @item in @list: if @item < @res_max: @res_max = @item ) /* clang-format on */ const uint8_t bc_min[] = { 0x4c, 0x00, 0x00, 0x00, /* instruct array size */ 0x10, 0x81, 0x01, 0x00, 0x10, 0x05, 0x07, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x04, 0x09, 0x00, 0x10, 0x81, 0x01, 0x00, 0x00, 0x02, 0x12, 0x00, 0x00, 0x04, 0x17, 0x00, 0x00, 0x82, 0x1b, 0x00, 0x00, 0x04, 0x28, 0x00, 0x00, 0x0d, 0x28, 0x00, 0x00, 0x07, 0x2e, 0x00, 0x11, 0x81, 0x28, 0x00, 0x11, 0x01, 0x09, 0x00, 0x01, 0x08, 0x30, 0x00, 0x01, 0x07, 0x32, 0x00, 0x02, 0x81, 0x28, 0x00, 0x02, 0x04, 0x09, 0x00, 0x00, 0x86, 0x34, 0x00, 0x00, 0x8c, 0x17, 0x00, /* instruct array */ 0x37, 0x00, 0x00, 0x00, /* const pool size */ 0x00, 0x40, 0x6c, 0x69, 0x73, 0x74, 0x00, 0x30, 0x00, 0x40, 0x72, 0x65, 0x73, 0x5f, 0x6d, 0x61, 0x78, 0x00, 0x69, 0x74, 0x65, 0x72, 0x00, 0x24, 0x6c, 0x30, 0x00, 0x24, 0x6c, 0x30, 0x2e, 0x5f, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x5f, 0x00, 0x40, 0x69, 0x74, 0x65, 0x6d, 0x00, 0x32, 0x00, 0x3c, 0x00, 0x31, 0x00, 0x2d, 0x31, 0x00, /* const pool */ }; Arg* _max_min(PikaObj* self, PikaTuple* val, uint8_t* bc) { int size = pikaTuple_getSize(val); if (size == 0) { obj_setSysOut(self, "TypeError: max expected 1 arguments, got 0"); obj_setErrorCode(self, PIKA_RES_ERR_INVALID_PARAM); return NULL; } if (size == 1) { ArgType type = arg_getType(pikaTuple_getArg(val, 0)); if (!argType_isIterable(type)) { obj_setSysOut(self, "TypeError: object is not iterable"); obj_setErrorCode(self, PIKA_RES_ERR_INVALID_PARAM); return NULL; } obj_setArg(self, "@list", pikaTuple_getArg(val, 0)); return pikaVM_runByteCodeReturn(self, (uint8_t*)bc, "@res_max"); } PikaTuple* oTuple = newNormalObj(New_PikaStdData_Tuple); obj_setPtr(oTuple, "list", obj_getPtr(val, "list")); obj_setInt(oTuple, "needfree", 0); Arg* aTuple = arg_newObj(oTuple); obj_setArg(self, "@list", aTuple); Arg* aRet = pikaVM_runByteCodeReturn(self, (uint8_t*)bc, "@res_max"); arg_deinit(aTuple); return aRet; } Arg* builtins_max(PikaObj* self, PikaTuple* val) { return _max_min(self, val, (uint8_t*)bc_max); } Arg* builtins_min(PikaObj* self, PikaTuple* val) { return _max_min(self, val, (uint8_t*)bc_min); } static PIKA_BOOL _check_no_buff_format(char* format) { while (*format) { if (*format == '%') { ++format; if (*format != 's' && *format != '%') { return PIKA_FALSE; } } ++format; } return PIKA_TRUE; } int pika_pvsprintf(char** buff, const char* fmt, va_list args) { int required_size; int current_size = PIKA_SPRINTF_BUFF_SIZE; *buff = (char*)pika_platform_malloc(current_size * sizeof(char)); if (*buff == NULL) { return -1; // Memory allocation failed } va_list args_copy; va_copy(args_copy, args); required_size = pika_platform_vsnprintf(*buff, current_size, fmt, args_copy); va_end(args_copy); while (required_size >= current_size) { current_size *= 2; char* new_buff = (char*)pika_reallocn(*buff, current_size / 2, current_size * sizeof(char)); if (new_buff == NULL) { pika_platform_free(*buff); *buff = NULL; return -1; // Memory allocation failed } else { *buff = new_buff; } va_copy(args_copy, args); required_size = pika_platform_vsnprintf(*buff, current_size, fmt, args_copy); va_end(args_copy); } return required_size; } static int _no_buff_vprintf(char* fmt, va_list args) { int written = 0; while (*fmt) { if (*fmt == '%') { ++fmt; if (*fmt == 's') { char* str = va_arg(args, char*); if (str == NULL) { str = "(null)"; } int len = strlen(str); written += len; for (int i = 0; i < len; i++) { pika_putchar(str[i]); } } else if (*fmt == '%') { pika_putchar('%'); ++written; } } else { pika_putchar(*fmt); ++written; } ++fmt; } return written; } int pika_vprintf(char* fmt, va_list args) { int ret = 0; if (_check_no_buff_format(fmt)) { _no_buff_vprintf(fmt, args); return 0; } char* buff = NULL; int required_size = pika_pvsprintf(&buff, fmt, args); if (required_size < 0) { ret = -1; // Memory allocation or other error occurred goto __exit; } // putchar for (int i = 0; i < strlen(buff); i++) { pika_putchar(buff[i]); } __exit: if (NULL != buff) { pika_platform_free(buff); } return ret; } int pika_sprintf(char* buff, char* fmt, ...) { va_list args; va_start(args, fmt); int res = pika_platform_vsnprintf(buff, PIKA_SPRINTF_BUFF_SIZE, fmt, args); va_end(args); if (res >= PIKA_SPRINTF_BUFF_SIZE) { pika_platform_printf( "OverflowError: sprintf buff size overflow, please use bigger " "PIKA_SPRINTF_BUFF_SIZE\r\n"); pika_platform_printf("Info: buff size request: %d\r\n", res); pika_platform_printf("Info: buff size now: %d\r\n", PIKA_SPRINTF_BUFF_SIZE); while (1) ; } return res; } int pika_vsprintf(char* buff, char* fmt, va_list args) { /* vsnprintf */ return pika_platform_vsnprintf(buff, PIKA_SPRINTF_BUFF_SIZE, fmt, args); } int pika_snprintf(char* buff, size_t size, const char* fmt, ...) { va_list args; va_start(args, fmt); int ret = pika_platform_vsnprintf(buff, size, fmt, args); va_end(args); return ret; } void _do_vsysOut(char* fmt, va_list args) { char* fmt_buff = pikaMalloc(strGetSize(fmt) + 2); pika_platform_memcpy(fmt_buff, fmt, strGetSize(fmt)); fmt_buff[strGetSize(fmt)] = '\n'; fmt_buff[strGetSize(fmt) + 1] = '\0'; char* out_buff = pikaMalloc(PIKA_SPRINTF_BUFF_SIZE); pika_platform_vsnprintf(out_buff, PIKA_SPRINTF_BUFF_SIZE, fmt_buff, args); pika_platform_printf("%s", out_buff); pikaFree(out_buff, PIKA_SPRINTF_BUFF_SIZE); pikaFree(fmt_buff, strGetSize(fmt) + 2); } void obj_setSysOut(PikaObj* self, char* fmt, ...) { if (NULL != self->vmFrame) { if (self->vmFrame->error.code == PIKA_RES_OK) { self->vmFrame->error.code = PIKA_RES_ERR_RUNTIME_ERROR; } if (self->vmFrame->vm_thread->try_state == TRY_STATE_INNER) { return; } } va_list args; va_start(args, fmt); _do_vsysOut(fmt, args); va_end(args); } pika_bool builtins_isinstance(PikaObj* self, Arg* object, Arg* classinfo) { if (!argType_isConstructor(arg_getType(classinfo)) && !argType_isCallable(arg_getType(classinfo))) { obj_setErrorCode(self, 1); obj_setSysOut(self, "TypeError: isinstance() arg 2 must be a type"); return pika_false; } return _isinstance(object, classinfo); } Arg* builtins_StringObj___next__(PikaObj* self) { return arg_newNone(); } Arg* builtins_RangeObj___next__(PikaObj* self) { RangeData* _ = (RangeData*)args_getStruct(self->list, "_"); int end = _->end; int step = _->step; /* exit */ if (_->i >= end) { return arg_newNone(); } Arg* res = arg_newInt(_->i); _->i += step; return res; } PikaObj* New_builtins(Args* args); PikaObj* obj_getBuiltins(void) { return newNormalObj(New_builtins); } void builtins_bytearray___init__(PikaObj* self, Arg* bytes) { obj_setArg_noCopy(self, "raw", builtins_bytes(self, bytes)); } Arg* builtins_bytearray___iter__(PikaObj* self) { obj_setInt(self, "__iter_i", 0); return arg_newRef(self); } int builtins_bytearray___len__(PikaObj* self) { return obj_getBytesSize(self, "raw"); } Arg* builtins_bytearray___next__(PikaObj* self) { int __iter_i = args_getInt(self->list, "__iter_i"); uint8_t* data = obj_getBytes(self, "raw"); uint16_t len = obj_getBytesSize(self, "raw"); Arg* res = NULL; char char_buff[] = " "; if (__iter_i < len) { char_buff[0] = data[__iter_i]; res = arg_newInt(char_buff[0]); } else { return arg_newNone(); } args_setInt(self->list, "__iter_i", __iter_i + 1); return res; } int builtins_bytearray___getitem__(PikaObj* self, int __key) { uint8_t* data = obj_getBytes(self, "raw"); uint16_t len = obj_getBytesSize(self, "raw"); if (__key < len) { return data[__key]; } else { return 0; } } pika_bool _bytes_contains(Arg* self, Arg* others) { ArgType type = arg_getType(others); if (type == ARG_TYPE_BYTES) { uint8_t* bytes1 = arg_getBytes(self); uint8_t* bytes2 = arg_getBytes(others); size_t size1 = arg_getBytesSize(self); size_t size2 = arg_getBytesSize(others); if (size1 > size2) { return pika_false; } size_t i = 0, j = 0, start_j = 0; while (j < size2) { if (bytes1[i] == bytes2[j]) { i++; j++; if (i == size1) { return pika_true; } } else { j = ++start_j; // Move `j` to the next start position i = 0; // Reset `i` } } } return pika_false; } int builtins_bytearray___contains__(PikaObj* self, Arg* others) { if (arg_isObject(others)) { others = obj_getArg(arg_getObj(others), "raw"); } return _bytes_contains(others, obj_getArg(self, "raw")); } void builtins_bytearray___setitem__(PikaObj* self, int __key, int __val) { uint8_t* data = obj_getBytes(self, "raw"); uint16_t len = obj_getBytesSize(self, "raw"); if (__key < len) { data[__key] = __val; } } char* builtins_bytearray___str__(PikaObj* self) { uint8_t* data = obj_getBytes(self, "raw"); uint16_t len = obj_getBytesSize(self, "raw"); Arg* str_arg = arg_newStr(""); str_arg = arg_strAppend(str_arg, "bytearray(b'"); for (int i = 0; i < len; i++) { char u8_str[] = "\\x00"; uint8_t u8 = data[i]; __platform_sprintf(u8_str, "\\x%02x", u8); str_arg = arg_strAppend(str_arg, u8_str); } str_arg = arg_strAppend(str_arg, "')"); obj_removeArg(self, "_buf"); obj_setStr(self, "_buf", arg_getStr(str_arg)); arg_deinit(str_arg); return obj_getStr(self, "_buf"); } char* builtins_bytearray_decode(PikaObj* self) { uint8_t* data = obj_getBytes(self, "raw"); return obj_cacheStr(self, (char*)data); } PikaObj* builtins_bytearray_split(PikaObj* self, PikaTuple* vars) { int max_splite = -1; Arg* sep = NULL; pika_bool sep_need_free = pika_false; if (pikaTuple_getSize(vars) >= 1) { sep = pikaTuple_getArg(vars, 0); } else { sep = arg_newBytes((uint8_t*)" ", 1); sep_need_free = pika_true; } if (pikaTuple_getSize(vars) == 2) { max_splite = pikaTuple_getInt(vars, 1); } if (arg_getType(sep) != ARG_TYPE_BYTES) { obj_setErrorCode(self, 1); obj_setSysOut(self, "TypeError: bytes is required"); return NULL; } PikaList* list = NULL; uint8_t* sep_data = arg_getBytes(sep); size_t sep_len = arg_getBytesSize(sep); if (sep_len == 0) { obj_setErrorCode(self, 1); obj_setSysOut(self, "ValueError: empty separator"); goto __exit; } list = New_PikaList(); uint8_t* data = obj_getBytes(self, "raw"); size_t len = obj_getBytesSize(self, "raw"); if (len == 0) { pikaList_append(list, arg_newBytes((uint8_t*)"", 0)); goto __exit; } size_t start = 0; int splits = 0; for (size_t i = 0; i < len; i++) { // Check if the current position can accommodate the separator if (i <= len - sep_len && memcmp(data + i, sep_data, sep_len) == 0) { // Found a separator, slice the bytearray from start to current // position uint8_t* target_data = data + start; size_t target_len = i - start; pikaList_append(list, arg_newBytes(target_data, target_len)); // Move the start index past the separator start = i + sep_len; i = start - 1; // Adjust `i` as it will be incremented by the loop // Increment the split count and check if we've reached the maximum // number of splits splits++; if (max_splite != -1 && splits >= max_splite) { break; } } } // Add the last segment if any remains if (start < len) { uint8_t* target_data = data + start; size_t target_len = len - start; pikaList_append(list, arg_newBytes(target_data, target_len)); } // After loop if (sep_len > 0 && start == len) { pikaList_append(list, arg_newBytes((uint8_t*)"", 0)); } __exit: if (sep_need_free) { arg_deinit(sep); } return list; } int32_t pikaDict_forEach(PikaObj* self, int32_t (*eachHandle)(PikaObj* self, Arg* keyEach, Arg* valEach, void* context), void* context) { Args* keys = _OBJ2KEYS(self); Args* dict = _OBJ2DICT(self); pika_assert(NULL != dict); pika_assert(NULL != keys); size_t size = args_getSize(keys); for (int i = size - 1; i >= 0; i--) { Arg* item_key = args_getArgByIndex(keys, i); Arg* item_val = args_getArgByIndex(dict, i); pika_assert(NULL != item_key); // Call the handle function on each key-value pair if (eachHandle(self, item_key, item_val, context) != 0) { return -1; } } return 0; } int32_t pikaList_forEach(PikaObj* self, int32_t (*eachHandle)(PikaObj* self, int itemIndex, Arg* itemEach, void* context), void* context) { int i = 0; while (PIKA_TRUE) { Arg* item = pikaList_get(self, i); if (NULL == item) { break; } // Call the handler function with the item. int32_t result = eachHandle(self, i, item, context); if (result != 0) { // If the handler function returns a non-zero value, // stop the iteration. return result; } i++; } return 0; } void pika_sleep_ms(uint32_t ms) { int64_t tick = pika_platform_get_tick(); while (1) { pika_platform_thread_yield(); #if PIKA_EVENT_ENABLE if (!pika_GIL_isInit()) { _VMEvent_pickupEvent(); } #endif if (pika_platform_get_tick() - tick >= ms) { break; } } } PikaObj* _New_pikaListOrTuple(int isTuple) { Args* list = New_args(NULL); /* set top index for append */ args_pushArg_name(list, "top", arg_newInt(0)); PikaObj* self = NULL; if (isTuple) { self = newNormalObj(New_PikaStdData_Tuple); } else { self = newNormalObj(New_PikaStdData_List); } obj_setPtr(self, "list", list); return self; } PikaList* New_PikaList(void) { return _New_pikaListOrTuple(0); } PikaTuple* New_pikaTuple(void) { return _New_pikaListOrTuple(1); } void pikaDict_init(PikaObj* self) { Args* dict = New_args(NULL); Args* keys = New_args(NULL); obj_setPtr(self, "dict", dict); obj_setPtr(self, "_keys", keys); } PikaDict* New_PikaDict(void) { PikaDict* self = newNormalObj(New_PikaStdData_Dict); pikaDict_init(self); return self; } PIKA_RES pikaList_set(PikaList* self, int index, Arg* arg) { char buff[11]; char* i_str = fast_itoa(buff, index); int top = pikaList_getSize(self); if (index > top) { return PIKA_RES_ERR_OUT_OF_RANGE; } arg = arg_setName(arg, i_str); args_setArg(_OBJ2LIST(self), arg); return PIKA_RES_OK; } Arg* pikaList_get(PikaList* self, int index) { pika_assert(NULL != self); char buff[11]; char* i_str = fast_itoa(buff, index); return args_getArg(_OBJ2LIST(self), i_str); } int pikaList_getInt(PikaList* self, int index) { Arg* arg = pikaList_get(self, index); return arg_getInt(arg); } pika_bool pikaList_getBool(PikaList* self, int index) { Arg* arg = pikaList_get(self, index); return arg_getBool(arg); } pika_float pikaList_getFloat(PikaList* self, int index) { Arg* arg = pikaList_get(self, index); return arg_getFloat(arg); } char* pikaList_getStr(PikaList* self, int index) { Arg* arg = pikaList_get(self, index); return arg_getStr(arg); } void* pikaList_getPtr(PikaList* self, int index) { Arg* arg = pikaList_get(self, index); return arg_getPtr(arg); } PikaObj* pikaList_getObj(PikaList* self, int index) { Arg* arg = pikaList_get(self, index); return arg_getObj(arg); } PIKA_RES pikaList_append(PikaList* self, Arg* arg) { if (NULL == arg) { return PIKA_RES_ERR_ARG_NO_FOUND; } int top = pikaList_getSize(self); char buff[11]; char* topStr = fast_itoa(buff, top); Arg* arg_to_push = arg; arg_setName(arg_to_push, topStr); args_setArg(_OBJ2LIST(self), arg_to_push); /* top++ */ return args_setInt(_OBJ2LIST(self), "top", top + 1); } void pikaList_deinit(PikaList* self) { args_deinit(_OBJ2LIST(self)); } void pikaTuple_deinit(PikaTuple* self) { pikaList_deinit(self); } ArgType pikaList_getType(PikaList* self, int index) { Arg* arg = pikaList_get(self, index); return arg_getType(arg); } Arg* pikaList_pop_withIndex(PikaList* self, int index) { int top = pikaList_getSize(self); if (top <= 0) { return NULL; } if (index < 0) { index = top + index; } Arg* arg = pikaList_get(self, index); Arg* res = arg_copy(arg); pikaList_remove(self, arg); return res; } Arg* pikaList_pop(PikaList* self) { int top = pikaList_getSize(self); if (top <= 0) { return NULL; } return pikaList_pop_withIndex(self, top - 1); } PIKA_RES pikaList_remove(PikaList* self, Arg* arg) { int top = pikaList_getSize(self); int i_remove = 0; if (top <= 0) { return PIKA_RES_ERR_OUT_OF_RANGE; } for (int i = 0; i < top; i++) { Arg* arg_now = pikaList_get(self, i); if (arg_isEqual(arg_now, arg)) { i_remove = i; args_removeArg(_OBJ2LIST(self), arg_now); break; } } /* move args */ for (int i = i_remove + 1; i < top; i++) { char buff[11]; char* i_str = fast_itoa(buff, i - 1); Arg* arg_now = pikaList_get(self, i); arg_setName(arg_now, i_str); } args_setInt(_OBJ2LIST(self), "top", top - 1); return PIKA_RES_OK; } PIKA_RES pikaList_insert(PikaList* self, int index, Arg* arg) { int top = pikaList_getSize(self); if (index > top) { return PIKA_RES_ERR_OUT_OF_RANGE; } /* move args */ for (int i = top - 1; i >= index; i--) { char buff[11]; char* i_str = fast_itoa(buff, i + 1); Arg* arg_now = pikaList_get(self, i); arg_setName(arg_now, i_str); } char buff[11]; char* i_str = fast_itoa(buff, index); Arg* arg_to_push = arg_copy(arg); arg_setName(arg_to_push, i_str); args_setArg(_OBJ2LIST(self), arg_to_push); args_setInt(_OBJ2LIST(self), "top", top + 1); return PIKA_RES_OK; } size_t pikaList_getSize(PikaList* self) { if (NULL == self) { return 0; } int64_t ret = args_getInt(_OBJ2LIST(self), "top"); pika_assert(ret >= 0); return ret; } void pikaList_init(PikaObj* self) { Args* list = New_args(NULL); args_pushArg_name(list, "top", arg_newInt(0)); obj_setPtr(self, "list", list); } void pikaList_reverse(PikaList* self) { pika_assert(NULL != self); int top = pikaList_getSize(self); for (int i = 0; i < top / 2; i++) { Arg* arg_i = arg_copy(pikaList_get(self, i)); Arg* arg_top = arg_copy(pikaList_get(self, top - i - 1)); pikaList_set(self, i, arg_top); pikaList_set(self, top - i - 1, arg_i); } } Arg* pikaTuple_getArg(PikaTuple* self, int index) { return pikaList_get(self, (index)); } size_t pikaTuple_getSize(PikaTuple* self) { if (self == NULL) { return 0; } return pikaList_getSize(self); } int64_t pikaTuple_getInt(PikaTuple* self, int index) { return pikaList_getInt(self, (index)); } pika_bool pikaTuple_getBool(PikaTuple* self, int index) { return pikaList_getBool(self, (index)); } pika_float pikaTuple_getFloat(PikaTuple* self, int index) { return pikaList_getFloat(self, (index)); } char* pikaTuple_getStr(PikaTuple* self, int index) { return pikaList_getStr(self, (index)); } void* pikaTuple_getPtr(PikaTuple* self, int index) { return pikaList_getPtr(self, (index)); } ArgType pikaTuple_getType(PikaTuple* self, int index) { return pikaList_getType(self, (index)); } PIKA_RES pikaDict_setInt(PikaDict* self, char* name, int64_t val) { return pikaDict_set(self, name, arg_newInt(val)); } pika_bool pikaDict_setBool(PikaDict* self, char* name, pika_bool val) { return pikaDict_set(self, name, arg_newBool(val)); } PIKA_RES pikaDict_setFloat(PikaDict* self, char* name, pika_float val) { return pikaDict_set(self, name, arg_newFloat(val)); } PIKA_RES pikaDict_setStr(PikaDict* self, char* name, char* val) { return pikaDict_set(self, name, arg_newStr(val)); } PIKA_RES pikaDict_setPtr(PikaDict* self, char* name, void* val) { return pikaDict_set(self, name, arg_newPtr(ARG_TYPE_POINTER, val)); } PIKA_RES _pikaDict_setVal(PikaDict* self, Arg* val) { return args_setArg(_OBJ2DICT(self), (val)); } PIKA_RES pikaDict_set(PikaDict* self, char* name, Arg* val) { val = arg_setName(val, name); _pikaDict_setVal(self, val); return args_setStr(_OBJ2KEYS(self), (name), (name)); } PIKA_RES pikaDict_removeArg(PikaDict* self, Arg* val) { // args_removeArg(_OBJ2KEYS(self), (val)); return args_removeArg(_OBJ2DICT(self), (val)); } PIKA_RES pikaDict_reverse(PikaDict* self) { args_reverse(_OBJ2KEYS(self)); args_reverse(_OBJ2DICT(self)); return PIKA_RES_OK; } PIKA_RES pikaDict_setBytes(PikaDict* self, char* name, uint8_t* val, size_t size) { return pikaDict_set(self, name, arg_newBytes(val, size)); } int64_t pikaDict_getInt(PikaDict* self, char* name) { return args_getInt(_OBJ2DICT(self), (name)); } pika_bool pikaDict_getBool(PikaDict* self, char* name) { return args_getBool(_OBJ2DICT(self), (name)); } pika_float pikaDict_getFloat(PikaDict* self, char* name) { return args_getFloat(_OBJ2DICT(self), (name)); } char* pikaDict_getStr(PikaDict* self, char* name) { return args_getStr(_OBJ2DICT(self), (name)); } void* pikaDict_getPtr(PikaDict* self, char* name) { return args_getPtr(_OBJ2DICT(self), (name)); } PikaObj* pikaDict_getObj(PikaDict* self, char* name) { return args_getPtr(_OBJ2DICT(self), (name)); } int pikaDict_getSize(PikaDict* self) { return args_getSize(_OBJ2DICT(self)); } Arg* pikaDict_getArgByindex(PikaDict* self, int index) { return args_getArgByIndex(_OBJ2DICT(self), (index)); } Arg* pikaDict_get(PikaDict* self, char* name) { return args_getArg(_OBJ2DICT(self), (name)); } int32_t pikaDict_isArgExist(PikaDict* self, char* name) { return args_isArgExist(_OBJ2DICT(self), (name)); } uint8_t* pikaDict_getBytes(PikaDict* self, char* name) { return args_getBytes(_OBJ2DICT(self), (name)); } ArgType pikaDict_getType(PikaDict* self, char* name) { return args_getType(_OBJ2DICT(self), (name)); } size_t pikaDict_getBytesSize(PikaDict* self, char* name) { return args_getBytesSize(_OBJ2DICT(self), (name)); } void pikaDict_deinit(PikaDict* self) { obj_deinit(self); } PIKA_RES insert_label_at_line(const char* filename, int N, char* buff, int buff_size) { FILE* file = pika_platform_fopen(filename, "r"); if (!file) { return PIKA_RES_ERR_IO_ERROR; } int line_count = 1; int buff_index = 0; char ch; while ((pika_platform_fread(&ch, 1, 1, file)) != 0) { if (line_count == N) { char* label = "#!label\n"; int label_length = strGetSize(label); if (buff_index + label_length >= buff_size) { pika_platform_fclose(file); return PIKA_RES_ERR_IO_ERROR; // Insufficient buffer size } strCopy(buff + buff_index, label); buff_index += label_length; line_count++; // Skip this line since we're adding a label } if (ch == '\n') { line_count++; } if (buff_index >= buff_size - 1) { // -1 to leave space for null terminator pika_platform_fclose(file); return PIKA_RES_ERR_IO_ERROR; // Insufficient buffer size } buff[buff_index] = ch; buff_index++; } buff[buff_index] = '\0'; // Null terminate the buffer pika_platform_fclose(file); return PIKA_RES_OK; } int32_t pika_debug_find_break_point_pc(char* pyFile, uint32_t pyLine) { ByteCodeFrame bytecode_frame; byteCodeFrame_init(&bytecode_frame); char* file_buff = pikaMalloc(PIKA_READ_FILE_BUFF_SIZE); FILE* file = pika_platform_fopen(pyFile, "r"); if (!file) { goto __exit; } if (PIKA_RES_OK != insert_label_at_line(pyFile, pyLine, file_buff, PIKA_READ_FILE_BUFF_SIZE)) { goto __exit; } pika_lines2Bytes(&bytecode_frame, file_buff); __exit: if (NULL != file) { pika_platform_fclose(file); } byteCodeFrame_deinit(&bytecode_frame); pikaFree(file_buff, PIKA_READ_FILE_BUFF_SIZE); return bytecode_frame.label_pc; }