mirror of
https://github.com/pocketpy/pocketpy
synced 2025-12-10 12:10:16 +00:00
Compare commits
4 Commits
adf5fa5ac2
...
4285324209
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4285324209 | ||
|
|
317a37a851 | ||
|
|
daf974657c | ||
|
|
ef9c5c98cc |
@ -3,7 +3,6 @@
|
||||
|
||||
const char* load_kPythonLib(const char* name);
|
||||
|
||||
extern const char kPythonLibs__enum[];
|
||||
extern const char kPythonLibs_bisect[];
|
||||
extern const char kPythonLibs_builtins[];
|
||||
extern const char kPythonLibs_cmath[];
|
||||
|
||||
35
include/pocketpy/common/linalg.h
Normal file
35
include/pocketpy/common/linalg.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct c11_vec2i {
|
||||
int x;
|
||||
int y;
|
||||
} c11_vec2i;
|
||||
|
||||
typedef struct c11_vec3i {
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
} c11_vec3i;
|
||||
|
||||
typedef struct c11_vec2 {
|
||||
float x;
|
||||
float y;
|
||||
} c11_vec2;
|
||||
|
||||
typedef struct c11_vec3 {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
} c11_vec3;
|
||||
|
||||
typedef struct c11_mat3x3 {
|
||||
union {
|
||||
struct {
|
||||
float _11, _12, _13;
|
||||
float _21, _22, _23;
|
||||
float _31, _32, _33;
|
||||
};
|
||||
float m[3][3];
|
||||
float v[9];
|
||||
};
|
||||
} c11_mat3x3;
|
||||
@ -10,4 +10,5 @@ void pk__add_module_json();
|
||||
void pk__add_module_gc();
|
||||
void pk__add_module_time();
|
||||
void pk__add_module_easing();
|
||||
void pk__add_module_traceback();
|
||||
void pk__add_module_traceback();
|
||||
void pk__add_module_enum();
|
||||
@ -48,7 +48,6 @@ typedef struct VM {
|
||||
py_TValue last_retval;
|
||||
py_TValue curr_exception;
|
||||
bool is_curr_exc_handled; // handled by try-except block but not cleared yet
|
||||
bool is_stopiteration;
|
||||
|
||||
py_TValue reg[8]; // users' registers
|
||||
|
||||
|
||||
@ -51,6 +51,8 @@ typedef py_TValue* py_GlobalRef;
|
||||
typedef py_TValue* py_StackRef;
|
||||
/// An item reference to a container object. It invalidates when the container is modified.
|
||||
typedef py_TValue* py_ItemRef;
|
||||
/// An output reference for returning a value.
|
||||
typedef py_TValue* py_OutRef;
|
||||
|
||||
/// Native function signature.
|
||||
/// @param argc number of arguments.
|
||||
@ -109,54 +111,57 @@ PK_EXPORT bool py_compile(const char* source,
|
||||
bool is_dynamic) PY_RAISE PY_RETURN;
|
||||
|
||||
/// Python equivalent to `globals()`.
|
||||
PK_EXPORT void py_newglobals(py_Ref);
|
||||
PK_EXPORT void py_newglobals(py_OutRef);
|
||||
/// Python equivalent to `locals()`.
|
||||
/// @return a temporary object, which expires on the associated function return.
|
||||
PK_EXPORT void py_newlocals(py_Ref);
|
||||
PK_EXPORT void py_newlocals(py_OutRef);
|
||||
|
||||
/************* Values Creation *************/
|
||||
|
||||
/// Create an `int` object.
|
||||
PK_EXPORT void py_newint(py_Ref, py_i64);
|
||||
PK_EXPORT void py_newint(py_OutRef, py_i64);
|
||||
/// Create a `float` object.
|
||||
PK_EXPORT void py_newfloat(py_Ref, py_f64);
|
||||
PK_EXPORT void py_newfloat(py_OutRef, py_f64);
|
||||
/// Create a `bool` object.
|
||||
PK_EXPORT void py_newbool(py_Ref, bool);
|
||||
PK_EXPORT void py_newbool(py_OutRef, bool);
|
||||
/// Create a `str` object from a null-terminated string (utf-8).
|
||||
PK_EXPORT void py_newstr(py_Ref, const char*);
|
||||
PK_EXPORT void py_newstr(py_OutRef, const char*);
|
||||
/// Create a `str` object from a char array (utf-8).
|
||||
PK_EXPORT void py_newstrn(py_Ref, const char*, int);
|
||||
PK_EXPORT void py_newstrn(py_OutRef, const char*, int);
|
||||
/// Create a `bytes` object with `n` UNINITIALIZED bytes.
|
||||
PK_EXPORT unsigned char* py_newbytes(py_Ref, int n);
|
||||
PK_EXPORT unsigned char* py_newbytes(py_OutRef, int n);
|
||||
/// Create a `None` object.
|
||||
PK_EXPORT void py_newnone(py_Ref);
|
||||
PK_EXPORT void py_newnone(py_OutRef);
|
||||
/// Create a `NotImplemented` object.
|
||||
PK_EXPORT void py_newnotimplemented(py_Ref out);
|
||||
PK_EXPORT void py_newnotimplemented(py_OutRef);
|
||||
/// Create a `...` object.
|
||||
PK_EXPORT void py_newellipsis(py_Ref out);
|
||||
PK_EXPORT void py_newellipsis(py_OutRef);
|
||||
/// Create a `nil` object. `nil` is an invalid representation of an object.
|
||||
/// Don't use it unless you know what you are doing.
|
||||
PK_EXPORT void py_newnil(py_Ref);
|
||||
PK_EXPORT void py_newnil(py_OutRef);
|
||||
/// Create a `tuple` with `n` UNINITIALIZED elements.
|
||||
/// You should initialize all elements before using it.
|
||||
PK_EXPORT void py_newtuple(py_Ref, int n);
|
||||
PK_EXPORT void py_newtuple(py_OutRef, int n);
|
||||
/// Create an empty `list`.
|
||||
PK_EXPORT void py_newlist(py_Ref);
|
||||
PK_EXPORT void py_newlist(py_OutRef);
|
||||
/// Create a `list` with `n` UNINITIALIZED elements.
|
||||
/// You should initialize all elements before using it.
|
||||
PK_EXPORT void py_newlistn(py_Ref, int n);
|
||||
PK_EXPORT void py_newlistn(py_OutRef, int n);
|
||||
/// Create an empty `dict`.
|
||||
PK_EXPORT void py_newdict(py_Ref);
|
||||
PK_EXPORT void py_newdict(py_OutRef);
|
||||
/// Create an UNINITIALIZED `slice` object.
|
||||
/// You should use `py_setslot()` to set `start`, `stop`, and `step`.
|
||||
PK_EXPORT void py_newslice(py_Ref);
|
||||
PK_EXPORT void py_newslice(py_OutRef);
|
||||
/// Create a `nativefunc` object.
|
||||
PK_EXPORT void py_newnativefunc(py_Ref out, py_CFunction);
|
||||
PK_EXPORT void py_newnativefunc(py_OutRef, py_CFunction);
|
||||
/// Create a `function` object.
|
||||
PK_EXPORT py_Name
|
||||
py_newfunction(py_Ref out, const char* sig, py_CFunction f, const char* docstring, int slots);
|
||||
PK_EXPORT py_Name py_newfunction(py_OutRef out,
|
||||
const char* sig,
|
||||
py_CFunction f,
|
||||
const char* docstring,
|
||||
int slots);
|
||||
/// Create a `boundmethod` object.
|
||||
PK_EXPORT void py_newboundmethod(py_Ref out, py_Ref self, py_Ref func);
|
||||
PK_EXPORT void py_newboundmethod(py_OutRef out, py_Ref self, py_Ref func);
|
||||
|
||||
/************* Name Convertions *************/
|
||||
|
||||
@ -189,7 +194,7 @@ PK_EXPORT py_Type py_newtype(const char* name,
|
||||
/// @param slots number of slots. Use `-1` to create a `__dict__`.
|
||||
/// @param udsize size of your userdata.
|
||||
/// @return pointer to the userdata.
|
||||
PK_EXPORT void* py_newobject(py_Ref out, py_Type type, int slots, int udsize);
|
||||
PK_EXPORT void* py_newobject(py_OutRef out, py_Type type, int slots, int udsize);
|
||||
|
||||
/************* Type Cast *************/
|
||||
|
||||
@ -295,6 +300,11 @@ PK_EXPORT void py_setdict(py_Ref self, py_Name name, py_Ref val);
|
||||
PK_EXPORT bool py_deldict(py_Ref self, py_Name name);
|
||||
/// Prepare an insertion to the object's `__dict__`.
|
||||
PK_EXPORT py_ItemRef py_emplacedict(py_Ref self, py_Name name);
|
||||
/// Apply a function to all items in the object's `__dict__`.
|
||||
/// Return `true` if the function is successful for all items.
|
||||
/// NOTE: Be careful if `f` modifies the object's `__dict__`.
|
||||
PK_EXPORT bool
|
||||
py_applydict(py_Ref self, bool (*f)(py_Name name, py_Ref val, void* ctx), void* ctx) PY_RAISE;
|
||||
|
||||
/// Get the i-th slot of the object.
|
||||
/// The object must have slots and `i` must be in valid range.
|
||||
@ -462,7 +472,7 @@ PK_EXPORT void py_clearexc(py_StackRef p0);
|
||||
#define UnboundLocalError(n) \
|
||||
py_exception(tp_UnboundLocalError, "local variable '%n' referenced before assignment", (n))
|
||||
|
||||
PK_EXPORT bool StopIteration();
|
||||
PK_EXPORT bool StopIteration() PY_RAISE;
|
||||
PK_EXPORT bool KeyError(py_Ref key) PY_RAISE;
|
||||
|
||||
/************* Operators *************/
|
||||
@ -470,7 +480,6 @@ PK_EXPORT bool KeyError(py_Ref key) PY_RAISE;
|
||||
/// Python equivalent to `bool(val)`.
|
||||
/// 1: true, 0: false, -1: error
|
||||
PK_EXPORT int py_bool(py_Ref val) PY_RAISE;
|
||||
|
||||
/// Compare two objects.
|
||||
/// 1: lhs == rhs, 0: lhs != rhs, -1: error
|
||||
PK_EXPORT int py_equal(py_Ref lhs, py_Ref rhs) PY_RAISE;
|
||||
|
||||
@ -59,6 +59,7 @@ MAGIC_METHOD(__package__)
|
||||
MAGIC_METHOD(__path__)
|
||||
MAGIC_METHOD(__class__)
|
||||
MAGIC_METHOD(__abs__)
|
||||
MAGIC_METHOD(__getattr__)
|
||||
MAGIC_METHOD(__missing__)
|
||||
|
||||
#endif
|
||||
@ -1,11 +0,0 @@
|
||||
class Enum:
|
||||
def __init__(self, name, value):
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
||||
def __str__(self):
|
||||
return f'{type(self).__name__}.{self.name}'
|
||||
|
||||
def __repr__(self):
|
||||
return f'<{str(self)}: {self.value!r}>'
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -68,7 +68,6 @@ void VM__ctor(VM* self) {
|
||||
self->last_retval = *py_NIL;
|
||||
self->curr_exception = *py_NIL;
|
||||
self->is_curr_exc_handled = false;
|
||||
self->is_stopiteration = false;
|
||||
|
||||
self->__curr_class = NULL;
|
||||
|
||||
@ -206,6 +205,7 @@ void VM__ctor(VM* self) {
|
||||
pk__add_module_time();
|
||||
pk__add_module_easing();
|
||||
pk__add_module_traceback();
|
||||
pk__add_module_enum();
|
||||
|
||||
// add python builtins
|
||||
do {
|
||||
|
||||
91
src/modules/enum.c
Normal file
91
src/modules/enum.c
Normal file
@ -0,0 +1,91 @@
|
||||
#include "pocketpy/pocketpy.h"
|
||||
#include "pocketpy/interpreter/vm.h"
|
||||
#include "pocketpy/common/sstream.h"
|
||||
|
||||
static bool Enum__wrapper_field(py_Name name, py_Ref value, void* ctx) {
|
||||
c11_sv name_sv = py_name2sv(name);
|
||||
if(name_sv.size == 0 || name_sv.data[0] == '_') return true;
|
||||
py_push(ctx);
|
||||
py_pushnil();
|
||||
py_newstr(py_pushtmp(), py_name2str(name));
|
||||
py_push(value);
|
||||
bool ok = py_vectorcall(2, 0);
|
||||
if(!ok) return false;
|
||||
py_assign(value, py_retval());
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Enum__on_end_subclass(py_TypeInfo* derived_ti) {
|
||||
derived_ti->is_sealed = true;
|
||||
py_applydict(&derived_ti->self, Enum__wrapper_field, &derived_ti->self);
|
||||
}
|
||||
|
||||
static bool Enum__new__(int argc, py_Ref argv) {
|
||||
py_newobject(py_retval(), py_totype(argv), 2, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Enum__init__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(3);
|
||||
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||
py_setslot(argv, 0, py_arg(1));
|
||||
py_setslot(argv, 1, py_arg(2));
|
||||
py_newnone(py_retval());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Enum__str__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
// f'{type(self).__name__}.{self.name}'
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
c11_sbuf__write_cstr(&buf, py_tpname(argv->type));
|
||||
c11_sbuf__write_char(&buf, '.');
|
||||
c11_sbuf__write_cstr(&buf, py_tostr(py_getslot(argv, 0)));
|
||||
c11_sbuf__py_submit(&buf, py_retval());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Enum__repr__(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
// f'<{str(self)}: {self.value!r}>'
|
||||
if(!py_str(argv)) return false;
|
||||
py_push(py_retval()); // str(self)
|
||||
if(!py_repr(py_getslot(argv, 1))) return false;
|
||||
py_push(py_retval()); // repr(self.value)
|
||||
c11_sbuf buf;
|
||||
c11_sbuf__ctor(&buf);
|
||||
c11_sbuf__write_cstr(&buf, "<");
|
||||
c11_sbuf__write_cstr(&buf, py_tostr(py_peek(-2)));
|
||||
c11_sbuf__write_cstr(&buf, ": ");
|
||||
c11_sbuf__write_cstr(&buf, py_tostr(py_peek(-1)));
|
||||
c11_sbuf__write_cstr(&buf, ">");
|
||||
c11_sbuf__py_submit(&buf, py_retval());
|
||||
py_shrink(2);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Enum__name(int argc, py_Ref argv) {
|
||||
py_assign(py_retval(), py_getslot(argv, 0));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Enum__value(int argc, py_Ref argv) {
|
||||
py_assign(py_retval(), py_getslot(argv, 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
void pk__add_module_enum() {
|
||||
py_Ref mod = py_newmodule("enum");
|
||||
py_Type type = py_newtype("Enum", tp_object, mod, NULL);
|
||||
|
||||
py_bindmagic(type, __new__, Enum__new__);
|
||||
py_bindmagic(type, __init__, Enum__init__);
|
||||
py_bindmagic(type, __str__, Enum__str__);
|
||||
py_bindmagic(type, __repr__, Enum__repr__);
|
||||
py_bindproperty(type, "name", Enum__name, NULL);
|
||||
py_bindproperty(type, "value", Enum__value, NULL);
|
||||
|
||||
py_TypeInfo* ti = c11__at(py_TypeInfo, &pk_current_vm->types, type);
|
||||
ti->on_end_subclass = Enum__on_end_subclass;
|
||||
}
|
||||
@ -105,7 +105,12 @@ bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) {
|
||||
py_StackRef p0 = py_peek(0);
|
||||
py_newnil(py_retval());
|
||||
bool ok = f(argc, argv);
|
||||
if(!ok) return false;
|
||||
if(!ok) {
|
||||
if(!py_checkexc(true)) {
|
||||
c11__abort("py_CFunction returns `false` but no exception is set!");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(py_peek(0) != p0) {
|
||||
c11__abort("py_CFunction corrupts the stack! Did you forget to call `py_pop()`?");
|
||||
}
|
||||
@ -219,9 +224,4 @@ bool pk_callmagic(py_Name name, int argc, py_Ref argv) {
|
||||
return py_call(tmp, argc, argv);
|
||||
}
|
||||
|
||||
bool StopIteration() {
|
||||
VM* vm = pk_current_vm;
|
||||
assert(!vm->is_stopiteration); // flag is already set
|
||||
vm->is_stopiteration = true;
|
||||
return false;
|
||||
}
|
||||
bool StopIteration() { return py_exception(tp_StopIteration, ""); }
|
||||
@ -152,7 +152,6 @@ void py_clearexc(py_StackRef p0) {
|
||||
vm->last_retval = *py_NIL;
|
||||
vm->curr_exception = *py_NIL;
|
||||
vm->is_curr_exc_handled = false;
|
||||
vm->is_stopiteration = false;
|
||||
vm->__curr_class = NULL;
|
||||
if(p0) vm->stack.sp = p0;
|
||||
}
|
||||
|
||||
@ -70,20 +70,17 @@ bool py_iter(py_Ref val) {
|
||||
|
||||
int py_next(py_Ref val) {
|
||||
VM* vm = pk_current_vm;
|
||||
vm->is_stopiteration = false;
|
||||
py_Ref tmp = py_tpfindmagic(val->type, __next__);
|
||||
if(!tmp) {
|
||||
TypeError("'%t' object is not an iterator", val->type);
|
||||
return -1;
|
||||
}
|
||||
if(py_call(tmp, 1, val)) return true;
|
||||
if(py_call(tmp, 1, val)) return 1;
|
||||
if(vm->curr_exception.type == tp_StopIteration) {
|
||||
py_clearexc(NULL);
|
||||
vm->is_stopiteration = true;
|
||||
return 0;
|
||||
}
|
||||
int retval = vm->is_stopiteration ? 0 : -1;
|
||||
vm->is_stopiteration = false;
|
||||
return retval;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool py_getattr(py_Ref self, py_Name name) {
|
||||
@ -154,6 +151,14 @@ bool py_getattr(py_Ref self, py_Name name) {
|
||||
}
|
||||
}
|
||||
|
||||
py_Ref fallback = py_tpfindmagic(type, __getattr__);
|
||||
if(fallback){
|
||||
py_push(fallback);
|
||||
py_push(self);
|
||||
py_newstr(py_pushtmp(), py_name2str(name));
|
||||
return py_vectorcall(1, 0);
|
||||
}
|
||||
|
||||
if(self->type == tp_module) {
|
||||
py_Ref path = py_getdict(self, __path__);
|
||||
c11_sbuf buf;
|
||||
|
||||
@ -34,6 +34,17 @@ py_ItemRef py_emplacedict(py_Ref self, py_Name name){
|
||||
return py_getdict(self, name);
|
||||
}
|
||||
|
||||
bool py_applydict(py_Ref self, bool (*f)(py_Name, py_Ref, void *), void *ctx){
|
||||
assert(self && self->is_ptr);
|
||||
NameDict* dict = PyObject__dict(self->_obj);
|
||||
for(int i = 0; i < dict->length; i++){
|
||||
NameDict_KV* kv = c11__at(NameDict_KV, dict, i);
|
||||
bool ok = f(kv->key, &kv->value, ctx);
|
||||
if(!ok) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool py_deldict(py_Ref self, py_Name name) {
|
||||
assert(self && self->is_ptr);
|
||||
if(!py_ismagicname(name) || self->type != tp_type) {
|
||||
|
||||
@ -26,3 +26,27 @@ except AttributeError:
|
||||
pass
|
||||
|
||||
assert getattr(a, 'xxx', 1) == 1
|
||||
|
||||
class A:
|
||||
def __init__(self, x):
|
||||
self.x = x
|
||||
|
||||
def __getattr__(self, name):
|
||||
if not name:
|
||||
raise AttributeError
|
||||
return name, None
|
||||
|
||||
a = A(1)
|
||||
assert a.x == 1
|
||||
assert a.y == ('y', None)
|
||||
assert a.zzz == ('zzz', None)
|
||||
|
||||
assert getattr(a, 'x') == 1
|
||||
assert getattr(a, 'zzz') == ('zzz', None)
|
||||
|
||||
assert hasattr(a, 'x')
|
||||
assert hasattr(a, 'y')
|
||||
assert hasattr(a, 'zzz')
|
||||
|
||||
assert not hasattr(a, '')
|
||||
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
exit()
|
||||
|
||||
from enum import Enum
|
||||
|
||||
class A(Enum):
|
||||
Loading…
x
Reference in New Issue
Block a user