improve err report and add struct model(not test)

This commit is contained in:
Lyon 2023-07-20 11:07:41 +08:00
parent f342cde844
commit 06b6d9f049
9 changed files with 976 additions and 52 deletions

255
package/struct/_struct.c Normal file
View File

@ -0,0 +1,255 @@
/*
* This file is part of the PikaPython project, https://pikapython.com
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
* Copyright (c) 2023 Lyon
*
* 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 "_struct.h"
#include "pika_adapter_mpy.h"
#define _SKIP_COMPILE 1
#ifndef _SKIP_COMPILE
/*
This module implements most of character typecodes from CPython, with
some extensions:
O - (Pointer to) an arbitrary Python object. This is useful for callback
data, etc. Note that you must keep reference to passed object in
your Python application, otherwise it may be garbage-collected,
and then when you get back this value from callback it may be
invalid (and lead to crash).
S - Pointer to a string (returned as a Python string). Note the
difference from "Ns", - the latter says "in this place of structure
is character data of up to N bytes length", while "S" means
"in this place of a structure is a pointer to zero-terminated
character data".
*/
STATIC char get_fmt_type(const char** fmt) {
char t = **fmt;
switch (t) {
case '!':
t = '>';
break;
case '@':
case '=':
case '<':
case '>':
break;
default:
return '@';
}
// Skip type char
(*fmt)++;
return t;
}
STATIC mp_uint_t get_fmt_num(const char** p) {
const char* num = *p;
uint len = 1;
while (unichar_isdigit(*++num)) {
len++;
}
char* buff = pika_platform_malloc(len + 1);
pika_platform_memset(buff, 0, len + 1);
pika_platform_memcpy(buff, *p, len);
mp_uint_t val = (mp_uint_t)fast_atoi((char*)num);
*p = num;
return val;
}
STATIC size_t calc_size_items(const char* fmt, size_t* total_sz) {
char fmt_type = get_fmt_type(&fmt);
size_t total_cnt = 0;
size_t size;
for (size = 0; *fmt; fmt++) {
mp_uint_t cnt = 1;
if (unichar_isdigit(*fmt)) {
cnt = get_fmt_num(&fmt);
}
if (*fmt == 's') {
total_cnt += 1;
size += cnt;
} else {
total_cnt += cnt;
size_t align;
size_t sz = mp_binary_get_size(fmt_type, *fmt, &align);
while (cnt--) {
// Apply alignment
size = (size + align - 1) & ~(align - 1);
size += sz;
}
}
}
*total_sz = size;
return total_cnt;
}
STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
const char* fmt = mp_obj_str_get_str(fmt_in);
size_t size;
calc_size_items(fmt, &size);
return MP_OBJ_NEW_SMALL_INT(size);
}
STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t* args) {
// unpack requires that the buffer be exactly the right size.
// unpack_from requires that the buffer be "big enough".
// Since we implement unpack and unpack_from using the same function
// we relax the "exact" requirement, and only implement "big enough".
const char* fmt = mp_obj_str_get_str((Arg*)args[0]);
size_t total_sz;
size_t num_items = calc_size_items(fmt, &total_sz);
char fmt_type = get_fmt_type(&fmt);
mp_obj_tuple_t* res = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_items, NULL));
mp_buffer_info_t bufinfo;
mp_get_buffer_raise((Arg*)args[1], &bufinfo, MP_BUFFER_READ);
byte* p = bufinfo.buf;
byte* end_p = &p[bufinfo.len];
mp_int_t offset = 0;
if (n_args > 2) {
// offset arg provided
offset = mp_obj_get_int((Arg*)args[2]);
if (offset < 0) {
// negative offsets are relative to the end of the buffer
offset = bufinfo.len + offset;
if (offset < 0) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer too small"));
}
}
p += offset;
}
byte* p_base = p;
// Check that the input buffer is big enough to unpack all the values
if (p + total_sz > end_p) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer too small"));
}
for (size_t i = 0; i < num_items;) {
mp_uint_t cnt = 1;
if (unichar_isdigit(*fmt)) {
cnt = get_fmt_num(&fmt);
}
mp_obj_t item;
if (*fmt == 's') {
item = mp_obj_new_bytes(p, cnt);
p += cnt;
res->items[i++] = item;
} else {
while (cnt--) {
item = mp_binary_get_val(fmt_type, *fmt, p_base, &p);
res->items[i++] = item;
}
}
fmt++;
}
return MP_OBJ_FROM_PTR(res);
}
// This function assumes there is enough room in p to store all the values
STATIC void struct_pack_into_internal(mp_obj_t fmt_in,
byte* p,
size_t n_args,
const mp_obj_t* args) {
const char* fmt = mp_obj_str_get_str(fmt_in);
char fmt_type = get_fmt_type(&fmt);
byte* p_base = p;
size_t i;
for (i = 0; i < n_args;) {
mp_uint_t cnt = 1;
if (*fmt == '\0') {
// more arguments given than used by format string; CPython raises
// struct.error here
break;
}
if (unichar_isdigit(*fmt)) {
cnt = get_fmt_num(&fmt);
}
if (*fmt == 's') {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[i++], &bufinfo, MP_BUFFER_READ);
mp_uint_t to_copy = cnt;
if (bufinfo.len < to_copy) {
to_copy = bufinfo.len;
}
memcpy(p, bufinfo.buf, to_copy);
memset(p + to_copy, 0, cnt - to_copy);
p += cnt;
} else {
// If we run out of args then we just finish; CPython would raise
// struct.error
while (cnt-- && i < n_args) {
mp_binary_set_val(fmt_type, *fmt, args[i++], p_base, &p);
}
}
fmt++;
}
}
STATIC mp_obj_t struct_pack(size_t n_args, const mp_obj_t* args) {
// TODO: "The arguments must match the values required by the format
// exactly."
mp_int_t size = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0]));
vstr_t vstr;
vstr_init_len(&vstr, size);
byte* p = (byte*)vstr.buf;
memset(p, 0, size);
struct_pack_into_internal(args[0], p, n_args - 1, &args[1]);
return mp_obj_new_bytes_from_vstr(&vstr);
}
STATIC mp_obj_t struct_pack_into(size_t n_args, const mp_obj_t* args) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
mp_int_t offset = mp_obj_get_int(args[2]);
if (offset < 0) {
// negative offsets are relative to the end of the buffer
offset = (mp_int_t)bufinfo.len + offset;
if (offset < 0) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer too small"));
}
}
byte* p = (byte*)bufinfo.buf;
byte* end_p = &p[bufinfo.len];
p += offset;
// Check that the output buffer is big enough to hold all the values
mp_int_t sz = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0]));
if (p + sz > end_p) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer too small"));
}
struct_pack_into_internal(args[0], p, n_args - 3, &args[3]);
return mp_const_none;
}
#endif

View File

View File

@ -0,0 +1,255 @@
/*
* This file is part of the PikaPython project, https://pikapython.com
*
* The MIT License (MIT)
*
* Copyright (c) 2013, 2014 Damien P. George
* Copyright (c) 2014 Paul Sokolovsky
* Copyright (c) 2023 Lyon
*
* 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 "_struct.h"
#include "pika_adapter_mpy.h"
#define _SKIP_COMPILE 1
#ifndef _SKIP_COMPILE
/*
This module implements most of character typecodes from CPython, with
some extensions:
O - (Pointer to) an arbitrary Python object. This is useful for callback
data, etc. Note that you must keep reference to passed object in
your Python application, otherwise it may be garbage-collected,
and then when you get back this value from callback it may be
invalid (and lead to crash).
S - Pointer to a string (returned as a Python string). Note the
difference from "Ns", - the latter says "in this place of structure
is character data of up to N bytes length", while "S" means
"in this place of a structure is a pointer to zero-terminated
character data".
*/
STATIC char get_fmt_type(const char** fmt) {
char t = **fmt;
switch (t) {
case '!':
t = '>';
break;
case '@':
case '=':
case '<':
case '>':
break;
default:
return '@';
}
// Skip type char
(*fmt)++;
return t;
}
STATIC mp_uint_t get_fmt_num(const char** p) {
const char* num = *p;
uint len = 1;
while (unichar_isdigit(*++num)) {
len++;
}
char* buff = pika_platform_malloc(len + 1);
pika_platform_memset(buff, 0, len + 1);
pika_platform_memcpy(buff, *p, len);
mp_uint_t val = (mp_uint_t)fast_atoi((char*)num);
*p = num;
return val;
}
STATIC size_t calc_size_items(const char* fmt, size_t* total_sz) {
char fmt_type = get_fmt_type(&fmt);
size_t total_cnt = 0;
size_t size;
for (size = 0; *fmt; fmt++) {
mp_uint_t cnt = 1;
if (unichar_isdigit(*fmt)) {
cnt = get_fmt_num(&fmt);
}
if (*fmt == 's') {
total_cnt += 1;
size += cnt;
} else {
total_cnt += cnt;
size_t align;
size_t sz = mp_binary_get_size(fmt_type, *fmt, &align);
while (cnt--) {
// Apply alignment
size = (size + align - 1) & ~(align - 1);
size += sz;
}
}
}
*total_sz = size;
return total_cnt;
}
STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
const char* fmt = mp_obj_str_get_str(fmt_in);
size_t size;
calc_size_items(fmt, &size);
return MP_OBJ_NEW_SMALL_INT(size);
}
STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t* args) {
// unpack requires that the buffer be exactly the right size.
// unpack_from requires that the buffer be "big enough".
// Since we implement unpack and unpack_from using the same function
// we relax the "exact" requirement, and only implement "big enough".
const char* fmt = mp_obj_str_get_str((Arg*)args[0]);
size_t total_sz;
size_t num_items = calc_size_items(fmt, &total_sz);
char fmt_type = get_fmt_type(&fmt);
mp_obj_tuple_t* res = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_items, NULL));
mp_buffer_info_t bufinfo;
mp_get_buffer_raise((Arg*)args[1], &bufinfo, MP_BUFFER_READ);
byte* p = bufinfo.buf;
byte* end_p = &p[bufinfo.len];
mp_int_t offset = 0;
if (n_args > 2) {
// offset arg provided
offset = mp_obj_get_int((Arg*)args[2]);
if (offset < 0) {
// negative offsets are relative to the end of the buffer
offset = bufinfo.len + offset;
if (offset < 0) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer too small"));
}
}
p += offset;
}
byte* p_base = p;
// Check that the input buffer is big enough to unpack all the values
if (p + total_sz > end_p) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer too small"));
}
for (size_t i = 0; i < num_items;) {
mp_uint_t cnt = 1;
if (unichar_isdigit(*fmt)) {
cnt = get_fmt_num(&fmt);
}
mp_obj_t item;
if (*fmt == 's') {
item = mp_obj_new_bytes(p, cnt);
p += cnt;
res->items[i++] = item;
} else {
while (cnt--) {
item = mp_binary_get_val(fmt_type, *fmt, p_base, &p);
res->items[i++] = item;
}
}
fmt++;
}
return MP_OBJ_FROM_PTR(res);
}
// This function assumes there is enough room in p to store all the values
STATIC void struct_pack_into_internal(mp_obj_t fmt_in,
byte* p,
size_t n_args,
const mp_obj_t* args) {
const char* fmt = mp_obj_str_get_str(fmt_in);
char fmt_type = get_fmt_type(&fmt);
byte* p_base = p;
size_t i;
for (i = 0; i < n_args;) {
mp_uint_t cnt = 1;
if (*fmt == '\0') {
// more arguments given than used by format string; CPython raises
// struct.error here
break;
}
if (unichar_isdigit(*fmt)) {
cnt = get_fmt_num(&fmt);
}
if (*fmt == 's') {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[i++], &bufinfo, MP_BUFFER_READ);
mp_uint_t to_copy = cnt;
if (bufinfo.len < to_copy) {
to_copy = bufinfo.len;
}
memcpy(p, bufinfo.buf, to_copy);
memset(p + to_copy, 0, cnt - to_copy);
p += cnt;
} else {
// If we run out of args then we just finish; CPython would raise
// struct.error
while (cnt-- && i < n_args) {
mp_binary_set_val(fmt_type, *fmt, args[i++], p_base, &p);
}
}
fmt++;
}
}
STATIC mp_obj_t struct_pack(size_t n_args, const mp_obj_t* args) {
// TODO: "The arguments must match the values required by the format
// exactly."
mp_int_t size = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0]));
vstr_t vstr;
vstr_init_len(&vstr, size);
byte* p = (byte*)vstr.buf;
memset(p, 0, size);
struct_pack_into_internal(args[0], p, n_args - 1, &args[1]);
return mp_obj_new_bytes_from_vstr(&vstr);
}
STATIC mp_obj_t struct_pack_into(size_t n_args, const mp_obj_t* args) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE);
mp_int_t offset = mp_obj_get_int(args[2]);
if (offset < 0) {
// negative offsets are relative to the end of the buffer
offset = (mp_int_t)bufinfo.len + offset;
if (offset < 0) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer too small"));
}
}
byte* p = (byte*)bufinfo.buf;
byte* end_p = &p[bufinfo.len];
p += offset;
// Check that the output buffer is big enough to hold all the values
mp_int_t sz = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0]));
if (p + sz > end_p) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer too small"));
}
struct_pack_into_internal(args[0], p, n_args - 3, &args[3]);
return mp_const_none;
}
#endif

View File

@ -565,12 +565,15 @@ static inline uint8_t obj_refcntNow(PikaObj* self) {
#define obj_setStruct(PikaObj_p_self, char_p_name, struct_) \
args_setStruct(((PikaObj_p_self)->list), char_p_name, struct_)
#define PIKA_ERR_STRING_SYNTAX_ERROR "SyntaxError: invalid syntax\r\n"
#define PIKA_ERR_STRING_SYNTAX_ERROR \
ANSI_COLOR_RED "SyntaxError: invalid syntax\r\n" ANSI_COLOR_RESET
#define ABSTRACT_METHOD_NEED_OVERRIDE_ERROR(_) \
obj_setErrorCode(self, 1); \
pika_platform_printf("Error: abstract method `%s()` need override.\r\n", \
__FUNCTION__)
pika_platform_printf( \
ANSI_COLOR_RED \
"Error: abstract method `%s()` need override.\r\n" ANSI_COLOR_RESET, \
__FUNCTION__)
char* obj_cacheStr(PikaObj* self, char* str);
PikaObj* _arg_to_obj(Arg* self, pika_bool* pIsTemp);
@ -613,9 +616,9 @@ const MethodProp floatMethod = {
#endif
#if PIKA_ARG_CACHE_ENABLE
#define _ARG_HEAP_SIZE_DEF .heap_size = 0,
#define _ARG_HEAP_SIZE_DEF() .heap_size = 0,
#else
#define _ARG_HEAP_SIZE_DEF
#define _ARG_HEAP_SIZE_DEF()
#endif
#if PIKA_KERNAL_DEBUG_ENABLE
@ -634,7 +637,7 @@ const MethodProp floatMethod = {
.buffer = (uint8_t*)&_method##Prop \
}, \
.size = sizeof(MethodPropNative), \
_ARG_HEAP_SIZE_DEF \
_ARG_HEAP_SIZE_DEF() \
.type = _type, \
.flag = 0, \
.name_hash = _hash, \
@ -695,14 +698,6 @@ Arg* pika_eventListener_sendSignalAwaitResult(PikaEventListener* self,
uint32_t eventId,
int eventSignal);
#define COLOR_RED "\x1b[31m"
#define COLOR_GREEN "\x1b[32m"
#define COLOR_YELLOW "\x1b[33m"
#define COLOR_BLUE "\x1b[34m"
#define COLOR_MAGENTA "\x1b[35m"
#define COLOR_CYAN "\x1b[36m"
#define COLOR_RESET "\x1b[0m"
void obj_printModules(PikaObj* self);
#if PIKA_DEBUG_ENABLE
#define pika_debug(fmt, ...) \

View File

@ -315,10 +315,7 @@ PIKA_WEAK char pika_platform_getchar(void) {
#if defined(__linux) || defined(_WIN32)
return getchar();
#else
pika_platform_printf(
"Error: pika_platform_getchar need implementation!\r\n");
while (1) {
}
WEAK_FUNCTION_NEED_OVERRIDE_ERROR_LOWLEVEL();
#endif
}
@ -327,9 +324,7 @@ PIKA_WEAK FILE* pika_platform_fopen(const char* filename, const char* modes) {
#if defined(__linux) || defined(_WIN32)
return fopen(filename, modes);
#else
pika_platform_printf("Error: pika_platform_fopen need implementation!\r\n");
while (1) {
}
WEAK_FUNCTION_NEED_OVERRIDE_ERROR_LOWLEVEL();
#endif
}
@ -338,10 +333,7 @@ PIKA_WEAK int pika_platform_fclose(FILE* stream) {
#if defined(__linux) || defined(_WIN32)
return fclose(stream);
#else
pika_platform_printf(
"Error: pika_platform_fclose need implementation!\r\n");
while (1) {
}
WEAK_FUNCTION_NEED_OVERRIDE_ERROR_LOWLEVEL();
#endif
}
@ -354,10 +346,7 @@ PIKA_WEAK size_t pika_platform_fwrite(const void* ptr,
#if defined(__linux) || defined(_WIN32)
return fwrite(ptr, size, n, stream);
#else
pika_platform_printf(
"Error: pika_platform_fwrite need implementation!\r\n");
while (1) {
}
WEAK_FUNCTION_NEED_OVERRIDE_ERROR_LOWLEVEL();
#endif
}
@ -369,9 +358,7 @@ PIKA_WEAK size_t pika_platform_fread(void* ptr,
#if defined(__linux) || defined(_WIN32)
return fread(ptr, size, n, stream);
#else
pika_platform_printf("Error: pika_platform_fread need implementation!\r\n");
while (1) {
}
WEAK_FUNCTION_NEED_OVERRIDE_ERROR_LOWLEVEL(_);
#endif
}
@ -380,9 +367,7 @@ PIKA_WEAK int pika_platform_fseek(FILE* stream, long offset, int whence) {
#if defined(__linux) || defined(_WIN32)
return fseek(stream, offset, whence);
#else
pika_platform_printf("Error: pika_platform_fseek need implementation!\r\n");
while (1) {
}
WEAK_FUNCTION_NEED_OVERRIDE_ERROR_LOWLEVEL(_);
#endif
}
@ -391,9 +376,7 @@ PIKA_WEAK long pika_platform_ftell(FILE* stream) {
#if defined(__linux) || defined(_WIN32)
return ftell(stream);
#else
pika_platform_printf("Error: pika_platform_ftell need implementation!\r\n");
while (1) {
}
WEAK_FUNCTION_NEED_OVERRIDE_ERROR_LOWLEVEL(_);
#endif
}
@ -426,10 +409,7 @@ PIKA_WEAK void pika_platform_sleep_ms(uint32_t ms) {
#elif defined(_WIN32) && !defined(CROSS_BUILD)
Sleep(ms);
#else
pika_platform_printf(
"Error: pika_platform_sleep_ms need implementation!\r\n");
while (1) {
}
WEAK_FUNCTION_NEED_OVERRIDE_ERROR_LOWLEVEL(_);
#endif
}

View File

@ -43,6 +43,14 @@ extern "C" {
#include <unistd.h>
#endif
#define ANSI_COLOR_RED "\x1b[31m"
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_YELLOW "\x1b[33m"
#define ANSI_COLOR_BLUE "\x1b[34m"
#define ANSI_COLOR_MAGENTA "\x1b[35m"
#define ANSI_COLOR_CYAN "\x1b[36m"
#define ANSI_COLOR_RESET "\x1b[0m"
#define PIKA_ASSERT_2(expr, msg, ...) \
if (!(expr)) { \
pika_platform_printf((char*)"Assertion \"%s\" failed, in function: %s(). \r\n (at %s:%d)\n" msg, #expr, __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); \
@ -309,11 +317,26 @@ void pika_platform_thread_timer_usleep(unsigned long usec);
void pika_platform_reboot(void);
void pika_platform_clear(void);
#define WEAK_FUNCTION_NEED_OVERRIDE_ERROR(_) \
pika_platform_printf("Error: weak function `%s()` need override.\r\n", \
__FUNCTION__); \
#define WEAK_FUNCTION_NEED_OVERRIDE_INFO(_) \
pika_platform_printf(ANSI_COLOR_RED \
"Error: The function `%s()` has been invoked, but " \
"it is not implemented.\r\n" ANSI_COLOR_RESET, \
__FUNCTION__); \
pika_platform_printf( \
ANSI_COLOR_CYAN \
"Info: The function `%s()` is defined as a weak function by default. " \
"It should be overridden on this platform.\r\n" ANSI_COLOR_RESET, \
__FUNCTION__);
#define WEAK_FUNCTION_NEED_OVERRIDE_ERROR(_) \
WEAK_FUNCTION_NEED_OVERRIDE_INFO(_) \
pika_platform_panic_handle();
#define WEAK_FUNCTION_NEED_OVERRIDE_ERROR_LOWLEVEL(_) \
WEAK_FUNCTION_NEED_OVERRIDE_INFO(_) \
while (1) { \
}
#endif
#ifdef __cplusplus

View File

@ -191,6 +191,14 @@ static inline void* pikaDict_getPtr(PikaDict* self, char* name) {
return args_getPtr((&((self)->super)), (name));
}
static inline int pikaDict_getSize(PikaDict* self) {
return args_getSize((&((self)->super)));
}
static inline Arg* pikaDict_getArgByidex(PikaDict* self, int index) {
return args_getArgByIndex((&((self)->super)), (index));
}
static inline Arg* pikaDict_getArg(PikaDict* self, char* name) {
return args_getArg((&((self)->super)), (name));
}

View File

@ -1,3 +1,31 @@
/*
* This file is part of the PikaPython project, http://pikapython.com
*
* The MIT License (MIT)
*
* Copyright (c) 2014-2017 Paul Sokolovsky
* Copyright (c) 2014-2019 Damien P. George
* Copyright (c) 2023 Lyon
*
* 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.
*/
#ifdef __cplusplus
extern "C" {
#endif
@ -5,6 +33,7 @@ extern "C" {
#ifndef __PIKA_ADAPTER_MPY_H__
#define __PIKA_ADAPTER_MPY_H__
#include <stdint.h>
#include <stddef.h>
#include "PikaObj.h"
#include "PikaStdData_List.h"
#define bool int
@ -15,12 +44,18 @@ extern "C" {
/* type define*/
#define STATIC static
#define NORETURN
typedef unsigned char byte;
typedef unsigned int uint;
typedef uint32_t unichar;
#define UTF8_IS_NONASCII(ch) ((ch)&0x80)
#define UTF8_IS_CONT(ch) (((ch)&0xC0) == 0x80)
/* object API */
#define MP_OBJ_NEW_SMALL_INT(...) arg_newInt(__VA_ARGS__)
#define mp_obj_new_bool(...) arg_newInt(__VA_ARGS__)
#define mp_obj_new_bytes(...) arg_newBytes(__VA_ARGS__)
#define mp_obj_new_float(...) arg_newFloat(__VA_ARGS__)
#define mp_obj_new_int(...) arg_newInt(__VA_ARGS__)
#define MP_OBJ_TO_PTR(...) arg_getPtr(__VA_ARGS__)
#define MP_OBJ_FROM_PTR(_p) arg_newPtr(ARG_TYPE_OBJECT, (_p))
#define mp_obj_get_int(...) arg_getInt(__VA_ARGS__)
@ -29,6 +64,13 @@ extern "C" {
#define mp_const_false arg_newInt(0)
#define mp_const_none arg_newNull()
#define mp_obj_new_int_from_ll mp_obj_new_int
#define mp_obj_new_int_from_ull mp_obj_new_int
#define mp_obj_new_float_from_f mp_obj_new_float
#define mp_obj_new_float_from_d mp_obj_new_float
#define MP_OBJ_SMALL_INT_VALUE(...) arg_getInt(__VA_ARGS__)
/* module API */
#define MP_DEFINE_CONST_DICT(...)
#define MP_DEFINE_CONST_FUN_OBJ_KW(...)
@ -94,7 +136,9 @@ static inline int mp_obj_str_get_qstr(Arg* arg) {
return hash_time33(arg_getStr(arg));
}
#define mp_obj_new_str(str, len) arg_newStr(str)
static inline Arg* mp_obj_new_str(const char* str, size_t len) {
return arg_newStrN((char*)str, len);
}
typedef struct _mp_buffer_info_t {
void* buf; // can be NULL if len == 0
@ -110,14 +154,14 @@ static inline Arg* mp_obj_new_list(int n, Arg** items) {
return arg_newObj(list);
}
static inline mp_obj_tuple_t* mp_obj_new_tuple(int n, Arg** items_in) {
static inline mp_obj_t mp_obj_new_tuple(int n, Arg** items_in) {
mp_obj_tuple_t* tuple = (mp_obj_tuple_t*)malloc(sizeof(mp_obj_tuple_t));
Arg** items = (Arg**)malloc(sizeof(Arg*) * n);
if (NULL == items_in) {
tuple->len = n;
tuple->items = items;
}
return tuple;
return arg_newPtr(ARG_TYPE_POINTER, tuple);
}
static inline void mp_obj_list_append(Arg* list, mp_obj_tuple_t* tuple) {
@ -158,20 +202,20 @@ static inline void pks_load_mp_map(PikaDict* kw, mp_map_t* map) {
map->table = (mp_map_elem_t*)malloc(sizeof(mp_map_elem_t) * len);
for (int i = 0; i < len; i++) {
Arg* item = pikaDict_getArgByidex(kw, i);
map->table[i].key = arg_getNameHash(item);
map->table[i].key = arg_newInt(arg_getNameHash(item));
map->table[i].value = item;
}
}
static inline void mp_get_buffer_raise(mp_obj_t item,
static inline void mp_get_buffer_raise(const mp_obj_t item,
mp_buffer_info_t* buf,
char* msg) {
buf->len = arg_getSize(item);
buf->len = arg_getSize((Arg*)item);
buf->buf = malloc(buf->len);
if (NULL == buf->buf) {
mp_raise_OSError(msg);
}
memcpy(buf->buf, arg_getBytes(item), buf->len);
memcpy(buf->buf, arg_getBytes((Arg*)item), buf->len);
}
static const ArgType mp_type_tuple = ARG_TYPE_TUPLE;
@ -218,6 +262,10 @@ typedef struct _mp_rom_map_elem_t {
} mp_rom_map_elem_t;
#define MICROPY_OBJ_BASE_ALIGNMENT
#define MP_ALIGN(ptr, alignment) \
(void*)(((uintptr_t)(ptr) + ((alignment)-1)) & ~((alignment)-1))
#define MP_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
typedef struct _mp_obj_type_t mp_obj_type_t;
struct _mp_obj_base_t {
const mp_obj_type_t* type MICROPY_OBJ_BASE_ALIGNMENT;
@ -337,6 +385,366 @@ typedef struct _mp_obj_list_t {
mp_obj_t* items;
} mp_obj_list_t;
// attribute flags
#define FL_PRINT (0x01)
#define FL_SPACE (0x02)
#define FL_DIGIT (0x04)
#define FL_ALPHA (0x08)
#define FL_UPPER (0x10)
#define FL_LOWER (0x20)
#define FL_XDIGIT (0x40)
// shorthand character attributes
#define AT_PR (FL_PRINT)
#define AT_SP (FL_SPACE | FL_PRINT)
#define AT_DI (FL_DIGIT | FL_PRINT | FL_XDIGIT)
#define AT_AL (FL_ALPHA | FL_PRINT)
#define AT_UP (FL_UPPER | FL_ALPHA | FL_PRINT)
#define AT_LO (FL_LOWER | FL_ALPHA | FL_PRINT)
#define AT_UX (FL_UPPER | FL_ALPHA | FL_PRINT | FL_XDIGIT)
#define AT_LX (FL_LOWER | FL_ALPHA | FL_PRINT | FL_XDIGIT)
// table of attributes for ascii characters
STATIC const uint8_t attr[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, AT_SP, AT_SP,
AT_SP, AT_SP, AT_SP, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, AT_SP,
AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR,
AT_PR, AT_PR, AT_PR, AT_PR, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI, AT_DI,
AT_DI, AT_DI, AT_DI, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_UX,
AT_UX, AT_UX, AT_UX, AT_UX, AT_UX, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP,
AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP, AT_UP,
AT_UP, AT_UP, AT_UP, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_PR, AT_LX, AT_LX,
AT_LX, AT_LX, AT_LX, AT_LX, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO,
AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO, AT_LO,
AT_LO, AT_LO, AT_PR, AT_PR, AT_PR, AT_PR, 0};
static unichar utf8_get_char(const byte* s) {
unichar ord = *s++;
if (!UTF8_IS_NONASCII(ord)) {
return ord;
}
ord &= 0x7F;
for (unichar mask = 0x40; ord & mask; mask >>= 1) {
ord &= ~mask;
}
while (UTF8_IS_CONT(*s)) {
ord = (ord << 6) | (*s++ & 0x3F);
}
return ord;
}
static const byte* utf8_next_char(const byte* s) {
++s;
while (UTF8_IS_CONT(*s)) {
++s;
}
return s;
}
static mp_uint_t utf8_ptr_to_index(const byte* s, const byte* ptr) {
mp_uint_t i = 0;
while (ptr > s) {
if (!UTF8_IS_CONT(*--ptr)) {
i++;
}
}
return i;
}
static size_t utf8_charlen(const byte* str, size_t len) {
size_t charlen = 0;
for (const byte* top = str + len; str < top; ++str) {
if (!UTF8_IS_CONT(*str)) {
++charlen;
}
}
return charlen;
}
// Be aware: These unichar_is* functions are actually ASCII-only!
static bool unichar_isspace(unichar c) {
return c < 128 && (attr[c] & FL_SPACE) != 0;
}
static bool unichar_isalpha(unichar c) {
return c < 128 && (attr[c] & FL_ALPHA) != 0;
}
/* unused
bool unichar_isprint(unichar c) {
return c < 128 && (attr[c] & FL_PRINT) != 0;
}
*/
static bool unichar_isdigit(unichar c) {
return c < 128 && (attr[c] & FL_DIGIT) != 0;
}
static bool unichar_isxdigit(unichar c) {
return c < 128 && (attr[c] & FL_XDIGIT) != 0;
}
static bool unichar_isident(unichar c) {
return c < 128 && ((attr[c] & (FL_ALPHA | FL_DIGIT)) != 0 || c == '_');
}
static bool unichar_isalnum(unichar c) {
return c < 128 && ((attr[c] & (FL_ALPHA | FL_DIGIT)) != 0);
}
static bool unichar_isupper(unichar c) {
return c < 128 && (attr[c] & FL_UPPER) != 0;
}
static bool unichar_islower(unichar c) {
return c < 128 && (attr[c] & FL_LOWER) != 0;
}
static unichar unichar_tolower(unichar c) {
if (unichar_isupper(c)) {
return c + 0x20;
}
return c;
}
static unichar unichar_toupper(unichar c) {
if (unichar_islower(c)) {
return c - 0x20;
}
return c;
}
static mp_uint_t unichar_xdigit_value(unichar c) {
// c is assumed to be hex digit
mp_uint_t n = c - '0';
if (n > 9) {
n &= ~('a' - 'A');
n -= ('A' - ('9' + 1));
}
return n;
}
static bool utf8_check(const byte* p, size_t len) {
uint8_t need = 0;
const byte* end = p + len;
for (; p < end; p++) {
byte c = *p;
if (need) {
if (UTF8_IS_CONT(c)) {
need--;
} else {
// mismatch
return 0;
}
} else {
if (c >= 0xc0) {
if (c >= 0xf8) {
// mismatch
return 0;
}
need = (0xe5 >> ((c >> 3) & 0x6)) & 3;
} else if (c >= 0x80) {
// mismatch
return 0;
}
}
}
return need == 0; // no pending fragments allowed
}
#ifndef alignof
#define alignof(type) \
offsetof( \
struct { \
char c; \
type t; \
}, \
t)
#endif
#define BYTEARRAY_TYPECODE 1
static size_t mp_binary_get_size(char struct_type,
char val_type,
size_t* palign) {
size_t size = 0;
int align = 1;
switch (struct_type) {
case '<':
case '>':
switch (val_type) {
case 'b':
case 'B':
size = 1;
break;
case 'h':
case 'H':
size = 2;
break;
case 'i':
case 'I':
size = 4;
break;
case 'l':
case 'L':
size = 4;
break;
case 'q':
case 'Q':
size = 8;
break;
case 'P':
case 'O':
case 'S':
size = sizeof(void*);
break;
case 'f':
size = sizeof(float);
break;
case 'd':
size = sizeof(double);
break;
}
break;
case '@': {
// TODO:
// The simplest heuristic for alignment is to align by value
// size, but that doesn't work for "bigger than int" types,
// for example, long long may very well have long alignment
// So, we introduce separate alignment handling, but having
// formal support for that is different from actually supporting
// particular (or any) ABI.
switch (val_type) {
case BYTEARRAY_TYPECODE:
case 'b':
case 'B':
align = size = 1;
break;
case 'h':
case 'H':
align = alignof(short);
size = sizeof(short);
break;
case 'i':
case 'I':
align = alignof(int);
size = sizeof(int);
break;
case 'l':
case 'L':
align = alignof(long);
size = sizeof(long);
break;
case 'q':
case 'Q':
align = alignof(long long);
size = sizeof(long long);
break;
case 'P':
case 'O':
case 'S':
align = alignof(void*);
size = sizeof(void*);
break;
case 'f':
align = alignof(float);
size = sizeof(float);
break;
case 'd':
align = alignof(double);
size = sizeof(double);
break;
}
}
}
if (size == 0) {
mp_raise_ValueError(MP_ERROR_TEXT("bad typecode"));
}
if (palign != NULL) {
*palign = align;
}
return size;
}
// The long long type is guaranteed to hold at least 64 bits, and size is at
// most 8 (for q and Q), so we will always be able to parse the given data
// and fit it into a long long.
static inline long long mp_binary_get_int(size_t size,
bool is_signed,
bool big_endian,
const byte* src) {
int delta;
if (!big_endian) {
delta = -1;
src += size - 1;
} else {
delta = 1;
}
unsigned long long val = 0;
if (is_signed && *src & 0x80) {
val = -1;
}
for (uint i = 0; i < size; i++) {
val <<= 8;
val |= *src;
src += delta;
}
return val;
}
#define is_signed(typecode) (typecode > 'Z')
static mp_obj_t mp_binary_get_val(char struct_type,
char val_type,
byte* p_base,
byte** ptr) {
byte* p = *ptr;
size_t align;
size_t size = mp_binary_get_size(struct_type, val_type, &align);
if (struct_type == '@') {
// Align p relative to p_base
p = p_base + (uintptr_t)MP_ALIGN(p - p_base, align);
#if MP_ENDIANNESS_LITTLE
struct_type = '<';
#else
struct_type = '>';
#endif
}
*ptr = p + size;
long long val =
mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p);
if (val_type == 'O') {
return (mp_obj_t)(mp_uint_t)val;
} else if (val_type == 'S') {
const char* s_val = (const char*)(uintptr_t)(mp_uint_t)val;
return mp_obj_new_str(s_val, strlen(s_val));
} else if (val_type == 'f') {
union {
uint32_t i;
float f;
} fpu = {val};
return mp_obj_new_float_from_f(fpu.f);
} else if (val_type == 'd') {
union {
uint64_t i;
double f;
} fpu = {val};
return mp_obj_new_float_from_d(fpu.f);
} else if (is_signed(val_type)) {
return mp_obj_new_int_from_ll(val);
} else {
return mp_obj_new_int_from_ull(val);
}
}
#endif
#ifdef __cplusplus
}