mirror of
https://github.com/pocketpy/pocketpy
synced 2026-06-09 18:43:36 +00:00
Format the world. (#259)
* add some clang-format offs. * add formats. * format the world. * AllowShortIfStatementsOnASingleLine * off REGION. * Rollback vm.hpp * Disable insert.
This commit is contained in:
parent
0b404a51cb
commit
1c82060daf
106
.clang-format
106
.clang-format
@ -1,6 +1,102 @@
|
|||||||
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
# clang-format configuration
|
||||||
BasedOnStyle: Google
|
# compatible with clang-format 18
|
||||||
IndentWidth: 4
|
|
||||||
UseTab: Never
|
|
||||||
|
|
||||||
IndentPPDirectives: BeforeHash
|
UseTab: Never
|
||||||
|
ColumnLimit: 120
|
||||||
|
|
||||||
|
# Indent
|
||||||
|
IndentWidth: 4
|
||||||
|
BracedInitializerIndentWidth: 4
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
IndentAccessModifiers: false
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentExternBlock: Indent
|
||||||
|
IndentGotoLabels: true
|
||||||
|
IndentRequiresClause: true
|
||||||
|
IndentWrappedFunctionNames: true
|
||||||
|
NamespaceIndentation: None
|
||||||
|
LambdaBodyIndentation: Signature
|
||||||
|
BitFieldColonSpacing: Both
|
||||||
|
|
||||||
|
# Insert
|
||||||
|
InsertBraces: false
|
||||||
|
InsertNewlineAtEOF: true
|
||||||
|
KeepEmptyLinesAtEOF: true
|
||||||
|
|
||||||
|
# Align
|
||||||
|
AlignAfterOpenBracket: true
|
||||||
|
AlignTrailingComments:
|
||||||
|
Kind: Always
|
||||||
|
|
||||||
|
AlignArrayOfStructures: Left
|
||||||
|
PointerAlignment: Left
|
||||||
|
|
||||||
|
BreakAfterAttributes: Leave
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeConceptDeclarations: Always
|
||||||
|
BreakBeforeInlineASMColon: OnlyMultiline
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializers: AfterColon
|
||||||
|
BreakInheritanceList: AfterColon
|
||||||
|
BreakAdjacentStringLiterals: false
|
||||||
|
BreakStringLiterals: false
|
||||||
|
CompactNamespaces: false
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
EmptyLineAfterAccessModifier: Never
|
||||||
|
EmptyLineBeforeAccessModifier: Always
|
||||||
|
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowBreakBeforeNoexceptSpecifier: Never
|
||||||
|
AllowShortBlocksOnASingleLine: Always
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
AllowShortCompoundRequirementOnASingleLine: true
|
||||||
|
AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||||
|
AllowShortLambdasOnASingleLine: None
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: true
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
RequiresClausePosition: OwnLine
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
|
||||||
|
# Space
|
||||||
|
SeparateDefinitionBlocks: Always
|
||||||
|
SpaceBeforeParens: Custom
|
||||||
|
SpaceBeforeParensOptions:
|
||||||
|
AfterControlStatements: false
|
||||||
|
AfterForeachMacros: false
|
||||||
|
AfterFunctionDeclarationName: false
|
||||||
|
AfterFunctionDefinitionName: false
|
||||||
|
AfterIfMacros: false
|
||||||
|
AfterOverloadedOperator: true
|
||||||
|
AfterRequiresInClause: true
|
||||||
|
AfterRequiresInExpression: false
|
||||||
|
BeforeNonEmptyParentheses: false
|
||||||
|
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: false
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpacesBeforeTrailingComments: 2
|
||||||
|
SpacesInAngles: Never
|
||||||
|
|
||||||
|
SpacesInParens: Custom
|
||||||
|
SpacesInParensOptions:
|
||||||
|
InConditionalStatements: false
|
||||||
|
InCStyleCasts: false
|
||||||
|
InEmptyParentheses: false
|
||||||
|
Other: false
|
||||||
|
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
|
||||||
|
# Order
|
||||||
|
QualifierAlignment: Custom
|
||||||
|
QualifierOrder: ["constexpr", "const", "inline", "static", "type"]
|
||||||
|
SortIncludes: Never
|
||||||
|
SortUsingDeclarations: LexicographicNumeric
|
||||||
|
IncludeBlocks: Merge
|
||||||
|
|
||||||
|
WhitespaceSensitiveMacros: ["PK_PROTECTED", "LUA_PROTECTED"]
|
||||||
|
|||||||
@ -10,22 +10,24 @@
|
|||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
inline constexpr bool is_any_sso_v = is_pod_v<T> && sizeof(T) <= sizeof(void*);
|
constexpr inline bool is_any_sso_v = is_pod_v<T> && sizeof(T) <= sizeof(void*);
|
||||||
|
|
||||||
struct any{
|
struct any {
|
||||||
struct vtable{
|
struct vtable {
|
||||||
const std::type_index type;
|
const std::type_index type;
|
||||||
void (*deleter)(void*);
|
void (*deleter)(void*);
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
inline static vtable* get(){
|
inline static vtable* get() {
|
||||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||||
if constexpr (is_any_sso_v<T>){
|
if constexpr(is_any_sso_v<T>) {
|
||||||
static vtable vt{ typeid(T), nullptr };
|
static vtable vt{typeid(T), nullptr};
|
||||||
return &vt;
|
return &vt;
|
||||||
}else{
|
} else {
|
||||||
static vtable vt{ typeid(T), [](void* ptr){ delete static_cast<T*>(ptr); } };
|
static vtable vt{typeid(T), [](void* ptr) {
|
||||||
|
delete static_cast<T*>(ptr);
|
||||||
|
}};
|
||||||
return &vt;
|
return &vt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,45 +38,45 @@ struct any{
|
|||||||
|
|
||||||
any() : data(nullptr), _vt(nullptr) {}
|
any() : data(nullptr), _vt(nullptr) {}
|
||||||
|
|
||||||
explicit operator bool() const { return _vt != nullptr; }
|
explicit operator bool () const { return _vt != nullptr; }
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
any(T&& value){
|
any(T&& value) {
|
||||||
using U = std::decay_t<T>;
|
using U = std::decay_t<T>;
|
||||||
static_assert(!std::is_same_v<U, any>, "any(const any&) is deleted");
|
static_assert(!std::is_same_v<U, any>, "any(const any&) is deleted");
|
||||||
static_assert(sizeof(U) == sizeof(T));
|
static_assert(sizeof(U) == sizeof(T));
|
||||||
if constexpr (is_any_sso_v<U>){
|
if constexpr(is_any_sso_v<U>) {
|
||||||
std::memcpy(&data, &value, sizeof(U));
|
std::memcpy(&data, &value, sizeof(U));
|
||||||
}else{
|
} else {
|
||||||
data = new U(std::forward<T>(value));
|
data = new U(std::forward<T>(value));
|
||||||
}
|
}
|
||||||
_vt = vtable::get<U>();
|
_vt = vtable::get<U>();
|
||||||
}
|
}
|
||||||
|
|
||||||
any(any&& other) noexcept;
|
any(any&& other) noexcept;
|
||||||
any& operator=(any&& other) noexcept;
|
any& operator= (any&& other) noexcept;
|
||||||
|
|
||||||
const std::type_index type_id() const{
|
const std::type_index type_id() const { return _vt ? _vt->type : typeid(void); }
|
||||||
return _vt ? _vt->type : typeid(void);
|
|
||||||
}
|
|
||||||
|
|
||||||
any(const any& other) = delete;
|
any(const any& other) = delete;
|
||||||
any& operator=(const any& other) = delete;
|
any& operator= (const any& other) = delete;
|
||||||
|
|
||||||
~any() { if(_vt && _vt->deleter) _vt->deleter(data); }
|
~any() {
|
||||||
|
if(_vt && _vt->deleter) _vt->deleter(data);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
T& _cast() const noexcept{
|
T& _cast() const noexcept {
|
||||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||||
if constexpr (is_any_sso_v<T>){
|
if constexpr(is_any_sso_v<T>) {
|
||||||
return *((T*)(&data));
|
return *((T*)(&data));
|
||||||
}else{
|
} else {
|
||||||
return *(static_cast<T*>(data));
|
return *(static_cast<T*>(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
T& cast() const{
|
T& cast() const {
|
||||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||||
if(type_id() != typeid(T)) __bad_any_cast(typeid(T), type_id());
|
if(type_id() != typeid(T)) __bad_any_cast(typeid(T), type_id());
|
||||||
return _cast<T>();
|
return _cast<T>();
|
||||||
@ -83,29 +85,29 @@ struct any{
|
|||||||
static void __bad_any_cast(const std::type_index expected, const std::type_index actual);
|
static void __bad_any_cast(const std::type_index expected, const std::type_index actual);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
struct function;
|
struct function;
|
||||||
|
|
||||||
template<typename Ret, typename... Params>
|
template <typename Ret, typename... Params>
|
||||||
struct function<Ret(Params...)>{
|
struct function<Ret(Params...)> {
|
||||||
any _impl;
|
any _impl;
|
||||||
Ret (*_wrapper)(const any&, Params...);
|
Ret (*_wrapper)(const any&, Params...);
|
||||||
|
|
||||||
function(): _impl(), _wrapper(nullptr) {}
|
function() : _impl(), _wrapper(nullptr) {}
|
||||||
|
|
||||||
explicit operator bool() const { return _wrapper != nullptr; }
|
explicit operator bool () const { return _wrapper != nullptr; }
|
||||||
|
|
||||||
template<typename F>
|
template <typename F>
|
||||||
function(F&& f) : _impl(std::forward<F>(f)){
|
function(F&& f) : _impl(std::forward<F>(f)) {
|
||||||
_wrapper = [](const any& impl, Params... params) -> Ret{
|
_wrapper = [](const any& impl, Params... params) -> Ret {
|
||||||
return impl._cast<std::decay_t<F>>()(std::forward<Params>(params)...);
|
return impl._cast<std::decay_t<F>>()(std::forward<Params>(params)...);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ret operator()(Params... params) const{
|
Ret operator() (Params... params) const {
|
||||||
assert(_wrapper);
|
assert(_wrapper);
|
||||||
return _wrapper(_impl, std::forward<Params>(params)...);
|
return _wrapper(_impl, std::forward<Params>(params)...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
/*************** feature settings ***************/
|
/*************** feature settings ***************/
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
||||||
//define something for Windows (32-bit and 64-bit, this part is common)
|
//define something for Windows (32-bit and 64-bit, this part is common)
|
||||||
|
|||||||
@ -5,10 +5,13 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
struct GIL {
|
struct GIL {
|
||||||
inline static std::mutex _mutex;
|
inline static std::mutex _mutex;
|
||||||
|
|
||||||
explicit GIL() { _mutex.lock(); }
|
explicit GIL() { _mutex.lock(); }
|
||||||
|
|
||||||
~GIL() { _mutex.unlock(); }
|
~GIL() { _mutex.unlock(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PK_GLOBAL_SCOPE_LOCK() GIL _lock;
|
#define PK_GLOBAL_SCOPE_LOCK() GIL _lock;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -6,10 +6,10 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
inline const int kPoolExprBlockSize = 128;
|
const inline int kPoolExprBlockSize = 128;
|
||||||
inline const int kPoolFrameBlockSize = 80;
|
const inline int kPoolFrameBlockSize = 80;
|
||||||
|
|
||||||
void* PoolExpr_alloc() noexcept;
|
void* PoolExpr_alloc() noexcept;
|
||||||
void PoolExpr_dealloc(void*) noexcept;
|
void PoolExpr_dealloc(void*) noexcept;
|
||||||
|
|||||||
@ -6,20 +6,22 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
constexpr T default_invalid_value(){
|
constexpr T default_invalid_value() {
|
||||||
if constexpr(std::is_same_v<int, T>) return -1;
|
if constexpr(std::is_same_v<int, T>)
|
||||||
else return nullptr;
|
return -1;
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
struct NameDictImpl {
|
struct NameDictImpl {
|
||||||
PK_ALWAYS_PASS_BY_POINTER(NameDictImpl)
|
PK_ALWAYS_PASS_BY_POINTER(NameDictImpl)
|
||||||
|
|
||||||
using Item = std::pair<StrName, T>;
|
using Item = std::pair<StrName, T>;
|
||||||
static constexpr uint16_t kInitialCapacity = 16;
|
constexpr static uint16_t kInitialCapacity = 16;
|
||||||
static_assert(is_pod_v<T>);
|
static_assert(is_pod_v<T>);
|
||||||
|
|
||||||
float _load_factor;
|
float _load_factor;
|
||||||
@ -31,26 +33,30 @@ struct NameDictImpl {
|
|||||||
|
|
||||||
Item* _items;
|
Item* _items;
|
||||||
|
|
||||||
#define HASH_PROBE_1(key, ok, i) \
|
#define HASH_PROBE_1(key, ok, i) \
|
||||||
ok = false; \
|
ok = false; \
|
||||||
i = key.index & _mask; \
|
i = key.index & _mask; \
|
||||||
while(!_items[i].first.empty()) { \
|
while(!_items[i].first.empty()) { \
|
||||||
if(_items[i].first == (key)) { ok = true; break; } \
|
if(_items[i].first == (key)) { \
|
||||||
i = (i + 1) & _mask; \
|
ok = true; \
|
||||||
}
|
break; \
|
||||||
|
} \
|
||||||
|
i = (i + 1) & _mask; \
|
||||||
|
}
|
||||||
|
|
||||||
#define HASH_PROBE_0 HASH_PROBE_1
|
#define HASH_PROBE_0 HASH_PROBE_1
|
||||||
|
|
||||||
NameDictImpl(float load_factor=PK_INST_ATTR_LOAD_FACTOR): _load_factor(load_factor), _size(0) {
|
NameDictImpl(float load_factor = PK_INST_ATTR_LOAD_FACTOR) : _load_factor(load_factor), _size(0) {
|
||||||
_set_capacity_and_alloc_items(kInitialCapacity);
|
_set_capacity_and_alloc_items(kInitialCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
~NameDictImpl(){ std::free(_items); }
|
~NameDictImpl() { std::free(_items); }
|
||||||
|
|
||||||
uint16_t size() const { return _size; }
|
uint16_t size() const { return _size; }
|
||||||
|
|
||||||
uint16_t capacity() const { return _capacity; }
|
uint16_t capacity() const { return _capacity; }
|
||||||
|
|
||||||
void _set_capacity_and_alloc_items(uint16_t val){
|
void _set_capacity_and_alloc_items(uint16_t val) {
|
||||||
_capacity = val;
|
_capacity = val;
|
||||||
_critical_size = val * _load_factor;
|
_critical_size = val * _load_factor;
|
||||||
_mask = val - 1;
|
_mask = val - 1;
|
||||||
@ -59,12 +65,13 @@ while(!_items[i].first.empty()) { \
|
|||||||
std::memset(_items, 0, _capacity * sizeof(Item));
|
std::memset(_items, 0, _capacity * sizeof(Item));
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(StrName key, T val){
|
void set(StrName key, T val) {
|
||||||
bool ok; uint16_t i;
|
bool ok;
|
||||||
|
uint16_t i;
|
||||||
HASH_PROBE_1(key, ok, i);
|
HASH_PROBE_1(key, ok, i);
|
||||||
if(!ok) {
|
if(!ok) {
|
||||||
_size++;
|
_size++;
|
||||||
if(_size > _critical_size){
|
if(_size > _critical_size) {
|
||||||
_rehash_2x();
|
_rehash_2x();
|
||||||
HASH_PROBE_1(key, ok, i);
|
HASH_PROBE_1(key, ok, i);
|
||||||
}
|
}
|
||||||
@ -73,13 +80,14 @@ while(!_items[i].first.empty()) { \
|
|||||||
_items[i].second = val;
|
_items[i].second = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _rehash_2x(){
|
void _rehash_2x() {
|
||||||
Item* old_items = _items;
|
Item* old_items = _items;
|
||||||
uint16_t old_capacity = _capacity;
|
uint16_t old_capacity = _capacity;
|
||||||
_set_capacity_and_alloc_items(_capacity * 2);
|
_set_capacity_and_alloc_items(_capacity * 2);
|
||||||
for(uint16_t i=0; i<old_capacity; i++){
|
for(uint16_t i = 0; i < old_capacity; i++) {
|
||||||
if(old_items[i].first.empty()) continue;
|
if(old_items[i].first.empty()) continue;
|
||||||
bool ok; uint16_t j;
|
bool ok;
|
||||||
|
uint16_t j;
|
||||||
HASH_PROBE_1(old_items[i].first, ok, j);
|
HASH_PROBE_1(old_items[i].first, ok, j);
|
||||||
assert(!ok);
|
assert(!ok);
|
||||||
_items[j] = old_items[i];
|
_items[j] = old_items[i];
|
||||||
@ -87,21 +95,23 @@ while(!_items[i].first.empty()) { \
|
|||||||
std::free(old_items);
|
std::free(old_items);
|
||||||
}
|
}
|
||||||
|
|
||||||
T try_get(StrName key) const{
|
T try_get(StrName key) const {
|
||||||
bool ok; uint16_t i;
|
bool ok;
|
||||||
|
uint16_t i;
|
||||||
HASH_PROBE_0(key, ok, i);
|
HASH_PROBE_0(key, ok, i);
|
||||||
if(!ok) return default_invalid_value<T>();
|
if(!ok) return default_invalid_value<T>();
|
||||||
return _items[i].second;
|
return _items[i].second;
|
||||||
}
|
}
|
||||||
|
|
||||||
T* try_get_2(StrName key) const{
|
T* try_get_2(StrName key) const {
|
||||||
bool ok; uint16_t i;
|
bool ok;
|
||||||
|
uint16_t i;
|
||||||
HASH_PROBE_0(key, ok, i);
|
HASH_PROBE_0(key, ok, i);
|
||||||
if(!ok) return nullptr;
|
if(!ok) return nullptr;
|
||||||
return &_items[i].second;
|
return &_items[i].second;
|
||||||
}
|
}
|
||||||
|
|
||||||
T try_get_likely_found(StrName key) const{
|
T try_get_likely_found(StrName key) const {
|
||||||
uint16_t i = key.index & _mask;
|
uint16_t i = key.index & _mask;
|
||||||
if(_items[i].first == key) return _items[i].second;
|
if(_items[i].first == key) return _items[i].second;
|
||||||
i = (i + 1) & _mask;
|
i = (i + 1) & _mask;
|
||||||
@ -109,7 +119,7 @@ while(!_items[i].first.empty()) { \
|
|||||||
return try_get(key);
|
return try_get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
T* try_get_2_likely_found(StrName key) const{
|
T* try_get_2_likely_found(StrName key) const {
|
||||||
uint16_t i = key.index & _mask;
|
uint16_t i = key.index & _mask;
|
||||||
if(_items[i].first == key) return &_items[i].second;
|
if(_items[i].first == key) return &_items[i].second;
|
||||||
i = (i + 1) & _mask;
|
i = (i + 1) & _mask;
|
||||||
@ -117,8 +127,9 @@ while(!_items[i].first.empty()) { \
|
|||||||
return try_get_2(key);
|
return try_get_2(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool del(StrName key){
|
bool del(StrName key) {
|
||||||
bool ok; uint16_t i;
|
bool ok;
|
||||||
|
uint16_t i;
|
||||||
HASH_PROBE_0(key, ok, i);
|
HASH_PROBE_0(key, ok, i);
|
||||||
if(!ok) return false;
|
if(!ok) return false;
|
||||||
_items[i].first = StrName();
|
_items[i].first = StrName();
|
||||||
@ -127,7 +138,7 @@ while(!_items[i].first.empty()) { \
|
|||||||
// tidy
|
// tidy
|
||||||
uint16_t pre_z = i;
|
uint16_t pre_z = i;
|
||||||
uint16_t z = (i + 1) & _mask;
|
uint16_t z = (i + 1) & _mask;
|
||||||
while(!_items[z].first.empty()){
|
while(!_items[z].first.empty()) {
|
||||||
uint16_t h = _items[z].first.index & _mask;
|
uint16_t h = _items[z].first.index & _mask;
|
||||||
if(h != i) break;
|
if(h != i) break;
|
||||||
std::swap(_items[pre_z], _items[z]);
|
std::swap(_items[pre_z], _items[z]);
|
||||||
@ -137,56 +148,56 @@ while(!_items[i].first.empty()) { \
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename __Func>
|
template <typename __Func>
|
||||||
void apply(__Func func) const {
|
void apply(__Func func) const {
|
||||||
for(uint16_t i=0; i<_capacity; i++){
|
for(uint16_t i = 0; i < _capacity; i++) {
|
||||||
if(_items[i].first.empty()) continue;
|
if(_items[i].first.empty()) continue;
|
||||||
func(_items[i].first, _items[i].second);
|
func(_items[i].first, _items[i].second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool contains(StrName key) const {
|
bool contains(StrName key) const {
|
||||||
bool ok; uint16_t i;
|
bool ok;
|
||||||
|
uint16_t i;
|
||||||
HASH_PROBE_0(key, ok, i);
|
HASH_PROBE_0(key, ok, i);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
T operator[](StrName key) const {
|
T operator[] (StrName key) const {
|
||||||
T* val = try_get_2_likely_found(key);
|
T* val = try_get_2_likely_found(key);
|
||||||
if(val == nullptr){
|
if(val == nullptr) { throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str()); }
|
||||||
throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str());
|
|
||||||
}
|
|
||||||
return *val;
|
return *val;
|
||||||
}
|
}
|
||||||
|
|
||||||
array<StrName> keys() const {
|
array<StrName> keys() const {
|
||||||
array<StrName> v(_size);
|
array<StrName> v(_size);
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for(uint16_t i=0; i<_capacity; i++){
|
for(uint16_t i = 0; i < _capacity; i++) {
|
||||||
if(_items[i].first.empty()) continue;
|
if(_items[i].first.empty()) continue;
|
||||||
new (&v[j++]) StrName(_items[i].first);
|
new (&v[j++]) StrName(_items[i].first);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
array<Item> items() const{
|
array<Item> items() const {
|
||||||
array<Item> v(_size);
|
array<Item> v(_size);
|
||||||
int j = 0;
|
int j = 0;
|
||||||
apply([&](StrName key, T val){
|
apply([&](StrName key, T val) {
|
||||||
new(&v[j++]) Item(key, val);
|
new (&v[j++]) Item(key, val);
|
||||||
});
|
});
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear(){
|
void clear() {
|
||||||
for(uint16_t i=0; i<_capacity; i++){
|
for(uint16_t i = 0; i < _capacity; i++) {
|
||||||
_items[i].first = StrName();
|
_items[i].first = StrName();
|
||||||
_items[i].second = nullptr;
|
_items[i].second = nullptr;
|
||||||
}
|
}
|
||||||
_size = 0;
|
_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef HASH_PROBE_0
|
#undef HASH_PROBE_0
|
||||||
#undef HASH_PROBE_1
|
#undef HASH_PROBE_1
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -9,10 +9,10 @@
|
|||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
int utf8len(unsigned char c, bool suppress=false);
|
int utf8len(unsigned char c, bool suppress = false);
|
||||||
struct SStream;
|
struct SStream;
|
||||||
|
|
||||||
struct Str{
|
struct Str {
|
||||||
int size;
|
int size;
|
||||||
bool is_ascii;
|
bool is_ascii;
|
||||||
char* data;
|
char* data;
|
||||||
@ -26,60 +26,70 @@ struct Str{
|
|||||||
Str(std::string_view s);
|
Str(std::string_view s);
|
||||||
Str(const char* s);
|
Str(const char* s);
|
||||||
Str(const char* s, int len);
|
Str(const char* s, int len);
|
||||||
Str(std::pair<char *, int>);
|
Str(std::pair<char*, int>);
|
||||||
Str(const Str& other);
|
Str(const Str& other);
|
||||||
Str(Str&& other);
|
Str(Str&& other);
|
||||||
|
|
||||||
operator std::string_view() const { return sv(); }
|
operator std::string_view () const { return sv(); }
|
||||||
|
|
||||||
const char* begin() const { return data; }
|
const char* begin() const { return data; }
|
||||||
|
|
||||||
const char* end() const { return data + size; }
|
const char* end() const { return data + size; }
|
||||||
char operator[](int idx) const { return data[idx]; }
|
|
||||||
|
char operator[] (int idx) const { return data[idx]; }
|
||||||
|
|
||||||
int length() const { return size; }
|
int length() const { return size; }
|
||||||
|
|
||||||
bool empty() const { return size == 0; }
|
bool empty() const { return size == 0; }
|
||||||
size_t hash() const{ return std::hash<std::string_view>()(sv()); }
|
|
||||||
|
|
||||||
Str& operator=(const Str&);
|
size_t hash() const { return std::hash<std::string_view>()(sv()); }
|
||||||
Str operator+(const Str&) const;
|
|
||||||
Str operator+(const char*) const;
|
|
||||||
friend Str operator+(const char*, const Str&);
|
|
||||||
|
|
||||||
bool operator==(const std::string_view other) const;
|
Str& operator= (const Str&);
|
||||||
bool operator!=(const std::string_view other) const;
|
Str operator+ (const Str&) const;
|
||||||
bool operator<(const std::string_view other) const;
|
Str operator+ (const char*) const;
|
||||||
friend bool operator<(const std::string_view other, const Str& str);
|
friend Str operator+ (const char*, const Str&);
|
||||||
|
|
||||||
bool operator==(const char* p) const;
|
bool operator== (const std::string_view other) const;
|
||||||
bool operator!=(const char* p) const;
|
bool operator!= (const std::string_view other) const;
|
||||||
|
bool operator< (const std::string_view other) const;
|
||||||
|
friend bool operator< (const std::string_view other, const Str& str);
|
||||||
|
|
||||||
bool operator==(const Str& other) const;
|
bool operator== (const char* p) const;
|
||||||
bool operator!=(const Str& other) const;
|
bool operator!= (const char* p) const;
|
||||||
bool operator<(const Str& other) const;
|
|
||||||
bool operator>(const Str& other) const;
|
bool operator== (const Str& other) const;
|
||||||
bool operator<=(const Str& other) const;
|
bool operator!= (const Str& other) const;
|
||||||
bool operator>=(const Str& other) const;
|
bool operator< (const Str& other) const;
|
||||||
|
bool operator> (const Str& other) const;
|
||||||
|
bool operator<= (const Str& other) const;
|
||||||
|
bool operator>= (const Str& other) const;
|
||||||
|
|
||||||
~Str();
|
~Str();
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& os, const Str& str);
|
friend std::ostream& operator<< (std::ostream& os, const Str& str);
|
||||||
|
|
||||||
const char* c_str() const { return data; }
|
const char* c_str() const { return data; }
|
||||||
|
|
||||||
std::string_view sv() const { return std::string_view(data, size); }
|
std::string_view sv() const { return std::string_view(data, size); }
|
||||||
|
|
||||||
std::string str() const { return std::string(data, size); }
|
std::string str() const { return std::string(data, size); }
|
||||||
|
|
||||||
Str substr(int start, int len) const;
|
Str substr(int start, int len) const;
|
||||||
Str substr(int start) const;
|
Str substr(int start) const;
|
||||||
Str strip(bool left, bool right, const Str& chars) const;
|
Str strip(bool left, bool right, const Str& chars) const;
|
||||||
Str strip(bool left=true, bool right=true) const;
|
Str strip(bool left = true, bool right = true) const;
|
||||||
|
|
||||||
Str lstrip() const { return strip(true, false); }
|
Str lstrip() const { return strip(true, false); }
|
||||||
|
|
||||||
Str rstrip() const { return strip(false, true); }
|
Str rstrip() const { return strip(false, true); }
|
||||||
|
|
||||||
Str lower() const;
|
Str lower() const;
|
||||||
Str upper() const;
|
Str upper() const;
|
||||||
Str escape(bool single_quote=true) const;
|
Str escape(bool single_quote = true) const;
|
||||||
void escape_(SStream& ss, bool single_quote=true) const;
|
void escape_(SStream& ss, bool single_quote = true) const;
|
||||||
int index(const Str& sub, int start=0) const;
|
int index(const Str& sub, int start = 0) const;
|
||||||
Str replace(char old, char new_) const;
|
Str replace(char old, char new_) const;
|
||||||
Str replace(const Str& old, const Str& new_, int count=-1) const;
|
Str replace(const Str& old, const Str& new_, int count = -1) const;
|
||||||
vector<std::string_view> split(const Str& sep) const;
|
vector<std::string_view> split(const Str& sep) const;
|
||||||
vector<std::string_view> split(char sep) const;
|
vector<std::string_view> split(char sep) const;
|
||||||
int count(const Str& sub) const;
|
int count(const Str& sub) const;
|
||||||
@ -95,32 +105,29 @@ struct Str{
|
|||||||
struct StrName {
|
struct StrName {
|
||||||
uint16_t index;
|
uint16_t index;
|
||||||
|
|
||||||
StrName(): index(0) {}
|
StrName() : index(0) {}
|
||||||
explicit StrName(uint16_t index): index(index) {}
|
|
||||||
StrName(const char* s): index(get(s).index) {}
|
explicit StrName(uint16_t index) : index(index) {}
|
||||||
StrName(const Str& s): index(get(s.sv()).index) {}
|
|
||||||
|
StrName(const char* s) : index(get(s).index) {}
|
||||||
|
|
||||||
|
StrName(const Str& s) : index(get(s.sv()).index) {}
|
||||||
|
|
||||||
|
std::string_view sv() const { return _r_interned()[index]; }
|
||||||
|
|
||||||
std::string_view sv() const { return _r_interned()[index];}
|
|
||||||
const char* c_str() const { return _r_interned()[index].c_str(); }
|
const char* c_str() const { return _r_interned()[index].c_str(); }
|
||||||
|
|
||||||
bool empty() const { return index == 0; }
|
bool empty() const { return index == 0; }
|
||||||
|
|
||||||
Str escape() const { return Str(sv()).escape(); }
|
Str escape() const { return Str(sv()).escape(); }
|
||||||
|
|
||||||
bool operator==(const StrName& other) const noexcept {
|
bool operator== (const StrName& other) const noexcept { return this->index == other.index; }
|
||||||
return this->index == other.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const StrName& other) const noexcept {
|
bool operator!= (const StrName& other) const noexcept { return this->index != other.index; }
|
||||||
return this->index != other.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<(const StrName& other) const noexcept {
|
bool operator< (const StrName& other) const noexcept { return sv() < other.sv(); }
|
||||||
return sv() < other.sv();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator>(const StrName& other) const noexcept {
|
bool operator> (const StrName& other) const noexcept { return sv() > other.sv(); }
|
||||||
return sv() > other.sv();
|
|
||||||
}
|
|
||||||
|
|
||||||
static StrName get(std::string_view s);
|
static StrName get(std::string_view s);
|
||||||
static std::map<std::string_view, uint16_t>& _interned();
|
static std::map<std::string_view, uint16_t>& _interned();
|
||||||
@ -128,32 +135,34 @@ struct StrName {
|
|||||||
static uint32_t _pesudo_random_index;
|
static uint32_t _pesudo_random_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SStream{
|
struct SStream {
|
||||||
PK_ALWAYS_PASS_BY_POINTER(SStream)
|
PK_ALWAYS_PASS_BY_POINTER(SStream)
|
||||||
|
|
||||||
vector<char> buffer;
|
vector<char> buffer;
|
||||||
int _precision = -1;
|
int _precision = -1;
|
||||||
|
|
||||||
bool empty() const { return buffer.empty(); }
|
bool empty() const { return buffer.empty(); }
|
||||||
|
|
||||||
void setprecision(int precision) { _precision = precision; }
|
void setprecision(int precision) { _precision = precision; }
|
||||||
|
|
||||||
SStream() {}
|
SStream() {}
|
||||||
SStream(int guess_size) { buffer.reserve(guess_size);}
|
|
||||||
|
SStream(int guess_size) { buffer.reserve(guess_size); }
|
||||||
|
|
||||||
Str str();
|
Str str();
|
||||||
|
|
||||||
SStream& operator<<(const Str&);
|
SStream& operator<< (const Str&);
|
||||||
SStream& operator<<(const char*);
|
SStream& operator<< (const char*);
|
||||||
SStream& operator<<(int);
|
SStream& operator<< (int);
|
||||||
SStream& operator<<(size_t);
|
SStream& operator<< (size_t);
|
||||||
SStream& operator<<(i64);
|
SStream& operator<< (i64);
|
||||||
SStream& operator<<(f64);
|
SStream& operator<< (f64);
|
||||||
SStream& operator<<(const std::string&);
|
SStream& operator<< (const std::string&);
|
||||||
SStream& operator<<(std::string_view);
|
SStream& operator<< (std::string_view);
|
||||||
SStream& operator<<(char);
|
SStream& operator<< (char);
|
||||||
SStream& operator<<(StrName);
|
SStream& operator<< (StrName);
|
||||||
|
|
||||||
void write_hex(unsigned char, bool non_zero=false);
|
void write_hex(unsigned char, bool non_zero = false);
|
||||||
void write_hex(void*);
|
void write_hex(void*);
|
||||||
void write_hex(i64);
|
void write_hex(i64);
|
||||||
};
|
};
|
||||||
@ -162,17 +171,19 @@ struct SStream{
|
|||||||
#undef _S
|
#undef _S
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename... Args>
|
template <typename... Args>
|
||||||
Str _S(Args&&... args) {
|
Str _S(Args&&... args) {
|
||||||
SStream ss;
|
SStream ss;
|
||||||
(ss << ... << args);
|
(ss << ... << args);
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CString{
|
struct CString {
|
||||||
const char* ptr;
|
const char* ptr;
|
||||||
CString(const char* ptr): ptr(ptr) {}
|
|
||||||
operator const char*() const { return ptr; }
|
CString(const char* ptr) : ptr(ptr) {}
|
||||||
|
|
||||||
|
operator const char* () const { return ptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// unary operators
|
// unary operators
|
||||||
@ -234,4 +245,4 @@ extern const StrName pk_id_complex;
|
|||||||
|
|
||||||
#define DEF_SNAME(name) const static StrName name(#name)
|
#define DEF_SNAME(name) const static StrName name(#name)
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -2,35 +2,39 @@
|
|||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
// is_pod_v<> for c++17 and c++20
|
// is_pod_v<> for c++17 and c++20
|
||||||
template<typename T>
|
template <typename T>
|
||||||
inline constexpr bool is_pod_v = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;
|
constexpr inline bool is_pod_v = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;
|
||||||
|
|
||||||
// https://en.cppreference.com/w/cpp/types/is_integral
|
// https://en.cppreference.com/w/cpp/types/is_integral
|
||||||
template<typename T>
|
template <typename T>
|
||||||
inline constexpr bool is_integral_v = !std::is_same_v<T, bool> && std::is_integral_v<T>;
|
constexpr inline bool is_integral_v = !std::is_same_v<T, bool> && std::is_integral_v<T>;
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
inline constexpr bool is_floating_point_v = std::is_same_v<T, float> || std::is_same_v<T, double>;
|
constexpr inline bool is_floating_point_v = std::is_same_v<T, float> || std::is_same_v<T, double>;
|
||||||
|
|
||||||
// by default, only `int` and `float` enable SSO
|
// by default, only `int` and `float` enable SSO
|
||||||
// users can specialize this template to enable SSO for other types
|
// users can specialize this template to enable SSO for other types
|
||||||
// SSO types cannot have instance dict
|
// SSO types cannot have instance dict
|
||||||
template<typename T>
|
template <typename T>
|
||||||
inline constexpr bool is_sso_v = is_integral_v<T> || is_floating_point_v<T>;
|
constexpr inline bool is_sso_v = is_integral_v<T> || is_floating_point_v<T>;
|
||||||
|
|
||||||
// if is_sso_v<T> is true, return T, else return T&
|
// if is_sso_v<T> is true, return T, else return T&
|
||||||
template<typename T>
|
template <typename T>
|
||||||
using obj_get_t = std::conditional_t<is_sso_v<T>, T, T&>;
|
using obj_get_t = std::conditional_t<is_sso_v<T>, T, T&>;
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
constexpr inline bool is_trivially_relocatable_v = std::is_trivially_copyable_v<T> && std::is_trivially_destructible_v<T>;
|
constexpr inline bool is_trivially_relocatable_v =
|
||||||
|
std::is_trivially_copyable_v<T> && std::is_trivially_destructible_v<T>;
|
||||||
|
|
||||||
template <typename, typename=void> struct has_gc_marker : std::false_type {};
|
template <typename, typename = void>
|
||||||
template <typename T> struct has_gc_marker<T, std::void_t<decltype(&T::_gc_mark)>> : std::true_type {};
|
struct has_gc_marker : std::false_type {};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
inline constexpr int py_sizeof = 16 + sizeof(T);
|
struct has_gc_marker<T, std::void_t<decltype(&T::_gc_mark)>> : std::true_type {};
|
||||||
} // namespace pkpy
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr inline int py_sizeof = 16 + sizeof(T);
|
||||||
|
} // namespace pkpy
|
||||||
|
|||||||
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
using i64 = int64_t; // always 64-bit
|
using i64 = int64_t; // always 64-bit
|
||||||
using f64 = double; // always 64-bit
|
using f64 = double; // always 64-bit
|
||||||
|
|
||||||
static_assert(sizeof(i64) == 8);
|
static_assert(sizeof(i64) == 8);
|
||||||
static_assert(sizeof(f64) == 8);
|
static_assert(sizeof(f64) == 8);
|
||||||
@ -16,9 +16,11 @@ struct explicit_copy_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Dummy types
|
// Dummy types
|
||||||
struct DummyInstance { };
|
struct DummyInstance {};
|
||||||
struct DummyModule { };
|
|
||||||
struct NoReturn { };
|
struct DummyModule {};
|
||||||
|
|
||||||
|
struct NoReturn {};
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
struct PyObject;
|
struct PyObject;
|
||||||
|
|||||||
@ -1,34 +1,34 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define PK_REGION(name) 1
|
#define PK_REGION(name) 1
|
||||||
|
|
||||||
#define PK_ALWAYS_PASS_BY_POINTER(T) \
|
#define PK_ALWAYS_PASS_BY_POINTER(T) \
|
||||||
T(const T&) = delete; \
|
T(const T&) = delete; \
|
||||||
T& operator=(const T&) = delete; \
|
T& operator= (const T&) = delete; \
|
||||||
T(T&&) = delete; \
|
T(T&&) = delete; \
|
||||||
T& operator=(T&&) = delete;
|
T& operator= (T&&) = delete;
|
||||||
|
|
||||||
#define PK_SLICE_LOOP(i, start, stop, step) for(int i=start; step>0?i<stop:i>stop; i+=step)
|
#define PK_SLICE_LOOP(i, start, stop, step) for(int i = start; step > 0 ? i < stop : i > stop; i += step)
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
// global constants
|
// global constants
|
||||||
inline const char* PK_HEX_TABLE = "0123456789abcdef";
|
const inline char* PK_HEX_TABLE = "0123456789abcdef";
|
||||||
|
|
||||||
inline const char* kPlatformStrings[] = {
|
const inline char* kPlatformStrings[] = {
|
||||||
"win32", // 0
|
"win32", // 0
|
||||||
"emscripten", // 1
|
"emscripten", // 1
|
||||||
"ios", // 2
|
"ios", // 2
|
||||||
"darwin", // 3
|
"darwin", // 3
|
||||||
"android", // 4
|
"android", // 4
|
||||||
"linux", // 5
|
"linux", // 5
|
||||||
"unknown" // 6
|
"unknown" // 6
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define PK_UNREACHABLE() __assume(0);
|
#define PK_UNREACHABLE() __assume(0);
|
||||||
#else
|
#else
|
||||||
#define PK_UNREACHABLE() __builtin_unreachable();
|
#define PK_UNREACHABLE() __builtin_unreachable();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -18,21 +18,27 @@ struct array {
|
|||||||
using size_type = int;
|
using size_type = int;
|
||||||
|
|
||||||
array() : _data(nullptr), _size(0) {}
|
array() : _data(nullptr), _size(0) {}
|
||||||
|
|
||||||
array(int size) : _data((T*)std::malloc(sizeof(T) * size)), _size(size) {}
|
array(int size) : _data((T*)std::malloc(sizeof(T) * size)), _size(size) {}
|
||||||
|
|
||||||
array(array&& other) noexcept : _data(other._data), _size(other._size) {
|
array(array&& other) noexcept : _data(other._data), _size(other._size) {
|
||||||
other._data = nullptr;
|
other._data = nullptr;
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
array(const array& other) = delete;
|
array(const array& other) = delete;
|
||||||
|
|
||||||
array(explicit_copy_t, const array& other) {
|
array(explicit_copy_t, const array& other) {
|
||||||
_data = (T*)std::malloc(sizeof(T) * other._size);
|
_data = (T*)std::malloc(sizeof(T) * other._size);
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
for (int i = 0; i < _size; i++) _data[i] = other._data[i];
|
for(int i = 0; i < _size; i++)
|
||||||
|
_data[i] = other._data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
array(T* data, int size) : _data(data), _size(size) {}
|
array(T* data, int size) : _data(data), _size(size) {}
|
||||||
|
|
||||||
array& operator=(array&& other) noexcept {
|
array& operator= (array&& other) noexcept {
|
||||||
if (_data) {
|
if(_data) {
|
||||||
std::destroy(begin(), end());
|
std::destroy(begin(), end());
|
||||||
std::free(_data);
|
std::free(_data);
|
||||||
}
|
}
|
||||||
@ -43,14 +49,14 @@ struct array {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
array& operator=(const array& other) = delete;
|
array& operator= (const array& other) = delete;
|
||||||
|
|
||||||
T& operator[](int i) {
|
T& operator[] (int i) {
|
||||||
assert(i >= 0 && i < _size);
|
assert(i >= 0 && i < _size);
|
||||||
return _data[i];
|
return _data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
const T& operator[](int i) const {
|
const T& operator[] (int i) const {
|
||||||
assert(i >= 0 && i < _size);
|
assert(i >= 0 && i < _size);
|
||||||
return _data[i];
|
return _data[i];
|
||||||
}
|
}
|
||||||
@ -58,7 +64,9 @@ struct array {
|
|||||||
int size() const { return _size; }
|
int size() const { return _size; }
|
||||||
|
|
||||||
T* begin() const { return _data; }
|
T* begin() const { return _data; }
|
||||||
|
|
||||||
T* end() const { return _data + _size; }
|
T* end() const { return _data + _size; }
|
||||||
|
|
||||||
T* data() const { return _data; }
|
T* data() const { return _data; }
|
||||||
|
|
||||||
std::pair<T*, int> detach() noexcept {
|
std::pair<T*, int> detach() noexcept {
|
||||||
@ -69,7 +77,7 @@ struct array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
~array() {
|
~array() {
|
||||||
if (_data) {
|
if(_data) {
|
||||||
std::destroy(begin(), end());
|
std::destroy(begin(), end());
|
||||||
std::free(_data);
|
std::free(_data);
|
||||||
}
|
}
|
||||||
@ -85,58 +93,63 @@ struct vector {
|
|||||||
using size_type = int;
|
using size_type = int;
|
||||||
|
|
||||||
vector() : _data(nullptr), _capacity(0), _size(0) {}
|
vector() : _data(nullptr), _capacity(0), _size(0) {}
|
||||||
vector(int size)
|
|
||||||
: _data((T*)std::malloc(sizeof(T) * size)),
|
vector(int size) : _data((T*)std::malloc(sizeof(T) * size)), _capacity(size), _size(size) {}
|
||||||
_capacity(size),
|
|
||||||
_size(size) {}
|
vector(vector&& other) noexcept : _data(other._data), _capacity(other._capacity), _size(other._size) {
|
||||||
vector(vector&& other) noexcept
|
|
||||||
: _data(other._data), _capacity(other._capacity), _size(other._size) {
|
|
||||||
other._data = nullptr;
|
other._data = nullptr;
|
||||||
other._capacity = 0;
|
other._capacity = 0;
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector(const vector& other) = delete;
|
vector(const vector& other) = delete;
|
||||||
vector(explicit_copy_t, const vector& other)
|
|
||||||
: _data((T*)std::malloc(sizeof(T) * other._size)),
|
vector(explicit_copy_t, const vector& other) :
|
||||||
_capacity(other._size),
|
_data((T*)std::malloc(sizeof(T) * other._size)), _capacity(other._size), _size(other._size) {
|
||||||
_size(other._size) {
|
for(int i = 0; i < _size; i++)
|
||||||
for (int i = 0; i < _size; i++) _data[i] = other._data[i];
|
_data[i] = other._data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow move
|
// allow move
|
||||||
vector& operator=(vector&& other) noexcept {
|
vector& operator= (vector&& other) noexcept {
|
||||||
if (_data) {
|
if(_data) {
|
||||||
std::destroy(begin(), end());
|
std::destroy(begin(), end());
|
||||||
std::free(_data);
|
std::free(_data);
|
||||||
}
|
}
|
||||||
new (this) vector(std::move(other));
|
new (this) vector(std::move(other));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// disallow copy
|
// disallow copy
|
||||||
vector& operator=(const vector& other) = delete;
|
vector& operator= (const vector& other) = delete;
|
||||||
|
|
||||||
bool empty() const { return _size == 0; }
|
bool empty() const { return _size == 0; }
|
||||||
|
|
||||||
int size() const { return _size; }
|
int size() const { return _size; }
|
||||||
|
|
||||||
int capacity() const { return _capacity; }
|
int capacity() const { return _capacity; }
|
||||||
|
|
||||||
T& back() { return _data[_size - 1]; }
|
T& back() { return _data[_size - 1]; }
|
||||||
|
|
||||||
T* begin() const { return _data; }
|
T* begin() const { return _data; }
|
||||||
|
|
||||||
T* end() const { return _data + _size; }
|
T* end() const { return _data + _size; }
|
||||||
|
|
||||||
T* data() const { return _data; }
|
T* data() const { return _data; }
|
||||||
|
|
||||||
void reserve(int cap) {
|
void reserve(int cap) {
|
||||||
if (cap < 4) cap = 4; // minimum capacity
|
if(cap < 4) cap = 4; // minimum capacity
|
||||||
if (cap <= capacity()) return;
|
if(cap <= capacity()) return;
|
||||||
T* new_data = (T*)std::malloc(sizeof(T) * cap);
|
T* new_data = (T*)std::malloc(sizeof(T) * cap);
|
||||||
if constexpr (is_trivially_relocatable_v<T>) {
|
if constexpr(is_trivially_relocatable_v<T>) {
|
||||||
std::memcpy(new_data, _data, sizeof(T) * _size);
|
std::memcpy(new_data, _data, sizeof(T) * _size);
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < _size; i++) {
|
for(int i = 0; i < _size; i++) {
|
||||||
new (&new_data[i]) T(std::move(_data[i]));
|
new (&new_data[i]) T(std::move(_data[i]));
|
||||||
_data[i].~T();
|
_data[i].~T();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_data) std::free(_data);
|
if(_data) std::free(_data);
|
||||||
_data = new_data;
|
_data = new_data;
|
||||||
_capacity = cap;
|
_capacity = cap;
|
||||||
}
|
}
|
||||||
@ -147,46 +160,49 @@ struct vector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void push_back(const T& t) {
|
void push_back(const T& t) {
|
||||||
if (_size == _capacity) reserve(_capacity * 2);
|
if(_size == _capacity) reserve(_capacity * 2);
|
||||||
new (&_data[_size++]) T(t);
|
new (&_data[_size++]) T(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(T&& t) {
|
void push_back(T&& t) {
|
||||||
if (_size == _capacity) reserve(_capacity * 2);
|
if(_size == _capacity) reserve(_capacity * 2);
|
||||||
new (&_data[_size++]) T(std::move(t));
|
new (&_data[_size++]) T(std::move(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool contains(const T& t) const {
|
bool contains(const T& t) const {
|
||||||
for (int i = 0; i < _size; i++) {
|
for(int i = 0; i < _size; i++) {
|
||||||
if (_data[i] == t) return true;
|
if(_data[i] == t) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void emplace_back(Args&&... args) {
|
void emplace_back(Args&&... args) {
|
||||||
if (_size == _capacity) reserve(_capacity * 2);
|
if(_size == _capacity) reserve(_capacity * 2);
|
||||||
new (&_data[_size++]) T(std::forward<Args>(args)...);
|
new (&_data[_size++]) T(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
T& operator[](int i) { return _data[i]; }
|
T& operator[] (int i) { return _data[i]; }
|
||||||
const T& operator[](int i) const { return _data[i]; }
|
|
||||||
|
const T& operator[] (int i) const { return _data[i]; }
|
||||||
|
|
||||||
void extend(T* begin, T* end) {
|
void extend(T* begin, T* end) {
|
||||||
int n = end - begin;
|
int n = end - begin;
|
||||||
reserve(_size + n);
|
reserve(_size + n);
|
||||||
for (int i = 0; i < n; i++) new (&_data[_size++]) T(begin[i]);
|
for(int i = 0; i < n; i++)
|
||||||
|
new (&_data[_size++]) T(begin[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(int index, const T& t) {
|
void insert(int index, const T& t) {
|
||||||
if (_size == _capacity) reserve(_capacity * 2);
|
if(_size == _capacity) reserve(_capacity * 2);
|
||||||
for (int i = _size; i > index; i--) _data[i] = std::move(_data[i - 1]);
|
for(int i = _size; i > index; i--)
|
||||||
|
_data[i] = std::move(_data[i - 1]);
|
||||||
_data[index] = t;
|
_data[index] = t;
|
||||||
_size++;
|
_size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void erase(int index) {
|
void erase(int index) {
|
||||||
for (int i = index; i < _size - 1; i++)
|
for(int i = index; i < _size - 1; i++)
|
||||||
_data[i] = std::move(_data[i + 1]);
|
_data[i] = std::move(_data[i + 1]);
|
||||||
_size--;
|
_size--;
|
||||||
}
|
}
|
||||||
@ -194,9 +210,7 @@ struct vector {
|
|||||||
void pop_back() {
|
void pop_back() {
|
||||||
assert(_size > 0);
|
assert(_size > 0);
|
||||||
_size--;
|
_size--;
|
||||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
if constexpr(!std::is_trivially_destructible_v<T>) { _data[_size].~T(); }
|
||||||
_data[_size].~T();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
@ -219,7 +233,7 @@ struct vector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
~vector() {
|
~vector() {
|
||||||
if (_data) {
|
if(_data) {
|
||||||
std::destroy(begin(), end());
|
std::destroy(begin(), end());
|
||||||
std::free(_data);
|
std::free(_data);
|
||||||
}
|
}
|
||||||
@ -230,37 +244,49 @@ template <typename T, typename Container = vector<T>>
|
|||||||
class stack {
|
class stack {
|
||||||
Container vec;
|
Container vec;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void push(const T& t) { vec.push_back(t); }
|
void push(const T& t) { vec.push_back(t); }
|
||||||
|
|
||||||
void push(T&& t) { vec.push_back(std::move(t)); }
|
void push(T&& t) { vec.push_back(std::move(t)); }
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void emplace(Args&&... args) {
|
void emplace(Args&&... args) {
|
||||||
vec.emplace_back(std::forward<Args>(args)...);
|
vec.emplace_back(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop() { vec.pop_back(); }
|
void pop() { vec.pop_back(); }
|
||||||
|
|
||||||
void clear() { vec.clear(); }
|
void clear() { vec.clear(); }
|
||||||
|
|
||||||
bool empty() const { return vec.empty(); }
|
bool empty() const { return vec.empty(); }
|
||||||
|
|
||||||
typename Container::size_type size() const { return vec.size(); }
|
typename Container::size_type size() const { return vec.size(); }
|
||||||
|
|
||||||
T& top() { return vec.back(); }
|
T& top() { return vec.back(); }
|
||||||
|
|
||||||
const T& top() const { return vec.back(); }
|
const T& top() const { return vec.back(); }
|
||||||
|
|
||||||
T popx() {
|
T popx() {
|
||||||
T t = std::move(vec.back());
|
T t = std::move(vec.back());
|
||||||
vec.pop_back();
|
vec.pop_back();
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reserve(int n) { vec.reserve(n); }
|
void reserve(int n) { vec.reserve(n); }
|
||||||
|
|
||||||
Container& container() { return vec; }
|
Container& container() { return vec; }
|
||||||
|
|
||||||
const Container& container() const { return vec; }
|
const Container& container() const { return vec; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename Container = vector<T>>
|
template <typename T, typename Container = vector<T>>
|
||||||
class stack_no_copy : public stack<T, Container> {
|
class stack_no_copy : public stack<T, Container> {
|
||||||
public:
|
public:
|
||||||
stack_no_copy() = default;
|
stack_no_copy() = default;
|
||||||
stack_no_copy(const stack_no_copy& other) = delete;
|
stack_no_copy(const stack_no_copy& other) = delete;
|
||||||
stack_no_copy& operator=(const stack_no_copy& other) = delete;
|
stack_no_copy& operator= (const stack_no_copy& other) = delete;
|
||||||
stack_no_copy(stack_no_copy&& other) noexcept = default;
|
stack_no_copy(stack_no_copy&& other) noexcept = default;
|
||||||
stack_no_copy& operator=(stack_no_copy&& other) noexcept = default;
|
stack_no_copy& operator= (stack_no_copy&& other) noexcept = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
@ -273,7 +299,7 @@ class small_vector {
|
|||||||
T* m_end;
|
T* m_end;
|
||||||
T* m_max;
|
T* m_max;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
using size_type = int;
|
using size_type = int;
|
||||||
using difference_type = int;
|
using difference_type = int;
|
||||||
@ -286,74 +312,82 @@ class small_vector {
|
|||||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||||
|
|
||||||
[[nodiscard]] bool is_small() const {
|
[[nodiscard]] bool is_small() const { return m_begin == reinterpret_cast<const T*>(m_buffer); }
|
||||||
return m_begin == reinterpret_cast<const T*>(m_buffer);
|
|
||||||
}
|
|
||||||
[[nodiscard]] size_type size() const { return m_end - m_begin; }
|
[[nodiscard]] size_type size() const { return m_end - m_begin; }
|
||||||
|
|
||||||
[[nodiscard]] size_type capacity() const { return m_max - m_begin; }
|
[[nodiscard]] size_type capacity() const { return m_max - m_begin; }
|
||||||
|
|
||||||
[[nodiscard]] bool empty() const { return m_begin == m_end; }
|
[[nodiscard]] bool empty() const { return m_begin == m_end; }
|
||||||
|
|
||||||
pointer data() { return m_begin; }
|
pointer data() { return m_begin; }
|
||||||
const_pointer data() const { return m_begin; }
|
|
||||||
reference operator[](size_type index) { return m_begin[index]; }
|
|
||||||
const_reference operator[](size_type index) const { return m_begin[index]; }
|
|
||||||
iterator begin() { return m_begin; }
|
|
||||||
const_iterator begin() const { return m_begin; }
|
|
||||||
iterator end() { return m_end; }
|
|
||||||
const_iterator end() const { return m_end; }
|
|
||||||
reference front() { return *begin(); }
|
|
||||||
const_reference front() const { return *begin(); }
|
|
||||||
reference back() { return *(end() - 1); }
|
|
||||||
const_reference back() const { return *(end() - 1); }
|
|
||||||
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
|
||||||
const_reverse_iterator rbegin() const {
|
|
||||||
return const_reverse_iterator(end());
|
|
||||||
}
|
|
||||||
reverse_iterator rend() { return reverse_iterator(begin()); }
|
|
||||||
const_reverse_iterator rend() const {
|
|
||||||
return const_reverse_iterator(begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
const_pointer data() const { return m_begin; }
|
||||||
|
|
||||||
|
reference operator[] (size_type index) { return m_begin[index]; }
|
||||||
|
|
||||||
|
const_reference operator[] (size_type index) const { return m_begin[index]; }
|
||||||
|
|
||||||
|
iterator begin() { return m_begin; }
|
||||||
|
|
||||||
|
const_iterator begin() const { return m_begin; }
|
||||||
|
|
||||||
|
iterator end() { return m_end; }
|
||||||
|
|
||||||
|
const_iterator end() const { return m_end; }
|
||||||
|
|
||||||
|
reference front() { return *begin(); }
|
||||||
|
|
||||||
|
const_reference front() const { return *begin(); }
|
||||||
|
|
||||||
|
reference back() { return *(end() - 1); }
|
||||||
|
|
||||||
|
const_reference back() const { return *(end() - 1); }
|
||||||
|
|
||||||
|
reverse_iterator rbegin() { return reverse_iterator(end()); }
|
||||||
|
|
||||||
|
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
|
||||||
|
|
||||||
|
reverse_iterator rend() { return reverse_iterator(begin()); }
|
||||||
|
|
||||||
|
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
|
||||||
|
|
||||||
|
private:
|
||||||
static void uninitialized_copy_n(const void* src, size_type n, void* dest) {
|
static void uninitialized_copy_n(const void* src, size_type n, void* dest) {
|
||||||
if constexpr (std::is_trivially_copyable_v<T>) {
|
if constexpr(std::is_trivially_copyable_v<T>) {
|
||||||
std::memcpy(dest, src, sizeof(T) * n);
|
std::memcpy(dest, src, sizeof(T) * n);
|
||||||
} else {
|
} else {
|
||||||
for (size_type i = 0; i < n; i++) {
|
for(size_type i = 0; i < n; i++) {
|
||||||
::new ((T*)dest + i) T(*((const T*)src + i));
|
::new ((T*)dest + i) T(*((const T*)src + i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uninitialized_relocate_n(void* src, size_type n, void* dest) {
|
static void uninitialized_relocate_n(void* src, size_type n, void* dest) {
|
||||||
if constexpr (is_trivially_relocatable_v<T>) {
|
if constexpr(is_trivially_relocatable_v<T>) {
|
||||||
std::memcpy(dest, src, sizeof(T) * n);
|
std::memcpy(dest, src, sizeof(T) * n);
|
||||||
} else {
|
} else {
|
||||||
for (size_type i = 0; i < n; i++) {
|
for(size_type i = 0; i < n; i++) {
|
||||||
::new ((T*)dest + i) T(std::move(*((T*)src + i)));
|
::new ((T*)dest + i) T(std::move(*((T*)src + i)));
|
||||||
((T*)src + i)->~T();
|
((T*)src + i)->~T();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
small_vector()
|
small_vector() : m_begin(reinterpret_cast<T*>(m_buffer)), m_end(m_begin), m_max(m_begin + N) {}
|
||||||
: m_begin(reinterpret_cast<T*>(m_buffer)),
|
|
||||||
m_end(m_begin),
|
|
||||||
m_max(m_begin + N) {}
|
|
||||||
|
|
||||||
small_vector(const small_vector& other) noexcept {
|
small_vector(const small_vector& other) noexcept {
|
||||||
const auto size = other.size();
|
const auto size = other.size();
|
||||||
const auto capacity = other.capacity();
|
const auto capacity = other.capacity();
|
||||||
m_begin = reinterpret_cast<T*>(
|
m_begin = reinterpret_cast<T*>(other.is_small() ? m_buffer : std::malloc(sizeof(T) * capacity));
|
||||||
other.is_small() ? m_buffer : std::malloc(sizeof(T) * capacity));
|
|
||||||
uninitialized_copy_n(other.m_begin, size, this->m_begin);
|
uninitialized_copy_n(other.m_begin, size, this->m_begin);
|
||||||
m_end = m_begin + size;
|
m_end = m_begin + size;
|
||||||
m_max = m_begin + capacity;
|
m_max = m_begin + capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
small_vector(small_vector&& other) noexcept {
|
small_vector(small_vector&& other) noexcept {
|
||||||
if (other.is_small()) {
|
if(other.is_small()) {
|
||||||
m_begin = reinterpret_cast<T*>(m_buffer);
|
m_begin = reinterpret_cast<T*>(m_buffer);
|
||||||
uninitialized_relocate_n(other.m_buffer, other.size(), m_buffer);
|
uninitialized_relocate_n(other.m_buffer, other.size(), m_buffer);
|
||||||
m_end = m_begin + other.size();
|
m_end = m_begin + other.size();
|
||||||
@ -368,16 +402,16 @@ class small_vector {
|
|||||||
other.m_max = other.m_begin + N;
|
other.m_max = other.m_begin + N;
|
||||||
}
|
}
|
||||||
|
|
||||||
small_vector& operator=(const small_vector& other) noexcept {
|
small_vector& operator= (const small_vector& other) noexcept {
|
||||||
if (this != &other) {
|
if(this != &other) {
|
||||||
~small_vector();
|
~small_vector();
|
||||||
::new (this) small_vector(other);
|
::new (this) small_vector(other);
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
small_vector& operator=(small_vector&& other) noexcept {
|
small_vector& operator= (small_vector&& other) noexcept {
|
||||||
if (this != &other) {
|
if(this != &other) {
|
||||||
~small_vector();
|
~small_vector();
|
||||||
::new (this) small_vector(std::move(other));
|
::new (this) small_vector(std::move(other));
|
||||||
}
|
}
|
||||||
@ -386,21 +420,19 @@ class small_vector {
|
|||||||
|
|
||||||
~small_vector() {
|
~small_vector() {
|
||||||
std::destroy(m_begin, m_end);
|
std::destroy(m_begin, m_end);
|
||||||
if (!is_small()) std::free(m_begin);
|
if(!is_small()) std::free(m_begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void emplace_back(Args&&... args) noexcept {
|
void emplace_back(Args&&... args) noexcept {
|
||||||
if (m_end == m_max) {
|
if(m_end == m_max) {
|
||||||
const auto new_capacity = capacity() * 2;
|
const auto new_capacity = capacity() * 2;
|
||||||
const auto size = this->size();
|
const auto size = this->size();
|
||||||
if (!is_small()) {
|
if(!is_small()) {
|
||||||
if constexpr (is_trivially_relocatable_v<T>) {
|
if constexpr(is_trivially_relocatable_v<T>) {
|
||||||
m_begin = (pointer)std::realloc(m_begin,
|
m_begin = (pointer)std::realloc(m_begin, sizeof(T) * new_capacity);
|
||||||
sizeof(T) * new_capacity);
|
|
||||||
} else {
|
} else {
|
||||||
auto new_data =
|
auto new_data = (pointer)std::malloc(sizeof(T) * new_capacity);
|
||||||
(pointer)std::malloc(sizeof(T) * new_capacity);
|
|
||||||
uninitialized_relocate_n(m_begin, size, new_data);
|
uninitialized_relocate_n(m_begin, size, new_data);
|
||||||
std::free(m_begin);
|
std::free(m_begin);
|
||||||
m_begin = new_data;
|
m_begin = new_data;
|
||||||
@ -418,13 +450,12 @@ class small_vector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void push_back(const T& value) { emplace_back(value); }
|
void push_back(const T& value) { emplace_back(value); }
|
||||||
|
|
||||||
void push_back(T&& value) { emplace_back(std::move(value)); }
|
void push_back(T&& value) { emplace_back(std::move(value)); }
|
||||||
|
|
||||||
void pop_back() {
|
void pop_back() {
|
||||||
m_end--;
|
m_end--;
|
||||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
if constexpr(!std::is_trivially_destructible_v<T>) { m_end->~T(); }
|
||||||
m_end->~T();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
@ -435,11 +466,11 @@ class small_vector {
|
|||||||
|
|
||||||
template <typename T, std::size_t N>
|
template <typename T, std::size_t N>
|
||||||
class small_vector_2 : public small_vector<T, N> {
|
class small_vector_2 : public small_vector<T, N> {
|
||||||
public:
|
public:
|
||||||
small_vector_2() = default;
|
small_vector_2() = default;
|
||||||
small_vector_2(const small_vector_2& other) = delete;
|
small_vector_2(const small_vector_2& other) = delete;
|
||||||
small_vector_2& operator=(const small_vector_2& other) = delete;
|
small_vector_2& operator= (const small_vector_2& other) = delete;
|
||||||
small_vector_2(small_vector_2&& other) = delete;
|
small_vector_2(small_vector_2&& other) = delete;
|
||||||
small_vector_2& operator=(small_vector_2&& other) = delete;
|
small_vector_2& operator= (small_vector_2&& other) = delete;
|
||||||
};
|
};
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
#define PK_VERSION "2.0.0"
|
#define PK_VERSION "2.0.0"
|
||||||
#define PK_VERSION_MAJOR 2
|
#define PK_VERSION_MAJOR 2
|
||||||
|
|||||||
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
#include "pocketpy/compiler/expr.hpp"
|
#include "pocketpy/compiler/expr.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
class Compiler;
|
class Compiler;
|
||||||
typedef void (Compiler::*PrattCallback)();
|
typedef void (Compiler::*PrattCallback)();
|
||||||
|
|
||||||
struct PrattRule{
|
struct PrattRule {
|
||||||
PrattCallback prefix;
|
PrattCallback prefix;
|
||||||
PrattCallback infix;
|
PrattCallback infix;
|
||||||
Precedence precedence;
|
Precedence precedence;
|
||||||
@ -21,22 +21,28 @@ class Compiler {
|
|||||||
Lexer lexer;
|
Lexer lexer;
|
||||||
stack_no_copy<CodeEmitContext> contexts;
|
stack_no_copy<CodeEmitContext> contexts;
|
||||||
VM* vm;
|
VM* vm;
|
||||||
bool unknown_global_scope; // for eval/exec() call
|
bool unknown_global_scope; // for eval/exec() call
|
||||||
// for parsing token stream
|
// for parsing token stream
|
||||||
int i = 0;
|
int i = 0;
|
||||||
vector<Token> tokens;
|
vector<Token> tokens;
|
||||||
|
|
||||||
const Token& prev() const{ return tokens[i-1]; }
|
const Token& prev() const { return tokens[i - 1]; }
|
||||||
const Token& curr() const{ return tokens[i]; }
|
|
||||||
const Token& next() const{ return tokens[i+1]; }
|
const Token& curr() const { return tokens[i]; }
|
||||||
const Token& err() const{
|
|
||||||
|
const Token& next() const { return tokens[i + 1]; }
|
||||||
|
|
||||||
|
const Token& err() const {
|
||||||
if(i >= tokens.size()) return prev();
|
if(i >= tokens.size()) return prev();
|
||||||
return curr();
|
return curr();
|
||||||
}
|
}
|
||||||
void advance(int delta=1) { i += delta; }
|
|
||||||
|
void advance(int delta = 1) { i += delta; }
|
||||||
|
|
||||||
CodeEmitContext* ctx() { return &contexts.top(); }
|
CodeEmitContext* ctx() { return &contexts.top(); }
|
||||||
CompileMode mode() const{ return lexer.src->mode; }
|
|
||||||
|
CompileMode mode() const { return lexer.src->mode; }
|
||||||
|
|
||||||
NameScope name_scope() const;
|
NameScope name_scope() const;
|
||||||
CodeObject_ push_global_context();
|
CodeObject_ push_global_context();
|
||||||
FuncDecl_ push_f_context(Str name);
|
FuncDecl_ push_f_context(Str name);
|
||||||
@ -48,13 +54,13 @@ class Compiler {
|
|||||||
void consume(TokenIndex expected);
|
void consume(TokenIndex expected);
|
||||||
bool match_newlines_repl();
|
bool match_newlines_repl();
|
||||||
|
|
||||||
bool match_newlines(bool repl_throw=false);
|
bool match_newlines(bool repl_throw = false);
|
||||||
bool match_end_stmt();
|
bool match_end_stmt();
|
||||||
void consume_end_stmt();
|
void consume_end_stmt();
|
||||||
|
|
||||||
/*************************************************/
|
/*************************************************/
|
||||||
void EXPR();
|
void EXPR();
|
||||||
void EXPR_TUPLE(bool allow_slice=false);
|
void EXPR_TUPLE(bool allow_slice = false);
|
||||||
Expr_ EXPR_VARS(); // special case for `for loop` and `comp`
|
Expr_ EXPR_VARS(); // special case for `for loop` and `comp`
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
@ -91,11 +97,11 @@ class Compiler {
|
|||||||
void exprSubscr();
|
void exprSubscr();
|
||||||
void exprLiteral0();
|
void exprLiteral0();
|
||||||
|
|
||||||
void compile_block_body(void (Compiler::*callback)()=nullptr);
|
void compile_block_body(void (Compiler::*callback)() = nullptr);
|
||||||
void compile_normal_import();
|
void compile_normal_import();
|
||||||
void compile_from_import();
|
void compile_from_import();
|
||||||
bool is_expression(bool allow_slice=false);
|
bool is_expression(bool allow_slice = false);
|
||||||
void parse_expression(int precedence, bool allow_slice=false);
|
void parse_expression(int precedence, bool allow_slice = false);
|
||||||
void compile_if_stmt();
|
void compile_if_stmt();
|
||||||
void compile_while_loop();
|
void compile_while_loop();
|
||||||
void compile_for_loop();
|
void compile_for_loop();
|
||||||
@ -106,31 +112,41 @@ class Compiler {
|
|||||||
void compile_stmt();
|
void compile_stmt();
|
||||||
void consume_type_hints();
|
void consume_type_hints();
|
||||||
void _add_decorators(const Expr_vector& decorators);
|
void _add_decorators(const Expr_vector& decorators);
|
||||||
void compile_class(const Expr_vector& decorators={});
|
void compile_class(const Expr_vector& decorators = {});
|
||||||
void _compile_f_args(FuncDecl_ decl, bool enable_type_hints);
|
void _compile_f_args(FuncDecl_ decl, bool enable_type_hints);
|
||||||
void compile_function(const Expr_vector& decorators={});
|
void compile_function(const Expr_vector& decorators = {});
|
||||||
|
|
||||||
PyVar to_object(const TokenValue& value);
|
PyVar to_object(const TokenValue& value);
|
||||||
PyVar read_literal();
|
PyVar read_literal();
|
||||||
|
|
||||||
void SyntaxError(Str msg){ lexer.throw_err("SyntaxError", msg, err().line, err().start); }
|
void SyntaxError(Str msg) { lexer.throw_err("SyntaxError", msg, err().line, err().start); }
|
||||||
void SyntaxError(){ lexer.throw_err("SyntaxError", "invalid syntax", err().line, err().start); }
|
|
||||||
void IndentationError(Str msg){ lexer.throw_err("IndentationError", msg, err().line, err().start); }
|
void SyntaxError() { lexer.throw_err("SyntaxError", "invalid syntax", err().line, err().start); }
|
||||||
|
|
||||||
|
void IndentationError(Str msg) { lexer.throw_err("IndentationError", msg, err().line, err().start); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Compiler(VM* vm, std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope=false);
|
Compiler(VM* vm, std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope = false);
|
||||||
Str precompile();
|
Str precompile();
|
||||||
void from_precompiled(const char* source);
|
void from_precompiled(const char* source);
|
||||||
CodeObject_ compile();
|
CodeObject_ compile();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TokenDeserializer{
|
struct TokenDeserializer {
|
||||||
const char* curr;
|
const char* curr;
|
||||||
const char* source;
|
const char* source;
|
||||||
|
|
||||||
TokenDeserializer(const char* source): curr(source), source(source) {}
|
TokenDeserializer(const char* source) : curr(source), source(source) {}
|
||||||
char read_char(){ return *curr++; }
|
|
||||||
bool match_char(char c){ if(*curr == c) { curr++; return true; } return false; }
|
char read_char() { return *curr++; }
|
||||||
|
|
||||||
|
bool match_char(char c) {
|
||||||
|
if(*curr == c) {
|
||||||
|
curr++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::string_view read_string(char c);
|
std::string_view read_string(char c);
|
||||||
Str read_string_from_hex(char c);
|
Str read_string_from_hex(char c);
|
||||||
@ -139,4 +155,4 @@ struct TokenDeserializer{
|
|||||||
f64 read_float(char c);
|
f64 read_float(char c);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -3,43 +3,64 @@
|
|||||||
#include "pocketpy/objects/codeobject.hpp"
|
#include "pocketpy/objects/codeobject.hpp"
|
||||||
#include "pocketpy/compiler/lexer.hpp"
|
#include "pocketpy/compiler/lexer.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
struct CodeEmitContext;
|
struct CodeEmitContext;
|
||||||
struct Expr;
|
struct Expr;
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
class unique_ptr_128{
|
class unique_ptr_128 {
|
||||||
T* ptr;
|
T* ptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
unique_ptr_128(): ptr(nullptr) {}
|
unique_ptr_128() : ptr(nullptr) {}
|
||||||
unique_ptr_128(T* ptr): ptr(ptr) {}
|
|
||||||
|
unique_ptr_128(T* ptr) : ptr(ptr) {}
|
||||||
|
|
||||||
T* operator->() const { return ptr; }
|
T* operator->() const { return ptr; }
|
||||||
|
|
||||||
T* get() const { return ptr; }
|
T* get() const { return ptr; }
|
||||||
T* detach() { T* p = ptr; ptr = nullptr; return p; }
|
|
||||||
|
T* detach() {
|
||||||
|
T* p = ptr;
|
||||||
|
ptr = nullptr;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
unique_ptr_128(const unique_ptr_128&) = delete;
|
unique_ptr_128(const unique_ptr_128&) = delete;
|
||||||
unique_ptr_128& operator=(const unique_ptr_128&) = delete;
|
unique_ptr_128& operator= (const unique_ptr_128&) = delete;
|
||||||
|
|
||||||
bool operator==(std::nullptr_t) const { return ptr == nullptr; }
|
bool operator== (std::nullptr_t) const { return ptr == nullptr; }
|
||||||
bool operator!=(std::nullptr_t) const { return ptr != nullptr; }
|
|
||||||
|
|
||||||
~unique_ptr_128(){ if(ptr) { ptr->~T(); PoolExpr_dealloc(ptr); } }
|
bool operator!= (std::nullptr_t) const { return ptr != nullptr; }
|
||||||
|
|
||||||
template<typename U>
|
~unique_ptr_128() {
|
||||||
unique_ptr_128(unique_ptr_128<U>&& other): ptr(other.detach()) {}
|
if(ptr) {
|
||||||
|
ptr->~T();
|
||||||
|
PoolExpr_dealloc(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
operator bool() const { return ptr != nullptr; }
|
template <typename U>
|
||||||
|
unique_ptr_128(unique_ptr_128<U>&& other) : ptr(other.detach()) {}
|
||||||
|
|
||||||
template<typename U>
|
operator bool () const { return ptr != nullptr; }
|
||||||
unique_ptr_128& operator=(unique_ptr_128<U>&& other) {
|
|
||||||
if(ptr) { ptr->~T(); PoolExpr_dealloc(ptr); };
|
template <typename U>
|
||||||
|
unique_ptr_128& operator= (unique_ptr_128<U>&& other) {
|
||||||
|
if(ptr) {
|
||||||
|
ptr->~T();
|
||||||
|
PoolExpr_dealloc(ptr);
|
||||||
|
};
|
||||||
ptr = other.detach();
|
ptr = other.detach();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ptr_128& operator=(std::nullptr_t) {
|
unique_ptr_128& operator= (std::nullptr_t) {
|
||||||
if(ptr) { ptr->~T(); PoolExpr_dealloc(ptr); }
|
if(ptr) {
|
||||||
|
ptr->~T();
|
||||||
|
PoolExpr_dealloc(ptr);
|
||||||
|
}
|
||||||
ptr = nullptr;
|
ptr = nullptr;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -48,52 +69,54 @@ public:
|
|||||||
typedef unique_ptr_128<Expr> Expr_;
|
typedef unique_ptr_128<Expr> Expr_;
|
||||||
typedef small_vector<Expr_, 4> Expr_vector;
|
typedef small_vector<Expr_, 4> Expr_vector;
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
constexpr inline bool is_trivially_relocatable_v<Expr_> = true;
|
constexpr inline bool is_trivially_relocatable_v<Expr_> = true;
|
||||||
|
|
||||||
struct Expr{
|
struct Expr {
|
||||||
int line = 0;
|
int line = 0;
|
||||||
virtual ~Expr() = default;
|
virtual ~Expr() = default;
|
||||||
virtual void emit_(CodeEmitContext* ctx) = 0;
|
virtual void emit_(CodeEmitContext* ctx) = 0;
|
||||||
|
|
||||||
virtual bool is_literal() const { return false; }
|
virtual bool is_literal() const { return false; }
|
||||||
|
|
||||||
virtual bool is_json_object() const { return false; }
|
virtual bool is_json_object() const { return false; }
|
||||||
|
|
||||||
virtual bool is_attrib() const { return false; }
|
virtual bool is_attrib() const { return false; }
|
||||||
|
|
||||||
virtual bool is_subscr() const { return false; }
|
virtual bool is_subscr() const { return false; }
|
||||||
|
|
||||||
virtual bool is_compare() const { return false; }
|
virtual bool is_compare() const { return false; }
|
||||||
|
|
||||||
virtual int star_level() const { return 0; }
|
virtual int star_level() const { return 0; }
|
||||||
|
|
||||||
virtual bool is_tuple() const { return false; }
|
virtual bool is_tuple() const { return false; }
|
||||||
|
|
||||||
virtual bool is_name() const { return false; }
|
virtual bool is_name() const { return false; }
|
||||||
|
|
||||||
bool is_starred() const { return star_level() > 0; }
|
bool is_starred() const { return star_level() > 0; }
|
||||||
|
|
||||||
// for OP_DELETE_XXX
|
// for OP_DELETE_XXX
|
||||||
[[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) {
|
[[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// for OP_STORE_XXX
|
// for OP_STORE_XXX
|
||||||
[[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) {
|
[[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void emit_inplace(CodeEmitContext* ctx) {
|
virtual void emit_inplace(CodeEmitContext* ctx) { emit_(ctx); }
|
||||||
emit_(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] virtual bool emit_store_inplace(CodeEmitContext* ctx) {
|
[[nodiscard]] virtual bool emit_store_inplace(CodeEmitContext* ctx) { return emit_store(ctx); }
|
||||||
return emit_store(ctx);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CodeEmitContext{
|
struct CodeEmitContext {
|
||||||
VM* vm;
|
VM* vm;
|
||||||
FuncDecl_ func; // optional
|
FuncDecl_ func; // optional
|
||||||
CodeObject_ co; // 1 CodeEmitContext <=> 1 CodeObject_
|
CodeObject_ co; // 1 CodeEmitContext <=> 1 CodeObject_
|
||||||
// some bugs on MSVC (error C2280) when using Expr_vector
|
// some bugs on MSVC (error C2280) when using Expr_vector
|
||||||
// so we use stack_no_copy instead
|
// so we use stack_no_copy instead
|
||||||
stack_no_copy<Expr_> s_expr;
|
stack_no_copy<Expr_> s_expr;
|
||||||
int level;
|
int level;
|
||||||
vector<Str> global_names;
|
vector<Str> global_names;
|
||||||
CodeEmitContext(VM* vm, CodeObject_ co, int level): vm(vm), co(co), level(level) {}
|
|
||||||
|
CodeEmitContext(VM* vm, CodeObject_ co, int level) : vm(vm), co(co), level(level) {}
|
||||||
|
|
||||||
int curr_iblock = 0;
|
int curr_iblock = 0;
|
||||||
bool is_compiling_class = false;
|
bool is_compiling_class = false;
|
||||||
@ -104,8 +127,8 @@ struct CodeEmitContext{
|
|||||||
int get_loop() const;
|
int get_loop() const;
|
||||||
CodeBlock* enter_block(CodeBlockType type);
|
CodeBlock* enter_block(CodeBlockType type);
|
||||||
void exit_block();
|
void exit_block();
|
||||||
void emit_expr(); // clear the expression stack and generate bytecode
|
void emit_expr(); // clear the expression stack and generate bytecode
|
||||||
int emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual=false);
|
int emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual = false);
|
||||||
void revert_last_emit_();
|
void revert_last_emit_();
|
||||||
int emit_int(i64 value, int line);
|
int emit_int(i64 value, int line);
|
||||||
void patch_jump(int index);
|
void patch_jump(int index);
|
||||||
@ -118,150 +141,189 @@ struct CodeEmitContext{
|
|||||||
void try_merge_for_iter_store(int);
|
void try_merge_for_iter_store(int);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NameExpr: Expr{
|
struct NameExpr : Expr {
|
||||||
StrName name;
|
StrName name;
|
||||||
NameScope scope;
|
NameScope scope;
|
||||||
NameExpr(StrName name, NameScope scope): name(name), scope(scope) {}
|
|
||||||
|
NameExpr(StrName name, NameScope scope) : name(name), scope(scope) {}
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
bool emit_del(CodeEmitContext* ctx) override;
|
bool emit_del(CodeEmitContext* ctx) override;
|
||||||
bool emit_store(CodeEmitContext* ctx) override;
|
bool emit_store(CodeEmitContext* ctx) override;
|
||||||
|
|
||||||
bool is_name() const override { return true; }
|
bool is_name() const override { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InvertExpr: Expr{
|
struct InvertExpr : Expr {
|
||||||
Expr_ child;
|
Expr_ child;
|
||||||
InvertExpr(Expr_&& child): child(std::move(child)) {}
|
|
||||||
|
InvertExpr(Expr_&& child) : child(std::move(child)) {}
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StarredExpr: Expr{
|
struct StarredExpr : Expr {
|
||||||
int level;
|
int level;
|
||||||
Expr_ child;
|
Expr_ child;
|
||||||
StarredExpr(int level, Expr_&& child): level(level), child(std::move(child)) {}
|
|
||||||
|
StarredExpr(int level, Expr_&& child) : level(level), child(std::move(child)) {}
|
||||||
|
|
||||||
int star_level() const override { return level; }
|
int star_level() const override { return level; }
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
bool emit_store(CodeEmitContext* ctx) override;
|
bool emit_store(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NotExpr: Expr{
|
struct NotExpr : Expr {
|
||||||
Expr_ child;
|
Expr_ child;
|
||||||
NotExpr(Expr_&& child): child(std::move(child)) {}
|
|
||||||
|
NotExpr(Expr_&& child) : child(std::move(child)) {}
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AndExpr: Expr{
|
struct AndExpr : Expr {
|
||||||
Expr_ lhs;
|
Expr_ lhs;
|
||||||
Expr_ rhs;
|
Expr_ rhs;
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OrExpr: Expr{
|
struct OrExpr : Expr {
|
||||||
Expr_ lhs;
|
Expr_ lhs;
|
||||||
Expr_ rhs;
|
Expr_ rhs;
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// [None, True, False, ...]
|
// [None, True, False, ...]
|
||||||
struct Literal0Expr: Expr{
|
struct Literal0Expr : Expr {
|
||||||
TokenIndex token;
|
TokenIndex token;
|
||||||
Literal0Expr(TokenIndex token): token(token) {}
|
|
||||||
|
Literal0Expr(TokenIndex token) : token(token) {}
|
||||||
|
|
||||||
bool is_json_object() const override { return true; }
|
bool is_json_object() const override { return true; }
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LongExpr: Expr{
|
struct LongExpr : Expr {
|
||||||
Str s;
|
Str s;
|
||||||
LongExpr(const Str& s): s(s) {}
|
|
||||||
|
LongExpr(const Str& s) : s(s) {}
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BytesExpr: Expr{
|
struct BytesExpr : Expr {
|
||||||
Str s;
|
Str s;
|
||||||
BytesExpr(const Str& s): s(s) {}
|
|
||||||
|
BytesExpr(const Str& s) : s(s) {}
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ImagExpr: Expr{
|
struct ImagExpr : Expr {
|
||||||
f64 value;
|
f64 value;
|
||||||
ImagExpr(f64 value): value(value) {}
|
|
||||||
|
ImagExpr(f64 value) : value(value) {}
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// @num, @str which needs to invoke OP_LOAD_CONST
|
// @num, @str which needs to invoke OP_LOAD_CONST
|
||||||
struct LiteralExpr: Expr{
|
struct LiteralExpr : Expr {
|
||||||
TokenValue value;
|
TokenValue value;
|
||||||
LiteralExpr(TokenValue value): value(value) {}
|
|
||||||
|
LiteralExpr(TokenValue value) : value(value) {}
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
|
|
||||||
bool is_literal() const override { return true; }
|
bool is_literal() const override { return true; }
|
||||||
|
|
||||||
bool is_json_object() const override { return true; }
|
bool is_json_object() const override { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NegatedExpr: Expr{
|
struct NegatedExpr : Expr {
|
||||||
Expr_ child;
|
Expr_ child;
|
||||||
NegatedExpr(Expr_&& child): child(std::move(child)) {}
|
|
||||||
|
NegatedExpr(Expr_&& child) : child(std::move(child)) {}
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
|
|
||||||
bool is_json_object() const override { return child->is_literal(); }
|
bool is_json_object() const override { return child->is_literal(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SliceExpr: Expr{
|
struct SliceExpr : Expr {
|
||||||
Expr_ start;
|
Expr_ start;
|
||||||
Expr_ stop;
|
Expr_ stop;
|
||||||
Expr_ step;
|
Expr_ step;
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DictItemExpr: Expr{
|
struct DictItemExpr : Expr {
|
||||||
Expr_ key; // maybe nullptr if it is **kwargs
|
Expr_ key; // maybe nullptr if it is **kwargs
|
||||||
Expr_ value;
|
Expr_ value;
|
||||||
|
|
||||||
int star_level() const override { return value->star_level(); }
|
int star_level() const override { return value->star_level(); }
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SequenceExpr: Expr{
|
struct SequenceExpr : Expr {
|
||||||
Expr_vector items;
|
Expr_vector items;
|
||||||
SequenceExpr(Expr_vector&& items): items(std::move(items)) {}
|
|
||||||
|
SequenceExpr(Expr_vector&& items) : items(std::move(items)) {}
|
||||||
|
|
||||||
virtual Opcode opcode() const = 0;
|
virtual Opcode opcode() const = 0;
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override {
|
void emit_(CodeEmitContext* ctx) override {
|
||||||
for(auto& item: items) item->emit_(ctx);
|
for(auto& item: items)
|
||||||
|
item->emit_(ctx);
|
||||||
ctx->emit_(opcode(), items.size(), line);
|
ctx->emit_(opcode(), items.size(), line);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ListExpr: SequenceExpr{
|
struct ListExpr : SequenceExpr {
|
||||||
using SequenceExpr::SequenceExpr;
|
using SequenceExpr::SequenceExpr;
|
||||||
|
|
||||||
Opcode opcode() const override {
|
Opcode opcode() const override {
|
||||||
for(auto& e: items) if(e->is_starred()) return OP_BUILD_LIST_UNPACK;
|
for(auto& e: items)
|
||||||
|
if(e->is_starred()) return OP_BUILD_LIST_UNPACK;
|
||||||
return OP_BUILD_LIST;
|
return OP_BUILD_LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_json_object() const override { return true; }
|
bool is_json_object() const override { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DictExpr: SequenceExpr{
|
struct DictExpr : SequenceExpr {
|
||||||
using SequenceExpr::SequenceExpr;
|
using SequenceExpr::SequenceExpr;
|
||||||
|
|
||||||
Opcode opcode() const override {
|
Opcode opcode() const override {
|
||||||
for(auto& e: items) if(e->is_starred()) return OP_BUILD_DICT_UNPACK;
|
for(auto& e: items)
|
||||||
|
if(e->is_starred()) return OP_BUILD_DICT_UNPACK;
|
||||||
return OP_BUILD_DICT;
|
return OP_BUILD_DICT;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_json_object() const override { return true; }
|
bool is_json_object() const override { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SetExpr: SequenceExpr{
|
struct SetExpr : SequenceExpr {
|
||||||
using SequenceExpr::SequenceExpr;
|
using SequenceExpr::SequenceExpr;
|
||||||
|
|
||||||
Opcode opcode() const override {
|
Opcode opcode() const override {
|
||||||
for(auto& e: items) if(e->is_starred()) return OP_BUILD_SET_UNPACK;
|
for(auto& e: items)
|
||||||
|
if(e->is_starred()) return OP_BUILD_SET_UNPACK;
|
||||||
return OP_BUILD_SET;
|
return OP_BUILD_SET;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TupleExpr: SequenceExpr{
|
struct TupleExpr : SequenceExpr {
|
||||||
using SequenceExpr::SequenceExpr;
|
using SequenceExpr::SequenceExpr;
|
||||||
|
|
||||||
bool is_tuple() const override { return true; }
|
bool is_tuple() const override { return true; }
|
||||||
|
|
||||||
Opcode opcode() const override {
|
Opcode opcode() const override {
|
||||||
for(auto& e: items) if(e->is_starred()) return OP_BUILD_TUPLE_UNPACK;
|
for(auto& e: items)
|
||||||
|
if(e->is_starred()) return OP_BUILD_TUPLE_UNPACK;
|
||||||
return OP_BUILD_TUPLE;
|
return OP_BUILD_TUPLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,11 +331,11 @@ struct TupleExpr: SequenceExpr{
|
|||||||
bool emit_del(CodeEmitContext* ctx) override;
|
bool emit_del(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CompExpr: Expr{
|
struct CompExpr : Expr {
|
||||||
Expr_ expr; // loop expr
|
Expr_ expr; // loop expr
|
||||||
Expr_ vars; // loop vars
|
Expr_ vars; // loop vars
|
||||||
Expr_ iter; // loop iter
|
Expr_ iter; // loop iter
|
||||||
Expr_ cond; // optional if condition
|
Expr_ cond; // optional if condition
|
||||||
|
|
||||||
virtual Opcode op0() = 0;
|
virtual Opcode op0() = 0;
|
||||||
virtual Opcode op1() = 0;
|
virtual Opcode op1() = 0;
|
||||||
@ -281,25 +343,28 @@ struct CompExpr: Expr{
|
|||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ListCompExpr: CompExpr{
|
struct ListCompExpr : CompExpr {
|
||||||
Opcode op0() override { return OP_BUILD_LIST; }
|
Opcode op0() override { return OP_BUILD_LIST; }
|
||||||
|
|
||||||
Opcode op1() override { return OP_LIST_APPEND; }
|
Opcode op1() override { return OP_LIST_APPEND; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DictCompExpr: CompExpr{
|
struct DictCompExpr : CompExpr {
|
||||||
Opcode op0() override { return OP_BUILD_DICT; }
|
Opcode op0() override { return OP_BUILD_DICT; }
|
||||||
|
|
||||||
Opcode op1() override { return OP_DICT_ADD; }
|
Opcode op1() override { return OP_DICT_ADD; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SetCompExpr: CompExpr{
|
struct SetCompExpr : CompExpr {
|
||||||
Opcode op0() override { return OP_BUILD_SET; }
|
Opcode op0() override { return OP_BUILD_SET; }
|
||||||
|
|
||||||
Opcode op1() override { return OP_SET_ADD; }
|
Opcode op1() override { return OP_SET_ADD; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LambdaExpr: Expr{
|
struct LambdaExpr : Expr {
|
||||||
FuncDecl_ decl;
|
FuncDecl_ decl;
|
||||||
|
|
||||||
LambdaExpr(FuncDecl_ decl): decl(decl) {}
|
LambdaExpr(FuncDecl_ decl) : decl(decl) {}
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override {
|
void emit_(CodeEmitContext* ctx) override {
|
||||||
int index = ctx->add_func_decl(decl);
|
int index = ctx->add_func_decl(decl);
|
||||||
@ -307,17 +372,21 @@ struct LambdaExpr: Expr{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FStringExpr: Expr{
|
struct FStringExpr : Expr {
|
||||||
Str src;
|
Str src;
|
||||||
FStringExpr(const Str& src): src(src) {}
|
|
||||||
|
FStringExpr(const Str& src) : src(src) {}
|
||||||
|
|
||||||
void _load_simple_expr(CodeEmitContext* ctx, Str expr);
|
void _load_simple_expr(CodeEmitContext* ctx, Str expr);
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SubscrExpr: Expr{
|
struct SubscrExpr : Expr {
|
||||||
Expr_ a;
|
Expr_ a;
|
||||||
Expr_ b;
|
Expr_ b;
|
||||||
|
|
||||||
bool is_subscr() const override { return true; }
|
bool is_subscr() const override { return true; }
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
bool emit_del(CodeEmitContext* ctx) override;
|
bool emit_del(CodeEmitContext* ctx) override;
|
||||||
bool emit_store(CodeEmitContext* ctx) override;
|
bool emit_store(CodeEmitContext* ctx) override;
|
||||||
@ -326,10 +395,11 @@ struct SubscrExpr: Expr{
|
|||||||
bool emit_store_inplace(CodeEmitContext* ctx) override;
|
bool emit_store_inplace(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AttribExpr: Expr{
|
struct AttribExpr : Expr {
|
||||||
Expr_ a;
|
Expr_ a;
|
||||||
StrName b;
|
StrName b;
|
||||||
AttribExpr(Expr_ a, StrName b): a(std::move(a)), b(b) {}
|
|
||||||
|
AttribExpr(Expr_ a, StrName b) : a(std::move(a)), b(b) {}
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
bool emit_del(CodeEmitContext* ctx) override;
|
bool emit_del(CodeEmitContext* ctx) override;
|
||||||
@ -337,11 +407,12 @@ struct AttribExpr: Expr{
|
|||||||
void emit_method(CodeEmitContext* ctx);
|
void emit_method(CodeEmitContext* ctx);
|
||||||
|
|
||||||
bool is_attrib() const override { return true; }
|
bool is_attrib() const override { return true; }
|
||||||
|
|
||||||
void emit_inplace(CodeEmitContext* ctx) override;
|
void emit_inplace(CodeEmitContext* ctx) override;
|
||||||
bool emit_store_inplace(CodeEmitContext* ctx) override;
|
bool emit_store_inplace(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CallExpr: Expr{
|
struct CallExpr : Expr {
|
||||||
Expr_ callable;
|
Expr_ callable;
|
||||||
Expr_vector args;
|
Expr_vector args;
|
||||||
// **a will be interpreted as a special keyword argument: {"**": a}
|
// **a will be interpreted as a special keyword argument: {"**": a}
|
||||||
@ -349,42 +420,36 @@ struct CallExpr: Expr{
|
|||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GroupedExpr: Expr{
|
struct GroupedExpr : Expr {
|
||||||
Expr_ a;
|
Expr_ a;
|
||||||
GroupedExpr(Expr_&& a): a(std::move(a)) {}
|
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override{
|
GroupedExpr(Expr_&& a) : a(std::move(a)) {}
|
||||||
a->emit_(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool emit_del(CodeEmitContext* ctx) override {
|
void emit_(CodeEmitContext* ctx) override { a->emit_(ctx); }
|
||||||
return a->emit_del(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool emit_store(CodeEmitContext* ctx) override {
|
bool emit_del(CodeEmitContext* ctx) override { return a->emit_del(ctx); }
|
||||||
return a->emit_store(ctx);
|
|
||||||
}
|
bool emit_store(CodeEmitContext* ctx) override { return a->emit_store(ctx); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BinaryExpr: Expr{
|
struct BinaryExpr : Expr {
|
||||||
TokenIndex op;
|
TokenIndex op;
|
||||||
Expr_ lhs;
|
Expr_ lhs;
|
||||||
Expr_ rhs;
|
Expr_ rhs;
|
||||||
bool inplace;
|
bool inplace;
|
||||||
|
|
||||||
BinaryExpr(bool inplace=false): inplace(inplace) {}
|
BinaryExpr(bool inplace = false) : inplace(inplace) {}
|
||||||
|
|
||||||
bool is_compare() const override;
|
bool is_compare() const override;
|
||||||
void _emit_compare(CodeEmitContext*, small_vector_2<int, 6>&);
|
void _emit_compare(CodeEmitContext*, small_vector_2<int, 6>&);
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TernaryExpr : Expr {
|
||||||
struct TernaryExpr: Expr{
|
|
||||||
Expr_ cond;
|
Expr_ cond;
|
||||||
Expr_ true_expr;
|
Expr_ true_expr;
|
||||||
Expr_ false_expr;
|
Expr_ false_expr;
|
||||||
void emit_(CodeEmitContext* ctx) override;
|
void emit_(CodeEmitContext* ctx) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace pkpy
|
||||||
} // namespace pkpy
|
|
||||||
|
|||||||
@ -5,10 +5,11 @@
|
|||||||
|
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
typedef uint8_t TokenIndex;
|
typedef uint8_t TokenIndex;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
constexpr const char* kTokens[] = {
|
constexpr const char* kTokens[] = {
|
||||||
"is not", "not in", "yield from",
|
"is not", "not in", "yield from",
|
||||||
"@eof", "@eol", "@sof",
|
"@eof", "@eol", "@sof",
|
||||||
@ -28,67 +29,71 @@ constexpr const char* kTokens[] = {
|
|||||||
"None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally",
|
"None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally",
|
||||||
"while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise"
|
"while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise"
|
||||||
};
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
using TokenValue = std::variant<std::monostate, i64, f64, Str>;
|
using TokenValue = std::variant<std::monostate, i64, f64, Str>;
|
||||||
const int kTokenCount = sizeof(kTokens) / sizeof(kTokens[0]);
|
const int kTokenCount = sizeof(kTokens) / sizeof(kTokens[0]);
|
||||||
|
|
||||||
constexpr TokenIndex TK(const char token[]) {
|
constexpr TokenIndex TK(const char token[]) {
|
||||||
for(int k=0; k<kTokenCount; k++){
|
for(int k = 0; k < kTokenCount; k++) {
|
||||||
const char* i = kTokens[k];
|
const char* i = kTokens[k];
|
||||||
const char* j = token;
|
const char* j = token;
|
||||||
while(*i && *j && *i == *j) { i++; j++;}
|
while(*i && *j && *i == *j) {
|
||||||
|
i++;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
if(*i == *j) return k;
|
if(*i == *j) return k;
|
||||||
}
|
}
|
||||||
return 255;
|
return 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline constexpr bool is_raw_string_used(TokenIndex t){
|
constexpr inline bool is_raw_string_used(TokenIndex t) { return t == TK("@id") || t == TK("@long"); }
|
||||||
return t == TK("@id") || t == TK("@long");
|
|
||||||
}
|
|
||||||
|
|
||||||
#define TK_STR(t) kTokens[t]
|
#define TK_STR(t) kTokens[t]
|
||||||
const std::map<std::string_view, TokenIndex> kTokenKwMap = [](){
|
const std::map<std::string_view, TokenIndex> kTokenKwMap = []() {
|
||||||
std::map<std::string_view, TokenIndex> map;
|
std::map<std::string_view, TokenIndex> map;
|
||||||
for(int k=TK("class"); k<kTokenCount; k++) map[kTokens[k]] = k;
|
for(int k = TK("class"); k < kTokenCount; k++)
|
||||||
|
map[kTokens[k]] = k;
|
||||||
return map;
|
return map;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
struct Token{
|
struct Token {
|
||||||
TokenIndex type;
|
TokenIndex type;
|
||||||
const char* start;
|
const char* start;
|
||||||
int length;
|
int length;
|
||||||
int line;
|
int line;
|
||||||
int brackets_level;
|
int brackets_level;
|
||||||
TokenValue value;
|
TokenValue value;
|
||||||
|
|
||||||
Str str() const { return Str(start, length);}
|
Str str() const { return Str(start, length); }
|
||||||
std::string_view sv() const { return std::string_view(start, length);}
|
|
||||||
|
std::string_view sv() const { return std::string_view(start, length); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://docs.python.org/3/reference/expressions.html#operator-precedence
|
// https://docs.python.org/3/reference/expressions.html#operator-precedence
|
||||||
enum Precedence {
|
enum Precedence {
|
||||||
PREC_LOWEST,
|
PREC_LOWEST,
|
||||||
PREC_LAMBDA, // lambda
|
PREC_LAMBDA, // lambda
|
||||||
PREC_TERNARY, // ?:
|
PREC_TERNARY, // ?:
|
||||||
PREC_LOGICAL_OR, // or
|
PREC_LOGICAL_OR, // or
|
||||||
PREC_LOGICAL_AND, // and
|
PREC_LOGICAL_AND, // and
|
||||||
PREC_LOGICAL_NOT, // not
|
PREC_LOGICAL_NOT, // not
|
||||||
/* https://docs.python.org/3/reference/expressions.html#comparisons
|
/* https://docs.python.org/3/reference/expressions.html#comparisons
|
||||||
* Unlike C, all comparison operations in Python have the same priority,
|
* Unlike C, all comparison operations in Python have the same priority,
|
||||||
* which is lower than that of any arithmetic, shifting or bitwise operation.
|
* which is lower than that of any arithmetic, shifting or bitwise operation.
|
||||||
* Also unlike C, expressions like a < b < c have the interpretation that is conventional in mathematics.
|
* Also unlike C, expressions like a < b < c have the interpretation that is conventional in mathematics.
|
||||||
*/
|
*/
|
||||||
PREC_COMPARISION, // < > <= >= != ==, in / is / is not / not in
|
PREC_COMPARISION, // < > <= >= != ==, in / is / is not / not in
|
||||||
PREC_BITWISE_OR, // |
|
PREC_BITWISE_OR, // |
|
||||||
PREC_BITWISE_XOR, // ^
|
PREC_BITWISE_XOR, // ^
|
||||||
PREC_BITWISE_AND, // &
|
PREC_BITWISE_AND, // &
|
||||||
PREC_BITWISE_SHIFT, // << >>
|
PREC_BITWISE_SHIFT, // << >>
|
||||||
PREC_TERM, // + -
|
PREC_TERM, // + -
|
||||||
PREC_FACTOR, // * / % // @
|
PREC_FACTOR, // * / % // @
|
||||||
PREC_UNARY, // - not ~
|
PREC_UNARY, // - not ~
|
||||||
PREC_EXPONENT, // **
|
PREC_EXPONENT, // **
|
||||||
PREC_PRIMARY, // f() x[] a.b 1:2
|
PREC_PRIMARY, // f() x[] a.b 1:2
|
||||||
PREC_HIGHEST,
|
PREC_HIGHEST,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum StringType { NORMAL_STRING, RAW_STRING, F_STRING, NORMAL_BYTES };
|
enum StringType { NORMAL_STRING, RAW_STRING, F_STRING, NORMAL_BYTES };
|
||||||
@ -103,7 +108,8 @@ struct Lexer {
|
|||||||
stack_no_copy<int, small_vector_2<int, 8>> indents;
|
stack_no_copy<int, small_vector_2<int, 8>> indents;
|
||||||
int brackets_level = 0;
|
int brackets_level = 0;
|
||||||
|
|
||||||
char peekchar() const{ return *curr_char; }
|
char peekchar() const { return *curr_char; }
|
||||||
|
|
||||||
bool match_n_chars(int n, char c0);
|
bool match_n_chars(int n, char c0);
|
||||||
bool match_string(const char* s);
|
bool match_string(const char* s);
|
||||||
int eat_spaces();
|
int eat_spaces();
|
||||||
@ -114,7 +120,7 @@ struct Lexer {
|
|||||||
int eat_name();
|
int eat_name();
|
||||||
void skip_line_comment();
|
void skip_line_comment();
|
||||||
bool matchchar(char c);
|
bool matchchar(char c);
|
||||||
void add_token(TokenIndex type, TokenValue value={});
|
void add_token(TokenIndex type, TokenValue value = {});
|
||||||
void add_token_2(char c, TokenIndex one, TokenIndex two);
|
void add_token_2(char c, TokenIndex one, TokenIndex two);
|
||||||
Str eat_string_until(char quote, bool raw);
|
Str eat_string_until(char quote, bool raw);
|
||||||
void eat_string(char quote, StringType type);
|
void eat_string(char quote, StringType type);
|
||||||
@ -125,16 +131,18 @@ struct Lexer {
|
|||||||
/***** Error Reporter *****/
|
/***** Error Reporter *****/
|
||||||
[[noreturn]] void throw_err(StrName type, Str msg);
|
[[noreturn]] void throw_err(StrName type, Str msg);
|
||||||
[[noreturn]] void throw_err(StrName type, Str msg, int lineno, const char* cursor);
|
[[noreturn]] void throw_err(StrName type, Str msg, int lineno, const char* cursor);
|
||||||
[[noreturn]] void SyntaxError(Str msg){ throw_err("SyntaxError", msg); }
|
|
||||||
[[noreturn]] void SyntaxError(){ throw_err("SyntaxError", "invalid syntax"); }
|
[[noreturn]] void SyntaxError(Str msg) { throw_err("SyntaxError", msg); }
|
||||||
[[noreturn]] void IndentationError(Str msg){ throw_err("IndentationError", msg); }
|
|
||||||
|
[[noreturn]] void SyntaxError() { throw_err("SyntaxError", "invalid syntax"); }
|
||||||
|
|
||||||
|
[[noreturn]] void IndentationError(Str msg) { throw_err("IndentationError", msg); }
|
||||||
|
|
||||||
Lexer(VM* vm, std::shared_ptr<SourceData> src);
|
Lexer(VM* vm, std::shared_ptr<SourceData> src);
|
||||||
vector<Token> run();
|
vector<Token> run();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class IntParsingResult {
|
||||||
enum class IntParsingResult{
|
|
||||||
Success,
|
Success,
|
||||||
Failure,
|
Failure,
|
||||||
Overflow,
|
Overflow,
|
||||||
@ -142,4 +150,4 @@ enum class IntParsingResult{
|
|||||||
|
|
||||||
IntParsingResult parse_uint(std::string_view text, i64* out, int base);
|
IntParsingResult parse_uint(std::string_view text, i64* out, int base);
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -2,104 +2,108 @@
|
|||||||
|
|
||||||
#include "pocketpy/interpreter/cffi.hpp"
|
#include "pocketpy/interpreter/cffi.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
struct NativeProxyFuncCBase {
|
struct NativeProxyFuncCBase {
|
||||||
virtual PyVar operator()(VM* vm, ArgsView args) = 0;
|
virtual PyVar operator() (VM* vm, ArgsView args) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret, typename... Params>
|
template <typename Ret, typename... Params>
|
||||||
struct NativeProxyFuncC final: NativeProxyFuncCBase {
|
struct NativeProxyFuncC final : NativeProxyFuncCBase {
|
||||||
static constexpr int N = sizeof...(Params);
|
constexpr static int N = sizeof...(Params);
|
||||||
using _Fp = Ret(*)(Params...);
|
using _Fp = Ret (*)(Params...);
|
||||||
_Fp func;
|
_Fp func;
|
||||||
|
|
||||||
NativeProxyFuncC(_Fp func) : func(func) {}
|
NativeProxyFuncC(_Fp func) : func(func) {}
|
||||||
|
|
||||||
PyVar operator()(VM* vm, ArgsView args) override {
|
PyVar operator() (VM* vm, ArgsView args) override {
|
||||||
assert(args.size() == N);
|
assert(args.size() == N);
|
||||||
return call<Ret>(vm, args, std::make_index_sequence<N>());
|
return call<Ret>(vm, args, std::make_index_sequence<N>());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename __Ret, size_t... Is>
|
template <typename __Ret, size_t... Is>
|
||||||
PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>){
|
PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>) {
|
||||||
if constexpr(std::is_void_v<__Ret>){
|
if constexpr(std::is_void_v<__Ret>) {
|
||||||
func(py_cast<Params>(vm, args[Is])...);
|
func(py_cast<Params>(vm, args[Is])...);
|
||||||
return vm->None;
|
return vm->None;
|
||||||
}else{
|
} else {
|
||||||
__Ret ret = func(py_cast<Params>(vm, args[Is])...);
|
__Ret ret = func(py_cast<Params>(vm, args[Is])...);
|
||||||
return VAR(std::move(ret));
|
return VAR(std::move(ret));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Ret, typename T, typename... Params>
|
template <typename Ret, typename T, typename... Params>
|
||||||
struct NativeProxyMethodC final: NativeProxyFuncCBase {
|
struct NativeProxyMethodC final : NativeProxyFuncCBase {
|
||||||
static constexpr int N = sizeof...(Params);
|
constexpr static int N = sizeof...(Params);
|
||||||
using _Fp = Ret(T::*)(Params...);
|
using _Fp = Ret (T::*)(Params...);
|
||||||
_Fp func;
|
_Fp func;
|
||||||
|
|
||||||
NativeProxyMethodC(_Fp func) : func(func) {}
|
NativeProxyMethodC(_Fp func) : func(func) {}
|
||||||
|
|
||||||
PyVar operator()(VM* vm, ArgsView args) override {
|
PyVar operator() (VM* vm, ArgsView args) override {
|
||||||
assert(args.size() == N+1);
|
assert(args.size() == N + 1);
|
||||||
return call<Ret>(vm, args, std::make_index_sequence<N>());
|
return call<Ret>(vm, args, std::make_index_sequence<N>());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename __Ret, size_t... Is>
|
template <typename __Ret, size_t... Is>
|
||||||
PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>){
|
PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>) {
|
||||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); // use unsafe cast for derived classes
|
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); // use unsafe cast for derived classes
|
||||||
if constexpr(std::is_void_v<__Ret>){
|
if constexpr(std::is_void_v<__Ret>) {
|
||||||
(self.*func)(py_cast<Params>(vm, args[Is+1])...);
|
(self.*func)(py_cast<Params>(vm, args[Is + 1])...);
|
||||||
return vm->None;
|
return vm->None;
|
||||||
}else{
|
} else {
|
||||||
__Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...);
|
__Ret ret = (self.*func)(py_cast<Params>(vm, args[Is + 1])...);
|
||||||
return VAR(std::move(ret));
|
return VAR(std::move(ret));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************/
|
/*****************************************************************/
|
||||||
inline PyVar __proxy_wrapper(VM* vm, ArgsView args){
|
inline PyVar __proxy_wrapper(VM* vm, ArgsView args) {
|
||||||
NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin());
|
NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin());
|
||||||
return (*pf)(vm, args);
|
return (*pf)(vm, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Ret, typename... Params>
|
template <typename Ret, typename... Params>
|
||||||
PyObject* VM::bind(PyObject* obj, const char* sig, Ret(*func)(Params...), BindType bt){
|
PyObject* VM::bind(PyObject* obj, const char* sig, Ret (*func)(Params...), BindType bt) {
|
||||||
NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
|
NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
|
||||||
return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
|
return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Ret, typename T, typename... Params>
|
template <typename Ret, typename T, typename... Params>
|
||||||
PyObject* VM::bind(PyObject* obj, const char* sig, Ret(T::*func)(Params...), BindType bt){
|
PyObject* VM::bind(PyObject* obj, const char* sig, Ret (T::*func)(Params...), BindType bt) {
|
||||||
NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
|
NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
|
||||||
return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
|
return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Ret, typename... Params>
|
template <typename Ret, typename... Params>
|
||||||
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret(*func)(Params...), BindType bt){
|
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret (*func)(Params...), BindType bt) {
|
||||||
NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
|
NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
|
||||||
return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
|
return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Ret, typename T, typename... Params>
|
template <typename Ret, typename T, typename... Params>
|
||||||
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret(T::*func)(Params...), BindType bt){
|
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret (T::*func)(Params...), BindType bt) {
|
||||||
NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
|
NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
|
||||||
return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
|
return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename F, bool ReadOnly>
|
template <typename T, typename F, bool ReadOnly>
|
||||||
PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
|
PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
|
||||||
static_assert(!std::is_reference_v<F>);
|
static_assert(!std::is_reference_v<F>);
|
||||||
assert(is_type(obj, tp_type));
|
assert(is_type(obj, tp_type));
|
||||||
std::string_view name_sv(name); int pos = name_sv.find(':');
|
std::string_view name_sv(name);
|
||||||
|
int pos = name_sv.find(':');
|
||||||
if(pos > 0) name_sv = name_sv.substr(0, pos);
|
if(pos > 0) name_sv = name_sv.substr(0, pos);
|
||||||
auto fget = [](VM* vm, ArgsView args) -> PyVar{
|
auto fget = [](VM* vm, ArgsView args) -> PyVar {
|
||||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
|
obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
|
||||||
F T::*field = lambda_get_userdata<F T::*>(args.begin());
|
F T::*field = lambda_get_userdata<F T::*>(args.begin());
|
||||||
return VAR(self.*field);
|
return VAR(self.*field);
|
||||||
};
|
};
|
||||||
PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1, field);
|
PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1, field);
|
||||||
PyVar _1 = vm->None;
|
PyVar _1 = vm->None;
|
||||||
if constexpr (!ReadOnly){
|
if constexpr(!ReadOnly) {
|
||||||
auto fset = [](VM* vm, ArgsView args){
|
auto fset = [](VM* vm, ArgsView args) {
|
||||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
|
obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
|
||||||
F T::*field = lambda_get_userdata<F T::*>(args.begin());
|
F T::*field = lambda_get_userdata<F T::*>(args.begin());
|
||||||
self.*field = py_cast<F>(vm, args[1]);
|
self.*field = py_cast<F>(vm, args[1]);
|
||||||
@ -114,94 +118,112 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
|
|||||||
|
|
||||||
/*****************************************************************/
|
/*****************************************************************/
|
||||||
|
|
||||||
#define PY_FIELD(T, NAME, EXPR) \
|
#define PY_FIELD(T, NAME, EXPR) \
|
||||||
vm->bind_property(type, NAME, \
|
vm->bind_property( \
|
||||||
[](VM* vm, ArgsView args){ \
|
type, \
|
||||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
NAME, \
|
||||||
return VAR(self.EXPR); \
|
[](VM* vm, ArgsView args) { \
|
||||||
}, \
|
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||||
[](VM* vm, ArgsView args){ \
|
return VAR(self.EXPR); \
|
||||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
}, \
|
||||||
self.EXPR = CAST(decltype(self.EXPR), args[1]); \
|
[](VM* vm, ArgsView args) { \
|
||||||
return vm->None; \
|
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||||
});
|
self.EXPR = CAST(decltype(self.EXPR), args[1]); \
|
||||||
|
return vm->None; \
|
||||||
|
});
|
||||||
|
|
||||||
#define PY_READONLY_FIELD(T, NAME, EXPR) \
|
#define PY_READONLY_FIELD(T, NAME, EXPR) \
|
||||||
vm->bind_property(type, NAME, \
|
vm->bind_property(type, NAME, [](VM* vm, ArgsView args) { \
|
||||||
[](VM* vm, ArgsView args){ \
|
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
return VAR(self.EXPR); \
|
||||||
return VAR(self.EXPR); \
|
});
|
||||||
});
|
|
||||||
|
|
||||||
#define PY_PROPERTY(T, NAME, FGET, FSET) \
|
#define PY_PROPERTY(T, NAME, FGET, FSET) \
|
||||||
vm->bind_property(type, NAME, \
|
vm->bind_property( \
|
||||||
[](VM* vm, ArgsView args){ \
|
type, \
|
||||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
NAME, \
|
||||||
return VAR(self.FGET()); \
|
[](VM* vm, ArgsView args) { \
|
||||||
}, \
|
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||||
[](VM* vm, ArgsView args){ \
|
return VAR(self.FGET()); \
|
||||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
}, \
|
||||||
using __NT = decltype(self.FGET()); \
|
[](VM* vm, ArgsView args) { \
|
||||||
self.FSET(CAST(__NT, args[1])); \
|
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||||
return vm->None; \
|
using __NT = decltype(self.FGET()); \
|
||||||
});
|
self.FSET(CAST(__NT, args[1])); \
|
||||||
|
return vm->None; \
|
||||||
|
});
|
||||||
|
|
||||||
#define PY_READONLY_PROPERTY(T, NAME, FGET) \
|
#define PY_READONLY_PROPERTY(T, NAME, FGET) \
|
||||||
vm->bind_property(type, NAME, \
|
vm->bind_property(type, NAME, [](VM* vm, ArgsView args) { \
|
||||||
[](VM* vm, ArgsView args){ \
|
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
return VAR(self.FGET()); \
|
||||||
return VAR(self.FGET()); \
|
});
|
||||||
});
|
|
||||||
/*****************************************************************/
|
/*****************************************************************/
|
||||||
#define PY_STRUCT_LIKE(wT) \
|
#define PY_STRUCT_LIKE(wT) \
|
||||||
static_assert(std::is_trivially_copyable<wT>::value); \
|
static_assert(std::is_trivially_copyable<wT>::value); \
|
||||||
static_assert(!is_sso_v<wT>); \
|
static_assert(!is_sso_v<wT>); \
|
||||||
type->attr().set("__struct__", vm->True); \
|
type->attr().set("__struct__", vm->True); \
|
||||||
vm->bind_func(type, "fromstruct", 1, [](VM* vm, ArgsView args){ \
|
vm->bind_func( \
|
||||||
Struct& s = CAST(Struct&, args[0]); \
|
type, \
|
||||||
if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \
|
"fromstruct", \
|
||||||
PyVar obj = vm->new_user_object<wT>(); \
|
1, \
|
||||||
std::memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \
|
[](VM* vm, ArgsView args) { \
|
||||||
return obj; \
|
Struct& s = CAST(Struct&, args[0]); \
|
||||||
}, {}, BindType::STATICMETHOD); \
|
if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \
|
||||||
vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args){ \
|
PyVar obj = vm->new_user_object<wT>(); \
|
||||||
wT& self = _CAST(wT&, args[0]); \
|
std::memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \
|
||||||
return vm->new_user_object<Struct>(&self, sizeof(wT)); \
|
return obj; \
|
||||||
}); \
|
}, \
|
||||||
vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args){ \
|
{}, \
|
||||||
wT& self = _CAST(wT&, args[0]); \
|
BindType::STATICMETHOD); \
|
||||||
return vm->new_user_object<VoidP>(&self); \
|
vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args) { \
|
||||||
}); \
|
wT& self = _CAST(wT&, args[0]); \
|
||||||
vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args){ \
|
return vm->new_user_object<Struct>(&self, sizeof(wT)); \
|
||||||
wT& self = _CAST(wT&, args[0]); \
|
}); \
|
||||||
return vm->new_user_object<wT>(self); \
|
vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args) { \
|
||||||
}); \
|
wT& self = _CAST(wT&, args[0]); \
|
||||||
vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args){ \
|
return vm->new_user_object<VoidP>(&self); \
|
||||||
return VAR(sizeof(wT)); \
|
}); \
|
||||||
}); \
|
vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args) { \
|
||||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ \
|
wT& self = _CAST(wT&, args[0]); \
|
||||||
wT& self = _CAST(wT&, _0); \
|
return vm->new_user_object<wT>(self); \
|
||||||
if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \
|
}); \
|
||||||
wT& other = _CAST(wT&, _1); \
|
vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args) { \
|
||||||
return VAR(self == other); \
|
return VAR(sizeof(wT)); \
|
||||||
}); \
|
}); \
|
||||||
|
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||||
|
wT& self = _CAST(wT&, _0); \
|
||||||
|
if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \
|
||||||
|
wT& other = _CAST(wT&, _1); \
|
||||||
|
return VAR(self == other); \
|
||||||
|
});
|
||||||
|
|
||||||
#define PY_POINTER_SETGETITEM(T) \
|
#define PY_POINTER_SETGETITEM(T) \
|
||||||
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ \
|
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||||
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \
|
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \
|
||||||
i64 i = CAST(i64, _1); \
|
i64 i = CAST(i64, _1); \
|
||||||
T* tgt = reinterpret_cast<T*>(self.ptr); \
|
T* tgt = reinterpret_cast<T*>(self.ptr); \
|
||||||
return VAR(tgt[i]); \
|
return VAR(tgt[i]); \
|
||||||
}); \
|
}); \
|
||||||
vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1, PyVar _2){ \
|
vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1, PyVar _2) { \
|
||||||
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \
|
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \
|
||||||
i64 i = CAST(i64, _1); \
|
i64 i = CAST(i64, _1); \
|
||||||
T* tgt = reinterpret_cast<T*>(self.ptr); \
|
T* tgt = reinterpret_cast<T*>(self.ptr); \
|
||||||
tgt[i] = CAST(T, _2); \
|
tgt[i] = CAST(T, _2); \
|
||||||
}); \
|
});
|
||||||
|
|
||||||
#define PK_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return x; })
|
#define PK_LAMBDA(x) \
|
||||||
#define PK_VAR_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return VAR(x); })
|
([](VM* vm, ArgsView args) -> PyVar { \
|
||||||
#define PK_ACTION(x) ([](VM* vm, ArgsView args) -> PyVar { x; return vm->None; })
|
return x; \
|
||||||
|
})
|
||||||
|
#define PK_VAR_LAMBDA(x) \
|
||||||
|
([](VM* vm, ArgsView args) -> PyVar { \
|
||||||
|
return VAR(x); \
|
||||||
|
})
|
||||||
|
#define PK_ACTION(x) \
|
||||||
|
([](VM* vm, ArgsView args) -> PyVar { \
|
||||||
|
x; \
|
||||||
|
return vm->None; \
|
||||||
|
})
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -4,28 +4,30 @@
|
|||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
#define PY_CLASS(T, mod, name) \
|
#define PY_CLASS(T, mod, name) \
|
||||||
[[deprecated]] static Type _type(VM* vm) { return vm->_cxx_typeid_map[typeid(T)]; } \
|
[[deprecated]] static Type _type(VM* vm) { return vm->_cxx_typeid_map[typeid(T)]; } \
|
||||||
[[deprecated]] static PyVar register_class(VM* vm, PyVar mod, Type base=VM::tp_object) { \
|
[[deprecated]] static PyVar register_class(VM* vm, PyVar mod, Type base = VM::tp_object) { \
|
||||||
return vm->register_user_class<T>(mod, #name, base); \
|
return vm->register_user_class<T>(mod, #name, base); \
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VoidP{
|
struct VoidP {
|
||||||
void* ptr;
|
void* ptr;
|
||||||
VoidP(const void* ptr): ptr(const_cast<void*>(ptr)){}
|
|
||||||
|
|
||||||
bool operator==(const VoidP& other) const {
|
VoidP(const void* ptr) : ptr(const_cast<void*>(ptr)) {}
|
||||||
return ptr == other.ptr;
|
|
||||||
}
|
|
||||||
bool operator!=(const VoidP& other) const {
|
|
||||||
return ptr != other.ptr;
|
|
||||||
}
|
|
||||||
bool operator<(const VoidP& other) const { return ptr < other.ptr; }
|
|
||||||
bool operator<=(const VoidP& other) const { return ptr <= other.ptr; }
|
|
||||||
bool operator>(const VoidP& other) const { return ptr > other.ptr; }
|
|
||||||
bool operator>=(const VoidP& other) const { return ptr >= other.ptr; }
|
|
||||||
|
|
||||||
Str hex() const{
|
bool operator== (const VoidP& other) const { return ptr == other.ptr; }
|
||||||
|
|
||||||
|
bool operator!= (const VoidP& other) const { return ptr != other.ptr; }
|
||||||
|
|
||||||
|
bool operator< (const VoidP& other) const { return ptr < other.ptr; }
|
||||||
|
|
||||||
|
bool operator<= (const VoidP& other) const { return ptr <= other.ptr; }
|
||||||
|
|
||||||
|
bool operator> (const VoidP& other) const { return ptr > other.ptr; }
|
||||||
|
|
||||||
|
bool operator>= (const VoidP& other) const { return ptr >= other.ptr; }
|
||||||
|
|
||||||
|
Str hex() const {
|
||||||
SStream ss;
|
SStream ss;
|
||||||
ss.write_hex(ptr);
|
ss.write_hex(ptr);
|
||||||
return ss.str();
|
return ss.str();
|
||||||
@ -34,11 +36,11 @@ struct VoidP{
|
|||||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define POINTER_VAR(Tp, NAME) \
|
#define POINTER_VAR(Tp, NAME) \
|
||||||
inline PyVar py_var(VM* vm, Tp val){ \
|
inline PyVar py_var(VM* vm, Tp val) { \
|
||||||
const static std::pair<StrName, StrName> P("c", NAME); \
|
const static std::pair<StrName, StrName> P("c", NAME); \
|
||||||
PyVar type = vm->_modules[P.first]->attr(P.second); \
|
PyVar type = vm->_modules[P.first]->attr(P.second); \
|
||||||
return vm->new_object<VoidP>(type->as<Type>(), val); \
|
return vm->new_object<VoidP>(type->as<Type>(), val); \
|
||||||
}
|
}
|
||||||
|
|
||||||
POINTER_VAR(char*, "char_p")
|
POINTER_VAR(char*, "char_p")
|
||||||
@ -58,43 +60,46 @@ POINTER_VAR(const bool*, "bool_p")
|
|||||||
|
|
||||||
#undef POINTER_VAR
|
#undef POINTER_VAR
|
||||||
|
|
||||||
|
struct Struct {
|
||||||
struct Struct{
|
constexpr static int INLINE_SIZE = 24;
|
||||||
static constexpr int INLINE_SIZE = 24;
|
|
||||||
|
|
||||||
char _inlined[INLINE_SIZE];
|
char _inlined[INLINE_SIZE];
|
||||||
char* p;
|
char* p;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
Struct(int new_size, bool zero_init=true){
|
Struct(int new_size, bool zero_init = true) {
|
||||||
this->size = new_size;
|
this->size = new_size;
|
||||||
if(size <= INLINE_SIZE){
|
if(size <= INLINE_SIZE) {
|
||||||
p = _inlined;
|
p = _inlined;
|
||||||
}else{
|
} else {
|
||||||
p = (char*)std::malloc(size);
|
p = (char*)std::malloc(size);
|
||||||
}
|
}
|
||||||
if(zero_init) std::memset(p, 0, size);
|
if(zero_init) std::memset(p, 0, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Struct(void* p, int size): Struct(size, false){
|
Struct(void* p, int size) : Struct(size, false) {
|
||||||
if(p != nullptr) std::memcpy(this->p, p, size);
|
if(p != nullptr) std::memcpy(this->p, p, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Struct(const Struct& other): Struct(other.p, other.size){}
|
Struct(const Struct& other) : Struct(other.p, other.size) {}
|
||||||
~Struct(){ if(p!=_inlined) std::free(p); }
|
|
||||||
|
~Struct() {
|
||||||
|
if(p != _inlined) std::free(p);
|
||||||
|
}
|
||||||
|
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||||
};
|
};
|
||||||
|
|
||||||
/***********************************************/
|
/***********************************************/
|
||||||
template<typename Tp>
|
template <typename Tp>
|
||||||
Tp to_void_p(VM* vm, PyVar var){
|
Tp to_void_p(VM* vm, PyVar var) {
|
||||||
static_assert(std::is_pointer_v<Tp>);
|
static_assert(std::is_pointer_v<Tp>);
|
||||||
if(var == vm->None) return nullptr; // None can be casted to any pointer implicitly
|
if(var == vm->None) return nullptr; // None can be casted to any pointer implicitly
|
||||||
VoidP& p = CAST(VoidP&, var);
|
VoidP& p = CAST(VoidP&, var);
|
||||||
return reinterpret_cast<Tp>(p.ptr);
|
return reinterpret_cast<Tp>(p.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************/
|
/*****************************************************************/
|
||||||
void add_module_c(VM* vm);
|
void add_module_c(VM* vm);
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -2,25 +2,27 @@
|
|||||||
|
|
||||||
#include "pocketpy/objects/codeobject.hpp"
|
#include "pocketpy/objects/codeobject.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
// weak reference fast locals
|
// weak reference fast locals
|
||||||
struct FastLocals{
|
struct FastLocals {
|
||||||
// this is a weak reference
|
// this is a weak reference
|
||||||
const CodeObject* co;
|
const CodeObject* co;
|
||||||
PyVar* a;
|
PyVar* a;
|
||||||
|
|
||||||
int size() const{ return co->nlocals;}
|
int size() const { return co->nlocals; }
|
||||||
|
|
||||||
PyVar& operator[](int i){ return a[i]; }
|
PyVar& operator[] (int i) { return a[i]; }
|
||||||
PyVar operator[](int i) const { return a[i]; }
|
|
||||||
|
|
||||||
FastLocals(const CodeObject* co, PyVar* a): co(co), a(a) {}
|
PyVar operator[] (int i) const { return a[i]; }
|
||||||
|
|
||||||
|
FastLocals(const CodeObject* co, PyVar* a) : co(co), a(a) {}
|
||||||
|
|
||||||
PyVar* try_get_name(StrName name);
|
PyVar* try_get_name(StrName name);
|
||||||
NameDict_ to_namedict();
|
NameDict_ to_namedict();
|
||||||
|
|
||||||
PyVar* begin() const { return a; }
|
PyVar* begin() const { return a; }
|
||||||
|
|
||||||
PyVar* end() const { return a + size(); }
|
PyVar* end() const { return a + size(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -28,49 +30,72 @@ struct ValueStack {
|
|||||||
PK_ALWAYS_PASS_BY_POINTER(ValueStack)
|
PK_ALWAYS_PASS_BY_POINTER(ValueStack)
|
||||||
|
|
||||||
// We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`.
|
// We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`.
|
||||||
PyVar _begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE/128];
|
PyVar _begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE / 128];
|
||||||
PyVar* _sp;
|
PyVar* _sp;
|
||||||
PyVar* _max_end;
|
PyVar* _max_end;
|
||||||
|
|
||||||
static constexpr size_t max_size() { return PK_VM_STACK_SIZE; }
|
constexpr static size_t max_size() { return PK_VM_STACK_SIZE; }
|
||||||
|
|
||||||
ValueStack(): _sp(_begin), _max_end(_begin + PK_VM_STACK_SIZE) {}
|
ValueStack() : _sp(_begin), _max_end(_begin + PK_VM_STACK_SIZE) {}
|
||||||
|
|
||||||
|
PyVar& top() { return _sp[-1]; }
|
||||||
|
|
||||||
PyVar& top(){ return _sp[-1]; }
|
|
||||||
PyVar top() const { return _sp[-1]; }
|
PyVar top() const { return _sp[-1]; }
|
||||||
PyVar& second(){ return _sp[-2]; }
|
|
||||||
|
PyVar& second() { return _sp[-2]; }
|
||||||
|
|
||||||
PyVar second() const { return _sp[-2]; }
|
PyVar second() const { return _sp[-2]; }
|
||||||
PyVar& third(){ return _sp[-3]; }
|
|
||||||
|
PyVar& third() { return _sp[-3]; }
|
||||||
|
|
||||||
PyVar third() const { return _sp[-3]; }
|
PyVar third() const { return _sp[-3]; }
|
||||||
PyVar& peek(int n){ return _sp[-n]; }
|
|
||||||
|
PyVar& peek(int n) { return _sp[-n]; }
|
||||||
|
|
||||||
PyVar peek(int n) const { return _sp[-n]; }
|
PyVar peek(int n) const { return _sp[-n]; }
|
||||||
void push(PyVar v){ *_sp++ = v; }
|
|
||||||
|
void push(PyVar v) { *_sp++ = v; }
|
||||||
|
|
||||||
void push(std::nullptr_t) { std::memset(_sp++, 0, sizeof(PyVar)); }
|
void push(std::nullptr_t) { std::memset(_sp++, 0, sizeof(PyVar)); }
|
||||||
void pop(){ --_sp; }
|
|
||||||
PyVar popx(){ --_sp; return *_sp; }
|
void pop() { --_sp; }
|
||||||
ArgsView view(int n){ return ArgsView(_sp-n, _sp); }
|
|
||||||
void shrink(int n){ _sp -= n; }
|
PyVar popx() {
|
||||||
|
--_sp;
|
||||||
|
return *_sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgsView view(int n) { return ArgsView(_sp - n, _sp); }
|
||||||
|
|
||||||
|
void shrink(int n) { _sp -= n; }
|
||||||
|
|
||||||
int size() const { return _sp - _begin; }
|
int size() const { return _sp - _begin; }
|
||||||
|
|
||||||
bool empty() const { return _sp == _begin; }
|
bool empty() const { return _sp == _begin; }
|
||||||
|
|
||||||
PyVar* begin() { return _begin; }
|
PyVar* begin() { return _begin; }
|
||||||
|
|
||||||
PyVar* end() { return _sp; }
|
PyVar* end() { return _sp; }
|
||||||
|
|
||||||
void reset(PyVar* sp) { _sp = sp; }
|
void reset(PyVar* sp) { _sp = sp; }
|
||||||
|
|
||||||
void clear() { _sp = _begin; }
|
void clear() { _sp = _begin; }
|
||||||
|
|
||||||
bool is_overflow() const { return _sp >= _max_end; }
|
bool is_overflow() const { return _sp >= _max_end; }
|
||||||
|
|
||||||
template<typename... Args>
|
template <typename... Args>
|
||||||
void emplace(Args&&... args){
|
void emplace(Args&&... args) {
|
||||||
new(_sp) PyVar(std::forward<Args>(args)...);
|
new (_sp) PyVar(std::forward<Args>(args)...);
|
||||||
++_sp;
|
++_sp;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UnwindTarget{
|
struct UnwindTarget {
|
||||||
UnwindTarget* next;
|
UnwindTarget* next;
|
||||||
int iblock;
|
int iblock;
|
||||||
int offset;
|
int offset;
|
||||||
|
|
||||||
UnwindTarget(int iblock, int offset): next(nullptr), iblock(iblock), offset(offset) {}
|
UnwindTarget(int iblock, int offset) : next(nullptr), iblock(iblock), offset(offset) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Frame {
|
struct Frame {
|
||||||
@ -82,36 +107,42 @@ struct Frame {
|
|||||||
|
|
||||||
const CodeObject* co;
|
const CodeObject* co;
|
||||||
PyObject* _module;
|
PyObject* _module;
|
||||||
PyObject* _callable; // a function object or nullptr (global scope)
|
PyObject* _callable; // a function object or nullptr (global scope)
|
||||||
FastLocals _locals;
|
FastLocals _locals;
|
||||||
|
|
||||||
// This list will be freed in __pop_frame
|
// This list will be freed in __pop_frame
|
||||||
UnwindTarget* _uw_list;
|
UnwindTarget* _uw_list;
|
||||||
|
|
||||||
NameDict& f_globals() { return _module->attr(); }
|
NameDict& f_globals() { return _module->attr(); }
|
||||||
|
|
||||||
PyVar* f_closure_try_get(StrName name);
|
PyVar* f_closure_try_get(StrName name);
|
||||||
|
|
||||||
int ip() const { return _ip - co->codes.data(); }
|
int ip() const { return _ip - co->codes.data(); }
|
||||||
|
|
||||||
// function scope
|
// function scope
|
||||||
Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, PyVar* _locals_base)
|
Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, PyVar* _locals_base) :
|
||||||
: _ip(co->codes.data()-1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(co, _locals_base), _uw_list(nullptr) { }
|
_ip(co->codes.data() - 1), _sp_base(p0), co(co), _module(_module), _callable(_callable),
|
||||||
|
_locals(co, _locals_base), _uw_list(nullptr) {}
|
||||||
|
|
||||||
// exec/eval
|
// exec/eval
|
||||||
Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, FastLocals _locals)
|
Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, FastLocals _locals) :
|
||||||
: _ip(co->codes.data()-1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals), _uw_list(nullptr) { }
|
_ip(co->codes.data() - 1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals),
|
||||||
|
_uw_list(nullptr) {}
|
||||||
|
|
||||||
// global scope
|
// global scope
|
||||||
Frame(PyVar* p0, const CodeObject_& co, PyObject* _module)
|
Frame(PyVar* p0, const CodeObject_& co, PyObject* _module) :
|
||||||
: _ip(co->codes.data()-1), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr), _locals(co.get(), p0), _uw_list(nullptr) { }
|
_ip(co->codes.data() - 1), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr),
|
||||||
|
_locals(co.get(), p0), _uw_list(nullptr) {}
|
||||||
|
|
||||||
PyVar* actual_sp_base() const { return _locals.a; }
|
PyVar* actual_sp_base() const { return _locals.a; }
|
||||||
|
|
||||||
ArgsView stack_view(ValueStack* _s) const { return ArgsView(actual_sp_base(), _s->_sp); }
|
ArgsView stack_view(ValueStack* _s) const { return ArgsView(actual_sp_base(), _s->_sp); }
|
||||||
|
|
||||||
[[nodiscard]] int prepare_jump_exception_handler(ValueStack*);
|
[[nodiscard]] int prepare_jump_exception_handler(ValueStack*);
|
||||||
void prepare_jump_break(ValueStack*, int);
|
void prepare_jump_break(ValueStack*, int);
|
||||||
int _exit_block(ValueStack*, int);
|
int _exit_block(ValueStack*, int);
|
||||||
|
|
||||||
[[nodiscard]] int prepare_loop_break(ValueStack* s_data){
|
[[nodiscard]] int prepare_loop_break(ValueStack* s_data) {
|
||||||
int target = co->_get_block_codei(ip()).end;
|
int target = co->_get_block_codei(ip()).end;
|
||||||
prepare_jump_break(s_data, target);
|
prepare_jump_break(s_data, target);
|
||||||
return target;
|
return target;
|
||||||
@ -126,29 +157,35 @@ struct Frame {
|
|||||||
~Frame();
|
~Frame();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LinkedFrame{
|
struct LinkedFrame {
|
||||||
LinkedFrame* f_back;
|
LinkedFrame* f_back;
|
||||||
Frame frame;
|
Frame frame;
|
||||||
template<typename... Args>
|
|
||||||
|
template <typename... Args>
|
||||||
LinkedFrame(LinkedFrame* f_back, Args&&... args) : f_back(f_back), frame(std::forward<Args>(args)...) {}
|
LinkedFrame(LinkedFrame* f_back, Args&&... args) : f_back(f_back), frame(std::forward<Args>(args)...) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CallStack {
|
||||||
struct CallStack{
|
|
||||||
static_assert(sizeof(LinkedFrame) <= 128);
|
static_assert(sizeof(LinkedFrame) <= 128);
|
||||||
|
|
||||||
LinkedFrame* _tail;
|
LinkedFrame* _tail;
|
||||||
int _size;
|
int _size;
|
||||||
CallStack(): _tail(nullptr), _size(0) {}
|
|
||||||
|
CallStack() : _tail(nullptr), _size(0) {}
|
||||||
|
|
||||||
int size() const { return _size; }
|
int size() const { return _size; }
|
||||||
bool empty() const { return _size == 0; }
|
|
||||||
void clear(){ while(!empty()) pop(); }
|
|
||||||
|
|
||||||
template<typename... Args>
|
bool empty() const { return _size == 0; }
|
||||||
void emplace(Args&&... args){
|
|
||||||
|
void clear() {
|
||||||
|
while(!empty())
|
||||||
|
pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void emplace(Args&&... args) {
|
||||||
static_assert(sizeof(LinkedFrame) <= kPoolFrameBlockSize);
|
static_assert(sizeof(LinkedFrame) <= kPoolFrameBlockSize);
|
||||||
_tail = new(PoolFrame_alloc()) LinkedFrame(_tail, std::forward<Args>(args)...);
|
_tail = new (PoolFrame_alloc()) LinkedFrame(_tail, std::forward<Args>(args)...);
|
||||||
++_size;
|
++_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,12 +198,13 @@ struct CallStack{
|
|||||||
return _tail->frame;
|
return _tail->frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Func>
|
template <typename Func>
|
||||||
void apply(Func&& f){
|
void apply(Func&& f) {
|
||||||
for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back) f(p->frame);
|
for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back)
|
||||||
|
f(p->frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
~CallStack(){ clear(); }
|
~CallStack() { clear(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace pkpy
|
}; // namespace pkpy
|
||||||
|
|||||||
@ -6,54 +6,52 @@
|
|||||||
#include "pocketpy/objects/object.hpp"
|
#include "pocketpy/objects/object.hpp"
|
||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
struct ManagedHeap{
|
struct ManagedHeap {
|
||||||
vector<PyObject*> _no_gc;
|
vector<PyObject*> _no_gc;
|
||||||
vector<PyObject*> gen;
|
vector<PyObject*> gen;
|
||||||
VM* vm;
|
VM* vm;
|
||||||
void (*_gc_on_delete)(VM*, PyObject*) = nullptr;
|
void (*_gc_on_delete)(VM*, PyObject*) = nullptr;
|
||||||
void (*_gc_marker_ex)(VM*) = nullptr;
|
void (*_gc_marker_ex)(VM*) = nullptr;
|
||||||
|
|
||||||
ManagedHeap(VM* vm): vm(vm) {}
|
ManagedHeap(VM* vm) : vm(vm) {}
|
||||||
|
|
||||||
int gc_threshold = PK_GC_MIN_THRESHOLD;
|
int gc_threshold = PK_GC_MIN_THRESHOLD;
|
||||||
int gc_counter = 0;
|
int gc_counter = 0;
|
||||||
|
|
||||||
/********************/
|
/********************/
|
||||||
int _gc_lock_counter = 0;
|
int _gc_lock_counter = 0;
|
||||||
struct ScopeLock{
|
|
||||||
|
struct ScopeLock {
|
||||||
PK_ALWAYS_PASS_BY_POINTER(ScopeLock)
|
PK_ALWAYS_PASS_BY_POINTER(ScopeLock)
|
||||||
|
|
||||||
ManagedHeap* heap;
|
ManagedHeap* heap;
|
||||||
ScopeLock(ManagedHeap* heap): heap(heap){
|
|
||||||
heap->_gc_lock_counter++;
|
ScopeLock(ManagedHeap* heap) : heap(heap) { heap->_gc_lock_counter++; }
|
||||||
}
|
|
||||||
~ScopeLock(){
|
~ScopeLock() { heap->_gc_lock_counter--; }
|
||||||
heap->_gc_lock_counter--;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ScopeLock gc_scope_lock(){
|
ScopeLock gc_scope_lock() { return ScopeLock(this); }
|
||||||
return ScopeLock(this);
|
|
||||||
}
|
|
||||||
/********************/
|
/********************/
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
PyObject* gcnew(Type type, Args&&... args){
|
PyObject* gcnew(Type type, Args&&... args) {
|
||||||
using __T = std::decay_t<T>;
|
using __T = std::decay_t<T>;
|
||||||
static_assert(!is_sso_v<__T>, "gcnew cannot be used with SSO types");
|
static_assert(!is_sso_v<__T>, "gcnew cannot be used with SSO types");
|
||||||
// https://github.com/pocketpy/pocketpy/issues/94#issuecomment-1594784476
|
// https://github.com/pocketpy/pocketpy/issues/94#issuecomment-1594784476
|
||||||
PyObject* p = new(PoolObject_alloc(py_sizeof<__T>)) PyObject(type);
|
PyObject* p = new (PoolObject_alloc(py_sizeof<__T>)) PyObject(type);
|
||||||
p->placement_new<__T>(std::forward<Args>(args)...);
|
p->placement_new<__T>(std::forward<Args>(args)...);
|
||||||
gen.push_back(p);
|
gen.push_back(p);
|
||||||
gc_counter++;
|
gc_counter++;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
PyObject* _new(Type type, Args&&... args){
|
PyObject* _new(Type type, Args&&... args) {
|
||||||
using __T = std::decay_t<T>;
|
using __T = std::decay_t<T>;
|
||||||
static_assert(!is_sso_v<__T>);
|
static_assert(!is_sso_v<__T>);
|
||||||
PyObject* p = new(PoolObject_alloc(py_sizeof<__T>)) PyObject(type);
|
PyObject* p = new (PoolObject_alloc(py_sizeof<__T>)) PyObject(type);
|
||||||
p->placement_new<__T>(std::forward<Args>(args)...);
|
p->placement_new<__T>(std::forward<Args>(args)...);
|
||||||
_no_gc.push_back(p);
|
_no_gc.push_back(p);
|
||||||
return p;
|
return p;
|
||||||
@ -67,9 +65,11 @@ struct ManagedHeap{
|
|||||||
|
|
||||||
int sweep();
|
int sweep();
|
||||||
void _auto_collect();
|
void _auto_collect();
|
||||||
|
|
||||||
bool _should_auto_collect() const { return gc_counter >= gc_threshold; }
|
bool _should_auto_collect() const { return gc_counter >= gc_threshold; }
|
||||||
|
|
||||||
int collect();
|
int collect();
|
||||||
void mark();
|
void mark();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -2,51 +2,57 @@
|
|||||||
|
|
||||||
#include "pocketpy/interpreter/bindings.hpp"
|
#include "pocketpy/interpreter/bindings.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
struct RangeIter{ // step > 0
|
struct RangeIter { // step > 0
|
||||||
Range r;
|
Range r;
|
||||||
i64 current;
|
i64 current;
|
||||||
|
|
||||||
RangeIter(Range r) : r(r), current(r.start) {}
|
RangeIter(Range r) : r(r), current(r.start) {}
|
||||||
|
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RangeIterR{ // step < 0
|
struct RangeIterR { // step < 0
|
||||||
Range r;
|
Range r;
|
||||||
i64 current;
|
i64 current;
|
||||||
|
|
||||||
RangeIterR(Range r) : r(r), current(r.start) {}
|
RangeIterR(Range r) : r(r), current(r.start) {}
|
||||||
|
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ArrayIter{
|
struct ArrayIter {
|
||||||
PyObject* ref;
|
PyObject* ref;
|
||||||
PyVar* end;
|
PyVar* end;
|
||||||
PyVar* current;
|
PyVar* current;
|
||||||
|
|
||||||
ArrayIter(PyObject* ref, PyVar* begin, PyVar* end)
|
ArrayIter(PyObject* ref, PyVar* begin, PyVar* end) : ref(ref), end(end), current(begin) {}
|
||||||
: ref(ref), end(end), current(begin) {}
|
|
||||||
|
void _gc_mark(VM* vm) const { vm->__obj_gc_mark(ref); }
|
||||||
|
|
||||||
void _gc_mark(VM* vm) const{ vm->__obj_gc_mark(ref); }
|
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StringIter{
|
struct StringIter {
|
||||||
PyVar ref;
|
PyVar ref;
|
||||||
int i; // byte index
|
int i; // byte index
|
||||||
|
|
||||||
StringIter(PyVar ref) : ref(ref), i(0) {}
|
StringIter(PyVar ref) : ref(ref), i(0) {}
|
||||||
void _gc_mark(VM* vm) const{ vm->obj_gc_mark(ref); }
|
|
||||||
|
void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
|
||||||
|
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Generator{
|
struct Generator {
|
||||||
LinkedFrame* lf;
|
LinkedFrame* lf;
|
||||||
int state; // 0,1,2
|
int state; // 0,1,2
|
||||||
List s_backup;
|
List s_backup;
|
||||||
|
|
||||||
Generator(LinkedFrame* lf, ArgsView buffer): lf(lf), state(0) {
|
Generator(LinkedFrame* lf, ArgsView buffer) : lf(lf), state(0) {
|
||||||
for(PyVar obj: buffer) s_backup.push_back(obj);
|
for(PyVar obj: buffer)
|
||||||
|
s_backup.push_back(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _gc_mark(VM* vm) {
|
void _gc_mark(VM* vm) {
|
||||||
@ -58,22 +64,23 @@ struct Generator{
|
|||||||
PyVar next(VM* vm);
|
PyVar next(VM* vm);
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||||
|
|
||||||
~Generator(){
|
~Generator() {
|
||||||
if(lf){
|
if(lf) {
|
||||||
lf->~LinkedFrame();
|
lf->~LinkedFrame();
|
||||||
PoolFrame_dealloc(lf);
|
PoolFrame_dealloc(lf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DictItemsIter{
|
struct DictItemsIter {
|
||||||
PyVar ref;
|
PyVar ref;
|
||||||
int i;
|
int i;
|
||||||
DictItemsIter(PyVar ref) : ref(ref) {
|
|
||||||
i = PK_OBJ_GET(Dict, ref)._head_idx;
|
DictItemsIter(PyVar ref) : ref(ref) { i = PK_OBJ_GET(Dict, ref)._head_idx; }
|
||||||
}
|
|
||||||
void _gc_mark(VM* vm) const{ vm->obj_gc_mark(ref); }
|
void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
|
||||||
|
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -6,23 +6,24 @@
|
|||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
struct _LineRecord{
|
struct _LineRecord {
|
||||||
int line;
|
int line;
|
||||||
i64 hits;
|
i64 hits;
|
||||||
clock_t time;
|
clock_t time;
|
||||||
|
|
||||||
_LineRecord(): line(-1), hits(0), time(0) {}
|
_LineRecord() : line(-1), hits(0), time(0) {}
|
||||||
|
|
||||||
bool is_valid() const { return line != -1; }
|
bool is_valid() const { return line != -1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _FrameRecord{
|
struct _FrameRecord {
|
||||||
int callstack_size;
|
int callstack_size;
|
||||||
Frame* frame;
|
Frame* frame;
|
||||||
clock_t prev_time;
|
clock_t prev_time;
|
||||||
_LineRecord* prev_record;
|
_LineRecord* prev_record;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LineProfiler{
|
struct LineProfiler {
|
||||||
// filename -> records
|
// filename -> records
|
||||||
std::map<std::string_view, vector<_LineRecord>> records;
|
std::map<std::string_view, vector<_LineRecord>> records;
|
||||||
stack_no_copy<_FrameRecord> frames;
|
stack_no_copy<_FrameRecord> frames;
|
||||||
@ -35,4 +36,4 @@ struct LineProfiler{
|
|||||||
Str stats();
|
Str stats();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -11,65 +11,74 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
/* Stack manipulation macros */
|
/* Stack manipulation macros */
|
||||||
// https://github.com/python/cpython/blob/3.9/Python/ceval.c#L1123
|
// https://github.com/python/cpython/blob/3.9/Python/ceval.c#L1123
|
||||||
#define TOP() (s_data.top())
|
#define TOP() (s_data.top())
|
||||||
#define SECOND() (s_data.second())
|
#define SECOND() (s_data.second())
|
||||||
#define THIRD() (s_data.third())
|
#define THIRD() (s_data.third())
|
||||||
#define STACK_SHRINK(n) (s_data.shrink(n))
|
#define STACK_SHRINK(n) (s_data.shrink(n))
|
||||||
#define PUSH(v) (s_data.push(v))
|
#define PUSH(v) (s_data.push(v))
|
||||||
#define POP() (s_data.pop())
|
#define POP() (s_data.pop())
|
||||||
#define POPX() (s_data.popx())
|
#define POPX() (s_data.popx())
|
||||||
#define STACK_VIEW(n) (s_data.view(n))
|
#define STACK_VIEW(n) (s_data.view(n))
|
||||||
|
|
||||||
typedef PyVar (*BinaryFuncC)(VM*, PyVar, PyVar);
|
typedef PyVar (*BinaryFuncC)(VM*, PyVar, PyVar);
|
||||||
typedef void (*RegisterFunc)(VM*, PyObject*, PyObject*);
|
typedef void (*RegisterFunc)(VM*, PyObject*, PyObject*);
|
||||||
|
|
||||||
#if PK_ENABLE_PROFILER
|
#if PK_ENABLE_PROFILER
|
||||||
struct NextBreakpoint{
|
struct NextBreakpoint {
|
||||||
int callstack_size;
|
int callstack_size;
|
||||||
int lineno;
|
int lineno;
|
||||||
bool should_step_into;
|
bool should_step_into;
|
||||||
NextBreakpoint(): callstack_size(0) {}
|
|
||||||
NextBreakpoint(int callstack_size, int lineno, bool should_step_into): callstack_size(callstack_size), lineno(lineno), should_step_into(should_step_into) {}
|
NextBreakpoint() : callstack_size(0) {}
|
||||||
|
|
||||||
|
NextBreakpoint(int callstack_size, int lineno, bool should_step_into) :
|
||||||
|
callstack_size(callstack_size), lineno(lineno), should_step_into(should_step_into) {}
|
||||||
|
|
||||||
void _step(VM* vm);
|
void _step(VM* vm);
|
||||||
|
|
||||||
bool empty() const { return callstack_size == 0; }
|
bool empty() const { return callstack_size == 0; }
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct PyTypeInfo{
|
struct PyTypeInfo {
|
||||||
struct Vt{
|
struct Vt {
|
||||||
void (*_dtor)(void*);
|
void (*_dtor)(void*);
|
||||||
void (*_gc_mark)(void*, VM*);
|
void (*_gc_mark)(void*, VM*);
|
||||||
|
|
||||||
Vt(): _dtor(nullptr), _gc_mark(nullptr) {}
|
Vt() : _dtor(nullptr), _gc_mark(nullptr) {}
|
||||||
|
|
||||||
operator bool() const { return _dtor || _gc_mark; }
|
operator bool () const { return _dtor || _gc_mark; }
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
inline static Vt get(){
|
inline static Vt get() {
|
||||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||||
Vt vt;
|
Vt vt;
|
||||||
if constexpr(!std::is_trivially_destructible_v<T>){
|
if constexpr(!std::is_trivially_destructible_v<T>) {
|
||||||
vt._dtor = [](void* p){ ((T*)p)->~T(); };
|
vt._dtor = [](void* p) {
|
||||||
|
((T*)p)->~T();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if constexpr(has_gc_marker<T>::value){
|
if constexpr(has_gc_marker<T>::value) {
|
||||||
vt._gc_mark = [](void* p, VM* vm){ ((T*)p)->_gc_mark(vm); };
|
vt._gc_mark = [](void* p, VM* vm) {
|
||||||
|
((T*)p)->_gc_mark(vm);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return vt;
|
return vt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PyObject* obj; // never be garbage collected
|
PyObject* obj; // never be garbage collected
|
||||||
Type base;
|
Type base;
|
||||||
PyObject* mod; // never be garbage collected
|
PyObject* mod; // never be garbage collected
|
||||||
StrName name;
|
StrName name;
|
||||||
bool subclass_enabled;
|
bool subclass_enabled;
|
||||||
Vt vt;
|
Vt vt;
|
||||||
|
|
||||||
PyTypeInfo(PyObject* obj, Type base, PyObject* mod, StrName name, bool subclass_enabled, Vt vt={}):
|
PyTypeInfo(PyObject* obj, Type base, PyObject* mod, StrName name, bool subclass_enabled, Vt vt = {}) :
|
||||||
obj(obj), base(base), mod(mod), name(name), subclass_enabled(subclass_enabled), vt(vt) {}
|
obj(obj), base(base), mod(mod), name(name), subclass_enabled(subclass_enabled), vt(vt) {}
|
||||||
|
|
||||||
vector<StrName> annotated_fields = {};
|
vector<StrName> annotated_fields = {};
|
||||||
@ -122,52 +131,53 @@ struct PyTypeInfo{
|
|||||||
void (*on_end_subclass)(VM* vm, PyTypeInfo*) = nullptr;
|
void (*on_end_subclass)(VM* vm, PyTypeInfo*) = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ImportContext{
|
struct ImportContext {
|
||||||
PK_ALWAYS_PASS_BY_POINTER(ImportContext)
|
PK_ALWAYS_PASS_BY_POINTER(ImportContext)
|
||||||
|
|
||||||
vector<Str> pending;
|
vector<Str> pending;
|
||||||
vector<bool> pending_is_init; // a.k.a __init__.py
|
vector<bool> pending_is_init; // a.k.a __init__.py
|
||||||
|
|
||||||
ImportContext() {}
|
ImportContext() {}
|
||||||
|
|
||||||
struct Temp{
|
struct Temp {
|
||||||
PK_ALWAYS_PASS_BY_POINTER(Temp)
|
PK_ALWAYS_PASS_BY_POINTER(Temp)
|
||||||
|
|
||||||
ImportContext* ctx;
|
ImportContext* ctx;
|
||||||
Temp(ImportContext* ctx, Str name, bool is_init) : ctx(ctx){
|
|
||||||
|
Temp(ImportContext* ctx, Str name, bool is_init) : ctx(ctx) {
|
||||||
ctx->pending.push_back(name);
|
ctx->pending.push_back(name);
|
||||||
ctx->pending_is_init.push_back(is_init);
|
ctx->pending_is_init.push_back(is_init);
|
||||||
}
|
}
|
||||||
~Temp(){
|
|
||||||
|
~Temp() {
|
||||||
ctx->pending.pop_back();
|
ctx->pending.pop_back();
|
||||||
ctx->pending_is_init.pop_back();
|
ctx->pending_is_init.pop_back();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Temp scope(Str name, bool is_init){
|
Temp scope(Str name, bool is_init) { return {this, name, is_init}; }
|
||||||
return {this, name, is_init};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class VM {
|
class VM {
|
||||||
PK_ALWAYS_PASS_BY_POINTER(VM)
|
PK_ALWAYS_PASS_BY_POINTER(VM)
|
||||||
|
|
||||||
VM* vm; // self reference to simplify code
|
VM* vm; // self reference to simplify code
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ManagedHeap heap;
|
ManagedHeap heap;
|
||||||
ValueStack s_data;
|
ValueStack s_data;
|
||||||
CallStack callstack;
|
CallStack callstack;
|
||||||
vector<PyTypeInfo> _all_types;
|
vector<PyTypeInfo> _all_types;
|
||||||
|
|
||||||
NameDict _modules; // loaded modules
|
NameDict _modules; // loaded modules
|
||||||
std::map<StrName, Str> _lazy_modules; // lazy loaded modules
|
std::map<StrName, Str> _lazy_modules; // lazy loaded modules
|
||||||
|
|
||||||
struct{
|
struct {
|
||||||
PyObject* error;
|
PyObject* error;
|
||||||
stack_no_copy<ArgsView> s_view;
|
stack_no_copy<ArgsView> s_view;
|
||||||
} __c;
|
} __c;
|
||||||
|
|
||||||
PyVar StopIteration; // a special Exception class
|
PyVar StopIteration; // a special Exception class
|
||||||
PyObject* builtins;
|
PyObject* builtins;
|
||||||
PyObject* _main;
|
PyObject* _main;
|
||||||
|
|
||||||
@ -191,34 +201,36 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void (*_ceval_on_step)(VM*, Frame*, Bytecode bc);
|
void (*_ceval_on_step)(VM*, Frame*, Bytecode bc);
|
||||||
void(*_stdout)(const char*, int);
|
void (*_stdout)(const char*, int);
|
||||||
void(*_stderr)(const char*, int);
|
void (*_stderr)(const char*, int);
|
||||||
unsigned char* (*_import_handler)(const char*, int*);
|
unsigned char* (*_import_handler)(const char*, int*);
|
||||||
// function<void(const char*, int)> _stdout;
|
// function<void(const char*, int)> _stdout;
|
||||||
// function<void(const char*, int)> _stderr;
|
// function<void(const char*, int)> _stderr;
|
||||||
// function<unsigned char*(const char*, int*)> _import_handler;
|
// function<unsigned char*(const char*, int*)> _import_handler;
|
||||||
|
|
||||||
// for quick access
|
// for quick access
|
||||||
static constexpr Type tp_object=Type(1), tp_type=Type(2);
|
constexpr static Type tp_object = Type(1), tp_type = Type(2);
|
||||||
static constexpr Type tp_int=Type(kTpIntIndex), tp_float=Type(kTpFloatIndex), tp_bool=Type(5), tp_str=Type(6);
|
constexpr static Type tp_int = Type(kTpIntIndex), tp_float = Type(kTpFloatIndex), tp_bool = Type(5),
|
||||||
static constexpr Type tp_list=Type(7), tp_tuple=Type(8);
|
tp_str = Type(6);
|
||||||
static constexpr Type tp_slice=Type(9), tp_range=Type(10), tp_module=Type(11);
|
constexpr static Type tp_list = Type(7), tp_tuple = Type(8);
|
||||||
static constexpr Type tp_function=Type(12), tp_native_func=Type(13), tp_bound_method=Type(14);
|
constexpr static Type tp_slice = Type(9), tp_range = Type(10), tp_module = Type(11);
|
||||||
static constexpr Type tp_super=Type(15), tp_exception=Type(16), tp_bytes=Type(17), tp_mappingproxy=Type(18);
|
constexpr static Type tp_function = Type(12), tp_native_func = Type(13), tp_bound_method = Type(14);
|
||||||
static constexpr Type tp_dict=Type(19), tp_property=Type(20), tp_star_wrapper=Type(21);
|
constexpr static Type tp_super = Type(15), tp_exception = Type(16), tp_bytes = Type(17), tp_mappingproxy = Type(18);
|
||||||
static constexpr Type tp_staticmethod=Type(22), tp_classmethod=Type(23);
|
constexpr static Type tp_dict = Type(19), tp_property = Type(20), tp_star_wrapper = Type(21);
|
||||||
static constexpr Type tp_none_type=Type(24), tp_not_implemented=Type(25), tp_ellipsis=Type(26);
|
constexpr static Type tp_staticmethod = Type(22), tp_classmethod = Type(23);
|
||||||
static constexpr Type tp_stack_memory=Type(kTpStackMemoryIndex);
|
constexpr static Type tp_none_type = Type(24), tp_not_implemented = Type(25), tp_ellipsis = Type(26);
|
||||||
|
constexpr static Type tp_stack_memory = Type(kTpStackMemoryIndex);
|
||||||
|
|
||||||
static constexpr PyVar True{const_sso_var(), tp_bool, 1};
|
constexpr static PyVar True{const_sso_var(), tp_bool, 1};
|
||||||
static constexpr PyVar False{const_sso_var(), tp_bool, 0};
|
constexpr static PyVar False{const_sso_var(), tp_bool, 0};
|
||||||
static constexpr PyVar None{const_sso_var(), tp_none_type, 0};
|
constexpr static PyVar None{const_sso_var(), tp_none_type, 0};
|
||||||
static constexpr PyVar NotImplemented{const_sso_var(), tp_not_implemented, 0};
|
constexpr static PyVar NotImplemented{const_sso_var(), tp_not_implemented, 0};
|
||||||
static constexpr PyVar Ellipsis{const_sso_var(), tp_ellipsis, 0};
|
constexpr static PyVar Ellipsis{const_sso_var(), tp_ellipsis, 0};
|
||||||
|
|
||||||
const bool enable_os;
|
const bool enable_os;
|
||||||
VM(bool enable_os=true);
|
VM(bool enable_os = true);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
#if PK_REGION("Python Equivalents")
|
#if PK_REGION("Python Equivalents")
|
||||||
Str py_str(PyVar obj); // x -> str(x)
|
Str py_str(PyVar obj); // x -> str(x)
|
||||||
Str py_repr(PyVar obj); // x -> repr(x)
|
Str py_repr(PyVar obj); // x -> repr(x)
|
||||||
@ -453,18 +465,19 @@ public:
|
|||||||
vm->s_data.emplace(p->type, p);
|
vm->s_data.emplace(p->type, p);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
Type _find_type_in_cxx_typeid_map(){
|
Type _find_type_in_cxx_typeid_map() {
|
||||||
auto it = _cxx_typeid_map.find(typeid(T));
|
auto it = _cxx_typeid_map.find(typeid(T));
|
||||||
if(it == _cxx_typeid_map.end()){
|
if(it == _cxx_typeid_map.end()) {
|
||||||
#if __GNUC__ || __clang__
|
#if __GNUC__ || __clang__
|
||||||
throw std::runtime_error(__PRETTY_FUNCTION__ + std::string(" failed: T not found"));
|
throw std::runtime_error(__PRETTY_FUNCTION__ + std::string(" failed: T not found"));
|
||||||
#elif _MSC_VER
|
#elif _MSC_VER
|
||||||
throw std::runtime_error(__FUNCSIG__ + std::string(" failed: T not found"));
|
throw std::runtime_error(__FUNCSIG__ + std::string(" failed: T not found"));
|
||||||
#else
|
#else
|
||||||
throw std::runtime_error("_find_type_in_cxx_typeid_map() failed: T not found");
|
throw std::runtime_error("_find_type_in_cxx_typeid_map() failed: T not found");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
@ -485,17 +498,35 @@ public:
|
|||||||
void __prepare_py_call(PyVar*, ArgsView, ArgsView, const FuncDecl_&);
|
void __prepare_py_call(PyVar*, ArgsView, ArgsView, const FuncDecl_&);
|
||||||
void __unpack_as_list(ArgsView args, List& list);
|
void __unpack_as_list(ArgsView args, List& list);
|
||||||
void __unpack_as_dict(ArgsView args, Dict& dict);
|
void __unpack_as_dict(ArgsView args, Dict& dict);
|
||||||
[[noreturn]] void __raise_exc(bool re_raise=false);
|
[[noreturn]] void __raise_exc(bool re_raise = false);
|
||||||
[[noreturn]] void __builtin_error(StrName type);
|
[[noreturn]] void __builtin_error(StrName type);
|
||||||
[[noreturn]] void __builtin_error(StrName type, PyVar arg);
|
[[noreturn]] void __builtin_error(StrName type, PyVar arg);
|
||||||
[[noreturn]] void __builtin_error(StrName type, const Str& msg);
|
[[noreturn]] void __builtin_error(StrName type, const Str& msg);
|
||||||
void __init_builtin_types();
|
void __init_builtin_types();
|
||||||
void __post_init_builtin_types();
|
void __post_init_builtin_types();
|
||||||
void __push_varargs(){}
|
|
||||||
void __push_varargs(PyVar _0){ PUSH(_0); }
|
void __push_varargs() {}
|
||||||
void __push_varargs(PyVar _0, PyVar _1){ PUSH(_0); PUSH(_1); }
|
|
||||||
void __push_varargs(PyVar _0, PyVar _1, PyVar _2){ PUSH(_0); PUSH(_1); PUSH(_2); }
|
void __push_varargs(PyVar _0) { PUSH(_0); }
|
||||||
void __push_varargs(PyVar _0, PyVar _1, PyVar _2, PyVar _3){ PUSH(_0); PUSH(_1); PUSH(_2); PUSH(_3); }
|
|
||||||
|
void __push_varargs(PyVar _0, PyVar _1) {
|
||||||
|
PUSH(_0);
|
||||||
|
PUSH(_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __push_varargs(PyVar _0, PyVar _1, PyVar _2) {
|
||||||
|
PUSH(_0);
|
||||||
|
PUSH(_1);
|
||||||
|
PUSH(_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __push_varargs(PyVar _0, PyVar _1, PyVar _2, PyVar _3) {
|
||||||
|
PUSH(_0);
|
||||||
|
PUSH(_1);
|
||||||
|
PUSH(_2);
|
||||||
|
PUSH(_3);
|
||||||
|
}
|
||||||
|
|
||||||
PyVar __pack_next_retval(unsigned);
|
PyVar __pack_next_retval(unsigned);
|
||||||
PyVar __minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key);
|
PyVar __minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key);
|
||||||
bool __py_bool_non_trivial(PyVar);
|
bool __py_bool_non_trivial(PyVar);
|
||||||
@ -504,128 +535,201 @@ public:
|
|||||||
void* __stack_alloc(int size);
|
void* __stack_alloc(int size);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr inline bool is_immutable_v =
|
||||||
|
is_integral_v<T> || is_floating_point_v<T> || std::is_same_v<T, Str> || std::is_same_v<T, Tuple> ||
|
||||||
|
std::is_same_v<T, Bytes> || std::is_same_v<T, bool> || std::is_same_v<T, Range> || std::is_same_v<T, Slice> ||
|
||||||
|
std::is_pointer_v<T> || std::is_enum_v<T>;
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
inline constexpr bool is_immutable_v = is_integral_v<T> || is_floating_point_v<T>
|
constexpr Type _find_type_in_const_cxx_typeid_map() {
|
||||||
|| std::is_same_v<T, Str> || std::is_same_v<T, Tuple> || std::is_same_v<T, Bytes> || std::is_same_v<T, bool>
|
return Type();
|
||||||
|| std::is_same_v<T, Range> || std::is_same_v<T, Slice>
|
}
|
||||||
|| std::is_pointer_v<T> || std::is_enum_v<T>;
|
|
||||||
|
|
||||||
template<typename T> constexpr Type _find_type_in_const_cxx_typeid_map(){ return Type(); }
|
template <>
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Str>(){ return VM::tp_str; }
|
constexpr Type _find_type_in_const_cxx_typeid_map<Str>() {
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<List>(){ return VM::tp_list; }
|
return VM::tp_str;
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Tuple>(){ return VM::tp_tuple; }
|
}
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Function>(){ return VM::tp_function; }
|
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<NativeFunc>(){ return VM::tp_native_func; }
|
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<BoundMethod>(){ return VM::tp_bound_method; }
|
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Range>(){ return VM::tp_range; }
|
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Slice>(){ return VM::tp_slice; }
|
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Exception>(){ return VM::tp_exception; }
|
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Bytes>(){ return VM::tp_bytes; }
|
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<MappingProxy>(){ return VM::tp_mappingproxy; }
|
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Dict>(){ return VM::tp_dict; }
|
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Property>(){ return VM::tp_property; }
|
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<StarWrapper>(){ return VM::tp_star_wrapper; }
|
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<StaticMethod>(){ return VM::tp_staticmethod; }
|
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<ClassMethod>(){ return VM::tp_classmethod; }
|
|
||||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<StackMemory>(){ return VM::tp_stack_memory; }
|
|
||||||
|
|
||||||
template<typename __T>
|
template <>
|
||||||
PyVar py_var(VM* vm, __T&& value){
|
constexpr Type _find_type_in_const_cxx_typeid_map<List>() {
|
||||||
|
return VM::tp_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<Tuple>() {
|
||||||
|
return VM::tp_tuple;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<Function>() {
|
||||||
|
return VM::tp_function;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<NativeFunc>() {
|
||||||
|
return VM::tp_native_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<BoundMethod>() {
|
||||||
|
return VM::tp_bound_method;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<Range>() {
|
||||||
|
return VM::tp_range;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<Slice>() {
|
||||||
|
return VM::tp_slice;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<Exception>() {
|
||||||
|
return VM::tp_exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<Bytes>() {
|
||||||
|
return VM::tp_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<MappingProxy>() {
|
||||||
|
return VM::tp_mappingproxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<Dict>() {
|
||||||
|
return VM::tp_dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<Property>() {
|
||||||
|
return VM::tp_property;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<StarWrapper>() {
|
||||||
|
return VM::tp_star_wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<StaticMethod>() {
|
||||||
|
return VM::tp_staticmethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<ClassMethod>() {
|
||||||
|
return VM::tp_classmethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr Type _find_type_in_const_cxx_typeid_map<StackMemory>() {
|
||||||
|
return VM::tp_stack_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename __T>
|
||||||
|
PyVar py_var(VM* vm, __T&& value) {
|
||||||
using T = std::decay_t<__T>;
|
using T = std::decay_t<__T>;
|
||||||
|
|
||||||
static_assert(!std::is_same_v<T, PyVar>, "py_var(VM*, PyVar) is not allowed");
|
static_assert(!std::is_same_v<T, PyVar>, "py_var(VM*, PyVar) is not allowed");
|
||||||
|
|
||||||
if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>){
|
if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, std::string> ||
|
||||||
|
std::is_same_v<T, std::string_view>) {
|
||||||
// str (shortcuts)
|
// str (shortcuts)
|
||||||
return VAR(Str(std::forward<__T>(value)));
|
return VAR(Str(std::forward<__T>(value)));
|
||||||
}else if constexpr(std::is_same_v<T, NoReturn>){
|
} else if constexpr(std::is_same_v<T, NoReturn>) {
|
||||||
// NoneType
|
// NoneType
|
||||||
return vm->None;
|
return vm->None;
|
||||||
}else if constexpr(std::is_same_v<T, bool>){
|
} else if constexpr(std::is_same_v<T, bool>) {
|
||||||
// bool
|
// bool
|
||||||
return value ? vm->True : vm->False;
|
return value ? vm->True : vm->False;
|
||||||
}else if constexpr(is_integral_v<T>){
|
} else if constexpr(is_integral_v<T>) {
|
||||||
// int
|
// int
|
||||||
return PyVar(VM::tp_int, static_cast<i64>(value));
|
return PyVar(VM::tp_int, static_cast<i64>(value));
|
||||||
}else if constexpr(is_floating_point_v<T>){
|
} else if constexpr(is_floating_point_v<T>) {
|
||||||
// float
|
// float
|
||||||
return PyVar(VM::tp_float, static_cast<f64>(value));
|
return PyVar(VM::tp_float, static_cast<f64>(value));
|
||||||
}else if constexpr(std::is_pointer_v<T>){
|
} else if constexpr(std::is_pointer_v<T>) {
|
||||||
return from_void_p(vm, (void*)value);
|
return from_void_p(vm, (void*)value);
|
||||||
}else{
|
} else {
|
||||||
constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
|
constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
|
||||||
if constexpr((bool)const_type){
|
if constexpr((bool)const_type) {
|
||||||
if constexpr(is_sso_v<T>) return PyVar(const_type, value);
|
if constexpr(is_sso_v<T>)
|
||||||
else return vm->heap.gcnew<T>(const_type, std::forward<__T>(value));
|
return PyVar(const_type, value);
|
||||||
}else{
|
else
|
||||||
|
return vm->heap.gcnew<T>(const_type, std::forward<__T>(value));
|
||||||
|
} else {
|
||||||
Type type = vm->_find_type_in_cxx_typeid_map<T>();
|
Type type = vm->_find_type_in_cxx_typeid_map<T>();
|
||||||
if constexpr(is_sso_v<T>) return PyVar(type, value);
|
if constexpr(is_sso_v<T>)
|
||||||
else return vm->heap.gcnew<T>(type, std::forward<__T>(value));
|
return PyVar(type, value);
|
||||||
|
else
|
||||||
|
return vm->heap.gcnew<T>(type, std::forward<__T>(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fast path for bool if py_var<> cannot be inlined
|
// fast path for bool if py_var<> cannot be inlined
|
||||||
inline PyVar py_var(VM* vm, bool value){
|
inline PyVar py_var(VM* vm, bool value) { return value ? vm->True : vm->False; }
|
||||||
return value ? vm->True : vm->False;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename __T, bool with_check>
|
template <typename __T, bool with_check>
|
||||||
__T _py_cast__internal(VM* vm, PyVar obj) {
|
__T _py_cast__internal(VM* vm, PyVar obj) {
|
||||||
static_assert(!std::is_rvalue_reference_v<__T>, "rvalue reference is not allowed");
|
static_assert(!std::is_rvalue_reference_v<__T>, "rvalue reference is not allowed");
|
||||||
using T = std::decay_t<__T>;
|
using T = std::decay_t<__T>;
|
||||||
static_assert(!(is_sso_v<T> && std::is_reference_v<__T>), "SSO types cannot be reference");
|
static_assert(!(is_sso_v<T> && std::is_reference_v<__T>), "SSO types cannot be reference");
|
||||||
|
|
||||||
if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, CString>){
|
if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, CString>) {
|
||||||
static_assert(!std::is_reference_v<__T>);
|
static_assert(!std::is_reference_v<__T>);
|
||||||
// str (shortcuts)
|
// str (shortcuts)
|
||||||
if(obj == vm->None) return nullptr;
|
if(obj == vm->None) return nullptr;
|
||||||
if constexpr(with_check) vm->check_type(obj, vm->tp_str);
|
if constexpr(with_check) vm->check_type(obj, vm->tp_str);
|
||||||
return PK_OBJ_GET(Str, obj).c_str();
|
return PK_OBJ_GET(Str, obj).c_str();
|
||||||
}else if constexpr(std::is_same_v<T, bool>){
|
} else if constexpr(std::is_same_v<T, bool>) {
|
||||||
static_assert(!std::is_reference_v<__T>);
|
static_assert(!std::is_reference_v<__T>);
|
||||||
// bool
|
// bool
|
||||||
if constexpr(with_check){
|
if constexpr(with_check) {
|
||||||
if(obj == vm->True) return true;
|
if(obj == vm->True) return true;
|
||||||
if(obj == vm->False) return false;
|
if(obj == vm->False) return false;
|
||||||
vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
|
vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||||
}
|
}
|
||||||
return obj == vm->True;
|
return obj == vm->True;
|
||||||
}else if constexpr(is_integral_v<T>){
|
} else if constexpr(is_integral_v<T>) {
|
||||||
static_assert(!std::is_reference_v<__T>);
|
static_assert(!std::is_reference_v<__T>);
|
||||||
// int
|
// int
|
||||||
if constexpr(with_check){
|
if constexpr(with_check) {
|
||||||
if(is_int(obj)) return (T)obj.as<i64>();
|
if(is_int(obj)) return (T)obj.as<i64>();
|
||||||
vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
|
vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||||
}
|
}
|
||||||
return (T)obj.as<i64>();
|
return (T)obj.as<i64>();
|
||||||
}else if constexpr(is_floating_point_v<T>){
|
} else if constexpr(is_floating_point_v<T>) {
|
||||||
static_assert(!std::is_reference_v<__T>);
|
static_assert(!std::is_reference_v<__T>);
|
||||||
if(is_float(obj)) return (T)obj.as<f64>();
|
if(is_float(obj)) return (T)obj.as<f64>();
|
||||||
if(is_int(obj)) return (T)obj.as<i64>();
|
if(is_int(obj)) return (T)obj.as<i64>();
|
||||||
vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape());
|
vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}else if constexpr(std::is_enum_v<T>){
|
} else if constexpr(std::is_enum_v<T>) {
|
||||||
static_assert(!std::is_reference_v<__T>);
|
static_assert(!std::is_reference_v<__T>);
|
||||||
return (__T)_py_cast__internal<i64, with_check>(vm, obj);
|
return (__T)_py_cast__internal<i64, with_check>(vm, obj);
|
||||||
}else if constexpr(std::is_pointer_v<T>){
|
} else if constexpr(std::is_pointer_v<T>) {
|
||||||
static_assert(!std::is_reference_v<__T>);
|
static_assert(!std::is_reference_v<__T>);
|
||||||
return to_void_p<T>(vm, obj);
|
return to_void_p<T>(vm, obj);
|
||||||
}else{
|
} else {
|
||||||
constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
|
constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
|
||||||
if constexpr((bool)const_type){
|
if constexpr((bool)const_type) {
|
||||||
if constexpr(with_check){
|
if constexpr(with_check) {
|
||||||
if constexpr(std::is_same_v<T, Exception>){
|
if constexpr(std::is_same_v<T, Exception>) {
|
||||||
// Exception is `subclass_enabled`
|
// Exception is `subclass_enabled`
|
||||||
vm->check_compatible_type(obj, const_type);
|
vm->check_compatible_type(obj, const_type);
|
||||||
}else{
|
} else {
|
||||||
vm->check_type(obj, const_type);
|
vm->check_type(obj, const_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return PK_OBJ_GET(T, obj);
|
return PK_OBJ_GET(T, obj);
|
||||||
}else{
|
} else {
|
||||||
if constexpr(with_check){
|
if constexpr(with_check) {
|
||||||
Type type = vm->_find_type_in_cxx_typeid_map<T>();
|
Type type = vm->_find_type_in_cxx_typeid_map<T>();
|
||||||
vm->check_compatible_type(obj, type);
|
vm->check_compatible_type(obj, type);
|
||||||
}
|
}
|
||||||
@ -634,25 +738,31 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename __T>
|
template <typename __T>
|
||||||
__T py_cast(VM* vm, PyVar obj) { return _py_cast__internal<__T, true>(vm, obj); }
|
__T py_cast(VM* vm, PyVar obj) {
|
||||||
template<typename __T>
|
return _py_cast__internal<__T, true>(vm, obj);
|
||||||
__T _py_cast(VM* vm, PyVar obj) { return _py_cast__internal<__T, false>(vm, obj); }
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename __T>
|
||||||
PyObject* VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _register, Type base, bool subclass_enabled){
|
__T _py_cast(VM* vm, PyVar obj) {
|
||||||
|
return _py_cast__internal<__T, false>(vm, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
PyObject*
|
||||||
|
VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _register, Type base, bool subclass_enabled) {
|
||||||
PyObject* type = new_type_object(mod, name, base, subclass_enabled, PyTypeInfo::Vt::get<T>());
|
PyObject* type = new_type_object(mod, name, base, subclass_enabled, PyTypeInfo::Vt::get<T>());
|
||||||
mod->attr().set(name, type);
|
mod->attr().set(name, type);
|
||||||
_cxx_typeid_map[typeid(T)] = type->as<Type>();
|
_cxx_typeid_map[typeid(T)] = type->as<Type>();
|
||||||
_register(this, mod, type);
|
_register(this, mod, type);
|
||||||
if(!type->attr().contains(__new__)){
|
if(!type->attr().contains(__new__)) {
|
||||||
if constexpr(std::is_default_constructible_v<T>) {
|
if constexpr(std::is_default_constructible_v<T>) {
|
||||||
bind_func(type, __new__, -1, [](VM* vm, ArgsView args){
|
bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
|
||||||
Type cls_t = args[0]->as<Type>();
|
Type cls_t = args[0]->as<Type>();
|
||||||
return vm->new_object<T>(cls_t);
|
return vm->new_object<T>(cls_t);
|
||||||
});
|
});
|
||||||
}else{
|
} else {
|
||||||
bind_func(type, __new__, -1, [](VM* vm, ArgsView args){
|
bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
|
||||||
vm->NotImplementedError();
|
vm->NotImplementedError();
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
@ -661,9 +771,9 @@ PyObject* VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _reg
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
PyObject* VM::register_user_class(PyObject* mod, StrName name, Type base, bool subclass_enabled){
|
PyObject* VM::register_user_class(PyObject* mod, StrName name, Type base, bool subclass_enabled) {
|
||||||
return register_user_class<T>(mod, name, &T::_register, base, subclass_enabled);
|
return register_user_class<T>(mod, name, &T::_register, base, subclass_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -6,4 +6,4 @@ namespace pkpy {
|
|||||||
|
|
||||||
void add_module_array2d(VM* vm);
|
void add_module_array2d(VM* vm);
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -6,4 +6,4 @@ namespace pkpy {
|
|||||||
|
|
||||||
void add_module_base64(VM* vm);
|
void add_module_base64(VM* vm);
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -6,4 +6,4 @@ namespace pkpy {
|
|||||||
|
|
||||||
void add_module_csv(VM* vm);
|
void add_module_csv(VM* vm);
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
#include "pocketpy/common/types.hpp"
|
#include "pocketpy/common/types.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
void add_module_dataclasses(VM* vm);
|
void add_module_dataclasses(VM* vm);
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
#include "pocketpy/common/types.hpp"
|
#include "pocketpy/common/types.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
void add_module_easing(VM* vm);
|
void add_module_easing(VM* vm);
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
#include "pocketpy/common/types.hpp"
|
#include "pocketpy/common/types.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
unsigned char* _default_import_handler(const char*, int*);
|
unsigned char* _default_import_handler(const char*, int*);
|
||||||
void add_module_os(VM* vm);
|
void add_module_os(VM* vm);
|
||||||
void add_module_io(VM* vm);
|
void add_module_io(VM* vm);
|
||||||
}
|
} // namespace pkpy
|
||||||
|
|||||||
@ -5,90 +5,167 @@
|
|||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
inline bool isclose(float a, float b){ return std::fabs(a - b) < 1e-4; }
|
inline bool isclose(float a, float b) { return std::fabs(a - b) < 1e-4; }
|
||||||
|
|
||||||
struct Vec2{
|
struct Vec2 {
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||||
|
|
||||||
float x, y;
|
float x, y;
|
||||||
|
|
||||||
Vec2() : x(0.0f), y(0.0f) {}
|
Vec2() : x(0.0f), y(0.0f) {}
|
||||||
|
|
||||||
Vec2(float x, float y) : x(x), y(y) {}
|
Vec2(float x, float y) : x(x), y(y) {}
|
||||||
|
|
||||||
Vec2 operator+(const Vec2& v) const { return Vec2(x + v.x, y + v.y); }
|
Vec2 operator+ (const Vec2& v) const { return Vec2(x + v.x, y + v.y); }
|
||||||
Vec2 operator-(const Vec2& v) const { return Vec2(x - v.x, y - v.y); }
|
|
||||||
Vec2 operator*(float s) const { return Vec2(x * s, y * s); }
|
Vec2 operator- (const Vec2& v) const { return Vec2(x - v.x, y - v.y); }
|
||||||
Vec2 operator*(const Vec2& v) const { return Vec2(x * v.x, y * v.y); }
|
|
||||||
Vec2 operator/(float s) const { return Vec2(x / s, y / s); }
|
Vec2 operator* (float s) const { return Vec2(x * s, y * s); }
|
||||||
Vec2 operator-() const { return Vec2(-x, -y); }
|
|
||||||
bool operator==(const Vec2& v) const { return isclose(x, v.x) && isclose(y, v.y); }
|
Vec2 operator* (const Vec2& v) const { return Vec2(x * v.x, y * v.y); }
|
||||||
bool operator!=(const Vec2& v) const { return !isclose(x, v.x) || !isclose(y, v.y); }
|
|
||||||
float operator[](int i) const { return (&x)[i]; }
|
Vec2 operator/ (float s) const { return Vec2(x / s, y / s); }
|
||||||
|
|
||||||
|
Vec2 operator- () const { return Vec2(-x, -y); }
|
||||||
|
|
||||||
|
bool operator== (const Vec2& v) const { return isclose(x, v.x) && isclose(y, v.y); }
|
||||||
|
|
||||||
|
bool operator!= (const Vec2& v) const { return !isclose(x, v.x) || !isclose(y, v.y); }
|
||||||
|
|
||||||
|
float operator[] (int i) const { return (&x)[i]; }
|
||||||
|
|
||||||
float dot(const Vec2& v) const { return x * v.x + y * v.y; }
|
float dot(const Vec2& v) const { return x * v.x + y * v.y; }
|
||||||
|
|
||||||
float cross(const Vec2& v) const { return x * v.y - y * v.x; }
|
float cross(const Vec2& v) const { return x * v.y - y * v.x; }
|
||||||
|
|
||||||
float length() const { return sqrtf(x * x + y * y); }
|
float length() const { return sqrtf(x * x + y * y); }
|
||||||
|
|
||||||
float length_squared() const { return x * x + y * y; }
|
float length_squared() const { return x * x + y * y; }
|
||||||
Vec2 normalize() const { float l = length(); return Vec2(x / l, y / l); }
|
|
||||||
Vec2 rotate(float radian) const { float cr = cosf(radian), sr = sinf(radian); return Vec2(x * cr - y * sr, x * sr + y * cr); }
|
Vec2 normalize() const {
|
||||||
|
float l = length();
|
||||||
|
return Vec2(x / l, y / l);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 rotate(float radian) const {
|
||||||
|
float cr = cosf(radian), sr = sinf(radian);
|
||||||
|
return Vec2(x * cr - y * sr, x * sr + y * cr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Vec3{
|
struct Vec3 {
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||||
|
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
|
|
||||||
Vec3() : x(0.0f), y(0.0f), z(0.0f) {}
|
Vec3() : x(0.0f), y(0.0f), z(0.0f) {}
|
||||||
|
|
||||||
Vec3(float x, float y, float z) : x(x), y(y), z(z) {}
|
Vec3(float x, float y, float z) : x(x), y(y), z(z) {}
|
||||||
|
|
||||||
Vec3 operator+(const Vec3& v) const { return Vec3(x + v.x, y + v.y, z + v.z); }
|
Vec3 operator+ (const Vec3& v) const { return Vec3(x + v.x, y + v.y, z + v.z); }
|
||||||
Vec3 operator-(const Vec3& v) const { return Vec3(x - v.x, y - v.y, z - v.z); }
|
|
||||||
Vec3 operator*(float s) const { return Vec3(x * s, y * s, z * s); }
|
Vec3 operator- (const Vec3& v) const { return Vec3(x - v.x, y - v.y, z - v.z); }
|
||||||
Vec3 operator*(const Vec3& v) const { return Vec3(x * v.x, y * v.y, z * v.z); }
|
|
||||||
Vec3 operator/(float s) const { return Vec3(x / s, y / s, z / s); }
|
Vec3 operator* (float s) const { return Vec3(x * s, y * s, z * s); }
|
||||||
Vec3 operator-() const { return Vec3(-x, -y, -z); }
|
|
||||||
bool operator==(const Vec3& v) const { return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z); }
|
Vec3 operator* (const Vec3& v) const { return Vec3(x * v.x, y * v.y, z * v.z); }
|
||||||
bool operator!=(const Vec3& v) const { return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z); }
|
|
||||||
float operator[](int i) const { return (&x)[i]; }
|
Vec3 operator/ (float s) const { return Vec3(x / s, y / s, z / s); }
|
||||||
|
|
||||||
|
Vec3 operator- () const { return Vec3(-x, -y, -z); }
|
||||||
|
|
||||||
|
bool operator== (const Vec3& v) const { return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z); }
|
||||||
|
|
||||||
|
bool operator!= (const Vec3& v) const { return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z); }
|
||||||
|
|
||||||
|
float operator[] (int i) const { return (&x)[i]; }
|
||||||
|
|
||||||
float dot(const Vec3& v) const { return x * v.x + y * v.y + z * v.z; }
|
float dot(const Vec3& v) const { return x * v.x + y * v.y + z * v.z; }
|
||||||
|
|
||||||
Vec3 cross(const Vec3& v) const { return Vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); }
|
Vec3 cross(const Vec3& v) const { return Vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); }
|
||||||
|
|
||||||
float length() const { return sqrtf(x * x + y * y + z * z); }
|
float length() const { return sqrtf(x * x + y * y + z * z); }
|
||||||
|
|
||||||
float length_squared() const { return x * x + y * y + z * z; }
|
float length_squared() const { return x * x + y * y + z * z; }
|
||||||
Vec3 normalize() const { float l = length(); return Vec3(x / l, y / l, z / l); }
|
|
||||||
|
Vec3 normalize() const {
|
||||||
|
float l = length();
|
||||||
|
return Vec3(x / l, y / l, z / l);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Vec4{
|
struct Vec4 {
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||||
|
|
||||||
float x, y, z, w;
|
float x, y, z, w;
|
||||||
|
|
||||||
Vec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) {}
|
Vec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) {}
|
||||||
|
|
||||||
Vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
|
Vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
|
||||||
|
|
||||||
Vec4 operator+(const Vec4& v) const { return Vec4(x + v.x, y + v.y, z + v.z, w + v.w); }
|
Vec4 operator+ (const Vec4& v) const { return Vec4(x + v.x, y + v.y, z + v.z, w + v.w); }
|
||||||
Vec4 operator-(const Vec4& v) const { return Vec4(x - v.x, y - v.y, z - v.z, w - v.w); }
|
|
||||||
Vec4 operator*(float s) const { return Vec4(x * s, y * s, z * s, w * s); }
|
Vec4 operator- (const Vec4& v) const { return Vec4(x - v.x, y - v.y, z - v.z, w - v.w); }
|
||||||
Vec4 operator*(const Vec4& v) const { return Vec4(x * v.x, y * v.y, z * v.z, w * v.w); }
|
|
||||||
Vec4 operator/(float s) const { return Vec4(x / s, y / s, z / s, w / s); }
|
Vec4 operator* (float s) const { return Vec4(x * s, y * s, z * s, w * s); }
|
||||||
Vec4 operator-() const { return Vec4(-x, -y, -z, -w); }
|
|
||||||
bool operator==(const Vec4& v) const { return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z) && isclose(w, v.w); }
|
Vec4 operator* (const Vec4& v) const { return Vec4(x * v.x, y * v.y, z * v.z, w * v.w); }
|
||||||
bool operator!=(const Vec4& v) const { return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z) || !isclose(w, v.w); }
|
|
||||||
float operator[](int i) const { return (&x)[i]; }
|
Vec4 operator/ (float s) const { return Vec4(x / s, y / s, z / s, w / s); }
|
||||||
|
|
||||||
|
Vec4 operator- () const { return Vec4(-x, -y, -z, -w); }
|
||||||
|
|
||||||
|
bool operator== (const Vec4& v) const {
|
||||||
|
return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z) && isclose(w, v.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!= (const Vec4& v) const {
|
||||||
|
return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z) || !isclose(w, v.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
float operator[] (int i) const { return (&x)[i]; }
|
||||||
|
|
||||||
float dot(const Vec4& v) const { return x * v.x + y * v.y + z * v.z + w * v.w; }
|
float dot(const Vec4& v) const { return x * v.x + y * v.y + z * v.z + w * v.w; }
|
||||||
|
|
||||||
float length() const { return sqrtf(x * x + y * y + z * z + w * w); }
|
float length() const { return sqrtf(x * x + y * y + z * z + w * w); }
|
||||||
|
|
||||||
float length_squared() const { return x * x + y * y + z * z + w * w; }
|
float length_squared() const { return x * x + y * y + z * z + w * w; }
|
||||||
Vec4 normalize() const { float l = length(); return Vec4(x / l, y / l, z / l, w / l); }
|
|
||||||
NoReturn normalize_() { float l = length(); x /= l; y /= l; z /= l; w /= l; return {}; }
|
Vec4 normalize() const {
|
||||||
NoReturn copy_(const Vec4& v) { x = v.x; y = v.y; z = v.z; w = v.w; return {}; }
|
float l = length();
|
||||||
|
return Vec4(x / l, y / l, z / l, w / l);
|
||||||
|
}
|
||||||
|
|
||||||
|
NoReturn normalize_() {
|
||||||
|
float l = length();
|
||||||
|
x /= l;
|
||||||
|
y /= l;
|
||||||
|
z /= l;
|
||||||
|
w /= l;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
NoReturn copy_(const Vec4& v) {
|
||||||
|
x = v.x;
|
||||||
|
y = v.y;
|
||||||
|
z = v.z;
|
||||||
|
w = v.w;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Mat3x3{
|
struct Mat3x3 {
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
float _11, _12, _13;
|
float _11, _12, _13;
|
||||||
float _21, _22, _23;
|
float _21, _22, _23;
|
||||||
float _31, _32, _33;
|
float _31, _32, _33;
|
||||||
};
|
};
|
||||||
|
|
||||||
float m[3][3];
|
float m[3][3];
|
||||||
float v[9];
|
float v[9];
|
||||||
};
|
};
|
||||||
@ -100,13 +177,13 @@ struct Mat3x3{
|
|||||||
static Mat3x3 ones();
|
static Mat3x3 ones();
|
||||||
static Mat3x3 identity();
|
static Mat3x3 identity();
|
||||||
|
|
||||||
Mat3x3 operator+(const Mat3x3& other) const;
|
Mat3x3 operator+ (const Mat3x3& other) const;
|
||||||
Mat3x3 operator-(const Mat3x3& other) const;
|
Mat3x3 operator- (const Mat3x3& other) const;
|
||||||
Mat3x3 operator*(float scalar) const;
|
Mat3x3 operator* (float scalar) const;
|
||||||
Mat3x3 operator/(float scalar) const;
|
Mat3x3 operator/ (float scalar) const;
|
||||||
|
|
||||||
bool operator==(const Mat3x3& other) const;
|
bool operator== (const Mat3x3& other) const;
|
||||||
bool operator!=(const Mat3x3& other) const;
|
bool operator!= (const Mat3x3& other) const;
|
||||||
|
|
||||||
Mat3x3 matmul(const Mat3x3& other) const;
|
Mat3x3 matmul(const Mat3x3& other) const;
|
||||||
Vec3 matmul(const Vec3& other) const;
|
Vec3 matmul(const Vec3& other) const;
|
||||||
@ -130,9 +207,9 @@ static_assert(is_pod_v<Vec3>);
|
|||||||
static_assert(is_pod_v<Vec4>);
|
static_assert(is_pod_v<Vec4>);
|
||||||
static_assert(is_pod_v<Mat3x3>);
|
static_assert(is_pod_v<Mat3x3>);
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
inline constexpr bool is_sso_v<Vec2> = true;
|
constexpr inline bool is_sso_v<Vec2> = true;
|
||||||
template<>
|
template <>
|
||||||
inline constexpr bool is_sso_v<Vec3> = true;
|
constexpr inline bool is_sso_v<Vec3> = true;
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "pocketpy/common/types.hpp"
|
#include "pocketpy/common/types.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
void add_module_time(VM* vm);
|
void add_module_time(VM* vm);
|
||||||
void add_module_sys(VM* vm);
|
void add_module_sys(VM* vm);
|
||||||
@ -15,4 +15,4 @@ void add_module_line_profiler(VM* vm);
|
|||||||
void add_module_enum(VM* vm);
|
void add_module_enum(VM* vm);
|
||||||
void add_module___builtins(VM* vm);
|
void add_module___builtins(VM* vm);
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
#include "pocketpy/common/types.hpp"
|
#include "pocketpy/common/types.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
void add_module_random(VM* vm);
|
void add_module_random(VM* vm);
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -8,25 +8,31 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
struct Type {
|
struct Type {
|
||||||
int16_t index;
|
int16_t index;
|
||||||
constexpr Type(): index(0) {}
|
|
||||||
explicit constexpr Type(int index): index(index) {}
|
constexpr Type() : index(0) {}
|
||||||
bool operator==(Type other) const { return this->index == other.index; }
|
|
||||||
bool operator!=(Type other) const { return this->index != other.index; }
|
explicit constexpr Type(int index) : index(index) {}
|
||||||
constexpr operator int() const { return index; }
|
|
||||||
|
bool operator== (Type other) const { return this->index == other.index; }
|
||||||
|
|
||||||
|
bool operator!= (Type other) const { return this->index != other.index; }
|
||||||
|
|
||||||
|
constexpr operator int () const { return index; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct const_sso_var {};
|
struct const_sso_var {};
|
||||||
|
|
||||||
struct PyVar final{
|
struct PyVar final {
|
||||||
Type type;
|
Type type;
|
||||||
bool is_ptr;
|
bool is_ptr;
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
// 12 bytes SSO
|
// 12 bytes SSO
|
||||||
int _0; i64 _1;
|
int _0;
|
||||||
|
i64 _1;
|
||||||
|
|
||||||
// uninitialized
|
// uninitialized
|
||||||
PyVar() = default;
|
PyVar() = default;
|
||||||
@ -36,45 +42,50 @@ struct PyVar final{
|
|||||||
|
|
||||||
/* We must initialize all members to allow == operator to work correctly */
|
/* We must initialize all members to allow == operator to work correctly */
|
||||||
// constexpr initialized
|
// constexpr initialized
|
||||||
constexpr PyVar(const const_sso_var&, Type type, int value): type(type), is_ptr(false), flags(0), _0(value), _1(0) {}
|
constexpr PyVar(const const_sso_var&, Type type, int value) :
|
||||||
|
type(type), is_ptr(false), flags(0), _0(value), _1(0) {}
|
||||||
|
|
||||||
// zero initialized
|
// zero initialized
|
||||||
constexpr PyVar(std::nullptr_t): type(0), is_ptr(false), flags(0), _0(0), _1(0) {}
|
constexpr PyVar(std::nullptr_t) : type(0), is_ptr(false), flags(0), _0(0), _1(0) {}
|
||||||
|
|
||||||
// PyObject* initialized (is_sso = false)
|
// PyObject* initialized (is_sso = false)
|
||||||
PyVar(Type type, PyObject* p): type(type), is_ptr(true), flags(0), _0(0), _1(reinterpret_cast<i64>(p)) {}
|
PyVar(Type type, PyObject* p) : type(type), is_ptr(true), flags(0), _0(0), _1(reinterpret_cast<i64>(p)) {}
|
||||||
|
|
||||||
// SSO initialized (is_sso = true)
|
// SSO initialized (is_sso = true)
|
||||||
template<typename T>
|
template <typename T>
|
||||||
PyVar(Type type, T value): type(type), is_ptr(false), flags(0), _0(0), _1(0) {
|
PyVar(Type type, T value) : type(type), is_ptr(false), flags(0), _0(0), _1(0) {
|
||||||
static_assert(sizeof(T) <= 12, "SSO size exceeded");
|
static_assert(sizeof(T) <= 12, "SSO size exceeded");
|
||||||
as<T>() = value;
|
as<T>() = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
T& as(){
|
T& as() {
|
||||||
static_assert(!std::is_reference_v<T>);
|
static_assert(!std::is_reference_v<T>);
|
||||||
if constexpr(sizeof(T) <= 8){
|
if constexpr(sizeof(T) <= 8) {
|
||||||
return reinterpret_cast<T&>(_1);
|
return reinterpret_cast<T&>(_1);
|
||||||
}else{
|
} else {
|
||||||
return reinterpret_cast<T&>(_0);
|
return reinterpret_cast<T&>(_0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit operator bool() const { return (bool)type; }
|
explicit operator bool () const { return (bool)type; }
|
||||||
|
|
||||||
void set_null() { _qword(0) = 0; _qword(1) = 0; }
|
void set_null() {
|
||||||
|
_qword(0) = 0;
|
||||||
|
_qword(1) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
i64 _qword(int i) const { return ((const i64*)this)[i]; }
|
i64 _qword(int i) const { return ((const i64*)this)[i]; }
|
||||||
|
|
||||||
i64& _qword(int i) { return ((i64*)this)[i]; }
|
i64& _qword(int i) { return ((i64*)this)[i]; }
|
||||||
|
|
||||||
bool operator==(const PyVar& other) const {
|
bool operator== (const PyVar& other) const { return _qword(0) == other._qword(0) && _qword(1) == other._qword(1); }
|
||||||
return _qword(0) == other._qword(0) && _qword(1) == other._qword(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const PyVar& other) const {
|
bool operator!= (const PyVar& other) const { return _qword(0) != other._qword(0) || _qword(1) != other._qword(1); }
|
||||||
return _qword(0) != other._qword(0) || _qword(1) != other._qword(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(std::nullptr_t) const { return !(bool)type; }
|
bool operator== (std::nullptr_t) const { return !(bool)type; }
|
||||||
bool operator!=(std::nullptr_t) const { return (bool)type; }
|
|
||||||
|
bool operator!= (std::nullptr_t) const { return (bool)type; }
|
||||||
|
|
||||||
PyObject* get() const {
|
PyObject* get() const {
|
||||||
assert(is_ptr);
|
assert(is_ptr);
|
||||||
@ -88,14 +99,12 @@ struct PyVar final{
|
|||||||
|
|
||||||
i64 hash() const { return _0 + _1; }
|
i64 hash() const { return _0 + _1; }
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
obj_get_t<T> obj_get();
|
obj_get_t<T> obj_get();
|
||||||
|
|
||||||
// for std::map<>
|
// for std::map<>
|
||||||
bool operator<(const PyVar& other) const {
|
bool operator< (const PyVar& other) const { return memcmp(this, &other, sizeof(PyVar)) < 0; }
|
||||||
return memcmp(this, &other, sizeof(PyVar)) < 0;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(PyVar) == 16 && is_pod_v<PyVar>);
|
static_assert(sizeof(PyVar) == 16 && is_pod_v<PyVar>);
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -3,31 +3,39 @@
|
|||||||
#include "pocketpy/common/vector.hpp"
|
#include "pocketpy/common/vector.hpp"
|
||||||
#include "pocketpy/objects/object.hpp"
|
#include "pocketpy/objects/object.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
struct BoundMethod {
|
struct BoundMethod {
|
||||||
PyVar self;
|
PyVar self;
|
||||||
PyVar func;
|
PyVar func;
|
||||||
|
|
||||||
BoundMethod(PyVar self, PyVar func) : self(self), func(func) {}
|
BoundMethod(PyVar self, PyVar func) : self(self), func(func) {}
|
||||||
|
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StaticMethod{
|
struct StaticMethod {
|
||||||
PyVar func;
|
PyVar func;
|
||||||
|
|
||||||
StaticMethod(PyVar func) : func(func) {}
|
StaticMethod(PyVar func) : func(func) {}
|
||||||
|
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ClassMethod{
|
struct ClassMethod {
|
||||||
PyVar func;
|
PyVar func;
|
||||||
|
|
||||||
ClassMethod(PyVar func) : func(func) {}
|
ClassMethod(PyVar func) : func(func) {}
|
||||||
|
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Property{
|
struct Property {
|
||||||
PyVar getter;
|
PyVar getter;
|
||||||
PyVar setter;
|
PyVar setter;
|
||||||
|
|
||||||
Property(PyVar getter, PyVar setter) : getter(getter), setter(setter) {}
|
Property(PyVar getter, PyVar setter) : getter(getter), setter(setter) {}
|
||||||
|
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -37,20 +45,23 @@ struct Range {
|
|||||||
i64 step = 1;
|
i64 step = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct StarWrapper {
|
||||||
struct StarWrapper{
|
int level; // either 1 or 2
|
||||||
int level; // either 1 or 2
|
|
||||||
PyVar obj;
|
PyVar obj;
|
||||||
|
|
||||||
StarWrapper(int level, PyVar obj) : level(level), obj(obj) {}
|
StarWrapper(int level, PyVar obj) : level(level), obj(obj) {}
|
||||||
|
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Bytes = array<unsigned char>;
|
using Bytes = array<unsigned char>;
|
||||||
|
|
||||||
struct Super{
|
struct Super {
|
||||||
PyVar first;
|
PyVar first;
|
||||||
Type second;
|
Type second;
|
||||||
|
|
||||||
Super(PyVar first, Type second) : first(first), second(second) {}
|
Super(PyVar first, Type second) : first(first), second(second) {}
|
||||||
|
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -58,16 +69,19 @@ struct Slice {
|
|||||||
PyVar start;
|
PyVar start;
|
||||||
PyVar stop;
|
PyVar stop;
|
||||||
PyVar step;
|
PyVar step;
|
||||||
|
|
||||||
Slice(PyVar start, PyVar stop, PyVar step) : start(start), stop(stop), step(step) {}
|
Slice(PyVar start, PyVar stop, PyVar step) : start(start), stop(stop), step(step) {}
|
||||||
|
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const inline int kTpIntIndex = 3;
|
||||||
inline const int kTpIntIndex = 3;
|
const inline int kTpFloatIndex = 4;
|
||||||
inline const int kTpFloatIndex = 4;
|
|
||||||
|
|
||||||
inline bool is_tagged(PyVar p) noexcept { return !p.is_ptr; }
|
inline bool is_tagged(PyVar p) noexcept { return !p.is_ptr; }
|
||||||
|
|
||||||
inline bool is_float(PyVar p) noexcept { return p.type.index == kTpFloatIndex; }
|
inline bool is_float(PyVar p) noexcept { return p.type.index == kTpFloatIndex; }
|
||||||
|
|
||||||
inline bool is_int(PyVar p) noexcept { return p.type.index == kTpIntIndex; }
|
inline bool is_int(PyVar p) noexcept { return p.type.index == kTpIntIndex; }
|
||||||
|
|
||||||
inline bool is_type(PyVar obj, Type type) {
|
inline bool is_type(PyVar obj, Type type) {
|
||||||
@ -80,23 +94,26 @@ inline bool is_type(PyObject* p, Type type) {
|
|||||||
return p->type == type;
|
return p->type == type;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MappingProxy{
|
struct MappingProxy {
|
||||||
PyObject* obj;
|
PyObject* obj;
|
||||||
|
|
||||||
MappingProxy(PyObject* obj) : obj(obj) {}
|
MappingProxy(PyObject* obj) : obj(obj) {}
|
||||||
|
|
||||||
NameDict& attr() { return obj->attr(); }
|
NameDict& attr() { return obj->attr(); }
|
||||||
|
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
StrName _type_name(VM* vm, Type type);
|
StrName _type_name(VM* vm, Type type);
|
||||||
template<typename T> T to_void_p(VM*, PyVar);
|
template <typename T>
|
||||||
|
T to_void_p(VM*, PyVar);
|
||||||
PyVar from_void_p(VM*, void*);
|
PyVar from_void_p(VM*, void*);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
template<typename T>
|
obj_get_t<T> PyVar::obj_get() {
|
||||||
obj_get_t<T> PyVar::obj_get(){
|
if constexpr(is_sso_v<T>) {
|
||||||
if constexpr(is_sso_v<T>){
|
|
||||||
return as<T>();
|
return as<T>();
|
||||||
}else{
|
} else {
|
||||||
assert(is_ptr);
|
assert(is_ptr);
|
||||||
void* v = ((PyObject*)_1)->_value_ptr();
|
void* v = ((PyObject*)_1)->_value_ptr();
|
||||||
return *reinterpret_cast<T*>(v);
|
return *reinterpret_cast<T*>(v);
|
||||||
@ -119,6 +136,6 @@ obj_get_t<T> PyVar::obj_get(){
|
|||||||
|
|
||||||
#define PY_NULL nullptr
|
#define PY_NULL nullptr
|
||||||
extern PyVar const PY_OP_CALL;
|
extern PyVar const PY_OP_CALL;
|
||||||
extern PyVar const PY_OP_YIELD;
|
extern const PyVar PY_OP_YIELD;
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
#include "pocketpy/objects/object.hpp"
|
#include "pocketpy/objects/object.hpp"
|
||||||
#include "pocketpy/objects/sourcedata.hpp"
|
#include "pocketpy/objects/sourcedata.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
#if PK_ENABLE_STD_FUNCTION
|
#if PK_ENABLE_STD_FUNCTION
|
||||||
using NativeFuncC = function<PyVar(VM*, ArgsView)>;
|
using NativeFuncC = function<PyVar(VM*, ArgsView)>;
|
||||||
@ -13,7 +13,7 @@ using NativeFuncC = function<PyVar(VM*, ArgsView)>;
|
|||||||
typedef PyVar (*NativeFuncC)(VM*, ArgsView);
|
typedef PyVar (*NativeFuncC)(VM*, ArgsView);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum class BindType{
|
enum class BindType {
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
STATICMETHOD,
|
STATICMETHOD,
|
||||||
CLASSMETHOD,
|
CLASSMETHOD,
|
||||||
@ -21,24 +21,23 @@ enum class BindType{
|
|||||||
|
|
||||||
enum NameScope { NAME_LOCAL, NAME_GLOBAL, NAME_GLOBAL_UNKNOWN };
|
enum NameScope { NAME_LOCAL, NAME_GLOBAL, NAME_GLOBAL_UNKNOWN };
|
||||||
|
|
||||||
enum Opcode: uint8_t {
|
enum Opcode : uint8_t {
|
||||||
#define OPCODE(name) OP_##name,
|
|
||||||
#include "pocketpy/opcodes.h"
|
#define OPCODE(name) OP_##name,
|
||||||
#undef OPCODE
|
#include "pocketpy/opcodes.h"
|
||||||
|
#undef OPCODE
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Bytecode{
|
struct Bytecode {
|
||||||
uint8_t op;
|
uint8_t op;
|
||||||
uint16_t arg;
|
uint16_t arg;
|
||||||
|
|
||||||
void set_signed_arg(int arg){
|
void set_signed_arg(int arg) {
|
||||||
assert(arg >= INT16_MIN && arg <= INT16_MAX);
|
assert(arg >= INT16_MIN && arg <= INT16_MAX);
|
||||||
this->arg = (int16_t)arg;
|
this->arg = (int16_t)arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_forward_jump() const{
|
bool is_forward_jump() const { return op >= OP_JUMP_FORWARD && op <= OP_LOOP_BREAK; }
|
||||||
return op >= OP_JUMP_FORWARD && op <= OP_LOOP_BREAK;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class CodeBlockType {
|
enum class CodeBlockType {
|
||||||
@ -49,20 +48,20 @@ enum class CodeBlockType {
|
|||||||
TRY_EXCEPT,
|
TRY_EXCEPT,
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const uint8_t BC_NOARG = 0;
|
const inline uint8_t BC_NOARG = 0;
|
||||||
inline const int BC_KEEPLINE = -1;
|
const inline int BC_KEEPLINE = -1;
|
||||||
|
|
||||||
struct CodeBlock {
|
struct CodeBlock {
|
||||||
CodeBlockType type;
|
CodeBlockType type;
|
||||||
int parent; // parent index in blocks
|
int parent; // parent index in blocks
|
||||||
int start; // start index of this block in codes, inclusive
|
int start; // start index of this block in codes, inclusive
|
||||||
int end; // end index of this block in codes, exclusive
|
int end; // end index of this block in codes, exclusive
|
||||||
int end2; // ...
|
int end2; // ...
|
||||||
|
|
||||||
CodeBlock(CodeBlockType type, int parent, int start):
|
CodeBlock(CodeBlockType type, int parent, int start) :
|
||||||
type(type), parent(parent), start(start), end(-1), end2(-1) {}
|
type(type), parent(parent), start(start), end(-1), end2(-1) {}
|
||||||
|
|
||||||
int get_break_end() const{
|
int get_break_end() const {
|
||||||
if(end2 != -1) return end2;
|
if(end2 != -1) return end2;
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
@ -74,10 +73,10 @@ using CodeObject_ = std::shared_ptr<CodeObject>;
|
|||||||
using FuncDecl_ = std::shared_ptr<FuncDecl>;
|
using FuncDecl_ = std::shared_ptr<FuncDecl>;
|
||||||
|
|
||||||
struct CodeObject {
|
struct CodeObject {
|
||||||
struct LineInfo{
|
struct LineInfo {
|
||||||
int lineno; // line number for each bytecode
|
int lineno; // line number for each bytecode
|
||||||
bool is_virtual; // whether this bytecode is virtual (not in source code)
|
bool is_virtual; // whether this bytecode is virtual (not in source code)
|
||||||
int iblock; // block index
|
int iblock; // block index
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<SourceData> src;
|
std::shared_ptr<SourceData> src;
|
||||||
@ -86,9 +85,9 @@ struct CodeObject {
|
|||||||
vector<Bytecode> codes;
|
vector<Bytecode> codes;
|
||||||
vector<LineInfo> lines;
|
vector<LineInfo> lines;
|
||||||
|
|
||||||
small_vector_2<PyVar, 8> consts; // constants
|
small_vector_2<PyVar, 8> consts; // constants
|
||||||
small_vector_2<StrName, 8> varnames; // local variables
|
small_vector_2<StrName, 8> varnames; // local variables
|
||||||
int nlocals; // varnames.size()
|
int nlocals; // varnames.size()
|
||||||
|
|
||||||
NameDictInt varnames_inv;
|
NameDictInt varnames_inv;
|
||||||
vector<CodeBlock> blocks;
|
vector<CodeBlock> blocks;
|
||||||
@ -98,15 +97,13 @@ struct CodeObject {
|
|||||||
int start_line;
|
int start_line;
|
||||||
int end_line;
|
int end_line;
|
||||||
|
|
||||||
const CodeBlock& _get_block_codei(int codei) const{
|
const CodeBlock& _get_block_codei(int codei) const { return blocks[lines[codei].iblock]; }
|
||||||
return blocks[lines[codei].iblock];
|
|
||||||
}
|
|
||||||
|
|
||||||
CodeObject(std::shared_ptr<SourceData> src, const Str& name);
|
CodeObject(std::shared_ptr<SourceData> src, const Str& name);
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class FuncType{
|
enum class FuncType {
|
||||||
UNSET,
|
UNSET,
|
||||||
NORMAL,
|
NORMAL,
|
||||||
SIMPLE,
|
SIMPLE,
|
||||||
@ -116,26 +113,27 @@ enum class FuncType{
|
|||||||
|
|
||||||
struct FuncDecl {
|
struct FuncDecl {
|
||||||
struct KwArg {
|
struct KwArg {
|
||||||
int index; // index in co->varnames
|
int index; // index in co->varnames
|
||||||
StrName key; // name of this argument
|
StrName key; // name of this argument
|
||||||
PyVar value; // default value
|
PyVar value; // default value
|
||||||
};
|
};
|
||||||
CodeObject_ code; // code object of this function
|
|
||||||
|
CodeObject_ code; // code object of this function
|
||||||
|
|
||||||
small_vector_2<int, 6> args; // indices in co->varnames
|
small_vector_2<int, 6> args; // indices in co->varnames
|
||||||
small_vector_2<KwArg, 6> kwargs; // indices in co->varnames
|
small_vector_2<KwArg, 6> kwargs; // indices in co->varnames
|
||||||
|
|
||||||
int starred_arg = -1; // index in co->varnames, -1 if no *arg
|
int starred_arg = -1; // index in co->varnames, -1 if no *arg
|
||||||
int starred_kwarg = -1; // index in co->varnames, -1 if no **kwarg
|
int starred_kwarg = -1; // index in co->varnames, -1 if no **kwarg
|
||||||
bool nested = false; // whether this function is nested
|
bool nested = false; // whether this function is nested
|
||||||
|
|
||||||
const char* docstring; // docstring of this function (weak ref)
|
const char* docstring; // docstring of this function (weak ref)
|
||||||
|
|
||||||
FuncType type = FuncType::UNSET;
|
FuncType type = FuncType::UNSET;
|
||||||
|
|
||||||
NameDictInt kw_to_index;
|
NameDictInt kw_to_index;
|
||||||
|
|
||||||
void add_kwarg(int index, StrName key, PyVar value){
|
void add_kwarg(int index, StrName key, PyVar value) {
|
||||||
kw_to_index.set(key, index);
|
kw_to_index.set(key, index);
|
||||||
kwargs.push_back(KwArg{index, key, value});
|
kwargs.push_back(KwArg{index, key, value});
|
||||||
}
|
}
|
||||||
@ -145,34 +143,38 @@ struct FuncDecl {
|
|||||||
|
|
||||||
struct NativeFunc {
|
struct NativeFunc {
|
||||||
NativeFuncC f;
|
NativeFuncC f;
|
||||||
int argc; // old style argc-based call
|
int argc; // old style argc-based call
|
||||||
FuncDecl_ decl; // new style decl-based call
|
FuncDecl_ decl; // new style decl-based call
|
||||||
any _userdata;
|
any _userdata;
|
||||||
|
|
||||||
NativeFunc(NativeFuncC f, int argc, any userdata={}): f(f), argc(argc), decl(nullptr), _userdata(std::move(userdata)) {}
|
NativeFunc(NativeFuncC f, int argc, any userdata = {}) :
|
||||||
NativeFunc(NativeFuncC f, FuncDecl_ decl, any userdata={}): f(f), argc(-1), decl(decl), _userdata(std::move(userdata)) {}
|
f(f), argc(argc), decl(nullptr), _userdata(std::move(userdata)) {}
|
||||||
|
|
||||||
|
NativeFunc(NativeFuncC f, FuncDecl_ decl, any userdata = {}) :
|
||||||
|
f(f), argc(-1), decl(decl), _userdata(std::move(userdata)) {}
|
||||||
|
|
||||||
PyVar call(VM* vm, ArgsView args) const { return f(vm, args); }
|
PyVar call(VM* vm, ArgsView args) const { return f(vm, args); }
|
||||||
|
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Function{
|
struct Function {
|
||||||
FuncDecl_ decl;
|
FuncDecl_ decl;
|
||||||
PyObject* _module; // weak ref
|
PyObject* _module; // weak ref
|
||||||
PyObject* _class; // weak ref
|
PyObject* _class; // weak ref
|
||||||
NameDict_ _closure;
|
NameDict_ _closure;
|
||||||
|
|
||||||
explicit Function(FuncDecl_ decl, PyObject* _module, PyObject* _class, NameDict_ _closure):
|
explicit Function(FuncDecl_ decl, PyObject* _module, PyObject* _class, NameDict_ _closure) :
|
||||||
decl(decl), _module(_module), _class(_class), _closure(_closure) {}
|
decl(decl), _module(_module), _class(_class), _closure(_closure) {}
|
||||||
|
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
T& lambda_get_userdata(PyVar* p){
|
T& lambda_get_userdata(PyVar* p) {
|
||||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||||
int offset = p[-1] != nullptr ? -1 : -2;
|
int offset = p[-1] != nullptr ? -1 : -2;
|
||||||
return p[offset].obj_get<NativeFunc>()._userdata.cast<T>();
|
return p[offset].obj_get<NativeFunc>()._userdata.cast<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -3,32 +3,32 @@
|
|||||||
#include "pocketpy/objects/base.hpp"
|
#include "pocketpy/objects/base.hpp"
|
||||||
#include "pocketpy/objects/tuplelist.hpp"
|
#include "pocketpy/objects/tuplelist.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
struct Dict{
|
struct Dict {
|
||||||
struct Item{
|
struct Item {
|
||||||
PyVar first;
|
PyVar first;
|
||||||
PyVar second;
|
PyVar second;
|
||||||
int prev;
|
int prev;
|
||||||
int next;
|
int next;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr int __Capacity = 8;
|
constexpr static int __Capacity = 8;
|
||||||
static constexpr float __LoadFactor = 0.67f;
|
constexpr static float __LoadFactor = 0.67f;
|
||||||
|
|
||||||
int _capacity;
|
int _capacity;
|
||||||
int _mask;
|
int _mask;
|
||||||
int _size;
|
int _size;
|
||||||
int _critical_size;
|
int _critical_size;
|
||||||
int _head_idx; // for order preserving
|
int _head_idx; // for order preserving
|
||||||
int _tail_idx; // for order preserving
|
int _tail_idx; // for order preserving
|
||||||
Item* _items;
|
Item* _items;
|
||||||
|
|
||||||
Dict();
|
Dict();
|
||||||
Dict(Dict&& other);
|
Dict(Dict&& other);
|
||||||
Dict(const Dict& other);
|
Dict(const Dict& other);
|
||||||
Dict& operator=(const Dict&) = delete;
|
Dict& operator= (const Dict&) = delete;
|
||||||
Dict& operator=(Dict&&) = delete;
|
Dict& operator= (Dict&&) = delete;
|
||||||
|
|
||||||
int size() const { return _size; }
|
int size() const { return _size; }
|
||||||
|
|
||||||
@ -44,10 +44,10 @@ struct Dict{
|
|||||||
bool del(VM* vm, PyVar key);
|
bool del(VM* vm, PyVar key);
|
||||||
void update(VM* vm, const Dict& other);
|
void update(VM* vm, const Dict& other);
|
||||||
|
|
||||||
template<typename __Func>
|
template <typename __Func>
|
||||||
void apply(__Func f) const {
|
void apply(__Func f) const {
|
||||||
int i = _head_idx;
|
int i = _head_idx;
|
||||||
while(i != -1){
|
while(i != -1) {
|
||||||
f(_items[i].first, _items[i].second);
|
f(_items[i].first, _items[i].second);
|
||||||
i = _items[i].next;
|
i = _items[i].next;
|
||||||
}
|
}
|
||||||
@ -63,4 +63,4 @@ struct Dict{
|
|||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -3,22 +3,23 @@
|
|||||||
#include "pocketpy/common/str.hpp"
|
#include "pocketpy/common/str.hpp"
|
||||||
#include "pocketpy/objects/sourcedata.hpp"
|
#include "pocketpy/objects/sourcedata.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
struct NeedMoreLines {
|
struct NeedMoreLines {
|
||||||
NeedMoreLines(bool is_compiling_class) : is_compiling_class(is_compiling_class) {}
|
NeedMoreLines(bool is_compiling_class) : is_compiling_class(is_compiling_class) {}
|
||||||
|
|
||||||
bool is_compiling_class;
|
bool is_compiling_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class InternalExceptionType: int{
|
enum class InternalExceptionType : int { Null, Handled, Unhandled, ToBeRaised };
|
||||||
Null, Handled, Unhandled, ToBeRaised
|
|
||||||
};
|
|
||||||
|
|
||||||
struct InternalException final{
|
struct InternalException final {
|
||||||
InternalExceptionType type;
|
InternalExceptionType type;
|
||||||
int arg;
|
int arg;
|
||||||
InternalException(): type(InternalExceptionType::Null), arg(-1) {}
|
|
||||||
InternalException(InternalExceptionType type, int arg=-1): type(type), arg(arg) {}
|
InternalException() : type(InternalExceptionType::Null), arg(-1) {}
|
||||||
|
|
||||||
|
InternalException(InternalExceptionType type, int arg = -1) : type(type), arg(arg) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Exception {
|
struct Exception {
|
||||||
@ -29,9 +30,9 @@ struct Exception {
|
|||||||
int _ip_on_error;
|
int _ip_on_error;
|
||||||
void* _code_on_error;
|
void* _code_on_error;
|
||||||
|
|
||||||
PyObject* _self; // weak reference
|
PyObject* _self; // weak reference
|
||||||
|
|
||||||
struct Frame{
|
struct Frame {
|
||||||
std::shared_ptr<SourceData> src;
|
std::shared_ptr<SourceData> src;
|
||||||
int lineno;
|
int lineno;
|
||||||
const char* cursor;
|
const char* cursor;
|
||||||
@ -39,20 +40,21 @@ struct Exception {
|
|||||||
|
|
||||||
Str snapshot() const { return src->snapshot(lineno, cursor, name); }
|
Str snapshot() const { return src->snapshot(lineno, cursor, name); }
|
||||||
|
|
||||||
Frame(std::shared_ptr<SourceData> src, int lineno, const char* cursor, std::string_view name):
|
Frame(std::shared_ptr<SourceData> src, int lineno, const char* cursor, std::string_view name) :
|
||||||
src(src), lineno(lineno), cursor(cursor), name(name) {}
|
src(src), lineno(lineno), cursor(cursor), name(name) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
stack<Frame> stacktrace;
|
stack<Frame> stacktrace;
|
||||||
Exception(StrName type): type(type), is_re(true), _ip_on_error(-1), _code_on_error(nullptr), _self(nullptr) {}
|
|
||||||
|
|
||||||
PyObject* self() const{
|
Exception(StrName type) : type(type), is_re(true), _ip_on_error(-1), _code_on_error(nullptr), _self(nullptr) {}
|
||||||
|
|
||||||
|
PyObject* self() const {
|
||||||
assert(_self != nullptr);
|
assert(_self != nullptr);
|
||||||
return _self;
|
return _self;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template <typename... Args>
|
||||||
void st_push(Args&&... args){
|
void st_push(Args&&... args) {
|
||||||
if(stacktrace.size() >= 7) return;
|
if(stacktrace.size() >= 7) return;
|
||||||
stacktrace.emplace(std::forward<Args>(args)...);
|
stacktrace.emplace(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
@ -60,10 +62,11 @@ struct Exception {
|
|||||||
Str summary() const;
|
Str summary() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TopLevelException: std::exception{
|
struct TopLevelException : std::exception {
|
||||||
VM* vm;
|
VM* vm;
|
||||||
Exception* ptr;
|
Exception* ptr;
|
||||||
TopLevelException(VM* vm, Exception* ptr): vm(vm), ptr(ptr) {}
|
|
||||||
|
TopLevelException(VM* vm, Exception* ptr) : vm(vm), ptr(ptr) {}
|
||||||
|
|
||||||
Str summary() const { return ptr->summary(); }
|
Str summary() const { return ptr->summary(); }
|
||||||
|
|
||||||
@ -74,4 +77,4 @@ struct TopLevelException: std::exception{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -3,22 +3,24 @@
|
|||||||
#include "pocketpy/common/namedict.hpp"
|
#include "pocketpy/common/namedict.hpp"
|
||||||
#include "pocketpy/objects/base.hpp"
|
#include "pocketpy/objects/base.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
using NameDict = NameDictImpl<PyVar>;
|
using NameDict = NameDictImpl<PyVar>;
|
||||||
using NameDict_ = std::shared_ptr<NameDict>;
|
using NameDict_ = std::shared_ptr<NameDict>;
|
||||||
using NameDictInt = NameDictImpl<int>;
|
using NameDictInt = NameDictImpl<int>;
|
||||||
|
|
||||||
static_assert(sizeof(NameDict) <= 128);
|
static_assert(sizeof(NameDict) <= 128);
|
||||||
|
|
||||||
struct PyObject final{
|
struct PyObject final {
|
||||||
bool gc_marked; // whether this object is marked
|
bool gc_marked; // whether this object is marked
|
||||||
Type type; // we have a duplicated type here for convenience
|
Type type; // we have a duplicated type here for convenience
|
||||||
NameDict* _attr; // gc will delete this on destruction
|
NameDict* _attr; // gc will delete this on destruction
|
||||||
|
|
||||||
bool is_attr_valid() const noexcept { return _attr != nullptr; }
|
bool is_attr_valid() const noexcept { return _attr != nullptr; }
|
||||||
|
|
||||||
void* _value_ptr() noexcept { return (char*)this + 16; }
|
void* _value_ptr() noexcept { return (char*)this + 16; }
|
||||||
|
|
||||||
template<typename T> T& as() noexcept {
|
template <typename T>
|
||||||
|
T& as() noexcept {
|
||||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||||
return *reinterpret_cast<T*>(_value_ptr());
|
return *reinterpret_cast<T*>(_value_ptr());
|
||||||
}
|
}
|
||||||
@ -35,17 +37,17 @@ struct PyObject final{
|
|||||||
|
|
||||||
PyObject(Type type) : gc_marked(false), type(type), _attr(nullptr) {}
|
PyObject(Type type) : gc_marked(false), type(type), _attr(nullptr) {}
|
||||||
|
|
||||||
template<typename T, typename ...Args>
|
template <typename T, typename... Args>
|
||||||
void placement_new(Args&&... args){
|
void placement_new(Args&&... args) {
|
||||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||||
new(_value_ptr()) T(std::forward<Args>(args)...);
|
new (_value_ptr()) T(std::forward<Args>(args)...);
|
||||||
|
|
||||||
// backdoor for important builtin types
|
// backdoor for important builtin types
|
||||||
if constexpr(std::is_same_v<T, DummyInstance>){
|
if constexpr(std::is_same_v<T, DummyInstance>) {
|
||||||
_attr = new NameDict();
|
_attr = new NameDict();
|
||||||
}else if constexpr(std::is_same_v<T, Type>){
|
} else if constexpr(std::is_same_v<T, Type>) {
|
||||||
_attr = new NameDict(PK_TYPE_ATTR_LOAD_FACTOR);
|
_attr = new NameDict(PK_TYPE_ATTR_LOAD_FACTOR);
|
||||||
}else if constexpr(std::is_same_v<T, DummyModule>){
|
} else if constexpr(std::is_same_v<T, DummyModule>) {
|
||||||
_attr = new NameDict(PK_TYPE_ATTR_LOAD_FACTOR);
|
_attr = new NameDict(PK_TYPE_ATTR_LOAD_FACTOR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,4 +55,4 @@ struct PyObject final{
|
|||||||
|
|
||||||
static_assert(sizeof(PyObject) <= 16);
|
static_assert(sizeof(PyObject) <= 16);
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -3,15 +3,9 @@
|
|||||||
#include "pocketpy/common/utils.hpp"
|
#include "pocketpy/common/utils.hpp"
|
||||||
#include "pocketpy/common/str.hpp"
|
#include "pocketpy/common/str.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
enum CompileMode {
|
enum CompileMode { EXEC_MODE, EVAL_MODE, REPL_MODE, JSON_MODE, CELL_MODE };
|
||||||
EXEC_MODE,
|
|
||||||
EVAL_MODE,
|
|
||||||
REPL_MODE,
|
|
||||||
JSON_MODE,
|
|
||||||
CELL_MODE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SourceData {
|
struct SourceData {
|
||||||
PK_ALWAYS_PASS_BY_POINTER(SourceData)
|
PK_ALWAYS_PASS_BY_POINTER(SourceData)
|
||||||
@ -27,9 +21,9 @@ struct SourceData {
|
|||||||
|
|
||||||
SourceData(std::string_view source, const Str& filename, CompileMode mode);
|
SourceData(std::string_view source, const Str& filename, CompileMode mode);
|
||||||
SourceData(const Str& filename, CompileMode mode);
|
SourceData(const Str& filename, CompileMode mode);
|
||||||
std::pair<const char*,const char*> _get_line(int lineno) const;
|
std::pair<const char*, const char*> _get_line(int lineno) const;
|
||||||
std::string_view get_line(int lineno) const;
|
std::string_view get_line(int lineno) const;
|
||||||
Str snapshot(int lineno, const char* cursor, std::string_view name) const;
|
Str snapshot(int lineno, const char* cursor, std::string_view name) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -2,16 +2,17 @@
|
|||||||
|
|
||||||
#include "pocketpy/common/traits.hpp"
|
#include "pocketpy/common/traits.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
struct StackMemory{
|
struct StackMemory {
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
StackMemory(int count) : count(count) {}
|
StackMemory(int count) : count(count) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
inline bool constexpr is_sso_v<StackMemory> = true;
|
constexpr inline bool is_sso_v<StackMemory> = true;
|
||||||
|
|
||||||
inline const int kTpStackMemoryIndex = 27;
|
const inline int kTpStackMemoryIndex = 27;
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
struct Tuple {
|
struct Tuple {
|
||||||
static const int INLINED_SIZE = 3;
|
const static int INLINED_SIZE = 3;
|
||||||
|
|
||||||
PyVar* _args;
|
PyVar* _args;
|
||||||
PyVar _inlined[INLINED_SIZE];
|
PyVar _inlined[INLINED_SIZE];
|
||||||
@ -15,52 +15,63 @@ struct Tuple {
|
|||||||
Tuple(int n);
|
Tuple(int n);
|
||||||
Tuple(Tuple&& other) noexcept;
|
Tuple(Tuple&& other) noexcept;
|
||||||
Tuple(const Tuple& other) = delete;
|
Tuple(const Tuple& other) = delete;
|
||||||
Tuple& operator=(const Tuple& other) = delete;
|
Tuple& operator= (const Tuple& other) = delete;
|
||||||
Tuple& operator=(Tuple&& other) = delete;
|
Tuple& operator= (Tuple&& other) = delete;
|
||||||
~Tuple();
|
~Tuple();
|
||||||
|
|
||||||
Tuple(PyVar, PyVar);
|
Tuple(PyVar, PyVar);
|
||||||
Tuple(PyVar, PyVar, PyVar);
|
Tuple(PyVar, PyVar, PyVar);
|
||||||
|
|
||||||
bool is_inlined() const { return _args == _inlined; }
|
bool is_inlined() const { return _args == _inlined; }
|
||||||
PyVar& operator[](int i){ return _args[i]; }
|
|
||||||
PyVar operator[](int i) const { return _args[i]; }
|
PyVar& operator[] (int i) { return _args[i]; }
|
||||||
|
|
||||||
|
PyVar operator[] (int i) const { return _args[i]; }
|
||||||
|
|
||||||
int size() const { return _size; }
|
int size() const { return _size; }
|
||||||
|
|
||||||
PyVar* begin() const { return _args; }
|
PyVar* begin() const { return _args; }
|
||||||
|
|
||||||
PyVar* end() const { return _args + _size; }
|
PyVar* end() const { return _args + _size; }
|
||||||
|
|
||||||
PyVar* data() const { return _args; }
|
PyVar* data() const { return _args; }
|
||||||
|
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct List: public vector<PyVar>{
|
struct List : public vector<PyVar> {
|
||||||
using vector<PyVar>::vector;
|
using vector<PyVar>::vector;
|
||||||
void _gc_mark(VM*) const;
|
void _gc_mark(VM*) const;
|
||||||
|
|
||||||
Tuple to_tuple() const{
|
Tuple to_tuple() const {
|
||||||
Tuple ret(size());
|
Tuple ret(size());
|
||||||
for(int i=0; i<size(); i++) ret[i] = (*this)[i];
|
for(int i = 0; i < size(); i++)
|
||||||
|
ret[i] = (*this)[i];
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// a lightweight view for function args, it does not own the memory
|
// a lightweight view for function args, it does not own the memory
|
||||||
struct ArgsView{
|
struct ArgsView {
|
||||||
PyVar* _begin;
|
PyVar* _begin;
|
||||||
PyVar* _end;
|
PyVar* _end;
|
||||||
|
|
||||||
ArgsView(PyVar* begin, PyVar* end) : _begin(begin), _end(end) {}
|
ArgsView(PyVar* begin, PyVar* end) : _begin(begin), _end(end) {}
|
||||||
|
|
||||||
ArgsView(const Tuple& t) : _begin(t.begin()), _end(t.end()) {}
|
ArgsView(const Tuple& t) : _begin(t.begin()), _end(t.end()) {}
|
||||||
|
|
||||||
PyVar* begin() const { return _begin; }
|
PyVar* begin() const { return _begin; }
|
||||||
|
|
||||||
PyVar* end() const { return _end; }
|
PyVar* end() const { return _end; }
|
||||||
|
|
||||||
int size() const { return _end - _begin; }
|
int size() const { return _end - _begin; }
|
||||||
|
|
||||||
bool empty() const { return _begin == _end; }
|
bool empty() const { return _begin == _end; }
|
||||||
PyVar operator[](int i) const { return _begin[i]; }
|
|
||||||
|
PyVar operator[] (int i) const { return _begin[i]; }
|
||||||
|
|
||||||
List to_list() const;
|
List to_list() const;
|
||||||
Tuple to_tuple() const;
|
Tuple to_tuple() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -9,17 +9,17 @@
|
|||||||
#include "pocketpy/modules/linalg.hpp"
|
#include "pocketpy/modules/linalg.hpp"
|
||||||
#include "pocketpy/tools/repl.hpp"
|
#include "pocketpy/tools/repl.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
static_assert(py_sizeof<Str> <= 64);
|
static_assert(py_sizeof<Str> <= 64);
|
||||||
static_assert(py_sizeof<Mat3x3> <= 64);
|
static_assert(py_sizeof<Mat3x3> <= 64);
|
||||||
static_assert(py_sizeof<Struct> <= 64);
|
static_assert(py_sizeof<Struct> <= 64);
|
||||||
static_assert(py_sizeof<Tuple> <= 80);
|
static_assert(py_sizeof<Tuple> <= 80);
|
||||||
static_assert(py_sizeof<List> <= 64);
|
static_assert(py_sizeof<List> <= 64);
|
||||||
static_assert(py_sizeof<Dict> <= 64);
|
static_assert(py_sizeof<Dict> <= 64);
|
||||||
static_assert(py_sizeof<RangeIter> <= 64);
|
static_assert(py_sizeof<RangeIter> <= 64);
|
||||||
static_assert(py_sizeof<RangeIterR> <= 64);
|
static_assert(py_sizeof<RangeIterR> <= 64);
|
||||||
static_assert(py_sizeof<ArrayIter> <= 64);
|
static_assert(py_sizeof<ArrayIter> <= 64);
|
||||||
static_assert(py_sizeof<StringIter> <= 64);
|
static_assert(py_sizeof<StringIter> <= 64);
|
||||||
static_assert(py_sizeof<Generator> <= 64);
|
static_assert(py_sizeof<Generator> <= 64);
|
||||||
static_assert(py_sizeof<DictItemsIter> <= 64);
|
static_assert(py_sizeof<DictItemsIter> <= 64);
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
@ -10,98 +10,97 @@ extern "C" {
|
|||||||
|
|
||||||
#include "pocketpy/common/export.h"
|
#include "pocketpy/common/export.h"
|
||||||
|
|
||||||
typedef struct pkpy_vm_handle pkpy_vm;
|
typedef struct pkpy_vm_handle pkpy_vm;
|
||||||
typedef int (*pkpy_CFunction)(pkpy_vm*);
|
typedef int (*pkpy_CFunction)(pkpy_vm*);
|
||||||
typedef void (*pkpy_COutputHandler)(const char*, int);
|
typedef void (*pkpy_COutputHandler)(const char*, int);
|
||||||
typedef unsigned char* (*pkpy_CImportHandler)(const char*, int*);
|
typedef unsigned char* (*pkpy_CImportHandler)(const char*, int*);
|
||||||
typedef int pkpy_CName;
|
typedef int pkpy_CName;
|
||||||
typedef int pkpy_CType;
|
typedef int pkpy_CType;
|
||||||
typedef const char* pkpy_CString;
|
typedef const char* pkpy_CString;
|
||||||
|
|
||||||
/* Basic Functions */
|
/* Basic Functions */
|
||||||
PK_EXPORT pkpy_vm* pkpy_new_vm(bool enable_os);
|
PK_EXPORT pkpy_vm* pkpy_new_vm(bool enable_os);
|
||||||
PK_EXPORT void pkpy_delete_vm(pkpy_vm*);
|
PK_EXPORT void pkpy_delete_vm(pkpy_vm*);
|
||||||
PK_EXPORT bool pkpy_exec(pkpy_vm*, const char* source);
|
PK_EXPORT bool pkpy_exec(pkpy_vm*, const char* source);
|
||||||
PK_EXPORT bool pkpy_exec_2(pkpy_vm*, const char* source, const char* filename, int mode, const char* module);
|
PK_EXPORT bool pkpy_exec_2(pkpy_vm*, const char* source, const char* filename, int mode, const char* module);
|
||||||
PK_EXPORT void pkpy_set_main_argv(pkpy_vm*, int argc, char** argv);
|
PK_EXPORT void pkpy_set_main_argv(pkpy_vm*, int argc, char** argv);
|
||||||
|
|
||||||
/* Stack Manipulation */
|
/* Stack Manipulation */
|
||||||
PK_EXPORT bool pkpy_dup(pkpy_vm*, int i);
|
PK_EXPORT bool pkpy_dup(pkpy_vm*, int i);
|
||||||
PK_EXPORT bool pkpy_pop(pkpy_vm*, int n);
|
PK_EXPORT bool pkpy_pop(pkpy_vm*, int n);
|
||||||
PK_EXPORT bool pkpy_pop_top(pkpy_vm*);
|
PK_EXPORT bool pkpy_pop_top(pkpy_vm*);
|
||||||
PK_EXPORT bool pkpy_dup_top(pkpy_vm*);
|
PK_EXPORT bool pkpy_dup_top(pkpy_vm*);
|
||||||
PK_EXPORT bool pkpy_rot_two(pkpy_vm*);
|
PK_EXPORT bool pkpy_rot_two(pkpy_vm*);
|
||||||
PK_EXPORT int pkpy_stack_size(pkpy_vm*);
|
PK_EXPORT int pkpy_stack_size(pkpy_vm*);
|
||||||
|
|
||||||
// int
|
// int
|
||||||
PK_EXPORT bool pkpy_push_int(pkpy_vm*, int val);
|
PK_EXPORT bool pkpy_push_int(pkpy_vm*, int val);
|
||||||
PK_EXPORT bool pkpy_is_int(pkpy_vm*, int i);
|
PK_EXPORT bool pkpy_is_int(pkpy_vm*, int i);
|
||||||
PK_EXPORT bool pkpy_to_int(pkpy_vm*, int i, int* out);
|
PK_EXPORT bool pkpy_to_int(pkpy_vm*, int i, int* out);
|
||||||
|
|
||||||
// float
|
// float
|
||||||
PK_EXPORT bool pkpy_push_float(pkpy_vm*, double val);
|
PK_EXPORT bool pkpy_push_float(pkpy_vm*, double val);
|
||||||
PK_EXPORT bool pkpy_is_float(pkpy_vm*, int i);
|
PK_EXPORT bool pkpy_is_float(pkpy_vm*, int i);
|
||||||
PK_EXPORT bool pkpy_to_float(pkpy_vm*, int i, double* out);
|
PK_EXPORT bool pkpy_to_float(pkpy_vm*, int i, double* out);
|
||||||
|
|
||||||
// bool
|
// bool
|
||||||
PK_EXPORT bool pkpy_push_bool(pkpy_vm*, bool val);
|
PK_EXPORT bool pkpy_push_bool(pkpy_vm*, bool val);
|
||||||
PK_EXPORT bool pkpy_is_bool(pkpy_vm*, int i);
|
PK_EXPORT bool pkpy_is_bool(pkpy_vm*, int i);
|
||||||
PK_EXPORT bool pkpy_to_bool(pkpy_vm*, int i, bool* out);
|
PK_EXPORT bool pkpy_to_bool(pkpy_vm*, int i, bool* out);
|
||||||
|
|
||||||
// string
|
// string
|
||||||
PK_EXPORT bool pkpy_push_string(pkpy_vm*, pkpy_CString val);
|
PK_EXPORT bool pkpy_push_string(pkpy_vm*, pkpy_CString val);
|
||||||
PK_EXPORT bool pkpy_is_string(pkpy_vm*, int i);
|
PK_EXPORT bool pkpy_is_string(pkpy_vm*, int i);
|
||||||
PK_EXPORT bool pkpy_to_string(pkpy_vm*, int i, pkpy_CString* out);
|
PK_EXPORT bool pkpy_to_string(pkpy_vm*, int i, pkpy_CString* out);
|
||||||
|
|
||||||
// void_p
|
// void_p
|
||||||
PK_EXPORT bool pkpy_push_voidp(pkpy_vm*, void* val);
|
PK_EXPORT bool pkpy_push_voidp(pkpy_vm*, void* val);
|
||||||
PK_EXPORT bool pkpy_is_voidp(pkpy_vm*, int i);
|
PK_EXPORT bool pkpy_is_voidp(pkpy_vm*, int i);
|
||||||
PK_EXPORT bool pkpy_to_voidp(pkpy_vm*, int i, void** out);
|
PK_EXPORT bool pkpy_to_voidp(pkpy_vm*, int i, void** out);
|
||||||
|
|
||||||
// none
|
// none
|
||||||
PK_EXPORT bool pkpy_push_none(pkpy_vm*);
|
PK_EXPORT bool pkpy_push_none(pkpy_vm*);
|
||||||
PK_EXPORT bool pkpy_is_none(pkpy_vm*, int i);
|
PK_EXPORT bool pkpy_is_none(pkpy_vm*, int i);
|
||||||
|
|
||||||
// special push
|
// special push
|
||||||
PK_EXPORT bool pkpy_push_null(pkpy_vm*);
|
PK_EXPORT bool pkpy_push_null(pkpy_vm*);
|
||||||
PK_EXPORT bool pkpy_push_function(pkpy_vm*, const char* sig, pkpy_CFunction val);
|
PK_EXPORT bool pkpy_push_function(pkpy_vm*, const char* sig, pkpy_CFunction val);
|
||||||
PK_EXPORT bool pkpy_push_module(pkpy_vm*, const char* name);
|
PK_EXPORT bool pkpy_push_module(pkpy_vm*, const char* name);
|
||||||
|
|
||||||
// some opt
|
// some opt
|
||||||
PK_EXPORT bool pkpy_getattr(pkpy_vm*, pkpy_CName name);
|
PK_EXPORT bool pkpy_getattr(pkpy_vm*, pkpy_CName name);
|
||||||
PK_EXPORT bool pkpy_setattr(pkpy_vm*, pkpy_CName name);
|
PK_EXPORT bool pkpy_setattr(pkpy_vm*, pkpy_CName name);
|
||||||
PK_EXPORT bool pkpy_getglobal(pkpy_vm*, pkpy_CName name);
|
PK_EXPORT bool pkpy_getglobal(pkpy_vm*, pkpy_CName name);
|
||||||
PK_EXPORT bool pkpy_setglobal(pkpy_vm*, pkpy_CName name);
|
PK_EXPORT bool pkpy_setglobal(pkpy_vm*, pkpy_CName name);
|
||||||
PK_EXPORT bool pkpy_eval(pkpy_vm*, const char* source);
|
PK_EXPORT bool pkpy_eval(pkpy_vm*, const char* source);
|
||||||
PK_EXPORT bool pkpy_unpack_sequence(pkpy_vm*, int size);
|
PK_EXPORT bool pkpy_unpack_sequence(pkpy_vm*, int size);
|
||||||
PK_EXPORT bool pkpy_get_unbound_method(pkpy_vm*, pkpy_CName name);
|
PK_EXPORT bool pkpy_get_unbound_method(pkpy_vm*, pkpy_CName name);
|
||||||
PK_EXPORT bool pkpy_py_repr(pkpy_vm*);
|
PK_EXPORT bool pkpy_py_repr(pkpy_vm*);
|
||||||
PK_EXPORT bool pkpy_py_str(pkpy_vm*);
|
PK_EXPORT bool pkpy_py_str(pkpy_vm*);
|
||||||
PK_EXPORT bool pkpy_py_import(pkpy_vm*, pkpy_CString name);
|
PK_EXPORT bool pkpy_py_import(pkpy_vm*, pkpy_CString name);
|
||||||
|
|
||||||
/* Error Handling */
|
/* Error Handling */
|
||||||
PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, pkpy_CString msg);
|
PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, pkpy_CString msg);
|
||||||
PK_EXPORT bool pkpy_check_error(pkpy_vm*);
|
PK_EXPORT bool pkpy_check_error(pkpy_vm*);
|
||||||
PK_EXPORT bool pkpy_clear_error(pkpy_vm*, char** message);
|
PK_EXPORT bool pkpy_clear_error(pkpy_vm*, char** message);
|
||||||
|
|
||||||
/* Callables */
|
/* Callables */
|
||||||
PK_EXPORT bool pkpy_vectorcall(pkpy_vm*, int argc);
|
PK_EXPORT bool pkpy_vectorcall(pkpy_vm*, int argc);
|
||||||
|
|
||||||
/* Special APIs */
|
/* Special APIs */
|
||||||
PK_EXPORT void pkpy_free(void* p);
|
PK_EXPORT void pkpy_free(void* p);
|
||||||
#define pkpy_string(__s) (__s)
|
#define pkpy_string(__s) (__s)
|
||||||
PK_EXPORT pkpy_CName pkpy_name(const char* s);
|
PK_EXPORT pkpy_CName pkpy_name(const char* s);
|
||||||
PK_EXPORT pkpy_CString pkpy_name_to_string(pkpy_CName name);
|
PK_EXPORT pkpy_CString pkpy_name_to_string(pkpy_CName name);
|
||||||
PK_EXPORT void pkpy_set_output_handler(pkpy_vm*, pkpy_COutputHandler handler);
|
PK_EXPORT void pkpy_set_output_handler(pkpy_vm*, pkpy_COutputHandler handler);
|
||||||
PK_EXPORT void pkpy_set_import_handler(pkpy_vm*, pkpy_CImportHandler handler);
|
PK_EXPORT void pkpy_set_import_handler(pkpy_vm*, pkpy_CImportHandler handler);
|
||||||
|
|
||||||
/* REPL */
|
/* REPL */
|
||||||
PK_EXPORT void* pkpy_new_repl(pkpy_vm*);
|
PK_EXPORT void* pkpy_new_repl(pkpy_vm*);
|
||||||
PK_EXPORT bool pkpy_repl_input(void* r, const char* line);
|
PK_EXPORT bool pkpy_repl_input(void* r, const char* line);
|
||||||
PK_EXPORT void pkpy_delete_repl(void* repl);
|
PK_EXPORT void pkpy_delete_repl(void* repl);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -2,16 +2,17 @@
|
|||||||
|
|
||||||
#include "pocketpy/interpreter/vm.hpp"
|
#include "pocketpy/interpreter/vm.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
class REPL {
|
class REPL {
|
||||||
protected:
|
protected:
|
||||||
int need_more_lines = 0;
|
int need_more_lines = 0;
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
VM* vm;
|
VM* vm;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
REPL(VM* vm);
|
REPL(VM* vm);
|
||||||
bool input(std::string line);
|
bool input(std::string line);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -3,115 +3,106 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
namespace pybind11 {
|
namespace pybind11 {
|
||||||
inline void exec(const char* code, handle global = {}, handle local = {}) {
|
inline void exec(const char* code, handle global = {}, handle local = {}) {
|
||||||
vm->py_exec(code, global.ptr(), local.ptr());
|
vm->py_exec(code, global.ptr(), local.ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrapper for builtin functions in Python
|
// wrapper for builtin functions in Python
|
||||||
inline bool hasattr(const handle& obj, const handle& name) {
|
inline bool hasattr(const handle& obj, const handle& name) {
|
||||||
auto& key = _builtin_cast<pkpy::Str>(name);
|
auto& key = _builtin_cast<pkpy::Str>(name);
|
||||||
return vm->getattr(obj.ptr(), key, false) != nullptr;
|
return vm->getattr(obj.ptr(), key, false) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool hasattr(const handle& obj, const char* name) {
|
inline bool hasattr(const handle& obj, const char* name) { return vm->getattr(obj.ptr(), name, false) != nullptr; }
|
||||||
return vm->getattr(obj.ptr(), name, false) != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void delattr(const handle& obj, const handle& name) {
|
inline void delattr(const handle& obj, const handle& name) {
|
||||||
auto& key = _builtin_cast<pkpy::Str>(name);
|
auto& key = _builtin_cast<pkpy::Str>(name);
|
||||||
vm->delattr(obj.ptr(), key);
|
vm->delattr(obj.ptr(), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void delattr(const handle& obj, const char* name) { vm->delattr(obj.ptr(), name); }
|
inline void delattr(const handle& obj, const char* name) { vm->delattr(obj.ptr(), name); }
|
||||||
|
|
||||||
inline object getattr(const handle& obj, const handle& name) {
|
inline object getattr(const handle& obj, const handle& name) {
|
||||||
auto& key = _builtin_cast<pkpy::Str>(name);
|
auto& key = _builtin_cast<pkpy::Str>(name);
|
||||||
return reinterpret_borrow<object>(vm->getattr(obj.ptr(), key));
|
return reinterpret_borrow<object>(vm->getattr(obj.ptr(), key));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline object getattr(const handle& obj, const char* name) {
|
inline object getattr(const handle& obj, const char* name) {
|
||||||
return reinterpret_borrow<object>(vm->getattr(obj.ptr(), name));
|
return reinterpret_borrow<object>(vm->getattr(obj.ptr(), name));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline object getattr(const handle& obj, const handle& name, const handle& default_) {
|
inline object getattr(const handle& obj, const handle& name, const handle& default_) {
|
||||||
if(!hasattr(obj, name)) {
|
if(!hasattr(obj, name)) { return reinterpret_borrow<object>(default_); }
|
||||||
return reinterpret_borrow<object>(default_);
|
return getattr(obj, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline object getattr(const handle& obj, const char* name, const handle& default_) {
|
||||||
|
if(!hasattr(obj, name)) { return reinterpret_borrow<object>(default_); }
|
||||||
|
return getattr(obj, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setattr(const handle& obj, const handle& name, const handle& value) {
|
||||||
|
auto& key = _builtin_cast<pkpy::Str>(name);
|
||||||
|
vm->setattr(obj.ptr(), key, value.ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setattr(const handle& obj, const char* name, const handle& value) {
|
||||||
|
vm->setattr(obj.ptr(), name, value.ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline bool isinstance(const handle& obj) {
|
||||||
|
pkpy::Type cls = _builtin_cast<pkpy::Type>(type::handle_of<T>().ptr());
|
||||||
|
return vm->isinstance(obj.ptr(), cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline bool isinstance<handle>(const handle&) = delete;
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline bool isinstance<iterable>(const handle& obj) {
|
||||||
|
return hasattr(obj, "__iter__");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline bool isinstance<iterator>(const handle& obj) {
|
||||||
|
return hasattr(obj, "__iter__") && hasattr(obj, "__next__");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isinstance(const handle& obj, const handle& type) {
|
||||||
|
return vm->isinstance(obj.ptr(), _builtin_cast<pkpy::Type>(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int64_t hash(const handle& obj) { return vm->py_hash(obj.ptr()); }
|
||||||
|
|
||||||
|
template <typename T, typename SFINAE = void>
|
||||||
|
struct type_caster;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
handle
|
||||||
|
_cast(T&& value, return_value_policy policy = return_value_policy::automatic_reference, handle parent = handle()) {
|
||||||
|
using U = std::remove_pointer_t<std::remove_cv_t<std::remove_reference_t<T>>>;
|
||||||
|
return type_caster<U>::cast(std::forward<T>(value), policy, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
object
|
||||||
|
cast(T&& value, return_value_policy policy = return_value_policy::automatic_reference, handle parent = handle()) {
|
||||||
|
return reinterpret_borrow<object>(_cast(std::forward<T>(value), policy, parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T cast(handle obj, bool convert = false) {
|
||||||
|
using Caster = type_caster<std::remove_pointer_t<std::remove_cv_t<std::remove_reference_t<T>>>>;
|
||||||
|
Caster caster;
|
||||||
|
|
||||||
|
if(caster.load(obj, convert)) {
|
||||||
|
if constexpr(std::is_rvalue_reference_v<T>) {
|
||||||
|
return std::move(caster.value);
|
||||||
|
} else {
|
||||||
|
return caster.value;
|
||||||
}
|
}
|
||||||
return getattr(obj, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline object getattr(const handle& obj, const char* name, const handle& default_) {
|
|
||||||
if(!hasattr(obj, name)) {
|
|
||||||
return reinterpret_borrow<object>(default_);
|
|
||||||
}
|
|
||||||
return getattr(obj, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setattr(const handle& obj, const handle& name, const handle& value) {
|
|
||||||
auto& key = _builtin_cast<pkpy::Str>(name);
|
|
||||||
vm->setattr(obj.ptr(), key, value.ptr());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setattr(const handle& obj, const char* name, const handle& value) {
|
|
||||||
vm->setattr(obj.ptr(), name, value.ptr());
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline bool isinstance(const handle& obj) {
|
|
||||||
pkpy::Type cls = _builtin_cast<pkpy::Type>(type::handle_of<T>().ptr());
|
|
||||||
return vm->isinstance(obj.ptr(), cls);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline bool isinstance<handle>(const handle&) = delete;
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline bool isinstance<iterable>(const handle& obj) {
|
|
||||||
return hasattr(obj, "__iter__");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
|
||||||
inline bool isinstance<iterator>(const handle& obj) {
|
|
||||||
return hasattr(obj, "__iter__") && hasattr(obj, "__next__");
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool isinstance(const handle& obj, const handle& type) {
|
|
||||||
return vm->isinstance(obj.ptr(), _builtin_cast<pkpy::Type>(type));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int64_t hash(const handle& obj) { return vm->py_hash(obj.ptr()); }
|
|
||||||
|
|
||||||
template <typename T, typename SFINAE = void>
|
|
||||||
struct type_caster;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
handle _cast(T&& value,
|
|
||||||
return_value_policy policy = return_value_policy::automatic_reference,
|
|
||||||
handle parent = handle()) {
|
|
||||||
using U = std::remove_pointer_t<std::remove_cv_t<std::remove_reference_t<T>>>;
|
|
||||||
return type_caster<U>::cast(std::forward<T>(value), policy, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
object cast(T&& value,
|
|
||||||
return_value_policy policy = return_value_policy::automatic_reference,
|
|
||||||
handle parent = handle()) {
|
|
||||||
return reinterpret_borrow<object>(_cast(std::forward<T>(value), policy, parent));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T cast(handle obj, bool convert = false) {
|
|
||||||
using Caster =
|
|
||||||
type_caster<std::remove_pointer_t<std::remove_cv_t<std::remove_reference_t<T>>>>;
|
|
||||||
Caster caster;
|
|
||||||
|
|
||||||
if(caster.load(obj, convert)) {
|
|
||||||
if constexpr(std::is_rvalue_reference_v<T>) {
|
|
||||||
return std::move(caster.value);
|
|
||||||
} else {
|
|
||||||
return caster.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw std::runtime_error("Unable to cast Python instance to C++ type");
|
|
||||||
}
|
}
|
||||||
|
throw std::runtime_error("Unable to cast Python instance to C++ type");
|
||||||
|
}
|
||||||
} // namespace pybind11
|
} // namespace pybind11
|
||||||
|
|||||||
@ -6,168 +6,161 @@
|
|||||||
|
|
||||||
namespace pybind11 {
|
namespace pybind11 {
|
||||||
|
|
||||||
using pkpy::is_floating_point_v;
|
using pkpy::is_floating_point_v;
|
||||||
using pkpy::is_integral_v;
|
using pkpy::is_integral_v;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr inline bool is_string_v =
|
constexpr inline bool is_string_v = std::is_same_v<T, char*> || std::is_same_v<T, const char*> ||
|
||||||
std::is_same_v<T, char*> || std::is_same_v<T, const char*> ||
|
std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>;
|
||||||
std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>;
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr bool is_pyobject_v = std::is_base_of_v<handle, T>;
|
constexpr bool is_pyobject_v = std::is_base_of_v<handle, T>;
|
||||||
|
|
||||||
template <typename T, typename>
|
template <typename T, typename>
|
||||||
struct type_caster;
|
struct type_caster;
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct type_caster<bool> {
|
struct type_caster<bool> {
|
||||||
bool value;
|
bool value;
|
||||||
|
|
||||||
bool load(const handle& src, bool) {
|
bool load(const handle& src, bool) {
|
||||||
if(isinstance<pybind11::bool_>(src)) {
|
if(isinstance<pybind11::bool_>(src)) {
|
||||||
value = pkpy::_py_cast<bool>(vm, src.ptr());
|
value = pkpy::_py_cast<bool>(vm, src.ptr());
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static handle cast(bool src, return_value_policy, handle) {
|
return false;
|
||||||
return src ? vm->True : vm->False;
|
}
|
||||||
|
|
||||||
|
static handle cast(bool src, return_value_policy, handle) { return src ? vm->True : vm->False; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct type_caster<T, std::enable_if_t<is_integral_v<T>>> {
|
||||||
|
T value;
|
||||||
|
|
||||||
|
bool load(const handle& src, bool convert) {
|
||||||
|
if(isinstance<pybind11::int_>(src)) {
|
||||||
|
value = pkpy::_py_cast<T>(vm, src.ptr());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static handle cast(T src, return_value_policy, handle) { return pkpy::py_var(vm, src); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct type_caster<T, std::enable_if_t<is_floating_point_v<T>>> {
|
||||||
|
T value;
|
||||||
|
|
||||||
|
bool load(const handle& src, bool convert) {
|
||||||
|
if(isinstance<pybind11::float_>(src)) {
|
||||||
|
value = pkpy::_py_cast<T>(vm, src.ptr());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(convert && isinstance<pybind11::int_>(src)) {
|
||||||
|
value = pkpy::_py_cast<int64_t>(vm, src.ptr());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static handle cast(T src, return_value_policy, handle) { return pkpy::py_var(vm, src); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct type_caster<T, std::enable_if_t<is_string_v<T>>> {
|
||||||
|
T value;
|
||||||
|
|
||||||
|
bool load(const handle& src, bool) {
|
||||||
|
if(isinstance<pybind11::str>(src)) {
|
||||||
|
// FIXME: support other kinds of string
|
||||||
|
value = pkpy::_py_cast<std::string>(vm, src.ptr());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static handle cast(const std::string& src, return_value_policy, handle) { return pkpy::py_var(vm, src); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct type_caster<T, std::enable_if_t<is_pyobject_v<T>>> {
|
||||||
|
T value;
|
||||||
|
|
||||||
|
bool load(const handle& src, bool) {
|
||||||
|
if(isinstance<T>(src)) {
|
||||||
|
value = reinterpret_borrow<T>(src);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
static handle cast(U&& src, return_value_policy, handle) {
|
||||||
|
return std::forward<U>(src);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename>
|
||||||
|
struct type_caster {
|
||||||
|
value_wrapper<T> value;
|
||||||
|
|
||||||
|
using underlying_type = std::remove_pointer_t<decltype(value.pointer)>;
|
||||||
|
|
||||||
|
bool load(handle src, bool convert) {
|
||||||
|
if(isinstance<underlying_type>(src)) {
|
||||||
|
auto& i = _builtin_cast<instance>(src);
|
||||||
|
value.pointer = &i.cast<underlying_type>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
static handle cast(U&& value, return_value_policy policy, const handle& parent = handle()) {
|
||||||
|
// TODO: support implicit cast
|
||||||
|
const auto& info = typeid(underlying_type);
|
||||||
|
bool existed = vm->_cxx_typeid_map.find(info) != vm->_cxx_typeid_map.end();
|
||||||
|
if(existed) {
|
||||||
|
auto type = vm->_cxx_typeid_map[info];
|
||||||
|
return instance::create(std::forward<U>(value), type, policy, parent.ptr());
|
||||||
|
}
|
||||||
|
vm->TypeError("type not registered");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct type_caster<T, std::enable_if_t<std::is_pointer_v<T> || std::is_reference_v<T>>> {
|
||||||
|
using underlying = std::conditional_t<std::is_pointer_v<T>, std::remove_pointer_t<T>, std::remove_reference_t<T>>;
|
||||||
|
|
||||||
|
struct wrapper {
|
||||||
|
type_caster<underlying> caster;
|
||||||
|
|
||||||
|
operator T () {
|
||||||
|
if constexpr(std::is_pointer_v<T>) {
|
||||||
|
return caster.value.pointer;
|
||||||
|
} else {
|
||||||
|
return caster.value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
wrapper value;
|
||||||
struct type_caster<T, std::enable_if_t<is_integral_v<T>>> {
|
|
||||||
T value;
|
|
||||||
|
|
||||||
bool load(const handle& src, bool convert) {
|
bool load(const handle& src, bool convert) { return value.caster.load(src, convert); }
|
||||||
if(isinstance<pybind11::int_>(src)) {
|
|
||||||
value = pkpy::_py_cast<T>(vm, src.ptr());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
template <typename U>
|
||||||
}
|
static handle cast(U&& value, return_value_policy policy, const handle& parent) {
|
||||||
|
return type_caster<underlying>::cast(std::forward<U>(value), policy, parent);
|
||||||
static handle cast(T src, return_value_policy, handle) { return pkpy::py_var(vm, src); }
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct type_caster<T, std::enable_if_t<is_floating_point_v<T>>> {
|
|
||||||
T value;
|
|
||||||
|
|
||||||
bool load(const handle& src, bool convert) {
|
|
||||||
if(isinstance<pybind11::float_>(src)) {
|
|
||||||
value = pkpy::_py_cast<T>(vm, src.ptr());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(convert && isinstance<pybind11::int_>(src)) {
|
|
||||||
value = pkpy::_py_cast<int64_t>(vm, src.ptr());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(T src, return_value_policy, handle) { return pkpy::py_var(vm, src); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct type_caster<T, std::enable_if_t<is_string_v<T>>> {
|
|
||||||
T value;
|
|
||||||
|
|
||||||
bool load(const handle& src, bool) {
|
|
||||||
if(isinstance<pybind11::str>(src)) {
|
|
||||||
// FIXME: support other kinds of string
|
|
||||||
value = pkpy::_py_cast<std::string>(vm, src.ptr());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static handle cast(const std::string& src, return_value_policy, handle) {
|
|
||||||
return pkpy::py_var(vm, src);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct type_caster<T, std::enable_if_t<is_pyobject_v<T>>> {
|
|
||||||
T value;
|
|
||||||
|
|
||||||
bool load(const handle& src, bool) {
|
|
||||||
if(isinstance<T>(src)) {
|
|
||||||
value = reinterpret_borrow<T>(src);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
static handle cast(U&& src, return_value_policy, handle) {
|
|
||||||
return std::forward<U>(src);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, typename>
|
|
||||||
struct type_caster {
|
|
||||||
value_wrapper<T> value;
|
|
||||||
|
|
||||||
using underlying_type = std::remove_pointer_t<decltype(value.pointer)>;
|
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
|
||||||
if(isinstance<underlying_type>(src)) {
|
|
||||||
auto& i = _builtin_cast<instance>(src);
|
|
||||||
value.pointer = &i.cast<underlying_type>();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
static handle cast(U&& value, return_value_policy policy, const handle& parent = handle()) {
|
|
||||||
// TODO: support implicit cast
|
|
||||||
const auto& info = typeid(underlying_type);
|
|
||||||
bool existed = vm->_cxx_typeid_map.find(info) != vm->_cxx_typeid_map.end();
|
|
||||||
if(existed) {
|
|
||||||
auto type = vm->_cxx_typeid_map[info];
|
|
||||||
return instance::create(std::forward<U>(value), type, policy, parent.ptr());
|
|
||||||
}
|
|
||||||
vm->TypeError("type not registered");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct type_caster<T, std::enable_if_t<std::is_pointer_v<T> || std::is_reference_v<T>>> {
|
|
||||||
using underlying = std::conditional_t<std::is_pointer_v<T>,
|
|
||||||
std::remove_pointer_t<T>,
|
|
||||||
std::remove_reference_t<T>>;
|
|
||||||
|
|
||||||
struct wrapper {
|
|
||||||
type_caster<underlying> caster;
|
|
||||||
|
|
||||||
operator T () {
|
|
||||||
if constexpr(std::is_pointer_v<T>) {
|
|
||||||
return caster.value.pointer;
|
|
||||||
} else {
|
|
||||||
return caster.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
wrapper value;
|
|
||||||
|
|
||||||
bool load(const handle& src, bool convert) { return value.caster.load(src, convert); }
|
|
||||||
|
|
||||||
template <typename U>
|
|
||||||
static handle cast(U&& value, return_value_policy policy, const handle& parent) {
|
|
||||||
return type_caster<underlying>::cast(std::forward<U>(value), policy, parent);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace pybind11
|
} // namespace pybind11
|
||||||
|
|
||||||
|
|||||||
@ -4,181 +4,174 @@
|
|||||||
|
|
||||||
namespace pybind11 {
|
namespace pybind11 {
|
||||||
|
|
||||||
class module : public object {
|
class module : public object {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using object::object;
|
using object::object;
|
||||||
|
|
||||||
static module import(const char* name) {
|
static module import(const char* name) {
|
||||||
if(name == std::string_view{"__main__"}) {
|
if(name == std::string_view{"__main__"}) {
|
||||||
return module{vm->_main, true};
|
return module{vm->_main, true};
|
||||||
} else {
|
} else {
|
||||||
return module{vm->py_import(name, false), true};
|
return module{vm->py_import(name, false), true};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// 1. inheritance
|
// 1. inheritance
|
||||||
// 2. virtual function
|
// 2. virtual function
|
||||||
// 3. factory function
|
// 3. factory function
|
||||||
|
|
||||||
template <typename T, typename... Others>
|
template <typename T, typename... Others>
|
||||||
class class_ : public type {
|
class class_ : public type {
|
||||||
public:
|
public:
|
||||||
using type::type;
|
using type::type;
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
class_(const handle& scope, const char* name, Args&&... args) :
|
class_(const handle& scope, const char* name, Args&&... args) :
|
||||||
type(vm->new_type_object(scope.ptr(),
|
type(vm->new_type_object(scope.ptr(), name, vm->tp_object, false, pkpy::PyTypeInfo::Vt::get<instance>()),
|
||||||
name,
|
true) {
|
||||||
vm->tp_object,
|
pkpy::PyVar mod = scope.ptr();
|
||||||
false,
|
mod->attr().set(name, m_ptr);
|
||||||
pkpy::PyTypeInfo::Vt::get<instance>()),
|
vm->_cxx_typeid_map[typeid(T)] = _builtin_cast<pkpy::Type>(m_ptr);
|
||||||
true) {
|
vm->bind_func(m_ptr, "__new__", -1, [](pkpy::VM* vm, pkpy::ArgsView args) {
|
||||||
pkpy::PyVar mod = scope.ptr();
|
auto cls = _builtin_cast<pkpy::Type>(args[0]);
|
||||||
mod->attr().set(name, m_ptr);
|
return instance::create<T>(cls);
|
||||||
vm->_cxx_typeid_map[typeid(T)] = _builtin_cast<pkpy::Type>(m_ptr);
|
});
|
||||||
vm->bind_func(m_ptr, "__new__", -1, [](pkpy::VM* vm, pkpy::ArgsView args) {
|
}
|
||||||
auto cls = _builtin_cast<pkpy::Type>(args[0]);
|
|
||||||
return instance::create<T>(cls);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// bind constructor
|
|
||||||
template <typename... Args, typename... Extra>
|
|
||||||
class_& def(init<Args...>, const Extra&... extra) {
|
|
||||||
if constexpr(!std::is_constructible_v<T, Args...>) {
|
|
||||||
static_assert(std::is_constructible_v<T, Args...>, "Invalid constructor arguments");
|
|
||||||
} else {
|
|
||||||
bind_function(
|
|
||||||
*this,
|
|
||||||
"__init__",
|
|
||||||
[](T* self, Args... args) { new (self) T(args...); },
|
|
||||||
pkpy::BindType::DEFAULT,
|
|
||||||
extra...);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// bind member function
|
|
||||||
template <typename Fn, typename... Extra>
|
|
||||||
class_& def(const char* name, Fn&& f, const Extra&... extra) {
|
|
||||||
using first = std::tuple_element_t<0, callable_args_t<remove_cvref_t<Fn>>>;
|
|
||||||
constexpr bool is_first_base_of_v =
|
|
||||||
std::is_reference_v<first> && std::is_base_of_v<T, remove_cvref_t<first>>;
|
|
||||||
|
|
||||||
if constexpr(!is_first_base_of_v) {
|
|
||||||
static_assert(
|
|
||||||
is_first_base_of_v,
|
|
||||||
"If you want to bind member function, the first argument must be the base class");
|
|
||||||
} else {
|
|
||||||
bind_function(*this, name, std::forward<Fn>(f), pkpy::BindType::DEFAULT, extra...);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// bind constructor
|
||||||
|
template <typename... Args, typename... Extra>
|
||||||
|
class_& def(init<Args...>, const Extra&... extra) {
|
||||||
|
if constexpr(!std::is_constructible_v<T, Args...>) {
|
||||||
|
static_assert(std::is_constructible_v<T, Args...>, "Invalid constructor arguments");
|
||||||
|
} else {
|
||||||
|
bind_function(
|
||||||
|
*this,
|
||||||
|
"__init__",
|
||||||
|
[](T* self, Args... args) {
|
||||||
|
new (self) T(args...);
|
||||||
|
},
|
||||||
|
pkpy::BindType::DEFAULT,
|
||||||
|
extra...);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// bind operators
|
/// bind member function
|
||||||
template <typename Operator, typename... Extras>
|
template <typename Fn, typename... Extra>
|
||||||
class_& def(Operator op, const Extras&... extras) {
|
class_& def(const char* name, Fn&& f, const Extra&... extra) {
|
||||||
op.execute(*this, extras...);
|
using first = std::tuple_element_t<0, callable_args_t<remove_cvref_t<Fn>>>;
|
||||||
return *this;
|
constexpr bool is_first_base_of_v = std::is_reference_v<first> && std::is_base_of_v<T, remove_cvref_t<first>>;
|
||||||
|
|
||||||
|
if constexpr(!is_first_base_of_v) {
|
||||||
|
static_assert(is_first_base_of_v,
|
||||||
|
"If you want to bind member function, the first argument must be the base class");
|
||||||
|
} else {
|
||||||
|
bind_function(*this, name, std::forward<Fn>(f), pkpy::BindType::DEFAULT, extra...);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: factory function
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/// bind static function
|
/// bind operators
|
||||||
template <typename Fn, typename... Extra>
|
template <typename Operator, typename... Extras>
|
||||||
class_& def_static(const char* name, Fn&& f, const Extra&... extra) {
|
class_& def(Operator op, const Extras&... extras) {
|
||||||
bind_function(*this, name, std::forward<Fn>(f), pkpy::BindType::STATICMETHOD, extra...);
|
op.execute(*this, extras...);
|
||||||
return *this;
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: factory function
|
||||||
|
|
||||||
|
/// bind static function
|
||||||
|
template <typename Fn, typename... Extra>
|
||||||
|
class_& def_static(const char* name, Fn&& f, const Extra&... extra) {
|
||||||
|
bind_function(*this, name, std::forward<Fn>(f), pkpy::BindType::STATICMETHOD, extra...);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename MP, typename... Extras>
|
||||||
|
class_& def_readwrite(const char* name, MP mp, const Extras&... extras) {
|
||||||
|
if constexpr(!std::is_member_object_pointer_v<MP>) {
|
||||||
|
static_assert(std::is_member_object_pointer_v<MP>, "def_readwrite only supports pointer to data member");
|
||||||
|
} else {
|
||||||
|
bind_property(*this, name, mp, mp, extras...);
|
||||||
}
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename MP, typename... Extras>
|
template <typename MP, typename... Extras>
|
||||||
class_& def_readwrite(const char* name, MP mp, const Extras&... extras) {
|
class_& def_readonly(const char* name, MP mp, const Extras&... extras) {
|
||||||
if constexpr(!std::is_member_object_pointer_v<MP>) {
|
if constexpr(!std::is_member_object_pointer_v<MP>) {
|
||||||
static_assert(std::is_member_object_pointer_v<MP>,
|
static_assert(std::is_member_object_pointer_v<MP>, "def_readonly only supports pointer to data member");
|
||||||
"def_readwrite only supports pointer to data member");
|
} else {
|
||||||
} else {
|
bind_property(*this, name, mp, nullptr, extras...);
|
||||||
bind_property(*this, name, mp, mp, extras...);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename MP, typename... Extras>
|
template <typename Getter, typename Setter, typename... Extras>
|
||||||
class_& def_readonly(const char* name, MP mp, const Extras&... extras) {
|
class_& def_property(const char* name, Getter&& g, Setter&& s, const Extras&... extras) {
|
||||||
if constexpr(!std::is_member_object_pointer_v<MP>) {
|
bind_property(*this, name, std::forward<Getter>(g), std::forward<Setter>(s), extras...);
|
||||||
static_assert(std::is_member_object_pointer_v<MP>,
|
return *this;
|
||||||
"def_readonly only supports pointer to data member");
|
}
|
||||||
} else {
|
|
||||||
bind_property(*this, name, mp, nullptr, extras...);
|
template <typename Getter, typename... Extras>
|
||||||
}
|
class_& def_property_readonly(const char* name, Getter&& mp, const Extras&... extras) {
|
||||||
return *this;
|
bind_property(*this, name, std::forward<Getter>(mp), nullptr, extras...);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Var, typename... Extras>
|
||||||
|
class_& def_readwrite_static(const char* name, Var& mp, const Extras&... extras) {
|
||||||
|
static_assert(
|
||||||
|
dependent_false<Var>,
|
||||||
|
"define static properties requires metaclass. This is a complex feature with few use cases, so it may never be implemented.");
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Var, typename... Extras>
|
||||||
|
class_& def_readonly_static(const char* name, Var& mp, const Extras&... extras) {
|
||||||
|
static_assert(
|
||||||
|
dependent_false<Var>,
|
||||||
|
"define static properties requires metaclass. This is a complex feature with few use cases, so it may never be implemented.");
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Getter, typename Setter, typename... Extras>
|
||||||
|
class_& def_property_static(const char* name, Getter&& g, Setter&& s, const Extras&... extras) {
|
||||||
|
static_assert(
|
||||||
|
dependent_false<Getter>,
|
||||||
|
"define static properties requires metaclass. This is a complex feature with few use cases, so it may never be implemented.");
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename... Others>
|
||||||
|
class enum_ : public class_<T, Others...> {
|
||||||
|
std::map<const char*, pkpy::PyVar> m_values;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using class_<T, Others...>::class_;
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
enum_(const handle& scope, const char* name, Args&&... args) :
|
||||||
|
class_<T, Others...>(scope, name, std::forward<Args>(args)...) {}
|
||||||
|
|
||||||
|
enum_& value(const char* name, T value) {
|
||||||
|
handle var = type_caster<T>::cast(value, return_value_policy::copy);
|
||||||
|
this->m_ptr->attr().set(name, var.ptr());
|
||||||
|
m_values[name] = var.ptr();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum_& export_values() {
|
||||||
|
pkpy::PyVar mod = this->m_ptr->attr("__module__");
|
||||||
|
for(auto& [name, value]: m_values) {
|
||||||
|
mod->attr().set(name, value);
|
||||||
}
|
}
|
||||||
|
return *this;
|
||||||
template <typename Getter, typename Setter, typename... Extras>
|
}
|
||||||
class_& def_property(const char* name, Getter&& g, Setter&& s, const Extras&... extras) {
|
};
|
||||||
bind_property(*this, name, std::forward<Getter>(g), std::forward<Setter>(s), extras...);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Getter, typename... Extras>
|
|
||||||
class_& def_property_readonly(const char* name, Getter&& mp, const Extras&... extras) {
|
|
||||||
bind_property(*this, name, std::forward<Getter>(mp), nullptr, extras...);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Var, typename... Extras>
|
|
||||||
class_& def_readwrite_static(const char* name, Var& mp, const Extras&... extras) {
|
|
||||||
static_assert(
|
|
||||||
dependent_false<Var>,
|
|
||||||
"define static properties requires metaclass. This is a complex feature with few use cases, so it may never be implemented.");
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Var, typename... Extras>
|
|
||||||
class_& def_readonly_static(const char* name, Var& mp, const Extras&... extras) {
|
|
||||||
static_assert(
|
|
||||||
dependent_false<Var>,
|
|
||||||
"define static properties requires metaclass. This is a complex feature with few use cases, so it may never be implemented.");
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Getter, typename Setter, typename... Extras>
|
|
||||||
class_&
|
|
||||||
def_property_static(const char* name, Getter&& g, Setter&& s, const Extras&... extras) {
|
|
||||||
static_assert(
|
|
||||||
dependent_false<Getter>,
|
|
||||||
"define static properties requires metaclass. This is a complex feature with few use cases, so it may never be implemented.");
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, typename... Others>
|
|
||||||
class enum_ : public class_<T, Others...> {
|
|
||||||
std::map<const char*, pkpy::PyVar> m_values;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using class_<T, Others...>::class_;
|
|
||||||
|
|
||||||
template <typename... Args>
|
|
||||||
enum_(const handle& scope, const char* name, Args&&... args) :
|
|
||||||
class_<T, Others...>(scope, name, std::forward<Args>(args)...) {}
|
|
||||||
|
|
||||||
enum_& value(const char* name, T value) {
|
|
||||||
handle var = type_caster<T>::cast(value, return_value_policy::copy);
|
|
||||||
this->m_ptr->attr().set(name, var.ptr());
|
|
||||||
m_values[name] = var.ptr();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum_& export_values() {
|
|
||||||
pkpy::PyVar mod = this->m_ptr->attr("__module__");
|
|
||||||
for(auto& [name, value]: m_values) {
|
|
||||||
mod->attr().set(name, value);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace pybind11
|
} // namespace pybind11
|
||||||
|
|||||||
@ -5,379 +5,354 @@
|
|||||||
|
|
||||||
namespace pybind11 {
|
namespace pybind11 {
|
||||||
|
|
||||||
template <std::size_t Nurse, std::size_t... Patients>
|
template <std::size_t Nurse, std::size_t... Patients>
|
||||||
struct keep_alive {};
|
struct keep_alive {};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct call_guard {
|
struct call_guard {
|
||||||
static_assert(std::is_default_constructible_v<T>,
|
static_assert(std::is_default_constructible_v<T>, "call_guard must be default constructible");
|
||||||
"call_guard must be default constructible");
|
};
|
||||||
|
|
||||||
|
// append the overload to the beginning of the overload list
|
||||||
|
struct prepend {};
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
struct init {};
|
||||||
|
|
||||||
|
// TODO: support more customized tags
|
||||||
|
// struct kw_only {};
|
||||||
|
//
|
||||||
|
// struct pos_only {};
|
||||||
|
//
|
||||||
|
// struct default_arg {};
|
||||||
|
//
|
||||||
|
// struct arg {
|
||||||
|
// const char* name;
|
||||||
|
// const char* description;
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// struct default_arg {
|
||||||
|
// const char* name;
|
||||||
|
// const char* description;
|
||||||
|
// const char* value;
|
||||||
|
// };
|
||||||
|
|
||||||
|
template <typename Fn,
|
||||||
|
typename Extra,
|
||||||
|
typename Args = callable_args_t<std::decay_t<Fn>>,
|
||||||
|
typename IndexSequence = std::make_index_sequence<std::tuple_size_v<Args>>>
|
||||||
|
struct generator;
|
||||||
|
|
||||||
|
class function_record {
|
||||||
|
union {
|
||||||
|
void* data;
|
||||||
|
char buffer[16];
|
||||||
};
|
};
|
||||||
|
|
||||||
// append the overload to the beginning of the overload list
|
// TODO: optimize the function_record size to reduce memory usage
|
||||||
struct prepend {};
|
const char* name;
|
||||||
|
function_record* next;
|
||||||
|
void (*destructor)(function_record*);
|
||||||
|
return_value_policy policy = return_value_policy::automatic;
|
||||||
|
handle (*wrapper)(function_record&, pkpy::ArgsView, bool convert, handle parent);
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename Fn, typename Extra, typename Args, typename IndexSequence>
|
||||||
struct init {};
|
friend struct generator;
|
||||||
|
|
||||||
// TODO: support more customized tags
|
public:
|
||||||
// struct kw_only {};
|
template <typename Fn, typename... Extras>
|
||||||
//
|
function_record(Fn&& f, const char* name, const Extras&... extras) : name(name), next(nullptr) {
|
||||||
// struct pos_only {};
|
|
||||||
//
|
|
||||||
// struct default_arg {};
|
|
||||||
//
|
|
||||||
// struct arg {
|
|
||||||
// const char* name;
|
|
||||||
// const char* description;
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// struct default_arg {
|
|
||||||
// const char* name;
|
|
||||||
// const char* description;
|
|
||||||
// const char* value;
|
|
||||||
// };
|
|
||||||
|
|
||||||
template <typename Fn,
|
if constexpr(sizeof(f) <= sizeof(buffer)) {
|
||||||
typename Extra,
|
new (buffer) auto(std::forward<Fn>(f));
|
||||||
typename Args = callable_args_t<std::decay_t<Fn>>,
|
destructor = [](function_record* self) {
|
||||||
typename IndexSequence = std::make_index_sequence<std::tuple_size_v<Args>>>
|
reinterpret_cast<Fn*>(self->buffer)->~Fn();
|
||||||
struct generator;
|
};
|
||||||
|
|
||||||
class function_record {
|
|
||||||
union {
|
|
||||||
void* data;
|
|
||||||
char buffer[16];
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: optimize the function_record size to reduce memory usage
|
|
||||||
const char* name;
|
|
||||||
function_record* next;
|
|
||||||
void (*destructor)(function_record*);
|
|
||||||
return_value_policy policy = return_value_policy::automatic;
|
|
||||||
handle (*wrapper)(function_record&, pkpy::ArgsView, bool convert, handle parent);
|
|
||||||
|
|
||||||
template <typename Fn, typename Extra, typename Args, typename IndexSequence>
|
|
||||||
friend struct generator;
|
|
||||||
|
|
||||||
public:
|
|
||||||
template <typename Fn, typename... Extras>
|
|
||||||
function_record(Fn&& f, const char* name, const Extras&... extras) :
|
|
||||||
name(name), next(nullptr) {
|
|
||||||
|
|
||||||
if constexpr(sizeof(f) <= sizeof(buffer)) {
|
|
||||||
new (buffer) auto(std::forward<Fn>(f));
|
|
||||||
destructor = [](function_record* self) {
|
|
||||||
reinterpret_cast<Fn*>(self->buffer)->~Fn();
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
data = new auto(std::forward<Fn>(f));
|
|
||||||
destructor = [](function_record* self) { delete static_cast<Fn*>(self->data); };
|
|
||||||
}
|
|
||||||
|
|
||||||
using Generator = generator<std::decay_t<Fn>, std::tuple<Extras...>>;
|
|
||||||
Generator::initialize(*this, extras...);
|
|
||||||
wrapper = Generator::generate();
|
|
||||||
}
|
|
||||||
|
|
||||||
~function_record() { destructor(this); }
|
|
||||||
|
|
||||||
template <typename Fn>
|
|
||||||
auto& cast() {
|
|
||||||
if constexpr(sizeof(Fn) <= sizeof(buffer)) {
|
|
||||||
return *reinterpret_cast<Fn*>(buffer);
|
|
||||||
} else {
|
|
||||||
return *static_cast<Fn*>(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void append(function_record* record) {
|
|
||||||
function_record* p = this;
|
|
||||||
while(p->next != nullptr) {
|
|
||||||
p = p->next;
|
|
||||||
}
|
|
||||||
p->next = record;
|
|
||||||
}
|
|
||||||
|
|
||||||
handle operator() (pkpy::ArgsView view) {
|
|
||||||
function_record* p = this;
|
|
||||||
// foreach function record and call the function with not convert
|
|
||||||
while(p != nullptr) {
|
|
||||||
handle result = p->wrapper(*this, view, false, {});
|
|
||||||
if(result) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
p = p->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = this;
|
|
||||||
// foreach function record and call the function with convert
|
|
||||||
while(p != nullptr) {
|
|
||||||
handle result = p->wrapper(*this, view, true, {});
|
|
||||||
if(result) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
p = p->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
vm->TypeError("no matching function found");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Fn, std::size_t... Is, typename... Args>
|
|
||||||
handle invoke(Fn&& fn,
|
|
||||||
std::index_sequence<Is...>,
|
|
||||||
std::tuple<type_caster<Args>...>& casters,
|
|
||||||
return_value_policy policy,
|
|
||||||
handle parent) {
|
|
||||||
using underlying_type = std::decay_t<Fn>;
|
|
||||||
using ret = callable_return_t<underlying_type>;
|
|
||||||
|
|
||||||
// if the return type is void, return None
|
|
||||||
if constexpr(std::is_void_v<ret>) {
|
|
||||||
// resolve the member function pointer
|
|
||||||
if constexpr(std::is_member_function_pointer_v<underlying_type>) {
|
|
||||||
[&](class_type_t<underlying_type>& self, auto&... args) {
|
|
||||||
(self.*fn)(args...);
|
|
||||||
}(std::get<Is>(casters).value...);
|
|
||||||
} else {
|
|
||||||
fn(std::get<Is>(casters).value...);
|
|
||||||
}
|
|
||||||
return vm->None;
|
|
||||||
} else {
|
} else {
|
||||||
// resolve the member function pointer
|
data = new auto(std::forward<Fn>(f));
|
||||||
if constexpr(std::is_member_function_pointer_v<remove_cvref_t<Fn>>) {
|
destructor = [](function_record* self) {
|
||||||
return type_caster<ret>::cast(
|
delete static_cast<Fn*>(self->data);
|
||||||
[&](class_type_t<underlying_type>& self, auto&... args) {
|
|
||||||
return (self.*fn)(args...);
|
|
||||||
}(std::get<Is>(casters).value...),
|
|
||||||
policy,
|
|
||||||
parent);
|
|
||||||
} else {
|
|
||||||
return type_caster<ret>::cast(fn(std::get<Is>(casters).value...), policy, parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Fn, typename... Args, std::size_t... Is, typename... Extras>
|
|
||||||
struct generator<Fn, std::tuple<Extras...>, std::tuple<Args...>, std::index_sequence<Is...>> {
|
|
||||||
static void initialize(function_record& record, const Extras&... extras) {}
|
|
||||||
|
|
||||||
static auto generate() {
|
|
||||||
return +[](function_record& self, pkpy::ArgsView view, bool convert, handle parent) {
|
|
||||||
// FIXME:
|
|
||||||
// Temporarily, args and kwargs must be at the end of the arguments list
|
|
||||||
// Named arguments are not supported yet
|
|
||||||
constexpr bool has_args = types_count_v<args, remove_cvref_t<Args>...> != 0;
|
|
||||||
constexpr bool has_kwargs = types_count_v<kwargs, remove_cvref_t<Args>...> != 0;
|
|
||||||
constexpr std::size_t count = sizeof...(Args) - has_args - has_kwargs;
|
|
||||||
|
|
||||||
handle stack[sizeof...(Args)] = {};
|
|
||||||
|
|
||||||
// initialize the stack
|
|
||||||
|
|
||||||
if(!has_args && (view.size() != count)) {
|
|
||||||
return handle();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(has_args && (view.size() < count)) {
|
|
||||||
return handle();
|
|
||||||
}
|
|
||||||
|
|
||||||
for(std::size_t i = 0; i < count; ++i) {
|
|
||||||
stack[i] = view[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// pack the args and kwargs
|
|
||||||
if constexpr(has_args) {
|
|
||||||
const auto n = view.size() - count;
|
|
||||||
pkpy::PyVar var = vm->new_object<pkpy::Tuple>(vm->tp_tuple, n);
|
|
||||||
auto& tuple = var.obj_get<pkpy::Tuple>();
|
|
||||||
for(std::size_t i = 0; i < n; ++i) {
|
|
||||||
tuple[i] = view[count + i];
|
|
||||||
}
|
|
||||||
stack[count] = var;
|
|
||||||
}
|
|
||||||
|
|
||||||
if constexpr(has_kwargs) {
|
|
||||||
const auto n = vm->s_data._sp - view.end();
|
|
||||||
pkpy::PyVar var = vm->new_object<pkpy::Dict>(vm->tp_dict);
|
|
||||||
auto& dict = var.obj_get<pkpy::Dict>();
|
|
||||||
|
|
||||||
for(std::size_t i = 0; i < n; i += 2) {
|
|
||||||
pkpy::i64 index = pkpy::_py_cast<pkpy::i64>(vm, view[count + i]);
|
|
||||||
pkpy::PyVar str =
|
|
||||||
vm->new_object<pkpy::Str>(vm->tp_str, pkpy::StrName(index).sv());
|
|
||||||
dict.set(vm, str, view[count + i + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
stack[count + 1] = var;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if all the arguments are not valid
|
|
||||||
for(std::size_t i = 0; i < sizeof...(Args); ++i) {
|
|
||||||
if(!stack[i]) {
|
|
||||||
return handle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ok, all the arguments are valid, call the function
|
|
||||||
std::tuple<type_caster<Args>...> casters;
|
|
||||||
|
|
||||||
// check type compatibility
|
|
||||||
if(((std::get<Is>(casters).load(stack[Is], convert)) && ...)) {
|
|
||||||
return invoke(self.cast<Fn>(),
|
|
||||||
std::index_sequence<Is...>{},
|
|
||||||
casters,
|
|
||||||
self.policy,
|
|
||||||
parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
return handle();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
constexpr inline static auto _wrapper = +[](pkpy::VM*, pkpy::ArgsView view) {
|
using Generator = generator<std::decay_t<Fn>, std::tuple<Extras...>>;
|
||||||
auto& record = pkpy::lambda_get_userdata<function_record>(view.begin());
|
Generator::initialize(*this, extras...);
|
||||||
return record(view).ptr();
|
wrapper = Generator::generate();
|
||||||
};
|
|
||||||
|
|
||||||
class cpp_function : public function {
|
|
||||||
public:
|
|
||||||
template <typename Fn, typename... Extras>
|
|
||||||
cpp_function(Fn&& f, const Extras&... extras) {
|
|
||||||
pkpy::any userdata = function_record(std::forward<Fn>(f), "anonymous", extras...);
|
|
||||||
m_ptr = vm->bind_func(nullptr, "", -1, _wrapper, std::move(userdata));
|
|
||||||
inc_ref();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Fn, typename... Extras>
|
|
||||||
handle bind_function(const handle& obj,
|
|
||||||
const char* name,
|
|
||||||
Fn&& fn,
|
|
||||||
pkpy::BindType type,
|
|
||||||
const Extras&... extras) {
|
|
||||||
// do not use cpp_function directly to avoid unnecessary reference count change
|
|
||||||
pkpy::PyVar var = obj.ptr();
|
|
||||||
pkpy::PyVar callable = var->attr().try_get(name);
|
|
||||||
|
|
||||||
// if the function is not bound yet, bind it
|
|
||||||
if(!callable) {
|
|
||||||
pkpy::any userdata = function_record(std::forward<Fn>(fn), name, extras...);
|
|
||||||
callable = vm->bind_func(var, name, -1, _wrapper, std::move(userdata));
|
|
||||||
} else {
|
|
||||||
auto& userdata = callable.obj_get<pkpy::NativeFunc>()._userdata;
|
|
||||||
function_record* record = new function_record(std::forward<Fn>(fn), name, extras...);
|
|
||||||
|
|
||||||
constexpr bool is_prepend = (types_count_v<prepend, Extras...> != 0);
|
|
||||||
if constexpr(is_prepend) {
|
|
||||||
// if prepend is specified, append the new record to the beginning of the list
|
|
||||||
function_record* last = (function_record*)userdata.data;
|
|
||||||
userdata.data = record;
|
|
||||||
record->append(last);
|
|
||||||
} else {
|
|
||||||
// otherwise, append the new record to the end of the list
|
|
||||||
function_record* last = (function_record*)userdata.data;
|
|
||||||
last->append(record);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return callable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Getter_, typename Setter_, typename... Extras>
|
~function_record() { destructor(this); }
|
||||||
handle bind_property(const handle& obj,
|
|
||||||
const char* name,
|
|
||||||
Getter_&& getter_,
|
|
||||||
Setter_&& setter_,
|
|
||||||
const Extras&... extras) {
|
|
||||||
pkpy::PyVar var = obj.ptr();
|
|
||||||
pkpy::PyVar getter = vm->None;
|
|
||||||
pkpy::PyVar setter = vm->None;
|
|
||||||
using Getter = std::decay_t<Getter_>;
|
|
||||||
using Setter = std::decay_t<Setter_>;
|
|
||||||
|
|
||||||
getter = vm->new_object<pkpy::NativeFunc>(
|
template <typename Fn>
|
||||||
vm->tp_native_func,
|
auto& cast() {
|
||||||
[](pkpy::VM* vm, pkpy::ArgsView view) -> pkpy::PyVar {
|
if constexpr(sizeof(Fn) <= sizeof(buffer)) {
|
||||||
auto& getter = pkpy::lambda_get_userdata<Getter>(view.begin());
|
return *reinterpret_cast<Fn*>(buffer);
|
||||||
|
} else {
|
||||||
|
return *static_cast<Fn*>(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if constexpr(std::is_member_pointer_v<Getter>) {
|
void append(function_record* record) {
|
||||||
using Self = class_type_t<Getter>;
|
function_record* p = this;
|
||||||
auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
|
while(p->next != nullptr) {
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
p->next = record;
|
||||||
|
}
|
||||||
|
|
||||||
if constexpr(std::is_member_object_pointer_v<Getter>) {
|
handle operator() (pkpy::ArgsView view) {
|
||||||
return type_caster<member_type_t<Getter>>::cast(
|
function_record* p = this;
|
||||||
self.*getter,
|
// foreach function record and call the function with not convert
|
||||||
return_value_policy::reference_internal,
|
while(p != nullptr) {
|
||||||
view[0])
|
handle result = p->wrapper(*this, view, false, {});
|
||||||
.ptr();
|
if(result) { return result; }
|
||||||
} else {
|
p = p->next;
|
||||||
return type_caster<callable_return_t<Getter>>::cast(
|
}
|
||||||
(self.*getter)(),
|
|
||||||
return_value_policy::reference_internal,
|
|
||||||
view[0])
|
|
||||||
.ptr();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
p = this;
|
||||||
|
// foreach function record and call the function with convert
|
||||||
|
while(p != nullptr) {
|
||||||
|
handle result = p->wrapper(*this, view, true, {});
|
||||||
|
if(result) { return result; }
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm->TypeError("no matching function found");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Fn, std::size_t... Is, typename... Args>
|
||||||
|
handle invoke(Fn&& fn,
|
||||||
|
std::index_sequence<Is...>,
|
||||||
|
std::tuple<type_caster<Args>...>& casters,
|
||||||
|
return_value_policy policy,
|
||||||
|
handle parent) {
|
||||||
|
using underlying_type = std::decay_t<Fn>;
|
||||||
|
using ret = callable_return_t<underlying_type>;
|
||||||
|
|
||||||
|
// if the return type is void, return None
|
||||||
|
if constexpr(std::is_void_v<ret>) {
|
||||||
|
// resolve the member function pointer
|
||||||
|
if constexpr(std::is_member_function_pointer_v<underlying_type>) {
|
||||||
|
[&](class_type_t<underlying_type>& self, auto&... args) {
|
||||||
|
(self.*fn)(args...);
|
||||||
|
}(std::get<Is>(casters).value...);
|
||||||
|
} else {
|
||||||
|
fn(std::get<Is>(casters).value...);
|
||||||
|
}
|
||||||
|
return vm->None;
|
||||||
|
} else {
|
||||||
|
// resolve the member function pointer
|
||||||
|
if constexpr(std::is_member_function_pointer_v<remove_cvref_t<Fn>>) {
|
||||||
|
return type_caster<ret>::cast(
|
||||||
|
[&](class_type_t<underlying_type>& self, auto&... args) {
|
||||||
|
return (self.*fn)(args...);
|
||||||
|
}(std::get<Is>(casters).value...),
|
||||||
|
policy,
|
||||||
|
parent);
|
||||||
|
} else {
|
||||||
|
return type_caster<ret>::cast(fn(std::get<Is>(casters).value...), policy, parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Fn, typename... Args, std::size_t... Is, typename... Extras>
|
||||||
|
struct generator<Fn, std::tuple<Extras...>, std::tuple<Args...>, std::index_sequence<Is...>> {
|
||||||
|
static void initialize(function_record& record, const Extras&... extras) {}
|
||||||
|
|
||||||
|
static auto generate() {
|
||||||
|
return +[](function_record& self, pkpy::ArgsView view, bool convert, handle parent) {
|
||||||
|
// FIXME:
|
||||||
|
// Temporarily, args and kwargs must be at the end of the arguments list
|
||||||
|
// Named arguments are not supported yet
|
||||||
|
constexpr bool has_args = types_count_v<args, remove_cvref_t<Args>...> != 0;
|
||||||
|
constexpr bool has_kwargs = types_count_v<kwargs, remove_cvref_t<Args>...> != 0;
|
||||||
|
constexpr std::size_t count = sizeof...(Args) - has_args - has_kwargs;
|
||||||
|
|
||||||
|
handle stack[sizeof...(Args)] = {};
|
||||||
|
|
||||||
|
// initialize the stack
|
||||||
|
|
||||||
|
if(!has_args && (view.size() != count)) { return handle(); }
|
||||||
|
|
||||||
|
if(has_args && (view.size() < count)) { return handle(); }
|
||||||
|
|
||||||
|
for(std::size_t i = 0; i < count; ++i) {
|
||||||
|
stack[i] = view[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// pack the args and kwargs
|
||||||
|
if constexpr(has_args) {
|
||||||
|
const auto n = view.size() - count;
|
||||||
|
pkpy::PyVar var = vm->new_object<pkpy::Tuple>(vm->tp_tuple, n);
|
||||||
|
auto& tuple = var.obj_get<pkpy::Tuple>();
|
||||||
|
for(std::size_t i = 0; i < n; ++i) {
|
||||||
|
tuple[i] = view[count + i];
|
||||||
|
}
|
||||||
|
stack[count] = var;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr(has_kwargs) {
|
||||||
|
const auto n = vm->s_data._sp - view.end();
|
||||||
|
pkpy::PyVar var = vm->new_object<pkpy::Dict>(vm->tp_dict);
|
||||||
|
auto& dict = var.obj_get<pkpy::Dict>();
|
||||||
|
|
||||||
|
for(std::size_t i = 0; i < n; i += 2) {
|
||||||
|
pkpy::i64 index = pkpy::_py_cast<pkpy::i64>(vm, view[count + i]);
|
||||||
|
pkpy::PyVar str = vm->new_object<pkpy::Str>(vm->tp_str, pkpy::StrName(index).sv());
|
||||||
|
dict.set(vm, str, view[count + i + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
stack[count + 1] = var;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if all the arguments are not valid
|
||||||
|
for(std::size_t i = 0; i < sizeof...(Args); ++i) {
|
||||||
|
if(!stack[i]) { return handle(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ok, all the arguments are valid, call the function
|
||||||
|
std::tuple<type_caster<Args>...> casters;
|
||||||
|
|
||||||
|
// check type compatibility
|
||||||
|
if(((std::get<Is>(casters).load(stack[Is], convert)) && ...)) {
|
||||||
|
return invoke(self.cast<Fn>(), std::index_sequence<Is...>{}, casters, self.policy, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline static auto _wrapper = +[](pkpy::VM*, pkpy::ArgsView view) {
|
||||||
|
auto& record = pkpy::lambda_get_userdata<function_record>(view.begin());
|
||||||
|
return record(view).ptr();
|
||||||
|
};
|
||||||
|
|
||||||
|
class cpp_function : public function {
|
||||||
|
public:
|
||||||
|
template <typename Fn, typename... Extras>
|
||||||
|
cpp_function(Fn&& f, const Extras&... extras) {
|
||||||
|
pkpy::any userdata = function_record(std::forward<Fn>(f), "anonymous", extras...);
|
||||||
|
m_ptr = vm->bind_func(nullptr, "", -1, _wrapper, std::move(userdata));
|
||||||
|
inc_ref();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Fn, typename... Extras>
|
||||||
|
handle bind_function(const handle& obj, const char* name, Fn&& fn, pkpy::BindType type, const Extras&... extras) {
|
||||||
|
// do not use cpp_function directly to avoid unnecessary reference count change
|
||||||
|
pkpy::PyVar var = obj.ptr();
|
||||||
|
pkpy::PyVar callable = var->attr().try_get(name);
|
||||||
|
|
||||||
|
// if the function is not bound yet, bind it
|
||||||
|
if(!callable) {
|
||||||
|
pkpy::any userdata = function_record(std::forward<Fn>(fn), name, extras...);
|
||||||
|
callable = vm->bind_func(var, name, -1, _wrapper, std::move(userdata));
|
||||||
|
} else {
|
||||||
|
auto& userdata = callable.obj_get<pkpy::NativeFunc>()._userdata;
|
||||||
|
function_record* record = new function_record(std::forward<Fn>(fn), name, extras...);
|
||||||
|
|
||||||
|
constexpr bool is_prepend = (types_count_v<prepend, Extras...> != 0);
|
||||||
|
if constexpr(is_prepend) {
|
||||||
|
// if prepend is specified, append the new record to the beginning of the list
|
||||||
|
function_record* last = (function_record*)userdata.data;
|
||||||
|
userdata.data = record;
|
||||||
|
record->append(last);
|
||||||
|
} else {
|
||||||
|
// otherwise, append the new record to the end of the list
|
||||||
|
function_record* last = (function_record*)userdata.data;
|
||||||
|
last->append(record);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Getter_, typename Setter_, typename... Extras>
|
||||||
|
handle
|
||||||
|
bind_property(const handle& obj, const char* name, Getter_&& getter_, Setter_&& setter_, const Extras&... extras) {
|
||||||
|
pkpy::PyVar var = obj.ptr();
|
||||||
|
pkpy::PyVar getter = vm->None;
|
||||||
|
pkpy::PyVar setter = vm->None;
|
||||||
|
using Getter = std::decay_t<Getter_>;
|
||||||
|
using Setter = std::decay_t<Setter_>;
|
||||||
|
|
||||||
|
getter = vm->new_object<pkpy::NativeFunc>(
|
||||||
|
vm->tp_native_func,
|
||||||
|
[](pkpy::VM* vm, pkpy::ArgsView view) -> pkpy::PyVar {
|
||||||
|
auto& getter = pkpy::lambda_get_userdata<Getter>(view.begin());
|
||||||
|
|
||||||
|
if constexpr(std::is_member_pointer_v<Getter>) {
|
||||||
|
using Self = class_type_t<Getter>;
|
||||||
|
auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
|
||||||
|
|
||||||
|
if constexpr(std::is_member_object_pointer_v<Getter>) {
|
||||||
|
return type_caster<member_type_t<Getter>>::cast(self.*getter,
|
||||||
|
return_value_policy::reference_internal,
|
||||||
|
view[0])
|
||||||
|
.ptr();
|
||||||
} else {
|
} else {
|
||||||
using Self = std::tuple_element_t<0, callable_args_t<Getter>>;
|
return type_caster<callable_return_t<Getter>>::cast((self.*getter)(),
|
||||||
auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
|
return_value_policy::reference_internal,
|
||||||
|
view[0])
|
||||||
return type_caster<callable_return_t<Getter>>::cast(
|
|
||||||
getter(self),
|
|
||||||
return_value_policy::reference_internal,
|
|
||||||
view[0])
|
|
||||||
.ptr();
|
.ptr();
|
||||||
}
|
}
|
||||||
},
|
|
||||||
1,
|
|
||||||
std::forward<Getter_>(getter_));
|
|
||||||
|
|
||||||
if constexpr(!std::is_same_v<Setter, std::nullptr_t>) {
|
} else {
|
||||||
setter = vm->new_object<pkpy::NativeFunc>(
|
using Self = std::tuple_element_t<0, callable_args_t<Getter>>;
|
||||||
vm->tp_native_func,
|
auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
|
||||||
[](pkpy::VM* vm, pkpy::ArgsView view) -> pkpy::PyVar {
|
|
||||||
auto& setter = pkpy::lambda_get_userdata<Setter>(view.begin());
|
|
||||||
|
|
||||||
if constexpr(std::is_member_pointer_v<Setter>) {
|
return type_caster<callable_return_t<Getter>>::cast(getter(self),
|
||||||
using Self = class_type_t<Setter>;
|
return_value_policy::reference_internal,
|
||||||
auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
|
view[0])
|
||||||
|
.ptr();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
std::forward<Getter_>(getter_));
|
||||||
|
|
||||||
if constexpr(std::is_member_object_pointer_v<Setter>) {
|
if constexpr(!std::is_same_v<Setter, std::nullptr_t>) {
|
||||||
type_caster<member_type_t<Setter>> caster;
|
setter = vm->new_object<pkpy::NativeFunc>(
|
||||||
if(caster.load(view[1], true)) {
|
vm->tp_native_func,
|
||||||
self.*setter = caster.value;
|
[](pkpy::VM* vm, pkpy::ArgsView view) -> pkpy::PyVar {
|
||||||
return vm->None;
|
auto& setter = pkpy::lambda_get_userdata<Setter>(view.begin());
|
||||||
}
|
|
||||||
} else {
|
if constexpr(std::is_member_pointer_v<Setter>) {
|
||||||
type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
|
using Self = class_type_t<Setter>;
|
||||||
if(caster.load(view[1], true)) {
|
auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
|
||||||
(self.*setter)(caster.value);
|
|
||||||
return vm->None;
|
if constexpr(std::is_member_object_pointer_v<Setter>) {
|
||||||
}
|
type_caster<member_type_t<Setter>> caster;
|
||||||
|
if(caster.load(view[1], true)) {
|
||||||
|
self.*setter = caster.value;
|
||||||
|
return vm->None;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
using Self = std::tuple_element_t<0, callable_args_t<Setter>>;
|
|
||||||
auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
|
|
||||||
|
|
||||||
type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
|
type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
|
||||||
if(caster.load(view[1], true)) {
|
if(caster.load(view[1], true)) {
|
||||||
setter(self, caster.value);
|
(self.*setter)(caster.value);
|
||||||
return vm->None;
|
return vm->None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
using Self = std::tuple_element_t<0, callable_args_t<Setter>>;
|
||||||
|
auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
|
||||||
|
|
||||||
vm->TypeError("invalid argument");
|
type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
|
||||||
},
|
if(caster.load(view[1], true)) {
|
||||||
2,
|
setter(self, caster.value);
|
||||||
std::forward<Setter_>(setter_));
|
return vm->None;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pkpy::PyVar property = vm->new_object<pkpy::Property>(vm->tp_property, getter, setter);
|
vm->TypeError("invalid argument");
|
||||||
var->attr().set(name, property);
|
},
|
||||||
return property;
|
2,
|
||||||
|
std::forward<Setter_>(setter_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pkpy::PyVar property = vm->new_object<pkpy::Property>(vm->tp_property, getter, setter);
|
||||||
|
var->attr().set(name, property);
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pybind11
|
} // namespace pybind11
|
||||||
|
|||||||
@ -3,145 +3,143 @@
|
|||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
|
||||||
namespace pybind11 {
|
namespace pybind11 {
|
||||||
struct type_info {
|
struct type_info {
|
||||||
const char* name;
|
const char* name;
|
||||||
std::size_t size;
|
std::size_t size;
|
||||||
std::size_t alignment;
|
std::size_t alignment;
|
||||||
void (*destructor)(void*);
|
void (*destructor)(void*);
|
||||||
void (*copy)(void*, const void*);
|
void (*copy)(void*, const void*);
|
||||||
void (*move)(void*, void*);
|
void (*move)(void*, void*);
|
||||||
const std::type_info* type;
|
const std::type_info* type;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static type_info& of() {
|
static type_info& of() {
|
||||||
static_assert(!std::is_reference_v<T> && !std::is_const_v<std::remove_reference_t<T>>,
|
static_assert(!std::is_reference_v<T> && !std::is_const_v<std::remove_reference_t<T>>,
|
||||||
"T must not be a reference type or const type.");
|
"T must not be a reference type or const type.");
|
||||||
static type_info info = {
|
static type_info info = {
|
||||||
typeid(T).name(),
|
typeid(T).name(),
|
||||||
sizeof(T),
|
sizeof(T),
|
||||||
alignof(T),
|
alignof(T),
|
||||||
[](void* ptr) {
|
[](void* ptr) {
|
||||||
((T*)ptr)->~T();
|
((T*)ptr)->~T();
|
||||||
operator delete (ptr);
|
operator delete (ptr);
|
||||||
},
|
},
|
||||||
[](void* dst, const void* src) { new (dst) T(*(const T*)src); },
|
[](void* dst, const void* src) {
|
||||||
[](void* dst, void* src) { new (dst) T(std::move(*(T*)src)); },
|
new (dst) T(*(const T*)src);
|
||||||
&typeid(T),
|
},
|
||||||
};
|
[](void* dst, void* src) {
|
||||||
return info;
|
new (dst) T(std::move(*(T*)src));
|
||||||
}
|
},
|
||||||
};
|
&typeid(T),
|
||||||
|
|
||||||
// all registered C++ class will be ensured as instance type.
|
|
||||||
class instance {
|
|
||||||
public:
|
|
||||||
// use to record the type information of C++ class.
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum Flag {
|
|
||||||
None = 0,
|
|
||||||
Own = 1 << 0, // if the instance is owned by C++ side.
|
|
||||||
Ref = 1 << 1, // need to mark the parent object.
|
|
||||||
};
|
};
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Flag flag;
|
// all registered C++ class will be ensured as instance type.
|
||||||
void* data;
|
class instance {
|
||||||
const type_info* type;
|
public:
|
||||||
pkpy::PyVar parent;
|
// use to record the type information of C++ class.
|
||||||
// pkpy::PyVar
|
|
||||||
|
|
||||||
public:
|
private:
|
||||||
instance() noexcept : flag(Flag::None), data(nullptr), type(nullptr), parent(nullptr) {}
|
enum Flag {
|
||||||
|
None = 0,
|
||||||
instance(const instance&) = delete;
|
Own = 1 << 0, // if the instance is owned by C++ side.
|
||||||
|
Ref = 1 << 1, // need to mark the parent object.
|
||||||
instance(instance&& other) noexcept :
|
|
||||||
flag(other.flag), data(other.data), type(other.type), parent(other.parent) {
|
|
||||||
other.flag = Flag::None;
|
|
||||||
other.data = nullptr;
|
|
||||||
other.type = nullptr;
|
|
||||||
other.parent = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static pkpy::PyVar create(pkpy::Type type) {
|
|
||||||
instance instance;
|
|
||||||
instance.type = &type_info::of<T>();
|
|
||||||
instance.data = operator new (sizeof(T));
|
|
||||||
instance.flag = Flag::Own;
|
|
||||||
return vm->new_object<pybind11::instance>(type, std::move(instance));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static pkpy::PyVar
|
|
||||||
create(T&& value,
|
|
||||||
pkpy::Type type,
|
|
||||||
return_value_policy policy = return_value_policy::automatic_reference,
|
|
||||||
pkpy::PyVar parent = nullptr) noexcept {
|
|
||||||
using underlying_type = std::remove_cv_t<std::remove_reference_t<T>>;
|
|
||||||
|
|
||||||
// resolve for automatic policy.
|
|
||||||
if(policy == return_value_policy::automatic) {
|
|
||||||
policy = std::is_pointer_v<underlying_type> ? return_value_policy::take_ownership
|
|
||||||
: std::is_lvalue_reference_v<T&&> ? return_value_policy::copy
|
|
||||||
: return_value_policy::move;
|
|
||||||
} else if(policy == return_value_policy::automatic_reference) {
|
|
||||||
policy = std::is_pointer_v<underlying_type> ? return_value_policy::reference
|
|
||||||
: std::is_lvalue_reference_v<T&&> ? return_value_policy::copy
|
|
||||||
: return_value_policy::move;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& _value = [&]() -> auto& {
|
|
||||||
/**
|
|
||||||
* note that, pybind11 will ignore the const qualifier.
|
|
||||||
* in fact, try to modify a const value will result in undefined behavior.
|
|
||||||
*/
|
|
||||||
if constexpr(std::is_pointer_v<underlying_type>) {
|
|
||||||
return *reinterpret_cast<underlying_type*>(value);
|
|
||||||
} else {
|
|
||||||
return const_cast<underlying_type&>(value);
|
|
||||||
}
|
|
||||||
}();
|
|
||||||
|
|
||||||
instance instance;
|
|
||||||
instance.type = &type_info::of<underlying_type>();
|
|
||||||
|
|
||||||
if(policy == return_value_policy::take_ownership) {
|
|
||||||
instance.data = &_value;
|
|
||||||
instance.flag = Flag::Own;
|
|
||||||
} else if(policy == return_value_policy::copy) {
|
|
||||||
instance.data = ::new auto(_value);
|
|
||||||
instance.flag = Flag::Own;
|
|
||||||
} else if(policy == return_value_policy::move) {
|
|
||||||
instance.data = ::new auto(std::move(_value));
|
|
||||||
instance.flag = Flag::Own;
|
|
||||||
} else if(policy == return_value_policy::reference) {
|
|
||||||
instance.data = &_value;
|
|
||||||
instance.flag = Flag::None;
|
|
||||||
} else if(policy == return_value_policy::reference_internal) {
|
|
||||||
instance.data = &_value;
|
|
||||||
instance.flag = Flag::Ref;
|
|
||||||
instance.parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return vm->new_object<pybind11::instance>(type, std::move(instance));
|
|
||||||
}
|
|
||||||
|
|
||||||
~instance() {
|
|
||||||
if(flag & Flag::Own) {
|
|
||||||
type->destructor(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _gc_mark(pkpy::VM* vm) const noexcept {
|
|
||||||
if(parent && (flag & Flag::Ref)) {
|
|
||||||
PK_OBJ_MARK(parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T& cast() noexcept {
|
|
||||||
return *static_cast<T*>(data);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Flag flag;
|
||||||
|
void* data;
|
||||||
|
const type_info* type;
|
||||||
|
pkpy::PyVar parent;
|
||||||
|
// pkpy::PyVar
|
||||||
|
|
||||||
|
public:
|
||||||
|
instance() noexcept : flag(Flag::None), data(nullptr), type(nullptr), parent(nullptr) {}
|
||||||
|
|
||||||
|
instance(const instance&) = delete;
|
||||||
|
|
||||||
|
instance(instance&& other) noexcept : flag(other.flag), data(other.data), type(other.type), parent(other.parent) {
|
||||||
|
other.flag = Flag::None;
|
||||||
|
other.data = nullptr;
|
||||||
|
other.type = nullptr;
|
||||||
|
other.parent = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static pkpy::PyVar create(pkpy::Type type) {
|
||||||
|
instance instance;
|
||||||
|
instance.type = &type_info::of<T>();
|
||||||
|
instance.data = operator new (sizeof(T));
|
||||||
|
instance.flag = Flag::Own;
|
||||||
|
return vm->new_object<pybind11::instance>(type, std::move(instance));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static pkpy::PyVar create(T&& value,
|
||||||
|
pkpy::Type type,
|
||||||
|
return_value_policy policy = return_value_policy::automatic_reference,
|
||||||
|
pkpy::PyVar parent = nullptr) noexcept {
|
||||||
|
using underlying_type = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||||
|
|
||||||
|
// resolve for automatic policy.
|
||||||
|
if(policy == return_value_policy::automatic) {
|
||||||
|
policy = std::is_pointer_v<underlying_type> ? return_value_policy::take_ownership
|
||||||
|
: std::is_lvalue_reference_v<T&&> ? return_value_policy::copy
|
||||||
|
: return_value_policy::move;
|
||||||
|
} else if(policy == return_value_policy::automatic_reference) {
|
||||||
|
policy = std::is_pointer_v<underlying_type> ? return_value_policy::reference
|
||||||
|
: std::is_lvalue_reference_v<T&&> ? return_value_policy::copy
|
||||||
|
: return_value_policy::move;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& _value = [&]() -> auto& {
|
||||||
|
/**
|
||||||
|
* note that, pybind11 will ignore the const qualifier.
|
||||||
|
* in fact, try to modify a const value will result in undefined behavior.
|
||||||
|
*/
|
||||||
|
if constexpr(std::is_pointer_v<underlying_type>) {
|
||||||
|
return *reinterpret_cast<underlying_type*>(value);
|
||||||
|
} else {
|
||||||
|
return const_cast<underlying_type&>(value);
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
instance instance;
|
||||||
|
instance.type = &type_info::of<underlying_type>();
|
||||||
|
|
||||||
|
if(policy == return_value_policy::take_ownership) {
|
||||||
|
instance.data = &_value;
|
||||||
|
instance.flag = Flag::Own;
|
||||||
|
} else if(policy == return_value_policy::copy) {
|
||||||
|
instance.data = ::new auto(_value);
|
||||||
|
instance.flag = Flag::Own;
|
||||||
|
} else if(policy == return_value_policy::move) {
|
||||||
|
instance.data = ::new auto(std::move(_value));
|
||||||
|
instance.flag = Flag::Own;
|
||||||
|
} else if(policy == return_value_policy::reference) {
|
||||||
|
instance.data = &_value;
|
||||||
|
instance.flag = Flag::None;
|
||||||
|
} else if(policy == return_value_policy::reference_internal) {
|
||||||
|
instance.data = &_value;
|
||||||
|
instance.flag = Flag::Ref;
|
||||||
|
instance.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vm->new_object<pybind11::instance>(type, std::move(instance));
|
||||||
|
}
|
||||||
|
|
||||||
|
~instance() {
|
||||||
|
if(flag & Flag::Own) { type->destructor(data); }
|
||||||
|
}
|
||||||
|
|
||||||
|
void _gc_mark(pkpy::VM* vm) const noexcept {
|
||||||
|
if(parent && (flag & Flag::Ref)) { PK_OBJ_MARK(parent); }
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T& cast() noexcept {
|
||||||
|
return *static_cast<T*>(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
} // namespace pybind11
|
} // namespace pybind11
|
||||||
|
|||||||
@ -2,107 +2,98 @@
|
|||||||
|
|
||||||
#include <pocketpy.h>
|
#include <pocketpy.h>
|
||||||
|
|
||||||
namespace pybind11
|
namespace pybind11 {
|
||||||
{
|
inline pkpy::VM* vm = nullptr;
|
||||||
inline pkpy::VM* vm = nullptr;
|
inline std::map<pkpy::PyVar, int*>* _ref_counts_map = nullptr;
|
||||||
inline std::map<pkpy::PyVar, int*>* _ref_counts_map = nullptr;
|
|
||||||
|
|
||||||
inline void initialize(bool enable_os = true)
|
inline void initialize(bool enable_os = true) {
|
||||||
{
|
vm = new pkpy::VM(enable_os);
|
||||||
vm = new pkpy::VM(enable_os);
|
_ref_counts_map = new std::map<pkpy::PyVar, int*>();
|
||||||
_ref_counts_map = new std::map<pkpy::PyVar, int*>();
|
|
||||||
|
|
||||||
// use to keep alive PyObject, when the object is hold by C++ side.
|
// use to keep alive PyObject, when the object is hold by C++ side.
|
||||||
vm->heap._gc_marker_ex = [](pkpy::VM* vm)
|
vm->heap._gc_marker_ex = [](pkpy::VM* vm) {
|
||||||
{
|
for(auto iter = _ref_counts_map->begin(); iter != _ref_counts_map->end();) {
|
||||||
for(auto iter = _ref_counts_map->begin(); iter != _ref_counts_map->end();)
|
auto ref_count = iter->second;
|
||||||
{
|
if(*ref_count != 0) {
|
||||||
auto ref_count = iter->second;
|
// if ref count is not zero, then mark it.
|
||||||
if(*ref_count != 0)
|
PK_OBJ_MARK(iter->first);
|
||||||
{
|
++iter;
|
||||||
// if ref count is not zero, then mark it.
|
} else {
|
||||||
PK_OBJ_MARK(iter->first);
|
// if ref count is zero, then delete it.
|
||||||
++iter;
|
iter = _ref_counts_map->erase(iter);
|
||||||
}
|
delete ref_count;
|
||||||
else
|
|
||||||
{
|
|
||||||
// if ref count is zero, then delete it.
|
|
||||||
iter = _ref_counts_map->erase(iter);
|
|
||||||
delete ref_count;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
|
||||||
|
|
||||||
inline void finalize()
|
|
||||||
{
|
|
||||||
delete _ref_counts_map;
|
|
||||||
delete vm;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class return_value_policy : uint8_t
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* This is the default return value policy, which falls back to the policy
|
|
||||||
* return_value_policy::take_ownership when the return value is a pointer.
|
|
||||||
* Otherwise, it uses return_value::move or return_value::copy for rvalue
|
|
||||||
* and lvalue references, respectively. See below for a description of what
|
|
||||||
* all of these different policies do.
|
|
||||||
*/
|
|
||||||
automatic = 0,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* As above, but use policy return_value_policy::reference when the return
|
|
||||||
* value is a pointer. This is the default conversion policy for function
|
|
||||||
* arguments when calling Python functions manually from C++ code (i.e. via
|
|
||||||
* handle::operator()). You probably won't need to use this.
|
|
||||||
*/
|
|
||||||
automatic_reference,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference an existing object (i.e. do not create a new copy) and take
|
|
||||||
* ownership. Python will call the destructor and delete operator when the
|
|
||||||
* object's reference count reaches zero. Undefined behavior ensues when
|
|
||||||
* the C++ side does the same..
|
|
||||||
*/
|
|
||||||
take_ownership,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new copy of the returned object, which will be owned by
|
|
||||||
* Python. This policy is comparably safe because the lifetimes of the two
|
|
||||||
* instances are decoupled.
|
|
||||||
*/
|
|
||||||
copy,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use std::move to move the return value contents into a new instance
|
|
||||||
* that will be owned by Python. This policy is comparably safe because the
|
|
||||||
* lifetimes of the two instances (move source and destination) are
|
|
||||||
* decoupled.
|
|
||||||
*/
|
|
||||||
move,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference an existing object, but do not take ownership. The C++ side
|
|
||||||
* is responsible for managing the object's lifetime and deallocating it
|
|
||||||
* when it is no longer used. Warning: undefined behavior will ensue when
|
|
||||||
* the C++ side deletes an object that is still referenced and used by
|
|
||||||
* Python.
|
|
||||||
*/
|
|
||||||
reference,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This policy only applies to methods and properties. It references the
|
|
||||||
* object without taking ownership similar to the above
|
|
||||||
* return_value_policy::reference policy. In contrast to that policy, the
|
|
||||||
* function or property's implicit this argument (called the parent) is
|
|
||||||
* considered to be the the owner of the return value (the child).
|
|
||||||
* pybind11 then couples the lifetime of the parent to the child via a
|
|
||||||
* reference relationship that ensures that the parent cannot be garbage
|
|
||||||
* collected while Python is still using the child. More advanced
|
|
||||||
* variations of this scheme are also possible using combinations of
|
|
||||||
* return_value_policy::reference and the keep_alive call policy
|
|
||||||
*/
|
|
||||||
reference_internal
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void finalize() {
|
||||||
|
delete _ref_counts_map;
|
||||||
|
delete vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class return_value_policy : uint8_t {
|
||||||
|
/**
|
||||||
|
* This is the default return value policy, which falls back to the policy
|
||||||
|
* return_value_policy::take_ownership when the return value is a pointer.
|
||||||
|
* Otherwise, it uses return_value::move or return_value::copy for rvalue
|
||||||
|
* and lvalue references, respectively. See below for a description of what
|
||||||
|
* all of these different policies do.
|
||||||
|
*/
|
||||||
|
automatic = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* As above, but use policy return_value_policy::reference when the return
|
||||||
|
* value is a pointer. This is the default conversion policy for function
|
||||||
|
* arguments when calling Python functions manually from C++ code (i.e. via
|
||||||
|
* handle::operator()). You probably won't need to use this.
|
||||||
|
*/
|
||||||
|
automatic_reference,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference an existing object (i.e. do not create a new copy) and take
|
||||||
|
* ownership. Python will call the destructor and delete operator when the
|
||||||
|
* object's reference count reaches zero. Undefined behavior ensues when
|
||||||
|
* the C++ side does the same..
|
||||||
|
*/
|
||||||
|
take_ownership,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new copy of the returned object, which will be owned by
|
||||||
|
* Python. This policy is comparably safe because the lifetimes of the two
|
||||||
|
* instances are decoupled.
|
||||||
|
*/
|
||||||
|
copy,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use std::move to move the return value contents into a new instance
|
||||||
|
* that will be owned by Python. This policy is comparably safe because the
|
||||||
|
* lifetimes of the two instances (move source and destination) are
|
||||||
|
* decoupled.
|
||||||
|
*/
|
||||||
|
move,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference an existing object, but do not take ownership. The C++ side
|
||||||
|
* is responsible for managing the object's lifetime and deallocating it
|
||||||
|
* when it is no longer used. Warning: undefined behavior will ensue when
|
||||||
|
* the C++ side deletes an object that is still referenced and used by
|
||||||
|
* Python.
|
||||||
|
*/
|
||||||
|
reference,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This policy only applies to methods and properties. It references the
|
||||||
|
* object without taking ownership similar to the above
|
||||||
|
* return_value_policy::reference policy. In contrast to that policy, the
|
||||||
|
* function or property's implicit this argument (called the parent) is
|
||||||
|
* considered to be the the owner of the return value (the child).
|
||||||
|
* pybind11 then couples the lifetime of the parent to the child via a
|
||||||
|
* reference relationship that ensures that the parent cannot be garbage
|
||||||
|
* collected while Python is still using the child. More advanced
|
||||||
|
* variations of this scheme are also possible using combinations of
|
||||||
|
* return_value_policy::reference and the keep_alive call policy
|
||||||
|
*/
|
||||||
|
reference_internal
|
||||||
|
};
|
||||||
} // namespace pybind11
|
} // namespace pybind11
|
||||||
|
|||||||
@ -3,253 +3,249 @@
|
|||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
|
||||||
namespace pybind11 {
|
namespace pybind11 {
|
||||||
class handle;
|
class handle;
|
||||||
class object;
|
class object;
|
||||||
class attr_accessor;
|
class attr_accessor;
|
||||||
class item_accessor;
|
class item_accessor;
|
||||||
class iterator;
|
class iterator;
|
||||||
class str;
|
class str;
|
||||||
class bytes;
|
class bytes;
|
||||||
class iterable;
|
class iterable;
|
||||||
class tuple;
|
class tuple;
|
||||||
class dict;
|
class dict;
|
||||||
class list;
|
class list;
|
||||||
class set;
|
class set;
|
||||||
class function;
|
class function;
|
||||||
class module;
|
class module;
|
||||||
class type;
|
class type;
|
||||||
class bool_;
|
class bool_;
|
||||||
class int_;
|
class int_;
|
||||||
class float_;
|
class float_;
|
||||||
class str;
|
class str;
|
||||||
class bytes;
|
class bytes;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T& _builtin_cast(const handle& obj);
|
T& _builtin_cast(const handle& obj);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T reinterpret_borrow(const handle& h);
|
T reinterpret_borrow(const handle& h);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T reinterpret_steal(const handle& h);
|
T reinterpret_steal(const handle& h);
|
||||||
|
|
||||||
class handle {
|
class handle {
|
||||||
protected:
|
protected:
|
||||||
pkpy::PyVar m_ptr = nullptr;
|
pkpy::PyVar m_ptr = nullptr;
|
||||||
mutable int* ref_count = nullptr;
|
mutable int* ref_count = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
handle() = default;
|
handle() = default;
|
||||||
handle(const handle& h) = default;
|
handle(const handle& h) = default;
|
||||||
handle& operator= (const handle& other) = default;
|
handle& operator= (const handle& other) = default;
|
||||||
|
|
||||||
handle(pkpy::PyVar ptr) : m_ptr(ptr) {}
|
handle(pkpy::PyVar ptr) : m_ptr(ptr) {}
|
||||||
|
|
||||||
pkpy::PyVar ptr() const { return m_ptr; }
|
pkpy::PyVar ptr() const { return m_ptr; }
|
||||||
|
|
||||||
int reference_count() const { return ref_count == nullptr ? 0 : *ref_count; }
|
int reference_count() const { return ref_count == nullptr ? 0 : *ref_count; }
|
||||||
|
|
||||||
const handle& inc_ref() const {
|
const handle& inc_ref() const {
|
||||||
assert(m_ptr != nullptr);
|
assert(m_ptr != nullptr);
|
||||||
if(ref_count == nullptr) {
|
if(ref_count == nullptr) {
|
||||||
auto iter = _ref_counts_map->find(m_ptr);
|
auto iter = _ref_counts_map->find(m_ptr);
|
||||||
if(iter == _ref_counts_map->end()) {
|
if(iter == _ref_counts_map->end()) {
|
||||||
ref_count = ::new int(1);
|
ref_count = ::new int(1);
|
||||||
_ref_counts_map->insert({m_ptr, ref_count});
|
_ref_counts_map->insert({m_ptr, ref_count});
|
||||||
} else {
|
|
||||||
ref_count = iter->second;
|
|
||||||
*ref_count += 1;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
ref_count = iter->second;
|
||||||
*ref_count += 1;
|
*ref_count += 1;
|
||||||
}
|
}
|
||||||
return *this;
|
} else {
|
||||||
|
*ref_count += 1;
|
||||||
}
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
const handle& dec_ref() const {
|
const handle& dec_ref() const {
|
||||||
assert(m_ptr != nullptr);
|
assert(m_ptr != nullptr);
|
||||||
assert(ref_count != nullptr);
|
assert(ref_count != nullptr);
|
||||||
|
|
||||||
*ref_count -= 1;
|
*ref_count -= 1;
|
||||||
try {
|
try {
|
||||||
if(*ref_count == 0) {
|
if(*ref_count == 0) {
|
||||||
_ref_counts_map->erase(m_ptr);
|
_ref_counts_map->erase(m_ptr);
|
||||||
::delete ref_count;
|
::delete ref_count;
|
||||||
ref_count = nullptr;
|
ref_count = nullptr;
|
||||||
}
|
}
|
||||||
} catch(std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; }
|
} catch(std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; }
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
T cast() const;
|
||||||
|
|
||||||
|
explicit operator bool () const { return m_ptr.operator bool (); }
|
||||||
|
|
||||||
|
bool is(const handle& other) const { return m_ptr == other.m_ptr; }
|
||||||
|
|
||||||
|
bool is_none() const { return m_ptr == vm->None; }
|
||||||
|
|
||||||
|
bool in(const handle& other) const {
|
||||||
|
return pkpy::py_cast<bool>(vm, vm->call(vm->py_op("contains"), other.m_ptr, m_ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const handle& other) const {
|
||||||
|
return pkpy::py_cast<bool>(vm, vm->call(vm->py_op("contains"), m_ptr, other.m_ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator begin() const;
|
||||||
|
iterator end() const;
|
||||||
|
|
||||||
|
str doc() const;
|
||||||
|
|
||||||
|
attr_accessor attr(const char* name) const;
|
||||||
|
attr_accessor attr(const handle& name) const;
|
||||||
|
attr_accessor attr(object&& name) const;
|
||||||
|
|
||||||
|
item_accessor operator[] (int64_t key) const;
|
||||||
|
item_accessor operator[] (const char* key) const;
|
||||||
|
item_accessor operator[] (const handle& key) const;
|
||||||
|
item_accessor operator[] (object&& key) const;
|
||||||
|
|
||||||
|
object operator- () const;
|
||||||
|
object operator~() const;
|
||||||
|
|
||||||
|
template <return_value_policy policy = return_value_policy::automatic, typename... Args>
|
||||||
|
object operator() (Args&&... args) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend object operator+ (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator- (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator* (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator% (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator/ (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator| (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator& (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator^ (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator<< (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator>> (const handle& lhs, const handle& rhs);
|
||||||
|
|
||||||
|
friend object operator+= (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator-= (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator*= (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator/= (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator%= (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator|= (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator&= (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator^= (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator<<= (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator>>= (const handle& lhs, const handle& rhs);
|
||||||
|
|
||||||
|
friend object operator== (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator!= (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator< (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator> (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator<= (const handle& lhs, const handle& rhs);
|
||||||
|
friend object operator>= (const handle& lhs, const handle& rhs);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
friend T& _builtin_cast(const handle& obj) {
|
||||||
|
// FIXME: 2.0 does not use Py_<T> anymore
|
||||||
|
static_assert(!std::is_reference_v<T>, "T must not be a reference type.");
|
||||||
|
return obj.ptr().obj_get<T>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(std::is_trivially_copyable_v<handle>);
|
||||||
|
|
||||||
|
class object : public handle {
|
||||||
|
public:
|
||||||
|
object(const object& other) : handle(other) { inc_ref(); }
|
||||||
|
|
||||||
|
object(object&& other) noexcept : handle(other) {
|
||||||
|
other.m_ptr = nullptr;
|
||||||
|
other.ref_count = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
object& operator= (const object& other) {
|
||||||
|
if(this != &other) {
|
||||||
|
dec_ref();
|
||||||
|
m_ptr = other.m_ptr;
|
||||||
|
ref_count = other.ref_count;
|
||||||
|
inc_ref();
|
||||||
}
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
object& operator= (object&& other) noexcept {
|
||||||
template <typename T>
|
if(this != &other) {
|
||||||
T cast() const;
|
dec_ref();
|
||||||
|
m_ptr = other.m_ptr;
|
||||||
explicit operator bool () const { return m_ptr.operator bool (); }
|
ref_count = other.ref_count;
|
||||||
|
|
||||||
bool is(const handle& other) const { return m_ptr == other.m_ptr; }
|
|
||||||
|
|
||||||
bool is_none() const { return m_ptr == vm->None; }
|
|
||||||
|
|
||||||
bool in(const handle& other) const {
|
|
||||||
return pkpy::py_cast<bool>(vm, vm->call(vm->py_op("contains"), other.m_ptr, m_ptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool contains(const handle& other) const {
|
|
||||||
return pkpy::py_cast<bool>(vm, vm->call(vm->py_op("contains"), m_ptr, other.m_ptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator begin() const;
|
|
||||||
iterator end() const;
|
|
||||||
|
|
||||||
str doc() const;
|
|
||||||
|
|
||||||
attr_accessor attr(const char* name) const;
|
|
||||||
attr_accessor attr(const handle& name) const;
|
|
||||||
attr_accessor attr(object&& name) const;
|
|
||||||
|
|
||||||
item_accessor operator[] (int64_t key) const;
|
|
||||||
item_accessor operator[] (const char* key) const;
|
|
||||||
item_accessor operator[] (const handle& key) const;
|
|
||||||
item_accessor operator[] (object&& key) const;
|
|
||||||
|
|
||||||
object operator- () const;
|
|
||||||
object operator~() const;
|
|
||||||
|
|
||||||
template <return_value_policy policy = return_value_policy::automatic, typename... Args>
|
|
||||||
object operator() (Args&&... args) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend object operator+ (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator- (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator* (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator% (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator/ (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator| (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator& (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator^ (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator<< (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator>> (const handle& lhs, const handle& rhs);
|
|
||||||
|
|
||||||
friend object operator+= (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator-= (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator*= (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator/= (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator%= (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator|= (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator&= (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator^= (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator<<= (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator>>= (const handle& lhs, const handle& rhs);
|
|
||||||
|
|
||||||
friend object operator== (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator!= (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator< (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator> (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator<= (const handle& lhs, const handle& rhs);
|
|
||||||
friend object operator>= (const handle& lhs, const handle& rhs);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
friend T& _builtin_cast(const handle& obj) {
|
|
||||||
// FIXME: 2.0 does not use Py_<T> anymore
|
|
||||||
static_assert(!std::is_reference_v<T>, "T must not be a reference type.");
|
|
||||||
return obj.ptr().obj_get<T>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(std::is_trivially_copyable_v<handle>);
|
|
||||||
|
|
||||||
class object : public handle {
|
|
||||||
public:
|
|
||||||
object(const object& other) : handle(other) { inc_ref(); }
|
|
||||||
|
|
||||||
object(object&& other) noexcept : handle(other) {
|
|
||||||
other.m_ptr = nullptr;
|
other.m_ptr = nullptr;
|
||||||
other.ref_count = nullptr;
|
other.ref_count = nullptr;
|
||||||
}
|
}
|
||||||
|
return *this;
|
||||||
object& operator= (const object& other) {
|
|
||||||
if(this != &other) {
|
|
||||||
dec_ref();
|
|
||||||
m_ptr = other.m_ptr;
|
|
||||||
ref_count = other.ref_count;
|
|
||||||
inc_ref();
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
object& operator= (object&& other) noexcept {
|
|
||||||
if(this != &other) {
|
|
||||||
dec_ref();
|
|
||||||
m_ptr = other.m_ptr;
|
|
||||||
ref_count = other.ref_count;
|
|
||||||
other.m_ptr = nullptr;
|
|
||||||
other.ref_count = nullptr;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~object() {
|
|
||||||
if(m_ptr != nullptr) {
|
|
||||||
dec_ref();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
object(const handle& h, bool borrow) : handle(h) {
|
|
||||||
if(borrow) {
|
|
||||||
inc_ref();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
friend T reinterpret_borrow(const handle& h) {
|
|
||||||
return {h, true};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
friend T reinterpret_steal(const handle& h) {
|
|
||||||
return {h, false};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void setattr(const handle& obj, const handle& name, const handle& value);
|
|
||||||
inline void setitem(const handle& obj, const handle& key, const handle& value);
|
|
||||||
|
|
||||||
#define PYBIND11_BINARY_OPERATOR(OP, NAME) \
|
|
||||||
inline object operator OP (const handle& lhs, const handle& rhs) { \
|
|
||||||
return reinterpret_borrow<object>(vm->call(vm->py_op(NAME), lhs.m_ptr, rhs.m_ptr)); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_BINARY_OPERATOR(+, "add");
|
~object() {
|
||||||
PYBIND11_BINARY_OPERATOR(-, "sub");
|
if(m_ptr != nullptr) { dec_ref(); }
|
||||||
PYBIND11_BINARY_OPERATOR(*, "mul");
|
}
|
||||||
PYBIND11_BINARY_OPERATOR(/, "truediv");
|
|
||||||
PYBIND11_BINARY_OPERATOR(%, "mod");
|
|
||||||
PYBIND11_BINARY_OPERATOR(|, "or_");
|
|
||||||
PYBIND11_BINARY_OPERATOR(&, "and_");
|
|
||||||
PYBIND11_BINARY_OPERATOR(^, "xor");
|
|
||||||
PYBIND11_BINARY_OPERATOR(<<, "lshift");
|
|
||||||
PYBIND11_BINARY_OPERATOR(>>, "rshift");
|
|
||||||
|
|
||||||
PYBIND11_BINARY_OPERATOR(+=, "iadd");
|
protected:
|
||||||
PYBIND11_BINARY_OPERATOR(-=, "isub");
|
object(const handle& h, bool borrow) : handle(h) {
|
||||||
PYBIND11_BINARY_OPERATOR(*=, "imul");
|
if(borrow) { inc_ref(); }
|
||||||
PYBIND11_BINARY_OPERATOR(/=, "itruediv");
|
}
|
||||||
PYBIND11_BINARY_OPERATOR(%=, "imod");
|
|
||||||
PYBIND11_BINARY_OPERATOR(|=, "ior");
|
|
||||||
PYBIND11_BINARY_OPERATOR(&=, "iand");
|
|
||||||
PYBIND11_BINARY_OPERATOR(^=, "ixor");
|
|
||||||
PYBIND11_BINARY_OPERATOR(<<=, "ilshift");
|
|
||||||
PYBIND11_BINARY_OPERATOR(>>=, "irshift");
|
|
||||||
|
|
||||||
PYBIND11_BINARY_OPERATOR(==, "eq");
|
template <typename T>
|
||||||
PYBIND11_BINARY_OPERATOR(!=, "ne");
|
friend T reinterpret_borrow(const handle& h) {
|
||||||
PYBIND11_BINARY_OPERATOR(<, "lt");
|
return {h, true};
|
||||||
PYBIND11_BINARY_OPERATOR(>, "gt");
|
}
|
||||||
PYBIND11_BINARY_OPERATOR(<=, "le");
|
|
||||||
PYBIND11_BINARY_OPERATOR(>=, "ge");
|
template <typename T>
|
||||||
|
friend T reinterpret_steal(const handle& h) {
|
||||||
|
return {h, false};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void setattr(const handle& obj, const handle& name, const handle& value);
|
||||||
|
inline void setitem(const handle& obj, const handle& key, const handle& value);
|
||||||
|
|
||||||
|
#define PYBIND11_BINARY_OPERATOR(OP, NAME) \
|
||||||
|
inline object operator OP (const handle& lhs, const handle& rhs) { \
|
||||||
|
return reinterpret_borrow<object>(vm->call(vm->py_op(NAME), lhs.m_ptr, rhs.m_ptr)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_BINARY_OPERATOR(+, "add");
|
||||||
|
PYBIND11_BINARY_OPERATOR(-, "sub");
|
||||||
|
PYBIND11_BINARY_OPERATOR(*, "mul");
|
||||||
|
PYBIND11_BINARY_OPERATOR(/, "truediv");
|
||||||
|
PYBIND11_BINARY_OPERATOR(%, "mod");
|
||||||
|
PYBIND11_BINARY_OPERATOR(|, "or_");
|
||||||
|
PYBIND11_BINARY_OPERATOR(&, "and_");
|
||||||
|
PYBIND11_BINARY_OPERATOR(^, "xor");
|
||||||
|
PYBIND11_BINARY_OPERATOR(<<, "lshift");
|
||||||
|
PYBIND11_BINARY_OPERATOR(>>, "rshift");
|
||||||
|
|
||||||
|
PYBIND11_BINARY_OPERATOR(+=, "iadd");
|
||||||
|
PYBIND11_BINARY_OPERATOR(-=, "isub");
|
||||||
|
PYBIND11_BINARY_OPERATOR(*=, "imul");
|
||||||
|
PYBIND11_BINARY_OPERATOR(/=, "itruediv");
|
||||||
|
PYBIND11_BINARY_OPERATOR(%=, "imod");
|
||||||
|
PYBIND11_BINARY_OPERATOR(|=, "ior");
|
||||||
|
PYBIND11_BINARY_OPERATOR(&=, "iand");
|
||||||
|
PYBIND11_BINARY_OPERATOR(^=, "ixor");
|
||||||
|
PYBIND11_BINARY_OPERATOR(<<=, "ilshift");
|
||||||
|
PYBIND11_BINARY_OPERATOR(>>=, "irshift");
|
||||||
|
|
||||||
|
PYBIND11_BINARY_OPERATOR(==, "eq");
|
||||||
|
PYBIND11_BINARY_OPERATOR(!=, "ne");
|
||||||
|
PYBIND11_BINARY_OPERATOR(<, "lt");
|
||||||
|
PYBIND11_BINARY_OPERATOR(>, "gt");
|
||||||
|
PYBIND11_BINARY_OPERATOR(<=, "le");
|
||||||
|
PYBIND11_BINARY_OPERATOR(>=, "ge");
|
||||||
|
|
||||||
#undef PYBIND11_BINARY_OPERATOR
|
#undef PYBIND11_BINARY_OPERATOR
|
||||||
|
|
||||||
|
|||||||
@ -4,154 +4,154 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace pybind11 {
|
namespace pybind11 {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr bool dependent_false = false;
|
constexpr bool dependent_false = false;
|
||||||
|
|
||||||
template <typename T, typename Tuple>
|
template <typename T, typename Tuple>
|
||||||
struct tuple_push_front;
|
struct tuple_push_front;
|
||||||
|
|
||||||
template <typename T, typename... Ts>
|
template <typename T, typename... Ts>
|
||||||
struct tuple_push_front<T, std::tuple<Ts...>> {
|
struct tuple_push_front<T, std::tuple<Ts...>> {
|
||||||
using type = std::tuple<T, Ts...>;
|
using type = std::tuple<T, Ts...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Tuple>
|
||||||
|
using tuple_push_front_t = typename tuple_push_front<T, Tuple>::type;
|
||||||
|
|
||||||
|
// traits for function types
|
||||||
|
template <typename Fn>
|
||||||
|
struct function_traits {
|
||||||
|
static_assert(dependent_false<Fn>, "unsupported function type");
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PYBIND11_FUNCTION_TRAITS_SPECIALIZE(qualifiers) \
|
||||||
|
template <typename R, typename... Args> \
|
||||||
|
struct function_traits<R(Args...) qualifiers> { \
|
||||||
|
using return_type = R; \
|
||||||
|
using args_type = std::tuple<Args...>; \
|
||||||
|
constexpr static std::size_t args_count = sizeof...(Args); \
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename Tuple>
|
PYBIND11_FUNCTION_TRAITS_SPECIALIZE()
|
||||||
using tuple_push_front_t = typename tuple_push_front<T, Tuple>::type;
|
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(&)
|
||||||
|
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(const)
|
||||||
// traits for function types
|
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(const&)
|
||||||
template <typename Fn>
|
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(noexcept)
|
||||||
struct function_traits {
|
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(& noexcept)
|
||||||
static_assert(dependent_false<Fn>, "unsupported function type");
|
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(const noexcept)
|
||||||
};
|
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(const& noexcept)
|
||||||
|
|
||||||
#define PYBIND11_FUNCTION_TRAITS_SPECIALIZE(qualifiers) \
|
|
||||||
template <typename R, typename... Args> \
|
|
||||||
struct function_traits<R(Args...) qualifiers> { \
|
|
||||||
using return_type = R; \
|
|
||||||
using args_type = std::tuple<Args...>; \
|
|
||||||
constexpr static std::size_t args_count = sizeof...(Args); \
|
|
||||||
};
|
|
||||||
|
|
||||||
PYBIND11_FUNCTION_TRAITS_SPECIALIZE()
|
|
||||||
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(&)
|
|
||||||
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(const)
|
|
||||||
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(const&)
|
|
||||||
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(noexcept)
|
|
||||||
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(& noexcept)
|
|
||||||
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(const noexcept)
|
|
||||||
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(const& noexcept)
|
|
||||||
|
|
||||||
#undef PYBIND11_FUNCTION_TRAITS_SPECIALIZE
|
#undef PYBIND11_FUNCTION_TRAITS_SPECIALIZE
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using function_return_t = typename function_traits<T>::return_type;
|
using function_return_t = typename function_traits<T>::return_type;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using function_args_t = typename function_traits<T>::args_type;
|
using function_args_t = typename function_traits<T>::args_type;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr std::size_t function_args_count = function_traits<T>::args_count;
|
constexpr std::size_t function_args_count = function_traits<T>::args_count;
|
||||||
|
|
||||||
// traits for member pointers
|
// traits for member pointers
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct member_traits;
|
struct member_traits;
|
||||||
|
|
||||||
template <typename M, typename C>
|
template <typename M, typename C>
|
||||||
struct member_traits<M C::*> {
|
struct member_traits<M C::*> {
|
||||||
using member_type = M;
|
using member_type = M;
|
||||||
using class_type = C;
|
using class_type = C;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using member_type_t = typename member_traits<T>::member_type;
|
using member_type_t = typename member_traits<T>::member_type;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using class_type_t = typename member_traits<T>::class_type;
|
using class_type_t = typename member_traits<T>::class_type;
|
||||||
|
|
||||||
// some traits for distinguishing between function pointers, member function pointers and
|
// some traits for distinguishing between function pointers, member function pointers and
|
||||||
// functors
|
// functors
|
||||||
using std::is_member_function_pointer_v;
|
using std::is_member_function_pointer_v;
|
||||||
using std::is_member_object_pointer_v;
|
using std::is_member_object_pointer_v;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr inline bool is_function_pointer_v = std::is_function_v<std::remove_pointer_t<T>>;
|
constexpr inline bool is_function_pointer_v = std::is_function_v<std::remove_pointer_t<T>>;
|
||||||
|
|
||||||
template <typename T, typename U = void>
|
template <typename T, typename U = void>
|
||||||
constexpr bool is_functor_v = false;
|
constexpr bool is_functor_v = false;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr inline bool is_functor_v<T, std::void_t<decltype(&T::operator())>> = true;
|
constexpr inline bool is_functor_v<T, std::void_t<decltype(&T::operator())>> = true;
|
||||||
|
|
||||||
template <typename T, typename SFINAE = void>
|
template <typename T, typename SFINAE = void>
|
||||||
struct callable_traits;
|
struct callable_traits;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct callable_traits<T, std::enable_if_t<is_member_function_pointer_v<T>>> {
|
struct callable_traits<T, std::enable_if_t<is_member_function_pointer_v<T>>> {
|
||||||
using args_type = tuple_push_front_t<class_type_t<T>&, function_args_t<member_type_t<T>>>;
|
using args_type = tuple_push_front_t<class_type_t<T>&, function_args_t<member_type_t<T>>>;
|
||||||
using return_type = function_return_t<member_type_t<T>>;
|
using return_type = function_return_t<member_type_t<T>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct callable_traits<T, std::enable_if_t<is_function_pointer_v<T>>> {
|
struct callable_traits<T, std::enable_if_t<is_function_pointer_v<T>>> {
|
||||||
using args_type = function_args_t<std::remove_pointer<T>>;
|
using args_type = function_args_t<std::remove_pointer<T>>;
|
||||||
using return_type = function_return_t<std::remove_pointer<T>>;
|
using return_type = function_return_t<std::remove_pointer<T>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct callable_traits<T, std::enable_if_t<is_functor_v<T>>> {
|
struct callable_traits<T, std::enable_if_t<is_functor_v<T>>> {
|
||||||
using args_type = function_args_t<member_type_t<decltype(&T::operator())>>;
|
using args_type = function_args_t<member_type_t<decltype(&T::operator())>>;
|
||||||
using return_type = function_return_t<member_type_t<decltype(&T::operator())>>;
|
using return_type = function_return_t<member_type_t<decltype(&T::operator())>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Callable>
|
template <typename Callable>
|
||||||
using callable_args_t = typename callable_traits<Callable>::args_type;
|
using callable_args_t = typename callable_traits<Callable>::args_type;
|
||||||
|
|
||||||
template <typename Callable>
|
template <typename Callable>
|
||||||
using callable_return_t = typename callable_traits<Callable>::return_type;
|
using callable_return_t = typename callable_traits<Callable>::return_type;
|
||||||
|
|
||||||
template <typename Callable>
|
template <typename Callable>
|
||||||
constexpr std::size_t callable_args_count_v = std::tuple_size_v<callable_args_t<Callable>>;
|
constexpr std::size_t callable_args_count_v = std::tuple_size_v<callable_args_t<Callable>>;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct type_identity {
|
struct type_identity {
|
||||||
using type = T;
|
using type = T;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||||
|
|
||||||
template <typename T, typename... Ts>
|
template <typename T, typename... Ts>
|
||||||
constexpr inline std::size_t types_count_v = (std::is_same_v<T, Ts> + ...);
|
constexpr inline std::size_t types_count_v = (std::is_same_v<T, Ts> + ...);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr inline std::size_t types_count_v<T> = 0;
|
constexpr inline std::size_t types_count_v<T> = 0;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct value_wrapper {
|
struct value_wrapper {
|
||||||
T* pointer;
|
T* pointer;
|
||||||
|
|
||||||
operator T& () { return *pointer; }
|
operator T& () { return *pointer; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct value_wrapper<T*> {
|
struct value_wrapper<T*> {
|
||||||
T* pointer;
|
T* pointer;
|
||||||
|
|
||||||
operator T* () { return pointer; }
|
operator T* () { return pointer; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct value_wrapper<T&> {
|
struct value_wrapper<T&> {
|
||||||
T* pointer;
|
T* pointer;
|
||||||
|
|
||||||
operator T& () { return *pointer; }
|
operator T& () { return *pointer; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct value_wrapper<T&&> {
|
struct value_wrapper<T&&> {
|
||||||
T* pointer;
|
T* pointer;
|
||||||
|
|
||||||
operator T&& () { return std::move(*pointer); }
|
operator T&& () { return std::move(*pointer); }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pybind11
|
} // namespace pybind11
|
||||||
|
|||||||
@ -3,216 +3,206 @@
|
|||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
|
||||||
namespace pybind11 {
|
namespace pybind11 {
|
||||||
class type : public object {
|
class type : public object {
|
||||||
public:
|
public:
|
||||||
using object::object;
|
using object::object;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static handle handle_of();
|
static handle handle_of();
|
||||||
};
|
};
|
||||||
|
|
||||||
class iterable : public object {
|
class iterable : public object {
|
||||||
public:
|
public:
|
||||||
using object::object;
|
using object::object;
|
||||||
iterable() = delete;
|
iterable() = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
class iterator : public object {
|
class iterator : public object {
|
||||||
public:
|
public:
|
||||||
using object::object;
|
using object::object;
|
||||||
iterator() = delete;
|
iterator() = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
class list : public object {
|
class list : public object {
|
||||||
public:
|
public:
|
||||||
using object::object;
|
using object::object;
|
||||||
|
|
||||||
list() : object(vm->new_object<pkpy::List>(pkpy::VM::tp_list), true) {}
|
list() : object(vm->new_object<pkpy::List>(pkpy::VM::tp_list), true) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class tuple : public object {
|
class tuple : public object {
|
||||||
public:
|
public:
|
||||||
using object::object;
|
using object::object;
|
||||||
|
|
||||||
tuple(int n) : object(vm->new_object<pkpy::Tuple>(pkpy::VM::tp_tuple, n), true) {}
|
tuple(int n) : object(vm->new_object<pkpy::Tuple>(pkpy::VM::tp_tuple, n), true) {}
|
||||||
|
|
||||||
//& operator[](int i){ return _args[i]; }
|
//& operator[](int i){ return _args[i]; }
|
||||||
// PyVar operator[](int i) const { return _args[i]; }
|
// PyVar operator[](int i) const { return _args[i]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class set : public object {
|
class set : public object {
|
||||||
public:
|
public:
|
||||||
using object::object;
|
using object::object;
|
||||||
// set() : object(vm->new_object<pkpy::Se>(pkpy::VM::tp_set), true) {}
|
// set() : object(vm->new_object<pkpy::Se>(pkpy::VM::tp_set), true) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class dict : public object {
|
class dict : public object {
|
||||||
public:
|
public:
|
||||||
using object::object;
|
using object::object;
|
||||||
|
|
||||||
dict() : object(vm->new_object<pkpy::Dict>(pkpy::VM::tp_dict), true) {}
|
dict() : object(vm->new_object<pkpy::Dict>(pkpy::VM::tp_dict), true) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class str : public object {
|
class str : public object {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using object::object;
|
using object::object;
|
||||||
str(const char* c, int len) :
|
str(const char* c, int len) :
|
||||||
object(vm->new_object<pkpy::Str>(pkpy::VM::tp_str, c, len), true) {
|
object(vm->new_object<pkpy::Str>(pkpy::VM::tp_str, c, len), true) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
str(const char* c = "") : str(c, strlen(c)) {}
|
str(const char* c = "") : str(c, strlen(c)) {}
|
||||||
|
|
||||||
str(const std::string& s) : str(s.data(), s.size()) {}
|
str(const std::string& s) : str(s.data(), s.size()) {}
|
||||||
|
|
||||||
str(std::string_view sv) : str(sv.data(), sv.size()) {}
|
str(std::string_view sv) : str(sv.data(), sv.size()) {}
|
||||||
|
|
||||||
explicit str(const bytes& b);
|
explicit str(const bytes& b);
|
||||||
explicit str(handle h);
|
explicit str(handle h);
|
||||||
operator std::string () const;
|
operator std::string () const;
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
str format(Args&&... args) const;
|
str format(Args&&... args) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class int_ : public object {
|
class int_ : public object {
|
||||||
public:
|
public:
|
||||||
using object::object;
|
using object::object;
|
||||||
|
|
||||||
int_(int64_t value) : object(pkpy::py_var(vm, value), true) {}
|
int_(int64_t value) : object(pkpy::py_var(vm, value), true) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class float_ : public object {
|
class float_ : public object {
|
||||||
public:
|
public:
|
||||||
using object::object;
|
using object::object;
|
||||||
|
|
||||||
float_(double value) : object(pkpy::py_var(vm, value), true) {}
|
float_(double value) : object(pkpy::py_var(vm, value), true) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class bool_ : public object {
|
class bool_ : public object {
|
||||||
public:
|
public:
|
||||||
using object::object;
|
using object::object;
|
||||||
|
|
||||||
bool_(bool value) : object(pkpy::py_var(vm, value), true) {}
|
bool_(bool value) : object(pkpy::py_var(vm, value), true) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class function : public object {
|
class function : public object {
|
||||||
public:
|
public:
|
||||||
using object::object;
|
using object::object;
|
||||||
};
|
};
|
||||||
|
|
||||||
class attr_accessor : public object {
|
class attr_accessor : public object {
|
||||||
private:
|
private:
|
||||||
object key;
|
object key;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
attr_accessor(const object& obj, T&& key) : object(obj), key(std::forward<T>(key)){};
|
attr_accessor(const object& obj, T&& key) : object(obj), key(std::forward<T>(key)){};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
attr_accessor& operator= (T&& value) & {
|
|
||||||
static_assert(std::is_base_of_v<object, std::decay_t<T>>,
|
|
||||||
"T must be derived from object");
|
|
||||||
m_ptr = std::forward<T>(value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
attr_accessor& operator= (T&& value) && {
|
|
||||||
static_assert(std::is_base_of_v<object, std::decay_t<T>>,
|
|
||||||
"T must be derived from object");
|
|
||||||
setattr(*this, key, std::forward<T>(value));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline attr_accessor handle::attr(const char* name) const {
|
|
||||||
return attr_accessor(reinterpret_borrow<object>(*this), str(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline attr_accessor handle::attr(const handle& name) const {
|
|
||||||
return attr_accessor(reinterpret_borrow<object>(*this), reinterpret_borrow<object>(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline attr_accessor handle::attr(object&& name) const {
|
|
||||||
return attr_accessor(reinterpret_borrow<object>(*this), std::move(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
class item_accessor : public object {
|
|
||||||
public:
|
|
||||||
object key;
|
|
||||||
|
|
||||||
public:
|
|
||||||
template <typename T>
|
|
||||||
item_accessor(const object& obj, T&& key) : object(obj), key(std::forward<T>(key)){};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
item_accessor& operator= (T&& value) & {
|
|
||||||
static_assert(std::is_base_of_v<object, std::decay_t<T>>,
|
|
||||||
"T must be derived from object");
|
|
||||||
m_ptr = std::forward<T>(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
item_accessor& operator= (object&& value) && {
|
|
||||||
static_assert(std::is_base_of_v<object, std::decay_t<T>>,
|
|
||||||
"T must be derived from object");
|
|
||||||
setitem(*this, key, std::forward<T>(value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline item_accessor handle::operator[] (int64_t key) const {
|
|
||||||
return item_accessor(reinterpret_borrow<object>(*this), int_(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline item_accessor handle::operator[] (const char* key) const {
|
|
||||||
return item_accessor(reinterpret_borrow<object>(*this), str(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline item_accessor handle::operator[] (const handle& key) const {
|
|
||||||
return item_accessor(reinterpret_borrow<object>(*this), reinterpret_borrow<object>(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline item_accessor handle::operator[] (object&& key) const {
|
|
||||||
return item_accessor(reinterpret_borrow<object>(*this), std::move(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
class args : public tuple {
|
|
||||||
using tuple::tuple;
|
|
||||||
};
|
|
||||||
|
|
||||||
class kwargs : public dict {
|
|
||||||
using dict::dict;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
handle type::handle_of() {
|
attr_accessor& operator= (T&& value) & {
|
||||||
if constexpr(std::is_same_v<T, object>) {
|
static_assert(std::is_base_of_v<object, std::decay_t<T>>, "T must be derived from object");
|
||||||
return vm->_t(vm->tp_object);
|
m_ptr = std::forward<T>(value);
|
||||||
}
|
return *this;
|
||||||
#define PYBIND11_TYPE_MAPPER(type, tp) \
|
|
||||||
else if constexpr(std::is_same_v<T, type>) { \
|
|
||||||
return vm->_t(vm->tp); \
|
|
||||||
}
|
}
|
||||||
PYBIND11_TYPE_MAPPER(type, tp_type)
|
|
||||||
PYBIND11_TYPE_MAPPER(str, tp_str)
|
|
||||||
PYBIND11_TYPE_MAPPER(int_, tp_int)
|
|
||||||
PYBIND11_TYPE_MAPPER(float_, tp_float)
|
|
||||||
PYBIND11_TYPE_MAPPER(bool_, tp_bool)
|
|
||||||
PYBIND11_TYPE_MAPPER(list, tp_list)
|
|
||||||
PYBIND11_TYPE_MAPPER(tuple, tp_tuple)
|
|
||||||
PYBIND11_TYPE_MAPPER(args, tp_tuple)
|
|
||||||
PYBIND11_TYPE_MAPPER(dict, tp_dict)
|
|
||||||
PYBIND11_TYPE_MAPPER(kwargs, tp_dict)
|
|
||||||
#undef PYBIND11_TYPE_MAPPER
|
|
||||||
else {
|
|
||||||
auto result = vm->_cxx_typeid_map.find(typeid(T));
|
|
||||||
if(result != vm->_cxx_typeid_map.end()) {
|
|
||||||
return vm->_t(result->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
vm->TypeError("Type not registered");
|
template <typename T>
|
||||||
}
|
attr_accessor& operator= (T&& value) && {
|
||||||
|
static_assert(std::is_base_of_v<object, std::decay_t<T>>, "T must be derived from object");
|
||||||
|
setattr(*this, key, std::forward<T>(value));
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline attr_accessor handle::attr(const char* name) const {
|
||||||
|
return attr_accessor(reinterpret_borrow<object>(*this), str(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline attr_accessor handle::attr(const handle& name) const {
|
||||||
|
return attr_accessor(reinterpret_borrow<object>(*this), reinterpret_borrow<object>(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline attr_accessor handle::attr(object&& name) const {
|
||||||
|
return attr_accessor(reinterpret_borrow<object>(*this), std::move(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
class item_accessor : public object {
|
||||||
|
public:
|
||||||
|
object key;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
item_accessor(const object& obj, T&& key) : object(obj), key(std::forward<T>(key)){};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
item_accessor& operator= (T&& value) & {
|
||||||
|
static_assert(std::is_base_of_v<object, std::decay_t<T>>, "T must be derived from object");
|
||||||
|
m_ptr = std::forward<T>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
item_accessor& operator= (object&& value) && {
|
||||||
|
static_assert(std::is_base_of_v<object, std::decay_t<T>>, "T must be derived from object");
|
||||||
|
setitem(*this, key, std::forward<T>(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline item_accessor handle::operator[] (int64_t key) const {
|
||||||
|
return item_accessor(reinterpret_borrow<object>(*this), int_(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline item_accessor handle::operator[] (const char* key) const {
|
||||||
|
return item_accessor(reinterpret_borrow<object>(*this), str(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline item_accessor handle::operator[] (const handle& key) const {
|
||||||
|
return item_accessor(reinterpret_borrow<object>(*this), reinterpret_borrow<object>(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline item_accessor handle::operator[] (object&& key) const {
|
||||||
|
return item_accessor(reinterpret_borrow<object>(*this), std::move(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
class args : public tuple {
|
||||||
|
using tuple::tuple;
|
||||||
|
};
|
||||||
|
|
||||||
|
class kwargs : public dict {
|
||||||
|
using dict::dict;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
handle type::handle_of() {
|
||||||
|
if constexpr(std::is_same_v<T, object>) { return vm->_t(vm->tp_object); }
|
||||||
|
#define PYBIND11_TYPE_MAPPER(type, tp) \
|
||||||
|
else if constexpr(std::is_same_v<T, type>) { return vm->_t(vm->tp); }
|
||||||
|
PYBIND11_TYPE_MAPPER(type, tp_type)
|
||||||
|
PYBIND11_TYPE_MAPPER(str, tp_str)
|
||||||
|
PYBIND11_TYPE_MAPPER(int_, tp_int)
|
||||||
|
PYBIND11_TYPE_MAPPER(float_, tp_float)
|
||||||
|
PYBIND11_TYPE_MAPPER(bool_, tp_bool)
|
||||||
|
PYBIND11_TYPE_MAPPER(list, tp_list)
|
||||||
|
PYBIND11_TYPE_MAPPER(tuple, tp_tuple)
|
||||||
|
PYBIND11_TYPE_MAPPER(args, tp_tuple)
|
||||||
|
PYBIND11_TYPE_MAPPER(dict, tp_dict)
|
||||||
|
PYBIND11_TYPE_MAPPER(kwargs, tp_dict)
|
||||||
|
#undef PYBIND11_TYPE_MAPPER
|
||||||
|
else {
|
||||||
|
auto result = vm->_cxx_typeid_map.find(typeid(T));
|
||||||
|
if(result != vm->_cxx_typeid_map.end()) { return vm->_t(result->second); }
|
||||||
|
|
||||||
|
vm->TypeError("Type not registered");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pybind11
|
} // namespace pybind11
|
||||||
|
|||||||
@ -16,7 +16,7 @@ def get_all_files(root: str):
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
files = []
|
files = []
|
||||||
# files.extend(get_all_files('include'))
|
files.extend(get_all_files('include'))
|
||||||
# files.extend(get_all_files('src'))
|
files.extend(get_all_files('src'))
|
||||||
files.extend(get_all_files('src2'))
|
files.extend(get_all_files('src2'))
|
||||||
subprocess.run(['clang-format', '-i'] + files, check=True)
|
subprocess.run(['clang-format', '-i'] + files, check=True)
|
||||||
|
|||||||
@ -3,20 +3,20 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
void any::__bad_any_cast(const std::type_index expected, const std::type_index actual){
|
void any::__bad_any_cast(const std::type_index expected, const std::type_index actual) {
|
||||||
char error[256];
|
char error[256];
|
||||||
snprintf(error, sizeof(error), "bad_any_cast: expected %s, got %s", expected.name(), actual.name());
|
snprintf(error, sizeof(error), "bad_any_cast: expected %s, got %s", expected.name(), actual.name());
|
||||||
throw std::runtime_error(error);
|
throw std::runtime_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
any::any(any&& other) noexcept: data(other.data), _vt(other._vt){
|
any::any(any&& other) noexcept : data(other.data), _vt(other._vt) {
|
||||||
other.data = nullptr;
|
other.data = nullptr;
|
||||||
other._vt = nullptr;
|
other._vt = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
any& any::operator=(any&& other) noexcept{
|
any& any::operator= (any&& other) noexcept {
|
||||||
if(data) _vt->deleter(data);
|
if(data) _vt->deleter(data);
|
||||||
data = other.data;
|
data = other.data;
|
||||||
_vt = other._vt;
|
_vt = other._vt;
|
||||||
@ -25,4 +25,4 @@ any& any::operator=(any&& other) noexcept{
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -6,28 +6,28 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
struct LinkedListNode{
|
struct LinkedListNode {
|
||||||
LinkedListNode* prev;
|
LinkedListNode* prev;
|
||||||
LinkedListNode* next;
|
LinkedListNode* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
struct DoubleLinkedList{
|
struct DoubleLinkedList {
|
||||||
static_assert(std::is_base_of_v<LinkedListNode, T>);
|
static_assert(std::is_base_of_v<LinkedListNode, T>);
|
||||||
int _size;
|
int _size;
|
||||||
LinkedListNode head;
|
LinkedListNode head;
|
||||||
LinkedListNode tail;
|
LinkedListNode tail;
|
||||||
|
|
||||||
DoubleLinkedList(): _size(0){
|
DoubleLinkedList() : _size(0) {
|
||||||
head.prev = nullptr;
|
head.prev = nullptr;
|
||||||
head.next = &tail;
|
head.next = &tail;
|
||||||
tail.prev = &head;
|
tail.prev = &head;
|
||||||
tail.next = nullptr;
|
tail.next = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(T* node){
|
void push_back(T* node) {
|
||||||
node->prev = tail.prev;
|
node->prev = tail.prev;
|
||||||
node->next = &tail;
|
node->next = &tail;
|
||||||
tail.prev->next = node;
|
tail.prev->next = node;
|
||||||
@ -35,7 +35,7 @@ struct DoubleLinkedList{
|
|||||||
_size++;
|
_size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_front(T* node){
|
void push_front(T* node) {
|
||||||
node->prev = &head;
|
node->prev = &head;
|
||||||
node->next = head.next;
|
node->next = head.next;
|
||||||
head.next->prev = node;
|
head.next->prev = node;
|
||||||
@ -43,14 +43,14 @@ struct DoubleLinkedList{
|
|||||||
_size++;
|
_size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_back(){
|
void pop_back() {
|
||||||
assert(!empty());
|
assert(!empty());
|
||||||
tail.prev->prev->next = &tail;
|
tail.prev->prev->next = &tail;
|
||||||
tail.prev = tail.prev->prev;
|
tail.prev = tail.prev->prev;
|
||||||
_size--;
|
_size--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_front(){
|
void pop_front() {
|
||||||
assert(!empty());
|
assert(!empty());
|
||||||
head.next->next->prev = &head;
|
head.next->next->prev = &head;
|
||||||
head.next = head.next->next;
|
head.next = head.next->next;
|
||||||
@ -67,22 +67,20 @@ struct DoubleLinkedList{
|
|||||||
return static_cast<T*>(head.next);
|
return static_cast<T*>(head.next);
|
||||||
}
|
}
|
||||||
|
|
||||||
void erase(T* node){
|
void erase(T* node) {
|
||||||
node->prev->next = node->next;
|
node->prev->next = node->next;
|
||||||
node->next->prev = node->prev;
|
node->next->prev = node->prev;
|
||||||
_size--;
|
_size--;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const {
|
bool empty() const { return _size == 0; }
|
||||||
return _size == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int size() const { return _size; }
|
int size() const { return _size; }
|
||||||
|
|
||||||
template<typename Func>
|
template <typename Func>
|
||||||
void apply(Func func){
|
void apply(Func func) {
|
||||||
LinkedListNode* p = head.next;
|
LinkedListNode* p = head.next;
|
||||||
while(p != &tail){
|
while(p != &tail) {
|
||||||
LinkedListNode* next = p->next;
|
LinkedListNode* next = p->next;
|
||||||
func(static_cast<T*>(p));
|
func(static_cast<T*>(p));
|
||||||
p = next;
|
p = next;
|
||||||
@ -90,42 +88,41 @@ struct DoubleLinkedList{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<int __BlockSize>
|
template <int __BlockSize>
|
||||||
struct MemoryPool{
|
struct MemoryPool {
|
||||||
static const int __MaxBlocks = 256*1024 / __BlockSize;
|
const static int __MaxBlocks = 256 * 1024 / __BlockSize;
|
||||||
static const int __MinArenaCount = PK_GC_MIN_THRESHOLD*100 / (256*1024);
|
const static int __MinArenaCount = PK_GC_MIN_THRESHOLD * 100 / (256 * 1024);
|
||||||
|
|
||||||
struct Block{
|
struct Block {
|
||||||
void* arena;
|
void* arena;
|
||||||
char data[__BlockSize];
|
char data[__BlockSize];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Arena: LinkedListNode{
|
struct Arena : LinkedListNode {
|
||||||
Block _blocks[__MaxBlocks];
|
Block _blocks[__MaxBlocks];
|
||||||
Block* _free_list[__MaxBlocks];
|
Block* _free_list[__MaxBlocks];
|
||||||
int _free_list_size;
|
int _free_list_size;
|
||||||
|
|
||||||
Arena(): _free_list_size(__MaxBlocks) {
|
Arena() : _free_list_size(__MaxBlocks) {
|
||||||
for(int i=0; i<__MaxBlocks; i++){
|
for(int i = 0; i < __MaxBlocks; i++) {
|
||||||
_blocks[i].arena = this;
|
_blocks[i].arena = this;
|
||||||
_free_list[i] = &_blocks[i];
|
_free_list[i] = &_blocks[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const { return _free_list_size == 0; }
|
bool empty() const { return _free_list_size == 0; }
|
||||||
|
|
||||||
bool full() const { return _free_list_size == __MaxBlocks; }
|
bool full() const { return _free_list_size == __MaxBlocks; }
|
||||||
|
|
||||||
size_t allocated_size() const{
|
size_t allocated_size() const { return __BlockSize * (__MaxBlocks - _free_list_size); }
|
||||||
return __BlockSize * (__MaxBlocks - _free_list_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
Block* alloc(){
|
Block* alloc() {
|
||||||
assert(!empty());
|
assert(!empty());
|
||||||
_free_list_size--;
|
_free_list_size--;
|
||||||
return _free_list[_free_list_size];
|
return _free_list[_free_list_size];
|
||||||
}
|
}
|
||||||
|
|
||||||
void dealloc(Block* block){
|
void dealloc(Block* block) {
|
||||||
assert(!full());
|
assert(!full());
|
||||||
_free_list[_free_list_size] = block;
|
_free_list[_free_list_size] = block;
|
||||||
_free_list_size++;
|
_free_list_size++;
|
||||||
@ -134,71 +131,73 @@ struct MemoryPool{
|
|||||||
|
|
||||||
MemoryPool() = default;
|
MemoryPool() = default;
|
||||||
MemoryPool(const MemoryPool&) = delete;
|
MemoryPool(const MemoryPool&) = delete;
|
||||||
MemoryPool& operator=(const MemoryPool&) = delete;
|
MemoryPool& operator= (const MemoryPool&) = delete;
|
||||||
MemoryPool(MemoryPool&&) = delete;
|
MemoryPool(MemoryPool&&) = delete;
|
||||||
MemoryPool& operator=(MemoryPool&&) = delete;
|
MemoryPool& operator= (MemoryPool&&) = delete;
|
||||||
|
|
||||||
DoubleLinkedList<Arena> _arenas;
|
DoubleLinkedList<Arena> _arenas;
|
||||||
DoubleLinkedList<Arena> _empty_arenas;
|
DoubleLinkedList<Arena> _empty_arenas;
|
||||||
|
|
||||||
void* alloc(size_t size){
|
void* alloc(size_t size) {
|
||||||
PK_GLOBAL_SCOPE_LOCK();
|
PK_GLOBAL_SCOPE_LOCK();
|
||||||
if(size > __BlockSize){
|
if(size > __BlockSize) {
|
||||||
void* p = std::malloc(sizeof(void*) + size);
|
void* p = std::malloc(sizeof(void*) + size);
|
||||||
std::memset(p, 0, sizeof(void*));
|
std::memset(p, 0, sizeof(void*));
|
||||||
return (char*)p + sizeof(void*);
|
return (char*)p + sizeof(void*);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_arenas.empty()){
|
if(_arenas.empty()) { _arenas.push_back(new Arena()); }
|
||||||
_arenas.push_back(new Arena());
|
|
||||||
}
|
|
||||||
Arena* arena = _arenas.back();
|
Arena* arena = _arenas.back();
|
||||||
void* p = arena->alloc()->data;
|
void* p = arena->alloc()->data;
|
||||||
if(arena->empty()){
|
if(arena->empty()) {
|
||||||
_arenas.pop_back();
|
_arenas.pop_back();
|
||||||
_empty_arenas.push_back(arena);
|
_empty_arenas.push_back(arena);
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dealloc(void* p){
|
void dealloc(void* p) {
|
||||||
PK_GLOBAL_SCOPE_LOCK();
|
PK_GLOBAL_SCOPE_LOCK();
|
||||||
assert(p != nullptr);
|
assert(p != nullptr);
|
||||||
Block* block = (Block*)((char*)p - sizeof(void*));
|
Block* block = (Block*)((char*)p - sizeof(void*));
|
||||||
if(block->arena == nullptr){
|
if(block->arena == nullptr) {
|
||||||
std::free(block);
|
std::free(block);
|
||||||
}else{
|
} else {
|
||||||
Arena* arena = (Arena*)block->arena;
|
Arena* arena = (Arena*)block->arena;
|
||||||
if(arena->empty()){
|
if(arena->empty()) {
|
||||||
_empty_arenas.erase(arena);
|
_empty_arenas.erase(arena);
|
||||||
_arenas.push_front(arena);
|
_arenas.push_front(arena);
|
||||||
arena->dealloc(block);
|
arena->dealloc(block);
|
||||||
}else{
|
} else {
|
||||||
arena->dealloc(block);
|
arena->dealloc(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void shrink_to_fit(){
|
void shrink_to_fit() {
|
||||||
PK_GLOBAL_SCOPE_LOCK();
|
PK_GLOBAL_SCOPE_LOCK();
|
||||||
if(_arenas.size() < __MinArenaCount) return;
|
if(_arenas.size() < __MinArenaCount) return;
|
||||||
_arenas.apply([this](Arena* arena){
|
_arenas.apply([this](Arena* arena) {
|
||||||
if(arena->full()){
|
if(arena->full()) {
|
||||||
_arenas.erase(arena);
|
_arenas.erase(arena);
|
||||||
delete arena;
|
delete arena;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
~MemoryPool(){
|
~MemoryPool() {
|
||||||
_arenas.apply([](Arena* arena){ delete arena; });
|
_arenas.apply([](Arena* arena) {
|
||||||
_empty_arenas.apply([](Arena* arena){ delete arena; });
|
delete arena;
|
||||||
|
});
|
||||||
|
_empty_arenas.apply([](Arena* arena) {
|
||||||
|
delete arena;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<int BlockSize, int BlockCount>
|
template <int BlockSize, int BlockCount>
|
||||||
struct FixedMemoryPool{
|
struct FixedMemoryPool {
|
||||||
struct Block{
|
struct Block {
|
||||||
char data[BlockSize];
|
char data[BlockSize];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -211,31 +210,29 @@ struct FixedMemoryPool{
|
|||||||
|
|
||||||
FixedMemoryPool() {
|
FixedMemoryPool() {
|
||||||
_free_list_end = _free_list + BlockCount;
|
_free_list_end = _free_list + BlockCount;
|
||||||
for(int i = 0; i < BlockCount; ++i){
|
for(int i = 0; i < BlockCount; ++i) {
|
||||||
_free_list[i] = _blocks + i;
|
_free_list[i] = _blocks + i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_valid(void* p){
|
bool is_valid(void* p) { return p >= _blocks && p < _blocks + BlockCount; }
|
||||||
return p >= _blocks && p < _blocks + BlockCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* alloc(){
|
void* alloc() {
|
||||||
PK_GLOBAL_SCOPE_LOCK()
|
PK_GLOBAL_SCOPE_LOCK()
|
||||||
if(_free_list_end != _free_list){
|
if(_free_list_end != _free_list) {
|
||||||
--_free_list_end;
|
--_free_list_end;
|
||||||
return *_free_list_end;
|
return *_free_list_end;
|
||||||
}else{
|
} else {
|
||||||
return std::malloc(BlockSize);
|
return std::malloc(BlockSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dealloc(void* p){
|
void dealloc(void* p) {
|
||||||
PK_GLOBAL_SCOPE_LOCK()
|
PK_GLOBAL_SCOPE_LOCK()
|
||||||
if(is_valid(p)){
|
if(is_valid(p)) {
|
||||||
*_free_list_end = static_cast<Block*>(p);
|
*_free_list_end = static_cast<Block*>(p);
|
||||||
++_free_list_end;
|
++_free_list_end;
|
||||||
}else{
|
} else {
|
||||||
std::free(p);
|
std::free(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,12 +243,17 @@ static FixedMemoryPool<kPoolFrameBlockSize, 128> PoolFrame;
|
|||||||
static MemoryPool<80> PoolObject;
|
static MemoryPool<80> PoolObject;
|
||||||
|
|
||||||
void* PoolExpr_alloc() noexcept { return PoolExpr.alloc(); }
|
void* PoolExpr_alloc() noexcept { return PoolExpr.alloc(); }
|
||||||
|
|
||||||
void PoolExpr_dealloc(void* p) noexcept { PoolExpr.dealloc(p); }
|
void PoolExpr_dealloc(void* p) noexcept { PoolExpr.dealloc(p); }
|
||||||
|
|
||||||
void* PoolFrame_alloc() noexcept { return PoolFrame.alloc(); }
|
void* PoolFrame_alloc() noexcept { return PoolFrame.alloc(); }
|
||||||
|
|
||||||
void PoolFrame_dealloc(void* p) noexcept { PoolFrame.dealloc(p); }
|
void PoolFrame_dealloc(void* p) noexcept { PoolFrame.dealloc(p); }
|
||||||
|
|
||||||
void* PoolObject_alloc(size_t size) noexcept { return PoolObject.alloc(size); }
|
void* PoolObject_alloc(size_t size) noexcept { return PoolObject.alloc(size); }
|
||||||
|
|
||||||
void PoolObject_dealloc(void* p) noexcept { PoolObject.dealloc(p); }
|
void PoolObject_dealloc(void* p) noexcept { PoolObject.dealloc(p); }
|
||||||
|
|
||||||
void PoolObject_shrink_to_fit() noexcept { PoolObject.shrink_to_fit(); }
|
void PoolObject_shrink_to_fit() noexcept { PoolObject.shrink_to_fit(); }
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
int utf8len(unsigned char c, bool suppress){
|
int utf8len(unsigned char c, bool suppress) {
|
||||||
if((c & 0b10000000) == 0) return 1;
|
if((c & 0b10000000) == 0) return 1;
|
||||||
if((c & 0b11100000) == 0b11000000) return 2;
|
if((c & 0b11100000) == 0b11000000) return 2;
|
||||||
if((c & 0b11110000) == 0b11100000) return 3;
|
if((c & 0b11110000) == 0b11100000) return 3;
|
||||||
@ -19,531 +19,499 @@ int utf8len(unsigned char c, bool suppress){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PK_STR_ALLOCATE() \
|
#define PK_STR_ALLOCATE() \
|
||||||
if(this->size < (int)sizeof(this->_inlined)){ \
|
if(this->size < (int)sizeof(this->_inlined)) { \
|
||||||
this->data = this->_inlined; \
|
this->data = this->_inlined; \
|
||||||
}else{ \
|
} else { \
|
||||||
this->data = (char*)std::malloc(this->size+1); \
|
this->data = (char*)std::malloc(this->size + 1); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PK_STR_COPY_INIT(__s) \
|
||||||
|
for(int i = 0; i < this->size; i++) { \
|
||||||
|
this->data[i] = __s[i]; \
|
||||||
|
if(!isascii(__s[i])) is_ascii = false; \
|
||||||
|
} \
|
||||||
|
this->data[this->size] = '\0';
|
||||||
|
|
||||||
|
Str::Str() : size(0), is_ascii(true), data(_inlined) { _inlined[0] = '\0'; }
|
||||||
|
|
||||||
|
Str::Str(int size, bool is_ascii) :
|
||||||
|
size(size), is_ascii(is_ascii){PK_STR_ALLOCATE()}
|
||||||
|
|
||||||
|
Str::Str(const std::string& s) :
|
||||||
|
size(s.size()), is_ascii(true){PK_STR_ALLOCATE() PK_STR_COPY_INIT(s)}
|
||||||
|
|
||||||
|
Str::Str(std::string_view s) :
|
||||||
|
size(s.size()), is_ascii(true){PK_STR_ALLOCATE() PK_STR_COPY_INIT(s)}
|
||||||
|
|
||||||
|
Str::Str(const char* s) :
|
||||||
|
size(strlen(s)), is_ascii(true){PK_STR_ALLOCATE() PK_STR_COPY_INIT(s)}
|
||||||
|
|
||||||
|
Str::Str(const char* s, int len) :
|
||||||
|
size(len), is_ascii(true){PK_STR_ALLOCATE() PK_STR_COPY_INIT(s)}
|
||||||
|
|
||||||
|
Str::Str(std::pair<char*, int> detached) : size(detached.second), is_ascii(true) {
|
||||||
|
this->data = detached.first;
|
||||||
|
for(int i = 0; i < size; i++) {
|
||||||
|
if(!isascii(data[i])) {
|
||||||
|
is_ascii = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PK_STR_COPY_INIT(__s) \
|
|
||||||
for(int i=0; i<this->size; i++){ \
|
|
||||||
this->data[i] = __s[i]; \
|
|
||||||
if(!isascii(__s[i])) is_ascii = false; \
|
|
||||||
} \
|
|
||||||
this->data[this->size] = '\0';
|
|
||||||
|
|
||||||
Str::Str(): size(0), is_ascii(true), data(_inlined) {
|
|
||||||
_inlined[0] = '\0';
|
|
||||||
}
|
}
|
||||||
|
assert(data[size] == '\0');
|
||||||
|
}
|
||||||
|
|
||||||
Str::Str(int size, bool is_ascii): size(size), is_ascii(is_ascii) {
|
Str::Str(const Str& other) : size(other.size), is_ascii(other.is_ascii) {
|
||||||
PK_STR_ALLOCATE()
|
PK_STR_ALLOCATE()
|
||||||
}
|
std::memcpy(data, other.data, size);
|
||||||
|
data[size] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
Str::Str(const std::string& s): size(s.size()), is_ascii(true) {
|
Str::Str(Str&& other) : size(other.size), is_ascii(other.is_ascii) {
|
||||||
PK_STR_ALLOCATE()
|
if(other.is_inlined()) {
|
||||||
PK_STR_COPY_INIT(s)
|
data = _inlined;
|
||||||
}
|
for(int i = 0; i < size; i++)
|
||||||
|
_inlined[i] = other._inlined[i];
|
||||||
Str::Str(std::string_view s): size(s.size()), is_ascii(true) {
|
|
||||||
PK_STR_ALLOCATE()
|
|
||||||
PK_STR_COPY_INIT(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
Str::Str(const char* s): size(strlen(s)), is_ascii(true) {
|
|
||||||
PK_STR_ALLOCATE()
|
|
||||||
PK_STR_COPY_INIT(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
Str::Str(const char* s, int len): size(len), is_ascii(true) {
|
|
||||||
PK_STR_ALLOCATE()
|
|
||||||
PK_STR_COPY_INIT(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
Str::Str(std::pair<char *, int> detached): size(detached.second), is_ascii(true) {
|
|
||||||
this->data = detached.first;
|
|
||||||
for(int i=0; i<size; i++){
|
|
||||||
if(!isascii(data[i])){ is_ascii = false; break; }
|
|
||||||
}
|
|
||||||
assert(data[size] == '\0');
|
|
||||||
}
|
|
||||||
|
|
||||||
Str::Str(const Str& other): size(other.size), is_ascii(other.is_ascii) {
|
|
||||||
PK_STR_ALLOCATE()
|
|
||||||
std::memcpy(data, other.data, size);
|
|
||||||
data[size] = '\0';
|
data[size] = '\0';
|
||||||
|
} else {
|
||||||
|
data = other.data;
|
||||||
|
// zero out `other`
|
||||||
|
other.data = other._inlined;
|
||||||
|
other.data[0] = '\0';
|
||||||
|
other.size = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Str::Str(Str&& other): size(other.size), is_ascii(other.is_ascii) {
|
Str operator+ (const char* p, const Str& str) {
|
||||||
if(other.is_inlined()){
|
Str other(p);
|
||||||
data = _inlined;
|
return other + str;
|
||||||
for(int i=0; i<size; i++) _inlined[i] = other._inlined[i];
|
}
|
||||||
data[size] = '\0';
|
|
||||||
}else{
|
std::ostream& operator<< (std::ostream& os, const Str& str) { return os << str.sv(); }
|
||||||
data = other.data;
|
|
||||||
// zero out `other`
|
bool operator< (const std::string_view other, const Str& str) { return other < str.sv(); }
|
||||||
other.data = other._inlined;
|
|
||||||
other.data[0] = '\0';
|
Str& Str::operator= (const Str& other) {
|
||||||
other.size = 0;
|
if(!is_inlined()) std::free(data);
|
||||||
}
|
size = other.size;
|
||||||
|
is_ascii = other.is_ascii;
|
||||||
|
PK_STR_ALLOCATE()
|
||||||
|
std::memcpy(data, other.data, size);
|
||||||
|
data[size] = '\0';
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Str Str::operator+ (const Str& other) const {
|
||||||
|
Str ret(size + other.size, is_ascii && other.is_ascii);
|
||||||
|
std::memcpy(ret.data, data, size);
|
||||||
|
std::memcpy(ret.data + size, other.data, other.size);
|
||||||
|
ret.data[ret.size] = '\0';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Str Str::operator+ (const char* p) const {
|
||||||
|
Str other(p);
|
||||||
|
return *this + other;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Str::operator== (const Str& other) const {
|
||||||
|
if(size != other.size) return false;
|
||||||
|
return memcmp(data, other.data, size) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Str::operator!= (const Str& other) const {
|
||||||
|
if(size != other.size) return true;
|
||||||
|
return memcmp(data, other.data, size) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Str::operator== (const std::string_view other) const {
|
||||||
|
if(size != (int)other.size()) return false;
|
||||||
|
return memcmp(data, other.data(), size) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Str::operator!= (const std::string_view other) const {
|
||||||
|
if(size != (int)other.size()) return true;
|
||||||
|
return memcmp(data, other.data(), size) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Str::operator== (const char* p) const { return *this == std::string_view(p); }
|
||||||
|
|
||||||
|
bool Str::operator!= (const char* p) const { return *this != std::string_view(p); }
|
||||||
|
|
||||||
|
bool Str::operator< (const Str& other) const { return this->sv() < other.sv(); }
|
||||||
|
|
||||||
|
bool Str::operator< (const std::string_view other) const { return this->sv() < other; }
|
||||||
|
|
||||||
|
bool Str::operator> (const Str& other) const { return this->sv() > other.sv(); }
|
||||||
|
|
||||||
|
bool Str::operator<= (const Str& other) const { return this->sv() <= other.sv(); }
|
||||||
|
|
||||||
|
bool Str::operator>= (const Str& other) const { return this->sv() >= other.sv(); }
|
||||||
|
|
||||||
|
Str::~Str() {
|
||||||
|
if(!is_inlined()) std::free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Str Str::substr(int start, int len) const {
|
||||||
|
Str ret(len, is_ascii);
|
||||||
|
std::memcpy(ret.data, data + start, len);
|
||||||
|
ret.data[len] = '\0';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Str Str::substr(int start) const { return substr(start, size - start); }
|
||||||
|
|
||||||
|
Str Str::strip(bool left, bool right, const Str& chars) const {
|
||||||
|
int L = 0;
|
||||||
|
int R = u8_length();
|
||||||
|
if(left) {
|
||||||
|
while(L < R && chars.index(u8_getitem(L)) != -1)
|
||||||
|
L++;
|
||||||
}
|
}
|
||||||
|
if(right) {
|
||||||
Str operator+(const char* p, const Str& str){
|
while(L < R && chars.index(u8_getitem(R - 1)) != -1)
|
||||||
Str other(p);
|
R--;
|
||||||
return other + str;
|
|
||||||
}
|
}
|
||||||
|
return u8_slice(L, R, 1);
|
||||||
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const Str& str){
|
Str Str::strip(bool left, bool right) const {
|
||||||
return os << str.sv();
|
if(is_ascii) {
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<(const std::string_view other, const Str& str){
|
|
||||||
return other < str.sv();
|
|
||||||
}
|
|
||||||
|
|
||||||
Str& Str::operator=(const Str& other){
|
|
||||||
if(!is_inlined()) std::free(data);
|
|
||||||
size = other.size;
|
|
||||||
is_ascii = other.is_ascii;
|
|
||||||
PK_STR_ALLOCATE()
|
|
||||||
std::memcpy(data, other.data, size);
|
|
||||||
data[size] = '\0';
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Str Str::operator+(const Str& other) const {
|
|
||||||
Str ret(size + other.size, is_ascii && other.is_ascii);
|
|
||||||
std::memcpy(ret.data, data, size);
|
|
||||||
std::memcpy(ret.data + size, other.data, other.size);
|
|
||||||
ret.data[ret.size] = '\0';
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
Str Str::operator+(const char* p) const {
|
|
||||||
Str other(p);
|
|
||||||
return *this + other;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Str::operator==(const Str& other) const {
|
|
||||||
if(size != other.size) return false;
|
|
||||||
return memcmp(data, other.data, size) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Str::operator!=(const Str& other) const {
|
|
||||||
if(size != other.size) return true;
|
|
||||||
return memcmp(data, other.data, size) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Str::operator==(const std::string_view other) const {
|
|
||||||
if(size != (int)other.size()) return false;
|
|
||||||
return memcmp(data, other.data(), size) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Str::operator!=(const std::string_view other) const {
|
|
||||||
if(size != (int)other.size()) return true;
|
|
||||||
return memcmp(data, other.data(), size) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Str::operator==(const char* p) const {
|
|
||||||
return *this == std::string_view(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Str::operator!=(const char* p) const {
|
|
||||||
return *this != std::string_view(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Str::operator<(const Str& other) const {
|
|
||||||
return this->sv() < other.sv();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Str::operator<(const std::string_view other) const {
|
|
||||||
return this->sv() < other;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Str::operator>(const Str& other) const {
|
|
||||||
return this->sv() > other.sv();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Str::operator<=(const Str& other) const {
|
|
||||||
return this->sv() <= other.sv();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Str::operator>=(const Str& other) const {
|
|
||||||
return this->sv() >= other.sv();
|
|
||||||
}
|
|
||||||
|
|
||||||
Str::~Str(){
|
|
||||||
if(!is_inlined()) std::free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
Str Str::substr(int start, int len) const {
|
|
||||||
Str ret(len, is_ascii);
|
|
||||||
std::memcpy(ret.data, data + start, len);
|
|
||||||
ret.data[len] = '\0';
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
Str Str::substr(int start) const {
|
|
||||||
return substr(start, size - start);
|
|
||||||
}
|
|
||||||
|
|
||||||
Str Str::strip(bool left, bool right, const Str& chars) const {
|
|
||||||
int L = 0;
|
int L = 0;
|
||||||
int R = u8_length();
|
int R = size;
|
||||||
if(left){
|
if(left) {
|
||||||
while(L < R && chars.index(u8_getitem(L)) != -1) L++;
|
while(L < R && (data[L] == ' ' || data[L] == '\t' || data[L] == '\n' || data[L] == '\r'))
|
||||||
|
L++;
|
||||||
}
|
}
|
||||||
if(right){
|
if(right) {
|
||||||
while(L < R && chars.index(u8_getitem(R-1)) != -1) R--;
|
while(L < R && (data[R - 1] == ' ' || data[R - 1] == '\t' || data[R - 1] == '\n' || data[R - 1] == '\r'))
|
||||||
|
R--;
|
||||||
}
|
}
|
||||||
return u8_slice(L, R, 1);
|
return substr(L, R - L);
|
||||||
|
} else {
|
||||||
|
return strip(left, right, " \t\n\r");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Str Str::strip(bool left, bool right) const {
|
Str Str::lower() const {
|
||||||
if(is_ascii){
|
std::string copy(data, size);
|
||||||
int L = 0;
|
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) {
|
||||||
int R = size;
|
if('A' <= c && c <= 'Z') return c + ('a' - 'A');
|
||||||
if(left){
|
return (int)c;
|
||||||
while(L < R && (data[L] == ' ' || data[L] == '\t' || data[L] == '\n' || data[L] == '\r')) L++;
|
});
|
||||||
}
|
return Str(copy);
|
||||||
if(right){
|
}
|
||||||
while(L < R && (data[R-1] == ' ' || data[R-1] == '\t' || data[R-1] == '\n' || data[R-1] == '\r')) R--;
|
|
||||||
}
|
Str Str::upper() const {
|
||||||
return substr(L, R - L);
|
std::string copy(data, size);
|
||||||
}else{
|
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) {
|
||||||
return strip(left, right, " \t\n\r");
|
if('a' <= c && c <= 'z') return c - ('a' - 'A');
|
||||||
|
return (int)c;
|
||||||
|
});
|
||||||
|
return Str(copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
Str Str::escape(bool single_quote) const {
|
||||||
|
SStream ss;
|
||||||
|
escape_(ss, single_quote);
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Str::escape_(SStream& ss, bool single_quote) const {
|
||||||
|
ss << (single_quote ? '\'' : '"');
|
||||||
|
for(int i = 0; i < length(); i++) {
|
||||||
|
char c = this->operator[] (i);
|
||||||
|
switch(c) {
|
||||||
|
case '"':
|
||||||
|
if(!single_quote) ss << '\\';
|
||||||
|
ss << '"';
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
if(single_quote) ss << '\\';
|
||||||
|
ss << '\'';
|
||||||
|
break;
|
||||||
|
case '\\': ss << '\\' << '\\'; break;
|
||||||
|
case '\n': ss << "\\n"; break;
|
||||||
|
case '\r': ss << "\\r"; break;
|
||||||
|
case '\t': ss << "\\t"; break;
|
||||||
|
case '\b': ss << "\\b"; break;
|
||||||
|
default:
|
||||||
|
if('\x00' <= c && c <= '\x1f') {
|
||||||
|
ss << "\\x"; // << std::hex << std::setw(2) << std::setfill('0') << (int)c;
|
||||||
|
ss << PK_HEX_TABLE[c >> 4];
|
||||||
|
ss << PK_HEX_TABLE[c & 0xf];
|
||||||
|
} else {
|
||||||
|
ss << c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ss << (single_quote ? '\'' : '"');
|
||||||
|
}
|
||||||
|
|
||||||
Str Str::lower() const{
|
int Str::index(const Str& sub, int start) const {
|
||||||
std::string copy(data, size);
|
auto p = std::search(data + start, data + size, sub.data, sub.data + sub.size);
|
||||||
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c){
|
if(p == data + size) return -1;
|
||||||
if('A' <= c && c <= 'Z') return c + ('a' - 'A');
|
return p - data;
|
||||||
return (int)c;
|
}
|
||||||
});
|
|
||||||
return Str(copy);
|
Str Str::replace(char old, char new_) const {
|
||||||
|
Str copied = *this;
|
||||||
|
for(int i = 0; i < copied.size; i++) {
|
||||||
|
if(copied.data[i] == old) copied.data[i] = new_;
|
||||||
}
|
}
|
||||||
|
return copied;
|
||||||
|
}
|
||||||
|
|
||||||
Str Str::upper() const{
|
Str Str::replace(const Str& old, const Str& new_, int count) const {
|
||||||
std::string copy(data, size);
|
SStream ss;
|
||||||
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c){
|
int start = 0;
|
||||||
if('a' <= c && c <= 'z') return c - ('a' - 'A');
|
while(true) {
|
||||||
return (int)c;
|
int i = index(old, start);
|
||||||
});
|
if(i == -1) break;
|
||||||
return Str(copy);
|
ss << substr(start, i - start);
|
||||||
|
ss << new_;
|
||||||
|
start = i + old.size;
|
||||||
|
if(count != -1 && --count == 0) break;
|
||||||
}
|
}
|
||||||
|
ss << substr(start, size - start);
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
Str Str::escape(bool single_quote) const{
|
int Str::_unicode_index_to_byte(int i) const {
|
||||||
SStream ss;
|
if(is_ascii) return i;
|
||||||
escape_(ss, single_quote);
|
int j = 0;
|
||||||
return ss.str();
|
while(i > 0) {
|
||||||
|
j += utf8len(data[j]);
|
||||||
|
i--;
|
||||||
}
|
}
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
void Str::escape_(SStream& ss, bool single_quote) const {
|
int Str::_byte_index_to_unicode(int n) const {
|
||||||
ss << (single_quote ? '\'' : '"');
|
if(is_ascii) return n;
|
||||||
for (int i=0; i<length(); i++) {
|
int cnt = 0;
|
||||||
char c = this->operator[](i);
|
for(int i = 0; i < n; i++) {
|
||||||
switch (c) {
|
if((data[i] & 0xC0) != 0x80) cnt++;
|
||||||
case '"':
|
|
||||||
if(!single_quote) ss << '\\';
|
|
||||||
ss << '"';
|
|
||||||
break;
|
|
||||||
case '\'':
|
|
||||||
if(single_quote) ss << '\\';
|
|
||||||
ss << '\'';
|
|
||||||
break;
|
|
||||||
case '\\': ss << '\\' << '\\'; break;
|
|
||||||
case '\n': ss << "\\n"; break;
|
|
||||||
case '\r': ss << "\\r"; break;
|
|
||||||
case '\t': ss << "\\t"; break;
|
|
||||||
case '\b': ss << "\\b"; break;
|
|
||||||
default:
|
|
||||||
if ('\x00' <= c && c <= '\x1f') {
|
|
||||||
ss << "\\x"; // << std::hex << std::setw(2) << std::setfill('0') << (int)c;
|
|
||||||
ss << PK_HEX_TABLE[c >> 4];
|
|
||||||
ss << PK_HEX_TABLE[c & 0xf];
|
|
||||||
} else {
|
|
||||||
ss << c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ss << (single_quote ? '\'' : '"');
|
|
||||||
}
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
int Str::index(const Str& sub, int start) const {
|
Str Str::u8_getitem(int i) const {
|
||||||
auto p = std::search(data + start, data + size, sub.data, sub.data + sub.size);
|
i = _unicode_index_to_byte(i);
|
||||||
if(p == data + size) return -1;
|
return substr(i, utf8len(data[i]));
|
||||||
return p - data;
|
}
|
||||||
|
|
||||||
|
Str Str::u8_slice(int start, int stop, int step) const {
|
||||||
|
SStream ss;
|
||||||
|
if(is_ascii) {
|
||||||
|
PK_SLICE_LOOP(i, start, stop, step) ss << data[i];
|
||||||
|
} else {
|
||||||
|
PK_SLICE_LOOP(i, start, stop, step) ss << u8_getitem(i);
|
||||||
}
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
Str Str::replace(char old, char new_) const{
|
int Str::u8_length() const { return _byte_index_to_unicode(size); }
|
||||||
Str copied = *this;
|
|
||||||
for(int i=0; i<copied.size; i++){
|
|
||||||
if(copied.data[i] == old) copied.data[i] = new_;
|
|
||||||
}
|
|
||||||
return copied;
|
|
||||||
}
|
|
||||||
|
|
||||||
Str Str::replace(const Str& old, const Str& new_, int count) const {
|
vector<std::string_view> Str::split(const Str& sep) const {
|
||||||
SStream ss;
|
vector<std::string_view> result;
|
||||||
int start = 0;
|
std::string_view tmp;
|
||||||
while(true){
|
int start = 0;
|
||||||
int i = index(old, start);
|
while(true) {
|
||||||
if(i == -1) break;
|
int i = index(sep, start);
|
||||||
ss << substr(start, i - start);
|
if(i == -1) break;
|
||||||
ss << new_;
|
tmp = sv().substr(start, i - start);
|
||||||
start = i + old.size;
|
|
||||||
if(count != -1 && --count == 0) break;
|
|
||||||
}
|
|
||||||
ss << substr(start, size - start);
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int Str::_unicode_index_to_byte(int i) const{
|
|
||||||
if(is_ascii) return i;
|
|
||||||
int j = 0;
|
|
||||||
while(i > 0){
|
|
||||||
j += utf8len(data[j]);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Str::_byte_index_to_unicode(int n) const{
|
|
||||||
if(is_ascii) return n;
|
|
||||||
int cnt = 0;
|
|
||||||
for(int i=0; i<n; i++){
|
|
||||||
if((data[i] & 0xC0) != 0x80) cnt++;
|
|
||||||
}
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
Str Str::u8_getitem(int i) const{
|
|
||||||
i = _unicode_index_to_byte(i);
|
|
||||||
return substr(i, utf8len(data[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
Str Str::u8_slice(int start, int stop, int step) const{
|
|
||||||
SStream ss;
|
|
||||||
if(is_ascii){
|
|
||||||
PK_SLICE_LOOP(i, start, stop, step) ss << data[i];
|
|
||||||
}else{
|
|
||||||
PK_SLICE_LOOP(i, start, stop, step) ss << u8_getitem(i);
|
|
||||||
}
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
int Str::u8_length() const {
|
|
||||||
return _byte_index_to_unicode(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
vector<std::string_view> Str::split(const Str& sep) const{
|
|
||||||
vector<std::string_view> result;
|
|
||||||
std::string_view tmp;
|
|
||||||
int start = 0;
|
|
||||||
while(true){
|
|
||||||
int i = index(sep, start);
|
|
||||||
if(i == -1) break;
|
|
||||||
tmp = sv().substr(start, i - start);
|
|
||||||
if(!tmp.empty()) result.push_back(tmp);
|
|
||||||
start = i + sep.size;
|
|
||||||
}
|
|
||||||
tmp = sv().substr(start, size - start);
|
|
||||||
if(!tmp.empty()) result.push_back(tmp);
|
if(!tmp.empty()) result.push_back(tmp);
|
||||||
return result;
|
start = i + sep.size;
|
||||||
}
|
}
|
||||||
|
tmp = sv().substr(start, size - start);
|
||||||
|
if(!tmp.empty()) result.push_back(tmp);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
vector<std::string_view> Str::split(char sep) const{
|
vector<std::string_view> Str::split(char sep) const {
|
||||||
vector<std::string_view> result;
|
vector<std::string_view> result;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for(int j = 0; j < size; j++){
|
for(int j = 0; j < size; j++) {
|
||||||
if(data[j] == sep){
|
if(data[j] == sep) {
|
||||||
if(j > i) result.emplace_back(data+i, j-i);
|
if(j > i) result.emplace_back(data + i, j - i);
|
||||||
i = j + 1;
|
i = j + 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(size > i) result.emplace_back(data+i, size-i);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
if(size > i) result.emplace_back(data + i, size - i);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
int Str::count(const Str& sub) const{
|
int Str::count(const Str& sub) const {
|
||||||
if(sub.empty()) return size + 1;
|
if(sub.empty()) return size + 1;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
int start = 0;
|
int start = 0;
|
||||||
while(true){
|
while(true) {
|
||||||
int i = index(sub, start);
|
int i = index(sub, start);
|
||||||
if(i == -1) break;
|
if(i == -1) break;
|
||||||
cnt++;
|
cnt++;
|
||||||
start = i + sub.size;
|
start = i + sub.size;
|
||||||
}
|
|
||||||
return cnt;
|
|
||||||
}
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
std::map<std::string_view, uint16_t>& StrName::_interned(){
|
std::map<std::string_view, uint16_t>& StrName::_interned() {
|
||||||
static std::map<std::string_view, uint16_t> interned;
|
static std::map<std::string_view, uint16_t> interned;
|
||||||
return interned;
|
return interned;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<uint16_t, std::string>& StrName::_r_interned(){
|
std::map<uint16_t, std::string>& StrName::_r_interned() {
|
||||||
static std::map<uint16_t, std::string> r_interned;
|
static std::map<uint16_t, std::string> r_interned;
|
||||||
return r_interned;
|
return r_interned;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t StrName::_pesudo_random_index = 0;
|
uint32_t StrName::_pesudo_random_index = 0;
|
||||||
|
|
||||||
StrName StrName::get(std::string_view s){
|
StrName StrName::get(std::string_view s) {
|
||||||
auto it = _interned().find(s);
|
auto it = _interned().find(s);
|
||||||
if(it != _interned().end()) return StrName(it->second);
|
if(it != _interned().end()) return StrName(it->second);
|
||||||
// generate new index
|
// generate new index
|
||||||
// https://github.com/python/cpython/blob/3.12/Objects/dictobject.c#L175
|
// https://github.com/python/cpython/blob/3.12/Objects/dictobject.c#L175
|
||||||
uint16_t index = ((_pesudo_random_index*5) + 1) & 65535;
|
uint16_t index = ((_pesudo_random_index * 5) + 1) & 65535;
|
||||||
if(index == 0) throw std::runtime_error("StrName index overflow");
|
if(index == 0) throw std::runtime_error("StrName index overflow");
|
||||||
auto res = _r_interned().emplace(index, s);
|
auto res = _r_interned().emplace(index, s);
|
||||||
assert(res.second);
|
assert(res.second);
|
||||||
s = std::string_view(res.first->second);
|
s = std::string_view(res.first->second);
|
||||||
_interned()[s] = index;
|
_interned()[s] = index;
|
||||||
_pesudo_random_index = index;
|
_pesudo_random_index = index;
|
||||||
return StrName(index);
|
return StrName(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
Str SStream::str(){
|
Str SStream::str() {
|
||||||
// after this call, the buffer is no longer valid
|
// after this call, the buffer is no longer valid
|
||||||
buffer.reserve(buffer.size() + 1); // allocate one more byte for '\0'
|
buffer.reserve(buffer.size() + 1); // allocate one more byte for '\0'
|
||||||
buffer[buffer.size()] = '\0'; // set '\0'
|
buffer[buffer.size()] = '\0'; // set '\0'
|
||||||
return Str(buffer.detach());
|
return Str(buffer.detach());
|
||||||
}
|
}
|
||||||
|
|
||||||
SStream& SStream::operator<<(const Str& s){
|
SStream& SStream::operator<< (const Str& s) {
|
||||||
for(char c: s) buffer.push_back(c);
|
for(char c: s)
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
SStream& SStream::operator<<(const char* s){
|
|
||||||
while(*s) buffer.push_back(*s++);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
SStream& SStream::operator<<(const std::string& s){
|
|
||||||
for(char c: s) buffer.push_back(c);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
SStream& SStream::operator<<(std::string_view s){
|
|
||||||
for(char c: s) buffer.push_back(c);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
SStream& SStream::operator<<(char c){
|
|
||||||
buffer.push_back(c);
|
buffer.push_back(c);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SStream& SStream::operator<< (const char* s) {
|
||||||
|
while(*s)
|
||||||
|
buffer.push_back(*s++);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SStream& SStream::operator<< (const std::string& s) {
|
||||||
|
for(char c: s)
|
||||||
|
buffer.push_back(c);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SStream& SStream::operator<< (std::string_view s) {
|
||||||
|
for(char c: s)
|
||||||
|
buffer.push_back(c);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SStream& SStream::operator<< (char c) {
|
||||||
|
buffer.push_back(c);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SStream& SStream::operator<< (StrName sn) { return *this << sn.sv(); }
|
||||||
|
|
||||||
|
SStream& SStream::operator<< (size_t val) {
|
||||||
|
// size_t could be out of range of `i64`, use `std::to_string` instead
|
||||||
|
return (*this) << std::to_string(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
SStream& SStream::operator<< (int val) { return (*this) << static_cast<i64>(val); }
|
||||||
|
|
||||||
|
SStream& SStream::operator<< (i64 val) {
|
||||||
|
// str(-2**64).__len__() == 21
|
||||||
|
buffer.reserve(buffer.size() + 24);
|
||||||
|
if(val == 0) {
|
||||||
|
buffer.push_back('0');
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
if(val < 0) {
|
||||||
SStream& SStream::operator<<(StrName sn){
|
buffer.push_back('-');
|
||||||
return *this << sn.sv();
|
val = -val;
|
||||||
}
|
}
|
||||||
|
auto begin = buffer.end();
|
||||||
SStream& SStream::operator<<(size_t val){
|
while(val) {
|
||||||
// size_t could be out of range of `i64`, use `std::to_string` instead
|
buffer.push_back('0' + val % 10);
|
||||||
return (*this) << std::to_string(val);
|
val /= 10;
|
||||||
}
|
}
|
||||||
|
std::reverse(begin, buffer.end());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
SStream& SStream::operator<<(int val){
|
SStream& SStream::operator<< (f64 val) {
|
||||||
return (*this) << static_cast<i64>(val);
|
if(std::isinf(val)) { return (*this) << (val > 0 ? "inf" : "-inf"); }
|
||||||
|
if(std::isnan(val)) { return (*this) << "nan"; }
|
||||||
|
char b[32];
|
||||||
|
if(_precision == -1) {
|
||||||
|
int prec = std::numeric_limits<f64>::max_digits10 - 1;
|
||||||
|
snprintf(b, sizeof(b), "%.*g", prec, val);
|
||||||
|
} else {
|
||||||
|
int prec = _precision;
|
||||||
|
snprintf(b, sizeof(b), "%.*f", prec, val);
|
||||||
}
|
}
|
||||||
|
(*this) << b;
|
||||||
|
if(std::all_of(b + 1, b + strlen(b), isdigit)) (*this) << ".0";
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
SStream& SStream::operator<<(i64 val){
|
void SStream::write_hex(unsigned char c, bool non_zero) {
|
||||||
// str(-2**64).__len__() == 21
|
unsigned char high = c >> 4;
|
||||||
buffer.reserve(buffer.size() + 24);
|
unsigned char low = c & 0xf;
|
||||||
if(val == 0){
|
if(non_zero) {
|
||||||
buffer.push_back('0');
|
if(high) (*this) << PK_HEX_TABLE[high];
|
||||||
return *this;
|
if(high || low) (*this) << PK_HEX_TABLE[low];
|
||||||
}
|
} else {
|
||||||
if(val < 0){
|
(*this) << PK_HEX_TABLE[high];
|
||||||
buffer.push_back('-');
|
(*this) << PK_HEX_TABLE[low];
|
||||||
val = -val;
|
|
||||||
}
|
|
||||||
auto begin = buffer.end();
|
|
||||||
while(val){
|
|
||||||
buffer.push_back('0' + val % 10);
|
|
||||||
val /= 10;
|
|
||||||
}
|
|
||||||
std::reverse(begin, buffer.end());
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SStream& SStream::operator<<(f64 val){
|
void SStream::write_hex(void* p) {
|
||||||
if(std::isinf(val)){
|
if(p == nullptr) {
|
||||||
return (*this) << (val > 0 ? "inf" : "-inf");
|
(*this) << "0x0";
|
||||||
}
|
return;
|
||||||
if(std::isnan(val)){
|
|
||||||
return (*this) << "nan";
|
|
||||||
}
|
|
||||||
char b[32];
|
|
||||||
if(_precision == -1){
|
|
||||||
int prec = std::numeric_limits<f64>::max_digits10-1;
|
|
||||||
snprintf(b, sizeof(b), "%.*g", prec, val);
|
|
||||||
}else{
|
|
||||||
int prec = _precision;
|
|
||||||
snprintf(b, sizeof(b), "%.*f", prec, val);
|
|
||||||
}
|
|
||||||
(*this) << b;
|
|
||||||
if(std::all_of(b+1, b+strlen(b), isdigit)) (*this) << ".0";
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
(*this) << "0x";
|
||||||
|
uintptr_t p_t = reinterpret_cast<uintptr_t>(p);
|
||||||
|
bool non_zero = true;
|
||||||
|
for(int i = sizeof(void*) - 1; i >= 0; i--) {
|
||||||
|
unsigned char cpnt = (p_t >> (i * 8)) & 0xff;
|
||||||
|
write_hex(cpnt, non_zero);
|
||||||
|
if(cpnt != 0) non_zero = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SStream::write_hex(unsigned char c, bool non_zero){
|
void SStream::write_hex(i64 val) {
|
||||||
unsigned char high = c >> 4;
|
if(val == 0) {
|
||||||
unsigned char low = c & 0xf;
|
(*this) << "0x0";
|
||||||
if(non_zero){
|
return;
|
||||||
if(high) (*this) << PK_HEX_TABLE[high];
|
|
||||||
if(high || low) (*this) << PK_HEX_TABLE[low];
|
|
||||||
}else{
|
|
||||||
(*this) << PK_HEX_TABLE[high];
|
|
||||||
(*this) << PK_HEX_TABLE[low];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if(val < 0) {
|
||||||
void SStream::write_hex(void* p){
|
(*this) << "-";
|
||||||
if(p == nullptr){
|
val = -val;
|
||||||
(*this) << "0x0";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
(*this) << "0x";
|
|
||||||
uintptr_t p_t = reinterpret_cast<uintptr_t>(p);
|
|
||||||
bool non_zero = true;
|
|
||||||
for(int i=sizeof(void*)-1; i>=0; i--){
|
|
||||||
unsigned char cpnt = (p_t >> (i * 8)) & 0xff;
|
|
||||||
write_hex(cpnt, non_zero);
|
|
||||||
if(cpnt != 0) non_zero = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
(*this) << "0x";
|
||||||
void SStream::write_hex(i64 val){
|
bool non_zero = true;
|
||||||
if(val == 0){
|
for(int i = 56; i >= 0; i -= 8) {
|
||||||
(*this) << "0x0";
|
unsigned char cpnt = (val >> i) & 0xff;
|
||||||
return;
|
write_hex(cpnt, non_zero);
|
||||||
}
|
if(cpnt != 0) non_zero = false;
|
||||||
if(val < 0){
|
|
||||||
(*this) << "-";
|
|
||||||
val = -val;
|
|
||||||
}
|
|
||||||
(*this) << "0x";
|
|
||||||
bool non_zero = true;
|
|
||||||
for(int i=56; i>=0; i-=8){
|
|
||||||
unsigned char cpnt = (val >> i) & 0xff;
|
|
||||||
write_hex(cpnt, non_zero);
|
|
||||||
if(cpnt != 0) non_zero = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#undef PK_STR_ALLOCATE
|
#undef PK_STR_ALLOCATE
|
||||||
#undef PK_STR_COPY_INIT
|
#undef PK_STR_COPY_INIT
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// unary operators
|
// unary operators
|
||||||
const StrName __repr__ = StrName::get("__repr__");
|
const StrName __repr__ = StrName::get("__repr__");
|
||||||
const StrName __str__ = StrName::get("__str__");
|
const StrName __str__ = StrName::get("__str__");
|
||||||
@ -601,5 +569,4 @@ const StrName pk_id_set = StrName::get("set");
|
|||||||
const StrName pk_id_long = StrName::get("long");
|
const StrName pk_id_long = StrName::get("long");
|
||||||
const StrName pk_id_complex = StrName::get("complex");
|
const StrName pk_id_complex = StrName::get("complex");
|
||||||
|
|
||||||
|
} // namespace pkpy
|
||||||
} // namespace pkpy
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,159 +1,173 @@
|
|||||||
#include "pocketpy/interpreter/cffi.hpp"
|
#include "pocketpy/interpreter/cffi.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
void VoidP::_register(VM* vm, PyObject* mod, PyObject* type){
|
void VoidP::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args){
|
vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args) {
|
||||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||||
i64 addr = CAST(i64, args[1]);
|
i64 addr = CAST(i64, args[1]);
|
||||||
return vm->new_object<VoidP>(cls, reinterpret_cast<void*>(addr));
|
return vm->new_object<VoidP>(cls, reinterpret_cast<void*>(addr));
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind__hash__(type->as<Type>(), [](VM* vm, PyVar obj){
|
vm->bind__hash__(type->as<Type>(), [](VM* vm, PyVar obj) {
|
||||||
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, obj);
|
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, obj);
|
||||||
return reinterpret_cast<i64>(self.ptr);
|
return reinterpret_cast<i64>(self.ptr);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str{
|
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
|
||||||
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, obj);
|
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, obj);
|
||||||
return _S("<void* at ", self.hex(), ">");
|
return _S("<void* at ", self.hex(), ">");
|
||||||
});
|
});
|
||||||
|
|
||||||
#define BIND_CMP(name, op) \
|
#define BIND_CMP(name, op) \
|
||||||
vm->bind##name(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs){ \
|
vm->bind##name(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) { \
|
||||||
if(!vm->isinstance(rhs, vm->_tp_user<VoidP>())) return vm->NotImplemented; \
|
if(!vm->isinstance(rhs, vm->_tp_user<VoidP>())) return vm->NotImplemented; \
|
||||||
void* _0 = PK_OBJ_GET(VoidP, lhs).ptr; \
|
void* _0 = PK_OBJ_GET(VoidP, lhs).ptr; \
|
||||||
void* _1 = PK_OBJ_GET(VoidP, rhs).ptr; \
|
void* _1 = PK_OBJ_GET(VoidP, rhs).ptr; \
|
||||||
return VAR(_0 op _1); \
|
return VAR(_0 op _1); \
|
||||||
});
|
});
|
||||||
|
|
||||||
BIND_CMP(__eq__, ==)
|
BIND_CMP(__eq__, ==)
|
||||||
BIND_CMP(__lt__, <)
|
BIND_CMP(__lt__, <)
|
||||||
BIND_CMP(__le__, <=)
|
BIND_CMP(__le__, <=)
|
||||||
BIND_CMP(__gt__, >)
|
BIND_CMP(__gt__, >)
|
||||||
BIND_CMP(__ge__, >=)
|
BIND_CMP(__ge__, >=)
|
||||||
|
|
||||||
#undef BIND_CMP
|
#undef BIND_CMP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
|
vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args) {
|
||||||
|
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||||
|
int size = CAST(int, args[1]);
|
||||||
|
return vm->new_object<Struct>(cls, size);
|
||||||
|
});
|
||||||
|
|
||||||
void Struct::_register(VM* vm, PyObject* mod, PyObject* type){
|
vm->bind_func(type, "hex", 1, [](VM* vm, ArgsView args) {
|
||||||
vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args){
|
const Struct& self = _CAST(Struct&, args[0]);
|
||||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
SStream ss;
|
||||||
int size = CAST(int, args[1]);
|
for(int i = 0; i < self.size; i++)
|
||||||
return vm->new_object<Struct>(cls, size);
|
ss.write_hex((unsigned char)self.p[i]);
|
||||||
});
|
return VAR(ss.str());
|
||||||
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "hex", 1, [](VM* vm, ArgsView args){
|
// @staticmethod
|
||||||
const Struct& self = _CAST(Struct&, args[0]);
|
vm->bind_func(
|
||||||
SStream ss;
|
type,
|
||||||
for(int i=0; i<self.size; i++) ss.write_hex((unsigned char)self.p[i]);
|
"fromhex",
|
||||||
return VAR(ss.str());
|
1,
|
||||||
});
|
[](VM* vm, ArgsView args) {
|
||||||
|
|
||||||
// @staticmethod
|
|
||||||
vm->bind_func(type, "fromhex", 1, [](VM* vm, ArgsView args){
|
|
||||||
const Str& s = CAST(Str&, args[0]);
|
const Str& s = CAST(Str&, args[0]);
|
||||||
if(s.size<2 || s.size%2!=0) vm->ValueError("invalid hex string");
|
if(s.size < 2 || s.size % 2 != 0) vm->ValueError("invalid hex string");
|
||||||
Struct buffer(s.size/2, false);
|
Struct buffer(s.size / 2, false);
|
||||||
for(int i=0; i<s.size; i+=2){
|
for(int i = 0; i < s.size; i += 2) {
|
||||||
char c = 0;
|
char c = 0;
|
||||||
if(s[i]>='0' && s[i]<='9') c += s[i]-'0';
|
if(s[i] >= '0' && s[i] <= '9')
|
||||||
else if(s[i]>='A' && s[i]<='F') c += s[i]-'A'+10;
|
c += s[i] - '0';
|
||||||
else if(s[i]>='a' && s[i]<='f') c += s[i]-'a'+10;
|
else if(s[i] >= 'A' && s[i] <= 'F')
|
||||||
else vm->ValueError(_S("invalid hex char: '", s[i], "'"));
|
c += s[i] - 'A' + 10;
|
||||||
|
else if(s[i] >= 'a' && s[i] <= 'f')
|
||||||
|
c += s[i] - 'a' + 10;
|
||||||
|
else
|
||||||
|
vm->ValueError(_S("invalid hex char: '", s[i], "'"));
|
||||||
c <<= 4;
|
c <<= 4;
|
||||||
if(s[i+1]>='0' && s[i+1]<='9') c += s[i+1]-'0';
|
if(s[i + 1] >= '0' && s[i + 1] <= '9')
|
||||||
else if(s[i+1]>='A' && s[i+1]<='F') c += s[i+1]-'A'+10;
|
c += s[i + 1] - '0';
|
||||||
else if(s[i+1]>='a' && s[i+1]<='f') c += s[i+1]-'a'+10;
|
else if(s[i + 1] >= 'A' && s[i + 1] <= 'F')
|
||||||
else vm->ValueError(_S("invalid hex char: '", s[i+1], "'"));
|
c += s[i + 1] - 'A' + 10;
|
||||||
buffer.p[i/2] = c;
|
else if(s[i + 1] >= 'a' && s[i + 1] <= 'f')
|
||||||
|
c += s[i + 1] - 'a' + 10;
|
||||||
|
else
|
||||||
|
vm->ValueError(_S("invalid hex char: '", s[i + 1], "'"));
|
||||||
|
buffer.p[i / 2] = c;
|
||||||
}
|
}
|
||||||
return vm->new_user_object<Struct>(std::move(buffer));
|
return vm->new_user_object<Struct>(std::move(buffer));
|
||||||
}, {}, BindType::STATICMETHOD);
|
},
|
||||||
|
{},
|
||||||
|
BindType::STATICMETHOD);
|
||||||
|
|
||||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj){
|
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) {
|
||||||
Struct& self = _CAST(Struct&, obj);
|
Struct& self = _CAST(Struct&, obj);
|
||||||
SStream ss;
|
SStream ss;
|
||||||
ss << "<struct object of " << self.size << " bytes>";
|
ss << "<struct object of " << self.size << " bytes>";
|
||||||
return ss.str();
|
return ss.str();
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args) {
|
||||||
Struct& self = _CAST(Struct&, args[0]);
|
Struct& self = _CAST(Struct&, args[0]);
|
||||||
return vm->new_user_object<VoidP>(self.p);
|
return vm->new_user_object<VoidP>(self.p);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args) {
|
||||||
Struct& self = _CAST(Struct&, args[0]);
|
Struct& self = _CAST(Struct&, args[0]);
|
||||||
return VAR(self.size);
|
return VAR(self.size);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args) {
|
||||||
const Struct& self = _CAST(Struct&, args[0]);
|
const Struct& self = _CAST(Struct&, args[0]);
|
||||||
return vm->new_object<Struct>(vm->_tp(args[0]), self);
|
return vm->new_object<Struct>(vm->_tp(args[0]), self);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs){
|
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) {
|
||||||
Struct& self = _CAST(Struct&, lhs);
|
Struct& self = _CAST(Struct&, lhs);
|
||||||
if(!vm->is_user_type<Struct>(rhs)) return vm->NotImplemented;
|
if(!vm->is_user_type<Struct>(rhs)) return vm->NotImplemented;
|
||||||
Struct& other = _CAST(Struct&, rhs);
|
Struct& other = _CAST(Struct&, rhs);
|
||||||
bool ok = self.size == other.size && memcmp(self.p, other.p, self.size) == 0;
|
bool ok = self.size == other.size && memcmp(self.p, other.p, self.size) == 0;
|
||||||
return VAR(ok);
|
return VAR(ok);
|
||||||
});
|
});
|
||||||
|
|
||||||
#define BIND_SETGET(T, name) \
|
#define BIND_SETGET(T, name) \
|
||||||
vm->bind(type, "read_" name "(self, offset=0)", [](VM* vm, ArgsView args){ \
|
vm->bind(type, "read_" name "(self, offset=0)", [](VM* vm, ArgsView args) { \
|
||||||
Struct& self = _CAST(Struct&, args[0]); \
|
Struct& self = _CAST(Struct&, args[0]); \
|
||||||
i64 offset = CAST(i64, args[1]); \
|
i64 offset = CAST(i64, args[1]); \
|
||||||
void* ptr = self.p + offset; \
|
void* ptr = self.p + offset; \
|
||||||
return VAR(*(T*)ptr); \
|
return VAR(*(T*)ptr); \
|
||||||
}); \
|
}); \
|
||||||
vm->bind(type, "write_" name "(self, value, offset=0)", [](VM* vm, ArgsView args){ \
|
vm->bind(type, "write_" name "(self, value, offset=0)", [](VM* vm, ArgsView args) { \
|
||||||
Struct& self = _CAST(Struct&, args[0]); \
|
Struct& self = _CAST(Struct&, args[0]); \
|
||||||
i64 offset = CAST(i64, args[2]); \
|
i64 offset = CAST(i64, args[2]); \
|
||||||
void* ptr = self.p + offset; \
|
void* ptr = self.p + offset; \
|
||||||
*(T*)ptr = CAST(T, args[1]); \
|
*(T*)ptr = CAST(T, args[1]); \
|
||||||
return vm->None; \
|
return vm->None; \
|
||||||
});
|
});
|
||||||
BIND_SETGET(char, "char")
|
BIND_SETGET(char, "char")
|
||||||
BIND_SETGET(unsigned char, "uchar")
|
BIND_SETGET(unsigned char, "uchar")
|
||||||
BIND_SETGET(short, "short")
|
BIND_SETGET(short, "short")
|
||||||
BIND_SETGET(unsigned short, "ushort")
|
BIND_SETGET(unsigned short, "ushort")
|
||||||
BIND_SETGET(int, "int")
|
BIND_SETGET(int, "int")
|
||||||
BIND_SETGET(unsigned int, "uint")
|
BIND_SETGET(unsigned int, "uint")
|
||||||
BIND_SETGET(long, "long")
|
BIND_SETGET(long, "long")
|
||||||
BIND_SETGET(unsigned long, "ulong")
|
BIND_SETGET(unsigned long, "ulong")
|
||||||
BIND_SETGET(long long, "longlong")
|
BIND_SETGET(long long, "longlong")
|
||||||
BIND_SETGET(unsigned long long, "ulonglong")
|
BIND_SETGET(unsigned long long, "ulonglong")
|
||||||
BIND_SETGET(float, "float")
|
BIND_SETGET(float, "float")
|
||||||
BIND_SETGET(double, "double")
|
BIND_SETGET(double, "double")
|
||||||
BIND_SETGET(bool, "bool")
|
BIND_SETGET(bool, "bool")
|
||||||
BIND_SETGET(void*, "void_p")
|
BIND_SETGET(void*, "void_p")
|
||||||
#undef BIND_SETGET
|
#undef BIND_SETGET
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_module_c(VM* vm){
|
void add_module_c(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("c");
|
PyObject* mod = vm->new_module("c");
|
||||||
|
|
||||||
vm->bind_func(mod, "malloc", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "malloc", 1, [](VM* vm, ArgsView args) {
|
||||||
i64 size = CAST(i64, args[0]);
|
i64 size = CAST(i64, args[0]);
|
||||||
return VAR(std::malloc(size));
|
return VAR(std::malloc(size));
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "free", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "free", 1, [](VM* vm, ArgsView args) {
|
||||||
void* p = CAST(void*, args[0]);
|
void* p = CAST(void*, args[0]);
|
||||||
std::free(p);
|
std::free(p);
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "memset", 3, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "memset", 3, [](VM* vm, ArgsView args) {
|
||||||
void* p = CAST(void*, args[0]);
|
void* p = CAST(void*, args[0]);
|
||||||
std::memset(p, CAST(int, args[1]), CAST(size_t, args[2]));
|
std::memset(p, CAST(int, args[1]), CAST(size_t, args[2]));
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "memcpy", 3, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "memcpy", 3, [](VM* vm, ArgsView args) {
|
||||||
void* dst = CAST(void*, args[0]);
|
void* dst = CAST(void*, args[0]);
|
||||||
void* src = CAST(void*, args[1]);
|
void* src = CAST(void*, args[1]);
|
||||||
i64 size = CAST(i64, args[2]);
|
i64 size = CAST(i64, args[2]);
|
||||||
@ -166,22 +180,20 @@ void add_module_c(VM* vm){
|
|||||||
|
|
||||||
mod->attr().set("NULL", vm->new_user_object<VoidP>(nullptr));
|
mod->attr().set("NULL", vm->new_user_object<VoidP>(nullptr));
|
||||||
|
|
||||||
vm->bind(mod, "p_cast(ptr: 'void_p', cls: type[T]) -> T", [](VM* vm, ArgsView args){
|
vm->bind(mod, "p_cast(ptr: 'void_p', cls: type[T]) -> T", [](VM* vm, ArgsView args) {
|
||||||
VoidP& ptr = CAST(VoidP&, args[0]);
|
VoidP& ptr = CAST(VoidP&, args[0]);
|
||||||
vm->check_type(args[1], vm->tp_type);
|
vm->check_type(args[1], vm->tp_type);
|
||||||
Type cls = PK_OBJ_GET(Type, args[1]);
|
Type cls = PK_OBJ_GET(Type, args[1]);
|
||||||
if(!vm->issubclass(cls, vm->_tp_user<VoidP>())){
|
if(!vm->issubclass(cls, vm->_tp_user<VoidP>())) { vm->ValueError("expected a subclass of void_p"); }
|
||||||
vm->ValueError("expected a subclass of void_p");
|
|
||||||
}
|
|
||||||
return vm->new_object<VoidP>(cls, ptr.ptr);
|
return vm->new_object<VoidP>(cls, ptr.ptr);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind(mod, "p_value(ptr: 'void_p') -> int", [](VM* vm, ArgsView args){
|
vm->bind(mod, "p_value(ptr: 'void_p') -> int", [](VM* vm, ArgsView args) {
|
||||||
VoidP& ptr = CAST(VoidP&, args[0]);
|
VoidP& ptr = CAST(VoidP&, args[0]);
|
||||||
return VAR(reinterpret_cast<i64>(ptr.ptr));
|
return VAR(reinterpret_cast<i64>(ptr.ptr));
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind(mod, "pp_deref(ptr: Tp) -> Tp", [](VM* vm, ArgsView args){
|
vm->bind(mod, "pp_deref(ptr: Tp) -> Tp", [](VM* vm, ArgsView args) {
|
||||||
VoidP& ptr = CAST(VoidP&, args[0]);
|
VoidP& ptr = CAST(VoidP&, args[0]);
|
||||||
void* value = *reinterpret_cast<void**>(ptr.ptr);
|
void* value = *reinterpret_cast<void**>(ptr.ptr);
|
||||||
return vm->new_object<VoidP>(args[0].type, value);
|
return vm->new_object<VoidP>(args[0].type, value);
|
||||||
@ -190,54 +202,54 @@ void add_module_c(VM* vm){
|
|||||||
PyObject* type;
|
PyObject* type;
|
||||||
Type type_t;
|
Type type_t;
|
||||||
|
|
||||||
#define BIND_PRIMITIVE(T, CNAME) \
|
#define BIND_PRIMITIVE(T, CNAME) \
|
||||||
vm->bind_func(mod, CNAME "_", 1, [](VM* vm, ArgsView args){ \
|
vm->bind_func(mod, CNAME "_", 1, [](VM* vm, ArgsView args) { \
|
||||||
T val = CAST(T, args[0]); \
|
T val = CAST(T, args[0]); \
|
||||||
return vm->new_user_object<Struct>(&val, sizeof(T)); \
|
return vm->new_user_object<Struct>(&val, sizeof(T)); \
|
||||||
}); \
|
}); \
|
||||||
type = vm->new_type_object(mod, CNAME "_p", vm->_tp_user<VoidP>(), true); \
|
type = vm->new_type_object(mod, CNAME "_p", vm->_tp_user<VoidP>(), true); \
|
||||||
mod->attr().set(CNAME "_p", type); \
|
mod->attr().set(CNAME "_p", type); \
|
||||||
type_t = type->as<Type>(); \
|
type_t = type->as<Type>(); \
|
||||||
vm->bind_func(type, "read", 1, [](VM* vm, ArgsView args){ \
|
vm->bind_func(type, "read", 1, [](VM* vm, ArgsView args) { \
|
||||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); \
|
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); \
|
||||||
T* target = (T*)voidp.ptr; \
|
T* target = (T*)voidp.ptr; \
|
||||||
return VAR(*target); \
|
return VAR(*target); \
|
||||||
}); \
|
}); \
|
||||||
vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args){ \
|
vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args) { \
|
||||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); \
|
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); \
|
||||||
T val = CAST(T, args[1]); \
|
T val = CAST(T, args[1]); \
|
||||||
T* target = (T*)voidp.ptr; \
|
T* target = (T*)voidp.ptr; \
|
||||||
*target = val; \
|
*target = val; \
|
||||||
return vm->None; \
|
return vm->None; \
|
||||||
}); \
|
}); \
|
||||||
vm->bind__getitem__(type_t, [](VM* vm, PyVar obj, PyVar index){ \
|
vm->bind__getitem__(type_t, [](VM* vm, PyVar obj, PyVar index) { \
|
||||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, obj); \
|
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, obj); \
|
||||||
i64 offset = CAST(i64, index); \
|
i64 offset = CAST(i64, index); \
|
||||||
T* target = (T*)voidp.ptr; \
|
T* target = (T*)voidp.ptr; \
|
||||||
return VAR(target[offset]); \
|
return VAR(target[offset]); \
|
||||||
}); \
|
}); \
|
||||||
vm->bind__setitem__(type_t, [](VM* vm, PyVar obj, PyVar index, PyVar value){ \
|
vm->bind__setitem__(type_t, [](VM* vm, PyVar obj, PyVar index, PyVar value) { \
|
||||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, obj); \
|
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, obj); \
|
||||||
i64 offset = CAST(i64, index); \
|
i64 offset = CAST(i64, index); \
|
||||||
T* target = (T*)voidp.ptr; \
|
T* target = (T*)voidp.ptr; \
|
||||||
target[offset] = CAST(T, value); \
|
target[offset] = CAST(T, value); \
|
||||||
}); \
|
}); \
|
||||||
vm->bind__add__(type_t, [](VM* vm, PyVar lhs, PyVar rhs){ \
|
vm->bind__add__(type_t, [](VM* vm, PyVar lhs, PyVar rhs) { \
|
||||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, lhs); \
|
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, lhs); \
|
||||||
i64 offset = CAST(i64, rhs); \
|
i64 offset = CAST(i64, rhs); \
|
||||||
T* target = (T*)voidp.ptr; \
|
T* target = (T*)voidp.ptr; \
|
||||||
return vm->new_object<VoidP>(lhs.type, target + offset); \
|
return vm->new_object<VoidP>(lhs.type, target + offset); \
|
||||||
}); \
|
}); \
|
||||||
vm->bind__sub__(type_t, [](VM* vm, PyVar lhs, PyVar rhs){ \
|
vm->bind__sub__(type_t, [](VM* vm, PyVar lhs, PyVar rhs) { \
|
||||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, lhs); \
|
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, lhs); \
|
||||||
i64 offset = CAST(i64, rhs); \
|
i64 offset = CAST(i64, rhs); \
|
||||||
T* target = (T*)voidp.ptr; \
|
T* target = (T*)voidp.ptr; \
|
||||||
return vm->new_object<VoidP>(lhs.type, target - offset); \
|
return vm->new_object<VoidP>(lhs.type, target - offset); \
|
||||||
}); \
|
}); \
|
||||||
vm->bind__repr__(type_t, [](VM* vm, PyVar obj) -> Str{ \
|
vm->bind__repr__(type_t, [](VM* vm, PyVar obj) -> Str { \
|
||||||
VoidP& self = _CAST(VoidP&, obj); \
|
VoidP& self = _CAST(VoidP&, obj); \
|
||||||
return _S("<", CNAME, "* at ", self.hex(), ">"); \
|
return _S("<", CNAME, "* at ", self.hex(), ">"); \
|
||||||
}); \
|
});
|
||||||
|
|
||||||
BIND_PRIMITIVE(char, "char")
|
BIND_PRIMITIVE(char, "char")
|
||||||
BIND_PRIMITIVE(unsigned char, "uchar")
|
BIND_PRIMITIVE(unsigned char, "uchar")
|
||||||
@ -256,13 +268,13 @@ void add_module_c(VM* vm){
|
|||||||
#undef BIND_PRIMITIVE
|
#undef BIND_PRIMITIVE
|
||||||
|
|
||||||
PyObject* char_p_t = mod->attr("char_p").get();
|
PyObject* char_p_t = mod->attr("char_p").get();
|
||||||
vm->bind(char_p_t, "read_string(self) -> str", [](VM* vm, ArgsView args){
|
vm->bind(char_p_t, "read_string(self) -> str", [](VM* vm, ArgsView args) {
|
||||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]);
|
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]);
|
||||||
const char* target = (const char*)voidp.ptr;
|
const char* target = (const char*)voidp.ptr;
|
||||||
return VAR(target);
|
return VAR(target);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind(char_p_t, "write_string(self, value: str)", [](VM* vm, ArgsView args){
|
vm->bind(char_p_t, "write_string(self, value: str)", [](VM* vm, ArgsView args) {
|
||||||
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]);
|
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]);
|
||||||
std::string_view sv = CAST(Str&, args[1]).sv();
|
std::string_view sv = CAST(Str&, args[1]).sv();
|
||||||
char* target = (char*)voidp.ptr;
|
char* target = (char*)voidp.ptr;
|
||||||
@ -272,8 +284,6 @@ void add_module_c(VM* vm){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar from_void_p(VM* vm, void* p){
|
PyVar from_void_p(VM* vm, void* p) { return vm->new_user_object<VoidP>(p); }
|
||||||
return vm->new_user_object<VoidP>(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -3,126 +3,128 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
PyVar* FastLocals::try_get_name(StrName name){
|
PyVar* FastLocals::try_get_name(StrName name) {
|
||||||
int index = co->varnames_inv.try_get(name);
|
int index = co->varnames_inv.try_get(name);
|
||||||
if(index == -1) return nullptr;
|
if(index == -1) return nullptr;
|
||||||
return &a[index];
|
return &a[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
NameDict_ FastLocals::to_namedict(){
|
NameDict_ FastLocals::to_namedict() {
|
||||||
NameDict_ dict = std::make_shared<NameDict>();
|
NameDict_ dict = std::make_shared<NameDict>();
|
||||||
co->varnames_inv.apply([&](StrName name, int index){
|
co->varnames_inv.apply([&](StrName name, int index) {
|
||||||
PyVar value = a[index];
|
PyVar value = a[index];
|
||||||
if(value) dict->set(name, value);
|
if(value) dict->set(name, value);
|
||||||
});
|
});
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar* Frame::f_closure_try_get(StrName name){
|
PyVar* Frame::f_closure_try_get(StrName name) {
|
||||||
if(_callable == nullptr) return nullptr;
|
if(_callable == nullptr) return nullptr;
|
||||||
Function& fn = _callable->as<Function>();
|
Function& fn = _callable->as<Function>();
|
||||||
if(fn._closure == nullptr) return nullptr;
|
if(fn._closure == nullptr) return nullptr;
|
||||||
return fn._closure->try_get_2(name);
|
return fn._closure->try_get_2(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Frame::prepare_jump_exception_handler(ValueStack* _s){
|
int Frame::prepare_jump_exception_handler(ValueStack* _s) {
|
||||||
// try to find a parent try block
|
// try to find a parent try block
|
||||||
int i = co->lines[ip()].iblock;
|
int i = co->lines[ip()].iblock;
|
||||||
while(i >= 0){
|
while(i >= 0) {
|
||||||
if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) break;
|
if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) break;
|
||||||
i = co->blocks[i].parent;
|
i = co->blocks[i].parent;
|
||||||
|
}
|
||||||
|
if(i < 0) return -1;
|
||||||
|
PyVar obj = _s->popx(); // pop exception object
|
||||||
|
UnwindTarget* uw = find_unwind_target(i);
|
||||||
|
_s->reset(actual_sp_base() + uw->offset); // unwind the stack
|
||||||
|
_s->push(obj); // push it back
|
||||||
|
return co->blocks[i].end;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Frame::_exit_block(ValueStack* _s, int i) {
|
||||||
|
auto type = co->blocks[i].type;
|
||||||
|
if(type == CodeBlockType::FOR_LOOP) {
|
||||||
|
_s->pop(); // pop the iterator
|
||||||
|
// pop possible stack memory slots
|
||||||
|
if(_s->top().type == kTpStackMemoryIndex) {
|
||||||
|
int count = _s->top().as<StackMemory>().count;
|
||||||
|
assert(count < 0);
|
||||||
|
_s->_sp += count;
|
||||||
|
_s->_sp -= 2; // pop header and tail
|
||||||
}
|
}
|
||||||
if(i < 0) return -1;
|
} else if(type == CodeBlockType::CONTEXT_MANAGER) {
|
||||||
PyVar obj = _s->popx(); // pop exception object
|
_s->pop();
|
||||||
UnwindTarget* uw = find_unwind_target(i);
|
|
||||||
_s->reset(actual_sp_base() + uw->offset); // unwind the stack
|
|
||||||
_s->push(obj); // push it back
|
|
||||||
return co->blocks[i].end;
|
|
||||||
}
|
}
|
||||||
|
return co->blocks[i].parent;
|
||||||
|
}
|
||||||
|
|
||||||
int Frame::_exit_block(ValueStack* _s, int i){
|
void Frame::prepare_jump_break(ValueStack* _s, int target) {
|
||||||
auto type = co->blocks[i].type;
|
int i = co->lines[ip()].iblock;
|
||||||
if(type == CodeBlockType::FOR_LOOP){
|
if(target >= co->codes.size()) {
|
||||||
_s->pop(); // pop the iterator
|
while(i >= 0)
|
||||||
// pop possible stack memory slots
|
i = _exit_block(_s, i);
|
||||||
if(_s->top().type == kTpStackMemoryIndex){
|
} else {
|
||||||
int count = _s->top().as<StackMemory>().count;
|
// BUG (solved)
|
||||||
assert(count < 0);
|
// for i in range(4):
|
||||||
_s->_sp += count;
|
// _ = 0
|
||||||
_s->_sp -= 2; // pop header and tail
|
// # if there is no op here, the block check will fail
|
||||||
}
|
// while i: --i
|
||||||
}else if(type==CodeBlockType::CONTEXT_MANAGER){
|
int next_block = co->lines[target].iblock;
|
||||||
_s->pop();
|
while(i >= 0 && i != next_block)
|
||||||
}
|
i = _exit_block(_s, i);
|
||||||
return co->blocks[i].parent;
|
if(i != next_block) throw std::runtime_error("invalid jump");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Frame::prepare_jump_break(ValueStack* _s, int target){
|
void Frame::set_unwind_target(PyVar* _sp) {
|
||||||
int i = co->lines[ip()].iblock;
|
int iblock = co->lines[ip()].iblock;
|
||||||
if(target >= co->codes.size()){
|
UnwindTarget* existing = find_unwind_target(iblock);
|
||||||
while(i>=0) i = _exit_block(_s, i);
|
if(existing) {
|
||||||
}else{
|
existing->offset = _sp - actual_sp_base();
|
||||||
// BUG (solved)
|
} else {
|
||||||
// for i in range(4):
|
UnwindTarget* prev = _uw_list;
|
||||||
// _ = 0
|
_uw_list = new UnwindTarget(iblock, _sp - actual_sp_base());
|
||||||
// # if there is no op here, the block check will fail
|
_uw_list->next = prev;
|
||||||
// while i: --i
|
|
||||||
int next_block = co->lines[target].iblock;
|
|
||||||
while(i>=0 && i!=next_block) i = _exit_block(_s, i);
|
|
||||||
if(i!=next_block) throw std::runtime_error("invalid jump");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Frame::set_unwind_target(PyVar* _sp){
|
UnwindTarget* Frame::find_unwind_target(int iblock) {
|
||||||
int iblock = co->lines[ip()].iblock;
|
UnwindTarget* p;
|
||||||
UnwindTarget* existing = find_unwind_target(iblock);
|
for(p = _uw_list; p != nullptr; p = p->next) {
|
||||||
if(existing){
|
if(p->iblock == iblock) return p;
|
||||||
existing->offset = _sp - actual_sp_base();
|
|
||||||
}else{
|
|
||||||
UnwindTarget* prev = _uw_list;
|
|
||||||
_uw_list = new UnwindTarget(iblock, _sp - actual_sp_base());
|
|
||||||
_uw_list->next = prev;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
UnwindTarget* Frame::find_unwind_target(int iblock){
|
Frame::~Frame() {
|
||||||
UnwindTarget* p;
|
while(_uw_list != nullptr) {
|
||||||
for(p=_uw_list; p!=nullptr; p=p->next){
|
UnwindTarget* p = _uw_list;
|
||||||
if(p->iblock == iblock) return p;
|
_uw_list = p->next;
|
||||||
}
|
delete p;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Frame::~Frame(){
|
void CallStack::pop() {
|
||||||
while(_uw_list != nullptr){
|
assert(!empty());
|
||||||
UnwindTarget* p = _uw_list;
|
LinkedFrame* p = _tail;
|
||||||
_uw_list = p->next;
|
_tail = p->f_back;
|
||||||
delete p;
|
p->~LinkedFrame();
|
||||||
}
|
PoolFrame_dealloc(p);
|
||||||
}
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
void CallStack::pop(){
|
LinkedFrame* CallStack::popx() {
|
||||||
assert(!empty());
|
assert(!empty());
|
||||||
LinkedFrame* p = _tail;
|
LinkedFrame* p = _tail;
|
||||||
_tail = p->f_back;
|
_tail = p->f_back;
|
||||||
p->~LinkedFrame();
|
--_size;
|
||||||
PoolFrame_dealloc(p);
|
p->f_back = nullptr; // unlink
|
||||||
--_size;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkedFrame* CallStack::popx(){
|
void CallStack::pushx(LinkedFrame* p) {
|
||||||
assert(!empty());
|
p->f_back = _tail;
|
||||||
LinkedFrame* p = _tail;
|
_tail = p;
|
||||||
_tail = p->f_back;
|
++_size;
|
||||||
--_size;
|
}
|
||||||
p->f_back = nullptr; // unlink
|
} // namespace pkpy
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CallStack::pushx(LinkedFrame* p){
|
|
||||||
p->f_back = _tail;
|
|
||||||
_tail = p;
|
|
||||||
++_size;
|
|
||||||
}
|
|
||||||
} // namespace pkpy
|
|
||||||
|
|||||||
@ -1,55 +1,56 @@
|
|||||||
#include "pocketpy/interpreter/gc.hpp"
|
#include "pocketpy/interpreter/gc.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
int ManagedHeap::sweep(){
|
int ManagedHeap::sweep() {
|
||||||
vector<PyObject*> alive;
|
vector<PyObject*> alive;
|
||||||
alive.reserve(gen.size() / 2);
|
alive.reserve(gen.size() / 2);
|
||||||
for(PyObject* obj: gen){
|
for(PyObject* obj: gen) {
|
||||||
if(obj->gc_marked){
|
if(obj->gc_marked) {
|
||||||
obj->gc_marked = false;
|
obj->gc_marked = false;
|
||||||
alive.push_back(obj);
|
alive.push_back(obj);
|
||||||
}else{
|
} else {
|
||||||
#if PK_DEBUG_GC_STATS
|
#if PK_DEBUG_GC_STATS
|
||||||
deleted[obj->type] += 1;
|
deleted[obj->type] += 1;
|
||||||
#endif
|
#endif
|
||||||
if(_gc_on_delete) _gc_on_delete(vm, obj);
|
if(_gc_on_delete) _gc_on_delete(vm, obj);
|
||||||
_delete(obj);
|
_delete(obj);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear _no_gc marked flag
|
|
||||||
for(PyObject* obj: _no_gc) obj->gc_marked = false;
|
|
||||||
|
|
||||||
int freed = gen.size() - alive.size();
|
|
||||||
|
|
||||||
#if PK_DEBUG_GC_STATS
|
|
||||||
for(auto& [type, count]: deleted){
|
|
||||||
std::cout << "GC: " << _type_name(vm, type).sv() << "=" << count << std::endl;
|
|
||||||
}
|
|
||||||
std::cout << "GC: " << alive.size() << "/" << gen.size() << " (" << freed << " freed)" << std::endl;
|
|
||||||
deleted.clear();
|
|
||||||
#endif
|
|
||||||
gen.clear();
|
|
||||||
gen.swap(alive);
|
|
||||||
PoolObject_shrink_to_fit();
|
|
||||||
return freed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ManagedHeap::_auto_collect(){
|
// clear _no_gc marked flag
|
||||||
|
for(PyObject* obj: _no_gc)
|
||||||
|
obj->gc_marked = false;
|
||||||
|
|
||||||
|
int freed = gen.size() - alive.size();
|
||||||
|
|
||||||
|
#if PK_DEBUG_GC_STATS
|
||||||
|
for(auto& [type, count]: deleted) {
|
||||||
|
std::cout << "GC: " << _type_name(vm, type).sv() << "=" << count << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << "GC: " << alive.size() << "/" << gen.size() << " (" << freed << " freed)" << std::endl;
|
||||||
|
deleted.clear();
|
||||||
|
#endif
|
||||||
|
gen.clear();
|
||||||
|
gen.swap(alive);
|
||||||
|
PoolObject_shrink_to_fit();
|
||||||
|
return freed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManagedHeap::_auto_collect() {
|
||||||
#if !PK_DEBUG_NO_AUTO_GC
|
#if !PK_DEBUG_NO_AUTO_GC
|
||||||
if(_gc_lock_counter > 0) return;
|
if(_gc_lock_counter > 0) return;
|
||||||
gc_counter = 0;
|
gc_counter = 0;
|
||||||
collect();
|
collect();
|
||||||
gc_threshold = gen.size() * 2;
|
gc_threshold = gen.size() * 2;
|
||||||
if(gc_threshold < PK_GC_MIN_THRESHOLD) gc_threshold = PK_GC_MIN_THRESHOLD;
|
if(gc_threshold < PK_GC_MIN_THRESHOLD) gc_threshold = PK_GC_MIN_THRESHOLD;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int ManagedHeap::collect(){
|
int ManagedHeap::collect() {
|
||||||
assert(_gc_lock_counter == 0);
|
assert(_gc_lock_counter == 0);
|
||||||
mark();
|
mark();
|
||||||
int freed = sweep();
|
int freed = sweep();
|
||||||
return freed;
|
return freed;
|
||||||
}
|
}
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -1,130 +1,144 @@
|
|||||||
#include "pocketpy/interpreter/iter.hpp"
|
#include "pocketpy/interpreter/iter.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
void RangeIter::_register(VM* vm, PyObject* mod, PyObject* type){
|
void RangeIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; });
|
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{
|
return _0;
|
||||||
RangeIter& self = PK_OBJ_GET(RangeIter, _0);
|
});
|
||||||
if(self.current >= self.r.stop) return 0;
|
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||||
vm->s_data.emplace(VM::tp_int, self.current);
|
RangeIter& self = PK_OBJ_GET(RangeIter, _0);
|
||||||
self.current += self.r.step;
|
if(self.current >= self.r.stop) return 0;
|
||||||
return 1;
|
vm->s_data.emplace(VM::tp_int, self.current);
|
||||||
});
|
self.current += self.r.step;
|
||||||
}
|
return 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void RangeIterR::_register(VM* vm, PyObject* mod, PyObject* type){
|
void RangeIterR::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; });
|
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{
|
return _0;
|
||||||
RangeIterR& self = PK_OBJ_GET(RangeIterR, _0);
|
});
|
||||||
if(self.current <= self.r.stop) return 0;
|
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||||
vm->s_data.emplace(VM::tp_int, self.current);
|
RangeIterR& self = PK_OBJ_GET(RangeIterR, _0);
|
||||||
self.current += self.r.step;
|
if(self.current <= self.r.stop) return 0;
|
||||||
return 1;
|
vm->s_data.emplace(VM::tp_int, self.current);
|
||||||
});
|
self.current += self.r.step;
|
||||||
}
|
return 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void ArrayIter::_register(VM* vm, PyObject* mod, PyObject* type){
|
void ArrayIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; });
|
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{
|
return _0;
|
||||||
ArrayIter& self = _CAST(ArrayIter&, _0);
|
});
|
||||||
if(self.current == self.end) return 0;
|
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||||
vm->s_data.push(*self.current++);
|
ArrayIter& self = _CAST(ArrayIter&, _0);
|
||||||
return 1;
|
if(self.current == self.end) return 0;
|
||||||
});
|
vm->s_data.push(*self.current++);
|
||||||
}
|
return 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void StringIter::_register(VM* vm, PyObject* mod, PyObject* type){
|
void StringIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; });
|
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{
|
return _0;
|
||||||
StringIter& self = _CAST(StringIter&, _0);
|
});
|
||||||
Str& s = PK_OBJ_GET(Str, self.ref);
|
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||||
if(self.i == s.size) return 0;
|
StringIter& self = _CAST(StringIter&, _0);
|
||||||
int start = self.i;
|
Str& s = PK_OBJ_GET(Str, self.ref);
|
||||||
int len = utf8len(s.data[self.i]);
|
if(self.i == s.size) return 0;
|
||||||
self.i += len;
|
int start = self.i;
|
||||||
vm->s_data.push(VAR(s.substr(start, len)));
|
int len = utf8len(s.data[self.i]);
|
||||||
return 1;
|
self.i += len;
|
||||||
});
|
vm->s_data.push(VAR(s.substr(start, len)));
|
||||||
}
|
return 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
PyVar Generator::next(VM* vm){
|
PyVar Generator::next(VM* vm) {
|
||||||
if(state == 2) return vm->StopIteration;
|
if(state == 2) return vm->StopIteration;
|
||||||
// reset frame._sp_base
|
// reset frame._sp_base
|
||||||
lf->frame._sp_base = vm->s_data._sp;
|
lf->frame._sp_base = vm->s_data._sp;
|
||||||
lf->frame._locals.a = vm->s_data._sp;
|
lf->frame._locals.a = vm->s_data._sp;
|
||||||
// restore the context
|
// restore the context
|
||||||
for(PyVar obj: s_backup) vm->s_data.push(obj);
|
for(PyVar obj: s_backup)
|
||||||
// relocate stack objects (their addresses become invalid)
|
vm->s_data.push(obj);
|
||||||
for(PyVar* p=lf->frame.actual_sp_base(); p!=vm->s_data.end(); p++){
|
// relocate stack objects (their addresses become invalid)
|
||||||
if(p->type == VM::tp_stack_memory){
|
for(PyVar* p = lf->frame.actual_sp_base(); p != vm->s_data.end(); p++) {
|
||||||
// TODO: refactor this
|
if(p->type == VM::tp_stack_memory) {
|
||||||
int count = p->as<StackMemory>().count;
|
// TODO: refactor this
|
||||||
if(count < 0){
|
int count = p->as<StackMemory>().count;
|
||||||
void* new_p = p + count;
|
if(count < 0) {
|
||||||
p[1]._1 = reinterpret_cast<i64>(new_p);
|
void* new_p = p + count;
|
||||||
}
|
p[1]._1 = reinterpret_cast<i64>(new_p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s_backup.clear();
|
}
|
||||||
vm->callstack.pushx(lf);
|
s_backup.clear();
|
||||||
lf = nullptr;
|
vm->callstack.pushx(lf);
|
||||||
|
lf = nullptr;
|
||||||
|
|
||||||
PyVar ret;
|
PyVar ret;
|
||||||
try{
|
try {
|
||||||
ret = vm->__run_top_frame();
|
ret = vm->__run_top_frame();
|
||||||
}catch(...){
|
} catch(...) {
|
||||||
state = 2; // end this generator immediately when an exception is thrown
|
state = 2; // end this generator immediately when an exception is thrown
|
||||||
throw;
|
throw;
|
||||||
}
|
|
||||||
|
|
||||||
if(ret == PY_OP_YIELD){
|
|
||||||
// backup the context
|
|
||||||
lf = vm->callstack.popx();
|
|
||||||
ret = vm->s_data.popx();
|
|
||||||
for(PyVar obj: lf->frame.stack_view(&vm->s_data)) s_backup.push_back(obj);
|
|
||||||
vm->s_data.reset(lf->frame._sp_base);
|
|
||||||
// TODO: should we add this snippet here?
|
|
||||||
// #if PK_ENABLE_PROFILER
|
|
||||||
// if(!_next_breakpoint.empty() && callstack.size()<_next_breakpoint.callstack_size){
|
|
||||||
// _next_breakpoint = NextBreakpoint();
|
|
||||||
// }
|
|
||||||
// #endif
|
|
||||||
state = 1;
|
|
||||||
if(ret == vm->StopIteration) state = 2;
|
|
||||||
return ret;
|
|
||||||
}else{
|
|
||||||
state = 2;
|
|
||||||
return vm->StopIteration;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Generator::_register(VM* vm, PyObject* mod, PyObject* type){
|
if(ret == PY_OP_YIELD) {
|
||||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; });
|
// backup the context
|
||||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{
|
lf = vm->callstack.popx();
|
||||||
Generator& self = _CAST(Generator&, _0);
|
ret = vm->s_data.popx();
|
||||||
PyVar retval = self.next(vm);
|
for(PyVar obj: lf->frame.stack_view(&vm->s_data))
|
||||||
if(retval == vm->StopIteration) return 0;
|
s_backup.push_back(obj);
|
||||||
vm->s_data.push(retval);
|
vm->s_data.reset(lf->frame._sp_base);
|
||||||
return 1;
|
// TODO: should we add this snippet here?
|
||||||
});
|
// #if PK_ENABLE_PROFILER
|
||||||
|
// if(!_next_breakpoint.empty() && callstack.size()<_next_breakpoint.callstack_size){
|
||||||
|
// _next_breakpoint = NextBreakpoint();
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
state = 1;
|
||||||
|
if(ret == vm->StopIteration) state = 2;
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
state = 2;
|
||||||
|
return vm->StopIteration;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DictItemsIter::_register(VM *vm, PyObject* mod, PyObject* type){
|
void Generator::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; });
|
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{
|
return _0;
|
||||||
DictItemsIter& self = _CAST(DictItemsIter&, _0);
|
});
|
||||||
Dict& d = PK_OBJ_GET(Dict, self.ref);
|
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||||
if(self.i == -1) return 0;
|
Generator& self = _CAST(Generator&, _0);
|
||||||
vm->s_data.push(d._items[self.i].first);
|
PyVar retval = self.next(vm);
|
||||||
vm->s_data.push(d._items[self.i].second);
|
if(retval == vm->StopIteration) return 0;
|
||||||
self.i = d._items[self.i].next;
|
vm->s_data.push(retval);
|
||||||
return 2;
|
return 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar VM::__py_generator(LinkedFrame* frame, ArgsView buffer){
|
void DictItemsIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
|
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
|
return _0;
|
||||||
|
});
|
||||||
|
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||||
|
DictItemsIter& self = _CAST(DictItemsIter&, _0);
|
||||||
|
Dict& d = PK_OBJ_GET(Dict, self.ref);
|
||||||
|
if(self.i == -1) return 0;
|
||||||
|
vm->s_data.push(d._items[self.i].first);
|
||||||
|
vm->s_data.push(d._items[self.i].second);
|
||||||
|
self.i = d._items[self.i].next;
|
||||||
|
return 2;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PyVar VM::__py_generator(LinkedFrame* frame, ArgsView buffer) {
|
||||||
return vm->new_user_object<Generator>(std::move(frame), buffer);
|
return vm->new_user_object<Generator>(std::move(frame), buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -1,41 +1,39 @@
|
|||||||
#include "pocketpy/interpreter/profiler.hpp"
|
#include "pocketpy/interpreter/profiler.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
static std::string left_pad(std::string s, int width){
|
static std::string left_pad(std::string s, int width) {
|
||||||
int n = width - s.size();
|
int n = width - s.size();
|
||||||
if(n <= 0) return s;
|
if(n <= 0) return s;
|
||||||
return std::string(n, ' ') + s;
|
return std::string(n, ' ') + s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string to_string_1f(f64 x){
|
static std::string to_string_1f(f64 x) {
|
||||||
char buf[32];
|
char buf[32];
|
||||||
snprintf(buf, 32, "%.1f", x);
|
snprintf(buf, 32, "%.1f", x);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineProfiler::begin(){
|
void LineProfiler::begin() { frames.clear(); }
|
||||||
frames.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LineProfiler::_step(int callstack_size, Frame* frame){
|
void LineProfiler::_step(int callstack_size, Frame* frame) {
|
||||||
auto line_info = frame->co->lines[frame->ip()];
|
auto line_info = frame->co->lines[frame->ip()];
|
||||||
if(line_info.is_virtual) return;
|
if(line_info.is_virtual) return;
|
||||||
std::string_view filename = frame->co->src->filename.sv();
|
std::string_view filename = frame->co->src->filename.sv();
|
||||||
int line = line_info.lineno;
|
int line = line_info.lineno;
|
||||||
|
|
||||||
if(frames.empty()){
|
if(frames.empty()) {
|
||||||
frames.push({callstack_size, frame, clock(), nullptr});
|
frames.push({callstack_size, frame, clock(), nullptr});
|
||||||
}else{
|
} else {
|
||||||
_step_end(callstack_size, frame, line);
|
_step_end(callstack_size, frame, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& file_records = records[filename];
|
auto& file_records = records[filename];
|
||||||
if(file_records.empty()){
|
if(file_records.empty()) {
|
||||||
// initialize file_records
|
// initialize file_records
|
||||||
int total_lines = frame->co->src->line_starts.size();
|
int total_lines = frame->co->src->line_starts.size();
|
||||||
file_records.resize(total_lines + 1);
|
file_records.resize(total_lines + 1);
|
||||||
for(int i=1; i<=total_lines; i++){
|
for(int i = 1; i <= total_lines; i++) {
|
||||||
file_records[i].line = i;
|
file_records[i].line = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,7 +41,7 @@ void LineProfiler::_step(int callstack_size, Frame* frame){
|
|||||||
frames.top().prev_record = &file_records[line];
|
frames.top().prev_record = &file_records[line];
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineProfiler::_step_end(int callstack_size, Frame* frame, int line){
|
void LineProfiler::_step_end(int callstack_size, Frame* frame, int line) {
|
||||||
clock_t now = clock();
|
clock_t now = clock();
|
||||||
_FrameRecord& top_frame_record = frames.top();
|
_FrameRecord& top_frame_record = frames.top();
|
||||||
_LineRecord* prev_record = top_frame_record.prev_record;
|
_LineRecord* prev_record = top_frame_record.prev_record;
|
||||||
@ -52,21 +50,21 @@ void LineProfiler::_step_end(int callstack_size, Frame* frame, int line){
|
|||||||
assert(abs(id_delta) <= 1);
|
assert(abs(id_delta) <= 1);
|
||||||
|
|
||||||
// current line is about to change
|
// current line is about to change
|
||||||
if(prev_record->line != line){
|
if(prev_record->line != line) {
|
||||||
clock_t delta = now - top_frame_record.prev_time;
|
clock_t delta = now - top_frame_record.prev_time;
|
||||||
top_frame_record.prev_time = now;
|
top_frame_record.prev_time = now;
|
||||||
if(id_delta != 1) prev_record->hits++;
|
if(id_delta != 1) prev_record->hits++;
|
||||||
prev_record->time += delta;
|
prev_record->time += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id_delta == 1){
|
if(id_delta == 1) {
|
||||||
frames.push({callstack_size, frame, now, nullptr});
|
frames.push({callstack_size, frame, now, nullptr});
|
||||||
}else{
|
} else {
|
||||||
if(id_delta == -1) frames.pop();
|
if(id_delta == -1) frames.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineProfiler::end(){
|
void LineProfiler::end() {
|
||||||
clock_t now = clock();
|
clock_t now = clock();
|
||||||
_FrameRecord& top_frame_record = frames.top();
|
_FrameRecord& top_frame_record = frames.top();
|
||||||
_LineRecord* prev_record = top_frame_record.prev_record;
|
_LineRecord* prev_record = top_frame_record.prev_record;
|
||||||
@ -80,9 +78,9 @@ void LineProfiler::end(){
|
|||||||
assert(frames.empty());
|
assert(frames.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
Str LineProfiler::stats(){
|
Str LineProfiler::stats() {
|
||||||
SStream ss;
|
SStream ss;
|
||||||
for(FuncDecl* decl: functions){
|
for(FuncDecl* decl: functions) {
|
||||||
int start_line = decl->code->start_line;
|
int start_line = decl->code->start_line;
|
||||||
int end_line = decl->code->end_line;
|
int end_line = decl->code->end_line;
|
||||||
if(start_line == -1 || end_line == -1) continue;
|
if(start_line == -1 || end_line == -1) continue;
|
||||||
@ -90,7 +88,7 @@ Str LineProfiler::stats(){
|
|||||||
vector<_LineRecord>& file_records = records[filename];
|
vector<_LineRecord>& file_records = records[filename];
|
||||||
if(file_records.empty()) continue;
|
if(file_records.empty()) continue;
|
||||||
clock_t total_time = 0;
|
clock_t total_time = 0;
|
||||||
for(int line = start_line; line <= end_line; line++){
|
for(int line = start_line; line <= end_line; line++) {
|
||||||
total_time += file_records[line].time;
|
total_time += file_records[line].time;
|
||||||
}
|
}
|
||||||
ss << "Total time: " << (f64)total_time / CLOCKS_PER_SEC << "s\n";
|
ss << "Total time: " << (f64)total_time / CLOCKS_PER_SEC << "s\n";
|
||||||
@ -98,19 +96,19 @@ Str LineProfiler::stats(){
|
|||||||
ss << "Function: " << decl->code->name << " at line " << start_line << "\n";
|
ss << "Function: " << decl->code->name << " at line " << start_line << "\n";
|
||||||
ss << "Line # Hits Time Per Hit % Time Line Contents\n";
|
ss << "Line # Hits Time Per Hit % Time Line Contents\n";
|
||||||
ss << "==============================================================\n";
|
ss << "==============================================================\n";
|
||||||
for(int line = start_line; line <= end_line; line++){
|
for(int line = start_line; line <= end_line; line++) {
|
||||||
const _LineRecord& record = file_records[line];
|
const _LineRecord& record = file_records[line];
|
||||||
if(!record.is_valid()) continue;
|
if(!record.is_valid()) continue;
|
||||||
ss << left_pad(std::to_string(line), 6);
|
ss << left_pad(std::to_string(line), 6);
|
||||||
if(record.hits == 0){
|
if(record.hits == 0) {
|
||||||
ss << std::string(10 + 13 + 9 + 9, ' ');
|
ss << std::string(10 + 13 + 9 + 9, ' ');
|
||||||
}else{
|
} else {
|
||||||
ss << left_pad(std::to_string(record.hits), 10);
|
ss << left_pad(std::to_string(record.hits), 10);
|
||||||
ss << left_pad(std::to_string(record.time), 13);
|
ss << left_pad(std::to_string(record.time), 13);
|
||||||
ss << left_pad(std::to_string(record.time / record.hits), 9);
|
ss << left_pad(std::to_string(record.time / record.hits), 9);
|
||||||
if(total_time == 0){
|
if(total_time == 0) {
|
||||||
ss << left_pad("0.0", 9);
|
ss << left_pad("0.0", 9);
|
||||||
}else{
|
} else {
|
||||||
ss << left_pad(to_string_1f(record.time * (f64)100 / total_time), 9);
|
ss << left_pad(to_string_1f(record.time * (f64)100 / total_time), 9);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,4 +120,4 @@ Str LineProfiler::stats(){
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,9 @@
|
|||||||
#include "pocketpy/modules/array2d.hpp"
|
#include "pocketpy/modules/array2d.hpp"
|
||||||
#include "pocketpy/interpreter/bindings.hpp"
|
#include "pocketpy/interpreter/bindings.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
struct Array2d{
|
struct Array2d {
|
||||||
PK_ALWAYS_PASS_BY_POINTER(Array2d)
|
PK_ALWAYS_PASS_BY_POINTER(Array2d)
|
||||||
|
|
||||||
PyVar* data;
|
PyVar* data;
|
||||||
@ -11,55 +11,49 @@ struct Array2d{
|
|||||||
int n_rows;
|
int n_rows;
|
||||||
int numel;
|
int numel;
|
||||||
|
|
||||||
Array2d(){
|
Array2d() {
|
||||||
data = nullptr;
|
data = nullptr;
|
||||||
n_cols = 0;
|
n_cols = 0;
|
||||||
n_rows = 0;
|
n_rows = 0;
|
||||||
numel = 0;
|
numel = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(int n_cols, int n_rows){
|
void init(int n_cols, int n_rows) {
|
||||||
this->n_cols = n_cols;
|
this->n_cols = n_cols;
|
||||||
this->n_rows = n_rows;
|
this->n_rows = n_rows;
|
||||||
this->numel = n_cols * n_rows;
|
this->numel = n_cols * n_rows;
|
||||||
this->data = new PyVar[numel];
|
this->data = new PyVar[numel];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_valid(int col, int row) const{
|
bool is_valid(int col, int row) const { return 0 <= col && col < n_cols && 0 <= row && row < n_rows; }
|
||||||
return 0 <= col && col < n_cols && 0 <= row && row < n_rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
void check_valid(VM* vm, int col, int row) const{
|
void check_valid(VM* vm, int col, int row) const {
|
||||||
if(is_valid(col, row)) return;
|
if(is_valid(col, row)) return;
|
||||||
vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')'));
|
vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')'));
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar _get(int col, int row){
|
PyVar _get(int col, int row) { return data[row * n_cols + col]; }
|
||||||
return data[row * n_cols + col];
|
|
||||||
}
|
|
||||||
|
|
||||||
void _set(int col, int row, PyVar value){
|
void _set(int col, int row, PyVar value) { data[row * n_cols + col] = value; }
|
||||||
data[row * n_cols + col] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind(type, "__new__(cls, *args, **kwargs)", [](VM* vm, ArgsView args){
|
vm->bind(type, "__new__(cls, *args, **kwargs)", [](VM* vm, ArgsView args) {
|
||||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||||
return vm->new_object<Array2d>(cls);
|
return vm->new_object<Array2d>(cls);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind(type, "__init__(self, n_cols: int, n_rows: int, default=None)", [](VM* vm, ArgsView args){
|
vm->bind(type, "__init__(self, n_cols: int, n_rows: int, default=None)", [](VM* vm, ArgsView args) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
int n_cols = CAST(int, args[1]);
|
int n_cols = CAST(int, args[1]);
|
||||||
int n_rows = CAST(int, args[2]);
|
int n_rows = CAST(int, args[2]);
|
||||||
if(n_cols <= 0 || n_rows <= 0){
|
if(n_cols <= 0 || n_rows <= 0) { vm->ValueError("n_cols and n_rows must be positive integers"); }
|
||||||
vm->ValueError("n_cols and n_rows must be positive integers");
|
|
||||||
}
|
|
||||||
self.init(n_cols, n_rows);
|
self.init(n_cols, n_rows);
|
||||||
if(vm->py_callable(args[3])){
|
if(vm->py_callable(args[3])) {
|
||||||
for(int i = 0; i < self.numel; i++) self.data[i] = vm->call(args[3]);
|
for(int i = 0; i < self.numel; i++)
|
||||||
}else{
|
self.data[i] = vm->call(args[3]);
|
||||||
for(int i = 0; i < self.numel; i++) self.data[i] = args[3];
|
} else {
|
||||||
|
for(int i = 0; i < self.numel; i++)
|
||||||
|
self.data[i] = args[3];
|
||||||
}
|
}
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
@ -71,7 +65,7 @@ struct Array2d{
|
|||||||
PY_READONLY_FIELD(Array2d, "numel", numel);
|
PY_READONLY_FIELD(Array2d, "numel", numel);
|
||||||
|
|
||||||
// _get
|
// _get
|
||||||
vm->bind_func(type, "_get", 3, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "_get", 3, [](VM* vm, ArgsView args) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
int col = CAST(int, args[1]);
|
int col = CAST(int, args[1]);
|
||||||
int row = CAST(int, args[2]);
|
int row = CAST(int, args[2]);
|
||||||
@ -80,7 +74,7 @@ struct Array2d{
|
|||||||
});
|
});
|
||||||
|
|
||||||
// _set
|
// _set
|
||||||
vm->bind_func(type, "_set", 4, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "_set", 4, [](VM* vm, ArgsView args) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
int col = CAST(int, args[1]);
|
int col = CAST(int, args[1]);
|
||||||
int row = CAST(int, args[2]);
|
int row = CAST(int, args[2]);
|
||||||
@ -89,14 +83,14 @@ struct Array2d{
|
|||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "is_valid", 3, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "is_valid", 3, [](VM* vm, ArgsView args) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
int col = CAST(int, args[1]);
|
int col = CAST(int, args[1]);
|
||||||
int row = CAST(int, args[2]);
|
int row = CAST(int, args[2]);
|
||||||
return VAR(self.is_valid(col, row));
|
return VAR(self.is_valid(col, row));
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind(type, "get(self, col: int, row: int, default=None)", [](VM* vm, ArgsView args){
|
vm->bind(type, "get(self, col: int, row: int, default=None)", [](VM* vm, ArgsView args) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
int col = CAST(int, args[1]);
|
int col = CAST(int, args[1]);
|
||||||
int row = CAST(int, args[2]);
|
int row = CAST(int, args[2]);
|
||||||
@ -104,34 +98,34 @@ struct Array2d{
|
|||||||
return self._get(col, row);
|
return self._get(col, row);
|
||||||
});
|
});
|
||||||
|
|
||||||
#define HANDLE_SLICE() \
|
#define HANDLE_SLICE() \
|
||||||
int start_col, stop_col, step_col; \
|
int start_col, stop_col, step_col; \
|
||||||
int start_row, stop_row, step_row; \
|
int start_row, stop_row, step_row; \
|
||||||
vm->parse_int_slice(PK_OBJ_GET(Slice, xy[0]), self.n_cols, start_col, stop_col, step_col); \
|
vm->parse_int_slice(PK_OBJ_GET(Slice, xy[0]), self.n_cols, start_col, stop_col, step_col); \
|
||||||
vm->parse_int_slice(PK_OBJ_GET(Slice, xy[1]), self.n_rows, start_row, stop_row, step_row); \
|
vm->parse_int_slice(PK_OBJ_GET(Slice, xy[1]), self.n_rows, start_row, stop_row, step_row); \
|
||||||
if(step_col != 1 || step_row != 1) vm->ValueError("slice step must be 1"); \
|
if(step_col != 1 || step_row != 1) vm->ValueError("slice step must be 1"); \
|
||||||
int slice_width = stop_col - start_col; \
|
int slice_width = stop_col - start_col; \
|
||||||
int slice_height = stop_row - start_row; \
|
int slice_height = stop_row - start_row; \
|
||||||
if(slice_width <= 0 || slice_height <= 0) vm->ValueError("slice width and height must be positive");
|
if(slice_width <= 0 || slice_height <= 0) vm->ValueError("slice width and height must be positive");
|
||||||
|
|
||||||
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){
|
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
||||||
const Tuple& xy = CAST(Tuple&, _1);
|
const Tuple& xy = CAST(Tuple&, _1);
|
||||||
|
|
||||||
if(is_int(xy[0]) && is_int(xy[1])){
|
if(is_int(xy[0]) && is_int(xy[1])) {
|
||||||
i64 col = xy[0].as<i64>();
|
i64 col = xy[0].as<i64>();
|
||||||
i64 row = xy[1].as<i64>();
|
i64 row = xy[1].as<i64>();
|
||||||
self.check_valid(vm, col, row);
|
self.check_valid(vm, col, row);
|
||||||
return self._get(col, row);
|
return self._get(col, row);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_type(xy[0], VM::tp_slice) && is_type(xy[1], VM::tp_slice)){
|
if(is_type(xy[0], VM::tp_slice) && is_type(xy[1], VM::tp_slice)) {
|
||||||
HANDLE_SLICE();
|
HANDLE_SLICE();
|
||||||
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
||||||
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
||||||
new_array.init(stop_col - start_col, stop_row - start_row);
|
new_array.init(stop_col - start_col, stop_row - start_row);
|
||||||
for(int j = start_row; j < stop_row; j++){
|
for(int j = start_row; j < stop_row; j++) {
|
||||||
for(int i = start_col; i < stop_col; i++){
|
for(int i = start_col; i < stop_col; i++) {
|
||||||
new_array._set(i - start_col, j - start_row, self._get(i, j));
|
new_array._set(i - start_col, j - start_row, self._get(i, j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,10 +134,10 @@ struct Array2d{
|
|||||||
vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index");
|
vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index");
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1, PyVar _2){
|
vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1, PyVar _2) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
||||||
const Tuple& xy = CAST(Tuple&, _1);
|
const Tuple& xy = CAST(Tuple&, _1);
|
||||||
if(is_int(xy[0]) && is_int(xy[1])){
|
if(is_int(xy[0]) && is_int(xy[1])) {
|
||||||
i64 col = xy[0].as<i64>();
|
i64 col = xy[0].as<i64>();
|
||||||
i64 row = xy[1].as<i64>();
|
i64 row = xy[1].as<i64>();
|
||||||
self.check_valid(vm, col, row);
|
self.check_valid(vm, col, row);
|
||||||
@ -151,11 +145,11 @@ struct Array2d{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_type(xy[0], VM::tp_slice) && is_type(xy[1], VM::tp_slice)){
|
if(is_type(xy[0], VM::tp_slice) && is_type(xy[1], VM::tp_slice)) {
|
||||||
HANDLE_SLICE();
|
HANDLE_SLICE();
|
||||||
|
|
||||||
bool is_basic_type = false;
|
bool is_basic_type = false;
|
||||||
switch(vm->_tp(_2).index){
|
switch(vm->_tp(_2).index) {
|
||||||
case VM::tp_int.index: is_basic_type = true; break;
|
case VM::tp_int.index: is_basic_type = true; break;
|
||||||
case VM::tp_float.index: is_basic_type = true; break;
|
case VM::tp_float.index: is_basic_type = true; break;
|
||||||
case VM::tp_str.index: is_basic_type = true; break;
|
case VM::tp_str.index: is_basic_type = true; break;
|
||||||
@ -163,19 +157,19 @@ struct Array2d{
|
|||||||
default: is_basic_type = _2 == vm->None;
|
default: is_basic_type = _2 == vm->None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_basic_type){
|
if(is_basic_type) {
|
||||||
for(int j = 0; j < slice_height; j++)
|
for(int j = 0; j < slice_height; j++)
|
||||||
for(int i = 0; i < slice_width; i++)
|
for(int i = 0; i < slice_width; i++)
|
||||||
self._set(i + start_col, j + start_row, _2);
|
self._set(i + start_col, j + start_row, _2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!vm->is_user_type<Array2d>(_2)){
|
if(!vm->is_user_type<Array2d>(_2)) {
|
||||||
vm->TypeError(_S("expected int/float/str/bool/None or an array2d instance"));
|
vm->TypeError(_S("expected int/float/str/bool/None or an array2d instance"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Array2d& other = PK_OBJ_GET(Array2d, _2);
|
Array2d& other = PK_OBJ_GET(Array2d, _2);
|
||||||
if(slice_width != other.n_cols || slice_height != other.n_rows){
|
if(slice_width != other.n_cols || slice_height != other.n_rows) {
|
||||||
vm->ValueError("array2d size does not match the slice size");
|
vm->ValueError("array2d size does not match the slice size");
|
||||||
}
|
}
|
||||||
for(int j = 0; j < slice_height; j++)
|
for(int j = 0; j < slice_height; j++)
|
||||||
@ -186,161 +180,163 @@ struct Array2d{
|
|||||||
vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index");
|
vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index");
|
||||||
});
|
});
|
||||||
|
|
||||||
#undef HANDLE_SLICE
|
#undef HANDLE_SLICE
|
||||||
|
|
||||||
vm->bind_func(type, "tolist", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "tolist", 1, [](VM* vm, ArgsView args) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
List t(self.n_rows);
|
List t(self.n_rows);
|
||||||
for(int j = 0; j < self.n_rows; j++){
|
for(int j = 0; j < self.n_rows; j++) {
|
||||||
List row(self.n_cols);
|
List row(self.n_cols);
|
||||||
for(int i = 0; i < self.n_cols; i++) row[i] = self._get(i, j);
|
for(int i = 0; i < self.n_cols; i++)
|
||||||
|
row[i] = self._get(i, j);
|
||||||
t[j] = VAR(std::move(row));
|
t[j] = VAR(std::move(row));
|
||||||
}
|
}
|
||||||
return VAR(std::move(t));
|
return VAR(std::move(t));
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind__len__(type->as<Type>(), [](VM* vm, PyVar _0){
|
vm->bind__len__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
||||||
return (i64)self.numel;
|
return (i64)self.numel;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar _0) -> Str{
|
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar _0) -> Str {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
||||||
return _S("array2d(", self.n_cols, ", ", self.n_rows, ')');
|
return _S("array2d(", self.n_cols, ", ", self.n_rows, ')');
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "map", 2, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "map", 2, [](VM* vm, ArgsView args) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
PyVar f = args[1];
|
PyVar f = args[1];
|
||||||
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
||||||
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
||||||
new_array.init(self.n_cols, self.n_rows);
|
new_array.init(self.n_cols, self.n_rows);
|
||||||
for(int i = 0; i < new_array.numel; i++){
|
for(int i = 0; i < new_array.numel; i++) {
|
||||||
new_array.data[i] = vm->call(f, self.data[i]);
|
new_array.data[i] = vm->call(f, self.data[i]);
|
||||||
}
|
}
|
||||||
return new_array_obj;
|
return new_array_obj;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
||||||
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
||||||
new_array.init(self.n_cols, self.n_rows);
|
new_array.init(self.n_cols, self.n_rows);
|
||||||
for(int i = 0; i < new_array.numel; i++){
|
for(int i = 0; i < new_array.numel; i++) {
|
||||||
new_array.data[i] = self.data[i];
|
new_array.data[i] = self.data[i];
|
||||||
}
|
}
|
||||||
return new_array_obj;
|
return new_array_obj;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "fill_", 2, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "fill_", 2, [](VM* vm, ArgsView args) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
for(int i = 0; i < self.numel; i++){
|
for(int i = 0; i < self.numel; i++) {
|
||||||
self.data[i] = args[1];
|
self.data[i] = args[1];
|
||||||
}
|
}
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "apply_", 2, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "apply_", 2, [](VM* vm, ArgsView args) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
PyVar f = args[1];
|
PyVar f = args[1];
|
||||||
for(int i = 0; i < self.numel; i++){
|
for(int i = 0; i < self.numel; i++) {
|
||||||
self.data[i] = vm->call(f, self.data[i]);
|
self.data[i] = vm->call(f, self.data[i]);
|
||||||
}
|
}
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "copy_", 2, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "copy_", 2, [](VM* vm, ArgsView args) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
if(is_type(args[1], VM::tp_list)){
|
if(is_type(args[1], VM::tp_list)) {
|
||||||
const List& list = PK_OBJ_GET(List, args[1]);
|
const List& list = PK_OBJ_GET(List, args[1]);
|
||||||
if(list.size() != self.numel){
|
if(list.size() != self.numel) {
|
||||||
vm->ValueError("list size must be equal to the number of elements in the array2d");
|
vm->ValueError("list size must be equal to the number of elements in the array2d");
|
||||||
}
|
}
|
||||||
for(int i = 0; i < self.numel; i++){
|
for(int i = 0; i < self.numel; i++) {
|
||||||
self.data[i] = list[i];
|
self.data[i] = list[i];
|
||||||
}
|
}
|
||||||
return vm->None;
|
return vm->None;
|
||||||
}
|
}
|
||||||
Array2d& other = CAST(Array2d&, args[1]);
|
Array2d& other = CAST(Array2d&, args[1]);
|
||||||
// if self and other have different sizes, re-initialize self
|
// if self and other have different sizes, re-initialize self
|
||||||
if(self.n_cols != other.n_cols || self.n_rows != other.n_rows){
|
if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) {
|
||||||
delete self.data;
|
delete self.data;
|
||||||
self.init(other.n_cols, other.n_rows);
|
self.init(other.n_cols, other.n_rows);
|
||||||
}
|
}
|
||||||
for(int i = 0; i < self.numel; i++){
|
for(int i = 0; i < self.numel; i++) {
|
||||||
self.data[i] = other.data[i];
|
self.data[i] = other.data[i];
|
||||||
}
|
}
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){
|
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
||||||
if(!vm->is_user_type<Array2d>(_1)) return vm->NotImplemented;
|
if(!vm->is_user_type<Array2d>(_1)) return vm->NotImplemented;
|
||||||
Array2d& other = PK_OBJ_GET(Array2d, _1);
|
Array2d& other = PK_OBJ_GET(Array2d, _1);
|
||||||
if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) return vm->False;
|
if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) return vm->False;
|
||||||
for(int i = 0; i < self.numel; i++){
|
for(int i = 0; i < self.numel; i++) {
|
||||||
if(vm->py_ne(self.data[i], other.data[i])) return vm->False;
|
if(vm->py_ne(self.data[i], other.data[i])) return vm->False;
|
||||||
}
|
}
|
||||||
return vm->True;
|
return vm->True;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind(type, "count_neighbors(self, value, neighborhood='Moore') -> array2d[int]", [](VM* vm, ArgsView args){
|
vm->bind(type, "count_neighbors(self, value, neighborhood='Moore') -> array2d[int]", [](VM* vm, ArgsView args) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
||||||
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
||||||
new_array.init(self.n_cols, self.n_rows);
|
new_array.init(self.n_cols, self.n_rows);
|
||||||
PyVar value = args[1];
|
PyVar value = args[1];
|
||||||
const Str& neighborhood = CAST(Str&, args[2]);
|
const Str& neighborhood = CAST(Str&, args[2]);
|
||||||
if(neighborhood == "Moore"){
|
if(neighborhood == "Moore") {
|
||||||
for(int j = 0; j < new_array.n_rows; j++){
|
for(int j = 0; j < new_array.n_rows; j++) {
|
||||||
for(int i = 0; i < new_array.n_cols; i++){
|
for(int i = 0; i < new_array.n_cols; i++) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
count += self.is_valid(i-1, j-1) && vm->py_eq(self._get(i-1, j-1), value);
|
count += self.is_valid(i - 1, j - 1) && vm->py_eq(self._get(i - 1, j - 1), value);
|
||||||
count += self.is_valid(i, j-1) && vm->py_eq(self._get(i, j-1), value);
|
count += self.is_valid(i, j - 1) && vm->py_eq(self._get(i, j - 1), value);
|
||||||
count += self.is_valid(i+1, j-1) && vm->py_eq(self._get(i+1, j-1), value);
|
count += self.is_valid(i + 1, j - 1) && vm->py_eq(self._get(i + 1, j - 1), value);
|
||||||
count += self.is_valid(i-1, j) && vm->py_eq(self._get(i-1, j), value);
|
count += self.is_valid(i - 1, j) && vm->py_eq(self._get(i - 1, j), value);
|
||||||
count += self.is_valid(i+1, j) && vm->py_eq(self._get(i+1, j), value);
|
count += self.is_valid(i + 1, j) && vm->py_eq(self._get(i + 1, j), value);
|
||||||
count += self.is_valid(i-1, j+1) && vm->py_eq(self._get(i-1, j+1), value);
|
count += self.is_valid(i - 1, j + 1) && vm->py_eq(self._get(i - 1, j + 1), value);
|
||||||
count += self.is_valid(i, j+1) && vm->py_eq(self._get(i, j+1), value);
|
count += self.is_valid(i, j + 1) && vm->py_eq(self._get(i, j + 1), value);
|
||||||
count += self.is_valid(i+1, j+1) && vm->py_eq(self._get(i+1, j+1), value);
|
count += self.is_valid(i + 1, j + 1) && vm->py_eq(self._get(i + 1, j + 1), value);
|
||||||
new_array._set(i, j, VAR(count));
|
new_array._set(i, j, VAR(count));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else if(neighborhood == "von Neumann"){
|
} else if(neighborhood == "von Neumann") {
|
||||||
for(int j = 0; j < new_array.n_rows; j++){
|
for(int j = 0; j < new_array.n_rows; j++) {
|
||||||
for(int i = 0; i < new_array.n_cols; i++){
|
for(int i = 0; i < new_array.n_cols; i++) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
count += self.is_valid(i, j-1) && vm->py_eq(self._get(i, j-1), value);
|
count += self.is_valid(i, j - 1) && vm->py_eq(self._get(i, j - 1), value);
|
||||||
count += self.is_valid(i-1, j) && vm->py_eq(self._get(i-1, j), value);
|
count += self.is_valid(i - 1, j) && vm->py_eq(self._get(i - 1, j), value);
|
||||||
count += self.is_valid(i+1, j) && vm->py_eq(self._get(i+1, j), value);
|
count += self.is_valid(i + 1, j) && vm->py_eq(self._get(i + 1, j), value);
|
||||||
count += self.is_valid(i, j+1) && vm->py_eq(self._get(i, j+1), value);
|
count += self.is_valid(i, j + 1) && vm->py_eq(self._get(i, j + 1), value);
|
||||||
new_array._set(i, j, VAR(count));
|
new_array._set(i, j, VAR(count));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
vm->ValueError("neighborhood must be 'Moore' or 'von Neumann'");
|
vm->ValueError("neighborhood must be 'Moore' or 'von Neumann'");
|
||||||
}
|
}
|
||||||
return new_array_obj;
|
return new_array_obj;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "count", 2, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "count", 2, [](VM* vm, ArgsView args) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
PyVar value = args[1];
|
PyVar value = args[1];
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for(int i = 0; i < self.numel; i++) count += vm->py_eq(self.data[i], value);
|
for(int i = 0; i < self.numel; i++)
|
||||||
|
count += vm->py_eq(self.data[i], value);
|
||||||
return VAR(count);
|
return VAR(count);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "find_bounding_rect", 2, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "find_bounding_rect", 2, [](VM* vm, ArgsView args) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
PyVar value = args[1];
|
PyVar value = args[1];
|
||||||
int left = self.n_cols;
|
int left = self.n_cols;
|
||||||
int top = self.n_rows;
|
int top = self.n_rows;
|
||||||
int right = 0;
|
int right = 0;
|
||||||
int bottom = 0;
|
int bottom = 0;
|
||||||
for(int j = 0; j < self.n_rows; j++){
|
for(int j = 0; j < self.n_rows; j++) {
|
||||||
for(int i = 0; i < self.n_cols; i++){
|
for(int i = 0; i < self.n_cols; i++) {
|
||||||
if(vm->py_eq(self._get(i, j), value)){
|
if(vm->py_eq(self._get(i, j), value)) {
|
||||||
left = (std::min)(left, i);
|
left = (std::min)(left, i);
|
||||||
top = (std::min)(top, j);
|
top = (std::min)(top, j);
|
||||||
right = (std::max)(right, i);
|
right = (std::max)(right, i);
|
||||||
@ -360,30 +356,30 @@ struct Array2d{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _gc_mark(VM* vm) const{
|
void _gc_mark(VM* vm) const {
|
||||||
for(int i = 0; i < numel; i++) vm->obj_gc_mark(data[i]);
|
for(int i = 0; i < numel; i++)
|
||||||
|
vm->obj_gc_mark(data[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Array2d(){
|
~Array2d() { delete[] data; }
|
||||||
delete[] data;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Array2dIter {
|
||||||
struct Array2dIter{
|
|
||||||
PK_ALWAYS_PASS_BY_POINTER(Array2dIter)
|
PK_ALWAYS_PASS_BY_POINTER(Array2dIter)
|
||||||
|
|
||||||
PyVar ref;
|
PyVar ref;
|
||||||
Array2d* a;
|
Array2d* a;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
Array2dIter(PyVar ref, Array2d* a): ref(ref), a(a), i(0){}
|
Array2dIter(PyVar ref, Array2d* a) : ref(ref), a(a), i(0) {}
|
||||||
|
|
||||||
void _gc_mark(VM* vm) const{ vm->obj_gc_mark(ref); }
|
void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
|
||||||
|
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
|
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{
|
return _0;
|
||||||
|
});
|
||||||
|
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||||
Array2dIter& self = PK_OBJ_GET(Array2dIter, _0);
|
Array2dIter& self = PK_OBJ_GET(Array2dIter, _0);
|
||||||
if(self.i == self.a->numel) return 0;
|
if(self.i == self.a->numel) return 0;
|
||||||
std::div_t res = std::div(self.i, self.a->n_cols);
|
std::div_t res = std::div(self.i, self.a->n_cols);
|
||||||
@ -395,20 +391,19 @@ struct Array2dIter{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void add_module_array2d(VM* vm){
|
void add_module_array2d(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("array2d");
|
PyObject* mod = vm->new_module("array2d");
|
||||||
|
|
||||||
vm->register_user_class<Array2d>(mod, "array2d", VM::tp_object, true);
|
vm->register_user_class<Array2d>(mod, "array2d", VM::tp_object, true);
|
||||||
vm->register_user_class<Array2dIter>(mod, "_array2d_iter");
|
vm->register_user_class<Array2dIter>(mod, "_array2d_iter");
|
||||||
|
|
||||||
Type array2d_iter_t = vm->_tp_user<Array2d>();
|
Type array2d_iter_t = vm->_tp_user<Array2d>();
|
||||||
vm->bind__iter__(array2d_iter_t, [](VM* vm, PyVar _0){
|
vm->bind__iter__(array2d_iter_t, [](VM* vm, PyVar _0) {
|
||||||
return vm->new_user_object<Array2dIter>(_0, &_0.obj_get<Array2d>());
|
return vm->new_user_object<Array2dIter>(_0, &_0.obj_get<Array2d>());
|
||||||
});
|
});
|
||||||
vm->_all_types[array2d_iter_t].op__iter__ = [](VM* vm, PyVar _0){
|
vm->_all_types[array2d_iter_t].op__iter__ = [](VM* vm, PyVar _0) {
|
||||||
vm->new_stack_object<Array2dIter>(vm->_tp_user<Array2dIter>(), _0, &_0.obj_get<Array2d>());
|
vm->new_stack_object<Array2dIter>(vm->_tp_user<Array2dIter>(), _0, &_0.obj_get<Array2d>());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace pkpy
|
||||||
} // namespace pkpy
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include "pocketpy/modules/base64.hpp"
|
#include "pocketpy/modules/base64.hpp"
|
||||||
#include "pocketpy/interpreter/bindings.hpp"
|
#include "pocketpy/interpreter/bindings.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
// https://github.com/zhicheng/base64/blob/master/base64.c
|
// https://github.com/zhicheng/base64/blob/master/base64.c
|
||||||
|
|
||||||
@ -9,6 +9,7 @@ const char BASE64_PAD = '=';
|
|||||||
const char BASE64DE_FIRST = '+';
|
const char BASE64DE_FIRST = '+';
|
||||||
const char BASE64DE_LAST = 'z';
|
const char BASE64DE_LAST = 'z';
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
/* BASE 64 encode table */
|
/* BASE 64 encode table */
|
||||||
const char base64en[] = {
|
const char base64en[] = {
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||||
@ -71,114 +72,99 @@ const unsigned char base64de[] = {
|
|||||||
/* 'x', 'y', 'z', '{', '|', '}', '~', del, */
|
/* 'x', 'y', 'z', '{', '|', '}', '~', del, */
|
||||||
49, 50, 51, 255, 255, 255, 255, 255
|
49, 50, 51, 255, 255, 255, 255, 255
|
||||||
};
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int base64_encode(const unsigned char* in, unsigned int inlen, char* out) {
|
||||||
base64_encode(const unsigned char *in, unsigned int inlen, char *out)
|
int s;
|
||||||
{
|
unsigned int i;
|
||||||
int s;
|
unsigned int j;
|
||||||
unsigned int i;
|
unsigned char c;
|
||||||
unsigned int j;
|
unsigned char l;
|
||||||
unsigned char c;
|
|
||||||
unsigned char l;
|
|
||||||
|
|
||||||
s = 0;
|
s = 0;
|
||||||
l = 0;
|
l = 0;
|
||||||
for (i = j = 0; i < inlen; i++) {
|
for(i = j = 0; i < inlen; i++) {
|
||||||
c = in[i];
|
c = in[i];
|
||||||
|
|
||||||
switch (s) {
|
switch(s) {
|
||||||
case 0:
|
case 0:
|
||||||
s = 1;
|
s = 1;
|
||||||
out[j++] = base64en[(c >> 2) & 0x3F];
|
out[j++] = base64en[(c >> 2) & 0x3F];
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
s = 2;
|
s = 2;
|
||||||
out[j++] = base64en[((l & 0x3) << 4) | ((c >> 4) & 0xF)];
|
out[j++] = base64en[((l & 0x3) << 4) | ((c >> 4) & 0xF)];
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
s = 0;
|
s = 0;
|
||||||
out[j++] = base64en[((l & 0xF) << 2) | ((c >> 6) & 0x3)];
|
out[j++] = base64en[((l & 0xF) << 2) | ((c >> 6) & 0x3)];
|
||||||
out[j++] = base64en[c & 0x3F];
|
out[j++] = base64en[c & 0x3F];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
l = c;
|
l = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (s) {
|
switch(s) {
|
||||||
case 1:
|
case 1:
|
||||||
out[j++] = base64en[(l & 0x3) << 4];
|
out[j++] = base64en[(l & 0x3) << 4];
|
||||||
out[j++] = BASE64_PAD;
|
out[j++] = BASE64_PAD;
|
||||||
out[j++] = BASE64_PAD;
|
out[j++] = BASE64_PAD;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
out[j++] = base64en[(l & 0xF) << 2];
|
out[j++] = base64en[(l & 0xF) << 2];
|
||||||
out[j++] = BASE64_PAD;
|
out[j++] = BASE64_PAD;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
out[j] = 0;
|
out[j] = 0;
|
||||||
|
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int base64_decode(const char* in, unsigned int inlen, unsigned char* out) {
|
||||||
base64_decode(const char *in, unsigned int inlen, unsigned char *out)
|
unsigned int i;
|
||||||
{
|
unsigned int j;
|
||||||
unsigned int i;
|
unsigned char c;
|
||||||
unsigned int j;
|
|
||||||
unsigned char c;
|
|
||||||
|
|
||||||
if (inlen & 0x3) {
|
if(inlen & 0x3) { return 0; }
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = j = 0; i < inlen; i++) {
|
for(i = j = 0; i < inlen; i++) {
|
||||||
if (in[i] == BASE64_PAD) {
|
if(in[i] == BASE64_PAD) { break; }
|
||||||
break;
|
if(in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) { return 0; }
|
||||||
}
|
|
||||||
if (in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
c = base64de[(unsigned char)in[i]];
|
c = base64de[(unsigned char)in[i]];
|
||||||
if (c == 255) {
|
if(c == 255) { return 0; }
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (i & 0x3) {
|
switch(i & 0x3) {
|
||||||
case 0:
|
case 0: out[j] = (c << 2) & 0xFF; break;
|
||||||
out[j] = (c << 2) & 0xFF;
|
case 1:
|
||||||
break;
|
out[j++] |= (c >> 4) & 0x3;
|
||||||
case 1:
|
out[j] = (c & 0xF) << 4;
|
||||||
out[j++] |= (c >> 4) & 0x3;
|
break;
|
||||||
out[j] = (c & 0xF) << 4;
|
case 2:
|
||||||
break;
|
out[j++] |= (c >> 2) & 0xF;
|
||||||
case 2:
|
out[j] = (c & 0x3) << 6;
|
||||||
out[j++] |= (c >> 2) & 0xF;
|
break;
|
||||||
out[j] = (c & 0x3) << 6;
|
case 3: out[j++] |= c; break;
|
||||||
break;
|
}
|
||||||
case 3:
|
}
|
||||||
out[j++] |= c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_module_base64(VM* vm){
|
void add_module_base64(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("base64");
|
PyObject* mod = vm->new_module("base64");
|
||||||
|
|
||||||
// b64encode
|
// b64encode
|
||||||
vm->bind_func(mod, "b64encode", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "b64encode", 1, [](VM* vm, ArgsView args) {
|
||||||
Bytes& b = CAST(Bytes&, args[0]);
|
Bytes& b = CAST(Bytes&, args[0]);
|
||||||
unsigned char* p = (unsigned char*)std::malloc(b.size() * 2);
|
unsigned char* p = (unsigned char*)std::malloc(b.size() * 2);
|
||||||
int size = base64_encode((const unsigned char*)b.data(), b.size(), (char*)p);
|
int size = base64_encode((const unsigned char*)b.data(), b.size(), (char*)p);
|
||||||
return VAR(Bytes(p, size));
|
return VAR(Bytes(p, size));
|
||||||
});
|
});
|
||||||
|
|
||||||
// b64decode
|
// b64decode
|
||||||
vm->bind_func(mod, "b64decode", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "b64decode", 1, [](VM* vm, ArgsView args) {
|
||||||
Bytes& b = CAST(Bytes&, args[0]);
|
Bytes& b = CAST(Bytes&, args[0]);
|
||||||
unsigned char* p = (unsigned char*)std::malloc(b.size());
|
unsigned char* p = (unsigned char*)std::malloc(b.size());
|
||||||
int size = base64_decode((const char*)b.data(), b.size(), p);
|
int size = base64_decode((const char*)b.data(), b.size(), p);
|
||||||
@ -186,4 +172,4 @@ void add_module_base64(VM* vm){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -1,60 +1,57 @@
|
|||||||
#include "pocketpy/modules/csv.hpp"
|
#include "pocketpy/modules/csv.hpp"
|
||||||
#include "pocketpy/interpreter/bindings.hpp"
|
#include "pocketpy/interpreter/bindings.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
void add_module_csv(VM *vm){
|
void add_module_csv(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("csv");
|
PyObject* mod = vm->new_module("csv");
|
||||||
|
|
||||||
vm->bind(mod, "reader(csvfile: list[str]) -> list[list]", [](VM* vm, ArgsView args){
|
vm->bind(mod, "reader(csvfile: list[str]) -> list[list]", [](VM* vm, ArgsView args) {
|
||||||
const List& csvfile = CAST(List&, args[0]);
|
const List& csvfile = CAST(List&, args[0]);
|
||||||
List ret;
|
List ret;
|
||||||
for(int i=0; i<csvfile.size(); i++){
|
for(int i = 0; i < csvfile.size(); i++) {
|
||||||
std::string_view line = CAST(Str&, csvfile[i]).sv();
|
std::string_view line = CAST(Str&, csvfile[i]).sv();
|
||||||
if(i == 0){
|
if(i == 0) {
|
||||||
// Skip utf8 BOM if there is any.
|
// Skip utf8 BOM if there is any.
|
||||||
if (strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) line = line.substr(3);
|
if(strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) line = line.substr(3);
|
||||||
}
|
}
|
||||||
List row;
|
List row;
|
||||||
int j;
|
int j;
|
||||||
bool in_quote = false;
|
bool in_quote = false;
|
||||||
std::string buffer;
|
std::string buffer;
|
||||||
__NEXT_LINE:
|
__NEXT_LINE:
|
||||||
j = 0;
|
j = 0;
|
||||||
while(j < line.size()){
|
while(j < line.size()) {
|
||||||
switch(line[j]){
|
switch(line[j]) {
|
||||||
case '"':
|
case '"':
|
||||||
if(in_quote){
|
if(in_quote) {
|
||||||
if(j+1 < line.size() && line[j+1] == '"'){
|
if(j + 1 < line.size() && line[j + 1] == '"') {
|
||||||
buffer += '"';
|
buffer += '"';
|
||||||
j++;
|
j++;
|
||||||
}else{
|
} else {
|
||||||
in_quote = false;
|
in_quote = false;
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
in_quote = true;
|
in_quote = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ',':
|
case ',':
|
||||||
if(in_quote){
|
if(in_quote) {
|
||||||
buffer += line[j];
|
buffer += line[j];
|
||||||
}else{
|
} else {
|
||||||
row.push_back(VAR(buffer));
|
row.push_back(VAR(buffer));
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '\r':
|
case '\r': break; // ignore
|
||||||
break; // ignore
|
default: buffer += line[j]; break;
|
||||||
default:
|
|
||||||
buffer += line[j];
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
if(in_quote){
|
if(in_quote) {
|
||||||
if(i == csvfile.size()-1){
|
if(i == csvfile.size() - 1) {
|
||||||
vm->ValueError("unterminated quote");
|
vm->ValueError("unterminated quote");
|
||||||
}else{
|
} else {
|
||||||
buffer += '\n';
|
buffer += '\n';
|
||||||
i++;
|
i++;
|
||||||
line = CAST(Str&, csvfile[i]).sv();
|
line = CAST(Str&, csvfile[i]).sv();
|
||||||
@ -67,22 +64,18 @@ __NEXT_LINE:
|
|||||||
return VAR(std::move(ret));
|
return VAR(std::move(ret));
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind(mod, "DictReader(csvfile: list[str]) -> list[dict]", [](VM* vm, ArgsView args){
|
vm->bind(mod, "DictReader(csvfile: list[str]) -> list[dict]", [](VM* vm, ArgsView args) {
|
||||||
PyVar csv_reader = vm->_modules["csv"]->attr("reader");
|
PyVar csv_reader = vm->_modules["csv"]->attr("reader");
|
||||||
PyVar ret_obj = vm->call(csv_reader, args[0]);
|
PyVar ret_obj = vm->call(csv_reader, args[0]);
|
||||||
const List& ret = CAST(List&, ret_obj);
|
const List& ret = CAST(List&, ret_obj);
|
||||||
if(ret.size() == 0){
|
if(ret.size() == 0) { vm->ValueError("empty csvfile"); }
|
||||||
vm->ValueError("empty csvfile");
|
|
||||||
}
|
|
||||||
const List& header = CAST(List&, ret[0]);
|
const List& header = CAST(List&, ret[0]);
|
||||||
List new_ret;
|
List new_ret;
|
||||||
for(int i=1; i<ret.size(); i++){
|
for(int i = 1; i < ret.size(); i++) {
|
||||||
const List& row = CAST(List&, ret[i]);
|
const List& row = CAST(List&, ret[i]);
|
||||||
if(row.size() != header.size()){
|
if(row.size() != header.size()) { vm->ValueError("row.size() != header.size()"); }
|
||||||
vm->ValueError("row.size() != header.size()");
|
|
||||||
}
|
|
||||||
Dict row_dict;
|
Dict row_dict;
|
||||||
for(int j=0; j<header.size(); j++){
|
for(int j = 0; j < header.size(); j++) {
|
||||||
row_dict.set(vm, header[j], row[j]);
|
row_dict.set(vm, header[j], row[j]);
|
||||||
}
|
}
|
||||||
new_ret.push_back(VAR(std::move(row_dict)));
|
new_ret.push_back(VAR(std::move(row_dict)));
|
||||||
@ -91,4 +84,4 @@ __NEXT_LINE:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
#include "pocketpy/modules/dataclasses.hpp"
|
#include "pocketpy/modules/dataclasses.hpp"
|
||||||
#include "pocketpy/interpreter/bindings.hpp"
|
#include "pocketpy/interpreter/bindings.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
static void patch__init__(VM* vm, Type cls){
|
static void patch__init__(VM* vm, Type cls) {
|
||||||
vm->bind(vm->_t(cls), "__init__(self, *args, **kwargs)", [](VM* vm, ArgsView _view){
|
vm->bind(vm->_t(cls), "__init__(self, *args, **kwargs)", [](VM* vm, ArgsView _view) {
|
||||||
PyVar self = _view[0];
|
PyVar self = _view[0];
|
||||||
const Tuple& args = CAST(Tuple&, _view[1]);
|
const Tuple& args = CAST(Tuple&, _view[1]);
|
||||||
const Dict& kwargs_ = CAST(Dict&, _view[2]);
|
const Dict& kwargs_ = CAST(Dict&, _view[2]);
|
||||||
NameDict kwargs;
|
NameDict kwargs;
|
||||||
kwargs_.apply([&](PyVar k, PyVar v){
|
kwargs_.apply([&](PyVar k, PyVar v) {
|
||||||
kwargs.set(CAST(Str&, k), v);
|
kwargs.set(CAST(Str&, k), v);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -18,26 +18,27 @@ static void patch__init__(VM* vm, Type cls){
|
|||||||
NameDict& cls_d = cls_info->obj->attr();
|
NameDict& cls_d = cls_info->obj->attr();
|
||||||
const auto& fields = cls_info->annotated_fields;
|
const auto& fields = cls_info->annotated_fields;
|
||||||
|
|
||||||
int i = 0; // index into args
|
int i = 0; // index into args
|
||||||
for(StrName field: fields){
|
for(StrName field: fields) {
|
||||||
if(kwargs.contains(field)){
|
if(kwargs.contains(field)) {
|
||||||
self->attr().set(field, kwargs[field]);
|
self->attr().set(field, kwargs[field]);
|
||||||
kwargs.del(field);
|
kwargs.del(field);
|
||||||
}else{
|
} else {
|
||||||
if(i < args.size()){
|
if(i < args.size()) {
|
||||||
self->attr().set(field, args[i]);
|
self->attr().set(field, args[i]);
|
||||||
++i;
|
++i;
|
||||||
}else if(cls_d.contains(field)){ // has default value
|
} else if(cls_d.contains(field)) { // has default value
|
||||||
self->attr().set(field, cls_d[field]);
|
self->attr().set(field, cls_d[field]);
|
||||||
}else{
|
} else {
|
||||||
vm->TypeError(_S(cls_info->name, " missing required argument ", field.escape()));
|
vm->TypeError(_S(cls_info->name, " missing required argument ", field.escape()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(args.size() > i){
|
if(args.size() > i) {
|
||||||
vm->TypeError(_S(cls_info->name, " takes ", fields.size(), " positional arguments but ", args.size(), " were given"));
|
vm->TypeError(
|
||||||
|
_S(cls_info->name, " takes ", fields.size(), " positional arguments but ", args.size(), " were given"));
|
||||||
}
|
}
|
||||||
if(kwargs.size() > 0){
|
if(kwargs.size() > 0) {
|
||||||
StrName unexpected_key = kwargs.items()[0].first;
|
StrName unexpected_key = kwargs.items()[0].first;
|
||||||
vm->TypeError(_S(cls_info->name, " got an unexpected keyword argument ", unexpected_key.escape()));
|
vm->TypeError(_S(cls_info->name, " got an unexpected keyword argument ", unexpected_key.escape()));
|
||||||
}
|
}
|
||||||
@ -45,17 +46,19 @@ static void patch__init__(VM* vm, Type cls){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void patch__repr__(VM* vm, Type cls){
|
static void patch__repr__(VM* vm, Type cls) {
|
||||||
vm->bind__repr__(cls, [](VM* vm, PyVar _0) -> Str{
|
vm->bind__repr__(cls, [](VM* vm, PyVar _0) -> Str {
|
||||||
const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)];
|
const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)];
|
||||||
const auto& fields = cls_info->annotated_fields;
|
const auto& fields = cls_info->annotated_fields;
|
||||||
const NameDict& obj_d = _0->attr();
|
const NameDict& obj_d = _0->attr();
|
||||||
SStream ss;
|
SStream ss;
|
||||||
ss << cls_info->name << "(";
|
ss << cls_info->name << "(";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for(StrName field: fields){
|
for(StrName field: fields) {
|
||||||
if(first) first = false;
|
if(first)
|
||||||
else ss << ", ";
|
first = false;
|
||||||
|
else
|
||||||
|
ss << ", ";
|
||||||
ss << field << "=" << vm->py_repr(obj_d[field]);
|
ss << field << "=" << vm->py_repr(obj_d[field]);
|
||||||
}
|
}
|
||||||
ss << ")";
|
ss << ")";
|
||||||
@ -63,12 +66,12 @@ static void patch__repr__(VM* vm, Type cls){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void patch__eq__(VM* vm, Type cls){
|
static void patch__eq__(VM* vm, Type cls) {
|
||||||
vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1){
|
vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
if(vm->_tp(_0) != vm->_tp(_1)) return vm->NotImplemented;
|
if(vm->_tp(_0) != vm->_tp(_1)) return vm->NotImplemented;
|
||||||
const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)];
|
const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)];
|
||||||
const auto& fields = cls_info->annotated_fields;
|
const auto& fields = cls_info->annotated_fields;
|
||||||
for(StrName field: fields){
|
for(StrName field: fields) {
|
||||||
PyVar lhs = _0->attr(field);
|
PyVar lhs = _0->attr(field);
|
||||||
PyVar rhs = _1->attr(field);
|
PyVar rhs = _1->attr(field);
|
||||||
if(vm->py_ne(lhs, rhs)) return vm->False;
|
if(vm->py_ne(lhs, rhs)) return vm->False;
|
||||||
@ -77,10 +80,10 @@ static void patch__eq__(VM* vm, Type cls){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_module_dataclasses(VM* vm){
|
void add_module_dataclasses(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("dataclasses");
|
PyObject* mod = vm->new_module("dataclasses");
|
||||||
|
|
||||||
vm->bind_func(mod, "dataclass", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "dataclass", 1, [](VM* vm, ArgsView args) {
|
||||||
vm->check_type(args[0], VM::tp_type);
|
vm->check_type(args[0], VM::tp_type);
|
||||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||||
NameDict& cls_d = args[0]->attr();
|
NameDict& cls_d = args[0]->attr();
|
||||||
@ -91,11 +94,11 @@ void add_module_dataclasses(VM* vm){
|
|||||||
|
|
||||||
const auto& fields = vm->_all_types[cls].annotated_fields;
|
const auto& fields = vm->_all_types[cls].annotated_fields;
|
||||||
bool has_default = false;
|
bool has_default = false;
|
||||||
for(StrName field: fields){
|
for(StrName field: fields) {
|
||||||
if(cls_d.contains(field)){
|
if(cls_d.contains(field)) {
|
||||||
has_default = true;
|
has_default = true;
|
||||||
}else{
|
} else {
|
||||||
if(has_default){
|
if(has_default) {
|
||||||
vm->TypeError(_S("non-default argument ", field.escape(), " follows default argument"));
|
vm->TypeError(_S("non-default argument ", field.escape(), " follows default argument"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,15 +106,15 @@ void add_module_dataclasses(VM* vm){
|
|||||||
return args[0];
|
return args[0];
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "asdict", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "asdict", 1, [](VM* vm, ArgsView args) {
|
||||||
const auto& fields = vm->_tp_info(args[0])->annotated_fields;
|
const auto& fields = vm->_tp_info(args[0])->annotated_fields;
|
||||||
const NameDict& obj_d = args[0]->attr();
|
const NameDict& obj_d = args[0]->attr();
|
||||||
Dict d;
|
Dict d;
|
||||||
for(StrName field: fields){
|
for(StrName field: fields) {
|
||||||
d.set(vm, VAR(field.sv()), obj_d[field]);
|
d.set(vm, VAR(field.sv()), obj_d[field]);
|
||||||
}
|
}
|
||||||
return VAR(std::move(d));
|
return VAR(std::move(d));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -3,193 +3,161 @@
|
|||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
// https://easings.net/
|
// https://easings.net/
|
||||||
|
|
||||||
const double kPi = 3.1415926545;
|
const double kPi = 3.1415926545;
|
||||||
|
|
||||||
static double easeLinear( double x ) {
|
static double easeLinear(double x) { return x; }
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeInSine( double x ) {
|
static double easeInSine(double x) { return 1.0 - std::cos(x * kPi / 2); }
|
||||||
return 1.0 - std::cos( x * kPi / 2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeOutSine( double x ) {
|
static double easeOutSine(double x) { return std::sin(x * kPi / 2); }
|
||||||
return std::sin( x * kPi / 2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeInOutSine( double x ) {
|
static double easeInOutSine(double x) { return -(std::cos(kPi * x) - 1) / 2; }
|
||||||
return -( std::cos( kPi * x ) - 1 ) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeInQuad( double x ) {
|
static double easeInQuad(double x) { return x * x; }
|
||||||
return x * x;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeOutQuad( double x ) {
|
static double easeOutQuad(double x) { return 1 - std::pow(1 - x, 2); }
|
||||||
return 1 - std::pow( 1 - x, 2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeInOutQuad( double x ) {
|
static double easeInOutQuad(double x) {
|
||||||
if( x < 0.5 ) {
|
if(x < 0.5) {
|
||||||
return 2 * x * x;
|
return 2 * x * x;
|
||||||
} else {
|
} else {
|
||||||
return 1 - std::pow( -2 * x + 2, 2 ) / 2;
|
return 1 - std::pow(-2 * x + 2, 2) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static double easeInCubic( double x ) {
|
static double easeInCubic(double x) { return x * x * x; }
|
||||||
return x * x * x;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeOutCubic( double x ) {
|
static double easeOutCubic(double x) { return 1 - std::pow(1 - x, 3); }
|
||||||
return 1 - std::pow( 1 - x, 3 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeInOutCubic( double x ) {
|
static double easeInOutCubic(double x) {
|
||||||
if( x < 0.5 ) {
|
if(x < 0.5) {
|
||||||
return 4 * x * x * x;
|
return 4 * x * x * x;
|
||||||
} else {
|
} else {
|
||||||
return 1 - std::pow( -2 * x + 2, 3 ) / 2;
|
return 1 - std::pow(-2 * x + 2, 3) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static double easeInQuart( double x ) {
|
static double easeInQuart(double x) { return std::pow(x, 4); }
|
||||||
return std::pow( x, 4 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeOutQuart( double x ) {
|
static double easeOutQuart(double x) { return 1 - std::pow(1 - x, 4); }
|
||||||
return 1 - std::pow( 1 - x, 4 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeInOutQuart( double x ) {
|
static double easeInOutQuart(double x) {
|
||||||
if( x < 0.5 ) {
|
if(x < 0.5) {
|
||||||
return 8 * std::pow( x, 4 );
|
return 8 * std::pow(x, 4);
|
||||||
} else {
|
} else {
|
||||||
return 1 - std::pow( -2 * x + 2, 4 ) / 2;
|
return 1 - std::pow(-2 * x + 2, 4) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static double easeInQuint( double x ) {
|
static double easeInQuint(double x) { return std::pow(x, 5); }
|
||||||
return std::pow( x, 5 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeOutQuint( double x ) {
|
static double easeOutQuint(double x) { return 1 - std::pow(1 - x, 5); }
|
||||||
return 1 - std::pow( 1 - x, 5 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeInOutQuint( double x ) {
|
static double easeInOutQuint(double x) {
|
||||||
if( x < 0.5 ) {
|
if(x < 0.5) {
|
||||||
return 16 * std::pow( x, 5 );
|
return 16 * std::pow(x, 5);
|
||||||
} else {
|
} else {
|
||||||
return 1 - std::pow( -2 * x + 2, 5 ) / 2;
|
return 1 - std::pow(-2 * x + 2, 5) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static double easeInExpo( double x ) {
|
static double easeInExpo(double x) { return x == 0 ? 0 : std::pow(2, 10 * x - 10); }
|
||||||
return x == 0 ? 0 : std::pow( 2, 10 * x - 10 );
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeOutExpo( double x ) {
|
static double easeOutExpo(double x) { return x == 1 ? 1 : 1 - std::pow(2, -10 * x); }
|
||||||
return x == 1 ? 1 : 1 - std::pow( 2, -10 * x );
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeInOutExpo( double x ) {
|
static double easeInOutExpo(double x) {
|
||||||
if( x == 0 ) {
|
if(x == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if( x == 1 ) {
|
} else if(x == 1) {
|
||||||
return 1;
|
return 1;
|
||||||
} else if( x < 0.5 ) {
|
} else if(x < 0.5) {
|
||||||
return std::pow( 2, 20 * x - 10 ) / 2;
|
return std::pow(2, 20 * x - 10) / 2;
|
||||||
} else {
|
} else {
|
||||||
return (2 - std::pow( 2, -20 * x + 10 )) / 2;
|
return (2 - std::pow(2, -20 * x + 10)) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static double easeInCirc( double x ) {
|
static double easeInCirc(double x) { return 1 - std::sqrt(1 - std::pow(x, 2)); }
|
||||||
return 1 - std::sqrt( 1 - std::pow( x, 2 ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeOutCirc( double x ) {
|
static double easeOutCirc(double x) { return std::sqrt(1 - std::pow(x - 1, 2)); }
|
||||||
return std::sqrt( 1 - std::pow( x - 1, 2 ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
static double easeInOutCirc( double x ) {
|
static double easeInOutCirc(double x) {
|
||||||
if( x < 0.5 ) {
|
if(x < 0.5) {
|
||||||
return (1 - std::sqrt( 1 - std::pow( 2 * x, 2 ) )) / 2;
|
return (1 - std::sqrt(1 - std::pow(2 * x, 2))) / 2;
|
||||||
} else {
|
} else {
|
||||||
return (std::sqrt( 1 - std::pow( -2 * x + 2, 2 ) ) + 1) / 2;
|
return (std::sqrt(1 - std::pow(-2 * x + 2, 2)) + 1) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static double easeInBack( double x ) {
|
static double easeInBack(double x) {
|
||||||
const double c1 = 1.70158;
|
const double c1 = 1.70158;
|
||||||
const double c3 = c1 + 1;
|
const double c3 = c1 + 1;
|
||||||
return c3 * x * x * x - c1 * x * x;
|
return c3 * x * x * x - c1 * x * x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static double easeOutBack( double x ) {
|
static double easeOutBack(double x) {
|
||||||
const double c1 = 1.70158;
|
const double c1 = 1.70158;
|
||||||
const double c3 = c1 + 1;
|
const double c3 = c1 + 1;
|
||||||
return 1 + c3 * std::pow( x - 1, 3 ) + c1 * std::pow( x - 1, 2 );
|
return 1 + c3 * std::pow(x - 1, 3) + c1 * std::pow(x - 1, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static double easeInOutBack( double x ) {
|
static double easeInOutBack(double x) {
|
||||||
const double c1 = 1.70158;
|
const double c1 = 1.70158;
|
||||||
const double c2 = c1 * 1.525;
|
const double c2 = c1 * 1.525;
|
||||||
if( x < 0.5 ) {
|
if(x < 0.5) {
|
||||||
return (std::pow( 2 * x, 2 ) * ((c2 + 1) * 2 * x - c2)) / 2;
|
return (std::pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2;
|
||||||
} else {
|
} else {
|
||||||
return (std::pow( 2 * x - 2, 2 ) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;
|
return (std::pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static double easeInElastic( double x ) {
|
static double easeInElastic(double x) {
|
||||||
const double c4 = (2 * kPi) / 3;
|
const double c4 = (2 * kPi) / 3;
|
||||||
if( x == 0 ) {
|
if(x == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if( x == 1 ) {
|
} else if(x == 1) {
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
return -std::pow( 2, 10 * x - 10 ) * std::sin( (x * 10 - 10.75) * c4 );
|
return -std::pow(2, 10 * x - 10) * std::sin((x * 10 - 10.75) * c4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static double easeOutElastic( double x ) {
|
static double easeOutElastic(double x) {
|
||||||
const double c4 = (2 * kPi) / 3;
|
const double c4 = (2 * kPi) / 3;
|
||||||
if( x == 0 ) {
|
if(x == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if( x == 1 ) {
|
} else if(x == 1) {
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
return std::pow( 2, -10 * x ) * std::sin( (x * 10 - 0.75) * c4 ) + 1;
|
return std::pow(2, -10 * x) * std::sin((x * 10 - 0.75) * c4) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static double easeInOutElastic( double x ) {
|
static double easeInOutElastic(double x) {
|
||||||
const double c5 = (2 * kPi) / 4.5;
|
const double c5 = (2 * kPi) / 4.5;
|
||||||
if( x == 0 ) {
|
if(x == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if( x == 1 ) {
|
} else if(x == 1) {
|
||||||
return 1;
|
return 1;
|
||||||
} else if( x < 0.5 ) {
|
} else if(x < 0.5) {
|
||||||
return -(std::pow( 2, 20 * x - 10 ) * std::sin( (20 * x - 11.125) * c5 )) / 2;
|
return -(std::pow(2, 20 * x - 10) * std::sin((20 * x - 11.125) * c5)) / 2;
|
||||||
} else {
|
} else {
|
||||||
return (std::pow( 2, -20 * x + 10 ) * std::sin( (20 * x - 11.125) * c5 )) / 2 + 1;
|
return (std::pow(2, -20 * x + 10) * std::sin((20 * x - 11.125) * c5)) / 2 + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static double easeOutBounce( double x ) {
|
static double easeOutBounce(double x) {
|
||||||
const double n1 = 7.5625;
|
const double n1 = 7.5625;
|
||||||
const double d1 = 2.75;
|
const double d1 = 2.75;
|
||||||
if( x < 1 / d1 ) {
|
if(x < 1 / d1) {
|
||||||
return n1 * x * x;
|
return n1 * x * x;
|
||||||
} else if( x < 2 / d1 ) {
|
} else if(x < 2 / d1) {
|
||||||
x -= 1.5 / d1;
|
x -= 1.5 / d1;
|
||||||
return n1 * x * x + 0.75;
|
return n1 * x * x + 0.75;
|
||||||
} else if( x < 2.5 / d1 ) {
|
} else if(x < 2.5 / d1) {
|
||||||
x -= 2.25 / d1;
|
x -= 2.25 / d1;
|
||||||
return n1 * x * x + 0.9375;
|
return n1 * x * x + 0.9375;
|
||||||
} else {
|
} else {
|
||||||
@ -198,23 +166,19 @@ static double easeOutBounce( double x ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static double easeInBounce( double x ) {
|
static double easeInBounce(double x) { return 1 - easeOutBounce(1 - x); }
|
||||||
return 1 - easeOutBounce(1 - x);
|
|
||||||
|
static double easeInOutBounce(double x) {
|
||||||
|
return x < 0.5 ? (1 - easeOutBounce(1 - 2 * x)) / 2 : (1 + easeOutBounce(2 * x - 1)) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static double easeInOutBounce( double x ) {
|
void add_module_easing(VM* vm) {
|
||||||
return x < 0.5
|
|
||||||
? (1 - easeOutBounce(1 - 2 * x)) / 2
|
|
||||||
: (1 + easeOutBounce(2 * x - 1)) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_module_easing(VM* vm){
|
|
||||||
PyObject* mod = vm->new_module("easing");
|
PyObject* mod = vm->new_module("easing");
|
||||||
|
|
||||||
#define EASE(name) \
|
#define EASE(name) \
|
||||||
vm->bind_func(mod, #name, 1, [](VM* vm, ArgsView args){ \
|
vm->bind_func(mod, #name, 1, [](VM* vm, ArgsView args) { \
|
||||||
f64 t = CAST(f64, args[0]); \
|
f64 t = CAST(f64, args[0]); \
|
||||||
return VAR(ease##name(t)); \
|
return VAR(ease##name(t)); \
|
||||||
});
|
});
|
||||||
|
|
||||||
EASE(Linear)
|
EASE(Linear)
|
||||||
@ -251,4 +215,4 @@ void add_module_easing(VM* vm){
|
|||||||
|
|
||||||
#undef EASE
|
#undef EASE
|
||||||
}
|
}
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
#if PK_ENABLE_OS
|
#if PK_ENABLE_OS
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ struct FileIO {
|
|||||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||||
};
|
};
|
||||||
|
|
||||||
static FILE* io_fopen(const char* name, const char* mode){
|
static FILE* io_fopen(const char* name, const char* mode) {
|
||||||
#if _MSC_VER
|
#if _MSC_VER
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
errno_t err = fopen_s(&fp, name, mode);
|
errno_t err = fopen_s(&fp, name, mode);
|
||||||
@ -30,7 +30,7 @@ static FILE* io_fopen(const char* name, const char* mode){
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t io_fread(void* buffer, size_t size, size_t count, FILE* fp){
|
static size_t io_fread(void* buffer, size_t size, size_t count, FILE* fp) {
|
||||||
#if _MSC_VER
|
#if _MSC_VER
|
||||||
return fread_s(buffer, std::numeric_limits<size_t>::max(), size, count, fp);
|
return fread_s(buffer, std::numeric_limits<size_t>::max(), size, count, fp);
|
||||||
#else
|
#else
|
||||||
@ -38,7 +38,7 @@ static size_t io_fread(void* buffer, size_t size, size_t count, FILE* fp){
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* _default_import_handler(const char* name, int* out_size){
|
unsigned char* _default_import_handler(const char* name, int* out_size) {
|
||||||
bool exists = std::filesystem::exists(std::filesystem::path(name));
|
bool exists = std::filesystem::exists(std::filesystem::path(name));
|
||||||
if(!exists) return nullptr;
|
if(!exists) return nullptr;
|
||||||
FILE* fp = io_fopen(name, "rb");
|
FILE* fp = io_fopen(name, "rb");
|
||||||
@ -48,30 +48,28 @@ unsigned char* _default_import_handler(const char* name, int* out_size){
|
|||||||
unsigned char* buffer = new unsigned char[buffer_size];
|
unsigned char* buffer = new unsigned char[buffer_size];
|
||||||
fseek(fp, 0, SEEK_SET);
|
fseek(fp, 0, SEEK_SET);
|
||||||
size_t sz = io_fread(buffer, 1, buffer_size, fp);
|
size_t sz = io_fread(buffer, 1, buffer_size, fp);
|
||||||
(void)sz; // suppress warning
|
(void)sz; // suppress warning
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
*out_size = buffer_size;
|
*out_size = buffer_size;
|
||||||
return buffer;
|
return buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){
|
void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args){
|
vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args) {
|
||||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||||
return vm->new_object<FileIO>(cls, vm,
|
return vm->new_object<FileIO>(cls, vm, py_cast<Str&>(vm, args[1]), py_cast<Str&>(vm, args[2]));
|
||||||
py_cast<Str&>(vm, args[1]),
|
|
||||||
py_cast<Str&>(vm, args[2]));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind(type, "read(self, size=-1)", [](VM* vm, ArgsView args){
|
vm->bind(type, "read(self, size=-1)", [](VM* vm, ArgsView args) {
|
||||||
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
||||||
i64 size = CAST(i64, args[1]);
|
i64 size = CAST(i64, args[1]);
|
||||||
i64 buffer_size;
|
i64 buffer_size;
|
||||||
if(size < 0){
|
if(size < 0) {
|
||||||
long current = ftell(io.fp);
|
long current = ftell(io.fp);
|
||||||
fseek(io.fp, 0, SEEK_END);
|
fseek(io.fp, 0, SEEK_END);
|
||||||
buffer_size = ftell(io.fp);
|
buffer_size = ftell(io.fp);
|
||||||
fseek(io.fp, current, SEEK_SET);
|
fseek(io.fp, current, SEEK_SET);
|
||||||
}else{
|
} else {
|
||||||
buffer_size = size;
|
buffer_size = size;
|
||||||
}
|
}
|
||||||
unsigned char* buffer = (unsigned char*)std::malloc(buffer_size);
|
unsigned char* buffer = (unsigned char*)std::malloc(buffer_size);
|
||||||
@ -79,32 +77,30 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){
|
|||||||
assert(actual_size <= buffer_size);
|
assert(actual_size <= buffer_size);
|
||||||
// in text mode, CR may be dropped, which may cause `actual_size < buffer_size`
|
// in text mode, CR may be dropped, which may cause `actual_size < buffer_size`
|
||||||
Bytes b(buffer, actual_size);
|
Bytes b(buffer, actual_size);
|
||||||
if(io.is_text){
|
if(io.is_text) { return VAR(std::string_view((char*)b.data(), b.size())); }
|
||||||
return VAR(std::string_view((char*)b.data(), b.size()));
|
|
||||||
}
|
|
||||||
return VAR(std::move(b));
|
return VAR(std::move(b));
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args) {
|
||||||
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
||||||
if(io.is_text){
|
if(io.is_text) {
|
||||||
Str& s = CAST(Str&, args[1]);
|
Str& s = CAST(Str&, args[1]);
|
||||||
fwrite(s.data, 1, s.length(), io.fp);
|
fwrite(s.data, 1, s.length(), io.fp);
|
||||||
}else{
|
} else {
|
||||||
Bytes& buffer = CAST(Bytes&, args[1]);
|
Bytes& buffer = CAST(Bytes&, args[1]);
|
||||||
fwrite(buffer.data(), 1, buffer.size(), io.fp);
|
fwrite(buffer.data(), 1, buffer.size(), io.fp);
|
||||||
}
|
}
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "tell", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "tell", 1, [](VM* vm, ArgsView args) {
|
||||||
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
||||||
long pos = ftell(io.fp);
|
long pos = ftell(io.fp);
|
||||||
if(pos == -1) vm->IOError(strerror(errno));
|
if(pos == -1) vm->IOError(strerror(errno));
|
||||||
return VAR(pos);
|
return VAR(pos);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "seek", 3, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "seek", 3, [](VM* vm, ArgsView args) {
|
||||||
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
||||||
long offset = CAST(long, args[1]);
|
long offset = CAST(long, args[1]);
|
||||||
int whence = CAST(int, args[2]);
|
int whence = CAST(int, args[2]);
|
||||||
@ -113,13 +109,13 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){
|
|||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "close", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(type, "close", 1, [](VM* vm, ArgsView args) {
|
||||||
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
||||||
io.close();
|
io.close();
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, __exit__, 1, [](VM* vm, ArgsView args){
|
vm->bind_func(type, __exit__, 1, [](VM* vm, ArgsView args) {
|
||||||
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
||||||
io.close();
|
io.close();
|
||||||
return vm->None;
|
return vm->None;
|
||||||
@ -128,19 +124,19 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){
|
|||||||
vm->bind_func(type, __enter__, 1, PK_LAMBDA(args[0]));
|
vm->bind_func(type, __enter__, 1, PK_LAMBDA(args[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
FileIO::FileIO(VM* vm, const Str& file, const Str& mode){
|
FileIO::FileIO(VM* vm, const Str& file, const Str& mode) {
|
||||||
this->is_text = mode.sv().find("b") == std::string::npos;
|
this->is_text = mode.sv().find("b") == std::string::npos;
|
||||||
fp = io_fopen(file.c_str(), mode.c_str());
|
fp = io_fopen(file.c_str(), mode.c_str());
|
||||||
if(!fp) vm->IOError(strerror(errno));
|
if(!fp) vm->IOError(strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileIO::close(){
|
void FileIO::close() {
|
||||||
if(fp == nullptr) return;
|
if(fp == nullptr) return;
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
fp = nullptr;
|
fp = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_module_io(VM* vm){
|
void add_module_io(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("io");
|
PyObject* mod = vm->new_module("io");
|
||||||
vm->register_user_class<FileIO>(mod, "FileIO");
|
vm->register_user_class<FileIO>(mod, "FileIO");
|
||||||
|
|
||||||
@ -148,105 +144,104 @@ void add_module_io(VM* vm){
|
|||||||
mod->attr().set("SEEK_CUR", VAR(SEEK_CUR));
|
mod->attr().set("SEEK_CUR", VAR(SEEK_CUR));
|
||||||
mod->attr().set("SEEK_END", VAR(SEEK_END));
|
mod->attr().set("SEEK_END", VAR(SEEK_END));
|
||||||
|
|
||||||
vm->bind(vm->builtins, "open(path, mode='r')", [](VM* vm, ArgsView args){
|
vm->bind(vm->builtins, "open(path, mode='r')", [](VM* vm, ArgsView args) {
|
||||||
return vm->call(vm->_modules["io"]->attr("FileIO"), args[0], args[1]);
|
return vm->call(vm->_modules["io"]->attr("FileIO"), args[0], args[1]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_module_os(VM* vm){
|
void add_module_os(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("os");
|
PyObject* mod = vm->new_module("os");
|
||||||
PyObject* path_obj = vm->heap.gcnew<DummyInstance>(VM::tp_object);
|
PyObject* path_obj = vm->heap.gcnew<DummyInstance>(VM::tp_object);
|
||||||
mod->attr().set("path", path_obj);
|
mod->attr().set("path", path_obj);
|
||||||
|
|
||||||
// Working directory is shared by all VMs!!
|
// Working directory is shared by all VMs!!
|
||||||
vm->bind_func(mod, "getcwd", 0, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "getcwd", 0, [](VM* vm, ArgsView args) {
|
||||||
return VAR(std::filesystem::current_path().string());
|
return VAR(std::filesystem::current_path().string());
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "chdir", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "chdir", 1, [](VM* vm, ArgsView args) {
|
||||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||||
std::filesystem::current_path(path);
|
std::filesystem::current_path(path);
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "listdir", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "listdir", 1, [](VM* vm, ArgsView args) {
|
||||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||||
std::filesystem::directory_iterator di;
|
std::filesystem::directory_iterator di;
|
||||||
try{
|
try {
|
||||||
di = std::filesystem::directory_iterator(path);
|
di = std::filesystem::directory_iterator(path);
|
||||||
}catch(std::filesystem::filesystem_error&){
|
} catch(std::filesystem::filesystem_error&) { vm->IOError(path.string()); }
|
||||||
vm->IOError(path.string());
|
|
||||||
}
|
|
||||||
List ret;
|
List ret;
|
||||||
for(auto& p: di) ret.push_back(VAR(p.path().filename().string()));
|
for(auto& p: di)
|
||||||
|
ret.push_back(VAR(p.path().filename().string()));
|
||||||
return VAR(std::move(ret));
|
return VAR(std::move(ret));
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "remove", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "remove", 1, [](VM* vm, ArgsView args) {
|
||||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||||
bool ok = std::filesystem::remove(path);
|
bool ok = std::filesystem::remove(path);
|
||||||
if(!ok) vm->IOError("operation failed");
|
if(!ok) vm->IOError("operation failed");
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "mkdir", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "mkdir", 1, [](VM* vm, ArgsView args) {
|
||||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||||
bool ok = std::filesystem::create_directory(path);
|
bool ok = std::filesystem::create_directory(path);
|
||||||
if(!ok) vm->IOError("operation failed");
|
if(!ok) vm->IOError("operation failed");
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "rmdir", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "rmdir", 1, [](VM* vm, ArgsView args) {
|
||||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||||
bool ok = std::filesystem::remove(path);
|
bool ok = std::filesystem::remove(path);
|
||||||
if(!ok) vm->IOError("operation failed");
|
if(!ok) vm->IOError("operation failed");
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(path_obj, "join", -1, [](VM* vm, ArgsView args){
|
vm->bind_func(path_obj, "join", -1, [](VM* vm, ArgsView args) {
|
||||||
std::filesystem::path path;
|
std::filesystem::path path;
|
||||||
for(int i=0; i<args.size(); i++){
|
for(int i = 0; i < args.size(); i++) {
|
||||||
path /= CAST(Str&, args[i]).sv();
|
path /= CAST(Str&, args[i]).sv();
|
||||||
}
|
}
|
||||||
return VAR(path.string());
|
return VAR(path.string());
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(path_obj, "exists", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(path_obj, "exists", 1, [](VM* vm, ArgsView args) {
|
||||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||||
bool exists = std::filesystem::exists(path);
|
bool exists = std::filesystem::exists(path);
|
||||||
return VAR(exists);
|
return VAR(exists);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(path_obj, "basename", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(path_obj, "basename", 1, [](VM* vm, ArgsView args) {
|
||||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||||
return VAR(path.filename().string());
|
return VAR(path.filename().string());
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(path_obj, "isdir", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(path_obj, "isdir", 1, [](VM* vm, ArgsView args) {
|
||||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||||
bool isdir = std::filesystem::is_directory(path);
|
bool isdir = std::filesystem::is_directory(path);
|
||||||
return VAR(isdir);
|
return VAR(isdir);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(path_obj, "isfile", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(path_obj, "isfile", 1, [](VM* vm, ArgsView args) {
|
||||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||||
bool isfile = std::filesystem::is_regular_file(path);
|
bool isfile = std::filesystem::is_regular_file(path);
|
||||||
return VAR(isfile);
|
return VAR(isfile);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(path_obj, "abspath", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(path_obj, "abspath", 1, [](VM* vm, ArgsView args) {
|
||||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||||
return VAR(std::filesystem::absolute(path).string());
|
return VAR(std::filesystem::absolute(path).string());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
void add_module_io(VM* vm){}
|
void add_module_io(VM* vm) {}
|
||||||
void add_module_os(VM* vm){}
|
|
||||||
unsigned char* _default_import_handler(const char* name, int* out_size){
|
void add_module_os(VM* vm) {}
|
||||||
return nullptr;
|
|
||||||
}
|
unsigned char* _default_import_handler(const char* name, int* out_size) { return nullptr; }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -8,9 +8,9 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
struct PyStructTime{
|
struct PyStructTime {
|
||||||
int tm_year;
|
int tm_year;
|
||||||
int tm_mon;
|
int tm_mon;
|
||||||
int tm_mday;
|
int tm_mday;
|
||||||
@ -21,7 +21,7 @@ struct PyStructTime{
|
|||||||
int tm_yday;
|
int tm_yday;
|
||||||
int tm_isdst;
|
int tm_isdst;
|
||||||
|
|
||||||
PyStructTime(std::time_t t){
|
PyStructTime(std::time_t t) {
|
||||||
std::tm* tm = std::localtime(&t);
|
std::tm* tm = std::localtime(&t);
|
||||||
tm_year = tm->tm_year + 1900;
|
tm_year = tm->tm_year + 1900;
|
||||||
tm_mon = tm->tm_mon + 1;
|
tm_mon = tm->tm_mon + 1;
|
||||||
@ -34,7 +34,7 @@ struct PyStructTime{
|
|||||||
tm_isdst = tm->tm_isdst;
|
tm_isdst = tm->tm_isdst;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
PY_READONLY_FIELD(PyStructTime, "tm_year", tm_year);
|
PY_READONLY_FIELD(PyStructTime, "tm_year", tm_year);
|
||||||
PY_READONLY_FIELD(PyStructTime, "tm_mon", tm_mon);
|
PY_READONLY_FIELD(PyStructTime, "tm_mon", tm_mon);
|
||||||
PY_READONLY_FIELD(PyStructTime, "tm_mday", tm_mday);
|
PY_READONLY_FIELD(PyStructTime, "tm_mday", tm_mday);
|
||||||
@ -47,7 +47,7 @@ struct PyStructTime{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void add_module_time(VM* vm){
|
void add_module_time(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("time");
|
PyObject* mod = vm->new_module("time");
|
||||||
vm->register_user_class<PyStructTime>(mod, "struct_time");
|
vm->register_user_class<PyStructTime>(mod, "struct_time");
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ void add_module_time(VM* vm){
|
|||||||
vm->bind_func(mod, "sleep", 1, [](VM* vm, ArgsView args) {
|
vm->bind_func(mod, "sleep", 1, [](VM* vm, ArgsView args) {
|
||||||
f64 seconds = CAST_F(args[0]);
|
f64 seconds = CAST_F(args[0]);
|
||||||
auto begin = std::chrono::system_clock::now();
|
auto begin = std::chrono::system_clock::now();
|
||||||
while(true){
|
while(true) {
|
||||||
auto now = std::chrono::system_clock::now();
|
auto now = std::chrono::system_clock::now();
|
||||||
f64 elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - begin).count() / 1000.0;
|
f64 elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - begin).count() / 1000.0;
|
||||||
if(elapsed >= seconds) break;
|
if(elapsed >= seconds) break;
|
||||||
@ -74,7 +74,7 @@ void add_module_time(VM* vm){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_module_sys(VM* vm){
|
void add_module_sys(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("sys");
|
PyObject* mod = vm->new_module("sys");
|
||||||
vm->setattr(mod, "version", VAR(PK_VERSION));
|
vm->setattr(mod, "version", VAR(PK_VERSION));
|
||||||
vm->setattr(mod, "platform", VAR(kPlatformStrings[PK_SYS_PLATFORM]));
|
vm->setattr(mod, "platform", VAR(kPlatformStrings[PK_SYS_PLATFORM]));
|
||||||
@ -97,14 +97,14 @@ void add_module_sys(VM* vm){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_module_json(VM* vm){
|
void add_module_json(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("json");
|
PyObject* mod = vm->new_module("json");
|
||||||
vm->bind_func(mod, "loads", 1, [](VM* vm, ArgsView args) {
|
vm->bind_func(mod, "loads", 1, [](VM* vm, ArgsView args) {
|
||||||
std::string_view sv;
|
std::string_view sv;
|
||||||
if(is_type(args[0], vm->tp_bytes)){
|
if(is_type(args[0], vm->tp_bytes)) {
|
||||||
const Bytes& b = PK_OBJ_GET(Bytes, args[0]);
|
const Bytes& b = PK_OBJ_GET(Bytes, args[0]);
|
||||||
sv = std::string_view((char*)b.data(), b.size());
|
sv = std::string_view((char*)b.data(), b.size());
|
||||||
}else{
|
} else {
|
||||||
sv = CAST(Str&, args[0]).sv();
|
sv = CAST(Str&, args[0]).sv();
|
||||||
}
|
}
|
||||||
CodeObject_ code = vm->compile(sv, "<json>", JSON_MODE);
|
CodeObject_ code = vm->compile(sv, "<json>", JSON_MODE);
|
||||||
@ -117,10 +117,10 @@ void add_module_json(VM* vm){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://docs.python.org/3.5/library/math.html
|
// https://docs.python.org/3.5/library/math.html
|
||||||
void add_module_math(VM* vm){
|
void add_module_math(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("math");
|
PyObject* mod = vm->new_module("math");
|
||||||
mod->attr().set("pi", VAR(3.1415926535897932384));
|
mod->attr().set("pi", VAR(3.1415926535897932384));
|
||||||
mod->attr().set("e" , VAR(2.7182818284590452354));
|
mod->attr().set("e", VAR(2.7182818284590452354));
|
||||||
mod->attr().set("inf", VAR(std::numeric_limits<double>::infinity()));
|
mod->attr().set("inf", VAR(std::numeric_limits<double>::infinity()));
|
||||||
mod->attr().set("nan", VAR(std::numeric_limits<double>::quiet_NaN()));
|
mod->attr().set("nan", VAR(std::numeric_limits<double>::quiet_NaN()));
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ void add_module_math(VM* vm){
|
|||||||
List& list = CAST(List&, args[0]);
|
List& list = CAST(List&, args[0]);
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
double c = 0;
|
double c = 0;
|
||||||
for(PyVar arg : list){
|
for(PyVar arg: list) {
|
||||||
double x = CAST_F(arg);
|
double x = CAST_F(arg);
|
||||||
double y = x - c;
|
double y = x - c;
|
||||||
double t = sum + y;
|
double t = sum + y;
|
||||||
@ -145,7 +145,7 @@ void add_module_math(VM* vm){
|
|||||||
i64 b = CAST(i64, args[1]);
|
i64 b = CAST(i64, args[1]);
|
||||||
if(a < 0) a = -a;
|
if(a < 0) a = -a;
|
||||||
if(b < 0) b = -b;
|
if(b < 0) b = -b;
|
||||||
while(b != 0){
|
while(b != 0) {
|
||||||
i64 t = b;
|
i64 t = b;
|
||||||
b = a % b;
|
b = a % b;
|
||||||
a = t;
|
a = t;
|
||||||
@ -165,7 +165,7 @@ void add_module_math(VM* vm){
|
|||||||
|
|
||||||
vm->bind_func(mod, "exp", 1, PK_LAMBDA(VAR(std::exp(CAST_F(args[0])))));
|
vm->bind_func(mod, "exp", 1, PK_LAMBDA(VAR(std::exp(CAST_F(args[0])))));
|
||||||
|
|
||||||
vm->bind(mod, "log(x, base=2.718281828459045)", [](VM* vm, ArgsView args){
|
vm->bind(mod, "log(x, base=2.718281828459045)", [](VM* vm, ArgsView args) {
|
||||||
f64 x = CAST_F(args[0]);
|
f64 x = CAST_F(args[0]);
|
||||||
f64 base = CAST_F(args[1]);
|
f64 base = CAST_F(args[1]);
|
||||||
return VAR(std::log(x) / std::log(base));
|
return VAR(std::log(x) / std::log(base));
|
||||||
@ -199,12 +199,13 @@ void add_module_math(VM* vm){
|
|||||||
i64 n = CAST(i64, args[0]);
|
i64 n = CAST(i64, args[0]);
|
||||||
if(n < 0) vm->ValueError("factorial() not defined for negative values");
|
if(n < 0) vm->ValueError("factorial() not defined for negative values");
|
||||||
i64 r = 1;
|
i64 r = 1;
|
||||||
for(i64 i=2; i<=n; i++) r *= i;
|
for(i64 i = 2; i <= n; i++)
|
||||||
|
r *= i;
|
||||||
return VAR(r);
|
return VAR(r);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_module_traceback(VM* vm){
|
void add_module_traceback(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("traceback");
|
PyObject* mod = vm->new_module("traceback");
|
||||||
vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) {
|
vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) {
|
||||||
if(vm->__last_exception == nullptr) vm->ValueError("no exception");
|
if(vm->__last_exception == nullptr) vm->ValueError("no exception");
|
||||||
@ -220,13 +221,13 @@ void add_module_traceback(VM* vm){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_module_dis(VM* vm){
|
void add_module_dis(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("dis");
|
PyObject* mod = vm->new_module("dis");
|
||||||
|
|
||||||
vm->bind_func(mod, "dis", 1, [](VM* vm, ArgsView args) {
|
vm->bind_func(mod, "dis", 1, [](VM* vm, ArgsView args) {
|
||||||
CodeObject_ code;
|
CodeObject_ code;
|
||||||
PyVar obj = args[0];
|
PyVar obj = args[0];
|
||||||
if(is_type(obj, vm->tp_str)){
|
if(is_type(obj, vm->tp_str)) {
|
||||||
const Str& source = CAST(Str, obj);
|
const Str& source = CAST(Str, obj);
|
||||||
code = vm->compile(source, "<dis>", EXEC_MODE);
|
code = vm->compile(source, "<dis>", EXEC_MODE);
|
||||||
}
|
}
|
||||||
@ -238,37 +239,36 @@ void add_module_dis(VM* vm){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_module_gc(VM* vm){
|
void add_module_gc(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("gc");
|
PyObject* mod = vm->new_module("gc");
|
||||||
vm->bind_func(mod, "collect", 0, PK_LAMBDA(VAR(vm->heap.collect())));
|
vm->bind_func(mod, "collect", 0, PK_LAMBDA(VAR(vm->heap.collect())));
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_module_enum(VM* vm){
|
void add_module_enum(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("enum");
|
PyObject* mod = vm->new_module("enum");
|
||||||
CodeObject_ code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE);
|
CodeObject_ code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE);
|
||||||
vm->_exec(code, mod);
|
vm->_exec(code, mod);
|
||||||
PyVar Enum = mod->attr("Enum");
|
PyVar Enum = mod->attr("Enum");
|
||||||
vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = \
|
vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = [](VM* vm, PyTypeInfo* new_ti) {
|
||||||
[](VM* vm, PyTypeInfo* new_ti){
|
new_ti->subclass_enabled = false; // Enum class cannot be subclassed twice
|
||||||
new_ti->subclass_enabled = false; // Enum class cannot be subclassed twice
|
NameDict& attr = new_ti->obj->attr();
|
||||||
NameDict& attr = new_ti->obj->attr();
|
for(auto [k, v]: attr.items()) {
|
||||||
for(auto [k, v]: attr.items()){
|
// wrap every attribute
|
||||||
// wrap every attribute
|
std::string_view k_sv = k.sv();
|
||||||
std::string_view k_sv = k.sv();
|
if(k_sv.empty() || k_sv[0] == '_') continue;
|
||||||
if(k_sv.empty() || k_sv[0] == '_') continue;
|
attr.set(k, vm->call(new_ti->obj, VAR(k_sv), v));
|
||||||
attr.set(k, vm->call(new_ti->obj, VAR(k_sv), v));
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_module___builtins(VM* vm){
|
void add_module___builtins(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("__builtins");
|
PyObject* mod = vm->new_module("__builtins");
|
||||||
|
|
||||||
vm->bind_func(mod, "next", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "next", 1, [](VM* vm, ArgsView args) {
|
||||||
return vm->py_next(args[0]);
|
return vm->py_next(args[0]);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "_enable_instance_dict", 1, [](VM* vm, ArgsView args){
|
vm->bind_func(mod, "_enable_instance_dict", 1, [](VM* vm, ArgsView args) {
|
||||||
PyVar self = args[0];
|
PyVar self = args[0];
|
||||||
if(is_tagged(self)) vm->TypeError("object: tagged object cannot enable instance dict");
|
if(is_tagged(self)) vm->TypeError("object: tagged object cannot enable instance dict");
|
||||||
if(self->is_attr_valid()) vm->RuntimeError("object: instance dict is already enabled");
|
if(self->is_attr_valid()) vm->RuntimeError("object: instance dict is already enabled");
|
||||||
@ -277,11 +277,11 @@ void add_module___builtins(VM* vm){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************************************/
|
/************************************************/
|
||||||
#if PK_ENABLE_PROFILER
|
#if PK_ENABLE_PROFILER
|
||||||
struct LineProfilerW;
|
struct LineProfilerW;
|
||||||
struct _LpGuard{
|
|
||||||
|
struct _LpGuard {
|
||||||
PK_ALWAYS_PASS_BY_POINTER(_LpGuard)
|
PK_ALWAYS_PASS_BY_POINTER(_LpGuard)
|
||||||
LineProfilerW* lp;
|
LineProfilerW* lp;
|
||||||
VM* vm;
|
VM* vm;
|
||||||
@ -290,16 +290,16 @@ struct _LpGuard{
|
|||||||
};
|
};
|
||||||
|
|
||||||
// line_profiler wrapper
|
// line_profiler wrapper
|
||||||
struct LineProfilerW{
|
struct LineProfilerW {
|
||||||
LineProfiler profiler;
|
LineProfiler profiler;
|
||||||
|
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args){
|
vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args) {
|
||||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||||
return vm->new_object<LineProfilerW>(cls);
|
return vm->new_object<LineProfilerW>(cls);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind(type, "add_function(self, func)", [](VM* vm, ArgsView args){
|
vm->bind(type, "add_function(self, func)", [](VM* vm, ArgsView args) {
|
||||||
LineProfilerW& self = PK_OBJ_GET(LineProfilerW, args[0]);
|
LineProfilerW& self = PK_OBJ_GET(LineProfilerW, args[0]);
|
||||||
vm->check_type(args[1], VM::tp_function);
|
vm->check_type(args[1], VM::tp_function);
|
||||||
auto decl = PK_OBJ_GET(Function, args[1]).decl.get();
|
auto decl = PK_OBJ_GET(Function, args[1]).decl.get();
|
||||||
@ -307,19 +307,20 @@ struct LineProfilerW{
|
|||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind(type, "runcall(self, func, *args)", [](VM* vm, ArgsView view){
|
vm->bind(type, "runcall(self, func, *args)", [](VM* vm, ArgsView view) {
|
||||||
LineProfilerW& self = PK_OBJ_GET(LineProfilerW, view[0]);
|
LineProfilerW& self = PK_OBJ_GET(LineProfilerW, view[0]);
|
||||||
PyVar func = view[1];
|
PyVar func = view[1];
|
||||||
const Tuple& args = CAST(Tuple&, view[2]);
|
const Tuple& args = CAST(Tuple&, view[2]);
|
||||||
vm->s_data.push(func);
|
vm->s_data.push(func);
|
||||||
vm->s_data.push(PY_NULL);
|
vm->s_data.push(PY_NULL);
|
||||||
for(PyVar arg : args) vm->s_data.push(arg);
|
for(PyVar arg: args)
|
||||||
|
vm->s_data.push(arg);
|
||||||
_LpGuard guard(&self, vm);
|
_LpGuard guard(&self, vm);
|
||||||
PyVar ret = vm->vectorcall(args.size());
|
PyVar ret = vm->vectorcall(args.size());
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind(type, "print_stats(self)", [](VM* vm, ArgsView args){
|
vm->bind(type, "print_stats(self)", [](VM* vm, ArgsView args) {
|
||||||
LineProfilerW& self = PK_OBJ_GET(LineProfilerW, args[0]);
|
LineProfilerW& self = PK_OBJ_GET(LineProfilerW, args[0]);
|
||||||
vm->stdout_write(self.profiler.stats());
|
vm->stdout_write(self.profiler.stats());
|
||||||
return vm->None;
|
return vm->None;
|
||||||
@ -327,28 +328,23 @@ struct LineProfilerW{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_LpGuard::_LpGuard(LineProfilerW* lp, VM* vm) : lp(lp), vm(vm) {
|
||||||
_LpGuard::_LpGuard(LineProfilerW* lp, VM* vm): lp(lp), vm(vm) {
|
if(vm->_profiler) { vm->ValueError("only one profiler can be enabled at a time"); }
|
||||||
if(vm->_profiler){
|
|
||||||
vm->ValueError("only one profiler can be enabled at a time");
|
|
||||||
}
|
|
||||||
vm->_profiler = &lp->profiler;
|
vm->_profiler = &lp->profiler;
|
||||||
lp->profiler.begin();
|
lp->profiler.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
_LpGuard::~_LpGuard(){
|
_LpGuard::~_LpGuard() {
|
||||||
vm->_profiler = nullptr;
|
vm->_profiler = nullptr;
|
||||||
lp->profiler.end();
|
lp->profiler.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_module_line_profiler(VM *vm){
|
void add_module_line_profiler(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("line_profiler");
|
PyObject* mod = vm->new_module("line_profiler");
|
||||||
vm->register_user_class<LineProfilerW>(mod, "LineProfiler");
|
vm->register_user_class<LineProfilerW>(mod, "LineProfiler");
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
void add_module_line_profiler(VM* vm){
|
void add_module_line_profiler(VM* vm) { (void)vm; }
|
||||||
(void)vm;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -36,23 +36,21 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct mt19937{
|
struct mt19937 {
|
||||||
static const int N = 624;
|
const static int N = 624;
|
||||||
static const int M = 397;
|
const static int M = 397;
|
||||||
const uint32_t MATRIX_A = 0x9908b0dfUL; /* constant vector a */
|
const uint32_t MATRIX_A = 0x9908b0dfUL; /* constant vector a */
|
||||||
const uint32_t UPPER_MASK = 0x80000000UL; /* most significant w-r bits */
|
const uint32_t UPPER_MASK = 0x80000000UL; /* most significant w-r bits */
|
||||||
const uint32_t LOWER_MASK = 0x7fffffffUL; /* least significant r bits */
|
const uint32_t LOWER_MASK = 0x7fffffffUL; /* least significant r bits */
|
||||||
|
|
||||||
uint32_t mt[N]; /* the array for the state vector */
|
uint32_t mt[N]; /* the array for the state vector */
|
||||||
int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
|
int mti = N + 1; /* mti==N+1 means mt[N] is not initialized */
|
||||||
|
|
||||||
/* initializes mt[N] with a seed */
|
/* initializes mt[N] with a seed */
|
||||||
void seed(uint32_t s)
|
void seed(uint32_t s) {
|
||||||
{
|
mt[0] = s & 0xffffffffUL;
|
||||||
mt[0]= s & 0xffffffffUL;
|
for(mti = 1; mti < N; mti++) {
|
||||||
for (mti=1; mti<N; mti++) {
|
mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
|
||||||
mt[mti] =
|
|
||||||
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
|
|
||||||
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
||||||
/* In the previous versions, MSBs of the seed affect */
|
/* In the previous versions, MSBs of the seed affect */
|
||||||
/* only MSBs of the array mt[]. */
|
/* only MSBs of the array mt[]. */
|
||||||
@ -63,28 +61,27 @@ struct mt19937{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* generates a random number on [0,0xffffffff]-interval */
|
/* generates a random number on [0,0xffffffff]-interval */
|
||||||
uint32_t next_uint32(void)
|
uint32_t next_uint32(void) {
|
||||||
{
|
|
||||||
uint32_t y;
|
uint32_t y;
|
||||||
static uint32_t mag01[2]={0x0UL, MATRIX_A};
|
static uint32_t mag01[2] = {0x0UL, MATRIX_A};
|
||||||
/* mag01[x] = x * MATRIX_A for x=0,1 */
|
/* mag01[x] = x * MATRIX_A for x=0,1 */
|
||||||
|
|
||||||
if (mti >= N) { /* generate N words at one time */
|
if(mti >= N) { /* generate N words at one time */
|
||||||
int kk;
|
int kk;
|
||||||
|
|
||||||
if (mti == N+1) /* if init_genrand() has not been called, */
|
if(mti == N + 1) /* if init_genrand() has not been called, */
|
||||||
seed(5489UL); /* a default initial seed is used */
|
seed(5489UL); /* a default initial seed is used */
|
||||||
|
|
||||||
for (kk=0;kk<N-M;kk++) {
|
for(kk = 0; kk < N - M; kk++) {
|
||||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
|
||||||
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||||
}
|
}
|
||||||
for (;kk<N-1;kk++) {
|
for(; kk < N - 1; kk++) {
|
||||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
|
||||||
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||||
}
|
}
|
||||||
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
|
y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
|
||||||
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||||
|
|
||||||
mti = 0;
|
mti = 0;
|
||||||
}
|
}
|
||||||
@ -100,44 +97,36 @@ struct mt19937{
|
|||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t next_uint64(void){
|
uint64_t next_uint64(void) { return (uint64_t(next_uint32()) << 32) | next_uint32(); }
|
||||||
return (uint64_t(next_uint32()) << 32) | next_uint32();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* generates a random number on [0,1)-real-interval */
|
/* generates a random number on [0,1)-real-interval */
|
||||||
float random(void)
|
float random(void) { return next_uint32() * (1.0 / 4294967296.0); /* divided by 2^32 */ }
|
||||||
{
|
|
||||||
return next_uint32()*(1.0/4294967296.0); /* divided by 2^32 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* generates a random number on [a, b]-interval */
|
/* generates a random number on [a, b]-interval */
|
||||||
int64_t randint(int64_t a, int64_t b){
|
int64_t randint(int64_t a, int64_t b) {
|
||||||
uint64_t delta = b - a + 1;
|
uint64_t delta = b - a + 1;
|
||||||
if(delta < 0x80000000UL){
|
if(delta < 0x80000000UL) {
|
||||||
return a + next_uint32() % (uint32_t)delta;
|
return a + next_uint32() % (uint32_t)delta;
|
||||||
}else{
|
} else {
|
||||||
return a + next_uint64() % delta;
|
return a + next_uint64() % delta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float uniform(float a, float b){
|
float uniform(float a, float b) { return a + random() * (b - a); }
|
||||||
return a + random() * (b - a);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace pkpy {
|
||||||
|
|
||||||
namespace pkpy{
|
struct Random {
|
||||||
|
|
||||||
struct Random{
|
|
||||||
mt19937 gen;
|
mt19937 gen;
|
||||||
|
|
||||||
Random(){
|
Random() {
|
||||||
auto count = std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
auto count = std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||||
gen.seed((uint32_t)count);
|
gen.seed((uint32_t)count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args){
|
vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args) {
|
||||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||||
return vm->new_object<Random>(cls);
|
return vm->new_object<Random>(cls);
|
||||||
});
|
});
|
||||||
@ -152,7 +141,7 @@ struct Random{
|
|||||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||||
i64 a = CAST(i64, args[1]);
|
i64 a = CAST(i64, args[1]);
|
||||||
i64 b = CAST(i64, args[2]);
|
i64 b = CAST(i64, args[2]);
|
||||||
if (a > b) vm->ValueError("randint(a, b): a must be less than or equal to b");
|
if(a > b) vm->ValueError("randint(a, b): a must be less than or equal to b");
|
||||||
return VAR(self.gen.randint(a, b));
|
return VAR(self.gen.randint(a, b));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -165,14 +154,14 @@ struct Random{
|
|||||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||||
f64 a = CAST(f64, args[1]);
|
f64 a = CAST(f64, args[1]);
|
||||||
f64 b = CAST(f64, args[2]);
|
f64 b = CAST(f64, args[2]);
|
||||||
if (a > b) std::swap(a, b);
|
if(a > b) std::swap(a, b);
|
||||||
return VAR(self.gen.uniform(a, b));
|
return VAR(self.gen.uniform(a, b));
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "shuffle", 2, [](VM* vm, ArgsView args) {
|
vm->bind_func(type, "shuffle", 2, [](VM* vm, ArgsView args) {
|
||||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||||
List& L = CAST(List&, args[1]);
|
List& L = CAST(List&, args[1]);
|
||||||
for(int i = L.size() - 1; i > 0; i--){
|
for(int i = L.size() - 1; i > 0; i--) {
|
||||||
int j = self.gen.randint(0, i);
|
int j = self.gen.randint(0, i);
|
||||||
std::swap(L[i], L[j]);
|
std::swap(L[i], L[j]);
|
||||||
}
|
}
|
||||||
@ -183,7 +172,7 @@ struct Random{
|
|||||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||||
ArgsView view = vm->cast_array_view(args[1]);
|
ArgsView view = vm->cast_array_view(args[1]);
|
||||||
if(view.empty()) vm->IndexError("cannot choose from an empty sequence");
|
if(view.empty()) vm->IndexError("cannot choose from an empty sequence");
|
||||||
int index = self.gen.randint(0, view.size()-1);
|
int index = self.gen.randint(0, view.size() - 1);
|
||||||
return view[index];
|
return view[index];
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -194,20 +183,21 @@ struct Random{
|
|||||||
int size = view.size();
|
int size = view.size();
|
||||||
if(size == 0) vm->IndexError("cannot choose from an empty sequence");
|
if(size == 0) vm->IndexError("cannot choose from an empty sequence");
|
||||||
array<f64> cum_weights(size);
|
array<f64> cum_weights(size);
|
||||||
if(args[2] == vm->None){
|
if(args[2] == vm->None) {
|
||||||
for(int i = 0; i < size; i++) cum_weights[i] = i + 1;
|
for(int i = 0; i < size; i++)
|
||||||
}else{
|
cum_weights[i] = i + 1;
|
||||||
|
} else {
|
||||||
ArgsView weights = vm->cast_array_view(args[2]);
|
ArgsView weights = vm->cast_array_view(args[2]);
|
||||||
if(weights.size() != size) vm->ValueError(_S("len(weights) != ", size));
|
if(weights.size() != size) vm->ValueError(_S("len(weights) != ", size));
|
||||||
cum_weights[0] = CAST(f64, weights[0]);
|
cum_weights[0] = CAST(f64, weights[0]);
|
||||||
for(int i = 1; i < size; i++){
|
for(int i = 1; i < size; i++) {
|
||||||
cum_weights[i] = cum_weights[i - 1] + CAST(f64, weights[i]);
|
cum_weights[i] = cum_weights[i - 1] + CAST(f64, weights[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(cum_weights[size - 1] <= 0) vm->ValueError("total of weights must be greater than zero");
|
if(cum_weights[size - 1] <= 0) vm->ValueError("total of weights must be greater than zero");
|
||||||
int k = CAST(int, args[3]);
|
int k = CAST(int, args[3]);
|
||||||
List result(k);
|
List result(k);
|
||||||
for(int i = 0; i < k; i++){
|
for(int i = 0; i < k; i++) {
|
||||||
f64 r = self.gen.uniform(0.0, cum_weights[size - 1]);
|
f64 r = self.gen.uniform(0.0, cum_weights[size - 1]);
|
||||||
int idx = std::lower_bound(cum_weights.begin(), cum_weights.end(), r) - cum_weights.begin();
|
int idx = std::lower_bound(cum_weights.begin(), cum_weights.end(), r) - cum_weights.begin();
|
||||||
result[i] = data[idx];
|
result[i] = data[idx];
|
||||||
@ -217,7 +207,7 @@ struct Random{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void add_module_random(VM* vm){
|
void add_module_random(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("random");
|
PyObject* mod = vm->new_module("random");
|
||||||
vm->register_user_class<Random>(mod, "Random");
|
vm->register_user_class<Random>(mod, "Random");
|
||||||
PyVar instance = vm->new_user_object<Random>();
|
PyVar instance = vm->new_user_object<Random>();
|
||||||
@ -230,4 +220,4 @@ void add_module_random(VM* vm){
|
|||||||
mod->attr().set("choices", vm->getattr(instance, "choices"));
|
mod->attr().set("choices", vm->getattr(instance, "choices"));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#include "pocketpy/objects/builtins.hpp"
|
#include "pocketpy/objects/builtins.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
PyVar const PY_OP_CALL(Type(), new PyObject(Type()));
|
const PyVar PY_OP_CALL(Type(), new PyObject(Type()));
|
||||||
PyVar const PY_OP_YIELD(Type(), new PyObject(Type()));
|
const PyVar PY_OP_YIELD(Type(), new PyObject(Type()));
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
#include "pocketpy/objects/codeobject.hpp"
|
#include "pocketpy/objects/codeobject.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
CodeObject::CodeObject(std::shared_ptr<SourceData> src, const Str& name):
|
CodeObject::CodeObject(std::shared_ptr<SourceData> src, const Str& name) :
|
||||||
src(src), name(name), nlocals(0), start_line(-1), end_line(-1) {
|
src(src), name(name), nlocals(0), start_line(-1), end_line(-1) {
|
||||||
blocks.push_back(CodeBlock(CodeBlockType::NO_BLOCK, -1, 0));
|
blocks.push_back(CodeBlock(CodeBlockType::NO_BLOCK, -1, 0));
|
||||||
}
|
}
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -1,174 +1,180 @@
|
|||||||
#include "pocketpy/objects/dict.hpp"
|
#include "pocketpy/objects/dict.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
|
|
||||||
Dict::Dict(): _capacity(__Capacity),
|
Dict::Dict() :
|
||||||
_mask(__Capacity-1),
|
_capacity(__Capacity), _mask(__Capacity - 1), _size(0), _critical_size(__Capacity * __LoadFactor + 0.5f),
|
||||||
_size(0), _critical_size(__Capacity*__LoadFactor+0.5f), _head_idx(-1), _tail_idx(-1){
|
_head_idx(-1), _tail_idx(-1) {
|
||||||
__alloc_items();
|
__alloc_items();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dict::__alloc_items(){
|
void Dict::__alloc_items() {
|
||||||
_items = (Item*)std::malloc(_capacity * sizeof(Item));
|
_items = (Item*)std::malloc(_capacity * sizeof(Item));
|
||||||
for(int i=0; i<_capacity; i++){
|
for(int i = 0; i < _capacity; i++) {
|
||||||
_items[i].first = nullptr;
|
|
||||||
_items[i].second = nullptr;
|
|
||||||
_items[i].prev = -1;
|
|
||||||
_items[i].next = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Dict::Dict(Dict&& other){
|
|
||||||
_capacity = other._capacity;
|
|
||||||
_mask = other._mask;
|
|
||||||
_size = other._size;
|
|
||||||
_critical_size = other._critical_size;
|
|
||||||
_head_idx = other._head_idx;
|
|
||||||
_tail_idx = other._tail_idx;
|
|
||||||
_items = other._items;
|
|
||||||
other._items = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dict::Dict(const Dict& other){
|
|
||||||
_capacity = other._capacity;
|
|
||||||
_mask = other._mask;
|
|
||||||
_size = other._size;
|
|
||||||
_critical_size = other._critical_size;
|
|
||||||
_head_idx = other._head_idx;
|
|
||||||
_tail_idx = other._tail_idx;
|
|
||||||
// copy items
|
|
||||||
_items = (Item*)std::malloc(_capacity * sizeof(Item));
|
|
||||||
std::memcpy(_items, other._items, _capacity * sizeof(Item));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dict::set(VM* vm, PyVar key, PyVar val){
|
|
||||||
// do possible rehash
|
|
||||||
if(_size+1 > _critical_size) _rehash(vm);
|
|
||||||
bool ok; int i;
|
|
||||||
_probe_1(vm, key, ok, i);
|
|
||||||
if(!ok) {
|
|
||||||
_size++;
|
|
||||||
_items[i].first = key;
|
|
||||||
|
|
||||||
// append to tail
|
|
||||||
if(_size == 0+1){
|
|
||||||
_head_idx = i;
|
|
||||||
_tail_idx = i;
|
|
||||||
}else{
|
|
||||||
_items[i].prev = _tail_idx;
|
|
||||||
_items[_tail_idx].next = i;
|
|
||||||
_tail_idx = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_items[i].second = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dict::_rehash(VM* vm){
|
|
||||||
Item* old_items = _items;
|
|
||||||
int old_head_idx = _head_idx;
|
|
||||||
|
|
||||||
_capacity *= 4;
|
|
||||||
_mask = _capacity - 1;
|
|
||||||
_size = 0;
|
|
||||||
_critical_size = _capacity*__LoadFactor+0.5f;
|
|
||||||
_head_idx = -1;
|
|
||||||
_tail_idx = -1;
|
|
||||||
|
|
||||||
__alloc_items();
|
|
||||||
|
|
||||||
// copy old items to new dict
|
|
||||||
int i = old_head_idx;
|
|
||||||
while(i != -1){
|
|
||||||
set(vm, old_items[i].first, old_items[i].second);
|
|
||||||
i = old_items[i].next;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::free(old_items);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyVar Dict::try_get(VM* vm, PyVar key) const{
|
|
||||||
bool ok; int i;
|
|
||||||
_probe_0(vm, key, ok, i);
|
|
||||||
if(!ok) return nullptr;
|
|
||||||
return _items[i].second;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Dict::contains(VM* vm, PyVar key) const{
|
|
||||||
bool ok; int i;
|
|
||||||
_probe_0(vm, key, ok, i);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Dict::del(VM* vm, PyVar key){
|
|
||||||
bool ok; int i;
|
|
||||||
_probe_0(vm, key, ok, i);
|
|
||||||
if(!ok) return false;
|
|
||||||
_items[i].first = nullptr;
|
_items[i].first = nullptr;
|
||||||
// _items[i].second = PY_DELETED_SLOT; // do not change .second if it is not NULL, it means the slot is occupied by a deleted item
|
_items[i].second = nullptr;
|
||||||
_size--;
|
|
||||||
|
|
||||||
if(_size == 0){
|
|
||||||
_head_idx = -1;
|
|
||||||
_tail_idx = -1;
|
|
||||||
}else{
|
|
||||||
if(_head_idx == i){
|
|
||||||
_head_idx = _items[i].next;
|
|
||||||
_items[_head_idx].prev = -1;
|
|
||||||
}else if(_tail_idx == i){
|
|
||||||
_tail_idx = _items[i].prev;
|
|
||||||
_items[_tail_idx].next = -1;
|
|
||||||
}else{
|
|
||||||
_items[_items[i].prev].next = _items[i].next;
|
|
||||||
_items[_items[i].next].prev = _items[i].prev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_items[i].prev = -1;
|
_items[i].prev = -1;
|
||||||
_items[i].next = -1;
|
_items[i].next = -1;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Dict::update(VM* vm, const Dict& other){
|
Dict::Dict(Dict&& other) {
|
||||||
other.apply([&](PyVar k, PyVar v){ set(vm, k, v); });
|
_capacity = other._capacity;
|
||||||
}
|
_mask = other._mask;
|
||||||
|
_size = other._size;
|
||||||
|
_critical_size = other._critical_size;
|
||||||
|
_head_idx = other._head_idx;
|
||||||
|
_tail_idx = other._tail_idx;
|
||||||
|
_items = other._items;
|
||||||
|
other._items = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Tuple Dict::keys() const{
|
Dict::Dict(const Dict& other) {
|
||||||
Tuple t(_size);
|
_capacity = other._capacity;
|
||||||
int i = _head_idx;
|
_mask = other._mask;
|
||||||
int j = 0;
|
_size = other._size;
|
||||||
while(i != -1){
|
_critical_size = other._critical_size;
|
||||||
t[j++] = _items[i].first;
|
_head_idx = other._head_idx;
|
||||||
i = _items[i].next;
|
_tail_idx = other._tail_idx;
|
||||||
|
// copy items
|
||||||
|
_items = (Item*)std::malloc(_capacity * sizeof(Item));
|
||||||
|
std::memcpy(_items, other._items, _capacity * sizeof(Item));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dict::set(VM* vm, PyVar key, PyVar val) {
|
||||||
|
// do possible rehash
|
||||||
|
if(_size + 1 > _critical_size) _rehash(vm);
|
||||||
|
bool ok;
|
||||||
|
int i;
|
||||||
|
_probe_1(vm, key, ok, i);
|
||||||
|
if(!ok) {
|
||||||
|
_size++;
|
||||||
|
_items[i].first = key;
|
||||||
|
|
||||||
|
// append to tail
|
||||||
|
if(_size == 0 + 1) {
|
||||||
|
_head_idx = i;
|
||||||
|
_tail_idx = i;
|
||||||
|
} else {
|
||||||
|
_items[i].prev = _tail_idx;
|
||||||
|
_items[_tail_idx].next = i;
|
||||||
|
_tail_idx = i;
|
||||||
}
|
}
|
||||||
assert(j == _size);
|
}
|
||||||
return t;
|
_items[i].second = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dict::_rehash(VM* vm) {
|
||||||
|
Item* old_items = _items;
|
||||||
|
int old_head_idx = _head_idx;
|
||||||
|
|
||||||
|
_capacity *= 4;
|
||||||
|
_mask = _capacity - 1;
|
||||||
|
_size = 0;
|
||||||
|
_critical_size = _capacity * __LoadFactor + 0.5f;
|
||||||
|
_head_idx = -1;
|
||||||
|
_tail_idx = -1;
|
||||||
|
|
||||||
|
__alloc_items();
|
||||||
|
|
||||||
|
// copy old items to new dict
|
||||||
|
int i = old_head_idx;
|
||||||
|
while(i != -1) {
|
||||||
|
set(vm, old_items[i].first, old_items[i].second);
|
||||||
|
i = old_items[i].next;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple Dict::values() const{
|
std::free(old_items);
|
||||||
Tuple t(_size);
|
}
|
||||||
int i = _head_idx;
|
|
||||||
int j = 0;
|
|
||||||
while(i != -1){
|
|
||||||
t[j++] = _items[i].second;
|
|
||||||
i = _items[i].next;
|
|
||||||
}
|
|
||||||
assert(j == _size);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Dict::clear(){
|
PyVar Dict::try_get(VM* vm, PyVar key) const {
|
||||||
_size = 0;
|
bool ok;
|
||||||
|
int i;
|
||||||
|
_probe_0(vm, key, ok, i);
|
||||||
|
if(!ok) return nullptr;
|
||||||
|
return _items[i].second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Dict::contains(VM* vm, PyVar key) const {
|
||||||
|
bool ok;
|
||||||
|
int i;
|
||||||
|
_probe_0(vm, key, ok, i);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Dict::del(VM* vm, PyVar key) {
|
||||||
|
bool ok;
|
||||||
|
int i;
|
||||||
|
_probe_0(vm, key, ok, i);
|
||||||
|
if(!ok) return false;
|
||||||
|
_items[i].first = nullptr;
|
||||||
|
// _items[i].second = PY_DELETED_SLOT; // do not change .second if it is not NULL, it means the slot is occupied by
|
||||||
|
// a deleted item
|
||||||
|
_size--;
|
||||||
|
|
||||||
|
if(_size == 0) {
|
||||||
_head_idx = -1;
|
_head_idx = -1;
|
||||||
_tail_idx = -1;
|
_tail_idx = -1;
|
||||||
for(int i=0; i<_capacity; i++){
|
} else {
|
||||||
_items[i].first = nullptr;
|
if(_head_idx == i) {
|
||||||
_items[i].second = nullptr;
|
_head_idx = _items[i].next;
|
||||||
_items[i].prev = -1;
|
_items[_head_idx].prev = -1;
|
||||||
_items[i].next = -1;
|
} else if(_tail_idx == i) {
|
||||||
|
_tail_idx = _items[i].prev;
|
||||||
|
_items[_tail_idx].next = -1;
|
||||||
|
} else {
|
||||||
|
_items[_items[i].prev].next = _items[i].next;
|
||||||
|
_items[_items[i].next].prev = _items[i].prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_items[i].prev = -1;
|
||||||
|
_items[i].next = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Dict::~Dict(){
|
void Dict::update(VM* vm, const Dict& other) {
|
||||||
if(_items) std::free(_items);
|
other.apply([&](PyVar k, PyVar v) {
|
||||||
|
set(vm, k, v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple Dict::keys() const {
|
||||||
|
Tuple t(_size);
|
||||||
|
int i = _head_idx;
|
||||||
|
int j = 0;
|
||||||
|
while(i != -1) {
|
||||||
|
t[j++] = _items[i].first;
|
||||||
|
i = _items[i].next;
|
||||||
}
|
}
|
||||||
} // namespace pkpy
|
assert(j == _size);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple Dict::values() const {
|
||||||
|
Tuple t(_size);
|
||||||
|
int i = _head_idx;
|
||||||
|
int j = 0;
|
||||||
|
while(i != -1) {
|
||||||
|
t[j++] = _items[i].second;
|
||||||
|
i = _items[i].next;
|
||||||
|
}
|
||||||
|
assert(j == _size);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dict::clear() {
|
||||||
|
_size = 0;
|
||||||
|
_head_idx = -1;
|
||||||
|
_tail_idx = -1;
|
||||||
|
for(int i = 0; i < _capacity; i++) {
|
||||||
|
_items[i].first = nullptr;
|
||||||
|
_items[i].second = nullptr;
|
||||||
|
_items[i].prev = -1;
|
||||||
|
_items[i].next = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dict::~Dict() {
|
||||||
|
if(_items) std::free(_items);
|
||||||
|
}
|
||||||
|
} // namespace pkpy
|
||||||
|
|||||||
@ -1,20 +1,22 @@
|
|||||||
#include "pocketpy/objects/error.hpp"
|
#include "pocketpy/objects/error.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
Str Exception::summary() const {
|
Str Exception::summary() const {
|
||||||
SStream ss;
|
SStream ss;
|
||||||
if(is_re) ss << "Traceback (most recent call last):\n";
|
if(is_re) ss << "Traceback (most recent call last):\n";
|
||||||
// while(!st.empty()) {
|
// while(!st.empty()) {
|
||||||
// ss << st.top().snapshot() << '\n';
|
// ss << st.top().snapshot() << '\n';
|
||||||
// st.pop();
|
// st.pop();
|
||||||
// }
|
// }
|
||||||
const auto& container = stacktrace.container();
|
const auto& container = stacktrace.container();
|
||||||
for(int i=container.size()-1; i>=0; i--){
|
for(int i = container.size() - 1; i >= 0; i--) {
|
||||||
ss << container[i].snapshot() << '\n';
|
ss << container[i].snapshot() << '\n';
|
||||||
}
|
|
||||||
if (!msg.empty()) ss << type.sv() << ": " << msg;
|
|
||||||
else ss << type.sv();
|
|
||||||
return ss.str();
|
|
||||||
}
|
}
|
||||||
|
if(!msg.empty())
|
||||||
|
ss << type.sv() << ": " << msg;
|
||||||
|
else
|
||||||
|
ss << type.sv();
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#include "pocketpy/objects/object.hpp"
|
#include "pocketpy/objects/object.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
PyVar::PyVar(PyObject* p): PyVar(p->type, p) {}
|
PyVar::PyVar(PyObject* p) : PyVar(p->type, p) {}
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -1,66 +1,68 @@
|
|||||||
#include "pocketpy/objects/sourcedata.hpp"
|
#include "pocketpy/objects/sourcedata.hpp"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy {
|
||||||
SourceData::SourceData(std::string_view source, const Str& filename, CompileMode mode): filename(filename), mode(mode) {
|
SourceData::SourceData(std::string_view source, const Str& filename, CompileMode mode) :
|
||||||
int index = 0;
|
filename(filename), mode(mode) {
|
||||||
// Skip utf8 BOM if there is any.
|
int index = 0;
|
||||||
if (strncmp(source.data(), "\xEF\xBB\xBF", 3) == 0) index += 3;
|
// Skip utf8 BOM if there is any.
|
||||||
// Drop all '\r'
|
if(strncmp(source.data(), "\xEF\xBB\xBF", 3) == 0) index += 3;
|
||||||
SStream ss(source.size() + 1);
|
// Drop all '\r'
|
||||||
while(index < source.size()){
|
SStream ss(source.size() + 1);
|
||||||
if(source[index] != '\r') ss << source[index];
|
while(index < source.size()) {
|
||||||
index++;
|
if(source[index] != '\r') ss << source[index];
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
this->source = ss.str();
|
||||||
|
if(this->source.size > 5 && this->source.sv().substr(0, 5) == "pkpy:") {
|
||||||
|
this->is_precompiled = true;
|
||||||
|
} else {
|
||||||
|
this->is_precompiled = false;
|
||||||
|
}
|
||||||
|
line_starts.push_back(this->source.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceData::SourceData(const Str& filename, CompileMode mode) : filename(filename), mode(mode) {
|
||||||
|
line_starts.push_back(this->source.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<const char*, const char*> SourceData::_get_line(int lineno) const {
|
||||||
|
if(is_precompiled || lineno == -1) return {nullptr, nullptr};
|
||||||
|
lineno -= 1;
|
||||||
|
if(lineno < 0) lineno = 0;
|
||||||
|
const char* _start = line_starts[lineno];
|
||||||
|
const char* i = _start;
|
||||||
|
// max 300 chars
|
||||||
|
while(*i != '\n' && *i != '\0' && i - _start < 300)
|
||||||
|
i++;
|
||||||
|
return {_start, i};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view SourceData::get_line(int lineno) const {
|
||||||
|
auto [_0, _1] = _get_line(lineno);
|
||||||
|
if(_0 && _1) return std::string_view(_0, _1 - _0);
|
||||||
|
return "<?>";
|
||||||
|
}
|
||||||
|
|
||||||
|
Str SourceData::snapshot(int lineno, const char* cursor, std::string_view name) const {
|
||||||
|
SStream ss;
|
||||||
|
ss << " " << "File \"" << filename << "\", line " << lineno;
|
||||||
|
if(!name.empty()) ss << ", in " << name;
|
||||||
|
if(!is_precompiled) {
|
||||||
|
ss << '\n';
|
||||||
|
std::pair<const char*, const char*> pair = _get_line(lineno);
|
||||||
|
Str line = "<?>";
|
||||||
|
int removed_spaces = 0;
|
||||||
|
if(pair.first && pair.second) {
|
||||||
|
line = Str(pair.first, pair.second - pair.first).lstrip();
|
||||||
|
removed_spaces = pair.second - pair.first - line.length();
|
||||||
|
if(line.empty()) line = "<?>";
|
||||||
}
|
}
|
||||||
this->source = ss.str();
|
ss << " " << line;
|
||||||
if(this->source.size>5 && this->source.sv().substr(0, 5)=="pkpy:"){
|
if(cursor && line != "<?>" && cursor >= pair.first && cursor <= pair.second) {
|
||||||
this->is_precompiled = true;
|
auto column = cursor - pair.first - removed_spaces;
|
||||||
}else{
|
if(column >= 0) ss << "\n " << std::string(column, ' ') << "^";
|
||||||
this->is_precompiled = false;
|
|
||||||
}
|
}
|
||||||
line_starts.push_back(this->source.c_str());
|
|
||||||
}
|
}
|
||||||
|
return ss.str();
|
||||||
SourceData::SourceData(const Str& filename, CompileMode mode): filename(filename), mode(mode) {
|
}
|
||||||
line_starts.push_back(this->source.c_str());
|
} // namespace pkpy
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<const char*,const char*> SourceData::_get_line(int lineno) const {
|
|
||||||
if(is_precompiled || lineno == -1) return {nullptr, nullptr};
|
|
||||||
lineno -= 1;
|
|
||||||
if(lineno < 0) lineno = 0;
|
|
||||||
const char* _start = line_starts[lineno];
|
|
||||||
const char* i = _start;
|
|
||||||
// max 300 chars
|
|
||||||
while(*i != '\n' && *i != '\0' && i-_start < 300) i++;
|
|
||||||
return {_start, i};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string_view SourceData::get_line(int lineno) const{
|
|
||||||
auto [_0, _1] = _get_line(lineno);
|
|
||||||
if(_0 && _1) return std::string_view(_0, _1-_0);
|
|
||||||
return "<?>";
|
|
||||||
}
|
|
||||||
|
|
||||||
Str SourceData::snapshot(int lineno, const char* cursor, std::string_view name) const{
|
|
||||||
SStream ss;
|
|
||||||
ss << " " << "File \"" << filename << "\", line " << lineno;
|
|
||||||
if(!name.empty()) ss << ", in " << name;
|
|
||||||
if(!is_precompiled){
|
|
||||||
ss << '\n';
|
|
||||||
std::pair<const char*,const char*> pair = _get_line(lineno);
|
|
||||||
Str line = "<?>";
|
|
||||||
int removed_spaces = 0;
|
|
||||||
if(pair.first && pair.second){
|
|
||||||
line = Str(pair.first, pair.second-pair.first).lstrip();
|
|
||||||
removed_spaces = pair.second - pair.first - line.length();
|
|
||||||
if(line.empty()) line = "<?>";
|
|
||||||
}
|
|
||||||
ss << " " << line;
|
|
||||||
if(cursor && line != "<?>" && cursor >= pair.first && cursor <= pair.second){
|
|
||||||
auto column = cursor - pair.first - removed_spaces;
|
|
||||||
if(column >= 0) ss << "\n " << std::string(column, ' ') << "^";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
} // namespace pkpy
|
|
||||||
|
|||||||
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
Tuple::Tuple(int n){
|
Tuple::Tuple(int n) {
|
||||||
if(n <= INLINED_SIZE){
|
if(n <= INLINED_SIZE) {
|
||||||
this->_args = _inlined;
|
this->_args = _inlined;
|
||||||
}else{
|
} else {
|
||||||
this->_args = (PyVar*)std::malloc(n * sizeof(PyVar));
|
this->_args = (PyVar*)std::malloc(n * sizeof(PyVar));
|
||||||
}
|
}
|
||||||
this->_size = n;
|
this->_size = n;
|
||||||
@ -13,39 +13,44 @@ Tuple::Tuple(int n){
|
|||||||
|
|
||||||
Tuple::Tuple(Tuple&& other) noexcept {
|
Tuple::Tuple(Tuple&& other) noexcept {
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
if(other.is_inlined()){
|
if(other.is_inlined()) {
|
||||||
_args = _inlined;
|
_args = _inlined;
|
||||||
for(int i=0; i<_size; i++) _args[i] = other._args[i];
|
for(int i = 0; i < _size; i++)
|
||||||
}else{
|
_args[i] = other._args[i];
|
||||||
|
} else {
|
||||||
_args = other._args;
|
_args = other._args;
|
||||||
other._args = other._inlined;
|
other._args = other._inlined;
|
||||||
other._size = 0;
|
other._size = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple::Tuple(PyVar _0, PyVar _1): Tuple(2){
|
Tuple::Tuple(PyVar _0, PyVar _1) : Tuple(2) {
|
||||||
_args[0] = _0;
|
_args[0] = _0;
|
||||||
_args[1] = _1;
|
_args[1] = _1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple::Tuple(PyVar _0, PyVar _1, PyVar _2): Tuple(3){
|
Tuple::Tuple(PyVar _0, PyVar _1, PyVar _2) : Tuple(3) {
|
||||||
_args[0] = _0;
|
_args[0] = _0;
|
||||||
_args[1] = _1;
|
_args[1] = _1;
|
||||||
_args[2] = _2;
|
_args[2] = _2;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple::~Tuple(){ if(!is_inlined()) std::free(_args); }
|
Tuple::~Tuple() {
|
||||||
|
if(!is_inlined()) std::free(_args);
|
||||||
|
}
|
||||||
|
|
||||||
List ArgsView::to_list() const{
|
List ArgsView::to_list() const {
|
||||||
List ret(size());
|
List ret(size());
|
||||||
for(int i=0; i<size(); i++) ret[i] = _begin[i];
|
for(int i = 0; i < size(); i++)
|
||||||
|
ret[i] = _begin[i];
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple ArgsView::to_tuple() const{
|
Tuple ArgsView::to_tuple() const {
|
||||||
Tuple ret(size());
|
Tuple ret(size());
|
||||||
for(int i=0; i<size(); i++) ret[i] = _begin[i];
|
for(int i = 0; i < size(); i++)
|
||||||
|
ret[i] = _begin[i];
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
542
src/pocketpy.cpp
542
src/pocketpy.cpp
File diff suppressed because it is too large
Load Diff
@ -7,32 +7,29 @@
|
|||||||
|
|
||||||
using namespace pkpy;
|
using namespace pkpy;
|
||||||
|
|
||||||
#define PK_ASSERT_N_EXTRA_ELEMENTS(n) \
|
#define PK_ASSERT_N_EXTRA_ELEMENTS(n) \
|
||||||
int __ex_count = count_extra_elements(vm, n); \
|
int __ex_count = count_extra_elements(vm, n); \
|
||||||
if(__ex_count < n){ \
|
if(__ex_count < n) { \
|
||||||
Str msg = _S("expected at least ", n, " elements, got ", __ex_count); \
|
Str msg = _S("expected at least ", n, " elements, got ", __ex_count); \
|
||||||
pkpy_error(vm_handle, "StackError", pkpy_string(msg.c_str())); \
|
pkpy_error(vm_handle, "StackError", pkpy_string(msg.c_str())); \
|
||||||
return false; \
|
return false; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PK_ASSERT_NO_ERROR() \
|
#define PK_ASSERT_NO_ERROR() \
|
||||||
if(vm->__c.error != nullptr) \
|
if(vm->__c.error != nullptr) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
static int count_extra_elements(VM* vm, int n){
|
static int count_extra_elements(VM* vm, int n) {
|
||||||
if(vm->callstack.empty()){
|
if(vm->callstack.empty()) { return vm->s_data.size(); }
|
||||||
return vm->s_data.size();
|
|
||||||
}
|
|
||||||
assert(!vm->__c.s_view.empty());
|
assert(!vm->__c.s_view.empty());
|
||||||
return vm->s_data._sp - vm->__c.s_view.top().end();
|
return vm->s_data._sp - vm->__c.s_view.top().end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyVar stack_item(VM* vm, int index){
|
static PyVar stack_item(VM* vm, int index) {
|
||||||
PyVar* begin;
|
PyVar* begin;
|
||||||
PyVar* end = vm->s_data.end();
|
PyVar* end = vm->s_data.end();
|
||||||
if(vm->callstack.empty()){
|
if(vm->callstack.empty()) {
|
||||||
begin = vm->s_data.begin();
|
begin = vm->s_data.begin();
|
||||||
}else{
|
} else {
|
||||||
assert(!vm->__c.s_view.empty());
|
assert(!vm->__c.s_view.empty());
|
||||||
begin = vm->__c.s_view.top().begin();
|
begin = vm->__c.s_view.top().begin();
|
||||||
}
|
}
|
||||||
@ -42,27 +39,24 @@ static PyVar stack_item(VM* vm, int index){
|
|||||||
return begin[index];
|
return begin[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PK_PROTECTED(__B) \
|
#define PK_PROTECTED(__B) \
|
||||||
try{ __B } \
|
try { \
|
||||||
catch(TopLevelException e) { \
|
__B \
|
||||||
vm->__c.error = e.ptr->self(); \
|
} catch(TopLevelException e) { \
|
||||||
return false; \
|
vm->__c.error = e.ptr->self(); \
|
||||||
} catch(const std::exception& re){ \
|
return false; \
|
||||||
PyObject* e_t = vm->_t(vm->tp_exception); \
|
} catch(const std::exception& re) { \
|
||||||
vm->__c.error = vm->call(e_t, VAR(re.what())).get(); \
|
PyObject* e_t = vm->_t(vm->tp_exception); \
|
||||||
return false; \
|
vm->__c.error = vm->call(e_t, VAR(re.what())).get(); \
|
||||||
|
return false; \
|
||||||
}
|
}
|
||||||
|
|
||||||
pkpy_vm* pkpy_new_vm(bool enable_os){
|
pkpy_vm* pkpy_new_vm(bool enable_os) { return (pkpy_vm*)new VM(enable_os); }
|
||||||
return (pkpy_vm*)new VM(enable_os);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pkpy_delete_vm(pkpy_vm* vm){
|
void pkpy_delete_vm(pkpy_vm* vm) { return delete (VM*)vm; }
|
||||||
return delete (VM*)vm;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_exec(pkpy_vm* vm_handle, const char* source) {
|
bool pkpy_exec(pkpy_vm* vm_handle, const char* source) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PyVar res;
|
PyVar res;
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
@ -72,16 +66,15 @@ bool pkpy_exec(pkpy_vm* vm_handle, const char* source) {
|
|||||||
return res != nullptr;
|
return res != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, const char* module){
|
bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, const char* module) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PyVar res;
|
PyVar res;
|
||||||
PyObject* mod;
|
PyObject* mod;
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
if(module == nullptr){
|
if(module == nullptr){ mod = vm->_main;
|
||||||
mod = vm->_main;
|
|
||||||
}else{
|
}else{
|
||||||
mod = vm->_modules[module].get(); // may raise
|
mod = vm->_modules[module].get(); // may raise
|
||||||
}
|
}
|
||||||
CodeObject_ code = vm->compile(source, filename, (CompileMode)mode);
|
CodeObject_ code = vm->compile(source, filename, (CompileMode)mode);
|
||||||
res = vm->_exec(code, mod);
|
res = vm->_exec(code, mod);
|
||||||
@ -89,13 +82,13 @@ bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, i
|
|||||||
return res != nullptr;
|
return res != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkpy_set_main_argv(pkpy_vm* vm_handle, int argc, char** argv){
|
void pkpy_set_main_argv(pkpy_vm* vm_handle, int argc, char** argv) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
vm->set_main_argv(argc, argv);
|
vm->set_main_argv(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_dup(pkpy_vm* vm_handle, int n){
|
bool pkpy_dup(pkpy_vm* vm_handle, int n) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
PyVar item = stack_item(vm, n);
|
PyVar item = stack_item(vm, n);
|
||||||
@ -104,15 +97,15 @@ bool pkpy_dup(pkpy_vm* vm_handle, int n){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_pop(pkpy_vm* vm_handle, int n){
|
bool pkpy_pop(pkpy_vm* vm_handle, int n) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_ASSERT_N_EXTRA_ELEMENTS(n)
|
PK_ASSERT_N_EXTRA_ELEMENTS(n)
|
||||||
vm->s_data.shrink(n);
|
vm->s_data.shrink(n);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_pop_top(pkpy_vm* vm_handle){
|
bool pkpy_pop_top(pkpy_vm* vm_handle) {
|
||||||
VM* vm = (VM*)vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
@ -120,7 +113,7 @@ bool pkpy_pop_top(pkpy_vm* vm_handle){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_dup_top(pkpy_vm* vm_handle){
|
bool pkpy_dup_top(pkpy_vm* vm_handle) {
|
||||||
VM* vm = (VM*)vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
@ -128,7 +121,7 @@ bool pkpy_dup_top(pkpy_vm* vm_handle){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_rot_two(pkpy_vm* vm_handle){
|
bool pkpy_rot_two(pkpy_vm* vm_handle) {
|
||||||
VM* vm = (VM*)vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_ASSERT_N_EXTRA_ELEMENTS(2)
|
PK_ASSERT_N_EXTRA_ELEMENTS(2)
|
||||||
@ -136,19 +129,17 @@ bool pkpy_rot_two(pkpy_vm* vm_handle){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pkpy_stack_size(pkpy_vm* vm_handle){
|
int pkpy_stack_size(pkpy_vm* vm_handle) {
|
||||||
VM* vm = (VM*)vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
if(vm->callstack.empty()){
|
if(vm->callstack.empty()) { return vm->s_data.size(); }
|
||||||
return vm->s_data.size();
|
|
||||||
}
|
|
||||||
if(vm->__c.s_view.empty()) exit(127);
|
if(vm->__c.s_view.empty()) exit(127);
|
||||||
return vm->s_data._sp - vm->__c.s_view.top().begin();
|
return vm->s_data._sp - vm->__c.s_view.top().begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
// int
|
// int
|
||||||
bool pkpy_push_int(pkpy_vm* vm_handle, int value) {
|
bool pkpy_push_int(pkpy_vm* vm_handle, int value) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PyVar res;
|
PyVar res;
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
@ -159,16 +150,16 @@ bool pkpy_push_int(pkpy_vm* vm_handle, int value) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_is_int(pkpy_vm* vm_handle, int i){
|
bool pkpy_is_int(pkpy_vm* vm_handle, int i) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
return is_int(stack_item(vm, i));
|
return is_int(stack_item(vm, i));
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_to_int(pkpy_vm* vm_handle, int i, int* out){
|
bool pkpy_to_int(pkpy_vm* vm_handle, int i, int* out) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
PyVar item = stack_item(vm, i);
|
PyVar item = stack_item(vm, i);
|
||||||
@ -179,15 +170,15 @@ bool pkpy_to_int(pkpy_vm* vm_handle, int i, int* out){
|
|||||||
|
|
||||||
// float
|
// float
|
||||||
bool pkpy_push_float(pkpy_vm* vm_handle, double value) {
|
bool pkpy_push_float(pkpy_vm* vm_handle, double value) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PyVar res = py_var(vm, value);
|
PyVar res = py_var(vm, value);
|
||||||
vm->s_data.push(res);
|
vm->s_data.push(res);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_is_float(pkpy_vm* vm_handle, int i){
|
bool pkpy_is_float(pkpy_vm* vm_handle, int i) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
PyVar item = stack_item(vm, i);
|
PyVar item = stack_item(vm, i);
|
||||||
@ -195,8 +186,8 @@ bool pkpy_is_float(pkpy_vm* vm_handle, int i){
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_to_float(pkpy_vm* vm_handle, int i, double* out){
|
bool pkpy_to_float(pkpy_vm* vm_handle, int i, double* out) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
PyVar item = stack_item(vm, i);
|
PyVar item = stack_item(vm, i);
|
||||||
@ -207,14 +198,14 @@ bool pkpy_to_float(pkpy_vm* vm_handle, int i, double* out){
|
|||||||
|
|
||||||
// bool
|
// bool
|
||||||
bool pkpy_push_bool(pkpy_vm* vm_handle, bool value) {
|
bool pkpy_push_bool(pkpy_vm* vm_handle, bool value) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
vm->s_data.push(value ? vm->True : vm->False);
|
vm->s_data.push(value ? vm->True : vm->False);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_is_bool(pkpy_vm* vm_handle, int i){
|
bool pkpy_is_bool(pkpy_vm* vm_handle, int i) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
PyVar item = stack_item(vm, i);
|
PyVar item = stack_item(vm, i);
|
||||||
@ -222,8 +213,8 @@ bool pkpy_is_bool(pkpy_vm* vm_handle, int i){
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_to_bool(pkpy_vm* vm_handle, int i, bool* out){
|
bool pkpy_to_bool(pkpy_vm* vm_handle, int i, bool* out) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
PyVar item = stack_item(vm, i);
|
PyVar item = stack_item(vm, i);
|
||||||
@ -234,15 +225,15 @@ bool pkpy_to_bool(pkpy_vm* vm_handle, int i, bool* out){
|
|||||||
|
|
||||||
// string
|
// string
|
||||||
bool pkpy_push_string(pkpy_vm* vm_handle, pkpy_CString value) {
|
bool pkpy_push_string(pkpy_vm* vm_handle, pkpy_CString value) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PyVar res = py_var(vm, value);
|
PyVar res = py_var(vm, value);
|
||||||
vm->s_data.push(res);
|
vm->s_data.push(res);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_is_string(pkpy_vm* vm_handle, int i){
|
bool pkpy_is_string(pkpy_vm* vm_handle, int i) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
PyVar item = stack_item(vm, i);
|
PyVar item = stack_item(vm, i);
|
||||||
@ -250,8 +241,8 @@ bool pkpy_is_string(pkpy_vm* vm_handle, int i){
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_to_string(pkpy_vm* vm_handle, int i, pkpy_CString* out){
|
bool pkpy_to_string(pkpy_vm* vm_handle, int i, pkpy_CString* out) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
PyVar item = stack_item(vm, i);
|
PyVar item = stack_item(vm, i);
|
||||||
@ -263,15 +254,15 @@ bool pkpy_to_string(pkpy_vm* vm_handle, int i, pkpy_CString* out){
|
|||||||
|
|
||||||
// void_p
|
// void_p
|
||||||
bool pkpy_push_voidp(pkpy_vm* vm_handle, void* value) {
|
bool pkpy_push_voidp(pkpy_vm* vm_handle, void* value) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PyVar res = py_var(vm, value);
|
PyVar res = py_var(vm, value);
|
||||||
vm->s_data.push(res);
|
vm->s_data.push(res);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_is_voidp(pkpy_vm* vm_handle, int i){
|
bool pkpy_is_voidp(pkpy_vm* vm_handle, int i) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
PyVar item = stack_item(vm, i);
|
PyVar item = stack_item(vm, i);
|
||||||
@ -279,8 +270,8 @@ bool pkpy_is_voidp(pkpy_vm* vm_handle, int i){
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_to_voidp(pkpy_vm* vm_handle, int i, void** out){
|
bool pkpy_to_voidp(pkpy_vm* vm_handle, int i, void** out) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
PyVar item = stack_item(vm, i);
|
PyVar item = stack_item(vm, i);
|
||||||
@ -292,14 +283,14 @@ bool pkpy_to_voidp(pkpy_vm* vm_handle, int i, void** out){
|
|||||||
|
|
||||||
// none
|
// none
|
||||||
bool pkpy_push_none(pkpy_vm* vm_handle) {
|
bool pkpy_push_none(pkpy_vm* vm_handle) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
vm->s_data.push(vm->None);
|
vm->s_data.push(vm->None);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_is_none(pkpy_vm* vm_handle, int i){
|
bool pkpy_is_none(pkpy_vm* vm_handle, int i) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
PyVar item = stack_item(vm, i);
|
PyVar item = stack_item(vm, i);
|
||||||
@ -309,25 +300,25 @@ bool pkpy_is_none(pkpy_vm* vm_handle, int i){
|
|||||||
|
|
||||||
// null
|
// null
|
||||||
bool pkpy_push_null(pkpy_vm* vm_handle) {
|
bool pkpy_push_null(pkpy_vm* vm_handle) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
vm->s_data.push(PY_NULL);
|
vm->s_data.push(PY_NULL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TempViewPopper{
|
struct TempViewPopper {
|
||||||
VM* vm;
|
VM* vm;
|
||||||
bool used;
|
bool used;
|
||||||
|
|
||||||
TempViewPopper(VM* vm): vm(vm), used(false) {}
|
TempViewPopper(VM* vm) : vm(vm), used(false) {}
|
||||||
|
|
||||||
void restore() noexcept{
|
void restore() noexcept {
|
||||||
if(used) return;
|
if(used) return;
|
||||||
vm->__c.s_view.pop();
|
vm->__c.s_view.pop();
|
||||||
used = true;
|
used = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
~TempViewPopper(){ restore(); }
|
~TempViewPopper() { restore(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// function
|
// function
|
||||||
@ -337,25 +328,25 @@ static PyVar c_function_wrapper(VM* vm, ArgsView args) {
|
|||||||
|
|
||||||
vm->__c.s_view.push(args);
|
vm->__c.s_view.push(args);
|
||||||
TempViewPopper _tvp(vm);
|
TempViewPopper _tvp(vm);
|
||||||
int retc = f((pkpy_vm*)vm); // may raise, _tvp will handle this via RAII
|
int retc = f((pkpy_vm*)vm); // may raise, _tvp will handle this via RAII
|
||||||
_tvp.restore();
|
_tvp.restore();
|
||||||
|
|
||||||
// propagate_if_errored
|
// propagate_if_errored
|
||||||
if (vm->__c.error != nullptr){
|
if(vm->__c.error != nullptr) {
|
||||||
PyObject* e_obj = vm->__c.error;
|
PyObject* e_obj = vm->__c.error;
|
||||||
vm->__c.error = nullptr;
|
vm->__c.error = nullptr;
|
||||||
vm->_error(e_obj);
|
vm->_error(e_obj);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
assert(retc == vm->s_data._sp-curr_sp);
|
assert(retc == vm->s_data._sp - curr_sp);
|
||||||
if(retc == 0) return vm->None;
|
if(retc == 0) return vm->None;
|
||||||
if (retc == 1) return vm->s_data.popx();
|
if(retc == 1) return vm->s_data.popx();
|
||||||
ArgsView ret_view(curr_sp, vm->s_data._sp);
|
ArgsView ret_view(curr_sp, vm->s_data._sp);
|
||||||
return py_var(vm, ret_view.to_tuple());
|
return py_var(vm, ret_view.to_tuple());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_push_function(pkpy_vm* vm_handle, const char* sig, pkpy_CFunction f) {
|
bool pkpy_push_function(pkpy_vm* vm_handle, const char* sig, pkpy_CFunction f) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PyVar f_obj;
|
PyVar f_obj;
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
@ -367,7 +358,7 @@ bool pkpy_push_function(pkpy_vm* vm_handle, const char* sig, pkpy_CFunction f) {
|
|||||||
|
|
||||||
// special push
|
// special push
|
||||||
bool pkpy_push_module(pkpy_vm* vm_handle, const char* name) {
|
bool pkpy_push_module(pkpy_vm* vm_handle, const char* name) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
PyObject* module = vm->new_module(name);
|
PyObject* module = vm->new_module(name);
|
||||||
@ -378,7 +369,7 @@ bool pkpy_push_module(pkpy_vm* vm_handle, const char* name) {
|
|||||||
|
|
||||||
// some opt
|
// some opt
|
||||||
bool pkpy_getattr(pkpy_vm* vm_handle, pkpy_CName name) {
|
bool pkpy_getattr(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
PyVar o = vm->s_data.top();
|
PyVar o = vm->s_data.top();
|
||||||
@ -389,7 +380,7 @@ bool pkpy_getattr(pkpy_vm* vm_handle, pkpy_CName name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_setattr(pkpy_vm* vm_handle, pkpy_CName name) {
|
bool pkpy_setattr(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_ASSERT_N_EXTRA_ELEMENTS(2)
|
PK_ASSERT_N_EXTRA_ELEMENTS(2)
|
||||||
PyVar a = vm->s_data.top();
|
PyVar a = vm->s_data.top();
|
||||||
@ -401,21 +392,21 @@ bool pkpy_setattr(pkpy_vm* vm_handle, pkpy_CName name) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//get global will also get bulitins
|
// get global will also get bulitins
|
||||||
bool pkpy_getglobal(pkpy_vm* vm_handle, pkpy_CName name) {
|
bool pkpy_getglobal(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PyVar o = vm->_main->attr().try_get(StrName(name));
|
PyVar o = vm->_main->attr().try_get(StrName(name));
|
||||||
if (o == nullptr) {
|
if(o == nullptr) {
|
||||||
o = vm->builtins->attr().try_get(StrName(name));
|
o = vm->builtins->attr().try_get(StrName(name));
|
||||||
if (o == nullptr) return false;
|
if(o == nullptr) return false;
|
||||||
}
|
}
|
||||||
vm->s_data.push(o);
|
vm->s_data.push(o);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_setglobal(pkpy_vm* vm_handle, pkpy_CName name) {
|
bool pkpy_setglobal(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
vm->_main->attr().set(StrName(name), vm->s_data.popx());
|
vm->_main->attr().set(StrName(name), vm->s_data.popx());
|
||||||
@ -423,7 +414,7 @@ bool pkpy_setglobal(pkpy_vm* vm_handle, pkpy_CName name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_eval(pkpy_vm* vm_handle, const char* source) {
|
bool pkpy_eval(pkpy_vm* vm_handle, const char* source) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
CodeObject_ co = vm->compile(source, "<eval>", EVAL_MODE);
|
CodeObject_ co = vm->compile(source, "<eval>", EVAL_MODE);
|
||||||
@ -434,7 +425,7 @@ bool pkpy_eval(pkpy_vm* vm_handle, const char* source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) {
|
bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
auto _lock = vm->heap.gc_scope_lock();
|
auto _lock = vm->heap.gc_scope_lock();
|
||||||
@ -450,8 +441,8 @@ bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_get_unbound_method(pkpy_vm* vm_handle, pkpy_CName name){
|
bool pkpy_get_unbound_method(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
PyVar o = vm->s_data.top();
|
PyVar o = vm->s_data.top();
|
||||||
@ -466,7 +457,7 @@ bool pkpy_get_unbound_method(pkpy_vm* vm_handle, pkpy_CName name){
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_py_repr(pkpy_vm* vm_handle) {
|
bool pkpy_py_repr(pkpy_vm* vm_handle) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
PyVar item = vm->s_data.top();
|
PyVar item = vm->s_data.top();
|
||||||
@ -478,7 +469,7 @@ bool pkpy_py_repr(pkpy_vm* vm_handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_py_str(pkpy_vm* vm_handle) {
|
bool pkpy_py_str(pkpy_vm* vm_handle) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
PyVar item = vm->s_data.top();
|
PyVar item = vm->s_data.top();
|
||||||
@ -490,7 +481,7 @@ bool pkpy_py_str(pkpy_vm* vm_handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_py_import(pkpy_vm* vm_handle, pkpy_CString name) {
|
bool pkpy_py_import(pkpy_vm* vm_handle, pkpy_CString name) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_PROTECTED(
|
PK_PROTECTED(
|
||||||
PyVar module = vm->py_import(name);
|
PyVar module = vm->py_import(name);
|
||||||
@ -501,14 +492,15 @@ bool pkpy_py_import(pkpy_vm* vm_handle, pkpy_CString name) {
|
|||||||
|
|
||||||
/* Error Handling */
|
/* Error Handling */
|
||||||
bool pkpy_error(pkpy_vm* vm_handle, const char* name, pkpy_CString message) {
|
bool pkpy_error(pkpy_vm* vm_handle, const char* name, pkpy_CString message) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PyVar e_t = vm->_main->attr().try_get_likely_found(name);
|
PyVar e_t = vm->_main->attr().try_get_likely_found(name);
|
||||||
if(e_t == nullptr){
|
if(e_t == nullptr) {
|
||||||
e_t = vm->builtins->attr().try_get_likely_found(name);
|
e_t = vm->builtins->attr().try_get_likely_found(name);
|
||||||
if(e_t == nullptr){
|
if(e_t == nullptr) {
|
||||||
e_t = vm->_t(vm->tp_exception);
|
e_t = vm->_t(vm->tp_exception);
|
||||||
std::cerr << "[warning] pkpy_error(): " << Str(name).escape() << " not found, fallback to 'Exception'" << std::endl;
|
std::cerr << "[warning] pkpy_error(): " << Str(name).escape() << " not found, fallback to 'Exception'"
|
||||||
|
<< std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vm->__c.error = vm->call(e_t, VAR(message)).get();
|
vm->__c.error = vm->call(e_t, VAR(message)).get();
|
||||||
@ -516,23 +508,23 @@ bool pkpy_error(pkpy_vm* vm_handle, const char* name, pkpy_CString message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_check_error(pkpy_vm* vm_handle) {
|
bool pkpy_check_error(pkpy_vm* vm_handle) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
return vm->__c.error != nullptr;
|
return vm->__c.error != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
|
bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
// no error
|
// no error
|
||||||
if (vm->__c.error == nullptr) return false;
|
if(vm->__c.error == nullptr) return false;
|
||||||
Exception& e = vm->__c.error->as<Exception>();
|
Exception& e = vm->__c.error->as<Exception>();
|
||||||
if (message != nullptr)
|
if(message != nullptr)
|
||||||
*message = strdup(e.summary().c_str());
|
*message = strdup(e.summary().c_str());
|
||||||
else
|
else
|
||||||
std::cout << e.summary() << std::endl;
|
std::cout << e.summary() << std::endl;
|
||||||
vm->__c.error = nullptr;
|
vm->__c.error = nullptr;
|
||||||
if(vm->callstack.empty()){
|
if(vm->callstack.empty()) {
|
||||||
vm->s_data.clear();
|
vm->s_data.clear();
|
||||||
}else{
|
} else {
|
||||||
if(vm->__c.s_view.empty()) exit(127);
|
if(vm->__c.s_view.empty()) exit(127);
|
||||||
vm->s_data.reset(vm->__c.s_view.top().end());
|
vm->s_data.reset(vm->__c.s_view.top().end());
|
||||||
}
|
}
|
||||||
@ -540,7 +532,7 @@ bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool pkpy_vectorcall(pkpy_vm* vm_handle, int argc) {
|
bool pkpy_vectorcall(pkpy_vm* vm_handle, int argc) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
PK_ASSERT_N_EXTRA_ELEMENTS(argc + 2)
|
PK_ASSERT_N_EXTRA_ELEMENTS(argc + 2)
|
||||||
PyVar res;
|
PyVar res;
|
||||||
@ -550,39 +542,28 @@ bool pkpy_vectorcall(pkpy_vm* vm_handle, int argc) {
|
|||||||
vm->s_data.push(res);
|
vm->s_data.push(res);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************/
|
/*****************************************************************/
|
||||||
void pkpy_free(void* p){
|
void pkpy_free(void* p) { std::free(p); }
|
||||||
std::free(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
pkpy_CName pkpy_name(const char* name){
|
pkpy_CName pkpy_name(const char* name) { return StrName(name).index; }
|
||||||
return StrName(name).index;
|
|
||||||
}
|
|
||||||
|
|
||||||
pkpy_CString pkpy_name_to_string(pkpy_CName name){
|
pkpy_CString pkpy_name_to_string(pkpy_CName name) { return StrName(name).c_str(); }
|
||||||
return StrName(name).c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
void pkpy_set_output_handler(pkpy_vm* vm_handle, pkpy_COutputHandler handler){
|
void pkpy_set_output_handler(pkpy_vm* vm_handle, pkpy_COutputHandler handler) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
vm->_stdout = handler;
|
vm->_stdout = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkpy_set_import_handler(pkpy_vm* vm_handle, pkpy_CImportHandler handler){
|
void pkpy_set_import_handler(pkpy_vm* vm_handle, pkpy_CImportHandler handler) {
|
||||||
VM* vm = (VM*) vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
vm->_import_handler = handler;
|
vm->_import_handler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* pkpy_new_repl(pkpy_vm* vm_handle){
|
void* pkpy_new_repl(pkpy_vm* vm_handle) { return new REPL((VM*)vm_handle); }
|
||||||
return new REPL((VM*)vm_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pkpy_repl_input(void* r, const char* line){
|
bool pkpy_repl_input(void* r, const char* line) { return ((REPL*)r)->input(line); }
|
||||||
return ((REPL*)r)->input(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pkpy_delete_repl(void* repl){
|
void pkpy_delete_repl(void* repl) { delete (REPL*)repl; }
|
||||||
delete (REPL*)repl;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // PK_NO_EXPORT_C_API
|
#endif // PK_NO_EXPORT_C_API
|
||||||
|
|||||||
@ -4,42 +4,42 @@
|
|||||||
#include "pocketpy/common/export.h"
|
#include "pocketpy/common/export.h"
|
||||||
|
|
||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
REPL::REPL(VM* vm) : vm(vm){
|
REPL::REPL(VM* vm) : vm(vm) {
|
||||||
vm->stdout_write("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") ");
|
vm->stdout_write("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") ");
|
||||||
vm->stdout_write(_S("[", sizeof(void*)*8, " bit] on ", kPlatformStrings[PK_SYS_PLATFORM], "\n"));
|
vm->stdout_write(_S("[", sizeof(void*) * 8, " bit] on ", kPlatformStrings[PK_SYS_PLATFORM], "\n"));
|
||||||
vm->stdout_write("https://github.com/pocketpy/pocketpy" "\n");
|
vm->stdout_write("https://github.com/pocketpy/pocketpy" "\n");
|
||||||
vm->stdout_write("Type \"exit()\" to exit." "\n");
|
vm->stdout_write("Type \"exit()\" to exit." "\n");
|
||||||
}
|
|
||||||
|
|
||||||
bool REPL::input(std::string line){
|
|
||||||
CompileMode mode = REPL_MODE;
|
|
||||||
if(need_more_lines){
|
|
||||||
buffer += line;
|
|
||||||
buffer += '\n';
|
|
||||||
int n = buffer.size();
|
|
||||||
if(n>=need_more_lines){
|
|
||||||
for(int i=buffer.size()-need_more_lines; i<buffer.size(); i++){
|
|
||||||
// no enough lines
|
|
||||||
if(buffer[i] != '\n') return true;
|
|
||||||
}
|
|
||||||
need_more_lines = 0;
|
|
||||||
line = buffer;
|
|
||||||
buffer.clear();
|
|
||||||
mode = CELL_MODE;
|
|
||||||
}else{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try{
|
|
||||||
vm->exec(line, "<stdin>", mode);
|
|
||||||
}catch(NeedMoreLines ne){
|
|
||||||
buffer += line;
|
|
||||||
buffer += '\n';
|
|
||||||
need_more_lines = ne.is_compiling_class ? 3 : 2;
|
|
||||||
if (need_more_lines) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool REPL::input(std::string line) {
|
||||||
|
CompileMode mode = REPL_MODE;
|
||||||
|
if(need_more_lines) {
|
||||||
|
buffer += line;
|
||||||
|
buffer += '\n';
|
||||||
|
int n = buffer.size();
|
||||||
|
if(n >= need_more_lines) {
|
||||||
|
for(int i = buffer.size() - need_more_lines; i < buffer.size(); i++) {
|
||||||
|
// no enough lines
|
||||||
|
if(buffer[i] != '\n') return true;
|
||||||
|
}
|
||||||
|
need_more_lines = 0;
|
||||||
|
line = buffer;
|
||||||
|
buffer.clear();
|
||||||
|
mode = CELL_MODE;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
vm->exec(line, "<stdin>", mode);
|
||||||
|
} catch(NeedMoreLines ne) {
|
||||||
|
buffer += line;
|
||||||
|
buffer += '\n';
|
||||||
|
need_more_lines = ne.is_compiling_class ? 3 : 2;
|
||||||
|
if(need_more_lines) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pkpy
|
||||||
|
|||||||
@ -4,34 +4,31 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#if __has_include("pocketpy_c.h")
|
#if __has_include("pocketpy_c.h")
|
||||||
#include "pocketpy_c.h"
|
#include "pocketpy_c.h"
|
||||||
#else
|
#else
|
||||||
// for amalgamated build
|
// for amalgamated build
|
||||||
#include "pocketpy.h"
|
#include "pocketpy.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
std::string pkpy_platform_getline(bool* eof) {
|
std::string pkpy_platform_getline(bool* eof) {
|
||||||
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
std::wstringstream wss;
|
std::wstringstream wss;
|
||||||
WCHAR buf;
|
WCHAR buf;
|
||||||
DWORD read;
|
DWORD read;
|
||||||
while (ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') {
|
while(ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') {
|
||||||
if (eof && buf == L'\x1A') *eof = true; // Ctrl+Z
|
if(eof && buf == L'\x1A') *eof = true; // Ctrl+Z
|
||||||
wss << buf;
|
wss << buf;
|
||||||
}
|
}
|
||||||
std::wstring wideInput = wss.str();
|
std::wstring wideInput = wss.str();
|
||||||
int length =
|
int length = WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), NULL, 0, NULL, NULL);
|
||||||
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(),
|
|
||||||
(int)wideInput.length(), NULL, 0, NULL, NULL);
|
|
||||||
std::string output;
|
std::string output;
|
||||||
output.resize(length);
|
output.resize(length);
|
||||||
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(),
|
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL);
|
||||||
&output[0], length, NULL, NULL);
|
if(!output.empty() && output.back() == '\r') output.pop_back();
|
||||||
if (!output.empty() && output.back() == '\r') output.pop_back();
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,8 +36,8 @@ std::string pkpy_platform_getline(bool* eof) {
|
|||||||
|
|
||||||
std::string pkpy_platform_getline(bool* eof) {
|
std::string pkpy_platform_getline(bool* eof) {
|
||||||
std::string output;
|
std::string output;
|
||||||
if (!std::getline(std::cin, output)) {
|
if(!std::getline(std::cin, output)) {
|
||||||
if (eof) *eof = true;
|
if(eof) *eof = true;
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@ -48,10 +45,10 @@ std::string pkpy_platform_getline(bool* eof) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int f_input(pkpy_vm* vm) {
|
static int f_input(pkpy_vm* vm) {
|
||||||
if (!pkpy_is_none(vm, -1)) {
|
if(!pkpy_is_none(vm, -1)) {
|
||||||
pkpy_CString prompt;
|
pkpy_CString prompt;
|
||||||
bool ok = pkpy_to_string(vm, -1, &prompt);
|
bool ok = pkpy_to_string(vm, -1, &prompt);
|
||||||
if (!ok) return 0;
|
if(!ok) return 0;
|
||||||
std::cout << prompt << std::flush;
|
std::cout << prompt << std::flush;
|
||||||
}
|
}
|
||||||
bool eof;
|
bool eof;
|
||||||
@ -71,44 +68,42 @@ int main(int argc, char** argv) {
|
|||||||
pkpy_py_import(vm, "builtins");
|
pkpy_py_import(vm, "builtins");
|
||||||
pkpy_setattr(vm, pkpy_name("input"));
|
pkpy_setattr(vm, pkpy_name("input"));
|
||||||
|
|
||||||
if (argc == 1) {
|
if(argc == 1) {
|
||||||
void* repl = pkpy_new_repl(vm);
|
void* repl = pkpy_new_repl(vm);
|
||||||
bool need_more_lines = false;
|
bool need_more_lines = false;
|
||||||
while (true) {
|
while(true) {
|
||||||
std::cout << (need_more_lines ? "... " : ">>> ");
|
std::cout << (need_more_lines ? "... " : ">>> ");
|
||||||
bool eof = false;
|
bool eof = false;
|
||||||
std::string line = pkpy_platform_getline(&eof);
|
std::string line = pkpy_platform_getline(&eof);
|
||||||
if (eof) break;
|
if(eof) break;
|
||||||
need_more_lines = pkpy_repl_input(repl, line.c_str());
|
need_more_lines = pkpy_repl_input(repl, line.c_str());
|
||||||
}
|
}
|
||||||
pkpy_delete_vm(vm);
|
pkpy_delete_vm(vm);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc == 2) {
|
if(argc == 2) {
|
||||||
std::string argv_1 = argv[1];
|
std::string argv_1 = argv[1];
|
||||||
if (argv_1 == "-h" || argv_1 == "--help") goto __HELP;
|
if(argv_1 == "-h" || argv_1 == "--help") goto __HELP;
|
||||||
|
|
||||||
std::filesystem::path filepath(argv[1]);
|
std::filesystem::path filepath(argv[1]);
|
||||||
filepath = std::filesystem::absolute(filepath);
|
filepath = std::filesystem::absolute(filepath);
|
||||||
if (!std::filesystem::exists(filepath)) {
|
if(!std::filesystem::exists(filepath)) {
|
||||||
std::cerr << "File not found: " << argv_1 << std::endl;
|
std::cerr << "File not found: " << argv_1 << std::endl;
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
std::ifstream file(filepath);
|
std::ifstream file(filepath);
|
||||||
if (!file.is_open()) {
|
if(!file.is_open()) {
|
||||||
std::cerr << "Failed to open file: " << argv_1 << std::endl;
|
std::cerr << "Failed to open file: " << argv_1 << std::endl;
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
std::string src((std::istreambuf_iterator<char>(file)),
|
std::string src((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||||
std::istreambuf_iterator<char>());
|
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
pkpy_set_main_argv(vm, argc, argv);
|
pkpy_set_main_argv(vm, argc, argv);
|
||||||
|
|
||||||
bool ok = pkpy_exec_2(vm, src.c_str(),
|
bool ok = pkpy_exec_2(vm, src.c_str(), filepath.filename().string().c_str(), 0, NULL);
|
||||||
filepath.filename().string().c_str(), 0, NULL);
|
if(!ok) pkpy_clear_error(vm, NULL);
|
||||||
if (!ok) pkpy_clear_error(vm, NULL);
|
|
||||||
pkpy_delete_vm(vm);
|
pkpy_delete_vm(vm);
|
||||||
return ok ? 0 : 1;
|
return ok ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user