mirror of
https://github.com/pocketpy/pocketpy
synced 2026-08-09 07:37:13 +08:00
Compare commits
14 Commits
b25cc37123
...
d3caeb7e46
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3caeb7e46 | ||
|
|
5e9b3c36dc | ||
|
|
e3255207c3 | ||
|
|
af9dbb39d7 | ||
|
|
01620fcb90 | ||
|
|
7435251873 | ||
|
|
eab5a75372 | ||
|
|
5546291c91 | ||
|
|
612910ab2a | ||
|
|
71f06c4ff1 | ||
|
|
fed2bcea78 | ||
|
|
799829a8aa | ||
|
|
a06e6ac6ba | ||
|
|
acc4f4104b |
10
.github/workflows/main.yml
vendored
10
.github/workflows/main.yml
vendored
@ -45,8 +45,6 @@ jobs:
|
||||
path: output
|
||||
- name: Unit Test
|
||||
run: python scripts/run_tests.py
|
||||
- name: Benchmark
|
||||
run: python scripts/run_tests.py benchmark
|
||||
build_linux:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
@ -56,11 +54,11 @@ jobs:
|
||||
- name: Setup Clang
|
||||
uses: egor-tensin/setup-clang@v1
|
||||
with:
|
||||
version: 17
|
||||
version: 19
|
||||
platform: x64
|
||||
- name: Run Sanitizers
|
||||
run: |
|
||||
sudo apt-get install -y libclang-rt-17-dev
|
||||
sudo apt-get install -y libclang-rt-19-dev
|
||||
bash build_g.sh
|
||||
bash run_tests.sh
|
||||
rm -rf ./main
|
||||
@ -90,8 +88,6 @@ jobs:
|
||||
with:
|
||||
name: linux
|
||||
path: output
|
||||
- name: Benchmark
|
||||
run: python scripts/run_tests.py benchmark
|
||||
build_darwin:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
@ -102,8 +98,6 @@ jobs:
|
||||
run: |
|
||||
python cmake_build.py Release -DPK_BUILD_MODULE_LZ4=ON -DPK_BUILD_MODULE_CUTE_PNG=ON -DPK_BUILD_MODULE_MSGPACK=ON
|
||||
python scripts/run_tests.py
|
||||
- name: Benchmark
|
||||
run: python scripts/run_tests.py benchmark
|
||||
- name: Test Amalgamated Build
|
||||
run: python amalgamate.py
|
||||
build_android_libs:
|
||||
|
||||
@ -8,7 +8,7 @@ from typing import List, Dict
|
||||
assert os.system("python prebuild.py") == 0
|
||||
|
||||
ROOT = 'include/pocketpy'
|
||||
PUBLIC_HEADERS = ['config.h', 'export.h', 'vmath.h', 'pocketpy.h']
|
||||
PUBLIC_HEADERS = ['config.h', 'export.h', 'vmath.h', 'sandbox.h', 'pocketpy.h']
|
||||
|
||||
COPYRIGHT = '''/*
|
||||
* Copyright (c) 2026 blueloveTH
|
||||
|
||||
@ -12,6 +12,8 @@
|
||||
#include "pocketpy/interpreter/line_profiler.h"
|
||||
#include <time.h>
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
// TODO:
|
||||
// 1. __eq__ and __ne__ fallbacks
|
||||
// 2. un-cleared exception detection
|
||||
@ -50,6 +52,8 @@ typedef struct VM {
|
||||
py_GlobalRef main; // __main__ module
|
||||
|
||||
py_Callbacks callbacks;
|
||||
py_Capabilities capabilities;
|
||||
atomic_bool is_interrupted;
|
||||
|
||||
py_TValue last_retval;
|
||||
py_TValue unhandled_exc;
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
typedef struct PyObject PyObject;
|
||||
typedef struct VM VM;
|
||||
extern _Thread_local VM* pk_current_vm;
|
||||
extern PK_THREAD_LOCAL VM* pk_current_vm;
|
||||
|
||||
typedef struct py_TValue {
|
||||
py_Type type;
|
||||
|
||||
@ -867,6 +867,7 @@ enum py_PredefinedType {
|
||||
tp_SyntaxError,
|
||||
tp_RecursionError,
|
||||
tp_OSError,
|
||||
tp_PermissionError,
|
||||
tp_NotImplementedError,
|
||||
tp_TypeError,
|
||||
tp_IndexError,
|
||||
|
||||
@ -13,10 +13,7 @@ typedef struct py_Capabilities {
|
||||
bool (*os_system)(const char* command);
|
||||
bool (*os_remove)(const char* path);
|
||||
// stdc
|
||||
bool stdc_write; // memset, write_bytes, ...
|
||||
bool stdc_read; // memcmp, read_bytes, ...
|
||||
bool stdc_malloc; // malloc
|
||||
bool stdc_free; // free
|
||||
bool stdc;
|
||||
} py_Capabilities;
|
||||
|
||||
/// Setup the capabilities for the current VM.
|
||||
|
||||
@ -17,7 +17,7 @@ rm -rf .coverage
|
||||
mkdir .coverage
|
||||
|
||||
UNITS=$(find ./ -name "*.gcno")
|
||||
llvm-cov-17 gcov ${UNITS} -r -s include/ -r -s src/ >> .coverage/coverage.txt
|
||||
llvm-cov-19 gcov ${UNITS} -r -s include/ -r -s src/ >> .coverage/coverage.txt
|
||||
|
||||
mv *.gcov .coverage
|
||||
rm *.gcda
|
||||
|
||||
@ -124,6 +124,20 @@ static bool type__annotations__(int argc, py_Ref argv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool type__subclasses__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
py_TypeInfo* base_ti = py_touserdata(argv);
|
||||
py_newlist(py_retval());
|
||||
|
||||
for(py_Type i = 1; i < pk_current_vm->types.length; i++) {
|
||||
py_TypeInfo* ti = pk_typeinfo(i);
|
||||
if(ti->base == base_ti->index) {
|
||||
py_list_append(py_retval(), &ti->self);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void pk_object__register() {
|
||||
py_bindmagic(tp_object, __new__, pk__object_new);
|
||||
|
||||
@ -142,4 +156,5 @@ void pk_object__register() {
|
||||
py_bindproperty(tp_type, "__name__", type__name__, NULL);
|
||||
py_bindproperty(tp_object, "__dict__", object__dict__, NULL);
|
||||
py_bindproperty(tp_type, "__annotations__", type__annotations__, NULL);
|
||||
py_bindmethod(tp_type, "__subclasses__", type__subclasses__);
|
||||
}
|
||||
@ -189,8 +189,8 @@ static Error* LexerError(Lexer* self, const char* fmt, ...) {
|
||||
err->src = self->src;
|
||||
PK_INCREF(self->src);
|
||||
err->lineno = self->current_line;
|
||||
const char* end = self->src->source->data + self->src->source->size;
|
||||
if(self->curr_char <= end && *self->curr_char == '\n') { err->lineno--; }
|
||||
const char* p_end = self->src->source->data + self->src->source->size;
|
||||
if(self->curr_char <= p_end && *self->curr_char == '\n') { err->lineno--; }
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(err->msg, sizeof(err->msg), fmt, args);
|
||||
@ -282,9 +282,16 @@ static Error* _eat_string(Lexer* self, c11_sbuf* buff, char quote, enum StringTy
|
||||
case 'b': c11_sbuf__write_char(buff, '\b'); break;
|
||||
case 'f': c11_sbuf__write_char(buff, '\f'); break;
|
||||
case 'v': c11_sbuf__write_char(buff, '\v'); break;
|
||||
// Special case for the often used \0 while we don't have full support for octal literals.
|
||||
// Special case for the often used \0 while we don't have full support for octal
|
||||
// literals.
|
||||
case '0': c11_sbuf__write_char(buff, '\0'); break;
|
||||
case 'x': {
|
||||
// check there are at least 2 chars can read
|
||||
const char* p_end = self->src->source->data + self->src->source->size;
|
||||
if(p_end - self->curr_char < 2) {
|
||||
return LexerError(self, "invalid hex escape");
|
||||
}
|
||||
|
||||
char hex[3] = {eatchar(self), eatchar(self), '\0'};
|
||||
int code;
|
||||
if(sscanf(hex, "%x", &code) != 1 || code > 0xFF) {
|
||||
|
||||
@ -124,6 +124,11 @@ __NEXT_STEP:
|
||||
}
|
||||
#endif
|
||||
|
||||
if(atomic_exchange(&self->is_interrupted, false)) {
|
||||
py_exception(tp_KeyboardInterrupt, "");
|
||||
goto __ERROR;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
pk_print_stack(self, frame, byte);
|
||||
#endif
|
||||
|
||||
@ -93,6 +93,9 @@ void VM__ctor(VM* self) {
|
||||
self->callbacks.flush = pk_default_flush;
|
||||
self->callbacks.getchr = pk_default_getchr;
|
||||
|
||||
memset(&self->capabilities, 0, sizeof(py_Capabilities));
|
||||
atomic_store(&self->is_interrupted, false);
|
||||
|
||||
self->last_retval = *py_NIL();
|
||||
self->unhandled_exc = *py_NIL();
|
||||
|
||||
@ -195,6 +198,7 @@ void VM__ctor(VM* self) {
|
||||
INJECT_BUILTIN_EXC(SyntaxError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(RecursionError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(OSError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(PermissionError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(NotImplementedError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(TypeError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(IndexError, tp_Exception);
|
||||
@ -579,8 +583,9 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
|
||||
}
|
||||
|
||||
if(p0->type == tp_type) {
|
||||
py_Type p0_type = py_totype(p0);
|
||||
// [cls, NULL, args..., kwargs...]
|
||||
py_Ref new_f = py_tpfindmagic(py_totype(p0), __new__);
|
||||
py_Ref new_f = py_tpfindmagic(p0_type, __new__);
|
||||
assert(new_f && py_isnil(p0 + 1));
|
||||
bool is_default_new = new_f->type == tp_nativefunc && new_f->_cfunc == pk__object_new;
|
||||
|
||||
@ -598,14 +603,16 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
|
||||
// NOTE: previously we use `get_unbound_method` but here we just use `tpfindmagic`
|
||||
// >> [cls, NULL, args..., kwargs...]
|
||||
// >> py_retval() is the new instance
|
||||
py_Ref init_f = py_tpfindmagic(py_totype(p0), __init__);
|
||||
py_Ref init_f = py_tpfindmagic(p0_type, __init__);
|
||||
if(init_f) {
|
||||
// do an inplace patch
|
||||
*p0 = *init_f; // __init__
|
||||
p0[1] = self->last_retval; // self
|
||||
// [__init__, self, args..., kwargs...]
|
||||
if(VM__vectorcall(self, argc, kwargc, false) == RES_ERROR) return RES_ERROR;
|
||||
*py_retval() = p0[1]; // restore the new instance
|
||||
if(py_isinstance(py_retval(), p0_type)) {
|
||||
// do an inplace patch
|
||||
*p0 = *init_f; // __init__
|
||||
p0[1] = self->last_retval; // self
|
||||
// [__init__, self, args..., kwargs...]
|
||||
if(VM__vectorcall(self, argc, kwargc, false) == RES_ERROR) return RES_ERROR;
|
||||
*py_retval() = p0[1]; // restore the new instance
|
||||
}
|
||||
} else {
|
||||
if(is_default_new) {
|
||||
if(argc != 0 || kwargc != 0) {
|
||||
@ -713,53 +720,62 @@ void ManagedHeap__mark(ManagedHeap* self) {
|
||||
}
|
||||
}
|
||||
|
||||
void* ud = PyObject__userdata(obj);
|
||||
switch(obj->type) {
|
||||
case tp_list: {
|
||||
List* self = ud;
|
||||
for(int i = 0; i < self->length; i++) {
|
||||
py_TValue* val = c11__at(py_TValue, self, i);
|
||||
pk__mark_value(val);
|
||||
if(obj->type > tp_object) {
|
||||
// NOTE: `defaultdict` -> `dict` -> `object`
|
||||
// NOTE: native types must extend from `object`.
|
||||
py_TypeInfo* ti = pk_typeinfo(obj->type);
|
||||
while(ti->base != tp_object) {
|
||||
ti = ti->base_ti;
|
||||
}
|
||||
|
||||
void* ud = PyObject__userdata(obj);
|
||||
switch(ti->index) {
|
||||
case tp_list: {
|
||||
List* self = ud;
|
||||
for(int i = 0; i < self->length; i++) {
|
||||
py_TValue* val = c11__at(py_TValue, self, i);
|
||||
pk__mark_value(val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_dict: {
|
||||
Dict* self = ud;
|
||||
for(int i = 0; i < self->entries.length; i++) {
|
||||
DictEntry* entry = c11__at(DictEntry, &self->entries, i);
|
||||
if(py_isnil(&entry->key)) continue;
|
||||
pk__mark_value(&entry->key);
|
||||
pk__mark_value(&entry->val);
|
||||
case tp_dict: {
|
||||
Dict* self = ud;
|
||||
for(int i = 0; i < self->entries.length; i++) {
|
||||
DictEntry* entry = c11__at(DictEntry, &self->entries, i);
|
||||
if(py_isnil(&entry->key)) continue;
|
||||
pk__mark_value(&entry->key);
|
||||
pk__mark_value(&entry->val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_generator: {
|
||||
Generator* self = ud;
|
||||
if(self->frame) Frame__gc_mark(self->frame, p_stack);
|
||||
break;
|
||||
}
|
||||
case tp_function: {
|
||||
function__gc_mark(ud, p_stack);
|
||||
break;
|
||||
}
|
||||
case tp_BaseException: {
|
||||
BaseException* self = ud;
|
||||
pk__mark_value(&self->args);
|
||||
pk__mark_value(&self->inner_exc);
|
||||
c11__foreach(BaseExceptionFrame, &self->stacktrace, frame) {
|
||||
pk__mark_value(&frame->locals);
|
||||
pk__mark_value(&frame->globals);
|
||||
case tp_generator: {
|
||||
Generator* self = ud;
|
||||
if(self->frame) Frame__gc_mark(self->frame, p_stack);
|
||||
break;
|
||||
}
|
||||
case tp_function: {
|
||||
function__gc_mark(ud, p_stack);
|
||||
break;
|
||||
}
|
||||
case tp_BaseException: {
|
||||
BaseException* self = ud;
|
||||
pk__mark_value(&self->args);
|
||||
pk__mark_value(&self->inner_exc);
|
||||
c11__foreach(BaseExceptionFrame, &self->stacktrace, frame) {
|
||||
pk__mark_value(&frame->locals);
|
||||
pk__mark_value(&frame->globals);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_code: {
|
||||
CodeObject* self = ud;
|
||||
CodeObject__gc_mark(self, p_stack);
|
||||
break;
|
||||
}
|
||||
case tp_chunked_array2d: {
|
||||
c11_chunked_array2d__mark(ud, p_stack);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case tp_code: {
|
||||
CodeObject* self = ud;
|
||||
CodeObject__gc_mark(self, p_stack);
|
||||
break;
|
||||
}
|
||||
case tp_chunked_array2d: {
|
||||
c11_chunked_array2d__mark(ud, p_stack);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +38,12 @@ static bool os_chdir(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
PY_CHECK_ARG_TYPE(0, tp_str);
|
||||
const char* path = py_tostr(py_arg(0));
|
||||
|
||||
py_Capabilities* caps = py_capabilities();
|
||||
if(!caps->os_chdir || !caps->os_chdir(path)) {
|
||||
return py_exception(tp_PermissionError, "disallowed capability");
|
||||
}
|
||||
|
||||
int code = platform_chdir(path);
|
||||
if(code != 0) {
|
||||
const char* msg = strerror(errno);
|
||||
@ -48,6 +54,13 @@ static bool os_chdir(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool os_getcwd(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(0);
|
||||
|
||||
py_Capabilities* caps = py_capabilities();
|
||||
if(!caps->os_getcwd || !caps->os_getcwd()) {
|
||||
return py_exception(tp_PermissionError, "disallowed capability");
|
||||
}
|
||||
|
||||
char buf[1024];
|
||||
if(!platform_getcwd(buf, sizeof(buf))) return OSError("getcwd() failed");
|
||||
py_newstr(py_retval(), buf);
|
||||
@ -59,6 +72,12 @@ static bool os_system(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARG_TYPE(0, tp_str);
|
||||
#if PK_IS_DESKTOP_PLATFORM
|
||||
const char* cmd = py_tostr(py_arg(0));
|
||||
|
||||
py_Capabilities* caps = py_capabilities();
|
||||
if(!caps->os_system || !caps->os_system(cmd)) {
|
||||
return py_exception(tp_PermissionError, "disallowed capability");
|
||||
}
|
||||
|
||||
int code = system(cmd);
|
||||
py_newint(py_retval(), code);
|
||||
return true;
|
||||
@ -71,6 +90,12 @@ static bool os_remove(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
PY_CHECK_ARG_TYPE(0, tp_str);
|
||||
const char* path = py_tostr(py_arg(0));
|
||||
|
||||
py_Capabilities* caps = py_capabilities();
|
||||
if(!caps->os_remove || !caps->os_remove(path)) {
|
||||
return py_exception(tp_PermissionError, "disallowed capability");
|
||||
}
|
||||
|
||||
int code = remove(path);
|
||||
if(code != 0) {
|
||||
const char* msg = strerror(errno);
|
||||
@ -111,6 +136,12 @@ static bool io_FileIO__new__(int argc, py_Ref argv) {
|
||||
io_FileIO* ud = py_newobject(py_retval(), cls, 0, sizeof(io_FileIO));
|
||||
ud->path = py_tostr(py_arg(1));
|
||||
ud->mode = py_tostr(py_arg(2));
|
||||
|
||||
py_Capabilities* caps = py_capabilities();
|
||||
if(!caps->file_open || !caps->file_open(ud->path, ud->mode)) {
|
||||
return py_exception(tp_PermissionError, "disallowed capability");
|
||||
}
|
||||
|
||||
ud->file = fopen(ud->path, ud->mode);
|
||||
if(ud->file == NULL) {
|
||||
const char* msg = strerror(errno);
|
||||
|
||||
@ -2,8 +2,17 @@
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static bool check_stdc_cap() {
|
||||
py_Capabilities* caps = py_capabilities();
|
||||
if(caps->stdc) return true;
|
||||
return py_exception(tp_PermissionError, "disallowed capability");
|
||||
}
|
||||
|
||||
|
||||
#define DEF_BUILTIN_MEMORY_T(Char_, char_, tp_int_, py_newint_, py_toint_, py_i64_) \
|
||||
static bool stdc_##Char_##__new__(int argc, py_Ref argv) { \
|
||||
if(!check_stdc_cap()) return false; \
|
||||
char_* ud = py_newobject(py_retval(), tp_stdc_##Char_, 0, sizeof(char_)); \
|
||||
if(argc == 2) { \
|
||||
PY_CHECK_ARG_TYPE(1, tp_int_); \
|
||||
@ -14,12 +23,14 @@
|
||||
return true; \
|
||||
} \
|
||||
static bool stdc_##Char_##__get_value(int argc, py_Ref argv) { \
|
||||
if(!check_stdc_cap()) return false; \
|
||||
PY_CHECK_ARGC(1); \
|
||||
char_* ud = py_touserdata(argv); \
|
||||
py_newint_(py_retval(), (py_i64_)(*ud)); \
|
||||
return true; \
|
||||
} \
|
||||
static bool stdc_##Char_##__set_value(int argc, py_Ref argv) { \
|
||||
if(!check_stdc_cap()) return false; \
|
||||
PY_CHECK_ARGC(2); \
|
||||
char_* ud = py_touserdata(argv); \
|
||||
PY_CHECK_ARG_TYPE(1, tp_int_); \
|
||||
@ -28,6 +39,7 @@
|
||||
return true; \
|
||||
} \
|
||||
static bool stdc_##Char_##__read_STATIC(int argc, py_Ref argv) { \
|
||||
if(!check_stdc_cap()) return false; \
|
||||
PY_CHECK_ARGC(2); \
|
||||
PY_CHECK_ARG_TYPE(0, tp_int); \
|
||||
PY_CHECK_ARG_TYPE(1, tp_int); \
|
||||
@ -37,6 +49,7 @@
|
||||
return true; \
|
||||
} \
|
||||
static bool stdc_##Char_##__write_STATIC(int argc, py_Ref argv) { \
|
||||
if(!check_stdc_cap()) return false; \
|
||||
PY_CHECK_ARGC(3); \
|
||||
PY_CHECK_ARG_TYPE(0, tp_int); \
|
||||
PY_CHECK_ARG_TYPE(1, tp_int); \
|
||||
@ -48,6 +61,7 @@
|
||||
return true; \
|
||||
} \
|
||||
static bool stdc_##Char_##__array_STATIC(int argc, py_Ref argv) { \
|
||||
if(!check_stdc_cap()) return false; \
|
||||
PY_CHECK_ARGC(1); \
|
||||
PY_CHECK_ARG_TYPE(0, tp_int); \
|
||||
int length = py_toint(argv); \
|
||||
@ -56,6 +70,7 @@
|
||||
return true; \
|
||||
} \
|
||||
static bool stdc_##Char_##__getitem__(int argc, py_Ref argv) { \
|
||||
if(!check_stdc_cap()) return false; \
|
||||
PY_CHECK_ARGC(2); \
|
||||
char_* ud = py_touserdata(argv); \
|
||||
PY_CHECK_ARG_TYPE(1, tp_int); \
|
||||
@ -64,6 +79,7 @@
|
||||
return true; \
|
||||
} \
|
||||
static bool stdc_##Char_##__setitem__(int argc, py_Ref argv) { \
|
||||
if(!check_stdc_cap()) return false; \
|
||||
PY_CHECK_ARGC(3); \
|
||||
char_* ud = py_touserdata(argv); \
|
||||
PY_CHECK_ARG_TYPE(1, tp_int); \
|
||||
@ -105,6 +121,7 @@ DEF_BUILTIN_MEMORY_T(Bool, bool, tp_bool, py_newbool, py_tobool, bool)
|
||||
#undef DEF_BUILTIN_MEMORY_T
|
||||
|
||||
static bool stdc_malloc(int argc, py_Ref argv) {
|
||||
if(!check_stdc_cap()) return false;
|
||||
PY_CHECK_ARGC(1);
|
||||
PY_CHECK_ARG_TYPE(0, tp_int);
|
||||
py_i64 size = py_toint(&argv[0]);
|
||||
@ -114,6 +131,7 @@ static bool stdc_malloc(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool stdc_free(int argc, py_Ref argv) {
|
||||
if(!check_stdc_cap()) return false;
|
||||
PY_CHECK_ARGC(1);
|
||||
PY_CHECK_ARG_TYPE(0, tp_int);
|
||||
void* p = (void*)(intptr_t)py_toint(&argv[0]);
|
||||
@ -123,6 +141,7 @@ static bool stdc_free(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool stdc_memcpy(int argc, py_Ref argv) {
|
||||
if(!check_stdc_cap()) return false;
|
||||
PY_CHECK_ARGC(3);
|
||||
PY_CHECK_ARG_TYPE(0, tp_int); // dst
|
||||
void* dst = (void*)(intptr_t)py_toint(&argv[0]);
|
||||
@ -143,6 +162,7 @@ static bool stdc_memcpy(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool stdc_memset(int argc, py_Ref argv) {
|
||||
if(!check_stdc_cap()) return false;
|
||||
PY_CHECK_ARGC(3);
|
||||
PY_CHECK_ARG_TYPE(0, tp_int);
|
||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||
@ -156,6 +176,7 @@ static bool stdc_memset(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool stdc_memcmp(int argc, py_Ref argv) {
|
||||
if(!check_stdc_cap()) return false;
|
||||
PY_CHECK_ARGC(3);
|
||||
PY_CHECK_ARG_TYPE(0, tp_int);
|
||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||
@ -169,6 +190,7 @@ static bool stdc_memcmp(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool stdc_addressof(int argc, py_Ref argv) {
|
||||
if(!check_stdc_cap()) return false;
|
||||
PY_CHECK_ARGC(1);
|
||||
if(!py_checkinstance(argv, tp_stdc_Memory)) return false;
|
||||
void* ud = py_touserdata(argv);
|
||||
@ -177,6 +199,7 @@ static bool stdc_addressof(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool stdc_sizeof(int argc, py_Ref argv) {
|
||||
if(!check_stdc_cap()) return false;
|
||||
PY_CHECK_ARGC(1);
|
||||
PY_CHECK_ARG_TYPE(0, tp_type);
|
||||
py_Type type = py_totype(&argv[0]);
|
||||
@ -188,6 +211,7 @@ static bool stdc_sizeof(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool stdc_read_cstr(int argc, py_Ref argv) {
|
||||
if(!check_stdc_cap()) return false;
|
||||
PY_CHECK_ARGC(1);
|
||||
PY_CHECK_ARG_TYPE(0, tp_int);
|
||||
char* p = (char*)(intptr_t)py_toint(&argv[0]);
|
||||
@ -196,6 +220,7 @@ static bool stdc_read_cstr(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool stdc_write_cstr(int argc, py_Ref argv) {
|
||||
if(!check_stdc_cap()) return false;
|
||||
PY_CHECK_ARGC(2);
|
||||
PY_CHECK_ARG_TYPE(0, tp_int);
|
||||
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||
@ -208,6 +233,7 @@ static bool stdc_write_cstr(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool stdc_read_bytes(int argc, py_Ref argv) {
|
||||
if(!check_stdc_cap()) return false;
|
||||
PY_CHECK_ARGC(2);
|
||||
PY_CHECK_ARG_TYPE(0, tp_int);
|
||||
PY_CHECK_ARG_TYPE(1, tp_int);
|
||||
@ -219,6 +245,7 @@ static bool stdc_read_bytes(int argc, py_Ref argv) {
|
||||
}
|
||||
|
||||
static bool stdc_write_bytes(int argc, py_Ref argv) {
|
||||
if(!check_stdc_cap()) return false;
|
||||
PY_CHECK_ARGC(2);
|
||||
PY_CHECK_ARG_TYPE(0, tp_int);
|
||||
PY_CHECK_ARG_TYPE(1, tp_bytes);
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#include "pocketpy/common/name.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
|
||||
_Thread_local VM* pk_current_vm;
|
||||
PK_THREAD_LOCAL VM* pk_current_vm;
|
||||
|
||||
static bool pk_initialized;
|
||||
static bool pk_finalized;
|
||||
@ -110,6 +110,10 @@ void py_setvmctx(void* ctx) { pk_current_vm->ctx = ctx; }
|
||||
|
||||
py_Callbacks* py_callbacks() { return &pk_current_vm->callbacks; }
|
||||
|
||||
py_Capabilities* py_capabilities() { return &pk_current_vm->capabilities; }
|
||||
|
||||
void py_interrupt() { atomic_store(&pk_current_vm->is_interrupted, true); }
|
||||
|
||||
py_AppCallbacks* py_appcallbacks() {
|
||||
static py_AppCallbacks _callbacks = {0};
|
||||
return &_callbacks;
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
print('sandbox mode, module is disabled')
|
||||
exit()
|
||||
|
||||
try:
|
||||
import os
|
||||
except ImportError:
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
print('sandbox mode, module is disabled')
|
||||
exit()
|
||||
|
||||
try:
|
||||
import os
|
||||
except ImportError:
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
print('sandbox mode, module is disabled')
|
||||
exit()
|
||||
|
||||
try:
|
||||
import os
|
||||
except ImportError:
|
||||
|
||||
@ -167,4 +167,14 @@ class DerivedClass(BaseClass):
|
||||
return super().f()
|
||||
|
||||
|
||||
assert DerivedClass.f() == 'BaseClass'
|
||||
assert DerivedClass.f() == 'BaseClass'
|
||||
|
||||
# bad __init__
|
||||
class A:
|
||||
def __new__(cls, *args, **kwargs):
|
||||
return 1
|
||||
|
||||
def __init__(self):
|
||||
assert False
|
||||
|
||||
A()
|
||||
|
||||
@ -50,3 +50,21 @@ assert hasattr(a, 'zzz')
|
||||
|
||||
assert not hasattr(a, '')
|
||||
|
||||
class Base:
|
||||
pass
|
||||
|
||||
class Child1(Base):
|
||||
pass
|
||||
|
||||
class Child2(Base):
|
||||
pass
|
||||
|
||||
class GrandChild(Child1):
|
||||
pass
|
||||
|
||||
subs = Base.__subclasses__()
|
||||
assert type(subs) is list
|
||||
assert Child1 in subs
|
||||
assert Child2 in subs
|
||||
assert GrandChild not in subs
|
||||
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
print('sandbox mode, module is disabled')
|
||||
exit()
|
||||
|
||||
try:
|
||||
import os
|
||||
import io
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
print('sandbox mode, module is disabled')
|
||||
exit()
|
||||
|
||||
from stdc import *
|
||||
|
||||
assert sizeof(Int8) == sizeof(UInt8) == 1
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
print('sandbox mode, module is disabled')
|
||||
exit()
|
||||
|
||||
try:
|
||||
import os
|
||||
except ImportError:
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
print('sandbox mode, module is disabled')
|
||||
exit()
|
||||
|
||||
# https://github.com/python/cpython/blob/v3.4.10/Lib/test/test_math.py
|
||||
|
||||
# Python test set -- math module
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user