Merge branch 'main' into c_binding_api

This commit is contained in:
Kolten Pearson 2023-04-29 13:38:15 -06:00
commit b4769d77ea
8 changed files with 182 additions and 170 deletions

View File

@ -46,6 +46,8 @@ jobs:
run: python3 scripts/run_tests.py
- name: Benchmark
run: python3 scripts/run_tests.py benchmark
- name: GCC Build Test
run: g++ -o pocketpy --std=c++17 src/main.cpp
build_macos:
runs-on: macos-latest
steps:

View File

@ -5,72 +5,25 @@
namespace pkpy {
// template<typename Ret, typename... Params>
// struct NativeProxyFunc {
// static constexpr int N = sizeof...(Params);
// using _Fp = Ret(*)(Params...);
// _Fp func;
// NativeProxyFunc(_Fp func) : func(func) {}
#define PY_CLASS(T, mod, name) \
static Type _type(VM* vm) { \
static const StrName __x0(#mod); \
static const StrName __x1(#name); \
return OBJ_GET(Type, vm->_modules[__x0]->attr(__x1)); \
} \
static PyObject* register_class(VM* vm, PyObject* mod) { \
PyObject* type = vm->new_type_object(mod, #name, vm->tp_object); \
if(OBJ_NAME(mod) != #mod) { \
auto msg = fmt("register_class() failed: ", OBJ_NAME(mod), " != ", #mod); \
throw std::runtime_error(msg); \
} \
T::_register(vm, mod, type); \
type->attr()._try_perfect_rehash(); \
return type; \
}
// PyObject* operator()(VM* vm, ArgsView args) {
// if (args.size() != N) {
// vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(args.size()));
// }
// return call<Ret>(vm, args, std::make_index_sequence<N>());
// }
#define VAR_T(T, ...) vm->heap.gcnew<T>(T::_type(vm), T(__VA_ARGS__))
// template<typename __Ret, size_t... Is>
// std::enable_if_t<std::is_void_v<__Ret>, PyObject*> call(VM* vm, ArgsView args, std::index_sequence<Is...>) {
// func(py_cast<Params>(vm, args[Is])...);
// return vm->None;
// }
// template<typename __Ret, size_t... Is>
// std::enable_if_t<!std::is_void_v<__Ret>, PyObject*> call(VM* vm, ArgsView args, std::index_sequence<Is...>) {
// __Ret ret = func(py_cast<Params>(vm, args[Is])...);
// return VAR(std::move(ret));
// }
// };
// template<typename Ret, typename T, typename... Params>
// struct NativeProxyMethod {
// static constexpr int N = sizeof...(Params);
// using _Fp = Ret(T::*)(Params...);
// _Fp func;
// NativeProxyMethod(_Fp func) : func(func) {}
// PyObject* operator()(VM* vm, ArgsView args) {
// int actual_size = args.size() - 1;
// if (actual_size != N) {
// vm->TypeError("expected " + std::to_string(N) + " arguments, but got " + std::to_string(actual_size));
// }
// return call<Ret>(vm, args, std::make_index_sequence<N>());
// }
// template<typename __Ret, size_t... Is>
// std::enable_if_t<std::is_void_v<__Ret>, PyObject*> call(VM* vm, ArgsView args, std::index_sequence<Is...>) {
// T& self = py_cast<T&>(vm, args[0]);
// (self.*func)(py_cast<Params>(vm, args[Is+1])...);
// return vm->None;
// }
// template<typename __Ret, size_t... Is>
// std::enable_if_t<!std::is_void_v<__Ret>, PyObject*> call(VM* vm, ArgsView args, std::index_sequence<Is...>) {
// T& self = py_cast<T&>(vm, args[0]);
// __Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...);
// return VAR(std::move(ret));
// }
// };
// template<typename Ret, typename... Params>
// auto native_proxy_callable(Ret(*func)(Params...)) {
// return NativeProxyFunc<Ret, Params...>(func);
// }
// template<typename Ret, typename T, typename... Params>
// auto native_proxy_callable(Ret(T::*func)(Params...)) {
// return NativeProxyMethod<Ret, T, Params...>(func);
// }
struct VoidP{
PY_CLASS(VoidP, c, void_p)

View File

@ -116,50 +116,4 @@ inline void FuncDecl::_gc_mark() const{
for(int i=0; i<kwargs.size(); i++) OBJ_MARK(kwargs[i].value);
}
template<> inline void gc_mark<List>(List& t){
for(PyObject* obj: t){
OBJ_MARK(obj);
}
}
template<> inline void gc_mark<Tuple>(Tuple& t){
for(PyObject* obj: t){
OBJ_MARK(obj);
}
}
template<> inline void gc_mark<NameDict>(NameDict& t){
if(t.size() == 0) return;
for(uint16_t i=0; i<t._capacity; i++){
if(t._items[i].first.empty()) continue;
OBJ_MARK(t._items[i].second);
}
}
template<> inline void gc_mark<MappingProxy>(MappingProxy& t){
OBJ_MARK(t.obj);
}
template<> inline void gc_mark<BoundMethod>(BoundMethod& t){
OBJ_MARK(t.self);
OBJ_MARK(t.func);
}
template<> inline void gc_mark<Slice>(Slice& t){
OBJ_MARK(t.start);
OBJ_MARK(t.stop);
OBJ_MARK(t.step);
}
template<> inline void gc_mark<Function>(Function& t){
t.decl->_gc_mark();
if(t._module != nullptr) OBJ_MARK(t._module);
if(t._closure != nullptr) gc_mark<NameDict>(*t._closure);
}
template<> inline void gc_mark<Super>(Super& t){
OBJ_MARK(t.first);
}
// NOTE: std::function may capture some PyObject*, they can not be marked
} // namespace pkpy

View File

@ -31,16 +31,16 @@ struct FileIO {
bool is_text() const { return mode != "rb" && mode != "wb" && mode != "ab"; }
FileIO(VM* vm, Str file, Str mode): file(file), mode(mode) {
std::ios_base::openmode extra = 0;
std::ios_base::openmode extra = static_cast<std::ios_base::openmode>(0);
if(mode == "rb" || mode == "wb" || mode == "ab"){
extra |= std::ios::binary;
}
if(mode == "rt" || mode == "r" || mode == "rb"){
_fs.open(file.sv(), std::ios::in | extra);
_fs.open(file.str(), std::ios::in | extra);
}else if(mode == "wt" || mode == "w" || mode == "wb"){
_fs.open(file.sv(), std::ios::out | extra);
_fs.open(file.str(), std::ios::out | extra);
}else if(mode == "at" || mode == "a" || mode == "ab"){
_fs.open(file.sv(), std::ios::app | extra);
_fs.open(file.str(), std::ios::app | extra);
}else{
vm->ValueError("invalid mode");
}

View File

@ -41,7 +41,7 @@ public:
return array->operator[](index++);
}
void _gc_mark() const override {
void _gc_mark() const{
OBJ_MARK(ref);
}
};
@ -60,7 +60,7 @@ public:
return VAR(str->u8_getitem(index++));
}
void _gc_mark() const override {
void _gc_mark() const{
OBJ_MARK(ref);
}
};
@ -95,11 +95,4 @@ inline void Generator::_gc_mark() const{
for(PyObject* obj: s_backup) OBJ_MARK(obj);
}
template<typename T>
void gc_mark(T& t) {
if constexpr(std::is_base_of_v<BaseIter, T>){
t._gc_mark();
}
}
} // namespace pkpy

View File

@ -38,7 +38,13 @@ constexpr TokenIndex TK(const char token[]) {
while(*i && *j && *i == *j) { i++; j++;}
if(*i == *j) return k;
}
#ifdef __GNUC__
// for old version of gcc, it is not smart enough to ignore FATAL_ERROR()
// so we must do a normal return
return 255;
#else
FATAL_ERROR();
#endif
}
#define TK_STR(t) kTokens[t]

192
src/obj.h
View File

@ -103,7 +103,6 @@ protected:
VM* vm;
public:
BaseIter(VM* vm) : vm(vm) {}
virtual void _gc_mark() const {}
virtual PyObject* next() = 0;
virtual ~BaseIter() = default;
};
@ -125,7 +124,8 @@ struct PyObject{
virtual void* value() = 0;
virtual void _obj_gc_mark() = 0;
PyObject(Type type) : type(type) {}
PyObject(Type type) : type(type), _attr(nullptr) {}
virtual ~PyObject() {
if(_attr == nullptr) return;
_attr->~NameDict();
@ -137,46 +137,45 @@ struct PyObject{
}
};
template<typename T>
void gc_mark(T& t);
template <typename, typename=void> struct has_gc_marker : std::false_type {};
template <typename T> struct has_gc_marker<T, std::void_t<decltype(&T::_gc_mark)>> : std::true_type {};
template <typename T>
struct Py_ final: PyObject {
T _value;
Py_(Type type, const T& val): PyObject(type), _value(val) { _init(); }
Py_(Type type, T&& val): PyObject(type), _value(std::move(val)) { _init(); }
void _init() noexcept {
if constexpr (std::is_same_v<T, Type> || std::is_same_v<T, DummyModule>) {
_attr = new(pool64.alloc<NameDict>()) NameDict(kTypeAttrLoadFactor);
}else if constexpr(std::is_same_v<T, DummyInstance>){
_attr = new(pool64.alloc<NameDict>()) NameDict(kInstAttrLoadFactor);
}else if constexpr(std::is_same_v<T, Function> || std::is_same_v<T, NativeFunc>){
_attr = new(pool64.alloc<NameDict>()) NameDict(kInstAttrLoadFactor);
}else{
_attr = nullptr;
}
}
void* value() override { return &_value; }
void _obj_gc_mark() override {
if(gc.marked) return;
gc.marked = true;
if(_attr != nullptr) pkpy::gc_mark<NameDict>(*_attr);
pkpy::gc_mark<T>(_value); // handle PyObject* inside _value `T`
if constexpr (has_gc_marker<T>::value) {
_value._gc_mark();
}
}
Py_(Type type, const T& value) : PyObject(type), _value(value) {}
Py_(Type type, T&& value) : PyObject(type), _value(std::move(value)) {}
};
struct MappingProxy{
PyObject* obj;
MappingProxy(PyObject* obj) : obj(obj) {}
NameDict& attr() noexcept { return obj->attr(); }
};
#define OBJ_GET(T, obj) (((Py_<T>*)(obj))->_value)
#define OBJ_MARK(obj) if(!is_tagged(obj)) (obj)->_obj_gc_mark()
// #define OBJ_GET(T, obj) (*reinterpret_cast<T*>((obj)->value()))
#define OBJ_MARK(obj) \
if(!is_tagged(obj) && !(obj)->gc.marked) { \
(obj)->gc.marked = true; \
(obj)->_obj_gc_mark(); \
if((obj)->is_attr_valid()) gc_mark_namedict((obj)->attr()); \
}
inline void gc_mark_namedict(NameDict& t){
if(t.size() == 0) return;
for(uint16_t i=0; i<t._capacity; i++){
if(t._items[i].first.empty()) continue;
OBJ_MARK(t._items[i].second);
}
}
Str obj_type_name(VM* vm, Type type);
@ -209,23 +208,6 @@ inline bool is_non_tagged_type(PyObject* obj, Type type) {
return !is_tagged(obj) && obj->type == type;
}
#define PY_CLASS(T, mod, name) \
static Type _type(VM* vm) { \
static const StrName __x0(#mod); \
static const StrName __x1(#name); \
return OBJ_GET(Type, vm->_modules[__x0]->attr(__x1)); \
} \
static PyObject* register_class(VM* vm, PyObject* mod) { \
PyObject* type = vm->new_type_object(mod, #name, vm->tp_object); \
if(OBJ_NAME(mod) != #mod) { \
auto msg = fmt("register_class() failed: ", OBJ_NAME(mod), " != ", #mod); \
throw std::runtime_error(msg); \
} \
T::_register(vm, mod, type); \
type->attr()._try_perfect_rehash(); \
return type; \
}
union BitsCvt {
i64 _int;
f64 _float;
@ -265,8 +247,130 @@ __T _py_cast(VM* vm, PyObject* obj) {
}
#define VAR(x) py_var(vm, x)
#define VAR_T(T, ...) vm->heap.gcnew<T>(T::_type(vm), T(__VA_ARGS__))
#define CAST(T, x) py_cast<T>(vm, x)
#define _CAST(T, x) _py_cast<T>(vm, x)
/*****************************************************************/
template<>
struct Py_<List> final: PyObject {
List _value;
void* value() override { return &_value; }
Py_(Type type, List&& val): PyObject(type), _value(std::move(val)) {}
Py_(Type type, const List& val): PyObject(type), _value(val) {}
void _obj_gc_mark() override {
for(PyObject* obj: _value) OBJ_MARK(obj);
}
};
template<>
struct Py_<Tuple> final: PyObject {
Tuple _value;
void* value() override { return &_value; }
Py_(Type type, Tuple&& val): PyObject(type), _value(std::move(val)) {}
Py_(Type type, const Tuple& val): PyObject(type), _value(val) {}
void _obj_gc_mark() override {
for(PyObject* obj: _value) OBJ_MARK(obj);
}
};
template<>
struct Py_<MappingProxy> final: PyObject {
MappingProxy _value;
void* value() override { return &_value; }
Py_(Type type, MappingProxy val): PyObject(type), _value(val) {}
void _obj_gc_mark() override {
OBJ_MARK(_value.obj);
}
};
template<>
struct Py_<BoundMethod> final: PyObject {
BoundMethod _value;
void* value() override { return &_value; }
Py_(Type type, BoundMethod val): PyObject(type), _value(val) {}
void _obj_gc_mark() override {
OBJ_MARK(_value.self);
OBJ_MARK(_value.func);
}
};
template<>
struct Py_<Slice> final: PyObject {
Slice _value;
void* value() override { return &_value; }
Py_(Type type, Slice val): PyObject(type), _value(val) {}
void _obj_gc_mark() override {
OBJ_MARK(_value.start);
OBJ_MARK(_value.stop);
OBJ_MARK(_value.step);
}
};
template<>
struct Py_<Function> final: PyObject {
Function _value;
void* value() override { return &_value; }
Py_(Type type, Function val): PyObject(type), _value(val) {
enable_instance_dict();
}
void _obj_gc_mark() override {
_value.decl->_gc_mark();
if(_value._module != nullptr) OBJ_MARK(_value._module);
if(_value._closure != nullptr) gc_mark_namedict(*_value._closure);
}
};
template<>
struct Py_<NativeFunc> final: PyObject {
NativeFunc _value;
void* value() override { return &_value; }
Py_(Type type, NativeFunc val): PyObject(type), _value(val) {
enable_instance_dict();
}
void _obj_gc_mark() override {}
};
template<>
struct Py_<Super> final: PyObject {
Super _value;
void* value() override { return &_value; }
Py_(Type type, Super val): PyObject(type), _value(val) {}
void _obj_gc_mark() override {
OBJ_MARK(_value.first);
}
};
template<>
struct Py_<DummyInstance> final: PyObject {
void* value() override { return nullptr; }
Py_(Type type, DummyInstance val): PyObject(type) {
enable_instance_dict();
}
void _obj_gc_mark() override {}
};
template<>
struct Py_<Type> final: PyObject {
Type _value;
void* value() override { return &_value; }
Py_(Type type, Type val): PyObject(type), _value(val) {
enable_instance_dict(kTypeAttrLoadFactor);
}
void _obj_gc_mark() override {}
};
template<>
struct Py_<DummyModule> final: PyObject {
void* value() override { return nullptr; }
Py_(Type type, DummyModule val): PyObject(type) {
enable_instance_dict(kTypeAttrLoadFactor);
}
void _obj_gc_mark() override {}
};
} // namespace pkpy

View File

@ -55,7 +55,7 @@ public:
}
PyObject* next() override;
void _gc_mark() const override;
void _gc_mark() const;
};
struct PyTypeInfo{