mirror of
https://github.com/pocketpy/pocketpy
synced 2026-06-10 02:53:37 +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
|
||||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
UseTab: Never
|
||||
# clang-format configuration
|
||||
# compatible with clang-format 18
|
||||
|
||||
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 {
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_any_sso_v = is_pod_v<T> && sizeof(T) <= sizeof(void*);
|
||||
template <typename T>
|
||||
constexpr inline bool is_any_sso_v = is_pod_v<T> && sizeof(T) <= sizeof(void*);
|
||||
|
||||
struct any{
|
||||
struct vtable{
|
||||
struct any {
|
||||
struct vtable {
|
||||
const std::type_index type;
|
||||
void (*deleter)(void*);
|
||||
|
||||
template<typename T>
|
||||
inline static vtable* get(){
|
||||
template <typename T>
|
||||
inline static vtable* get() {
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
if constexpr (is_any_sso_v<T>){
|
||||
static vtable vt{ typeid(T), nullptr };
|
||||
if constexpr(is_any_sso_v<T>) {
|
||||
static vtable vt{typeid(T), nullptr};
|
||||
return &vt;
|
||||
}else{
|
||||
static vtable vt{ typeid(T), [](void* ptr){ delete static_cast<T*>(ptr); } };
|
||||
} else {
|
||||
static vtable vt{typeid(T), [](void* ptr) {
|
||||
delete static_cast<T*>(ptr);
|
||||
}};
|
||||
return &vt;
|
||||
}
|
||||
}
|
||||
@ -36,45 +38,45 @@ struct any{
|
||||
|
||||
any() : data(nullptr), _vt(nullptr) {}
|
||||
|
||||
explicit operator bool() const { return _vt != nullptr; }
|
||||
explicit operator bool () const { return _vt != nullptr; }
|
||||
|
||||
template<typename T>
|
||||
any(T&& value){
|
||||
template <typename T>
|
||||
any(T&& value) {
|
||||
using U = std::decay_t<T>;
|
||||
static_assert(!std::is_same_v<U, any>, "any(const any&) is deleted");
|
||||
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));
|
||||
}else{
|
||||
} else {
|
||||
data = new U(std::forward<T>(value));
|
||||
}
|
||||
_vt = vtable::get<U>();
|
||||
}
|
||||
|
||||
any(any&& other) noexcept;
|
||||
any& operator=(any&& other) noexcept;
|
||||
any& operator= (any&& other) noexcept;
|
||||
|
||||
const std::type_index type_id() const{
|
||||
return _vt ? _vt->type : typeid(void);
|
||||
}
|
||||
const std::type_index type_id() const { return _vt ? _vt->type : typeid(void); }
|
||||
|
||||
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>
|
||||
T& _cast() const noexcept{
|
||||
template <typename T>
|
||||
T& _cast() const noexcept {
|
||||
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));
|
||||
}else{
|
||||
} else {
|
||||
return *(static_cast<T*>(data));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& cast() const{
|
||||
template <typename T>
|
||||
T& cast() const {
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
if(type_id() != typeid(T)) __bad_any_cast(typeid(T), type_id());
|
||||
return _cast<T>();
|
||||
@ -83,26 +85,26 @@ struct any{
|
||||
static void __bad_any_cast(const std::type_index expected, const std::type_index actual);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
struct function;
|
||||
|
||||
template<typename Ret, typename... Params>
|
||||
struct function<Ret(Params...)>{
|
||||
template <typename Ret, typename... Params>
|
||||
struct function<Ret(Params...)> {
|
||||
any _impl;
|
||||
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>
|
||||
function(F&& f) : _impl(std::forward<F>(f)){
|
||||
_wrapper = [](const any& impl, Params... params) -> Ret{
|
||||
template <typename F>
|
||||
function(F&& f) : _impl(std::forward<F>(f)) {
|
||||
_wrapper = [](const any& impl, Params... params) -> Ret {
|
||||
return impl._cast<std::decay_t<F>>()(std::forward<Params>(params)...);
|
||||
};
|
||||
}
|
||||
|
||||
Ret operator()(Params... params) const{
|
||||
Ret operator() (Params... params) const {
|
||||
assert(_wrapper);
|
||||
return _wrapper(_impl, std::forward<Params>(params)...);
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
/*************** feature settings ***************/
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
||||
//define something for Windows (32-bit and 64-bit, this part is common)
|
||||
|
||||
@ -6,9 +6,12 @@
|
||||
|
||||
struct GIL {
|
||||
inline static std::mutex _mutex;
|
||||
|
||||
explicit GIL() { _mutex.lock(); }
|
||||
|
||||
~GIL() { _mutex.unlock(); }
|
||||
};
|
||||
|
||||
#define PK_GLOBAL_SCOPE_LOCK() GIL _lock;
|
||||
|
||||
#else
|
||||
|
||||
@ -6,10 +6,10 @@
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
inline const int kPoolExprBlockSize = 128;
|
||||
inline const int kPoolFrameBlockSize = 80;
|
||||
const inline int kPoolExprBlockSize = 128;
|
||||
const inline int kPoolFrameBlockSize = 80;
|
||||
|
||||
void* PoolExpr_alloc() noexcept;
|
||||
void PoolExpr_dealloc(void*) noexcept;
|
||||
|
||||
@ -6,20 +6,22 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
template<typename T>
|
||||
constexpr T default_invalid_value(){
|
||||
if constexpr(std::is_same_v<int, T>) return -1;
|
||||
else return nullptr;
|
||||
template <typename T>
|
||||
constexpr T default_invalid_value() {
|
||||
if constexpr(std::is_same_v<int, T>)
|
||||
return -1;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
struct NameDictImpl {
|
||||
PK_ALWAYS_PASS_BY_POINTER(NameDictImpl)
|
||||
|
||||
using Item = std::pair<StrName, T>;
|
||||
static constexpr uint16_t kInitialCapacity = 16;
|
||||
constexpr static uint16_t kInitialCapacity = 16;
|
||||
static_assert(is_pod_v<T>);
|
||||
|
||||
float _load_factor;
|
||||
@ -32,25 +34,29 @@ struct NameDictImpl {
|
||||
Item* _items;
|
||||
|
||||
#define HASH_PROBE_1(key, ok, i) \
|
||||
ok = false; \
|
||||
i = key.index & _mask; \
|
||||
while(!_items[i].first.empty()) { \
|
||||
if(_items[i].first == (key)) { ok = true; break; } \
|
||||
ok = false; \
|
||||
i = key.index & _mask; \
|
||||
while(!_items[i].first.empty()) { \
|
||||
if(_items[i].first == (key)) { \
|
||||
ok = true; \
|
||||
break; \
|
||||
} \
|
||||
i = (i + 1) & _mask; \
|
||||
}
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
~NameDictImpl(){ std::free(_items); }
|
||||
~NameDictImpl() { std::free(_items); }
|
||||
|
||||
uint16_t size() const { return _size; }
|
||||
|
||||
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;
|
||||
_critical_size = val * _load_factor;
|
||||
_mask = val - 1;
|
||||
@ -59,12 +65,13 @@ while(!_items[i].first.empty()) { \
|
||||
std::memset(_items, 0, _capacity * sizeof(Item));
|
||||
}
|
||||
|
||||
void set(StrName key, T val){
|
||||
bool ok; uint16_t i;
|
||||
void set(StrName key, T val) {
|
||||
bool ok;
|
||||
uint16_t i;
|
||||
HASH_PROBE_1(key, ok, i);
|
||||
if(!ok) {
|
||||
_size++;
|
||||
if(_size > _critical_size){
|
||||
if(_size > _critical_size) {
|
||||
_rehash_2x();
|
||||
HASH_PROBE_1(key, ok, i);
|
||||
}
|
||||
@ -73,13 +80,14 @@ while(!_items[i].first.empty()) { \
|
||||
_items[i].second = val;
|
||||
}
|
||||
|
||||
void _rehash_2x(){
|
||||
void _rehash_2x() {
|
||||
Item* old_items = _items;
|
||||
uint16_t old_capacity = _capacity;
|
||||
_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;
|
||||
bool ok; uint16_t j;
|
||||
bool ok;
|
||||
uint16_t j;
|
||||
HASH_PROBE_1(old_items[i].first, ok, j);
|
||||
assert(!ok);
|
||||
_items[j] = old_items[i];
|
||||
@ -87,21 +95,23 @@ while(!_items[i].first.empty()) { \
|
||||
std::free(old_items);
|
||||
}
|
||||
|
||||
T try_get(StrName key) const{
|
||||
bool ok; uint16_t i;
|
||||
T try_get(StrName key) const {
|
||||
bool ok;
|
||||
uint16_t i;
|
||||
HASH_PROBE_0(key, ok, i);
|
||||
if(!ok) return default_invalid_value<T>();
|
||||
return _items[i].second;
|
||||
}
|
||||
|
||||
T* try_get_2(StrName key) const{
|
||||
bool ok; uint16_t i;
|
||||
T* try_get_2(StrName key) const {
|
||||
bool ok;
|
||||
uint16_t i;
|
||||
HASH_PROBE_0(key, ok, i);
|
||||
if(!ok) return nullptr;
|
||||
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;
|
||||
if(_items[i].first == key) return _items[i].second;
|
||||
i = (i + 1) & _mask;
|
||||
@ -109,7 +119,7 @@ while(!_items[i].first.empty()) { \
|
||||
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;
|
||||
if(_items[i].first == key) return &_items[i].second;
|
||||
i = (i + 1) & _mask;
|
||||
@ -117,8 +127,9 @@ while(!_items[i].first.empty()) { \
|
||||
return try_get_2(key);
|
||||
}
|
||||
|
||||
bool del(StrName key){
|
||||
bool ok; uint16_t i;
|
||||
bool del(StrName key) {
|
||||
bool ok;
|
||||
uint16_t i;
|
||||
HASH_PROBE_0(key, ok, i);
|
||||
if(!ok) return false;
|
||||
_items[i].first = StrName();
|
||||
@ -127,7 +138,7 @@ while(!_items[i].first.empty()) { \
|
||||
// tidy
|
||||
uint16_t pre_z = i;
|
||||
uint16_t z = (i + 1) & _mask;
|
||||
while(!_items[z].first.empty()){
|
||||
while(!_items[z].first.empty()) {
|
||||
uint16_t h = _items[z].first.index & _mask;
|
||||
if(h != i) break;
|
||||
std::swap(_items[pre_z], _items[z]);
|
||||
@ -137,54 +148,54 @@ while(!_items[i].first.empty()) { \
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename __Func>
|
||||
template <typename __Func>
|
||||
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;
|
||||
func(_items[i].first, _items[i].second);
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(StrName key) const {
|
||||
bool ok; uint16_t i;
|
||||
bool ok;
|
||||
uint16_t i;
|
||||
HASH_PROBE_0(key, ok, i);
|
||||
return ok;
|
||||
}
|
||||
|
||||
T operator[](StrName key) const {
|
||||
T operator[] (StrName key) const {
|
||||
T* val = try_get_2_likely_found(key);
|
||||
if(val == nullptr){
|
||||
throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str());
|
||||
}
|
||||
if(val == nullptr) { throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str()); }
|
||||
return *val;
|
||||
}
|
||||
|
||||
array<StrName> keys() const {
|
||||
array<StrName> v(_size);
|
||||
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;
|
||||
new (&v[j++]) StrName(_items[i].first);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
array<Item> items() const{
|
||||
array<Item> items() const {
|
||||
array<Item> v(_size);
|
||||
int j = 0;
|
||||
apply([&](StrName key, T val){
|
||||
new(&v[j++]) Item(key, val);
|
||||
apply([&](StrName key, T val) {
|
||||
new (&v[j++]) Item(key, val);
|
||||
});
|
||||
return v;
|
||||
}
|
||||
|
||||
void clear(){
|
||||
for(uint16_t i=0; i<_capacity; i++){
|
||||
void clear() {
|
||||
for(uint16_t i = 0; i < _capacity; i++) {
|
||||
_items[i].first = StrName();
|
||||
_items[i].second = nullptr;
|
||||
}
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
#undef HASH_PROBE_0
|
||||
#undef HASH_PROBE_1
|
||||
};
|
||||
|
||||
@ -9,10 +9,10 @@
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
int utf8len(unsigned char c, bool suppress=false);
|
||||
int utf8len(unsigned char c, bool suppress = false);
|
||||
struct SStream;
|
||||
|
||||
struct Str{
|
||||
struct Str {
|
||||
int size;
|
||||
bool is_ascii;
|
||||
char* data;
|
||||
@ -26,60 +26,70 @@ struct Str{
|
||||
Str(std::string_view s);
|
||||
Str(const char* s);
|
||||
Str(const char* s, int len);
|
||||
Str(std::pair<char *, int>);
|
||||
Str(std::pair<char*, int>);
|
||||
Str(const 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* 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; }
|
||||
|
||||
bool empty() const { return size == 0; }
|
||||
size_t hash() const{ return std::hash<std::string_view>()(sv()); }
|
||||
|
||||
Str& operator=(const Str&);
|
||||
Str operator+(const Str&) const;
|
||||
Str operator+(const char*) const;
|
||||
friend Str operator+(const char*, const Str&);
|
||||
size_t hash() const { return std::hash<std::string_view>()(sv()); }
|
||||
|
||||
bool operator==(const std::string_view other) 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);
|
||||
Str& operator= (const Str&);
|
||||
Str operator+ (const Str&) const;
|
||||
Str operator+ (const char*) const;
|
||||
friend Str operator+ (const char*, const Str&);
|
||||
|
||||
bool operator==(const char* p) const;
|
||||
bool operator!=(const char* p) const;
|
||||
bool operator== (const std::string_view other) 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 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 char* p) 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;
|
||||
|
||||
~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; }
|
||||
|
||||
std::string_view sv() const { return std::string_view(data, size); }
|
||||
|
||||
std::string str() const { return std::string(data, size); }
|
||||
|
||||
Str substr(int start, int len) const;
|
||||
Str substr(int start) 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 rstrip() const { return strip(false, true); }
|
||||
|
||||
Str lower() const;
|
||||
Str upper() const;
|
||||
Str escape(bool single_quote=true) const;
|
||||
void escape_(SStream& ss, bool single_quote=true) const;
|
||||
int index(const Str& sub, int start=0) const;
|
||||
Str escape(bool single_quote = true) const;
|
||||
void escape_(SStream& ss, bool single_quote = true) const;
|
||||
int index(const Str& sub, int start = 0) 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(char sep) const;
|
||||
int count(const Str& sub) const;
|
||||
@ -95,32 +105,29 @@ struct Str{
|
||||
struct StrName {
|
||||
uint16_t index;
|
||||
|
||||
StrName(): index(0) {}
|
||||
explicit StrName(uint16_t index): index(index) {}
|
||||
StrName(const char* s): index(get(s).index) {}
|
||||
StrName(const Str& s): index(get(s.sv()).index) {}
|
||||
StrName() : index(0) {}
|
||||
|
||||
explicit StrName(uint16_t index) : index(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(); }
|
||||
|
||||
bool empty() const { return index == 0; }
|
||||
|
||||
Str escape() const { return Str(sv()).escape(); }
|
||||
|
||||
bool operator==(const StrName& other) const noexcept {
|
||||
return this->index == other.index;
|
||||
}
|
||||
bool operator== (const StrName& other) const noexcept { return this->index == other.index; }
|
||||
|
||||
bool operator!=(const StrName& other) const noexcept {
|
||||
return this->index != other.index;
|
||||
}
|
||||
bool operator!= (const StrName& other) const noexcept { return this->index != other.index; }
|
||||
|
||||
bool operator<(const StrName& other) const noexcept {
|
||||
return sv() < other.sv();
|
||||
}
|
||||
bool operator< (const StrName& other) const noexcept { return sv() < other.sv(); }
|
||||
|
||||
bool operator>(const StrName& other) const noexcept {
|
||||
return sv() > other.sv();
|
||||
}
|
||||
bool operator> (const StrName& other) const noexcept { return sv() > other.sv(); }
|
||||
|
||||
static StrName get(std::string_view s);
|
||||
static std::map<std::string_view, uint16_t>& _interned();
|
||||
@ -128,32 +135,34 @@ struct StrName {
|
||||
static uint32_t _pesudo_random_index;
|
||||
};
|
||||
|
||||
struct SStream{
|
||||
struct SStream {
|
||||
PK_ALWAYS_PASS_BY_POINTER(SStream)
|
||||
|
||||
vector<char> buffer;
|
||||
int _precision = -1;
|
||||
|
||||
bool empty() const { return buffer.empty(); }
|
||||
|
||||
void setprecision(int precision) { _precision = precision; }
|
||||
|
||||
SStream() {}
|
||||
SStream(int guess_size) { buffer.reserve(guess_size);}
|
||||
|
||||
SStream(int guess_size) { buffer.reserve(guess_size); }
|
||||
|
||||
Str str();
|
||||
|
||||
SStream& operator<<(const Str&);
|
||||
SStream& operator<<(const char*);
|
||||
SStream& operator<<(int);
|
||||
SStream& operator<<(size_t);
|
||||
SStream& operator<<(i64);
|
||||
SStream& operator<<(f64);
|
||||
SStream& operator<<(const std::string&);
|
||||
SStream& operator<<(std::string_view);
|
||||
SStream& operator<<(char);
|
||||
SStream& operator<<(StrName);
|
||||
SStream& operator<< (const Str&);
|
||||
SStream& operator<< (const char*);
|
||||
SStream& operator<< (int);
|
||||
SStream& operator<< (size_t);
|
||||
SStream& operator<< (i64);
|
||||
SStream& operator<< (f64);
|
||||
SStream& operator<< (const std::string&);
|
||||
SStream& operator<< (std::string_view);
|
||||
SStream& operator<< (char);
|
||||
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(i64);
|
||||
};
|
||||
@ -162,17 +171,19 @@ struct SStream{
|
||||
#undef _S
|
||||
#endif
|
||||
|
||||
template<typename... Args>
|
||||
template <typename... Args>
|
||||
Str _S(Args&&... args) {
|
||||
SStream ss;
|
||||
(ss << ... << args);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
struct CString{
|
||||
struct CString {
|
||||
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
|
||||
|
||||
@ -2,35 +2,39 @@
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
// is_pod_v<> for c++17 and c++20
|
||||
template<typename T>
|
||||
inline constexpr bool is_pod_v = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;
|
||||
template <typename 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
|
||||
template<typename T>
|
||||
inline constexpr bool is_integral_v = !std::is_same_v<T, bool> && std::is_integral_v<T>;
|
||||
template <typename T>
|
||||
constexpr inline bool is_integral_v = !std::is_same_v<T, bool> && std::is_integral_v<T>;
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_floating_point_v = std::is_same_v<T, float> || std::is_same_v<T, double>;
|
||||
template <typename T>
|
||||
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
|
||||
// users can specialize this template to enable SSO for other types
|
||||
// SSO types cannot have instance dict
|
||||
template<typename T>
|
||||
inline constexpr bool is_sso_v = is_integral_v<T> || is_floating_point_v<T>;
|
||||
template <typename 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&
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
using obj_get_t = std::conditional_t<is_sso_v<T>, T, T&>;
|
||||
|
||||
template<typename T>
|
||||
constexpr inline bool is_trivially_relocatable_v = std::is_trivially_copyable_v<T> && std::is_trivially_destructible_v<T>;
|
||||
template <typename 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 T> struct has_gc_marker<T, std::void_t<decltype(&T::_gc_mark)>> : std::true_type {};
|
||||
template <typename, typename = void>
|
||||
struct has_gc_marker : std::false_type {};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr int py_sizeof = 16 + sizeof(T);
|
||||
template <typename T>
|
||||
struct has_gc_marker<T, std::void_t<decltype(&T::_gc_mark)>> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
constexpr inline int py_sizeof = 16 + sizeof(T);
|
||||
} // namespace pkpy
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
using i64 = int64_t; // always 64-bit
|
||||
using f64 = double; // always 64-bit
|
||||
@ -16,9 +16,11 @@ struct explicit_copy_t {
|
||||
};
|
||||
|
||||
// Dummy types
|
||||
struct DummyInstance { };
|
||||
struct DummyModule { };
|
||||
struct NoReturn { };
|
||||
struct DummyInstance {};
|
||||
|
||||
struct DummyModule {};
|
||||
|
||||
struct NoReturn {};
|
||||
|
||||
// Forward declarations
|
||||
struct PyObject;
|
||||
|
||||
@ -4,18 +4,18 @@
|
||||
|
||||
#define PK_ALWAYS_PASS_BY_POINTER(T) \
|
||||
T(const T&) = delete; \
|
||||
T& operator=(const T&) = delete; \
|
||||
T& operator= (const 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
|
||||
inline const char* PK_HEX_TABLE = "0123456789abcdef";
|
||||
const inline char* PK_HEX_TABLE = "0123456789abcdef";
|
||||
|
||||
inline const char* kPlatformStrings[] = {
|
||||
const inline char* kPlatformStrings[] = {
|
||||
"win32", // 0
|
||||
"emscripten", // 1
|
||||
"ios", // 2
|
||||
|
||||
@ -18,21 +18,27 @@ struct array {
|
||||
using size_type = int;
|
||||
|
||||
array() : _data(nullptr), _size(0) {}
|
||||
|
||||
array(int size) : _data((T*)std::malloc(sizeof(T) * size)), _size(size) {}
|
||||
|
||||
array(array&& other) noexcept : _data(other._data), _size(other._size) {
|
||||
other._data = nullptr;
|
||||
other._size = 0;
|
||||
}
|
||||
|
||||
array(const array& other) = delete;
|
||||
|
||||
array(explicit_copy_t, const array& other) {
|
||||
_data = (T*)std::malloc(sizeof(T) * 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& operator=(array&& other) noexcept {
|
||||
if (_data) {
|
||||
array& operator= (array&& other) noexcept {
|
||||
if(_data) {
|
||||
std::destroy(begin(), end());
|
||||
std::free(_data);
|
||||
}
|
||||
@ -43,14 +49,14 @@ struct array {
|
||||
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);
|
||||
return _data[i];
|
||||
}
|
||||
|
||||
const T& operator[](int i) const {
|
||||
const T& operator[] (int i) const {
|
||||
assert(i >= 0 && i < _size);
|
||||
return _data[i];
|
||||
}
|
||||
@ -58,7 +64,9 @@ struct array {
|
||||
int size() const { return _size; }
|
||||
|
||||
T* begin() const { return _data; }
|
||||
|
||||
T* end() const { return _data + _size; }
|
||||
|
||||
T* data() const { return _data; }
|
||||
|
||||
std::pair<T*, int> detach() noexcept {
|
||||
@ -69,7 +77,7 @@ struct array {
|
||||
}
|
||||
|
||||
~array() {
|
||||
if (_data) {
|
||||
if(_data) {
|
||||
std::destroy(begin(), end());
|
||||
std::free(_data);
|
||||
}
|
||||
@ -85,58 +93,63 @@ struct vector {
|
||||
using size_type = int;
|
||||
|
||||
vector() : _data(nullptr), _capacity(0), _size(0) {}
|
||||
vector(int size)
|
||||
: _data((T*)std::malloc(sizeof(T) * size)),
|
||||
_capacity(size),
|
||||
_size(size) {}
|
||||
vector(vector&& other) noexcept
|
||||
: _data(other._data), _capacity(other._capacity), _size(other._size) {
|
||||
|
||||
vector(int size) : _data((T*)std::malloc(sizeof(T) * size)), _capacity(size), _size(size) {}
|
||||
|
||||
vector(vector&& other) noexcept : _data(other._data), _capacity(other._capacity), _size(other._size) {
|
||||
other._data = nullptr;
|
||||
other._capacity = 0;
|
||||
other._size = 0;
|
||||
}
|
||||
|
||||
vector(const vector& other) = delete;
|
||||
vector(explicit_copy_t, const vector& other)
|
||||
: _data((T*)std::malloc(sizeof(T) * other._size)),
|
||||
_capacity(other._size),
|
||||
_size(other._size) {
|
||||
for (int i = 0; i < _size; i++) _data[i] = other._data[i];
|
||||
|
||||
vector(explicit_copy_t, const vector& other) :
|
||||
_data((T*)std::malloc(sizeof(T) * other._size)), _capacity(other._size), _size(other._size) {
|
||||
for(int i = 0; i < _size; i++)
|
||||
_data[i] = other._data[i];
|
||||
}
|
||||
|
||||
// allow move
|
||||
vector& operator=(vector&& other) noexcept {
|
||||
if (_data) {
|
||||
vector& operator= (vector&& other) noexcept {
|
||||
if(_data) {
|
||||
std::destroy(begin(), end());
|
||||
std::free(_data);
|
||||
}
|
||||
new (this) vector(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// disallow copy
|
||||
vector& operator=(const vector& other) = delete;
|
||||
vector& operator= (const vector& other) = delete;
|
||||
|
||||
bool empty() const { return _size == 0; }
|
||||
|
||||
int size() const { return _size; }
|
||||
|
||||
int capacity() const { return _capacity; }
|
||||
|
||||
T& back() { return _data[_size - 1]; }
|
||||
|
||||
T* begin() const { return _data; }
|
||||
|
||||
T* end() const { return _data + _size; }
|
||||
|
||||
T* data() const { return _data; }
|
||||
|
||||
void reserve(int cap) {
|
||||
if (cap < 4) cap = 4; // minimum capacity
|
||||
if (cap <= capacity()) return;
|
||||
if(cap < 4) cap = 4; // minimum capacity
|
||||
if(cap <= capacity()) return;
|
||||
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);
|
||||
} else {
|
||||
for (int i = 0; i < _size; i++) {
|
||||
for(int i = 0; i < _size; i++) {
|
||||
new (&new_data[i]) T(std::move(_data[i]));
|
||||
_data[i].~T();
|
||||
}
|
||||
}
|
||||
if (_data) std::free(_data);
|
||||
if(_data) std::free(_data);
|
||||
_data = new_data;
|
||||
_capacity = cap;
|
||||
}
|
||||
@ -147,46 +160,49 @@ struct vector {
|
||||
}
|
||||
|
||||
void push_back(const T& t) {
|
||||
if (_size == _capacity) reserve(_capacity * 2);
|
||||
if(_size == _capacity) reserve(_capacity * 2);
|
||||
new (&_data[_size++]) 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));
|
||||
}
|
||||
|
||||
bool contains(const T& t) const {
|
||||
for (int i = 0; i < _size; i++) {
|
||||
if (_data[i] == t) return true;
|
||||
for(int i = 0; i < _size; i++) {
|
||||
if(_data[i] == t) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename... 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)...);
|
||||
}
|
||||
|
||||
T& operator[](int i) { return _data[i]; }
|
||||
const T& operator[](int i) const { return _data[i]; }
|
||||
T& operator[] (int i) { return _data[i]; }
|
||||
|
||||
const T& operator[] (int i) const { return _data[i]; }
|
||||
|
||||
void extend(T* begin, T* end) {
|
||||
int n = end - begin;
|
||||
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) {
|
||||
if (_size == _capacity) reserve(_capacity * 2);
|
||||
for (int i = _size; i > index; i--) _data[i] = std::move(_data[i - 1]);
|
||||
if(_size == _capacity) reserve(_capacity * 2);
|
||||
for(int i = _size; i > index; i--)
|
||||
_data[i] = std::move(_data[i - 1]);
|
||||
_data[index] = t;
|
||||
_size++;
|
||||
}
|
||||
|
||||
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]);
|
||||
_size--;
|
||||
}
|
||||
@ -194,9 +210,7 @@ struct vector {
|
||||
void pop_back() {
|
||||
assert(_size > 0);
|
||||
_size--;
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
_data[_size].~T();
|
||||
}
|
||||
if constexpr(!std::is_trivially_destructible_v<T>) { _data[_size].~T(); }
|
||||
}
|
||||
|
||||
void clear() {
|
||||
@ -219,7 +233,7 @@ struct vector {
|
||||
}
|
||||
|
||||
~vector() {
|
||||
if (_data) {
|
||||
if(_data) {
|
||||
std::destroy(begin(), end());
|
||||
std::free(_data);
|
||||
}
|
||||
@ -230,37 +244,49 @@ template <typename T, typename Container = vector<T>>
|
||||
class stack {
|
||||
Container vec;
|
||||
|
||||
public:
|
||||
public:
|
||||
void push(const T& t) { vec.push_back(t); }
|
||||
|
||||
void push(T&& t) { vec.push_back(std::move(t)); }
|
||||
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... args) {
|
||||
vec.emplace_back(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void pop() { vec.pop_back(); }
|
||||
|
||||
void clear() { vec.clear(); }
|
||||
|
||||
bool empty() const { return vec.empty(); }
|
||||
|
||||
typename Container::size_type size() const { return vec.size(); }
|
||||
|
||||
T& top() { return vec.back(); }
|
||||
|
||||
const T& top() const { return vec.back(); }
|
||||
|
||||
T popx() {
|
||||
T t = std::move(vec.back());
|
||||
vec.pop_back();
|
||||
return t;
|
||||
}
|
||||
|
||||
void reserve(int n) { vec.reserve(n); }
|
||||
|
||||
Container& container() { return vec; }
|
||||
|
||||
const Container& container() const { return vec; }
|
||||
};
|
||||
|
||||
template <typename T, typename Container = vector<T>>
|
||||
class stack_no_copy : public stack<T, Container> {
|
||||
public:
|
||||
public:
|
||||
stack_no_copy() = default;
|
||||
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& operator=(stack_no_copy&& other) noexcept = default;
|
||||
stack_no_copy& operator= (stack_no_copy&& other) noexcept = default;
|
||||
};
|
||||
|
||||
} // namespace pkpy
|
||||
@ -273,7 +299,7 @@ class small_vector {
|
||||
T* m_end;
|
||||
T* m_max;
|
||||
|
||||
public:
|
||||
public:
|
||||
using value_type = T;
|
||||
using size_type = int;
|
||||
using difference_type = int;
|
||||
@ -286,74 +312,82 @@ class small_vector {
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
[[nodiscard]] bool is_small() const {
|
||||
return m_begin == reinterpret_cast<const T*>(m_buffer);
|
||||
}
|
||||
[[nodiscard]] bool is_small() const { return m_begin == reinterpret_cast<const T*>(m_buffer); }
|
||||
|
||||
[[nodiscard]] size_type size() const { return m_end - m_begin; }
|
||||
|
||||
[[nodiscard]] size_type capacity() const { return m_max - m_begin; }
|
||||
|
||||
[[nodiscard]] bool empty() const { return m_begin == m_end; }
|
||||
|
||||
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) {
|
||||
if constexpr (std::is_trivially_copyable_v<T>) {
|
||||
if constexpr(std::is_trivially_copyable_v<T>) {
|
||||
std::memcpy(dest, src, sizeof(T) * n);
|
||||
} 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
} 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)));
|
||||
((T*)src + i)->~T();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
small_vector()
|
||||
: m_begin(reinterpret_cast<T*>(m_buffer)),
|
||||
m_end(m_begin),
|
||||
m_max(m_begin + N) {}
|
||||
public:
|
||||
small_vector() : m_begin(reinterpret_cast<T*>(m_buffer)), m_end(m_begin), m_max(m_begin + N) {}
|
||||
|
||||
small_vector(const small_vector& other) noexcept {
|
||||
const auto size = other.size();
|
||||
const auto capacity = other.capacity();
|
||||
m_begin = reinterpret_cast<T*>(
|
||||
other.is_small() ? m_buffer : std::malloc(sizeof(T) * capacity));
|
||||
m_begin = reinterpret_cast<T*>(other.is_small() ? m_buffer : std::malloc(sizeof(T) * capacity));
|
||||
uninitialized_copy_n(other.m_begin, size, this->m_begin);
|
||||
m_end = m_begin + size;
|
||||
m_max = m_begin + capacity;
|
||||
}
|
||||
|
||||
small_vector(small_vector&& other) noexcept {
|
||||
if (other.is_small()) {
|
||||
if(other.is_small()) {
|
||||
m_begin = reinterpret_cast<T*>(m_buffer);
|
||||
uninitialized_relocate_n(other.m_buffer, other.size(), m_buffer);
|
||||
m_end = m_begin + other.size();
|
||||
@ -368,16 +402,16 @@ class small_vector {
|
||||
other.m_max = other.m_begin + N;
|
||||
}
|
||||
|
||||
small_vector& operator=(const small_vector& other) noexcept {
|
||||
if (this != &other) {
|
||||
small_vector& operator= (const small_vector& other) noexcept {
|
||||
if(this != &other) {
|
||||
~small_vector();
|
||||
::new (this) small_vector(other);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
small_vector& operator=(small_vector&& other) noexcept {
|
||||
if (this != &other) {
|
||||
small_vector& operator= (small_vector&& other) noexcept {
|
||||
if(this != &other) {
|
||||
~small_vector();
|
||||
::new (this) small_vector(std::move(other));
|
||||
}
|
||||
@ -386,21 +420,19 @@ class small_vector {
|
||||
|
||||
~small_vector() {
|
||||
std::destroy(m_begin, m_end);
|
||||
if (!is_small()) std::free(m_begin);
|
||||
if(!is_small()) std::free(m_begin);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void emplace_back(Args&&... args) noexcept {
|
||||
if (m_end == m_max) {
|
||||
if(m_end == m_max) {
|
||||
const auto new_capacity = capacity() * 2;
|
||||
const auto size = this->size();
|
||||
if (!is_small()) {
|
||||
if constexpr (is_trivially_relocatable_v<T>) {
|
||||
m_begin = (pointer)std::realloc(m_begin,
|
||||
sizeof(T) * new_capacity);
|
||||
if(!is_small()) {
|
||||
if constexpr(is_trivially_relocatable_v<T>) {
|
||||
m_begin = (pointer)std::realloc(m_begin, sizeof(T) * new_capacity);
|
||||
} else {
|
||||
auto new_data =
|
||||
(pointer)std::malloc(sizeof(T) * new_capacity);
|
||||
auto new_data = (pointer)std::malloc(sizeof(T) * new_capacity);
|
||||
uninitialized_relocate_n(m_begin, size, new_data);
|
||||
std::free(m_begin);
|
||||
m_begin = new_data;
|
||||
@ -418,13 +450,12 @@ class small_vector {
|
||||
}
|
||||
|
||||
void push_back(const T& value) { emplace_back(value); }
|
||||
|
||||
void push_back(T&& value) { emplace_back(std::move(value)); }
|
||||
|
||||
void pop_back() {
|
||||
m_end--;
|
||||
if constexpr (!std::is_trivially_destructible_v<T>) {
|
||||
m_end->~T();
|
||||
}
|
||||
if constexpr(!std::is_trivially_destructible_v<T>) { m_end->~T(); }
|
||||
}
|
||||
|
||||
void clear() {
|
||||
@ -435,11 +466,11 @@ class small_vector {
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
class small_vector_2 : public small_vector<T, N> {
|
||||
public:
|
||||
public:
|
||||
small_vector_2() = default;
|
||||
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& operator=(small_vector_2&& other) = delete;
|
||||
small_vector_2& operator= (small_vector_2&& other) = delete;
|
||||
};
|
||||
} // namespace pkpy
|
||||
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
// clang-format off
|
||||
|
||||
#define PK_VERSION "2.0.0"
|
||||
#define PK_VERSION_MAJOR 2
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
|
||||
#include "pocketpy/compiler/expr.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
class Compiler;
|
||||
typedef void (Compiler::*PrattCallback)();
|
||||
|
||||
struct PrattRule{
|
||||
struct PrattRule {
|
||||
PrattCallback prefix;
|
||||
PrattCallback infix;
|
||||
Precedence precedence;
|
||||
@ -26,17 +26,23 @@ class Compiler {
|
||||
int i = 0;
|
||||
vector<Token> tokens;
|
||||
|
||||
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& err() const{
|
||||
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& err() const {
|
||||
if(i >= tokens.size()) return prev();
|
||||
return curr();
|
||||
}
|
||||
void advance(int delta=1) { i += delta; }
|
||||
|
||||
void advance(int delta = 1) { i += delta; }
|
||||
|
||||
CodeEmitContext* ctx() { return &contexts.top(); }
|
||||
CompileMode mode() const{ return lexer.src->mode; }
|
||||
|
||||
CompileMode mode() const { return lexer.src->mode; }
|
||||
|
||||
NameScope name_scope() const;
|
||||
CodeObject_ push_global_context();
|
||||
FuncDecl_ push_f_context(Str name);
|
||||
@ -48,13 +54,13 @@ class Compiler {
|
||||
void consume(TokenIndex expected);
|
||||
bool match_newlines_repl();
|
||||
|
||||
bool match_newlines(bool repl_throw=false);
|
||||
bool match_newlines(bool repl_throw = false);
|
||||
bool match_end_stmt();
|
||||
void consume_end_stmt();
|
||||
|
||||
/*************************************************/
|
||||
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`
|
||||
|
||||
template <typename T, typename... Args>
|
||||
@ -91,11 +97,11 @@ class Compiler {
|
||||
void exprSubscr();
|
||||
void exprLiteral0();
|
||||
|
||||
void compile_block_body(void (Compiler::*callback)()=nullptr);
|
||||
void compile_block_body(void (Compiler::*callback)() = nullptr);
|
||||
void compile_normal_import();
|
||||
void compile_from_import();
|
||||
bool is_expression(bool allow_slice=false);
|
||||
void parse_expression(int precedence, bool allow_slice=false);
|
||||
bool is_expression(bool allow_slice = false);
|
||||
void parse_expression(int precedence, bool allow_slice = false);
|
||||
void compile_if_stmt();
|
||||
void compile_while_loop();
|
||||
void compile_for_loop();
|
||||
@ -106,31 +112,41 @@ class Compiler {
|
||||
void compile_stmt();
|
||||
void consume_type_hints();
|
||||
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_function(const Expr_vector& decorators={});
|
||||
void compile_function(const Expr_vector& decorators = {});
|
||||
|
||||
PyVar to_object(const TokenValue& value);
|
||||
PyVar read_literal();
|
||||
|
||||
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(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); }
|
||||
|
||||
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();
|
||||
void from_precompiled(const char* source);
|
||||
CodeObject_ compile();
|
||||
};
|
||||
|
||||
struct TokenDeserializer{
|
||||
struct TokenDeserializer {
|
||||
const char* curr;
|
||||
const char* 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; }
|
||||
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;
|
||||
}
|
||||
|
||||
std::string_view read_string(char c);
|
||||
Str read_string_from_hex(char c);
|
||||
|
||||
@ -3,43 +3,64 @@
|
||||
#include "pocketpy/objects/codeobject.hpp"
|
||||
#include "pocketpy/compiler/lexer.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
struct CodeEmitContext;
|
||||
struct Expr;
|
||||
|
||||
template<typename T>
|
||||
class unique_ptr_128{
|
||||
template <typename T>
|
||||
class unique_ptr_128 {
|
||||
T* ptr;
|
||||
|
||||
public:
|
||||
unique_ptr_128(): ptr(nullptr) {}
|
||||
unique_ptr_128(T* ptr): ptr(ptr) {}
|
||||
unique_ptr_128() : ptr(nullptr) {}
|
||||
|
||||
unique_ptr_128(T* ptr) : ptr(ptr) {}
|
||||
|
||||
T* operator->() 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& 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<U>&& other): ptr(other.detach()) {}
|
||||
~unique_ptr_128() {
|
||||
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>
|
||||
unique_ptr_128& operator=(unique_ptr_128<U>&& other) {
|
||||
if(ptr) { ptr->~T(); PoolExpr_dealloc(ptr); };
|
||||
operator bool () const { return ptr != nullptr; }
|
||||
|
||||
template <typename U>
|
||||
unique_ptr_128& operator= (unique_ptr_128<U>&& other) {
|
||||
if(ptr) {
|
||||
ptr->~T();
|
||||
PoolExpr_dealloc(ptr);
|
||||
};
|
||||
ptr = other.detach();
|
||||
return *this;
|
||||
}
|
||||
|
||||
unique_ptr_128& operator=(std::nullptr_t) {
|
||||
if(ptr) { ptr->~T(); PoolExpr_dealloc(ptr); }
|
||||
unique_ptr_128& operator= (std::nullptr_t) {
|
||||
if(ptr) {
|
||||
ptr->~T();
|
||||
PoolExpr_dealloc(ptr);
|
||||
}
|
||||
ptr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
@ -48,43 +69,44 @@ public:
|
||||
typedef unique_ptr_128<Expr> Expr_;
|
||||
typedef small_vector<Expr_, 4> Expr_vector;
|
||||
|
||||
template<>
|
||||
template <>
|
||||
constexpr inline bool is_trivially_relocatable_v<Expr_> = true;
|
||||
|
||||
struct Expr{
|
||||
struct Expr {
|
||||
int line = 0;
|
||||
virtual ~Expr() = default;
|
||||
virtual void emit_(CodeEmitContext* ctx) = 0;
|
||||
|
||||
virtual bool is_literal() const { return false; }
|
||||
|
||||
virtual bool is_json_object() const { return false; }
|
||||
|
||||
virtual bool is_attrib() const { return false; }
|
||||
|
||||
virtual bool is_subscr() const { return false; }
|
||||
|
||||
virtual bool is_compare() const { return false; }
|
||||
|
||||
virtual int star_level() const { return 0; }
|
||||
|
||||
virtual bool is_tuple() const { return false; }
|
||||
|
||||
virtual bool is_name() const { return false; }
|
||||
|
||||
bool is_starred() const { return star_level() > 0; }
|
||||
|
||||
// for OP_DELETE_XXX
|
||||
[[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) {
|
||||
return false;
|
||||
}
|
||||
[[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) { return false; }
|
||||
|
||||
// for OP_STORE_XXX
|
||||
[[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) {
|
||||
return false;
|
||||
}
|
||||
[[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) { return false; }
|
||||
|
||||
virtual void emit_inplace(CodeEmitContext* ctx) {
|
||||
emit_(ctx);
|
||||
}
|
||||
virtual void emit_inplace(CodeEmitContext* ctx) { emit_(ctx); }
|
||||
|
||||
[[nodiscard]] virtual bool emit_store_inplace(CodeEmitContext* ctx) {
|
||||
return emit_store(ctx);
|
||||
}
|
||||
[[nodiscard]] virtual bool emit_store_inplace(CodeEmitContext* ctx) { return emit_store(ctx); }
|
||||
};
|
||||
|
||||
struct CodeEmitContext{
|
||||
struct CodeEmitContext {
|
||||
VM* vm;
|
||||
FuncDecl_ func; // optional
|
||||
CodeObject_ co; // 1 CodeEmitContext <=> 1 CodeObject_
|
||||
@ -93,7 +115,8 @@ struct CodeEmitContext{
|
||||
stack_no_copy<Expr_> s_expr;
|
||||
int level;
|
||||
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;
|
||||
bool is_compiling_class = false;
|
||||
@ -105,7 +128,7 @@ struct CodeEmitContext{
|
||||
CodeBlock* enter_block(CodeBlockType type);
|
||||
void exit_block();
|
||||
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_();
|
||||
int emit_int(i64 value, int line);
|
||||
void patch_jump(int index);
|
||||
@ -118,150 +141,189 @@ struct CodeEmitContext{
|
||||
void try_merge_for_iter_store(int);
|
||||
};
|
||||
|
||||
struct NameExpr: Expr{
|
||||
struct NameExpr : Expr {
|
||||
StrName name;
|
||||
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;
|
||||
bool emit_del(CodeEmitContext* ctx) override;
|
||||
bool emit_store(CodeEmitContext* ctx) override;
|
||||
|
||||
bool is_name() const override { return true; }
|
||||
};
|
||||
|
||||
struct InvertExpr: Expr{
|
||||
struct InvertExpr : Expr {
|
||||
Expr_ child;
|
||||
InvertExpr(Expr_&& child): child(std::move(child)) {}
|
||||
|
||||
InvertExpr(Expr_&& child) : child(std::move(child)) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct StarredExpr: Expr{
|
||||
struct StarredExpr : Expr {
|
||||
int level;
|
||||
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; }
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
bool emit_store(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct NotExpr: Expr{
|
||||
struct NotExpr : Expr {
|
||||
Expr_ child;
|
||||
NotExpr(Expr_&& child): child(std::move(child)) {}
|
||||
|
||||
NotExpr(Expr_&& child) : child(std::move(child)) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct AndExpr: Expr{
|
||||
struct AndExpr : Expr {
|
||||
Expr_ lhs;
|
||||
Expr_ rhs;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct OrExpr: Expr{
|
||||
struct OrExpr : Expr {
|
||||
Expr_ lhs;
|
||||
Expr_ rhs;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
// [None, True, False, ...]
|
||||
struct Literal0Expr: Expr{
|
||||
struct Literal0Expr : Expr {
|
||||
TokenIndex token;
|
||||
Literal0Expr(TokenIndex token): token(token) {}
|
||||
|
||||
Literal0Expr(TokenIndex token) : token(token) {}
|
||||
|
||||
bool is_json_object() const override { return true; }
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct LongExpr: Expr{
|
||||
struct LongExpr : Expr {
|
||||
Str s;
|
||||
LongExpr(const Str& s): s(s) {}
|
||||
|
||||
LongExpr(const Str& s) : s(s) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct BytesExpr: Expr{
|
||||
struct BytesExpr : Expr {
|
||||
Str s;
|
||||
BytesExpr(const Str& s): s(s) {}
|
||||
|
||||
BytesExpr(const Str& s) : s(s) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct ImagExpr: Expr{
|
||||
struct ImagExpr : Expr {
|
||||
f64 value;
|
||||
ImagExpr(f64 value): value(value) {}
|
||||
|
||||
ImagExpr(f64 value) : value(value) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
// @num, @str which needs to invoke OP_LOAD_CONST
|
||||
struct LiteralExpr: Expr{
|
||||
struct LiteralExpr : Expr {
|
||||
TokenValue value;
|
||||
LiteralExpr(TokenValue value): value(value) {}
|
||||
|
||||
LiteralExpr(TokenValue value) : value(value) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
|
||||
bool is_literal() const override { return true; }
|
||||
|
||||
bool is_json_object() const override { return true; }
|
||||
};
|
||||
|
||||
struct NegatedExpr: Expr{
|
||||
struct NegatedExpr : Expr {
|
||||
Expr_ child;
|
||||
NegatedExpr(Expr_&& child): child(std::move(child)) {}
|
||||
|
||||
NegatedExpr(Expr_&& child) : child(std::move(child)) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
|
||||
bool is_json_object() const override { return child->is_literal(); }
|
||||
};
|
||||
|
||||
struct SliceExpr: Expr{
|
||||
struct SliceExpr : Expr {
|
||||
Expr_ start;
|
||||
Expr_ stop;
|
||||
Expr_ step;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct DictItemExpr: Expr{
|
||||
struct DictItemExpr : Expr {
|
||||
Expr_ key; // maybe nullptr if it is **kwargs
|
||||
Expr_ value;
|
||||
|
||||
int star_level() const override { return value->star_level(); }
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct SequenceExpr: Expr{
|
||||
struct SequenceExpr : Expr {
|
||||
Expr_vector items;
|
||||
SequenceExpr(Expr_vector&& items): items(std::move(items)) {}
|
||||
|
||||
SequenceExpr(Expr_vector&& items) : items(std::move(items)) {}
|
||||
|
||||
virtual Opcode opcode() const = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
struct ListExpr: SequenceExpr{
|
||||
struct ListExpr : SequenceExpr {
|
||||
using SequenceExpr::SequenceExpr;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool is_json_object() const override { return true; }
|
||||
};
|
||||
|
||||
struct DictExpr: SequenceExpr{
|
||||
struct DictExpr : SequenceExpr {
|
||||
using SequenceExpr::SequenceExpr;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool is_json_object() const override { return true; }
|
||||
};
|
||||
|
||||
struct SetExpr: SequenceExpr{
|
||||
struct SetExpr : SequenceExpr {
|
||||
using SequenceExpr::SequenceExpr;
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
struct TupleExpr: SequenceExpr{
|
||||
struct TupleExpr : SequenceExpr {
|
||||
using SequenceExpr::SequenceExpr;
|
||||
|
||||
bool is_tuple() const override { return true; }
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -269,7 +331,7 @@ struct TupleExpr: SequenceExpr{
|
||||
bool emit_del(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct CompExpr: Expr{
|
||||
struct CompExpr : Expr {
|
||||
Expr_ expr; // loop expr
|
||||
Expr_ vars; // loop vars
|
||||
Expr_ iter; // loop iter
|
||||
@ -281,25 +343,28 @@ struct CompExpr: Expr{
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct ListCompExpr: CompExpr{
|
||||
struct ListCompExpr : CompExpr {
|
||||
Opcode op0() override { return OP_BUILD_LIST; }
|
||||
|
||||
Opcode op1() override { return OP_LIST_APPEND; }
|
||||
};
|
||||
|
||||
struct DictCompExpr: CompExpr{
|
||||
struct DictCompExpr : CompExpr {
|
||||
Opcode op0() override { return OP_BUILD_DICT; }
|
||||
|
||||
Opcode op1() override { return OP_DICT_ADD; }
|
||||
};
|
||||
|
||||
struct SetCompExpr: CompExpr{
|
||||
struct SetCompExpr : CompExpr {
|
||||
Opcode op0() override { return OP_BUILD_SET; }
|
||||
|
||||
Opcode op1() override { return OP_SET_ADD; }
|
||||
};
|
||||
|
||||
struct LambdaExpr: Expr{
|
||||
struct LambdaExpr : Expr {
|
||||
FuncDecl_ decl;
|
||||
|
||||
LambdaExpr(FuncDecl_ decl): decl(decl) {}
|
||||
LambdaExpr(FuncDecl_ decl) : decl(decl) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override {
|
||||
int index = ctx->add_func_decl(decl);
|
||||
@ -307,17 +372,21 @@ struct LambdaExpr: Expr{
|
||||
}
|
||||
};
|
||||
|
||||
struct FStringExpr: Expr{
|
||||
struct FStringExpr : Expr {
|
||||
Str src;
|
||||
FStringExpr(const Str& src): src(src) {}
|
||||
|
||||
FStringExpr(const Str& src) : src(src) {}
|
||||
|
||||
void _load_simple_expr(CodeEmitContext* ctx, Str expr);
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct SubscrExpr: Expr{
|
||||
struct SubscrExpr : Expr {
|
||||
Expr_ a;
|
||||
Expr_ b;
|
||||
|
||||
bool is_subscr() const override { return true; }
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
bool emit_del(CodeEmitContext* ctx) override;
|
||||
bool emit_store(CodeEmitContext* ctx) override;
|
||||
@ -326,10 +395,11 @@ struct SubscrExpr: Expr{
|
||||
bool emit_store_inplace(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct AttribExpr: Expr{
|
||||
struct AttribExpr : Expr {
|
||||
Expr_ a;
|
||||
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;
|
||||
bool emit_del(CodeEmitContext* ctx) override;
|
||||
@ -337,11 +407,12 @@ struct AttribExpr: Expr{
|
||||
void emit_method(CodeEmitContext* ctx);
|
||||
|
||||
bool is_attrib() const override { return true; }
|
||||
|
||||
void emit_inplace(CodeEmitContext* ctx) override;
|
||||
bool emit_store_inplace(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct CallExpr: Expr{
|
||||
struct CallExpr : Expr {
|
||||
Expr_ callable;
|
||||
Expr_vector args;
|
||||
// **a will be interpreted as a special keyword argument: {"**": a}
|
||||
@ -349,42 +420,36 @@ struct CallExpr: Expr{
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
struct GroupedExpr: Expr{
|
||||
struct GroupedExpr : Expr {
|
||||
Expr_ a;
|
||||
GroupedExpr(Expr_&& a): a(std::move(a)) {}
|
||||
|
||||
void emit_(CodeEmitContext* ctx) override{
|
||||
a->emit_(ctx);
|
||||
}
|
||||
GroupedExpr(Expr_&& a) : a(std::move(a)) {}
|
||||
|
||||
bool emit_del(CodeEmitContext* ctx) override {
|
||||
return a->emit_del(ctx);
|
||||
}
|
||||
void emit_(CodeEmitContext* ctx) override { a->emit_(ctx); }
|
||||
|
||||
bool emit_store(CodeEmitContext* ctx) override {
|
||||
return a->emit_store(ctx);
|
||||
}
|
||||
bool emit_del(CodeEmitContext* ctx) override { return a->emit_del(ctx); }
|
||||
|
||||
bool emit_store(CodeEmitContext* ctx) override { return a->emit_store(ctx); }
|
||||
};
|
||||
|
||||
struct BinaryExpr: Expr{
|
||||
struct BinaryExpr : Expr {
|
||||
TokenIndex op;
|
||||
Expr_ lhs;
|
||||
Expr_ rhs;
|
||||
bool inplace;
|
||||
|
||||
BinaryExpr(bool inplace=false): inplace(inplace) {}
|
||||
BinaryExpr(bool inplace = false) : inplace(inplace) {}
|
||||
|
||||
bool is_compare() const override;
|
||||
void _emit_compare(CodeEmitContext*, small_vector_2<int, 6>&);
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
|
||||
struct TernaryExpr: Expr{
|
||||
struct TernaryExpr : Expr {
|
||||
Expr_ cond;
|
||||
Expr_ true_expr;
|
||||
Expr_ false_expr;
|
||||
void emit_(CodeEmitContext* ctx) override;
|
||||
};
|
||||
|
||||
|
||||
} // namespace pkpy
|
||||
@ -5,10 +5,11 @@
|
||||
|
||||
#include <variant>
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
typedef uint8_t TokenIndex;
|
||||
|
||||
// clang-format off
|
||||
constexpr const char* kTokens[] = {
|
||||
"is not", "not in", "yield from",
|
||||
"@eof", "@eol", "@sof",
|
||||
@ -28,32 +29,35 @@ constexpr const char* kTokens[] = {
|
||||
"None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally",
|
||||
"while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise"
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
using TokenValue = std::variant<std::monostate, i64, f64, Str>;
|
||||
const int kTokenCount = sizeof(kTokens) / sizeof(kTokens[0]);
|
||||
|
||||
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* j = token;
|
||||
while(*i && *j && *i == *j) { i++; j++;}
|
||||
while(*i && *j && *i == *j) {
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
if(*i == *j) return k;
|
||||
}
|
||||
return 255;
|
||||
}
|
||||
|
||||
inline constexpr bool is_raw_string_used(TokenIndex t){
|
||||
return t == TK("@id") || t == TK("@long");
|
||||
}
|
||||
constexpr inline bool is_raw_string_used(TokenIndex t) { return t == TK("@id") || t == TK("@long"); }
|
||||
|
||||
#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;
|
||||
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;
|
||||
}();
|
||||
|
||||
struct Token{
|
||||
struct Token {
|
||||
TokenIndex type;
|
||||
const char* start;
|
||||
int length;
|
||||
@ -61,8 +65,9 @@ struct Token{
|
||||
int brackets_level;
|
||||
TokenValue value;
|
||||
|
||||
Str str() const { return Str(start, length);}
|
||||
std::string_view sv() const { return std::string_view(start, length);}
|
||||
Str str() const { return Str(start, length); }
|
||||
|
||||
std::string_view sv() const { return std::string_view(start, length); }
|
||||
};
|
||||
|
||||
// https://docs.python.org/3/reference/expressions.html#operator-precedence
|
||||
@ -103,7 +108,8 @@ struct Lexer {
|
||||
stack_no_copy<int, small_vector_2<int, 8>> indents;
|
||||
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_string(const char* s);
|
||||
int eat_spaces();
|
||||
@ -114,7 +120,7 @@ struct Lexer {
|
||||
int eat_name();
|
||||
void skip_line_comment();
|
||||
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);
|
||||
Str eat_string_until(char quote, bool raw);
|
||||
void eat_string(char quote, StringType type);
|
||||
@ -125,16 +131,18 @@ struct Lexer {
|
||||
/***** Error Reporter *****/
|
||||
[[noreturn]] void throw_err(StrName type, Str msg);
|
||||
[[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 IndentationError(Str msg){ throw_err("IndentationError", msg); }
|
||||
|
||||
[[noreturn]] void SyntaxError(Str msg) { throw_err("SyntaxError", 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);
|
||||
vector<Token> run();
|
||||
};
|
||||
|
||||
|
||||
enum class IntParsingResult{
|
||||
enum class IntParsingResult {
|
||||
Success,
|
||||
Failure,
|
||||
Overflow,
|
||||
|
||||
@ -2,104 +2,108 @@
|
||||
|
||||
#include "pocketpy/interpreter/cffi.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
struct NativeProxyFuncCBase {
|
||||
virtual PyVar operator()(VM* vm, ArgsView args) = 0;
|
||||
virtual PyVar operator() (VM* vm, ArgsView args) = 0;
|
||||
};
|
||||
|
||||
template<typename Ret, typename... Params>
|
||||
struct NativeProxyFuncC final: NativeProxyFuncCBase {
|
||||
static constexpr int N = sizeof...(Params);
|
||||
using _Fp = Ret(*)(Params...);
|
||||
template <typename Ret, typename... Params>
|
||||
struct NativeProxyFuncC final : NativeProxyFuncCBase {
|
||||
constexpr static int N = sizeof...(Params);
|
||||
using _Fp = Ret (*)(Params...);
|
||||
_Fp func;
|
||||
|
||||
NativeProxyFuncC(_Fp func) : func(func) {}
|
||||
|
||||
PyVar operator()(VM* vm, ArgsView args) override {
|
||||
PyVar operator() (VM* vm, ArgsView args) override {
|
||||
assert(args.size() == N);
|
||||
return call<Ret>(vm, args, std::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
template<typename __Ret, size_t... Is>
|
||||
PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>){
|
||||
if constexpr(std::is_void_v<__Ret>){
|
||||
template <typename __Ret, size_t... Is>
|
||||
PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>) {
|
||||
if constexpr(std::is_void_v<__Ret>) {
|
||||
func(py_cast<Params>(vm, args[Is])...);
|
||||
return vm->None;
|
||||
}else{
|
||||
} else {
|
||||
__Ret ret = func(py_cast<Params>(vm, args[Is])...);
|
||||
return VAR(std::move(ret));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ret, typename T, typename... Params>
|
||||
struct NativeProxyMethodC final: NativeProxyFuncCBase {
|
||||
static constexpr int N = sizeof...(Params);
|
||||
using _Fp = Ret(T::*)(Params...);
|
||||
template <typename Ret, typename T, typename... Params>
|
||||
struct NativeProxyMethodC final : NativeProxyFuncCBase {
|
||||
constexpr static int N = sizeof...(Params);
|
||||
using _Fp = Ret (T::*)(Params...);
|
||||
_Fp func;
|
||||
|
||||
NativeProxyMethodC(_Fp func) : func(func) {}
|
||||
|
||||
PyVar operator()(VM* vm, ArgsView args) override {
|
||||
assert(args.size() == N+1);
|
||||
PyVar operator() (VM* vm, ArgsView args) override {
|
||||
assert(args.size() == N + 1);
|
||||
return call<Ret>(vm, args, std::make_index_sequence<N>());
|
||||
}
|
||||
|
||||
template<typename __Ret, size_t... Is>
|
||||
PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>){
|
||||
template <typename __Ret, size_t... 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
|
||||
if constexpr(std::is_void_v<__Ret>){
|
||||
(self.*func)(py_cast<Params>(vm, args[Is+1])...);
|
||||
if constexpr(std::is_void_v<__Ret>) {
|
||||
(self.*func)(py_cast<Params>(vm, args[Is + 1])...);
|
||||
return vm->None;
|
||||
}else{
|
||||
__Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...);
|
||||
} else {
|
||||
__Ret ret = (self.*func)(py_cast<Params>(vm, args[Is + 1])...);
|
||||
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());
|
||||
return (*pf)(vm, args);
|
||||
}
|
||||
|
||||
template<typename Ret, typename... Params>
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, Ret(*func)(Params...), BindType bt){
|
||||
template <typename Ret, typename... Params>
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, Ret (*func)(Params...), BindType bt) {
|
||||
NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
|
||||
return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
|
||||
}
|
||||
|
||||
template<typename Ret, typename T, typename... Params>
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, Ret(T::*func)(Params...), BindType bt){
|
||||
template <typename Ret, typename T, typename... Params>
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, Ret (T::*func)(Params...), BindType bt) {
|
||||
NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
|
||||
return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
|
||||
}
|
||||
|
||||
template<typename Ret, typename... Params>
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret(*func)(Params...), BindType bt){
|
||||
template <typename Ret, typename... Params>
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret (*func)(Params...), BindType bt) {
|
||||
NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
|
||||
return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
|
||||
}
|
||||
|
||||
template<typename Ret, typename T, typename... Params>
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret(T::*func)(Params...), BindType bt){
|
||||
template <typename Ret, typename T, typename... Params>
|
||||
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);
|
||||
return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
|
||||
}
|
||||
|
||||
template<typename T, typename F, bool ReadOnly>
|
||||
PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
|
||||
template <typename T, typename F, bool ReadOnly>
|
||||
PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
|
||||
static_assert(!std::is_reference_v<F>);
|
||||
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);
|
||||
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]);
|
||||
F T::*field = lambda_get_userdata<F T::*>(args.begin());
|
||||
return VAR(self.*field);
|
||||
};
|
||||
PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1, field);
|
||||
PyVar _1 = vm->None;
|
||||
if constexpr (!ReadOnly){
|
||||
auto fset = [](VM* vm, ArgsView args){
|
||||
if constexpr(!ReadOnly) {
|
||||
auto fset = [](VM* vm, ArgsView args) {
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
|
||||
F T::*field = lambda_get_userdata<F T::*>(args.begin());
|
||||
self.*field = py_cast<F>(vm, args[1]);
|
||||
@ -115,31 +119,34 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
|
||||
/*****************************************************************/
|
||||
|
||||
#define PY_FIELD(T, NAME, EXPR) \
|
||||
vm->bind_property(type, NAME, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
vm->bind_property( \
|
||||
type, \
|
||||
NAME, \
|
||||
[](VM* vm, ArgsView args) { \
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||
return VAR(self.EXPR); \
|
||||
}, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
[](VM* vm, ArgsView args) { \
|
||||
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) \
|
||||
vm->bind_property(type, NAME, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
vm->bind_property(type, NAME, [](VM* vm, ArgsView args) { \
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||
return VAR(self.EXPR); \
|
||||
});
|
||||
|
||||
#define PY_PROPERTY(T, NAME, FGET, FSET) \
|
||||
vm->bind_property(type, NAME, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
vm->bind_property( \
|
||||
type, \
|
||||
NAME, \
|
||||
[](VM* vm, ArgsView args) { \
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||
return VAR(self.FGET()); \
|
||||
}, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
[](VM* vm, ArgsView args) { \
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||
using __NT = decltype(self.FGET()); \
|
||||
self.FSET(CAST(__NT, args[1])); \
|
||||
@ -147,8 +154,7 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
|
||||
});
|
||||
|
||||
#define PY_READONLY_PROPERTY(T, NAME, FGET) \
|
||||
vm->bind_property(type, NAME, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
vm->bind_property(type, NAME, [](VM* vm, ArgsView args) { \
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
|
||||
return VAR(self.FGET()); \
|
||||
});
|
||||
@ -157,51 +163,67 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
|
||||
static_assert(std::is_trivially_copyable<wT>::value); \
|
||||
static_assert(!is_sso_v<wT>); \
|
||||
type->attr().set("__struct__", vm->True); \
|
||||
vm->bind_func(type, "fromstruct", 1, [](VM* vm, ArgsView args){ \
|
||||
vm->bind_func( \
|
||||
type, \
|
||||
"fromstruct", \
|
||||
1, \
|
||||
[](VM* vm, ArgsView args) { \
|
||||
Struct& s = CAST(Struct&, args[0]); \
|
||||
if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \
|
||||
PyVar obj = vm->new_user_object<wT>(); \
|
||||
std::memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \
|
||||
return obj; \
|
||||
}, {}, BindType::STATICMETHOD); \
|
||||
vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args){ \
|
||||
}, \
|
||||
{}, \
|
||||
BindType::STATICMETHOD); \
|
||||
vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args) { \
|
||||
wT& self = _CAST(wT&, args[0]); \
|
||||
return vm->new_user_object<Struct>(&self, sizeof(wT)); \
|
||||
}); \
|
||||
vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args){ \
|
||||
vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args) { \
|
||||
wT& self = _CAST(wT&, args[0]); \
|
||||
return vm->new_user_object<VoidP>(&self); \
|
||||
}); \
|
||||
vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args){ \
|
||||
vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args) { \
|
||||
wT& self = _CAST(wT&, args[0]); \
|
||||
return vm->new_user_object<wT>(self); \
|
||||
}); \
|
||||
vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args){ \
|
||||
vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args) { \
|
||||
return VAR(sizeof(wT)); \
|
||||
}); \
|
||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ \
|
||||
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) \
|
||||
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); \
|
||||
i64 i = CAST(i64, _1); \
|
||||
T* tgt = reinterpret_cast<T*>(self.ptr); \
|
||||
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); \
|
||||
i64 i = CAST(i64, _1); \
|
||||
T* tgt = reinterpret_cast<T*>(self.ptr); \
|
||||
tgt[i] = CAST(T, _2); \
|
||||
}); \
|
||||
});
|
||||
|
||||
#define PK_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { 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; })
|
||||
#define PK_LAMBDA(x) \
|
||||
([](VM* vm, ArgsView args) -> PyVar { \
|
||||
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
|
||||
@ -6,26 +6,28 @@ namespace pkpy {
|
||||
|
||||
#define PY_CLASS(T, mod, name) \
|
||||
[[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); \
|
||||
}
|
||||
|
||||
struct VoidP{
|
||||
struct VoidP {
|
||||
void* ptr;
|
||||
VoidP(const void* ptr): ptr(const_cast<void*>(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; }
|
||||
bool operator>=(const VoidP& other) const { return ptr >= other.ptr; }
|
||||
VoidP(const void* ptr) : ptr(const_cast<void*>(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;
|
||||
ss.write_hex(ptr);
|
||||
return ss.str();
|
||||
@ -35,7 +37,7 @@ struct VoidP{
|
||||
};
|
||||
|
||||
#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); \
|
||||
PyVar type = vm->_modules[P.first]->attr(P.second); \
|
||||
return vm->new_object<VoidP>(type->as<Type>(), val); \
|
||||
@ -58,42 +60,45 @@ POINTER_VAR(const bool*, "bool_p")
|
||||
|
||||
#undef POINTER_VAR
|
||||
|
||||
|
||||
struct Struct{
|
||||
static constexpr int INLINE_SIZE = 24;
|
||||
struct Struct {
|
||||
constexpr static int INLINE_SIZE = 24;
|
||||
|
||||
char _inlined[INLINE_SIZE];
|
||||
char* p;
|
||||
int size;
|
||||
|
||||
Struct(int new_size, bool zero_init=true){
|
||||
Struct(int new_size, bool zero_init = true) {
|
||||
this->size = new_size;
|
||||
if(size <= INLINE_SIZE){
|
||||
if(size <= INLINE_SIZE) {
|
||||
p = _inlined;
|
||||
}else{
|
||||
} else {
|
||||
p = (char*)std::malloc(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);
|
||||
}
|
||||
|
||||
Struct(const Struct& other): Struct(other.p, other.size){}
|
||||
~Struct(){ if(p!=_inlined) std::free(p); }
|
||||
Struct(const Struct& other) : Struct(other.p, other.size) {}
|
||||
|
||||
~Struct() {
|
||||
if(p != _inlined) std::free(p);
|
||||
}
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
};
|
||||
|
||||
/***********************************************/
|
||||
template<typename Tp>
|
||||
Tp to_void_p(VM* vm, PyVar var){
|
||||
template <typename Tp>
|
||||
Tp to_void_p(VM* vm, PyVar var) {
|
||||
static_assert(std::is_pointer_v<Tp>);
|
||||
if(var == vm->None) return nullptr; // None can be casted to any pointer implicitly
|
||||
VoidP& p = CAST(VoidP&, var);
|
||||
return reinterpret_cast<Tp>(p.ptr);
|
||||
}
|
||||
|
||||
/*****************************************************************/
|
||||
void add_module_c(VM* vm);
|
||||
|
||||
|
||||
@ -2,25 +2,27 @@
|
||||
|
||||
#include "pocketpy/objects/codeobject.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
// weak reference fast locals
|
||||
struct FastLocals{
|
||||
struct FastLocals {
|
||||
// this is a weak reference
|
||||
const CodeObject* co;
|
||||
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) const { return a[i]; }
|
||||
PyVar& operator[] (int i) { 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);
|
||||
NameDict_ to_namedict();
|
||||
|
||||
PyVar* begin() const { return a; }
|
||||
|
||||
PyVar* end() const { return a + size(); }
|
||||
};
|
||||
|
||||
@ -28,49 +30,72 @@ struct ValueStack {
|
||||
PK_ALWAYS_PASS_BY_POINTER(ValueStack)
|
||||
|
||||
// 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* _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& second(){ return _sp[-2]; }
|
||||
|
||||
PyVar& second() { 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& peek(int n){ return _sp[-n]; }
|
||||
|
||||
PyVar& peek(int n) { 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 pop(){ --_sp; }
|
||||
PyVar popx(){ --_sp; return *_sp; }
|
||||
ArgsView view(int n){ return ArgsView(_sp-n, _sp); }
|
||||
void shrink(int n){ _sp -= n; }
|
||||
|
||||
void pop() { --_sp; }
|
||||
|
||||
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; }
|
||||
|
||||
bool empty() const { return _sp == _begin; }
|
||||
|
||||
PyVar* begin() { return _begin; }
|
||||
|
||||
PyVar* end() { return _sp; }
|
||||
|
||||
void reset(PyVar* sp) { _sp = sp; }
|
||||
|
||||
void clear() { _sp = _begin; }
|
||||
|
||||
bool is_overflow() const { return _sp >= _max_end; }
|
||||
|
||||
template<typename... Args>
|
||||
void emplace(Args&&... args){
|
||||
new(_sp) PyVar(std::forward<Args>(args)...);
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... args) {
|
||||
new (_sp) PyVar(std::forward<Args>(args)...);
|
||||
++_sp;
|
||||
}
|
||||
};
|
||||
|
||||
struct UnwindTarget{
|
||||
struct UnwindTarget {
|
||||
UnwindTarget* next;
|
||||
int iblock;
|
||||
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 {
|
||||
@ -89,29 +114,35 @@ struct Frame {
|
||||
UnwindTarget* _uw_list;
|
||||
|
||||
NameDict& f_globals() { return _module->attr(); }
|
||||
|
||||
PyVar* f_closure_try_get(StrName name);
|
||||
|
||||
int ip() const { return _ip - co->codes.data(); }
|
||||
|
||||
// function scope
|
||||
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) { }
|
||||
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) {}
|
||||
|
||||
// exec/eval
|
||||
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) { }
|
||||
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) {}
|
||||
|
||||
// global scope
|
||||
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) { }
|
||||
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) {}
|
||||
|
||||
PyVar* actual_sp_base() const { return _locals.a; }
|
||||
|
||||
ArgsView stack_view(ValueStack* _s) const { return ArgsView(actual_sp_base(), _s->_sp); }
|
||||
|
||||
[[nodiscard]] int prepare_jump_exception_handler(ValueStack*);
|
||||
void prepare_jump_break(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;
|
||||
prepare_jump_break(s_data, target);
|
||||
return target;
|
||||
@ -126,29 +157,35 @@ struct Frame {
|
||||
~Frame();
|
||||
};
|
||||
|
||||
struct LinkedFrame{
|
||||
struct LinkedFrame {
|
||||
LinkedFrame* f_back;
|
||||
Frame frame;
|
||||
template<typename... Args>
|
||||
|
||||
template <typename... 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);
|
||||
|
||||
LinkedFrame* _tail;
|
||||
int _size;
|
||||
CallStack(): _tail(nullptr), _size(0) {}
|
||||
|
||||
CallStack() : _tail(nullptr), _size(0) {}
|
||||
|
||||
int size() const { return _size; }
|
||||
bool empty() const { return _size == 0; }
|
||||
void clear(){ while(!empty()) pop(); }
|
||||
|
||||
template<typename... Args>
|
||||
void emplace(Args&&... args){
|
||||
bool empty() const { return _size == 0; }
|
||||
|
||||
void clear() {
|
||||
while(!empty())
|
||||
pop();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... args) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -161,12 +198,13 @@ struct CallStack{
|
||||
return _tail->frame;
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
void apply(Func&& f){
|
||||
for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back) f(p->frame);
|
||||
template <typename Func>
|
||||
void apply(Func&& f) {
|
||||
for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back)
|
||||
f(p->frame);
|
||||
}
|
||||
|
||||
~CallStack(){ clear(); }
|
||||
~CallStack() { clear(); }
|
||||
};
|
||||
|
||||
}; // namespace pkpy
|
||||
@ -6,54 +6,52 @@
|
||||
#include "pocketpy/objects/object.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
struct ManagedHeap{
|
||||
struct ManagedHeap {
|
||||
vector<PyObject*> _no_gc;
|
||||
vector<PyObject*> gen;
|
||||
VM* vm;
|
||||
void (*_gc_on_delete)(VM*, PyObject*) = 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_counter = 0;
|
||||
|
||||
/********************/
|
||||
int _gc_lock_counter = 0;
|
||||
struct ScopeLock{
|
||||
|
||||
struct ScopeLock {
|
||||
PK_ALWAYS_PASS_BY_POINTER(ScopeLock)
|
||||
|
||||
ManagedHeap* heap;
|
||||
ScopeLock(ManagedHeap* heap): heap(heap){
|
||||
heap->_gc_lock_counter++;
|
||||
}
|
||||
~ScopeLock(){
|
||||
heap->_gc_lock_counter--;
|
||||
}
|
||||
|
||||
ScopeLock(ManagedHeap* heap) : heap(heap) { heap->_gc_lock_counter++; }
|
||||
|
||||
~ScopeLock() { heap->_gc_lock_counter--; }
|
||||
};
|
||||
|
||||
ScopeLock gc_scope_lock(){
|
||||
return ScopeLock(this);
|
||||
}
|
||||
ScopeLock gc_scope_lock() { return ScopeLock(this); }
|
||||
|
||||
/********************/
|
||||
|
||||
template<typename T, typename... Args>
|
||||
PyObject* gcnew(Type type, Args&&... args){
|
||||
template <typename T, typename... Args>
|
||||
PyObject* gcnew(Type type, Args&&... args) {
|
||||
using __T = std::decay_t<T>;
|
||||
static_assert(!is_sso_v<__T>, "gcnew cannot be used with SSO types");
|
||||
// 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)...);
|
||||
gen.push_back(p);
|
||||
gc_counter++;
|
||||
return p;
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
PyObject* _new(Type type, Args&&... args){
|
||||
template <typename T, typename... Args>
|
||||
PyObject* _new(Type type, Args&&... args) {
|
||||
using __T = std::decay_t<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)...);
|
||||
_no_gc.push_back(p);
|
||||
return p;
|
||||
@ -67,7 +65,9 @@ struct ManagedHeap{
|
||||
|
||||
int sweep();
|
||||
void _auto_collect();
|
||||
|
||||
bool _should_auto_collect() const { return gc_counter >= gc_threshold; }
|
||||
|
||||
int collect();
|
||||
void mark();
|
||||
};
|
||||
|
||||
@ -2,51 +2,57 @@
|
||||
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
struct RangeIter{ // step > 0
|
||||
struct RangeIter { // step > 0
|
||||
Range r;
|
||||
i64 current;
|
||||
|
||||
RangeIter(Range r) : r(r), current(r.start) {}
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
};
|
||||
|
||||
struct RangeIterR{ // step < 0
|
||||
struct RangeIterR { // step < 0
|
||||
Range r;
|
||||
i64 current;
|
||||
|
||||
RangeIterR(Range r) : r(r), current(r.start) {}
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
};
|
||||
|
||||
struct ArrayIter{
|
||||
struct ArrayIter {
|
||||
PyObject* ref;
|
||||
PyVar* end;
|
||||
PyVar* current;
|
||||
|
||||
ArrayIter(PyObject* ref, PyVar* begin, PyVar* end)
|
||||
: ref(ref), end(end), current(begin) {}
|
||||
ArrayIter(PyObject* ref, PyVar* begin, PyVar* end) : 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);
|
||||
};
|
||||
|
||||
struct StringIter{
|
||||
struct StringIter {
|
||||
PyVar ref;
|
||||
int i; // byte index
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
struct Generator{
|
||||
struct Generator {
|
||||
LinkedFrame* lf;
|
||||
int state; // 0,1,2
|
||||
List s_backup;
|
||||
|
||||
Generator(LinkedFrame* lf, ArgsView buffer): lf(lf), state(0) {
|
||||
for(PyVar obj: buffer) s_backup.push_back(obj);
|
||||
Generator(LinkedFrame* lf, ArgsView buffer) : lf(lf), state(0) {
|
||||
for(PyVar obj: buffer)
|
||||
s_backup.push_back(obj);
|
||||
}
|
||||
|
||||
void _gc_mark(VM* vm) {
|
||||
@ -58,21 +64,22 @@ struct Generator{
|
||||
PyVar next(VM* vm);
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
|
||||
~Generator(){
|
||||
if(lf){
|
||||
~Generator() {
|
||||
if(lf) {
|
||||
lf->~LinkedFrame();
|
||||
PoolFrame_dealloc(lf);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct DictItemsIter{
|
||||
struct DictItemsIter {
|
||||
PyVar ref;
|
||||
int i;
|
||||
DictItemsIter(PyVar ref) : ref(ref) {
|
||||
i = PK_OBJ_GET(Dict, ref)._head_idx;
|
||||
}
|
||||
void _gc_mark(VM* vm) const{ vm->obj_gc_mark(ref); }
|
||||
|
||||
DictItemsIter(PyVar ref) : ref(ref) { i = PK_OBJ_GET(Dict, ref)._head_idx; }
|
||||
|
||||
void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
};
|
||||
|
||||
|
||||
@ -6,23 +6,24 @@
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
struct _LineRecord{
|
||||
struct _LineRecord {
|
||||
int line;
|
||||
i64 hits;
|
||||
clock_t time;
|
||||
|
||||
_LineRecord(): line(-1), hits(0), time(0) {}
|
||||
_LineRecord() : line(-1), hits(0), time(0) {}
|
||||
|
||||
bool is_valid() const { return line != -1; }
|
||||
};
|
||||
|
||||
struct _FrameRecord{
|
||||
struct _FrameRecord {
|
||||
int callstack_size;
|
||||
Frame* frame;
|
||||
clock_t prev_time;
|
||||
_LineRecord* prev_record;
|
||||
};
|
||||
|
||||
struct LineProfiler{
|
||||
struct LineProfiler {
|
||||
// filename -> records
|
||||
std::map<std::string_view, vector<_LineRecord>> records;
|
||||
stack_no_copy<_FrameRecord> frames;
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
/* Stack manipulation macros */
|
||||
// https://github.com/python/cpython/blob/3.9/Python/ceval.c#L1123
|
||||
@ -28,35 +28,44 @@ typedef PyVar (*BinaryFuncC)(VM*, PyVar, PyVar);
|
||||
typedef void (*RegisterFunc)(VM*, PyObject*, PyObject*);
|
||||
|
||||
#if PK_ENABLE_PROFILER
|
||||
struct NextBreakpoint{
|
||||
struct NextBreakpoint {
|
||||
int callstack_size;
|
||||
int lineno;
|
||||
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);
|
||||
|
||||
bool empty() const { return callstack_size == 0; }
|
||||
};
|
||||
#endif
|
||||
|
||||
struct PyTypeInfo{
|
||||
struct Vt{
|
||||
struct PyTypeInfo {
|
||||
struct Vt {
|
||||
void (*_dtor)(void*);
|
||||
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>
|
||||
inline static Vt get(){
|
||||
template <typename T>
|
||||
inline static Vt get() {
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
Vt vt;
|
||||
if constexpr(!std::is_trivially_destructible_v<T>){
|
||||
vt._dtor = [](void* p){ ((T*)p)->~T(); };
|
||||
if constexpr(!std::is_trivially_destructible_v<T>) {
|
||||
vt._dtor = [](void* p) {
|
||||
((T*)p)->~T();
|
||||
};
|
||||
}
|
||||
if constexpr(has_gc_marker<T>::value){
|
||||
vt._gc_mark = [](void* p, VM* vm){ ((T*)p)->_gc_mark(vm); };
|
||||
if constexpr(has_gc_marker<T>::value) {
|
||||
vt._gc_mark = [](void* p, VM* vm) {
|
||||
((T*)p)->_gc_mark(vm);
|
||||
};
|
||||
}
|
||||
return vt;
|
||||
}
|
||||
@ -69,7 +78,7 @@ struct PyTypeInfo{
|
||||
bool subclass_enabled;
|
||||
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) {}
|
||||
|
||||
vector<StrName> annotated_fields = {};
|
||||
@ -122,7 +131,7 @@ struct PyTypeInfo{
|
||||
void (*on_end_subclass)(VM* vm, PyTypeInfo*) = nullptr;
|
||||
};
|
||||
|
||||
struct ImportContext{
|
||||
struct ImportContext {
|
||||
PK_ALWAYS_PASS_BY_POINTER(ImportContext)
|
||||
|
||||
vector<Str> pending;
|
||||
@ -130,29 +139,30 @@ struct ImportContext{
|
||||
|
||||
ImportContext() {}
|
||||
|
||||
struct Temp{
|
||||
struct Temp {
|
||||
PK_ALWAYS_PASS_BY_POINTER(Temp)
|
||||
|
||||
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_is_init.push_back(is_init);
|
||||
}
|
||||
~Temp(){
|
||||
|
||||
~Temp() {
|
||||
ctx->pending.pop_back();
|
||||
ctx->pending_is_init.pop_back();
|
||||
}
|
||||
};
|
||||
|
||||
Temp scope(Str name, bool is_init){
|
||||
return {this, name, is_init};
|
||||
}
|
||||
Temp scope(Str name, bool is_init) { return {this, name, is_init}; }
|
||||
};
|
||||
|
||||
class VM {
|
||||
PK_ALWAYS_PASS_BY_POINTER(VM)
|
||||
|
||||
VM* vm; // self reference to simplify code
|
||||
|
||||
public:
|
||||
ManagedHeap heap;
|
||||
ValueStack s_data;
|
||||
@ -162,7 +172,7 @@ public:
|
||||
NameDict _modules; // loaded modules
|
||||
std::map<StrName, Str> _lazy_modules; // lazy loaded modules
|
||||
|
||||
struct{
|
||||
struct {
|
||||
PyObject* error;
|
||||
stack_no_copy<ArgsView> s_view;
|
||||
} __c;
|
||||
@ -191,34 +201,36 @@ public:
|
||||
#endif
|
||||
|
||||
void (*_ceval_on_step)(VM*, Frame*, Bytecode bc);
|
||||
void(*_stdout)(const char*, int);
|
||||
void(*_stderr)(const char*, int);
|
||||
void (*_stdout)(const char*, int);
|
||||
void (*_stderr)(const char*, int);
|
||||
unsigned char* (*_import_handler)(const char*, int*);
|
||||
// function<void(const char*, int)> _stdout;
|
||||
// function<void(const char*, int)> _stderr;
|
||||
// function<unsigned char*(const char*, int*)> _import_handler;
|
||||
|
||||
// for quick access
|
||||
static constexpr 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);
|
||||
static constexpr Type tp_list=Type(7), tp_tuple=Type(8);
|
||||
static constexpr Type tp_slice=Type(9), tp_range=Type(10), tp_module=Type(11);
|
||||
static constexpr Type tp_function=Type(12), tp_native_func=Type(13), tp_bound_method=Type(14);
|
||||
static constexpr Type tp_super=Type(15), tp_exception=Type(16), tp_bytes=Type(17), tp_mappingproxy=Type(18);
|
||||
static constexpr Type tp_dict=Type(19), tp_property=Type(20), tp_star_wrapper=Type(21);
|
||||
static constexpr Type tp_staticmethod=Type(22), tp_classmethod=Type(23);
|
||||
static constexpr Type tp_none_type=Type(24), tp_not_implemented=Type(25), tp_ellipsis=Type(26);
|
||||
static constexpr Type tp_stack_memory=Type(kTpStackMemoryIndex);
|
||||
constexpr static Type tp_object = Type(1), tp_type = Type(2);
|
||||
constexpr static Type tp_int = Type(kTpIntIndex), tp_float = Type(kTpFloatIndex), tp_bool = Type(5),
|
||||
tp_str = Type(6);
|
||||
constexpr static Type tp_list = Type(7), tp_tuple = Type(8);
|
||||
constexpr static Type tp_slice = Type(9), tp_range = Type(10), tp_module = Type(11);
|
||||
constexpr static Type tp_function = Type(12), tp_native_func = Type(13), tp_bound_method = Type(14);
|
||||
constexpr static Type tp_super = Type(15), tp_exception = Type(16), tp_bytes = Type(17), tp_mappingproxy = Type(18);
|
||||
constexpr static Type tp_dict = Type(19), tp_property = Type(20), tp_star_wrapper = Type(21);
|
||||
constexpr static Type tp_staticmethod = Type(22), tp_classmethod = Type(23);
|
||||
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};
|
||||
static constexpr PyVar False{const_sso_var(), tp_bool, 0};
|
||||
static constexpr PyVar None{const_sso_var(), tp_none_type, 0};
|
||||
static constexpr PyVar NotImplemented{const_sso_var(), tp_not_implemented, 0};
|
||||
static constexpr PyVar Ellipsis{const_sso_var(), tp_ellipsis, 0};
|
||||
constexpr static PyVar True{const_sso_var(), tp_bool, 1};
|
||||
constexpr static PyVar False{const_sso_var(), tp_bool, 0};
|
||||
constexpr static PyVar None{const_sso_var(), tp_none_type, 0};
|
||||
constexpr static PyVar NotImplemented{const_sso_var(), tp_not_implemented, 0};
|
||||
constexpr static PyVar Ellipsis{const_sso_var(), tp_ellipsis, 0};
|
||||
|
||||
const bool enable_os;
|
||||
VM(bool enable_os=true);
|
||||
VM(bool enable_os = true);
|
||||
|
||||
// clang-format off
|
||||
#if PK_REGION("Python Equivalents")
|
||||
Str py_str(PyVar obj); // x -> str(x)
|
||||
Str py_repr(PyVar obj); // x -> repr(x)
|
||||
@ -453,18 +465,19 @@ public:
|
||||
vm->s_data.emplace(p->type, p);
|
||||
}
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
template<typename T>
|
||||
Type _find_type_in_cxx_typeid_map(){
|
||||
template <typename T>
|
||||
Type _find_type_in_cxx_typeid_map() {
|
||||
auto it = _cxx_typeid_map.find(typeid(T));
|
||||
if(it == _cxx_typeid_map.end()){
|
||||
#if __GNUC__ || __clang__
|
||||
if(it == _cxx_typeid_map.end()) {
|
||||
#if __GNUC__ || __clang__
|
||||
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"));
|
||||
#else
|
||||
#else
|
||||
throw std::runtime_error("_find_type_in_cxx_typeid_map() failed: T not found");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
@ -485,17 +498,35 @@ public:
|
||||
void __prepare_py_call(PyVar*, ArgsView, ArgsView, const FuncDecl_&);
|
||||
void __unpack_as_list(ArgsView args, List& list);
|
||||
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, PyVar arg);
|
||||
[[noreturn]] void __builtin_error(StrName type, const Str& msg);
|
||||
void __init_builtin_types();
|
||||
void __post_init_builtin_types();
|
||||
void __push_varargs(){}
|
||||
void __push_varargs(PyVar _0){ PUSH(_0); }
|
||||
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); }
|
||||
|
||||
void __push_varargs() {}
|
||||
|
||||
void __push_varargs(PyVar _0) { PUSH(_0); }
|
||||
|
||||
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 __minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key);
|
||||
bool __py_bool_non_trivial(PyVar);
|
||||
@ -504,128 +535,201 @@ public:
|
||||
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>
|
||||
inline constexpr 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>
|
||||
constexpr Type _find_type_in_const_cxx_typeid_map() {
|
||||
return Type();
|
||||
}
|
||||
|
||||
template<typename T> constexpr Type _find_type_in_const_cxx_typeid_map(){ return Type(); }
|
||||
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Str>(){ return VM::tp_str; }
|
||||
template<> 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 <>
|
||||
constexpr Type _find_type_in_const_cxx_typeid_map<Str>() {
|
||||
return VM::tp_str;
|
||||
}
|
||||
|
||||
template<typename __T>
|
||||
PyVar py_var(VM* vm, __T&& value){
|
||||
template <>
|
||||
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>;
|
||||
|
||||
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)
|
||||
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
|
||||
return vm->None;
|
||||
}else if constexpr(std::is_same_v<T, bool>){
|
||||
} else if constexpr(std::is_same_v<T, bool>) {
|
||||
// bool
|
||||
return value ? vm->True : vm->False;
|
||||
}else if constexpr(is_integral_v<T>){
|
||||
} else if constexpr(is_integral_v<T>) {
|
||||
// int
|
||||
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
|
||||
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);
|
||||
}else{
|
||||
} else {
|
||||
constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
|
||||
if constexpr((bool)const_type){
|
||||
if constexpr(is_sso_v<T>) return PyVar(const_type, value);
|
||||
else return vm->heap.gcnew<T>(const_type, std::forward<__T>(value));
|
||||
}else{
|
||||
if constexpr((bool)const_type) {
|
||||
if constexpr(is_sso_v<T>)
|
||||
return PyVar(const_type, value);
|
||||
else
|
||||
return vm->heap.gcnew<T>(const_type, std::forward<__T>(value));
|
||||
} else {
|
||||
Type type = vm->_find_type_in_cxx_typeid_map<T>();
|
||||
if constexpr(is_sso_v<T>) return PyVar(type, value);
|
||||
else return vm->heap.gcnew<T>(type, std::forward<__T>(value));
|
||||
if constexpr(is_sso_v<T>)
|
||||
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
|
||||
inline PyVar py_var(VM* vm, bool value){
|
||||
return value ? vm->True : vm->False;
|
||||
}
|
||||
inline PyVar py_var(VM* vm, bool value) { 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) {
|
||||
static_assert(!std::is_rvalue_reference_v<__T>, "rvalue reference is not allowed");
|
||||
using T = std::decay_t<__T>;
|
||||
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>);
|
||||
// str (shortcuts)
|
||||
if(obj == vm->None) return nullptr;
|
||||
if constexpr(with_check) vm->check_type(obj, vm->tp_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>);
|
||||
// bool
|
||||
if constexpr(with_check){
|
||||
if constexpr(with_check) {
|
||||
if(obj == vm->True) return true;
|
||||
if(obj == vm->False) return false;
|
||||
vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||
}
|
||||
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>);
|
||||
// int
|
||||
if constexpr(with_check){
|
||||
if constexpr(with_check) {
|
||||
if(is_int(obj)) return (T)obj.as<i64>();
|
||||
vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||
}
|
||||
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>);
|
||||
if(is_float(obj)) return (T)obj.as<f64>();
|
||||
if(is_int(obj)) return (T)obj.as<i64>();
|
||||
vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||
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>);
|
||||
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>);
|
||||
return to_void_p<T>(vm, obj);
|
||||
}else{
|
||||
} else {
|
||||
constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
|
||||
if constexpr((bool)const_type){
|
||||
if constexpr(with_check){
|
||||
if constexpr(std::is_same_v<T, Exception>){
|
||||
if constexpr((bool)const_type) {
|
||||
if constexpr(with_check) {
|
||||
if constexpr(std::is_same_v<T, Exception>) {
|
||||
// Exception is `subclass_enabled`
|
||||
vm->check_compatible_type(obj, const_type);
|
||||
}else{
|
||||
} else {
|
||||
vm->check_type(obj, const_type);
|
||||
}
|
||||
}
|
||||
return PK_OBJ_GET(T, obj);
|
||||
}else{
|
||||
if constexpr(with_check){
|
||||
} else {
|
||||
if constexpr(with_check) {
|
||||
Type type = vm->_find_type_in_cxx_typeid_map<T>();
|
||||
vm->check_compatible_type(obj, type);
|
||||
}
|
||||
@ -634,25 +738,31 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename __T>
|
||||
__T py_cast(VM* vm, PyVar obj) { return _py_cast__internal<__T, true>(vm, obj); }
|
||||
template<typename __T>
|
||||
__T _py_cast(VM* vm, PyVar obj) { return _py_cast__internal<__T, false>(vm, obj); }
|
||||
template <typename __T>
|
||||
__T py_cast(VM* vm, PyVar obj) {
|
||||
return _py_cast__internal<__T, true>(vm, obj);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
PyObject* VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _register, Type base, bool subclass_enabled){
|
||||
template <typename __T>
|
||||
__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>());
|
||||
mod->attr().set(name, type);
|
||||
_cxx_typeid_map[typeid(T)] = type->as<Type>();
|
||||
_register(this, mod, type);
|
||||
if(!type->attr().contains(__new__)){
|
||||
if(!type->attr().contains(__new__)) {
|
||||
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>();
|
||||
return vm->new_object<T>(cls_t);
|
||||
});
|
||||
}else{
|
||||
bind_func(type, __new__, -1, [](VM* vm, ArgsView args){
|
||||
} else {
|
||||
bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
|
||||
vm->NotImplementedError();
|
||||
return vm->None;
|
||||
});
|
||||
@ -661,8 +771,8 @@ PyObject* VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _reg
|
||||
return type;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
PyObject* VM::register_user_class(PyObject* mod, StrName name, Type base, bool subclass_enabled){
|
||||
template <typename T>
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_dataclasses(VM* vm);
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_easing(VM* vm);
|
||||
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
unsigned char* _default_import_handler(const char*, int*);
|
||||
void add_module_os(VM* vm);
|
||||
void add_module_io(VM* vm);
|
||||
}
|
||||
namespace pkpy {
|
||||
unsigned char* _default_import_handler(const char*, int*);
|
||||
void add_module_os(VM* vm);
|
||||
void add_module_io(VM* vm);
|
||||
} // namespace pkpy
|
||||
|
||||
@ -5,82 +5,158 @@
|
||||
|
||||
#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);
|
||||
|
||||
float x, y;
|
||||
|
||||
Vec2() : x(0.0f), y(0.0f) {}
|
||||
|
||||
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*(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/(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]; }
|
||||
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/ (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 cross(const Vec2& v) const { return x * v.y - y * v.x; }
|
||||
|
||||
float length() const { return sqrtf(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);
|
||||
|
||||
float x, y, z;
|
||||
|
||||
Vec3() : x(0.0f), y(0.0f), z(0.0f) {}
|
||||
|
||||
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*(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/(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]; }
|
||||
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/ (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; }
|
||||
|
||||
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_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);
|
||||
|
||||
float x, y, z, w;
|
||||
|
||||
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 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/(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]; }
|
||||
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/ (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 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; }
|
||||
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 {}; }
|
||||
NoReturn copy_(const Vec4& v) { x = v.x; y = v.y; z = v.z; w = v.w; return {}; }
|
||||
|
||||
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 {};
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
union {
|
||||
@ -89,6 +165,7 @@ struct Mat3x3{
|
||||
float _21, _22, _23;
|
||||
float _31, _32, _33;
|
||||
};
|
||||
|
||||
float m[3][3];
|
||||
float v[9];
|
||||
};
|
||||
@ -100,13 +177,13 @@ struct Mat3x3{
|
||||
static Mat3x3 ones();
|
||||
static Mat3x3 identity();
|
||||
|
||||
Mat3x3 operator+(const Mat3x3& other) const;
|
||||
Mat3x3 operator-(const Mat3x3& other) const;
|
||||
Mat3x3 operator*(float scalar) const;
|
||||
Mat3x3 operator/(float scalar) const;
|
||||
Mat3x3 operator+ (const Mat3x3& other) const;
|
||||
Mat3x3 operator- (const Mat3x3& other) 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;
|
||||
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<Mat3x3>);
|
||||
|
||||
template<>
|
||||
inline constexpr bool is_sso_v<Vec2> = true;
|
||||
template<>
|
||||
inline constexpr bool is_sso_v<Vec3> = true;
|
||||
template <>
|
||||
constexpr inline bool is_sso_v<Vec2> = true;
|
||||
template <>
|
||||
constexpr inline bool is_sso_v<Vec3> = true;
|
||||
|
||||
} // namespace pkpy
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_time(VM* vm);
|
||||
void add_module_sys(VM* vm);
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
#include "pocketpy/common/types.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
void add_module_random(VM* vm);
|
||||
|
||||
|
||||
@ -8,25 +8,31 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
struct Type {
|
||||
int16_t index;
|
||||
constexpr Type(): index(0) {}
|
||||
explicit constexpr Type(int index): index(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; }
|
||||
|
||||
constexpr Type() : index(0) {}
|
||||
|
||||
explicit constexpr Type(int index) : index(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 PyVar final{
|
||||
struct PyVar final {
|
||||
Type type;
|
||||
bool is_ptr;
|
||||
uint8_t flags;
|
||||
// 12 bytes SSO
|
||||
int _0; i64 _1;
|
||||
int _0;
|
||||
i64 _1;
|
||||
|
||||
// uninitialized
|
||||
PyVar() = default;
|
||||
@ -36,45 +42,50 @@ struct PyVar final{
|
||||
|
||||
/* We must initialize all members to allow == operator to work correctly */
|
||||
// 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
|
||||
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)
|
||||
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)
|
||||
template<typename T>
|
||||
PyVar(Type type, T value): type(type), is_ptr(false), flags(0), _0(0), _1(0) {
|
||||
template <typename T>
|
||||
PyVar(Type type, T value) : type(type), is_ptr(false), flags(0), _0(0), _1(0) {
|
||||
static_assert(sizeof(T) <= 12, "SSO size exceeded");
|
||||
as<T>() = value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& as(){
|
||||
template <typename T>
|
||||
T& as() {
|
||||
static_assert(!std::is_reference_v<T>);
|
||||
if constexpr(sizeof(T) <= 8){
|
||||
if constexpr(sizeof(T) <= 8) {
|
||||
return reinterpret_cast<T&>(_1);
|
||||
}else{
|
||||
} else {
|
||||
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) { return ((i64*)this)[i]; }
|
||||
|
||||
bool operator==(const PyVar& other) const {
|
||||
return _qword(0) == other._qword(0) && _qword(1) == other._qword(1);
|
||||
}
|
||||
bool operator== (const PyVar& other) const { return _qword(0) == other._qword(0) && _qword(1) == other._qword(1); }
|
||||
|
||||
bool operator!=(const PyVar& other) const {
|
||||
return _qword(0) != other._qword(0) || _qword(1) != other._qword(1);
|
||||
}
|
||||
bool operator!= (const PyVar& other) const { 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 {
|
||||
assert(is_ptr);
|
||||
@ -88,13 +99,11 @@ struct PyVar final{
|
||||
|
||||
i64 hash() const { return _0 + _1; }
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
obj_get_t<T> obj_get();
|
||||
|
||||
// for std::map<>
|
||||
bool operator<(const PyVar& other) const {
|
||||
return memcmp(this, &other, sizeof(PyVar)) < 0;
|
||||
}
|
||||
bool operator< (const PyVar& other) const { return memcmp(this, &other, sizeof(PyVar)) < 0; }
|
||||
};
|
||||
|
||||
static_assert(sizeof(PyVar) == 16 && is_pod_v<PyVar>);
|
||||
|
||||
@ -3,31 +3,39 @@
|
||||
#include "pocketpy/common/vector.hpp"
|
||||
#include "pocketpy/objects/object.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
struct BoundMethod {
|
||||
PyVar self;
|
||||
PyVar func;
|
||||
|
||||
BoundMethod(PyVar self, PyVar func) : self(self), func(func) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
struct StaticMethod{
|
||||
struct StaticMethod {
|
||||
PyVar func;
|
||||
|
||||
StaticMethod(PyVar func) : func(func) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
struct ClassMethod{
|
||||
struct ClassMethod {
|
||||
PyVar func;
|
||||
|
||||
ClassMethod(PyVar func) : func(func) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
struct Property{
|
||||
struct Property {
|
||||
PyVar getter;
|
||||
PyVar setter;
|
||||
|
||||
Property(PyVar getter, PyVar setter) : getter(getter), setter(setter) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
@ -37,20 +45,23 @@ struct Range {
|
||||
i64 step = 1;
|
||||
};
|
||||
|
||||
|
||||
struct StarWrapper{
|
||||
struct StarWrapper {
|
||||
int level; // either 1 or 2
|
||||
PyVar obj;
|
||||
|
||||
StarWrapper(int level, PyVar obj) : level(level), obj(obj) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
using Bytes = array<unsigned char>;
|
||||
|
||||
struct Super{
|
||||
struct Super {
|
||||
PyVar first;
|
||||
Type second;
|
||||
|
||||
Super(PyVar first, Type second) : first(first), second(second) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
@ -58,16 +69,19 @@ struct Slice {
|
||||
PyVar start;
|
||||
PyVar stop;
|
||||
PyVar step;
|
||||
|
||||
Slice(PyVar start, PyVar stop, PyVar step) : start(start), stop(stop), step(step) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
|
||||
inline const int kTpIntIndex = 3;
|
||||
inline const int kTpFloatIndex = 4;
|
||||
const inline int kTpIntIndex = 3;
|
||||
const inline int kTpFloatIndex = 4;
|
||||
|
||||
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_int(PyVar p) noexcept { return p.type.index == kTpIntIndex; }
|
||||
|
||||
inline bool is_type(PyVar obj, Type type) {
|
||||
@ -80,23 +94,26 @@ inline bool is_type(PyObject* p, Type type) {
|
||||
return p->type == type;
|
||||
}
|
||||
|
||||
struct MappingProxy{
|
||||
struct MappingProxy {
|
||||
PyObject* obj;
|
||||
|
||||
MappingProxy(PyObject* obj) : obj(obj) {}
|
||||
|
||||
NameDict& attr() { return obj->attr(); }
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
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*);
|
||||
|
||||
|
||||
template<typename T>
|
||||
obj_get_t<T> PyVar::obj_get(){
|
||||
if constexpr(is_sso_v<T>){
|
||||
template <typename T>
|
||||
obj_get_t<T> PyVar::obj_get() {
|
||||
if constexpr(is_sso_v<T>) {
|
||||
return as<T>();
|
||||
}else{
|
||||
} else {
|
||||
assert(is_ptr);
|
||||
void* v = ((PyObject*)_1)->_value_ptr();
|
||||
return *reinterpret_cast<T*>(v);
|
||||
@ -119,6 +136,6 @@ obj_get_t<T> PyVar::obj_get(){
|
||||
|
||||
#define PY_NULL nullptr
|
||||
extern PyVar const PY_OP_CALL;
|
||||
extern PyVar const PY_OP_YIELD;
|
||||
extern const PyVar PY_OP_YIELD;
|
||||
|
||||
} // namespace pkpy
|
||||
@ -5,7 +5,7 @@
|
||||
#include "pocketpy/objects/object.hpp"
|
||||
#include "pocketpy/objects/sourcedata.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
#if PK_ENABLE_STD_FUNCTION
|
||||
using NativeFuncC = function<PyVar(VM*, ArgsView)>;
|
||||
@ -13,7 +13,7 @@ using NativeFuncC = function<PyVar(VM*, ArgsView)>;
|
||||
typedef PyVar (*NativeFuncC)(VM*, ArgsView);
|
||||
#endif
|
||||
|
||||
enum class BindType{
|
||||
enum class BindType {
|
||||
DEFAULT,
|
||||
STATICMETHOD,
|
||||
CLASSMETHOD,
|
||||
@ -21,24 +21,23 @@ enum class BindType{
|
||||
|
||||
enum NameScope { NAME_LOCAL, NAME_GLOBAL, NAME_GLOBAL_UNKNOWN };
|
||||
|
||||
enum Opcode: uint8_t {
|
||||
#define OPCODE(name) OP_##name,
|
||||
#include "pocketpy/opcodes.h"
|
||||
#undef OPCODE
|
||||
enum Opcode : uint8_t {
|
||||
|
||||
#define OPCODE(name) OP_##name,
|
||||
#include "pocketpy/opcodes.h"
|
||||
#undef OPCODE
|
||||
};
|
||||
|
||||
struct Bytecode{
|
||||
struct Bytecode {
|
||||
uint8_t op;
|
||||
uint16_t arg;
|
||||
|
||||
void set_signed_arg(int arg){
|
||||
void set_signed_arg(int arg) {
|
||||
assert(arg >= INT16_MIN && arg <= INT16_MAX);
|
||||
this->arg = (int16_t)arg;
|
||||
}
|
||||
|
||||
bool is_forward_jump() const{
|
||||
return op >= OP_JUMP_FORWARD && op <= OP_LOOP_BREAK;
|
||||
}
|
||||
bool is_forward_jump() const { return op >= OP_JUMP_FORWARD && op <= OP_LOOP_BREAK; }
|
||||
};
|
||||
|
||||
enum class CodeBlockType {
|
||||
@ -49,8 +48,8 @@ enum class CodeBlockType {
|
||||
TRY_EXCEPT,
|
||||
};
|
||||
|
||||
inline const uint8_t BC_NOARG = 0;
|
||||
inline const int BC_KEEPLINE = -1;
|
||||
const inline uint8_t BC_NOARG = 0;
|
||||
const inline int BC_KEEPLINE = -1;
|
||||
|
||||
struct CodeBlock {
|
||||
CodeBlockType type;
|
||||
@ -59,10 +58,10 @@ struct CodeBlock {
|
||||
int end; // end index of this block in codes, exclusive
|
||||
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) {}
|
||||
|
||||
int get_break_end() const{
|
||||
int get_break_end() const {
|
||||
if(end2 != -1) return end2;
|
||||
return end;
|
||||
}
|
||||
@ -74,7 +73,7 @@ using CodeObject_ = std::shared_ptr<CodeObject>;
|
||||
using FuncDecl_ = std::shared_ptr<FuncDecl>;
|
||||
|
||||
struct CodeObject {
|
||||
struct LineInfo{
|
||||
struct LineInfo {
|
||||
int lineno; // line number for each bytecode
|
||||
bool is_virtual; // whether this bytecode is virtual (not in source code)
|
||||
int iblock; // block index
|
||||
@ -98,15 +97,13 @@ struct CodeObject {
|
||||
int start_line;
|
||||
int end_line;
|
||||
|
||||
const CodeBlock& _get_block_codei(int codei) const{
|
||||
return blocks[lines[codei].iblock];
|
||||
}
|
||||
const CodeBlock& _get_block_codei(int codei) const { return blocks[lines[codei].iblock]; }
|
||||
|
||||
CodeObject(std::shared_ptr<SourceData> src, const Str& name);
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
enum class FuncType{
|
||||
enum class FuncType {
|
||||
UNSET,
|
||||
NORMAL,
|
||||
SIMPLE,
|
||||
@ -120,6 +117,7 @@ struct FuncDecl {
|
||||
StrName key; // name of this argument
|
||||
PyVar value; // default value
|
||||
};
|
||||
|
||||
CodeObject_ code; // code object of this function
|
||||
|
||||
small_vector_2<int, 6> args; // indices in co->varnames
|
||||
@ -135,7 +133,7 @@ struct FuncDecl {
|
||||
|
||||
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);
|
||||
kwargs.push_back(KwArg{index, key, value});
|
||||
}
|
||||
@ -149,27 +147,31 @@ struct NativeFunc {
|
||||
FuncDecl_ decl; // new style decl-based call
|
||||
any _userdata;
|
||||
|
||||
NativeFunc(NativeFuncC f, int argc, any 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)) {}
|
||||
NativeFunc(NativeFuncC f, int argc, any 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); }
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
struct Function{
|
||||
struct Function {
|
||||
FuncDecl_ decl;
|
||||
PyObject* _module; // weak ref
|
||||
PyObject* _class; // weak ref
|
||||
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) {}
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T& lambda_get_userdata(PyVar* p){
|
||||
template <typename T>
|
||||
T& lambda_get_userdata(PyVar* p) {
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
int offset = p[-1] != nullptr ? -1 : -2;
|
||||
return p[offset].obj_get<NativeFunc>()._userdata.cast<T>();
|
||||
|
||||
@ -3,18 +3,18 @@
|
||||
#include "pocketpy/objects/base.hpp"
|
||||
#include "pocketpy/objects/tuplelist.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
struct Dict{
|
||||
struct Item{
|
||||
struct Dict {
|
||||
struct Item {
|
||||
PyVar first;
|
||||
PyVar second;
|
||||
int prev;
|
||||
int next;
|
||||
};
|
||||
|
||||
static constexpr int __Capacity = 8;
|
||||
static constexpr float __LoadFactor = 0.67f;
|
||||
constexpr static int __Capacity = 8;
|
||||
constexpr static float __LoadFactor = 0.67f;
|
||||
|
||||
int _capacity;
|
||||
int _mask;
|
||||
@ -27,8 +27,8 @@ struct Dict{
|
||||
Dict();
|
||||
Dict(Dict&& other);
|
||||
Dict(const Dict& other);
|
||||
Dict& operator=(const Dict&) = delete;
|
||||
Dict& operator=(Dict&&) = delete;
|
||||
Dict& operator= (const Dict&) = delete;
|
||||
Dict& operator= (Dict&&) = delete;
|
||||
|
||||
int size() const { return _size; }
|
||||
|
||||
@ -44,10 +44,10 @@ struct Dict{
|
||||
bool del(VM* vm, PyVar key);
|
||||
void update(VM* vm, const Dict& other);
|
||||
|
||||
template<typename __Func>
|
||||
template <typename __Func>
|
||||
void apply(__Func f) const {
|
||||
int i = _head_idx;
|
||||
while(i != -1){
|
||||
while(i != -1) {
|
||||
f(_items[i].first, _items[i].second);
|
||||
i = _items[i].next;
|
||||
}
|
||||
|
||||
@ -3,22 +3,23 @@
|
||||
#include "pocketpy/common/str.hpp"
|
||||
#include "pocketpy/objects/sourcedata.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
struct NeedMoreLines {
|
||||
NeedMoreLines(bool is_compiling_class) : is_compiling_class(is_compiling_class) {}
|
||||
|
||||
bool is_compiling_class;
|
||||
};
|
||||
|
||||
enum class InternalExceptionType: int{
|
||||
Null, Handled, Unhandled, ToBeRaised
|
||||
};
|
||||
enum class InternalExceptionType : int { Null, Handled, Unhandled, ToBeRaised };
|
||||
|
||||
struct InternalException final{
|
||||
struct InternalException final {
|
||||
InternalExceptionType type;
|
||||
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 {
|
||||
@ -31,7 +32,7 @@ struct Exception {
|
||||
|
||||
PyObject* _self; // weak reference
|
||||
|
||||
struct Frame{
|
||||
struct Frame {
|
||||
std::shared_ptr<SourceData> src;
|
||||
int lineno;
|
||||
const char* cursor;
|
||||
@ -39,20 +40,21 @@ struct Exception {
|
||||
|
||||
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) {}
|
||||
};
|
||||
|
||||
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);
|
||||
return _self;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void st_push(Args&&... args){
|
||||
template <typename... Args>
|
||||
void st_push(Args&&... args) {
|
||||
if(stacktrace.size() >= 7) return;
|
||||
stacktrace.emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
@ -60,10 +62,11 @@ struct Exception {
|
||||
Str summary() const;
|
||||
};
|
||||
|
||||
struct TopLevelException: std::exception{
|
||||
struct TopLevelException : std::exception {
|
||||
VM* vm;
|
||||
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(); }
|
||||
|
||||
|
||||
@ -3,22 +3,24 @@
|
||||
#include "pocketpy/common/namedict.hpp"
|
||||
#include "pocketpy/objects/base.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
using NameDict = NameDictImpl<PyVar>;
|
||||
using NameDict_ = std::shared_ptr<NameDict>;
|
||||
using NameDictInt = NameDictImpl<int>;
|
||||
|
||||
static_assert(sizeof(NameDict) <= 128);
|
||||
|
||||
struct PyObject final{
|
||||
struct PyObject final {
|
||||
bool gc_marked; // whether this object is marked
|
||||
Type type; // we have a duplicated type here for convenience
|
||||
NameDict* _attr; // gc will delete this on destruction
|
||||
|
||||
bool is_attr_valid() const noexcept { return _attr != nullptr; }
|
||||
|
||||
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>>);
|
||||
return *reinterpret_cast<T*>(_value_ptr());
|
||||
}
|
||||
@ -35,17 +37,17 @@ struct PyObject final{
|
||||
|
||||
PyObject(Type type) : gc_marked(false), type(type), _attr(nullptr) {}
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
void placement_new(Args&&... args){
|
||||
template <typename T, typename... Args>
|
||||
void placement_new(Args&&... args) {
|
||||
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
|
||||
if constexpr(std::is_same_v<T, DummyInstance>){
|
||||
if constexpr(std::is_same_v<T, DummyInstance>) {
|
||||
_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);
|
||||
}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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,15 +3,9 @@
|
||||
#include "pocketpy/common/utils.hpp"
|
||||
#include "pocketpy/common/str.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
enum CompileMode {
|
||||
EXEC_MODE,
|
||||
EVAL_MODE,
|
||||
REPL_MODE,
|
||||
JSON_MODE,
|
||||
CELL_MODE
|
||||
};
|
||||
enum CompileMode { EXEC_MODE, EVAL_MODE, REPL_MODE, JSON_MODE, CELL_MODE };
|
||||
|
||||
struct SourceData {
|
||||
PK_ALWAYS_PASS_BY_POINTER(SourceData)
|
||||
@ -27,7 +21,7 @@ struct SourceData {
|
||||
|
||||
SourceData(std::string_view source, 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;
|
||||
Str snapshot(int lineno, const char* cursor, std::string_view name) const;
|
||||
};
|
||||
|
||||
@ -2,16 +2,17 @@
|
||||
|
||||
#include "pocketpy/common/traits.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
struct StackMemory{
|
||||
struct StackMemory {
|
||||
int count;
|
||||
|
||||
StackMemory(int count) : count(count) {}
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool constexpr is_sso_v<StackMemory> = true;
|
||||
template <>
|
||||
constexpr inline bool is_sso_v<StackMemory> = true;
|
||||
|
||||
inline const int kTpStackMemoryIndex = 27;
|
||||
const inline int kTpStackMemoryIndex = 27;
|
||||
|
||||
} // namespace pkpy
|
||||
@ -6,7 +6,7 @@
|
||||
namespace pkpy {
|
||||
|
||||
struct Tuple {
|
||||
static const int INLINED_SIZE = 3;
|
||||
const static int INLINED_SIZE = 3;
|
||||
|
||||
PyVar* _args;
|
||||
PyVar _inlined[INLINED_SIZE];
|
||||
@ -15,49 +15,60 @@ struct Tuple {
|
||||
Tuple(int n);
|
||||
Tuple(Tuple&& other) noexcept;
|
||||
Tuple(const Tuple& other) = delete;
|
||||
Tuple& operator=(const Tuple& other) = delete;
|
||||
Tuple& operator=(Tuple&& other) = delete;
|
||||
Tuple& operator= (const Tuple& other) = delete;
|
||||
Tuple& operator= (Tuple&& other) = delete;
|
||||
~Tuple();
|
||||
|
||||
Tuple(PyVar, PyVar);
|
||||
Tuple(PyVar, PyVar, PyVar);
|
||||
|
||||
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; }
|
||||
|
||||
PyVar* begin() const { return _args; }
|
||||
|
||||
PyVar* end() const { return _args + _size; }
|
||||
|
||||
PyVar* data() const { return _args; }
|
||||
|
||||
void _gc_mark(VM*) const;
|
||||
};
|
||||
|
||||
struct List: public vector<PyVar>{
|
||||
struct List : public vector<PyVar> {
|
||||
using vector<PyVar>::vector;
|
||||
void _gc_mark(VM*) const;
|
||||
|
||||
Tuple to_tuple() const{
|
||||
Tuple to_tuple() const {
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
// a lightweight view for function args, it does not own the memory
|
||||
struct ArgsView{
|
||||
struct ArgsView {
|
||||
PyVar* _begin;
|
||||
PyVar* _end;
|
||||
|
||||
ArgsView(PyVar* begin, PyVar* end) : _begin(begin), _end(end) {}
|
||||
|
||||
ArgsView(const Tuple& t) : _begin(t.begin()), _end(t.end()) {}
|
||||
|
||||
PyVar* begin() const { return _begin; }
|
||||
|
||||
PyVar* end() const { return _end; }
|
||||
|
||||
int size() const { return _end - _begin; }
|
||||
|
||||
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;
|
||||
Tuple to_tuple() const;
|
||||
|
||||
@ -9,17 +9,17 @@
|
||||
#include "pocketpy/modules/linalg.hpp"
|
||||
#include "pocketpy/tools/repl.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
static_assert(py_sizeof<Str> <= 64);
|
||||
static_assert(py_sizeof<Mat3x3> <= 64);
|
||||
static_assert(py_sizeof<Struct> <= 64);
|
||||
static_assert(py_sizeof<Tuple> <= 80);
|
||||
static_assert(py_sizeof<List> <= 64);
|
||||
static_assert(py_sizeof<Dict> <= 64);
|
||||
static_assert(py_sizeof<RangeIter> <= 64);
|
||||
static_assert(py_sizeof<RangeIterR> <= 64);
|
||||
static_assert(py_sizeof<ArrayIter> <= 64);
|
||||
static_assert(py_sizeof<StringIter> <= 64);
|
||||
static_assert(py_sizeof<Generator> <= 64);
|
||||
static_assert(py_sizeof<DictItemsIter> <= 64);
|
||||
namespace pkpy {
|
||||
static_assert(py_sizeof<Str> <= 64);
|
||||
static_assert(py_sizeof<Mat3x3> <= 64);
|
||||
static_assert(py_sizeof<Struct> <= 64);
|
||||
static_assert(py_sizeof<Tuple> <= 80);
|
||||
static_assert(py_sizeof<List> <= 64);
|
||||
static_assert(py_sizeof<Dict> <= 64);
|
||||
static_assert(py_sizeof<RangeIter> <= 64);
|
||||
static_assert(py_sizeof<RangeIterR> <= 64);
|
||||
static_assert(py_sizeof<ArrayIter> <= 64);
|
||||
static_assert(py_sizeof<StringIter> <= 64);
|
||||
static_assert(py_sizeof<Generator> <= 64);
|
||||
static_assert(py_sizeof<DictItemsIter> <= 64);
|
||||
} // namespace pkpy
|
||||
@ -10,98 +10,97 @@ extern "C" {
|
||||
|
||||
#include "pocketpy/common/export.h"
|
||||
|
||||
typedef struct pkpy_vm_handle pkpy_vm;
|
||||
typedef int (*pkpy_CFunction)(pkpy_vm*);
|
||||
typedef void (*pkpy_COutputHandler)(const char*, int);
|
||||
typedef unsigned char* (*pkpy_CImportHandler)(const char*, int*);
|
||||
typedef int pkpy_CName;
|
||||
typedef int pkpy_CType;
|
||||
typedef const char* pkpy_CString;
|
||||
typedef struct pkpy_vm_handle pkpy_vm;
|
||||
typedef int (*pkpy_CFunction)(pkpy_vm*);
|
||||
typedef void (*pkpy_COutputHandler)(const char*, int);
|
||||
typedef unsigned char* (*pkpy_CImportHandler)(const char*, int*);
|
||||
typedef int pkpy_CName;
|
||||
typedef int pkpy_CType;
|
||||
typedef const char* pkpy_CString;
|
||||
|
||||
/* Basic Functions */
|
||||
PK_EXPORT pkpy_vm* pkpy_new_vm(bool enable_os);
|
||||
PK_EXPORT void pkpy_delete_vm(pkpy_vm*);
|
||||
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 void pkpy_set_main_argv(pkpy_vm*, int argc, char** argv);
|
||||
/* Basic Functions */
|
||||
PK_EXPORT pkpy_vm* pkpy_new_vm(bool enable_os);
|
||||
PK_EXPORT void pkpy_delete_vm(pkpy_vm*);
|
||||
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 void pkpy_set_main_argv(pkpy_vm*, int argc, char** argv);
|
||||
|
||||
/* Stack Manipulation */
|
||||
PK_EXPORT bool pkpy_dup(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_pop(pkpy_vm*, int n);
|
||||
PK_EXPORT bool pkpy_pop_top(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_dup_top(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_rot_two(pkpy_vm*);
|
||||
PK_EXPORT int pkpy_stack_size(pkpy_vm*);
|
||||
/* Stack Manipulation */
|
||||
PK_EXPORT bool pkpy_dup(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_pop(pkpy_vm*, int n);
|
||||
PK_EXPORT bool pkpy_pop_top(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_dup_top(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_rot_two(pkpy_vm*);
|
||||
PK_EXPORT int pkpy_stack_size(pkpy_vm*);
|
||||
|
||||
// int
|
||||
PK_EXPORT bool pkpy_push_int(pkpy_vm*, int val);
|
||||
PK_EXPORT bool pkpy_is_int(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_int(pkpy_vm*, int i, int* out);
|
||||
// int
|
||||
PK_EXPORT bool pkpy_push_int(pkpy_vm*, int val);
|
||||
PK_EXPORT bool pkpy_is_int(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_int(pkpy_vm*, int i, int* out);
|
||||
|
||||
// float
|
||||
PK_EXPORT bool pkpy_push_float(pkpy_vm*, double val);
|
||||
PK_EXPORT bool pkpy_is_float(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_float(pkpy_vm*, int i, double* out);
|
||||
// float
|
||||
PK_EXPORT bool pkpy_push_float(pkpy_vm*, double val);
|
||||
PK_EXPORT bool pkpy_is_float(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_float(pkpy_vm*, int i, double* out);
|
||||
|
||||
// bool
|
||||
PK_EXPORT bool pkpy_push_bool(pkpy_vm*, bool val);
|
||||
PK_EXPORT bool pkpy_is_bool(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_bool(pkpy_vm*, int i, bool* out);
|
||||
// bool
|
||||
PK_EXPORT bool pkpy_push_bool(pkpy_vm*, bool val);
|
||||
PK_EXPORT bool pkpy_is_bool(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_bool(pkpy_vm*, int i, bool* out);
|
||||
|
||||
// string
|
||||
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_to_string(pkpy_vm*, int i, pkpy_CString* out);
|
||||
// string
|
||||
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_to_string(pkpy_vm*, int i, pkpy_CString* out);
|
||||
|
||||
// void_p
|
||||
PK_EXPORT bool pkpy_push_voidp(pkpy_vm*, void* val);
|
||||
PK_EXPORT bool pkpy_is_voidp(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_voidp(pkpy_vm*, int i, void** out);
|
||||
// void_p
|
||||
PK_EXPORT bool pkpy_push_voidp(pkpy_vm*, void* val);
|
||||
PK_EXPORT bool pkpy_is_voidp(pkpy_vm*, int i);
|
||||
PK_EXPORT bool pkpy_to_voidp(pkpy_vm*, int i, void** out);
|
||||
|
||||
// none
|
||||
PK_EXPORT bool pkpy_push_none(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_is_none(pkpy_vm*, int i);
|
||||
// none
|
||||
PK_EXPORT bool pkpy_push_none(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_is_none(pkpy_vm*, int i);
|
||||
|
||||
// special push
|
||||
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_module(pkpy_vm*, const char* name);
|
||||
// special push
|
||||
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_module(pkpy_vm*, const char* name);
|
||||
|
||||
// some opt
|
||||
PK_EXPORT bool pkpy_getattr(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_setglobal(pkpy_vm*, pkpy_CName name);
|
||||
PK_EXPORT bool pkpy_eval(pkpy_vm*, const char* source);
|
||||
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_py_repr(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_py_str(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_py_import(pkpy_vm*, pkpy_CString name);
|
||||
// some opt
|
||||
PK_EXPORT bool pkpy_getattr(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_setglobal(pkpy_vm*, pkpy_CName name);
|
||||
PK_EXPORT bool pkpy_eval(pkpy_vm*, const char* source);
|
||||
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_py_repr(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_py_str(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_py_import(pkpy_vm*, pkpy_CString name);
|
||||
|
||||
/* Error Handling */
|
||||
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_clear_error(pkpy_vm*, char** message);
|
||||
/* Error Handling */
|
||||
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_clear_error(pkpy_vm*, char** message);
|
||||
|
||||
/* Callables */
|
||||
PK_EXPORT bool pkpy_vectorcall(pkpy_vm*, int argc);
|
||||
/* Callables */
|
||||
PK_EXPORT bool pkpy_vectorcall(pkpy_vm*, int argc);
|
||||
|
||||
/* Special APIs */
|
||||
PK_EXPORT void pkpy_free(void* p);
|
||||
/* Special APIs */
|
||||
PK_EXPORT void pkpy_free(void* p);
|
||||
#define pkpy_string(__s) (__s)
|
||||
PK_EXPORT pkpy_CName pkpy_name(const char* s);
|
||||
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_import_handler(pkpy_vm*, pkpy_CImportHandler handler);
|
||||
PK_EXPORT pkpy_CName pkpy_name(const char* s);
|
||||
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_import_handler(pkpy_vm*, pkpy_CImportHandler handler);
|
||||
|
||||
/* REPL */
|
||||
PK_EXPORT void* pkpy_new_repl(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_repl_input(void* r, const char* line);
|
||||
PK_EXPORT void pkpy_delete_repl(void* repl);
|
||||
/* REPL */
|
||||
PK_EXPORT void* pkpy_new_repl(pkpy_vm*);
|
||||
PK_EXPORT bool pkpy_repl_input(void* r, const char* line);
|
||||
PK_EXPORT void pkpy_delete_repl(void* repl);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -2,13 +2,14 @@
|
||||
|
||||
#include "pocketpy/interpreter/vm.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
class REPL {
|
||||
protected:
|
||||
int need_more_lines = 0;
|
||||
std::string buffer;
|
||||
VM* vm;
|
||||
|
||||
public:
|
||||
REPL(VM* vm);
|
||||
bool input(std::string line);
|
||||
|
||||
@ -3,106 +3,97 @@
|
||||
#include "types.h"
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
// wrapper for builtin functions in Python
|
||||
inline bool hasattr(const handle& obj, const handle& name) {
|
||||
// wrapper for builtin functions in Python
|
||||
inline bool hasattr(const handle& obj, const handle& name) {
|
||||
auto& key = _builtin_cast<pkpy::Str>(name);
|
||||
return vm->getattr(obj.ptr(), key, false) != nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool hasattr(const handle& obj, const char* name) {
|
||||
return vm->getattr(obj.ptr(), name, false) != nullptr;
|
||||
}
|
||||
inline bool hasattr(const handle& obj, const char* name) { 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);
|
||||
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);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
inline object getattr(const handle& obj, const handle& name, const handle& default_) {
|
||||
if(!hasattr(obj, name)) {
|
||||
return reinterpret_borrow<object>(default_);
|
||||
}
|
||||
inline object getattr(const handle& obj, const handle& name, const handle& default_) {
|
||||
if(!hasattr(obj, name)) { 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_);
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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<handle>(const handle&) = delete;
|
||||
|
||||
template <>
|
||||
inline bool isinstance<iterable>(const handle& obj) {
|
||||
template <>
|
||||
inline bool isinstance<iterable>(const handle& obj) {
|
||||
return hasattr(obj, "__iter__");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool isinstance<iterator>(const handle& obj) {
|
||||
template <>
|
||||
inline bool isinstance<iterator>(const handle& obj) {
|
||||
return hasattr(obj, "__iter__") && hasattr(obj, "__next__");
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isinstance(const handle& obj, const handle& type) {
|
||||
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()); }
|
||||
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, 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()) {
|
||||
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()) {
|
||||
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>>>>;
|
||||
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)) {
|
||||
@ -113,5 +104,5 @@ namespace pybind11 {
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Unable to cast Python instance to C++ type");
|
||||
}
|
||||
}
|
||||
} // namespace pybind11
|
||||
|
||||
@ -6,22 +6,21 @@
|
||||
|
||||
namespace pybind11 {
|
||||
|
||||
using pkpy::is_floating_point_v;
|
||||
using pkpy::is_integral_v;
|
||||
using pkpy::is_floating_point_v;
|
||||
using pkpy::is_integral_v;
|
||||
|
||||
template <typename T>
|
||||
constexpr inline bool is_string_v =
|
||||
std::is_same_v<T, char*> || std::is_same_v<T, const char*> ||
|
||||
template <typename T>
|
||||
constexpr inline bool is_string_v = 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>;
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_pyobject_v = std::is_base_of_v<handle, T>;
|
||||
template <typename T>
|
||||
constexpr bool is_pyobject_v = std::is_base_of_v<handle, T>;
|
||||
|
||||
template <typename T, typename>
|
||||
struct type_caster;
|
||||
template <typename T, typename>
|
||||
struct type_caster;
|
||||
|
||||
template <>
|
||||
struct type_caster<bool> {
|
||||
template <>
|
||||
struct type_caster<bool> {
|
||||
bool value;
|
||||
|
||||
bool load(const handle& src, bool) {
|
||||
@ -33,13 +32,11 @@ namespace pybind11 {
|
||||
return false;
|
||||
}
|
||||
|
||||
static handle cast(bool src, return_value_policy, handle) {
|
||||
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>>> {
|
||||
template <typename T>
|
||||
struct type_caster<T, std::enable_if_t<is_integral_v<T>>> {
|
||||
T value;
|
||||
|
||||
bool load(const handle& src, bool convert) {
|
||||
@ -52,10 +49,10 @@ namespace pybind11 {
|
||||
}
|
||||
|
||||
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>>> {
|
||||
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) {
|
||||
@ -73,10 +70,10 @@ namespace pybind11 {
|
||||
}
|
||||
|
||||
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>>> {
|
||||
template <typename T>
|
||||
struct type_caster<T, std::enable_if_t<is_string_v<T>>> {
|
||||
T value;
|
||||
|
||||
bool load(const handle& src, bool) {
|
||||
@ -89,13 +86,11 @@ namespace pybind11 {
|
||||
return false;
|
||||
}
|
||||
|
||||
static handle cast(const std::string& src, return_value_policy, handle) {
|
||||
return pkpy::py_var(vm, src);
|
||||
}
|
||||
};
|
||||
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>>> {
|
||||
template <typename T>
|
||||
struct type_caster<T, std::enable_if_t<is_pyobject_v<T>>> {
|
||||
T value;
|
||||
|
||||
bool load(const handle& src, bool) {
|
||||
@ -111,10 +106,10 @@ namespace pybind11 {
|
||||
static handle cast(U&& src, return_value_policy, handle) {
|
||||
return std::forward<U>(src);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T, typename>
|
||||
struct type_caster {
|
||||
template <typename T, typename>
|
||||
struct type_caster {
|
||||
value_wrapper<T> value;
|
||||
|
||||
using underlying_type = std::remove_pointer_t<decltype(value.pointer)>;
|
||||
@ -140,13 +135,11 @@ namespace pybind11 {
|
||||
}
|
||||
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>>;
|
||||
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;
|
||||
@ -168,6 +161,6 @@ namespace pybind11 {
|
||||
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
|
||||
|
||||
|
||||
@ -4,9 +4,9 @@
|
||||
|
||||
namespace pybind11 {
|
||||
|
||||
class module : public object {
|
||||
class module : public object {
|
||||
|
||||
public:
|
||||
public:
|
||||
using object::object;
|
||||
|
||||
static module import(const char* name) {
|
||||
@ -16,25 +16,21 @@ namespace pybind11 {
|
||||
return module{vm->py_import(name, false), true};
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// TODO:
|
||||
// 1. inheritance
|
||||
// 2. virtual function
|
||||
// 3. factory function
|
||||
// TODO:
|
||||
// 1. inheritance
|
||||
// 2. virtual function
|
||||
// 3. factory function
|
||||
|
||||
template <typename T, typename... Others>
|
||||
class class_ : public type {
|
||||
public:
|
||||
template <typename T, typename... Others>
|
||||
class class_ : public type {
|
||||
public:
|
||||
using type::type;
|
||||
|
||||
template <typename... Args>
|
||||
class_(const handle& scope, const char* name, Args&&... args) :
|
||||
type(vm->new_type_object(scope.ptr(),
|
||||
name,
|
||||
vm->tp_object,
|
||||
false,
|
||||
pkpy::PyTypeInfo::Vt::get<instance>()),
|
||||
type(vm->new_type_object(scope.ptr(), name, vm->tp_object, false, pkpy::PyTypeInfo::Vt::get<instance>()),
|
||||
true) {
|
||||
pkpy::PyVar mod = scope.ptr();
|
||||
mod->attr().set(name, m_ptr);
|
||||
@ -54,7 +50,9 @@ namespace pybind11 {
|
||||
bind_function(
|
||||
*this,
|
||||
"__init__",
|
||||
[](T* self, Args... args) { new (self) T(args...); },
|
||||
[](T* self, Args... args) {
|
||||
new (self) T(args...);
|
||||
},
|
||||
pkpy::BindType::DEFAULT,
|
||||
extra...);
|
||||
return *this;
|
||||
@ -65,12 +63,10 @@ namespace pybind11 {
|
||||
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>>;
|
||||
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,
|
||||
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...);
|
||||
@ -98,8 +94,7 @@ namespace pybind11 {
|
||||
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");
|
||||
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...);
|
||||
}
|
||||
@ -109,8 +104,7 @@ namespace pybind11 {
|
||||
template <typename MP, typename... Extras>
|
||||
class_& def_readonly(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_readonly only supports pointer to data member");
|
||||
static_assert(std::is_member_object_pointer_v<MP>, "def_readonly only supports pointer to data member");
|
||||
} else {
|
||||
bind_property(*this, name, mp, nullptr, extras...);
|
||||
}
|
||||
@ -146,20 +140,19 @@ namespace pybind11 {
|
||||
}
|
||||
|
||||
template <typename Getter, typename Setter, typename... Extras>
|
||||
class_&
|
||||
def_property_static(const char* name, Getter&& g, Setter&& s, const Extras&... 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...> {
|
||||
template <typename T, typename... Others>
|
||||
class enum_ : public class_<T, Others...> {
|
||||
std::map<const char*, pkpy::PyVar> m_values;
|
||||
|
||||
public:
|
||||
public:
|
||||
using class_<T, Others...>::class_;
|
||||
|
||||
template <typename... Args>
|
||||
@ -180,5 +173,5 @@ namespace pybind11 {
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
};
|
||||
} // namespace pybind11
|
||||
|
||||
@ -5,46 +5,45 @@
|
||||
|
||||
namespace pybind11 {
|
||||
|
||||
template <std::size_t Nurse, std::size_t... Patients>
|
||||
struct keep_alive {};
|
||||
template <std::size_t Nurse, std::size_t... Patients>
|
||||
struct keep_alive {};
|
||||
|
||||
template <typename T>
|
||||
struct call_guard {
|
||||
static_assert(std::is_default_constructible_v<T>,
|
||||
"call_guard must be default constructible");
|
||||
};
|
||||
template <typename T>
|
||||
struct call_guard {
|
||||
static_assert(std::is_default_constructible_v<T>, "call_guard must be default constructible");
|
||||
};
|
||||
|
||||
// append the overload to the beginning of the overload list
|
||||
struct prepend {};
|
||||
// append the overload to the beginning of the overload list
|
||||
struct prepend {};
|
||||
|
||||
template <typename... Args>
|
||||
struct init {};
|
||||
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;
|
||||
// };
|
||||
// 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,
|
||||
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;
|
||||
struct generator;
|
||||
|
||||
class function_record {
|
||||
class function_record {
|
||||
union {
|
||||
void* data;
|
||||
char buffer[16];
|
||||
@ -60,10 +59,9 @@ namespace pybind11 {
|
||||
template <typename Fn, typename Extra, typename Args, typename IndexSequence>
|
||||
friend struct generator;
|
||||
|
||||
public:
|
||||
public:
|
||||
template <typename Fn, typename... Extras>
|
||||
function_record(Fn&& f, const char* name, const Extras&... extras) :
|
||||
name(name), next(nullptr) {
|
||||
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));
|
||||
@ -72,7 +70,9 @@ namespace pybind11 {
|
||||
};
|
||||
} else {
|
||||
data = new auto(std::forward<Fn>(f));
|
||||
destructor = [](function_record* self) { delete static_cast<Fn*>(self->data); };
|
||||
destructor = [](function_record* self) {
|
||||
delete static_cast<Fn*>(self->data);
|
||||
};
|
||||
}
|
||||
|
||||
using Generator = generator<std::decay_t<Fn>, std::tuple<Extras...>>;
|
||||
@ -104,9 +104,7 @@ namespace pybind11 {
|
||||
// foreach function record and call the function with not convert
|
||||
while(p != nullptr) {
|
||||
handle result = p->wrapper(*this, view, false, {});
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
if(result) { return result; }
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
@ -114,18 +112,16 @@ namespace pybind11 {
|
||||
// foreach function record and call the function with convert
|
||||
while(p != nullptr) {
|
||||
handle result = p->wrapper(*this, view, true, {});
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
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,
|
||||
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,
|
||||
@ -157,10 +153,10 @@ namespace pybind11 {
|
||||
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...>> {
|
||||
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() {
|
||||
@ -176,13 +172,9 @@ namespace pybind11 {
|
||||
|
||||
// initialize the stack
|
||||
|
||||
if(!has_args && (view.size() != count)) {
|
||||
return handle();
|
||||
}
|
||||
if(!has_args && (view.size() != count)) { return handle(); }
|
||||
|
||||
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];
|
||||
@ -206,8 +198,7 @@ namespace pybind11 {
|
||||
|
||||
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());
|
||||
pkpy::PyVar str = vm->new_object<pkpy::Str>(vm->tp_str, pkpy::StrName(index).sv());
|
||||
dict.set(vm, str, view[count + i + 1]);
|
||||
}
|
||||
|
||||
@ -216,9 +207,7 @@ namespace pybind11 {
|
||||
|
||||
// check if all the arguments are not valid
|
||||
for(std::size_t i = 0; i < sizeof...(Args); ++i) {
|
||||
if(!stack[i]) {
|
||||
return handle();
|
||||
}
|
||||
if(!stack[i]) { return handle(); }
|
||||
}
|
||||
|
||||
// ok, all the arguments are valid, call the function
|
||||
@ -226,39 +215,31 @@ namespace pybind11 {
|
||||
|
||||
// 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 invoke(self.cast<Fn>(), std::index_sequence<Is...>{}, casters, self.policy, parent);
|
||||
}
|
||||
|
||||
return handle();
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
constexpr inline static auto _wrapper = +[](pkpy::VM*, pkpy::ArgsView view) {
|
||||
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:
|
||||
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) {
|
||||
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);
|
||||
@ -284,14 +265,11 @@ namespace pybind11 {
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
@ -308,14 +286,12 @@ namespace pybind11 {
|
||||
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 type_caster<member_type_t<Getter>>::cast(self.*getter,
|
||||
return_value_policy::reference_internal,
|
||||
view[0])
|
||||
.ptr();
|
||||
} else {
|
||||
return type_caster<callable_return_t<Getter>>::cast(
|
||||
(self.*getter)(),
|
||||
return type_caster<callable_return_t<Getter>>::cast((self.*getter)(),
|
||||
return_value_policy::reference_internal,
|
||||
view[0])
|
||||
.ptr();
|
||||
@ -325,8 +301,7 @@ namespace pybind11 {
|
||||
using Self = std::tuple_element_t<0, callable_args_t<Getter>>;
|
||||
auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
|
||||
|
||||
return type_caster<callable_return_t<Getter>>::cast(
|
||||
getter(self),
|
||||
return type_caster<callable_return_t<Getter>>::cast(getter(self),
|
||||
return_value_policy::reference_internal,
|
||||
view[0])
|
||||
.ptr();
|
||||
@ -378,6 +353,6 @@ namespace pybind11 {
|
||||
pkpy::PyVar property = vm->new_object<pkpy::Property>(vm->tp_property, getter, setter);
|
||||
var->attr().set(name, property);
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pybind11
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#include "kernel.h"
|
||||
|
||||
namespace pybind11 {
|
||||
struct type_info {
|
||||
struct type_info {
|
||||
const char* name;
|
||||
std::size_t size;
|
||||
std::size_t alignment;
|
||||
@ -24,20 +24,24 @@ namespace pybind11 {
|
||||
((T*)ptr)->~T();
|
||||
operator delete (ptr);
|
||||
},
|
||||
[](void* dst, const void* src) { new (dst) T(*(const T*)src); },
|
||||
[](void* dst, void* src) { new (dst) T(std::move(*(T*)src)); },
|
||||
[](void* dst, const void* src) {
|
||||
new (dst) T(*(const T*)src);
|
||||
},
|
||||
[](void* dst, void* src) {
|
||||
new (dst) T(std::move(*(T*)src));
|
||||
},
|
||||
&typeid(T),
|
||||
};
|
||||
return info;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// all registered C++ class will be ensured as instance type.
|
||||
class instance {
|
||||
public:
|
||||
// all registered C++ class will be ensured as instance type.
|
||||
class instance {
|
||||
public:
|
||||
// use to record the type information of C++ class.
|
||||
|
||||
private:
|
||||
private:
|
||||
enum Flag {
|
||||
None = 0,
|
||||
Own = 1 << 0, // if the instance is owned by C++ side.
|
||||
@ -50,13 +54,12 @@ namespace pybind11 {
|
||||
pkpy::PyVar parent;
|
||||
// pkpy::PyVar
|
||||
|
||||
public:
|
||||
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) {
|
||||
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;
|
||||
@ -73,8 +76,7 @@ namespace pybind11 {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static pkpy::PyVar
|
||||
create(T&& value,
|
||||
static pkpy::PyVar create(T&& value,
|
||||
pkpy::Type type,
|
||||
return_value_policy policy = return_value_policy::automatic_reference,
|
||||
pkpy::PyVar parent = nullptr) noexcept {
|
||||
@ -128,20 +130,16 @@ namespace pybind11 {
|
||||
}
|
||||
|
||||
~instance() {
|
||||
if(flag & Flag::Own) {
|
||||
type->destructor(data);
|
||||
}
|
||||
if(flag & Flag::Own) { type->destructor(data); }
|
||||
}
|
||||
|
||||
void _gc_mark(pkpy::VM* vm) const noexcept {
|
||||
if(parent && (flag & Flag::Ref)) {
|
||||
PK_OBJ_MARK(parent);
|
||||
}
|
||||
if(parent && (flag & Flag::Ref)) { PK_OBJ_MARK(parent); }
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& cast() noexcept {
|
||||
return *static_cast<T*>(data);
|
||||
}
|
||||
};
|
||||
};
|
||||
} // namespace pybind11
|
||||
|
||||
@ -2,46 +2,37 @@
|
||||
|
||||
#include <pocketpy.h>
|
||||
|
||||
namespace pybind11
|
||||
{
|
||||
inline pkpy::VM* vm = nullptr;
|
||||
inline std::map<pkpy::PyVar, int*>* _ref_counts_map = nullptr;
|
||||
namespace pybind11 {
|
||||
inline pkpy::VM* vm = 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);
|
||||
_ref_counts_map = new std::map<pkpy::PyVar, int*>();
|
||||
|
||||
// use to keep alive PyObject, when the object is hold by C++ side.
|
||||
vm->heap._gc_marker_ex = [](pkpy::VM* vm)
|
||||
{
|
||||
for(auto iter = _ref_counts_map->begin(); iter != _ref_counts_map->end();)
|
||||
{
|
||||
vm->heap._gc_marker_ex = [](pkpy::VM* vm) {
|
||||
for(auto iter = _ref_counts_map->begin(); iter != _ref_counts_map->end();) {
|
||||
auto ref_count = iter->second;
|
||||
if(*ref_count != 0)
|
||||
{
|
||||
if(*ref_count != 0) {
|
||||
// if ref count is not zero, then mark it.
|
||||
PK_OBJ_MARK(iter->first);
|
||||
++iter;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// if ref count is zero, then delete it.
|
||||
iter = _ref_counts_map->erase(iter);
|
||||
delete ref_count;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
inline void finalize()
|
||||
{
|
||||
inline void finalize() {
|
||||
delete _ref_counts_map;
|
||||
delete vm;
|
||||
}
|
||||
}
|
||||
|
||||
enum class return_value_policy : uint8_t
|
||||
{
|
||||
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.
|
||||
@ -104,5 +95,5 @@ namespace pybind11
|
||||
* return_value_policy::reference and the keep_alive call policy
|
||||
*/
|
||||
reference_internal
|
||||
};
|
||||
};
|
||||
} // namespace pybind11
|
||||
|
||||
@ -3,42 +3,42 @@
|
||||
#include "kernel.h"
|
||||
|
||||
namespace pybind11 {
|
||||
class handle;
|
||||
class object;
|
||||
class attr_accessor;
|
||||
class item_accessor;
|
||||
class iterator;
|
||||
class str;
|
||||
class bytes;
|
||||
class iterable;
|
||||
class tuple;
|
||||
class dict;
|
||||
class list;
|
||||
class set;
|
||||
class function;
|
||||
class module;
|
||||
class type;
|
||||
class bool_;
|
||||
class int_;
|
||||
class float_;
|
||||
class str;
|
||||
class bytes;
|
||||
class handle;
|
||||
class object;
|
||||
class attr_accessor;
|
||||
class item_accessor;
|
||||
class iterator;
|
||||
class str;
|
||||
class bytes;
|
||||
class iterable;
|
||||
class tuple;
|
||||
class dict;
|
||||
class list;
|
||||
class set;
|
||||
class function;
|
||||
class module;
|
||||
class type;
|
||||
class bool_;
|
||||
class int_;
|
||||
class float_;
|
||||
class str;
|
||||
class bytes;
|
||||
|
||||
template <typename T>
|
||||
T& _builtin_cast(const handle& obj);
|
||||
template <typename T>
|
||||
T& _builtin_cast(const handle& obj);
|
||||
|
||||
template <typename T>
|
||||
T reinterpret_borrow(const handle& h);
|
||||
template <typename T>
|
||||
T reinterpret_borrow(const handle& h);
|
||||
|
||||
template <typename T>
|
||||
T reinterpret_steal(const handle& h);
|
||||
template <typename T>
|
||||
T reinterpret_steal(const handle& h);
|
||||
|
||||
class handle {
|
||||
protected:
|
||||
class handle {
|
||||
protected:
|
||||
pkpy::PyVar m_ptr = nullptr;
|
||||
mutable int* ref_count = nullptr;
|
||||
|
||||
public:
|
||||
public:
|
||||
handle() = default;
|
||||
handle(const handle& h) = default;
|
||||
handle& operator= (const handle& other) = default;
|
||||
@ -82,7 +82,7 @@ namespace pybind11 {
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
public:
|
||||
template <typename T>
|
||||
T cast() const;
|
||||
|
||||
@ -120,7 +120,7 @@ namespace pybind11 {
|
||||
template <return_value_policy policy = return_value_policy::automatic, typename... Args>
|
||||
object operator() (Args&&... args) const;
|
||||
|
||||
private:
|
||||
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);
|
||||
@ -156,12 +156,12 @@ namespace pybind11 {
|
||||
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>);
|
||||
static_assert(std::is_trivially_copyable_v<handle>);
|
||||
|
||||
class object : public handle {
|
||||
public:
|
||||
class object : public handle {
|
||||
public:
|
||||
object(const object& other) : handle(other) { inc_ref(); }
|
||||
|
||||
object(object&& other) noexcept : handle(other) {
|
||||
@ -191,16 +191,12 @@ namespace pybind11 {
|
||||
}
|
||||
|
||||
~object() {
|
||||
if(m_ptr != nullptr) {
|
||||
dec_ref();
|
||||
}
|
||||
if(m_ptr != nullptr) { dec_ref(); }
|
||||
}
|
||||
|
||||
protected:
|
||||
protected:
|
||||
object(const handle& h, bool borrow) : handle(h) {
|
||||
if(borrow) {
|
||||
inc_ref();
|
||||
}
|
||||
if(borrow) { inc_ref(); }
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -212,44 +208,44 @@ namespace pybind11 {
|
||||
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);
|
||||
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(+, "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(+=, "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");
|
||||
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
|
||||
|
||||
|
||||
@ -4,25 +4,25 @@
|
||||
#include <type_traits>
|
||||
|
||||
namespace pybind11 {
|
||||
template <typename T>
|
||||
constexpr bool dependent_false = false;
|
||||
template <typename T>
|
||||
constexpr bool dependent_false = false;
|
||||
|
||||
template <typename T, typename Tuple>
|
||||
struct tuple_push_front;
|
||||
template <typename T, typename Tuple>
|
||||
struct tuple_push_front;
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
struct tuple_push_front<T, std::tuple<Ts...>> {
|
||||
template <typename T, typename... Ts>
|
||||
struct tuple_push_front<T, std::tuple<Ts...>> {
|
||||
using type = std::tuple<T, Ts...>;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T, typename Tuple>
|
||||
using tuple_push_front_t = typename tuple_push_front<T, Tuple>::type;
|
||||
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 {
|
||||
// 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> \
|
||||
@ -32,126 +32,126 @@ namespace pybind11 {
|
||||
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)
|
||||
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
|
||||
|
||||
template <typename T>
|
||||
using function_return_t = typename function_traits<T>::return_type;
|
||||
template <typename T>
|
||||
using function_return_t = typename function_traits<T>::return_type;
|
||||
|
||||
template <typename T>
|
||||
using function_args_t = typename function_traits<T>::args_type;
|
||||
template <typename T>
|
||||
using function_args_t = typename function_traits<T>::args_type;
|
||||
|
||||
template <typename T>
|
||||
constexpr std::size_t function_args_count = function_traits<T>::args_count;
|
||||
template <typename T>
|
||||
constexpr std::size_t function_args_count = function_traits<T>::args_count;
|
||||
|
||||
// traits for member pointers
|
||||
template <typename T>
|
||||
struct member_traits;
|
||||
// traits for member pointers
|
||||
template <typename T>
|
||||
struct member_traits;
|
||||
|
||||
template <typename M, typename C>
|
||||
struct member_traits<M C::*> {
|
||||
template <typename M, typename C>
|
||||
struct member_traits<M C::*> {
|
||||
using member_type = M;
|
||||
using class_type = C;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using member_type_t = typename member_traits<T>::member_type;
|
||||
template <typename T>
|
||||
using member_type_t = typename member_traits<T>::member_type;
|
||||
|
||||
template <typename T>
|
||||
using class_type_t = typename member_traits<T>::class_type;
|
||||
template <typename T>
|
||||
using class_type_t = typename member_traits<T>::class_type;
|
||||
|
||||
// some traits for distinguishing between function pointers, member function pointers and
|
||||
// functors
|
||||
using std::is_member_function_pointer_v;
|
||||
using std::is_member_object_pointer_v;
|
||||
// some traits for distinguishing between function pointers, member function pointers and
|
||||
// functors
|
||||
using std::is_member_function_pointer_v;
|
||||
using std::is_member_object_pointer_v;
|
||||
|
||||
template <typename T>
|
||||
constexpr inline bool is_function_pointer_v = std::is_function_v<std::remove_pointer_t<T>>;
|
||||
template <typename T>
|
||||
constexpr inline bool is_function_pointer_v = std::is_function_v<std::remove_pointer_t<T>>;
|
||||
|
||||
template <typename T, typename U = void>
|
||||
constexpr bool is_functor_v = false;
|
||||
template <typename T, typename U = void>
|
||||
constexpr bool is_functor_v = false;
|
||||
|
||||
template <typename T>
|
||||
constexpr inline bool is_functor_v<T, std::void_t<decltype(&T::operator())>> = true;
|
||||
template <typename T>
|
||||
constexpr inline bool is_functor_v<T, std::void_t<decltype(&T::operator())>> = true;
|
||||
|
||||
template <typename T, typename SFINAE = void>
|
||||
struct callable_traits;
|
||||
template <typename T, typename SFINAE = void>
|
||||
struct callable_traits;
|
||||
|
||||
template <typename T>
|
||||
struct callable_traits<T, std::enable_if_t<is_member_function_pointer_v<T>>> {
|
||||
template <typename 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 return_type = function_return_t<member_type_t<T>>;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct callable_traits<T, std::enable_if_t<is_function_pointer_v<T>>> {
|
||||
template <typename 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 return_type = function_return_t<std::remove_pointer<T>>;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct callable_traits<T, std::enable_if_t<is_functor_v<T>>> {
|
||||
template <typename 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 return_type = function_return_t<member_type_t<decltype(&T::operator())>>;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename Callable>
|
||||
using callable_args_t = typename callable_traits<Callable>::args_type;
|
||||
template <typename Callable>
|
||||
using callable_args_t = typename callable_traits<Callable>::args_type;
|
||||
|
||||
template <typename Callable>
|
||||
using callable_return_t = typename callable_traits<Callable>::return_type;
|
||||
template <typename Callable>
|
||||
using callable_return_t = typename callable_traits<Callable>::return_type;
|
||||
|
||||
template <typename Callable>
|
||||
constexpr std::size_t callable_args_count_v = std::tuple_size_v<callable_args_t<Callable>>;
|
||||
template <typename Callable>
|
||||
constexpr std::size_t callable_args_count_v = std::tuple_size_v<callable_args_t<Callable>>;
|
||||
|
||||
template <typename T>
|
||||
struct type_identity {
|
||||
template <typename T>
|
||||
struct type_identity {
|
||||
using type = T;
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
template <typename T>
|
||||
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
constexpr inline std::size_t types_count_v = (std::is_same_v<T, Ts> + ...);
|
||||
template <typename T, typename... Ts>
|
||||
constexpr inline std::size_t types_count_v = (std::is_same_v<T, Ts> + ...);
|
||||
|
||||
template <typename T>
|
||||
constexpr inline std::size_t types_count_v<T> = 0;
|
||||
template <typename T>
|
||||
constexpr inline std::size_t types_count_v<T> = 0;
|
||||
|
||||
template <typename T>
|
||||
struct value_wrapper {
|
||||
template <typename T>
|
||||
struct value_wrapper {
|
||||
T* pointer;
|
||||
|
||||
operator T& () { return *pointer; }
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct value_wrapper<T*> {
|
||||
template <typename T>
|
||||
struct value_wrapper<T*> {
|
||||
T* pointer;
|
||||
|
||||
operator T* () { return pointer; }
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct value_wrapper<T&> {
|
||||
template <typename T>
|
||||
struct value_wrapper<T&> {
|
||||
T* pointer;
|
||||
|
||||
operator T& () { return *pointer; }
|
||||
};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct value_wrapper<T&&> {
|
||||
template <typename T>
|
||||
struct value_wrapper<T&&> {
|
||||
T* pointer;
|
||||
|
||||
operator T&& () { return std::move(*pointer); }
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace pybind11
|
||||
|
||||
@ -3,58 +3,58 @@
|
||||
#include "object.h"
|
||||
|
||||
namespace pybind11 {
|
||||
class type : public object {
|
||||
public:
|
||||
class type : public object {
|
||||
public:
|
||||
using object::object;
|
||||
template <typename T>
|
||||
static handle handle_of();
|
||||
};
|
||||
};
|
||||
|
||||
class iterable : public object {
|
||||
public:
|
||||
class iterable : public object {
|
||||
public:
|
||||
using object::object;
|
||||
iterable() = delete;
|
||||
};
|
||||
};
|
||||
|
||||
class iterator : public object {
|
||||
public:
|
||||
class iterator : public object {
|
||||
public:
|
||||
using object::object;
|
||||
iterator() = delete;
|
||||
};
|
||||
};
|
||||
|
||||
class list : public object {
|
||||
public:
|
||||
class list : public object {
|
||||
public:
|
||||
using object::object;
|
||||
|
||||
list() : object(vm->new_object<pkpy::List>(pkpy::VM::tp_list), true) {}
|
||||
};
|
||||
};
|
||||
|
||||
class tuple : public object {
|
||||
public:
|
||||
class tuple : public object {
|
||||
public:
|
||||
using object::object;
|
||||
|
||||
tuple(int n) : object(vm->new_object<pkpy::Tuple>(pkpy::VM::tp_tuple, n), true) {}
|
||||
|
||||
//& operator[](int i){ return _args[i]; }
|
||||
// PyVar operator[](int i) const { return _args[i]; }
|
||||
};
|
||||
};
|
||||
|
||||
class set : public object {
|
||||
public:
|
||||
class set : public object {
|
||||
public:
|
||||
using object::object;
|
||||
// set() : object(vm->new_object<pkpy::Se>(pkpy::VM::tp_set), true) {}
|
||||
};
|
||||
};
|
||||
|
||||
class dict : public object {
|
||||
public:
|
||||
class dict : public object {
|
||||
public:
|
||||
using object::object;
|
||||
|
||||
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;
|
||||
str(const char* c, int len) :
|
||||
object(vm->new_object<pkpy::Str>(pkpy::VM::tp_str, c, len), true) {
|
||||
@ -73,127 +73,119 @@ namespace pybind11 {
|
||||
|
||||
template <typename... Args>
|
||||
str format(Args&&... args) const;
|
||||
};
|
||||
};
|
||||
|
||||
class int_ : public object {
|
||||
public:
|
||||
class int_ : public object {
|
||||
public:
|
||||
using object::object;
|
||||
|
||||
int_(int64_t value) : object(pkpy::py_var(vm, value), true) {}
|
||||
};
|
||||
};
|
||||
|
||||
class float_ : public object {
|
||||
public:
|
||||
class float_ : public object {
|
||||
public:
|
||||
using object::object;
|
||||
|
||||
float_(double value) : object(pkpy::py_var(vm, value), true) {}
|
||||
};
|
||||
};
|
||||
|
||||
class bool_ : public object {
|
||||
public:
|
||||
class bool_ : public object {
|
||||
public:
|
||||
using object::object;
|
||||
|
||||
bool_(bool value) : object(pkpy::py_var(vm, value), true) {}
|
||||
};
|
||||
};
|
||||
|
||||
class function : public object {
|
||||
public:
|
||||
class function : public object {
|
||||
public:
|
||||
using object::object;
|
||||
};
|
||||
};
|
||||
|
||||
class attr_accessor : public object {
|
||||
private:
|
||||
class attr_accessor : public object {
|
||||
private:
|
||||
object key;
|
||||
|
||||
public:
|
||||
public:
|
||||
template <typename T>
|
||||
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");
|
||||
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");
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
inline attr_accessor handle::attr(object&& name) const {
|
||||
return attr_accessor(reinterpret_borrow<object>(*this), std::move(name));
|
||||
}
|
||||
}
|
||||
|
||||
class item_accessor : public object {
|
||||
public:
|
||||
class item_accessor : public object {
|
||||
public:
|
||||
object key;
|
||||
|
||||
public:
|
||||
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");
|
||||
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");
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
inline item_accessor handle::operator[] (object&& key) const {
|
||||
return item_accessor(reinterpret_borrow<object>(*this), std::move(key));
|
||||
}
|
||||
}
|
||||
|
||||
class args : public tuple {
|
||||
class args : public tuple {
|
||||
using tuple::tuple;
|
||||
};
|
||||
};
|
||||
|
||||
class kwargs : public dict {
|
||||
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);
|
||||
}
|
||||
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); \
|
||||
}
|
||||
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)
|
||||
@ -207,12 +199,10 @@ namespace pybind11 {
|
||||
#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);
|
||||
}
|
||||
if(result != vm->_cxx_typeid_map.end()) { return vm->_t(result->second); }
|
||||
|
||||
vm->TypeError("Type not registered");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pybind11
|
||||
|
||||
@ -16,7 +16,7 @@ def get_all_files(root: str):
|
||||
|
||||
if __name__ == '__main__':
|
||||
files = []
|
||||
# files.extend(get_all_files('include'))
|
||||
# files.extend(get_all_files('src'))
|
||||
files.extend(get_all_files('include'))
|
||||
files.extend(get_all_files('src'))
|
||||
files.extend(get_all_files('src2'))
|
||||
subprocess.run(['clang-format', '-i'] + files, check=True)
|
||||
|
||||
@ -3,20 +3,20 @@
|
||||
#include <stdexcept>
|
||||
#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];
|
||||
snprintf(error, sizeof(error), "bad_any_cast: expected %s, got %s", expected.name(), actual.name());
|
||||
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._vt = nullptr;
|
||||
}
|
||||
|
||||
any& any::operator=(any&& other) noexcept{
|
||||
any& any::operator= (any&& other) noexcept {
|
||||
if(data) _vt->deleter(data);
|
||||
data = other.data;
|
||||
_vt = other._vt;
|
||||
|
||||
@ -6,28 +6,28 @@
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
struct LinkedListNode{
|
||||
struct LinkedListNode {
|
||||
LinkedListNode* prev;
|
||||
LinkedListNode* next;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DoubleLinkedList{
|
||||
template <typename T>
|
||||
struct DoubleLinkedList {
|
||||
static_assert(std::is_base_of_v<LinkedListNode, T>);
|
||||
int _size;
|
||||
LinkedListNode head;
|
||||
LinkedListNode tail;
|
||||
|
||||
DoubleLinkedList(): _size(0){
|
||||
DoubleLinkedList() : _size(0) {
|
||||
head.prev = nullptr;
|
||||
head.next = &tail;
|
||||
tail.prev = &head;
|
||||
tail.next = nullptr;
|
||||
}
|
||||
|
||||
void push_back(T* node){
|
||||
void push_back(T* node) {
|
||||
node->prev = tail.prev;
|
||||
node->next = &tail;
|
||||
tail.prev->next = node;
|
||||
@ -35,7 +35,7 @@ struct DoubleLinkedList{
|
||||
_size++;
|
||||
}
|
||||
|
||||
void push_front(T* node){
|
||||
void push_front(T* node) {
|
||||
node->prev = &head;
|
||||
node->next = head.next;
|
||||
head.next->prev = node;
|
||||
@ -43,14 +43,14 @@ struct DoubleLinkedList{
|
||||
_size++;
|
||||
}
|
||||
|
||||
void pop_back(){
|
||||
void pop_back() {
|
||||
assert(!empty());
|
||||
tail.prev->prev->next = &tail;
|
||||
tail.prev = tail.prev->prev;
|
||||
_size--;
|
||||
}
|
||||
|
||||
void pop_front(){
|
||||
void pop_front() {
|
||||
assert(!empty());
|
||||
head.next->next->prev = &head;
|
||||
head.next = head.next->next;
|
||||
@ -67,22 +67,20 @@ struct DoubleLinkedList{
|
||||
return static_cast<T*>(head.next);
|
||||
}
|
||||
|
||||
void erase(T* node){
|
||||
void erase(T* node) {
|
||||
node->prev->next = node->next;
|
||||
node->next->prev = node->prev;
|
||||
_size--;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return _size == 0;
|
||||
}
|
||||
bool empty() const { return _size == 0; }
|
||||
|
||||
int size() const { return _size; }
|
||||
|
||||
template<typename Func>
|
||||
void apply(Func func){
|
||||
template <typename Func>
|
||||
void apply(Func func) {
|
||||
LinkedListNode* p = head.next;
|
||||
while(p != &tail){
|
||||
while(p != &tail) {
|
||||
LinkedListNode* next = p->next;
|
||||
func(static_cast<T*>(p));
|
||||
p = next;
|
||||
@ -90,42 +88,41 @@ struct DoubleLinkedList{
|
||||
}
|
||||
};
|
||||
|
||||
template<int __BlockSize>
|
||||
struct MemoryPool{
|
||||
static const int __MaxBlocks = 256*1024 / __BlockSize;
|
||||
static const int __MinArenaCount = PK_GC_MIN_THRESHOLD*100 / (256*1024);
|
||||
template <int __BlockSize>
|
||||
struct MemoryPool {
|
||||
const static int __MaxBlocks = 256 * 1024 / __BlockSize;
|
||||
const static int __MinArenaCount = PK_GC_MIN_THRESHOLD * 100 / (256 * 1024);
|
||||
|
||||
struct Block{
|
||||
struct Block {
|
||||
void* arena;
|
||||
char data[__BlockSize];
|
||||
};
|
||||
|
||||
struct Arena: LinkedListNode{
|
||||
struct Arena : LinkedListNode {
|
||||
Block _blocks[__MaxBlocks];
|
||||
Block* _free_list[__MaxBlocks];
|
||||
int _free_list_size;
|
||||
|
||||
Arena(): _free_list_size(__MaxBlocks) {
|
||||
for(int i=0; i<__MaxBlocks; i++){
|
||||
Arena() : _free_list_size(__MaxBlocks) {
|
||||
for(int i = 0; i < __MaxBlocks; i++) {
|
||||
_blocks[i].arena = this;
|
||||
_free_list[i] = &_blocks[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool empty() const { return _free_list_size == 0; }
|
||||
|
||||
bool full() const { return _free_list_size == __MaxBlocks; }
|
||||
|
||||
size_t allocated_size() const{
|
||||
return __BlockSize * (__MaxBlocks - _free_list_size);
|
||||
}
|
||||
size_t allocated_size() const { return __BlockSize * (__MaxBlocks - _free_list_size); }
|
||||
|
||||
Block* alloc(){
|
||||
Block* alloc() {
|
||||
assert(!empty());
|
||||
_free_list_size--;
|
||||
return _free_list[_free_list_size];
|
||||
}
|
||||
|
||||
void dealloc(Block* block){
|
||||
void dealloc(Block* block) {
|
||||
assert(!full());
|
||||
_free_list[_free_list_size] = block;
|
||||
_free_list_size++;
|
||||
@ -134,71 +131,73 @@ struct MemoryPool{
|
||||
|
||||
MemoryPool() = default;
|
||||
MemoryPool(const MemoryPool&) = delete;
|
||||
MemoryPool& operator=(const MemoryPool&) = delete;
|
||||
MemoryPool& operator= (const MemoryPool&) = delete;
|
||||
MemoryPool(MemoryPool&&) = delete;
|
||||
MemoryPool& operator=(MemoryPool&&) = delete;
|
||||
MemoryPool& operator= (MemoryPool&&) = delete;
|
||||
|
||||
DoubleLinkedList<Arena> _arenas;
|
||||
DoubleLinkedList<Arena> _empty_arenas;
|
||||
|
||||
void* alloc(size_t size){
|
||||
void* alloc(size_t size) {
|
||||
PK_GLOBAL_SCOPE_LOCK();
|
||||
if(size > __BlockSize){
|
||||
if(size > __BlockSize) {
|
||||
void* p = std::malloc(sizeof(void*) + size);
|
||||
std::memset(p, 0, sizeof(void*));
|
||||
return (char*)p + sizeof(void*);
|
||||
}
|
||||
|
||||
if(_arenas.empty()){
|
||||
_arenas.push_back(new Arena());
|
||||
}
|
||||
if(_arenas.empty()) { _arenas.push_back(new Arena()); }
|
||||
Arena* arena = _arenas.back();
|
||||
void* p = arena->alloc()->data;
|
||||
if(arena->empty()){
|
||||
if(arena->empty()) {
|
||||
_arenas.pop_back();
|
||||
_empty_arenas.push_back(arena);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void dealloc(void* p){
|
||||
void dealloc(void* p) {
|
||||
PK_GLOBAL_SCOPE_LOCK();
|
||||
assert(p != nullptr);
|
||||
Block* block = (Block*)((char*)p - sizeof(void*));
|
||||
if(block->arena == nullptr){
|
||||
if(block->arena == nullptr) {
|
||||
std::free(block);
|
||||
}else{
|
||||
} else {
|
||||
Arena* arena = (Arena*)block->arena;
|
||||
if(arena->empty()){
|
||||
if(arena->empty()) {
|
||||
_empty_arenas.erase(arena);
|
||||
_arenas.push_front(arena);
|
||||
arena->dealloc(block);
|
||||
}else{
|
||||
} else {
|
||||
arena->dealloc(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void shrink_to_fit(){
|
||||
void shrink_to_fit() {
|
||||
PK_GLOBAL_SCOPE_LOCK();
|
||||
if(_arenas.size() < __MinArenaCount) return;
|
||||
_arenas.apply([this](Arena* arena){
|
||||
if(arena->full()){
|
||||
_arenas.apply([this](Arena* arena) {
|
||||
if(arena->full()) {
|
||||
_arenas.erase(arena);
|
||||
delete arena;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
~MemoryPool(){
|
||||
_arenas.apply([](Arena* arena){ delete arena; });
|
||||
_empty_arenas.apply([](Arena* arena){ delete arena; });
|
||||
~MemoryPool() {
|
||||
_arenas.apply([](Arena* arena) {
|
||||
delete arena;
|
||||
});
|
||||
_empty_arenas.apply([](Arena* arena) {
|
||||
delete arena;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
template<int BlockSize, int BlockCount>
|
||||
struct FixedMemoryPool{
|
||||
struct Block{
|
||||
template <int BlockSize, int BlockCount>
|
||||
struct FixedMemoryPool {
|
||||
struct Block {
|
||||
char data[BlockSize];
|
||||
};
|
||||
|
||||
@ -211,31 +210,29 @@ struct FixedMemoryPool{
|
||||
|
||||
FixedMemoryPool() {
|
||||
_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;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_valid(void* p){
|
||||
return p >= _blocks && p < _blocks + BlockCount;
|
||||
}
|
||||
bool is_valid(void* p) { return p >= _blocks && p < _blocks + BlockCount; }
|
||||
|
||||
void* alloc(){
|
||||
void* alloc() {
|
||||
PK_GLOBAL_SCOPE_LOCK()
|
||||
if(_free_list_end != _free_list){
|
||||
if(_free_list_end != _free_list) {
|
||||
--_free_list_end;
|
||||
return *_free_list_end;
|
||||
}else{
|
||||
} else {
|
||||
return std::malloc(BlockSize);
|
||||
}
|
||||
}
|
||||
|
||||
void dealloc(void* p){
|
||||
void dealloc(void* p) {
|
||||
PK_GLOBAL_SCOPE_LOCK()
|
||||
if(is_valid(p)){
|
||||
if(is_valid(p)) {
|
||||
*_free_list_end = static_cast<Block*>(p);
|
||||
++_free_list_end;
|
||||
}else{
|
||||
} else {
|
||||
std::free(p);
|
||||
}
|
||||
}
|
||||
@ -246,12 +243,17 @@ static FixedMemoryPool<kPoolFrameBlockSize, 128> PoolFrame;
|
||||
static MemoryPool<80> PoolObject;
|
||||
|
||||
void* PoolExpr_alloc() noexcept { return PoolExpr.alloc(); }
|
||||
|
||||
void PoolExpr_dealloc(void* p) noexcept { PoolExpr.dealloc(p); }
|
||||
|
||||
void* PoolFrame_alloc() noexcept { return PoolFrame.alloc(); }
|
||||
|
||||
void PoolFrame_dealloc(void* p) noexcept { PoolFrame.dealloc(p); }
|
||||
|
||||
void* PoolObject_alloc(size_t size) noexcept { return PoolObject.alloc(size); }
|
||||
|
||||
void PoolObject_dealloc(void* p) noexcept { PoolObject.dealloc(p); }
|
||||
|
||||
void PoolObject_shrink_to_fit() noexcept { PoolObject.shrink_to_fit(); }
|
||||
|
||||
} // namespace pkpy
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
int utf8len(unsigned char c, bool suppress){
|
||||
int utf8len(unsigned char c, bool suppress) {
|
||||
if((c & 0b10000000) == 0) return 1;
|
||||
if((c & 0b11100000) == 0b11000000) return 2;
|
||||
if((c & 0b11110000) == 0b11100000) return 3;
|
||||
@ -20,89 +20,78 @@ int utf8len(unsigned char c, bool suppress){
|
||||
}
|
||||
|
||||
#define PK_STR_ALLOCATE() \
|
||||
if(this->size < (int)sizeof(this->_inlined)){ \
|
||||
if(this->size < (int)sizeof(this->_inlined)) { \
|
||||
this->data = this->_inlined; \
|
||||
}else{ \
|
||||
this->data = (char*)std::malloc(this->size+1); \
|
||||
} else { \
|
||||
this->data = (char*)std::malloc(this->size + 1); \
|
||||
}
|
||||
|
||||
#define PK_STR_COPY_INIT(__s) \
|
||||
for(int i=0; i<this->size; i++){ \
|
||||
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() : 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(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(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(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) :
|
||||
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(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) {
|
||||
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; }
|
||||
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) {
|
||||
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';
|
||||
}
|
||||
}
|
||||
|
||||
Str::Str(Str&& other): size(other.size), is_ascii(other.is_ascii) {
|
||||
if(other.is_inlined()){
|
||||
Str::Str(Str&& other) : size(other.size), is_ascii(other.is_ascii) {
|
||||
if(other.is_inlined()) {
|
||||
data = _inlined;
|
||||
for(int i=0; i<size; i++) _inlined[i] = other._inlined[i];
|
||||
for(int i = 0; i < size; i++)
|
||||
_inlined[i] = other._inlined[i];
|
||||
data[size] = '\0';
|
||||
}else{
|
||||
} else {
|
||||
data = other.data;
|
||||
// zero out `other`
|
||||
other.data = other._inlined;
|
||||
other.data[0] = '\0';
|
||||
other.size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Str operator+(const char* p, const Str& str){
|
||||
Str operator+ (const char* p, const Str& str) {
|
||||
Str other(p);
|
||||
return other + str;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Str& str){
|
||||
return os << str.sv();
|
||||
}
|
||||
std::ostream& operator<< (std::ostream& os, const Str& str) { return os << str.sv(); }
|
||||
|
||||
bool operator<(const std::string_view other, const Str& str){
|
||||
return other < str.sv();
|
||||
}
|
||||
bool operator< (const std::string_view other, const Str& str) { return other < str.sv(); }
|
||||
|
||||
Str& Str::operator=(const Str& other){
|
||||
Str& Str::operator= (const Str& other) {
|
||||
if(!is_inlined()) std::free(data);
|
||||
size = other.size;
|
||||
is_ascii = other.is_ascii;
|
||||
@ -110,141 +99,129 @@ int utf8len(unsigned char c, bool suppress){
|
||||
std::memcpy(data, other.data, size);
|
||||
data[size] = '\0';
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
Str Str::operator+(const Str& other) const {
|
||||
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 Str::operator+ (const char* p) const {
|
||||
Str other(p);
|
||||
return *this + other;
|
||||
}
|
||||
}
|
||||
|
||||
bool Str::operator==(const Str& other) const {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 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 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 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();
|
||||
}
|
||||
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(){
|
||||
Str::~Str() {
|
||||
if(!is_inlined()) std::free(data);
|
||||
}
|
||||
}
|
||||
|
||||
Str Str::substr(int start, int len) const {
|
||||
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::substr(int start) const { return substr(start, size - start); }
|
||||
|
||||
Str Str::strip(bool left, bool right, const Str& chars) const {
|
||||
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(left) {
|
||||
while(L < R && chars.index(u8_getitem(L)) != -1)
|
||||
L++;
|
||||
}
|
||||
if(right){
|
||||
while(L < R && chars.index(u8_getitem(R-1)) != -1) R--;
|
||||
if(right) {
|
||||
while(L < R && chars.index(u8_getitem(R - 1)) != -1)
|
||||
R--;
|
||||
}
|
||||
return u8_slice(L, R, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Str Str::strip(bool left, bool right) const {
|
||||
if(is_ascii){
|
||||
Str Str::strip(bool left, bool right) const {
|
||||
if(is_ascii) {
|
||||
int L = 0;
|
||||
int R = size;
|
||||
if(left){
|
||||
while(L < R && (data[L] == ' ' || data[L] == '\t' || data[L] == '\n' || data[L] == '\r')) L++;
|
||||
if(left) {
|
||||
while(L < R && (data[L] == ' ' || data[L] == '\t' || data[L] == '\n' || data[L] == '\r'))
|
||||
L++;
|
||||
}
|
||||
if(right){
|
||||
while(L < R && (data[R-1] == ' ' || data[R-1] == '\t' || data[R-1] == '\n' || data[R-1] == '\r')) R--;
|
||||
if(right) {
|
||||
while(L < R && (data[R - 1] == ' ' || data[R - 1] == '\t' || data[R - 1] == '\n' || data[R - 1] == '\r'))
|
||||
R--;
|
||||
}
|
||||
return substr(L, R - L);
|
||||
}else{
|
||||
} else {
|
||||
return strip(left, right, " \t\n\r");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Str Str::lower() const{
|
||||
Str Str::lower() const {
|
||||
std::string copy(data, size);
|
||||
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c){
|
||||
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) {
|
||||
if('A' <= c && c <= 'Z') return c + ('a' - 'A');
|
||||
return (int)c;
|
||||
});
|
||||
return Str(copy);
|
||||
}
|
||||
}
|
||||
|
||||
Str Str::upper() const{
|
||||
Str Str::upper() const {
|
||||
std::string copy(data, size);
|
||||
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c){
|
||||
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) {
|
||||
if('a' <= c && c <= 'z') return c - ('a' - 'A');
|
||||
return (int)c;
|
||||
});
|
||||
return Str(copy);
|
||||
}
|
||||
}
|
||||
|
||||
Str Str::escape(bool single_quote) const{
|
||||
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 {
|
||||
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) {
|
||||
for(int i = 0; i < length(); i++) {
|
||||
char c = this->operator[] (i);
|
||||
switch(c) {
|
||||
case '"':
|
||||
if(!single_quote) ss << '\\';
|
||||
ss << '"';
|
||||
@ -259,7 +236,7 @@ int utf8len(unsigned char c, bool suppress){
|
||||
case '\t': ss << "\\t"; break;
|
||||
case '\b': ss << "\\b"; break;
|
||||
default:
|
||||
if ('\x00' <= c && c <= '\x1f') {
|
||||
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];
|
||||
@ -269,26 +246,26 @@ int utf8len(unsigned char c, bool suppress){
|
||||
}
|
||||
}
|
||||
ss << (single_quote ? '\'' : '"');
|
||||
}
|
||||
}
|
||||
|
||||
int Str::index(const Str& sub, int start) const {
|
||||
int Str::index(const Str& sub, int start) const {
|
||||
auto p = std::search(data + start, data + size, sub.data, sub.data + sub.size);
|
||||
if(p == data + size) return -1;
|
||||
return p - data;
|
||||
}
|
||||
}
|
||||
|
||||
Str Str::replace(char old, char new_) const{
|
||||
Str Str::replace(char old, char new_) const {
|
||||
Str copied = *this;
|
||||
for(int i=0; i<copied.size; i++){
|
||||
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 {
|
||||
Str Str::replace(const Str& old, const Str& new_, int count) const {
|
||||
SStream ss;
|
||||
int start = 0;
|
||||
while(true){
|
||||
while(true) {
|
||||
int i = index(old, start);
|
||||
if(i == -1) break;
|
||||
ss << substr(start, i - start);
|
||||
@ -298,52 +275,49 @@ int utf8len(unsigned char c, bool suppress){
|
||||
}
|
||||
ss << substr(start, size - start);
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Str::_unicode_index_to_byte(int i) const{
|
||||
int Str::_unicode_index_to_byte(int i) const {
|
||||
if(is_ascii) return i;
|
||||
int j = 0;
|
||||
while(i > 0){
|
||||
while(i > 0) {
|
||||
j += utf8len(data[j]);
|
||||
i--;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
}
|
||||
|
||||
int Str::_byte_index_to_unicode(int n) const{
|
||||
int Str::_byte_index_to_unicode(int n) const {
|
||||
if(is_ascii) return n;
|
||||
int cnt = 0;
|
||||
for(int i=0; i<n; i++){
|
||||
for(int i = 0; i < n; i++) {
|
||||
if((data[i] & 0xC0) != 0x80) cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
}
|
||||
|
||||
Str Str::u8_getitem(int i) const{
|
||||
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{
|
||||
Str Str::u8_slice(int start, int stop, int step) const {
|
||||
SStream ss;
|
||||
if(is_ascii){
|
||||
if(is_ascii) {
|
||||
PK_SLICE_LOOP(i, start, stop, step) ss << data[i];
|
||||
}else{
|
||||
} 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);
|
||||
}
|
||||
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> Str::split(const Str& sep) const {
|
||||
vector<std::string_view> result;
|
||||
std::string_view tmp;
|
||||
int start = 0;
|
||||
while(true){
|
||||
while(true) {
|
||||
int i = index(sep, start);
|
||||
if(i == -1) break;
|
||||
tmp = sv().substr(start, i - start);
|
||||
@ -353,53 +327,53 @@ int utf8len(unsigned char c, bool suppress){
|
||||
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;
|
||||
int i = 0;
|
||||
for(int j = 0; j < size; j++){
|
||||
if(data[j] == sep){
|
||||
if(j > i) result.emplace_back(data+i, j-i);
|
||||
for(int j = 0; j < size; j++) {
|
||||
if(data[j] == sep) {
|
||||
if(j > i) result.emplace_back(data + i, j - i);
|
||||
i = j + 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(size > i) result.emplace_back(data+i, size-i);
|
||||
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;
|
||||
int cnt = 0;
|
||||
int start = 0;
|
||||
while(true){
|
||||
while(true) {
|
||||
int i = index(sub, start);
|
||||
if(i == -1) break;
|
||||
cnt++;
|
||||
start = i + sub.size;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
if(it != _interned().end()) return StrName(it->second);
|
||||
// generate new index
|
||||
// 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");
|
||||
auto res = _r_interned().emplace(index, s);
|
||||
assert(res.second);
|
||||
@ -407,143 +381,137 @@ int utf8len(unsigned char c, bool suppress){
|
||||
_interned()[s] = index;
|
||||
_pesudo_random_index = index;
|
||||
return StrName(index);
|
||||
}
|
||||
}
|
||||
|
||||
Str SStream::str(){
|
||||
Str SStream::str() {
|
||||
// after this call, the buffer is no longer valid
|
||||
buffer.reserve(buffer.size() + 1); // allocate one more byte for '\0'
|
||||
buffer[buffer.size()] = '\0'; // set '\0'
|
||||
return Str(buffer.detach());
|
||||
}
|
||||
}
|
||||
|
||||
SStream& SStream::operator<<(const Str& s){
|
||||
for(char c: s) 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){
|
||||
SStream& SStream::operator<< (const Str& s) {
|
||||
for(char c: s)
|
||||
buffer.push_back(c);
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
SStream& SStream::operator<<(StrName sn){
|
||||
return *this << sn.sv();
|
||||
}
|
||||
SStream& SStream::operator<< (const char* s) {
|
||||
while(*s)
|
||||
buffer.push_back(*s++);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SStream& SStream::operator<<(size_t val){
|
||||
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<< (int val) { return (*this) << static_cast<i64>(val); }
|
||||
|
||||
SStream& SStream::operator<<(i64 val){
|
||||
SStream& SStream::operator<< (i64 val) {
|
||||
// str(-2**64).__len__() == 21
|
||||
buffer.reserve(buffer.size() + 24);
|
||||
if(val == 0){
|
||||
if(val == 0) {
|
||||
buffer.push_back('0');
|
||||
return *this;
|
||||
}
|
||||
if(val < 0){
|
||||
if(val < 0) {
|
||||
buffer.push_back('-');
|
||||
val = -val;
|
||||
}
|
||||
auto begin = buffer.end();
|
||||
while(val){
|
||||
while(val) {
|
||||
buffer.push_back('0' + val % 10);
|
||||
val /= 10;
|
||||
}
|
||||
std::reverse(begin, buffer.end());
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
SStream& SStream::operator<<(f64 val){
|
||||
if(std::isinf(val)){
|
||||
return (*this) << (val > 0 ? "inf" : "-inf");
|
||||
}
|
||||
if(std::isnan(val)){
|
||||
return (*this) << "nan";
|
||||
}
|
||||
SStream& SStream::operator<< (f64 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;
|
||||
if(_precision == -1) {
|
||||
int prec = std::numeric_limits<f64>::max_digits10 - 1;
|
||||
snprintf(b, sizeof(b), "%.*g", prec, val);
|
||||
}else{
|
||||
} 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";
|
||||
if(std::all_of(b + 1, b + strlen(b), isdigit)) (*this) << ".0";
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
void SStream::write_hex(unsigned char c, bool non_zero){
|
||||
void SStream::write_hex(unsigned char c, bool non_zero) {
|
||||
unsigned char high = c >> 4;
|
||||
unsigned char low = c & 0xf;
|
||||
if(non_zero){
|
||||
if(non_zero) {
|
||||
if(high) (*this) << PK_HEX_TABLE[high];
|
||||
if(high || low) (*this) << PK_HEX_TABLE[low];
|
||||
}else{
|
||||
} else {
|
||||
(*this) << PK_HEX_TABLE[high];
|
||||
(*this) << PK_HEX_TABLE[low];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SStream::write_hex(void* p){
|
||||
if(p == nullptr){
|
||||
void SStream::write_hex(void* p) {
|
||||
if(p == nullptr) {
|
||||
(*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--){
|
||||
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(i64 val){
|
||||
if(val == 0){
|
||||
void SStream::write_hex(i64 val) {
|
||||
if(val == 0) {
|
||||
(*this) << "0x0";
|
||||
return;
|
||||
}
|
||||
if(val < 0){
|
||||
if(val < 0) {
|
||||
(*this) << "-";
|
||||
val = -val;
|
||||
}
|
||||
(*this) << "0x";
|
||||
bool non_zero = true;
|
||||
for(int i=56; i>=0; i-=8){
|
||||
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_COPY_INIT
|
||||
|
||||
|
||||
|
||||
// unary operators
|
||||
const StrName __repr__ = StrName::get("__repr__");
|
||||
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_complex = StrName::get("complex");
|
||||
|
||||
|
||||
} // namespace pkpy
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,108 +1,109 @@
|
||||
#include "pocketpy/compiler/expr.hpp"
|
||||
#include "pocketpy/interpreter/vm.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
inline bool is_identifier(std::string_view s){
|
||||
inline bool is_identifier(std::string_view s) {
|
||||
if(s.empty()) return false;
|
||||
if(!isalpha(s[0]) && s[0] != '_') return false;
|
||||
for(char c: s) if(!isalnum(c) && c != '_') return false;
|
||||
for(char c: s)
|
||||
if(!isalnum(c) && c != '_') return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_small_int(i64 value){
|
||||
return value >= INT16_MIN && value <= INT16_MAX;
|
||||
}
|
||||
inline bool is_small_int(i64 value) { return value >= INT16_MIN && value <= INT16_MAX; }
|
||||
|
||||
int CodeEmitContext::get_loop() const {
|
||||
int CodeEmitContext::get_loop() const {
|
||||
int index = curr_iblock;
|
||||
while(index >= 0){
|
||||
while(index >= 0) {
|
||||
if(co->blocks[index].type == CodeBlockType::FOR_LOOP) break;
|
||||
if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) break;
|
||||
index = co->blocks[index].parent;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
CodeBlock* CodeEmitContext::enter_block(CodeBlockType type){
|
||||
CodeBlock* CodeEmitContext::enter_block(CodeBlockType type) {
|
||||
co->blocks.push_back(CodeBlock(type, curr_iblock, (int)co->codes.size()));
|
||||
curr_iblock = co->blocks.size()-1;
|
||||
curr_iblock = co->blocks.size() - 1;
|
||||
return &co->blocks[curr_iblock];
|
||||
}
|
||||
}
|
||||
|
||||
void CodeEmitContext::exit_block(){
|
||||
void CodeEmitContext::exit_block() {
|
||||
auto curr_type = co->blocks[curr_iblock].type;
|
||||
co->blocks[curr_iblock].end = co->codes.size();
|
||||
curr_iblock = co->blocks[curr_iblock].parent;
|
||||
assert(curr_iblock >= 0);
|
||||
if(curr_type == CodeBlockType::FOR_LOOP){
|
||||
if(curr_type == CodeBlockType::FOR_LOOP) {
|
||||
// add a no op here to make block check work
|
||||
emit_(OP_NO_OP, BC_NOARG, BC_KEEPLINE, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clear the expression stack and generate bytecode
|
||||
void CodeEmitContext::emit_expr(){
|
||||
// clear the expression stack and generate bytecode
|
||||
void CodeEmitContext::emit_expr() {
|
||||
assert(s_expr.size() == 1);
|
||||
Expr_ expr = s_expr.popx();
|
||||
expr->emit_(this);
|
||||
}
|
||||
}
|
||||
|
||||
int CodeEmitContext::emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual) {
|
||||
int CodeEmitContext::emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual) {
|
||||
co->codes.push_back(Bytecode{(uint8_t)opcode, arg});
|
||||
co->lines.push_back(CodeObject::LineInfo{line, is_virtual, curr_iblock});
|
||||
int i = co->codes.size() - 1;
|
||||
if(line == BC_KEEPLINE){
|
||||
if(i >= 1) co->lines[i].lineno = co->lines[i-1].lineno;
|
||||
else co->lines[i].lineno = 1;
|
||||
if(line == BC_KEEPLINE) {
|
||||
if(i >= 1)
|
||||
co->lines[i].lineno = co->lines[i - 1].lineno;
|
||||
else
|
||||
co->lines[i].lineno = 1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
void CodeEmitContext::revert_last_emit_(){
|
||||
void CodeEmitContext::revert_last_emit_() {
|
||||
co->codes.pop_back();
|
||||
co->lines.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void CodeEmitContext::try_merge_for_iter_store(int i){
|
||||
void CodeEmitContext::try_merge_for_iter_store(int i) {
|
||||
// [FOR_ITER, STORE_?, ]
|
||||
if(co->codes[i].op != OP_FOR_ITER) return;
|
||||
if(co->codes.size() - i != 2) return;
|
||||
uint16_t arg = co->codes[i+1].arg;
|
||||
if(co->codes[i+1].op == OP_STORE_FAST){
|
||||
uint16_t arg = co->codes[i + 1].arg;
|
||||
if(co->codes[i + 1].op == OP_STORE_FAST) {
|
||||
revert_last_emit_();
|
||||
co->codes[i].op = OP_FOR_ITER_STORE_FAST;
|
||||
co->codes[i].arg = arg;
|
||||
return;
|
||||
}
|
||||
if(co->codes[i+1].op == OP_STORE_GLOBAL){
|
||||
if(co->codes[i + 1].op == OP_STORE_GLOBAL) {
|
||||
revert_last_emit_();
|
||||
co->codes[i].op = OP_FOR_ITER_STORE_GLOBAL;
|
||||
co->codes[i].arg = arg;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CodeEmitContext::emit_int(i64 value, int line){
|
||||
if(is_small_int(value)){
|
||||
int CodeEmitContext::emit_int(i64 value, int line) {
|
||||
if(is_small_int(value)) {
|
||||
return emit_(OP_LOAD_SMALL_INT, (uint16_t)value, line);
|
||||
}else{
|
||||
} else {
|
||||
return emit_(OP_LOAD_CONST, add_const(VAR(value)), line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CodeEmitContext::patch_jump(int index) {
|
||||
void CodeEmitContext::patch_jump(int index) {
|
||||
int target = co->codes.size();
|
||||
co->codes[index].set_signed_arg(target-index);
|
||||
}
|
||||
co->codes[index].set_signed_arg(target - index);
|
||||
}
|
||||
|
||||
bool CodeEmitContext::add_label(StrName name){
|
||||
bool CodeEmitContext::add_label(StrName name) {
|
||||
if(co->labels.contains(name)) return false;
|
||||
co->labels.set(name, co->codes.size());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int CodeEmitContext::add_varname(StrName name){
|
||||
int CodeEmitContext::add_varname(StrName name) {
|
||||
// PK_MAX_CO_VARNAMES will be checked when pop_context(), not here
|
||||
int index = co->varnames_inv.try_get(name);
|
||||
if(index >= 0) return index;
|
||||
@ -111,191 +112,178 @@ namespace pkpy{
|
||||
index = co->varnames.size() - 1;
|
||||
co->varnames_inv.set(name, index);
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
int CodeEmitContext::add_const_string(std::string_view key){
|
||||
int CodeEmitContext::add_const_string(std::string_view key) {
|
||||
auto it = _co_consts_string_dedup_map.find(key);
|
||||
if(it != _co_consts_string_dedup_map.end()){
|
||||
if(it != _co_consts_string_dedup_map.end()) {
|
||||
return it->second;
|
||||
}else{
|
||||
} else {
|
||||
co->consts.push_back(VAR(key));
|
||||
int index = co->consts.size() - 1;
|
||||
key = co->consts.back().obj_get<Str>().sv();
|
||||
_co_consts_string_dedup_map[key] = index;
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CodeEmitContext::add_const(PyVar v){
|
||||
int CodeEmitContext::add_const(PyVar v) {
|
||||
assert(!is_type(v, VM::tp_str));
|
||||
// non-string deduplication
|
||||
auto it = _co_consts_nonstring_dedup_map.find(v);
|
||||
if(it != _co_consts_nonstring_dedup_map.end()){
|
||||
if(it != _co_consts_nonstring_dedup_map.end()) {
|
||||
return it->second;
|
||||
}else{
|
||||
} else {
|
||||
co->consts.push_back(v);
|
||||
int index = co->consts.size() - 1;
|
||||
_co_consts_nonstring_dedup_map[v] = index;
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CodeEmitContext::add_func_decl(FuncDecl_ decl){
|
||||
int CodeEmitContext::add_func_decl(FuncDecl_ decl) {
|
||||
co->func_decls.push_back(decl);
|
||||
return co->func_decls.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void CodeEmitContext::emit_store_name(NameScope scope, StrName name, int line){
|
||||
switch(scope){
|
||||
case NAME_LOCAL:
|
||||
emit_(OP_STORE_FAST, add_varname(name), line);
|
||||
break;
|
||||
case NAME_GLOBAL:
|
||||
emit_(OP_STORE_GLOBAL, StrName(name).index, line);
|
||||
break;
|
||||
case NAME_GLOBAL_UNKNOWN:
|
||||
emit_(OP_STORE_NAME, StrName(name).index, line);
|
||||
break;
|
||||
void CodeEmitContext::emit_store_name(NameScope scope, StrName name, int line) {
|
||||
switch(scope) {
|
||||
case NAME_LOCAL: emit_(OP_STORE_FAST, add_varname(name), line); break;
|
||||
case NAME_GLOBAL: emit_(OP_STORE_GLOBAL, StrName(name).index, line); break;
|
||||
case NAME_GLOBAL_UNKNOWN: emit_(OP_STORE_NAME, StrName(name).index, line); break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NameExpr::emit_(CodeEmitContext* ctx) {
|
||||
void NameExpr::emit_(CodeEmitContext* ctx) {
|
||||
int index = ctx->co->varnames_inv.try_get(name);
|
||||
if(scope == NAME_LOCAL && index >= 0){
|
||||
if(scope == NAME_LOCAL && index >= 0) {
|
||||
ctx->emit_(OP_LOAD_FAST, index, line);
|
||||
}else{
|
||||
} else {
|
||||
Opcode op = ctx->level <= 1 ? OP_LOAD_GLOBAL : OP_LOAD_NONLOCAL;
|
||||
if(ctx->is_compiling_class && scope == NAME_GLOBAL){
|
||||
if(ctx->is_compiling_class && scope == NAME_GLOBAL) {
|
||||
// if we are compiling a class, we should use OP_LOAD_ATTR_GLOBAL instead of OP_LOAD_GLOBAL
|
||||
// this supports @property.setter
|
||||
op = OP_LOAD_CLASS_GLOBAL;
|
||||
// exec()/eval() won't work with OP_LOAD_ATTR_GLOBAL in class body
|
||||
}else{
|
||||
} else {
|
||||
// we cannot determine the scope when calling exec()/eval()
|
||||
if(scope == NAME_GLOBAL_UNKNOWN) op = OP_LOAD_NAME;
|
||||
}
|
||||
ctx->emit_(op, StrName(name).index, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NameExpr::emit_del(CodeEmitContext* ctx) {
|
||||
switch(scope){
|
||||
case NAME_LOCAL:
|
||||
ctx->emit_(OP_DELETE_FAST, ctx->add_varname(name), line);
|
||||
break;
|
||||
case NAME_GLOBAL:
|
||||
ctx->emit_(OP_DELETE_GLOBAL, StrName(name).index, line);
|
||||
break;
|
||||
case NAME_GLOBAL_UNKNOWN:
|
||||
ctx->emit_(OP_DELETE_NAME, StrName(name).index, line);
|
||||
break;
|
||||
bool NameExpr::emit_del(CodeEmitContext* ctx) {
|
||||
switch(scope) {
|
||||
case NAME_LOCAL: ctx->emit_(OP_DELETE_FAST, ctx->add_varname(name), line); break;
|
||||
case NAME_GLOBAL: ctx->emit_(OP_DELETE_GLOBAL, StrName(name).index, line); break;
|
||||
case NAME_GLOBAL_UNKNOWN: ctx->emit_(OP_DELETE_NAME, StrName(name).index, line); break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool NameExpr::emit_store(CodeEmitContext* ctx) {
|
||||
if(ctx->is_compiling_class){
|
||||
bool NameExpr::emit_store(CodeEmitContext* ctx) {
|
||||
if(ctx->is_compiling_class) {
|
||||
ctx->emit_(OP_STORE_CLASS_ATTR, name.index, line);
|
||||
return true;
|
||||
}
|
||||
ctx->emit_store_name(scope, name, line);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void InvertExpr::emit_(CodeEmitContext* ctx) {
|
||||
void InvertExpr::emit_(CodeEmitContext* ctx) {
|
||||
child->emit_(ctx);
|
||||
ctx->emit_(OP_UNARY_INVERT, BC_NOARG, line);
|
||||
}
|
||||
}
|
||||
|
||||
void StarredExpr::emit_(CodeEmitContext* ctx) {
|
||||
void StarredExpr::emit_(CodeEmitContext* ctx) {
|
||||
child->emit_(ctx);
|
||||
ctx->emit_(OP_UNARY_STAR, level, line);
|
||||
}
|
||||
}
|
||||
|
||||
bool StarredExpr::emit_store(CodeEmitContext* ctx) {
|
||||
bool StarredExpr::emit_store(CodeEmitContext* ctx) {
|
||||
if(level != 1) return false;
|
||||
// simply proxy to child
|
||||
return child->emit_store(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void NotExpr::emit_(CodeEmitContext* ctx) {
|
||||
void NotExpr::emit_(CodeEmitContext* ctx) {
|
||||
child->emit_(ctx);
|
||||
ctx->emit_(OP_UNARY_NOT, BC_NOARG, line);
|
||||
}
|
||||
}
|
||||
|
||||
void AndExpr::emit_(CodeEmitContext* ctx) {
|
||||
void AndExpr::emit_(CodeEmitContext* ctx) {
|
||||
lhs->emit_(ctx);
|
||||
int patch = ctx->emit_(OP_JUMP_IF_FALSE_OR_POP, BC_NOARG, line);
|
||||
rhs->emit_(ctx);
|
||||
ctx->patch_jump(patch);
|
||||
}
|
||||
}
|
||||
|
||||
void OrExpr::emit_(CodeEmitContext* ctx) {
|
||||
void OrExpr::emit_(CodeEmitContext* ctx) {
|
||||
lhs->emit_(ctx);
|
||||
int patch = ctx->emit_(OP_JUMP_IF_TRUE_OR_POP, BC_NOARG, line);
|
||||
rhs->emit_(ctx);
|
||||
ctx->patch_jump(patch);
|
||||
}
|
||||
}
|
||||
|
||||
void Literal0Expr::emit_(CodeEmitContext* ctx){
|
||||
switch (token) {
|
||||
void Literal0Expr::emit_(CodeEmitContext* ctx) {
|
||||
switch(token) {
|
||||
case TK("None"): ctx->emit_(OP_LOAD_NONE, BC_NOARG, line); break;
|
||||
case TK("True"): ctx->emit_(OP_LOAD_TRUE, BC_NOARG, line); break;
|
||||
case TK("False"): ctx->emit_(OP_LOAD_FALSE, BC_NOARG, line); break;
|
||||
case TK("..."): ctx->emit_(OP_LOAD_ELLIPSIS, BC_NOARG, line); break;
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LongExpr::emit_(CodeEmitContext* ctx) {
|
||||
void LongExpr::emit_(CodeEmitContext* ctx) {
|
||||
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(s.sv()), line);
|
||||
ctx->emit_(OP_BUILD_LONG, BC_NOARG, line);
|
||||
}
|
||||
}
|
||||
|
||||
void ImagExpr::emit_(CodeEmitContext* ctx) {
|
||||
void ImagExpr::emit_(CodeEmitContext* ctx) {
|
||||
VM* vm = ctx->vm;
|
||||
ctx->emit_(OP_LOAD_CONST, ctx->add_const(VAR(value)), line);
|
||||
ctx->emit_(OP_BUILD_IMAG, BC_NOARG, line);
|
||||
}
|
||||
}
|
||||
|
||||
void BytesExpr::emit_(CodeEmitContext* ctx) {
|
||||
void BytesExpr::emit_(CodeEmitContext* ctx) {
|
||||
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(s.sv()), line);
|
||||
ctx->emit_(OP_BUILD_BYTES, BC_NOARG, line);
|
||||
}
|
||||
}
|
||||
|
||||
void LiteralExpr::emit_(CodeEmitContext* ctx) {
|
||||
void LiteralExpr::emit_(CodeEmitContext* ctx) {
|
||||
VM* vm = ctx->vm;
|
||||
if(std::holds_alternative<i64>(value)){
|
||||
if(std::holds_alternative<i64>(value)) {
|
||||
i64 _val = std::get<i64>(value);
|
||||
ctx->emit_int(_val, line);
|
||||
return;
|
||||
}
|
||||
if(std::holds_alternative<f64>(value)){
|
||||
if(std::holds_alternative<f64>(value)) {
|
||||
f64 _val = std::get<f64>(value);
|
||||
ctx->emit_(OP_LOAD_CONST, ctx->add_const(VAR(_val)), line);
|
||||
return;
|
||||
}
|
||||
if(std::holds_alternative<Str>(value)){
|
||||
if(std::holds_alternative<Str>(value)) {
|
||||
std::string_view key = std::get<Str>(value).sv();
|
||||
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(key), line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NegatedExpr::emit_(CodeEmitContext* ctx){
|
||||
void NegatedExpr::emit_(CodeEmitContext* ctx) {
|
||||
VM* vm = ctx->vm;
|
||||
// if child is a int of float, do constant folding
|
||||
if(child->is_literal()){
|
||||
if(child->is_literal()) {
|
||||
LiteralExpr* lit = static_cast<LiteralExpr*>(child.get());
|
||||
if(std::holds_alternative<i64>(lit->value)){
|
||||
if(std::holds_alternative<i64>(lit->value)) {
|
||||
i64 _val = -std::get<i64>(lit->value);
|
||||
ctx->emit_int(_val, line);
|
||||
return;
|
||||
}
|
||||
if(std::holds_alternative<f64>(lit->value)){
|
||||
if(std::holds_alternative<f64>(lit->value)) {
|
||||
f64 _val = -std::get<f64>(lit->value);
|
||||
ctx->emit_(OP_LOAD_CONST, ctx->add_const(VAR(_val)), line);
|
||||
return;
|
||||
@ -303,91 +291,92 @@ namespace pkpy{
|
||||
}
|
||||
child->emit_(ctx);
|
||||
ctx->emit_(OP_UNARY_NEGATIVE, BC_NOARG, line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SliceExpr::emit_(CodeEmitContext* ctx){
|
||||
if(start){
|
||||
void SliceExpr::emit_(CodeEmitContext* ctx) {
|
||||
if(start) {
|
||||
start->emit_(ctx);
|
||||
}else{
|
||||
} else {
|
||||
ctx->emit_(OP_LOAD_NONE, BC_NOARG, line);
|
||||
}
|
||||
|
||||
if(stop){
|
||||
if(stop) {
|
||||
stop->emit_(ctx);
|
||||
}else{
|
||||
} else {
|
||||
ctx->emit_(OP_LOAD_NONE, BC_NOARG, line);
|
||||
}
|
||||
|
||||
if(step){
|
||||
if(step) {
|
||||
step->emit_(ctx);
|
||||
}else{
|
||||
} else {
|
||||
ctx->emit_(OP_LOAD_NONE, BC_NOARG, line);
|
||||
}
|
||||
|
||||
ctx->emit_(OP_BUILD_SLICE, BC_NOARG, line);
|
||||
}
|
||||
}
|
||||
|
||||
void DictItemExpr::emit_(CodeEmitContext* ctx) {
|
||||
if(is_starred()){
|
||||
void DictItemExpr::emit_(CodeEmitContext* ctx) {
|
||||
if(is_starred()) {
|
||||
assert(key == nullptr);
|
||||
value->emit_(ctx);
|
||||
}else{
|
||||
} else {
|
||||
value->emit_(ctx);
|
||||
key->emit_(ctx); // reverse order
|
||||
ctx->emit_(OP_BUILD_TUPLE, 2, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TupleExpr::emit_store(CodeEmitContext* ctx) {
|
||||
bool TupleExpr::emit_store(CodeEmitContext* ctx) {
|
||||
// TOS is an iterable
|
||||
// items may contain StarredExpr, we should check it
|
||||
int starred_i = -1;
|
||||
for(int i=0; i<items.size(); i++){
|
||||
for(int i = 0; i < items.size(); i++) {
|
||||
if(!items[i]->is_starred()) continue;
|
||||
if(starred_i == -1) starred_i = i;
|
||||
else return false; // multiple StarredExpr not allowed
|
||||
if(starred_i == -1)
|
||||
starred_i = i;
|
||||
else
|
||||
return false; // multiple StarredExpr not allowed
|
||||
}
|
||||
|
||||
if(starred_i == -1){
|
||||
if(starred_i == -1) {
|
||||
Bytecode& prev = ctx->co->codes.back();
|
||||
if(prev.op == OP_BUILD_TUPLE && prev.arg == items.size()){
|
||||
if(prev.op == OP_BUILD_TUPLE && prev.arg == items.size()) {
|
||||
// build tuple and unpack it is meaningless
|
||||
ctx->revert_last_emit_();
|
||||
}else{
|
||||
if(prev.op == OP_FOR_ITER){
|
||||
} else {
|
||||
if(prev.op == OP_FOR_ITER) {
|
||||
prev.op = OP_FOR_ITER_UNPACK;
|
||||
prev.arg = items.size();
|
||||
}else{
|
||||
} else {
|
||||
ctx->emit_(OP_UNPACK_SEQUENCE, items.size(), line);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
// starred assignment target must be in a tuple
|
||||
if(items.size() == 1) return false;
|
||||
// starred assignment target must be the last one (differ from cpython)
|
||||
if(starred_i != items.size()-1) return false;
|
||||
if(starred_i != items.size() - 1) return false;
|
||||
// a,*b = [1,2,3]
|
||||
// stack is [1,2,3] -> [1,[2,3]]
|
||||
ctx->emit_(OP_UNPACK_EX, items.size()-1, line);
|
||||
ctx->emit_(OP_UNPACK_EX, items.size() - 1, line);
|
||||
}
|
||||
// do reverse emit
|
||||
for(int i=items.size()-1; i>=0; i--){
|
||||
for(int i = items.size() - 1; i >= 0; i--) {
|
||||
bool ok = items[i]->emit_store(ctx);
|
||||
if(!ok) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool TupleExpr::emit_del(CodeEmitContext* ctx){
|
||||
for(auto& e: items){
|
||||
bool TupleExpr::emit_del(CodeEmitContext* ctx) {
|
||||
for(auto& e: items) {
|
||||
bool ok = e->emit_del(ctx);
|
||||
if(!ok) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void CompExpr::emit_(CodeEmitContext* ctx){
|
||||
void CompExpr::emit_(CodeEmitContext* ctx) {
|
||||
ctx->emit_(op0(), 0, line);
|
||||
iter->emit_(ctx);
|
||||
ctx->emit_(OP_GET_ITER, BC_NOARG, BC_KEEPLINE);
|
||||
@ -398,41 +387,46 @@ namespace pkpy{
|
||||
// this error occurs in `vars` instead of this line, but...nevermind
|
||||
assert(ok); // this should raise a SyntaxError, but we just assert it
|
||||
ctx->try_merge_for_iter_store(for_codei);
|
||||
if(cond){
|
||||
if(cond) {
|
||||
cond->emit_(ctx);
|
||||
int patch = ctx->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE);
|
||||
expr->emit_(ctx);
|
||||
ctx->emit_(op1(), BC_NOARG, BC_KEEPLINE);
|
||||
ctx->patch_jump(patch);
|
||||
}else{
|
||||
} else {
|
||||
expr->emit_(ctx);
|
||||
ctx->emit_(op1(), BC_NOARG, BC_KEEPLINE);
|
||||
}
|
||||
ctx->emit_(OP_LOOP_CONTINUE, curr_iblock, BC_KEEPLINE);
|
||||
ctx->exit_block();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FStringExpr::_load_simple_expr(CodeEmitContext* ctx, Str expr){
|
||||
void FStringExpr::_load_simple_expr(CodeEmitContext* ctx, Str expr) {
|
||||
bool repr = false;
|
||||
if(expr.size>=2 && expr.end()[-2]=='!'){
|
||||
switch(expr.end()[-1]){
|
||||
case 'r': repr = true; expr = expr.substr(0, expr.size-2); break;
|
||||
case 's': repr = false; expr = expr.substr(0, expr.size-2); break;
|
||||
if(expr.size >= 2 && expr.end()[-2] == '!') {
|
||||
switch(expr.end()[-1]) {
|
||||
case 'r':
|
||||
repr = true;
|
||||
expr = expr.substr(0, expr.size - 2);
|
||||
break;
|
||||
case 's':
|
||||
repr = false;
|
||||
expr = expr.substr(0, expr.size - 2);
|
||||
break;
|
||||
default: break; // nothing happens
|
||||
}
|
||||
}
|
||||
// name or name.name
|
||||
bool is_fastpath = false;
|
||||
if(is_identifier(expr.sv())){
|
||||
if(is_identifier(expr.sv())) {
|
||||
ctx->emit_(OP_LOAD_NAME, StrName(expr.sv()).index, line);
|
||||
is_fastpath = true;
|
||||
}else{
|
||||
} else {
|
||||
int dot = expr.index(".");
|
||||
if(dot > 0){
|
||||
if(dot > 0) {
|
||||
std::string_view a = expr.sv().substr(0, dot);
|
||||
std::string_view b = expr.sv().substr(dot+1);
|
||||
if(is_identifier(a) && is_identifier(b)){
|
||||
std::string_view b = expr.sv().substr(dot + 1);
|
||||
if(is_identifier(a) && is_identifier(b)) {
|
||||
ctx->emit_(OP_LOAD_NAME, StrName(a).index, line);
|
||||
ctx->emit_(OP_LOAD_ATTR, StrName(b).index, line);
|
||||
is_fastpath = true;
|
||||
@ -440,88 +434,93 @@ namespace pkpy{
|
||||
}
|
||||
}
|
||||
|
||||
if(!is_fastpath){
|
||||
if(!is_fastpath) {
|
||||
int index = ctx->add_const_string(expr.sv());
|
||||
ctx->emit_(OP_FSTRING_EVAL, index, line);
|
||||
}
|
||||
|
||||
if(repr){
|
||||
ctx->emit_(OP_REPR, BC_NOARG, line);
|
||||
}
|
||||
}
|
||||
if(repr) { ctx->emit_(OP_REPR, BC_NOARG, line); }
|
||||
}
|
||||
|
||||
static bool is_fmt_valid_char(char c){
|
||||
switch(c){
|
||||
static bool is_fmt_valid_char(char c) {
|
||||
switch(c) {
|
||||
// clang-format off
|
||||
case '-': case '=': case '*': case '#': case '@': case '!': case '~':
|
||||
case '<': case '>': case '^':
|
||||
case '.': case 'f': case 'd': case 's':
|
||||
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
|
||||
return true;
|
||||
default: return false;
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FStringExpr::emit_(CodeEmitContext* ctx){
|
||||
void FStringExpr::emit_(CodeEmitContext* ctx) {
|
||||
int i = 0; // left index
|
||||
int j = 0; // right index
|
||||
int count = 0; // how many string parts
|
||||
bool flag = false; // true if we are in a expression
|
||||
|
||||
while(j < src.size){
|
||||
if(flag){
|
||||
if(src[j] == '}'){
|
||||
while(j < src.size) {
|
||||
if(flag) {
|
||||
if(src[j] == '}') {
|
||||
// add expression
|
||||
Str expr = src.substr(i, j-i);
|
||||
Str expr = src.substr(i, j - i);
|
||||
// BUG: ':' is not a format specifier in f"{stack[2:]}"
|
||||
int conon = expr.index(":");
|
||||
if(conon >= 0){
|
||||
Str spec = expr.substr(conon+1);
|
||||
if(conon >= 0) {
|
||||
Str spec = expr.substr(conon + 1);
|
||||
// filter some invalid spec
|
||||
bool ok = true;
|
||||
for(char c: spec) if(!is_fmt_valid_char(c)){ ok = false; break; }
|
||||
if(ok){
|
||||
for(char c: spec)
|
||||
if(!is_fmt_valid_char(c)) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
if(ok) {
|
||||
_load_simple_expr(ctx, expr.substr(0, conon));
|
||||
ctx->emit_(OP_FORMAT_STRING, ctx->add_const_string(spec.sv()), line);
|
||||
}else{
|
||||
} else {
|
||||
// ':' is not a spec indicator
|
||||
_load_simple_expr(ctx, expr);
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
_load_simple_expr(ctx, expr);
|
||||
}
|
||||
flag = false;
|
||||
count++;
|
||||
}
|
||||
}else{
|
||||
if(src[j] == '{'){
|
||||
} else {
|
||||
if(src[j] == '{') {
|
||||
// look at next char
|
||||
if(j+1 < src.size && src[j+1] == '{'){
|
||||
if(j + 1 < src.size && src[j + 1] == '{') {
|
||||
// {{ -> {
|
||||
j++;
|
||||
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string("{"), line);
|
||||
count++;
|
||||
}else{
|
||||
} else {
|
||||
// { -> }
|
||||
flag = true;
|
||||
i = j+1;
|
||||
i = j + 1;
|
||||
}
|
||||
}else if(src[j] == '}'){
|
||||
} else if(src[j] == '}') {
|
||||
// look at next char
|
||||
if(j+1 < src.size && src[j+1] == '}'){
|
||||
if(j + 1 < src.size && src[j + 1] == '}') {
|
||||
// }} -> }
|
||||
j++;
|
||||
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string("}"), line);
|
||||
count++;
|
||||
}else{
|
||||
} else {
|
||||
// } -> error
|
||||
// throw std::runtime_error("f-string: unexpected }");
|
||||
// just ignore
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
// literal
|
||||
i = j;
|
||||
while(j < src.size && src[j] != '{' && src[j] != '}') j++;
|
||||
Str literal = src.substr(i, j-i);
|
||||
while(j < src.size && src[j] != '{' && src[j] != '}')
|
||||
j++;
|
||||
Str literal = src.substr(i, j - i);
|
||||
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(literal.sv()), line);
|
||||
count++;
|
||||
continue; // skip j++
|
||||
@ -530,126 +529,128 @@ namespace pkpy{
|
||||
j++;
|
||||
}
|
||||
|
||||
if(flag){
|
||||
if(flag) {
|
||||
// literal
|
||||
Str literal = src.substr(i, src.size-i);
|
||||
Str literal = src.substr(i, src.size - i);
|
||||
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(literal.sv()), line);
|
||||
count++;
|
||||
}
|
||||
|
||||
ctx->emit_(OP_BUILD_STRING, count, line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SubscrExpr::emit_(CodeEmitContext* ctx){
|
||||
void SubscrExpr::emit_(CodeEmitContext* ctx) {
|
||||
a->emit_(ctx);
|
||||
b->emit_(ctx);
|
||||
Bytecode last_bc = ctx->co->codes.back();
|
||||
if(b->is_name() && last_bc.op == OP_LOAD_FAST){
|
||||
if(b->is_name() && last_bc.op == OP_LOAD_FAST) {
|
||||
ctx->revert_last_emit_();
|
||||
ctx->emit_(OP_LOAD_SUBSCR_FAST, last_bc.arg, line);
|
||||
}else if(b->is_literal() && last_bc.op == OP_LOAD_SMALL_INT){
|
||||
} else if(b->is_literal() && last_bc.op == OP_LOAD_SMALL_INT) {
|
||||
ctx->revert_last_emit_();
|
||||
ctx->emit_(OP_LOAD_SUBSCR_SMALL_INT, last_bc.arg, line);
|
||||
}else{
|
||||
} else {
|
||||
ctx->emit_(OP_LOAD_SUBSCR, BC_NOARG, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SubscrExpr::emit_store(CodeEmitContext* ctx){
|
||||
bool SubscrExpr::emit_store(CodeEmitContext* ctx) {
|
||||
a->emit_(ctx);
|
||||
b->emit_(ctx);
|
||||
Bytecode last_bc = ctx->co->codes.back();
|
||||
if(b->is_name() && last_bc.op == OP_LOAD_FAST){
|
||||
if(b->is_name() && last_bc.op == OP_LOAD_FAST) {
|
||||
ctx->revert_last_emit_();
|
||||
ctx->emit_(OP_STORE_SUBSCR_FAST, last_bc.arg, line);
|
||||
}else{
|
||||
} else {
|
||||
ctx->emit_(OP_STORE_SUBSCR, BC_NOARG, line);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void SubscrExpr::emit_inplace(CodeEmitContext* ctx){
|
||||
void SubscrExpr::emit_inplace(CodeEmitContext* ctx) {
|
||||
a->emit_(ctx);
|
||||
b->emit_(ctx);
|
||||
ctx->emit_(OP_DUP_TOP_TWO, BC_NOARG, line);
|
||||
ctx->emit_(OP_LOAD_SUBSCR, BC_NOARG, line);
|
||||
}
|
||||
}
|
||||
|
||||
bool SubscrExpr::emit_store_inplace(CodeEmitContext* ctx){
|
||||
bool SubscrExpr::emit_store_inplace(CodeEmitContext* ctx) {
|
||||
// [a, b, val] -> [val, a, b]
|
||||
ctx->emit_(OP_ROT_THREE, BC_NOARG, line);
|
||||
ctx->emit_(OP_STORE_SUBSCR, BC_NOARG, line);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool SubscrExpr::emit_del(CodeEmitContext* ctx){
|
||||
bool SubscrExpr::emit_del(CodeEmitContext* ctx) {
|
||||
a->emit_(ctx);
|
||||
b->emit_(ctx);
|
||||
ctx->emit_(OP_DELETE_SUBSCR, BC_NOARG, line);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void AttribExpr::emit_(CodeEmitContext* ctx){
|
||||
void AttribExpr::emit_(CodeEmitContext* ctx) {
|
||||
a->emit_(ctx);
|
||||
ctx->emit_(OP_LOAD_ATTR, b.index, line);
|
||||
}
|
||||
}
|
||||
|
||||
bool AttribExpr::emit_del(CodeEmitContext* ctx) {
|
||||
bool AttribExpr::emit_del(CodeEmitContext* ctx) {
|
||||
a->emit_(ctx);
|
||||
ctx->emit_(OP_DELETE_ATTR, b.index, line);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool AttribExpr::emit_store(CodeEmitContext* ctx){
|
||||
bool AttribExpr::emit_store(CodeEmitContext* ctx) {
|
||||
a->emit_(ctx);
|
||||
ctx->emit_(OP_STORE_ATTR, b.index, line);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void AttribExpr::emit_method(CodeEmitContext* ctx) {
|
||||
void AttribExpr::emit_method(CodeEmitContext* ctx) {
|
||||
a->emit_(ctx);
|
||||
ctx->emit_(OP_LOAD_METHOD, b.index, line);
|
||||
}
|
||||
}
|
||||
|
||||
void AttribExpr::emit_inplace(CodeEmitContext* ctx) {
|
||||
void AttribExpr::emit_inplace(CodeEmitContext* ctx) {
|
||||
a->emit_(ctx);
|
||||
ctx->emit_(OP_DUP_TOP, BC_NOARG, line);
|
||||
ctx->emit_(OP_LOAD_ATTR, b.index, line);
|
||||
}
|
||||
}
|
||||
|
||||
bool AttribExpr::emit_store_inplace(CodeEmitContext* ctx) {
|
||||
bool AttribExpr::emit_store_inplace(CodeEmitContext* ctx) {
|
||||
// [a, val] -> [val, a]
|
||||
ctx->emit_(OP_ROT_TWO, BC_NOARG, line);
|
||||
ctx->emit_(OP_STORE_ATTR, b.index, line);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void CallExpr::emit_(CodeEmitContext* ctx) {
|
||||
void CallExpr::emit_(CodeEmitContext* ctx) {
|
||||
bool vargs = false;
|
||||
bool vkwargs = false;
|
||||
for(auto& arg: args) if(arg->is_starred()) vargs = true;
|
||||
for(auto& item: kwargs) if(item.second->is_starred()) vkwargs = true;
|
||||
for(auto& arg: args)
|
||||
if(arg->is_starred()) vargs = true;
|
||||
for(auto& item: kwargs)
|
||||
if(item.second->is_starred()) vkwargs = true;
|
||||
|
||||
// if callable is a AttrExpr, we should try to use `fast_call` instead of use `boundmethod` proxy
|
||||
if(callable->is_attrib()){
|
||||
if(callable->is_attrib()) {
|
||||
auto p = static_cast<AttribExpr*>(callable.get());
|
||||
p->emit_method(ctx); // OP_LOAD_METHOD
|
||||
}else{
|
||||
} else {
|
||||
callable->emit_(ctx);
|
||||
ctx->emit_(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE);
|
||||
}
|
||||
|
||||
if(vargs || vkwargs){
|
||||
for(auto& item: args) item->emit_(ctx);
|
||||
if(vargs || vkwargs) {
|
||||
for(auto& item: args)
|
||||
item->emit_(ctx);
|
||||
ctx->emit_(OP_BUILD_TUPLE_UNPACK, (uint16_t)args.size(), line);
|
||||
|
||||
if(!kwargs.empty()){
|
||||
for(auto& item: kwargs){
|
||||
if(item.second->is_starred()){
|
||||
if(!kwargs.empty()) {
|
||||
for(auto& item: kwargs) {
|
||||
if(item.second->is_starred()) {
|
||||
assert(item.second->star_level() == 2);
|
||||
item.second->emit_(ctx);
|
||||
}else{
|
||||
} else {
|
||||
// k=v
|
||||
int index = ctx->add_const_string(item.first.sv());
|
||||
ctx->emit_(OP_LOAD_CONST, index, line);
|
||||
@ -659,42 +660,46 @@ namespace pkpy{
|
||||
}
|
||||
ctx->emit_(OP_BUILD_DICT_UNPACK, (int)kwargs.size(), line);
|
||||
ctx->emit_(OP_CALL_TP, 1, line);
|
||||
}else{
|
||||
} else {
|
||||
ctx->emit_(OP_CALL_TP, 0, line);
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
// vectorcall protocol
|
||||
for(auto& item: args) item->emit_(ctx);
|
||||
for(auto& item: kwargs){
|
||||
for(auto& item: args)
|
||||
item->emit_(ctx);
|
||||
for(auto& item: kwargs) {
|
||||
i64 _val = StrName(item.first.sv()).index;
|
||||
ctx->emit_int(_val, line);
|
||||
item.second->emit_(ctx);
|
||||
}
|
||||
int KWARGC = kwargs.size();
|
||||
int ARGC = args.size();
|
||||
ctx->emit_(OP_CALL, (KWARGC<<8)|ARGC, line);
|
||||
}
|
||||
ctx->emit_(OP_CALL, (KWARGC << 8) | ARGC, line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool BinaryExpr::is_compare() const {
|
||||
switch(op){
|
||||
case TK("<"): case TK("<="): case TK("=="):
|
||||
case TK("!="): case TK(">"): case TK(">="): return true;
|
||||
bool BinaryExpr::is_compare() const {
|
||||
switch(op) {
|
||||
case TK("<"):
|
||||
case TK("<="):
|
||||
case TK("=="):
|
||||
case TK("!="):
|
||||
case TK(">"):
|
||||
case TK(">="): return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryExpr::_emit_compare(CodeEmitContext* ctx, small_vector_2<int, 6>& jmps){
|
||||
if(lhs->is_compare()){
|
||||
void BinaryExpr::_emit_compare(CodeEmitContext* ctx, small_vector_2<int, 6>& jmps) {
|
||||
if(lhs->is_compare()) {
|
||||
static_cast<BinaryExpr*>(lhs.get())->_emit_compare(ctx, jmps);
|
||||
}else{
|
||||
} else {
|
||||
lhs->emit_(ctx); // [a]
|
||||
}
|
||||
rhs->emit_(ctx); // [a, b]
|
||||
ctx->emit_(OP_DUP_TOP, BC_NOARG, line); // [a, b, b]
|
||||
ctx->emit_(OP_ROT_THREE, BC_NOARG, line); // [b, a, b]
|
||||
switch(op){
|
||||
switch(op) {
|
||||
case TK("<"): ctx->emit_(OP_COMPARE_LT, BC_NOARG, line); break;
|
||||
case TK("<="): ctx->emit_(OP_COMPARE_LE, BC_NOARG, line); break;
|
||||
case TK("=="): ctx->emit_(OP_COMPARE_EQ, BC_NOARG, line); break;
|
||||
@ -706,25 +711,25 @@ namespace pkpy{
|
||||
// [b, RES]
|
||||
int index = ctx->emit_(OP_SHORTCUT_IF_FALSE_OR_POP, BC_NOARG, line);
|
||||
jmps.push_back(index);
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryExpr::emit_(CodeEmitContext* ctx) {
|
||||
void BinaryExpr::emit_(CodeEmitContext* ctx) {
|
||||
small_vector_2<int, 6> jmps;
|
||||
if(is_compare() && lhs->is_compare()){
|
||||
if(is_compare() && lhs->is_compare()) {
|
||||
// (a < b) < c
|
||||
static_cast<BinaryExpr*>(lhs.get())->_emit_compare(ctx, jmps);
|
||||
// [b, RES]
|
||||
}else{
|
||||
} else {
|
||||
// (1 + 2) < c
|
||||
if(inplace){
|
||||
if(inplace) {
|
||||
lhs->emit_inplace(ctx);
|
||||
}else{
|
||||
} else {
|
||||
lhs->emit_(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
rhs->emit_(ctx);
|
||||
switch (op) {
|
||||
switch(op) {
|
||||
case TK("+"): ctx->emit_(OP_BINARY_ADD, BC_NOARG, line); break;
|
||||
case TK("-"): ctx->emit_(OP_BINARY_SUB, BC_NOARG, line); break;
|
||||
case TK("*"): ctx->emit_(OP_BINARY_MUL, BC_NOARG, line); break;
|
||||
@ -755,10 +760,11 @@ namespace pkpy{
|
||||
default: assert(false);
|
||||
}
|
||||
|
||||
for(int i: jmps) ctx->patch_jump(i);
|
||||
}
|
||||
for(int i: jmps)
|
||||
ctx->patch_jump(i);
|
||||
}
|
||||
|
||||
void TernaryExpr::emit_(CodeEmitContext* ctx){
|
||||
void TernaryExpr::emit_(CodeEmitContext* ctx) {
|
||||
cond->emit_(ctx);
|
||||
int patch = ctx->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, cond->line);
|
||||
true_expr->emit_(ctx);
|
||||
@ -766,6 +772,6 @@ namespace pkpy{
|
||||
ctx->patch_jump(patch);
|
||||
false_expr->emit_(ctx);
|
||||
ctx->patch_jump(patch_2);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,18 +1,22 @@
|
||||
#include "pocketpy/compiler/lexer.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
// clang-format off
|
||||
static const uint32_t kLoRangeA[] = {170,186,443,448,660,1488,1519,1568,1601,1646,1649,1749,1774,1786,1791,1808,1810,1869,1969,1994,2048,2112,2144,2208,2230,2308,2365,2384,2392,2418,2437,2447,2451,2474,2482,2486,2493,2510,2524,2527,2544,2556,2565,2575,2579,2602,2610,2613,2616,2649,2654,2674,2693,2703,2707,2730,2738,2741,2749,2768,2784,2809,2821,2831,2835,2858,2866,2869,2877,2908,2911,2929,2947,2949,2958,2962,2969,2972,2974,2979,2984,2990,3024,3077,3086,3090,3114,3133,3160,3168,3200,3205,3214,3218,3242,3253,3261,3294,3296,3313,3333,3342,3346,3389,3406,3412,3423,3450,3461,3482,3507,3517,3520,3585,3634,3648,3713,3716,3718,3724,3749,3751,3762,3773,3776,3804,3840,3904,3913,3976,4096,4159,4176,4186,4193,4197,4206,4213,4238,4352,4682,4688,4696,4698,4704,4746,4752,4786,4792,4800,4802,4808,4824,4882,4888,4992,5121,5743,5761,5792,5873,5888,5902,5920,5952,5984,5998,6016,6108,6176,6212,6272,6279,6314,6320,6400,6480,6512,6528,6576,6656,6688,6917,6981,7043,7086,7098,7168,7245,7258,7401,7406,7413,7418,8501,11568,11648,11680,11688,11696,11704,11712,11720,11728,11736,12294,12348,12353,12447,12449,12543,12549,12593,12704,12784,13312,19968,40960,40982,42192,42240,42512,42538,42606,42656,42895,42999,43003,43011,43015,43020,43072,43138,43250,43259,43261,43274,43312,43360,43396,43488,43495,43514,43520,43584,43588,43616,43633,43642,43646,43697,43701,43705,43712,43714,43739,43744,43762,43777,43785,43793,43808,43816,43968,44032,55216,55243,63744,64112,64285,64287,64298,64312,64318,64320,64323,64326,64467,64848,64914,65008,65136,65142,65382,65393,65440,65474,65482,65490,65498,65536,65549,65576,65596,65599,65616,65664,66176,66208,66304,66349,66370,66384,66432,66464,66504,66640,66816,66864,67072,67392,67424,67584,67592,67594,67639,67644,67647,67680,67712,67808,67828,67840,67872,67968,68030,68096,68112,68117,68121,68192,68224,68288,68297,68352,68416,68448,68480,68608,68864,69376,69415,69424,69600,69635,69763,69840,69891,69956,69968,70006,70019,70081,70106,70108,70144,70163,70272,70280,70282,70287,70303,70320,70405,70415,70419,70442,70450,70453,70461,70480,70493,70656,70727,70751,70784,70852,70855,71040,71128,71168,71236,71296,71352,71424,71680,71935,72096,72106,72161,72163,72192,72203,72250,72272,72284,72349,72384,72704,72714,72768,72818,72960,72968,72971,73030,73056,73063,73066,73112,73440,73728,74880,77824,82944,92160,92736,92880,92928,93027,93053,93952,94032,94208,100352,110592,110928,110948,110960,113664,113776,113792,113808,123136,123214,123584,124928,126464,126469,126497,126500,126503,126505,126516,126521,126523,126530,126535,126537,126539,126541,126545,126548,126551,126553,126555,126557,126559,126561,126564,126567,126572,126580,126585,126590,126592,126603,126625,126629,126635,131072,173824,177984,178208,183984,194560};
|
||||
static const uint32_t kLoRangeB[] = {170,186,443,451,660,1514,1522,1599,1610,1647,1747,1749,1775,1788,1791,1808,1839,1957,1969,2026,2069,2136,2154,2228,2237,2361,2365,2384,2401,2432,2444,2448,2472,2480,2482,2489,2493,2510,2525,2529,2545,2556,2570,2576,2600,2608,2611,2614,2617,2652,2654,2676,2701,2705,2728,2736,2739,2745,2749,2768,2785,2809,2828,2832,2856,2864,2867,2873,2877,2909,2913,2929,2947,2954,2960,2965,2970,2972,2975,2980,2986,3001,3024,3084,3088,3112,3129,3133,3162,3169,3200,3212,3216,3240,3251,3257,3261,3294,3297,3314,3340,3344,3386,3389,3406,3414,3425,3455,3478,3505,3515,3517,3526,3632,3635,3653,3714,3716,3722,3747,3749,3760,3763,3773,3780,3807,3840,3911,3948,3980,4138,4159,4181,4189,4193,4198,4208,4225,4238,4680,4685,4694,4696,4701,4744,4749,4784,4789,4798,4800,4805,4822,4880,4885,4954,5007,5740,5759,5786,5866,5880,5900,5905,5937,5969,5996,6000,6067,6108,6210,6264,6276,6312,6314,6389,6430,6509,6516,6571,6601,6678,6740,6963,6987,7072,7087,7141,7203,7247,7287,7404,7411,7414,7418,8504,11623,11670,11686,11694,11702,11710,11718,11726,11734,11742,12294,12348,12438,12447,12538,12543,12591,12686,12730,12799,19893,40943,40980,42124,42231,42507,42527,42539,42606,42725,42895,42999,43009,43013,43018,43042,43123,43187,43255,43259,43262,43301,43334,43388,43442,43492,43503,43518,43560,43586,43595,43631,43638,43642,43695,43697,43702,43709,43712,43714,43740,43754,43762,43782,43790,43798,43814,43822,44002,55203,55238,55291,64109,64217,64285,64296,64310,64316,64318,64321,64324,64433,64829,64911,64967,65019,65140,65276,65391,65437,65470,65479,65487,65495,65500,65547,65574,65594,65597,65613,65629,65786,66204,66256,66335,66368,66377,66421,66461,66499,66511,66717,66855,66915,67382,67413,67431,67589,67592,67637,67640,67644,67669,67702,67742,67826,67829,67861,67897,68023,68031,68096,68115,68119,68149,68220,68252,68295,68324,68405,68437,68466,68497,68680,68899,69404,69415,69445,69622,69687,69807,69864,69926,69956,70002,70006,70066,70084,70106,70108,70161,70187,70278,70280,70285,70301,70312,70366,70412,70416,70440,70448,70451,70457,70461,70480,70497,70708,70730,70751,70831,70853,70855,71086,71131,71215,71236,71338,71352,71450,71723,71935,72103,72144,72161,72163,72192,72242,72250,72272,72329,72349,72440,72712,72750,72768,72847,72966,72969,73008,73030,73061,73064,73097,73112,73458,74649,75075,78894,83526,92728,92766,92909,92975,93047,93071,94026,94032,100343,101106,110878,110930,110951,111355,113770,113788,113800,113817,123180,123214,123627,125124,126467,126495,126498,126500,126503,126514,126519,126521,126523,126530,126535,126537,126539,126543,126546,126548,126551,126553,126555,126557,126559,126562,126564,126570,126578,126583,126588,126590,126601,126619,126627,126633,126651,173782,177972,178205,183969,191456,195101};
|
||||
// clang-format on
|
||||
|
||||
static bool is_possible_number_char(char c){
|
||||
switch(c){
|
||||
static bool is_possible_number_char(char c) {
|
||||
switch(c) {
|
||||
// clang-format off
|
||||
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
|
||||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
||||
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
||||
case '.': case 'L': case 'x': case 'o': case 'j':
|
||||
return true;
|
||||
default: return false;
|
||||
// clang-format on
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,85 +30,86 @@ static bool is_unicode_Lo_char(uint32_t c) {
|
||||
return c >= kLoRangeA[index] && c <= kLoRangeB[index];
|
||||
}
|
||||
|
||||
bool Lexer::match_n_chars(int n, char c0){
|
||||
bool Lexer::match_n_chars(int n, char c0) {
|
||||
const char* c = curr_char;
|
||||
for(int i=0; i<n; i++){
|
||||
for(int i = 0; i < n; i++) {
|
||||
if(*c == '\0') return false;
|
||||
if(*c != c0) return false;
|
||||
c++;
|
||||
}
|
||||
for(int i=0; i<n; i++) eatchar_include_newline();
|
||||
for(int i = 0; i < n; i++)
|
||||
eatchar_include_newline();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Lexer::match_string(const char* s){
|
||||
bool Lexer::match_string(const char* s) {
|
||||
int s_len = strlen(s);
|
||||
bool ok = strncmp(curr_char, s, s_len) == 0;
|
||||
if(ok) for(int i=0; i<s_len; i++) eatchar_include_newline();
|
||||
if(ok)
|
||||
for(int i = 0; i < s_len; i++)
|
||||
eatchar_include_newline();
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
|
||||
int Lexer::eat_spaces(){
|
||||
int Lexer::eat_spaces() {
|
||||
int count = 0;
|
||||
while (true) {
|
||||
switch (peekchar()) {
|
||||
case ' ' : count+=1; break;
|
||||
case '\t': count+=4; break;
|
||||
while(true) {
|
||||
switch(peekchar()) {
|
||||
case ' ': count += 1; break;
|
||||
case '\t': count += 4; break;
|
||||
default: return count;
|
||||
}
|
||||
eatchar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Lexer::eat_indentation(){
|
||||
bool Lexer::eat_indentation() {
|
||||
if(brackets_level > 0) return true;
|
||||
int spaces = eat_spaces();
|
||||
if(peekchar() == '#') skip_line_comment();
|
||||
if(peekchar() == '\0' || peekchar() == '\n') return true;
|
||||
// https://docs.python.org/3/reference/lexical_analysis.html#indentation
|
||||
if(spaces > indents.top()){
|
||||
if(spaces > indents.top()) {
|
||||
indents.push(spaces);
|
||||
nexts.push_back(Token{TK("@indent"), token_start, 0, current_line, brackets_level, {}});
|
||||
} else if(spaces < indents.top()){
|
||||
while(spaces < indents.top()){
|
||||
} else if(spaces < indents.top()) {
|
||||
while(spaces < indents.top()) {
|
||||
indents.pop();
|
||||
nexts.push_back(Token{TK("@dedent"), token_start, 0, current_line, brackets_level, {}});
|
||||
}
|
||||
if(spaces != indents.top()){
|
||||
return false;
|
||||
}
|
||||
if(spaces != indents.top()) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
char Lexer::eatchar() {
|
||||
char Lexer::eatchar() {
|
||||
char c = peekchar();
|
||||
assert(c != '\n'); // eatchar() cannot consume a newline
|
||||
curr_char++;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
char Lexer::eatchar_include_newline() {
|
||||
char Lexer::eatchar_include_newline() {
|
||||
char c = peekchar();
|
||||
curr_char++;
|
||||
if (c == '\n'){
|
||||
if(c == '\n') {
|
||||
current_line++;
|
||||
src->line_starts.push_back(curr_char);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
int Lexer::eat_name() {
|
||||
int Lexer::eat_name() {
|
||||
curr_char--;
|
||||
while(true){
|
||||
while(true) {
|
||||
unsigned char c = peekchar();
|
||||
int u8bytes = utf8len(c, true);
|
||||
if(u8bytes == 0) return 1;
|
||||
if(u8bytes == 1){
|
||||
if(isalpha(c) || c=='_' || isdigit(c)) {
|
||||
if(u8bytes == 1) {
|
||||
if(isalpha(c) || c == '_' || isdigit(c)) {
|
||||
curr_char++;
|
||||
continue;
|
||||
}else{
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -112,30 +117,35 @@ static bool is_unicode_Lo_char(uint32_t c) {
|
||||
Str u8str(curr_char, u8bytes);
|
||||
if(u8str.size != u8bytes) return 2;
|
||||
uint32_t value = 0;
|
||||
for(int k=0; k < u8bytes; k++){
|
||||
for(int k = 0; k < u8bytes; k++) {
|
||||
uint8_t b = u8str[k];
|
||||
if(k==0){
|
||||
if(u8bytes == 2) value = (b & 0b00011111) << 6;
|
||||
else if(u8bytes == 3) value = (b & 0b00001111) << 12;
|
||||
else if(u8bytes == 4) value = (b & 0b00000111) << 18;
|
||||
}else{
|
||||
value |= (b & 0b00111111) << (6*(u8bytes-k-1));
|
||||
if(k == 0) {
|
||||
if(u8bytes == 2)
|
||||
value = (b & 0b00011111) << 6;
|
||||
else if(u8bytes == 3)
|
||||
value = (b & 0b00001111) << 12;
|
||||
else if(u8bytes == 4)
|
||||
value = (b & 0b00000111) << 18;
|
||||
} else {
|
||||
value |= (b & 0b00111111) << (6 * (u8bytes - k - 1));
|
||||
}
|
||||
}
|
||||
if(is_unicode_Lo_char(value)) curr_char += u8bytes;
|
||||
else break;
|
||||
if(is_unicode_Lo_char(value))
|
||||
curr_char += u8bytes;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
int length = (int)(curr_char - token_start);
|
||||
if(length == 0) return 3;
|
||||
std::string_view name(token_start, length);
|
||||
|
||||
if(src->mode == JSON_MODE){
|
||||
if(name == "true"){
|
||||
if(src->mode == JSON_MODE) {
|
||||
if(name == "true") {
|
||||
add_token(TK("True"));
|
||||
} else if(name == "false"){
|
||||
} else if(name == "false") {
|
||||
add_token(TK("False"));
|
||||
} else if(name == "null"){
|
||||
} else if(name == "null") {
|
||||
add_token(TK("None"));
|
||||
} else {
|
||||
return 4;
|
||||
@ -143,92 +153,95 @@ static bool is_unicode_Lo_char(uint32_t c) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(kTokenKwMap.count(name)){
|
||||
if(kTokenKwMap.count(name)) {
|
||||
add_token(kTokenKwMap.at(name));
|
||||
} else {
|
||||
add_token(TK("@id"));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Lexer::skip_line_comment() {
|
||||
void Lexer::skip_line_comment() {
|
||||
char c;
|
||||
while ((c = peekchar()) != '\0') {
|
||||
if (c == '\n') return;
|
||||
while((c = peekchar()) != '\0') {
|
||||
if(c == '\n') return;
|
||||
eatchar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Lexer::matchchar(char c) {
|
||||
if (peekchar() != c) return false;
|
||||
bool Lexer::matchchar(char c) {
|
||||
if(peekchar() != c) return false;
|
||||
eatchar_include_newline();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void Lexer::add_token(TokenIndex type, TokenValue value) {
|
||||
switch(type){
|
||||
case TK("{"): case TK("["): case TK("("): brackets_level++; break;
|
||||
case TK(")"): case TK("]"): case TK("}"): brackets_level--; break;
|
||||
void Lexer::add_token(TokenIndex type, TokenValue value) {
|
||||
switch(type) {
|
||||
case TK("{"):
|
||||
case TK("["):
|
||||
case TK("("): brackets_level++; break;
|
||||
case TK(")"):
|
||||
case TK("]"):
|
||||
case TK("}"): brackets_level--; break;
|
||||
}
|
||||
auto token = Token{
|
||||
type,
|
||||
auto token = Token{type,
|
||||
token_start,
|
||||
(int)(curr_char - token_start),
|
||||
current_line - ((type == TK("@eol")) ? 1 : 0),
|
||||
brackets_level,
|
||||
value
|
||||
};
|
||||
value};
|
||||
// handle "not in", "is not", "yield from"
|
||||
if(!nexts.empty()){
|
||||
if(!nexts.empty()) {
|
||||
auto& back = nexts.back();
|
||||
if(back.type == TK("not") && type == TK("in")){
|
||||
if(back.type == TK("not") && type == TK("in")) {
|
||||
back.type = TK("not in");
|
||||
return;
|
||||
}
|
||||
if(back.type == TK("is") && type == TK("not")){
|
||||
if(back.type == TK("is") && type == TK("not")) {
|
||||
back.type = TK("is not");
|
||||
return;
|
||||
}
|
||||
if(back.type == TK("yield") && type == TK("from")){
|
||||
if(back.type == TK("yield") && type == TK("from")) {
|
||||
back.type = TK("yield from");
|
||||
return;
|
||||
}
|
||||
nexts.push_back(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Lexer::add_token_2(char c, TokenIndex one, TokenIndex two) {
|
||||
if (matchchar(c)) add_token(two);
|
||||
else add_token(one);
|
||||
}
|
||||
void Lexer::add_token_2(char c, TokenIndex one, TokenIndex two) {
|
||||
if(matchchar(c))
|
||||
add_token(two);
|
||||
else
|
||||
add_token(one);
|
||||
}
|
||||
|
||||
Str Lexer::eat_string_until(char quote, bool raw) {
|
||||
Str Lexer::eat_string_until(char quote, bool raw) {
|
||||
bool quote3 = match_n_chars(2, quote);
|
||||
small_vector_2<char, 32> buff;
|
||||
while (true) {
|
||||
while(true) {
|
||||
char c = eatchar_include_newline();
|
||||
if (c == quote){
|
||||
if(quote3 && !match_n_chars(2, quote)){
|
||||
if(c == quote) {
|
||||
if(quote3 && !match_n_chars(2, quote)) {
|
||||
buff.push_back(c);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (c == '\0'){
|
||||
if(quote3 && src->mode == REPL_MODE){
|
||||
throw NeedMoreLines(false);
|
||||
}
|
||||
if(c == '\0') {
|
||||
if(quote3 && src->mode == REPL_MODE) { throw NeedMoreLines(false); }
|
||||
SyntaxError("EOL while scanning string literal");
|
||||
}
|
||||
if (c == '\n'){
|
||||
if(!quote3) SyntaxError("EOL while scanning string literal");
|
||||
else{
|
||||
if(c == '\n') {
|
||||
if(!quote3)
|
||||
SyntaxError("EOL while scanning string literal");
|
||||
else {
|
||||
buff.push_back(c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!raw && c == '\\') {
|
||||
switch (eatchar_include_newline()) {
|
||||
if(!raw && c == '\\') {
|
||||
switch(eatchar_include_newline()) {
|
||||
case '"': buff.push_back('"'); break;
|
||||
case '\'': buff.push_back('\''); break;
|
||||
case '\\': buff.push_back('\\'); break;
|
||||
@ -240,12 +253,10 @@ static bool is_unicode_Lo_char(uint32_t c) {
|
||||
char hex[3] = {eatchar(), eatchar(), '\0'};
|
||||
size_t parsed;
|
||||
char code;
|
||||
try{
|
||||
try {
|
||||
code = (char)std::stoi(hex, &parsed, 16);
|
||||
}catch(...){
|
||||
SyntaxError("invalid hex char");
|
||||
}
|
||||
if (parsed != 2) SyntaxError("invalid hex char");
|
||||
} catch(...) { SyntaxError("invalid hex char"); }
|
||||
if(parsed != 2) SyntaxError("invalid hex char");
|
||||
buff.push_back(code);
|
||||
} break;
|
||||
default: SyntaxError("invalid escape char");
|
||||
@ -255,83 +266,79 @@ static bool is_unicode_Lo_char(uint32_t c) {
|
||||
}
|
||||
}
|
||||
return Str(buff.data(), buff.size());
|
||||
}
|
||||
}
|
||||
|
||||
void Lexer::eat_string(char quote, StringType type) {
|
||||
void Lexer::eat_string(char quote, StringType type) {
|
||||
Str s = eat_string_until(quote, type == RAW_STRING);
|
||||
if(type == F_STRING){
|
||||
if(type == F_STRING) {
|
||||
add_token(TK("@fstr"), s);
|
||||
return;
|
||||
}
|
||||
if(type == NORMAL_BYTES){
|
||||
if(type == NORMAL_BYTES) {
|
||||
add_token(TK("@bytes"), s);
|
||||
return;
|
||||
}
|
||||
add_token(TK("@str"), s);
|
||||
}
|
||||
}
|
||||
|
||||
void Lexer::eat_number() {
|
||||
void Lexer::eat_number() {
|
||||
const char* i = token_start;
|
||||
while(is_possible_number_char(*i)) i++;
|
||||
while(is_possible_number_char(*i))
|
||||
i++;
|
||||
|
||||
bool is_scientific_notation = false;
|
||||
if(*(i-1) == 'e' && (*i == '+' || *i == '-')){
|
||||
if(*(i - 1) == 'e' && (*i == '+' || *i == '-')) {
|
||||
i++;
|
||||
while(isdigit(*i) || *i == 'j')
|
||||
i++;
|
||||
while(isdigit(*i) || *i=='j') i++;
|
||||
is_scientific_notation = true;
|
||||
}
|
||||
|
||||
std::string_view text(token_start, i - token_start);
|
||||
this->curr_char = i;
|
||||
|
||||
if(text[0] != '.' && !is_scientific_notation){
|
||||
if(text[0] != '.' && !is_scientific_notation) {
|
||||
// try long
|
||||
if(i[-1] == 'L'){
|
||||
if(i[-1] == 'L') {
|
||||
add_token(TK("@long"));
|
||||
return;
|
||||
}
|
||||
// try integer
|
||||
i64 int_out;
|
||||
switch(parse_uint(text, &int_out, -1)){
|
||||
case IntParsingResult::Success:
|
||||
add_token(TK("@num"), int_out);
|
||||
return;
|
||||
case IntParsingResult::Overflow:
|
||||
SyntaxError("int literal is too large");
|
||||
return;
|
||||
case IntParsingResult::Failure:
|
||||
break; // do nothing
|
||||
switch(parse_uint(text, &int_out, -1)) {
|
||||
case IntParsingResult::Success: add_token(TK("@num"), int_out); return;
|
||||
case IntParsingResult::Overflow: SyntaxError("int literal is too large"); return;
|
||||
case IntParsingResult::Failure: break; // do nothing
|
||||
}
|
||||
}
|
||||
|
||||
// try float
|
||||
double float_out;
|
||||
char* p_end;
|
||||
try{
|
||||
try {
|
||||
float_out = std::strtod(text.data(), &p_end);
|
||||
}catch(...){
|
||||
SyntaxError("invalid number literal");
|
||||
}
|
||||
} catch(...) { SyntaxError("invalid number literal"); }
|
||||
|
||||
if(p_end == text.data() + text.size()){
|
||||
if(p_end == text.data() + text.size()) {
|
||||
add_token(TK("@num"), (f64)float_out);
|
||||
return;
|
||||
}
|
||||
|
||||
if(i[-1] == 'j' && p_end == text.data() + text.size() - 1){
|
||||
if(i[-1] == 'j' && p_end == text.data() + text.size() - 1) {
|
||||
add_token(TK("@imag"), (f64)float_out);
|
||||
return;
|
||||
}
|
||||
|
||||
SyntaxError("invalid number literal");
|
||||
}
|
||||
}
|
||||
|
||||
bool Lexer::lex_one_token() {
|
||||
while (peekchar() != '\0') {
|
||||
bool Lexer::lex_one_token() {
|
||||
while(peekchar() != '\0') {
|
||||
token_start = curr_char;
|
||||
char c = eatchar_include_newline();
|
||||
switch (c) {
|
||||
case '\'': case '"': eat_string(c, NORMAL_STRING); return true;
|
||||
switch(c) {
|
||||
case '\'':
|
||||
case '"': eat_string(c, NORMAL_STRING); return true;
|
||||
case '#': skip_line_comment(); break;
|
||||
case '~': add_token(TK("~")); return true;
|
||||
case '{': add_token(TK("{")); return true;
|
||||
@ -347,7 +354,7 @@ static bool is_unicode_Lo_char(uint32_t c) {
|
||||
case '\\': {
|
||||
// line continuation character
|
||||
char c = eatchar_include_newline();
|
||||
if (c != '\n'){
|
||||
if(c != '\n') {
|
||||
if(src->mode == REPL_MODE && c == '\0') throw NeedMoreLines(false);
|
||||
SyntaxError("expected newline after line continuation character");
|
||||
}
|
||||
@ -367,9 +374,9 @@ static bool is_unicode_Lo_char(uint32_t c) {
|
||||
}
|
||||
} else {
|
||||
char next_char = peekchar();
|
||||
if(next_char >= '0' && next_char <= '9'){
|
||||
if(next_char >= '0' && next_char <= '9') {
|
||||
eat_number();
|
||||
}else{
|
||||
} else {
|
||||
add_token(TK("."));
|
||||
}
|
||||
}
|
||||
@ -377,40 +384,51 @@ static bool is_unicode_Lo_char(uint32_t c) {
|
||||
}
|
||||
case '=': add_token_2('=', TK("="), TK("==")); return true;
|
||||
case '+':
|
||||
if(matchchar('+')){
|
||||
if(matchchar('+')) {
|
||||
add_token(TK("++"));
|
||||
}else{
|
||||
} else {
|
||||
add_token_2('=', TK("+"), TK("+="));
|
||||
}
|
||||
return true;
|
||||
case '>': {
|
||||
if(matchchar('=')) add_token(TK(">="));
|
||||
else if(matchchar('>')) add_token_2('=', TK(">>"), TK(">>="));
|
||||
else add_token(TK(">"));
|
||||
if(matchchar('='))
|
||||
add_token(TK(">="));
|
||||
else if(matchchar('>'))
|
||||
add_token_2('=', TK(">>"), TK(">>="));
|
||||
else
|
||||
add_token(TK(">"));
|
||||
return true;
|
||||
}
|
||||
case '<': {
|
||||
if(matchchar('=')) add_token(TK("<="));
|
||||
else if(matchchar('<')) add_token_2('=', TK("<<"), TK("<<="));
|
||||
else add_token(TK("<"));
|
||||
if(matchchar('='))
|
||||
add_token(TK("<="));
|
||||
else if(matchchar('<'))
|
||||
add_token_2('=', TK("<<"), TK("<<="));
|
||||
else
|
||||
add_token(TK("<"));
|
||||
return true;
|
||||
}
|
||||
case '-': {
|
||||
if(matchchar('-')){
|
||||
if(matchchar('-')) {
|
||||
add_token(TK("--"));
|
||||
}else{
|
||||
if(matchchar('=')) add_token(TK("-="));
|
||||
else if(matchchar('>')) add_token(TK("->"));
|
||||
else add_token(TK("-"));
|
||||
} else {
|
||||
if(matchchar('='))
|
||||
add_token(TK("-="));
|
||||
else if(matchchar('>'))
|
||||
add_token(TK("->"));
|
||||
else
|
||||
add_token(TK("-"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case '!':
|
||||
if(matchchar('=')) add_token(TK("!="));
|
||||
else SyntaxError("expected '=' after '!'");
|
||||
if(matchchar('='))
|
||||
add_token(TK("!="));
|
||||
else
|
||||
SyntaxError("expected '=' after '!'");
|
||||
break;
|
||||
case '*':
|
||||
if (matchchar('*')) {
|
||||
if(matchchar('*')) {
|
||||
add_token(TK("**")); // '**'
|
||||
} else {
|
||||
add_token_2('=', TK("*"), TK("*="));
|
||||
@ -423,29 +441,47 @@ static bool is_unicode_Lo_char(uint32_t c) {
|
||||
add_token_2('=', TK("/"), TK("/="));
|
||||
}
|
||||
return true;
|
||||
case ' ': case '\t': eat_spaces(); break;
|
||||
case ' ':
|
||||
case '\t': eat_spaces(); break;
|
||||
case '\n': {
|
||||
add_token(TK("@eol"));
|
||||
if(!eat_indentation()) IndentationError("unindent does not match any outer indentation level");
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
if(c == 'f'){
|
||||
if(matchchar('\'')) {eat_string('\'', F_STRING); return true;}
|
||||
if(matchchar('"')) {eat_string('"', F_STRING); return true;}
|
||||
}else if(c == 'r'){
|
||||
if(matchchar('\'')) {eat_string('\'', RAW_STRING); return true;}
|
||||
if(matchchar('"')) {eat_string('"', RAW_STRING); return true;}
|
||||
}else if(c == 'b'){
|
||||
if(matchchar('\'')) {eat_string('\'', NORMAL_BYTES); return true;}
|
||||
if(matchchar('"')) {eat_string('"', NORMAL_BYTES); return true;}
|
||||
if(c == 'f') {
|
||||
if(matchchar('\'')) {
|
||||
eat_string('\'', F_STRING);
|
||||
return true;
|
||||
}
|
||||
if (c >= '0' && c <= '9') {
|
||||
if(matchchar('"')) {
|
||||
eat_string('"', F_STRING);
|
||||
return true;
|
||||
}
|
||||
} else if(c == 'r') {
|
||||
if(matchchar('\'')) {
|
||||
eat_string('\'', RAW_STRING);
|
||||
return true;
|
||||
}
|
||||
if(matchchar('"')) {
|
||||
eat_string('"', RAW_STRING);
|
||||
return true;
|
||||
}
|
||||
} else if(c == 'b') {
|
||||
if(matchchar('\'')) {
|
||||
eat_string('\'', NORMAL_BYTES);
|
||||
return true;
|
||||
}
|
||||
if(matchchar('"')) {
|
||||
eat_string('"', NORMAL_BYTES);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(c >= '0' && c <= '9') {
|
||||
eat_number();
|
||||
return true;
|
||||
}
|
||||
switch (eat_name())
|
||||
{
|
||||
switch(eat_name()) {
|
||||
case 0: break;
|
||||
case 1: SyntaxError("invalid char: " + std::string(1, c)); break;
|
||||
case 2: SyntaxError("invalid utf8 sequence: " + std::string(1, c)); break;
|
||||
@ -459,110 +495,115 @@ static bool is_unicode_Lo_char(uint32_t c) {
|
||||
}
|
||||
|
||||
token_start = curr_char;
|
||||
while(indents.size() > 1){
|
||||
while(indents.size() > 1) {
|
||||
indents.pop();
|
||||
add_token(TK("@dedent"));
|
||||
return true;
|
||||
}
|
||||
add_token(TK("@eof"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Lexer::throw_err(StrName type, Str msg){
|
||||
void Lexer::throw_err(StrName type, Str msg) {
|
||||
int lineno = current_line;
|
||||
const char* cursor = curr_char;
|
||||
if(peekchar() == '\n'){
|
||||
if(peekchar() == '\n') {
|
||||
lineno--;
|
||||
cursor--;
|
||||
}
|
||||
throw_err(type, msg, lineno, cursor);
|
||||
}
|
||||
}
|
||||
|
||||
Lexer::Lexer(VM* vm, std::shared_ptr<SourceData> src) : vm(vm), src(src) {
|
||||
Lexer::Lexer(VM* vm, std::shared_ptr<SourceData> src) : vm(vm), src(src) {
|
||||
this->token_start = src->source.c_str();
|
||||
this->curr_char = src->source.c_str();
|
||||
this->nexts.push_back(Token{TK("@sof"), token_start, 0, current_line, brackets_level, {}});
|
||||
this->indents.push(0);
|
||||
}
|
||||
}
|
||||
|
||||
vector<Token> Lexer::run() {
|
||||
vector<Token> Lexer::run() {
|
||||
assert(curr_char == src->source.c_str());
|
||||
while (lex_one_token());
|
||||
while(lex_one_token())
|
||||
;
|
||||
return std::move(nexts);
|
||||
}
|
||||
}
|
||||
|
||||
inline constexpr bool f_startswith_2(std::string_view t, const char* prefix){
|
||||
constexpr inline bool f_startswith_2(std::string_view t, const char* prefix) {
|
||||
if(t.length() < 2) return false;
|
||||
return t[0] == prefix[0] && t[1] == prefix[1];
|
||||
}
|
||||
|
||||
IntParsingResult parse_uint(std::string_view text, i64* out, int base){
|
||||
IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
|
||||
*out = 0;
|
||||
|
||||
if(base == -1){
|
||||
if(f_startswith_2(text, "0b")) base = 2;
|
||||
else if(f_startswith_2(text, "0o")) base = 8;
|
||||
else if(f_startswith_2(text, "0x")) base = 16;
|
||||
else base = 10;
|
||||
if(base == -1) {
|
||||
if(f_startswith_2(text, "0b"))
|
||||
base = 2;
|
||||
else if(f_startswith_2(text, "0o"))
|
||||
base = 8;
|
||||
else if(f_startswith_2(text, "0x"))
|
||||
base = 16;
|
||||
else
|
||||
base = 10;
|
||||
}
|
||||
|
||||
if(base == 10){
|
||||
if(base == 10) {
|
||||
// 10-base 12334
|
||||
if(text.length() == 0) return IntParsingResult::Failure;
|
||||
for(char c : text){
|
||||
if(c >= '0' && c <= '9'){
|
||||
for(char c: text) {
|
||||
if(c >= '0' && c <= '9') {
|
||||
i64 prev_out = *out;
|
||||
*out = (*out * 10) + (c - '0');
|
||||
if(*out < prev_out) return IntParsingResult::Overflow;
|
||||
}else{
|
||||
} else {
|
||||
return IntParsingResult::Failure;
|
||||
}
|
||||
}
|
||||
return IntParsingResult::Success;
|
||||
}else if(base == 2){
|
||||
} else if(base == 2) {
|
||||
// 2-base 0b101010
|
||||
if(f_startswith_2(text, "0b")) text.remove_prefix(2);
|
||||
if(text.length() == 0) return IntParsingResult::Failure;
|
||||
for(char c : text){
|
||||
if(c == '0' || c == '1'){
|
||||
for(char c: text) {
|
||||
if(c == '0' || c == '1') {
|
||||
i64 prev_out = *out;
|
||||
*out = (*out << 1) | (c - '0');
|
||||
if(*out < prev_out) return IntParsingResult::Overflow;
|
||||
}else{
|
||||
} else {
|
||||
return IntParsingResult::Failure;
|
||||
}
|
||||
}
|
||||
return IntParsingResult::Success;
|
||||
}else if(base == 8){
|
||||
} else if(base == 8) {
|
||||
// 8-base 0o123
|
||||
if(f_startswith_2(text, "0o")) text.remove_prefix(2);
|
||||
if(text.length() == 0) return IntParsingResult::Failure;
|
||||
for(char c : text){
|
||||
if(c >= '0' && c <= '7'){
|
||||
for(char c: text) {
|
||||
if(c >= '0' && c <= '7') {
|
||||
i64 prev_out = *out;
|
||||
*out = (*out << 3) | (c - '0');
|
||||
if(*out < prev_out) return IntParsingResult::Overflow;
|
||||
}else{
|
||||
} else {
|
||||
return IntParsingResult::Failure;
|
||||
}
|
||||
}
|
||||
return IntParsingResult::Success;
|
||||
}else if(base == 16){
|
||||
} else if(base == 16) {
|
||||
// 16-base 0x123
|
||||
if(f_startswith_2(text, "0x")) text.remove_prefix(2);
|
||||
if(text.length() == 0) return IntParsingResult::Failure;
|
||||
for(char c : text){
|
||||
for(char c: text) {
|
||||
i64 prev_out = *out;
|
||||
if(c >= '0' && c <= '9'){
|
||||
if(c >= '0' && c <= '9') {
|
||||
*out = (*out << 4) | (c - '0');
|
||||
if(*out < prev_out) return IntParsingResult::Overflow;
|
||||
}else if(c >= 'a' && c <= 'f'){
|
||||
} else if(c >= 'a' && c <= 'f') {
|
||||
*out = (*out << 4) | (c - 'a' + 10);
|
||||
if(*out < prev_out) return IntParsingResult::Overflow;
|
||||
}else if(c >= 'A' && c <= 'F'){
|
||||
} else if(c >= 'A' && c <= 'F') {
|
||||
*out = (*out << 4) | (c - 'A' + 10);
|
||||
if(*out < prev_out) return IntParsingResult::Overflow;
|
||||
}else{
|
||||
} else {
|
||||
return IntParsingResult::Failure;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,26 +1,26 @@
|
||||
#include "pocketpy/interpreter/cffi.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
void VoidP::_register(VM* vm, PyObject* mod, PyObject* type){
|
||||
vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args){
|
||||
void VoidP::_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]);
|
||||
i64 addr = CAST(i64, args[1]);
|
||||
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);
|
||||
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);
|
||||
return _S("<void* at ", self.hex(), ">");
|
||||
});
|
||||
|
||||
#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; \
|
||||
void* _0 = PK_OBJ_GET(VoidP, lhs).ptr; \
|
||||
void* _1 = PK_OBJ_GET(VoidP, rhs).ptr; \
|
||||
@ -34,67 +34,81 @@ namespace pkpy{
|
||||
BIND_CMP(__ge__, >=)
|
||||
|
||||
#undef BIND_CMP
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Struct::_register(VM* vm, PyObject* mod, PyObject* type){
|
||||
vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args){
|
||||
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);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "hex", 1, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "hex", 1, [](VM* vm, ArgsView args) {
|
||||
const Struct& self = _CAST(Struct&, args[0]);
|
||||
SStream ss;
|
||||
for(int i=0; i<self.size; i++) ss.write_hex((unsigned char)self.p[i]);
|
||||
for(int i = 0; i < self.size; i++)
|
||||
ss.write_hex((unsigned char)self.p[i]);
|
||||
return VAR(ss.str());
|
||||
});
|
||||
|
||||
// @staticmethod
|
||||
vm->bind_func(type, "fromhex", 1, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(
|
||||
type,
|
||||
"fromhex",
|
||||
1,
|
||||
[](VM* vm, ArgsView args) {
|
||||
const Str& s = CAST(Str&, args[0]);
|
||||
if(s.size<2 || s.size%2!=0) vm->ValueError("invalid hex string");
|
||||
Struct buffer(s.size/2, false);
|
||||
for(int i=0; i<s.size; i+=2){
|
||||
if(s.size < 2 || s.size % 2 != 0) vm->ValueError("invalid hex string");
|
||||
Struct buffer(s.size / 2, false);
|
||||
for(int i = 0; i < s.size; i += 2) {
|
||||
char c = 0;
|
||||
if(s[i]>='0' && s[i]<='9') 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') c += s[i]-'a'+10;
|
||||
else vm->ValueError(_S("invalid hex char: '", s[i], "'"));
|
||||
if(s[i] >= '0' && s[i] <= '9')
|
||||
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')
|
||||
c += s[i] - 'a' + 10;
|
||||
else
|
||||
vm->ValueError(_S("invalid hex char: '", s[i], "'"));
|
||||
c <<= 4;
|
||||
if(s[i+1]>='0' && s[i+1]<='9') 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') c += s[i+1]-'a'+10;
|
||||
else vm->ValueError(_S("invalid hex char: '", s[i+1], "'"));
|
||||
buffer.p[i/2] = c;
|
||||
if(s[i + 1] >= '0' && s[i + 1] <= '9')
|
||||
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')
|
||||
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));
|
||||
}, {}, 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);
|
||||
SStream ss;
|
||||
ss << "<struct object of " << self.size << " bytes>";
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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);
|
||||
if(!vm->is_user_type<Struct>(rhs)) return vm->NotImplemented;
|
||||
Struct& other = _CAST(Struct&, rhs);
|
||||
@ -103,13 +117,13 @@ namespace pkpy{
|
||||
});
|
||||
|
||||
#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]); \
|
||||
i64 offset = CAST(i64, args[1]); \
|
||||
void* ptr = self.p + offset; \
|
||||
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]); \
|
||||
i64 offset = CAST(i64, args[2]); \
|
||||
void* ptr = self.p + offset; \
|
||||
@ -131,29 +145,29 @@ namespace pkpy{
|
||||
BIND_SETGET(bool, "bool")
|
||||
BIND_SETGET(void*, "void_p")
|
||||
#undef BIND_SETGET
|
||||
}
|
||||
}
|
||||
|
||||
void add_module_c(VM* vm){
|
||||
void add_module_c(VM* vm) {
|
||||
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]);
|
||||
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]);
|
||||
std::free(p);
|
||||
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]);
|
||||
std::memset(p, CAST(int, args[1]), CAST(size_t, args[2]));
|
||||
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* src = CAST(void*, args[1]);
|
||||
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));
|
||||
|
||||
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]);
|
||||
vm->check_type(args[1], vm->tp_type);
|
||||
Type cls = PK_OBJ_GET(Type, args[1]);
|
||||
if(!vm->issubclass(cls, vm->_tp_user<VoidP>())){
|
||||
vm->ValueError("expected a subclass of void_p");
|
||||
}
|
||||
if(!vm->issubclass(cls, vm->_tp_user<VoidP>())) { vm->ValueError("expected a subclass of void_p"); }
|
||||
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]);
|
||||
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]);
|
||||
void* value = *reinterpret_cast<void**>(ptr.ptr);
|
||||
return vm->new_object<VoidP>(args[0].type, value);
|
||||
@ -191,53 +203,53 @@ void add_module_c(VM* vm){
|
||||
Type type_t;
|
||||
|
||||
#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]); \
|
||||
return vm->new_user_object<Struct>(&val, sizeof(T)); \
|
||||
}); \
|
||||
type = vm->new_type_object(mod, CNAME "_p", vm->_tp_user<VoidP>(), true); \
|
||||
mod->attr().set(CNAME "_p", 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]); \
|
||||
T* target = (T*)voidp.ptr; \
|
||||
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]); \
|
||||
T val = CAST(T, args[1]); \
|
||||
T* target = (T*)voidp.ptr; \
|
||||
*target = val; \
|
||||
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); \
|
||||
i64 offset = CAST(i64, index); \
|
||||
T* target = (T*)voidp.ptr; \
|
||||
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); \
|
||||
i64 offset = CAST(i64, index); \
|
||||
T* target = (T*)voidp.ptr; \
|
||||
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); \
|
||||
i64 offset = CAST(i64, rhs); \
|
||||
T* target = (T*)voidp.ptr; \
|
||||
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); \
|
||||
i64 offset = CAST(i64, rhs); \
|
||||
T* target = (T*)voidp.ptr; \
|
||||
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); \
|
||||
return _S("<", CNAME, "* at ", self.hex(), ">"); \
|
||||
}); \
|
||||
});
|
||||
|
||||
BIND_PRIMITIVE(char, "char")
|
||||
BIND_PRIMITIVE(unsigned char, "uchar")
|
||||
@ -256,13 +268,13 @@ void add_module_c(VM* vm){
|
||||
#undef BIND_PRIMITIVE
|
||||
|
||||
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]);
|
||||
const char* target = (const char*)voidp.ptr;
|
||||
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]);
|
||||
std::string_view sv = CAST(Str&, args[1]).sv();
|
||||
char* target = (char*)voidp.ptr;
|
||||
@ -272,8 +284,6 @@ void add_module_c(VM* vm){
|
||||
});
|
||||
}
|
||||
|
||||
PyVar from_void_p(VM* vm, void* p){
|
||||
return vm->new_user_object<VoidP>(p);
|
||||
}
|
||||
PyVar from_void_p(VM* vm, void* p) { return vm->new_user_object<VoidP>(p); }
|
||||
|
||||
} // namespace pkpy
|
||||
@ -3,33 +3,33 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace pkpy{
|
||||
PyVar* FastLocals::try_get_name(StrName name){
|
||||
namespace pkpy {
|
||||
PyVar* FastLocals::try_get_name(StrName name) {
|
||||
int index = co->varnames_inv.try_get(name);
|
||||
if(index == -1) return nullptr;
|
||||
return &a[index];
|
||||
}
|
||||
}
|
||||
|
||||
NameDict_ FastLocals::to_namedict(){
|
||||
NameDict_ FastLocals::to_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];
|
||||
if(value) dict->set(name, value);
|
||||
});
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
|
||||
PyVar* Frame::f_closure_try_get(StrName name){
|
||||
PyVar* Frame::f_closure_try_get(StrName name) {
|
||||
if(_callable == nullptr) return nullptr;
|
||||
Function& fn = _callable->as<Function>();
|
||||
if(fn._closure == nullptr) return nullptr;
|
||||
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
|
||||
int i = co->lines[ip()].iblock;
|
||||
while(i >= 0){
|
||||
while(i >= 0) {
|
||||
if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) break;
|
||||
i = co->blocks[i].parent;
|
||||
}
|
||||
@ -39,90 +39,92 @@ namespace pkpy{
|
||||
_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){
|
||||
int Frame::_exit_block(ValueStack* _s, int i) {
|
||||
auto type = co->blocks[i].type;
|
||||
if(type == CodeBlockType::FOR_LOOP){
|
||||
if(type == CodeBlockType::FOR_LOOP) {
|
||||
_s->pop(); // pop the iterator
|
||||
// pop possible stack memory slots
|
||||
if(_s->top().type == kTpStackMemoryIndex){
|
||||
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
|
||||
}
|
||||
}else if(type==CodeBlockType::CONTEXT_MANAGER){
|
||||
} else if(type == CodeBlockType::CONTEXT_MANAGER) {
|
||||
_s->pop();
|
||||
}
|
||||
return co->blocks[i].parent;
|
||||
}
|
||||
}
|
||||
|
||||
void Frame::prepare_jump_break(ValueStack* _s, int target){
|
||||
void Frame::prepare_jump_break(ValueStack* _s, int target) {
|
||||
int i = co->lines[ip()].iblock;
|
||||
if(target >= co->codes.size()){
|
||||
while(i>=0) i = _exit_block(_s, i);
|
||||
}else{
|
||||
if(target >= co->codes.size()) {
|
||||
while(i >= 0)
|
||||
i = _exit_block(_s, i);
|
||||
} else {
|
||||
// BUG (solved)
|
||||
// for i in range(4):
|
||||
// _ = 0
|
||||
// # if there is no op here, the block check will fail
|
||||
// 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");
|
||||
}
|
||||
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){
|
||||
void Frame::set_unwind_target(PyVar* _sp) {
|
||||
int iblock = co->lines[ip()].iblock;
|
||||
UnwindTarget* existing = find_unwind_target(iblock);
|
||||
if(existing){
|
||||
if(existing) {
|
||||
existing->offset = _sp - actual_sp_base();
|
||||
}else{
|
||||
} else {
|
||||
UnwindTarget* prev = _uw_list;
|
||||
_uw_list = new UnwindTarget(iblock, _sp - actual_sp_base());
|
||||
_uw_list->next = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UnwindTarget* Frame::find_unwind_target(int iblock){
|
||||
UnwindTarget* Frame::find_unwind_target(int iblock) {
|
||||
UnwindTarget* p;
|
||||
for(p=_uw_list; p!=nullptr; p=p->next){
|
||||
for(p = _uw_list; p != nullptr; p = p->next) {
|
||||
if(p->iblock == iblock) return p;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Frame::~Frame(){
|
||||
while(_uw_list != nullptr){
|
||||
Frame::~Frame() {
|
||||
while(_uw_list != nullptr) {
|
||||
UnwindTarget* p = _uw_list;
|
||||
_uw_list = p->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CallStack::pop(){
|
||||
void CallStack::pop() {
|
||||
assert(!empty());
|
||||
LinkedFrame* p = _tail;
|
||||
_tail = p->f_back;
|
||||
p->~LinkedFrame();
|
||||
PoolFrame_dealloc(p);
|
||||
--_size;
|
||||
}
|
||||
}
|
||||
|
||||
LinkedFrame* CallStack::popx(){
|
||||
LinkedFrame* CallStack::popx() {
|
||||
assert(!empty());
|
||||
LinkedFrame* p = _tail;
|
||||
_tail = p->f_back;
|
||||
--_size;
|
||||
p->f_back = nullptr; // unlink
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
void CallStack::pushx(LinkedFrame* p){
|
||||
void CallStack::pushx(LinkedFrame* p) {
|
||||
p->f_back = _tail;
|
||||
_tail = p;
|
||||
++_size;
|
||||
}
|
||||
}
|
||||
} // namespace pkpy
|
||||
@ -1,15 +1,15 @@
|
||||
#include "pocketpy/interpreter/gc.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
int ManagedHeap::sweep(){
|
||||
int ManagedHeap::sweep() {
|
||||
vector<PyObject*> alive;
|
||||
alive.reserve(gen.size() / 2);
|
||||
for(PyObject* obj: gen){
|
||||
if(obj->gc_marked){
|
||||
for(PyObject* obj: gen) {
|
||||
if(obj->gc_marked) {
|
||||
obj->gc_marked = false;
|
||||
alive.push_back(obj);
|
||||
}else{
|
||||
} else {
|
||||
#if PK_DEBUG_GC_STATS
|
||||
deleted[obj->type] += 1;
|
||||
#endif
|
||||
@ -19,12 +19,13 @@ namespace pkpy{
|
||||
}
|
||||
|
||||
// clear _no_gc marked flag
|
||||
for(PyObject* obj: _no_gc) obj->gc_marked = false;
|
||||
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){
|
||||
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;
|
||||
@ -34,9 +35,9 @@ namespace pkpy{
|
||||
gen.swap(alive);
|
||||
PoolObject_shrink_to_fit();
|
||||
return freed;
|
||||
}
|
||||
}
|
||||
|
||||
void ManagedHeap::_auto_collect(){
|
||||
void ManagedHeap::_auto_collect() {
|
||||
#if !PK_DEBUG_NO_AUTO_GC
|
||||
if(_gc_lock_counter > 0) return;
|
||||
gc_counter = 0;
|
||||
@ -44,12 +45,12 @@ namespace pkpy{
|
||||
gc_threshold = gen.size() * 2;
|
||||
if(gc_threshold < PK_GC_MIN_THRESHOLD) gc_threshold = PK_GC_MIN_THRESHOLD;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int ManagedHeap::collect(){
|
||||
int ManagedHeap::collect() {
|
||||
assert(_gc_lock_counter == 0);
|
||||
mark();
|
||||
int freed = sweep();
|
||||
return freed;
|
||||
}
|
||||
}
|
||||
} // namespace pkpy
|
||||
@ -1,42 +1,50 @@
|
||||
#include "pocketpy/interpreter/iter.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
void RangeIter::_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{
|
||||
void RangeIter::_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 {
|
||||
RangeIter& self = PK_OBJ_GET(RangeIter, _0);
|
||||
if(self.current >= self.r.stop) return 0;
|
||||
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){
|
||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; });
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{
|
||||
void RangeIterR::_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 {
|
||||
RangeIterR& self = PK_OBJ_GET(RangeIterR, _0);
|
||||
if(self.current <= self.r.stop) return 0;
|
||||
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){
|
||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; });
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{
|
||||
void ArrayIter::_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 {
|
||||
ArrayIter& self = _CAST(ArrayIter&, _0);
|
||||
if(self.current == self.end) return 0;
|
||||
vm->s_data.push(*self.current++);
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void StringIter::_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{
|
||||
void StringIter::_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 {
|
||||
StringIter& self = _CAST(StringIter&, _0);
|
||||
Str& s = PK_OBJ_GET(Str, self.ref);
|
||||
if(self.i == s.size) return 0;
|
||||
@ -46,21 +54,22 @@ namespace pkpy{
|
||||
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;
|
||||
// reset frame._sp_base
|
||||
lf->frame._sp_base = vm->s_data._sp;
|
||||
lf->frame._locals.a = vm->s_data._sp;
|
||||
// restore the context
|
||||
for(PyVar obj: s_backup) vm->s_data.push(obj);
|
||||
for(PyVar obj: s_backup)
|
||||
vm->s_data.push(obj);
|
||||
// relocate stack objects (their addresses become invalid)
|
||||
for(PyVar* p=lf->frame.actual_sp_base(); p!=vm->s_data.end(); p++){
|
||||
if(p->type == VM::tp_stack_memory){
|
||||
for(PyVar* p = lf->frame.actual_sp_base(); p != vm->s_data.end(); p++) {
|
||||
if(p->type == VM::tp_stack_memory) {
|
||||
// TODO: refactor this
|
||||
int count = p->as<StackMemory>().count;
|
||||
if(count < 0){
|
||||
if(count < 0) {
|
||||
void* new_p = p + count;
|
||||
p[1]._1 = reinterpret_cast<i64>(new_p);
|
||||
}
|
||||
@ -71,48 +80,53 @@ namespace pkpy{
|
||||
lf = nullptr;
|
||||
|
||||
PyVar ret;
|
||||
try{
|
||||
try {
|
||||
ret = vm->__run_top_frame();
|
||||
}catch(...){
|
||||
} catch(...) {
|
||||
state = 2; // end this generator immediately when an exception is thrown
|
||||
throw;
|
||||
}
|
||||
|
||||
if(ret == PY_OP_YIELD){
|
||||
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);
|
||||
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
|
||||
// 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{
|
||||
} else {
|
||||
state = 2;
|
||||
return vm->StopIteration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Generator::_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{
|
||||
void Generator::_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 {
|
||||
Generator& self = _CAST(Generator&, _0);
|
||||
PyVar retval = self.next(vm);
|
||||
if(retval == vm->StopIteration) return 0;
|
||||
vm->s_data.push(retval);
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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{
|
||||
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;
|
||||
@ -121,9 +135,9 @@ namespace pkpy{
|
||||
self.i = d._items[self.i].next;
|
||||
return 2;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
PyVar VM::__py_generator(LinkedFrame* frame, ArgsView buffer){
|
||||
PyVar VM::__py_generator(LinkedFrame* frame, ArgsView buffer) {
|
||||
return vm->new_user_object<Generator>(std::move(frame), buffer);
|
||||
}
|
||||
|
||||
|
||||
@ -1,41 +1,39 @@
|
||||
#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();
|
||||
if(n <= 0) return 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];
|
||||
snprintf(buf, 32, "%.1f", x);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void LineProfiler::begin(){
|
||||
frames.clear();
|
||||
}
|
||||
void LineProfiler::begin() { 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()];
|
||||
if(line_info.is_virtual) return;
|
||||
std::string_view filename = frame->co->src->filename.sv();
|
||||
int line = line_info.lineno;
|
||||
|
||||
if(frames.empty()){
|
||||
if(frames.empty()) {
|
||||
frames.push({callstack_size, frame, clock(), nullptr});
|
||||
}else{
|
||||
} else {
|
||||
_step_end(callstack_size, frame, line);
|
||||
}
|
||||
|
||||
auto& file_records = records[filename];
|
||||
if(file_records.empty()){
|
||||
if(file_records.empty()) {
|
||||
// initialize file_records
|
||||
int total_lines = frame->co->src->line_starts.size();
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -43,7 +41,7 @@ void LineProfiler::_step(int callstack_size, Frame* frame){
|
||||
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();
|
||||
_FrameRecord& top_frame_record = frames.top();
|
||||
_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);
|
||||
|
||||
// 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;
|
||||
top_frame_record.prev_time = now;
|
||||
if(id_delta != 1) prev_record->hits++;
|
||||
prev_record->time += delta;
|
||||
}
|
||||
|
||||
if(id_delta == 1){
|
||||
if(id_delta == 1) {
|
||||
frames.push({callstack_size, frame, now, nullptr});
|
||||
}else{
|
||||
} else {
|
||||
if(id_delta == -1) frames.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void LineProfiler::end(){
|
||||
void LineProfiler::end() {
|
||||
clock_t now = clock();
|
||||
_FrameRecord& top_frame_record = frames.top();
|
||||
_LineRecord* prev_record = top_frame_record.prev_record;
|
||||
@ -80,9 +78,9 @@ void LineProfiler::end(){
|
||||
assert(frames.empty());
|
||||
}
|
||||
|
||||
Str LineProfiler::stats(){
|
||||
Str LineProfiler::stats() {
|
||||
SStream ss;
|
||||
for(FuncDecl* decl: functions){
|
||||
for(FuncDecl* decl: functions) {
|
||||
int start_line = decl->code->start_line;
|
||||
int end_line = decl->code->end_line;
|
||||
if(start_line == -1 || end_line == -1) continue;
|
||||
@ -90,7 +88,7 @@ Str LineProfiler::stats(){
|
||||
vector<_LineRecord>& file_records = records[filename];
|
||||
if(file_records.empty()) continue;
|
||||
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;
|
||||
}
|
||||
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 << "Line # Hits Time Per Hit % Time Line Contents\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];
|
||||
if(!record.is_valid()) continue;
|
||||
ss << left_pad(std::to_string(line), 6);
|
||||
if(record.hits == 0){
|
||||
if(record.hits == 0) {
|
||||
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.time), 13);
|
||||
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);
|
||||
}else{
|
||||
} else {
|
||||
ss << left_pad(to_string_1f(record.time * (f64)100 / total_time), 9);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,9 @@
|
||||
#include "pocketpy/modules/array2d.hpp"
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
struct Array2d{
|
||||
struct Array2d {
|
||||
PK_ALWAYS_PASS_BY_POINTER(Array2d)
|
||||
|
||||
PyVar* data;
|
||||
@ -11,55 +11,49 @@ struct Array2d{
|
||||
int n_rows;
|
||||
int numel;
|
||||
|
||||
Array2d(){
|
||||
Array2d() {
|
||||
data = nullptr;
|
||||
n_cols = 0;
|
||||
n_rows = 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_rows = n_rows;
|
||||
this->numel = n_cols * n_rows;
|
||||
this->data = new PyVar[numel];
|
||||
}
|
||||
|
||||
bool is_valid(int col, int row) const{
|
||||
return 0 <= col && col < n_cols && 0 <= row && row < n_rows;
|
||||
}
|
||||
bool is_valid(int col, int row) const { 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;
|
||||
vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')'));
|
||||
}
|
||||
|
||||
PyVar _get(int col, int row){
|
||||
return data[row * n_cols + col];
|
||||
}
|
||||
PyVar _get(int col, int row) { return data[row * n_cols + col]; }
|
||||
|
||||
void _set(int col, int row, PyVar value){
|
||||
data[row * n_cols + col] = value;
|
||||
}
|
||||
void _set(int col, int row, PyVar value) { data[row * n_cols + col] = value; }
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||
vm->bind(type, "__new__(cls, *args, **kwargs)", [](VM* vm, ArgsView args){
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind(type, "__new__(cls, *args, **kwargs)", [](VM* vm, ArgsView args) {
|
||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||
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]);
|
||||
int n_cols = CAST(int, args[1]);
|
||||
int n_rows = CAST(int, args[2]);
|
||||
if(n_cols <= 0 || n_rows <= 0){
|
||||
vm->ValueError("n_cols and n_rows must be positive integers");
|
||||
}
|
||||
if(n_cols <= 0 || n_rows <= 0) { vm->ValueError("n_cols and n_rows must be positive integers"); }
|
||||
self.init(n_cols, n_rows);
|
||||
if(vm->py_callable(args[3])){
|
||||
for(int i = 0; i < self.numel; i++) self.data[i] = vm->call(args[3]);
|
||||
}else{
|
||||
for(int i = 0; i < self.numel; i++) self.data[i] = args[3];
|
||||
if(vm->py_callable(args[3])) {
|
||||
for(int i = 0; i < self.numel; i++)
|
||||
self.data[i] = vm->call(args[3]);
|
||||
} else {
|
||||
for(int i = 0; i < self.numel; i++)
|
||||
self.data[i] = args[3];
|
||||
}
|
||||
return vm->None;
|
||||
});
|
||||
@ -71,7 +65,7 @@ struct Array2d{
|
||||
PY_READONLY_FIELD(Array2d, "numel", numel);
|
||||
|
||||
// _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]);
|
||||
int col = CAST(int, args[1]);
|
||||
int row = CAST(int, args[2]);
|
||||
@ -80,7 +74,7 @@ struct Array2d{
|
||||
});
|
||||
|
||||
// _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]);
|
||||
int col = CAST(int, args[1]);
|
||||
int row = CAST(int, args[2]);
|
||||
@ -89,14 +83,14 @@ struct Array2d{
|
||||
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]);
|
||||
int col = CAST(int, args[1]);
|
||||
int row = CAST(int, args[2]);
|
||||
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]);
|
||||
int col = CAST(int, args[1]);
|
||||
int row = CAST(int, args[2]);
|
||||
@ -104,7 +98,7 @@ struct Array2d{
|
||||
return self._get(col, row);
|
||||
});
|
||||
|
||||
#define HANDLE_SLICE() \
|
||||
#define HANDLE_SLICE() \
|
||||
int start_col, stop_col, step_col; \
|
||||
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); \
|
||||
@ -114,24 +108,24 @@ struct Array2d{
|
||||
int slice_height = stop_row - start_row; \
|
||||
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);
|
||||
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 row = xy[1].as<i64>();
|
||||
self.check_valid(vm, 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();
|
||||
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
||||
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
||||
new_array.init(stop_col - start_col, stop_row - start_row);
|
||||
for(int j = start_row; j < stop_row; j++){
|
||||
for(int i = start_col; i < stop_col; i++){
|
||||
for(int j = start_row; j < stop_row; j++) {
|
||||
for(int i = start_col; i < stop_col; i++) {
|
||||
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->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);
|
||||
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 row = xy[1].as<i64>();
|
||||
self.check_valid(vm, col, row);
|
||||
@ -151,11 +145,11 @@ struct Array2d{
|
||||
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();
|
||||
|
||||
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_float.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;
|
||||
}
|
||||
|
||||
if(is_basic_type){
|
||||
if(is_basic_type) {
|
||||
for(int j = 0; j < slice_height; j++)
|
||||
for(int i = 0; i < slice_width; i++)
|
||||
self._set(i + start_col, j + start_row, _2);
|
||||
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"));
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
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");
|
||||
});
|
||||
|
||||
#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]);
|
||||
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);
|
||||
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));
|
||||
}
|
||||
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);
|
||||
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);
|
||||
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]);
|
||||
PyVar f = args[1];
|
||||
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
||||
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
||||
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]);
|
||||
}
|
||||
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]);
|
||||
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
||||
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
||||
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];
|
||||
}
|
||||
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]);
|
||||
for(int i = 0; i < self.numel; i++){
|
||||
for(int i = 0; i < self.numel; i++) {
|
||||
self.data[i] = args[1];
|
||||
}
|
||||
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]);
|
||||
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]);
|
||||
}
|
||||
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]);
|
||||
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]);
|
||||
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");
|
||||
}
|
||||
for(int i = 0; i < self.numel; i++){
|
||||
for(int i = 0; i < self.numel; i++) {
|
||||
self.data[i] = list[i];
|
||||
}
|
||||
return vm->None;
|
||||
}
|
||||
Array2d& other = CAST(Array2d&, args[1]);
|
||||
// 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;
|
||||
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];
|
||||
}
|
||||
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);
|
||||
if(!vm->is_user_type<Array2d>(_1)) return vm->NotImplemented;
|
||||
Array2d& other = PK_OBJ_GET(Array2d, _1);
|
||||
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;
|
||||
}
|
||||
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]);
|
||||
PyVar new_array_obj = vm->new_user_object<Array2d>();
|
||||
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
|
||||
new_array.init(self.n_cols, self.n_rows);
|
||||
PyVar value = args[1];
|
||||
const Str& neighborhood = CAST(Str&, args[2]);
|
||||
if(neighborhood == "Moore"){
|
||||
for(int j = 0; j < new_array.n_rows; j++){
|
||||
for(int i = 0; i < new_array.n_cols; i++){
|
||||
if(neighborhood == "Moore") {
|
||||
for(int j = 0; j < new_array.n_rows; j++) {
|
||||
for(int i = 0; i < new_array.n_cols; i++) {
|
||||
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, 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) && 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, 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, 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) && 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, 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);
|
||||
new_array._set(i, j, VAR(count));
|
||||
}
|
||||
}
|
||||
}else if(neighborhood == "von Neumann"){
|
||||
for(int j = 0; j < new_array.n_rows; j++){
|
||||
for(int i = 0; i < new_array.n_cols; i++){
|
||||
} else if(neighborhood == "von Neumann") {
|
||||
for(int j = 0; j < new_array.n_rows; j++) {
|
||||
for(int i = 0; i < new_array.n_cols; i++) {
|
||||
int count = 0;
|
||||
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, 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, j + 1) && vm->py_eq(self._get(i, j + 1), value);
|
||||
new_array._set(i, j, VAR(count));
|
||||
}
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
vm->ValueError("neighborhood must be 'Moore' or 'von Neumann'");
|
||||
}
|
||||
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]);
|
||||
PyVar value = args[1];
|
||||
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);
|
||||
});
|
||||
|
||||
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]);
|
||||
PyVar value = args[1];
|
||||
int left = self.n_cols;
|
||||
int top = self.n_rows;
|
||||
int right = 0;
|
||||
int bottom = 0;
|
||||
for(int j = 0; j < self.n_rows; j++){
|
||||
for(int i = 0; i < self.n_cols; i++){
|
||||
if(vm->py_eq(self._get(i, j), value)){
|
||||
for(int j = 0; j < self.n_rows; j++) {
|
||||
for(int i = 0; i < self.n_cols; i++) {
|
||||
if(vm->py_eq(self._get(i, j), value)) {
|
||||
left = (std::min)(left, i);
|
||||
top = (std::min)(top, j);
|
||||
right = (std::max)(right, i);
|
||||
@ -360,30 +356,30 @@ struct Array2d{
|
||||
});
|
||||
}
|
||||
|
||||
void _gc_mark(VM* vm) const{
|
||||
for(int i = 0; i < numel; i++) vm->obj_gc_mark(data[i]);
|
||||
void _gc_mark(VM* vm) const {
|
||||
for(int i = 0; i < numel; i++)
|
||||
vm->obj_gc_mark(data[i]);
|
||||
}
|
||||
|
||||
~Array2d(){
|
||||
delete[] data;
|
||||
}
|
||||
~Array2d() { delete[] data; }
|
||||
};
|
||||
|
||||
|
||||
struct Array2dIter{
|
||||
struct Array2dIter {
|
||||
PK_ALWAYS_PASS_BY_POINTER(Array2dIter)
|
||||
|
||||
PyVar ref;
|
||||
Array2d* a;
|
||||
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){
|
||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{
|
||||
static void _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 {
|
||||
Array2dIter& self = PK_OBJ_GET(Array2dIter, _0);
|
||||
if(self.i == self.a->numel) return 0;
|
||||
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");
|
||||
|
||||
vm->register_user_class<Array2d>(mod, "array2d", VM::tp_object, true);
|
||||
vm->register_user_class<Array2dIter>(mod, "_array2d_iter");
|
||||
|
||||
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>());
|
||||
});
|
||||
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>());
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,7 +1,7 @@
|
||||
#include "pocketpy/modules/base64.hpp"
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
// https://github.com/zhicheng/base64/blob/master/base64.c
|
||||
|
||||
@ -9,6 +9,7 @@ const char BASE64_PAD = '=';
|
||||
const char BASE64DE_FIRST = '+';
|
||||
const char BASE64DE_LAST = 'z';
|
||||
|
||||
// clang-format off
|
||||
/* BASE 64 encode table */
|
||||
const char base64en[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
@ -71,10 +72,9 @@ const unsigned char base64de[] = {
|
||||
/* 'x', 'y', 'z', '{', '|', '}', '~', del, */
|
||||
49, 50, 51, 255, 255, 255, 255, 255
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
static unsigned int
|
||||
base64_encode(const unsigned char *in, unsigned int inlen, char *out)
|
||||
{
|
||||
static unsigned int base64_encode(const unsigned char* in, unsigned int inlen, char* out) {
|
||||
int s;
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
@ -83,10 +83,10 @@ base64_encode(const unsigned char *in, unsigned int inlen, char *out)
|
||||
|
||||
s = 0;
|
||||
l = 0;
|
||||
for (i = j = 0; i < inlen; i++) {
|
||||
for(i = j = 0; i < inlen; i++) {
|
||||
c = in[i];
|
||||
|
||||
switch (s) {
|
||||
switch(s) {
|
||||
case 0:
|
||||
s = 1;
|
||||
out[j++] = base64en[(c >> 2) & 0x3F];
|
||||
@ -104,7 +104,7 @@ base64_encode(const unsigned char *in, unsigned int inlen, char *out)
|
||||
l = c;
|
||||
}
|
||||
|
||||
switch (s) {
|
||||
switch(s) {
|
||||
case 1:
|
||||
out[j++] = base64en[(l & 0x3) << 4];
|
||||
out[j++] = BASE64_PAD;
|
||||
@ -121,34 +121,22 @@ base64_encode(const unsigned char *in, unsigned int inlen, char *out)
|
||||
return j;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
base64_decode(const char *in, unsigned int inlen, unsigned char *out)
|
||||
{
|
||||
static unsigned int base64_decode(const char* in, unsigned int inlen, unsigned char* out) {
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
unsigned char c;
|
||||
|
||||
if (inlen & 0x3) {
|
||||
return 0;
|
||||
}
|
||||
if(inlen & 0x3) { return 0; }
|
||||
|
||||
for (i = j = 0; i < inlen; i++) {
|
||||
if (in[i] == BASE64_PAD) {
|
||||
break;
|
||||
}
|
||||
if (in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) {
|
||||
return 0;
|
||||
}
|
||||
for(i = j = 0; i < inlen; i++) {
|
||||
if(in[i] == BASE64_PAD) { break; }
|
||||
if(in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) { return 0; }
|
||||
|
||||
c = base64de[(unsigned char)in[i]];
|
||||
if (c == 255) {
|
||||
return 0;
|
||||
}
|
||||
if(c == 255) { return 0; }
|
||||
|
||||
switch (i & 0x3) {
|
||||
case 0:
|
||||
out[j] = (c << 2) & 0xFF;
|
||||
break;
|
||||
switch(i & 0x3) {
|
||||
case 0: out[j] = (c << 2) & 0xFF; break;
|
||||
case 1:
|
||||
out[j++] |= (c >> 4) & 0x3;
|
||||
out[j] = (c & 0xF) << 4;
|
||||
@ -157,20 +145,18 @@ base64_decode(const char *in, unsigned int inlen, unsigned char *out)
|
||||
out[j++] |= (c >> 2) & 0xF;
|
||||
out[j] = (c & 0x3) << 6;
|
||||
break;
|
||||
case 3:
|
||||
out[j++] |= c;
|
||||
break;
|
||||
case 3: out[j++] |= c; break;
|
||||
}
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
void add_module_base64(VM* vm){
|
||||
void add_module_base64(VM* vm) {
|
||||
PyObject* mod = vm->new_module("base64");
|
||||
|
||||
// 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]);
|
||||
unsigned char* p = (unsigned char*)std::malloc(b.size() * 2);
|
||||
int size = base64_encode((const unsigned char*)b.data(), b.size(), (char*)p);
|
||||
@ -178,7 +164,7 @@ void add_module_base64(VM* vm){
|
||||
});
|
||||
|
||||
// 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]);
|
||||
unsigned char* p = (unsigned char*)std::malloc(b.size());
|
||||
int size = base64_decode((const char*)b.data(), b.size(), p);
|
||||
|
||||
@ -1,60 +1,57 @@
|
||||
#include "pocketpy/modules/csv.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");
|
||||
|
||||
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]);
|
||||
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();
|
||||
if(i == 0){
|
||||
if(i == 0) {
|
||||
// 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;
|
||||
int j;
|
||||
bool in_quote = false;
|
||||
std::string buffer;
|
||||
__NEXT_LINE:
|
||||
__NEXT_LINE:
|
||||
j = 0;
|
||||
while(j < line.size()){
|
||||
switch(line[j]){
|
||||
while(j < line.size()) {
|
||||
switch(line[j]) {
|
||||
case '"':
|
||||
if(in_quote){
|
||||
if(j+1 < line.size() && line[j+1] == '"'){
|
||||
if(in_quote) {
|
||||
if(j + 1 < line.size() && line[j + 1] == '"') {
|
||||
buffer += '"';
|
||||
j++;
|
||||
}else{
|
||||
} else {
|
||||
in_quote = false;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
in_quote = true;
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
if(in_quote){
|
||||
if(in_quote) {
|
||||
buffer += line[j];
|
||||
}else{
|
||||
} else {
|
||||
row.push_back(VAR(buffer));
|
||||
buffer.clear();
|
||||
}
|
||||
break;
|
||||
case '\r':
|
||||
break; // ignore
|
||||
default:
|
||||
buffer += line[j];
|
||||
break;
|
||||
case '\r': break; // ignore
|
||||
default: buffer += line[j]; break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
if(in_quote){
|
||||
if(i == csvfile.size()-1){
|
||||
if(in_quote) {
|
||||
if(i == csvfile.size() - 1) {
|
||||
vm->ValueError("unterminated quote");
|
||||
}else{
|
||||
} else {
|
||||
buffer += '\n';
|
||||
i++;
|
||||
line = CAST(Str&, csvfile[i]).sv();
|
||||
@ -67,22 +64,18 @@ __NEXT_LINE:
|
||||
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 ret_obj = vm->call(csv_reader, args[0]);
|
||||
const List& ret = CAST(List&, ret_obj);
|
||||
if(ret.size() == 0){
|
||||
vm->ValueError("empty csvfile");
|
||||
}
|
||||
if(ret.size() == 0) { vm->ValueError("empty csvfile"); }
|
||||
const List& header = CAST(List&, ret[0]);
|
||||
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]);
|
||||
if(row.size() != header.size()){
|
||||
vm->ValueError("row.size() != header.size()");
|
||||
}
|
||||
if(row.size() != header.size()) { vm->ValueError("row.size() != header.size()"); }
|
||||
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]);
|
||||
}
|
||||
new_ret.push_back(VAR(std::move(row_dict)));
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
#include "pocketpy/modules/dataclasses.hpp"
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
static void patch__init__(VM* vm, Type cls){
|
||||
vm->bind(vm->_t(cls), "__init__(self, *args, **kwargs)", [](VM* vm, ArgsView _view){
|
||||
static void patch__init__(VM* vm, Type cls) {
|
||||
vm->bind(vm->_t(cls), "__init__(self, *args, **kwargs)", [](VM* vm, ArgsView _view) {
|
||||
PyVar self = _view[0];
|
||||
const Tuple& args = CAST(Tuple&, _view[1]);
|
||||
const Dict& kwargs_ = CAST(Dict&, _view[2]);
|
||||
NameDict kwargs;
|
||||
kwargs_.apply([&](PyVar k, PyVar v){
|
||||
kwargs_.apply([&](PyVar k, PyVar v) {
|
||||
kwargs.set(CAST(Str&, k), v);
|
||||
});
|
||||
|
||||
@ -19,25 +19,26 @@ static void patch__init__(VM* vm, Type cls){
|
||||
const auto& fields = cls_info->annotated_fields;
|
||||
|
||||
int i = 0; // index into args
|
||||
for(StrName field: fields){
|
||||
if(kwargs.contains(field)){
|
||||
for(StrName field: fields) {
|
||||
if(kwargs.contains(field)) {
|
||||
self->attr().set(field, kwargs[field]);
|
||||
kwargs.del(field);
|
||||
}else{
|
||||
if(i < args.size()){
|
||||
} else {
|
||||
if(i < args.size()) {
|
||||
self->attr().set(field, args[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]);
|
||||
}else{
|
||||
} else {
|
||||
vm->TypeError(_S(cls_info->name, " missing required argument ", field.escape()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(args.size() > i){
|
||||
vm->TypeError(_S(cls_info->name, " takes ", fields.size(), " positional arguments but ", args.size(), " were given"));
|
||||
if(args.size() > i) {
|
||||
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;
|
||||
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){
|
||||
vm->bind__repr__(cls, [](VM* vm, PyVar _0) -> Str{
|
||||
static void patch__repr__(VM* vm, Type cls) {
|
||||
vm->bind__repr__(cls, [](VM* vm, PyVar _0) -> Str {
|
||||
const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)];
|
||||
const auto& fields = cls_info->annotated_fields;
|
||||
const NameDict& obj_d = _0->attr();
|
||||
SStream ss;
|
||||
ss << cls_info->name << "(";
|
||||
bool first = true;
|
||||
for(StrName field: fields){
|
||||
if(first) first = false;
|
||||
else ss << ", ";
|
||||
for(StrName field: fields) {
|
||||
if(first)
|
||||
first = false;
|
||||
else
|
||||
ss << ", ";
|
||||
ss << field << "=" << vm->py_repr(obj_d[field]);
|
||||
}
|
||||
ss << ")";
|
||||
@ -63,12 +66,12 @@ static void patch__repr__(VM* vm, Type cls){
|
||||
});
|
||||
}
|
||||
|
||||
static void patch__eq__(VM* vm, Type cls){
|
||||
vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1){
|
||||
static void patch__eq__(VM* vm, Type cls) {
|
||||
vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
if(vm->_tp(_0) != vm->_tp(_1)) return vm->NotImplemented;
|
||||
const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)];
|
||||
const auto& fields = cls_info->annotated_fields;
|
||||
for(StrName field: fields){
|
||||
for(StrName field: fields) {
|
||||
PyVar lhs = _0->attr(field);
|
||||
PyVar rhs = _1->attr(field);
|
||||
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");
|
||||
|
||||
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);
|
||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||
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;
|
||||
bool has_default = false;
|
||||
for(StrName field: fields){
|
||||
if(cls_d.contains(field)){
|
||||
for(StrName field: fields) {
|
||||
if(cls_d.contains(field)) {
|
||||
has_default = true;
|
||||
}else{
|
||||
if(has_default){
|
||||
} else {
|
||||
if(has_default) {
|
||||
vm->TypeError(_S("non-default argument ", field.escape(), " follows default argument"));
|
||||
}
|
||||
}
|
||||
@ -103,11 +106,11 @@ void add_module_dataclasses(VM* vm){
|
||||
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 NameDict& obj_d = args[0]->attr();
|
||||
Dict d;
|
||||
for(StrName field: fields){
|
||||
for(StrName field: fields) {
|
||||
d.set(vm, VAR(field.sv()), obj_d[field]);
|
||||
}
|
||||
return VAR(std::move(d));
|
||||
|
||||
@ -3,193 +3,161 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
// https://easings.net/
|
||||
|
||||
const double kPi = 3.1415926545;
|
||||
|
||||
static double easeLinear( double x ) {
|
||||
return x;
|
||||
}
|
||||
static double easeLinear(double x) { return x; }
|
||||
|
||||
static double easeInSine( double x ) {
|
||||
return 1.0 - std::cos( x * kPi / 2 );
|
||||
}
|
||||
static double easeInSine(double x) { return 1.0 - std::cos(x * kPi / 2); }
|
||||
|
||||
static double easeOutSine( double x ) {
|
||||
return std::sin( x * kPi / 2 );
|
||||
}
|
||||
static double easeOutSine(double x) { return std::sin(x * kPi / 2); }
|
||||
|
||||
static double easeInOutSine( double x ) {
|
||||
return -( std::cos( kPi * x ) - 1 ) / 2;
|
||||
}
|
||||
static double easeInOutSine(double x) { return -(std::cos(kPi * x) - 1) / 2; }
|
||||
|
||||
static double easeInQuad( double x ) {
|
||||
return x * x;
|
||||
}
|
||||
static double easeInQuad(double x) { return x * x; }
|
||||
|
||||
static double easeOutQuad( double x ) {
|
||||
return 1 - std::pow( 1 - x, 2 );
|
||||
}
|
||||
static double easeOutQuad(double x) { return 1 - std::pow(1 - x, 2); }
|
||||
|
||||
static double easeInOutQuad( double x ) {
|
||||
if( x < 0.5 ) {
|
||||
static double easeInOutQuad(double x) {
|
||||
if(x < 0.5) {
|
||||
return 2 * x * x;
|
||||
} else {
|
||||
return 1 - std::pow( -2 * x + 2, 2 ) / 2;
|
||||
return 1 - std::pow(-2 * x + 2, 2) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInCubic( double x ) {
|
||||
return x * x * x;
|
||||
}
|
||||
static double easeInCubic(double x) { return x * x * x; }
|
||||
|
||||
static double easeOutCubic( double x ) {
|
||||
return 1 - std::pow( 1 - x, 3 );
|
||||
}
|
||||
static double easeOutCubic(double x) { return 1 - std::pow(1 - x, 3); }
|
||||
|
||||
static double easeInOutCubic( double x ) {
|
||||
if( x < 0.5 ) {
|
||||
static double easeInOutCubic(double x) {
|
||||
if(x < 0.5) {
|
||||
return 4 * x * x * x;
|
||||
} else {
|
||||
return 1 - std::pow( -2 * x + 2, 3 ) / 2;
|
||||
return 1 - std::pow(-2 * x + 2, 3) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInQuart( double x ) {
|
||||
return std::pow( x, 4 );
|
||||
}
|
||||
static double easeInQuart(double x) { return std::pow(x, 4); }
|
||||
|
||||
static double easeOutQuart( double x ) {
|
||||
return 1 - std::pow( 1 - x, 4 );
|
||||
}
|
||||
static double easeOutQuart(double x) { return 1 - std::pow(1 - x, 4); }
|
||||
|
||||
static double easeInOutQuart( double x ) {
|
||||
if( x < 0.5 ) {
|
||||
return 8 * std::pow( x, 4 );
|
||||
static double easeInOutQuart(double x) {
|
||||
if(x < 0.5) {
|
||||
return 8 * std::pow(x, 4);
|
||||
} else {
|
||||
return 1 - std::pow( -2 * x + 2, 4 ) / 2;
|
||||
return 1 - std::pow(-2 * x + 2, 4) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInQuint( double x ) {
|
||||
return std::pow( x, 5 );
|
||||
}
|
||||
static double easeInQuint(double x) { return std::pow(x, 5); }
|
||||
|
||||
static double easeOutQuint( double x ) {
|
||||
return 1 - std::pow( 1 - x, 5 );
|
||||
}
|
||||
static double easeOutQuint(double x) { return 1 - std::pow(1 - x, 5); }
|
||||
|
||||
static double easeInOutQuint( double x ) {
|
||||
if( x < 0.5 ) {
|
||||
return 16 * std::pow( x, 5 );
|
||||
static double easeInOutQuint(double x) {
|
||||
if(x < 0.5) {
|
||||
return 16 * std::pow(x, 5);
|
||||
} else {
|
||||
return 1 - std::pow( -2 * x + 2, 5 ) / 2;
|
||||
return 1 - std::pow(-2 * x + 2, 5) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInExpo( double x ) {
|
||||
return x == 0 ? 0 : std::pow( 2, 10 * x - 10 );
|
||||
}
|
||||
static double easeInExpo(double x) { return x == 0 ? 0 : std::pow(2, 10 * x - 10); }
|
||||
|
||||
static double easeOutExpo( double x ) {
|
||||
return x == 1 ? 1 : 1 - std::pow( 2, -10 * x );
|
||||
}
|
||||
static double easeOutExpo(double x) { return x == 1 ? 1 : 1 - std::pow(2, -10 * x); }
|
||||
|
||||
static double easeInOutExpo( double x ) {
|
||||
if( x == 0 ) {
|
||||
static double easeInOutExpo(double x) {
|
||||
if(x == 0) {
|
||||
return 0;
|
||||
} else if( x == 1 ) {
|
||||
} else if(x == 1) {
|
||||
return 1;
|
||||
} else if( x < 0.5 ) {
|
||||
return std::pow( 2, 20 * x - 10 ) / 2;
|
||||
} else if(x < 0.5) {
|
||||
return std::pow(2, 20 * x - 10) / 2;
|
||||
} else {
|
||||
return (2 - std::pow( 2, -20 * x + 10 )) / 2;
|
||||
return (2 - std::pow(2, -20 * x + 10)) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInCirc( double x ) {
|
||||
return 1 - std::sqrt( 1 - std::pow( x, 2 ) );
|
||||
}
|
||||
static double easeInCirc(double x) { return 1 - std::sqrt(1 - std::pow(x, 2)); }
|
||||
|
||||
static double easeOutCirc( double x ) {
|
||||
return std::sqrt( 1 - std::pow( x - 1, 2 ) );
|
||||
}
|
||||
static double easeOutCirc(double x) { return std::sqrt(1 - std::pow(x - 1, 2)); }
|
||||
|
||||
static double easeInOutCirc( double x ) {
|
||||
if( x < 0.5 ) {
|
||||
return (1 - std::sqrt( 1 - std::pow( 2 * x, 2 ) )) / 2;
|
||||
static double easeInOutCirc(double x) {
|
||||
if(x < 0.5) {
|
||||
return (1 - std::sqrt(1 - std::pow(2 * x, 2))) / 2;
|
||||
} 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 c3 = c1 + 1;
|
||||
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 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 c2 = c1 * 1.525;
|
||||
if( x < 0.5 ) {
|
||||
return (std::pow( 2 * x, 2 ) * ((c2 + 1) * 2 * x - c2)) / 2;
|
||||
if(x < 0.5) {
|
||||
return (std::pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2;
|
||||
} 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;
|
||||
if( x == 0 ) {
|
||||
if(x == 0) {
|
||||
return 0;
|
||||
} else if( x == 1 ) {
|
||||
} else if(x == 1) {
|
||||
return 1;
|
||||
} 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;
|
||||
if( x == 0 ) {
|
||||
if(x == 0) {
|
||||
return 0;
|
||||
} else if( x == 1 ) {
|
||||
} else if(x == 1) {
|
||||
return 1;
|
||||
} 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;
|
||||
if( x == 0 ) {
|
||||
if(x == 0) {
|
||||
return 0;
|
||||
} else if( x == 1 ) {
|
||||
} else if(x == 1) {
|
||||
return 1;
|
||||
} else if( x < 0.5 ) {
|
||||
return -(std::pow( 2, 20 * x - 10 ) * std::sin( (20 * x - 11.125) * c5 )) / 2;
|
||||
} else if(x < 0.5) {
|
||||
return -(std::pow(2, 20 * x - 10) * std::sin((20 * x - 11.125) * c5)) / 2;
|
||||
} 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 d1 = 2.75;
|
||||
if( x < 1 / d1 ) {
|
||||
if(x < 1 / d1) {
|
||||
return n1 * x * x;
|
||||
} else if( x < 2 / d1 ) {
|
||||
} else if(x < 2 / d1) {
|
||||
x -= 1.5 / d1;
|
||||
return n1 * x * x + 0.75;
|
||||
} else if( x < 2.5 / d1 ) {
|
||||
} else if(x < 2.5 / d1) {
|
||||
x -= 2.25 / d1;
|
||||
return n1 * x * x + 0.9375;
|
||||
} else {
|
||||
@ -198,21 +166,17 @@ static double easeOutBounce( double x ) {
|
||||
}
|
||||
}
|
||||
|
||||
static double easeInBounce( double x ) {
|
||||
return 1 - easeOutBounce(1 - x);
|
||||
static double easeInBounce(double 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 ) {
|
||||
return x < 0.5
|
||||
? (1 - easeOutBounce(1 - 2 * x)) / 2
|
||||
: (1 + easeOutBounce(2 * x - 1)) / 2;
|
||||
}
|
||||
|
||||
void add_module_easing(VM* vm){
|
||||
void add_module_easing(VM* vm) {
|
||||
PyObject* mod = vm->new_module("easing");
|
||||
|
||||
#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]); \
|
||||
return VAR(ease##name(t)); \
|
||||
});
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
#if PK_ENABLE_OS
|
||||
|
||||
@ -19,7 +19,7 @@ struct FileIO {
|
||||
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
|
||||
FILE* fp;
|
||||
errno_t err = fopen_s(&fp, name, mode);
|
||||
@ -30,7 +30,7 @@ static FILE* io_fopen(const char* name, const char* mode){
|
||||
#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
|
||||
return fread_s(buffer, std::numeric_limits<size_t>::max(), size, count, fp);
|
||||
#else
|
||||
@ -38,7 +38,7 @@ static size_t io_fread(void* buffer, size_t size, size_t count, FILE* fp){
|
||||
#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));
|
||||
if(!exists) return nullptr;
|
||||
FILE* fp = io_fopen(name, "rb");
|
||||
@ -54,24 +54,22 @@ unsigned char* _default_import_handler(const char* name, int* out_size){
|
||||
return buffer;
|
||||
};
|
||||
|
||||
void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){
|
||||
vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args){
|
||||
void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args) {
|
||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||
return vm->new_object<FileIO>(cls, vm,
|
||||
py_cast<Str&>(vm, args[1]),
|
||||
py_cast<Str&>(vm, args[2]));
|
||||
return vm->new_object<FileIO>(cls, vm, 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]);
|
||||
i64 size = CAST(i64, args[1]);
|
||||
i64 buffer_size;
|
||||
if(size < 0){
|
||||
if(size < 0) {
|
||||
long current = ftell(io.fp);
|
||||
fseek(io.fp, 0, SEEK_END);
|
||||
buffer_size = ftell(io.fp);
|
||||
fseek(io.fp, current, SEEK_SET);
|
||||
}else{
|
||||
} else {
|
||||
buffer_size = 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);
|
||||
// in text mode, CR may be dropped, which may cause `actual_size < buffer_size`
|
||||
Bytes b(buffer, actual_size);
|
||||
if(io.is_text){
|
||||
return VAR(std::string_view((char*)b.data(), b.size()));
|
||||
}
|
||||
if(io.is_text) { return VAR(std::string_view((char*)b.data(), b.size())); }
|
||||
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]);
|
||||
if(io.is_text){
|
||||
if(io.is_text) {
|
||||
Str& s = CAST(Str&, args[1]);
|
||||
fwrite(s.data, 1, s.length(), io.fp);
|
||||
}else{
|
||||
} else {
|
||||
Bytes& buffer = CAST(Bytes&, args[1]);
|
||||
fwrite(buffer.data(), 1, buffer.size(), io.fp);
|
||||
}
|
||||
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]);
|
||||
long pos = ftell(io.fp);
|
||||
if(pos == -1) vm->IOError(strerror(errno));
|
||||
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]);
|
||||
long offset = CAST(long, args[1]);
|
||||
int whence = CAST(int, args[2]);
|
||||
@ -113,13 +109,13 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){
|
||||
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]);
|
||||
io.close();
|
||||
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]);
|
||||
io.close();
|
||||
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]));
|
||||
}
|
||||
|
||||
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;
|
||||
fp = io_fopen(file.c_str(), mode.c_str());
|
||||
if(!fp) vm->IOError(strerror(errno));
|
||||
}
|
||||
|
||||
void FileIO::close(){
|
||||
void FileIO::close() {
|
||||
if(fp == nullptr) return;
|
||||
fclose(fp);
|
||||
fp = nullptr;
|
||||
}
|
||||
|
||||
void add_module_io(VM* vm){
|
||||
void add_module_io(VM* vm) {
|
||||
PyObject* mod = vm->new_module("io");
|
||||
vm->register_user_class<FileIO>(mod, "FileIO");
|
||||
|
||||
@ -148,104 +144,103 @@ void add_module_io(VM* vm){
|
||||
mod->attr().set("SEEK_CUR", VAR(SEEK_CUR));
|
||||
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]);
|
||||
});
|
||||
}
|
||||
|
||||
void add_module_os(VM* vm){
|
||||
void add_module_os(VM* vm) {
|
||||
PyObject* mod = vm->new_module("os");
|
||||
PyObject* path_obj = vm->heap.gcnew<DummyInstance>(VM::tp_object);
|
||||
mod->attr().set("path", path_obj);
|
||||
|
||||
// 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());
|
||||
});
|
||||
|
||||
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::current_path(path);
|
||||
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::directory_iterator di;
|
||||
try{
|
||||
try {
|
||||
di = std::filesystem::directory_iterator(path);
|
||||
}catch(std::filesystem::filesystem_error&){
|
||||
vm->IOError(path.string());
|
||||
}
|
||||
} catch(std::filesystem::filesystem_error&) { vm->IOError(path.string()); }
|
||||
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));
|
||||
});
|
||||
|
||||
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());
|
||||
bool ok = std::filesystem::remove(path);
|
||||
if(!ok) vm->IOError("operation failed");
|
||||
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());
|
||||
bool ok = std::filesystem::create_directory(path);
|
||||
if(!ok) vm->IOError("operation failed");
|
||||
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());
|
||||
bool ok = std::filesystem::remove(path);
|
||||
if(!ok) vm->IOError("operation failed");
|
||||
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;
|
||||
for(int i=0; i<args.size(); i++){
|
||||
for(int i = 0; i < args.size(); i++) {
|
||||
path /= CAST(Str&, args[i]).sv();
|
||||
}
|
||||
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());
|
||||
bool exists = std::filesystem::exists(path);
|
||||
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());
|
||||
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());
|
||||
bool isdir = std::filesystem::is_directory(path);
|
||||
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());
|
||||
bool isfile = std::filesystem::is_regular_file(path);
|
||||
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());
|
||||
return VAR(std::filesystem::absolute(path).string());
|
||||
});
|
||||
}
|
||||
#else
|
||||
|
||||
void add_module_io(VM* vm){}
|
||||
void add_module_os(VM* vm){}
|
||||
unsigned char* _default_import_handler(const char* name, int* out_size){
|
||||
return nullptr;
|
||||
}
|
||||
void add_module_io(VM* vm) {}
|
||||
|
||||
void add_module_os(VM* vm) {}
|
||||
|
||||
unsigned char* _default_import_handler(const char* name, int* out_size) { return nullptr; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,58 +1,58 @@
|
||||
#include "pocketpy/modules/linalg.hpp"
|
||||
#include "pocketpy/interpreter/bindings.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
#define BIND_VEC_VEC_OP(D, name, op) \
|
||||
vm->bind##name(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ \
|
||||
vm->bind##name(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||
Vec##D self = _CAST(Vec##D, _0); \
|
||||
Vec##D other = CAST(Vec##D, _1); \
|
||||
return VAR(self op other); \
|
||||
});
|
||||
|
||||
#define BIND_VEC_FLOAT_OP(D, name, op) \
|
||||
vm->bind##name(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ \
|
||||
vm->bind##name(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||
Vec##D self = _CAST(Vec##D, _0); \
|
||||
f64 other = CAST(f64, _1); \
|
||||
return VAR(self op other); \
|
||||
});
|
||||
|
||||
#define BIND_VEC_FUNCTION_0(T, name) \
|
||||
vm->bind_func(type, #name, 1, [](VM* vm, ArgsView args){ \
|
||||
vm->bind_func(type, #name, 1, [](VM* vm, ArgsView args) { \
|
||||
T self = _CAST(T, args[0]); \
|
||||
return VAR(self.name()); \
|
||||
});
|
||||
|
||||
#define BIND_VEC_FUNCTION_1(T, name) \
|
||||
vm->bind_func(type, #name, 2, [](VM* vm, ArgsView args){ \
|
||||
vm->bind_func(type, #name, 2, [](VM* vm, ArgsView args) { \
|
||||
T self = _CAST(T, args[0]); \
|
||||
T other = CAST(T, args[1]); \
|
||||
return VAR(self.name(other)); \
|
||||
});
|
||||
|
||||
#define BIND_VEC_MUL_OP(D) \
|
||||
vm->bind__mul__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ \
|
||||
vm->bind__mul__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||
Vec##D self = _CAST(Vec##D, _0); \
|
||||
if(vm->is_user_type<Vec##D>(_1)){ \
|
||||
if(vm->is_user_type<Vec##D>(_1)) { \
|
||||
Vec##D other = _CAST(Vec##D, _1); \
|
||||
return VAR(self * other); \
|
||||
} \
|
||||
f64 other = CAST(f64, _1); \
|
||||
return VAR(self * other); \
|
||||
}); \
|
||||
vm->bind_func(type, "__rmul__", 2, [](VM* vm, ArgsView args){ \
|
||||
vm->bind_func(type, "__rmul__", 2, [](VM* vm, ArgsView args) { \
|
||||
Vec##D self = _CAST(Vec##D, args[0]); \
|
||||
f64 other = CAST(f64, args[1]); \
|
||||
return VAR(self * other); \
|
||||
}); \
|
||||
vm->bind__truediv__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ \
|
||||
vm->bind__truediv__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||
Vec##D self = _CAST(Vec##D, _0); \
|
||||
f64 other = CAST(f64, _1); \
|
||||
return VAR(self / other); \
|
||||
});
|
||||
|
||||
#define BIND_VEC_GETITEM(D) \
|
||||
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index){ \
|
||||
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index) { \
|
||||
Vec##D self = _CAST(Vec##D, obj); \
|
||||
i64 i = CAST(i64, index); \
|
||||
if(i < 0 || i >= D) vm->IndexError("index out of range"); \
|
||||
@ -60,22 +60,23 @@ namespace pkpy{
|
||||
});
|
||||
|
||||
#define BIND_SSO_VEC_COMMON(D) \
|
||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ \
|
||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||
Vec##D self = _CAST(Vec##D, _0); \
|
||||
if(!vm->is_user_type<Vec##D>(_1)) return vm->NotImplemented; \
|
||||
Vec##D other = _CAST(Vec##D, _1); \
|
||||
return VAR(self == other); \
|
||||
}); \
|
||||
vm->bind_func(type, "__getnewargs__", 1, [](VM* vm, ArgsView args){ \
|
||||
vm->bind_func(type, "__getnewargs__", 1, [](VM* vm, ArgsView args) { \
|
||||
Vec##D self = _CAST(Vec##D, args[0]); \
|
||||
Tuple t(D); \
|
||||
for(int i=0; i<D; i++) t[i] = VAR(self[i]); \
|
||||
for(int i = 0; i < D; i++) \
|
||||
t[i] = VAR(self[i]); \
|
||||
return VAR(std::move(t)); \
|
||||
});
|
||||
|
||||
// https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Math/Vector2.cs#L289
|
||||
static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float smoothTime, float maxSpeed, float deltaTime)
|
||||
{
|
||||
static Vec2
|
||||
SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float smoothTime, float maxSpeed, float deltaTime) {
|
||||
// Based on Game Programming Gems 4 Chapter 1.10
|
||||
smoothTime = (std::max)(0.0001F, smoothTime);
|
||||
float omega = 2.0F / smoothTime;
|
||||
@ -92,8 +93,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
|
||||
float maxChangeSq = maxChange * maxChange;
|
||||
float sqDist = change_x * change_x + change_y * change_y;
|
||||
if (sqDist > maxChangeSq)
|
||||
{
|
||||
if(sqDist > maxChangeSq) {
|
||||
float mag = std::sqrt(sqDist);
|
||||
change_x = change_x / mag * maxChange;
|
||||
change_y = change_y / mag * maxChange;
|
||||
@ -117,8 +117,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
float outMinusOrig_x = output_x - originalTo.x;
|
||||
float outMinusOrig_y = output_y - originalTo.y;
|
||||
|
||||
if (origMinusCurrent_x * outMinusOrig_x + origMinusCurrent_y * outMinusOrig_y > 0)
|
||||
{
|
||||
if(origMinusCurrent_x * outMinusOrig_x + origMinusCurrent_y * outMinusOrig_y > 0) {
|
||||
output_x = originalTo.x;
|
||||
output_y = originalTo.y;
|
||||
|
||||
@ -128,18 +127,21 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
return Vec2(output_x, output_y);
|
||||
}
|
||||
|
||||
void Vec2::_register(VM* vm, PyObject* mod, PyObject* type){
|
||||
void Vec2::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
type->attr().set("ZERO", vm->new_user_object<Vec2>(0, 0));
|
||||
type->attr().set("ONE", vm->new_user_object<Vec2>(1, 1));
|
||||
|
||||
vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args) {
|
||||
float x = CAST_F(args[1]);
|
||||
float y = CAST_F(args[2]);
|
||||
return vm->new_object<Vec2>(PK_OBJ_GET(Type, args[0]), x, y);
|
||||
});
|
||||
|
||||
// @staticmethod
|
||||
vm->bind(type, "smooth_damp(current: vec2, target: vec2, current_velocity_: vec2, smooth_time: float, max_speed: float, delta_time: float) -> vec2", [](VM* vm, ArgsView args){
|
||||
vm->bind(
|
||||
type,
|
||||
"smooth_damp(current: vec2, target: vec2, current_velocity_: vec2, smooth_time: float, max_speed: float, delta_time: float) -> vec2",
|
||||
[](VM* vm, ArgsView args) {
|
||||
Vec2 current = CAST(Vec2, args[0]);
|
||||
Vec2 target = CAST(Vec2, args[1]);
|
||||
Vec2 current_velocity_ = CAST(Vec2, args[2]);
|
||||
@ -148,20 +150,27 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
float delta_time = CAST_F(args[5]);
|
||||
Vec2 ret = SmoothDamp(current, target, current_velocity_, smooth_time, max_speed, delta_time);
|
||||
return VAR(Tuple(VAR(ret), VAR(current_velocity_)));
|
||||
}, {}, BindType::STATICMETHOD);
|
||||
},
|
||||
{},
|
||||
BindType::STATICMETHOD);
|
||||
|
||||
// @staticmethod
|
||||
vm->bind(type, "angle(__from: vec2, __to: vec2) -> float", [](VM* vm, ArgsView args){
|
||||
vm->bind(
|
||||
type,
|
||||
"angle(__from: vec2, __to: vec2) -> float",
|
||||
[](VM* vm, ArgsView args) {
|
||||
Vec2 __from = CAST(Vec2, args[0]);
|
||||
Vec2 __to = CAST(Vec2, args[1]);
|
||||
float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x);
|
||||
const float PI = 3.1415926535897932384f;
|
||||
if(val > PI) val -= 2*PI;
|
||||
if(val < -PI) val += 2*PI;
|
||||
if(val > PI) val -= 2 * PI;
|
||||
if(val < -PI) val += 2 * PI;
|
||||
return VAR(val);
|
||||
}, {}, BindType::STATICMETHOD);
|
||||
},
|
||||
{},
|
||||
BindType::STATICMETHOD);
|
||||
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str{
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
|
||||
Vec2 self = _CAST(Vec2, obj);
|
||||
SStream ss;
|
||||
ss.setprecision(3);
|
||||
@ -169,7 +178,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
return ss.str();
|
||||
});
|
||||
|
||||
vm->bind_func(type, "rotate", 2, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "rotate", 2, [](VM* vm, ArgsView args) {
|
||||
Vec2 self = _CAST(Vec2, args[0]);
|
||||
float radian = CAST(f64, args[1]);
|
||||
return vm->new_user_object<Vec2>(self.rotate(radian));
|
||||
@ -189,20 +198,20 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
BIND_VEC_FUNCTION_0(Vec2, normalize)
|
||||
BIND_VEC_GETITEM(2)
|
||||
BIND_SSO_VEC_COMMON(2)
|
||||
}
|
||||
}
|
||||
|
||||
void Vec3::_register(VM* vm, PyObject* mod, PyObject* type){
|
||||
void Vec3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
type->attr().set("ZERO", vm->new_user_object<Vec3>(0, 0, 0));
|
||||
type->attr().set("ONE", vm->new_user_object<Vec3>(1, 1, 1));
|
||||
|
||||
vm->bind_func(type, __new__, 4, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, __new__, 4, [](VM* vm, ArgsView args) {
|
||||
float x = CAST_F(args[1]);
|
||||
float y = CAST_F(args[2]);
|
||||
float z = CAST_F(args[3]);
|
||||
return vm->new_object<Vec3>(PK_OBJ_GET(Type, args[0]), x, y, z);
|
||||
});
|
||||
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str{
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
|
||||
Vec3 self = _CAST(Vec3, obj);
|
||||
SStream ss;
|
||||
ss.setprecision(3);
|
||||
@ -224,15 +233,15 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
BIND_VEC_FUNCTION_0(Vec3, normalize)
|
||||
BIND_VEC_GETITEM(3)
|
||||
BIND_SSO_VEC_COMMON(3)
|
||||
}
|
||||
}
|
||||
|
||||
void Vec4::_register(VM* vm, PyObject* mod, PyObject* type){
|
||||
void Vec4::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
PY_STRUCT_LIKE(Vec4)
|
||||
|
||||
type->attr().set("ZERO", vm->new_user_object<Vec4>(0, 0, 0, 0));
|
||||
type->attr().set("ONE", vm->new_user_object<Vec4>(1, 1, 1, 1));
|
||||
|
||||
vm->bind_func(type, __new__, 5, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, __new__, 5, [](VM* vm, ArgsView args) {
|
||||
float x = CAST_F(args[1]);
|
||||
float y = CAST_F(args[2]);
|
||||
float z = CAST_F(args[3]);
|
||||
@ -240,7 +249,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
return vm->new_object<Vec4>(PK_OBJ_GET(Type, args[0]), x, y, z, w);
|
||||
});
|
||||
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str{
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
|
||||
Vec4 self = _CAST(Vec4&, obj);
|
||||
SStream ss;
|
||||
ss.setprecision(3);
|
||||
@ -263,7 +272,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
BIND_VEC_FUNCTION_0(Vec4&, normalize)
|
||||
BIND_VEC_FUNCTION_0(Vec4&, normalize_)
|
||||
BIND_VEC_GETITEM(4)
|
||||
}
|
||||
}
|
||||
|
||||
#undef BIND_VEC_VEC_OP
|
||||
#undef BIND_VEC_MUL_OP
|
||||
@ -271,35 +280,37 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
#undef BIND_VEC_FUNCTION_1
|
||||
#undef BIND_VEC_GETITEM
|
||||
|
||||
void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type){
|
||||
void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
PY_STRUCT_LIKE(Mat3x3)
|
||||
|
||||
vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args){
|
||||
if(args.size() == 1+0) return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros());
|
||||
if(args.size() == 1+1){
|
||||
vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
|
||||
if(args.size() == 1 + 0) return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros());
|
||||
if(args.size() == 1 + 1) {
|
||||
const List& list = CAST(List&, args[1]);
|
||||
if(list.size() != 9) vm->TypeError("Mat3x3.__new__ takes a list of 9 floats");
|
||||
Mat3x3 mat;
|
||||
for(int i=0; i<9; i++) mat.v[i] = CAST_F(list[i]);
|
||||
for(int i = 0; i < 9; i++)
|
||||
mat.v[i] = CAST_F(list[i]);
|
||||
return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
|
||||
}
|
||||
if(args.size() == 1+9){
|
||||
if(args.size() == 1 + 9) {
|
||||
Mat3x3 mat;
|
||||
for(int i=0; i<9; i++) mat.v[i] = CAST_F(args[1+i]);
|
||||
for(int i = 0; i < 9; i++)
|
||||
mat.v[i] = CAST_F(args[1 + i]);
|
||||
return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
|
||||
}
|
||||
vm->TypeError(_S("Mat3x3.__new__ takes 0 or 1 or 9 arguments, got ", args.size()-1));
|
||||
vm->TypeError(_S("Mat3x3.__new__ takes 0 or 1 or 9 arguments, got ", args.size() - 1));
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "copy_", 2, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "copy_", 2, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
const Mat3x3& other = CAST(Mat3x3&, args[1]);
|
||||
self = other;
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str{
|
||||
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
|
||||
const Mat3x3& self = _CAST(Mat3x3&, obj);
|
||||
SStream ss;
|
||||
ss.setprecision(3);
|
||||
@ -309,31 +320,23 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
return ss.str();
|
||||
});
|
||||
|
||||
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index){
|
||||
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, obj);
|
||||
Tuple& t = CAST(Tuple&, index);
|
||||
if(t.size() != 2){
|
||||
vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers");
|
||||
}
|
||||
if(t.size() != 2) { vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers"); }
|
||||
i64 i = CAST(i64, t[0]);
|
||||
i64 j = CAST(i64, t[1]);
|
||||
if(i < 0 || i >= 3 || j < 0 || j >= 3){
|
||||
vm->IndexError("index out of range");
|
||||
}
|
||||
if(i < 0 || i >= 3 || j < 0 || j >= 3) { vm->IndexError("index out of range"); }
|
||||
return VAR(self.m[i][j]);
|
||||
});
|
||||
|
||||
vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index, PyVar value){
|
||||
vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index, PyVar value) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, obj);
|
||||
const Tuple& t = CAST(Tuple&, index);
|
||||
if(t.size() != 2){
|
||||
vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers");
|
||||
}
|
||||
if(t.size() != 2) { vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers"); }
|
||||
i64 i = CAST(i64, t[0]);
|
||||
i64 j = CAST(i64, t[1]);
|
||||
if(i < 0 || i >= 3 || j < 0 || j >= 3){
|
||||
vm->IndexError("index out of range");
|
||||
}
|
||||
if(i < 0 || i >= 3 || j < 0 || j >= 3) { vm->IndexError("index out of range"); }
|
||||
self.m[i][j] = CAST_F(value);
|
||||
});
|
||||
|
||||
@ -347,86 +350,86 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
vm->bind_field(type, "_32", &Mat3x3::_32);
|
||||
vm->bind_field(type, "_33", &Mat3x3::_33);
|
||||
|
||||
vm->bind__add__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){
|
||||
vm->bind__add__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, _0);
|
||||
Mat3x3& other = CAST(Mat3x3&, _1);
|
||||
return vm->new_user_object<Mat3x3>(self + other);
|
||||
});
|
||||
|
||||
vm->bind__sub__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){
|
||||
vm->bind__sub__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, _0);
|
||||
Mat3x3& other = CAST(Mat3x3&, _1);
|
||||
return vm->new_user_object<Mat3x3>(self - other);
|
||||
});
|
||||
|
||||
vm->bind__mul__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){
|
||||
vm->bind__mul__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, _0);
|
||||
f64 other = CAST_F(_1);
|
||||
return vm->new_user_object<Mat3x3>(self * other);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "__rmul__", 2, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "__rmul__", 2, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
f64 other = CAST_F(args[1]);
|
||||
return vm->new_user_object<Mat3x3>(self * other);
|
||||
});
|
||||
|
||||
vm->bind__truediv__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){
|
||||
vm->bind__truediv__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, _0);
|
||||
f64 other = CAST_F(_1);
|
||||
return vm->new_user_object<Mat3x3>(self / other);
|
||||
});
|
||||
|
||||
vm->bind__matmul__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){
|
||||
vm->bind__matmul__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, _0);
|
||||
if(vm->is_user_type<Mat3x3>(_1)){
|
||||
if(vm->is_user_type<Mat3x3>(_1)) {
|
||||
const Mat3x3& other = _CAST(Mat3x3&, _1);
|
||||
return vm->new_user_object<Mat3x3>(self.matmul(other));
|
||||
}
|
||||
if(vm->is_user_type<Vec3>(_1)){
|
||||
if(vm->is_user_type<Vec3>(_1)) {
|
||||
const Vec3 other = _CAST(Vec3, _1);
|
||||
return vm->new_user_object<Vec3>(self.matmul(other));
|
||||
}
|
||||
return vm->NotImplemented;
|
||||
});
|
||||
|
||||
vm->bind(type, "matmul(self, other: mat3x3, out: mat3x3 = None)", [](VM* vm, ArgsView args){
|
||||
vm->bind(type, "matmul(self, other: mat3x3, out: mat3x3 = None)", [](VM* vm, ArgsView args) {
|
||||
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
const Mat3x3& other = CAST(Mat3x3&, args[1]);
|
||||
if(args[2] == vm->None){
|
||||
if(args[2] == vm->None) {
|
||||
return vm->new_user_object<Mat3x3>(self.matmul(other));
|
||||
}else{
|
||||
} else {
|
||||
Mat3x3& out = CAST(Mat3x3&, args[2]);
|
||||
out = self.matmul(other);
|
||||
return vm->None;
|
||||
}
|
||||
});
|
||||
|
||||
vm->bind_func(type, "determinant", 1, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "determinant", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
return VAR(self.determinant());
|
||||
});
|
||||
|
||||
vm->bind_func(type, "transpose", 1, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "transpose", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
return vm->new_user_object<Mat3x3>(self.transpose());
|
||||
});
|
||||
|
||||
vm->bind__invert__(type->as<Type>(), [](VM* vm, PyVar obj){
|
||||
vm->bind__invert__(type->as<Type>(), [](VM* vm, PyVar obj) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, obj);
|
||||
Mat3x3 ret;
|
||||
if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
|
||||
return vm->new_user_object<Mat3x3>(ret);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "inverse", 1, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "inverse", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Mat3x3 ret;
|
||||
if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
|
||||
return vm->new_user_object<Mat3x3>(ret);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "inverse_", 1, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "inverse_", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Mat3x3 ret;
|
||||
if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
|
||||
@ -434,37 +437,60 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "transpose_", 1, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "transpose_", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
self = self.transpose();
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
// @staticmethod
|
||||
vm->bind_func(type, "zeros", 0, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(
|
||||
type,
|
||||
"zeros",
|
||||
0,
|
||||
[](VM* vm, ArgsView args) {
|
||||
return vm->new_user_object<Mat3x3>(Mat3x3::zeros());
|
||||
}, {}, BindType::STATICMETHOD);
|
||||
},
|
||||
{},
|
||||
BindType::STATICMETHOD);
|
||||
|
||||
// @staticmethod
|
||||
vm->bind_func(type, "ones", 0, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(
|
||||
type,
|
||||
"ones",
|
||||
0,
|
||||
[](VM* vm, ArgsView args) {
|
||||
return vm->new_user_object<Mat3x3>(Mat3x3::ones());
|
||||
}, {}, BindType::STATICMETHOD);
|
||||
},
|
||||
{},
|
||||
BindType::STATICMETHOD);
|
||||
|
||||
// @staticmethod
|
||||
vm->bind_func(type, "identity", 0, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(
|
||||
type,
|
||||
"identity",
|
||||
0,
|
||||
[](VM* vm, ArgsView args) {
|
||||
return vm->new_user_object<Mat3x3>(Mat3x3::identity());
|
||||
}, {}, BindType::STATICMETHOD);
|
||||
},
|
||||
{},
|
||||
BindType::STATICMETHOD);
|
||||
|
||||
/*************** affine transformations ***************/
|
||||
// @staticmethod
|
||||
vm->bind(type, "trs(t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args){
|
||||
vm->bind(
|
||||
type,
|
||||
"trs(t: vec2, r: float, s: vec2)",
|
||||
[](VM* vm, ArgsView args) {
|
||||
Vec2 t = CAST(Vec2, args[0]);
|
||||
f64 r = CAST_F(args[1]);
|
||||
Vec2 s = CAST(Vec2, args[2]);
|
||||
return vm->new_user_object<Mat3x3>(Mat3x3::trs(t, r, s));
|
||||
}, {}, BindType::STATICMETHOD);
|
||||
},
|
||||
{},
|
||||
BindType::STATICMETHOD);
|
||||
|
||||
vm->bind(type, "copy_trs_(self, t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args){
|
||||
vm->bind(type, "copy_trs_(self, t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 t = CAST(Vec2, args[1]);
|
||||
f64 r = CAST_F(args[2]);
|
||||
@ -473,55 +499,55 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind(type, "copy_t_(self, t: vec2)", [](VM* vm, ArgsView args){
|
||||
vm->bind(type, "copy_t_(self, t: vec2)", [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 t = CAST(Vec2, args[1]);
|
||||
self = Mat3x3::trs(t, self._r(), self._s());
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind(type, "copy_r_(self, r: float)", [](VM* vm, ArgsView args){
|
||||
vm->bind(type, "copy_r_(self, r: float)", [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
f64 r = CAST_F(args[1]);
|
||||
self = Mat3x3::trs(self._t(), r, self._s());
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind(type, "copy_s_(self, s: vec2)", [](VM* vm, ArgsView args){
|
||||
vm->bind(type, "copy_s_(self, s: vec2)", [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 s = CAST(Vec2, args[1]);
|
||||
self = Mat3x3::trs(self._t(), self._r(), s);
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(type, "is_affine", 1, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "is_affine", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
return VAR(self.is_affine());
|
||||
});
|
||||
|
||||
vm->bind_func(type, "_t", 1, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "_t", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
return vm->new_user_object<Vec2>(self._t());
|
||||
});
|
||||
|
||||
vm->bind_func(type, "_r", 1, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "_r", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
return VAR(self._r());
|
||||
});
|
||||
|
||||
vm->bind_func(type, "_s", 1, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "_s", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
return vm->new_user_object<Vec2>(self._s());
|
||||
});
|
||||
|
||||
vm->bind_func(type, "transform_point", 2, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "transform_point", 2, [](VM* vm, ArgsView args) {
|
||||
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 v = CAST(Vec2, args[1]);
|
||||
Vec2 res(self._11 * v.x + self._12 * v.y + self._13, self._21 * v.x + self._22 * v.y + self._23);
|
||||
return vm->new_user_object<Vec2>(res);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "inverse_transform_point", 2, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "inverse_transform_point", 2, [](VM* vm, ArgsView args) {
|
||||
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 v = CAST(Vec2, args[1]);
|
||||
Mat3x3 inv;
|
||||
@ -530,14 +556,14 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
return vm->new_user_object<Vec2>(res);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "transform_vector", 2, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "transform_vector", 2, [](VM* vm, ArgsView args) {
|
||||
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 v = CAST(Vec2, args[1]);
|
||||
Vec2 res(self._11 * v.x + self._12 * v.y, self._21 * v.x + self._22 * v.y);
|
||||
return vm->new_user_object<Vec2>(res);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "inverse_transform_vector", 2, [](VM* vm, ArgsView args){
|
||||
vm->bind_func(type, "inverse_transform_vector", 2, [](VM* vm, ArgsView args) {
|
||||
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 v = CAST(Vec2, args[1]);
|
||||
Mat3x3 inv;
|
||||
@ -545,10 +571,9 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
|
||||
Vec2 res(inv._11 * v.x + inv._12 * v.y, inv._21 * v.x + inv._22 * v.y);
|
||||
return vm->new_user_object<Vec2>(res);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void add_module_linalg(VM* vm){
|
||||
void add_module_linalg(VM* vm) {
|
||||
PyObject* linalg = vm->new_module("linalg");
|
||||
|
||||
vm->register_user_class<Vec2>(linalg, "vec2", VM::tp_object);
|
||||
@ -561,67 +586,61 @@ void add_module_linalg(VM* vm){
|
||||
linalg->attr().set("mat3x3_p", float_p);
|
||||
}
|
||||
|
||||
/////////////// mat3x3 ///////////////
|
||||
Mat3x3::Mat3x3() {}
|
||||
|
||||
/////////////// mat3x3 ///////////////
|
||||
Mat3x3::Mat3x3() {}
|
||||
Mat3x3::Mat3x3(float _11, float _12, float _13,
|
||||
float _21, float _22, float _23,
|
||||
float _31, float _32, float _33)
|
||||
: _11(_11), _12(_12), _13(_13)
|
||||
, _21(_21), _22(_22), _23(_23)
|
||||
, _31(_31), _32(_32), _33(_33) {}
|
||||
Mat3x3::Mat3x3(float _11, float _12, float _13, float _21, float _22, float _23, float _31, float _32, float _33) :
|
||||
_11(_11), _12(_12), _13(_13), _21(_21), _22(_22), _23(_23), _31(_31), _32(_32), _33(_33) {}
|
||||
|
||||
Mat3x3 Mat3x3::zeros(){
|
||||
return Mat3x3(0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
Mat3x3 Mat3x3::zeros() { return Mat3x3(0, 0, 0, 0, 0, 0, 0, 0, 0); }
|
||||
|
||||
Mat3x3 Mat3x3::ones(){
|
||||
return Mat3x3(1, 1, 1, 1, 1, 1, 1, 1, 1);
|
||||
}
|
||||
Mat3x3 Mat3x3::ones() { return Mat3x3(1, 1, 1, 1, 1, 1, 1, 1, 1); }
|
||||
|
||||
Mat3x3 Mat3x3::identity(){
|
||||
return Mat3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
|
||||
}
|
||||
Mat3x3 Mat3x3::identity() { return Mat3x3(1, 0, 0, 0, 1, 0, 0, 0, 1); }
|
||||
|
||||
Mat3x3 Mat3x3::operator+(const Mat3x3& other) const{
|
||||
Mat3x3 Mat3x3::operator+ (const Mat3x3& other) const {
|
||||
Mat3x3 ret;
|
||||
for (int i=0; i<9; ++i) ret.v[i] = v[i] + other.v[i];
|
||||
for(int i = 0; i < 9; ++i)
|
||||
ret.v[i] = v[i] + other.v[i];
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::operator-(const Mat3x3& other) const{
|
||||
Mat3x3 Mat3x3::operator- (const Mat3x3& other) const {
|
||||
Mat3x3 ret;
|
||||
for (int i=0; i<9; ++i) ret.v[i] = v[i] - other.v[i];
|
||||
for(int i = 0; i < 9; ++i)
|
||||
ret.v[i] = v[i] - other.v[i];
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::operator*(float scalar) const{
|
||||
Mat3x3 Mat3x3::operator* (float scalar) const {
|
||||
Mat3x3 ret;
|
||||
for (int i=0; i<9; ++i) ret.v[i] = v[i] * scalar;
|
||||
for(int i = 0; i < 9; ++i)
|
||||
ret.v[i] = v[i] * scalar;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::operator/(float scalar) const{
|
||||
Mat3x3 Mat3x3::operator/ (float scalar) const {
|
||||
Mat3x3 ret;
|
||||
for (int i=0; i<9; ++i) ret.v[i] = v[i] / scalar;
|
||||
for(int i = 0; i < 9; ++i)
|
||||
ret.v[i] = v[i] / scalar;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
bool Mat3x3::operator==(const Mat3x3& other) const{
|
||||
for (int i=0; i<9; ++i){
|
||||
if (!isclose(v[i], other.v[i])) return false;
|
||||
bool Mat3x3::operator== (const Mat3x3& other) const {
|
||||
for(int i = 0; i < 9; ++i) {
|
||||
if(!isclose(v[i], other.v[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Mat3x3::operator!=(const Mat3x3& other) const{
|
||||
for (int i=0; i<9; ++i){
|
||||
if (!isclose(v[i], other.v[i])) return true;
|
||||
bool Mat3x3::operator!= (const Mat3x3& other) const {
|
||||
for(int i = 0; i < 9; ++i) {
|
||||
if(!isclose(v[i], other.v[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::matmul(const Mat3x3& other) const{
|
||||
Mat3x3 Mat3x3::matmul(const Mat3x3& other) const {
|
||||
Mat3x3 out;
|
||||
out._11 = _11 * other._11 + _12 * other._21 + _13 * other._31;
|
||||
out._12 = _11 * other._12 + _12 * other._22 + _13 * other._32;
|
||||
@ -633,32 +652,37 @@ void add_module_linalg(VM* vm){
|
||||
out._32 = _31 * other._12 + _32 * other._22 + _33 * other._32;
|
||||
out._33 = _31 * other._13 + _32 * other._23 + _33 * other._33;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
Vec3 Mat3x3::matmul(const Vec3& other) const{
|
||||
Vec3 Mat3x3::matmul(const Vec3& other) const {
|
||||
Vec3 out;
|
||||
out.x = _11 * other.x + _12 * other.y + _13 * other.z;
|
||||
out.y = _21 * other.x + _22 * other.y + _23 * other.z;
|
||||
out.z = _31 * other.x + _32 * other.y + _33 * other.z;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
float Mat3x3::determinant() const{
|
||||
return _11 * _22 * _33 + _12 * _23 * _31 + _13 * _21 * _32
|
||||
- _11 * _23 * _32 - _12 * _21 * _33 - _13 * _22 * _31;
|
||||
}
|
||||
float Mat3x3::determinant() const {
|
||||
return _11 * _22 * _33 + _12 * _23 * _31 + _13 * _21 * _32 - _11 * _23 * _32 - _12 * _21 * _33 - _13 * _22 * _31;
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::transpose() const{
|
||||
Mat3x3 Mat3x3::transpose() const {
|
||||
Mat3x3 ret;
|
||||
ret._11 = _11; ret._12 = _21; ret._13 = _31;
|
||||
ret._21 = _12; ret._22 = _22; ret._23 = _32;
|
||||
ret._31 = _13; ret._32 = _23; ret._33 = _33;
|
||||
ret._11 = _11;
|
||||
ret._12 = _21;
|
||||
ret._13 = _31;
|
||||
ret._21 = _12;
|
||||
ret._22 = _22;
|
||||
ret._23 = _32;
|
||||
ret._31 = _13;
|
||||
ret._32 = _23;
|
||||
ret._33 = _33;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
bool Mat3x3::inverse(Mat3x3& out) const{
|
||||
bool Mat3x3::inverse(Mat3x3& out) const {
|
||||
float det = determinant();
|
||||
if (isclose(det, 0)) return false;
|
||||
if(isclose(det, 0)) return false;
|
||||
float inv_det = 1.0f / det;
|
||||
out._11 = (_22 * _33 - _23 * _32) * inv_det;
|
||||
out._12 = (_13 * _32 - _12 * _33) * inv_det;
|
||||
@ -670,29 +694,24 @@ void add_module_linalg(VM* vm){
|
||||
out._32 = (_12 * _31 - _11 * _32) * inv_det;
|
||||
out._33 = (_11 * _22 - _12 * _21) * inv_det;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Mat3x3 Mat3x3::trs(Vec2 t, float radian, Vec2 s){
|
||||
Mat3x3 Mat3x3::trs(Vec2 t, float radian, Vec2 s) {
|
||||
float cr = cosf(radian);
|
||||
float sr = sinf(radian);
|
||||
return Mat3x3(s.x * cr, -s.y * sr, t.x,
|
||||
s.x * sr, s.y * cr, t.y,
|
||||
0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
return Mat3x3(s.x * cr, -s.y * sr, t.x, s.x * sr, s.y * cr, t.y, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
bool Mat3x3::is_affine() const{
|
||||
bool Mat3x3::is_affine() const {
|
||||
float det = _11 * _22 - _12 * _21;
|
||||
if(isclose(det, 0)) return false;
|
||||
return _31 == 0.0f && _32 == 0.0f && _33 == 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
Vec2 Mat3x3::_t() const { return Vec2(_13, _23); }
|
||||
float Mat3x3::_r() const { return atan2f(_21, _11); }
|
||||
Vec2 Mat3x3::_s() const {
|
||||
return Vec2(
|
||||
sqrtf(_11 * _11 + _21 * _21),
|
||||
sqrtf(_12 * _12 + _22 * _22)
|
||||
);
|
||||
}
|
||||
Vec2 Mat3x3::_t() const { return Vec2(_13, _23); }
|
||||
|
||||
float Mat3x3::_r() const { return atan2f(_21, _11); }
|
||||
|
||||
Vec2 Mat3x3::_s() const { return Vec2(sqrtf(_11 * _11 + _21 * _21), sqrtf(_12 * _12 + _22 * _22)); }
|
||||
|
||||
} // namespace pkpy
|
||||
@ -8,9 +8,9 @@
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
struct PyStructTime{
|
||||
struct PyStructTime {
|
||||
int tm_year;
|
||||
int tm_mon;
|
||||
int tm_mday;
|
||||
@ -21,7 +21,7 @@ struct PyStructTime{
|
||||
int tm_yday;
|
||||
int tm_isdst;
|
||||
|
||||
PyStructTime(std::time_t t){
|
||||
PyStructTime(std::time_t t) {
|
||||
std::tm* tm = std::localtime(&t);
|
||||
tm_year = tm->tm_year + 1900;
|
||||
tm_mon = tm->tm_mon + 1;
|
||||
@ -34,7 +34,7 @@ struct PyStructTime{
|
||||
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_mon", tm_mon);
|
||||
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");
|
||||
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) {
|
||||
f64 seconds = CAST_F(args[0]);
|
||||
auto begin = std::chrono::system_clock::now();
|
||||
while(true){
|
||||
while(true) {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
f64 elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - begin).count() / 1000.0;
|
||||
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");
|
||||
vm->setattr(mod, "version", VAR(PK_VERSION));
|
||||
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");
|
||||
vm->bind_func(mod, "loads", 1, [](VM* vm, ArgsView args) {
|
||||
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]);
|
||||
sv = std::string_view((char*)b.data(), b.size());
|
||||
}else{
|
||||
} else {
|
||||
sv = CAST(Str&, args[0]).sv();
|
||||
}
|
||||
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
|
||||
void add_module_math(VM* vm){
|
||||
void add_module_math(VM* vm) {
|
||||
PyObject* mod = vm->new_module("math");
|
||||
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("nan", VAR(std::numeric_limits<double>::quiet_NaN()));
|
||||
|
||||
@ -131,7 +131,7 @@ void add_module_math(VM* vm){
|
||||
List& list = CAST(List&, args[0]);
|
||||
double sum = 0;
|
||||
double c = 0;
|
||||
for(PyVar arg : list){
|
||||
for(PyVar arg: list) {
|
||||
double x = CAST_F(arg);
|
||||
double y = x - c;
|
||||
double t = sum + y;
|
||||
@ -145,7 +145,7 @@ void add_module_math(VM* vm){
|
||||
i64 b = CAST(i64, args[1]);
|
||||
if(a < 0) a = -a;
|
||||
if(b < 0) b = -b;
|
||||
while(b != 0){
|
||||
while(b != 0) {
|
||||
i64 t = b;
|
||||
b = a % b;
|
||||
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(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 base = CAST_F(args[1]);
|
||||
return VAR(std::log(x) / std::log(base));
|
||||
@ -199,12 +199,13 @@ void add_module_math(VM* vm){
|
||||
i64 n = CAST(i64, args[0]);
|
||||
if(n < 0) vm->ValueError("factorial() not defined for negative values");
|
||||
i64 r = 1;
|
||||
for(i64 i=2; i<=n; i++) r *= i;
|
||||
for(i64 i = 2; i <= n; i++)
|
||||
r *= i;
|
||||
return VAR(r);
|
||||
});
|
||||
}
|
||||
|
||||
void add_module_traceback(VM* vm){
|
||||
void add_module_traceback(VM* vm) {
|
||||
PyObject* mod = vm->new_module("traceback");
|
||||
vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) {
|
||||
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");
|
||||
|
||||
vm->bind_func(mod, "dis", 1, [](VM* vm, ArgsView args) {
|
||||
CodeObject_ code;
|
||||
PyVar obj = args[0];
|
||||
if(is_type(obj, vm->tp_str)){
|
||||
if(is_type(obj, vm->tp_str)) {
|
||||
const Str& source = CAST(Str, obj);
|
||||
code = vm->compile(source, "<dis>", EXEC_MODE);
|
||||
}
|
||||
@ -238,21 +239,20 @@ void add_module_dis(VM* vm){
|
||||
});
|
||||
}
|
||||
|
||||
void add_module_gc(VM* vm){
|
||||
void add_module_gc(VM* vm) {
|
||||
PyObject* mod = vm->new_module("gc");
|
||||
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");
|
||||
CodeObject_ code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE);
|
||||
vm->_exec(code, mod);
|
||||
PyVar Enum = mod->attr("Enum");
|
||||
vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = \
|
||||
[](VM* vm, PyTypeInfo* new_ti){
|
||||
vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = [](VM* vm, PyTypeInfo* new_ti) {
|
||||
new_ti->subclass_enabled = false; // Enum class cannot be subclassed twice
|
||||
NameDict& attr = new_ti->obj->attr();
|
||||
for(auto [k, v]: attr.items()){
|
||||
for(auto [k, v]: attr.items()) {
|
||||
// wrap every attribute
|
||||
std::string_view k_sv = k.sv();
|
||||
if(k_sv.empty() || k_sv[0] == '_') continue;
|
||||
@ -261,14 +261,14 @@ void add_module_enum(VM* vm){
|
||||
};
|
||||
}
|
||||
|
||||
void add_module___builtins(VM* vm){
|
||||
void add_module___builtins(VM* vm) {
|
||||
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]);
|
||||
});
|
||||
|
||||
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];
|
||||
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");
|
||||
@ -277,11 +277,11 @@ void add_module___builtins(VM* vm){
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/************************************************/
|
||||
#if PK_ENABLE_PROFILER
|
||||
struct LineProfilerW;
|
||||
struct _LpGuard{
|
||||
|
||||
struct _LpGuard {
|
||||
PK_ALWAYS_PASS_BY_POINTER(_LpGuard)
|
||||
LineProfilerW* lp;
|
||||
VM* vm;
|
||||
@ -290,16 +290,16 @@ struct _LpGuard{
|
||||
};
|
||||
|
||||
// line_profiler wrapper
|
||||
struct LineProfilerW{
|
||||
struct LineProfilerW {
|
||||
LineProfiler profiler;
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||
vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args){
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args) {
|
||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||
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]);
|
||||
vm->check_type(args[1], VM::tp_function);
|
||||
auto decl = PK_OBJ_GET(Function, args[1]).decl.get();
|
||||
@ -307,19 +307,20 @@ struct LineProfilerW{
|
||||
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]);
|
||||
PyVar func = view[1];
|
||||
const Tuple& args = CAST(Tuple&, view[2]);
|
||||
vm->s_data.push(func);
|
||||
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);
|
||||
PyVar ret = vm->vectorcall(args.size());
|
||||
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]);
|
||||
vm->stdout_write(self.profiler.stats());
|
||||
return vm->None;
|
||||
@ -327,28 +328,23 @@ struct LineProfilerW{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
_LpGuard::_LpGuard(LineProfilerW* lp, VM* vm): lp(lp), vm(vm) {
|
||||
if(vm->_profiler){
|
||||
vm->ValueError("only one profiler can be enabled at a time");
|
||||
}
|
||||
_LpGuard::_LpGuard(LineProfilerW* lp, VM* vm) : lp(lp), vm(vm) {
|
||||
if(vm->_profiler) { vm->ValueError("only one profiler can be enabled at a time"); }
|
||||
vm->_profiler = &lp->profiler;
|
||||
lp->profiler.begin();
|
||||
}
|
||||
|
||||
_LpGuard::~_LpGuard(){
|
||||
_LpGuard::~_LpGuard() {
|
||||
vm->_profiler = nullptr;
|
||||
lp->profiler.end();
|
||||
}
|
||||
|
||||
void add_module_line_profiler(VM *vm){
|
||||
void add_module_line_profiler(VM* vm) {
|
||||
PyObject* mod = vm->new_module("line_profiler");
|
||||
vm->register_user_class<LineProfilerW>(mod, "LineProfiler");
|
||||
}
|
||||
#else
|
||||
void add_module_line_profiler(VM* vm){
|
||||
(void)vm;
|
||||
}
|
||||
void add_module_line_profiler(VM* vm) { (void)vm; }
|
||||
#endif
|
||||
|
||||
} // 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.
|
||||
*/
|
||||
|
||||
struct mt19937{
|
||||
static const int N = 624;
|
||||
static const int M = 397;
|
||||
struct mt19937 {
|
||||
const static int N = 624;
|
||||
const static int M = 397;
|
||||
const uint32_t MATRIX_A = 0x9908b0dfUL; /* constant vector a */
|
||||
const uint32_t UPPER_MASK = 0x80000000UL; /* most significant w-r bits */
|
||||
const uint32_t LOWER_MASK = 0x7fffffffUL; /* least significant r bits */
|
||||
|
||||
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 */
|
||||
void seed(uint32_t s)
|
||||
{
|
||||
mt[0]= s & 0xffffffffUL;
|
||||
for (mti=1; mti<N; mti++) {
|
||||
mt[mti] =
|
||||
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
|
||||
void seed(uint32_t s) {
|
||||
mt[0] = s & 0xffffffffUL;
|
||||
for(mti = 1; mti < N; mti++) {
|
||||
mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
|
||||
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
|
||||
/* In the previous versions, MSBs of the seed affect */
|
||||
/* only MSBs of the array mt[]. */
|
||||
@ -63,28 +61,27 @@ struct mt19937{
|
||||
}
|
||||
|
||||
/* generates a random number on [0,0xffffffff]-interval */
|
||||
uint32_t next_uint32(void)
|
||||
{
|
||||
uint32_t next_uint32(void) {
|
||||
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 */
|
||||
|
||||
if (mti >= N) { /* generate N words at one time */
|
||||
if(mti >= N) { /* generate N words at one time */
|
||||
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 */
|
||||
|
||||
for (kk=0;kk<N-M;kk++) {
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
for(kk = 0; kk < N - M; kk++) {
|
||||
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
|
||||
mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
}
|
||||
for (;kk<N-1;kk++) {
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
for(; kk < N - 1; kk++) {
|
||||
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
|
||||
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
}
|
||||
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
|
||||
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
|
||||
mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL];
|
||||
|
||||
mti = 0;
|
||||
}
|
||||
@ -100,44 +97,36 @@ struct mt19937{
|
||||
return y;
|
||||
}
|
||||
|
||||
uint64_t next_uint64(void){
|
||||
return (uint64_t(next_uint32()) << 32) | next_uint32();
|
||||
}
|
||||
uint64_t next_uint64(void) { return (uint64_t(next_uint32()) << 32) | next_uint32(); }
|
||||
|
||||
/* generates a random number on [0,1)-real-interval */
|
||||
float random(void)
|
||||
{
|
||||
return next_uint32()*(1.0/4294967296.0); /* divided by 2^32 */
|
||||
}
|
||||
float random(void) { return next_uint32() * (1.0 / 4294967296.0); /* divided by 2^32 */ }
|
||||
|
||||
/* 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;
|
||||
if(delta < 0x80000000UL){
|
||||
if(delta < 0x80000000UL) {
|
||||
return a + next_uint32() % (uint32_t)delta;
|
||||
}else{
|
||||
} else {
|
||||
return a + next_uint64() % delta;
|
||||
}
|
||||
}
|
||||
|
||||
float uniform(float a, float b){
|
||||
return a + random() * (b - a);
|
||||
}
|
||||
float uniform(float a, float b) { return a + random() * (b - a); }
|
||||
};
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
namespace pkpy{
|
||||
|
||||
struct Random{
|
||||
struct Random {
|
||||
mt19937 gen;
|
||||
|
||||
Random(){
|
||||
Random() {
|
||||
auto count = std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||
gen.seed((uint32_t)count);
|
||||
}
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type){
|
||||
vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args){
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args) {
|
||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||
return vm->new_object<Random>(cls);
|
||||
});
|
||||
@ -152,7 +141,7 @@ struct Random{
|
||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||
i64 a = CAST(i64, args[1]);
|
||||
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));
|
||||
});
|
||||
|
||||
@ -165,14 +154,14 @@ struct Random{
|
||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||
f64 a = CAST(f64, args[1]);
|
||||
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));
|
||||
});
|
||||
|
||||
vm->bind_func(type, "shuffle", 2, [](VM* vm, ArgsView args) {
|
||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||
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);
|
||||
std::swap(L[i], L[j]);
|
||||
}
|
||||
@ -183,7 +172,7 @@ struct Random{
|
||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||
ArgsView view = vm->cast_array_view(args[1]);
|
||||
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];
|
||||
});
|
||||
|
||||
@ -194,20 +183,21 @@ struct Random{
|
||||
int size = view.size();
|
||||
if(size == 0) vm->IndexError("cannot choose from an empty sequence");
|
||||
array<f64> cum_weights(size);
|
||||
if(args[2] == vm->None){
|
||||
for(int i = 0; i < size; i++) cum_weights[i] = i + 1;
|
||||
}else{
|
||||
if(args[2] == vm->None) {
|
||||
for(int i = 0; i < size; i++)
|
||||
cum_weights[i] = i + 1;
|
||||
} else {
|
||||
ArgsView weights = vm->cast_array_view(args[2]);
|
||||
if(weights.size() != size) vm->ValueError(_S("len(weights) != ", size));
|
||||
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]);
|
||||
}
|
||||
}
|
||||
if(cum_weights[size - 1] <= 0) vm->ValueError("total of weights must be greater than zero");
|
||||
int k = CAST(int, args[3]);
|
||||
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]);
|
||||
int idx = std::lower_bound(cum_weights.begin(), cum_weights.end(), r) - cum_weights.begin();
|
||||
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");
|
||||
vm->register_user_class<Random>(mod, "Random");
|
||||
PyVar instance = vm->new_user_object<Random>();
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#include "pocketpy/objects/builtins.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
PyVar const PY_OP_CALL(Type(), new PyObject(Type()));
|
||||
PyVar const PY_OP_YIELD(Type(), new PyObject(Type()));
|
||||
namespace pkpy {
|
||||
const PyVar PY_OP_CALL(Type(), new PyObject(Type()));
|
||||
const PyVar PY_OP_YIELD(Type(), new PyObject(Type()));
|
||||
} // namespace pkpy
|
||||
@ -1,9 +1,9 @@
|
||||
#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) {
|
||||
blocks.push_back(CodeBlock(CodeBlockType::NO_BLOCK, -1, 0));
|
||||
}
|
||||
}
|
||||
} // namespace pkpy
|
||||
@ -1,24 +1,24 @@
|
||||
#include "pocketpy/objects/dict.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
namespace pkpy {
|
||||
|
||||
Dict::Dict(): _capacity(__Capacity),
|
||||
_mask(__Capacity-1),
|
||||
_size(0), _critical_size(__Capacity*__LoadFactor+0.5f), _head_idx(-1), _tail_idx(-1){
|
||||
Dict::Dict() :
|
||||
_capacity(__Capacity), _mask(__Capacity - 1), _size(0), _critical_size(__Capacity * __LoadFactor + 0.5f),
|
||||
_head_idx(-1), _tail_idx(-1) {
|
||||
__alloc_items();
|
||||
}
|
||||
}
|
||||
|
||||
void Dict::__alloc_items(){
|
||||
void Dict::__alloc_items() {
|
||||
_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){
|
||||
Dict::Dict(Dict&& other) {
|
||||
_capacity = other._capacity;
|
||||
_mask = other._mask;
|
||||
_size = other._size;
|
||||
@ -27,9 +27,9 @@ namespace pkpy{
|
||||
_tail_idx = other._tail_idx;
|
||||
_items = other._items;
|
||||
other._items = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Dict::Dict(const Dict& other){
|
||||
Dict::Dict(const Dict& other) {
|
||||
_capacity = other._capacity;
|
||||
_mask = other._mask;
|
||||
_size = other._size;
|
||||
@ -39,38 +39,39 @@ namespace pkpy{
|
||||
// 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){
|
||||
void Dict::set(VM* vm, PyVar key, PyVar val) {
|
||||
// do possible rehash
|
||||
if(_size+1 > _critical_size) _rehash(vm);
|
||||
bool ok; int i;
|
||||
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){
|
||||
if(_size == 0 + 1) {
|
||||
_head_idx = i;
|
||||
_tail_idx = i;
|
||||
}else{
|
||||
} else {
|
||||
_items[i].prev = _tail_idx;
|
||||
_items[_tail_idx].next = i;
|
||||
_tail_idx = i;
|
||||
}
|
||||
}
|
||||
_items[i].second = val;
|
||||
}
|
||||
}
|
||||
|
||||
void Dict::_rehash(VM* vm){
|
||||
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;
|
||||
_critical_size = _capacity * __LoadFactor + 0.5f;
|
||||
_head_idx = -1;
|
||||
_tail_idx = -1;
|
||||
|
||||
@ -78,47 +79,50 @@ namespace pkpy{
|
||||
|
||||
// copy old items to new dict
|
||||
int i = old_head_idx;
|
||||
while(i != -1){
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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
|
||||
// _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){
|
||||
if(_size == 0) {
|
||||
_head_idx = -1;
|
||||
_tail_idx = -1;
|
||||
}else{
|
||||
if(_head_idx == i){
|
||||
} else {
|
||||
if(_head_idx == i) {
|
||||
_head_idx = _items[i].next;
|
||||
_items[_head_idx].prev = -1;
|
||||
}else if(_tail_idx == i){
|
||||
} else if(_tail_idx == i) {
|
||||
_tail_idx = _items[i].prev;
|
||||
_items[_tail_idx].next = -1;
|
||||
}else{
|
||||
} else {
|
||||
_items[_items[i].prev].next = _items[i].next;
|
||||
_items[_items[i].next].prev = _items[i].prev;
|
||||
}
|
||||
@ -126,49 +130,51 @@ namespace pkpy{
|
||||
_items[i].prev = -1;
|
||||
_items[i].next = -1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void Dict::update(VM* vm, const Dict& other){
|
||||
other.apply([&](PyVar k, PyVar v){ set(vm, k, v); });
|
||||
}
|
||||
void Dict::update(VM* vm, const Dict& other) {
|
||||
other.apply([&](PyVar k, PyVar v) {
|
||||
set(vm, k, v);
|
||||
});
|
||||
}
|
||||
|
||||
Tuple Dict::keys() const{
|
||||
Tuple Dict::keys() const {
|
||||
Tuple t(_size);
|
||||
int i = _head_idx;
|
||||
int j = 0;
|
||||
while(i != -1){
|
||||
while(i != -1) {
|
||||
t[j++] = _items[i].first;
|
||||
i = _items[i].next;
|
||||
}
|
||||
assert(j == _size);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
Tuple Dict::values() const{
|
||||
Tuple Dict::values() const {
|
||||
Tuple t(_size);
|
||||
int i = _head_idx;
|
||||
int j = 0;
|
||||
while(i != -1){
|
||||
while(i != -1) {
|
||||
t[j++] = _items[i].second;
|
||||
i = _items[i].next;
|
||||
}
|
||||
assert(j == _size);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
void Dict::clear(){
|
||||
void Dict::clear() {
|
||||
_size = 0;
|
||||
_head_idx = -1;
|
||||
_tail_idx = -1;
|
||||
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::~Dict() {
|
||||
if(_items) std::free(_items);
|
||||
}
|
||||
}
|
||||
} // namespace pkpy
|
||||
@ -1,7 +1,7 @@
|
||||
#include "pocketpy/objects/error.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
Str Exception::summary() const {
|
||||
namespace pkpy {
|
||||
Str Exception::summary() const {
|
||||
SStream ss;
|
||||
if(is_re) ss << "Traceback (most recent call last):\n";
|
||||
// while(!st.empty()) {
|
||||
@ -9,12 +9,14 @@ namespace pkpy{
|
||||
// st.pop();
|
||||
// }
|
||||
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';
|
||||
}
|
||||
if (!msg.empty()) ss << type.sv() << ": " << msg;
|
||||
else ss << type.sv();
|
||||
if(!msg.empty())
|
||||
ss << type.sv() << ": " << msg;
|
||||
else
|
||||
ss << type.sv();
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
@ -1,5 +1,5 @@
|
||||
#include "pocketpy/objects/object.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
PyVar::PyVar(PyObject* p): PyVar(p->type, p) {}
|
||||
namespace pkpy {
|
||||
PyVar::PyVar(PyObject* p) : PyVar(p->type, p) {}
|
||||
} // namespace pkpy
|
||||
@ -1,66 +1,68 @@
|
||||
#include "pocketpy/objects/sourcedata.hpp"
|
||||
|
||||
namespace pkpy{
|
||||
SourceData::SourceData(std::string_view source, const Str& filename, CompileMode mode): filename(filename), mode(mode) {
|
||||
namespace pkpy {
|
||||
SourceData::SourceData(std::string_view source, const Str& filename, CompileMode mode) :
|
||||
filename(filename), mode(mode) {
|
||||
int index = 0;
|
||||
// Skip utf8 BOM if there is any.
|
||||
if (strncmp(source.data(), "\xEF\xBB\xBF", 3) == 0) index += 3;
|
||||
if(strncmp(source.data(), "\xEF\xBB\xBF", 3) == 0) index += 3;
|
||||
// Drop all '\r'
|
||||
SStream ss(source.size() + 1);
|
||||
while(index < source.size()){
|
||||
while(index < source.size()) {
|
||||
if(source[index] != '\r') ss << source[index];
|
||||
index++;
|
||||
}
|
||||
this->source = ss.str();
|
||||
if(this->source.size>5 && this->source.sv().substr(0, 5)=="pkpy:"){
|
||||
if(this->source.size > 5 && this->source.sv().substr(0, 5) == "pkpy:") {
|
||||
this->is_precompiled = true;
|
||||
}else{
|
||||
} else {
|
||||
this->is_precompiled = false;
|
||||
}
|
||||
line_starts.push_back(this->source.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
SourceData::SourceData(const Str& filename, CompileMode mode): filename(filename), mode(mode) {
|
||||
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 {
|
||||
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++;
|
||||
while(*i != '\n' && *i != '\0' && i - _start < 300)
|
||||
i++;
|
||||
return {_start, i};
|
||||
}
|
||||
}
|
||||
|
||||
std::string_view SourceData::get_line(int lineno) const{
|
||||
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);
|
||||
if(_0 && _1) return std::string_view(_0, _1 - _0);
|
||||
return "<?>";
|
||||
}
|
||||
}
|
||||
|
||||
Str SourceData::snapshot(int lineno, const char* cursor, std::string_view name) const{
|
||||
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){
|
||||
if(!is_precompiled) {
|
||||
ss << '\n';
|
||||
std::pair<const char*,const char*> pair = _get_line(lineno);
|
||||
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();
|
||||
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){
|
||||
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 {
|
||||
|
||||
Tuple::Tuple(int n){
|
||||
if(n <= INLINED_SIZE){
|
||||
Tuple::Tuple(int n) {
|
||||
if(n <= INLINED_SIZE) {
|
||||
this->_args = _inlined;
|
||||
}else{
|
||||
} else {
|
||||
this->_args = (PyVar*)std::malloc(n * sizeof(PyVar));
|
||||
}
|
||||
this->_size = n;
|
||||
@ -13,38 +13,43 @@ Tuple::Tuple(int n){
|
||||
|
||||
Tuple::Tuple(Tuple&& other) noexcept {
|
||||
_size = other._size;
|
||||
if(other.is_inlined()){
|
||||
if(other.is_inlined()) {
|
||||
_args = _inlined;
|
||||
for(int i=0; i<_size; i++) _args[i] = other._args[i];
|
||||
}else{
|
||||
for(int i = 0; i < _size; i++)
|
||||
_args[i] = other._args[i];
|
||||
} else {
|
||||
_args = other._args;
|
||||
other._args = other._inlined;
|
||||
other._size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Tuple::Tuple(PyVar _0, PyVar _1): Tuple(2){
|
||||
Tuple::Tuple(PyVar _0, PyVar _1) : Tuple(2) {
|
||||
_args[0] = _0;
|
||||
_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[1] = _1;
|
||||
_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());
|
||||
for(int i=0; i<size(); i++) ret[i] = _begin[i];
|
||||
for(int i = 0; i < size(); i++)
|
||||
ret[i] = _begin[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
Tuple ArgsView::to_tuple() const{
|
||||
Tuple ArgsView::to_tuple() const {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
460
src/pocketpy.cpp
460
src/pocketpy.cpp
File diff suppressed because it is too large
Load Diff
@ -9,30 +9,27 @@ using namespace pkpy;
|
||||
|
||||
#define PK_ASSERT_N_EXTRA_ELEMENTS(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); \
|
||||
pkpy_error(vm_handle, "StackError", pkpy_string(msg.c_str())); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
#define PK_ASSERT_NO_ERROR() \
|
||||
if(vm->__c.error != nullptr) \
|
||||
return false;
|
||||
if(vm->__c.error != nullptr) return false;
|
||||
|
||||
static int count_extra_elements(VM* vm, int n){
|
||||
if(vm->callstack.empty()){
|
||||
return vm->s_data.size();
|
||||
}
|
||||
static int count_extra_elements(VM* vm, int n) {
|
||||
if(vm->callstack.empty()) { return vm->s_data.size(); }
|
||||
assert(!vm->__c.s_view.empty());
|
||||
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* end = vm->s_data.end();
|
||||
if(vm->callstack.empty()){
|
||||
if(vm->callstack.empty()) {
|
||||
begin = vm->s_data.begin();
|
||||
}else{
|
||||
} else {
|
||||
assert(!vm->__c.s_view.empty());
|
||||
begin = vm->__c.s_view.top().begin();
|
||||
}
|
||||
@ -43,26 +40,23 @@ static PyVar stack_item(VM* vm, int index){
|
||||
}
|
||||
|
||||
#define PK_PROTECTED(__B) \
|
||||
try{ __B } \
|
||||
catch(TopLevelException e) { \
|
||||
try { \
|
||||
__B \
|
||||
} catch(TopLevelException e) { \
|
||||
vm->__c.error = e.ptr->self(); \
|
||||
return false; \
|
||||
} catch(const std::exception& re){ \
|
||||
} catch(const std::exception& re) { \
|
||||
PyObject* e_t = vm->_t(vm->tp_exception); \
|
||||
vm->__c.error = vm->call(e_t, VAR(re.what())).get(); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
pkpy_vm* pkpy_new_vm(bool enable_os){
|
||||
return (pkpy_vm*)new VM(enable_os);
|
||||
}
|
||||
pkpy_vm* pkpy_new_vm(bool enable_os) { return (pkpy_vm*)new VM(enable_os); }
|
||||
|
||||
void pkpy_delete_vm(pkpy_vm* vm){
|
||||
return delete (VM*)vm;
|
||||
}
|
||||
void pkpy_delete_vm(pkpy_vm* vm) { return delete (VM*)vm; }
|
||||
|
||||
bool pkpy_exec(pkpy_vm* vm_handle, const char* source) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar res;
|
||||
PK_PROTECTED(
|
||||
@ -72,14 +66,13 @@ bool pkpy_exec(pkpy_vm* vm_handle, const char* source) {
|
||||
return res != nullptr;
|
||||
}
|
||||
|
||||
bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, const char* module){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, const char* module) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar res;
|
||||
PyObject* mod;
|
||||
PK_PROTECTED(
|
||||
if(module == nullptr){
|
||||
mod = vm->_main;
|
||||
if(module == nullptr){ mod = vm->_main;
|
||||
}else{
|
||||
mod = vm->_modules[module].get(); // may raise
|
||||
}
|
||||
@ -89,13 +82,13 @@ bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, i
|
||||
return res != nullptr;
|
||||
}
|
||||
|
||||
void pkpy_set_main_argv(pkpy_vm* vm_handle, int argc, char** argv){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
void pkpy_set_main_argv(pkpy_vm* vm_handle, int argc, char** argv) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
vm->set_main_argv(argc, argv);
|
||||
}
|
||||
|
||||
bool pkpy_dup(pkpy_vm* vm_handle, int n){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_dup(pkpy_vm* vm_handle, int n) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, n);
|
||||
@ -104,15 +97,15 @@ bool pkpy_dup(pkpy_vm* vm_handle, int n){
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_pop(pkpy_vm* vm_handle, int n){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_pop(pkpy_vm* vm_handle, int n) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(n)
|
||||
vm->s_data.shrink(n);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_pop_top(pkpy_vm* vm_handle){
|
||||
bool pkpy_pop_top(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
@ -120,7 +113,7 @@ bool pkpy_pop_top(pkpy_vm* vm_handle){
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_dup_top(pkpy_vm* vm_handle){
|
||||
bool pkpy_dup_top(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
@ -128,7 +121,7 @@ bool pkpy_dup_top(pkpy_vm* vm_handle){
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_rot_two(pkpy_vm* vm_handle){
|
||||
bool pkpy_rot_two(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(2)
|
||||
@ -136,19 +129,17 @@ bool pkpy_rot_two(pkpy_vm* vm_handle){
|
||||
return true;
|
||||
}
|
||||
|
||||
int pkpy_stack_size(pkpy_vm* vm_handle){
|
||||
int pkpy_stack_size(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
if(vm->callstack.empty()){
|
||||
return vm->s_data.size();
|
||||
}
|
||||
if(vm->callstack.empty()) { return vm->s_data.size(); }
|
||||
if(vm->__c.s_view.empty()) exit(127);
|
||||
return vm->s_data._sp - vm->__c.s_view.top().begin();
|
||||
}
|
||||
|
||||
// int
|
||||
bool pkpy_push_int(pkpy_vm* vm_handle, int value) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar res;
|
||||
PK_PROTECTED(
|
||||
@ -159,16 +150,16 @@ bool pkpy_push_int(pkpy_vm* vm_handle, int value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_is_int(pkpy_vm* vm_handle, int i){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_is_int(pkpy_vm* vm_handle, int i) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
return is_int(stack_item(vm, i));
|
||||
)
|
||||
}
|
||||
|
||||
bool pkpy_to_int(pkpy_vm* vm_handle, int i, int* out){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_to_int(pkpy_vm* vm_handle, int i, int* out) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
@ -179,15 +170,15 @@ bool pkpy_to_int(pkpy_vm* vm_handle, int i, int* out){
|
||||
|
||||
// float
|
||||
bool pkpy_push_float(pkpy_vm* vm_handle, double value) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar res = py_var(vm, value);
|
||||
vm->s_data.push(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_is_float(pkpy_vm* vm_handle, int i){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_is_float(pkpy_vm* vm_handle, int i) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
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){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_to_float(pkpy_vm* vm_handle, int i, double* out) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
@ -207,14 +198,14 @@ bool pkpy_to_float(pkpy_vm* vm_handle, int i, double* out){
|
||||
|
||||
// bool
|
||||
bool pkpy_push_bool(pkpy_vm* vm_handle, bool value) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
vm->s_data.push(value ? vm->True : vm->False);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_is_bool(pkpy_vm* vm_handle, int i){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_is_bool(pkpy_vm* vm_handle, int i) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
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){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_to_bool(pkpy_vm* vm_handle, int i, bool* out) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
@ -234,15 +225,15 @@ bool pkpy_to_bool(pkpy_vm* vm_handle, int i, bool* out){
|
||||
|
||||
// string
|
||||
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()
|
||||
PyVar res = py_var(vm, value);
|
||||
vm->s_data.push(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_is_string(pkpy_vm* vm_handle, int i){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_is_string(pkpy_vm* vm_handle, int i) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
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){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_to_string(pkpy_vm* vm_handle, int i, pkpy_CString* out) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
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
|
||||
bool pkpy_push_voidp(pkpy_vm* vm_handle, void* value) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar res = py_var(vm, value);
|
||||
vm->s_data.push(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_is_voidp(pkpy_vm* vm_handle, int i){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_is_voidp(pkpy_vm* vm_handle, int i) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
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){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_to_voidp(pkpy_vm* vm_handle, int i, void** out) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
@ -292,14 +283,14 @@ bool pkpy_to_voidp(pkpy_vm* vm_handle, int i, void** out){
|
||||
|
||||
// none
|
||||
bool pkpy_push_none(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
vm->s_data.push(vm->None);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_is_none(pkpy_vm* vm_handle, int i){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_is_none(pkpy_vm* vm_handle, int i) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar item = stack_item(vm, i);
|
||||
@ -309,25 +300,25 @@ bool pkpy_is_none(pkpy_vm* vm_handle, int i){
|
||||
|
||||
// null
|
||||
bool pkpy_push_null(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
vm->s_data.push(PY_NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct TempViewPopper{
|
||||
struct TempViewPopper {
|
||||
VM* vm;
|
||||
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;
|
||||
vm->__c.s_view.pop();
|
||||
used = true;
|
||||
}
|
||||
|
||||
~TempViewPopper(){ restore(); }
|
||||
~TempViewPopper() { restore(); }
|
||||
};
|
||||
|
||||
// function
|
||||
@ -341,21 +332,21 @@ static PyVar c_function_wrapper(VM* vm, ArgsView args) {
|
||||
_tvp.restore();
|
||||
|
||||
// propagate_if_errored
|
||||
if (vm->__c.error != nullptr){
|
||||
if(vm->__c.error != nullptr) {
|
||||
PyObject* e_obj = vm->__c.error;
|
||||
vm->__c.error = nullptr;
|
||||
vm->_error(e_obj);
|
||||
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 == 1) return vm->s_data.popx();
|
||||
if(retc == 1) return vm->s_data.popx();
|
||||
ArgsView ret_view(curr_sp, vm->s_data._sp);
|
||||
return py_var(vm, ret_view.to_tuple());
|
||||
}
|
||||
|
||||
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()
|
||||
PyVar f_obj;
|
||||
PK_PROTECTED(
|
||||
@ -367,7 +358,7 @@ bool pkpy_push_function(pkpy_vm* vm_handle, const char* sig, pkpy_CFunction f) {
|
||||
|
||||
// special push
|
||||
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_PROTECTED(
|
||||
PyObject* module = vm->new_module(name);
|
||||
@ -378,7 +369,7 @@ bool pkpy_push_module(pkpy_vm* vm_handle, const char* name) {
|
||||
|
||||
// some opt
|
||||
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_N_EXTRA_ELEMENTS(1)
|
||||
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) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(2)
|
||||
PyVar a = vm->s_data.top();
|
||||
@ -401,21 +392,21 @@ bool pkpy_setattr(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//get global will also get bulitins
|
||||
// get global will also get bulitins
|
||||
bool pkpy_getglobal(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PyVar o = vm->_main->attr().try_get(StrName(name));
|
||||
if (o == nullptr) {
|
||||
if(o == nullptr) {
|
||||
o = vm->builtins->attr().try_get(StrName(name));
|
||||
if (o == nullptr) return false;
|
||||
if(o == nullptr) return false;
|
||||
}
|
||||
vm->s_data.push(o);
|
||||
return true;
|
||||
}
|
||||
|
||||
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_N_EXTRA_ELEMENTS(1)
|
||||
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) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
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) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
auto _lock = vm->heap.gc_scope_lock();
|
||||
@ -450,8 +441,8 @@ bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pkpy_get_unbound_method(pkpy_vm* vm_handle, pkpy_CName name){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
bool pkpy_get_unbound_method(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
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) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
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) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
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) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_PROTECTED(
|
||||
PyVar module = vm->py_import(name);
|
||||
@ -501,14 +492,15 @@ bool pkpy_py_import(pkpy_vm* vm_handle, pkpy_CString name) {
|
||||
|
||||
/* Error Handling */
|
||||
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()
|
||||
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);
|
||||
if(e_t == nullptr){
|
||||
if(e_t == nullptr) {
|
||||
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();
|
||||
@ -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) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
return vm->__c.error != nullptr;
|
||||
}
|
||||
|
||||
bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
// no error
|
||||
if (vm->__c.error == nullptr) return false;
|
||||
if(vm->__c.error == nullptr) return false;
|
||||
Exception& e = vm->__c.error->as<Exception>();
|
||||
if (message != nullptr)
|
||||
if(message != nullptr)
|
||||
*message = strdup(e.summary().c_str());
|
||||
else
|
||||
std::cout << e.summary() << std::endl;
|
||||
vm->__c.error = nullptr;
|
||||
if(vm->callstack.empty()){
|
||||
if(vm->callstack.empty()) {
|
||||
vm->s_data.clear();
|
||||
}else{
|
||||
} else {
|
||||
if(vm->__c.s_view.empty()) exit(127);
|
||||
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) {
|
||||
VM* vm = (VM*) vm_handle;
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(argc + 2)
|
||||
PyVar res;
|
||||
@ -550,39 +542,28 @@ bool pkpy_vectorcall(pkpy_vm* vm_handle, int argc) {
|
||||
vm->s_data.push(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****************************************************************/
|
||||
void pkpy_free(void* p){
|
||||
std::free(p);
|
||||
}
|
||||
void pkpy_free(void* p) { std::free(p); }
|
||||
|
||||
pkpy_CName pkpy_name(const char* name){
|
||||
return StrName(name).index;
|
||||
}
|
||||
pkpy_CName pkpy_name(const char* name) { return StrName(name).index; }
|
||||
|
||||
pkpy_CString pkpy_name_to_string(pkpy_CName name){
|
||||
return StrName(name).c_str();
|
||||
}
|
||||
pkpy_CString pkpy_name_to_string(pkpy_CName name) { return StrName(name).c_str(); }
|
||||
|
||||
void pkpy_set_output_handler(pkpy_vm* vm_handle, pkpy_COutputHandler handler){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
void pkpy_set_output_handler(pkpy_vm* vm_handle, pkpy_COutputHandler handler) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
vm->_stdout = handler;
|
||||
}
|
||||
|
||||
void pkpy_set_import_handler(pkpy_vm* vm_handle, pkpy_CImportHandler handler){
|
||||
VM* vm = (VM*) vm_handle;
|
||||
void pkpy_set_import_handler(pkpy_vm* vm_handle, pkpy_CImportHandler handler) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
vm->_import_handler = handler;
|
||||
}
|
||||
|
||||
void* pkpy_new_repl(pkpy_vm* vm_handle){
|
||||
return new REPL((VM*)vm_handle);
|
||||
}
|
||||
void* pkpy_new_repl(pkpy_vm* vm_handle) { return new REPL((VM*)vm_handle); }
|
||||
|
||||
bool pkpy_repl_input(void* r, const char* line){
|
||||
return ((REPL*)r)->input(line);
|
||||
}
|
||||
bool pkpy_repl_input(void* r, const char* line) { return ((REPL*)r)->input(line); }
|
||||
|
||||
void pkpy_delete_repl(void* repl){
|
||||
delete (REPL*)repl;
|
||||
}
|
||||
void pkpy_delete_repl(void* repl) { delete (REPL*)repl; }
|
||||
|
||||
#endif // PK_NO_EXPORT_C_API
|
||||
@ -4,21 +4,21 @@
|
||||
#include "pocketpy/common/export.h"
|
||||
|
||||
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(_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("Type \"exit()\" to exit." "\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool REPL::input(std::string line){
|
||||
bool REPL::input(std::string line) {
|
||||
CompileMode mode = REPL_MODE;
|
||||
if(need_more_lines){
|
||||
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++){
|
||||
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;
|
||||
}
|
||||
@ -26,20 +26,20 @@ namespace pkpy {
|
||||
line = buffer;
|
||||
buffer.clear();
|
||||
mode = CELL_MODE;
|
||||
}else{
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
try{
|
||||
try {
|
||||
vm->exec(line, "<stdin>", mode);
|
||||
}catch(NeedMoreLines ne){
|
||||
} catch(NeedMoreLines ne) {
|
||||
buffer += line;
|
||||
buffer += '\n';
|
||||
need_more_lines = ne.is_compiling_class ? 3 : 2;
|
||||
if (need_more_lines) return true;
|
||||
if(need_more_lines) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
||||
|
||||
@ -4,34 +4,31 @@
|
||||
#include <sstream>
|
||||
|
||||
#if __has_include("pocketpy_c.h")
|
||||
#include "pocketpy_c.h"
|
||||
#include "pocketpy_c.h"
|
||||
#else
|
||||
// for amalgamated build
|
||||
#include "pocketpy.h"
|
||||
// for amalgamated build
|
||||
#include "pocketpy.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
#include <windows.h>
|
||||
|
||||
std::string pkpy_platform_getline(bool* eof) {
|
||||
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
std::wstringstream wss;
|
||||
WCHAR buf;
|
||||
DWORD read;
|
||||
while (ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') {
|
||||
if (eof && buf == L'\x1A') *eof = true; // Ctrl+Z
|
||||
while(ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') {
|
||||
if(eof && buf == L'\x1A') *eof = true; // Ctrl+Z
|
||||
wss << buf;
|
||||
}
|
||||
std::wstring wideInput = wss.str();
|
||||
int length =
|
||||
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(),
|
||||
(int)wideInput.length(), NULL, 0, NULL, NULL);
|
||||
int length = WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), NULL, 0, NULL, NULL);
|
||||
std::string output;
|
||||
output.resize(length);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(),
|
||||
&output[0], length, NULL, NULL);
|
||||
if (!output.empty() && output.back() == '\r') output.pop_back();
|
||||
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL);
|
||||
if(!output.empty() && output.back() == '\r') output.pop_back();
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -39,8 +36,8 @@ std::string pkpy_platform_getline(bool* eof) {
|
||||
|
||||
std::string pkpy_platform_getline(bool* eof) {
|
||||
std::string output;
|
||||
if (!std::getline(std::cin, output)) {
|
||||
if (eof) *eof = true;
|
||||
if(!std::getline(std::cin, output)) {
|
||||
if(eof) *eof = true;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
@ -48,10 +45,10 @@ std::string pkpy_platform_getline(bool* eof) {
|
||||
#endif
|
||||
|
||||
static int f_input(pkpy_vm* vm) {
|
||||
if (!pkpy_is_none(vm, -1)) {
|
||||
if(!pkpy_is_none(vm, -1)) {
|
||||
pkpy_CString prompt;
|
||||
bool ok = pkpy_to_string(vm, -1, &prompt);
|
||||
if (!ok) return 0;
|
||||
if(!ok) return 0;
|
||||
std::cout << prompt << std::flush;
|
||||
}
|
||||
bool eof;
|
||||
@ -71,44 +68,42 @@ int main(int argc, char** argv) {
|
||||
pkpy_py_import(vm, "builtins");
|
||||
pkpy_setattr(vm, pkpy_name("input"));
|
||||
|
||||
if (argc == 1) {
|
||||
if(argc == 1) {
|
||||
void* repl = pkpy_new_repl(vm);
|
||||
bool need_more_lines = false;
|
||||
while (true) {
|
||||
while(true) {
|
||||
std::cout << (need_more_lines ? "... " : ">>> ");
|
||||
bool eof = false;
|
||||
std::string line = pkpy_platform_getline(&eof);
|
||||
if (eof) break;
|
||||
if(eof) break;
|
||||
need_more_lines = pkpy_repl_input(repl, line.c_str());
|
||||
}
|
||||
pkpy_delete_vm(vm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
if(argc == 2) {
|
||||
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]);
|
||||
filepath = std::filesystem::absolute(filepath);
|
||||
if (!std::filesystem::exists(filepath)) {
|
||||
if(!std::filesystem::exists(filepath)) {
|
||||
std::cerr << "File not found: " << argv_1 << std::endl;
|
||||
return 2;
|
||||
}
|
||||
std::ifstream file(filepath);
|
||||
if (!file.is_open()) {
|
||||
if(!file.is_open()) {
|
||||
std::cerr << "Failed to open file: " << argv_1 << std::endl;
|
||||
return 3;
|
||||
}
|
||||
std::string src((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
std::string src((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||
file.close();
|
||||
|
||||
pkpy_set_main_argv(vm, argc, argv);
|
||||
|
||||
bool ok = pkpy_exec_2(vm, src.c_str(),
|
||||
filepath.filename().string().c_str(), 0, NULL);
|
||||
if (!ok) pkpy_clear_error(vm, NULL);
|
||||
bool ok = pkpy_exec_2(vm, src.c_str(), filepath.filename().string().c_str(), 0, NULL);
|
||||
if(!ok) pkpy_clear_error(vm, NULL);
|
||||
pkpy_delete_vm(vm);
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user