mirror of
https://github.com/pocketpy/pocketpy
synced 2026-02-04 06:30:17 +00:00
Compare commits
8 Commits
f95b765207
...
1e17b49403
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e17b49403 | ||
|
|
550f8c9d0e | ||
|
|
0c004a9a16 | ||
|
|
2684038ccf | ||
|
|
a094dcb34d | ||
|
|
3731efba5c | ||
|
|
6cad72453b | ||
|
|
5c7fb79a14 |
@ -1,4 +1,5 @@
|
|||||||
#include "pocketpy.h"
|
#include "pocketpy.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#define CUTE_PNG_IMPLEMENTATION
|
#define CUTE_PNG_IMPLEMENTATION
|
||||||
#include "cute_png.h"
|
#include "cute_png.h"
|
||||||
@ -9,7 +10,7 @@ static bool cute_png_loads(int argc, py_Ref argv) {
|
|||||||
int size;
|
int size;
|
||||||
unsigned char* data = py_tobytes(argv, &size);
|
unsigned char* data = py_tobytes(argv, &size);
|
||||||
cp_image_t image = cp_load_png_mem(data, size);
|
cp_image_t image = cp_load_png_mem(data, size);
|
||||||
if(image.pix == NULL) return ValueError("cute_png: %s", cp_error_reason);
|
if(image.pix == NULL) return ValueError("cp_load_png_mem() failed");
|
||||||
py_newarray2d(py_retval(), image.w, image.h);
|
py_newarray2d(py_retval(), image.w, image.h);
|
||||||
for(int y = 0; y < image.h; y++) {
|
for(int y = 0; y < image.h; y++) {
|
||||||
for(int x = 0; x < image.w; x++) {
|
for(int x = 0; x < image.w; x++) {
|
||||||
@ -73,7 +74,19 @@ static bool cute_png_Image__from_bytes_STATIC(int argc, py_Ref argv) {
|
|||||||
int size;
|
int size;
|
||||||
unsigned char* data = py_tobytes(argv, &size);
|
unsigned char* data = py_tobytes(argv, &size);
|
||||||
cp_image_t image = cp_load_png_mem(data, size);
|
cp_image_t image = cp_load_png_mem(data, size);
|
||||||
if(image.pix == NULL) return ValueError("cute_png: %s", cp_error_reason);
|
if(image.pix == NULL) return ValueError("cp_load_png_mem() failed");
|
||||||
|
cp_image_t* ud =
|
||||||
|
py_newobject(py_retval(), py_gettype("cute_png", py_name("Image")), 0, sizeof(cp_image_t));
|
||||||
|
*ud = image;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cute_png_Image__from_file_STATIC(int argc, py_Ref argv) {
|
||||||
|
PY_CHECK_ARGC(1);
|
||||||
|
PY_CHECK_ARG_TYPE(0, tp_str);
|
||||||
|
const char* path = py_tostr(argv);
|
||||||
|
cp_image_t image = cp_load_png(path);
|
||||||
|
if(image.pix == NULL) return ValueError("cp_load_png() failed");
|
||||||
cp_image_t* ud =
|
cp_image_t* ud =
|
||||||
py_newobject(py_retval(), py_gettype("cute_png", py_name("Image")), 0, sizeof(cp_image_t));
|
py_newobject(py_retval(), py_gettype("cute_png", py_name("Image")), 0, sizeof(cp_image_t));
|
||||||
*ud = image;
|
*ud = image;
|
||||||
@ -147,10 +160,41 @@ static bool cute_png_Image__clear(int argc, py_Ref argv) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cute_png_Image__to_rgb565_bytes(int argc, py_Ref argv) {
|
static bool cute_png_Image__to_png_bytes(int argc, py_Ref argv) {
|
||||||
PY_CHECK_ARGC(1);
|
PY_CHECK_ARGC(1);
|
||||||
cp_image_t* image = py_touserdata(argv);
|
cp_image_t* image = py_touserdata(argv);
|
||||||
unsigned char* data = py_newbytes(py_retval(), image->w * image->h * 2);
|
cp_saved_png_t saved_image = cp_save_png_to_memory(image);
|
||||||
|
assert(saved_image.data != NULL);
|
||||||
|
unsigned char* data = py_newbytes(py_retval(), saved_image.size);
|
||||||
|
memcpy(data, saved_image.data, saved_image.size);
|
||||||
|
CUTE_PNG_FREE(saved_image.data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cute_png_Image__to_png_file(int argc, py_Ref argv) {
|
||||||
|
PY_CHECK_ARGC(2);
|
||||||
|
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||||
|
cp_image_t* image = py_touserdata(argv);
|
||||||
|
const char* path = py_tostr(py_arg(1));
|
||||||
|
FILE* fp = fopen(path, "wb");
|
||||||
|
if(fp == NULL) return OSError("cannot open file '%s' for writing", path);
|
||||||
|
cp_saved_png_t saved_image = cp_save_png_to_memory(image);
|
||||||
|
assert(saved_image.data != NULL);
|
||||||
|
size_t size = fwrite(saved_image.data, saved_image.size, 1, fp);
|
||||||
|
CUTE_PNG_FREE(saved_image.data);
|
||||||
|
fclose(fp);
|
||||||
|
py_newint(py_retval(), size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cute_png_Image__to_rgb565_file(int argc, py_Ref argv) {
|
||||||
|
PY_CHECK_ARGC(2);
|
||||||
|
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||||
|
cp_image_t* image = py_touserdata(argv);
|
||||||
|
const char* path = py_tostr(py_arg(1));
|
||||||
|
FILE* fp = fopen(path, "wb");
|
||||||
|
if(fp == NULL) return OSError("cannot open file '%s' for writing", path);
|
||||||
|
size_t size = 0;
|
||||||
for(int y = 0; y < image->h; y++) {
|
for(int y = 0; y < image->h; y++) {
|
||||||
for(int x = 0; x < image->w; x++) {
|
for(int x = 0; x < image->w; x++) {
|
||||||
size_t idx = y * image->w + x;
|
size_t idx = y * image->w + x;
|
||||||
@ -160,21 +204,15 @@ static bool cute_png_Image__to_rgb565_bytes(int argc, py_Ref argv) {
|
|||||||
uint16_t b = (pixel.b >> 3) & 0x1F;
|
uint16_t b = (pixel.b >> 3) & 0x1F;
|
||||||
uint16_t rgb565 = (r << 11) | (g << 5) | b;
|
uint16_t rgb565 = (r << 11) | (g << 5) | b;
|
||||||
// use little-endian
|
// use little-endian
|
||||||
data[idx * 2 + 0] = rgb565 & 0xFF;
|
size_t delta = fwrite(&rgb565, 1, 2, fp);
|
||||||
data[idx * 2 + 1] = (rgb565 >> 8) & 0xFF;
|
size += delta;
|
||||||
|
if(delta != 2) {
|
||||||
|
py_newint(py_retval(), size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
py_newint(py_retval(), size);
|
||||||
}
|
|
||||||
|
|
||||||
static bool cute_png_Image__to_png_bytes(int argc, py_Ref argv) {
|
|
||||||
PY_CHECK_ARGC(1);
|
|
||||||
cp_image_t* image = py_touserdata(argv);
|
|
||||||
cp_saved_png_t saved_image = cp_save_png_to_memory(image);
|
|
||||||
assert(saved_image.data != NULL);
|
|
||||||
unsigned char* data = py_newbytes(py_retval(), saved_image.size);
|
|
||||||
memcpy(data, saved_image.data, saved_image.size);
|
|
||||||
CUTE_PNG_FREE(saved_image.data);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,6 +226,7 @@ void pk__add_module_cute_png() {
|
|||||||
|
|
||||||
py_bindmethod(tp_image, "__new__", cute_png_Image__new__);
|
py_bindmethod(tp_image, "__new__", cute_png_Image__new__);
|
||||||
py_bindstaticmethod(tp_image, "from_bytes", cute_png_Image__from_bytes_STATIC);
|
py_bindstaticmethod(tp_image, "from_bytes", cute_png_Image__from_bytes_STATIC);
|
||||||
|
py_bindstaticmethod(tp_image, "from_file", cute_png_Image__from_file_STATIC);
|
||||||
|
|
||||||
py_bindproperty(tp_image, "width", cute_png_Image__width, NULL);
|
py_bindproperty(tp_image, "width", cute_png_Image__width, NULL);
|
||||||
py_bindproperty(tp_image, "height", cute_png_Image__height, NULL);
|
py_bindproperty(tp_image, "height", cute_png_Image__height, NULL);
|
||||||
@ -196,6 +235,7 @@ void pk__add_module_cute_png() {
|
|||||||
py_bindmethod(tp_image, "getpixel", cute_png_Image__getpixel);
|
py_bindmethod(tp_image, "getpixel", cute_png_Image__getpixel);
|
||||||
py_bindmethod(tp_image, "clear", cute_png_Image__clear);
|
py_bindmethod(tp_image, "clear", cute_png_Image__clear);
|
||||||
|
|
||||||
py_bindmethod(tp_image, "to_rgb565_bytes", cute_png_Image__to_rgb565_bytes);
|
|
||||||
py_bindmethod(tp_image, "to_png_bytes", cute_png_Image__to_png_bytes);
|
py_bindmethod(tp_image, "to_png_bytes", cute_png_Image__to_png_bytes);
|
||||||
|
py_bindmethod(tp_image, "to_png_file", cute_png_Image__to_png_file);
|
||||||
|
py_bindmethod(tp_image, "to_rgb565_file", cute_png_Image__to_rgb565_file);
|
||||||
}
|
}
|
||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "pocketpy/common/vector.h"
|
#include "pocketpy/common/vector.h"
|
||||||
#include "pocketpy/objects/base.h"
|
#include "pocketpy/objects/base.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint64_t hash;
|
uint64_t hash;
|
||||||
@ -22,3 +23,9 @@ typedef c11_vector List;
|
|||||||
|
|
||||||
void c11_chunked_array2d__mark(void* ud, c11_vector* p_stack);
|
void c11_chunked_array2d__mark(void* ud, c11_vector* p_stack);
|
||||||
void function__gc_mark(void* ud, c11_vector* p_stack);
|
void function__gc_mark(void* ud, c11_vector* p_stack);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FILE* file; // cute_png will cast the whole userdata to FILE**
|
||||||
|
const char* path;
|
||||||
|
const char* mode;
|
||||||
|
} io_FileIO;
|
||||||
|
|||||||
@ -11,13 +11,17 @@ class Image:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_bytes(data: bytes) -> "Image": ...
|
def from_bytes(data: bytes) -> "Image": ...
|
||||||
|
@staticmethod
|
||||||
|
def from_file(path: str) -> "Image": ...
|
||||||
|
|
||||||
def setpixel(self, x: int, y: int, color: color32) -> None: ...
|
def setpixel(self, x: int, y: int, color: color32) -> None: ...
|
||||||
def getpixel(self, x: int, y: int) -> color32: ...
|
def getpixel(self, x: int, y: int) -> color32: ...
|
||||||
def clear(self, color: color32) -> None: ...
|
def clear(self, color: color32) -> None: ...
|
||||||
|
|
||||||
def to_rgb565_bytes(self) -> bytes: ...
|
|
||||||
def to_png_bytes(self) -> bytes: ...
|
def to_png_bytes(self) -> bytes: ...
|
||||||
|
def to_png_file(self, path: str) -> int: ...
|
||||||
|
def to_rgb565_file(self, path: str) -> int: ...
|
||||||
|
|
||||||
|
|
||||||
def loads(data: bytes) -> array2d[color32]: ...
|
def loads(data: bytes) -> array2d[color32]: ...
|
||||||
def dumps(image: array2d[color32]) -> bytes: ...
|
def dumps(image: array2d[color32]) -> bytes: ...
|
||||||
|
|||||||
17
include/typings/io.pyi
Normal file
17
include/typings/io.pyi
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
class FileIO:
|
||||||
|
def __new__(cls, file: str, mode: str) -> "FileIO": ...
|
||||||
|
|
||||||
|
def __enter__(self) -> "FileIO": ...
|
||||||
|
def __exit__(self) -> None: ...
|
||||||
|
|
||||||
|
def read(self, size: int | None = None) -> bytes: ...
|
||||||
|
def write(self, data: bytes) -> int: ...
|
||||||
|
def close(self) -> None: ...
|
||||||
|
def tell(self) -> int: ...
|
||||||
|
def seek(self, offset: int, whence: int) -> None: ...
|
||||||
|
def flush(self) -> None: ...
|
||||||
|
|
||||||
|
SEEK_SET: int
|
||||||
|
SEEK_CUR: int
|
||||||
|
SEEK_END: int
|
||||||
@ -580,6 +580,7 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
|
|||||||
// [cls, NULL, args..., kwargs...]
|
// [cls, NULL, args..., kwargs...]
|
||||||
py_Ref new_f = py_tpfindmagic(py_totype(p0), __new__);
|
py_Ref new_f = py_tpfindmagic(py_totype(p0), __new__);
|
||||||
assert(new_f && py_isnil(p0 + 1));
|
assert(new_f && py_isnil(p0 + 1));
|
||||||
|
bool is_default_new = new_f->type == tp_nativefunc && new_f->_cfunc == pk__object_new;
|
||||||
|
|
||||||
// prepare a copy of args and kwargs
|
// prepare a copy of args and kwargs
|
||||||
int span = self->stack.sp - argv;
|
int span = self->stack.sp - argv;
|
||||||
@ -603,6 +604,13 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
|
|||||||
// [__init__, self, args..., kwargs...]
|
// [__init__, self, args..., kwargs...]
|
||||||
if(VM__vectorcall(self, argc, kwargc, false) == RES_ERROR) return RES_ERROR;
|
if(VM__vectorcall(self, argc, kwargc, false) == RES_ERROR) return RES_ERROR;
|
||||||
*py_retval() = p0[1]; // restore the new instance
|
*py_retval() = p0[1]; // restore the new instance
|
||||||
|
} else {
|
||||||
|
if(is_default_new) {
|
||||||
|
if(argc != 0 || kwargc != 0) {
|
||||||
|
TypeError("%t() takes no arguments", py_totype(p0));
|
||||||
|
return RES_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// reset the stack
|
// reset the stack
|
||||||
self->stack.sp = p0;
|
self->stack.sp = p0;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "pocketpy/objects/base.h"
|
#include "pocketpy/objects/base.h"
|
||||||
#include "pocketpy/pocketpy.h"
|
#include "pocketpy/pocketpy.h"
|
||||||
|
#include "pocketpy/interpreter/types.h"
|
||||||
#include "pocketpy/interpreter/vm.h"
|
#include "pocketpy/interpreter/vm.h"
|
||||||
|
|
||||||
#if PK_ENABLE_OS
|
#if PK_ENABLE_OS
|
||||||
@ -101,12 +102,6 @@ void pk__add_module_os() {
|
|||||||
py_newdict(py_emplacedict(mod, py_name("environ")));
|
py_newdict(py_emplacedict(mod, py_name("environ")));
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char* path;
|
|
||||||
const char* mode;
|
|
||||||
FILE* file;
|
|
||||||
} io_FileIO;
|
|
||||||
|
|
||||||
static bool io_FileIO__new__(int argc, py_Ref argv) {
|
static bool io_FileIO__new__(int argc, py_Ref argv) {
|
||||||
// __new__(cls, file, mode)
|
// __new__(cls, file, mode)
|
||||||
PY_CHECK_ARGC(3);
|
PY_CHECK_ARGC(3);
|
||||||
@ -213,6 +208,14 @@ static bool io_FileIO_write(int argc, py_Ref argv) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool io_FileIO_flush(int argc, py_Ref argv) {
|
||||||
|
PY_CHECK_ARGC(1);
|
||||||
|
io_FileIO* ud = py_touserdata(py_arg(0));
|
||||||
|
fflush(ud->file);
|
||||||
|
py_newnone(py_retval());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void pk__add_module_io() {
|
void pk__add_module_io() {
|
||||||
py_Ref mod = py_newmodule("io");
|
py_Ref mod = py_newmodule("io");
|
||||||
|
|
||||||
@ -226,6 +229,7 @@ void pk__add_module_io() {
|
|||||||
py_bindmethod(FileIO, "close", io_FileIO_close);
|
py_bindmethod(FileIO, "close", io_FileIO_close);
|
||||||
py_bindmethod(FileIO, "tell", io_FileIO_tell);
|
py_bindmethod(FileIO, "tell", io_FileIO_tell);
|
||||||
py_bindmethod(FileIO, "seek", io_FileIO_seek);
|
py_bindmethod(FileIO, "seek", io_FileIO_seek);
|
||||||
|
py_bindmethod(FileIO, "flush", io_FileIO_flush);
|
||||||
|
|
||||||
py_newint(py_emplacedict(mod, py_name("SEEK_SET")), SEEK_SET);
|
py_newint(py_emplacedict(mod, py_name("SEEK_SET")), SEEK_SET);
|
||||||
py_newint(py_emplacedict(mod, py_name("SEEK_CUR")), SEEK_CUR);
|
py_newint(py_emplacedict(mod, py_name("SEEK_CUR")), SEEK_CUR);
|
||||||
|
|||||||
@ -167,8 +167,26 @@ static bool list__setitem__(int argc, py_Ref argv) {
|
|||||||
|
|
||||||
static bool list__delitem__(int argc, py_Ref argv) {
|
static bool list__delitem__(int argc, py_Ref argv) {
|
||||||
PY_CHECK_ARGC(2);
|
PY_CHECK_ARGC(2);
|
||||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
|
||||||
List* self = py_touserdata(py_arg(0));
|
List* self = py_touserdata(py_arg(0));
|
||||||
|
|
||||||
|
if(py_istype(py_arg(1), tp_slice)) {
|
||||||
|
int start, stop, step;
|
||||||
|
bool ok = pk__parse_int_slice(py_arg(1), self->length, &start, &stop, &step);
|
||||||
|
if(!ok) return false;
|
||||||
|
if(step != 1) return ValueError("slice step must be 1 for deletion");
|
||||||
|
int n = stop - start;
|
||||||
|
if(n > 0) {
|
||||||
|
py_TValue* p = self->data;
|
||||||
|
for(int i = stop; i < self->length; i++) {
|
||||||
|
p[start + i - stop] = p[i];
|
||||||
|
}
|
||||||
|
self->length -= n;
|
||||||
|
}
|
||||||
|
py_newnone(py_retval());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||||
int index = py_toint(py_arg(1));
|
int index = py_toint(py_arg(1));
|
||||||
if(!pk__normalize_index(&index, self->length)) return false;
|
if(!pk__normalize_index(&index, self->length)) return false;
|
||||||
c11_vector__erase(py_TValue, self, index);
|
c11_vector__erase(py_TValue, self, index);
|
||||||
|
|||||||
@ -160,6 +160,16 @@ b = [(1, 2), (3, 3), (5, 1)]
|
|||||||
b.sort(key=lambda x:x[1])
|
b.sort(key=lambda x:x[1])
|
||||||
assert b == [(5, 1), (1, 2), (3,3)]
|
assert b == [(5, 1), (1, 2), (3,3)]
|
||||||
|
|
||||||
|
# test del slice
|
||||||
|
a = [1, 2, 3, 4]
|
||||||
|
b = a.copy(); del b[:2]; assert b == [3, 4]
|
||||||
|
b = a.copy(); del b[1:3]; assert b == [1, 4]
|
||||||
|
b = a.copy(); del b[2:]; assert b == [1, 2]
|
||||||
|
b = a.copy(); del b[:-1]; assert b == [4]
|
||||||
|
b = a.copy(); del b[-1:]; assert b == [1, 2, 3]
|
||||||
|
b = a.copy(); del b[:]; assert b == []
|
||||||
|
assert a == [1, 2, 3, 4]
|
||||||
|
|
||||||
# test cyclic reference
|
# test cyclic reference
|
||||||
# a = []
|
# a = []
|
||||||
# a.append(0)
|
# a.append(0)
|
||||||
|
|||||||
@ -135,4 +135,24 @@ assert MyClass.b == 1
|
|||||||
assert MyClass.c == 2
|
assert MyClass.c == 2
|
||||||
assert MyClass.d == 3
|
assert MyClass.d == 3
|
||||||
|
|
||||||
assert MyClass(1, 2).m == 1
|
assert MyClass(1, 2).m == 1
|
||||||
|
|
||||||
|
class E: pass
|
||||||
|
try:
|
||||||
|
E(1,2,3)
|
||||||
|
exit(1)
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class E1:
|
||||||
|
def __new__(cls, a, b):
|
||||||
|
o = object.__new__(cls)
|
||||||
|
o.a = a
|
||||||
|
o.b = b
|
||||||
|
return o
|
||||||
|
|
||||||
|
def sum(self):
|
||||||
|
return self.a + self.b
|
||||||
|
|
||||||
|
e1 = E1(3,4)
|
||||||
|
assert e1.sum() == 7
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user