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:
ykiko 2024-06-04 22:55:17 +08:00 committed by GitHub
parent 0b404a51cb
commit 1c82060daf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
93 changed files with 10429 additions and 9836 deletions

View File

@ -1,6 +1,102 @@
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html # clang-format configuration
BasedOnStyle: Google # compatible with clang-format 18
IndentWidth: 4
UseTab: Never
IndentPPDirectives: BeforeHash UseTab: Never
ColumnLimit: 120
# Indent
IndentWidth: 4
BracedInitializerIndentWidth: 4
AccessModifierOffset: -4
IndentAccessModifiers: false
IndentCaseLabels: true
IndentExternBlock: Indent
IndentGotoLabels: true
IndentRequiresClause: true
IndentWrappedFunctionNames: true
NamespaceIndentation: None
LambdaBodyIndentation: Signature
BitFieldColonSpacing: Both
# Insert
InsertBraces: false
InsertNewlineAtEOF: true
KeepEmptyLinesAtEOF: true
# Align
AlignAfterOpenBracket: true
AlignTrailingComments:
Kind: Always
AlignArrayOfStructures: Left
PointerAlignment: Left
BreakAfterAttributes: Leave
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
BreakInheritanceList: AfterColon
BreakAdjacentStringLiterals: false
BreakStringLiterals: false
CompactNamespaces: false
Cpp11BracedListStyle: true
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: Always
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: true
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLambdasOnASingleLine: None
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
RequiresClausePosition: OwnLine
BinPackArguments: false
BinPackParameters: false
# Space
SeparateDefinitionBlocks: Always
SpaceBeforeParens: Custom
SpaceBeforeParensOptions:
AfterControlStatements: false
AfterForeachMacros: false
AfterFunctionDeclarationName: false
AfterFunctionDefinitionName: false
AfterIfMacros: false
AfterOverloadedOperator: true
AfterRequiresInClause: true
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: false
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: Never
SpacesInParens: Custom
SpacesInParensOptions:
InConditionalStatements: false
InCStyleCasts: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
# Order
QualifierAlignment: Custom
QualifierOrder: ["constexpr", "const", "inline", "static", "type"]
SortIncludes: Never
SortUsingDeclarations: LexicographicNumeric
IncludeBlocks: Merge
WhitespaceSensitiveMacros: ["PK_PROTECTED", "LUA_PROTECTED"]

View File

@ -10,22 +10,24 @@
namespace pkpy { namespace pkpy {
template<typename T> template <typename T>
inline constexpr bool is_any_sso_v = is_pod_v<T> && sizeof(T) <= sizeof(void*); constexpr inline bool is_any_sso_v = is_pod_v<T> && sizeof(T) <= sizeof(void*);
struct any{ struct any {
struct vtable{ struct vtable {
const std::type_index type; const std::type_index type;
void (*deleter)(void*); void (*deleter)(void*);
template<typename T> template <typename T>
inline static vtable* get(){ inline static vtable* get() {
static_assert(std::is_same_v<T, std::decay_t<T>>); static_assert(std::is_same_v<T, std::decay_t<T>>);
if constexpr (is_any_sso_v<T>){ if constexpr(is_any_sso_v<T>) {
static vtable vt{ typeid(T), nullptr }; static vtable vt{typeid(T), nullptr};
return &vt; return &vt;
}else{ } else {
static vtable vt{ typeid(T), [](void* ptr){ delete static_cast<T*>(ptr); } }; static vtable vt{typeid(T), [](void* ptr) {
delete static_cast<T*>(ptr);
}};
return &vt; return &vt;
} }
} }
@ -36,45 +38,45 @@ struct any{
any() : data(nullptr), _vt(nullptr) {} any() : data(nullptr), _vt(nullptr) {}
explicit operator bool() const { return _vt != nullptr; } explicit operator bool () const { return _vt != nullptr; }
template<typename T> template <typename T>
any(T&& value){ any(T&& value) {
using U = std::decay_t<T>; using U = std::decay_t<T>;
static_assert(!std::is_same_v<U, any>, "any(const any&) is deleted"); static_assert(!std::is_same_v<U, any>, "any(const any&) is deleted");
static_assert(sizeof(U) == sizeof(T)); static_assert(sizeof(U) == sizeof(T));
if constexpr (is_any_sso_v<U>){ if constexpr(is_any_sso_v<U>) {
std::memcpy(&data, &value, sizeof(U)); std::memcpy(&data, &value, sizeof(U));
}else{ } else {
data = new U(std::forward<T>(value)); data = new U(std::forward<T>(value));
} }
_vt = vtable::get<U>(); _vt = vtable::get<U>();
} }
any(any&& other) noexcept; any(any&& other) noexcept;
any& operator=(any&& other) noexcept; any& operator= (any&& other) noexcept;
const std::type_index type_id() const{ const std::type_index type_id() const { return _vt ? _vt->type : typeid(void); }
return _vt ? _vt->type : typeid(void);
}
any(const any& other) = delete; any(const any& other) = delete;
any& operator=(const any& other) = delete; any& operator= (const any& other) = delete;
~any() { if(_vt && _vt->deleter) _vt->deleter(data); } ~any() {
if(_vt && _vt->deleter) _vt->deleter(data);
}
template<typename T> template <typename T>
T& _cast() const noexcept{ T& _cast() const noexcept {
static_assert(std::is_same_v<T, std::decay_t<T>>); static_assert(std::is_same_v<T, std::decay_t<T>>);
if constexpr (is_any_sso_v<T>){ if constexpr(is_any_sso_v<T>) {
return *((T*)(&data)); return *((T*)(&data));
}else{ } else {
return *(static_cast<T*>(data)); return *(static_cast<T*>(data));
} }
} }
template<typename T> template <typename T>
T& cast() const{ T& cast() const {
static_assert(std::is_same_v<T, std::decay_t<T>>); static_assert(std::is_same_v<T, std::decay_t<T>>);
if(type_id() != typeid(T)) __bad_any_cast(typeid(T), type_id()); if(type_id() != typeid(T)) __bad_any_cast(typeid(T), type_id());
return _cast<T>(); return _cast<T>();
@ -83,26 +85,26 @@ struct any{
static void __bad_any_cast(const std::type_index expected, const std::type_index actual); static void __bad_any_cast(const std::type_index expected, const std::type_index actual);
}; };
template<typename T> template <typename T>
struct function; struct function;
template<typename Ret, typename... Params> template <typename Ret, typename... Params>
struct function<Ret(Params...)>{ struct function<Ret(Params...)> {
any _impl; any _impl;
Ret (*_wrapper)(const any&, Params...); Ret (*_wrapper)(const any&, Params...);
function(): _impl(), _wrapper(nullptr) {} function() : _impl(), _wrapper(nullptr) {}
explicit operator bool() const { return _wrapper != nullptr; } explicit operator bool () const { return _wrapper != nullptr; }
template<typename F> template <typename F>
function(F&& f) : _impl(std::forward<F>(f)){ function(F&& f) : _impl(std::forward<F>(f)) {
_wrapper = [](const any& impl, Params... params) -> Ret{ _wrapper = [](const any& impl, Params... params) -> Ret {
return impl._cast<std::decay_t<F>>()(std::forward<Params>(params)...); return impl._cast<std::decay_t<F>>()(std::forward<Params>(params)...);
}; };
} }
Ret operator()(Params... params) const{ Ret operator() (Params... params) const {
assert(_wrapper); assert(_wrapper);
return _wrapper(_impl, std::forward<Params>(params)...); return _wrapper(_impl, std::forward<Params>(params)...);
} }

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
// clang-format off
/*************** feature settings ***************/ /*************** feature settings ***************/

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
// clang-format off
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
//define something for Windows (32-bit and 64-bit, this part is common) //define something for Windows (32-bit and 64-bit, this part is common)

View File

@ -6,9 +6,12 @@
struct GIL { struct GIL {
inline static std::mutex _mutex; inline static std::mutex _mutex;
explicit GIL() { _mutex.lock(); } explicit GIL() { _mutex.lock(); }
~GIL() { _mutex.unlock(); } ~GIL() { _mutex.unlock(); }
}; };
#define PK_GLOBAL_SCOPE_LOCK() GIL _lock; #define PK_GLOBAL_SCOPE_LOCK() GIL _lock;
#else #else

View File

@ -6,10 +6,10 @@
#include <cassert> #include <cassert>
#include <string> #include <string>
namespace pkpy{ namespace pkpy {
inline const int kPoolExprBlockSize = 128; const inline int kPoolExprBlockSize = 128;
inline const int kPoolFrameBlockSize = 80; const inline int kPoolFrameBlockSize = 80;
void* PoolExpr_alloc() noexcept; void* PoolExpr_alloc() noexcept;
void PoolExpr_dealloc(void*) noexcept; void PoolExpr_dealloc(void*) noexcept;

View File

@ -6,20 +6,22 @@
#include <stdexcept> #include <stdexcept>
namespace pkpy{ namespace pkpy {
template<typename T> template <typename T>
constexpr T default_invalid_value(){ constexpr T default_invalid_value() {
if constexpr(std::is_same_v<int, T>) return -1; if constexpr(std::is_same_v<int, T>)
else return nullptr; return -1;
else
return nullptr;
} }
template<typename T> template <typename T>
struct NameDictImpl { struct NameDictImpl {
PK_ALWAYS_PASS_BY_POINTER(NameDictImpl) PK_ALWAYS_PASS_BY_POINTER(NameDictImpl)
using Item = std::pair<StrName, T>; using Item = std::pair<StrName, T>;
static constexpr uint16_t kInitialCapacity = 16; constexpr static uint16_t kInitialCapacity = 16;
static_assert(is_pod_v<T>); static_assert(is_pod_v<T>);
float _load_factor; float _load_factor;
@ -32,25 +34,29 @@ struct NameDictImpl {
Item* _items; Item* _items;
#define HASH_PROBE_1(key, ok, i) \ #define HASH_PROBE_1(key, ok, i) \
ok = false; \ ok = false; \
i = key.index & _mask; \ i = key.index & _mask; \
while(!_items[i].first.empty()) { \ while(!_items[i].first.empty()) { \
if(_items[i].first == (key)) { ok = true; break; } \ if(_items[i].first == (key)) { \
ok = true; \
break; \
} \
i = (i + 1) & _mask; \ i = (i + 1) & _mask; \
} }
#define HASH_PROBE_0 HASH_PROBE_1 #define HASH_PROBE_0 HASH_PROBE_1
NameDictImpl(float load_factor=PK_INST_ATTR_LOAD_FACTOR): _load_factor(load_factor), _size(0) { NameDictImpl(float load_factor = PK_INST_ATTR_LOAD_FACTOR) : _load_factor(load_factor), _size(0) {
_set_capacity_and_alloc_items(kInitialCapacity); _set_capacity_and_alloc_items(kInitialCapacity);
} }
~NameDictImpl(){ std::free(_items); } ~NameDictImpl() { std::free(_items); }
uint16_t size() const { return _size; } uint16_t size() const { return _size; }
uint16_t capacity() const { return _capacity; } uint16_t capacity() const { return _capacity; }
void _set_capacity_and_alloc_items(uint16_t val){ void _set_capacity_and_alloc_items(uint16_t val) {
_capacity = val; _capacity = val;
_critical_size = val * _load_factor; _critical_size = val * _load_factor;
_mask = val - 1; _mask = val - 1;
@ -59,12 +65,13 @@ while(!_items[i].first.empty()) { \
std::memset(_items, 0, _capacity * sizeof(Item)); std::memset(_items, 0, _capacity * sizeof(Item));
} }
void set(StrName key, T val){ void set(StrName key, T val) {
bool ok; uint16_t i; bool ok;
uint16_t i;
HASH_PROBE_1(key, ok, i); HASH_PROBE_1(key, ok, i);
if(!ok) { if(!ok) {
_size++; _size++;
if(_size > _critical_size){ if(_size > _critical_size) {
_rehash_2x(); _rehash_2x();
HASH_PROBE_1(key, ok, i); HASH_PROBE_1(key, ok, i);
} }
@ -73,13 +80,14 @@ while(!_items[i].first.empty()) { \
_items[i].second = val; _items[i].second = val;
} }
void _rehash_2x(){ void _rehash_2x() {
Item* old_items = _items; Item* old_items = _items;
uint16_t old_capacity = _capacity; uint16_t old_capacity = _capacity;
_set_capacity_and_alloc_items(_capacity * 2); _set_capacity_and_alloc_items(_capacity * 2);
for(uint16_t i=0; i<old_capacity; i++){ for(uint16_t i = 0; i < old_capacity; i++) {
if(old_items[i].first.empty()) continue; if(old_items[i].first.empty()) continue;
bool ok; uint16_t j; bool ok;
uint16_t j;
HASH_PROBE_1(old_items[i].first, ok, j); HASH_PROBE_1(old_items[i].first, ok, j);
assert(!ok); assert(!ok);
_items[j] = old_items[i]; _items[j] = old_items[i];
@ -87,21 +95,23 @@ while(!_items[i].first.empty()) { \
std::free(old_items); std::free(old_items);
} }
T try_get(StrName key) const{ T try_get(StrName key) const {
bool ok; uint16_t i; bool ok;
uint16_t i;
HASH_PROBE_0(key, ok, i); HASH_PROBE_0(key, ok, i);
if(!ok) return default_invalid_value<T>(); if(!ok) return default_invalid_value<T>();
return _items[i].second; return _items[i].second;
} }
T* try_get_2(StrName key) const{ T* try_get_2(StrName key) const {
bool ok; uint16_t i; bool ok;
uint16_t i;
HASH_PROBE_0(key, ok, i); HASH_PROBE_0(key, ok, i);
if(!ok) return nullptr; if(!ok) return nullptr;
return &_items[i].second; return &_items[i].second;
} }
T try_get_likely_found(StrName key) const{ T try_get_likely_found(StrName key) const {
uint16_t i = key.index & _mask; uint16_t i = key.index & _mask;
if(_items[i].first == key) return _items[i].second; if(_items[i].first == key) return _items[i].second;
i = (i + 1) & _mask; i = (i + 1) & _mask;
@ -109,7 +119,7 @@ while(!_items[i].first.empty()) { \
return try_get(key); return try_get(key);
} }
T* try_get_2_likely_found(StrName key) const{ T* try_get_2_likely_found(StrName key) const {
uint16_t i = key.index & _mask; uint16_t i = key.index & _mask;
if(_items[i].first == key) return &_items[i].second; if(_items[i].first == key) return &_items[i].second;
i = (i + 1) & _mask; i = (i + 1) & _mask;
@ -117,8 +127,9 @@ while(!_items[i].first.empty()) { \
return try_get_2(key); return try_get_2(key);
} }
bool del(StrName key){ bool del(StrName key) {
bool ok; uint16_t i; bool ok;
uint16_t i;
HASH_PROBE_0(key, ok, i); HASH_PROBE_0(key, ok, i);
if(!ok) return false; if(!ok) return false;
_items[i].first = StrName(); _items[i].first = StrName();
@ -127,7 +138,7 @@ while(!_items[i].first.empty()) { \
// tidy // tidy
uint16_t pre_z = i; uint16_t pre_z = i;
uint16_t z = (i + 1) & _mask; uint16_t z = (i + 1) & _mask;
while(!_items[z].first.empty()){ while(!_items[z].first.empty()) {
uint16_t h = _items[z].first.index & _mask; uint16_t h = _items[z].first.index & _mask;
if(h != i) break; if(h != i) break;
std::swap(_items[pre_z], _items[z]); std::swap(_items[pre_z], _items[z]);
@ -137,54 +148,54 @@ while(!_items[i].first.empty()) { \
return true; return true;
} }
template<typename __Func> template <typename __Func>
void apply(__Func func) const { void apply(__Func func) const {
for(uint16_t i=0; i<_capacity; i++){ for(uint16_t i = 0; i < _capacity; i++) {
if(_items[i].first.empty()) continue; if(_items[i].first.empty()) continue;
func(_items[i].first, _items[i].second); func(_items[i].first, _items[i].second);
} }
} }
bool contains(StrName key) const { bool contains(StrName key) const {
bool ok; uint16_t i; bool ok;
uint16_t i;
HASH_PROBE_0(key, ok, i); HASH_PROBE_0(key, ok, i);
return ok; return ok;
} }
T operator[](StrName key) const { T operator[] (StrName key) const {
T* val = try_get_2_likely_found(key); T* val = try_get_2_likely_found(key);
if(val == nullptr){ if(val == nullptr) { throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str()); }
throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str());
}
return *val; return *val;
} }
array<StrName> keys() const { array<StrName> keys() const {
array<StrName> v(_size); array<StrName> v(_size);
int j = 0; int j = 0;
for(uint16_t i=0; i<_capacity; i++){ for(uint16_t i = 0; i < _capacity; i++) {
if(_items[i].first.empty()) continue; if(_items[i].first.empty()) continue;
new (&v[j++]) StrName(_items[i].first); new (&v[j++]) StrName(_items[i].first);
} }
return v; return v;
} }
array<Item> items() const{ array<Item> items() const {
array<Item> v(_size); array<Item> v(_size);
int j = 0; int j = 0;
apply([&](StrName key, T val){ apply([&](StrName key, T val) {
new(&v[j++]) Item(key, val); new (&v[j++]) Item(key, val);
}); });
return v; return v;
} }
void clear(){ void clear() {
for(uint16_t i=0; i<_capacity; i++){ for(uint16_t i = 0; i < _capacity; i++) {
_items[i].first = StrName(); _items[i].first = StrName();
_items[i].second = nullptr; _items[i].second = nullptr;
} }
_size = 0; _size = 0;
} }
#undef HASH_PROBE_0 #undef HASH_PROBE_0
#undef HASH_PROBE_1 #undef HASH_PROBE_1
}; };

View File

@ -9,10 +9,10 @@
namespace pkpy { namespace pkpy {
int utf8len(unsigned char c, bool suppress=false); int utf8len(unsigned char c, bool suppress = false);
struct SStream; struct SStream;
struct Str{ struct Str {
int size; int size;
bool is_ascii; bool is_ascii;
char* data; char* data;
@ -26,60 +26,70 @@ struct Str{
Str(std::string_view s); Str(std::string_view s);
Str(const char* s); Str(const char* s);
Str(const char* s, int len); Str(const char* s, int len);
Str(std::pair<char *, int>); Str(std::pair<char*, int>);
Str(const Str& other); Str(const Str& other);
Str(Str&& other); Str(Str&& other);
operator std::string_view() const { return sv(); } operator std::string_view () const { return sv(); }
const char* begin() const { return data; } const char* begin() const { return data; }
const char* end() const { return data + size; } const char* end() const { return data + size; }
char operator[](int idx) const { return data[idx]; }
char operator[] (int idx) const { return data[idx]; }
int length() const { return size; } int length() const { return size; }
bool empty() const { return size == 0; } bool empty() const { return size == 0; }
size_t hash() const{ return std::hash<std::string_view>()(sv()); }
Str& operator=(const Str&); size_t hash() const { return std::hash<std::string_view>()(sv()); }
Str operator+(const Str&) const;
Str operator+(const char*) const;
friend Str operator+(const char*, const Str&);
bool operator==(const std::string_view other) const; Str& operator= (const Str&);
bool operator!=(const std::string_view other) const; Str operator+ (const Str&) const;
bool operator<(const std::string_view other) const; Str operator+ (const char*) const;
friend bool operator<(const std::string_view other, const Str& str); friend Str operator+ (const char*, const Str&);
bool operator==(const char* p) const; bool operator== (const std::string_view other) const;
bool operator!=(const char* p) const; bool operator!= (const std::string_view other) const;
bool operator< (const std::string_view other) const;
friend bool operator< (const std::string_view other, const Str& str);
bool operator==(const Str& other) const; bool operator== (const char* p) const;
bool operator!=(const Str& other) const; bool operator!= (const char* p) const;
bool operator<(const Str& other) const;
bool operator>(const Str& other) const; bool operator== (const Str& other) const;
bool operator<=(const Str& other) const; bool operator!= (const Str& other) const;
bool operator>=(const Str& other) const; bool operator< (const Str& other) const;
bool operator> (const Str& other) const;
bool operator<= (const Str& other) const;
bool operator>= (const Str& other) const;
~Str(); ~Str();
friend std::ostream& operator<<(std::ostream& os, const Str& str); friend std::ostream& operator<< (std::ostream& os, const Str& str);
const char* c_str() const { return data; } const char* c_str() const { return data; }
std::string_view sv() const { return std::string_view(data, size); } std::string_view sv() const { return std::string_view(data, size); }
std::string str() const { return std::string(data, size); } std::string str() const { return std::string(data, size); }
Str substr(int start, int len) const; Str substr(int start, int len) const;
Str substr(int start) const; Str substr(int start) const;
Str strip(bool left, bool right, const Str& chars) const; Str strip(bool left, bool right, const Str& chars) const;
Str strip(bool left=true, bool right=true) const; Str strip(bool left = true, bool right = true) const;
Str lstrip() const { return strip(true, false); } Str lstrip() const { return strip(true, false); }
Str rstrip() const { return strip(false, true); } Str rstrip() const { return strip(false, true); }
Str lower() const; Str lower() const;
Str upper() const; Str upper() const;
Str escape(bool single_quote=true) const; Str escape(bool single_quote = true) const;
void escape_(SStream& ss, bool single_quote=true) const; void escape_(SStream& ss, bool single_quote = true) const;
int index(const Str& sub, int start=0) const; int index(const Str& sub, int start = 0) const;
Str replace(char old, char new_) const; Str replace(char old, char new_) const;
Str replace(const Str& old, const Str& new_, int count=-1) const; Str replace(const Str& old, const Str& new_, int count = -1) const;
vector<std::string_view> split(const Str& sep) const; vector<std::string_view> split(const Str& sep) const;
vector<std::string_view> split(char sep) const; vector<std::string_view> split(char sep) const;
int count(const Str& sub) const; int count(const Str& sub) const;
@ -95,32 +105,29 @@ struct Str{
struct StrName { struct StrName {
uint16_t index; uint16_t index;
StrName(): index(0) {} StrName() : index(0) {}
explicit StrName(uint16_t index): index(index) {}
StrName(const char* s): index(get(s).index) {} explicit StrName(uint16_t index) : index(index) {}
StrName(const Str& s): index(get(s.sv()).index) {}
StrName(const char* s) : index(get(s).index) {}
StrName(const Str& s) : index(get(s.sv()).index) {}
std::string_view sv() const { return _r_interned()[index]; }
std::string_view sv() const { return _r_interned()[index];}
const char* c_str() const { return _r_interned()[index].c_str(); } const char* c_str() const { return _r_interned()[index].c_str(); }
bool empty() const { return index == 0; } bool empty() const { return index == 0; }
Str escape() const { return Str(sv()).escape(); } Str escape() const { return Str(sv()).escape(); }
bool operator==(const StrName& other) const noexcept { bool operator== (const StrName& other) const noexcept { return this->index == other.index; }
return this->index == other.index;
}
bool operator!=(const StrName& other) const noexcept { bool operator!= (const StrName& other) const noexcept { return this->index != other.index; }
return this->index != other.index;
}
bool operator<(const StrName& other) const noexcept { bool operator< (const StrName& other) const noexcept { return sv() < other.sv(); }
return sv() < other.sv();
}
bool operator>(const StrName& other) const noexcept { bool operator> (const StrName& other) const noexcept { return sv() > other.sv(); }
return sv() > other.sv();
}
static StrName get(std::string_view s); static StrName get(std::string_view s);
static std::map<std::string_view, uint16_t>& _interned(); static std::map<std::string_view, uint16_t>& _interned();
@ -128,32 +135,34 @@ struct StrName {
static uint32_t _pesudo_random_index; static uint32_t _pesudo_random_index;
}; };
struct SStream{ struct SStream {
PK_ALWAYS_PASS_BY_POINTER(SStream) PK_ALWAYS_PASS_BY_POINTER(SStream)
vector<char> buffer; vector<char> buffer;
int _precision = -1; int _precision = -1;
bool empty() const { return buffer.empty(); } bool empty() const { return buffer.empty(); }
void setprecision(int precision) { _precision = precision; } void setprecision(int precision) { _precision = precision; }
SStream() {} SStream() {}
SStream(int guess_size) { buffer.reserve(guess_size);}
SStream(int guess_size) { buffer.reserve(guess_size); }
Str str(); Str str();
SStream& operator<<(const Str&); SStream& operator<< (const Str&);
SStream& operator<<(const char*); SStream& operator<< (const char*);
SStream& operator<<(int); SStream& operator<< (int);
SStream& operator<<(size_t); SStream& operator<< (size_t);
SStream& operator<<(i64); SStream& operator<< (i64);
SStream& operator<<(f64); SStream& operator<< (f64);
SStream& operator<<(const std::string&); SStream& operator<< (const std::string&);
SStream& operator<<(std::string_view); SStream& operator<< (std::string_view);
SStream& operator<<(char); SStream& operator<< (char);
SStream& operator<<(StrName); SStream& operator<< (StrName);
void write_hex(unsigned char, bool non_zero=false); void write_hex(unsigned char, bool non_zero = false);
void write_hex(void*); void write_hex(void*);
void write_hex(i64); void write_hex(i64);
}; };
@ -162,17 +171,19 @@ struct SStream{
#undef _S #undef _S
#endif #endif
template<typename... Args> template <typename... Args>
Str _S(Args&&... args) { Str _S(Args&&... args) {
SStream ss; SStream ss;
(ss << ... << args); (ss << ... << args);
return ss.str(); return ss.str();
} }
struct CString{ struct CString {
const char* ptr; const char* ptr;
CString(const char* ptr): ptr(ptr) {}
operator const char*() const { return ptr; } CString(const char* ptr) : ptr(ptr) {}
operator const char* () const { return ptr; }
}; };
// unary operators // unary operators

View File

@ -2,35 +2,39 @@
#include <type_traits> #include <type_traits>
namespace pkpy{ namespace pkpy {
// is_pod_v<> for c++17 and c++20 // is_pod_v<> for c++17 and c++20
template<typename T> template <typename T>
inline constexpr bool is_pod_v = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>; constexpr inline bool is_pod_v = std::is_trivially_copyable_v<T> && std::is_standard_layout_v<T>;
// https://en.cppreference.com/w/cpp/types/is_integral // https://en.cppreference.com/w/cpp/types/is_integral
template<typename T> template <typename T>
inline constexpr bool is_integral_v = !std::is_same_v<T, bool> && std::is_integral_v<T>; constexpr inline bool is_integral_v = !std::is_same_v<T, bool> && std::is_integral_v<T>;
template<typename T> template <typename T>
inline constexpr bool is_floating_point_v = std::is_same_v<T, float> || std::is_same_v<T, double>; constexpr inline bool is_floating_point_v = std::is_same_v<T, float> || std::is_same_v<T, double>;
// by default, only `int` and `float` enable SSO // by default, only `int` and `float` enable SSO
// users can specialize this template to enable SSO for other types // users can specialize this template to enable SSO for other types
// SSO types cannot have instance dict // SSO types cannot have instance dict
template<typename T> template <typename T>
inline constexpr bool is_sso_v = is_integral_v<T> || is_floating_point_v<T>; constexpr inline bool is_sso_v = is_integral_v<T> || is_floating_point_v<T>;
// if is_sso_v<T> is true, return T, else return T& // if is_sso_v<T> is true, return T, else return T&
template<typename T> template <typename T>
using obj_get_t = std::conditional_t<is_sso_v<T>, T, T&>; using obj_get_t = std::conditional_t<is_sso_v<T>, T, T&>;
template<typename T> template <typename T>
constexpr inline bool is_trivially_relocatable_v = std::is_trivially_copyable_v<T> && std::is_trivially_destructible_v<T>; constexpr inline bool is_trivially_relocatable_v =
std::is_trivially_copyable_v<T> && std::is_trivially_destructible_v<T>;
template <typename, typename=void> struct has_gc_marker : std::false_type {}; template <typename, typename = void>
template <typename T> struct has_gc_marker<T, std::void_t<decltype(&T::_gc_mark)>> : std::true_type {}; struct has_gc_marker : std::false_type {};
template<typename T> template <typename T>
inline constexpr int py_sizeof = 16 + sizeof(T); struct has_gc_marker<T, std::void_t<decltype(&T::_gc_mark)>> : std::true_type {};
template <typename T>
constexpr inline int py_sizeof = 16 + sizeof(T);
} // namespace pkpy } // namespace pkpy

View File

@ -2,7 +2,7 @@
#include <cstdint> #include <cstdint>
namespace pkpy{ namespace pkpy {
using i64 = int64_t; // always 64-bit using i64 = int64_t; // always 64-bit
using f64 = double; // always 64-bit using f64 = double; // always 64-bit
@ -16,9 +16,11 @@ struct explicit_copy_t {
}; };
// Dummy types // Dummy types
struct DummyInstance { }; struct DummyInstance {};
struct DummyModule { };
struct NoReturn { }; struct DummyModule {};
struct NoReturn {};
// Forward declarations // Forward declarations
struct PyObject; struct PyObject;

View File

@ -4,18 +4,18 @@
#define PK_ALWAYS_PASS_BY_POINTER(T) \ #define PK_ALWAYS_PASS_BY_POINTER(T) \
T(const T&) = delete; \ T(const T&) = delete; \
T& operator=(const T&) = delete; \ T& operator= (const T&) = delete; \
T(T&&) = delete; \ T(T&&) = delete; \
T& operator=(T&&) = delete; T& operator= (T&&) = delete;
#define PK_SLICE_LOOP(i, start, stop, step) for(int i=start; step>0?i<stop:i>stop; i+=step) #define PK_SLICE_LOOP(i, start, stop, step) for(int i = start; step > 0 ? i < stop : i > stop; i += step)
namespace pkpy{ namespace pkpy {
// global constants // global constants
inline const char* PK_HEX_TABLE = "0123456789abcdef"; const inline char* PK_HEX_TABLE = "0123456789abcdef";
inline const char* kPlatformStrings[] = { const inline char* kPlatformStrings[] = {
"win32", // 0 "win32", // 0
"emscripten", // 1 "emscripten", // 1
"ios", // 2 "ios", // 2

View File

@ -18,21 +18,27 @@ struct array {
using size_type = int; using size_type = int;
array() : _data(nullptr), _size(0) {} array() : _data(nullptr), _size(0) {}
array(int size) : _data((T*)std::malloc(sizeof(T) * size)), _size(size) {} array(int size) : _data((T*)std::malloc(sizeof(T) * size)), _size(size) {}
array(array&& other) noexcept : _data(other._data), _size(other._size) { array(array&& other) noexcept : _data(other._data), _size(other._size) {
other._data = nullptr; other._data = nullptr;
other._size = 0; other._size = 0;
} }
array(const array& other) = delete; array(const array& other) = delete;
array(explicit_copy_t, const array& other) { array(explicit_copy_t, const array& other) {
_data = (T*)std::malloc(sizeof(T) * other._size); _data = (T*)std::malloc(sizeof(T) * other._size);
_size = other._size; _size = other._size;
for (int i = 0; i < _size; i++) _data[i] = other._data[i]; for(int i = 0; i < _size; i++)
_data[i] = other._data[i];
} }
array(T* data, int size) : _data(data), _size(size) {} array(T* data, int size) : _data(data), _size(size) {}
array& operator=(array&& other) noexcept { array& operator= (array&& other) noexcept {
if (_data) { if(_data) {
std::destroy(begin(), end()); std::destroy(begin(), end());
std::free(_data); std::free(_data);
} }
@ -43,14 +49,14 @@ struct array {
return *this; return *this;
} }
array& operator=(const array& other) = delete; array& operator= (const array& other) = delete;
T& operator[](int i) { T& operator[] (int i) {
assert(i >= 0 && i < _size); assert(i >= 0 && i < _size);
return _data[i]; return _data[i];
} }
const T& operator[](int i) const { const T& operator[] (int i) const {
assert(i >= 0 && i < _size); assert(i >= 0 && i < _size);
return _data[i]; return _data[i];
} }
@ -58,7 +64,9 @@ struct array {
int size() const { return _size; } int size() const { return _size; }
T* begin() const { return _data; } T* begin() const { return _data; }
T* end() const { return _data + _size; } T* end() const { return _data + _size; }
T* data() const { return _data; } T* data() const { return _data; }
std::pair<T*, int> detach() noexcept { std::pair<T*, int> detach() noexcept {
@ -69,7 +77,7 @@ struct array {
} }
~array() { ~array() {
if (_data) { if(_data) {
std::destroy(begin(), end()); std::destroy(begin(), end());
std::free(_data); std::free(_data);
} }
@ -85,58 +93,63 @@ struct vector {
using size_type = int; using size_type = int;
vector() : _data(nullptr), _capacity(0), _size(0) {} vector() : _data(nullptr), _capacity(0), _size(0) {}
vector(int size)
: _data((T*)std::malloc(sizeof(T) * size)), vector(int size) : _data((T*)std::malloc(sizeof(T) * size)), _capacity(size), _size(size) {}
_capacity(size),
_size(size) {} vector(vector&& other) noexcept : _data(other._data), _capacity(other._capacity), _size(other._size) {
vector(vector&& other) noexcept
: _data(other._data), _capacity(other._capacity), _size(other._size) {
other._data = nullptr; other._data = nullptr;
other._capacity = 0; other._capacity = 0;
other._size = 0; other._size = 0;
} }
vector(const vector& other) = delete; vector(const vector& other) = delete;
vector(explicit_copy_t, const vector& other)
: _data((T*)std::malloc(sizeof(T) * other._size)), vector(explicit_copy_t, const vector& other) :
_capacity(other._size), _data((T*)std::malloc(sizeof(T) * other._size)), _capacity(other._size), _size(other._size) {
_size(other._size) { for(int i = 0; i < _size; i++)
for (int i = 0; i < _size; i++) _data[i] = other._data[i]; _data[i] = other._data[i];
} }
// allow move // allow move
vector& operator=(vector&& other) noexcept { vector& operator= (vector&& other) noexcept {
if (_data) { if(_data) {
std::destroy(begin(), end()); std::destroy(begin(), end());
std::free(_data); std::free(_data);
} }
new (this) vector(std::move(other)); new (this) vector(std::move(other));
return *this; return *this;
} }
// disallow copy // disallow copy
vector& operator=(const vector& other) = delete; vector& operator= (const vector& other) = delete;
bool empty() const { return _size == 0; } bool empty() const { return _size == 0; }
int size() const { return _size; } int size() const { return _size; }
int capacity() const { return _capacity; } int capacity() const { return _capacity; }
T& back() { return _data[_size - 1]; } T& back() { return _data[_size - 1]; }
T* begin() const { return _data; } T* begin() const { return _data; }
T* end() const { return _data + _size; } T* end() const { return _data + _size; }
T* data() const { return _data; } T* data() const { return _data; }
void reserve(int cap) { void reserve(int cap) {
if (cap < 4) cap = 4; // minimum capacity if(cap < 4) cap = 4; // minimum capacity
if (cap <= capacity()) return; if(cap <= capacity()) return;
T* new_data = (T*)std::malloc(sizeof(T) * cap); T* new_data = (T*)std::malloc(sizeof(T) * cap);
if constexpr (is_trivially_relocatable_v<T>) { if constexpr(is_trivially_relocatable_v<T>) {
std::memcpy(new_data, _data, sizeof(T) * _size); std::memcpy(new_data, _data, sizeof(T) * _size);
} else { } else {
for (int i = 0; i < _size; i++) { for(int i = 0; i < _size; i++) {
new (&new_data[i]) T(std::move(_data[i])); new (&new_data[i]) T(std::move(_data[i]));
_data[i].~T(); _data[i].~T();
} }
} }
if (_data) std::free(_data); if(_data) std::free(_data);
_data = new_data; _data = new_data;
_capacity = cap; _capacity = cap;
} }
@ -147,46 +160,49 @@ struct vector {
} }
void push_back(const T& t) { void push_back(const T& t) {
if (_size == _capacity) reserve(_capacity * 2); if(_size == _capacity) reserve(_capacity * 2);
new (&_data[_size++]) T(t); new (&_data[_size++]) T(t);
} }
void push_back(T&& t) { void push_back(T&& t) {
if (_size == _capacity) reserve(_capacity * 2); if(_size == _capacity) reserve(_capacity * 2);
new (&_data[_size++]) T(std::move(t)); new (&_data[_size++]) T(std::move(t));
} }
bool contains(const T& t) const { bool contains(const T& t) const {
for (int i = 0; i < _size; i++) { for(int i = 0; i < _size; i++) {
if (_data[i] == t) return true; if(_data[i] == t) return true;
} }
return false; return false;
} }
template <typename... Args> template <typename... Args>
void emplace_back(Args&&... args) { void emplace_back(Args&&... args) {
if (_size == _capacity) reserve(_capacity * 2); if(_size == _capacity) reserve(_capacity * 2);
new (&_data[_size++]) T(std::forward<Args>(args)...); new (&_data[_size++]) T(std::forward<Args>(args)...);
} }
T& operator[](int i) { return _data[i]; } T& operator[] (int i) { return _data[i]; }
const T& operator[](int i) const { return _data[i]; }
const T& operator[] (int i) const { return _data[i]; }
void extend(T* begin, T* end) { void extend(T* begin, T* end) {
int n = end - begin; int n = end - begin;
reserve(_size + n); reserve(_size + n);
for (int i = 0; i < n; i++) new (&_data[_size++]) T(begin[i]); for(int i = 0; i < n; i++)
new (&_data[_size++]) T(begin[i]);
} }
void insert(int index, const T& t) { void insert(int index, const T& t) {
if (_size == _capacity) reserve(_capacity * 2); if(_size == _capacity) reserve(_capacity * 2);
for (int i = _size; i > index; i--) _data[i] = std::move(_data[i - 1]); for(int i = _size; i > index; i--)
_data[i] = std::move(_data[i - 1]);
_data[index] = t; _data[index] = t;
_size++; _size++;
} }
void erase(int index) { void erase(int index) {
for (int i = index; i < _size - 1; i++) for(int i = index; i < _size - 1; i++)
_data[i] = std::move(_data[i + 1]); _data[i] = std::move(_data[i + 1]);
_size--; _size--;
} }
@ -194,9 +210,7 @@ struct vector {
void pop_back() { void pop_back() {
assert(_size > 0); assert(_size > 0);
_size--; _size--;
if constexpr (!std::is_trivially_destructible_v<T>) { if constexpr(!std::is_trivially_destructible_v<T>) { _data[_size].~T(); }
_data[_size].~T();
}
} }
void clear() { void clear() {
@ -219,7 +233,7 @@ struct vector {
} }
~vector() { ~vector() {
if (_data) { if(_data) {
std::destroy(begin(), end()); std::destroy(begin(), end());
std::free(_data); std::free(_data);
} }
@ -230,37 +244,49 @@ template <typename T, typename Container = vector<T>>
class stack { class stack {
Container vec; Container vec;
public: public:
void push(const T& t) { vec.push_back(t); } void push(const T& t) { vec.push_back(t); }
void push(T&& t) { vec.push_back(std::move(t)); } void push(T&& t) { vec.push_back(std::move(t)); }
template <typename... Args> template <typename... Args>
void emplace(Args&&... args) { void emplace(Args&&... args) {
vec.emplace_back(std::forward<Args>(args)...); vec.emplace_back(std::forward<Args>(args)...);
} }
void pop() { vec.pop_back(); } void pop() { vec.pop_back(); }
void clear() { vec.clear(); } void clear() { vec.clear(); }
bool empty() const { return vec.empty(); } bool empty() const { return vec.empty(); }
typename Container::size_type size() const { return vec.size(); } typename Container::size_type size() const { return vec.size(); }
T& top() { return vec.back(); } T& top() { return vec.back(); }
const T& top() const { return vec.back(); } const T& top() const { return vec.back(); }
T popx() { T popx() {
T t = std::move(vec.back()); T t = std::move(vec.back());
vec.pop_back(); vec.pop_back();
return t; return t;
} }
void reserve(int n) { vec.reserve(n); } void reserve(int n) { vec.reserve(n); }
Container& container() { return vec; } Container& container() { return vec; }
const Container& container() const { return vec; } const Container& container() const { return vec; }
}; };
template <typename T, typename Container = vector<T>> template <typename T, typename Container = vector<T>>
class stack_no_copy : public stack<T, Container> { class stack_no_copy : public stack<T, Container> {
public: public:
stack_no_copy() = default; stack_no_copy() = default;
stack_no_copy(const stack_no_copy& other) = delete; stack_no_copy(const stack_no_copy& other) = delete;
stack_no_copy& operator=(const stack_no_copy& other) = delete; stack_no_copy& operator= (const stack_no_copy& other) = delete;
stack_no_copy(stack_no_copy&& other) noexcept = default; stack_no_copy(stack_no_copy&& other) noexcept = default;
stack_no_copy& operator=(stack_no_copy&& other) noexcept = default; stack_no_copy& operator= (stack_no_copy&& other) noexcept = default;
}; };
} // namespace pkpy } // namespace pkpy
@ -273,7 +299,7 @@ class small_vector {
T* m_end; T* m_end;
T* m_max; T* m_max;
public: public:
using value_type = T; using value_type = T;
using size_type = int; using size_type = int;
using difference_type = int; using difference_type = int;
@ -286,74 +312,82 @@ class small_vector {
using reverse_iterator = std::reverse_iterator<iterator>; using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>;
[[nodiscard]] bool is_small() const { [[nodiscard]] bool is_small() const { return m_begin == reinterpret_cast<const T*>(m_buffer); }
return m_begin == reinterpret_cast<const T*>(m_buffer);
}
[[nodiscard]] size_type size() const { return m_end - m_begin; } [[nodiscard]] size_type size() const { return m_end - m_begin; }
[[nodiscard]] size_type capacity() const { return m_max - m_begin; } [[nodiscard]] size_type capacity() const { return m_max - m_begin; }
[[nodiscard]] bool empty() const { return m_begin == m_end; } [[nodiscard]] bool empty() const { return m_begin == m_end; }
pointer data() { return m_begin; } pointer data() { return m_begin; }
const_pointer data() const { return m_begin; }
reference operator[](size_type index) { return m_begin[index]; }
const_reference operator[](size_type index) const { return m_begin[index]; }
iterator begin() { return m_begin; }
const_iterator begin() const { return m_begin; }
iterator end() { return m_end; }
const_iterator end() const { return m_end; }
reference front() { return *begin(); }
const_reference front() const { return *begin(); }
reference back() { return *(end() - 1); }
const_reference back() const { return *(end() - 1); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
private: const_pointer data() const { return m_begin; }
reference operator[] (size_type index) { return m_begin[index]; }
const_reference operator[] (size_type index) const { return m_begin[index]; }
iterator begin() { return m_begin; }
const_iterator begin() const { return m_begin; }
iterator end() { return m_end; }
const_iterator end() const { return m_end; }
reference front() { return *begin(); }
const_reference front() const { return *begin(); }
reference back() { return *(end() - 1); }
const_reference back() const { return *(end() - 1); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
private:
static void uninitialized_copy_n(const void* src, size_type n, void* dest) { static void uninitialized_copy_n(const void* src, size_type n, void* dest) {
if constexpr (std::is_trivially_copyable_v<T>) { if constexpr(std::is_trivially_copyable_v<T>) {
std::memcpy(dest, src, sizeof(T) * n); std::memcpy(dest, src, sizeof(T) * n);
} else { } else {
for (size_type i = 0; i < n; i++) { for(size_type i = 0; i < n; i++) {
::new ((T*)dest + i) T(*((const T*)src + i)); ::new ((T*)dest + i) T(*((const T*)src + i));
} }
} }
} }
static void uninitialized_relocate_n(void* src, size_type n, void* dest) { static void uninitialized_relocate_n(void* src, size_type n, void* dest) {
if constexpr (is_trivially_relocatable_v<T>) { if constexpr(is_trivially_relocatable_v<T>) {
std::memcpy(dest, src, sizeof(T) * n); std::memcpy(dest, src, sizeof(T) * n);
} else { } else {
for (size_type i = 0; i < n; i++) { for(size_type i = 0; i < n; i++) {
::new ((T*)dest + i) T(std::move(*((T*)src + i))); ::new ((T*)dest + i) T(std::move(*((T*)src + i)));
((T*)src + i)->~T(); ((T*)src + i)->~T();
} }
} }
} }
public: public:
small_vector() small_vector() : m_begin(reinterpret_cast<T*>(m_buffer)), m_end(m_begin), m_max(m_begin + N) {}
: m_begin(reinterpret_cast<T*>(m_buffer)),
m_end(m_begin),
m_max(m_begin + N) {}
small_vector(const small_vector& other) noexcept { small_vector(const small_vector& other) noexcept {
const auto size = other.size(); const auto size = other.size();
const auto capacity = other.capacity(); const auto capacity = other.capacity();
m_begin = reinterpret_cast<T*>( m_begin = reinterpret_cast<T*>(other.is_small() ? m_buffer : std::malloc(sizeof(T) * capacity));
other.is_small() ? m_buffer : std::malloc(sizeof(T) * capacity));
uninitialized_copy_n(other.m_begin, size, this->m_begin); uninitialized_copy_n(other.m_begin, size, this->m_begin);
m_end = m_begin + size; m_end = m_begin + size;
m_max = m_begin + capacity; m_max = m_begin + capacity;
} }
small_vector(small_vector&& other) noexcept { small_vector(small_vector&& other) noexcept {
if (other.is_small()) { if(other.is_small()) {
m_begin = reinterpret_cast<T*>(m_buffer); m_begin = reinterpret_cast<T*>(m_buffer);
uninitialized_relocate_n(other.m_buffer, other.size(), m_buffer); uninitialized_relocate_n(other.m_buffer, other.size(), m_buffer);
m_end = m_begin + other.size(); m_end = m_begin + other.size();
@ -368,16 +402,16 @@ class small_vector {
other.m_max = other.m_begin + N; other.m_max = other.m_begin + N;
} }
small_vector& operator=(const small_vector& other) noexcept { small_vector& operator= (const small_vector& other) noexcept {
if (this != &other) { if(this != &other) {
~small_vector(); ~small_vector();
::new (this) small_vector(other); ::new (this) small_vector(other);
} }
return *this; return *this;
} }
small_vector& operator=(small_vector&& other) noexcept { small_vector& operator= (small_vector&& other) noexcept {
if (this != &other) { if(this != &other) {
~small_vector(); ~small_vector();
::new (this) small_vector(std::move(other)); ::new (this) small_vector(std::move(other));
} }
@ -386,21 +420,19 @@ class small_vector {
~small_vector() { ~small_vector() {
std::destroy(m_begin, m_end); std::destroy(m_begin, m_end);
if (!is_small()) std::free(m_begin); if(!is_small()) std::free(m_begin);
} }
template <typename... Args> template <typename... Args>
void emplace_back(Args&&... args) noexcept { void emplace_back(Args&&... args) noexcept {
if (m_end == m_max) { if(m_end == m_max) {
const auto new_capacity = capacity() * 2; const auto new_capacity = capacity() * 2;
const auto size = this->size(); const auto size = this->size();
if (!is_small()) { if(!is_small()) {
if constexpr (is_trivially_relocatable_v<T>) { if constexpr(is_trivially_relocatable_v<T>) {
m_begin = (pointer)std::realloc(m_begin, m_begin = (pointer)std::realloc(m_begin, sizeof(T) * new_capacity);
sizeof(T) * new_capacity);
} else { } else {
auto new_data = auto new_data = (pointer)std::malloc(sizeof(T) * new_capacity);
(pointer)std::malloc(sizeof(T) * new_capacity);
uninitialized_relocate_n(m_begin, size, new_data); uninitialized_relocate_n(m_begin, size, new_data);
std::free(m_begin); std::free(m_begin);
m_begin = new_data; m_begin = new_data;
@ -418,13 +450,12 @@ class small_vector {
} }
void push_back(const T& value) { emplace_back(value); } void push_back(const T& value) { emplace_back(value); }
void push_back(T&& value) { emplace_back(std::move(value)); } void push_back(T&& value) { emplace_back(std::move(value)); }
void pop_back() { void pop_back() {
m_end--; m_end--;
if constexpr (!std::is_trivially_destructible_v<T>) { if constexpr(!std::is_trivially_destructible_v<T>) { m_end->~T(); }
m_end->~T();
}
} }
void clear() { void clear() {
@ -435,11 +466,11 @@ class small_vector {
template <typename T, std::size_t N> template <typename T, std::size_t N>
class small_vector_2 : public small_vector<T, N> { class small_vector_2 : public small_vector<T, N> {
public: public:
small_vector_2() = default; small_vector_2() = default;
small_vector_2(const small_vector_2& other) = delete; small_vector_2(const small_vector_2& other) = delete;
small_vector_2& operator=(const small_vector_2& other) = delete; small_vector_2& operator= (const small_vector_2& other) = delete;
small_vector_2(small_vector_2&& other) = delete; small_vector_2(small_vector_2&& other) = delete;
small_vector_2& operator=(small_vector_2&& other) = delete; small_vector_2& operator= (small_vector_2&& other) = delete;
}; };
} // namespace pkpy } // namespace pkpy

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
// clang-format off
#define PK_VERSION "2.0.0" #define PK_VERSION "2.0.0"
#define PK_VERSION_MAJOR 2 #define PK_VERSION_MAJOR 2

View File

@ -2,12 +2,12 @@
#include "pocketpy/compiler/expr.hpp" #include "pocketpy/compiler/expr.hpp"
namespace pkpy{ namespace pkpy {
class Compiler; class Compiler;
typedef void (Compiler::*PrattCallback)(); typedef void (Compiler::*PrattCallback)();
struct PrattRule{ struct PrattRule {
PrattCallback prefix; PrattCallback prefix;
PrattCallback infix; PrattCallback infix;
Precedence precedence; Precedence precedence;
@ -26,17 +26,23 @@ class Compiler {
int i = 0; int i = 0;
vector<Token> tokens; vector<Token> tokens;
const Token& prev() const{ return tokens[i-1]; } const Token& prev() const { return tokens[i - 1]; }
const Token& curr() const{ return tokens[i]; }
const Token& next() const{ return tokens[i+1]; } const Token& curr() const { return tokens[i]; }
const Token& err() const{
const Token& next() const { return tokens[i + 1]; }
const Token& err() const {
if(i >= tokens.size()) return prev(); if(i >= tokens.size()) return prev();
return curr(); return curr();
} }
void advance(int delta=1) { i += delta; }
void advance(int delta = 1) { i += delta; }
CodeEmitContext* ctx() { return &contexts.top(); } CodeEmitContext* ctx() { return &contexts.top(); }
CompileMode mode() const{ return lexer.src->mode; }
CompileMode mode() const { return lexer.src->mode; }
NameScope name_scope() const; NameScope name_scope() const;
CodeObject_ push_global_context(); CodeObject_ push_global_context();
FuncDecl_ push_f_context(Str name); FuncDecl_ push_f_context(Str name);
@ -48,13 +54,13 @@ class Compiler {
void consume(TokenIndex expected); void consume(TokenIndex expected);
bool match_newlines_repl(); bool match_newlines_repl();
bool match_newlines(bool repl_throw=false); bool match_newlines(bool repl_throw = false);
bool match_end_stmt(); bool match_end_stmt();
void consume_end_stmt(); void consume_end_stmt();
/*************************************************/ /*************************************************/
void EXPR(); void EXPR();
void EXPR_TUPLE(bool allow_slice=false); void EXPR_TUPLE(bool allow_slice = false);
Expr_ EXPR_VARS(); // special case for `for loop` and `comp` Expr_ EXPR_VARS(); // special case for `for loop` and `comp`
template <typename T, typename... Args> template <typename T, typename... Args>
@ -91,11 +97,11 @@ class Compiler {
void exprSubscr(); void exprSubscr();
void exprLiteral0(); void exprLiteral0();
void compile_block_body(void (Compiler::*callback)()=nullptr); void compile_block_body(void (Compiler::*callback)() = nullptr);
void compile_normal_import(); void compile_normal_import();
void compile_from_import(); void compile_from_import();
bool is_expression(bool allow_slice=false); bool is_expression(bool allow_slice = false);
void parse_expression(int precedence, bool allow_slice=false); void parse_expression(int precedence, bool allow_slice = false);
void compile_if_stmt(); void compile_if_stmt();
void compile_while_loop(); void compile_while_loop();
void compile_for_loop(); void compile_for_loop();
@ -106,31 +112,41 @@ class Compiler {
void compile_stmt(); void compile_stmt();
void consume_type_hints(); void consume_type_hints();
void _add_decorators(const Expr_vector& decorators); void _add_decorators(const Expr_vector& decorators);
void compile_class(const Expr_vector& decorators={}); void compile_class(const Expr_vector& decorators = {});
void _compile_f_args(FuncDecl_ decl, bool enable_type_hints); void _compile_f_args(FuncDecl_ decl, bool enable_type_hints);
void compile_function(const Expr_vector& decorators={}); void compile_function(const Expr_vector& decorators = {});
PyVar to_object(const TokenValue& value); PyVar to_object(const TokenValue& value);
PyVar read_literal(); PyVar read_literal();
void SyntaxError(Str msg){ lexer.throw_err("SyntaxError", msg, err().line, err().start); } void SyntaxError(Str msg) { lexer.throw_err("SyntaxError", msg, err().line, err().start); }
void SyntaxError(){ lexer.throw_err("SyntaxError", "invalid syntax", err().line, err().start); }
void IndentationError(Str msg){ lexer.throw_err("IndentationError", msg, err().line, err().start); } void SyntaxError() { lexer.throw_err("SyntaxError", "invalid syntax", err().line, err().start); }
void IndentationError(Str msg) { lexer.throw_err("IndentationError", msg, err().line, err().start); }
public: public:
Compiler(VM* vm, std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope=false); Compiler(VM* vm, std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope = false);
Str precompile(); Str precompile();
void from_precompiled(const char* source); void from_precompiled(const char* source);
CodeObject_ compile(); CodeObject_ compile();
}; };
struct TokenDeserializer{ struct TokenDeserializer {
const char* curr; const char* curr;
const char* source; const char* source;
TokenDeserializer(const char* source): curr(source), source(source) {} TokenDeserializer(const char* source) : curr(source), source(source) {}
char read_char(){ return *curr++; }
bool match_char(char c){ if(*curr == c) { curr++; return true; } return false; } char read_char() { return *curr++; }
bool match_char(char c) {
if(*curr == c) {
curr++;
return true;
}
return false;
}
std::string_view read_string(char c); std::string_view read_string(char c);
Str read_string_from_hex(char c); Str read_string_from_hex(char c);

View File

@ -3,43 +3,64 @@
#include "pocketpy/objects/codeobject.hpp" #include "pocketpy/objects/codeobject.hpp"
#include "pocketpy/compiler/lexer.hpp" #include "pocketpy/compiler/lexer.hpp"
namespace pkpy{ namespace pkpy {
struct CodeEmitContext; struct CodeEmitContext;
struct Expr; struct Expr;
template<typename T> template <typename T>
class unique_ptr_128{ class unique_ptr_128 {
T* ptr; T* ptr;
public: public:
unique_ptr_128(): ptr(nullptr) {} unique_ptr_128() : ptr(nullptr) {}
unique_ptr_128(T* ptr): ptr(ptr) {}
unique_ptr_128(T* ptr) : ptr(ptr) {}
T* operator->() const { return ptr; } T* operator->() const { return ptr; }
T* get() const { return ptr; } T* get() const { return ptr; }
T* detach() { T* p = ptr; ptr = nullptr; return p; }
T* detach() {
T* p = ptr;
ptr = nullptr;
return p;
}
unique_ptr_128(const unique_ptr_128&) = delete; unique_ptr_128(const unique_ptr_128&) = delete;
unique_ptr_128& operator=(const unique_ptr_128&) = delete; unique_ptr_128& operator= (const unique_ptr_128&) = delete;
bool operator==(std::nullptr_t) const { return ptr == nullptr; } bool operator== (std::nullptr_t) const { return ptr == nullptr; }
bool operator!=(std::nullptr_t) const { return ptr != nullptr; }
~unique_ptr_128(){ if(ptr) { ptr->~T(); PoolExpr_dealloc(ptr); } } bool operator!= (std::nullptr_t) const { return ptr != nullptr; }
template<typename U> ~unique_ptr_128() {
unique_ptr_128(unique_ptr_128<U>&& other): ptr(other.detach()) {} if(ptr) {
ptr->~T();
PoolExpr_dealloc(ptr);
}
}
operator bool() const { return ptr != nullptr; } template <typename U>
unique_ptr_128(unique_ptr_128<U>&& other) : ptr(other.detach()) {}
template<typename U> operator bool () const { return ptr != nullptr; }
unique_ptr_128& operator=(unique_ptr_128<U>&& other) {
if(ptr) { ptr->~T(); PoolExpr_dealloc(ptr); }; template <typename U>
unique_ptr_128& operator= (unique_ptr_128<U>&& other) {
if(ptr) {
ptr->~T();
PoolExpr_dealloc(ptr);
};
ptr = other.detach(); ptr = other.detach();
return *this; return *this;
} }
unique_ptr_128& operator=(std::nullptr_t) { unique_ptr_128& operator= (std::nullptr_t) {
if(ptr) { ptr->~T(); PoolExpr_dealloc(ptr); } if(ptr) {
ptr->~T();
PoolExpr_dealloc(ptr);
}
ptr = nullptr; ptr = nullptr;
return *this; return *this;
} }
@ -48,43 +69,44 @@ public:
typedef unique_ptr_128<Expr> Expr_; typedef unique_ptr_128<Expr> Expr_;
typedef small_vector<Expr_, 4> Expr_vector; typedef small_vector<Expr_, 4> Expr_vector;
template<> template <>
constexpr inline bool is_trivially_relocatable_v<Expr_> = true; constexpr inline bool is_trivially_relocatable_v<Expr_> = true;
struct Expr{ struct Expr {
int line = 0; int line = 0;
virtual ~Expr() = default; virtual ~Expr() = default;
virtual void emit_(CodeEmitContext* ctx) = 0; virtual void emit_(CodeEmitContext* ctx) = 0;
virtual bool is_literal() const { return false; } virtual bool is_literal() const { return false; }
virtual bool is_json_object() const { return false; } virtual bool is_json_object() const { return false; }
virtual bool is_attrib() const { return false; } virtual bool is_attrib() const { return false; }
virtual bool is_subscr() const { return false; } virtual bool is_subscr() const { return false; }
virtual bool is_compare() const { return false; } virtual bool is_compare() const { return false; }
virtual int star_level() const { return 0; } virtual int star_level() const { return 0; }
virtual bool is_tuple() const { return false; } virtual bool is_tuple() const { return false; }
virtual bool is_name() const { return false; } virtual bool is_name() const { return false; }
bool is_starred() const { return star_level() > 0; } bool is_starred() const { return star_level() > 0; }
// for OP_DELETE_XXX // for OP_DELETE_XXX
[[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) { [[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) { return false; }
return false;
}
// for OP_STORE_XXX // for OP_STORE_XXX
[[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) { [[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) { return false; }
return false;
}
virtual void emit_inplace(CodeEmitContext* ctx) { virtual void emit_inplace(CodeEmitContext* ctx) { emit_(ctx); }
emit_(ctx);
}
[[nodiscard]] virtual bool emit_store_inplace(CodeEmitContext* ctx) { [[nodiscard]] virtual bool emit_store_inplace(CodeEmitContext* ctx) { return emit_store(ctx); }
return emit_store(ctx);
}
}; };
struct CodeEmitContext{ struct CodeEmitContext {
VM* vm; VM* vm;
FuncDecl_ func; // optional FuncDecl_ func; // optional
CodeObject_ co; // 1 CodeEmitContext <=> 1 CodeObject_ CodeObject_ co; // 1 CodeEmitContext <=> 1 CodeObject_
@ -93,7 +115,8 @@ struct CodeEmitContext{
stack_no_copy<Expr_> s_expr; stack_no_copy<Expr_> s_expr;
int level; int level;
vector<Str> global_names; vector<Str> global_names;
CodeEmitContext(VM* vm, CodeObject_ co, int level): vm(vm), co(co), level(level) {}
CodeEmitContext(VM* vm, CodeObject_ co, int level) : vm(vm), co(co), level(level) {}
int curr_iblock = 0; int curr_iblock = 0;
bool is_compiling_class = false; bool is_compiling_class = false;
@ -105,7 +128,7 @@ struct CodeEmitContext{
CodeBlock* enter_block(CodeBlockType type); CodeBlock* enter_block(CodeBlockType type);
void exit_block(); void exit_block();
void emit_expr(); // clear the expression stack and generate bytecode void emit_expr(); // clear the expression stack and generate bytecode
int emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual=false); int emit_(Opcode opcode, uint16_t arg, int line, bool is_virtual = false);
void revert_last_emit_(); void revert_last_emit_();
int emit_int(i64 value, int line); int emit_int(i64 value, int line);
void patch_jump(int index); void patch_jump(int index);
@ -118,150 +141,189 @@ struct CodeEmitContext{
void try_merge_for_iter_store(int); void try_merge_for_iter_store(int);
}; };
struct NameExpr: Expr{ struct NameExpr : Expr {
StrName name; StrName name;
NameScope scope; NameScope scope;
NameExpr(StrName name, NameScope scope): name(name), scope(scope) {}
NameExpr(StrName name, NameScope scope) : name(name), scope(scope) {}
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
bool emit_del(CodeEmitContext* ctx) override; bool emit_del(CodeEmitContext* ctx) override;
bool emit_store(CodeEmitContext* ctx) override; bool emit_store(CodeEmitContext* ctx) override;
bool is_name() const override { return true; } bool is_name() const override { return true; }
}; };
struct InvertExpr: Expr{ struct InvertExpr : Expr {
Expr_ child; Expr_ child;
InvertExpr(Expr_&& child): child(std::move(child)) {}
InvertExpr(Expr_&& child) : child(std::move(child)) {}
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
struct StarredExpr: Expr{ struct StarredExpr : Expr {
int level; int level;
Expr_ child; Expr_ child;
StarredExpr(int level, Expr_&& child): level(level), child(std::move(child)) {}
StarredExpr(int level, Expr_&& child) : level(level), child(std::move(child)) {}
int star_level() const override { return level; } int star_level() const override { return level; }
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
bool emit_store(CodeEmitContext* ctx) override; bool emit_store(CodeEmitContext* ctx) override;
}; };
struct NotExpr: Expr{ struct NotExpr : Expr {
Expr_ child; Expr_ child;
NotExpr(Expr_&& child): child(std::move(child)) {}
NotExpr(Expr_&& child) : child(std::move(child)) {}
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
struct AndExpr: Expr{ struct AndExpr : Expr {
Expr_ lhs; Expr_ lhs;
Expr_ rhs; Expr_ rhs;
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
struct OrExpr: Expr{ struct OrExpr : Expr {
Expr_ lhs; Expr_ lhs;
Expr_ rhs; Expr_ rhs;
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
// [None, True, False, ...] // [None, True, False, ...]
struct Literal0Expr: Expr{ struct Literal0Expr : Expr {
TokenIndex token; TokenIndex token;
Literal0Expr(TokenIndex token): token(token) {}
Literal0Expr(TokenIndex token) : token(token) {}
bool is_json_object() const override { return true; } bool is_json_object() const override { return true; }
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
struct LongExpr: Expr{ struct LongExpr : Expr {
Str s; Str s;
LongExpr(const Str& s): s(s) {}
LongExpr(const Str& s) : s(s) {}
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
struct BytesExpr: Expr{ struct BytesExpr : Expr {
Str s; Str s;
BytesExpr(const Str& s): s(s) {}
BytesExpr(const Str& s) : s(s) {}
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
struct ImagExpr: Expr{ struct ImagExpr : Expr {
f64 value; f64 value;
ImagExpr(f64 value): value(value) {}
ImagExpr(f64 value) : value(value) {}
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
// @num, @str which needs to invoke OP_LOAD_CONST // @num, @str which needs to invoke OP_LOAD_CONST
struct LiteralExpr: Expr{ struct LiteralExpr : Expr {
TokenValue value; TokenValue value;
LiteralExpr(TokenValue value): value(value) {}
LiteralExpr(TokenValue value) : value(value) {}
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
bool is_literal() const override { return true; } bool is_literal() const override { return true; }
bool is_json_object() const override { return true; } bool is_json_object() const override { return true; }
}; };
struct NegatedExpr: Expr{ struct NegatedExpr : Expr {
Expr_ child; Expr_ child;
NegatedExpr(Expr_&& child): child(std::move(child)) {}
NegatedExpr(Expr_&& child) : child(std::move(child)) {}
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
bool is_json_object() const override { return child->is_literal(); } bool is_json_object() const override { return child->is_literal(); }
}; };
struct SliceExpr: Expr{ struct SliceExpr : Expr {
Expr_ start; Expr_ start;
Expr_ stop; Expr_ stop;
Expr_ step; Expr_ step;
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
struct DictItemExpr: Expr{ struct DictItemExpr : Expr {
Expr_ key; // maybe nullptr if it is **kwargs Expr_ key; // maybe nullptr if it is **kwargs
Expr_ value; Expr_ value;
int star_level() const override { return value->star_level(); } int star_level() const override { return value->star_level(); }
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
struct SequenceExpr: Expr{ struct SequenceExpr : Expr {
Expr_vector items; Expr_vector items;
SequenceExpr(Expr_vector&& items): items(std::move(items)) {}
SequenceExpr(Expr_vector&& items) : items(std::move(items)) {}
virtual Opcode opcode() const = 0; virtual Opcode opcode() const = 0;
void emit_(CodeEmitContext* ctx) override { void emit_(CodeEmitContext* ctx) override {
for(auto& item: items) item->emit_(ctx); for(auto& item: items)
item->emit_(ctx);
ctx->emit_(opcode(), items.size(), line); ctx->emit_(opcode(), items.size(), line);
} }
}; };
struct ListExpr: SequenceExpr{ struct ListExpr : SequenceExpr {
using SequenceExpr::SequenceExpr; using SequenceExpr::SequenceExpr;
Opcode opcode() const override { Opcode opcode() const override {
for(auto& e: items) if(e->is_starred()) return OP_BUILD_LIST_UNPACK; for(auto& e: items)
if(e->is_starred()) return OP_BUILD_LIST_UNPACK;
return OP_BUILD_LIST; return OP_BUILD_LIST;
} }
bool is_json_object() const override { return true; } bool is_json_object() const override { return true; }
}; };
struct DictExpr: SequenceExpr{ struct DictExpr : SequenceExpr {
using SequenceExpr::SequenceExpr; using SequenceExpr::SequenceExpr;
Opcode opcode() const override { Opcode opcode() const override {
for(auto& e: items) if(e->is_starred()) return OP_BUILD_DICT_UNPACK; for(auto& e: items)
if(e->is_starred()) return OP_BUILD_DICT_UNPACK;
return OP_BUILD_DICT; return OP_BUILD_DICT;
} }
bool is_json_object() const override { return true; } bool is_json_object() const override { return true; }
}; };
struct SetExpr: SequenceExpr{ struct SetExpr : SequenceExpr {
using SequenceExpr::SequenceExpr; using SequenceExpr::SequenceExpr;
Opcode opcode() const override { Opcode opcode() const override {
for(auto& e: items) if(e->is_starred()) return OP_BUILD_SET_UNPACK; for(auto& e: items)
if(e->is_starred()) return OP_BUILD_SET_UNPACK;
return OP_BUILD_SET; return OP_BUILD_SET;
} }
}; };
struct TupleExpr: SequenceExpr{ struct TupleExpr : SequenceExpr {
using SequenceExpr::SequenceExpr; using SequenceExpr::SequenceExpr;
bool is_tuple() const override { return true; } bool is_tuple() const override { return true; }
Opcode opcode() const override { Opcode opcode() const override {
for(auto& e: items) if(e->is_starred()) return OP_BUILD_TUPLE_UNPACK; for(auto& e: items)
if(e->is_starred()) return OP_BUILD_TUPLE_UNPACK;
return OP_BUILD_TUPLE; return OP_BUILD_TUPLE;
} }
@ -269,7 +331,7 @@ struct TupleExpr: SequenceExpr{
bool emit_del(CodeEmitContext* ctx) override; bool emit_del(CodeEmitContext* ctx) override;
}; };
struct CompExpr: Expr{ struct CompExpr : Expr {
Expr_ expr; // loop expr Expr_ expr; // loop expr
Expr_ vars; // loop vars Expr_ vars; // loop vars
Expr_ iter; // loop iter Expr_ iter; // loop iter
@ -281,25 +343,28 @@ struct CompExpr: Expr{
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
struct ListCompExpr: CompExpr{ struct ListCompExpr : CompExpr {
Opcode op0() override { return OP_BUILD_LIST; } Opcode op0() override { return OP_BUILD_LIST; }
Opcode op1() override { return OP_LIST_APPEND; } Opcode op1() override { return OP_LIST_APPEND; }
}; };
struct DictCompExpr: CompExpr{ struct DictCompExpr : CompExpr {
Opcode op0() override { return OP_BUILD_DICT; } Opcode op0() override { return OP_BUILD_DICT; }
Opcode op1() override { return OP_DICT_ADD; } Opcode op1() override { return OP_DICT_ADD; }
}; };
struct SetCompExpr: CompExpr{ struct SetCompExpr : CompExpr {
Opcode op0() override { return OP_BUILD_SET; } Opcode op0() override { return OP_BUILD_SET; }
Opcode op1() override { return OP_SET_ADD; } Opcode op1() override { return OP_SET_ADD; }
}; };
struct LambdaExpr: Expr{ struct LambdaExpr : Expr {
FuncDecl_ decl; FuncDecl_ decl;
LambdaExpr(FuncDecl_ decl): decl(decl) {} LambdaExpr(FuncDecl_ decl) : decl(decl) {}
void emit_(CodeEmitContext* ctx) override { void emit_(CodeEmitContext* ctx) override {
int index = ctx->add_func_decl(decl); int index = ctx->add_func_decl(decl);
@ -307,17 +372,21 @@ struct LambdaExpr: Expr{
} }
}; };
struct FStringExpr: Expr{ struct FStringExpr : Expr {
Str src; Str src;
FStringExpr(const Str& src): src(src) {}
FStringExpr(const Str& src) : src(src) {}
void _load_simple_expr(CodeEmitContext* ctx, Str expr); void _load_simple_expr(CodeEmitContext* ctx, Str expr);
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
struct SubscrExpr: Expr{ struct SubscrExpr : Expr {
Expr_ a; Expr_ a;
Expr_ b; Expr_ b;
bool is_subscr() const override { return true; } bool is_subscr() const override { return true; }
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
bool emit_del(CodeEmitContext* ctx) override; bool emit_del(CodeEmitContext* ctx) override;
bool emit_store(CodeEmitContext* ctx) override; bool emit_store(CodeEmitContext* ctx) override;
@ -326,10 +395,11 @@ struct SubscrExpr: Expr{
bool emit_store_inplace(CodeEmitContext* ctx) override; bool emit_store_inplace(CodeEmitContext* ctx) override;
}; };
struct AttribExpr: Expr{ struct AttribExpr : Expr {
Expr_ a; Expr_ a;
StrName b; StrName b;
AttribExpr(Expr_ a, StrName b): a(std::move(a)), b(b) {}
AttribExpr(Expr_ a, StrName b) : a(std::move(a)), b(b) {}
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
bool emit_del(CodeEmitContext* ctx) override; bool emit_del(CodeEmitContext* ctx) override;
@ -337,11 +407,12 @@ struct AttribExpr: Expr{
void emit_method(CodeEmitContext* ctx); void emit_method(CodeEmitContext* ctx);
bool is_attrib() const override { return true; } bool is_attrib() const override { return true; }
void emit_inplace(CodeEmitContext* ctx) override; void emit_inplace(CodeEmitContext* ctx) override;
bool emit_store_inplace(CodeEmitContext* ctx) override; bool emit_store_inplace(CodeEmitContext* ctx) override;
}; };
struct CallExpr: Expr{ struct CallExpr : Expr {
Expr_ callable; Expr_ callable;
Expr_vector args; Expr_vector args;
// **a will be interpreted as a special keyword argument: {"**": a} // **a will be interpreted as a special keyword argument: {"**": a}
@ -349,42 +420,36 @@ struct CallExpr: Expr{
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
struct GroupedExpr: Expr{ struct GroupedExpr : Expr {
Expr_ a; Expr_ a;
GroupedExpr(Expr_&& a): a(std::move(a)) {}
void emit_(CodeEmitContext* ctx) override{ GroupedExpr(Expr_&& a) : a(std::move(a)) {}
a->emit_(ctx);
}
bool emit_del(CodeEmitContext* ctx) override { void emit_(CodeEmitContext* ctx) override { a->emit_(ctx); }
return a->emit_del(ctx);
}
bool emit_store(CodeEmitContext* ctx) override { bool emit_del(CodeEmitContext* ctx) override { return a->emit_del(ctx); }
return a->emit_store(ctx);
} bool emit_store(CodeEmitContext* ctx) override { return a->emit_store(ctx); }
}; };
struct BinaryExpr: Expr{ struct BinaryExpr : Expr {
TokenIndex op; TokenIndex op;
Expr_ lhs; Expr_ lhs;
Expr_ rhs; Expr_ rhs;
bool inplace; bool inplace;
BinaryExpr(bool inplace=false): inplace(inplace) {} BinaryExpr(bool inplace = false) : inplace(inplace) {}
bool is_compare() const override; bool is_compare() const override;
void _emit_compare(CodeEmitContext*, small_vector_2<int, 6>&); void _emit_compare(CodeEmitContext*, small_vector_2<int, 6>&);
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
struct TernaryExpr : Expr {
struct TernaryExpr: Expr{
Expr_ cond; Expr_ cond;
Expr_ true_expr; Expr_ true_expr;
Expr_ false_expr; Expr_ false_expr;
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
} // namespace pkpy } // namespace pkpy

View File

@ -5,10 +5,11 @@
#include <variant> #include <variant>
namespace pkpy{ namespace pkpy {
typedef uint8_t TokenIndex; typedef uint8_t TokenIndex;
// clang-format off
constexpr const char* kTokens[] = { constexpr const char* kTokens[] = {
"is not", "not in", "yield from", "is not", "not in", "yield from",
"@eof", "@eol", "@sof", "@eof", "@eol", "@sof",
@ -28,32 +29,35 @@ constexpr const char* kTokens[] = {
"None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally", "None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally",
"while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise" "while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise"
}; };
// clang-format on
using TokenValue = std::variant<std::monostate, i64, f64, Str>; using TokenValue = std::variant<std::monostate, i64, f64, Str>;
const int kTokenCount = sizeof(kTokens) / sizeof(kTokens[0]); const int kTokenCount = sizeof(kTokens) / sizeof(kTokens[0]);
constexpr TokenIndex TK(const char token[]) { constexpr TokenIndex TK(const char token[]) {
for(int k=0; k<kTokenCount; k++){ for(int k = 0; k < kTokenCount; k++) {
const char* i = kTokens[k]; const char* i = kTokens[k];
const char* j = token; const char* j = token;
while(*i && *j && *i == *j) { i++; j++;} while(*i && *j && *i == *j) {
i++;
j++;
}
if(*i == *j) return k; if(*i == *j) return k;
} }
return 255; return 255;
} }
inline constexpr bool is_raw_string_used(TokenIndex t){ constexpr inline bool is_raw_string_used(TokenIndex t) { return t == TK("@id") || t == TK("@long"); }
return t == TK("@id") || t == TK("@long");
}
#define TK_STR(t) kTokens[t] #define TK_STR(t) kTokens[t]
const std::map<std::string_view, TokenIndex> kTokenKwMap = [](){ const std::map<std::string_view, TokenIndex> kTokenKwMap = []() {
std::map<std::string_view, TokenIndex> map; std::map<std::string_view, TokenIndex> map;
for(int k=TK("class"); k<kTokenCount; k++) map[kTokens[k]] = k; for(int k = TK("class"); k < kTokenCount; k++)
map[kTokens[k]] = k;
return map; return map;
}(); }();
struct Token{ struct Token {
TokenIndex type; TokenIndex type;
const char* start; const char* start;
int length; int length;
@ -61,8 +65,9 @@ struct Token{
int brackets_level; int brackets_level;
TokenValue value; TokenValue value;
Str str() const { return Str(start, length);} Str str() const { return Str(start, length); }
std::string_view sv() const { return std::string_view(start, length);}
std::string_view sv() const { return std::string_view(start, length); }
}; };
// https://docs.python.org/3/reference/expressions.html#operator-precedence // https://docs.python.org/3/reference/expressions.html#operator-precedence
@ -103,7 +108,8 @@ struct Lexer {
stack_no_copy<int, small_vector_2<int, 8>> indents; stack_no_copy<int, small_vector_2<int, 8>> indents;
int brackets_level = 0; int brackets_level = 0;
char peekchar() const{ return *curr_char; } char peekchar() const { return *curr_char; }
bool match_n_chars(int n, char c0); bool match_n_chars(int n, char c0);
bool match_string(const char* s); bool match_string(const char* s);
int eat_spaces(); int eat_spaces();
@ -114,7 +120,7 @@ struct Lexer {
int eat_name(); int eat_name();
void skip_line_comment(); void skip_line_comment();
bool matchchar(char c); bool matchchar(char c);
void add_token(TokenIndex type, TokenValue value={}); void add_token(TokenIndex type, TokenValue value = {});
void add_token_2(char c, TokenIndex one, TokenIndex two); void add_token_2(char c, TokenIndex one, TokenIndex two);
Str eat_string_until(char quote, bool raw); Str eat_string_until(char quote, bool raw);
void eat_string(char quote, StringType type); void eat_string(char quote, StringType type);
@ -125,16 +131,18 @@ struct Lexer {
/***** Error Reporter *****/ /***** Error Reporter *****/
[[noreturn]] void throw_err(StrName type, Str msg); [[noreturn]] void throw_err(StrName type, Str msg);
[[noreturn]] void throw_err(StrName type, Str msg, int lineno, const char* cursor); [[noreturn]] void throw_err(StrName type, Str msg, int lineno, const char* cursor);
[[noreturn]] void SyntaxError(Str msg){ throw_err("SyntaxError", msg); }
[[noreturn]] void SyntaxError(){ throw_err("SyntaxError", "invalid syntax"); } [[noreturn]] void SyntaxError(Str msg) { throw_err("SyntaxError", msg); }
[[noreturn]] void IndentationError(Str msg){ throw_err("IndentationError", msg); }
[[noreturn]] void SyntaxError() { throw_err("SyntaxError", "invalid syntax"); }
[[noreturn]] void IndentationError(Str msg) { throw_err("IndentationError", msg); }
Lexer(VM* vm, std::shared_ptr<SourceData> src); Lexer(VM* vm, std::shared_ptr<SourceData> src);
vector<Token> run(); vector<Token> run();
}; };
enum class IntParsingResult {
enum class IntParsingResult{
Success, Success,
Failure, Failure,
Overflow, Overflow,

View File

@ -2,104 +2,108 @@
#include "pocketpy/interpreter/cffi.hpp" #include "pocketpy/interpreter/cffi.hpp"
namespace pkpy{ namespace pkpy {
struct NativeProxyFuncCBase { struct NativeProxyFuncCBase {
virtual PyVar operator()(VM* vm, ArgsView args) = 0; virtual PyVar operator() (VM* vm, ArgsView args) = 0;
}; };
template<typename Ret, typename... Params> template <typename Ret, typename... Params>
struct NativeProxyFuncC final: NativeProxyFuncCBase { struct NativeProxyFuncC final : NativeProxyFuncCBase {
static constexpr int N = sizeof...(Params); constexpr static int N = sizeof...(Params);
using _Fp = Ret(*)(Params...); using _Fp = Ret (*)(Params...);
_Fp func; _Fp func;
NativeProxyFuncC(_Fp func) : func(func) {} NativeProxyFuncC(_Fp func) : func(func) {}
PyVar operator()(VM* vm, ArgsView args) override { PyVar operator() (VM* vm, ArgsView args) override {
assert(args.size() == N); assert(args.size() == N);
return call<Ret>(vm, args, std::make_index_sequence<N>()); return call<Ret>(vm, args, std::make_index_sequence<N>());
} }
template<typename __Ret, size_t... Is> template <typename __Ret, size_t... Is>
PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>){ PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>) {
if constexpr(std::is_void_v<__Ret>){ if constexpr(std::is_void_v<__Ret>) {
func(py_cast<Params>(vm, args[Is])...); func(py_cast<Params>(vm, args[Is])...);
return vm->None; return vm->None;
}else{ } else {
__Ret ret = func(py_cast<Params>(vm, args[Is])...); __Ret ret = func(py_cast<Params>(vm, args[Is])...);
return VAR(std::move(ret)); return VAR(std::move(ret));
} }
} }
}; };
template<typename Ret, typename T, typename... Params> template <typename Ret, typename T, typename... Params>
struct NativeProxyMethodC final: NativeProxyFuncCBase { struct NativeProxyMethodC final : NativeProxyFuncCBase {
static constexpr int N = sizeof...(Params); constexpr static int N = sizeof...(Params);
using _Fp = Ret(T::*)(Params...); using _Fp = Ret (T::*)(Params...);
_Fp func; _Fp func;
NativeProxyMethodC(_Fp func) : func(func) {} NativeProxyMethodC(_Fp func) : func(func) {}
PyVar operator()(VM* vm, ArgsView args) override { PyVar operator() (VM* vm, ArgsView args) override {
assert(args.size() == N+1); assert(args.size() == N + 1);
return call<Ret>(vm, args, std::make_index_sequence<N>()); return call<Ret>(vm, args, std::make_index_sequence<N>());
} }
template<typename __Ret, size_t... Is> template <typename __Ret, size_t... Is>
PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>){ PyVar call(VM* vm, ArgsView args, std::index_sequence<Is...>) {
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); // use unsafe cast for derived classes obj_get_t<T> self = PK_OBJ_GET(T, args[0]); // use unsafe cast for derived classes
if constexpr(std::is_void_v<__Ret>){ if constexpr(std::is_void_v<__Ret>) {
(self.*func)(py_cast<Params>(vm, args[Is+1])...); (self.*func)(py_cast<Params>(vm, args[Is + 1])...);
return vm->None; return vm->None;
}else{ } else {
__Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...); __Ret ret = (self.*func)(py_cast<Params>(vm, args[Is + 1])...);
return VAR(std::move(ret)); return VAR(std::move(ret));
} }
} }
}; };
/*****************************************************************/ /*****************************************************************/
inline PyVar __proxy_wrapper(VM* vm, ArgsView args){ inline PyVar __proxy_wrapper(VM* vm, ArgsView args) {
NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin()); NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin());
return (*pf)(vm, args); return (*pf)(vm, args);
} }
template<typename Ret, typename... Params> template <typename Ret, typename... Params>
PyObject* VM::bind(PyObject* obj, const char* sig, Ret(*func)(Params...), BindType bt){ PyObject* VM::bind(PyObject* obj, const char* sig, Ret (*func)(Params...), BindType bt) {
NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func); NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
return vm->bind(obj, sig, __proxy_wrapper, proxy, bt); return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
} }
template<typename Ret, typename T, typename... Params> template <typename Ret, typename T, typename... Params>
PyObject* VM::bind(PyObject* obj, const char* sig, Ret(T::*func)(Params...), BindType bt){ PyObject* VM::bind(PyObject* obj, const char* sig, Ret (T::*func)(Params...), BindType bt) {
NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func); NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
return vm->bind(obj, sig, __proxy_wrapper, proxy, bt); return vm->bind(obj, sig, __proxy_wrapper, proxy, bt);
} }
template<typename Ret, typename... Params> template <typename Ret, typename... Params>
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret(*func)(Params...), BindType bt){ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret (*func)(Params...), BindType bt) {
NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func); NativeProxyFuncCBase* proxy = new NativeProxyFuncC<Ret, Params...>(func);
return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt); return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
} }
template<typename Ret, typename T, typename... Params> template <typename Ret, typename T, typename... Params>
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret(T::*func)(Params...), BindType bt){ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Ret (T::*func)(Params...), BindType bt) {
NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func); NativeProxyFuncCBase* proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt); return vm->bind(obj, sig, docstring, __proxy_wrapper, proxy, bt);
} }
template<typename T, typename F, bool ReadOnly> template <typename T, typename F, bool ReadOnly>
PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
static_assert(!std::is_reference_v<F>); static_assert(!std::is_reference_v<F>);
assert(is_type(obj, tp_type)); assert(is_type(obj, tp_type));
std::string_view name_sv(name); int pos = name_sv.find(':'); std::string_view name_sv(name);
int pos = name_sv.find(':');
if(pos > 0) name_sv = name_sv.substr(0, pos); if(pos > 0) name_sv = name_sv.substr(0, pos);
auto fget = [](VM* vm, ArgsView args) -> PyVar{ auto fget = [](VM* vm, ArgsView args) -> PyVar {
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
F T::*field = lambda_get_userdata<F T::*>(args.begin()); F T::*field = lambda_get_userdata<F T::*>(args.begin());
return VAR(self.*field); return VAR(self.*field);
}; };
PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1, field); PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1, field);
PyVar _1 = vm->None; PyVar _1 = vm->None;
if constexpr (!ReadOnly){ if constexpr(!ReadOnly) {
auto fset = [](VM* vm, ArgsView args){ auto fset = [](VM* vm, ArgsView args) {
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
F T::*field = lambda_get_userdata<F T::*>(args.begin()); F T::*field = lambda_get_userdata<F T::*>(args.begin());
self.*field = py_cast<F>(vm, args[1]); self.*field = py_cast<F>(vm, args[1]);
@ -115,31 +119,34 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
/*****************************************************************/ /*****************************************************************/
#define PY_FIELD(T, NAME, EXPR) \ #define PY_FIELD(T, NAME, EXPR) \
vm->bind_property(type, NAME, \ vm->bind_property( \
[](VM* vm, ArgsView args){ \ type, \
NAME, \
[](VM* vm, ArgsView args) { \
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \ obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
return VAR(self.EXPR); \ return VAR(self.EXPR); \
}, \ }, \
[](VM* vm, ArgsView args){ \ [](VM* vm, ArgsView args) { \
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \ obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
self.EXPR = CAST(decltype(self.EXPR), args[1]); \ self.EXPR = CAST(decltype(self.EXPR), args[1]); \
return vm->None; \ return vm->None; \
}); });
#define PY_READONLY_FIELD(T, NAME, EXPR) \ #define PY_READONLY_FIELD(T, NAME, EXPR) \
vm->bind_property(type, NAME, \ vm->bind_property(type, NAME, [](VM* vm, ArgsView args) { \
[](VM* vm, ArgsView args){ \
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \ obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
return VAR(self.EXPR); \ return VAR(self.EXPR); \
}); });
#define PY_PROPERTY(T, NAME, FGET, FSET) \ #define PY_PROPERTY(T, NAME, FGET, FSET) \
vm->bind_property(type, NAME, \ vm->bind_property( \
[](VM* vm, ArgsView args){ \ type, \
NAME, \
[](VM* vm, ArgsView args) { \
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \ obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
return VAR(self.FGET()); \ return VAR(self.FGET()); \
}, \ }, \
[](VM* vm, ArgsView args){ \ [](VM* vm, ArgsView args) { \
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \ obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
using __NT = decltype(self.FGET()); \ using __NT = decltype(self.FGET()); \
self.FSET(CAST(__NT, args[1])); \ 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) \ #define PY_READONLY_PROPERTY(T, NAME, FGET) \
vm->bind_property(type, NAME, \ vm->bind_property(type, NAME, [](VM* vm, ArgsView args) { \
[](VM* vm, ArgsView args){ \
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \ obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
return VAR(self.FGET()); \ return VAR(self.FGET()); \
}); });
@ -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(std::is_trivially_copyable<wT>::value); \
static_assert(!is_sso_v<wT>); \ static_assert(!is_sso_v<wT>); \
type->attr().set("__struct__", vm->True); \ type->attr().set("__struct__", vm->True); \
vm->bind_func(type, "fromstruct", 1, [](VM* vm, ArgsView args){ \ vm->bind_func( \
type, \
"fromstruct", \
1, \
[](VM* vm, ArgsView args) { \
Struct& s = CAST(Struct&, args[0]); \ Struct& s = CAST(Struct&, args[0]); \
if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \ if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \
PyVar obj = vm->new_user_object<wT>(); \ PyVar obj = vm->new_user_object<wT>(); \
std::memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \ std::memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \
return obj; \ 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]); \ wT& self = _CAST(wT&, args[0]); \
return vm->new_user_object<Struct>(&self, sizeof(wT)); \ 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]); \ wT& self = _CAST(wT&, args[0]); \
return vm->new_user_object<VoidP>(&self); \ 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]); \ wT& self = _CAST(wT&, args[0]); \
return vm->new_user_object<wT>(self); \ 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)); \ 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); \ wT& self = _CAST(wT&, _0); \
if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \ if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \
wT& other = _CAST(wT&, _1); \ wT& other = _CAST(wT&, _1); \
return VAR(self == other); \ return VAR(self == other); \
}); \ });
#define PY_POINTER_SETGETITEM(T) \ #define PY_POINTER_SETGETITEM(T) \
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ \ vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \ obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \
i64 i = CAST(i64, _1); \ i64 i = CAST(i64, _1); \
T* tgt = reinterpret_cast<T*>(self.ptr); \ T* tgt = reinterpret_cast<T*>(self.ptr); \
return VAR(tgt[i]); \ return VAR(tgt[i]); \
}); \ }); \
vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1, PyVar _2){ \ vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1, PyVar _2) { \
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \ obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, _0); \
i64 i = CAST(i64, _1); \ i64 i = CAST(i64, _1); \
T* tgt = reinterpret_cast<T*>(self.ptr); \ T* tgt = reinterpret_cast<T*>(self.ptr); \
tgt[i] = CAST(T, _2); \ tgt[i] = CAST(T, _2); \
}); \ });
#define PK_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return x; }) #define PK_LAMBDA(x) \
#define PK_VAR_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return VAR(x); }) ([](VM* vm, ArgsView args) -> PyVar { \
#define PK_ACTION(x) ([](VM* vm, ArgsView args) -> PyVar { x; return vm->None; }) return x; \
})
#define PK_VAR_LAMBDA(x) \
([](VM* vm, ArgsView args) -> PyVar { \
return VAR(x); \
})
#define PK_ACTION(x) \
([](VM* vm, ArgsView args) -> PyVar { \
x; \
return vm->None; \
})
} // namespace pkpy } // namespace pkpy

View File

@ -6,26 +6,28 @@ namespace pkpy {
#define PY_CLASS(T, mod, name) \ #define PY_CLASS(T, mod, name) \
[[deprecated]] static Type _type(VM* vm) { return vm->_cxx_typeid_map[typeid(T)]; } \ [[deprecated]] static Type _type(VM* vm) { return vm->_cxx_typeid_map[typeid(T)]; } \
[[deprecated]] static PyVar register_class(VM* vm, PyVar mod, Type base=VM::tp_object) { \ [[deprecated]] static PyVar register_class(VM* vm, PyVar mod, Type base = VM::tp_object) { \
return vm->register_user_class<T>(mod, #name, base); \ return vm->register_user_class<T>(mod, #name, base); \
} }
struct VoidP{ struct VoidP {
void* ptr; void* ptr;
VoidP(const void* ptr): ptr(const_cast<void*>(ptr)){}
bool operator==(const VoidP& other) const { VoidP(const void* ptr) : ptr(const_cast<void*>(ptr)) {}
return ptr == other.ptr;
}
bool operator!=(const VoidP& other) const {
return ptr != other.ptr;
}
bool operator<(const VoidP& other) const { return ptr < other.ptr; }
bool operator<=(const VoidP& other) const { return ptr <= other.ptr; }
bool operator>(const VoidP& other) const { return ptr > other.ptr; }
bool operator>=(const VoidP& other) const { return ptr >= other.ptr; }
Str hex() const{ bool operator== (const VoidP& other) const { return ptr == other.ptr; }
bool operator!= (const VoidP& other) const { return ptr != other.ptr; }
bool operator< (const VoidP& other) const { return ptr < other.ptr; }
bool operator<= (const VoidP& other) const { return ptr <= other.ptr; }
bool operator> (const VoidP& other) const { return ptr > other.ptr; }
bool operator>= (const VoidP& other) const { return ptr >= other.ptr; }
Str hex() const {
SStream ss; SStream ss;
ss.write_hex(ptr); ss.write_hex(ptr);
return ss.str(); return ss.str();
@ -35,7 +37,7 @@ struct VoidP{
}; };
#define POINTER_VAR(Tp, NAME) \ #define POINTER_VAR(Tp, NAME) \
inline PyVar py_var(VM* vm, Tp val){ \ inline PyVar py_var(VM* vm, Tp val) { \
const static std::pair<StrName, StrName> P("c", NAME); \ const static std::pair<StrName, StrName> P("c", NAME); \
PyVar type = vm->_modules[P.first]->attr(P.second); \ PyVar type = vm->_modules[P.first]->attr(P.second); \
return vm->new_object<VoidP>(type->as<Type>(), val); \ return vm->new_object<VoidP>(type->as<Type>(), val); \
@ -58,42 +60,45 @@ POINTER_VAR(const bool*, "bool_p")
#undef POINTER_VAR #undef POINTER_VAR
struct Struct {
struct Struct{ constexpr static int INLINE_SIZE = 24;
static constexpr int INLINE_SIZE = 24;
char _inlined[INLINE_SIZE]; char _inlined[INLINE_SIZE];
char* p; char* p;
int size; int size;
Struct(int new_size, bool zero_init=true){ Struct(int new_size, bool zero_init = true) {
this->size = new_size; this->size = new_size;
if(size <= INLINE_SIZE){ if(size <= INLINE_SIZE) {
p = _inlined; p = _inlined;
}else{ } else {
p = (char*)std::malloc(size); p = (char*)std::malloc(size);
} }
if(zero_init) std::memset(p, 0, size); if(zero_init) std::memset(p, 0, size);
} }
Struct(void* p, int size): Struct(size, false){ Struct(void* p, int size) : Struct(size, false) {
if(p != nullptr) std::memcpy(this->p, p, size); if(p != nullptr) std::memcpy(this->p, p, size);
} }
Struct(const Struct& other): Struct(other.p, other.size){} Struct(const Struct& other) : Struct(other.p, other.size) {}
~Struct(){ if(p!=_inlined) std::free(p); }
~Struct() {
if(p != _inlined) std::free(p);
}
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);
}; };
/***********************************************/ /***********************************************/
template<typename Tp> template <typename Tp>
Tp to_void_p(VM* vm, PyVar var){ Tp to_void_p(VM* vm, PyVar var) {
static_assert(std::is_pointer_v<Tp>); static_assert(std::is_pointer_v<Tp>);
if(var == vm->None) return nullptr; // None can be casted to any pointer implicitly if(var == vm->None) return nullptr; // None can be casted to any pointer implicitly
VoidP& p = CAST(VoidP&, var); VoidP& p = CAST(VoidP&, var);
return reinterpret_cast<Tp>(p.ptr); return reinterpret_cast<Tp>(p.ptr);
} }
/*****************************************************************/ /*****************************************************************/
void add_module_c(VM* vm); void add_module_c(VM* vm);

View File

@ -2,25 +2,27 @@
#include "pocketpy/objects/codeobject.hpp" #include "pocketpy/objects/codeobject.hpp"
namespace pkpy{ namespace pkpy {
// weak reference fast locals // weak reference fast locals
struct FastLocals{ struct FastLocals {
// this is a weak reference // this is a weak reference
const CodeObject* co; const CodeObject* co;
PyVar* a; PyVar* a;
int size() const{ return co->nlocals;} int size() const { return co->nlocals; }
PyVar& operator[](int i){ return a[i]; } PyVar& operator[] (int i) { return a[i]; }
PyVar operator[](int i) const { return a[i]; }
FastLocals(const CodeObject* co, PyVar* a): co(co), a(a) {} PyVar operator[] (int i) const { return a[i]; }
FastLocals(const CodeObject* co, PyVar* a) : co(co), a(a) {}
PyVar* try_get_name(StrName name); PyVar* try_get_name(StrName name);
NameDict_ to_namedict(); NameDict_ to_namedict();
PyVar* begin() const { return a; } PyVar* begin() const { return a; }
PyVar* end() const { return a + size(); } PyVar* end() const { return a + size(); }
}; };
@ -28,49 +30,72 @@ struct ValueStack {
PK_ALWAYS_PASS_BY_POINTER(ValueStack) PK_ALWAYS_PASS_BY_POINTER(ValueStack)
// We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`. // We allocate extra PK_VM_STACK_SIZE/128 places to keep `_sp` valid when `is_overflow() == true`.
PyVar _begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE/128]; PyVar _begin[PK_VM_STACK_SIZE + PK_VM_STACK_SIZE / 128];
PyVar* _sp; PyVar* _sp;
PyVar* _max_end; PyVar* _max_end;
static constexpr size_t max_size() { return PK_VM_STACK_SIZE; } constexpr static size_t max_size() { return PK_VM_STACK_SIZE; }
ValueStack(): _sp(_begin), _max_end(_begin + PK_VM_STACK_SIZE) {} ValueStack() : _sp(_begin), _max_end(_begin + PK_VM_STACK_SIZE) {}
PyVar& top() { return _sp[-1]; }
PyVar& top(){ return _sp[-1]; }
PyVar top() const { return _sp[-1]; } PyVar top() const { return _sp[-1]; }
PyVar& second(){ return _sp[-2]; }
PyVar& second() { return _sp[-2]; }
PyVar second() const { return _sp[-2]; } PyVar second() const { return _sp[-2]; }
PyVar& third(){ return _sp[-3]; }
PyVar& third() { return _sp[-3]; }
PyVar third() const { return _sp[-3]; } PyVar third() const { return _sp[-3]; }
PyVar& peek(int n){ return _sp[-n]; }
PyVar& peek(int n) { return _sp[-n]; }
PyVar peek(int n) const { return _sp[-n]; } PyVar peek(int n) const { return _sp[-n]; }
void push(PyVar v){ *_sp++ = v; }
void push(PyVar v) { *_sp++ = v; }
void push(std::nullptr_t) { std::memset(_sp++, 0, sizeof(PyVar)); } void push(std::nullptr_t) { std::memset(_sp++, 0, sizeof(PyVar)); }
void pop(){ --_sp; }
PyVar popx(){ --_sp; return *_sp; } void pop() { --_sp; }
ArgsView view(int n){ return ArgsView(_sp-n, _sp); }
void shrink(int n){ _sp -= n; } PyVar popx() {
--_sp;
return *_sp;
}
ArgsView view(int n) { return ArgsView(_sp - n, _sp); }
void shrink(int n) { _sp -= n; }
int size() const { return _sp - _begin; } int size() const { return _sp - _begin; }
bool empty() const { return _sp == _begin; } bool empty() const { return _sp == _begin; }
PyVar* begin() { return _begin; } PyVar* begin() { return _begin; }
PyVar* end() { return _sp; } PyVar* end() { return _sp; }
void reset(PyVar* sp) { _sp = sp; } void reset(PyVar* sp) { _sp = sp; }
void clear() { _sp = _begin; } void clear() { _sp = _begin; }
bool is_overflow() const { return _sp >= _max_end; } bool is_overflow() const { return _sp >= _max_end; }
template<typename... Args> template <typename... Args>
void emplace(Args&&... args){ void emplace(Args&&... args) {
new(_sp) PyVar(std::forward<Args>(args)...); new (_sp) PyVar(std::forward<Args>(args)...);
++_sp; ++_sp;
} }
}; };
struct UnwindTarget{ struct UnwindTarget {
UnwindTarget* next; UnwindTarget* next;
int iblock; int iblock;
int offset; int offset;
UnwindTarget(int iblock, int offset): next(nullptr), iblock(iblock), offset(offset) {} UnwindTarget(int iblock, int offset) : next(nullptr), iblock(iblock), offset(offset) {}
}; };
struct Frame { struct Frame {
@ -89,29 +114,35 @@ struct Frame {
UnwindTarget* _uw_list; UnwindTarget* _uw_list;
NameDict& f_globals() { return _module->attr(); } NameDict& f_globals() { return _module->attr(); }
PyVar* f_closure_try_get(StrName name); PyVar* f_closure_try_get(StrName name);
int ip() const { return _ip - co->codes.data(); } int ip() const { return _ip - co->codes.data(); }
// function scope // function scope
Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, PyVar* _locals_base) Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, PyVar* _locals_base) :
: _ip(co->codes.data()-1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(co, _locals_base), _uw_list(nullptr) { } _ip(co->codes.data() - 1), _sp_base(p0), co(co), _module(_module), _callable(_callable),
_locals(co, _locals_base), _uw_list(nullptr) {}
// exec/eval // exec/eval
Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, FastLocals _locals) Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, FastLocals _locals) :
: _ip(co->codes.data()-1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals), _uw_list(nullptr) { } _ip(co->codes.data() - 1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals),
_uw_list(nullptr) {}
// global scope // global scope
Frame(PyVar* p0, const CodeObject_& co, PyObject* _module) Frame(PyVar* p0, const CodeObject_& co, PyObject* _module) :
: _ip(co->codes.data()-1), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr), _locals(co.get(), p0), _uw_list(nullptr) { } _ip(co->codes.data() - 1), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr),
_locals(co.get(), p0), _uw_list(nullptr) {}
PyVar* actual_sp_base() const { return _locals.a; } PyVar* actual_sp_base() const { return _locals.a; }
ArgsView stack_view(ValueStack* _s) const { return ArgsView(actual_sp_base(), _s->_sp); } ArgsView stack_view(ValueStack* _s) const { return ArgsView(actual_sp_base(), _s->_sp); }
[[nodiscard]] int prepare_jump_exception_handler(ValueStack*); [[nodiscard]] int prepare_jump_exception_handler(ValueStack*);
void prepare_jump_break(ValueStack*, int); void prepare_jump_break(ValueStack*, int);
int _exit_block(ValueStack*, int); int _exit_block(ValueStack*, int);
[[nodiscard]] int prepare_loop_break(ValueStack* s_data){ [[nodiscard]] int prepare_loop_break(ValueStack* s_data) {
int target = co->_get_block_codei(ip()).end; int target = co->_get_block_codei(ip()).end;
prepare_jump_break(s_data, target); prepare_jump_break(s_data, target);
return target; return target;
@ -126,29 +157,35 @@ struct Frame {
~Frame(); ~Frame();
}; };
struct LinkedFrame{ struct LinkedFrame {
LinkedFrame* f_back; LinkedFrame* f_back;
Frame frame; Frame frame;
template<typename... Args>
template <typename... Args>
LinkedFrame(LinkedFrame* f_back, Args&&... args) : f_back(f_back), frame(std::forward<Args>(args)...) {} LinkedFrame(LinkedFrame* f_back, Args&&... args) : f_back(f_back), frame(std::forward<Args>(args)...) {}
}; };
struct CallStack {
struct CallStack{
static_assert(sizeof(LinkedFrame) <= 128); static_assert(sizeof(LinkedFrame) <= 128);
LinkedFrame* _tail; LinkedFrame* _tail;
int _size; int _size;
CallStack(): _tail(nullptr), _size(0) {}
CallStack() : _tail(nullptr), _size(0) {}
int size() const { return _size; } int size() const { return _size; }
bool empty() const { return _size == 0; }
void clear(){ while(!empty()) pop(); }
template<typename... Args> bool empty() const { return _size == 0; }
void emplace(Args&&... args){
void clear() {
while(!empty())
pop();
}
template <typename... Args>
void emplace(Args&&... args) {
static_assert(sizeof(LinkedFrame) <= kPoolFrameBlockSize); static_assert(sizeof(LinkedFrame) <= kPoolFrameBlockSize);
_tail = new(PoolFrame_alloc()) LinkedFrame(_tail, std::forward<Args>(args)...); _tail = new (PoolFrame_alloc()) LinkedFrame(_tail, std::forward<Args>(args)...);
++_size; ++_size;
} }
@ -161,12 +198,13 @@ struct CallStack{
return _tail->frame; return _tail->frame;
} }
template<typename Func> template <typename Func>
void apply(Func&& f){ void apply(Func&& f) {
for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back) f(p->frame); for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back)
f(p->frame);
} }
~CallStack(){ clear(); } ~CallStack() { clear(); }
}; };
}; // namespace pkpy }; // namespace pkpy

View File

@ -6,54 +6,52 @@
#include "pocketpy/objects/object.hpp" #include "pocketpy/objects/object.hpp"
namespace pkpy { namespace pkpy {
struct ManagedHeap{ struct ManagedHeap {
vector<PyObject*> _no_gc; vector<PyObject*> _no_gc;
vector<PyObject*> gen; vector<PyObject*> gen;
VM* vm; VM* vm;
void (*_gc_on_delete)(VM*, PyObject*) = nullptr; void (*_gc_on_delete)(VM*, PyObject*) = nullptr;
void (*_gc_marker_ex)(VM*) = nullptr; void (*_gc_marker_ex)(VM*) = nullptr;
ManagedHeap(VM* vm): vm(vm) {} ManagedHeap(VM* vm) : vm(vm) {}
int gc_threshold = PK_GC_MIN_THRESHOLD; int gc_threshold = PK_GC_MIN_THRESHOLD;
int gc_counter = 0; int gc_counter = 0;
/********************/ /********************/
int _gc_lock_counter = 0; int _gc_lock_counter = 0;
struct ScopeLock{
struct ScopeLock {
PK_ALWAYS_PASS_BY_POINTER(ScopeLock) PK_ALWAYS_PASS_BY_POINTER(ScopeLock)
ManagedHeap* heap; ManagedHeap* heap;
ScopeLock(ManagedHeap* heap): heap(heap){
heap->_gc_lock_counter++; ScopeLock(ManagedHeap* heap) : heap(heap) { heap->_gc_lock_counter++; }
}
~ScopeLock(){ ~ScopeLock() { heap->_gc_lock_counter--; }
heap->_gc_lock_counter--;
}
}; };
ScopeLock gc_scope_lock(){ ScopeLock gc_scope_lock() { return ScopeLock(this); }
return ScopeLock(this);
}
/********************/ /********************/
template<typename T, typename... Args> template <typename T, typename... Args>
PyObject* gcnew(Type type, Args&&... args){ PyObject* gcnew(Type type, Args&&... args) {
using __T = std::decay_t<T>; using __T = std::decay_t<T>;
static_assert(!is_sso_v<__T>, "gcnew cannot be used with SSO types"); static_assert(!is_sso_v<__T>, "gcnew cannot be used with SSO types");
// https://github.com/pocketpy/pocketpy/issues/94#issuecomment-1594784476 // https://github.com/pocketpy/pocketpy/issues/94#issuecomment-1594784476
PyObject* p = new(PoolObject_alloc(py_sizeof<__T>)) PyObject(type); PyObject* p = new (PoolObject_alloc(py_sizeof<__T>)) PyObject(type);
p->placement_new<__T>(std::forward<Args>(args)...); p->placement_new<__T>(std::forward<Args>(args)...);
gen.push_back(p); gen.push_back(p);
gc_counter++; gc_counter++;
return p; return p;
} }
template<typename T, typename... Args> template <typename T, typename... Args>
PyObject* _new(Type type, Args&&... args){ PyObject* _new(Type type, Args&&... args) {
using __T = std::decay_t<T>; using __T = std::decay_t<T>;
static_assert(!is_sso_v<__T>); static_assert(!is_sso_v<__T>);
PyObject* p = new(PoolObject_alloc(py_sizeof<__T>)) PyObject(type); PyObject* p = new (PoolObject_alloc(py_sizeof<__T>)) PyObject(type);
p->placement_new<__T>(std::forward<Args>(args)...); p->placement_new<__T>(std::forward<Args>(args)...);
_no_gc.push_back(p); _no_gc.push_back(p);
return p; return p;
@ -67,7 +65,9 @@ struct ManagedHeap{
int sweep(); int sweep();
void _auto_collect(); void _auto_collect();
bool _should_auto_collect() const { return gc_counter >= gc_threshold; } bool _should_auto_collect() const { return gc_counter >= gc_threshold; }
int collect(); int collect();
void mark(); void mark();
}; };

View File

@ -2,51 +2,57 @@
#include "pocketpy/interpreter/bindings.hpp" #include "pocketpy/interpreter/bindings.hpp"
namespace pkpy{ namespace pkpy {
struct RangeIter{ // step > 0 struct RangeIter { // step > 0
Range r; Range r;
i64 current; i64 current;
RangeIter(Range r) : r(r), current(r.start) {} RangeIter(Range r) : r(r), current(r.start) {}
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);
}; };
struct RangeIterR{ // step < 0 struct RangeIterR { // step < 0
Range r; Range r;
i64 current; i64 current;
RangeIterR(Range r) : r(r), current(r.start) {} RangeIterR(Range r) : r(r), current(r.start) {}
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);
}; };
struct ArrayIter{ struct ArrayIter {
PyObject* ref; PyObject* ref;
PyVar* end; PyVar* end;
PyVar* current; PyVar* current;
ArrayIter(PyObject* ref, PyVar* begin, PyVar* end) ArrayIter(PyObject* ref, PyVar* begin, PyVar* end) : ref(ref), end(end), current(begin) {}
: ref(ref), end(end), current(begin) {}
void _gc_mark(VM* vm) const { vm->__obj_gc_mark(ref); }
void _gc_mark(VM* vm) const{ vm->__obj_gc_mark(ref); }
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);
}; };
struct StringIter{ struct StringIter {
PyVar ref; PyVar ref;
int i; // byte index int i; // byte index
StringIter(PyVar ref) : ref(ref), i(0) {} StringIter(PyVar ref) : ref(ref), i(0) {}
void _gc_mark(VM* vm) const{ vm->obj_gc_mark(ref); }
void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);
}; };
struct Generator{ struct Generator {
LinkedFrame* lf; LinkedFrame* lf;
int state; // 0,1,2 int state; // 0,1,2
List s_backup; List s_backup;
Generator(LinkedFrame* lf, ArgsView buffer): lf(lf), state(0) { Generator(LinkedFrame* lf, ArgsView buffer) : lf(lf), state(0) {
for(PyVar obj: buffer) s_backup.push_back(obj); for(PyVar obj: buffer)
s_backup.push_back(obj);
} }
void _gc_mark(VM* vm) { void _gc_mark(VM* vm) {
@ -58,21 +64,22 @@ struct Generator{
PyVar next(VM* vm); PyVar next(VM* vm);
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);
~Generator(){ ~Generator() {
if(lf){ if(lf) {
lf->~LinkedFrame(); lf->~LinkedFrame();
PoolFrame_dealloc(lf); PoolFrame_dealloc(lf);
} }
} }
}; };
struct DictItemsIter{ struct DictItemsIter {
PyVar ref; PyVar ref;
int i; int i;
DictItemsIter(PyVar ref) : ref(ref) {
i = PK_OBJ_GET(Dict, ref)._head_idx; DictItemsIter(PyVar ref) : ref(ref) { i = PK_OBJ_GET(Dict, ref)._head_idx; }
}
void _gc_mark(VM* vm) const{ vm->obj_gc_mark(ref); } void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);
}; };

View File

@ -6,23 +6,24 @@
namespace pkpy { namespace pkpy {
struct _LineRecord{ struct _LineRecord {
int line; int line;
i64 hits; i64 hits;
clock_t time; clock_t time;
_LineRecord(): line(-1), hits(0), time(0) {} _LineRecord() : line(-1), hits(0), time(0) {}
bool is_valid() const { return line != -1; } bool is_valid() const { return line != -1; }
}; };
struct _FrameRecord{ struct _FrameRecord {
int callstack_size; int callstack_size;
Frame* frame; Frame* frame;
clock_t prev_time; clock_t prev_time;
_LineRecord* prev_record; _LineRecord* prev_record;
}; };
struct LineProfiler{ struct LineProfiler {
// filename -> records // filename -> records
std::map<std::string_view, vector<_LineRecord>> records; std::map<std::string_view, vector<_LineRecord>> records;
stack_no_copy<_FrameRecord> frames; stack_no_copy<_FrameRecord> frames;

View File

@ -11,7 +11,7 @@
#include <stdexcept> #include <stdexcept>
namespace pkpy{ namespace pkpy {
/* Stack manipulation macros */ /* Stack manipulation macros */
// https://github.com/python/cpython/blob/3.9/Python/ceval.c#L1123 // https://github.com/python/cpython/blob/3.9/Python/ceval.c#L1123
@ -28,35 +28,44 @@ typedef PyVar (*BinaryFuncC)(VM*, PyVar, PyVar);
typedef void (*RegisterFunc)(VM*, PyObject*, PyObject*); typedef void (*RegisterFunc)(VM*, PyObject*, PyObject*);
#if PK_ENABLE_PROFILER #if PK_ENABLE_PROFILER
struct NextBreakpoint{ struct NextBreakpoint {
int callstack_size; int callstack_size;
int lineno; int lineno;
bool should_step_into; bool should_step_into;
NextBreakpoint(): callstack_size(0) {}
NextBreakpoint(int callstack_size, int lineno, bool should_step_into): callstack_size(callstack_size), lineno(lineno), should_step_into(should_step_into) {} NextBreakpoint() : callstack_size(0) {}
NextBreakpoint(int callstack_size, int lineno, bool should_step_into) :
callstack_size(callstack_size), lineno(lineno), should_step_into(should_step_into) {}
void _step(VM* vm); void _step(VM* vm);
bool empty() const { return callstack_size == 0; } bool empty() const { return callstack_size == 0; }
}; };
#endif #endif
struct PyTypeInfo{ struct PyTypeInfo {
struct Vt{ struct Vt {
void (*_dtor)(void*); void (*_dtor)(void*);
void (*_gc_mark)(void*, VM*); void (*_gc_mark)(void*, VM*);
Vt(): _dtor(nullptr), _gc_mark(nullptr) {} Vt() : _dtor(nullptr), _gc_mark(nullptr) {}
operator bool() const { return _dtor || _gc_mark; } operator bool () const { return _dtor || _gc_mark; }
template<typename T> template <typename T>
inline static Vt get(){ inline static Vt get() {
static_assert(std::is_same_v<T, std::decay_t<T>>); static_assert(std::is_same_v<T, std::decay_t<T>>);
Vt vt; Vt vt;
if constexpr(!std::is_trivially_destructible_v<T>){ if constexpr(!std::is_trivially_destructible_v<T>) {
vt._dtor = [](void* p){ ((T*)p)->~T(); }; vt._dtor = [](void* p) {
((T*)p)->~T();
};
} }
if constexpr(has_gc_marker<T>::value){ if constexpr(has_gc_marker<T>::value) {
vt._gc_mark = [](void* p, VM* vm){ ((T*)p)->_gc_mark(vm); }; vt._gc_mark = [](void* p, VM* vm) {
((T*)p)->_gc_mark(vm);
};
} }
return vt; return vt;
} }
@ -69,7 +78,7 @@ struct PyTypeInfo{
bool subclass_enabled; bool subclass_enabled;
Vt vt; Vt vt;
PyTypeInfo(PyObject* obj, Type base, PyObject* mod, StrName name, bool subclass_enabled, Vt vt={}): PyTypeInfo(PyObject* obj, Type base, PyObject* mod, StrName name, bool subclass_enabled, Vt vt = {}) :
obj(obj), base(base), mod(mod), name(name), subclass_enabled(subclass_enabled), vt(vt) {} obj(obj), base(base), mod(mod), name(name), subclass_enabled(subclass_enabled), vt(vt) {}
vector<StrName> annotated_fields = {}; vector<StrName> annotated_fields = {};
@ -122,7 +131,7 @@ struct PyTypeInfo{
void (*on_end_subclass)(VM* vm, PyTypeInfo*) = nullptr; void (*on_end_subclass)(VM* vm, PyTypeInfo*) = nullptr;
}; };
struct ImportContext{ struct ImportContext {
PK_ALWAYS_PASS_BY_POINTER(ImportContext) PK_ALWAYS_PASS_BY_POINTER(ImportContext)
vector<Str> pending; vector<Str> pending;
@ -130,29 +139,30 @@ struct ImportContext{
ImportContext() {} ImportContext() {}
struct Temp{ struct Temp {
PK_ALWAYS_PASS_BY_POINTER(Temp) PK_ALWAYS_PASS_BY_POINTER(Temp)
ImportContext* ctx; ImportContext* ctx;
Temp(ImportContext* ctx, Str name, bool is_init) : ctx(ctx){
Temp(ImportContext* ctx, Str name, bool is_init) : ctx(ctx) {
ctx->pending.push_back(name); ctx->pending.push_back(name);
ctx->pending_is_init.push_back(is_init); ctx->pending_is_init.push_back(is_init);
} }
~Temp(){
~Temp() {
ctx->pending.pop_back(); ctx->pending.pop_back();
ctx->pending_is_init.pop_back(); ctx->pending_is_init.pop_back();
} }
}; };
Temp scope(Str name, bool is_init){ Temp scope(Str name, bool is_init) { return {this, name, is_init}; }
return {this, name, is_init};
}
}; };
class VM { class VM {
PK_ALWAYS_PASS_BY_POINTER(VM) PK_ALWAYS_PASS_BY_POINTER(VM)
VM* vm; // self reference to simplify code VM* vm; // self reference to simplify code
public: public:
ManagedHeap heap; ManagedHeap heap;
ValueStack s_data; ValueStack s_data;
@ -162,7 +172,7 @@ public:
NameDict _modules; // loaded modules NameDict _modules; // loaded modules
std::map<StrName, Str> _lazy_modules; // lazy loaded modules std::map<StrName, Str> _lazy_modules; // lazy loaded modules
struct{ struct {
PyObject* error; PyObject* error;
stack_no_copy<ArgsView> s_view; stack_no_copy<ArgsView> s_view;
} __c; } __c;
@ -191,34 +201,36 @@ public:
#endif #endif
void (*_ceval_on_step)(VM*, Frame*, Bytecode bc); void (*_ceval_on_step)(VM*, Frame*, Bytecode bc);
void(*_stdout)(const char*, int); void (*_stdout)(const char*, int);
void(*_stderr)(const char*, int); void (*_stderr)(const char*, int);
unsigned char* (*_import_handler)(const char*, int*); unsigned char* (*_import_handler)(const char*, int*);
// function<void(const char*, int)> _stdout; // function<void(const char*, int)> _stdout;
// function<void(const char*, int)> _stderr; // function<void(const char*, int)> _stderr;
// function<unsigned char*(const char*, int*)> _import_handler; // function<unsigned char*(const char*, int*)> _import_handler;
// for quick access // for quick access
static constexpr Type tp_object=Type(1), tp_type=Type(2); constexpr static Type tp_object = Type(1), tp_type = Type(2);
static constexpr Type tp_int=Type(kTpIntIndex), tp_float=Type(kTpFloatIndex), tp_bool=Type(5), tp_str=Type(6); constexpr static Type tp_int = Type(kTpIntIndex), tp_float = Type(kTpFloatIndex), tp_bool = Type(5),
static constexpr Type tp_list=Type(7), tp_tuple=Type(8); tp_str = Type(6);
static constexpr Type tp_slice=Type(9), tp_range=Type(10), tp_module=Type(11); constexpr static Type tp_list = Type(7), tp_tuple = Type(8);
static constexpr Type tp_function=Type(12), tp_native_func=Type(13), tp_bound_method=Type(14); constexpr static Type tp_slice = Type(9), tp_range = Type(10), tp_module = Type(11);
static constexpr Type tp_super=Type(15), tp_exception=Type(16), tp_bytes=Type(17), tp_mappingproxy=Type(18); constexpr static Type tp_function = Type(12), tp_native_func = Type(13), tp_bound_method = Type(14);
static constexpr Type tp_dict=Type(19), tp_property=Type(20), tp_star_wrapper=Type(21); constexpr static Type tp_super = Type(15), tp_exception = Type(16), tp_bytes = Type(17), tp_mappingproxy = Type(18);
static constexpr Type tp_staticmethod=Type(22), tp_classmethod=Type(23); constexpr static Type tp_dict = Type(19), tp_property = Type(20), tp_star_wrapper = Type(21);
static constexpr Type tp_none_type=Type(24), tp_not_implemented=Type(25), tp_ellipsis=Type(26); constexpr static Type tp_staticmethod = Type(22), tp_classmethod = Type(23);
static constexpr Type tp_stack_memory=Type(kTpStackMemoryIndex); constexpr static Type tp_none_type = Type(24), tp_not_implemented = Type(25), tp_ellipsis = Type(26);
constexpr static Type tp_stack_memory = Type(kTpStackMemoryIndex);
static constexpr PyVar True{const_sso_var(), tp_bool, 1}; constexpr static PyVar True{const_sso_var(), tp_bool, 1};
static constexpr PyVar False{const_sso_var(), tp_bool, 0}; constexpr static PyVar False{const_sso_var(), tp_bool, 0};
static constexpr PyVar None{const_sso_var(), tp_none_type, 0}; constexpr static PyVar None{const_sso_var(), tp_none_type, 0};
static constexpr PyVar NotImplemented{const_sso_var(), tp_not_implemented, 0}; constexpr static PyVar NotImplemented{const_sso_var(), tp_not_implemented, 0};
static constexpr PyVar Ellipsis{const_sso_var(), tp_ellipsis, 0}; constexpr static PyVar Ellipsis{const_sso_var(), tp_ellipsis, 0};
const bool enable_os; const bool enable_os;
VM(bool enable_os=true); VM(bool enable_os = true);
// clang-format off
#if PK_REGION("Python Equivalents") #if PK_REGION("Python Equivalents")
Str py_str(PyVar obj); // x -> str(x) Str py_str(PyVar obj); // x -> str(x)
Str py_repr(PyVar obj); // x -> repr(x) Str py_repr(PyVar obj); // x -> repr(x)
@ -453,18 +465,19 @@ public:
vm->s_data.emplace(p->type, p); vm->s_data.emplace(p->type, p);
} }
#endif #endif
// clang-format on
template<typename T> template <typename T>
Type _find_type_in_cxx_typeid_map(){ Type _find_type_in_cxx_typeid_map() {
auto it = _cxx_typeid_map.find(typeid(T)); auto it = _cxx_typeid_map.find(typeid(T));
if(it == _cxx_typeid_map.end()){ if(it == _cxx_typeid_map.end()) {
#if __GNUC__ || __clang__ #if __GNUC__ || __clang__
throw std::runtime_error(__PRETTY_FUNCTION__ + std::string(" failed: T not found")); throw std::runtime_error(__PRETTY_FUNCTION__ + std::string(" failed: T not found"));
#elif _MSC_VER #elif _MSC_VER
throw std::runtime_error(__FUNCSIG__ + std::string(" failed: T not found")); throw std::runtime_error(__FUNCSIG__ + std::string(" failed: T not found"));
#else #else
throw std::runtime_error("_find_type_in_cxx_typeid_map() failed: T not found"); throw std::runtime_error("_find_type_in_cxx_typeid_map() failed: T not found");
#endif #endif
} }
return it->second; return it->second;
} }
@ -485,17 +498,35 @@ public:
void __prepare_py_call(PyVar*, ArgsView, ArgsView, const FuncDecl_&); void __prepare_py_call(PyVar*, ArgsView, ArgsView, const FuncDecl_&);
void __unpack_as_list(ArgsView args, List& list); void __unpack_as_list(ArgsView args, List& list);
void __unpack_as_dict(ArgsView args, Dict& dict); void __unpack_as_dict(ArgsView args, Dict& dict);
[[noreturn]] void __raise_exc(bool re_raise=false); [[noreturn]] void __raise_exc(bool re_raise = false);
[[noreturn]] void __builtin_error(StrName type); [[noreturn]] void __builtin_error(StrName type);
[[noreturn]] void __builtin_error(StrName type, PyVar arg); [[noreturn]] void __builtin_error(StrName type, PyVar arg);
[[noreturn]] void __builtin_error(StrName type, const Str& msg); [[noreturn]] void __builtin_error(StrName type, const Str& msg);
void __init_builtin_types(); void __init_builtin_types();
void __post_init_builtin_types(); void __post_init_builtin_types();
void __push_varargs(){}
void __push_varargs(PyVar _0){ PUSH(_0); } void __push_varargs() {}
void __push_varargs(PyVar _0, PyVar _1){ PUSH(_0); PUSH(_1); }
void __push_varargs(PyVar _0, PyVar _1, PyVar _2){ PUSH(_0); PUSH(_1); PUSH(_2); } void __push_varargs(PyVar _0) { PUSH(_0); }
void __push_varargs(PyVar _0, PyVar _1, PyVar _2, PyVar _3){ PUSH(_0); PUSH(_1); PUSH(_2); PUSH(_3); }
void __push_varargs(PyVar _0, PyVar _1) {
PUSH(_0);
PUSH(_1);
}
void __push_varargs(PyVar _0, PyVar _1, PyVar _2) {
PUSH(_0);
PUSH(_1);
PUSH(_2);
}
void __push_varargs(PyVar _0, PyVar _1, PyVar _2, PyVar _3) {
PUSH(_0);
PUSH(_1);
PUSH(_2);
PUSH(_3);
}
PyVar __pack_next_retval(unsigned); PyVar __pack_next_retval(unsigned);
PyVar __minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key); PyVar __minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key);
bool __py_bool_non_trivial(PyVar); bool __py_bool_non_trivial(PyVar);
@ -504,128 +535,201 @@ public:
void* __stack_alloc(int size); void* __stack_alloc(int size);
}; };
template <typename T>
constexpr inline bool is_immutable_v =
is_integral_v<T> || is_floating_point_v<T> || std::is_same_v<T, Str> || std::is_same_v<T, Tuple> ||
std::is_same_v<T, Bytes> || std::is_same_v<T, bool> || std::is_same_v<T, Range> || std::is_same_v<T, Slice> ||
std::is_pointer_v<T> || std::is_enum_v<T>;
template<typename T> template <typename T>
inline constexpr bool is_immutable_v = is_integral_v<T> || is_floating_point_v<T> constexpr Type _find_type_in_const_cxx_typeid_map() {
|| std::is_same_v<T, Str> || std::is_same_v<T, Tuple> || std::is_same_v<T, Bytes> || std::is_same_v<T, bool> return Type();
|| std::is_same_v<T, Range> || std::is_same_v<T, Slice> }
|| std::is_pointer_v<T> || std::is_enum_v<T>;
template<typename T> constexpr Type _find_type_in_const_cxx_typeid_map(){ return Type(); } template <>
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Str>(){ return VM::tp_str; } constexpr Type _find_type_in_const_cxx_typeid_map<Str>() {
template<> constexpr Type _find_type_in_const_cxx_typeid_map<List>(){ return VM::tp_list; } return VM::tp_str;
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Tuple>(){ return VM::tp_tuple; } }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Function>(){ return VM::tp_function; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<NativeFunc>(){ return VM::tp_native_func; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<BoundMethod>(){ return VM::tp_bound_method; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Range>(){ return VM::tp_range; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Slice>(){ return VM::tp_slice; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Exception>(){ return VM::tp_exception; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Bytes>(){ return VM::tp_bytes; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<MappingProxy>(){ return VM::tp_mappingproxy; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Dict>(){ return VM::tp_dict; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Property>(){ return VM::tp_property; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<StarWrapper>(){ return VM::tp_star_wrapper; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<StaticMethod>(){ return VM::tp_staticmethod; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<ClassMethod>(){ return VM::tp_classmethod; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<StackMemory>(){ return VM::tp_stack_memory; }
template<typename __T> template <>
PyVar py_var(VM* vm, __T&& value){ constexpr Type _find_type_in_const_cxx_typeid_map<List>() {
return VM::tp_list;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Tuple>() {
return VM::tp_tuple;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Function>() {
return VM::tp_function;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<NativeFunc>() {
return VM::tp_native_func;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<BoundMethod>() {
return VM::tp_bound_method;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Range>() {
return VM::tp_range;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Slice>() {
return VM::tp_slice;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Exception>() {
return VM::tp_exception;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Bytes>() {
return VM::tp_bytes;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<MappingProxy>() {
return VM::tp_mappingproxy;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Dict>() {
return VM::tp_dict;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Property>() {
return VM::tp_property;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<StarWrapper>() {
return VM::tp_star_wrapper;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<StaticMethod>() {
return VM::tp_staticmethod;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<ClassMethod>() {
return VM::tp_classmethod;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<StackMemory>() {
return VM::tp_stack_memory;
}
template <typename __T>
PyVar py_var(VM* vm, __T&& value) {
using T = std::decay_t<__T>; using T = std::decay_t<__T>;
static_assert(!std::is_same_v<T, PyVar>, "py_var(VM*, PyVar) is not allowed"); static_assert(!std::is_same_v<T, PyVar>, "py_var(VM*, PyVar) is not allowed");
if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>){ if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, std::string> ||
std::is_same_v<T, std::string_view>) {
// str (shortcuts) // str (shortcuts)
return VAR(Str(std::forward<__T>(value))); return VAR(Str(std::forward<__T>(value)));
}else if constexpr(std::is_same_v<T, NoReturn>){ } else if constexpr(std::is_same_v<T, NoReturn>) {
// NoneType // NoneType
return vm->None; return vm->None;
}else if constexpr(std::is_same_v<T, bool>){ } else if constexpr(std::is_same_v<T, bool>) {
// bool // bool
return value ? vm->True : vm->False; return value ? vm->True : vm->False;
}else if constexpr(is_integral_v<T>){ } else if constexpr(is_integral_v<T>) {
// int // int
return PyVar(VM::tp_int, static_cast<i64>(value)); return PyVar(VM::tp_int, static_cast<i64>(value));
}else if constexpr(is_floating_point_v<T>){ } else if constexpr(is_floating_point_v<T>) {
// float // float
return PyVar(VM::tp_float, static_cast<f64>(value)); return PyVar(VM::tp_float, static_cast<f64>(value));
}else if constexpr(std::is_pointer_v<T>){ } else if constexpr(std::is_pointer_v<T>) {
return from_void_p(vm, (void*)value); return from_void_p(vm, (void*)value);
}else{ } else {
constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>(); constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
if constexpr((bool)const_type){ if constexpr((bool)const_type) {
if constexpr(is_sso_v<T>) return PyVar(const_type, value); if constexpr(is_sso_v<T>)
else return vm->heap.gcnew<T>(const_type, std::forward<__T>(value)); return PyVar(const_type, value);
}else{ else
return vm->heap.gcnew<T>(const_type, std::forward<__T>(value));
} else {
Type type = vm->_find_type_in_cxx_typeid_map<T>(); Type type = vm->_find_type_in_cxx_typeid_map<T>();
if constexpr(is_sso_v<T>) return PyVar(type, value); if constexpr(is_sso_v<T>)
else return vm->heap.gcnew<T>(type, std::forward<__T>(value)); return PyVar(type, value);
else
return vm->heap.gcnew<T>(type, std::forward<__T>(value));
} }
} }
} }
// fast path for bool if py_var<> cannot be inlined // fast path for bool if py_var<> cannot be inlined
inline PyVar py_var(VM* vm, bool value){ inline PyVar py_var(VM* vm, bool value) { return value ? vm->True : vm->False; }
return value ? vm->True : vm->False;
}
template<typename __T, bool with_check> template <typename __T, bool with_check>
__T _py_cast__internal(VM* vm, PyVar obj) { __T _py_cast__internal(VM* vm, PyVar obj) {
static_assert(!std::is_rvalue_reference_v<__T>, "rvalue reference is not allowed"); static_assert(!std::is_rvalue_reference_v<__T>, "rvalue reference is not allowed");
using T = std::decay_t<__T>; using T = std::decay_t<__T>;
static_assert(!(is_sso_v<T> && std::is_reference_v<__T>), "SSO types cannot be reference"); static_assert(!(is_sso_v<T> && std::is_reference_v<__T>), "SSO types cannot be reference");
if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, CString>){ if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, CString>) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
// str (shortcuts) // str (shortcuts)
if(obj == vm->None) return nullptr; if(obj == vm->None) return nullptr;
if constexpr(with_check) vm->check_type(obj, vm->tp_str); if constexpr(with_check) vm->check_type(obj, vm->tp_str);
return PK_OBJ_GET(Str, obj).c_str(); return PK_OBJ_GET(Str, obj).c_str();
}else if constexpr(std::is_same_v<T, bool>){ } else if constexpr(std::is_same_v<T, bool>) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
// bool // bool
if constexpr(with_check){ if constexpr(with_check) {
if(obj == vm->True) return true; if(obj == vm->True) return true;
if(obj == vm->False) return false; if(obj == vm->False) return false;
vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape()); vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
} }
return obj == vm->True; return obj == vm->True;
}else if constexpr(is_integral_v<T>){ } else if constexpr(is_integral_v<T>) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
// int // int
if constexpr(with_check){ if constexpr(with_check) {
if(is_int(obj)) return (T)obj.as<i64>(); if(is_int(obj)) return (T)obj.as<i64>();
vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape()); vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
} }
return (T)obj.as<i64>(); return (T)obj.as<i64>();
}else if constexpr(is_floating_point_v<T>){ } else if constexpr(is_floating_point_v<T>) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
if(is_float(obj)) return (T)obj.as<f64>(); if(is_float(obj)) return (T)obj.as<f64>();
if(is_int(obj)) return (T)obj.as<i64>(); if(is_int(obj)) return (T)obj.as<i64>();
vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape()); vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape());
return 0.0f; return 0.0f;
}else if constexpr(std::is_enum_v<T>){ } else if constexpr(std::is_enum_v<T>) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
return (__T)_py_cast__internal<i64, with_check>(vm, obj); return (__T)_py_cast__internal<i64, with_check>(vm, obj);
}else if constexpr(std::is_pointer_v<T>){ } else if constexpr(std::is_pointer_v<T>) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
return to_void_p<T>(vm, obj); return to_void_p<T>(vm, obj);
}else{ } else {
constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>(); constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
if constexpr((bool)const_type){ if constexpr((bool)const_type) {
if constexpr(with_check){ if constexpr(with_check) {
if constexpr(std::is_same_v<T, Exception>){ if constexpr(std::is_same_v<T, Exception>) {
// Exception is `subclass_enabled` // Exception is `subclass_enabled`
vm->check_compatible_type(obj, const_type); vm->check_compatible_type(obj, const_type);
}else{ } else {
vm->check_type(obj, const_type); vm->check_type(obj, const_type);
} }
} }
return PK_OBJ_GET(T, obj); return PK_OBJ_GET(T, obj);
}else{ } else {
if constexpr(with_check){ if constexpr(with_check) {
Type type = vm->_find_type_in_cxx_typeid_map<T>(); Type type = vm->_find_type_in_cxx_typeid_map<T>();
vm->check_compatible_type(obj, type); vm->check_compatible_type(obj, type);
} }
@ -634,25 +738,31 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
} }
} }
template<typename __T> template <typename __T>
__T py_cast(VM* vm, PyVar obj) { return _py_cast__internal<__T, true>(vm, obj); } __T py_cast(VM* vm, PyVar obj) {
template<typename __T> return _py_cast__internal<__T, true>(vm, obj);
__T _py_cast(VM* vm, PyVar obj) { return _py_cast__internal<__T, false>(vm, obj); } }
template<typename T> template <typename __T>
PyObject* VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _register, Type base, bool subclass_enabled){ __T _py_cast(VM* vm, PyVar obj) {
return _py_cast__internal<__T, false>(vm, obj);
}
template <typename T>
PyObject*
VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _register, Type base, bool subclass_enabled) {
PyObject* type = new_type_object(mod, name, base, subclass_enabled, PyTypeInfo::Vt::get<T>()); PyObject* type = new_type_object(mod, name, base, subclass_enabled, PyTypeInfo::Vt::get<T>());
mod->attr().set(name, type); mod->attr().set(name, type);
_cxx_typeid_map[typeid(T)] = type->as<Type>(); _cxx_typeid_map[typeid(T)] = type->as<Type>();
_register(this, mod, type); _register(this, mod, type);
if(!type->attr().contains(__new__)){ if(!type->attr().contains(__new__)) {
if constexpr(std::is_default_constructible_v<T>) { if constexpr(std::is_default_constructible_v<T>) {
bind_func(type, __new__, -1, [](VM* vm, ArgsView args){ bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
Type cls_t = args[0]->as<Type>(); Type cls_t = args[0]->as<Type>();
return vm->new_object<T>(cls_t); return vm->new_object<T>(cls_t);
}); });
}else{ } else {
bind_func(type, __new__, -1, [](VM* vm, ArgsView args){ bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
vm->NotImplementedError(); vm->NotImplementedError();
return vm->None; return vm->None;
}); });
@ -661,8 +771,8 @@ PyObject* VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _reg
return type; return type;
} }
template<typename T> template <typename T>
PyObject* VM::register_user_class(PyObject* mod, StrName name, Type base, bool subclass_enabled){ PyObject* VM::register_user_class(PyObject* mod, StrName name, Type base, bool subclass_enabled) {
return register_user_class<T>(mod, name, &T::_register, base, subclass_enabled); return register_user_class<T>(mod, name, &T::_register, base, subclass_enabled);
} }

View File

@ -2,7 +2,7 @@
#include "pocketpy/common/types.hpp" #include "pocketpy/common/types.hpp"
namespace pkpy{ namespace pkpy {
void add_module_dataclasses(VM* vm); void add_module_dataclasses(VM* vm);

View File

@ -2,7 +2,7 @@
#include "pocketpy/common/types.hpp" #include "pocketpy/common/types.hpp"
namespace pkpy{ namespace pkpy {
void add_module_easing(VM* vm); void add_module_easing(VM* vm);

View File

@ -2,8 +2,8 @@
#include "pocketpy/common/types.hpp" #include "pocketpy/common/types.hpp"
namespace pkpy{ namespace pkpy {
unsigned char* _default_import_handler(const char*, int*); unsigned char* _default_import_handler(const char*, int*);
void add_module_os(VM* vm); void add_module_os(VM* vm);
void add_module_io(VM* vm); void add_module_io(VM* vm);
} } // namespace pkpy

View File

@ -5,82 +5,158 @@
#include <cmath> #include <cmath>
namespace pkpy{ namespace pkpy {
inline bool isclose(float a, float b){ return std::fabs(a - b) < 1e-4; } inline bool isclose(float a, float b) { return std::fabs(a - b) < 1e-4; }
struct Vec2{ struct Vec2 {
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);
float x, y; float x, y;
Vec2() : x(0.0f), y(0.0f) {} Vec2() : x(0.0f), y(0.0f) {}
Vec2(float x, float y) : x(x), y(y) {} Vec2(float x, float y) : x(x), y(y) {}
Vec2 operator+(const Vec2& v) const { return Vec2(x + v.x, y + v.y); } Vec2 operator+ (const Vec2& v) const { return Vec2(x + v.x, y + v.y); }
Vec2 operator-(const Vec2& v) const { return Vec2(x - v.x, y - v.y); }
Vec2 operator*(float s) const { return Vec2(x * s, y * s); } Vec2 operator- (const Vec2& v) const { return Vec2(x - v.x, y - v.y); }
Vec2 operator*(const Vec2& v) const { return Vec2(x * v.x, y * v.y); }
Vec2 operator/(float s) const { return Vec2(x / s, y / s); } Vec2 operator* (float s) const { return Vec2(x * s, y * s); }
Vec2 operator-() const { return Vec2(-x, -y); }
bool operator==(const Vec2& v) const { return isclose(x, v.x) && isclose(y, v.y); } Vec2 operator* (const Vec2& v) const { return Vec2(x * v.x, y * v.y); }
bool operator!=(const Vec2& v) const { return !isclose(x, v.x) || !isclose(y, v.y); }
float operator[](int i) const { return (&x)[i]; } Vec2 operator/ (float s) const { return Vec2(x / s, y / s); }
Vec2 operator- () const { return Vec2(-x, -y); }
bool operator== (const Vec2& v) const { return isclose(x, v.x) && isclose(y, v.y); }
bool operator!= (const Vec2& v) const { return !isclose(x, v.x) || !isclose(y, v.y); }
float operator[] (int i) const { return (&x)[i]; }
float dot(const Vec2& v) const { return x * v.x + y * v.y; } float dot(const Vec2& v) const { return x * v.x + y * v.y; }
float cross(const Vec2& v) const { return x * v.y - y * v.x; } float cross(const Vec2& v) const { return x * v.y - y * v.x; }
float length() const { return sqrtf(x * x + y * y); } float length() const { return sqrtf(x * x + y * y); }
float length_squared() const { return x * x + y * y; } float length_squared() const { return x * x + y * y; }
Vec2 normalize() const { float l = length(); return Vec2(x / l, y / l); }
Vec2 rotate(float radian) const { float cr = cosf(radian), sr = sinf(radian); return Vec2(x * cr - y * sr, x * sr + y * cr); } Vec2 normalize() const {
float l = length();
return Vec2(x / l, y / l);
}
Vec2 rotate(float radian) const {
float cr = cosf(radian), sr = sinf(radian);
return Vec2(x * cr - y * sr, x * sr + y * cr);
}
}; };
struct Vec3{ struct Vec3 {
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);
float x, y, z; float x, y, z;
Vec3() : x(0.0f), y(0.0f), z(0.0f) {} Vec3() : x(0.0f), y(0.0f), z(0.0f) {}
Vec3(float x, float y, float z) : x(x), y(y), z(z) {} Vec3(float x, float y, float z) : x(x), y(y), z(z) {}
Vec3 operator+(const Vec3& v) const { return Vec3(x + v.x, y + v.y, z + v.z); } Vec3 operator+ (const Vec3& v) const { return Vec3(x + v.x, y + v.y, z + v.z); }
Vec3 operator-(const Vec3& v) const { return Vec3(x - v.x, y - v.y, z - v.z); }
Vec3 operator*(float s) const { return Vec3(x * s, y * s, z * s); } Vec3 operator- (const Vec3& v) const { return Vec3(x - v.x, y - v.y, z - v.z); }
Vec3 operator*(const Vec3& v) const { return Vec3(x * v.x, y * v.y, z * v.z); }
Vec3 operator/(float s) const { return Vec3(x / s, y / s, z / s); } Vec3 operator* (float s) const { return Vec3(x * s, y * s, z * s); }
Vec3 operator-() const { return Vec3(-x, -y, -z); }
bool operator==(const Vec3& v) const { return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z); } Vec3 operator* (const Vec3& v) const { return Vec3(x * v.x, y * v.y, z * v.z); }
bool operator!=(const Vec3& v) const { return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z); }
float operator[](int i) const { return (&x)[i]; } Vec3 operator/ (float s) const { return Vec3(x / s, y / s, z / s); }
Vec3 operator- () const { return Vec3(-x, -y, -z); }
bool operator== (const Vec3& v) const { return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z); }
bool operator!= (const Vec3& v) const { return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z); }
float operator[] (int i) const { return (&x)[i]; }
float dot(const Vec3& v) const { return x * v.x + y * v.y + z * v.z; } float dot(const Vec3& v) const { return x * v.x + y * v.y + z * v.z; }
Vec3 cross(const Vec3& v) const { return Vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); } Vec3 cross(const Vec3& v) const { return Vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); }
float length() const { return sqrtf(x * x + y * y + z * z); } float length() const { return sqrtf(x * x + y * y + z * z); }
float length_squared() const { return x * x + y * y + z * z; } float length_squared() const { return x * x + y * y + z * z; }
Vec3 normalize() const { float l = length(); return Vec3(x / l, y / l, z / l); }
Vec3 normalize() const {
float l = length();
return Vec3(x / l, y / l, z / l);
}
}; };
struct Vec4{ struct Vec4 {
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);
float x, y, z, w; float x, y, z, w;
Vec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) {} Vec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) {}
Vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {} Vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
Vec4 operator+(const Vec4& v) const { return Vec4(x + v.x, y + v.y, z + v.z, w + v.w); } Vec4 operator+ (const Vec4& v) const { return Vec4(x + v.x, y + v.y, z + v.z, w + v.w); }
Vec4 operator-(const Vec4& v) const { return Vec4(x - v.x, y - v.y, z - v.z, w - v.w); }
Vec4 operator*(float s) const { return Vec4(x * s, y * s, z * s, w * s); } Vec4 operator- (const Vec4& v) const { return Vec4(x - v.x, y - v.y, z - v.z, w - v.w); }
Vec4 operator*(const Vec4& v) const { return Vec4(x * v.x, y * v.y, z * v.z, w * v.w); }
Vec4 operator/(float s) const { return Vec4(x / s, y / s, z / s, w / s); } Vec4 operator* (float s) const { return Vec4(x * s, y * s, z * s, w * s); }
Vec4 operator-() const { return Vec4(-x, -y, -z, -w); }
bool operator==(const Vec4& v) const { return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z) && isclose(w, v.w); } Vec4 operator* (const Vec4& v) const { return Vec4(x * v.x, y * v.y, z * v.z, w * v.w); }
bool operator!=(const Vec4& v) const { return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z) || !isclose(w, v.w); }
float operator[](int i) const { return (&x)[i]; } Vec4 operator/ (float s) const { return Vec4(x / s, y / s, z / s, w / s); }
Vec4 operator- () const { return Vec4(-x, -y, -z, -w); }
bool operator== (const Vec4& v) const {
return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z) && isclose(w, v.w);
}
bool operator!= (const Vec4& v) const {
return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z) || !isclose(w, v.w);
}
float operator[] (int i) const { return (&x)[i]; }
float dot(const Vec4& v) const { return x * v.x + y * v.y + z * v.z + w * v.w; } float dot(const Vec4& v) const { return x * v.x + y * v.y + z * v.z + w * v.w; }
float length() const { return sqrtf(x * x + y * y + z * z + w * w); } float length() const { return sqrtf(x * x + y * y + z * z + w * w); }
float length_squared() const { return x * x + y * y + z * z + w * w; } float length_squared() const { return x * x + y * y + z * z + w * w; }
Vec4 normalize() const { float l = length(); return Vec4(x / l, y / l, z / l, w / l); }
NoReturn normalize_() { float l = length(); x /= l; y /= l; z /= l; w /= l; return {}; } Vec4 normalize() const {
NoReturn copy_(const Vec4& v) { x = v.x; y = v.y; z = v.z; w = v.w; return {}; } float l = length();
return Vec4(x / l, y / l, z / l, w / l);
}
NoReturn normalize_() {
float l = length();
x /= l;
y /= l;
z /= l;
w /= l;
return {};
}
NoReturn copy_(const Vec4& v) {
x = v.x;
y = v.y;
z = v.z;
w = v.w;
return {};
}
}; };
struct Mat3x3{ struct Mat3x3 {
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);
union { union {
@ -89,6 +165,7 @@ struct Mat3x3{
float _21, _22, _23; float _21, _22, _23;
float _31, _32, _33; float _31, _32, _33;
}; };
float m[3][3]; float m[3][3];
float v[9]; float v[9];
}; };
@ -100,13 +177,13 @@ struct Mat3x3{
static Mat3x3 ones(); static Mat3x3 ones();
static Mat3x3 identity(); static Mat3x3 identity();
Mat3x3 operator+(const Mat3x3& other) const; Mat3x3 operator+ (const Mat3x3& other) const;
Mat3x3 operator-(const Mat3x3& other) const; Mat3x3 operator- (const Mat3x3& other) const;
Mat3x3 operator*(float scalar) const; Mat3x3 operator* (float scalar) const;
Mat3x3 operator/(float scalar) const; Mat3x3 operator/ (float scalar) const;
bool operator==(const Mat3x3& other) const; bool operator== (const Mat3x3& other) const;
bool operator!=(const Mat3x3& other) const; bool operator!= (const Mat3x3& other) const;
Mat3x3 matmul(const Mat3x3& other) const; Mat3x3 matmul(const Mat3x3& other) const;
Vec3 matmul(const Vec3& other) const; Vec3 matmul(const Vec3& other) const;
@ -130,9 +207,9 @@ static_assert(is_pod_v<Vec3>);
static_assert(is_pod_v<Vec4>); static_assert(is_pod_v<Vec4>);
static_assert(is_pod_v<Mat3x3>); static_assert(is_pod_v<Mat3x3>);
template<> template <>
inline constexpr bool is_sso_v<Vec2> = true; constexpr inline bool is_sso_v<Vec2> = true;
template<> template <>
inline constexpr bool is_sso_v<Vec3> = true; constexpr inline bool is_sso_v<Vec3> = true;
} // namespace pkpy } // namespace pkpy

View File

@ -2,7 +2,7 @@
#include "pocketpy/common/types.hpp" #include "pocketpy/common/types.hpp"
namespace pkpy{ namespace pkpy {
void add_module_time(VM* vm); void add_module_time(VM* vm);
void add_module_sys(VM* vm); void add_module_sys(VM* vm);

View File

@ -2,7 +2,7 @@
#include "pocketpy/common/types.hpp" #include "pocketpy/common/types.hpp"
namespace pkpy{ namespace pkpy {
void add_module_random(VM* vm); void add_module_random(VM* vm);

View File

@ -8,25 +8,31 @@
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
namespace pkpy{ namespace pkpy {
struct Type { struct Type {
int16_t index; int16_t index;
constexpr Type(): index(0) {}
explicit constexpr Type(int index): index(index) {} constexpr Type() : index(0) {}
bool operator==(Type other) const { return this->index == other.index; }
bool operator!=(Type other) const { return this->index != other.index; } explicit constexpr Type(int index) : index(index) {}
constexpr operator int() const { return index; }
bool operator== (Type other) const { return this->index == other.index; }
bool operator!= (Type other) const { return this->index != other.index; }
constexpr operator int () const { return index; }
}; };
struct const_sso_var {}; struct const_sso_var {};
struct PyVar final{ struct PyVar final {
Type type; Type type;
bool is_ptr; bool is_ptr;
uint8_t flags; uint8_t flags;
// 12 bytes SSO // 12 bytes SSO
int _0; i64 _1; int _0;
i64 _1;
// uninitialized // uninitialized
PyVar() = default; PyVar() = default;
@ -36,45 +42,50 @@ struct PyVar final{
/* We must initialize all members to allow == operator to work correctly */ /* We must initialize all members to allow == operator to work correctly */
// constexpr initialized // constexpr initialized
constexpr PyVar(const const_sso_var&, Type type, int value): type(type), is_ptr(false), flags(0), _0(value), _1(0) {} constexpr PyVar(const const_sso_var&, Type type, int value) :
type(type), is_ptr(false), flags(0), _0(value), _1(0) {}
// zero initialized // zero initialized
constexpr PyVar(std::nullptr_t): type(0), is_ptr(false), flags(0), _0(0), _1(0) {} constexpr PyVar(std::nullptr_t) : type(0), is_ptr(false), flags(0), _0(0), _1(0) {}
// PyObject* initialized (is_sso = false) // PyObject* initialized (is_sso = false)
PyVar(Type type, PyObject* p): type(type), is_ptr(true), flags(0), _0(0), _1(reinterpret_cast<i64>(p)) {} PyVar(Type type, PyObject* p) : type(type), is_ptr(true), flags(0), _0(0), _1(reinterpret_cast<i64>(p)) {}
// SSO initialized (is_sso = true) // SSO initialized (is_sso = true)
template<typename T> template <typename T>
PyVar(Type type, T value): type(type), is_ptr(false), flags(0), _0(0), _1(0) { PyVar(Type type, T value) : type(type), is_ptr(false), flags(0), _0(0), _1(0) {
static_assert(sizeof(T) <= 12, "SSO size exceeded"); static_assert(sizeof(T) <= 12, "SSO size exceeded");
as<T>() = value; as<T>() = value;
} }
template<typename T> template <typename T>
T& as(){ T& as() {
static_assert(!std::is_reference_v<T>); static_assert(!std::is_reference_v<T>);
if constexpr(sizeof(T) <= 8){ if constexpr(sizeof(T) <= 8) {
return reinterpret_cast<T&>(_1); return reinterpret_cast<T&>(_1);
}else{ } else {
return reinterpret_cast<T&>(_0); return reinterpret_cast<T&>(_0);
} }
} }
explicit operator bool() const { return (bool)type; } explicit operator bool () const { return (bool)type; }
void set_null() { _qword(0) = 0; _qword(1) = 0; } void set_null() {
_qword(0) = 0;
_qword(1) = 0;
}
i64 _qword(int i) const { return ((const i64*)this)[i]; } i64 _qword(int i) const { return ((const i64*)this)[i]; }
i64& _qword(int i) { return ((i64*)this)[i]; } i64& _qword(int i) { return ((i64*)this)[i]; }
bool operator==(const PyVar& other) const { bool operator== (const PyVar& other) const { return _qword(0) == other._qword(0) && _qword(1) == other._qword(1); }
return _qword(0) == other._qword(0) && _qword(1) == other._qword(1);
}
bool operator!=(const PyVar& other) const { bool operator!= (const PyVar& other) const { return _qword(0) != other._qword(0) || _qword(1) != other._qword(1); }
return _qword(0) != other._qword(0) || _qword(1) != other._qword(1);
}
bool operator==(std::nullptr_t) const { return !(bool)type; } bool operator== (std::nullptr_t) const { return !(bool)type; }
bool operator!=(std::nullptr_t) const { return (bool)type; }
bool operator!= (std::nullptr_t) const { return (bool)type; }
PyObject* get() const { PyObject* get() const {
assert(is_ptr); assert(is_ptr);
@ -88,13 +99,11 @@ struct PyVar final{
i64 hash() const { return _0 + _1; } i64 hash() const { return _0 + _1; }
template<typename T> template <typename T>
obj_get_t<T> obj_get(); obj_get_t<T> obj_get();
// for std::map<> // for std::map<>
bool operator<(const PyVar& other) const { bool operator< (const PyVar& other) const { return memcmp(this, &other, sizeof(PyVar)) < 0; }
return memcmp(this, &other, sizeof(PyVar)) < 0;
}
}; };
static_assert(sizeof(PyVar) == 16 && is_pod_v<PyVar>); static_assert(sizeof(PyVar) == 16 && is_pod_v<PyVar>);

View File

@ -3,31 +3,39 @@
#include "pocketpy/common/vector.hpp" #include "pocketpy/common/vector.hpp"
#include "pocketpy/objects/object.hpp" #include "pocketpy/objects/object.hpp"
namespace pkpy{ namespace pkpy {
struct BoundMethod { struct BoundMethod {
PyVar self; PyVar self;
PyVar func; PyVar func;
BoundMethod(PyVar self, PyVar func) : self(self), func(func) {} BoundMethod(PyVar self, PyVar func) : self(self), func(func) {}
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
}; };
struct StaticMethod{ struct StaticMethod {
PyVar func; PyVar func;
StaticMethod(PyVar func) : func(func) {} StaticMethod(PyVar func) : func(func) {}
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
}; };
struct ClassMethod{ struct ClassMethod {
PyVar func; PyVar func;
ClassMethod(PyVar func) : func(func) {} ClassMethod(PyVar func) : func(func) {}
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
}; };
struct Property{ struct Property {
PyVar getter; PyVar getter;
PyVar setter; PyVar setter;
Property(PyVar getter, PyVar setter) : getter(getter), setter(setter) {} Property(PyVar getter, PyVar setter) : getter(getter), setter(setter) {}
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
}; };
@ -37,20 +45,23 @@ struct Range {
i64 step = 1; i64 step = 1;
}; };
struct StarWrapper {
struct StarWrapper{
int level; // either 1 or 2 int level; // either 1 or 2
PyVar obj; PyVar obj;
StarWrapper(int level, PyVar obj) : level(level), obj(obj) {} StarWrapper(int level, PyVar obj) : level(level), obj(obj) {}
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
}; };
using Bytes = array<unsigned char>; using Bytes = array<unsigned char>;
struct Super{ struct Super {
PyVar first; PyVar first;
Type second; Type second;
Super(PyVar first, Type second) : first(first), second(second) {} Super(PyVar first, Type second) : first(first), second(second) {}
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
}; };
@ -58,16 +69,19 @@ struct Slice {
PyVar start; PyVar start;
PyVar stop; PyVar stop;
PyVar step; PyVar step;
Slice(PyVar start, PyVar stop, PyVar step) : start(start), stop(stop), step(step) {} Slice(PyVar start, PyVar stop, PyVar step) : start(start), stop(stop), step(step) {}
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
}; };
const inline int kTpIntIndex = 3;
inline const int kTpIntIndex = 3; const inline int kTpFloatIndex = 4;
inline const int kTpFloatIndex = 4;
inline bool is_tagged(PyVar p) noexcept { return !p.is_ptr; } inline bool is_tagged(PyVar p) noexcept { return !p.is_ptr; }
inline bool is_float(PyVar p) noexcept { return p.type.index == kTpFloatIndex; } inline bool is_float(PyVar p) noexcept { return p.type.index == kTpFloatIndex; }
inline bool is_int(PyVar p) noexcept { return p.type.index == kTpIntIndex; } inline bool is_int(PyVar p) noexcept { return p.type.index == kTpIntIndex; }
inline bool is_type(PyVar obj, Type type) { inline bool is_type(PyVar obj, Type type) {
@ -80,23 +94,26 @@ inline bool is_type(PyObject* p, Type type) {
return p->type == type; return p->type == type;
} }
struct MappingProxy{ struct MappingProxy {
PyObject* obj; PyObject* obj;
MappingProxy(PyObject* obj) : obj(obj) {} MappingProxy(PyObject* obj) : obj(obj) {}
NameDict& attr() { return obj->attr(); } NameDict& attr() { return obj->attr(); }
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
}; };
StrName _type_name(VM* vm, Type type); StrName _type_name(VM* vm, Type type);
template<typename T> T to_void_p(VM*, PyVar); template <typename T>
T to_void_p(VM*, PyVar);
PyVar from_void_p(VM*, void*); PyVar from_void_p(VM*, void*);
template <typename T>
template<typename T> obj_get_t<T> PyVar::obj_get() {
obj_get_t<T> PyVar::obj_get(){ if constexpr(is_sso_v<T>) {
if constexpr(is_sso_v<T>){
return as<T>(); return as<T>();
}else{ } else {
assert(is_ptr); assert(is_ptr);
void* v = ((PyObject*)_1)->_value_ptr(); void* v = ((PyObject*)_1)->_value_ptr();
return *reinterpret_cast<T*>(v); return *reinterpret_cast<T*>(v);
@ -119,6 +136,6 @@ obj_get_t<T> PyVar::obj_get(){
#define PY_NULL nullptr #define PY_NULL nullptr
extern PyVar const PY_OP_CALL; extern PyVar const PY_OP_CALL;
extern PyVar const PY_OP_YIELD; extern const PyVar PY_OP_YIELD;
} // namespace pkpy } // namespace pkpy

View File

@ -5,7 +5,7 @@
#include "pocketpy/objects/object.hpp" #include "pocketpy/objects/object.hpp"
#include "pocketpy/objects/sourcedata.hpp" #include "pocketpy/objects/sourcedata.hpp"
namespace pkpy{ namespace pkpy {
#if PK_ENABLE_STD_FUNCTION #if PK_ENABLE_STD_FUNCTION
using NativeFuncC = function<PyVar(VM*, ArgsView)>; using NativeFuncC = function<PyVar(VM*, ArgsView)>;
@ -13,7 +13,7 @@ using NativeFuncC = function<PyVar(VM*, ArgsView)>;
typedef PyVar (*NativeFuncC)(VM*, ArgsView); typedef PyVar (*NativeFuncC)(VM*, ArgsView);
#endif #endif
enum class BindType{ enum class BindType {
DEFAULT, DEFAULT,
STATICMETHOD, STATICMETHOD,
CLASSMETHOD, CLASSMETHOD,
@ -21,24 +21,23 @@ enum class BindType{
enum NameScope { NAME_LOCAL, NAME_GLOBAL, NAME_GLOBAL_UNKNOWN }; enum NameScope { NAME_LOCAL, NAME_GLOBAL, NAME_GLOBAL_UNKNOWN };
enum Opcode: uint8_t { enum Opcode : uint8_t {
#define OPCODE(name) OP_##name,
#include "pocketpy/opcodes.h" #define OPCODE(name) OP_##name,
#undef OPCODE #include "pocketpy/opcodes.h"
#undef OPCODE
}; };
struct Bytecode{ struct Bytecode {
uint8_t op; uint8_t op;
uint16_t arg; uint16_t arg;
void set_signed_arg(int arg){ void set_signed_arg(int arg) {
assert(arg >= INT16_MIN && arg <= INT16_MAX); assert(arg >= INT16_MIN && arg <= INT16_MAX);
this->arg = (int16_t)arg; this->arg = (int16_t)arg;
} }
bool is_forward_jump() const{ bool is_forward_jump() const { return op >= OP_JUMP_FORWARD && op <= OP_LOOP_BREAK; }
return op >= OP_JUMP_FORWARD && op <= OP_LOOP_BREAK;
}
}; };
enum class CodeBlockType { enum class CodeBlockType {
@ -49,8 +48,8 @@ enum class CodeBlockType {
TRY_EXCEPT, TRY_EXCEPT,
}; };
inline const uint8_t BC_NOARG = 0; const inline uint8_t BC_NOARG = 0;
inline const int BC_KEEPLINE = -1; const inline int BC_KEEPLINE = -1;
struct CodeBlock { struct CodeBlock {
CodeBlockType type; CodeBlockType type;
@ -59,10 +58,10 @@ struct CodeBlock {
int end; // end index of this block in codes, exclusive int end; // end index of this block in codes, exclusive
int end2; // ... int end2; // ...
CodeBlock(CodeBlockType type, int parent, int start): CodeBlock(CodeBlockType type, int parent, int start) :
type(type), parent(parent), start(start), end(-1), end2(-1) {} type(type), parent(parent), start(start), end(-1), end2(-1) {}
int get_break_end() const{ int get_break_end() const {
if(end2 != -1) return end2; if(end2 != -1) return end2;
return end; return end;
} }
@ -74,7 +73,7 @@ using CodeObject_ = std::shared_ptr<CodeObject>;
using FuncDecl_ = std::shared_ptr<FuncDecl>; using FuncDecl_ = std::shared_ptr<FuncDecl>;
struct CodeObject { struct CodeObject {
struct LineInfo{ struct LineInfo {
int lineno; // line number for each bytecode int lineno; // line number for each bytecode
bool is_virtual; // whether this bytecode is virtual (not in source code) bool is_virtual; // whether this bytecode is virtual (not in source code)
int iblock; // block index int iblock; // block index
@ -98,15 +97,13 @@ struct CodeObject {
int start_line; int start_line;
int end_line; int end_line;
const CodeBlock& _get_block_codei(int codei) const{ const CodeBlock& _get_block_codei(int codei) const { return blocks[lines[codei].iblock]; }
return blocks[lines[codei].iblock];
}
CodeObject(std::shared_ptr<SourceData> src, const Str& name); CodeObject(std::shared_ptr<SourceData> src, const Str& name);
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
}; };
enum class FuncType{ enum class FuncType {
UNSET, UNSET,
NORMAL, NORMAL,
SIMPLE, SIMPLE,
@ -120,6 +117,7 @@ struct FuncDecl {
StrName key; // name of this argument StrName key; // name of this argument
PyVar value; // default value PyVar value; // default value
}; };
CodeObject_ code; // code object of this function CodeObject_ code; // code object of this function
small_vector_2<int, 6> args; // indices in co->varnames small_vector_2<int, 6> args; // indices in co->varnames
@ -135,7 +133,7 @@ struct FuncDecl {
NameDictInt kw_to_index; NameDictInt kw_to_index;
void add_kwarg(int index, StrName key, PyVar value){ void add_kwarg(int index, StrName key, PyVar value) {
kw_to_index.set(key, index); kw_to_index.set(key, index);
kwargs.push_back(KwArg{index, key, value}); kwargs.push_back(KwArg{index, key, value});
} }
@ -149,27 +147,31 @@ struct NativeFunc {
FuncDecl_ decl; // new style decl-based call FuncDecl_ decl; // new style decl-based call
any _userdata; any _userdata;
NativeFunc(NativeFuncC f, int argc, any userdata={}): f(f), argc(argc), decl(nullptr), _userdata(std::move(userdata)) {} NativeFunc(NativeFuncC f, int argc, any userdata = {}) :
NativeFunc(NativeFuncC f, FuncDecl_ decl, any userdata={}): f(f), argc(-1), decl(decl), _userdata(std::move(userdata)) {} f(f), argc(argc), decl(nullptr), _userdata(std::move(userdata)) {}
NativeFunc(NativeFuncC f, FuncDecl_ decl, any userdata = {}) :
f(f), argc(-1), decl(decl), _userdata(std::move(userdata)) {}
PyVar call(VM* vm, ArgsView args) const { return f(vm, args); } PyVar call(VM* vm, ArgsView args) const { return f(vm, args); }
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
}; };
struct Function{ struct Function {
FuncDecl_ decl; FuncDecl_ decl;
PyObject* _module; // weak ref PyObject* _module; // weak ref
PyObject* _class; // weak ref PyObject* _class; // weak ref
NameDict_ _closure; NameDict_ _closure;
explicit Function(FuncDecl_ decl, PyObject* _module, PyObject* _class, NameDict_ _closure): explicit Function(FuncDecl_ decl, PyObject* _module, PyObject* _class, NameDict_ _closure) :
decl(decl), _module(_module), _class(_class), _closure(_closure) {} decl(decl), _module(_module), _class(_class), _closure(_closure) {}
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
}; };
template<typename T> template <typename T>
T& lambda_get_userdata(PyVar* p){ T& lambda_get_userdata(PyVar* p) {
static_assert(std::is_same_v<T, std::decay_t<T>>); static_assert(std::is_same_v<T, std::decay_t<T>>);
int offset = p[-1] != nullptr ? -1 : -2; int offset = p[-1] != nullptr ? -1 : -2;
return p[offset].obj_get<NativeFunc>()._userdata.cast<T>(); return p[offset].obj_get<NativeFunc>()._userdata.cast<T>();

View File

@ -3,18 +3,18 @@
#include "pocketpy/objects/base.hpp" #include "pocketpy/objects/base.hpp"
#include "pocketpy/objects/tuplelist.hpp" #include "pocketpy/objects/tuplelist.hpp"
namespace pkpy{ namespace pkpy {
struct Dict{ struct Dict {
struct Item{ struct Item {
PyVar first; PyVar first;
PyVar second; PyVar second;
int prev; int prev;
int next; int next;
}; };
static constexpr int __Capacity = 8; constexpr static int __Capacity = 8;
static constexpr float __LoadFactor = 0.67f; constexpr static float __LoadFactor = 0.67f;
int _capacity; int _capacity;
int _mask; int _mask;
@ -27,8 +27,8 @@ struct Dict{
Dict(); Dict();
Dict(Dict&& other); Dict(Dict&& other);
Dict(const Dict& other); Dict(const Dict& other);
Dict& operator=(const Dict&) = delete; Dict& operator= (const Dict&) = delete;
Dict& operator=(Dict&&) = delete; Dict& operator= (Dict&&) = delete;
int size() const { return _size; } int size() const { return _size; }
@ -44,10 +44,10 @@ struct Dict{
bool del(VM* vm, PyVar key); bool del(VM* vm, PyVar key);
void update(VM* vm, const Dict& other); void update(VM* vm, const Dict& other);
template<typename __Func> template <typename __Func>
void apply(__Func f) const { void apply(__Func f) const {
int i = _head_idx; int i = _head_idx;
while(i != -1){ while(i != -1) {
f(_items[i].first, _items[i].second); f(_items[i].first, _items[i].second);
i = _items[i].next; i = _items[i].next;
} }

View File

@ -3,22 +3,23 @@
#include "pocketpy/common/str.hpp" #include "pocketpy/common/str.hpp"
#include "pocketpy/objects/sourcedata.hpp" #include "pocketpy/objects/sourcedata.hpp"
namespace pkpy{ namespace pkpy {
struct NeedMoreLines { struct NeedMoreLines {
NeedMoreLines(bool is_compiling_class) : is_compiling_class(is_compiling_class) {} NeedMoreLines(bool is_compiling_class) : is_compiling_class(is_compiling_class) {}
bool is_compiling_class; bool is_compiling_class;
}; };
enum class InternalExceptionType: int{ enum class InternalExceptionType : int { Null, Handled, Unhandled, ToBeRaised };
Null, Handled, Unhandled, ToBeRaised
};
struct InternalException final{ struct InternalException final {
InternalExceptionType type; InternalExceptionType type;
int arg; int arg;
InternalException(): type(InternalExceptionType::Null), arg(-1) {}
InternalException(InternalExceptionType type, int arg=-1): type(type), arg(arg) {} InternalException() : type(InternalExceptionType::Null), arg(-1) {}
InternalException(InternalExceptionType type, int arg = -1) : type(type), arg(arg) {}
}; };
struct Exception { struct Exception {
@ -31,7 +32,7 @@ struct Exception {
PyObject* _self; // weak reference PyObject* _self; // weak reference
struct Frame{ struct Frame {
std::shared_ptr<SourceData> src; std::shared_ptr<SourceData> src;
int lineno; int lineno;
const char* cursor; const char* cursor;
@ -39,20 +40,21 @@ struct Exception {
Str snapshot() const { return src->snapshot(lineno, cursor, name); } Str snapshot() const { return src->snapshot(lineno, cursor, name); }
Frame(std::shared_ptr<SourceData> src, int lineno, const char* cursor, std::string_view name): Frame(std::shared_ptr<SourceData> src, int lineno, const char* cursor, std::string_view name) :
src(src), lineno(lineno), cursor(cursor), name(name) {} src(src), lineno(lineno), cursor(cursor), name(name) {}
}; };
stack<Frame> stacktrace; stack<Frame> stacktrace;
Exception(StrName type): type(type), is_re(true), _ip_on_error(-1), _code_on_error(nullptr), _self(nullptr) {}
PyObject* self() const{ Exception(StrName type) : type(type), is_re(true), _ip_on_error(-1), _code_on_error(nullptr), _self(nullptr) {}
PyObject* self() const {
assert(_self != nullptr); assert(_self != nullptr);
return _self; return _self;
} }
template<typename... Args> template <typename... Args>
void st_push(Args&&... args){ void st_push(Args&&... args) {
if(stacktrace.size() >= 7) return; if(stacktrace.size() >= 7) return;
stacktrace.emplace(std::forward<Args>(args)...); stacktrace.emplace(std::forward<Args>(args)...);
} }
@ -60,10 +62,11 @@ struct Exception {
Str summary() const; Str summary() const;
}; };
struct TopLevelException: std::exception{ struct TopLevelException : std::exception {
VM* vm; VM* vm;
Exception* ptr; Exception* ptr;
TopLevelException(VM* vm, Exception* ptr): vm(vm), ptr(ptr) {}
TopLevelException(VM* vm, Exception* ptr) : vm(vm), ptr(ptr) {}
Str summary() const { return ptr->summary(); } Str summary() const { return ptr->summary(); }

View File

@ -3,22 +3,24 @@
#include "pocketpy/common/namedict.hpp" #include "pocketpy/common/namedict.hpp"
#include "pocketpy/objects/base.hpp" #include "pocketpy/objects/base.hpp"
namespace pkpy{ namespace pkpy {
using NameDict = NameDictImpl<PyVar>; using NameDict = NameDictImpl<PyVar>;
using NameDict_ = std::shared_ptr<NameDict>; using NameDict_ = std::shared_ptr<NameDict>;
using NameDictInt = NameDictImpl<int>; using NameDictInt = NameDictImpl<int>;
static_assert(sizeof(NameDict) <= 128); static_assert(sizeof(NameDict) <= 128);
struct PyObject final{ struct PyObject final {
bool gc_marked; // whether this object is marked bool gc_marked; // whether this object is marked
Type type; // we have a duplicated type here for convenience Type type; // we have a duplicated type here for convenience
NameDict* _attr; // gc will delete this on destruction NameDict* _attr; // gc will delete this on destruction
bool is_attr_valid() const noexcept { return _attr != nullptr; } bool is_attr_valid() const noexcept { return _attr != nullptr; }
void* _value_ptr() noexcept { return (char*)this + 16; } void* _value_ptr() noexcept { return (char*)this + 16; }
template<typename T> T& as() noexcept { template <typename T>
T& as() noexcept {
static_assert(std::is_same_v<T, std::decay_t<T>>); static_assert(std::is_same_v<T, std::decay_t<T>>);
return *reinterpret_cast<T*>(_value_ptr()); return *reinterpret_cast<T*>(_value_ptr());
} }
@ -35,17 +37,17 @@ struct PyObject final{
PyObject(Type type) : gc_marked(false), type(type), _attr(nullptr) {} PyObject(Type type) : gc_marked(false), type(type), _attr(nullptr) {}
template<typename T, typename ...Args> template <typename T, typename... Args>
void placement_new(Args&&... args){ void placement_new(Args&&... args) {
static_assert(std::is_same_v<T, std::decay_t<T>>); static_assert(std::is_same_v<T, std::decay_t<T>>);
new(_value_ptr()) T(std::forward<Args>(args)...); new (_value_ptr()) T(std::forward<Args>(args)...);
// backdoor for important builtin types // backdoor for important builtin types
if constexpr(std::is_same_v<T, DummyInstance>){ if constexpr(std::is_same_v<T, DummyInstance>) {
_attr = new NameDict(); _attr = new NameDict();
}else if constexpr(std::is_same_v<T, Type>){ } else if constexpr(std::is_same_v<T, Type>) {
_attr = new NameDict(PK_TYPE_ATTR_LOAD_FACTOR); _attr = new NameDict(PK_TYPE_ATTR_LOAD_FACTOR);
}else if constexpr(std::is_same_v<T, DummyModule>){ } else if constexpr(std::is_same_v<T, DummyModule>) {
_attr = new NameDict(PK_TYPE_ATTR_LOAD_FACTOR); _attr = new NameDict(PK_TYPE_ATTR_LOAD_FACTOR);
} }
} }

View File

@ -3,15 +3,9 @@
#include "pocketpy/common/utils.hpp" #include "pocketpy/common/utils.hpp"
#include "pocketpy/common/str.hpp" #include "pocketpy/common/str.hpp"
namespace pkpy{ namespace pkpy {
enum CompileMode { enum CompileMode { EXEC_MODE, EVAL_MODE, REPL_MODE, JSON_MODE, CELL_MODE };
EXEC_MODE,
EVAL_MODE,
REPL_MODE,
JSON_MODE,
CELL_MODE
};
struct SourceData { struct SourceData {
PK_ALWAYS_PASS_BY_POINTER(SourceData) PK_ALWAYS_PASS_BY_POINTER(SourceData)
@ -27,7 +21,7 @@ struct SourceData {
SourceData(std::string_view source, const Str& filename, CompileMode mode); SourceData(std::string_view source, const Str& filename, CompileMode mode);
SourceData(const Str& filename, CompileMode mode); SourceData(const Str& filename, CompileMode mode);
std::pair<const char*,const char*> _get_line(int lineno) const; std::pair<const char*, const char*> _get_line(int lineno) const;
std::string_view get_line(int lineno) const; std::string_view get_line(int lineno) const;
Str snapshot(int lineno, const char* cursor, std::string_view name) const; Str snapshot(int lineno, const char* cursor, std::string_view name) const;
}; };

View File

@ -2,16 +2,17 @@
#include "pocketpy/common/traits.hpp" #include "pocketpy/common/traits.hpp"
namespace pkpy{ namespace pkpy {
struct StackMemory{ struct StackMemory {
int count; int count;
StackMemory(int count) : count(count) {} StackMemory(int count) : count(count) {}
}; };
template<> template <>
inline bool constexpr is_sso_v<StackMemory> = true; constexpr inline bool is_sso_v<StackMemory> = true;
inline const int kTpStackMemoryIndex = 27; const inline int kTpStackMemoryIndex = 27;
} // namespace pkpy } // namespace pkpy

View File

@ -6,7 +6,7 @@
namespace pkpy { namespace pkpy {
struct Tuple { struct Tuple {
static const int INLINED_SIZE = 3; const static int INLINED_SIZE = 3;
PyVar* _args; PyVar* _args;
PyVar _inlined[INLINED_SIZE]; PyVar _inlined[INLINED_SIZE];
@ -15,49 +15,60 @@ struct Tuple {
Tuple(int n); Tuple(int n);
Tuple(Tuple&& other) noexcept; Tuple(Tuple&& other) noexcept;
Tuple(const Tuple& other) = delete; Tuple(const Tuple& other) = delete;
Tuple& operator=(const Tuple& other) = delete; Tuple& operator= (const Tuple& other) = delete;
Tuple& operator=(Tuple&& other) = delete; Tuple& operator= (Tuple&& other) = delete;
~Tuple(); ~Tuple();
Tuple(PyVar, PyVar); Tuple(PyVar, PyVar);
Tuple(PyVar, PyVar, PyVar); Tuple(PyVar, PyVar, PyVar);
bool is_inlined() const { return _args == _inlined; } bool is_inlined() const { return _args == _inlined; }
PyVar& operator[](int i){ return _args[i]; }
PyVar operator[](int i) const { return _args[i]; } PyVar& operator[] (int i) { return _args[i]; }
PyVar operator[] (int i) const { return _args[i]; }
int size() const { return _size; } int size() const { return _size; }
PyVar* begin() const { return _args; } PyVar* begin() const { return _args; }
PyVar* end() const { return _args + _size; } PyVar* end() const { return _args + _size; }
PyVar* data() const { return _args; } PyVar* data() const { return _args; }
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
}; };
struct List: public vector<PyVar>{ struct List : public vector<PyVar> {
using vector<PyVar>::vector; using vector<PyVar>::vector;
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
Tuple to_tuple() const{ Tuple to_tuple() const {
Tuple ret(size()); Tuple ret(size());
for(int i=0; i<size(); i++) ret[i] = (*this)[i]; for(int i = 0; i < size(); i++)
ret[i] = (*this)[i];
return ret; return ret;
} }
}; };
// a lightweight view for function args, it does not own the memory // a lightweight view for function args, it does not own the memory
struct ArgsView{ struct ArgsView {
PyVar* _begin; PyVar* _begin;
PyVar* _end; PyVar* _end;
ArgsView(PyVar* begin, PyVar* end) : _begin(begin), _end(end) {} ArgsView(PyVar* begin, PyVar* end) : _begin(begin), _end(end) {}
ArgsView(const Tuple& t) : _begin(t.begin()), _end(t.end()) {} ArgsView(const Tuple& t) : _begin(t.begin()), _end(t.end()) {}
PyVar* begin() const { return _begin; } PyVar* begin() const { return _begin; }
PyVar* end() const { return _end; } PyVar* end() const { return _end; }
int size() const { return _end - _begin; } int size() const { return _end - _begin; }
bool empty() const { return _begin == _end; } bool empty() const { return _begin == _end; }
PyVar operator[](int i) const { return _begin[i]; }
PyVar operator[] (int i) const { return _begin[i]; }
List to_list() const; List to_list() const;
Tuple to_tuple() const; Tuple to_tuple() const;

View File

@ -9,17 +9,17 @@
#include "pocketpy/modules/linalg.hpp" #include "pocketpy/modules/linalg.hpp"
#include "pocketpy/tools/repl.hpp" #include "pocketpy/tools/repl.hpp"
namespace pkpy{ namespace pkpy {
static_assert(py_sizeof<Str> <= 64); static_assert(py_sizeof<Str> <= 64);
static_assert(py_sizeof<Mat3x3> <= 64); static_assert(py_sizeof<Mat3x3> <= 64);
static_assert(py_sizeof<Struct> <= 64); static_assert(py_sizeof<Struct> <= 64);
static_assert(py_sizeof<Tuple> <= 80); static_assert(py_sizeof<Tuple> <= 80);
static_assert(py_sizeof<List> <= 64); static_assert(py_sizeof<List> <= 64);
static_assert(py_sizeof<Dict> <= 64); static_assert(py_sizeof<Dict> <= 64);
static_assert(py_sizeof<RangeIter> <= 64); static_assert(py_sizeof<RangeIter> <= 64);
static_assert(py_sizeof<RangeIterR> <= 64); static_assert(py_sizeof<RangeIterR> <= 64);
static_assert(py_sizeof<ArrayIter> <= 64); static_assert(py_sizeof<ArrayIter> <= 64);
static_assert(py_sizeof<StringIter> <= 64); static_assert(py_sizeof<StringIter> <= 64);
static_assert(py_sizeof<Generator> <= 64); static_assert(py_sizeof<Generator> <= 64);
static_assert(py_sizeof<DictItemsIter> <= 64); static_assert(py_sizeof<DictItemsIter> <= 64);
} // namespace pkpy } // namespace pkpy

View File

@ -10,98 +10,97 @@ extern "C" {
#include "pocketpy/common/export.h" #include "pocketpy/common/export.h"
typedef struct pkpy_vm_handle pkpy_vm; typedef struct pkpy_vm_handle pkpy_vm;
typedef int (*pkpy_CFunction)(pkpy_vm*); typedef int (*pkpy_CFunction)(pkpy_vm*);
typedef void (*pkpy_COutputHandler)(const char*, int); typedef void (*pkpy_COutputHandler)(const char*, int);
typedef unsigned char* (*pkpy_CImportHandler)(const char*, int*); typedef unsigned char* (*pkpy_CImportHandler)(const char*, int*);
typedef int pkpy_CName; typedef int pkpy_CName;
typedef int pkpy_CType; typedef int pkpy_CType;
typedef const char* pkpy_CString; typedef const char* pkpy_CString;
/* Basic Functions */ /* Basic Functions */
PK_EXPORT pkpy_vm* pkpy_new_vm(bool enable_os); PK_EXPORT pkpy_vm* pkpy_new_vm(bool enable_os);
PK_EXPORT void pkpy_delete_vm(pkpy_vm*); PK_EXPORT void pkpy_delete_vm(pkpy_vm*);
PK_EXPORT bool pkpy_exec(pkpy_vm*, const char* source); PK_EXPORT bool pkpy_exec(pkpy_vm*, const char* source);
PK_EXPORT bool pkpy_exec_2(pkpy_vm*, const char* source, const char* filename, int mode, const char* module); PK_EXPORT bool pkpy_exec_2(pkpy_vm*, const char* source, const char* filename, int mode, const char* module);
PK_EXPORT void pkpy_set_main_argv(pkpy_vm*, int argc, char** argv); PK_EXPORT void pkpy_set_main_argv(pkpy_vm*, int argc, char** argv);
/* Stack Manipulation */ /* Stack Manipulation */
PK_EXPORT bool pkpy_dup(pkpy_vm*, int i); PK_EXPORT bool pkpy_dup(pkpy_vm*, int i);
PK_EXPORT bool pkpy_pop(pkpy_vm*, int n); PK_EXPORT bool pkpy_pop(pkpy_vm*, int n);
PK_EXPORT bool pkpy_pop_top(pkpy_vm*); PK_EXPORT bool pkpy_pop_top(pkpy_vm*);
PK_EXPORT bool pkpy_dup_top(pkpy_vm*); PK_EXPORT bool pkpy_dup_top(pkpy_vm*);
PK_EXPORT bool pkpy_rot_two(pkpy_vm*); PK_EXPORT bool pkpy_rot_two(pkpy_vm*);
PK_EXPORT int pkpy_stack_size(pkpy_vm*); PK_EXPORT int pkpy_stack_size(pkpy_vm*);
// int // int
PK_EXPORT bool pkpy_push_int(pkpy_vm*, int val); PK_EXPORT bool pkpy_push_int(pkpy_vm*, int val);
PK_EXPORT bool pkpy_is_int(pkpy_vm*, int i); PK_EXPORT bool pkpy_is_int(pkpy_vm*, int i);
PK_EXPORT bool pkpy_to_int(pkpy_vm*, int i, int* out); PK_EXPORT bool pkpy_to_int(pkpy_vm*, int i, int* out);
// float // float
PK_EXPORT bool pkpy_push_float(pkpy_vm*, double val); PK_EXPORT bool pkpy_push_float(pkpy_vm*, double val);
PK_EXPORT bool pkpy_is_float(pkpy_vm*, int i); PK_EXPORT bool pkpy_is_float(pkpy_vm*, int i);
PK_EXPORT bool pkpy_to_float(pkpy_vm*, int i, double* out); PK_EXPORT bool pkpy_to_float(pkpy_vm*, int i, double* out);
// bool // bool
PK_EXPORT bool pkpy_push_bool(pkpy_vm*, bool val); PK_EXPORT bool pkpy_push_bool(pkpy_vm*, bool val);
PK_EXPORT bool pkpy_is_bool(pkpy_vm*, int i); PK_EXPORT bool pkpy_is_bool(pkpy_vm*, int i);
PK_EXPORT bool pkpy_to_bool(pkpy_vm*, int i, bool* out); PK_EXPORT bool pkpy_to_bool(pkpy_vm*, int i, bool* out);
// string // string
PK_EXPORT bool pkpy_push_string(pkpy_vm*, pkpy_CString val); PK_EXPORT bool pkpy_push_string(pkpy_vm*, pkpy_CString val);
PK_EXPORT bool pkpy_is_string(pkpy_vm*, int i); PK_EXPORT bool pkpy_is_string(pkpy_vm*, int i);
PK_EXPORT bool pkpy_to_string(pkpy_vm*, int i, pkpy_CString* out); PK_EXPORT bool pkpy_to_string(pkpy_vm*, int i, pkpy_CString* out);
// void_p // void_p
PK_EXPORT bool pkpy_push_voidp(pkpy_vm*, void* val); PK_EXPORT bool pkpy_push_voidp(pkpy_vm*, void* val);
PK_EXPORT bool pkpy_is_voidp(pkpy_vm*, int i); PK_EXPORT bool pkpy_is_voidp(pkpy_vm*, int i);
PK_EXPORT bool pkpy_to_voidp(pkpy_vm*, int i, void** out); PK_EXPORT bool pkpy_to_voidp(pkpy_vm*, int i, void** out);
// none // none
PK_EXPORT bool pkpy_push_none(pkpy_vm*); PK_EXPORT bool pkpy_push_none(pkpy_vm*);
PK_EXPORT bool pkpy_is_none(pkpy_vm*, int i); PK_EXPORT bool pkpy_is_none(pkpy_vm*, int i);
// special push // special push
PK_EXPORT bool pkpy_push_null(pkpy_vm*); PK_EXPORT bool pkpy_push_null(pkpy_vm*);
PK_EXPORT bool pkpy_push_function(pkpy_vm*, const char* sig, pkpy_CFunction val); PK_EXPORT bool pkpy_push_function(pkpy_vm*, const char* sig, pkpy_CFunction val);
PK_EXPORT bool pkpy_push_module(pkpy_vm*, const char* name); PK_EXPORT bool pkpy_push_module(pkpy_vm*, const char* name);
// some opt // some opt
PK_EXPORT bool pkpy_getattr(pkpy_vm*, pkpy_CName name); PK_EXPORT bool pkpy_getattr(pkpy_vm*, pkpy_CName name);
PK_EXPORT bool pkpy_setattr(pkpy_vm*, pkpy_CName name); PK_EXPORT bool pkpy_setattr(pkpy_vm*, pkpy_CName name);
PK_EXPORT bool pkpy_getglobal(pkpy_vm*, pkpy_CName name); PK_EXPORT bool pkpy_getglobal(pkpy_vm*, pkpy_CName name);
PK_EXPORT bool pkpy_setglobal(pkpy_vm*, pkpy_CName name); PK_EXPORT bool pkpy_setglobal(pkpy_vm*, pkpy_CName name);
PK_EXPORT bool pkpy_eval(pkpy_vm*, const char* source); PK_EXPORT bool pkpy_eval(pkpy_vm*, const char* source);
PK_EXPORT bool pkpy_unpack_sequence(pkpy_vm*, int size); PK_EXPORT bool pkpy_unpack_sequence(pkpy_vm*, int size);
PK_EXPORT bool pkpy_get_unbound_method(pkpy_vm*, pkpy_CName name); PK_EXPORT bool pkpy_get_unbound_method(pkpy_vm*, pkpy_CName name);
PK_EXPORT bool pkpy_py_repr(pkpy_vm*); PK_EXPORT bool pkpy_py_repr(pkpy_vm*);
PK_EXPORT bool pkpy_py_str(pkpy_vm*); PK_EXPORT bool pkpy_py_str(pkpy_vm*);
PK_EXPORT bool pkpy_py_import(pkpy_vm*, pkpy_CString name); PK_EXPORT bool pkpy_py_import(pkpy_vm*, pkpy_CString name);
/* Error Handling */ /* Error Handling */
PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, pkpy_CString msg); PK_EXPORT bool pkpy_error(pkpy_vm*, const char* name, pkpy_CString msg);
PK_EXPORT bool pkpy_check_error(pkpy_vm*); PK_EXPORT bool pkpy_check_error(pkpy_vm*);
PK_EXPORT bool pkpy_clear_error(pkpy_vm*, char** message); PK_EXPORT bool pkpy_clear_error(pkpy_vm*, char** message);
/* Callables */ /* Callables */
PK_EXPORT bool pkpy_vectorcall(pkpy_vm*, int argc); PK_EXPORT bool pkpy_vectorcall(pkpy_vm*, int argc);
/* Special APIs */ /* Special APIs */
PK_EXPORT void pkpy_free(void* p); PK_EXPORT void pkpy_free(void* p);
#define pkpy_string(__s) (__s) #define pkpy_string(__s) (__s)
PK_EXPORT pkpy_CName pkpy_name(const char* s); PK_EXPORT pkpy_CName pkpy_name(const char* s);
PK_EXPORT pkpy_CString pkpy_name_to_string(pkpy_CName name); PK_EXPORT pkpy_CString pkpy_name_to_string(pkpy_CName name);
PK_EXPORT void pkpy_set_output_handler(pkpy_vm*, pkpy_COutputHandler handler); PK_EXPORT void pkpy_set_output_handler(pkpy_vm*, pkpy_COutputHandler handler);
PK_EXPORT void pkpy_set_import_handler(pkpy_vm*, pkpy_CImportHandler handler); PK_EXPORT void pkpy_set_import_handler(pkpy_vm*, pkpy_CImportHandler handler);
/* REPL */ /* REPL */
PK_EXPORT void* pkpy_new_repl(pkpy_vm*); PK_EXPORT void* pkpy_new_repl(pkpy_vm*);
PK_EXPORT bool pkpy_repl_input(void* r, const char* line); PK_EXPORT bool pkpy_repl_input(void* r, const char* line);
PK_EXPORT void pkpy_delete_repl(void* repl); PK_EXPORT void pkpy_delete_repl(void* repl);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif #endif

View File

@ -2,13 +2,14 @@
#include "pocketpy/interpreter/vm.hpp" #include "pocketpy/interpreter/vm.hpp"
namespace pkpy{ namespace pkpy {
class REPL { class REPL {
protected: protected:
int need_more_lines = 0; int need_more_lines = 0;
std::string buffer; std::string buffer;
VM* vm; VM* vm;
public: public:
REPL(VM* vm); REPL(VM* vm);
bool input(std::string line); bool input(std::string line);

View File

@ -3,106 +3,97 @@
#include "types.h" #include "types.h"
namespace pybind11 { namespace pybind11 {
inline void exec(const char* code, handle global = {}, handle local = {}) { inline void exec(const char* code, handle global = {}, handle local = {}) {
vm->py_exec(code, global.ptr(), local.ptr()); vm->py_exec(code, global.ptr(), local.ptr());
} }
// wrapper for builtin functions in Python // wrapper for builtin functions in Python
inline bool hasattr(const handle& obj, const handle& name) { inline bool hasattr(const handle& obj, const handle& name) {
auto& key = _builtin_cast<pkpy::Str>(name); auto& key = _builtin_cast<pkpy::Str>(name);
return vm->getattr(obj.ptr(), key, false) != nullptr; return vm->getattr(obj.ptr(), key, false) != nullptr;
} }
inline bool hasattr(const handle& obj, const char* name) { inline bool hasattr(const handle& obj, const char* name) { return vm->getattr(obj.ptr(), name, false) != nullptr; }
return vm->getattr(obj.ptr(), name, false) != nullptr;
}
inline void delattr(const handle& obj, const handle& name) { inline void delattr(const handle& obj, const handle& name) {
auto& key = _builtin_cast<pkpy::Str>(name); auto& key = _builtin_cast<pkpy::Str>(name);
vm->delattr(obj.ptr(), key); vm->delattr(obj.ptr(), key);
} }
inline void delattr(const handle& obj, const char* name) { vm->delattr(obj.ptr(), name); } inline void delattr(const handle& obj, const char* name) { vm->delattr(obj.ptr(), name); }
inline object getattr(const handle& obj, const handle& name) { inline object getattr(const handle& obj, const handle& name) {
auto& key = _builtin_cast<pkpy::Str>(name); auto& key = _builtin_cast<pkpy::Str>(name);
return reinterpret_borrow<object>(vm->getattr(obj.ptr(), key)); return reinterpret_borrow<object>(vm->getattr(obj.ptr(), key));
} }
inline object getattr(const handle& obj, const char* name) { inline object getattr(const handle& obj, const char* name) {
return reinterpret_borrow<object>(vm->getattr(obj.ptr(), name)); return reinterpret_borrow<object>(vm->getattr(obj.ptr(), name));
} }
inline object getattr(const handle& obj, const handle& name, const handle& default_) { inline object getattr(const handle& obj, const handle& name, const handle& default_) {
if(!hasattr(obj, name)) { if(!hasattr(obj, name)) { return reinterpret_borrow<object>(default_); }
return reinterpret_borrow<object>(default_);
}
return getattr(obj, name); return getattr(obj, name);
} }
inline object getattr(const handle& obj, const char* name, const handle& default_) { inline object getattr(const handle& obj, const char* name, const handle& default_) {
if(!hasattr(obj, name)) { if(!hasattr(obj, name)) { return reinterpret_borrow<object>(default_); }
return reinterpret_borrow<object>(default_);
}
return getattr(obj, name); 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); auto& key = _builtin_cast<pkpy::Str>(name);
vm->setattr(obj.ptr(), key, value.ptr()); 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()); vm->setattr(obj.ptr(), name, value.ptr());
} }
template <typename T> template <typename T>
inline bool isinstance(const handle& obj) { inline bool isinstance(const handle& obj) {
pkpy::Type cls = _builtin_cast<pkpy::Type>(type::handle_of<T>().ptr()); pkpy::Type cls = _builtin_cast<pkpy::Type>(type::handle_of<T>().ptr());
return vm->isinstance(obj.ptr(), cls); return vm->isinstance(obj.ptr(), cls);
} }
template <> template <>
inline bool isinstance<handle>(const handle&) = delete; inline bool isinstance<handle>(const handle&) = delete;
template <> template <>
inline bool isinstance<iterable>(const handle& obj) { inline bool isinstance<iterable>(const handle& obj) {
return hasattr(obj, "__iter__"); return hasattr(obj, "__iter__");
} }
template <> template <>
inline bool isinstance<iterator>(const handle& obj) { inline bool isinstance<iterator>(const handle& obj) {
return hasattr(obj, "__iter__") && hasattr(obj, "__next__"); 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)); 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> template <typename T, typename SFINAE = void>
struct type_caster; struct type_caster;
template <typename T> template <typename T>
handle _cast(T&& value, handle
return_value_policy policy = return_value_policy::automatic_reference, _cast(T&& value, return_value_policy policy = return_value_policy::automatic_reference, handle parent = handle()) {
handle parent = handle()) {
using U = std::remove_pointer_t<std::remove_cv_t<std::remove_reference_t<T>>>; 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); return type_caster<U>::cast(std::forward<T>(value), policy, parent);
} }
template <typename T> template <typename T>
object cast(T&& value, object
return_value_policy policy = return_value_policy::automatic_reference, cast(T&& value, return_value_policy policy = return_value_policy::automatic_reference, handle parent = handle()) {
handle parent = handle()) {
return reinterpret_borrow<object>(_cast(std::forward<T>(value), policy, parent)); return reinterpret_borrow<object>(_cast(std::forward<T>(value), policy, parent));
} }
template <typename T> template <typename T>
T cast(handle obj, bool convert = false) { T cast(handle obj, bool convert = false) {
using Caster = using Caster = type_caster<std::remove_pointer_t<std::remove_cv_t<std::remove_reference_t<T>>>>;
type_caster<std::remove_pointer_t<std::remove_cv_t<std::remove_reference_t<T>>>>;
Caster caster; Caster caster;
if(caster.load(obj, convert)) { if(caster.load(obj, convert)) {
@ -113,5 +104,5 @@ namespace pybind11 {
} }
} }
throw std::runtime_error("Unable to cast Python instance to C++ type"); throw std::runtime_error("Unable to cast Python instance to C++ type");
} }
} // namespace pybind11 } // namespace pybind11

View File

@ -6,22 +6,21 @@
namespace pybind11 { namespace pybind11 {
using pkpy::is_floating_point_v; using pkpy::is_floating_point_v;
using pkpy::is_integral_v; using pkpy::is_integral_v;
template <typename T> template <typename T>
constexpr inline bool is_string_v = constexpr inline bool is_string_v = std::is_same_v<T, char*> || std::is_same_v<T, const char*> ||
std::is_same_v<T, char*> || std::is_same_v<T, const char*> ||
std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>; std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>;
template <typename T> template <typename T>
constexpr bool is_pyobject_v = std::is_base_of_v<handle, T>; constexpr bool is_pyobject_v = std::is_base_of_v<handle, T>;
template <typename T, typename> template <typename T, typename>
struct type_caster; struct type_caster;
template <> template <>
struct type_caster<bool> { struct type_caster<bool> {
bool value; bool value;
bool load(const handle& src, bool) { bool load(const handle& src, bool) {
@ -33,13 +32,11 @@ namespace pybind11 {
return false; return false;
} }
static handle cast(bool src, return_value_policy, handle) { static handle cast(bool src, return_value_policy, handle) { return src ? vm->True : vm->False; }
return src ? vm->True : vm->False; };
}
};
template <typename T> template <typename T>
struct type_caster<T, std::enable_if_t<is_integral_v<T>>> { struct type_caster<T, std::enable_if_t<is_integral_v<T>>> {
T value; T value;
bool load(const handle& src, bool convert) { 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); } static handle cast(T src, return_value_policy, handle) { return pkpy::py_var(vm, src); }
}; };
template <typename T> template <typename T>
struct type_caster<T, std::enable_if_t<is_floating_point_v<T>>> { struct type_caster<T, std::enable_if_t<is_floating_point_v<T>>> {
T value; T value;
bool load(const handle& src, bool convert) { 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); } static handle cast(T src, return_value_policy, handle) { return pkpy::py_var(vm, src); }
}; };
template <typename T> template <typename T>
struct type_caster<T, std::enable_if_t<is_string_v<T>>> { struct type_caster<T, std::enable_if_t<is_string_v<T>>> {
T value; T value;
bool load(const handle& src, bool) { bool load(const handle& src, bool) {
@ -89,13 +86,11 @@ namespace pybind11 {
return false; return false;
} }
static handle cast(const std::string& src, return_value_policy, handle) { static handle cast(const std::string& src, return_value_policy, handle) { return pkpy::py_var(vm, src); }
return pkpy::py_var(vm, src); };
}
};
template <typename T> template <typename T>
struct type_caster<T, std::enable_if_t<is_pyobject_v<T>>> { struct type_caster<T, std::enable_if_t<is_pyobject_v<T>>> {
T value; T value;
bool load(const handle& src, bool) { bool load(const handle& src, bool) {
@ -111,10 +106,10 @@ namespace pybind11 {
static handle cast(U&& src, return_value_policy, handle) { static handle cast(U&& src, return_value_policy, handle) {
return std::forward<U>(src); return std::forward<U>(src);
} }
}; };
template <typename T, typename> template <typename T, typename>
struct type_caster { struct type_caster {
value_wrapper<T> value; value_wrapper<T> value;
using underlying_type = std::remove_pointer_t<decltype(value.pointer)>; using underlying_type = std::remove_pointer_t<decltype(value.pointer)>;
@ -140,13 +135,11 @@ namespace pybind11 {
} }
vm->TypeError("type not registered"); vm->TypeError("type not registered");
} }
}; };
template <typename T> template <typename T>
struct type_caster<T, std::enable_if_t<std::is_pointer_v<T> || std::is_reference_v<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>, using underlying = std::conditional_t<std::is_pointer_v<T>, std::remove_pointer_t<T>, std::remove_reference_t<T>>;
std::remove_pointer_t<T>,
std::remove_reference_t<T>>;
struct wrapper { struct wrapper {
type_caster<underlying> caster; type_caster<underlying> caster;
@ -168,6 +161,6 @@ namespace pybind11 {
static handle cast(U&& value, return_value_policy policy, const handle& parent) { static handle cast(U&& value, return_value_policy policy, const handle& parent) {
return type_caster<underlying>::cast(std::forward<U>(value), policy, parent); return type_caster<underlying>::cast(std::forward<U>(value), policy, parent);
} }
}; };
} // namespace pybind11 } // namespace pybind11

View File

@ -4,9 +4,9 @@
namespace pybind11 { namespace pybind11 {
class module : public object { class module : public object {
public: public:
using object::object; using object::object;
static module import(const char* name) { static module import(const char* name) {
@ -16,25 +16,21 @@ namespace pybind11 {
return module{vm->py_import(name, false), true}; return module{vm->py_import(name, false), true};
} }
} }
}; };
// TODO: // TODO:
// 1. inheritance // 1. inheritance
// 2. virtual function // 2. virtual function
// 3. factory function // 3. factory function
template <typename T, typename... Others> template <typename T, typename... Others>
class class_ : public type { class class_ : public type {
public: public:
using type::type; using type::type;
template <typename... Args> template <typename... Args>
class_(const handle& scope, const char* name, Args&&... args) : class_(const handle& scope, const char* name, Args&&... args) :
type(vm->new_type_object(scope.ptr(), type(vm->new_type_object(scope.ptr(), name, vm->tp_object, false, pkpy::PyTypeInfo::Vt::get<instance>()),
name,
vm->tp_object,
false,
pkpy::PyTypeInfo::Vt::get<instance>()),
true) { true) {
pkpy::PyVar mod = scope.ptr(); pkpy::PyVar mod = scope.ptr();
mod->attr().set(name, m_ptr); mod->attr().set(name, m_ptr);
@ -54,7 +50,9 @@ namespace pybind11 {
bind_function( bind_function(
*this, *this,
"__init__", "__init__",
[](T* self, Args... args) { new (self) T(args...); }, [](T* self, Args... args) {
new (self) T(args...);
},
pkpy::BindType::DEFAULT, pkpy::BindType::DEFAULT,
extra...); extra...);
return *this; return *this;
@ -65,12 +63,10 @@ namespace pybind11 {
template <typename Fn, typename... Extra> template <typename Fn, typename... Extra>
class_& def(const char* name, Fn&& f, const Extra&... 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>>>; using first = std::tuple_element_t<0, callable_args_t<remove_cvref_t<Fn>>>;
constexpr bool is_first_base_of_v = constexpr bool is_first_base_of_v = std::is_reference_v<first> && std::is_base_of_v<T, remove_cvref_t<first>>;
std::is_reference_v<first> && std::is_base_of_v<T, remove_cvref_t<first>>;
if constexpr(!is_first_base_of_v) { if constexpr(!is_first_base_of_v) {
static_assert( static_assert(is_first_base_of_v,
is_first_base_of_v,
"If you want to bind member function, the first argument must be the base class"); "If you want to bind member function, the first argument must be the base class");
} else { } else {
bind_function(*this, name, std::forward<Fn>(f), pkpy::BindType::DEFAULT, extra...); bind_function(*this, name, std::forward<Fn>(f), pkpy::BindType::DEFAULT, extra...);
@ -98,8 +94,7 @@ namespace pybind11 {
template <typename MP, typename... Extras> template <typename MP, typename... Extras>
class_& def_readwrite(const char* name, MP mp, const Extras&... extras) { class_& def_readwrite(const char* name, MP mp, const Extras&... extras) {
if constexpr(!std::is_member_object_pointer_v<MP>) { if constexpr(!std::is_member_object_pointer_v<MP>) {
static_assert(std::is_member_object_pointer_v<MP>, static_assert(std::is_member_object_pointer_v<MP>, "def_readwrite only supports pointer to data member");
"def_readwrite only supports pointer to data member");
} else { } else {
bind_property(*this, name, mp, mp, extras...); bind_property(*this, name, mp, mp, extras...);
} }
@ -109,8 +104,7 @@ namespace pybind11 {
template <typename MP, typename... Extras> template <typename MP, typename... Extras>
class_& def_readonly(const char* name, MP mp, const Extras&... extras) { class_& def_readonly(const char* name, MP mp, const Extras&... extras) {
if constexpr(!std::is_member_object_pointer_v<MP>) { if constexpr(!std::is_member_object_pointer_v<MP>) {
static_assert(std::is_member_object_pointer_v<MP>, static_assert(std::is_member_object_pointer_v<MP>, "def_readonly only supports pointer to data member");
"def_readonly only supports pointer to data member");
} else { } else {
bind_property(*this, name, mp, nullptr, extras...); bind_property(*this, name, mp, nullptr, extras...);
} }
@ -146,20 +140,19 @@ namespace pybind11 {
} }
template <typename Getter, typename Setter, typename... Extras> template <typename Getter, typename Setter, typename... Extras>
class_& class_& def_property_static(const char* name, Getter&& g, Setter&& s, const Extras&... extras) {
def_property_static(const char* name, Getter&& g, Setter&& s, const Extras&... extras) {
static_assert( static_assert(
dependent_false<Getter>, dependent_false<Getter>,
"define static properties requires metaclass. This is a complex feature with few use cases, so it may never be implemented."); "define static properties requires metaclass. This is a complex feature with few use cases, so it may never be implemented.");
return *this; return *this;
} }
}; };
template <typename T, typename... Others> template <typename T, typename... Others>
class enum_ : public class_<T, Others...> { class enum_ : public class_<T, Others...> {
std::map<const char*, pkpy::PyVar> m_values; std::map<const char*, pkpy::PyVar> m_values;
public: public:
using class_<T, Others...>::class_; using class_<T, Others...>::class_;
template <typename... Args> template <typename... Args>
@ -180,5 +173,5 @@ namespace pybind11 {
} }
return *this; return *this;
} }
}; };
} // namespace pybind11 } // namespace pybind11

View File

@ -5,46 +5,45 @@
namespace pybind11 { namespace pybind11 {
template <std::size_t Nurse, std::size_t... Patients> template <std::size_t Nurse, std::size_t... Patients>
struct keep_alive {}; struct keep_alive {};
template <typename T> template <typename T>
struct call_guard { struct call_guard {
static_assert(std::is_default_constructible_v<T>, static_assert(std::is_default_constructible_v<T>, "call_guard must be default constructible");
"call_guard must be default constructible"); };
};
// append the overload to the beginning of the overload list // append the overload to the beginning of the overload list
struct prepend {}; struct prepend {};
template <typename... Args> template <typename... Args>
struct init {}; struct init {};
// TODO: support more customized tags // TODO: support more customized tags
// struct kw_only {}; // struct kw_only {};
// //
// struct pos_only {}; // struct pos_only {};
// //
// struct default_arg {}; // struct default_arg {};
// //
// struct arg { // struct arg {
// const char* name; // const char* name;
// const char* description; // const char* description;
// }; // };
// //
// struct default_arg { // struct default_arg {
// const char* name; // const char* name;
// const char* description; // const char* description;
// const char* value; // const char* value;
// }; // };
template <typename Fn, template <typename Fn,
typename Extra, typename Extra,
typename Args = callable_args_t<std::decay_t<Fn>>, typename Args = callable_args_t<std::decay_t<Fn>>,
typename IndexSequence = std::make_index_sequence<std::tuple_size_v<Args>>> typename IndexSequence = std::make_index_sequence<std::tuple_size_v<Args>>>
struct generator; struct generator;
class function_record { class function_record {
union { union {
void* data; void* data;
char buffer[16]; char buffer[16];
@ -60,10 +59,9 @@ namespace pybind11 {
template <typename Fn, typename Extra, typename Args, typename IndexSequence> template <typename Fn, typename Extra, typename Args, typename IndexSequence>
friend struct generator; friend struct generator;
public: public:
template <typename Fn, typename... Extras> template <typename Fn, typename... Extras>
function_record(Fn&& f, const char* name, const Extras&... extras) : function_record(Fn&& f, const char* name, const Extras&... extras) : name(name), next(nullptr) {
name(name), next(nullptr) {
if constexpr(sizeof(f) <= sizeof(buffer)) { if constexpr(sizeof(f) <= sizeof(buffer)) {
new (buffer) auto(std::forward<Fn>(f)); new (buffer) auto(std::forward<Fn>(f));
@ -72,7 +70,9 @@ namespace pybind11 {
}; };
} else { } else {
data = new auto(std::forward<Fn>(f)); 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...>>; 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 // foreach function record and call the function with not convert
while(p != nullptr) { while(p != nullptr) {
handle result = p->wrapper(*this, view, false, {}); handle result = p->wrapper(*this, view, false, {});
if(result) { if(result) { return result; }
return result;
}
p = p->next; p = p->next;
} }
@ -114,18 +112,16 @@ namespace pybind11 {
// foreach function record and call the function with convert // foreach function record and call the function with convert
while(p != nullptr) { while(p != nullptr) {
handle result = p->wrapper(*this, view, true, {}); handle result = p->wrapper(*this, view, true, {});
if(result) { if(result) { return result; }
return result;
}
p = p->next; p = p->next;
} }
vm->TypeError("no matching function found"); vm->TypeError("no matching function found");
} }
}; };
template <typename Fn, std::size_t... Is, typename... Args> template <typename Fn, std::size_t... Is, typename... Args>
handle invoke(Fn&& fn, handle invoke(Fn&& fn,
std::index_sequence<Is...>, std::index_sequence<Is...>,
std::tuple<type_caster<Args>...>& casters, std::tuple<type_caster<Args>...>& casters,
return_value_policy policy, return_value_policy policy,
@ -157,10 +153,10 @@ namespace pybind11 {
return type_caster<ret>::cast(fn(std::get<Is>(casters).value...), policy, parent); return type_caster<ret>::cast(fn(std::get<Is>(casters).value...), policy, parent);
} }
} }
} }
template <typename Fn, typename... Args, std::size_t... Is, typename... Extras> template <typename Fn, typename... Args, std::size_t... Is, typename... Extras>
struct generator<Fn, std::tuple<Extras...>, std::tuple<Args...>, std::index_sequence<Is...>> { struct generator<Fn, std::tuple<Extras...>, std::tuple<Args...>, std::index_sequence<Is...>> {
static void initialize(function_record& record, const Extras&... extras) {} static void initialize(function_record& record, const Extras&... extras) {}
static auto generate() { static auto generate() {
@ -176,13 +172,9 @@ namespace pybind11 {
// initialize the stack // initialize the stack
if(!has_args && (view.size() != count)) { if(!has_args && (view.size() != count)) { return handle(); }
return handle();
}
if(has_args && (view.size() < count)) { if(has_args && (view.size() < count)) { return handle(); }
return handle();
}
for(std::size_t i = 0; i < count; ++i) { for(std::size_t i = 0; i < count; ++i) {
stack[i] = view[i]; stack[i] = view[i];
@ -206,8 +198,7 @@ namespace pybind11 {
for(std::size_t i = 0; i < n; i += 2) { for(std::size_t i = 0; i < n; i += 2) {
pkpy::i64 index = pkpy::_py_cast<pkpy::i64>(vm, view[count + i]); pkpy::i64 index = pkpy::_py_cast<pkpy::i64>(vm, view[count + i]);
pkpy::PyVar str = pkpy::PyVar str = vm->new_object<pkpy::Str>(vm->tp_str, pkpy::StrName(index).sv());
vm->new_object<pkpy::Str>(vm->tp_str, pkpy::StrName(index).sv());
dict.set(vm, str, view[count + i + 1]); dict.set(vm, str, view[count + i + 1]);
} }
@ -216,9 +207,7 @@ namespace pybind11 {
// check if all the arguments are not valid // check if all the arguments are not valid
for(std::size_t i = 0; i < sizeof...(Args); ++i) { for(std::size_t i = 0; i < sizeof...(Args); ++i) {
if(!stack[i]) { if(!stack[i]) { return handle(); }
return handle();
}
} }
// ok, all the arguments are valid, call the function // ok, all the arguments are valid, call the function
@ -226,39 +215,31 @@ namespace pybind11 {
// check type compatibility // check type compatibility
if(((std::get<Is>(casters).load(stack[Is], convert)) && ...)) { if(((std::get<Is>(casters).load(stack[Is], convert)) && ...)) {
return invoke(self.cast<Fn>(), return invoke(self.cast<Fn>(), std::index_sequence<Is...>{}, casters, self.policy, parent);
std::index_sequence<Is...>{},
casters,
self.policy,
parent);
} }
return handle(); 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()); auto& record = pkpy::lambda_get_userdata<function_record>(view.begin());
return record(view).ptr(); return record(view).ptr();
}; };
class cpp_function : public function { class cpp_function : public function {
public: public:
template <typename Fn, typename... Extras> template <typename Fn, typename... Extras>
cpp_function(Fn&& f, const Extras&... extras) { cpp_function(Fn&& f, const Extras&... extras) {
pkpy::any userdata = function_record(std::forward<Fn>(f), "anonymous", extras...); pkpy::any userdata = function_record(std::forward<Fn>(f), "anonymous", extras...);
m_ptr = vm->bind_func(nullptr, "", -1, _wrapper, std::move(userdata)); m_ptr = vm->bind_func(nullptr, "", -1, _wrapper, std::move(userdata));
inc_ref(); inc_ref();
} }
}; };
template <typename Fn, typename... Extras> template <typename Fn, typename... Extras>
handle bind_function(const handle& obj, handle bind_function(const handle& obj, const char* name, Fn&& fn, pkpy::BindType type, const Extras&... extras) {
const char* name,
Fn&& fn,
pkpy::BindType type,
const Extras&... extras) {
// do not use cpp_function directly to avoid unnecessary reference count change // do not use cpp_function directly to avoid unnecessary reference count change
pkpy::PyVar var = obj.ptr(); pkpy::PyVar var = obj.ptr();
pkpy::PyVar callable = var->attr().try_get(name); pkpy::PyVar callable = var->attr().try_get(name);
@ -284,14 +265,11 @@ namespace pybind11 {
} }
} }
return callable; return callable;
} }
template <typename Getter_, typename Setter_, typename... Extras> template <typename Getter_, typename Setter_, typename... Extras>
handle bind_property(const handle& obj, handle
const char* name, bind_property(const handle& obj, const char* name, Getter_&& getter_, Setter_&& setter_, const Extras&... extras) {
Getter_&& getter_,
Setter_&& setter_,
const Extras&... extras) {
pkpy::PyVar var = obj.ptr(); pkpy::PyVar var = obj.ptr();
pkpy::PyVar getter = vm->None; pkpy::PyVar getter = vm->None;
pkpy::PyVar setter = vm->None; pkpy::PyVar setter = vm->None;
@ -308,14 +286,12 @@ namespace pybind11 {
auto& self = _builtin_cast<instance>(view[0]).cast<Self>(); auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
if constexpr(std::is_member_object_pointer_v<Getter>) { if constexpr(std::is_member_object_pointer_v<Getter>) {
return type_caster<member_type_t<Getter>>::cast( return type_caster<member_type_t<Getter>>::cast(self.*getter,
self.*getter,
return_value_policy::reference_internal, return_value_policy::reference_internal,
view[0]) view[0])
.ptr(); .ptr();
} else { } else {
return type_caster<callable_return_t<Getter>>::cast( return type_caster<callable_return_t<Getter>>::cast((self.*getter)(),
(self.*getter)(),
return_value_policy::reference_internal, return_value_policy::reference_internal,
view[0]) view[0])
.ptr(); .ptr();
@ -325,8 +301,7 @@ namespace pybind11 {
using Self = std::tuple_element_t<0, callable_args_t<Getter>>; using Self = std::tuple_element_t<0, callable_args_t<Getter>>;
auto& self = _builtin_cast<instance>(view[0]).cast<Self>(); auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
return type_caster<callable_return_t<Getter>>::cast( return type_caster<callable_return_t<Getter>>::cast(getter(self),
getter(self),
return_value_policy::reference_internal, return_value_policy::reference_internal,
view[0]) view[0])
.ptr(); .ptr();
@ -378,6 +353,6 @@ namespace pybind11 {
pkpy::PyVar property = vm->new_object<pkpy::Property>(vm->tp_property, getter, setter); pkpy::PyVar property = vm->new_object<pkpy::Property>(vm->tp_property, getter, setter);
var->attr().set(name, property); var->attr().set(name, property);
return property; return property;
} }
} // namespace pybind11 } // namespace pybind11

View File

@ -3,7 +3,7 @@
#include "kernel.h" #include "kernel.h"
namespace pybind11 { namespace pybind11 {
struct type_info { struct type_info {
const char* name; const char* name;
std::size_t size; std::size_t size;
std::size_t alignment; std::size_t alignment;
@ -24,20 +24,24 @@ namespace pybind11 {
((T*)ptr)->~T(); ((T*)ptr)->~T();
operator delete (ptr); operator delete (ptr);
}, },
[](void* dst, const void* src) { new (dst) T(*(const T*)src); }, [](void* dst, const void* src) {
[](void* dst, void* src) { new (dst) T(std::move(*(T*)src)); }, new (dst) T(*(const T*)src);
},
[](void* dst, void* src) {
new (dst) T(std::move(*(T*)src));
},
&typeid(T), &typeid(T),
}; };
return info; return info;
} }
}; };
// all registered C++ class will be ensured as instance type. // all registered C++ class will be ensured as instance type.
class instance { class instance {
public: public:
// use to record the type information of C++ class. // use to record the type information of C++ class.
private: private:
enum Flag { enum Flag {
None = 0, None = 0,
Own = 1 << 0, // if the instance is owned by C++ side. Own = 1 << 0, // if the instance is owned by C++ side.
@ -50,13 +54,12 @@ namespace pybind11 {
pkpy::PyVar parent; pkpy::PyVar parent;
// pkpy::PyVar // pkpy::PyVar
public: public:
instance() noexcept : flag(Flag::None), data(nullptr), type(nullptr), parent(nullptr) {} instance() noexcept : flag(Flag::None), data(nullptr), type(nullptr), parent(nullptr) {}
instance(const instance&) = delete; instance(const instance&) = delete;
instance(instance&& other) noexcept : instance(instance&& other) noexcept : flag(other.flag), data(other.data), type(other.type), parent(other.parent) {
flag(other.flag), data(other.data), type(other.type), parent(other.parent) {
other.flag = Flag::None; other.flag = Flag::None;
other.data = nullptr; other.data = nullptr;
other.type = nullptr; other.type = nullptr;
@ -73,8 +76,7 @@ namespace pybind11 {
} }
template <typename T> template <typename T>
static pkpy::PyVar static pkpy::PyVar create(T&& value,
create(T&& value,
pkpy::Type type, pkpy::Type type,
return_value_policy policy = return_value_policy::automatic_reference, return_value_policy policy = return_value_policy::automatic_reference,
pkpy::PyVar parent = nullptr) noexcept { pkpy::PyVar parent = nullptr) noexcept {
@ -128,20 +130,16 @@ namespace pybind11 {
} }
~instance() { ~instance() {
if(flag & Flag::Own) { if(flag & Flag::Own) { type->destructor(data); }
type->destructor(data);
}
} }
void _gc_mark(pkpy::VM* vm) const noexcept { void _gc_mark(pkpy::VM* vm) const noexcept {
if(parent && (flag & Flag::Ref)) { if(parent && (flag & Flag::Ref)) { PK_OBJ_MARK(parent); }
PK_OBJ_MARK(parent);
}
} }
template <typename T> template <typename T>
T& cast() noexcept { T& cast() noexcept {
return *static_cast<T*>(data); return *static_cast<T*>(data);
} }
}; };
} // namespace pybind11 } // namespace pybind11

View File

@ -2,46 +2,37 @@
#include <pocketpy.h> #include <pocketpy.h>
namespace pybind11 namespace pybind11 {
{ inline pkpy::VM* vm = nullptr;
inline pkpy::VM* vm = nullptr; inline std::map<pkpy::PyVar, int*>* _ref_counts_map = nullptr;
inline std::map<pkpy::PyVar, int*>* _ref_counts_map = nullptr;
inline void initialize(bool enable_os = true) inline void initialize(bool enable_os = true) {
{
vm = new pkpy::VM(enable_os); vm = new pkpy::VM(enable_os);
_ref_counts_map = new std::map<pkpy::PyVar, int*>(); _ref_counts_map = new std::map<pkpy::PyVar, int*>();
// use to keep alive PyObject, when the object is hold by C++ side. // use to keep alive PyObject, when the object is hold by C++ side.
vm->heap._gc_marker_ex = [](pkpy::VM* vm) vm->heap._gc_marker_ex = [](pkpy::VM* vm) {
{ for(auto iter = _ref_counts_map->begin(); iter != _ref_counts_map->end();) {
for(auto iter = _ref_counts_map->begin(); iter != _ref_counts_map->end();)
{
auto ref_count = iter->second; auto ref_count = iter->second;
if(*ref_count != 0) if(*ref_count != 0) {
{
// if ref count is not zero, then mark it. // if ref count is not zero, then mark it.
PK_OBJ_MARK(iter->first); PK_OBJ_MARK(iter->first);
++iter; ++iter;
} } else {
else
{
// if ref count is zero, then delete it. // if ref count is zero, then delete it.
iter = _ref_counts_map->erase(iter); iter = _ref_counts_map->erase(iter);
delete ref_count; delete ref_count;
} }
} }
}; };
} }
inline void finalize() inline void finalize() {
{
delete _ref_counts_map; delete _ref_counts_map;
delete vm; 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 * 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. * 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 * return_value_policy::reference and the keep_alive call policy
*/ */
reference_internal reference_internal
}; };
} // namespace pybind11 } // namespace pybind11

View File

@ -3,42 +3,42 @@
#include "kernel.h" #include "kernel.h"
namespace pybind11 { namespace pybind11 {
class handle; class handle;
class object; class object;
class attr_accessor; class attr_accessor;
class item_accessor; class item_accessor;
class iterator; class iterator;
class str; class str;
class bytes; class bytes;
class iterable; class iterable;
class tuple; class tuple;
class dict; class dict;
class list; class list;
class set; class set;
class function; class function;
class module; class module;
class type; class type;
class bool_; class bool_;
class int_; class int_;
class float_; class float_;
class str; class str;
class bytes; class bytes;
template <typename T> template <typename T>
T& _builtin_cast(const handle& obj); T& _builtin_cast(const handle& obj);
template <typename T> template <typename T>
T reinterpret_borrow(const handle& h); T reinterpret_borrow(const handle& h);
template <typename T> template <typename T>
T reinterpret_steal(const handle& h); T reinterpret_steal(const handle& h);
class handle { class handle {
protected: protected:
pkpy::PyVar m_ptr = nullptr; pkpy::PyVar m_ptr = nullptr;
mutable int* ref_count = nullptr; mutable int* ref_count = nullptr;
public: public:
handle() = default; handle() = default;
handle(const handle& h) = default; handle(const handle& h) = default;
handle& operator= (const handle& other) = default; handle& operator= (const handle& other) = default;
@ -82,7 +82,7 @@ namespace pybind11 {
return *this; return *this;
} }
public: public:
template <typename T> template <typename T>
T cast() const; T cast() const;
@ -120,7 +120,7 @@ namespace pybind11 {
template <return_value_policy policy = return_value_policy::automatic, typename... Args> template <return_value_policy policy = return_value_policy::automatic, typename... Args>
object operator() (Args&&... args) const; 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); 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."); static_assert(!std::is_reference_v<T>, "T must not be a reference type.");
return obj.ptr().obj_get<T>(); 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 { class object : public handle {
public: public:
object(const object& other) : handle(other) { inc_ref(); } object(const object& other) : handle(other) { inc_ref(); }
object(object&& other) noexcept : handle(other) { object(object&& other) noexcept : handle(other) {
@ -191,16 +191,12 @@ namespace pybind11 {
} }
~object() { ~object() {
if(m_ptr != nullptr) { if(m_ptr != nullptr) { dec_ref(); }
dec_ref();
}
} }
protected: protected:
object(const handle& h, bool borrow) : handle(h) { object(const handle& h, bool borrow) : handle(h) {
if(borrow) { if(borrow) { inc_ref(); }
inc_ref();
}
} }
template <typename T> template <typename T>
@ -212,44 +208,44 @@ namespace pybind11 {
friend T reinterpret_steal(const handle& h) { friend T reinterpret_steal(const handle& h) {
return {h, false}; return {h, false};
} }
}; };
inline void setattr(const handle& obj, const handle& name, 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); inline void setitem(const handle& obj, const handle& key, const handle& value);
#define PYBIND11_BINARY_OPERATOR(OP, NAME) \ #define PYBIND11_BINARY_OPERATOR(OP, NAME) \
inline object operator OP (const handle& lhs, const handle& rhs) { \ 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)); \ return reinterpret_borrow<object>(vm->call(vm->py_op(NAME), lhs.m_ptr, rhs.m_ptr)); \
} }
PYBIND11_BINARY_OPERATOR(+, "add"); PYBIND11_BINARY_OPERATOR(+, "add");
PYBIND11_BINARY_OPERATOR(-, "sub"); PYBIND11_BINARY_OPERATOR(-, "sub");
PYBIND11_BINARY_OPERATOR(*, "mul"); PYBIND11_BINARY_OPERATOR(*, "mul");
PYBIND11_BINARY_OPERATOR(/, "truediv"); PYBIND11_BINARY_OPERATOR(/, "truediv");
PYBIND11_BINARY_OPERATOR(%, "mod"); PYBIND11_BINARY_OPERATOR(%, "mod");
PYBIND11_BINARY_OPERATOR(|, "or_"); PYBIND11_BINARY_OPERATOR(|, "or_");
PYBIND11_BINARY_OPERATOR(&, "and_"); PYBIND11_BINARY_OPERATOR(&, "and_");
PYBIND11_BINARY_OPERATOR(^, "xor"); PYBIND11_BINARY_OPERATOR(^, "xor");
PYBIND11_BINARY_OPERATOR(<<, "lshift"); PYBIND11_BINARY_OPERATOR(<<, "lshift");
PYBIND11_BINARY_OPERATOR(>>, "rshift"); PYBIND11_BINARY_OPERATOR(>>, "rshift");
PYBIND11_BINARY_OPERATOR(+=, "iadd"); PYBIND11_BINARY_OPERATOR(+=, "iadd");
PYBIND11_BINARY_OPERATOR(-=, "isub"); PYBIND11_BINARY_OPERATOR(-=, "isub");
PYBIND11_BINARY_OPERATOR(*=, "imul"); PYBIND11_BINARY_OPERATOR(*=, "imul");
PYBIND11_BINARY_OPERATOR(/=, "itruediv"); PYBIND11_BINARY_OPERATOR(/=, "itruediv");
PYBIND11_BINARY_OPERATOR(%=, "imod"); PYBIND11_BINARY_OPERATOR(%=, "imod");
PYBIND11_BINARY_OPERATOR(|=, "ior"); PYBIND11_BINARY_OPERATOR(|=, "ior");
PYBIND11_BINARY_OPERATOR(&=, "iand"); PYBIND11_BINARY_OPERATOR(&=, "iand");
PYBIND11_BINARY_OPERATOR(^=, "ixor"); PYBIND11_BINARY_OPERATOR(^=, "ixor");
PYBIND11_BINARY_OPERATOR(<<=, "ilshift"); PYBIND11_BINARY_OPERATOR(<<=, "ilshift");
PYBIND11_BINARY_OPERATOR(>>=, "irshift"); PYBIND11_BINARY_OPERATOR(>>=, "irshift");
PYBIND11_BINARY_OPERATOR(==, "eq"); PYBIND11_BINARY_OPERATOR(==, "eq");
PYBIND11_BINARY_OPERATOR(!=, "ne"); PYBIND11_BINARY_OPERATOR(!=, "ne");
PYBIND11_BINARY_OPERATOR(<, "lt"); PYBIND11_BINARY_OPERATOR(<, "lt");
PYBIND11_BINARY_OPERATOR(>, "gt"); PYBIND11_BINARY_OPERATOR(>, "gt");
PYBIND11_BINARY_OPERATOR(<=, "le"); PYBIND11_BINARY_OPERATOR(<=, "le");
PYBIND11_BINARY_OPERATOR(>=, "ge"); PYBIND11_BINARY_OPERATOR(>=, "ge");
#undef PYBIND11_BINARY_OPERATOR #undef PYBIND11_BINARY_OPERATOR

View File

@ -4,25 +4,25 @@
#include <type_traits> #include <type_traits>
namespace pybind11 { namespace pybind11 {
template <typename T> template <typename T>
constexpr bool dependent_false = false; constexpr bool dependent_false = false;
template <typename T, typename Tuple> template <typename T, typename Tuple>
struct tuple_push_front; struct tuple_push_front;
template <typename T, typename... Ts> template <typename T, typename... Ts>
struct tuple_push_front<T, std::tuple<Ts...>> { struct tuple_push_front<T, std::tuple<Ts...>> {
using type = std::tuple<T, Ts...>; using type = std::tuple<T, Ts...>;
}; };
template <typename T, typename Tuple> template <typename T, typename Tuple>
using tuple_push_front_t = typename tuple_push_front<T, Tuple>::type; using tuple_push_front_t = typename tuple_push_front<T, Tuple>::type;
// traits for function types // traits for function types
template <typename Fn> template <typename Fn>
struct function_traits { struct function_traits {
static_assert(dependent_false<Fn>, "unsupported function type"); static_assert(dependent_false<Fn>, "unsupported function type");
}; };
#define PYBIND11_FUNCTION_TRAITS_SPECIALIZE(qualifiers) \ #define PYBIND11_FUNCTION_TRAITS_SPECIALIZE(qualifiers) \
template <typename R, typename... Args> \ template <typename R, typename... Args> \
@ -32,126 +32,126 @@ namespace pybind11 {
constexpr static std::size_t args_count = sizeof...(Args); \ constexpr static std::size_t args_count = sizeof...(Args); \
}; };
PYBIND11_FUNCTION_TRAITS_SPECIALIZE() PYBIND11_FUNCTION_TRAITS_SPECIALIZE()
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(&) PYBIND11_FUNCTION_TRAITS_SPECIALIZE(&)
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(const) PYBIND11_FUNCTION_TRAITS_SPECIALIZE(const)
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(const&) PYBIND11_FUNCTION_TRAITS_SPECIALIZE(const&)
PYBIND11_FUNCTION_TRAITS_SPECIALIZE(noexcept) PYBIND11_FUNCTION_TRAITS_SPECIALIZE(noexcept)
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(const& noexcept) PYBIND11_FUNCTION_TRAITS_SPECIALIZE(const& noexcept)
#undef PYBIND11_FUNCTION_TRAITS_SPECIALIZE #undef PYBIND11_FUNCTION_TRAITS_SPECIALIZE
template <typename T> template <typename T>
using function_return_t = typename function_traits<T>::return_type; using function_return_t = typename function_traits<T>::return_type;
template <typename T> template <typename T>
using function_args_t = typename function_traits<T>::args_type; using function_args_t = typename function_traits<T>::args_type;
template <typename T> template <typename T>
constexpr std::size_t function_args_count = function_traits<T>::args_count; constexpr std::size_t function_args_count = function_traits<T>::args_count;
// traits for member pointers // traits for member pointers
template <typename T> template <typename T>
struct member_traits; struct member_traits;
template <typename M, typename C> template <typename M, typename C>
struct member_traits<M C::*> { struct member_traits<M C::*> {
using member_type = M; using member_type = M;
using class_type = C; using class_type = C;
}; };
template <typename T> template <typename T>
using member_type_t = typename member_traits<T>::member_type; using member_type_t = typename member_traits<T>::member_type;
template <typename T> template <typename T>
using class_type_t = typename member_traits<T>::class_type; using class_type_t = typename member_traits<T>::class_type;
// some traits for distinguishing between function pointers, member function pointers and // some traits for distinguishing between function pointers, member function pointers and
// functors // functors
using std::is_member_function_pointer_v; using std::is_member_function_pointer_v;
using std::is_member_object_pointer_v; using std::is_member_object_pointer_v;
template <typename T> template <typename T>
constexpr inline bool is_function_pointer_v = std::is_function_v<std::remove_pointer_t<T>>; constexpr inline bool is_function_pointer_v = std::is_function_v<std::remove_pointer_t<T>>;
template <typename T, typename U = void> template <typename T, typename U = void>
constexpr bool is_functor_v = false; constexpr bool is_functor_v = false;
template <typename T> template <typename T>
constexpr inline bool is_functor_v<T, std::void_t<decltype(&T::operator())>> = true; constexpr inline bool is_functor_v<T, std::void_t<decltype(&T::operator())>> = true;
template <typename T, typename SFINAE = void> template <typename T, typename SFINAE = void>
struct callable_traits; struct callable_traits;
template <typename T> template <typename T>
struct callable_traits<T, std::enable_if_t<is_member_function_pointer_v<T>>> { struct callable_traits<T, std::enable_if_t<is_member_function_pointer_v<T>>> {
using args_type = tuple_push_front_t<class_type_t<T>&, function_args_t<member_type_t<T>>>; using args_type = tuple_push_front_t<class_type_t<T>&, function_args_t<member_type_t<T>>>;
using return_type = function_return_t<member_type_t<T>>; using return_type = function_return_t<member_type_t<T>>;
}; };
template <typename T> template <typename T>
struct callable_traits<T, std::enable_if_t<is_function_pointer_v<T>>> { struct callable_traits<T, std::enable_if_t<is_function_pointer_v<T>>> {
using args_type = function_args_t<std::remove_pointer<T>>; using args_type = function_args_t<std::remove_pointer<T>>;
using return_type = function_return_t<std::remove_pointer<T>>; using return_type = function_return_t<std::remove_pointer<T>>;
}; };
template <typename T> template <typename T>
struct callable_traits<T, std::enable_if_t<is_functor_v<T>>> { struct callable_traits<T, std::enable_if_t<is_functor_v<T>>> {
using args_type = function_args_t<member_type_t<decltype(&T::operator())>>; using args_type = function_args_t<member_type_t<decltype(&T::operator())>>;
using return_type = function_return_t<member_type_t<decltype(&T::operator())>>; using return_type = function_return_t<member_type_t<decltype(&T::operator())>>;
}; };
template <typename Callable> template <typename Callable>
using callable_args_t = typename callable_traits<Callable>::args_type; using callable_args_t = typename callable_traits<Callable>::args_type;
template <typename Callable> template <typename Callable>
using callable_return_t = typename callable_traits<Callable>::return_type; using callable_return_t = typename callable_traits<Callable>::return_type;
template <typename Callable> template <typename Callable>
constexpr std::size_t callable_args_count_v = std::tuple_size_v<callable_args_t<Callable>>; constexpr std::size_t callable_args_count_v = std::tuple_size_v<callable_args_t<Callable>>;
template <typename T> template <typename T>
struct type_identity { struct type_identity {
using type = T; using type = T;
}; };
template <typename T> template <typename T>
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>; using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
template <typename T, typename... Ts> template <typename T, typename... Ts>
constexpr inline std::size_t types_count_v = (std::is_same_v<T, Ts> + ...); constexpr inline std::size_t types_count_v = (std::is_same_v<T, Ts> + ...);
template <typename T> template <typename T>
constexpr inline std::size_t types_count_v<T> = 0; constexpr inline std::size_t types_count_v<T> = 0;
template <typename T> template <typename T>
struct value_wrapper { struct value_wrapper {
T* pointer; T* pointer;
operator T& () { return *pointer; } operator T& () { return *pointer; }
}; };
template <typename T> template <typename T>
struct value_wrapper<T*> { struct value_wrapper<T*> {
T* pointer; T* pointer;
operator T* () { return pointer; } operator T* () { return pointer; }
}; };
template <typename T> template <typename T>
struct value_wrapper<T&> { struct value_wrapper<T&> {
T* pointer; T* pointer;
operator T& () { return *pointer; } operator T& () { return *pointer; }
}; };
template <typename T> template <typename T>
struct value_wrapper<T&&> { struct value_wrapper<T&&> {
T* pointer; T* pointer;
operator T&& () { return std::move(*pointer); } operator T&& () { return std::move(*pointer); }
}; };
} // namespace pybind11 } // namespace pybind11

View File

@ -3,58 +3,58 @@
#include "object.h" #include "object.h"
namespace pybind11 { namespace pybind11 {
class type : public object { class type : public object {
public: public:
using object::object; using object::object;
template <typename T> template <typename T>
static handle handle_of(); static handle handle_of();
}; };
class iterable : public object { class iterable : public object {
public: public:
using object::object; using object::object;
iterable() = delete; iterable() = delete;
}; };
class iterator : public object { class iterator : public object {
public: public:
using object::object; using object::object;
iterator() = delete; iterator() = delete;
}; };
class list : public object { class list : public object {
public: public:
using object::object; using object::object;
list() : object(vm->new_object<pkpy::List>(pkpy::VM::tp_list), true) {} list() : object(vm->new_object<pkpy::List>(pkpy::VM::tp_list), true) {}
}; };
class tuple : public object { class tuple : public object {
public: public:
using object::object; using object::object;
tuple(int n) : object(vm->new_object<pkpy::Tuple>(pkpy::VM::tp_tuple, n), true) {} tuple(int n) : object(vm->new_object<pkpy::Tuple>(pkpy::VM::tp_tuple, n), true) {}
//& operator[](int i){ return _args[i]; } //& operator[](int i){ return _args[i]; }
// PyVar operator[](int i) const { return _args[i]; } // PyVar operator[](int i) const { return _args[i]; }
}; };
class set : public object { class set : public object {
public: public:
using object::object; using object::object;
// set() : object(vm->new_object<pkpy::Se>(pkpy::VM::tp_set), true) {} // set() : object(vm->new_object<pkpy::Se>(pkpy::VM::tp_set), true) {}
}; };
class dict : public object { class dict : public object {
public: public:
using object::object; using object::object;
dict() : object(vm->new_object<pkpy::Dict>(pkpy::VM::tp_dict), true) {} dict() : object(vm->new_object<pkpy::Dict>(pkpy::VM::tp_dict), true) {}
}; };
class str : public object { class str : public object {
public: public:
using object::object; using object::object;
str(const char* c, int len) : str(const char* c, int len) :
object(vm->new_object<pkpy::Str>(pkpy::VM::tp_str, c, len), true) { object(vm->new_object<pkpy::Str>(pkpy::VM::tp_str, c, len), true) {
@ -73,127 +73,119 @@ namespace pybind11 {
template <typename... Args> template <typename... Args>
str format(Args&&... args) const; str format(Args&&... args) const;
}; };
class int_ : public object { class int_ : public object {
public: public:
using object::object; using object::object;
int_(int64_t value) : object(pkpy::py_var(vm, value), true) {} int_(int64_t value) : object(pkpy::py_var(vm, value), true) {}
}; };
class float_ : public object { class float_ : public object {
public: public:
using object::object; using object::object;
float_(double value) : object(pkpy::py_var(vm, value), true) {} float_(double value) : object(pkpy::py_var(vm, value), true) {}
}; };
class bool_ : public object { class bool_ : public object {
public: public:
using object::object; using object::object;
bool_(bool value) : object(pkpy::py_var(vm, value), true) {} bool_(bool value) : object(pkpy::py_var(vm, value), true) {}
}; };
class function : public object { class function : public object {
public: public:
using object::object; using object::object;
}; };
class attr_accessor : public object { class attr_accessor : public object {
private: private:
object key; object key;
public: public:
template <typename T> template <typename T>
attr_accessor(const object& obj, T&& key) : object(obj), key(std::forward<T>(key)){}; attr_accessor(const object& obj, T&& key) : object(obj), key(std::forward<T>(key)){};
template <typename T> template <typename T>
attr_accessor& operator= (T&& value) & { attr_accessor& operator= (T&& value) & {
static_assert(std::is_base_of_v<object, std::decay_t<T>>, static_assert(std::is_base_of_v<object, std::decay_t<T>>, "T must be derived from object");
"T must be derived from object");
m_ptr = std::forward<T>(value); m_ptr = std::forward<T>(value);
return *this; return *this;
} }
template <typename T> template <typename T>
attr_accessor& operator= (T&& value) && { attr_accessor& operator= (T&& value) && {
static_assert(std::is_base_of_v<object, std::decay_t<T>>, static_assert(std::is_base_of_v<object, std::decay_t<T>>, "T must be derived from object");
"T must be derived from object");
setattr(*this, key, std::forward<T>(value)); setattr(*this, key, std::forward<T>(value));
return *this; 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)); 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)); 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)); return attr_accessor(reinterpret_borrow<object>(*this), std::move(name));
} }
class item_accessor : public object { class item_accessor : public object {
public: public:
object key; object key;
public: public:
template <typename T> template <typename T>
item_accessor(const object& obj, T&& key) : object(obj), key(std::forward<T>(key)){}; item_accessor(const object& obj, T&& key) : object(obj), key(std::forward<T>(key)){};
template <typename T> template <typename T>
item_accessor& operator= (T&& value) & { item_accessor& operator= (T&& value) & {
static_assert(std::is_base_of_v<object, std::decay_t<T>>, static_assert(std::is_base_of_v<object, std::decay_t<T>>, "T must be derived from object");
"T must be derived from object");
m_ptr = std::forward<T>(value); m_ptr = std::forward<T>(value);
} }
template <typename T> template <typename T>
item_accessor& operator= (object&& value) && { item_accessor& operator= (object&& value) && {
static_assert(std::is_base_of_v<object, std::decay_t<T>>, static_assert(std::is_base_of_v<object, std::decay_t<T>>, "T must be derived from object");
"T must be derived from object");
setitem(*this, key, std::forward<T>(value)); 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)); 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)); 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)); 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)); return item_accessor(reinterpret_borrow<object>(*this), std::move(key));
} }
class args : public tuple { class args : public tuple {
using tuple::tuple; using tuple::tuple;
}; };
class kwargs : public dict { class kwargs : public dict {
using dict::dict; using dict::dict;
}; };
template <typename T> template <typename T>
handle type::handle_of() { handle type::handle_of() {
if constexpr(std::is_same_v<T, object>) { if constexpr(std::is_same_v<T, object>) { return vm->_t(vm->tp_object); }
return vm->_t(vm->tp_object);
}
#define PYBIND11_TYPE_MAPPER(type, tp) \ #define PYBIND11_TYPE_MAPPER(type, tp) \
else if constexpr(std::is_same_v<T, type>) { \ else if constexpr(std::is_same_v<T, type>) { return vm->_t(vm->tp); }
return vm->_t(vm->tp); \
}
PYBIND11_TYPE_MAPPER(type, tp_type) PYBIND11_TYPE_MAPPER(type, tp_type)
PYBIND11_TYPE_MAPPER(str, tp_str) PYBIND11_TYPE_MAPPER(str, tp_str)
PYBIND11_TYPE_MAPPER(int_, tp_int) PYBIND11_TYPE_MAPPER(int_, tp_int)
@ -207,12 +199,10 @@ namespace pybind11 {
#undef PYBIND11_TYPE_MAPPER #undef PYBIND11_TYPE_MAPPER
else { else {
auto result = vm->_cxx_typeid_map.find(typeid(T)); auto result = vm->_cxx_typeid_map.find(typeid(T));
if(result != vm->_cxx_typeid_map.end()) { if(result != vm->_cxx_typeid_map.end()) { return vm->_t(result->second); }
return vm->_t(result->second);
}
vm->TypeError("Type not registered"); vm->TypeError("Type not registered");
} }
} }
} // namespace pybind11 } // namespace pybind11

View File

@ -16,7 +16,7 @@ def get_all_files(root: str):
if __name__ == '__main__': if __name__ == '__main__':
files = [] files = []
# files.extend(get_all_files('include')) files.extend(get_all_files('include'))
# files.extend(get_all_files('src')) files.extend(get_all_files('src'))
files.extend(get_all_files('src2')) files.extend(get_all_files('src2'))
subprocess.run(['clang-format', '-i'] + files, check=True) subprocess.run(['clang-format', '-i'] + files, check=True)

View File

@ -3,20 +3,20 @@
#include <stdexcept> #include <stdexcept>
#include <cstdio> #include <cstdio>
namespace pkpy{ namespace pkpy {
void any::__bad_any_cast(const std::type_index expected, const std::type_index actual){ void any::__bad_any_cast(const std::type_index expected, const std::type_index actual) {
char error[256]; char error[256];
snprintf(error, sizeof(error), "bad_any_cast: expected %s, got %s", expected.name(), actual.name()); snprintf(error, sizeof(error), "bad_any_cast: expected %s, got %s", expected.name(), actual.name());
throw std::runtime_error(error); throw std::runtime_error(error);
} }
any::any(any&& other) noexcept: data(other.data), _vt(other._vt){ any::any(any&& other) noexcept : data(other.data), _vt(other._vt) {
other.data = nullptr; other.data = nullptr;
other._vt = nullptr; other._vt = nullptr;
} }
any& any::operator=(any&& other) noexcept{ any& any::operator= (any&& other) noexcept {
if(data) _vt->deleter(data); if(data) _vt->deleter(data);
data = other.data; data = other.data;
_vt = other._vt; _vt = other._vt;

View File

@ -6,28 +6,28 @@
#include <cassert> #include <cassert>
#include <stdexcept> #include <stdexcept>
namespace pkpy{ namespace pkpy {
struct LinkedListNode{ struct LinkedListNode {
LinkedListNode* prev; LinkedListNode* prev;
LinkedListNode* next; LinkedListNode* next;
}; };
template<typename T> template <typename T>
struct DoubleLinkedList{ struct DoubleLinkedList {
static_assert(std::is_base_of_v<LinkedListNode, T>); static_assert(std::is_base_of_v<LinkedListNode, T>);
int _size; int _size;
LinkedListNode head; LinkedListNode head;
LinkedListNode tail; LinkedListNode tail;
DoubleLinkedList(): _size(0){ DoubleLinkedList() : _size(0) {
head.prev = nullptr; head.prev = nullptr;
head.next = &tail; head.next = &tail;
tail.prev = &head; tail.prev = &head;
tail.next = nullptr; tail.next = nullptr;
} }
void push_back(T* node){ void push_back(T* node) {
node->prev = tail.prev; node->prev = tail.prev;
node->next = &tail; node->next = &tail;
tail.prev->next = node; tail.prev->next = node;
@ -35,7 +35,7 @@ struct DoubleLinkedList{
_size++; _size++;
} }
void push_front(T* node){ void push_front(T* node) {
node->prev = &head; node->prev = &head;
node->next = head.next; node->next = head.next;
head.next->prev = node; head.next->prev = node;
@ -43,14 +43,14 @@ struct DoubleLinkedList{
_size++; _size++;
} }
void pop_back(){ void pop_back() {
assert(!empty()); assert(!empty());
tail.prev->prev->next = &tail; tail.prev->prev->next = &tail;
tail.prev = tail.prev->prev; tail.prev = tail.prev->prev;
_size--; _size--;
} }
void pop_front(){ void pop_front() {
assert(!empty()); assert(!empty());
head.next->next->prev = &head; head.next->next->prev = &head;
head.next = head.next->next; head.next = head.next->next;
@ -67,22 +67,20 @@ struct DoubleLinkedList{
return static_cast<T*>(head.next); return static_cast<T*>(head.next);
} }
void erase(T* node){ void erase(T* node) {
node->prev->next = node->next; node->prev->next = node->next;
node->next->prev = node->prev; node->next->prev = node->prev;
_size--; _size--;
} }
bool empty() const { bool empty() const { return _size == 0; }
return _size == 0;
}
int size() const { return _size; } int size() const { return _size; }
template<typename Func> template <typename Func>
void apply(Func func){ void apply(Func func) {
LinkedListNode* p = head.next; LinkedListNode* p = head.next;
while(p != &tail){ while(p != &tail) {
LinkedListNode* next = p->next; LinkedListNode* next = p->next;
func(static_cast<T*>(p)); func(static_cast<T*>(p));
p = next; p = next;
@ -90,42 +88,41 @@ struct DoubleLinkedList{
} }
}; };
template<int __BlockSize> template <int __BlockSize>
struct MemoryPool{ struct MemoryPool {
static const int __MaxBlocks = 256*1024 / __BlockSize; const static int __MaxBlocks = 256 * 1024 / __BlockSize;
static const int __MinArenaCount = PK_GC_MIN_THRESHOLD*100 / (256*1024); const static int __MinArenaCount = PK_GC_MIN_THRESHOLD * 100 / (256 * 1024);
struct Block{ struct Block {
void* arena; void* arena;
char data[__BlockSize]; char data[__BlockSize];
}; };
struct Arena: LinkedListNode{ struct Arena : LinkedListNode {
Block _blocks[__MaxBlocks]; Block _blocks[__MaxBlocks];
Block* _free_list[__MaxBlocks]; Block* _free_list[__MaxBlocks];
int _free_list_size; int _free_list_size;
Arena(): _free_list_size(__MaxBlocks) { Arena() : _free_list_size(__MaxBlocks) {
for(int i=0; i<__MaxBlocks; i++){ for(int i = 0; i < __MaxBlocks; i++) {
_blocks[i].arena = this; _blocks[i].arena = this;
_free_list[i] = &_blocks[i]; _free_list[i] = &_blocks[i];
} }
} }
bool empty() const { return _free_list_size == 0; } bool empty() const { return _free_list_size == 0; }
bool full() const { return _free_list_size == __MaxBlocks; } bool full() const { return _free_list_size == __MaxBlocks; }
size_t allocated_size() const{ size_t allocated_size() const { return __BlockSize * (__MaxBlocks - _free_list_size); }
return __BlockSize * (__MaxBlocks - _free_list_size);
}
Block* alloc(){ Block* alloc() {
assert(!empty()); assert(!empty());
_free_list_size--; _free_list_size--;
return _free_list[_free_list_size]; return _free_list[_free_list_size];
} }
void dealloc(Block* block){ void dealloc(Block* block) {
assert(!full()); assert(!full());
_free_list[_free_list_size] = block; _free_list[_free_list_size] = block;
_free_list_size++; _free_list_size++;
@ -134,71 +131,73 @@ struct MemoryPool{
MemoryPool() = default; MemoryPool() = default;
MemoryPool(const MemoryPool&) = delete; MemoryPool(const MemoryPool&) = delete;
MemoryPool& operator=(const MemoryPool&) = delete; MemoryPool& operator= (const MemoryPool&) = delete;
MemoryPool(MemoryPool&&) = delete; MemoryPool(MemoryPool&&) = delete;
MemoryPool& operator=(MemoryPool&&) = delete; MemoryPool& operator= (MemoryPool&&) = delete;
DoubleLinkedList<Arena> _arenas; DoubleLinkedList<Arena> _arenas;
DoubleLinkedList<Arena> _empty_arenas; DoubleLinkedList<Arena> _empty_arenas;
void* alloc(size_t size){ void* alloc(size_t size) {
PK_GLOBAL_SCOPE_LOCK(); PK_GLOBAL_SCOPE_LOCK();
if(size > __BlockSize){ if(size > __BlockSize) {
void* p = std::malloc(sizeof(void*) + size); void* p = std::malloc(sizeof(void*) + size);
std::memset(p, 0, sizeof(void*)); std::memset(p, 0, sizeof(void*));
return (char*)p + sizeof(void*); return (char*)p + sizeof(void*);
} }
if(_arenas.empty()){ if(_arenas.empty()) { _arenas.push_back(new Arena()); }
_arenas.push_back(new Arena());
}
Arena* arena = _arenas.back(); Arena* arena = _arenas.back();
void* p = arena->alloc()->data; void* p = arena->alloc()->data;
if(arena->empty()){ if(arena->empty()) {
_arenas.pop_back(); _arenas.pop_back();
_empty_arenas.push_back(arena); _empty_arenas.push_back(arena);
} }
return p; return p;
} }
void dealloc(void* p){ void dealloc(void* p) {
PK_GLOBAL_SCOPE_LOCK(); PK_GLOBAL_SCOPE_LOCK();
assert(p != nullptr); assert(p != nullptr);
Block* block = (Block*)((char*)p - sizeof(void*)); Block* block = (Block*)((char*)p - sizeof(void*));
if(block->arena == nullptr){ if(block->arena == nullptr) {
std::free(block); std::free(block);
}else{ } else {
Arena* arena = (Arena*)block->arena; Arena* arena = (Arena*)block->arena;
if(arena->empty()){ if(arena->empty()) {
_empty_arenas.erase(arena); _empty_arenas.erase(arena);
_arenas.push_front(arena); _arenas.push_front(arena);
arena->dealloc(block); arena->dealloc(block);
}else{ } else {
arena->dealloc(block); arena->dealloc(block);
} }
} }
} }
void shrink_to_fit(){ void shrink_to_fit() {
PK_GLOBAL_SCOPE_LOCK(); PK_GLOBAL_SCOPE_LOCK();
if(_arenas.size() < __MinArenaCount) return; if(_arenas.size() < __MinArenaCount) return;
_arenas.apply([this](Arena* arena){ _arenas.apply([this](Arena* arena) {
if(arena->full()){ if(arena->full()) {
_arenas.erase(arena); _arenas.erase(arena);
delete arena; delete arena;
} }
}); });
} }
~MemoryPool(){ ~MemoryPool() {
_arenas.apply([](Arena* arena){ delete arena; }); _arenas.apply([](Arena* arena) {
_empty_arenas.apply([](Arena* arena){ delete arena; }); delete arena;
});
_empty_arenas.apply([](Arena* arena) {
delete arena;
});
} }
}; };
template<int BlockSize, int BlockCount> template <int BlockSize, int BlockCount>
struct FixedMemoryPool{ struct FixedMemoryPool {
struct Block{ struct Block {
char data[BlockSize]; char data[BlockSize];
}; };
@ -211,31 +210,29 @@ struct FixedMemoryPool{
FixedMemoryPool() { FixedMemoryPool() {
_free_list_end = _free_list + BlockCount; _free_list_end = _free_list + BlockCount;
for(int i = 0; i < BlockCount; ++i){ for(int i = 0; i < BlockCount; ++i) {
_free_list[i] = _blocks + i; _free_list[i] = _blocks + i;
} }
} }
bool is_valid(void* p){ bool is_valid(void* p) { return p >= _blocks && p < _blocks + BlockCount; }
return p >= _blocks && p < _blocks + BlockCount;
}
void* alloc(){ void* alloc() {
PK_GLOBAL_SCOPE_LOCK() PK_GLOBAL_SCOPE_LOCK()
if(_free_list_end != _free_list){ if(_free_list_end != _free_list) {
--_free_list_end; --_free_list_end;
return *_free_list_end; return *_free_list_end;
}else{ } else {
return std::malloc(BlockSize); return std::malloc(BlockSize);
} }
} }
void dealloc(void* p){ void dealloc(void* p) {
PK_GLOBAL_SCOPE_LOCK() PK_GLOBAL_SCOPE_LOCK()
if(is_valid(p)){ if(is_valid(p)) {
*_free_list_end = static_cast<Block*>(p); *_free_list_end = static_cast<Block*>(p);
++_free_list_end; ++_free_list_end;
}else{ } else {
std::free(p); std::free(p);
} }
} }
@ -246,12 +243,17 @@ static FixedMemoryPool<kPoolFrameBlockSize, 128> PoolFrame;
static MemoryPool<80> PoolObject; static MemoryPool<80> PoolObject;
void* PoolExpr_alloc() noexcept { return PoolExpr.alloc(); } void* PoolExpr_alloc() noexcept { return PoolExpr.alloc(); }
void PoolExpr_dealloc(void* p) noexcept { PoolExpr.dealloc(p); } void PoolExpr_dealloc(void* p) noexcept { PoolExpr.dealloc(p); }
void* PoolFrame_alloc() noexcept { return PoolFrame.alloc(); } void* PoolFrame_alloc() noexcept { return PoolFrame.alloc(); }
void PoolFrame_dealloc(void* p) noexcept { PoolFrame.dealloc(p); } void PoolFrame_dealloc(void* p) noexcept { PoolFrame.dealloc(p); }
void* PoolObject_alloc(size_t size) noexcept { return PoolObject.alloc(size); } void* PoolObject_alloc(size_t size) noexcept { return PoolObject.alloc(size); }
void PoolObject_dealloc(void* p) noexcept { PoolObject.dealloc(p); } void PoolObject_dealloc(void* p) noexcept { PoolObject.dealloc(p); }
void PoolObject_shrink_to_fit() noexcept { PoolObject.shrink_to_fit(); } void PoolObject_shrink_to_fit() noexcept { PoolObject.shrink_to_fit(); }
} // namespace pkpy } // namespace pkpy

View File

@ -8,7 +8,7 @@
namespace pkpy { namespace pkpy {
int utf8len(unsigned char c, bool suppress){ int utf8len(unsigned char c, bool suppress) {
if((c & 0b10000000) == 0) return 1; if((c & 0b10000000) == 0) return 1;
if((c & 0b11100000) == 0b11000000) return 2; if((c & 0b11100000) == 0b11000000) return 2;
if((c & 0b11110000) == 0b11100000) return 3; if((c & 0b11110000) == 0b11100000) return 3;
@ -20,89 +20,78 @@ int utf8len(unsigned char c, bool suppress){
} }
#define PK_STR_ALLOCATE() \ #define PK_STR_ALLOCATE() \
if(this->size < (int)sizeof(this->_inlined)){ \ if(this->size < (int)sizeof(this->_inlined)) { \
this->data = this->_inlined; \ this->data = this->_inlined; \
}else{ \ } else { \
this->data = (char*)std::malloc(this->size+1); \ this->data = (char*)std::malloc(this->size + 1); \
} }
#define PK_STR_COPY_INIT(__s) \ #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]; \ this->data[i] = __s[i]; \
if(!isascii(__s[i])) is_ascii = false; \ if(!isascii(__s[i])) is_ascii = false; \
} \ } \
this->data[this->size] = '\0'; this->data[this->size] = '\0';
Str::Str(): size(0), is_ascii(true), data(_inlined) { Str::Str() : size(0), is_ascii(true), data(_inlined) { _inlined[0] = '\0'; }
_inlined[0] = '\0';
}
Str::Str(int size, bool is_ascii): size(size), is_ascii(is_ascii) { Str::Str(int size, bool is_ascii) :
PK_STR_ALLOCATE() size(size), is_ascii(is_ascii){PK_STR_ALLOCATE()}
}
Str::Str(const std::string& s): size(s.size()), is_ascii(true) { Str::Str(const std::string& s) :
PK_STR_ALLOCATE() size(s.size()), is_ascii(true){PK_STR_ALLOCATE() PK_STR_COPY_INIT(s)}
PK_STR_COPY_INIT(s)
}
Str::Str(std::string_view s): size(s.size()), is_ascii(true) { Str::Str(std::string_view s) :
PK_STR_ALLOCATE() size(s.size()), is_ascii(true){PK_STR_ALLOCATE() PK_STR_COPY_INIT(s)}
PK_STR_COPY_INIT(s)
}
Str::Str(const char* s): size(strlen(s)), is_ascii(true) { Str::Str(const char* s) :
PK_STR_ALLOCATE() size(strlen(s)), is_ascii(true){PK_STR_ALLOCATE() PK_STR_COPY_INIT(s)}
PK_STR_COPY_INIT(s)
}
Str::Str(const char* s, int len): size(len), is_ascii(true) { Str::Str(const char* s, int len) :
PK_STR_ALLOCATE() size(len), is_ascii(true){PK_STR_ALLOCATE() PK_STR_COPY_INIT(s)}
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; this->data = detached.first;
for(int i=0; i<size; i++){ for(int i = 0; i < size; i++) {
if(!isascii(data[i])){ is_ascii = false; break; } if(!isascii(data[i])) {
is_ascii = false;
break;
}
} }
assert(data[size] == '\0'); 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() PK_STR_ALLOCATE()
std::memcpy(data, other.data, size); std::memcpy(data, other.data, size);
data[size] = '\0'; data[size] = '\0';
} }
Str::Str(Str&& other): size(other.size), is_ascii(other.is_ascii) { Str::Str(Str&& other) : size(other.size), is_ascii(other.is_ascii) {
if(other.is_inlined()){ if(other.is_inlined()) {
data = _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'; data[size] = '\0';
}else{ } else {
data = other.data; data = other.data;
// zero out `other` // zero out `other`
other.data = other._inlined; other.data = other._inlined;
other.data[0] = '\0'; other.data[0] = '\0';
other.size = 0; other.size = 0;
} }
} }
Str operator+(const char* p, const Str& str){ Str operator+ (const char* p, const Str& str) {
Str other(p); Str other(p);
return other + str; return other + str;
} }
std::ostream& operator<<(std::ostream& os, const Str& str){ std::ostream& operator<< (std::ostream& os, const Str& str) { return os << str.sv(); }
return os << str.sv();
}
bool operator<(const std::string_view other, const Str& str){ bool operator< (const std::string_view other, const Str& str) { return other < str.sv(); }
return other < str.sv();
}
Str& Str::operator=(const Str& other){ Str& Str::operator= (const Str& other) {
if(!is_inlined()) std::free(data); if(!is_inlined()) std::free(data);
size = other.size; size = other.size;
is_ascii = other.is_ascii; is_ascii = other.is_ascii;
@ -110,141 +99,129 @@ int utf8len(unsigned char c, bool suppress){
std::memcpy(data, other.data, size); std::memcpy(data, other.data, size);
data[size] = '\0'; data[size] = '\0';
return *this; 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); Str ret(size + other.size, is_ascii && other.is_ascii);
std::memcpy(ret.data, data, size); std::memcpy(ret.data, data, size);
std::memcpy(ret.data + size, other.data, other.size); std::memcpy(ret.data + size, other.data, other.size);
ret.data[ret.size] = '\0'; ret.data[ret.size] = '\0';
return ret; return ret;
} }
Str Str::operator+(const char* p) const { Str Str::operator+ (const char* p) const {
Str other(p); Str other(p);
return *this + other; return *this + other;
} }
bool Str::operator==(const Str& other) const { bool Str::operator== (const Str& other) const {
if(size != other.size) return false; if(size != other.size) return false;
return memcmp(data, other.data, size) == 0; 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; if(size != other.size) return true;
return memcmp(data, other.data, size) != 0; 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; if(size != (int)other.size()) return false;
return memcmp(data, other.data(), size) == 0; 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; if(size != (int)other.size()) return true;
return memcmp(data, other.data(), size) != 0; return memcmp(data, other.data(), size) != 0;
} }
bool Str::operator==(const char* p) const { bool Str::operator== (const char* p) const { return *this == std::string_view(p); }
return *this == std::string_view(p);
}
bool Str::operator!=(const char* p) const { bool Str::operator!= (const char* p) const { return *this != std::string_view(p); }
return *this != std::string_view(p);
}
bool Str::operator<(const Str& other) const { bool Str::operator< (const Str& other) const { return this->sv() < other.sv(); }
return this->sv() < other.sv();
}
bool Str::operator<(const std::string_view other) const { bool Str::operator< (const std::string_view other) const { return this->sv() < other; }
return this->sv() < other;
}
bool Str::operator>(const Str& other) const { bool Str::operator> (const Str& other) const { return this->sv() > other.sv(); }
return this->sv() > other.sv();
}
bool Str::operator<=(const Str& other) const { bool Str::operator<= (const Str& other) const { return this->sv() <= other.sv(); }
return this->sv() <= other.sv();
}
bool Str::operator>=(const Str& other) const { bool Str::operator>= (const Str& other) const { return this->sv() >= other.sv(); }
return this->sv() >= other.sv();
}
Str::~Str(){ Str::~Str() {
if(!is_inlined()) std::free(data); 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); Str ret(len, is_ascii);
std::memcpy(ret.data, data + start, len); std::memcpy(ret.data, data + start, len);
ret.data[len] = '\0'; ret.data[len] = '\0';
return ret; return ret;
} }
Str Str::substr(int start) const { Str Str::substr(int start) const { return substr(start, size - start); }
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 L = 0;
int R = u8_length(); int R = u8_length();
if(left){ if(left) {
while(L < R && chars.index(u8_getitem(L)) != -1) L++; while(L < R && chars.index(u8_getitem(L)) != -1)
L++;
} }
if(right){ if(right) {
while(L < R && chars.index(u8_getitem(R-1)) != -1) R--; while(L < R && chars.index(u8_getitem(R - 1)) != -1)
R--;
} }
return u8_slice(L, R, 1); return u8_slice(L, R, 1);
} }
Str Str::strip(bool left, bool right) const { Str Str::strip(bool left, bool right) const {
if(is_ascii){ if(is_ascii) {
int L = 0; int L = 0;
int R = size; int R = size;
if(left){ if(left) {
while(L < R && (data[L] == ' ' || data[L] == '\t' || data[L] == '\n' || data[L] == '\r')) L++; while(L < R && (data[L] == ' ' || data[L] == '\t' || data[L] == '\n' || data[L] == '\r'))
L++;
} }
if(right){ if(right) {
while(L < R && (data[R-1] == ' ' || data[R-1] == '\t' || data[R-1] == '\n' || data[R-1] == '\r')) R--; while(L < R && (data[R - 1] == ' ' || data[R - 1] == '\t' || data[R - 1] == '\n' || data[R - 1] == '\r'))
R--;
} }
return substr(L, R - L); return substr(L, R - L);
}else{ } else {
return strip(left, right, " \t\n\r"); return strip(left, right, " \t\n\r");
} }
} }
Str Str::lower() const{ Str Str::lower() const {
std::string copy(data, size); 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'); if('A' <= c && c <= 'Z') return c + ('a' - 'A');
return (int)c; return (int)c;
}); });
return Str(copy); return Str(copy);
} }
Str Str::upper() const{ Str Str::upper() const {
std::string copy(data, size); 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'); if('a' <= c && c <= 'z') return c - ('a' - 'A');
return (int)c; return (int)c;
}); });
return Str(copy); return Str(copy);
} }
Str Str::escape(bool single_quote) const{ Str Str::escape(bool single_quote) const {
SStream ss; SStream ss;
escape_(ss, single_quote); escape_(ss, single_quote);
return ss.str(); return ss.str();
} }
void Str::escape_(SStream& ss, bool single_quote) const { void Str::escape_(SStream& ss, bool single_quote) const {
ss << (single_quote ? '\'' : '"'); ss << (single_quote ? '\'' : '"');
for (int i=0; i<length(); i++) { for(int i = 0; i < length(); i++) {
char c = this->operator[](i); char c = this->operator[] (i);
switch (c) { switch(c) {
case '"': case '"':
if(!single_quote) ss << '\\'; if(!single_quote) ss << '\\';
ss << '"'; ss << '"';
@ -259,7 +236,7 @@ int utf8len(unsigned char c, bool suppress){
case '\t': ss << "\\t"; break; case '\t': ss << "\\t"; break;
case '\b': ss << "\\b"; break; case '\b': ss << "\\b"; break;
default: default:
if ('\x00' <= c && c <= '\x1f') { if('\x00' <= c && c <= '\x1f') {
ss << "\\x"; // << std::hex << std::setw(2) << std::setfill('0') << (int)c; ss << "\\x"; // << std::hex << std::setw(2) << std::setfill('0') << (int)c;
ss << PK_HEX_TABLE[c >> 4]; ss << PK_HEX_TABLE[c >> 4];
ss << PK_HEX_TABLE[c & 0xf]; ss << PK_HEX_TABLE[c & 0xf];
@ -269,26 +246,26 @@ int utf8len(unsigned char c, bool suppress){
} }
} }
ss << (single_quote ? '\'' : '"'); 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); auto p = std::search(data + start, data + size, sub.data, sub.data + sub.size);
if(p == data + size) return -1; if(p == data + size) return -1;
return p - data; return p - data;
} }
Str Str::replace(char old, char new_) const{ Str Str::replace(char old, char new_) const {
Str copied = *this; 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_; if(copied.data[i] == old) copied.data[i] = new_;
} }
return copied; 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; SStream ss;
int start = 0; int start = 0;
while(true){ while(true) {
int i = index(old, start); int i = index(old, start);
if(i == -1) break; if(i == -1) break;
ss << substr(start, i - start); ss << substr(start, i - start);
@ -298,52 +275,49 @@ int utf8len(unsigned char c, bool suppress){
} }
ss << substr(start, size - start); ss << substr(start, size - start);
return ss.str(); 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; if(is_ascii) return i;
int j = 0; int j = 0;
while(i > 0){ while(i > 0) {
j += utf8len(data[j]); j += utf8len(data[j]);
i--; i--;
} }
return j; 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; if(is_ascii) return n;
int cnt = 0; int cnt = 0;
for(int i=0; i<n; i++){ for(int i = 0; i < n; i++) {
if((data[i] & 0xC0) != 0x80) cnt++; if((data[i] & 0xC0) != 0x80) cnt++;
} }
return cnt; return cnt;
} }
Str Str::u8_getitem(int i) const{ Str Str::u8_getitem(int i) const {
i = _unicode_index_to_byte(i); i = _unicode_index_to_byte(i);
return substr(i, utf8len(data[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; SStream ss;
if(is_ascii){ if(is_ascii) {
PK_SLICE_LOOP(i, start, stop, step) ss << data[i]; PK_SLICE_LOOP(i, start, stop, step) ss << data[i];
}else{ } else {
PK_SLICE_LOOP(i, start, stop, step) ss << u8_getitem(i); PK_SLICE_LOOP(i, start, stop, step) ss << u8_getitem(i);
} }
return ss.str(); return ss.str();
} }
int Str::u8_length() const { int Str::u8_length() const { return _byte_index_to_unicode(size); }
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; vector<std::string_view> result;
std::string_view tmp; std::string_view tmp;
int start = 0; int start = 0;
while(true){ while(true) {
int i = index(sep, start); int i = index(sep, start);
if(i == -1) break; if(i == -1) break;
tmp = sv().substr(start, i - start); tmp = sv().substr(start, i - start);
@ -353,53 +327,53 @@ int utf8len(unsigned char c, bool suppress){
tmp = sv().substr(start, size - start); tmp = sv().substr(start, size - start);
if(!tmp.empty()) result.push_back(tmp); if(!tmp.empty()) result.push_back(tmp);
return result; return result;
} }
vector<std::string_view> Str::split(char sep) const{ vector<std::string_view> Str::split(char sep) const {
vector<std::string_view> result; vector<std::string_view> result;
int i = 0; int i = 0;
for(int j = 0; j < size; j++){ for(int j = 0; j < size; j++) {
if(data[j] == sep){ if(data[j] == sep) {
if(j > i) result.emplace_back(data+i, j-i); if(j > i) result.emplace_back(data + i, j - i);
i = j + 1; i = j + 1;
continue; continue;
} }
} }
if(size > i) result.emplace_back(data+i, size-i); if(size > i) result.emplace_back(data + i, size - i);
return result; return result;
} }
int Str::count(const Str& sub) const{ int Str::count(const Str& sub) const {
if(sub.empty()) return size + 1; if(sub.empty()) return size + 1;
int cnt = 0; int cnt = 0;
int start = 0; int start = 0;
while(true){ while(true) {
int i = index(sub, start); int i = index(sub, start);
if(i == -1) break; if(i == -1) break;
cnt++; cnt++;
start = i + sub.size; start = i + sub.size;
} }
return cnt; return cnt;
} }
std::map<std::string_view, uint16_t>& StrName::_interned(){ std::map<std::string_view, uint16_t>& StrName::_interned() {
static std::map<std::string_view, uint16_t> interned; static std::map<std::string_view, uint16_t> interned;
return interned; return interned;
} }
std::map<uint16_t, std::string>& StrName::_r_interned(){ std::map<uint16_t, std::string>& StrName::_r_interned() {
static std::map<uint16_t, std::string> r_interned; static std::map<uint16_t, std::string> r_interned;
return r_interned; return r_interned;
} }
uint32_t StrName::_pesudo_random_index = 0; uint32_t StrName::_pesudo_random_index = 0;
StrName StrName::get(std::string_view s){ StrName StrName::get(std::string_view s) {
auto it = _interned().find(s); auto it = _interned().find(s);
if(it != _interned().end()) return StrName(it->second); if(it != _interned().end()) return StrName(it->second);
// generate new index // generate new index
// https://github.com/python/cpython/blob/3.12/Objects/dictobject.c#L175 // https://github.com/python/cpython/blob/3.12/Objects/dictobject.c#L175
uint16_t index = ((_pesudo_random_index*5) + 1) & 65535; uint16_t index = ((_pesudo_random_index * 5) + 1) & 65535;
if(index == 0) throw std::runtime_error("StrName index overflow"); if(index == 0) throw std::runtime_error("StrName index overflow");
auto res = _r_interned().emplace(index, s); auto res = _r_interned().emplace(index, s);
assert(res.second); assert(res.second);
@ -407,143 +381,137 @@ int utf8len(unsigned char c, bool suppress){
_interned()[s] = index; _interned()[s] = index;
_pesudo_random_index = index; _pesudo_random_index = index;
return StrName(index); return StrName(index);
} }
Str SStream::str(){ Str SStream::str() {
// after this call, the buffer is no longer valid // after this call, the buffer is no longer valid
buffer.reserve(buffer.size() + 1); // allocate one more byte for '\0' buffer.reserve(buffer.size() + 1); // allocate one more byte for '\0'
buffer[buffer.size()] = '\0'; // set '\0' buffer[buffer.size()] = '\0'; // set '\0'
return Str(buffer.detach()); return Str(buffer.detach());
} }
SStream& SStream::operator<<(const Str& s){ SStream& SStream::operator<< (const Str& s) {
for(char c: s) buffer.push_back(c); for(char c: s)
return *this;
}
SStream& SStream::operator<<(const char* s){
while(*s) buffer.push_back(*s++);
return *this;
}
SStream& SStream::operator<<(const std::string& s){
for(char c: s) buffer.push_back(c);
return *this;
}
SStream& SStream::operator<<(std::string_view s){
for(char c: s) buffer.push_back(c);
return *this;
}
SStream& SStream::operator<<(char c){
buffer.push_back(c); buffer.push_back(c);
return *this; return *this;
} }
SStream& SStream::operator<<(StrName sn){ SStream& SStream::operator<< (const char* s) {
return *this << sn.sv(); 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 // size_t could be out of range of `i64`, use `std::to_string` instead
return (*this) << std::to_string(val); return (*this) << std::to_string(val);
} }
SStream& SStream::operator<<(int val){ SStream& SStream::operator<< (int val) { return (*this) << static_cast<i64>(val); }
return (*this) << static_cast<i64>(val);
}
SStream& SStream::operator<<(i64 val){ SStream& SStream::operator<< (i64 val) {
// str(-2**64).__len__() == 21 // str(-2**64).__len__() == 21
buffer.reserve(buffer.size() + 24); buffer.reserve(buffer.size() + 24);
if(val == 0){ if(val == 0) {
buffer.push_back('0'); buffer.push_back('0');
return *this; return *this;
} }
if(val < 0){ if(val < 0) {
buffer.push_back('-'); buffer.push_back('-');
val = -val; val = -val;
} }
auto begin = buffer.end(); auto begin = buffer.end();
while(val){ while(val) {
buffer.push_back('0' + val % 10); buffer.push_back('0' + val % 10);
val /= 10; val /= 10;
} }
std::reverse(begin, buffer.end()); std::reverse(begin, buffer.end());
return *this; return *this;
} }
SStream& SStream::operator<<(f64 val){ SStream& SStream::operator<< (f64 val) {
if(std::isinf(val)){ if(std::isinf(val)) { return (*this) << (val > 0 ? "inf" : "-inf"); }
return (*this) << (val > 0 ? "inf" : "-inf"); if(std::isnan(val)) { return (*this) << "nan"; }
}
if(std::isnan(val)){
return (*this) << "nan";
}
char b[32]; char b[32];
if(_precision == -1){ if(_precision == -1) {
int prec = std::numeric_limits<f64>::max_digits10-1; int prec = std::numeric_limits<f64>::max_digits10 - 1;
snprintf(b, sizeof(b), "%.*g", prec, val); snprintf(b, sizeof(b), "%.*g", prec, val);
}else{ } else {
int prec = _precision; int prec = _precision;
snprintf(b, sizeof(b), "%.*f", prec, val); snprintf(b, sizeof(b), "%.*f", prec, val);
} }
(*this) << b; (*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; 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 high = c >> 4;
unsigned char low = c & 0xf; unsigned char low = c & 0xf;
if(non_zero){ if(non_zero) {
if(high) (*this) << PK_HEX_TABLE[high]; if(high) (*this) << PK_HEX_TABLE[high];
if(high || low) (*this) << PK_HEX_TABLE[low]; if(high || low) (*this) << PK_HEX_TABLE[low];
}else{ } else {
(*this) << PK_HEX_TABLE[high]; (*this) << PK_HEX_TABLE[high];
(*this) << PK_HEX_TABLE[low]; (*this) << PK_HEX_TABLE[low];
} }
} }
void SStream::write_hex(void* p){ void SStream::write_hex(void* p) {
if(p == nullptr){ if(p == nullptr) {
(*this) << "0x0"; (*this) << "0x0";
return; return;
} }
(*this) << "0x"; (*this) << "0x";
uintptr_t p_t = reinterpret_cast<uintptr_t>(p); uintptr_t p_t = reinterpret_cast<uintptr_t>(p);
bool non_zero = true; 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; unsigned char cpnt = (p_t >> (i * 8)) & 0xff;
write_hex(cpnt, non_zero); write_hex(cpnt, non_zero);
if(cpnt != 0) non_zero = false; if(cpnt != 0) non_zero = false;
} }
} }
void SStream::write_hex(i64 val){ void SStream::write_hex(i64 val) {
if(val == 0){ if(val == 0) {
(*this) << "0x0"; (*this) << "0x0";
return; return;
} }
if(val < 0){ if(val < 0) {
(*this) << "-"; (*this) << "-";
val = -val; val = -val;
} }
(*this) << "0x"; (*this) << "0x";
bool non_zero = true; 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; unsigned char cpnt = (val >> i) & 0xff;
write_hex(cpnt, non_zero); write_hex(cpnt, non_zero);
if(cpnt != 0) non_zero = false; if(cpnt != 0) non_zero = false;
} }
} }
#undef PK_STR_ALLOCATE #undef PK_STR_ALLOCATE
#undef PK_STR_COPY_INIT #undef PK_STR_COPY_INIT
// unary operators // unary operators
const StrName __repr__ = StrName::get("__repr__"); const StrName __repr__ = StrName::get("__repr__");
const StrName __str__ = StrName::get("__str__"); const StrName __str__ = StrName::get("__str__");
@ -601,5 +569,4 @@ const StrName pk_id_set = StrName::get("set");
const StrName pk_id_long = StrName::get("long"); const StrName pk_id_long = StrName::get("long");
const StrName pk_id_complex = StrName::get("complex"); const StrName pk_id_complex = StrName::get("complex");
} // namespace pkpy } // namespace pkpy

File diff suppressed because it is too large Load Diff

View File

@ -1,108 +1,109 @@
#include "pocketpy/compiler/expr.hpp" #include "pocketpy/compiler/expr.hpp"
#include "pocketpy/interpreter/vm.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(s.empty()) return false;
if(!isalpha(s[0]) && s[0] != '_') 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; return true;
} }
inline bool is_small_int(i64 value){ inline bool is_small_int(i64 value) { return value >= INT16_MIN && value <= INT16_MAX; }
return value >= INT16_MIN && value <= INT16_MAX;
}
int CodeEmitContext::get_loop() const { int CodeEmitContext::get_loop() const {
int index = curr_iblock; 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::FOR_LOOP) break;
if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) break; if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) break;
index = co->blocks[index].parent; index = co->blocks[index].parent;
} }
return index; 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())); 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]; return &co->blocks[curr_iblock];
} }
void CodeEmitContext::exit_block(){ void CodeEmitContext::exit_block() {
auto curr_type = co->blocks[curr_iblock].type; auto curr_type = co->blocks[curr_iblock].type;
co->blocks[curr_iblock].end = co->codes.size(); co->blocks[curr_iblock].end = co->codes.size();
curr_iblock = co->blocks[curr_iblock].parent; curr_iblock = co->blocks[curr_iblock].parent;
assert(curr_iblock >= 0); 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 // add a no op here to make block check work
emit_(OP_NO_OP, BC_NOARG, BC_KEEPLINE, true); emit_(OP_NO_OP, BC_NOARG, BC_KEEPLINE, true);
} }
} }
// clear the expression stack and generate bytecode // clear the expression stack and generate bytecode
void CodeEmitContext::emit_expr(){ void CodeEmitContext::emit_expr() {
assert(s_expr.size() == 1); assert(s_expr.size() == 1);
Expr_ expr = s_expr.popx(); Expr_ expr = s_expr.popx();
expr->emit_(this); 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->codes.push_back(Bytecode{(uint8_t)opcode, arg});
co->lines.push_back(CodeObject::LineInfo{line, is_virtual, curr_iblock}); co->lines.push_back(CodeObject::LineInfo{line, is_virtual, curr_iblock});
int i = co->codes.size() - 1; int i = co->codes.size() - 1;
if(line == BC_KEEPLINE){ if(line == BC_KEEPLINE) {
if(i >= 1) co->lines[i].lineno = co->lines[i-1].lineno; if(i >= 1)
else co->lines[i].lineno = 1; co->lines[i].lineno = co->lines[i - 1].lineno;
else
co->lines[i].lineno = 1;
} }
return i; return i;
} }
void CodeEmitContext::revert_last_emit_(){ void CodeEmitContext::revert_last_emit_() {
co->codes.pop_back(); co->codes.pop_back();
co->lines.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_?, ] // [FOR_ITER, STORE_?, ]
if(co->codes[i].op != OP_FOR_ITER) return; if(co->codes[i].op != OP_FOR_ITER) return;
if(co->codes.size() - i != 2) return; if(co->codes.size() - i != 2) return;
uint16_t arg = co->codes[i+1].arg; uint16_t arg = co->codes[i + 1].arg;
if(co->codes[i+1].op == OP_STORE_FAST){ if(co->codes[i + 1].op == OP_STORE_FAST) {
revert_last_emit_(); revert_last_emit_();
co->codes[i].op = OP_FOR_ITER_STORE_FAST; co->codes[i].op = OP_FOR_ITER_STORE_FAST;
co->codes[i].arg = arg; co->codes[i].arg = arg;
return; return;
} }
if(co->codes[i+1].op == OP_STORE_GLOBAL){ if(co->codes[i + 1].op == OP_STORE_GLOBAL) {
revert_last_emit_(); revert_last_emit_();
co->codes[i].op = OP_FOR_ITER_STORE_GLOBAL; co->codes[i].op = OP_FOR_ITER_STORE_GLOBAL;
co->codes[i].arg = arg; co->codes[i].arg = arg;
return; return;
} }
} }
int CodeEmitContext::emit_int(i64 value, int line){ int CodeEmitContext::emit_int(i64 value, int line) {
if(is_small_int(value)){ if(is_small_int(value)) {
return emit_(OP_LOAD_SMALL_INT, (uint16_t)value, line); return emit_(OP_LOAD_SMALL_INT, (uint16_t)value, line);
}else{ } else {
return emit_(OP_LOAD_CONST, add_const(VAR(value)), line); 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(); 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; if(co->labels.contains(name)) return false;
co->labels.set(name, co->codes.size()); co->labels.set(name, co->codes.size());
return true; 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 // PK_MAX_CO_VARNAMES will be checked when pop_context(), not here
int index = co->varnames_inv.try_get(name); int index = co->varnames_inv.try_get(name);
if(index >= 0) return index; if(index >= 0) return index;
@ -111,191 +112,178 @@ namespace pkpy{
index = co->varnames.size() - 1; index = co->varnames.size() - 1;
co->varnames_inv.set(name, index); co->varnames_inv.set(name, index);
return 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); 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; return it->second;
}else{ } else {
co->consts.push_back(VAR(key)); co->consts.push_back(VAR(key));
int index = co->consts.size() - 1; int index = co->consts.size() - 1;
key = co->consts.back().obj_get<Str>().sv(); key = co->consts.back().obj_get<Str>().sv();
_co_consts_string_dedup_map[key] = index; _co_consts_string_dedup_map[key] = index;
return index; return index;
} }
} }
int CodeEmitContext::add_const(PyVar v){ int CodeEmitContext::add_const(PyVar v) {
assert(!is_type(v, VM::tp_str)); assert(!is_type(v, VM::tp_str));
// non-string deduplication // non-string deduplication
auto it = _co_consts_nonstring_dedup_map.find(v); 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; return it->second;
}else{ } else {
co->consts.push_back(v); co->consts.push_back(v);
int index = co->consts.size() - 1; int index = co->consts.size() - 1;
_co_consts_nonstring_dedup_map[v] = index; _co_consts_nonstring_dedup_map[v] = index;
return index; return index;
} }
} }
int CodeEmitContext::add_func_decl(FuncDecl_ decl){ int CodeEmitContext::add_func_decl(FuncDecl_ decl) {
co->func_decls.push_back(decl); co->func_decls.push_back(decl);
return co->func_decls.size() - 1; return co->func_decls.size() - 1;
} }
void CodeEmitContext::emit_store_name(NameScope scope, StrName name, int line){ void CodeEmitContext::emit_store_name(NameScope scope, StrName name, int line) {
switch(scope){ switch(scope) {
case NAME_LOCAL: case NAME_LOCAL: emit_(OP_STORE_FAST, add_varname(name), line); break;
emit_(OP_STORE_FAST, add_varname(name), line); case NAME_GLOBAL: emit_(OP_STORE_GLOBAL, StrName(name).index, line); break;
break; case NAME_GLOBAL_UNKNOWN: emit_(OP_STORE_NAME, StrName(name).index, 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; default: assert(false); break;
} }
} }
void NameExpr::emit_(CodeEmitContext* ctx) {
void NameExpr::emit_(CodeEmitContext* ctx) {
int index = ctx->co->varnames_inv.try_get(name); 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); ctx->emit_(OP_LOAD_FAST, index, line);
}else{ } else {
Opcode op = ctx->level <= 1 ? OP_LOAD_GLOBAL : OP_LOAD_NONLOCAL; 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 // if we are compiling a class, we should use OP_LOAD_ATTR_GLOBAL instead of OP_LOAD_GLOBAL
// this supports @property.setter // this supports @property.setter
op = OP_LOAD_CLASS_GLOBAL; op = OP_LOAD_CLASS_GLOBAL;
// exec()/eval() won't work with OP_LOAD_ATTR_GLOBAL in class body // exec()/eval() won't work with OP_LOAD_ATTR_GLOBAL in class body
}else{ } else {
// we cannot determine the scope when calling exec()/eval() // we cannot determine the scope when calling exec()/eval()
if(scope == NAME_GLOBAL_UNKNOWN) op = OP_LOAD_NAME; if(scope == NAME_GLOBAL_UNKNOWN) op = OP_LOAD_NAME;
} }
ctx->emit_(op, StrName(name).index, line); ctx->emit_(op, StrName(name).index, line);
} }
} }
bool NameExpr::emit_del(CodeEmitContext* ctx) { bool NameExpr::emit_del(CodeEmitContext* ctx) {
switch(scope){ switch(scope) {
case NAME_LOCAL: case NAME_LOCAL: ctx->emit_(OP_DELETE_FAST, ctx->add_varname(name), line); break;
ctx->emit_(OP_DELETE_FAST, ctx->add_varname(name), line); case NAME_GLOBAL: ctx->emit_(OP_DELETE_GLOBAL, StrName(name).index, line); break;
break; case NAME_GLOBAL_UNKNOWN: ctx->emit_(OP_DELETE_NAME, StrName(name).index, 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; default: assert(false); break;
} }
return true; return true;
} }
bool NameExpr::emit_store(CodeEmitContext* ctx) { bool NameExpr::emit_store(CodeEmitContext* ctx) {
if(ctx->is_compiling_class){ if(ctx->is_compiling_class) {
ctx->emit_(OP_STORE_CLASS_ATTR, name.index, line); ctx->emit_(OP_STORE_CLASS_ATTR, name.index, line);
return true; return true;
} }
ctx->emit_store_name(scope, name, line); ctx->emit_store_name(scope, name, line);
return true; return true;
} }
void InvertExpr::emit_(CodeEmitContext* ctx) { void InvertExpr::emit_(CodeEmitContext* ctx) {
child->emit_(ctx); child->emit_(ctx);
ctx->emit_(OP_UNARY_INVERT, BC_NOARG, line); ctx->emit_(OP_UNARY_INVERT, BC_NOARG, line);
} }
void StarredExpr::emit_(CodeEmitContext* ctx) { void StarredExpr::emit_(CodeEmitContext* ctx) {
child->emit_(ctx); child->emit_(ctx);
ctx->emit_(OP_UNARY_STAR, level, line); ctx->emit_(OP_UNARY_STAR, level, line);
} }
bool StarredExpr::emit_store(CodeEmitContext* ctx) { bool StarredExpr::emit_store(CodeEmitContext* ctx) {
if(level != 1) return false; if(level != 1) return false;
// simply proxy to child // simply proxy to child
return child->emit_store(ctx); return child->emit_store(ctx);
} }
void NotExpr::emit_(CodeEmitContext* ctx) { void NotExpr::emit_(CodeEmitContext* ctx) {
child->emit_(ctx); child->emit_(ctx);
ctx->emit_(OP_UNARY_NOT, BC_NOARG, line); ctx->emit_(OP_UNARY_NOT, BC_NOARG, line);
} }
void AndExpr::emit_(CodeEmitContext* ctx) { void AndExpr::emit_(CodeEmitContext* ctx) {
lhs->emit_(ctx); lhs->emit_(ctx);
int patch = ctx->emit_(OP_JUMP_IF_FALSE_OR_POP, BC_NOARG, line); int patch = ctx->emit_(OP_JUMP_IF_FALSE_OR_POP, BC_NOARG, line);
rhs->emit_(ctx); rhs->emit_(ctx);
ctx->patch_jump(patch); ctx->patch_jump(patch);
} }
void OrExpr::emit_(CodeEmitContext* ctx) { void OrExpr::emit_(CodeEmitContext* ctx) {
lhs->emit_(ctx); lhs->emit_(ctx);
int patch = ctx->emit_(OP_JUMP_IF_TRUE_OR_POP, BC_NOARG, line); int patch = ctx->emit_(OP_JUMP_IF_TRUE_OR_POP, BC_NOARG, line);
rhs->emit_(ctx); rhs->emit_(ctx);
ctx->patch_jump(patch); ctx->patch_jump(patch);
} }
void Literal0Expr::emit_(CodeEmitContext* ctx){ void Literal0Expr::emit_(CodeEmitContext* ctx) {
switch (token) { switch(token) {
case TK("None"): ctx->emit_(OP_LOAD_NONE, BC_NOARG, line); break; 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("True"): ctx->emit_(OP_LOAD_TRUE, BC_NOARG, line); break;
case TK("False"): ctx->emit_(OP_LOAD_FALSE, 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; case TK("..."): ctx->emit_(OP_LOAD_ELLIPSIS, BC_NOARG, line); break;
default: assert(false); 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_LOAD_CONST, ctx->add_const_string(s.sv()), line);
ctx->emit_(OP_BUILD_LONG, BC_NOARG, line); ctx->emit_(OP_BUILD_LONG, BC_NOARG, line);
} }
void ImagExpr::emit_(CodeEmitContext* ctx) { void ImagExpr::emit_(CodeEmitContext* ctx) {
VM* vm = ctx->vm; VM* vm = ctx->vm;
ctx->emit_(OP_LOAD_CONST, ctx->add_const(VAR(value)), line); ctx->emit_(OP_LOAD_CONST, ctx->add_const(VAR(value)), line);
ctx->emit_(OP_BUILD_IMAG, BC_NOARG, 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_LOAD_CONST, ctx->add_const_string(s.sv()), line);
ctx->emit_(OP_BUILD_BYTES, BC_NOARG, line); ctx->emit_(OP_BUILD_BYTES, BC_NOARG, line);
} }
void LiteralExpr::emit_(CodeEmitContext* ctx) { void LiteralExpr::emit_(CodeEmitContext* ctx) {
VM* vm = ctx->vm; VM* vm = ctx->vm;
if(std::holds_alternative<i64>(value)){ if(std::holds_alternative<i64>(value)) {
i64 _val = std::get<i64>(value); i64 _val = std::get<i64>(value);
ctx->emit_int(_val, line); ctx->emit_int(_val, line);
return; return;
} }
if(std::holds_alternative<f64>(value)){ if(std::holds_alternative<f64>(value)) {
f64 _val = std::get<f64>(value); f64 _val = std::get<f64>(value);
ctx->emit_(OP_LOAD_CONST, ctx->add_const(VAR(_val)), line); ctx->emit_(OP_LOAD_CONST, ctx->add_const(VAR(_val)), line);
return; return;
} }
if(std::holds_alternative<Str>(value)){ if(std::holds_alternative<Str>(value)) {
std::string_view key = std::get<Str>(value).sv(); std::string_view key = std::get<Str>(value).sv();
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(key), line); ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(key), line);
return; return;
} }
} }
void NegatedExpr::emit_(CodeEmitContext* ctx){ void NegatedExpr::emit_(CodeEmitContext* ctx) {
VM* vm = ctx->vm; VM* vm = ctx->vm;
// if child is a int of float, do constant folding // 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()); 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); i64 _val = -std::get<i64>(lit->value);
ctx->emit_int(_val, line); ctx->emit_int(_val, line);
return; return;
} }
if(std::holds_alternative<f64>(lit->value)){ if(std::holds_alternative<f64>(lit->value)) {
f64 _val = -std::get<f64>(lit->value); f64 _val = -std::get<f64>(lit->value);
ctx->emit_(OP_LOAD_CONST, ctx->add_const(VAR(_val)), line); ctx->emit_(OP_LOAD_CONST, ctx->add_const(VAR(_val)), line);
return; return;
@ -303,91 +291,92 @@ namespace pkpy{
} }
child->emit_(ctx); child->emit_(ctx);
ctx->emit_(OP_UNARY_NEGATIVE, BC_NOARG, line); ctx->emit_(OP_UNARY_NEGATIVE, BC_NOARG, line);
} }
void SliceExpr::emit_(CodeEmitContext* ctx) {
void SliceExpr::emit_(CodeEmitContext* ctx){ if(start) {
if(start){
start->emit_(ctx); start->emit_(ctx);
}else{ } else {
ctx->emit_(OP_LOAD_NONE, BC_NOARG, line); ctx->emit_(OP_LOAD_NONE, BC_NOARG, line);
} }
if(stop){ if(stop) {
stop->emit_(ctx); stop->emit_(ctx);
}else{ } else {
ctx->emit_(OP_LOAD_NONE, BC_NOARG, line); ctx->emit_(OP_LOAD_NONE, BC_NOARG, line);
} }
if(step){ if(step) {
step->emit_(ctx); step->emit_(ctx);
}else{ } else {
ctx->emit_(OP_LOAD_NONE, BC_NOARG, line); ctx->emit_(OP_LOAD_NONE, BC_NOARG, line);
} }
ctx->emit_(OP_BUILD_SLICE, BC_NOARG, line); ctx->emit_(OP_BUILD_SLICE, BC_NOARG, line);
} }
void DictItemExpr::emit_(CodeEmitContext* ctx) { void DictItemExpr::emit_(CodeEmitContext* ctx) {
if(is_starred()){ if(is_starred()) {
assert(key == nullptr); assert(key == nullptr);
value->emit_(ctx); value->emit_(ctx);
}else{ } else {
value->emit_(ctx); value->emit_(ctx);
key->emit_(ctx); // reverse order key->emit_(ctx); // reverse order
ctx->emit_(OP_BUILD_TUPLE, 2, line); ctx->emit_(OP_BUILD_TUPLE, 2, line);
} }
} }
bool TupleExpr::emit_store(CodeEmitContext* ctx) { bool TupleExpr::emit_store(CodeEmitContext* ctx) {
// TOS is an iterable // TOS is an iterable
// items may contain StarredExpr, we should check it // items may contain StarredExpr, we should check it
int starred_i = -1; 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(!items[i]->is_starred()) continue;
if(starred_i == -1) starred_i = i; if(starred_i == -1)
else return false; // multiple StarredExpr not allowed starred_i = i;
else
return false; // multiple StarredExpr not allowed
} }
if(starred_i == -1){ if(starred_i == -1) {
Bytecode& prev = ctx->co->codes.back(); 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 // build tuple and unpack it is meaningless
ctx->revert_last_emit_(); ctx->revert_last_emit_();
}else{ } else {
if(prev.op == OP_FOR_ITER){ if(prev.op == OP_FOR_ITER) {
prev.op = OP_FOR_ITER_UNPACK; prev.op = OP_FOR_ITER_UNPACK;
prev.arg = items.size(); prev.arg = items.size();
}else{ } else {
ctx->emit_(OP_UNPACK_SEQUENCE, items.size(), line); ctx->emit_(OP_UNPACK_SEQUENCE, items.size(), line);
} }
} }
}else{ } else {
// starred assignment target must be in a tuple // starred assignment target must be in a tuple
if(items.size() == 1) return false; if(items.size() == 1) return false;
// starred assignment target must be the last one (differ from cpython) // 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] // a,*b = [1,2,3]
// stack is [1,2,3] -> [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 // 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); bool ok = items[i]->emit_store(ctx);
if(!ok) return false; if(!ok) return false;
} }
return true; return true;
} }
bool TupleExpr::emit_del(CodeEmitContext* ctx){ bool TupleExpr::emit_del(CodeEmitContext* ctx) {
for(auto& e: items){ for(auto& e: items) {
bool ok = e->emit_del(ctx); bool ok = e->emit_del(ctx);
if(!ok) return false; if(!ok) return false;
} }
return true; return true;
} }
void CompExpr::emit_(CodeEmitContext* ctx){ void CompExpr::emit_(CodeEmitContext* ctx) {
ctx->emit_(op0(), 0, line); ctx->emit_(op0(), 0, line);
iter->emit_(ctx); iter->emit_(ctx);
ctx->emit_(OP_GET_ITER, BC_NOARG, BC_KEEPLINE); 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 // this error occurs in `vars` instead of this line, but...nevermind
assert(ok); // this should raise a SyntaxError, but we just assert it assert(ok); // this should raise a SyntaxError, but we just assert it
ctx->try_merge_for_iter_store(for_codei); ctx->try_merge_for_iter_store(for_codei);
if(cond){ if(cond) {
cond->emit_(ctx); cond->emit_(ctx);
int patch = ctx->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE); int patch = ctx->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, BC_KEEPLINE);
expr->emit_(ctx); expr->emit_(ctx);
ctx->emit_(op1(), BC_NOARG, BC_KEEPLINE); ctx->emit_(op1(), BC_NOARG, BC_KEEPLINE);
ctx->patch_jump(patch); ctx->patch_jump(patch);
}else{ } else {
expr->emit_(ctx); expr->emit_(ctx);
ctx->emit_(op1(), BC_NOARG, BC_KEEPLINE); ctx->emit_(op1(), BC_NOARG, BC_KEEPLINE);
} }
ctx->emit_(OP_LOOP_CONTINUE, curr_iblock, BC_KEEPLINE); ctx->emit_(OP_LOOP_CONTINUE, curr_iblock, BC_KEEPLINE);
ctx->exit_block(); ctx->exit_block();
} }
void FStringExpr::_load_simple_expr(CodeEmitContext* ctx, Str expr) {
void FStringExpr::_load_simple_expr(CodeEmitContext* ctx, Str expr){
bool repr = false; bool repr = false;
if(expr.size>=2 && expr.end()[-2]=='!'){ if(expr.size >= 2 && expr.end()[-2] == '!') {
switch(expr.end()[-1]){ switch(expr.end()[-1]) {
case 'r': repr = true; expr = expr.substr(0, expr.size-2); break; case 'r':
case 's': repr = false; expr = expr.substr(0, expr.size-2); break; 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 default: break; // nothing happens
} }
} }
// name or name.name // name or name.name
bool is_fastpath = false; bool is_fastpath = false;
if(is_identifier(expr.sv())){ if(is_identifier(expr.sv())) {
ctx->emit_(OP_LOAD_NAME, StrName(expr.sv()).index, line); ctx->emit_(OP_LOAD_NAME, StrName(expr.sv()).index, line);
is_fastpath = true; is_fastpath = true;
}else{ } else {
int dot = expr.index("."); int dot = expr.index(".");
if(dot > 0){ if(dot > 0) {
std::string_view a = expr.sv().substr(0, dot); std::string_view a = expr.sv().substr(0, dot);
std::string_view b = expr.sv().substr(dot+1); std::string_view b = expr.sv().substr(dot + 1);
if(is_identifier(a) && is_identifier(b)){ if(is_identifier(a) && is_identifier(b)) {
ctx->emit_(OP_LOAD_NAME, StrName(a).index, line); ctx->emit_(OP_LOAD_NAME, StrName(a).index, line);
ctx->emit_(OP_LOAD_ATTR, StrName(b).index, line); ctx->emit_(OP_LOAD_ATTR, StrName(b).index, line);
is_fastpath = true; is_fastpath = true;
@ -440,88 +434,93 @@ namespace pkpy{
} }
} }
if(!is_fastpath){ if(!is_fastpath) {
int index = ctx->add_const_string(expr.sv()); int index = ctx->add_const_string(expr.sv());
ctx->emit_(OP_FSTRING_EVAL, index, line); ctx->emit_(OP_FSTRING_EVAL, index, line);
} }
if(repr){ if(repr) { ctx->emit_(OP_REPR, BC_NOARG, line); }
ctx->emit_(OP_REPR, BC_NOARG, line); }
}
}
static bool is_fmt_valid_char(char c){ static bool is_fmt_valid_char(char c) {
switch(c){ switch(c) {
// clang-format off
case '-': case '=': case '*': case '#': case '@': case '!': case '~': case '-': case '=': case '*': case '#': case '@': case '!': case '~':
case '<': case '>': case '^': case '<': case '>': case '^':
case '.': case 'f': case 'd': case 's': 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': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
return true; return true;
default: return false; default: return false;
// clang-format on
} }
} }
void FStringExpr::emit_(CodeEmitContext* ctx){ void FStringExpr::emit_(CodeEmitContext* ctx) {
int i = 0; // left index int i = 0; // left index
int j = 0; // right index int j = 0; // right index
int count = 0; // how many string parts int count = 0; // how many string parts
bool flag = false; // true if we are in a expression bool flag = false; // true if we are in a expression
while(j < src.size){ while(j < src.size) {
if(flag){ if(flag) {
if(src[j] == '}'){ if(src[j] == '}') {
// add expression // 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:]}" // BUG: ':' is not a format specifier in f"{stack[2:]}"
int conon = expr.index(":"); int conon = expr.index(":");
if(conon >= 0){ if(conon >= 0) {
Str spec = expr.substr(conon+1); Str spec = expr.substr(conon + 1);
// filter some invalid spec // filter some invalid spec
bool ok = true; bool ok = true;
for(char c: spec) if(!is_fmt_valid_char(c)){ ok = false; break; } for(char c: spec)
if(ok){ if(!is_fmt_valid_char(c)) {
ok = false;
break;
}
if(ok) {
_load_simple_expr(ctx, expr.substr(0, conon)); _load_simple_expr(ctx, expr.substr(0, conon));
ctx->emit_(OP_FORMAT_STRING, ctx->add_const_string(spec.sv()), line); ctx->emit_(OP_FORMAT_STRING, ctx->add_const_string(spec.sv()), line);
}else{ } else {
// ':' is not a spec indicator // ':' is not a spec indicator
_load_simple_expr(ctx, expr); _load_simple_expr(ctx, expr);
} }
}else{ } else {
_load_simple_expr(ctx, expr); _load_simple_expr(ctx, expr);
} }
flag = false; flag = false;
count++; count++;
} }
}else{ } else {
if(src[j] == '{'){ if(src[j] == '{') {
// look at next char // look at next char
if(j+1 < src.size && src[j+1] == '{'){ if(j + 1 < src.size && src[j + 1] == '{') {
// {{ -> { // {{ -> {
j++; j++;
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string("{"), line); ctx->emit_(OP_LOAD_CONST, ctx->add_const_string("{"), line);
count++; count++;
}else{ } else {
// { -> } // { -> }
flag = true; flag = true;
i = j+1; i = j + 1;
} }
}else if(src[j] == '}'){ } else if(src[j] == '}') {
// look at next char // look at next char
if(j+1 < src.size && src[j+1] == '}'){ if(j + 1 < src.size && src[j + 1] == '}') {
// }} -> } // }} -> }
j++; j++;
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string("}"), line); ctx->emit_(OP_LOAD_CONST, ctx->add_const_string("}"), line);
count++; count++;
}else{ } else {
// } -> error // } -> error
// throw std::runtime_error("f-string: unexpected }"); // throw std::runtime_error("f-string: unexpected }");
// just ignore // just ignore
} }
}else{ } else {
// literal // literal
i = j; i = j;
while(j < src.size && src[j] != '{' && src[j] != '}') j++; while(j < src.size && src[j] != '{' && src[j] != '}')
Str literal = src.substr(i, j-i); j++;
Str literal = src.substr(i, j - i);
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(literal.sv()), line); ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(literal.sv()), line);
count++; count++;
continue; // skip j++ continue; // skip j++
@ -530,126 +529,128 @@ namespace pkpy{
j++; j++;
} }
if(flag){ if(flag) {
// literal // 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); ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(literal.sv()), line);
count++; count++;
} }
ctx->emit_(OP_BUILD_STRING, count, line); ctx->emit_(OP_BUILD_STRING, count, line);
} }
void SubscrExpr::emit_(CodeEmitContext* ctx) {
void SubscrExpr::emit_(CodeEmitContext* ctx){
a->emit_(ctx); a->emit_(ctx);
b->emit_(ctx); b->emit_(ctx);
Bytecode last_bc = ctx->co->codes.back(); 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->revert_last_emit_();
ctx->emit_(OP_LOAD_SUBSCR_FAST, last_bc.arg, line); 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->revert_last_emit_();
ctx->emit_(OP_LOAD_SUBSCR_SMALL_INT, last_bc.arg, line); ctx->emit_(OP_LOAD_SUBSCR_SMALL_INT, last_bc.arg, line);
}else{ } else {
ctx->emit_(OP_LOAD_SUBSCR, BC_NOARG, line); ctx->emit_(OP_LOAD_SUBSCR, BC_NOARG, line);
} }
} }
bool SubscrExpr::emit_store(CodeEmitContext* ctx){ bool SubscrExpr::emit_store(CodeEmitContext* ctx) {
a->emit_(ctx); a->emit_(ctx);
b->emit_(ctx); b->emit_(ctx);
Bytecode last_bc = ctx->co->codes.back(); 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->revert_last_emit_();
ctx->emit_(OP_STORE_SUBSCR_FAST, last_bc.arg, line); ctx->emit_(OP_STORE_SUBSCR_FAST, last_bc.arg, line);
}else{ } else {
ctx->emit_(OP_STORE_SUBSCR, BC_NOARG, line); ctx->emit_(OP_STORE_SUBSCR, BC_NOARG, line);
} }
return true; return true;
} }
void SubscrExpr::emit_inplace(CodeEmitContext* ctx){ void SubscrExpr::emit_inplace(CodeEmitContext* ctx) {
a->emit_(ctx); a->emit_(ctx);
b->emit_(ctx); b->emit_(ctx);
ctx->emit_(OP_DUP_TOP_TWO, BC_NOARG, line); ctx->emit_(OP_DUP_TOP_TWO, BC_NOARG, line);
ctx->emit_(OP_LOAD_SUBSCR, 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] // [a, b, val] -> [val, a, b]
ctx->emit_(OP_ROT_THREE, BC_NOARG, line); ctx->emit_(OP_ROT_THREE, BC_NOARG, line);
ctx->emit_(OP_STORE_SUBSCR, BC_NOARG, line); ctx->emit_(OP_STORE_SUBSCR, BC_NOARG, line);
return true; return true;
} }
bool SubscrExpr::emit_del(CodeEmitContext* ctx){ bool SubscrExpr::emit_del(CodeEmitContext* ctx) {
a->emit_(ctx); a->emit_(ctx);
b->emit_(ctx); b->emit_(ctx);
ctx->emit_(OP_DELETE_SUBSCR, BC_NOARG, line); ctx->emit_(OP_DELETE_SUBSCR, BC_NOARG, line);
return true; return true;
} }
void AttribExpr::emit_(CodeEmitContext* ctx){ void AttribExpr::emit_(CodeEmitContext* ctx) {
a->emit_(ctx); a->emit_(ctx);
ctx->emit_(OP_LOAD_ATTR, b.index, line); ctx->emit_(OP_LOAD_ATTR, b.index, line);
} }
bool AttribExpr::emit_del(CodeEmitContext* ctx) { bool AttribExpr::emit_del(CodeEmitContext* ctx) {
a->emit_(ctx); a->emit_(ctx);
ctx->emit_(OP_DELETE_ATTR, b.index, line); ctx->emit_(OP_DELETE_ATTR, b.index, line);
return true; return true;
} }
bool AttribExpr::emit_store(CodeEmitContext* ctx){ bool AttribExpr::emit_store(CodeEmitContext* ctx) {
a->emit_(ctx); a->emit_(ctx);
ctx->emit_(OP_STORE_ATTR, b.index, line); ctx->emit_(OP_STORE_ATTR, b.index, line);
return true; return true;
} }
void AttribExpr::emit_method(CodeEmitContext* ctx) { void AttribExpr::emit_method(CodeEmitContext* ctx) {
a->emit_(ctx); a->emit_(ctx);
ctx->emit_(OP_LOAD_METHOD, b.index, line); ctx->emit_(OP_LOAD_METHOD, b.index, line);
} }
void AttribExpr::emit_inplace(CodeEmitContext* ctx) { void AttribExpr::emit_inplace(CodeEmitContext* ctx) {
a->emit_(ctx); a->emit_(ctx);
ctx->emit_(OP_DUP_TOP, BC_NOARG, line); ctx->emit_(OP_DUP_TOP, BC_NOARG, line);
ctx->emit_(OP_LOAD_ATTR, b.index, 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] // [a, val] -> [val, a]
ctx->emit_(OP_ROT_TWO, BC_NOARG, line); ctx->emit_(OP_ROT_TWO, BC_NOARG, line);
ctx->emit_(OP_STORE_ATTR, b.index, line); ctx->emit_(OP_STORE_ATTR, b.index, line);
return true; return true;
} }
void CallExpr::emit_(CodeEmitContext* ctx) { void CallExpr::emit_(CodeEmitContext* ctx) {
bool vargs = false; bool vargs = false;
bool vkwargs = false; bool vkwargs = false;
for(auto& arg: args) if(arg->is_starred()) vargs = true; for(auto& arg: args)
for(auto& item: kwargs) if(item.second->is_starred()) vkwargs = true; 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 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()); auto p = static_cast<AttribExpr*>(callable.get());
p->emit_method(ctx); // OP_LOAD_METHOD p->emit_method(ctx); // OP_LOAD_METHOD
}else{ } else {
callable->emit_(ctx); callable->emit_(ctx);
ctx->emit_(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE); ctx->emit_(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE);
} }
if(vargs || vkwargs){ if(vargs || vkwargs) {
for(auto& item: args) item->emit_(ctx); for(auto& item: args)
item->emit_(ctx);
ctx->emit_(OP_BUILD_TUPLE_UNPACK, (uint16_t)args.size(), line); ctx->emit_(OP_BUILD_TUPLE_UNPACK, (uint16_t)args.size(), line);
if(!kwargs.empty()){ if(!kwargs.empty()) {
for(auto& item: kwargs){ for(auto& item: kwargs) {
if(item.second->is_starred()){ if(item.second->is_starred()) {
assert(item.second->star_level() == 2); assert(item.second->star_level() == 2);
item.second->emit_(ctx); item.second->emit_(ctx);
}else{ } else {
// k=v // k=v
int index = ctx->add_const_string(item.first.sv()); int index = ctx->add_const_string(item.first.sv());
ctx->emit_(OP_LOAD_CONST, index, line); 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_BUILD_DICT_UNPACK, (int)kwargs.size(), line);
ctx->emit_(OP_CALL_TP, 1, line); ctx->emit_(OP_CALL_TP, 1, line);
}else{ } else {
ctx->emit_(OP_CALL_TP, 0, line); ctx->emit_(OP_CALL_TP, 0, line);
} }
}else{ } else {
// vectorcall protocol // vectorcall protocol
for(auto& item: args) item->emit_(ctx); for(auto& item: args)
for(auto& item: kwargs){ item->emit_(ctx);
for(auto& item: kwargs) {
i64 _val = StrName(item.first.sv()).index; i64 _val = StrName(item.first.sv()).index;
ctx->emit_int(_val, line); ctx->emit_int(_val, line);
item.second->emit_(ctx); item.second->emit_(ctx);
} }
int KWARGC = kwargs.size(); int KWARGC = kwargs.size();
int ARGC = args.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 {
bool BinaryExpr::is_compare() const { switch(op) {
switch(op){ case TK("<"):
case TK("<"): case TK("<="): case TK("=="): case TK("<="):
case TK("!="): case TK(">"): case TK(">="): return true; case TK("=="):
case TK("!="):
case TK(">"):
case TK(">="): return true;
default: return false; default: return false;
} }
} }
void BinaryExpr::_emit_compare(CodeEmitContext* ctx, small_vector_2<int, 6>& jmps){ void BinaryExpr::_emit_compare(CodeEmitContext* ctx, small_vector_2<int, 6>& jmps) {
if(lhs->is_compare()){ if(lhs->is_compare()) {
static_cast<BinaryExpr*>(lhs.get())->_emit_compare(ctx, jmps); static_cast<BinaryExpr*>(lhs.get())->_emit_compare(ctx, jmps);
}else{ } else {
lhs->emit_(ctx); // [a] lhs->emit_(ctx); // [a]
} }
rhs->emit_(ctx); // [a, b] rhs->emit_(ctx); // [a, b]
ctx->emit_(OP_DUP_TOP, BC_NOARG, line); // [a, b, b] ctx->emit_(OP_DUP_TOP, BC_NOARG, line); // [a, b, b]
ctx->emit_(OP_ROT_THREE, BC_NOARG, line); // [b, a, 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_LT, BC_NOARG, line); break;
case TK("<="): ctx->emit_(OP_COMPARE_LE, 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; case TK("=="): ctx->emit_(OP_COMPARE_EQ, BC_NOARG, line); break;
@ -706,25 +711,25 @@ namespace pkpy{
// [b, RES] // [b, RES]
int index = ctx->emit_(OP_SHORTCUT_IF_FALSE_OR_POP, BC_NOARG, line); int index = ctx->emit_(OP_SHORTCUT_IF_FALSE_OR_POP, BC_NOARG, line);
jmps.push_back(index); jmps.push_back(index);
} }
void BinaryExpr::emit_(CodeEmitContext* ctx) { void BinaryExpr::emit_(CodeEmitContext* ctx) {
small_vector_2<int, 6> jmps; small_vector_2<int, 6> jmps;
if(is_compare() && lhs->is_compare()){ if(is_compare() && lhs->is_compare()) {
// (a < b) < c // (a < b) < c
static_cast<BinaryExpr*>(lhs.get())->_emit_compare(ctx, jmps); static_cast<BinaryExpr*>(lhs.get())->_emit_compare(ctx, jmps);
// [b, RES] // [b, RES]
}else{ } else {
// (1 + 2) < c // (1 + 2) < c
if(inplace){ if(inplace) {
lhs->emit_inplace(ctx); lhs->emit_inplace(ctx);
}else{ } else {
lhs->emit_(ctx); lhs->emit_(ctx);
} }
} }
rhs->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_ADD, BC_NOARG, line); break;
case TK("-"): ctx->emit_(OP_BINARY_SUB, 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; case TK("*"): ctx->emit_(OP_BINARY_MUL, BC_NOARG, line); break;
@ -755,10 +760,11 @@ namespace pkpy{
default: assert(false); 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); cond->emit_(ctx);
int patch = ctx->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, cond->line); int patch = ctx->emit_(OP_POP_JUMP_IF_FALSE, BC_NOARG, cond->line);
true_expr->emit_(ctx); true_expr->emit_(ctx);
@ -766,6 +772,6 @@ namespace pkpy{
ctx->patch_jump(patch); ctx->patch_jump(patch);
false_expr->emit_(ctx); false_expr->emit_(ctx);
ctx->patch_jump(patch_2); ctx->patch_jump(patch_2);
} }
} // namespace pkpy } // namespace pkpy

View File

@ -1,18 +1,22 @@
#include "pocketpy/compiler/lexer.hpp" #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 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}; 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){ static bool is_possible_number_char(char c) {
switch(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 '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 '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': case '.': case 'L': case 'x': case 'o': case 'j':
return true; return true;
default: return false; 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]; 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; 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 == '\0') return false;
if(*c != c0) return false; if(*c != c0) return false;
c++; c++;
} }
for(int i=0; i<n; i++) eatchar_include_newline(); for(int i = 0; i < n; i++)
eatchar_include_newline();
return true; return true;
} }
bool Lexer::match_string(const char* s){ bool Lexer::match_string(const char* s) {
int s_len = strlen(s); int s_len = strlen(s);
bool ok = strncmp(curr_char, s, s_len) == 0; 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; return ok;
} }
int Lexer::eat_spaces(){ int Lexer::eat_spaces() {
int count = 0; int count = 0;
while (true) { while(true) {
switch (peekchar()) { switch(peekchar()) {
case ' ' : count+=1; break; case ' ': count += 1; break;
case '\t': count+=4; break; case '\t': count += 4; break;
default: return count; default: return count;
} }
eatchar(); eatchar();
} }
} }
bool Lexer::eat_indentation(){ bool Lexer::eat_indentation() {
if(brackets_level > 0) return true; if(brackets_level > 0) return true;
int spaces = eat_spaces(); int spaces = eat_spaces();
if(peekchar() == '#') skip_line_comment(); if(peekchar() == '#') skip_line_comment();
if(peekchar() == '\0' || peekchar() == '\n') return true; if(peekchar() == '\0' || peekchar() == '\n') return true;
// https://docs.python.org/3/reference/lexical_analysis.html#indentation // https://docs.python.org/3/reference/lexical_analysis.html#indentation
if(spaces > indents.top()){ if(spaces > indents.top()) {
indents.push(spaces); indents.push(spaces);
nexts.push_back(Token{TK("@indent"), token_start, 0, current_line, brackets_level, {}}); nexts.push_back(Token{TK("@indent"), token_start, 0, current_line, brackets_level, {}});
} else if(spaces < indents.top()){ } else if(spaces < indents.top()) {
while(spaces < indents.top()){ while(spaces < indents.top()) {
indents.pop(); indents.pop();
nexts.push_back(Token{TK("@dedent"), token_start, 0, current_line, brackets_level, {}}); nexts.push_back(Token{TK("@dedent"), token_start, 0, current_line, brackets_level, {}});
} }
if(spaces != indents.top()){ if(spaces != indents.top()) { return false; }
return false;
}
} }
return true; return true;
} }
char Lexer::eatchar() { char Lexer::eatchar() {
char c = peekchar(); char c = peekchar();
assert(c != '\n'); // eatchar() cannot consume a newline assert(c != '\n'); // eatchar() cannot consume a newline
curr_char++; curr_char++;
return c; return c;
} }
char Lexer::eatchar_include_newline() { char Lexer::eatchar_include_newline() {
char c = peekchar(); char c = peekchar();
curr_char++; curr_char++;
if (c == '\n'){ if(c == '\n') {
current_line++; current_line++;
src->line_starts.push_back(curr_char); src->line_starts.push_back(curr_char);
} }
return c; return c;
} }
int Lexer::eat_name() { int Lexer::eat_name() {
curr_char--; curr_char--;
while(true){ while(true) {
unsigned char c = peekchar(); unsigned char c = peekchar();
int u8bytes = utf8len(c, true); int u8bytes = utf8len(c, true);
if(u8bytes == 0) return 1; if(u8bytes == 0) return 1;
if(u8bytes == 1){ if(u8bytes == 1) {
if(isalpha(c) || c=='_' || isdigit(c)) { if(isalpha(c) || c == '_' || isdigit(c)) {
curr_char++; curr_char++;
continue; continue;
}else{ } else {
break; break;
} }
} }
@ -112,30 +117,35 @@ static bool is_unicode_Lo_char(uint32_t c) {
Str u8str(curr_char, u8bytes); Str u8str(curr_char, u8bytes);
if(u8str.size != u8bytes) return 2; if(u8str.size != u8bytes) return 2;
uint32_t value = 0; uint32_t value = 0;
for(int k=0; k < u8bytes; k++){ for(int k = 0; k < u8bytes; k++) {
uint8_t b = u8str[k]; uint8_t b = u8str[k];
if(k==0){ if(k == 0) {
if(u8bytes == 2) value = (b & 0b00011111) << 6; if(u8bytes == 2)
else if(u8bytes == 3) value = (b & 0b00001111) << 12; value = (b & 0b00011111) << 6;
else if(u8bytes == 4) value = (b & 0b00000111) << 18; else if(u8bytes == 3)
}else{ value = (b & 0b00001111) << 12;
value |= (b & 0b00111111) << (6*(u8bytes-k-1)); 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; if(is_unicode_Lo_char(value))
else break; curr_char += u8bytes;
else
break;
} }
int length = (int)(curr_char - token_start); int length = (int)(curr_char - token_start);
if(length == 0) return 3; if(length == 0) return 3;
std::string_view name(token_start, length); std::string_view name(token_start, length);
if(src->mode == JSON_MODE){ if(src->mode == JSON_MODE) {
if(name == "true"){ if(name == "true") {
add_token(TK("True")); add_token(TK("True"));
} else if(name == "false"){ } else if(name == "false") {
add_token(TK("False")); add_token(TK("False"));
} else if(name == "null"){ } else if(name == "null") {
add_token(TK("None")); add_token(TK("None"));
} else { } else {
return 4; return 4;
@ -143,92 +153,95 @@ static bool is_unicode_Lo_char(uint32_t c) {
return 0; return 0;
} }
if(kTokenKwMap.count(name)){ if(kTokenKwMap.count(name)) {
add_token(kTokenKwMap.at(name)); add_token(kTokenKwMap.at(name));
} else { } else {
add_token(TK("@id")); add_token(TK("@id"));
} }
return 0; return 0;
} }
void Lexer::skip_line_comment() { void Lexer::skip_line_comment() {
char c; char c;
while ((c = peekchar()) != '\0') { while((c = peekchar()) != '\0') {
if (c == '\n') return; if(c == '\n') return;
eatchar(); eatchar();
} }
} }
bool Lexer::matchchar(char c) { bool Lexer::matchchar(char c) {
if (peekchar() != c) return false; if(peekchar() != c) return false;
eatchar_include_newline(); eatchar_include_newline();
return true; return true;
} }
void Lexer::add_token(TokenIndex type, TokenValue value) { void Lexer::add_token(TokenIndex type, TokenValue value) {
switch(type){ switch(type) {
case TK("{"): case TK("["): case TK("("): brackets_level++; break; case TK("{"):
case TK(")"): case TK("]"): case TK("}"): brackets_level--; break; case TK("["):
case TK("("): brackets_level++; break;
case TK(")"):
case TK("]"):
case TK("}"): brackets_level--; break;
} }
auto token = Token{ auto token = Token{type,
type,
token_start, token_start,
(int)(curr_char - token_start), (int)(curr_char - token_start),
current_line - ((type == TK("@eol")) ? 1 : 0), current_line - ((type == TK("@eol")) ? 1 : 0),
brackets_level, brackets_level,
value value};
};
// handle "not in", "is not", "yield from" // handle "not in", "is not", "yield from"
if(!nexts.empty()){ if(!nexts.empty()) {
auto& back = nexts.back(); 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"); back.type = TK("not in");
return; return;
} }
if(back.type == TK("is") && type == TK("not")){ if(back.type == TK("is") && type == TK("not")) {
back.type = TK("is not"); back.type = TK("is not");
return; return;
} }
if(back.type == TK("yield") && type == TK("from")){ if(back.type == TK("yield") && type == TK("from")) {
back.type = TK("yield from"); back.type = TK("yield from");
return; return;
} }
nexts.push_back(token); nexts.push_back(token);
} }
} }
void Lexer::add_token_2(char c, TokenIndex one, TokenIndex two) { void Lexer::add_token_2(char c, TokenIndex one, TokenIndex two) {
if (matchchar(c)) add_token(two); if(matchchar(c))
else add_token(one); 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); bool quote3 = match_n_chars(2, quote);
small_vector_2<char, 32> buff; small_vector_2<char, 32> buff;
while (true) { while(true) {
char c = eatchar_include_newline(); char c = eatchar_include_newline();
if (c == quote){ if(c == quote) {
if(quote3 && !match_n_chars(2, quote)){ if(quote3 && !match_n_chars(2, quote)) {
buff.push_back(c); buff.push_back(c);
continue; continue;
} }
break; break;
} }
if (c == '\0'){ if(c == '\0') {
if(quote3 && src->mode == REPL_MODE){ if(quote3 && src->mode == REPL_MODE) { throw NeedMoreLines(false); }
throw NeedMoreLines(false);
}
SyntaxError("EOL while scanning string literal"); SyntaxError("EOL while scanning string literal");
} }
if (c == '\n'){ if(c == '\n') {
if(!quote3) SyntaxError("EOL while scanning string literal"); if(!quote3)
else{ SyntaxError("EOL while scanning string literal");
else {
buff.push_back(c); buff.push_back(c);
continue; continue;
} }
} }
if (!raw && c == '\\') { if(!raw && c == '\\') {
switch (eatchar_include_newline()) { switch(eatchar_include_newline()) {
case '"': buff.push_back('"'); break; case '"': buff.push_back('"'); break;
case '\'': buff.push_back('\''); break; 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'}; char hex[3] = {eatchar(), eatchar(), '\0'};
size_t parsed; size_t parsed;
char code; char code;
try{ try {
code = (char)std::stoi(hex, &parsed, 16); code = (char)std::stoi(hex, &parsed, 16);
}catch(...){ } catch(...) { SyntaxError("invalid hex char"); }
SyntaxError("invalid hex char"); if(parsed != 2) SyntaxError("invalid hex char");
}
if (parsed != 2) SyntaxError("invalid hex char");
buff.push_back(code); buff.push_back(code);
} break; } break;
default: SyntaxError("invalid escape char"); default: SyntaxError("invalid escape char");
@ -255,83 +266,79 @@ static bool is_unicode_Lo_char(uint32_t c) {
} }
} }
return Str(buff.data(), buff.size()); 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); Str s = eat_string_until(quote, type == RAW_STRING);
if(type == F_STRING){ if(type == F_STRING) {
add_token(TK("@fstr"), s); add_token(TK("@fstr"), s);
return; return;
} }
if(type == NORMAL_BYTES){ if(type == NORMAL_BYTES) {
add_token(TK("@bytes"), s); add_token(TK("@bytes"), s);
return; return;
} }
add_token(TK("@str"), s); add_token(TK("@str"), s);
} }
void Lexer::eat_number() { void Lexer::eat_number() {
const char* i = token_start; const char* i = token_start;
while(is_possible_number_char(*i)) i++; while(is_possible_number_char(*i))
i++;
bool is_scientific_notation = false; bool is_scientific_notation = false;
if(*(i-1) == 'e' && (*i == '+' || *i == '-')){ if(*(i - 1) == 'e' && (*i == '+' || *i == '-')) {
i++;
while(isdigit(*i) || *i == 'j')
i++; i++;
while(isdigit(*i) || *i=='j') i++;
is_scientific_notation = true; is_scientific_notation = true;
} }
std::string_view text(token_start, i - token_start); std::string_view text(token_start, i - token_start);
this->curr_char = i; this->curr_char = i;
if(text[0] != '.' && !is_scientific_notation){ if(text[0] != '.' && !is_scientific_notation) {
// try long // try long
if(i[-1] == 'L'){ if(i[-1] == 'L') {
add_token(TK("@long")); add_token(TK("@long"));
return; return;
} }
// try integer // try integer
i64 int_out; i64 int_out;
switch(parse_uint(text, &int_out, -1)){ switch(parse_uint(text, &int_out, -1)) {
case IntParsingResult::Success: case IntParsingResult::Success: add_token(TK("@num"), int_out); return;
add_token(TK("@num"), int_out); case IntParsingResult::Overflow: SyntaxError("int literal is too large"); return;
return; case IntParsingResult::Failure: break; // do nothing
case IntParsingResult::Overflow:
SyntaxError("int literal is too large");
return;
case IntParsingResult::Failure:
break; // do nothing
} }
} }
// try float // try float
double float_out; double float_out;
char* p_end; char* p_end;
try{ try {
float_out = std::strtod(text.data(), &p_end); float_out = std::strtod(text.data(), &p_end);
}catch(...){ } catch(...) { SyntaxError("invalid number literal"); }
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); add_token(TK("@num"), (f64)float_out);
return; 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); add_token(TK("@imag"), (f64)float_out);
return; return;
} }
SyntaxError("invalid number literal"); SyntaxError("invalid number literal");
} }
bool Lexer::lex_one_token() { bool Lexer::lex_one_token() {
while (peekchar() != '\0') { while(peekchar() != '\0') {
token_start = curr_char; token_start = curr_char;
char c = eatchar_include_newline(); char c = eatchar_include_newline();
switch (c) { switch(c) {
case '\'': case '"': eat_string(c, NORMAL_STRING); return true; case '\'':
case '"': eat_string(c, NORMAL_STRING); return true;
case '#': skip_line_comment(); break; case '#': skip_line_comment(); break;
case '~': add_token(TK("~")); return true; case '~': add_token(TK("~")); return true;
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 '\\': { case '\\': {
// line continuation character // line continuation character
char c = eatchar_include_newline(); char c = eatchar_include_newline();
if (c != '\n'){ if(c != '\n') {
if(src->mode == REPL_MODE && c == '\0') throw NeedMoreLines(false); if(src->mode == REPL_MODE && c == '\0') throw NeedMoreLines(false);
SyntaxError("expected newline after line continuation character"); SyntaxError("expected newline after line continuation character");
} }
@ -367,9 +374,9 @@ static bool is_unicode_Lo_char(uint32_t c) {
} }
} else { } else {
char next_char = peekchar(); char next_char = peekchar();
if(next_char >= '0' && next_char <= '9'){ if(next_char >= '0' && next_char <= '9') {
eat_number(); eat_number();
}else{ } else {
add_token(TK(".")); 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 '=': add_token_2('=', TK("="), TK("==")); return true;
case '+': case '+':
if(matchchar('+')){ if(matchchar('+')) {
add_token(TK("++")); add_token(TK("++"));
}else{ } else {
add_token_2('=', TK("+"), TK("+=")); add_token_2('=', TK("+"), TK("+="));
} }
return true; return true;
case '>': { case '>': {
if(matchchar('=')) add_token(TK(">=")); if(matchchar('='))
else if(matchchar('>')) add_token_2('=', TK(">>"), TK(">>=")); add_token(TK(">="));
else add_token(TK(">")); else if(matchchar('>'))
add_token_2('=', TK(">>"), TK(">>="));
else
add_token(TK(">"));
return true; return true;
} }
case '<': { case '<': {
if(matchchar('=')) add_token(TK("<=")); if(matchchar('='))
else if(matchchar('<')) add_token_2('=', TK("<<"), TK("<<=")); add_token(TK("<="));
else add_token(TK("<")); else if(matchchar('<'))
add_token_2('=', TK("<<"), TK("<<="));
else
add_token(TK("<"));
return true; return true;
} }
case '-': { case '-': {
if(matchchar('-')){ if(matchchar('-')) {
add_token(TK("--")); add_token(TK("--"));
}else{ } else {
if(matchchar('=')) add_token(TK("-=")); if(matchchar('='))
else if(matchchar('>')) add_token(TK("->")); add_token(TK("-="));
else add_token(TK("-")); else if(matchchar('>'))
add_token(TK("->"));
else
add_token(TK("-"));
} }
return true; return true;
} }
case '!': case '!':
if(matchchar('=')) add_token(TK("!=")); if(matchchar('='))
else SyntaxError("expected '=' after '!'"); add_token(TK("!="));
else
SyntaxError("expected '=' after '!'");
break; break;
case '*': case '*':
if (matchchar('*')) { if(matchchar('*')) {
add_token(TK("**")); // '**' add_token(TK("**")); // '**'
} else { } else {
add_token_2('=', TK("*"), TK("*=")); add_token_2('=', TK("*"), TK("*="));
@ -423,29 +441,47 @@ static bool is_unicode_Lo_char(uint32_t c) {
add_token_2('=', TK("/"), TK("/=")); add_token_2('=', TK("/"), TK("/="));
} }
return true; return true;
case ' ': case '\t': eat_spaces(); break; case ' ':
case '\t': eat_spaces(); break;
case '\n': { case '\n': {
add_token(TK("@eol")); add_token(TK("@eol"));
if(!eat_indentation()) IndentationError("unindent does not match any outer indentation level"); if(!eat_indentation()) IndentationError("unindent does not match any outer indentation level");
return true; return true;
} }
default: { default: {
if(c == 'f'){ if(c == 'f') {
if(matchchar('\'')) {eat_string('\'', F_STRING); return true;} if(matchchar('\'')) {
if(matchchar('"')) {eat_string('"', F_STRING); return true;} eat_string('\'', F_STRING);
}else if(c == 'r'){ return true;
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') { 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(); eat_number();
return true; return true;
} }
switch (eat_name()) switch(eat_name()) {
{
case 0: break; case 0: break;
case 1: SyntaxError("invalid char: " + std::string(1, c)); break; case 1: SyntaxError("invalid char: " + std::string(1, c)); break;
case 2: SyntaxError("invalid utf8 sequence: " + 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; token_start = curr_char;
while(indents.size() > 1){ while(indents.size() > 1) {
indents.pop(); indents.pop();
add_token(TK("@dedent")); add_token(TK("@dedent"));
return true; return true;
} }
add_token(TK("@eof")); add_token(TK("@eof"));
return false; return false;
} }
void Lexer::throw_err(StrName type, Str msg){ void Lexer::throw_err(StrName type, Str msg) {
int lineno = current_line; int lineno = current_line;
const char* cursor = curr_char; const char* cursor = curr_char;
if(peekchar() == '\n'){ if(peekchar() == '\n') {
lineno--; lineno--;
cursor--; cursor--;
} }
throw_err(type, msg, 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->token_start = src->source.c_str();
this->curr_char = 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->nexts.push_back(Token{TK("@sof"), token_start, 0, current_line, brackets_level, {}});
this->indents.push(0); this->indents.push(0);
} }
vector<Token> Lexer::run() { vector<Token> Lexer::run() {
assert(curr_char == src->source.c_str()); assert(curr_char == src->source.c_str());
while (lex_one_token()); while(lex_one_token())
;
return std::move(nexts); 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; if(t.length() < 2) return false;
return t[0] == prefix[0] && t[1] == prefix[1]; 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; *out = 0;
if(base == -1){ if(base == -1) {
if(f_startswith_2(text, "0b")) base = 2; if(f_startswith_2(text, "0b"))
else if(f_startswith_2(text, "0o")) base = 8; base = 2;
else if(f_startswith_2(text, "0x")) base = 16; else if(f_startswith_2(text, "0o"))
else base = 10; base = 8;
else if(f_startswith_2(text, "0x"))
base = 16;
else
base = 10;
} }
if(base == 10){ if(base == 10) {
// 10-base 12334 // 10-base 12334
if(text.length() == 0) return IntParsingResult::Failure; if(text.length() == 0) return IntParsingResult::Failure;
for(char c : text){ for(char c: text) {
if(c >= '0' && c <= '9'){ if(c >= '0' && c <= '9') {
i64 prev_out = *out; i64 prev_out = *out;
*out = (*out * 10) + (c - '0'); *out = (*out * 10) + (c - '0');
if(*out < prev_out) return IntParsingResult::Overflow; if(*out < prev_out) return IntParsingResult::Overflow;
}else{ } else {
return IntParsingResult::Failure; return IntParsingResult::Failure;
} }
} }
return IntParsingResult::Success; return IntParsingResult::Success;
}else if(base == 2){ } else if(base == 2) {
// 2-base 0b101010 // 2-base 0b101010
if(f_startswith_2(text, "0b")) text.remove_prefix(2); if(f_startswith_2(text, "0b")) text.remove_prefix(2);
if(text.length() == 0) return IntParsingResult::Failure; if(text.length() == 0) return IntParsingResult::Failure;
for(char c : text){ for(char c: text) {
if(c == '0' || c == '1'){ if(c == '0' || c == '1') {
i64 prev_out = *out; i64 prev_out = *out;
*out = (*out << 1) | (c - '0'); *out = (*out << 1) | (c - '0');
if(*out < prev_out) return IntParsingResult::Overflow; if(*out < prev_out) return IntParsingResult::Overflow;
}else{ } else {
return IntParsingResult::Failure; return IntParsingResult::Failure;
} }
} }
return IntParsingResult::Success; return IntParsingResult::Success;
}else if(base == 8){ } else if(base == 8) {
// 8-base 0o123 // 8-base 0o123
if(f_startswith_2(text, "0o")) text.remove_prefix(2); if(f_startswith_2(text, "0o")) text.remove_prefix(2);
if(text.length() == 0) return IntParsingResult::Failure; if(text.length() == 0) return IntParsingResult::Failure;
for(char c : text){ for(char c: text) {
if(c >= '0' && c <= '7'){ if(c >= '0' && c <= '7') {
i64 prev_out = *out; i64 prev_out = *out;
*out = (*out << 3) | (c - '0'); *out = (*out << 3) | (c - '0');
if(*out < prev_out) return IntParsingResult::Overflow; if(*out < prev_out) return IntParsingResult::Overflow;
}else{ } else {
return IntParsingResult::Failure; return IntParsingResult::Failure;
} }
} }
return IntParsingResult::Success; return IntParsingResult::Success;
}else if(base == 16){ } else if(base == 16) {
// 16-base 0x123 // 16-base 0x123
if(f_startswith_2(text, "0x")) text.remove_prefix(2); if(f_startswith_2(text, "0x")) text.remove_prefix(2);
if(text.length() == 0) return IntParsingResult::Failure; if(text.length() == 0) return IntParsingResult::Failure;
for(char c : text){ for(char c: text) {
i64 prev_out = *out; i64 prev_out = *out;
if(c >= '0' && c <= '9'){ if(c >= '0' && c <= '9') {
*out = (*out << 4) | (c - '0'); *out = (*out << 4) | (c - '0');
if(*out < prev_out) return IntParsingResult::Overflow; 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); *out = (*out << 4) | (c - 'a' + 10);
if(*out < prev_out) return IntParsingResult::Overflow; 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); *out = (*out << 4) | (c - 'A' + 10);
if(*out < prev_out) return IntParsingResult::Overflow; if(*out < prev_out) return IntParsingResult::Overflow;
}else{ } else {
return IntParsingResult::Failure; return IntParsingResult::Failure;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,26 @@
#include "pocketpy/interpreter/cffi.hpp" #include "pocketpy/interpreter/cffi.hpp"
namespace pkpy{ namespace pkpy {
void VoidP::_register(VM* vm, PyObject* mod, PyObject* type){ void VoidP::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args){ vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args) {
Type cls = PK_OBJ_GET(Type, args[0]); Type cls = PK_OBJ_GET(Type, args[0]);
i64 addr = CAST(i64, args[1]); i64 addr = CAST(i64, args[1]);
return vm->new_object<VoidP>(cls, reinterpret_cast<void*>(addr)); return vm->new_object<VoidP>(cls, reinterpret_cast<void*>(addr));
}); });
vm->bind__hash__(type->as<Type>(), [](VM* vm, PyVar obj){ vm->bind__hash__(type->as<Type>(), [](VM* vm, PyVar obj) {
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, obj); obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, obj);
return reinterpret_cast<i64>(self.ptr); return reinterpret_cast<i64>(self.ptr);
}); });
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str{ vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, obj); obj_get_t<VoidP> self = PK_OBJ_GET(VoidP, obj);
return _S("<void* at ", self.hex(), ">"); return _S("<void* at ", self.hex(), ">");
}); });
#define BIND_CMP(name, op) \ #define BIND_CMP(name, op) \
vm->bind##name(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs){ \ vm->bind##name(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) { \
if(!vm->isinstance(rhs, vm->_tp_user<VoidP>())) return vm->NotImplemented; \ if(!vm->isinstance(rhs, vm->_tp_user<VoidP>())) return vm->NotImplemented; \
void* _0 = PK_OBJ_GET(VoidP, lhs).ptr; \ void* _0 = PK_OBJ_GET(VoidP, lhs).ptr; \
void* _1 = PK_OBJ_GET(VoidP, rhs).ptr; \ void* _1 = PK_OBJ_GET(VoidP, rhs).ptr; \
@ -34,67 +34,81 @@ namespace pkpy{
BIND_CMP(__ge__, >=) BIND_CMP(__ge__, >=)
#undef BIND_CMP #undef BIND_CMP
} }
void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
void Struct::_register(VM* vm, PyObject* mod, PyObject* type){ vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args) {
vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args){
Type cls = PK_OBJ_GET(Type, args[0]); Type cls = PK_OBJ_GET(Type, args[0]);
int size = CAST(int, args[1]); int size = CAST(int, args[1]);
return vm->new_object<Struct>(cls, size); 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]); const Struct& self = _CAST(Struct&, args[0]);
SStream ss; 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()); return VAR(ss.str());
}); });
// @staticmethod // @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]); const Str& s = CAST(Str&, args[0]);
if(s.size<2 || s.size%2!=0) vm->ValueError("invalid hex string"); if(s.size < 2 || s.size % 2 != 0) vm->ValueError("invalid hex string");
Struct buffer(s.size/2, false); Struct buffer(s.size / 2, false);
for(int i=0; i<s.size; i+=2){ for(int i = 0; i < s.size; i += 2) {
char c = 0; char c = 0;
if(s[i]>='0' && s[i]<='9') c += s[i]-'0'; if(s[i] >= '0' && s[i] <= '9')
else if(s[i]>='A' && s[i]<='F') c += s[i]-'A'+10; c += s[i] - '0';
else if(s[i]>='a' && s[i]<='f') c += s[i]-'a'+10; else if(s[i] >= 'A' && s[i] <= 'F')
else vm->ValueError(_S("invalid hex char: '", s[i], "'")); c += s[i] - 'A' + 10;
else if(s[i] >= 'a' && s[i] <= 'f')
c += s[i] - 'a' + 10;
else
vm->ValueError(_S("invalid hex char: '", s[i], "'"));
c <<= 4; c <<= 4;
if(s[i+1]>='0' && s[i+1]<='9') c += s[i+1]-'0'; if(s[i + 1] >= '0' && s[i + 1] <= '9')
else if(s[i+1]>='A' && s[i+1]<='F') c += s[i+1]-'A'+10; c += s[i + 1] - '0';
else if(s[i+1]>='a' && s[i+1]<='f') c += s[i+1]-'a'+10; else if(s[i + 1] >= 'A' && s[i + 1] <= 'F')
else vm->ValueError(_S("invalid hex char: '", s[i+1], "'")); c += s[i + 1] - 'A' + 10;
buffer.p[i/2] = c; else if(s[i + 1] >= 'a' && s[i + 1] <= 'f')
c += s[i + 1] - 'a' + 10;
else
vm->ValueError(_S("invalid hex char: '", s[i + 1], "'"));
buffer.p[i / 2] = c;
} }
return vm->new_user_object<Struct>(std::move(buffer)); return vm->new_user_object<Struct>(std::move(buffer));
}, {}, BindType::STATICMETHOD); },
{},
BindType::STATICMETHOD);
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj){ vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) {
Struct& self = _CAST(Struct&, obj); Struct& self = _CAST(Struct&, obj);
SStream ss; SStream ss;
ss << "<struct object of " << self.size << " bytes>"; ss << "<struct object of " << self.size << " bytes>";
return ss.str(); return ss.str();
}); });
vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args){ vm->bind_func(type, "addr", 1, [](VM* vm, ArgsView args) {
Struct& self = _CAST(Struct&, args[0]); Struct& self = _CAST(Struct&, args[0]);
return vm->new_user_object<VoidP>(self.p); return vm->new_user_object<VoidP>(self.p);
}); });
vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args){ vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args) {
Struct& self = _CAST(Struct&, args[0]); Struct& self = _CAST(Struct&, args[0]);
return VAR(self.size); return VAR(self.size);
}); });
vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args){ vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args) {
const Struct& self = _CAST(Struct&, args[0]); const Struct& self = _CAST(Struct&, args[0]);
return vm->new_object<Struct>(vm->_tp(args[0]), self); return vm->new_object<Struct>(vm->_tp(args[0]), self);
}); });
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs){ vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) {
Struct& self = _CAST(Struct&, lhs); Struct& self = _CAST(Struct&, lhs);
if(!vm->is_user_type<Struct>(rhs)) return vm->NotImplemented; if(!vm->is_user_type<Struct>(rhs)) return vm->NotImplemented;
Struct& other = _CAST(Struct&, rhs); Struct& other = _CAST(Struct&, rhs);
@ -103,13 +117,13 @@ namespace pkpy{
}); });
#define BIND_SETGET(T, name) \ #define BIND_SETGET(T, name) \
vm->bind(type, "read_" name "(self, offset=0)", [](VM* vm, ArgsView args){ \ vm->bind(type, "read_" name "(self, offset=0)", [](VM* vm, ArgsView args) { \
Struct& self = _CAST(Struct&, args[0]); \ Struct& self = _CAST(Struct&, args[0]); \
i64 offset = CAST(i64, args[1]); \ i64 offset = CAST(i64, args[1]); \
void* ptr = self.p + offset; \ void* ptr = self.p + offset; \
return VAR(*(T*)ptr); \ return VAR(*(T*)ptr); \
}); \ }); \
vm->bind(type, "write_" name "(self, value, offset=0)", [](VM* vm, ArgsView args){ \ vm->bind(type, "write_" name "(self, value, offset=0)", [](VM* vm, ArgsView args) { \
Struct& self = _CAST(Struct&, args[0]); \ Struct& self = _CAST(Struct&, args[0]); \
i64 offset = CAST(i64, args[2]); \ i64 offset = CAST(i64, args[2]); \
void* ptr = self.p + offset; \ void* ptr = self.p + offset; \
@ -131,29 +145,29 @@ namespace pkpy{
BIND_SETGET(bool, "bool") BIND_SETGET(bool, "bool")
BIND_SETGET(void*, "void_p") BIND_SETGET(void*, "void_p")
#undef BIND_SETGET #undef BIND_SETGET
} }
void add_module_c(VM* vm){ void add_module_c(VM* vm) {
PyObject* mod = vm->new_module("c"); PyObject* mod = vm->new_module("c");
vm->bind_func(mod, "malloc", 1, [](VM* vm, ArgsView args){ vm->bind_func(mod, "malloc", 1, [](VM* vm, ArgsView args) {
i64 size = CAST(i64, args[0]); i64 size = CAST(i64, args[0]);
return VAR(std::malloc(size)); return VAR(std::malloc(size));
}); });
vm->bind_func(mod, "free", 1, [](VM* vm, ArgsView args){ vm->bind_func(mod, "free", 1, [](VM* vm, ArgsView args) {
void* p = CAST(void*, args[0]); void* p = CAST(void*, args[0]);
std::free(p); std::free(p);
return vm->None; return vm->None;
}); });
vm->bind_func(mod, "memset", 3, [](VM* vm, ArgsView args){ vm->bind_func(mod, "memset", 3, [](VM* vm, ArgsView args) {
void* p = CAST(void*, args[0]); void* p = CAST(void*, args[0]);
std::memset(p, CAST(int, args[1]), CAST(size_t, args[2])); std::memset(p, CAST(int, args[1]), CAST(size_t, args[2]));
return vm->None; return vm->None;
}); });
vm->bind_func(mod, "memcpy", 3, [](VM* vm, ArgsView args){ vm->bind_func(mod, "memcpy", 3, [](VM* vm, ArgsView args) {
void* dst = CAST(void*, args[0]); void* dst = CAST(void*, args[0]);
void* src = CAST(void*, args[1]); void* src = CAST(void*, args[1]);
i64 size = CAST(i64, args[2]); i64 size = CAST(i64, args[2]);
@ -166,22 +180,20 @@ void add_module_c(VM* vm){
mod->attr().set("NULL", vm->new_user_object<VoidP>(nullptr)); mod->attr().set("NULL", vm->new_user_object<VoidP>(nullptr));
vm->bind(mod, "p_cast(ptr: 'void_p', cls: type[T]) -> T", [](VM* vm, ArgsView args){ vm->bind(mod, "p_cast(ptr: 'void_p', cls: type[T]) -> T", [](VM* vm, ArgsView args) {
VoidP& ptr = CAST(VoidP&, args[0]); VoidP& ptr = CAST(VoidP&, args[0]);
vm->check_type(args[1], vm->tp_type); vm->check_type(args[1], vm->tp_type);
Type cls = PK_OBJ_GET(Type, args[1]); Type cls = PK_OBJ_GET(Type, args[1]);
if(!vm->issubclass(cls, vm->_tp_user<VoidP>())){ if(!vm->issubclass(cls, vm->_tp_user<VoidP>())) { vm->ValueError("expected a subclass of void_p"); }
vm->ValueError("expected a subclass of void_p");
}
return vm->new_object<VoidP>(cls, ptr.ptr); return vm->new_object<VoidP>(cls, ptr.ptr);
}); });
vm->bind(mod, "p_value(ptr: 'void_p') -> int", [](VM* vm, ArgsView args){ vm->bind(mod, "p_value(ptr: 'void_p') -> int", [](VM* vm, ArgsView args) {
VoidP& ptr = CAST(VoidP&, args[0]); VoidP& ptr = CAST(VoidP&, args[0]);
return VAR(reinterpret_cast<i64>(ptr.ptr)); return VAR(reinterpret_cast<i64>(ptr.ptr));
}); });
vm->bind(mod, "pp_deref(ptr: Tp) -> Tp", [](VM* vm, ArgsView args){ vm->bind(mod, "pp_deref(ptr: Tp) -> Tp", [](VM* vm, ArgsView args) {
VoidP& ptr = CAST(VoidP&, args[0]); VoidP& ptr = CAST(VoidP&, args[0]);
void* value = *reinterpret_cast<void**>(ptr.ptr); void* value = *reinterpret_cast<void**>(ptr.ptr);
return vm->new_object<VoidP>(args[0].type, value); return vm->new_object<VoidP>(args[0].type, value);
@ -191,53 +203,53 @@ void add_module_c(VM* vm){
Type type_t; Type type_t;
#define BIND_PRIMITIVE(T, CNAME) \ #define BIND_PRIMITIVE(T, CNAME) \
vm->bind_func(mod, CNAME "_", 1, [](VM* vm, ArgsView args){ \ vm->bind_func(mod, CNAME "_", 1, [](VM* vm, ArgsView args) { \
T val = CAST(T, args[0]); \ T val = CAST(T, args[0]); \
return vm->new_user_object<Struct>(&val, sizeof(T)); \ return vm->new_user_object<Struct>(&val, sizeof(T)); \
}); \ }); \
type = vm->new_type_object(mod, CNAME "_p", vm->_tp_user<VoidP>(), true); \ type = vm->new_type_object(mod, CNAME "_p", vm->_tp_user<VoidP>(), true); \
mod->attr().set(CNAME "_p", type); \ mod->attr().set(CNAME "_p", type); \
type_t = type->as<Type>(); \ type_t = type->as<Type>(); \
vm->bind_func(type, "read", 1, [](VM* vm, ArgsView args){ \ vm->bind_func(type, "read", 1, [](VM* vm, ArgsView args) { \
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); \ obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); \
T* target = (T*)voidp.ptr; \ T* target = (T*)voidp.ptr; \
return VAR(*target); \ return VAR(*target); \
}); \ }); \
vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args){ \ vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args) { \
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); \ obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); \
T val = CAST(T, args[1]); \ T val = CAST(T, args[1]); \
T* target = (T*)voidp.ptr; \ T* target = (T*)voidp.ptr; \
*target = val; \ *target = val; \
return vm->None; \ return vm->None; \
}); \ }); \
vm->bind__getitem__(type_t, [](VM* vm, PyVar obj, PyVar index){ \ vm->bind__getitem__(type_t, [](VM* vm, PyVar obj, PyVar index) { \
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, obj); \ obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, obj); \
i64 offset = CAST(i64, index); \ i64 offset = CAST(i64, index); \
T* target = (T*)voidp.ptr; \ T* target = (T*)voidp.ptr; \
return VAR(target[offset]); \ return VAR(target[offset]); \
}); \ }); \
vm->bind__setitem__(type_t, [](VM* vm, PyVar obj, PyVar index, PyVar value){ \ vm->bind__setitem__(type_t, [](VM* vm, PyVar obj, PyVar index, PyVar value) { \
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, obj); \ obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, obj); \
i64 offset = CAST(i64, index); \ i64 offset = CAST(i64, index); \
T* target = (T*)voidp.ptr; \ T* target = (T*)voidp.ptr; \
target[offset] = CAST(T, value); \ target[offset] = CAST(T, value); \
}); \ }); \
vm->bind__add__(type_t, [](VM* vm, PyVar lhs, PyVar rhs){ \ vm->bind__add__(type_t, [](VM* vm, PyVar lhs, PyVar rhs) { \
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, lhs); \ obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, lhs); \
i64 offset = CAST(i64, rhs); \ i64 offset = CAST(i64, rhs); \
T* target = (T*)voidp.ptr; \ T* target = (T*)voidp.ptr; \
return vm->new_object<VoidP>(lhs.type, target + offset); \ return vm->new_object<VoidP>(lhs.type, target + offset); \
}); \ }); \
vm->bind__sub__(type_t, [](VM* vm, PyVar lhs, PyVar rhs){ \ vm->bind__sub__(type_t, [](VM* vm, PyVar lhs, PyVar rhs) { \
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, lhs); \ obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, lhs); \
i64 offset = CAST(i64, rhs); \ i64 offset = CAST(i64, rhs); \
T* target = (T*)voidp.ptr; \ T* target = (T*)voidp.ptr; \
return vm->new_object<VoidP>(lhs.type, target - offset); \ return vm->new_object<VoidP>(lhs.type, target - offset); \
}); \ }); \
vm->bind__repr__(type_t, [](VM* vm, PyVar obj) -> Str{ \ vm->bind__repr__(type_t, [](VM* vm, PyVar obj) -> Str { \
VoidP& self = _CAST(VoidP&, obj); \ VoidP& self = _CAST(VoidP&, obj); \
return _S("<", CNAME, "* at ", self.hex(), ">"); \ return _S("<", CNAME, "* at ", self.hex(), ">"); \
}); \ });
BIND_PRIMITIVE(char, "char") BIND_PRIMITIVE(char, "char")
BIND_PRIMITIVE(unsigned char, "uchar") BIND_PRIMITIVE(unsigned char, "uchar")
@ -256,13 +268,13 @@ void add_module_c(VM* vm){
#undef BIND_PRIMITIVE #undef BIND_PRIMITIVE
PyObject* char_p_t = mod->attr("char_p").get(); PyObject* char_p_t = mod->attr("char_p").get();
vm->bind(char_p_t, "read_string(self) -> str", [](VM* vm, ArgsView args){ vm->bind(char_p_t, "read_string(self) -> str", [](VM* vm, ArgsView args) {
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]);
const char* target = (const char*)voidp.ptr; const char* target = (const char*)voidp.ptr;
return VAR(target); return VAR(target);
}); });
vm->bind(char_p_t, "write_string(self, value: str)", [](VM* vm, ArgsView args){ vm->bind(char_p_t, "write_string(self, value: str)", [](VM* vm, ArgsView args) {
obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]); obj_get_t<VoidP> voidp = PK_OBJ_GET(VoidP, args[0]);
std::string_view sv = CAST(Str&, args[1]).sv(); std::string_view sv = CAST(Str&, args[1]).sv();
char* target = (char*)voidp.ptr; char* target = (char*)voidp.ptr;
@ -272,8 +284,6 @@ void add_module_c(VM* vm){
}); });
} }
PyVar from_void_p(VM* vm, void* p){ PyVar from_void_p(VM* vm, void* p) { return vm->new_user_object<VoidP>(p); }
return vm->new_user_object<VoidP>(p);
}
} // namespace pkpy } // namespace pkpy

View File

@ -3,33 +3,33 @@
#include <stdexcept> #include <stdexcept>
namespace pkpy{ namespace pkpy {
PyVar* FastLocals::try_get_name(StrName name){ PyVar* FastLocals::try_get_name(StrName name) {
int index = co->varnames_inv.try_get(name); int index = co->varnames_inv.try_get(name);
if(index == -1) return nullptr; if(index == -1) return nullptr;
return &a[index]; return &a[index];
} }
NameDict_ FastLocals::to_namedict(){ NameDict_ FastLocals::to_namedict() {
NameDict_ dict = std::make_shared<NameDict>(); NameDict_ dict = std::make_shared<NameDict>();
co->varnames_inv.apply([&](StrName name, int index){ co->varnames_inv.apply([&](StrName name, int index) {
PyVar value = a[index]; PyVar value = a[index];
if(value) dict->set(name, value); if(value) dict->set(name, value);
}); });
return dict; return dict;
} }
PyVar* Frame::f_closure_try_get(StrName name){ PyVar* Frame::f_closure_try_get(StrName name) {
if(_callable == nullptr) return nullptr; if(_callable == nullptr) return nullptr;
Function& fn = _callable->as<Function>(); Function& fn = _callable->as<Function>();
if(fn._closure == nullptr) return nullptr; if(fn._closure == nullptr) return nullptr;
return fn._closure->try_get_2(name); return fn._closure->try_get_2(name);
} }
int Frame::prepare_jump_exception_handler(ValueStack* _s){ int Frame::prepare_jump_exception_handler(ValueStack* _s) {
// try to find a parent try block // try to find a parent try block
int i = co->lines[ip()].iblock; int i = co->lines[ip()].iblock;
while(i >= 0){ while(i >= 0) {
if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) break; if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) break;
i = co->blocks[i].parent; i = co->blocks[i].parent;
} }
@ -39,90 +39,92 @@ namespace pkpy{
_s->reset(actual_sp_base() + uw->offset); // unwind the stack _s->reset(actual_sp_base() + uw->offset); // unwind the stack
_s->push(obj); // push it back _s->push(obj); // push it back
return co->blocks[i].end; 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; auto type = co->blocks[i].type;
if(type == CodeBlockType::FOR_LOOP){ if(type == CodeBlockType::FOR_LOOP) {
_s->pop(); // pop the iterator _s->pop(); // pop the iterator
// pop possible stack memory slots // pop possible stack memory slots
if(_s->top().type == kTpStackMemoryIndex){ if(_s->top().type == kTpStackMemoryIndex) {
int count = _s->top().as<StackMemory>().count; int count = _s->top().as<StackMemory>().count;
assert(count < 0); assert(count < 0);
_s->_sp += count; _s->_sp += count;
_s->_sp -= 2; // pop header and tail _s->_sp -= 2; // pop header and tail
} }
}else if(type==CodeBlockType::CONTEXT_MANAGER){ } else if(type == CodeBlockType::CONTEXT_MANAGER) {
_s->pop(); _s->pop();
} }
return co->blocks[i].parent; 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; int i = co->lines[ip()].iblock;
if(target >= co->codes.size()){ if(target >= co->codes.size()) {
while(i>=0) i = _exit_block(_s, i); while(i >= 0)
}else{ i = _exit_block(_s, i);
} else {
// BUG (solved) // BUG (solved)
// for i in range(4): // for i in range(4):
// _ = 0 // _ = 0
// # if there is no op here, the block check will fail // # if there is no op here, the block check will fail
// while i: --i // while i: --i
int next_block = co->lines[target].iblock; int next_block = co->lines[target].iblock;
while(i>=0 && i!=next_block) i = _exit_block(_s, i); while(i >= 0 && i != next_block)
if(i!=next_block) throw std::runtime_error("invalid jump"); 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; int iblock = co->lines[ip()].iblock;
UnwindTarget* existing = find_unwind_target(iblock); UnwindTarget* existing = find_unwind_target(iblock);
if(existing){ if(existing) {
existing->offset = _sp - actual_sp_base(); existing->offset = _sp - actual_sp_base();
}else{ } else {
UnwindTarget* prev = _uw_list; UnwindTarget* prev = _uw_list;
_uw_list = new UnwindTarget(iblock, _sp - actual_sp_base()); _uw_list = new UnwindTarget(iblock, _sp - actual_sp_base());
_uw_list->next = prev; _uw_list->next = prev;
} }
} }
UnwindTarget* Frame::find_unwind_target(int iblock){ UnwindTarget* Frame::find_unwind_target(int iblock) {
UnwindTarget* p; 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; if(p->iblock == iblock) return p;
} }
return nullptr; return nullptr;
} }
Frame::~Frame(){ Frame::~Frame() {
while(_uw_list != nullptr){ while(_uw_list != nullptr) {
UnwindTarget* p = _uw_list; UnwindTarget* p = _uw_list;
_uw_list = p->next; _uw_list = p->next;
delete p; delete p;
} }
} }
void CallStack::pop(){ void CallStack::pop() {
assert(!empty()); assert(!empty());
LinkedFrame* p = _tail; LinkedFrame* p = _tail;
_tail = p->f_back; _tail = p->f_back;
p->~LinkedFrame(); p->~LinkedFrame();
PoolFrame_dealloc(p); PoolFrame_dealloc(p);
--_size; --_size;
} }
LinkedFrame* CallStack::popx(){ LinkedFrame* CallStack::popx() {
assert(!empty()); assert(!empty());
LinkedFrame* p = _tail; LinkedFrame* p = _tail;
_tail = p->f_back; _tail = p->f_back;
--_size; --_size;
p->f_back = nullptr; // unlink p->f_back = nullptr; // unlink
return p; return p;
} }
void CallStack::pushx(LinkedFrame* p){ void CallStack::pushx(LinkedFrame* p) {
p->f_back = _tail; p->f_back = _tail;
_tail = p; _tail = p;
++_size; ++_size;
} }
} // namespace pkpy } // namespace pkpy

View File

@ -1,15 +1,15 @@
#include "pocketpy/interpreter/gc.hpp" #include "pocketpy/interpreter/gc.hpp"
namespace pkpy{ namespace pkpy {
int ManagedHeap::sweep(){ int ManagedHeap::sweep() {
vector<PyObject*> alive; vector<PyObject*> alive;
alive.reserve(gen.size() / 2); alive.reserve(gen.size() / 2);
for(PyObject* obj: gen){ for(PyObject* obj: gen) {
if(obj->gc_marked){ if(obj->gc_marked) {
obj->gc_marked = false; obj->gc_marked = false;
alive.push_back(obj); alive.push_back(obj);
}else{ } else {
#if PK_DEBUG_GC_STATS #if PK_DEBUG_GC_STATS
deleted[obj->type] += 1; deleted[obj->type] += 1;
#endif #endif
@ -19,12 +19,13 @@ namespace pkpy{
} }
// clear _no_gc marked flag // 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(); int freed = gen.size() - alive.size();
#if PK_DEBUG_GC_STATS #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: " << _type_name(vm, type).sv() << "=" << count << std::endl;
} }
std::cout << "GC: " << alive.size() << "/" << gen.size() << " (" << freed << " freed)" << std::endl; std::cout << "GC: " << alive.size() << "/" << gen.size() << " (" << freed << " freed)" << std::endl;
@ -34,9 +35,9 @@ namespace pkpy{
gen.swap(alive); gen.swap(alive);
PoolObject_shrink_to_fit(); PoolObject_shrink_to_fit();
return freed; return freed;
} }
void ManagedHeap::_auto_collect(){ void ManagedHeap::_auto_collect() {
#if !PK_DEBUG_NO_AUTO_GC #if !PK_DEBUG_NO_AUTO_GC
if(_gc_lock_counter > 0) return; if(_gc_lock_counter > 0) return;
gc_counter = 0; gc_counter = 0;
@ -44,12 +45,12 @@ namespace pkpy{
gc_threshold = gen.size() * 2; gc_threshold = gen.size() * 2;
if(gc_threshold < PK_GC_MIN_THRESHOLD) gc_threshold = PK_GC_MIN_THRESHOLD; if(gc_threshold < PK_GC_MIN_THRESHOLD) gc_threshold = PK_GC_MIN_THRESHOLD;
#endif #endif
} }
int ManagedHeap::collect(){ int ManagedHeap::collect() {
assert(_gc_lock_counter == 0); assert(_gc_lock_counter == 0);
mark(); mark();
int freed = sweep(); int freed = sweep();
return freed; return freed;
} }
} // namespace pkpy } // namespace pkpy

View File

@ -1,42 +1,50 @@
#include "pocketpy/interpreter/iter.hpp" #include "pocketpy/interpreter/iter.hpp"
namespace pkpy{ namespace pkpy {
void RangeIter::_register(VM* vm, PyObject* mod, PyObject* type){ void RangeIter::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{ return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
RangeIter& self = PK_OBJ_GET(RangeIter, _0); RangeIter& self = PK_OBJ_GET(RangeIter, _0);
if(self.current >= self.r.stop) return 0; if(self.current >= self.r.stop) return 0;
vm->s_data.emplace(VM::tp_int, self.current); vm->s_data.emplace(VM::tp_int, self.current);
self.current += self.r.step; self.current += self.r.step;
return 1; return 1;
}); });
} }
void RangeIterR::_register(VM* vm, PyObject* mod, PyObject* type){ void RangeIterR::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{ return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
RangeIterR& self = PK_OBJ_GET(RangeIterR, _0); RangeIterR& self = PK_OBJ_GET(RangeIterR, _0);
if(self.current <= self.r.stop) return 0; if(self.current <= self.r.stop) return 0;
vm->s_data.emplace(VM::tp_int, self.current); vm->s_data.emplace(VM::tp_int, self.current);
self.current += self.r.step; self.current += self.r.step;
return 1; return 1;
}); });
} }
void ArrayIter::_register(VM* vm, PyObject* mod, PyObject* type){ void ArrayIter::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{ return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
ArrayIter& self = _CAST(ArrayIter&, _0); ArrayIter& self = _CAST(ArrayIter&, _0);
if(self.current == self.end) return 0; if(self.current == self.end) return 0;
vm->s_data.push(*self.current++); vm->s_data.push(*self.current++);
return 1; return 1;
}); });
} }
void StringIter::_register(VM* vm, PyObject* mod, PyObject* type){ void StringIter::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{ return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
StringIter& self = _CAST(StringIter&, _0); StringIter& self = _CAST(StringIter&, _0);
Str& s = PK_OBJ_GET(Str, self.ref); Str& s = PK_OBJ_GET(Str, self.ref);
if(self.i == s.size) return 0; if(self.i == s.size) return 0;
@ -46,21 +54,22 @@ namespace pkpy{
vm->s_data.push(VAR(s.substr(start, len))); vm->s_data.push(VAR(s.substr(start, len)));
return 1; return 1;
}); });
} }
PyVar Generator::next(VM* vm){ PyVar Generator::next(VM* vm) {
if(state == 2) return vm->StopIteration; if(state == 2) return vm->StopIteration;
// reset frame._sp_base // reset frame._sp_base
lf->frame._sp_base = vm->s_data._sp; lf->frame._sp_base = vm->s_data._sp;
lf->frame._locals.a = vm->s_data._sp; lf->frame._locals.a = vm->s_data._sp;
// restore the context // restore the context
for(PyVar obj: s_backup) vm->s_data.push(obj); for(PyVar obj: s_backup)
vm->s_data.push(obj);
// relocate stack objects (their addresses become invalid) // relocate stack objects (their addresses become invalid)
for(PyVar* p=lf->frame.actual_sp_base(); p!=vm->s_data.end(); p++){ for(PyVar* p = lf->frame.actual_sp_base(); p != vm->s_data.end(); p++) {
if(p->type == VM::tp_stack_memory){ if(p->type == VM::tp_stack_memory) {
// TODO: refactor this // TODO: refactor this
int count = p->as<StackMemory>().count; int count = p->as<StackMemory>().count;
if(count < 0){ if(count < 0) {
void* new_p = p + count; void* new_p = p + count;
p[1]._1 = reinterpret_cast<i64>(new_p); p[1]._1 = reinterpret_cast<i64>(new_p);
} }
@ -71,48 +80,53 @@ namespace pkpy{
lf = nullptr; lf = nullptr;
PyVar ret; PyVar ret;
try{ try {
ret = vm->__run_top_frame(); ret = vm->__run_top_frame();
}catch(...){ } catch(...) {
state = 2; // end this generator immediately when an exception is thrown state = 2; // end this generator immediately when an exception is thrown
throw; throw;
} }
if(ret == PY_OP_YIELD){ if(ret == PY_OP_YIELD) {
// backup the context // backup the context
lf = vm->callstack.popx(); lf = vm->callstack.popx();
ret = vm->s_data.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); vm->s_data.reset(lf->frame._sp_base);
// TODO: should we add this snippet here? // TODO: should we add this snippet here?
// #if PK_ENABLE_PROFILER // #if PK_ENABLE_PROFILER
// if(!_next_breakpoint.empty() && callstack.size()<_next_breakpoint.callstack_size){ // if(!_next_breakpoint.empty() && callstack.size()<_next_breakpoint.callstack_size){
// _next_breakpoint = NextBreakpoint(); // _next_breakpoint = NextBreakpoint();
// } // }
// #endif // #endif
state = 1; state = 1;
if(ret == vm->StopIteration) state = 2; if(ret == vm->StopIteration) state = 2;
return ret; return ret;
}else{ } else {
state = 2; state = 2;
return vm->StopIteration; return vm->StopIteration;
} }
} }
void Generator::_register(VM* vm, PyObject* mod, PyObject* type){ void Generator::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{ return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
Generator& self = _CAST(Generator&, _0); Generator& self = _CAST(Generator&, _0);
PyVar retval = self.next(vm); PyVar retval = self.next(vm);
if(retval == vm->StopIteration) return 0; if(retval == vm->StopIteration) return 0;
vm->s_data.push(retval); vm->s_data.push(retval);
return 1; return 1;
}); });
} }
void DictItemsIter::_register(VM *vm, PyObject* mod, PyObject* type){ void DictItemsIter::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{ return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
DictItemsIter& self = _CAST(DictItemsIter&, _0); DictItemsIter& self = _CAST(DictItemsIter&, _0);
Dict& d = PK_OBJ_GET(Dict, self.ref); Dict& d = PK_OBJ_GET(Dict, self.ref);
if(self.i == -1) return 0; if(self.i == -1) return 0;
@ -121,9 +135,9 @@ namespace pkpy{
self.i = d._items[self.i].next; self.i = d._items[self.i].next;
return 2; 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); return vm->new_user_object<Generator>(std::move(frame), buffer);
} }

View File

@ -1,41 +1,39 @@
#include "pocketpy/interpreter/profiler.hpp" #include "pocketpy/interpreter/profiler.hpp"
namespace pkpy{ namespace pkpy {
static std::string left_pad(std::string s, int width){ static std::string left_pad(std::string s, int width) {
int n = width - s.size(); int n = width - s.size();
if(n <= 0) return s; if(n <= 0) return s;
return std::string(n, ' ') + s; return std::string(n, ' ') + s;
} }
static std::string to_string_1f(f64 x){ static std::string to_string_1f(f64 x) {
char buf[32]; char buf[32];
snprintf(buf, 32, "%.1f", x); snprintf(buf, 32, "%.1f", x);
return buf; return buf;
} }
void LineProfiler::begin(){ void LineProfiler::begin() { frames.clear(); }
frames.clear();
}
void LineProfiler::_step(int callstack_size, Frame* frame){ void LineProfiler::_step(int callstack_size, Frame* frame) {
auto line_info = frame->co->lines[frame->ip()]; auto line_info = frame->co->lines[frame->ip()];
if(line_info.is_virtual) return; if(line_info.is_virtual) return;
std::string_view filename = frame->co->src->filename.sv(); std::string_view filename = frame->co->src->filename.sv();
int line = line_info.lineno; int line = line_info.lineno;
if(frames.empty()){ if(frames.empty()) {
frames.push({callstack_size, frame, clock(), nullptr}); frames.push({callstack_size, frame, clock(), nullptr});
}else{ } else {
_step_end(callstack_size, frame, line); _step_end(callstack_size, frame, line);
} }
auto& file_records = records[filename]; auto& file_records = records[filename];
if(file_records.empty()){ if(file_records.empty()) {
// initialize file_records // initialize file_records
int total_lines = frame->co->src->line_starts.size(); int total_lines = frame->co->src->line_starts.size();
file_records.resize(total_lines + 1); file_records.resize(total_lines + 1);
for(int i=1; i<=total_lines; i++){ for(int i = 1; i <= total_lines; i++) {
file_records[i].line = i; file_records[i].line = i;
} }
} }
@ -43,7 +41,7 @@ void LineProfiler::_step(int callstack_size, Frame* frame){
frames.top().prev_record = &file_records[line]; frames.top().prev_record = &file_records[line];
} }
void LineProfiler::_step_end(int callstack_size, Frame* frame, int line){ void LineProfiler::_step_end(int callstack_size, Frame* frame, int line) {
clock_t now = clock(); clock_t now = clock();
_FrameRecord& top_frame_record = frames.top(); _FrameRecord& top_frame_record = frames.top();
_LineRecord* prev_record = top_frame_record.prev_record; _LineRecord* prev_record = top_frame_record.prev_record;
@ -52,21 +50,21 @@ void LineProfiler::_step_end(int callstack_size, Frame* frame, int line){
assert(abs(id_delta) <= 1); assert(abs(id_delta) <= 1);
// current line is about to change // current line is about to change
if(prev_record->line != line){ if(prev_record->line != line) {
clock_t delta = now - top_frame_record.prev_time; clock_t delta = now - top_frame_record.prev_time;
top_frame_record.prev_time = now; top_frame_record.prev_time = now;
if(id_delta != 1) prev_record->hits++; if(id_delta != 1) prev_record->hits++;
prev_record->time += delta; prev_record->time += delta;
} }
if(id_delta == 1){ if(id_delta == 1) {
frames.push({callstack_size, frame, now, nullptr}); frames.push({callstack_size, frame, now, nullptr});
}else{ } else {
if(id_delta == -1) frames.pop(); if(id_delta == -1) frames.pop();
} }
} }
void LineProfiler::end(){ void LineProfiler::end() {
clock_t now = clock(); clock_t now = clock();
_FrameRecord& top_frame_record = frames.top(); _FrameRecord& top_frame_record = frames.top();
_LineRecord* prev_record = top_frame_record.prev_record; _LineRecord* prev_record = top_frame_record.prev_record;
@ -80,9 +78,9 @@ void LineProfiler::end(){
assert(frames.empty()); assert(frames.empty());
} }
Str LineProfiler::stats(){ Str LineProfiler::stats() {
SStream ss; SStream ss;
for(FuncDecl* decl: functions){ for(FuncDecl* decl: functions) {
int start_line = decl->code->start_line; int start_line = decl->code->start_line;
int end_line = decl->code->end_line; int end_line = decl->code->end_line;
if(start_line == -1 || end_line == -1) continue; if(start_line == -1 || end_line == -1) continue;
@ -90,7 +88,7 @@ Str LineProfiler::stats(){
vector<_LineRecord>& file_records = records[filename]; vector<_LineRecord>& file_records = records[filename];
if(file_records.empty()) continue; if(file_records.empty()) continue;
clock_t total_time = 0; clock_t total_time = 0;
for(int line = start_line; line <= end_line; line++){ for(int line = start_line; line <= end_line; line++) {
total_time += file_records[line].time; total_time += file_records[line].time;
} }
ss << "Total time: " << (f64)total_time / CLOCKS_PER_SEC << "s\n"; ss << "Total time: " << (f64)total_time / CLOCKS_PER_SEC << "s\n";
@ -98,19 +96,19 @@ Str LineProfiler::stats(){
ss << "Function: " << decl->code->name << " at line " << start_line << "\n"; ss << "Function: " << decl->code->name << " at line " << start_line << "\n";
ss << "Line # Hits Time Per Hit % Time Line Contents\n"; ss << "Line # Hits Time Per Hit % Time Line Contents\n";
ss << "==============================================================\n"; ss << "==============================================================\n";
for(int line = start_line; line <= end_line; line++){ for(int line = start_line; line <= end_line; line++) {
const _LineRecord& record = file_records[line]; const _LineRecord& record = file_records[line];
if(!record.is_valid()) continue; if(!record.is_valid()) continue;
ss << left_pad(std::to_string(line), 6); ss << left_pad(std::to_string(line), 6);
if(record.hits == 0){ if(record.hits == 0) {
ss << std::string(10 + 13 + 9 + 9, ' '); ss << std::string(10 + 13 + 9 + 9, ' ');
}else{ } else {
ss << left_pad(std::to_string(record.hits), 10); ss << left_pad(std::to_string(record.hits), 10);
ss << left_pad(std::to_string(record.time), 13); ss << left_pad(std::to_string(record.time), 13);
ss << left_pad(std::to_string(record.time / record.hits), 9); ss << left_pad(std::to_string(record.time / record.hits), 9);
if(total_time == 0){ if(total_time == 0) {
ss << left_pad("0.0", 9); ss << left_pad("0.0", 9);
}else{ } else {
ss << left_pad(to_string_1f(record.time * (f64)100 / total_time), 9); ss << left_pad(to_string_1f(record.time * (f64)100 / total_time), 9);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
#include "pocketpy/modules/array2d.hpp" #include "pocketpy/modules/array2d.hpp"
#include "pocketpy/interpreter/bindings.hpp" #include "pocketpy/interpreter/bindings.hpp"
namespace pkpy{ namespace pkpy {
struct Array2d{ struct Array2d {
PK_ALWAYS_PASS_BY_POINTER(Array2d) PK_ALWAYS_PASS_BY_POINTER(Array2d)
PyVar* data; PyVar* data;
@ -11,55 +11,49 @@ struct Array2d{
int n_rows; int n_rows;
int numel; int numel;
Array2d(){ Array2d() {
data = nullptr; data = nullptr;
n_cols = 0; n_cols = 0;
n_rows = 0; n_rows = 0;
numel = 0; numel = 0;
} }
void init(int n_cols, int n_rows){ void init(int n_cols, int n_rows) {
this->n_cols = n_cols; this->n_cols = n_cols;
this->n_rows = n_rows; this->n_rows = n_rows;
this->numel = n_cols * n_rows; this->numel = n_cols * n_rows;
this->data = new PyVar[numel]; this->data = new PyVar[numel];
} }
bool is_valid(int col, int row) const{ bool is_valid(int col, int row) const { return 0 <= col && col < n_cols && 0 <= row && row < n_rows; }
return 0 <= col && col < n_cols && 0 <= row && row < n_rows;
}
void check_valid(VM* vm, int col, int row) const{ void check_valid(VM* vm, int col, int row) const {
if(is_valid(col, row)) return; if(is_valid(col, row)) return;
vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')')); vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')'));
} }
PyVar _get(int col, int row){ PyVar _get(int col, int row) { return data[row * n_cols + col]; }
return data[row * n_cols + col];
}
void _set(int col, int row, PyVar value){ void _set(int col, int row, PyVar value) { data[row * n_cols + col] = value; }
data[row * n_cols + col] = value;
}
static void _register(VM* vm, PyObject* mod, PyObject* type){ static void _register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind(type, "__new__(cls, *args, **kwargs)", [](VM* vm, ArgsView args){ vm->bind(type, "__new__(cls, *args, **kwargs)", [](VM* vm, ArgsView args) {
Type cls = PK_OBJ_GET(Type, args[0]); Type cls = PK_OBJ_GET(Type, args[0]);
return vm->new_object<Array2d>(cls); return vm->new_object<Array2d>(cls);
}); });
vm->bind(type, "__init__(self, n_cols: int, n_rows: int, default=None)", [](VM* vm, ArgsView args){ vm->bind(type, "__init__(self, n_cols: int, n_rows: int, default=None)", [](VM* vm, ArgsView args) {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
int n_cols = CAST(int, args[1]); int n_cols = CAST(int, args[1]);
int n_rows = CAST(int, args[2]); int n_rows = CAST(int, args[2]);
if(n_cols <= 0 || n_rows <= 0){ if(n_cols <= 0 || n_rows <= 0) { vm->ValueError("n_cols and n_rows must be positive integers"); }
vm->ValueError("n_cols and n_rows must be positive integers");
}
self.init(n_cols, n_rows); self.init(n_cols, n_rows);
if(vm->py_callable(args[3])){ if(vm->py_callable(args[3])) {
for(int i = 0; i < self.numel; i++) self.data[i] = vm->call(args[3]); for(int i = 0; i < self.numel; i++)
}else{ self.data[i] = vm->call(args[3]);
for(int i = 0; i < self.numel; i++) self.data[i] = args[3]; } else {
for(int i = 0; i < self.numel; i++)
self.data[i] = args[3];
} }
return vm->None; return vm->None;
}); });
@ -71,7 +65,7 @@ struct Array2d{
PY_READONLY_FIELD(Array2d, "numel", numel); PY_READONLY_FIELD(Array2d, "numel", numel);
// _get // _get
vm->bind_func(type, "_get", 3, [](VM* vm, ArgsView args){ vm->bind_func(type, "_get", 3, [](VM* vm, ArgsView args) {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
int col = CAST(int, args[1]); int col = CAST(int, args[1]);
int row = CAST(int, args[2]); int row = CAST(int, args[2]);
@ -80,7 +74,7 @@ struct Array2d{
}); });
// _set // _set
vm->bind_func(type, "_set", 4, [](VM* vm, ArgsView args){ vm->bind_func(type, "_set", 4, [](VM* vm, ArgsView args) {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
int col = CAST(int, args[1]); int col = CAST(int, args[1]);
int row = CAST(int, args[2]); int row = CAST(int, args[2]);
@ -89,14 +83,14 @@ struct Array2d{
return vm->None; return vm->None;
}); });
vm->bind_func(type, "is_valid", 3, [](VM* vm, ArgsView args){ vm->bind_func(type, "is_valid", 3, [](VM* vm, ArgsView args) {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
int col = CAST(int, args[1]); int col = CAST(int, args[1]);
int row = CAST(int, args[2]); int row = CAST(int, args[2]);
return VAR(self.is_valid(col, row)); return VAR(self.is_valid(col, row));
}); });
vm->bind(type, "get(self, col: int, row: int, default=None)", [](VM* vm, ArgsView args){ vm->bind(type, "get(self, col: int, row: int, default=None)", [](VM* vm, ArgsView args) {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
int col = CAST(int, args[1]); int col = CAST(int, args[1]);
int row = CAST(int, args[2]); int row = CAST(int, args[2]);
@ -104,7 +98,7 @@ struct Array2d{
return self._get(col, row); return self._get(col, row);
}); });
#define HANDLE_SLICE() \ #define HANDLE_SLICE() \
int start_col, stop_col, step_col; \ int start_col, stop_col, step_col; \
int start_row, stop_row, step_row; \ int start_row, stop_row, step_row; \
vm->parse_int_slice(PK_OBJ_GET(Slice, xy[0]), self.n_cols, start_col, stop_col, step_col); \ vm->parse_int_slice(PK_OBJ_GET(Slice, xy[0]), self.n_cols, start_col, stop_col, step_col); \
@ -114,24 +108,24 @@ struct Array2d{
int slice_height = stop_row - start_row; \ int slice_height = stop_row - start_row; \
if(slice_width <= 0 || slice_height <= 0) vm->ValueError("slice width and height must be positive"); if(slice_width <= 0 || slice_height <= 0) vm->ValueError("slice width and height must be positive");
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
Array2d& self = PK_OBJ_GET(Array2d, _0); Array2d& self = PK_OBJ_GET(Array2d, _0);
const Tuple& xy = CAST(Tuple&, _1); const Tuple& xy = CAST(Tuple&, _1);
if(is_int(xy[0]) && is_int(xy[1])){ if(is_int(xy[0]) && is_int(xy[1])) {
i64 col = xy[0].as<i64>(); i64 col = xy[0].as<i64>();
i64 row = xy[1].as<i64>(); i64 row = xy[1].as<i64>();
self.check_valid(vm, col, row); self.check_valid(vm, col, row);
return self._get(col, row); return self._get(col, row);
} }
if(is_type(xy[0], VM::tp_slice) && is_type(xy[1], VM::tp_slice)){ if(is_type(xy[0], VM::tp_slice) && is_type(xy[1], VM::tp_slice)) {
HANDLE_SLICE(); HANDLE_SLICE();
PyVar new_array_obj = vm->new_user_object<Array2d>(); PyVar new_array_obj = vm->new_user_object<Array2d>();
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj); Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
new_array.init(stop_col - start_col, stop_row - start_row); new_array.init(stop_col - start_col, stop_row - start_row);
for(int j = start_row; j < stop_row; j++){ for(int j = start_row; j < stop_row; j++) {
for(int i = start_col; i < stop_col; i++){ for(int i = start_col; i < stop_col; i++) {
new_array._set(i - start_col, j - start_row, self._get(i, j)); new_array._set(i - start_col, j - start_row, self._get(i, j));
} }
} }
@ -140,10 +134,10 @@ struct Array2d{
vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index"); vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index");
}); });
vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1, PyVar _2){ vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1, PyVar _2) {
Array2d& self = PK_OBJ_GET(Array2d, _0); Array2d& self = PK_OBJ_GET(Array2d, _0);
const Tuple& xy = CAST(Tuple&, _1); const Tuple& xy = CAST(Tuple&, _1);
if(is_int(xy[0]) && is_int(xy[1])){ if(is_int(xy[0]) && is_int(xy[1])) {
i64 col = xy[0].as<i64>(); i64 col = xy[0].as<i64>();
i64 row = xy[1].as<i64>(); i64 row = xy[1].as<i64>();
self.check_valid(vm, col, row); self.check_valid(vm, col, row);
@ -151,11 +145,11 @@ struct Array2d{
return; return;
} }
if(is_type(xy[0], VM::tp_slice) && is_type(xy[1], VM::tp_slice)){ if(is_type(xy[0], VM::tp_slice) && is_type(xy[1], VM::tp_slice)) {
HANDLE_SLICE(); HANDLE_SLICE();
bool is_basic_type = false; bool is_basic_type = false;
switch(vm->_tp(_2).index){ switch(vm->_tp(_2).index) {
case VM::tp_int.index: is_basic_type = true; break; case VM::tp_int.index: is_basic_type = true; break;
case VM::tp_float.index: is_basic_type = true; break; case VM::tp_float.index: is_basic_type = true; break;
case VM::tp_str.index: is_basic_type = true; break; case VM::tp_str.index: is_basic_type = true; break;
@ -163,19 +157,19 @@ struct Array2d{
default: is_basic_type = _2 == vm->None; default: is_basic_type = _2 == vm->None;
} }
if(is_basic_type){ if(is_basic_type) {
for(int j = 0; j < slice_height; j++) for(int j = 0; j < slice_height; j++)
for(int i = 0; i < slice_width; i++) for(int i = 0; i < slice_width; i++)
self._set(i + start_col, j + start_row, _2); self._set(i + start_col, j + start_row, _2);
return; return;
} }
if(!vm->is_user_type<Array2d>(_2)){ if(!vm->is_user_type<Array2d>(_2)) {
vm->TypeError(_S("expected int/float/str/bool/None or an array2d instance")); vm->TypeError(_S("expected int/float/str/bool/None or an array2d instance"));
} }
Array2d& other = PK_OBJ_GET(Array2d, _2); Array2d& other = PK_OBJ_GET(Array2d, _2);
if(slice_width != other.n_cols || slice_height != other.n_rows){ if(slice_width != other.n_cols || slice_height != other.n_rows) {
vm->ValueError("array2d size does not match the slice size"); vm->ValueError("array2d size does not match the slice size");
} }
for(int j = 0; j < slice_height; j++) for(int j = 0; j < slice_height; j++)
@ -186,161 +180,163 @@ struct Array2d{
vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index"); vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index");
}); });
#undef HANDLE_SLICE #undef HANDLE_SLICE
vm->bind_func(type, "tolist", 1, [](VM* vm, ArgsView args){ vm->bind_func(type, "tolist", 1, [](VM* vm, ArgsView args) {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
List t(self.n_rows); List t(self.n_rows);
for(int j = 0; j < self.n_rows; j++){ for(int j = 0; j < self.n_rows; j++) {
List row(self.n_cols); List row(self.n_cols);
for(int i = 0; i < self.n_cols; i++) row[i] = self._get(i, j); for(int i = 0; i < self.n_cols; i++)
row[i] = self._get(i, j);
t[j] = VAR(std::move(row)); t[j] = VAR(std::move(row));
} }
return VAR(std::move(t)); return VAR(std::move(t));
}); });
vm->bind__len__(type->as<Type>(), [](VM* vm, PyVar _0){ vm->bind__len__(type->as<Type>(), [](VM* vm, PyVar _0) {
Array2d& self = PK_OBJ_GET(Array2d, _0); Array2d& self = PK_OBJ_GET(Array2d, _0);
return (i64)self.numel; return (i64)self.numel;
}); });
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar _0) -> Str{ vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar _0) -> Str {
Array2d& self = PK_OBJ_GET(Array2d, _0); Array2d& self = PK_OBJ_GET(Array2d, _0);
return _S("array2d(", self.n_cols, ", ", self.n_rows, ')'); return _S("array2d(", self.n_cols, ", ", self.n_rows, ')');
}); });
vm->bind_func(type, "map", 2, [](VM* vm, ArgsView args){ vm->bind_func(type, "map", 2, [](VM* vm, ArgsView args) {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
PyVar f = args[1]; PyVar f = args[1];
PyVar new_array_obj = vm->new_user_object<Array2d>(); PyVar new_array_obj = vm->new_user_object<Array2d>();
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj); Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
new_array.init(self.n_cols, self.n_rows); new_array.init(self.n_cols, self.n_rows);
for(int i = 0; i < new_array.numel; i++){ for(int i = 0; i < new_array.numel; i++) {
new_array.data[i] = vm->call(f, self.data[i]); new_array.data[i] = vm->call(f, self.data[i]);
} }
return new_array_obj; return new_array_obj;
}); });
vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args){ vm->bind_func(type, "copy", 1, [](VM* vm, ArgsView args) {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
PyVar new_array_obj = vm->new_user_object<Array2d>(); PyVar new_array_obj = vm->new_user_object<Array2d>();
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj); Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
new_array.init(self.n_cols, self.n_rows); new_array.init(self.n_cols, self.n_rows);
for(int i = 0; i < new_array.numel; i++){ for(int i = 0; i < new_array.numel; i++) {
new_array.data[i] = self.data[i]; new_array.data[i] = self.data[i];
} }
return new_array_obj; return new_array_obj;
}); });
vm->bind_func(type, "fill_", 2, [](VM* vm, ArgsView args){ vm->bind_func(type, "fill_", 2, [](VM* vm, ArgsView args) {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
for(int i = 0; i < self.numel; i++){ for(int i = 0; i < self.numel; i++) {
self.data[i] = args[1]; self.data[i] = args[1];
} }
return vm->None; return vm->None;
}); });
vm->bind_func(type, "apply_", 2, [](VM* vm, ArgsView args){ vm->bind_func(type, "apply_", 2, [](VM* vm, ArgsView args) {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
PyVar f = args[1]; PyVar f = args[1];
for(int i = 0; i < self.numel; i++){ for(int i = 0; i < self.numel; i++) {
self.data[i] = vm->call(f, self.data[i]); self.data[i] = vm->call(f, self.data[i]);
} }
return vm->None; return vm->None;
}); });
vm->bind_func(type, "copy_", 2, [](VM* vm, ArgsView args){ vm->bind_func(type, "copy_", 2, [](VM* vm, ArgsView args) {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
if(is_type(args[1], VM::tp_list)){ if(is_type(args[1], VM::tp_list)) {
const List& list = PK_OBJ_GET(List, args[1]); const List& list = PK_OBJ_GET(List, args[1]);
if(list.size() != self.numel){ if(list.size() != self.numel) {
vm->ValueError("list size must be equal to the number of elements in the array2d"); vm->ValueError("list size must be equal to the number of elements in the array2d");
} }
for(int i = 0; i < self.numel; i++){ for(int i = 0; i < self.numel; i++) {
self.data[i] = list[i]; self.data[i] = list[i];
} }
return vm->None; return vm->None;
} }
Array2d& other = CAST(Array2d&, args[1]); Array2d& other = CAST(Array2d&, args[1]);
// if self and other have different sizes, re-initialize self // if self and other have different sizes, re-initialize self
if(self.n_cols != other.n_cols || self.n_rows != other.n_rows){ if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) {
delete self.data; delete self.data;
self.init(other.n_cols, other.n_rows); self.init(other.n_cols, other.n_rows);
} }
for(int i = 0; i < self.numel; i++){ for(int i = 0; i < self.numel; i++) {
self.data[i] = other.data[i]; self.data[i] = other.data[i];
} }
return vm->None; return vm->None;
}); });
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1){ vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
Array2d& self = PK_OBJ_GET(Array2d, _0); Array2d& self = PK_OBJ_GET(Array2d, _0);
if(!vm->is_user_type<Array2d>(_1)) return vm->NotImplemented; if(!vm->is_user_type<Array2d>(_1)) return vm->NotImplemented;
Array2d& other = PK_OBJ_GET(Array2d, _1); Array2d& other = PK_OBJ_GET(Array2d, _1);
if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) return vm->False; if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) return vm->False;
for(int i = 0; i < self.numel; i++){ for(int i = 0; i < self.numel; i++) {
if(vm->py_ne(self.data[i], other.data[i])) return vm->False; if(vm->py_ne(self.data[i], other.data[i])) return vm->False;
} }
return vm->True; return vm->True;
}); });
vm->bind(type, "count_neighbors(self, value, neighborhood='Moore') -> array2d[int]", [](VM* vm, ArgsView args){ vm->bind(type, "count_neighbors(self, value, neighborhood='Moore') -> array2d[int]", [](VM* vm, ArgsView args) {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
PyVar new_array_obj = vm->new_user_object<Array2d>(); PyVar new_array_obj = vm->new_user_object<Array2d>();
Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj); Array2d& new_array = PK_OBJ_GET(Array2d, new_array_obj);
new_array.init(self.n_cols, self.n_rows); new_array.init(self.n_cols, self.n_rows);
PyVar value = args[1]; PyVar value = args[1];
const Str& neighborhood = CAST(Str&, args[2]); const Str& neighborhood = CAST(Str&, args[2]);
if(neighborhood == "Moore"){ if(neighborhood == "Moore") {
for(int j = 0; j < new_array.n_rows; j++){ for(int j = 0; j < new_array.n_rows; j++) {
for(int i = 0; i < new_array.n_cols; i++){ for(int i = 0; i < new_array.n_cols; i++) {
int count = 0; int count = 0;
count += self.is_valid(i-1, j-1) && vm->py_eq(self._get(i-1, j-1), value); count += self.is_valid(i - 1, j - 1) && vm->py_eq(self._get(i - 1, j - 1), value);
count += self.is_valid(i, j-1) && vm->py_eq(self._get(i, j-1), value); count += self.is_valid(i, j - 1) && vm->py_eq(self._get(i, j - 1), value);
count += self.is_valid(i+1, j-1) && vm->py_eq(self._get(i+1, j-1), value); count += self.is_valid(i + 1, j - 1) && vm->py_eq(self._get(i + 1, j - 1), value);
count += self.is_valid(i-1, j) && vm->py_eq(self._get(i-1, j), value); count += self.is_valid(i - 1, j) && vm->py_eq(self._get(i - 1, j), value);
count += self.is_valid(i+1, j) && vm->py_eq(self._get(i+1, j), value); count += self.is_valid(i + 1, j) && vm->py_eq(self._get(i + 1, j), value);
count += self.is_valid(i-1, j+1) && vm->py_eq(self._get(i-1, j+1), value); count += self.is_valid(i - 1, j + 1) && vm->py_eq(self._get(i - 1, j + 1), value);
count += self.is_valid(i, j+1) && vm->py_eq(self._get(i, j+1), value); count += self.is_valid(i, j + 1) && vm->py_eq(self._get(i, j + 1), value);
count += self.is_valid(i+1, j+1) && vm->py_eq(self._get(i+1, j+1), value); count += self.is_valid(i + 1, j + 1) && vm->py_eq(self._get(i + 1, j + 1), value);
new_array._set(i, j, VAR(count)); new_array._set(i, j, VAR(count));
} }
} }
}else if(neighborhood == "von Neumann"){ } else if(neighborhood == "von Neumann") {
for(int j = 0; j < new_array.n_rows; j++){ for(int j = 0; j < new_array.n_rows; j++) {
for(int i = 0; i < new_array.n_cols; i++){ for(int i = 0; i < new_array.n_cols; i++) {
int count = 0; int count = 0;
count += self.is_valid(i, j-1) && vm->py_eq(self._get(i, j-1), value); count += self.is_valid(i, j - 1) && vm->py_eq(self._get(i, j - 1), value);
count += self.is_valid(i-1, j) && vm->py_eq(self._get(i-1, j), value); count += self.is_valid(i - 1, j) && vm->py_eq(self._get(i - 1, j), value);
count += self.is_valid(i+1, j) && vm->py_eq(self._get(i+1, j), value); count += self.is_valid(i + 1, j) && vm->py_eq(self._get(i + 1, j), value);
count += self.is_valid(i, j+1) && vm->py_eq(self._get(i, j+1), value); count += self.is_valid(i, j + 1) && vm->py_eq(self._get(i, j + 1), value);
new_array._set(i, j, VAR(count)); new_array._set(i, j, VAR(count));
} }
} }
}else{ } else {
vm->ValueError("neighborhood must be 'Moore' or 'von Neumann'"); vm->ValueError("neighborhood must be 'Moore' or 'von Neumann'");
} }
return new_array_obj; return new_array_obj;
}); });
vm->bind_func(type, "count", 2, [](VM* vm, ArgsView args){ vm->bind_func(type, "count", 2, [](VM* vm, ArgsView args) {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
PyVar value = args[1]; PyVar value = args[1];
int count = 0; int count = 0;
for(int i = 0; i < self.numel; i++) count += vm->py_eq(self.data[i], value); for(int i = 0; i < self.numel; i++)
count += vm->py_eq(self.data[i], value);
return VAR(count); return VAR(count);
}); });
vm->bind_func(type, "find_bounding_rect", 2, [](VM* vm, ArgsView args){ vm->bind_func(type, "find_bounding_rect", 2, [](VM* vm, ArgsView args) {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
PyVar value = args[1]; PyVar value = args[1];
int left = self.n_cols; int left = self.n_cols;
int top = self.n_rows; int top = self.n_rows;
int right = 0; int right = 0;
int bottom = 0; int bottom = 0;
for(int j = 0; j < self.n_rows; j++){ for(int j = 0; j < self.n_rows; j++) {
for(int i = 0; i < self.n_cols; i++){ for(int i = 0; i < self.n_cols; i++) {
if(vm->py_eq(self._get(i, j), value)){ if(vm->py_eq(self._get(i, j), value)) {
left = (std::min)(left, i); left = (std::min)(left, i);
top = (std::min)(top, j); top = (std::min)(top, j);
right = (std::max)(right, i); right = (std::max)(right, i);
@ -360,30 +356,30 @@ struct Array2d{
}); });
} }
void _gc_mark(VM* vm) const{ void _gc_mark(VM* vm) const {
for(int i = 0; i < numel; i++) vm->obj_gc_mark(data[i]); for(int i = 0; i < numel; i++)
vm->obj_gc_mark(data[i]);
} }
~Array2d(){ ~Array2d() { delete[] data; }
delete[] data;
}
}; };
struct Array2dIter {
struct Array2dIter{
PK_ALWAYS_PASS_BY_POINTER(Array2dIter) PK_ALWAYS_PASS_BY_POINTER(Array2dIter)
PyVar ref; PyVar ref;
Array2d* a; Array2d* a;
int i; int i;
Array2dIter(PyVar ref, Array2d* a): ref(ref), a(a), i(0){} Array2dIter(PyVar ref, Array2d* a) : ref(ref), a(a), i(0) {}
void _gc_mark(VM* vm) const{ vm->obj_gc_mark(ref); } void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
static void _register(VM* vm, PyObject* mod, PyObject* type){ static void _register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned{ return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
Array2dIter& self = PK_OBJ_GET(Array2dIter, _0); Array2dIter& self = PK_OBJ_GET(Array2dIter, _0);
if(self.i == self.a->numel) return 0; if(self.i == self.a->numel) return 0;
std::div_t res = std::div(self.i, self.a->n_cols); std::div_t res = std::div(self.i, self.a->n_cols);
@ -395,20 +391,19 @@ struct Array2dIter{
} }
}; };
void add_module_array2d(VM* vm){ void add_module_array2d(VM* vm) {
PyObject* mod = vm->new_module("array2d"); PyObject* mod = vm->new_module("array2d");
vm->register_user_class<Array2d>(mod, "array2d", VM::tp_object, true); vm->register_user_class<Array2d>(mod, "array2d", VM::tp_object, true);
vm->register_user_class<Array2dIter>(mod, "_array2d_iter"); vm->register_user_class<Array2dIter>(mod, "_array2d_iter");
Type array2d_iter_t = vm->_tp_user<Array2d>(); Type array2d_iter_t = vm->_tp_user<Array2d>();
vm->bind__iter__(array2d_iter_t, [](VM* vm, PyVar _0){ vm->bind__iter__(array2d_iter_t, [](VM* vm, PyVar _0) {
return vm->new_user_object<Array2dIter>(_0, &_0.obj_get<Array2d>()); return vm->new_user_object<Array2dIter>(_0, &_0.obj_get<Array2d>());
}); });
vm->_all_types[array2d_iter_t].op__iter__ = [](VM* vm, PyVar _0){ vm->_all_types[array2d_iter_t].op__iter__ = [](VM* vm, PyVar _0) {
vm->new_stack_object<Array2dIter>(vm->_tp_user<Array2dIter>(), _0, &_0.obj_get<Array2d>()); vm->new_stack_object<Array2dIter>(vm->_tp_user<Array2dIter>(), _0, &_0.obj_get<Array2d>());
}; };
} }
} // namespace pkpy } // namespace pkpy

View File

@ -1,7 +1,7 @@
#include "pocketpy/modules/base64.hpp" #include "pocketpy/modules/base64.hpp"
#include "pocketpy/interpreter/bindings.hpp" #include "pocketpy/interpreter/bindings.hpp"
namespace pkpy{ namespace pkpy {
// https://github.com/zhicheng/base64/blob/master/base64.c // https://github.com/zhicheng/base64/blob/master/base64.c
@ -9,6 +9,7 @@ const char BASE64_PAD = '=';
const char BASE64DE_FIRST = '+'; const char BASE64DE_FIRST = '+';
const char BASE64DE_LAST = 'z'; const char BASE64DE_LAST = 'z';
// clang-format off
/* BASE 64 encode table */ /* BASE 64 encode table */
const char base64en[] = { const char base64en[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
@ -71,10 +72,9 @@ const unsigned char base64de[] = {
/* 'x', 'y', 'z', '{', '|', '}', '~', del, */ /* 'x', 'y', 'z', '{', '|', '}', '~', del, */
49, 50, 51, 255, 255, 255, 255, 255 49, 50, 51, 255, 255, 255, 255, 255
}; };
// clang-format on
static unsigned int static unsigned int base64_encode(const unsigned char* in, unsigned int inlen, char* out) {
base64_encode(const unsigned char *in, unsigned int inlen, char *out)
{
int s; int s;
unsigned int i; unsigned int i;
unsigned int j; unsigned int j;
@ -83,10 +83,10 @@ base64_encode(const unsigned char *in, unsigned int inlen, char *out)
s = 0; s = 0;
l = 0; l = 0;
for (i = j = 0; i < inlen; i++) { for(i = j = 0; i < inlen; i++) {
c = in[i]; c = in[i];
switch (s) { switch(s) {
case 0: case 0:
s = 1; s = 1;
out[j++] = base64en[(c >> 2) & 0x3F]; out[j++] = base64en[(c >> 2) & 0x3F];
@ -104,7 +104,7 @@ base64_encode(const unsigned char *in, unsigned int inlen, char *out)
l = c; l = c;
} }
switch (s) { switch(s) {
case 1: case 1:
out[j++] = base64en[(l & 0x3) << 4]; out[j++] = base64en[(l & 0x3) << 4];
out[j++] = BASE64_PAD; out[j++] = BASE64_PAD;
@ -121,34 +121,22 @@ base64_encode(const unsigned char *in, unsigned int inlen, char *out)
return j; return j;
} }
static unsigned int static unsigned int base64_decode(const char* in, unsigned int inlen, unsigned char* out) {
base64_decode(const char *in, unsigned int inlen, unsigned char *out)
{
unsigned int i; unsigned int i;
unsigned int j; unsigned int j;
unsigned char c; unsigned char c;
if (inlen & 0x3) { if(inlen & 0x3) { return 0; }
return 0;
}
for (i = j = 0; i < inlen; i++) { for(i = j = 0; i < inlen; i++) {
if (in[i] == BASE64_PAD) { if(in[i] == BASE64_PAD) { break; }
break; if(in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) { return 0; }
}
if (in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) {
return 0;
}
c = base64de[(unsigned char)in[i]]; c = base64de[(unsigned char)in[i]];
if (c == 255) { if(c == 255) { return 0; }
return 0;
}
switch (i & 0x3) { switch(i & 0x3) {
case 0: case 0: out[j] = (c << 2) & 0xFF; break;
out[j] = (c << 2) & 0xFF;
break;
case 1: case 1:
out[j++] |= (c >> 4) & 0x3; out[j++] |= (c >> 4) & 0x3;
out[j] = (c & 0xF) << 4; 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 >> 2) & 0xF;
out[j] = (c & 0x3) << 6; out[j] = (c & 0x3) << 6;
break; break;
case 3: case 3: out[j++] |= c; break;
out[j++] |= c;
break;
} }
} }
return j; return j;
} }
void add_module_base64(VM* vm){ void add_module_base64(VM* vm) {
PyObject* mod = vm->new_module("base64"); PyObject* mod = vm->new_module("base64");
// b64encode // b64encode
vm->bind_func(mod, "b64encode", 1, [](VM* vm, ArgsView args){ vm->bind_func(mod, "b64encode", 1, [](VM* vm, ArgsView args) {
Bytes& b = CAST(Bytes&, args[0]); Bytes& b = CAST(Bytes&, args[0]);
unsigned char* p = (unsigned char*)std::malloc(b.size() * 2); unsigned char* p = (unsigned char*)std::malloc(b.size() * 2);
int size = base64_encode((const unsigned char*)b.data(), b.size(), (char*)p); int size = base64_encode((const unsigned char*)b.data(), b.size(), (char*)p);
@ -178,7 +164,7 @@ void add_module_base64(VM* vm){
}); });
// b64decode // b64decode
vm->bind_func(mod, "b64decode", 1, [](VM* vm, ArgsView args){ vm->bind_func(mod, "b64decode", 1, [](VM* vm, ArgsView args) {
Bytes& b = CAST(Bytes&, args[0]); Bytes& b = CAST(Bytes&, args[0]);
unsigned char* p = (unsigned char*)std::malloc(b.size()); unsigned char* p = (unsigned char*)std::malloc(b.size());
int size = base64_decode((const char*)b.data(), b.size(), p); int size = base64_decode((const char*)b.data(), b.size(), p);

View File

@ -1,60 +1,57 @@
#include "pocketpy/modules/csv.hpp" #include "pocketpy/modules/csv.hpp"
#include "pocketpy/interpreter/bindings.hpp" #include "pocketpy/interpreter/bindings.hpp"
namespace pkpy{ namespace pkpy {
void add_module_csv(VM *vm){ void add_module_csv(VM* vm) {
PyObject* mod = vm->new_module("csv"); PyObject* mod = vm->new_module("csv");
vm->bind(mod, "reader(csvfile: list[str]) -> list[list]", [](VM* vm, ArgsView args){ vm->bind(mod, "reader(csvfile: list[str]) -> list[list]", [](VM* vm, ArgsView args) {
const List& csvfile = CAST(List&, args[0]); const List& csvfile = CAST(List&, args[0]);
List ret; List ret;
for(int i=0; i<csvfile.size(); i++){ for(int i = 0; i < csvfile.size(); i++) {
std::string_view line = CAST(Str&, csvfile[i]).sv(); std::string_view line = CAST(Str&, csvfile[i]).sv();
if(i == 0){ if(i == 0) {
// Skip utf8 BOM if there is any. // Skip utf8 BOM if there is any.
if (strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) line = line.substr(3); if(strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) line = line.substr(3);
} }
List row; List row;
int j; int j;
bool in_quote = false; bool in_quote = false;
std::string buffer; std::string buffer;
__NEXT_LINE: __NEXT_LINE:
j = 0; j = 0;
while(j < line.size()){ while(j < line.size()) {
switch(line[j]){ switch(line[j]) {
case '"': case '"':
if(in_quote){ if(in_quote) {
if(j+1 < line.size() && line[j+1] == '"'){ if(j + 1 < line.size() && line[j + 1] == '"') {
buffer += '"'; buffer += '"';
j++; j++;
}else{ } else {
in_quote = false; in_quote = false;
} }
}else{ } else {
in_quote = true; in_quote = true;
} }
break; break;
case ',': case ',':
if(in_quote){ if(in_quote) {
buffer += line[j]; buffer += line[j];
}else{ } else {
row.push_back(VAR(buffer)); row.push_back(VAR(buffer));
buffer.clear(); buffer.clear();
} }
break; break;
case '\r': case '\r': break; // ignore
break; // ignore default: buffer += line[j]; break;
default:
buffer += line[j];
break;
} }
j++; j++;
} }
if(in_quote){ if(in_quote) {
if(i == csvfile.size()-1){ if(i == csvfile.size() - 1) {
vm->ValueError("unterminated quote"); vm->ValueError("unterminated quote");
}else{ } else {
buffer += '\n'; buffer += '\n';
i++; i++;
line = CAST(Str&, csvfile[i]).sv(); line = CAST(Str&, csvfile[i]).sv();
@ -67,22 +64,18 @@ __NEXT_LINE:
return VAR(std::move(ret)); return VAR(std::move(ret));
}); });
vm->bind(mod, "DictReader(csvfile: list[str]) -> list[dict]", [](VM* vm, ArgsView args){ vm->bind(mod, "DictReader(csvfile: list[str]) -> list[dict]", [](VM* vm, ArgsView args) {
PyVar csv_reader = vm->_modules["csv"]->attr("reader"); PyVar csv_reader = vm->_modules["csv"]->attr("reader");
PyVar ret_obj = vm->call(csv_reader, args[0]); PyVar ret_obj = vm->call(csv_reader, args[0]);
const List& ret = CAST(List&, ret_obj); const List& ret = CAST(List&, ret_obj);
if(ret.size() == 0){ if(ret.size() == 0) { vm->ValueError("empty csvfile"); }
vm->ValueError("empty csvfile");
}
const List& header = CAST(List&, ret[0]); const List& header = CAST(List&, ret[0]);
List new_ret; List new_ret;
for(int i=1; i<ret.size(); i++){ for(int i = 1; i < ret.size(); i++) {
const List& row = CAST(List&, ret[i]); const List& row = CAST(List&, ret[i]);
if(row.size() != header.size()){ if(row.size() != header.size()) { vm->ValueError("row.size() != header.size()"); }
vm->ValueError("row.size() != header.size()");
}
Dict row_dict; Dict row_dict;
for(int j=0; j<header.size(); j++){ for(int j = 0; j < header.size(); j++) {
row_dict.set(vm, header[j], row[j]); row_dict.set(vm, header[j], row[j]);
} }
new_ret.push_back(VAR(std::move(row_dict))); new_ret.push_back(VAR(std::move(row_dict)));

View File

@ -1,15 +1,15 @@
#include "pocketpy/modules/dataclasses.hpp" #include "pocketpy/modules/dataclasses.hpp"
#include "pocketpy/interpreter/bindings.hpp" #include "pocketpy/interpreter/bindings.hpp"
namespace pkpy{ namespace pkpy {
static void patch__init__(VM* vm, Type cls){ static void patch__init__(VM* vm, Type cls) {
vm->bind(vm->_t(cls), "__init__(self, *args, **kwargs)", [](VM* vm, ArgsView _view){ vm->bind(vm->_t(cls), "__init__(self, *args, **kwargs)", [](VM* vm, ArgsView _view) {
PyVar self = _view[0]; PyVar self = _view[0];
const Tuple& args = CAST(Tuple&, _view[1]); const Tuple& args = CAST(Tuple&, _view[1]);
const Dict& kwargs_ = CAST(Dict&, _view[2]); const Dict& kwargs_ = CAST(Dict&, _view[2]);
NameDict kwargs; NameDict kwargs;
kwargs_.apply([&](PyVar k, PyVar v){ kwargs_.apply([&](PyVar k, PyVar v) {
kwargs.set(CAST(Str&, k), v); kwargs.set(CAST(Str&, k), v);
}); });
@ -19,25 +19,26 @@ static void patch__init__(VM* vm, Type cls){
const auto& fields = cls_info->annotated_fields; const auto& fields = cls_info->annotated_fields;
int i = 0; // index into args int i = 0; // index into args
for(StrName field: fields){ for(StrName field: fields) {
if(kwargs.contains(field)){ if(kwargs.contains(field)) {
self->attr().set(field, kwargs[field]); self->attr().set(field, kwargs[field]);
kwargs.del(field); kwargs.del(field);
}else{ } else {
if(i < args.size()){ if(i < args.size()) {
self->attr().set(field, args[i]); self->attr().set(field, args[i]);
++i; ++i;
}else if(cls_d.contains(field)){ // has default value } else if(cls_d.contains(field)) { // has default value
self->attr().set(field, cls_d[field]); self->attr().set(field, cls_d[field]);
}else{ } else {
vm->TypeError(_S(cls_info->name, " missing required argument ", field.escape())); vm->TypeError(_S(cls_info->name, " missing required argument ", field.escape()));
} }
} }
} }
if(args.size() > i){ if(args.size() > i) {
vm->TypeError(_S(cls_info->name, " takes ", fields.size(), " positional arguments but ", args.size(), " were given")); vm->TypeError(
_S(cls_info->name, " takes ", fields.size(), " positional arguments but ", args.size(), " were given"));
} }
if(kwargs.size() > 0){ if(kwargs.size() > 0) {
StrName unexpected_key = kwargs.items()[0].first; StrName unexpected_key = kwargs.items()[0].first;
vm->TypeError(_S(cls_info->name, " got an unexpected keyword argument ", unexpected_key.escape())); vm->TypeError(_S(cls_info->name, " got an unexpected keyword argument ", unexpected_key.escape()));
} }
@ -45,17 +46,19 @@ static void patch__init__(VM* vm, Type cls){
}); });
} }
static void patch__repr__(VM* vm, Type cls){ static void patch__repr__(VM* vm, Type cls) {
vm->bind__repr__(cls, [](VM* vm, PyVar _0) -> Str{ vm->bind__repr__(cls, [](VM* vm, PyVar _0) -> Str {
const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)]; const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)];
const auto& fields = cls_info->annotated_fields; const auto& fields = cls_info->annotated_fields;
const NameDict& obj_d = _0->attr(); const NameDict& obj_d = _0->attr();
SStream ss; SStream ss;
ss << cls_info->name << "("; ss << cls_info->name << "(";
bool first = true; bool first = true;
for(StrName field: fields){ for(StrName field: fields) {
if(first) first = false; if(first)
else ss << ", "; first = false;
else
ss << ", ";
ss << field << "=" << vm->py_repr(obj_d[field]); ss << field << "=" << vm->py_repr(obj_d[field]);
} }
ss << ")"; ss << ")";
@ -63,12 +66,12 @@ static void patch__repr__(VM* vm, Type cls){
}); });
} }
static void patch__eq__(VM* vm, Type cls){ static void patch__eq__(VM* vm, Type cls) {
vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1){ vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1) {
if(vm->_tp(_0) != vm->_tp(_1)) return vm->NotImplemented; if(vm->_tp(_0) != vm->_tp(_1)) return vm->NotImplemented;
const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)]; const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)];
const auto& fields = cls_info->annotated_fields; const auto& fields = cls_info->annotated_fields;
for(StrName field: fields){ for(StrName field: fields) {
PyVar lhs = _0->attr(field); PyVar lhs = _0->attr(field);
PyVar rhs = _1->attr(field); PyVar rhs = _1->attr(field);
if(vm->py_ne(lhs, rhs)) return vm->False; if(vm->py_ne(lhs, rhs)) return vm->False;
@ -77,10 +80,10 @@ static void patch__eq__(VM* vm, Type cls){
}); });
} }
void add_module_dataclasses(VM* vm){ void add_module_dataclasses(VM* vm) {
PyObject* mod = vm->new_module("dataclasses"); PyObject* mod = vm->new_module("dataclasses");
vm->bind_func(mod, "dataclass", 1, [](VM* vm, ArgsView args){ vm->bind_func(mod, "dataclass", 1, [](VM* vm, ArgsView args) {
vm->check_type(args[0], VM::tp_type); vm->check_type(args[0], VM::tp_type);
Type cls = PK_OBJ_GET(Type, args[0]); Type cls = PK_OBJ_GET(Type, args[0]);
NameDict& cls_d = args[0]->attr(); NameDict& cls_d = args[0]->attr();
@ -91,11 +94,11 @@ void add_module_dataclasses(VM* vm){
const auto& fields = vm->_all_types[cls].annotated_fields; const auto& fields = vm->_all_types[cls].annotated_fields;
bool has_default = false; bool has_default = false;
for(StrName field: fields){ for(StrName field: fields) {
if(cls_d.contains(field)){ if(cls_d.contains(field)) {
has_default = true; has_default = true;
}else{ } else {
if(has_default){ if(has_default) {
vm->TypeError(_S("non-default argument ", field.escape(), " follows default argument")); vm->TypeError(_S("non-default argument ", field.escape(), " follows default argument"));
} }
} }
@ -103,11 +106,11 @@ void add_module_dataclasses(VM* vm){
return args[0]; return args[0];
}); });
vm->bind_func(mod, "asdict", 1, [](VM* vm, ArgsView args){ vm->bind_func(mod, "asdict", 1, [](VM* vm, ArgsView args) {
const auto& fields = vm->_tp_info(args[0])->annotated_fields; const auto& fields = vm->_tp_info(args[0])->annotated_fields;
const NameDict& obj_d = args[0]->attr(); const NameDict& obj_d = args[0]->attr();
Dict d; Dict d;
for(StrName field: fields){ for(StrName field: fields) {
d.set(vm, VAR(field.sv()), obj_d[field]); d.set(vm, VAR(field.sv()), obj_d[field]);
} }
return VAR(std::move(d)); return VAR(std::move(d));

View File

@ -3,193 +3,161 @@
#include <cmath> #include <cmath>
namespace pkpy{ namespace pkpy {
// https://easings.net/ // https://easings.net/
const double kPi = 3.1415926545; const double kPi = 3.1415926545;
static double easeLinear( double x ) { static double easeLinear(double x) { return x; }
return x;
}
static double easeInSine( double x ) { static double easeInSine(double x) { return 1.0 - std::cos(x * kPi / 2); }
return 1.0 - std::cos( x * kPi / 2 );
}
static double easeOutSine( double x ) { static double easeOutSine(double x) { return std::sin(x * kPi / 2); }
return std::sin( x * kPi / 2 );
}
static double easeInOutSine( double x ) { static double easeInOutSine(double x) { return -(std::cos(kPi * x) - 1) / 2; }
return -( std::cos( kPi * x ) - 1 ) / 2;
}
static double easeInQuad( double x ) { static double easeInQuad(double x) { return x * x; }
return x * x;
}
static double easeOutQuad( double x ) { static double easeOutQuad(double x) { return 1 - std::pow(1 - x, 2); }
return 1 - std::pow( 1 - x, 2 );
}
static double easeInOutQuad( double x ) { static double easeInOutQuad(double x) {
if( x < 0.5 ) { if(x < 0.5) {
return 2 * x * x; return 2 * x * x;
} else { } else {
return 1 - std::pow( -2 * x + 2, 2 ) / 2; return 1 - std::pow(-2 * x + 2, 2) / 2;
} }
} }
static double easeInCubic( double x ) { static double easeInCubic(double x) { return x * x * x; }
return x * x * x;
}
static double easeOutCubic( double x ) { static double easeOutCubic(double x) { return 1 - std::pow(1 - x, 3); }
return 1 - std::pow( 1 - x, 3 );
}
static double easeInOutCubic( double x ) { static double easeInOutCubic(double x) {
if( x < 0.5 ) { if(x < 0.5) {
return 4 * x * x * x; return 4 * x * x * x;
} else { } else {
return 1 - std::pow( -2 * x + 2, 3 ) / 2; return 1 - std::pow(-2 * x + 2, 3) / 2;
} }
} }
static double easeInQuart( double x ) { static double easeInQuart(double x) { return std::pow(x, 4); }
return std::pow( x, 4 );
}
static double easeOutQuart( double x ) { static double easeOutQuart(double x) { return 1 - std::pow(1 - x, 4); }
return 1 - std::pow( 1 - x, 4 );
}
static double easeInOutQuart( double x ) { static double easeInOutQuart(double x) {
if( x < 0.5 ) { if(x < 0.5) {
return 8 * std::pow( x, 4 ); return 8 * std::pow(x, 4);
} else { } else {
return 1 - std::pow( -2 * x + 2, 4 ) / 2; return 1 - std::pow(-2 * x + 2, 4) / 2;
} }
} }
static double easeInQuint( double x ) { static double easeInQuint(double x) { return std::pow(x, 5); }
return std::pow( x, 5 );
}
static double easeOutQuint( double x ) { static double easeOutQuint(double x) { return 1 - std::pow(1 - x, 5); }
return 1 - std::pow( 1 - x, 5 );
}
static double easeInOutQuint( double x ) { static double easeInOutQuint(double x) {
if( x < 0.5 ) { if(x < 0.5) {
return 16 * std::pow( x, 5 ); return 16 * std::pow(x, 5);
} else { } else {
return 1 - std::pow( -2 * x + 2, 5 ) / 2; return 1 - std::pow(-2 * x + 2, 5) / 2;
} }
} }
static double easeInExpo( double x ) { static double easeInExpo(double x) { return x == 0 ? 0 : std::pow(2, 10 * x - 10); }
return x == 0 ? 0 : std::pow( 2, 10 * x - 10 );
}
static double easeOutExpo( double x ) { static double easeOutExpo(double x) { return x == 1 ? 1 : 1 - std::pow(2, -10 * x); }
return x == 1 ? 1 : 1 - std::pow( 2, -10 * x );
}
static double easeInOutExpo( double x ) { static double easeInOutExpo(double x) {
if( x == 0 ) { if(x == 0) {
return 0; return 0;
} else if( x == 1 ) { } else if(x == 1) {
return 1; return 1;
} else if( x < 0.5 ) { } else if(x < 0.5) {
return std::pow( 2, 20 * x - 10 ) / 2; return std::pow(2, 20 * x - 10) / 2;
} else { } else {
return (2 - std::pow( 2, -20 * x + 10 )) / 2; return (2 - std::pow(2, -20 * x + 10)) / 2;
} }
} }
static double easeInCirc( double x ) { static double easeInCirc(double x) { return 1 - std::sqrt(1 - std::pow(x, 2)); }
return 1 - std::sqrt( 1 - std::pow( x, 2 ) );
}
static double easeOutCirc( double x ) { static double easeOutCirc(double x) { return std::sqrt(1 - std::pow(x - 1, 2)); }
return std::sqrt( 1 - std::pow( x - 1, 2 ) );
}
static double easeInOutCirc( double x ) { static double easeInOutCirc(double x) {
if( x < 0.5 ) { if(x < 0.5) {
return (1 - std::sqrt( 1 - std::pow( 2 * x, 2 ) )) / 2; return (1 - std::sqrt(1 - std::pow(2 * x, 2))) / 2;
} else { } else {
return (std::sqrt( 1 - std::pow( -2 * x + 2, 2 ) ) + 1) / 2; return (std::sqrt(1 - std::pow(-2 * x + 2, 2)) + 1) / 2;
} }
} }
static double easeInBack( double x ) { static double easeInBack(double x) {
const double c1 = 1.70158; const double c1 = 1.70158;
const double c3 = c1 + 1; const double c3 = c1 + 1;
return c3 * x * x * x - c1 * x * x; return c3 * x * x * x - c1 * x * x;
} }
static double easeOutBack( double x ) { static double easeOutBack(double x) {
const double c1 = 1.70158; const double c1 = 1.70158;
const double c3 = c1 + 1; const double c3 = c1 + 1;
return 1 + c3 * std::pow( x - 1, 3 ) + c1 * std::pow( x - 1, 2 ); return 1 + c3 * std::pow(x - 1, 3) + c1 * std::pow(x - 1, 2);
} }
static double easeInOutBack( double x ) { static double easeInOutBack(double x) {
const double c1 = 1.70158; const double c1 = 1.70158;
const double c2 = c1 * 1.525; const double c2 = c1 * 1.525;
if( x < 0.5 ) { if(x < 0.5) {
return (std::pow( 2 * x, 2 ) * ((c2 + 1) * 2 * x - c2)) / 2; return (std::pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2;
} else { } else {
return (std::pow( 2 * x - 2, 2 ) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2; return (std::pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;
} }
} }
static double easeInElastic( double x ) { static double easeInElastic(double x) {
const double c4 = (2 * kPi) / 3; const double c4 = (2 * kPi) / 3;
if( x == 0 ) { if(x == 0) {
return 0; return 0;
} else if( x == 1 ) { } else if(x == 1) {
return 1; return 1;
} else { } else {
return -std::pow( 2, 10 * x - 10 ) * std::sin( (x * 10 - 10.75) * c4 ); return -std::pow(2, 10 * x - 10) * std::sin((x * 10 - 10.75) * c4);
} }
} }
static double easeOutElastic( double x ) { static double easeOutElastic(double x) {
const double c4 = (2 * kPi) / 3; const double c4 = (2 * kPi) / 3;
if( x == 0 ) { if(x == 0) {
return 0; return 0;
} else if( x == 1 ) { } else if(x == 1) {
return 1; return 1;
} else { } else {
return std::pow( 2, -10 * x ) * std::sin( (x * 10 - 0.75) * c4 ) + 1; return std::pow(2, -10 * x) * std::sin((x * 10 - 0.75) * c4) + 1;
} }
} }
static double easeInOutElastic( double x ) { static double easeInOutElastic(double x) {
const double c5 = (2 * kPi) / 4.5; const double c5 = (2 * kPi) / 4.5;
if( x == 0 ) { if(x == 0) {
return 0; return 0;
} else if( x == 1 ) { } else if(x == 1) {
return 1; return 1;
} else if( x < 0.5 ) { } else if(x < 0.5) {
return -(std::pow( 2, 20 * x - 10 ) * std::sin( (20 * x - 11.125) * c5 )) / 2; return -(std::pow(2, 20 * x - 10) * std::sin((20 * x - 11.125) * c5)) / 2;
} else { } else {
return (std::pow( 2, -20 * x + 10 ) * std::sin( (20 * x - 11.125) * c5 )) / 2 + 1; return (std::pow(2, -20 * x + 10) * std::sin((20 * x - 11.125) * c5)) / 2 + 1;
} }
} }
static double easeOutBounce( double x ) { static double easeOutBounce(double x) {
const double n1 = 7.5625; const double n1 = 7.5625;
const double d1 = 2.75; const double d1 = 2.75;
if( x < 1 / d1 ) { if(x < 1 / d1) {
return n1 * x * x; return n1 * x * x;
} else if( x < 2 / d1 ) { } else if(x < 2 / d1) {
x -= 1.5 / d1; x -= 1.5 / d1;
return n1 * x * x + 0.75; return n1 * x * x + 0.75;
} else if( x < 2.5 / d1 ) { } else if(x < 2.5 / d1) {
x -= 2.25 / d1; x -= 2.25 / d1;
return n1 * x * x + 0.9375; return n1 * x * x + 0.9375;
} else { } else {
@ -198,21 +166,17 @@ static double easeOutBounce( double x ) {
} }
} }
static double easeInBounce( double x ) { static double easeInBounce(double x) { return 1 - easeOutBounce(1 - x); }
return 1 - easeOutBounce(1 - x);
static double easeInOutBounce(double x) {
return x < 0.5 ? (1 - easeOutBounce(1 - 2 * x)) / 2 : (1 + easeOutBounce(2 * x - 1)) / 2;
} }
static double easeInOutBounce( double x ) { void add_module_easing(VM* vm) {
return x < 0.5
? (1 - easeOutBounce(1 - 2 * x)) / 2
: (1 + easeOutBounce(2 * x - 1)) / 2;
}
void add_module_easing(VM* vm){
PyObject* mod = vm->new_module("easing"); PyObject* mod = vm->new_module("easing");
#define EASE(name) \ #define EASE(name) \
vm->bind_func(mod, #name, 1, [](VM* vm, ArgsView args){ \ vm->bind_func(mod, #name, 1, [](VM* vm, ArgsView args) { \
f64 t = CAST(f64, args[0]); \ f64 t = CAST(f64, args[0]); \
return VAR(ease##name(t)); \ return VAR(ease##name(t)); \
}); });

View File

@ -6,7 +6,7 @@
#include <cstdio> #include <cstdio>
#endif #endif
namespace pkpy{ namespace pkpy {
#if PK_ENABLE_OS #if PK_ENABLE_OS
@ -19,7 +19,7 @@ struct FileIO {
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);
}; };
static FILE* io_fopen(const char* name, const char* mode){ static FILE* io_fopen(const char* name, const char* mode) {
#if _MSC_VER #if _MSC_VER
FILE* fp; FILE* fp;
errno_t err = fopen_s(&fp, name, mode); errno_t err = fopen_s(&fp, name, mode);
@ -30,7 +30,7 @@ static FILE* io_fopen(const char* name, const char* mode){
#endif #endif
} }
static size_t io_fread(void* buffer, size_t size, size_t count, FILE* fp){ static size_t io_fread(void* buffer, size_t size, size_t count, FILE* fp) {
#if _MSC_VER #if _MSC_VER
return fread_s(buffer, std::numeric_limits<size_t>::max(), size, count, fp); return fread_s(buffer, std::numeric_limits<size_t>::max(), size, count, fp);
#else #else
@ -38,7 +38,7 @@ static size_t io_fread(void* buffer, size_t size, size_t count, FILE* fp){
#endif #endif
} }
unsigned char* _default_import_handler(const char* name, int* out_size){ unsigned char* _default_import_handler(const char* name, int* out_size) {
bool exists = std::filesystem::exists(std::filesystem::path(name)); bool exists = std::filesystem::exists(std::filesystem::path(name));
if(!exists) return nullptr; if(!exists) return nullptr;
FILE* fp = io_fopen(name, "rb"); FILE* fp = io_fopen(name, "rb");
@ -54,24 +54,22 @@ unsigned char* _default_import_handler(const char* name, int* out_size){
return buffer; return buffer;
}; };
void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args){ vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args) {
Type cls = PK_OBJ_GET(Type, args[0]); Type cls = PK_OBJ_GET(Type, args[0]);
return vm->new_object<FileIO>(cls, vm, return vm->new_object<FileIO>(cls, vm, py_cast<Str&>(vm, args[1]), py_cast<Str&>(vm, args[2]));
py_cast<Str&>(vm, args[1]),
py_cast<Str&>(vm, args[2]));
}); });
vm->bind(type, "read(self, size=-1)", [](VM* vm, ArgsView args){ vm->bind(type, "read(self, size=-1)", [](VM* vm, ArgsView args) {
FileIO& io = PK_OBJ_GET(FileIO, args[0]); FileIO& io = PK_OBJ_GET(FileIO, args[0]);
i64 size = CAST(i64, args[1]); i64 size = CAST(i64, args[1]);
i64 buffer_size; i64 buffer_size;
if(size < 0){ if(size < 0) {
long current = ftell(io.fp); long current = ftell(io.fp);
fseek(io.fp, 0, SEEK_END); fseek(io.fp, 0, SEEK_END);
buffer_size = ftell(io.fp); buffer_size = ftell(io.fp);
fseek(io.fp, current, SEEK_SET); fseek(io.fp, current, SEEK_SET);
}else{ } else {
buffer_size = size; buffer_size = size;
} }
unsigned char* buffer = (unsigned char*)std::malloc(buffer_size); unsigned char* buffer = (unsigned char*)std::malloc(buffer_size);
@ -79,32 +77,30 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){
assert(actual_size <= buffer_size); assert(actual_size <= buffer_size);
// in text mode, CR may be dropped, which may cause `actual_size < buffer_size` // in text mode, CR may be dropped, which may cause `actual_size < buffer_size`
Bytes b(buffer, actual_size); Bytes b(buffer, actual_size);
if(io.is_text){ if(io.is_text) { return VAR(std::string_view((char*)b.data(), b.size())); }
return VAR(std::string_view((char*)b.data(), b.size()));
}
return VAR(std::move(b)); return VAR(std::move(b));
}); });
vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args){ vm->bind_func(type, "write", 2, [](VM* vm, ArgsView args) {
FileIO& io = PK_OBJ_GET(FileIO, args[0]); FileIO& io = PK_OBJ_GET(FileIO, args[0]);
if(io.is_text){ if(io.is_text) {
Str& s = CAST(Str&, args[1]); Str& s = CAST(Str&, args[1]);
fwrite(s.data, 1, s.length(), io.fp); fwrite(s.data, 1, s.length(), io.fp);
}else{ } else {
Bytes& buffer = CAST(Bytes&, args[1]); Bytes& buffer = CAST(Bytes&, args[1]);
fwrite(buffer.data(), 1, buffer.size(), io.fp); fwrite(buffer.data(), 1, buffer.size(), io.fp);
} }
return vm->None; return vm->None;
}); });
vm->bind_func(type, "tell", 1, [](VM* vm, ArgsView args){ vm->bind_func(type, "tell", 1, [](VM* vm, ArgsView args) {
FileIO& io = PK_OBJ_GET(FileIO, args[0]); FileIO& io = PK_OBJ_GET(FileIO, args[0]);
long pos = ftell(io.fp); long pos = ftell(io.fp);
if(pos == -1) vm->IOError(strerror(errno)); if(pos == -1) vm->IOError(strerror(errno));
return VAR(pos); return VAR(pos);
}); });
vm->bind_func(type, "seek", 3, [](VM* vm, ArgsView args){ vm->bind_func(type, "seek", 3, [](VM* vm, ArgsView args) {
FileIO& io = PK_OBJ_GET(FileIO, args[0]); FileIO& io = PK_OBJ_GET(FileIO, args[0]);
long offset = CAST(long, args[1]); long offset = CAST(long, args[1]);
int whence = CAST(int, args[2]); int whence = CAST(int, args[2]);
@ -113,13 +109,13 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){
return vm->None; return vm->None;
}); });
vm->bind_func(type, "close", 1, [](VM* vm, ArgsView args){ vm->bind_func(type, "close", 1, [](VM* vm, ArgsView args) {
FileIO& io = PK_OBJ_GET(FileIO, args[0]); FileIO& io = PK_OBJ_GET(FileIO, args[0]);
io.close(); io.close();
return vm->None; return vm->None;
}); });
vm->bind_func(type, __exit__, 1, [](VM* vm, ArgsView args){ vm->bind_func(type, __exit__, 1, [](VM* vm, ArgsView args) {
FileIO& io = PK_OBJ_GET(FileIO, args[0]); FileIO& io = PK_OBJ_GET(FileIO, args[0]);
io.close(); io.close();
return vm->None; return vm->None;
@ -128,19 +124,19 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){
vm->bind_func(type, __enter__, 1, PK_LAMBDA(args[0])); vm->bind_func(type, __enter__, 1, PK_LAMBDA(args[0]));
} }
FileIO::FileIO(VM* vm, const Str& file, const Str& mode){ FileIO::FileIO(VM* vm, const Str& file, const Str& mode) {
this->is_text = mode.sv().find("b") == std::string::npos; this->is_text = mode.sv().find("b") == std::string::npos;
fp = io_fopen(file.c_str(), mode.c_str()); fp = io_fopen(file.c_str(), mode.c_str());
if(!fp) vm->IOError(strerror(errno)); if(!fp) vm->IOError(strerror(errno));
} }
void FileIO::close(){ void FileIO::close() {
if(fp == nullptr) return; if(fp == nullptr) return;
fclose(fp); fclose(fp);
fp = nullptr; fp = nullptr;
} }
void add_module_io(VM* vm){ void add_module_io(VM* vm) {
PyObject* mod = vm->new_module("io"); PyObject* mod = vm->new_module("io");
vm->register_user_class<FileIO>(mod, "FileIO"); vm->register_user_class<FileIO>(mod, "FileIO");
@ -148,104 +144,103 @@ void add_module_io(VM* vm){
mod->attr().set("SEEK_CUR", VAR(SEEK_CUR)); mod->attr().set("SEEK_CUR", VAR(SEEK_CUR));
mod->attr().set("SEEK_END", VAR(SEEK_END)); mod->attr().set("SEEK_END", VAR(SEEK_END));
vm->bind(vm->builtins, "open(path, mode='r')", [](VM* vm, ArgsView args){ vm->bind(vm->builtins, "open(path, mode='r')", [](VM* vm, ArgsView args) {
return vm->call(vm->_modules["io"]->attr("FileIO"), args[0], args[1]); return vm->call(vm->_modules["io"]->attr("FileIO"), args[0], args[1]);
}); });
} }
void add_module_os(VM* vm){ void add_module_os(VM* vm) {
PyObject* mod = vm->new_module("os"); PyObject* mod = vm->new_module("os");
PyObject* path_obj = vm->heap.gcnew<DummyInstance>(VM::tp_object); PyObject* path_obj = vm->heap.gcnew<DummyInstance>(VM::tp_object);
mod->attr().set("path", path_obj); mod->attr().set("path", path_obj);
// Working directory is shared by all VMs!! // Working directory is shared by all VMs!!
vm->bind_func(mod, "getcwd", 0, [](VM* vm, ArgsView args){ vm->bind_func(mod, "getcwd", 0, [](VM* vm, ArgsView args) {
return VAR(std::filesystem::current_path().string()); return VAR(std::filesystem::current_path().string());
}); });
vm->bind_func(mod, "chdir", 1, [](VM* vm, ArgsView args){ vm->bind_func(mod, "chdir", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
std::filesystem::current_path(path); std::filesystem::current_path(path);
return vm->None; return vm->None;
}); });
vm->bind_func(mod, "listdir", 1, [](VM* vm, ArgsView args){ vm->bind_func(mod, "listdir", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
std::filesystem::directory_iterator di; std::filesystem::directory_iterator di;
try{ try {
di = std::filesystem::directory_iterator(path); di = std::filesystem::directory_iterator(path);
}catch(std::filesystem::filesystem_error&){ } catch(std::filesystem::filesystem_error&) { vm->IOError(path.string()); }
vm->IOError(path.string());
}
List ret; List ret;
for(auto& p: di) ret.push_back(VAR(p.path().filename().string())); for(auto& p: di)
ret.push_back(VAR(p.path().filename().string()));
return VAR(std::move(ret)); return VAR(std::move(ret));
}); });
vm->bind_func(mod, "remove", 1, [](VM* vm, ArgsView args){ vm->bind_func(mod, "remove", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
bool ok = std::filesystem::remove(path); bool ok = std::filesystem::remove(path);
if(!ok) vm->IOError("operation failed"); if(!ok) vm->IOError("operation failed");
return vm->None; return vm->None;
}); });
vm->bind_func(mod, "mkdir", 1, [](VM* vm, ArgsView args){ vm->bind_func(mod, "mkdir", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
bool ok = std::filesystem::create_directory(path); bool ok = std::filesystem::create_directory(path);
if(!ok) vm->IOError("operation failed"); if(!ok) vm->IOError("operation failed");
return vm->None; return vm->None;
}); });
vm->bind_func(mod, "rmdir", 1, [](VM* vm, ArgsView args){ vm->bind_func(mod, "rmdir", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
bool ok = std::filesystem::remove(path); bool ok = std::filesystem::remove(path);
if(!ok) vm->IOError("operation failed"); if(!ok) vm->IOError("operation failed");
return vm->None; return vm->None;
}); });
vm->bind_func(path_obj, "join", -1, [](VM* vm, ArgsView args){ vm->bind_func(path_obj, "join", -1, [](VM* vm, ArgsView args) {
std::filesystem::path path; std::filesystem::path path;
for(int i=0; i<args.size(); i++){ for(int i = 0; i < args.size(); i++) {
path /= CAST(Str&, args[i]).sv(); path /= CAST(Str&, args[i]).sv();
} }
return VAR(path.string()); return VAR(path.string());
}); });
vm->bind_func(path_obj, "exists", 1, [](VM* vm, ArgsView args){ vm->bind_func(path_obj, "exists", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
bool exists = std::filesystem::exists(path); bool exists = std::filesystem::exists(path);
return VAR(exists); return VAR(exists);
}); });
vm->bind_func(path_obj, "basename", 1, [](VM* vm, ArgsView args){ vm->bind_func(path_obj, "basename", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
return VAR(path.filename().string()); return VAR(path.filename().string());
}); });
vm->bind_func(path_obj, "isdir", 1, [](VM* vm, ArgsView args){ vm->bind_func(path_obj, "isdir", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
bool isdir = std::filesystem::is_directory(path); bool isdir = std::filesystem::is_directory(path);
return VAR(isdir); return VAR(isdir);
}); });
vm->bind_func(path_obj, "isfile", 1, [](VM* vm, ArgsView args){ vm->bind_func(path_obj, "isfile", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
bool isfile = std::filesystem::is_regular_file(path); bool isfile = std::filesystem::is_regular_file(path);
return VAR(isfile); return VAR(isfile);
}); });
vm->bind_func(path_obj, "abspath", 1, [](VM* vm, ArgsView args){ vm->bind_func(path_obj, "abspath", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
return VAR(std::filesystem::absolute(path).string()); return VAR(std::filesystem::absolute(path).string());
}); });
} }
#else #else
void add_module_io(VM* vm){} void add_module_io(VM* vm) {}
void add_module_os(VM* vm){}
unsigned char* _default_import_handler(const char* name, int* out_size){ void add_module_os(VM* vm) {}
return nullptr;
} unsigned char* _default_import_handler(const char* name, int* out_size) { return nullptr; }
#endif #endif

View File

@ -1,58 +1,58 @@
#include "pocketpy/modules/linalg.hpp" #include "pocketpy/modules/linalg.hpp"
#include "pocketpy/interpreter/bindings.hpp" #include "pocketpy/interpreter/bindings.hpp"
namespace pkpy{ namespace pkpy {
#define BIND_VEC_VEC_OP(D, name, op) \ #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 self = _CAST(Vec##D, _0); \
Vec##D other = CAST(Vec##D, _1); \ Vec##D other = CAST(Vec##D, _1); \
return VAR(self op other); \ return VAR(self op other); \
}); });
#define BIND_VEC_FLOAT_OP(D, name, op) \ #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); \ Vec##D self = _CAST(Vec##D, _0); \
f64 other = CAST(f64, _1); \ f64 other = CAST(f64, _1); \
return VAR(self op other); \ return VAR(self op other); \
}); });
#define BIND_VEC_FUNCTION_0(T, name) \ #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]); \ T self = _CAST(T, args[0]); \
return VAR(self.name()); \ return VAR(self.name()); \
}); });
#define BIND_VEC_FUNCTION_1(T, 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 self = _CAST(T, args[0]); \
T other = CAST(T, args[1]); \ T other = CAST(T, args[1]); \
return VAR(self.name(other)); \ return VAR(self.name(other)); \
}); });
#define BIND_VEC_MUL_OP(D) \ #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); \ 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); \ Vec##D other = _CAST(Vec##D, _1); \
return VAR(self * other); \ return VAR(self * other); \
} \ } \
f64 other = CAST(f64, _1); \ f64 other = CAST(f64, _1); \
return VAR(self * other); \ 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]); \ Vec##D self = _CAST(Vec##D, args[0]); \
f64 other = CAST(f64, args[1]); \ f64 other = CAST(f64, args[1]); \
return VAR(self * other); \ 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); \ Vec##D self = _CAST(Vec##D, _0); \
f64 other = CAST(f64, _1); \ f64 other = CAST(f64, _1); \
return VAR(self / other); \ return VAR(self / other); \
}); });
#define BIND_VEC_GETITEM(D) \ #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); \ Vec##D self = _CAST(Vec##D, obj); \
i64 i = CAST(i64, index); \ i64 i = CAST(i64, index); \
if(i < 0 || i >= D) vm->IndexError("index out of range"); \ if(i < 0 || i >= D) vm->IndexError("index out of range"); \
@ -60,22 +60,23 @@ namespace pkpy{
}); });
#define BIND_SSO_VEC_COMMON(D) \ #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); \ Vec##D self = _CAST(Vec##D, _0); \
if(!vm->is_user_type<Vec##D>(_1)) return vm->NotImplemented; \ if(!vm->is_user_type<Vec##D>(_1)) return vm->NotImplemented; \
Vec##D other = _CAST(Vec##D, _1); \ Vec##D other = _CAST(Vec##D, _1); \
return VAR(self == other); \ 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]); \ Vec##D self = _CAST(Vec##D, args[0]); \
Tuple t(D); \ 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)); \ return VAR(std::move(t)); \
}); });
// https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Math/Vector2.cs#L289 // 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 // Based on Game Programming Gems 4 Chapter 1.10
smoothTime = (std::max)(0.0001F, smoothTime); smoothTime = (std::max)(0.0001F, smoothTime);
float omega = 2.0F / 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 maxChangeSq = maxChange * maxChange;
float sqDist = change_x * change_x + change_y * change_y; float sqDist = change_x * change_x + change_y * change_y;
if (sqDist > maxChangeSq) if(sqDist > maxChangeSq) {
{
float mag = std::sqrt(sqDist); float mag = std::sqrt(sqDist);
change_x = change_x / mag * maxChange; change_x = change_x / mag * maxChange;
change_y = change_y / 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_x = output_x - originalTo.x;
float outMinusOrig_y = output_y - originalTo.y; 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_x = originalTo.x;
output_y = originalTo.y; 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); 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("ZERO", vm->new_user_object<Vec2>(0, 0));
type->attr().set("ONE", vm->new_user_object<Vec2>(1, 1)); 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 x = CAST_F(args[1]);
float y = CAST_F(args[2]); float y = CAST_F(args[2]);
return vm->new_object<Vec2>(PK_OBJ_GET(Type, args[0]), x, y); return vm->new_object<Vec2>(PK_OBJ_GET(Type, args[0]), x, y);
}); });
// @staticmethod // @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 current = CAST(Vec2, args[0]);
Vec2 target = CAST(Vec2, args[1]); Vec2 target = CAST(Vec2, args[1]);
Vec2 current_velocity_ = CAST(Vec2, args[2]); 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]); float delta_time = CAST_F(args[5]);
Vec2 ret = SmoothDamp(current, target, current_velocity_, smooth_time, max_speed, delta_time); Vec2 ret = SmoothDamp(current, target, current_velocity_, smooth_time, max_speed, delta_time);
return VAR(Tuple(VAR(ret), VAR(current_velocity_))); return VAR(Tuple(VAR(ret), VAR(current_velocity_)));
}, {}, BindType::STATICMETHOD); },
{},
BindType::STATICMETHOD);
// @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 __from = CAST(Vec2, args[0]);
Vec2 __to = CAST(Vec2, args[1]); Vec2 __to = CAST(Vec2, args[1]);
float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x); float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x);
const float PI = 3.1415926535897932384f; 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); 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); Vec2 self = _CAST(Vec2, obj);
SStream ss; SStream ss;
ss.setprecision(3); ss.setprecision(3);
@ -169,7 +178,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
return ss.str(); 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]); Vec2 self = _CAST(Vec2, args[0]);
float radian = CAST(f64, args[1]); float radian = CAST(f64, args[1]);
return vm->new_user_object<Vec2>(self.rotate(radian)); 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_FUNCTION_0(Vec2, normalize)
BIND_VEC_GETITEM(2) BIND_VEC_GETITEM(2)
BIND_SSO_VEC_COMMON(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("ZERO", vm->new_user_object<Vec3>(0, 0, 0));
type->attr().set("ONE", vm->new_user_object<Vec3>(1, 1, 1)); 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 x = CAST_F(args[1]);
float y = CAST_F(args[2]); float y = CAST_F(args[2]);
float z = CAST_F(args[3]); float z = CAST_F(args[3]);
return vm->new_object<Vec3>(PK_OBJ_GET(Type, args[0]), x, y, z); 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); Vec3 self = _CAST(Vec3, obj);
SStream ss; SStream ss;
ss.setprecision(3); 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_FUNCTION_0(Vec3, normalize)
BIND_VEC_GETITEM(3) BIND_VEC_GETITEM(3)
BIND_SSO_VEC_COMMON(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) PY_STRUCT_LIKE(Vec4)
type->attr().set("ZERO", vm->new_user_object<Vec4>(0, 0, 0, 0)); 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)); 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 x = CAST_F(args[1]);
float y = CAST_F(args[2]); float y = CAST_F(args[2]);
float z = CAST_F(args[3]); 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); 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); Vec4 self = _CAST(Vec4&, obj);
SStream ss; SStream ss;
ss.setprecision(3); 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_FUNCTION_0(Vec4&, normalize_) BIND_VEC_FUNCTION_0(Vec4&, normalize_)
BIND_VEC_GETITEM(4) BIND_VEC_GETITEM(4)
} }
#undef BIND_VEC_VEC_OP #undef BIND_VEC_VEC_OP
#undef BIND_VEC_MUL_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_FUNCTION_1
#undef BIND_VEC_GETITEM #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) PY_STRUCT_LIKE(Mat3x3)
vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args){ 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 + 0) return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros());
if(args.size() == 1+1){ if(args.size() == 1 + 1) {
const List& list = CAST(List&, args[1]); const List& list = CAST(List&, args[1]);
if(list.size() != 9) vm->TypeError("Mat3x3.__new__ takes a list of 9 floats"); if(list.size() != 9) vm->TypeError("Mat3x3.__new__ takes a list of 9 floats");
Mat3x3 mat; 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); return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
} }
if(args.size() == 1+9){ if(args.size() == 1 + 9) {
Mat3x3 mat; 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); 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; 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]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
const Mat3x3& other = CAST(Mat3x3&, args[1]); const Mat3x3& other = CAST(Mat3x3&, args[1]);
self = other; self = other;
return vm->None; 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); const Mat3x3& self = _CAST(Mat3x3&, obj);
SStream ss; SStream ss;
ss.setprecision(3); ss.setprecision(3);
@ -309,31 +320,23 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
return ss.str(); 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); Mat3x3& self = _CAST(Mat3x3&, obj);
Tuple& t = CAST(Tuple&, index); Tuple& t = CAST(Tuple&, index);
if(t.size() != 2){ if(t.size() != 2) { vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers"); }
vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers");
}
i64 i = CAST(i64, t[0]); i64 i = CAST(i64, t[0]);
i64 j = CAST(i64, t[1]); i64 j = CAST(i64, t[1]);
if(i < 0 || i >= 3 || j < 0 || j >= 3){ if(i < 0 || i >= 3 || j < 0 || j >= 3) { vm->IndexError("index out of range"); }
vm->IndexError("index out of range");
}
return VAR(self.m[i][j]); 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); Mat3x3& self = _CAST(Mat3x3&, obj);
const Tuple& t = CAST(Tuple&, index); const Tuple& t = CAST(Tuple&, index);
if(t.size() != 2){ if(t.size() != 2) { vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers"); }
vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers");
}
i64 i = CAST(i64, t[0]); i64 i = CAST(i64, t[0]);
i64 j = CAST(i64, t[1]); i64 j = CAST(i64, t[1]);
if(i < 0 || i >= 3 || j < 0 || j >= 3){ if(i < 0 || i >= 3 || j < 0 || j >= 3) { vm->IndexError("index out of range"); }
vm->IndexError("index out of range");
}
self.m[i][j] = CAST_F(value); 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, "_32", &Mat3x3::_32);
vm->bind_field(type, "_33", &Mat3x3::_33); 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& self = _CAST(Mat3x3&, _0);
Mat3x3& other = CAST(Mat3x3&, _1); Mat3x3& other = CAST(Mat3x3&, _1);
return vm->new_user_object<Mat3x3>(self + other); 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& self = _CAST(Mat3x3&, _0);
Mat3x3& other = CAST(Mat3x3&, _1); Mat3x3& other = CAST(Mat3x3&, _1);
return vm->new_user_object<Mat3x3>(self - other); 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); Mat3x3& self = _CAST(Mat3x3&, _0);
f64 other = CAST_F(_1); f64 other = CAST_F(_1);
return vm->new_user_object<Mat3x3>(self * other); 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]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
f64 other = CAST_F(args[1]); f64 other = CAST_F(args[1]);
return vm->new_user_object<Mat3x3>(self * other); 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); Mat3x3& self = _CAST(Mat3x3&, _0);
f64 other = CAST_F(_1); f64 other = CAST_F(_1);
return vm->new_user_object<Mat3x3>(self / other); 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); 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); const Mat3x3& other = _CAST(Mat3x3&, _1);
return vm->new_user_object<Mat3x3>(self.matmul(other)); 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); const Vec3 other = _CAST(Vec3, _1);
return vm->new_user_object<Vec3>(self.matmul(other)); return vm->new_user_object<Vec3>(self.matmul(other));
} }
return vm->NotImplemented; 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& self = _CAST(Mat3x3&, args[0]);
const Mat3x3& other = CAST(Mat3x3&, args[1]); 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)); return vm->new_user_object<Mat3x3>(self.matmul(other));
}else{ } else {
Mat3x3& out = CAST(Mat3x3&, args[2]); Mat3x3& out = CAST(Mat3x3&, args[2]);
out = self.matmul(other); out = self.matmul(other);
return vm->None; 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]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
return VAR(self.determinant()); 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]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
return vm->new_user_object<Mat3x3>(self.transpose()); 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& self = _CAST(Mat3x3&, obj);
Mat3x3 ret; Mat3x3 ret;
if(!self.inverse(ret)) vm->ValueError("matrix is not invertible"); if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
return vm->new_user_object<Mat3x3>(ret); 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& self = _CAST(Mat3x3&, args[0]);
Mat3x3 ret; Mat3x3 ret;
if(!self.inverse(ret)) vm->ValueError("matrix is not invertible"); if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
return vm->new_user_object<Mat3x3>(ret); 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& self = _CAST(Mat3x3&, args[0]);
Mat3x3 ret; Mat3x3 ret;
if(!self.inverse(ret)) vm->ValueError("matrix is not invertible"); 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; 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]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
self = self.transpose(); self = self.transpose();
return vm->None; return vm->None;
}); });
// @staticmethod // @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()); return vm->new_user_object<Mat3x3>(Mat3x3::zeros());
}, {}, BindType::STATICMETHOD); },
{},
BindType::STATICMETHOD);
// @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()); return vm->new_user_object<Mat3x3>(Mat3x3::ones());
}, {}, BindType::STATICMETHOD); },
{},
BindType::STATICMETHOD);
// @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()); return vm->new_user_object<Mat3x3>(Mat3x3::identity());
}, {}, BindType::STATICMETHOD); },
{},
BindType::STATICMETHOD);
/*************** affine transformations ***************/ /*************** affine transformations ***************/
// @staticmethod // @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]); Vec2 t = CAST(Vec2, args[0]);
f64 r = CAST_F(args[1]); f64 r = CAST_F(args[1]);
Vec2 s = CAST(Vec2, args[2]); Vec2 s = CAST(Vec2, args[2]);
return vm->new_user_object<Mat3x3>(Mat3x3::trs(t, r, s)); 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]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
Vec2 t = CAST(Vec2, args[1]); Vec2 t = CAST(Vec2, args[1]);
f64 r = CAST_F(args[2]); f64 r = CAST_F(args[2]);
@ -473,55 +499,55 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
return vm->None; 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]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
Vec2 t = CAST(Vec2, args[1]); Vec2 t = CAST(Vec2, args[1]);
self = Mat3x3::trs(t, self._r(), self._s()); self = Mat3x3::trs(t, self._r(), self._s());
return vm->None; 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]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
f64 r = CAST_F(args[1]); f64 r = CAST_F(args[1]);
self = Mat3x3::trs(self._t(), r, self._s()); self = Mat3x3::trs(self._t(), r, self._s());
return vm->None; 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]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
Vec2 s = CAST(Vec2, args[1]); Vec2 s = CAST(Vec2, args[1]);
self = Mat3x3::trs(self._t(), self._r(), s); self = Mat3x3::trs(self._t(), self._r(), s);
return vm->None; 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]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
return VAR(self.is_affine()); 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]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
return vm->new_user_object<Vec2>(self._t()); 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]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
return VAR(self._r()); 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]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
return vm->new_user_object<Vec2>(self._s()); 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]); const Mat3x3& self = _CAST(Mat3x3&, args[0]);
Vec2 v = CAST(Vec2, args[1]); 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); 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); 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]); const Mat3x3& self = _CAST(Mat3x3&, args[0]);
Vec2 v = CAST(Vec2, args[1]); Vec2 v = CAST(Vec2, args[1]);
Mat3x3 inv; Mat3x3 inv;
@ -530,14 +556,14 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
return vm->new_user_object<Vec2>(res); 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]); const Mat3x3& self = _CAST(Mat3x3&, args[0]);
Vec2 v = CAST(Vec2, args[1]); Vec2 v = CAST(Vec2, args[1]);
Vec2 res(self._11 * v.x + self._12 * v.y, self._21 * v.x + self._22 * v.y); 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); 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]); const Mat3x3& self = _CAST(Mat3x3&, args[0]);
Vec2 v = CAST(Vec2, args[1]); Vec2 v = CAST(Vec2, args[1]);
Mat3x3 inv; 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); 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); 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"); PyObject* linalg = vm->new_module("linalg");
vm->register_user_class<Vec2>(linalg, "vec2", VM::tp_object); 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); linalg->attr().set("mat3x3_p", float_p);
} }
/////////////// mat3x3 ///////////////
Mat3x3::Mat3x3() {}
/////////////// mat3x3 /////////////// Mat3x3::Mat3x3(float _11, float _12, float _13, float _21, float _22, float _23, float _31, float _32, float _33) :
Mat3x3::Mat3x3() {} _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(){ Mat3x3 Mat3x3::zeros() { return Mat3x3(0, 0, 0, 0, 0, 0, 0, 0, 0); }
return Mat3x3(0, 0, 0, 0, 0, 0, 0, 0, 0);
}
Mat3x3 Mat3x3::ones(){ Mat3x3 Mat3x3::ones() { return Mat3x3(1, 1, 1, 1, 1, 1, 1, 1, 1); }
return Mat3x3(1, 1, 1, 1, 1, 1, 1, 1, 1);
}
Mat3x3 Mat3x3::identity(){ Mat3x3 Mat3x3::identity() { return Mat3x3(1, 0, 0, 0, 1, 0, 0, 0, 1); }
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; 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; return ret;
} }
Mat3x3 Mat3x3::operator-(const Mat3x3& other) const{ Mat3x3 Mat3x3::operator- (const Mat3x3& other) const {
Mat3x3 ret; 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; return ret;
} }
Mat3x3 Mat3x3::operator*(float scalar) const{ Mat3x3 Mat3x3::operator* (float scalar) const {
Mat3x3 ret; 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; return ret;
} }
Mat3x3 Mat3x3::operator/(float scalar) const{ Mat3x3 Mat3x3::operator/ (float scalar) const {
Mat3x3 ret; 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; return ret;
} }
bool Mat3x3::operator==(const Mat3x3& other) const{ bool Mat3x3::operator== (const Mat3x3& other) const {
for (int i=0; i<9; ++i){ for(int i = 0; i < 9; ++i) {
if (!isclose(v[i], other.v[i])) return false; if(!isclose(v[i], other.v[i])) return false;
} }
return true; return true;
} }
bool Mat3x3::operator!=(const Mat3x3& other) const{ bool Mat3x3::operator!= (const Mat3x3& other) const {
for (int i=0; i<9; ++i){ for(int i = 0; i < 9; ++i) {
if (!isclose(v[i], other.v[i])) return true; if(!isclose(v[i], other.v[i])) return true;
} }
return false; return false;
} }
Mat3x3 Mat3x3::matmul(const Mat3x3& other) const{ Mat3x3 Mat3x3::matmul(const Mat3x3& other) const {
Mat3x3 out; Mat3x3 out;
out._11 = _11 * other._11 + _12 * other._21 + _13 * other._31; out._11 = _11 * other._11 + _12 * other._21 + _13 * other._31;
out._12 = _11 * other._12 + _12 * other._22 + _13 * other._32; 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._32 = _31 * other._12 + _32 * other._22 + _33 * other._32;
out._33 = _31 * other._13 + _32 * other._23 + _33 * other._33; out._33 = _31 * other._13 + _32 * other._23 + _33 * other._33;
return out; return out;
} }
Vec3 Mat3x3::matmul(const Vec3& other) const{ Vec3 Mat3x3::matmul(const Vec3& other) const {
Vec3 out; Vec3 out;
out.x = _11 * other.x + _12 * other.y + _13 * other.z; out.x = _11 * other.x + _12 * other.y + _13 * other.z;
out.y = _21 * other.x + _22 * other.y + _23 * other.z; out.y = _21 * other.x + _22 * other.y + _23 * other.z;
out.z = _31 * other.x + _32 * other.y + _33 * other.z; out.z = _31 * other.x + _32 * other.y + _33 * other.z;
return out; return out;
} }
float Mat3x3::determinant() const{ float Mat3x3::determinant() const {
return _11 * _22 * _33 + _12 * _23 * _31 + _13 * _21 * _32 return _11 * _22 * _33 + _12 * _23 * _31 + _13 * _21 * _32 - _11 * _23 * _32 - _12 * _21 * _33 - _13 * _22 * _31;
- _11 * _23 * _32 - _12 * _21 * _33 - _13 * _22 * _31; }
}
Mat3x3 Mat3x3::transpose() const{ Mat3x3 Mat3x3::transpose() const {
Mat3x3 ret; Mat3x3 ret;
ret._11 = _11; ret._12 = _21; ret._13 = _31; ret._11 = _11;
ret._21 = _12; ret._22 = _22; ret._23 = _32; ret._12 = _21;
ret._31 = _13; ret._32 = _23; ret._33 = _33; ret._13 = _31;
ret._21 = _12;
ret._22 = _22;
ret._23 = _32;
ret._31 = _13;
ret._32 = _23;
ret._33 = _33;
return ret; return ret;
} }
bool Mat3x3::inverse(Mat3x3& out) const{ bool Mat3x3::inverse(Mat3x3& out) const {
float det = determinant(); float det = determinant();
if (isclose(det, 0)) return false; if(isclose(det, 0)) return false;
float inv_det = 1.0f / det; float inv_det = 1.0f / det;
out._11 = (_22 * _33 - _23 * _32) * inv_det; out._11 = (_22 * _33 - _23 * _32) * inv_det;
out._12 = (_13 * _32 - _12 * _33) * 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._32 = (_12 * _31 - _11 * _32) * inv_det;
out._33 = (_11 * _22 - _12 * _21) * inv_det; out._33 = (_11 * _22 - _12 * _21) * inv_det;
return true; 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 cr = cosf(radian);
float sr = sinf(radian); float sr = sinf(radian);
return Mat3x3(s.x * cr, -s.y * sr, t.x, return Mat3x3(s.x * cr, -s.y * sr, t.x, s.x * sr, s.y * cr, t.y, 0.0f, 0.0f, 1.0f);
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; float det = _11 * _22 - _12 * _21;
if(isclose(det, 0)) return false; if(isclose(det, 0)) return false;
return _31 == 0.0f && _32 == 0.0f && _33 == 1.0f; return _31 == 0.0f && _32 == 0.0f && _33 == 1.0f;
} }
Vec2 Mat3x3::_t() const { return Vec2(_13, _23); } Vec2 Mat3x3::_t() const { return Vec2(_13, _23); }
float Mat3x3::_r() const { return atan2f(_21, _11); }
Vec2 Mat3x3::_s() const { float Mat3x3::_r() const { return atan2f(_21, _11); }
return Vec2(
sqrtf(_11 * _11 + _21 * _21), Vec2 Mat3x3::_s() const { return Vec2(sqrtf(_11 * _11 + _21 * _21), sqrtf(_12 * _12 + _22 * _22)); }
sqrtf(_12 * _12 + _22 * _22)
);
}
} // namespace pkpy } // namespace pkpy

View File

@ -8,9 +8,9 @@
#include <chrono> #include <chrono>
#include <cmath> #include <cmath>
namespace pkpy{ namespace pkpy {
struct PyStructTime{ struct PyStructTime {
int tm_year; int tm_year;
int tm_mon; int tm_mon;
int tm_mday; int tm_mday;
@ -21,7 +21,7 @@ struct PyStructTime{
int tm_yday; int tm_yday;
int tm_isdst; int tm_isdst;
PyStructTime(std::time_t t){ PyStructTime(std::time_t t) {
std::tm* tm = std::localtime(&t); std::tm* tm = std::localtime(&t);
tm_year = tm->tm_year + 1900; tm_year = tm->tm_year + 1900;
tm_mon = tm->tm_mon + 1; tm_mon = tm->tm_mon + 1;
@ -34,7 +34,7 @@ struct PyStructTime{
tm_isdst = tm->tm_isdst; tm_isdst = tm->tm_isdst;
} }
static void _register(VM* vm, PyObject* mod, PyObject* type){ static void _register(VM* vm, PyObject* mod, PyObject* type) {
PY_READONLY_FIELD(PyStructTime, "tm_year", tm_year); PY_READONLY_FIELD(PyStructTime, "tm_year", tm_year);
PY_READONLY_FIELD(PyStructTime, "tm_mon", tm_mon); PY_READONLY_FIELD(PyStructTime, "tm_mon", tm_mon);
PY_READONLY_FIELD(PyStructTime, "tm_mday", tm_mday); PY_READONLY_FIELD(PyStructTime, "tm_mday", tm_mday);
@ -47,7 +47,7 @@ struct PyStructTime{
} }
}; };
void add_module_time(VM* vm){ void add_module_time(VM* vm) {
PyObject* mod = vm->new_module("time"); PyObject* mod = vm->new_module("time");
vm->register_user_class<PyStructTime>(mod, "struct_time"); vm->register_user_class<PyStructTime>(mod, "struct_time");
@ -59,7 +59,7 @@ void add_module_time(VM* vm){
vm->bind_func(mod, "sleep", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "sleep", 1, [](VM* vm, ArgsView args) {
f64 seconds = CAST_F(args[0]); f64 seconds = CAST_F(args[0]);
auto begin = std::chrono::system_clock::now(); auto begin = std::chrono::system_clock::now();
while(true){ while(true) {
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
f64 elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - begin).count() / 1000.0; f64 elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - begin).count() / 1000.0;
if(elapsed >= seconds) break; if(elapsed >= seconds) break;
@ -74,7 +74,7 @@ void add_module_time(VM* vm){
}); });
} }
void add_module_sys(VM* vm){ void add_module_sys(VM* vm) {
PyObject* mod = vm->new_module("sys"); PyObject* mod = vm->new_module("sys");
vm->setattr(mod, "version", VAR(PK_VERSION)); vm->setattr(mod, "version", VAR(PK_VERSION));
vm->setattr(mod, "platform", VAR(kPlatformStrings[PK_SYS_PLATFORM])); vm->setattr(mod, "platform", VAR(kPlatformStrings[PK_SYS_PLATFORM]));
@ -97,14 +97,14 @@ void add_module_sys(VM* vm){
}); });
} }
void add_module_json(VM* vm){ void add_module_json(VM* vm) {
PyObject* mod = vm->new_module("json"); PyObject* mod = vm->new_module("json");
vm->bind_func(mod, "loads", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "loads", 1, [](VM* vm, ArgsView args) {
std::string_view sv; std::string_view sv;
if(is_type(args[0], vm->tp_bytes)){ if(is_type(args[0], vm->tp_bytes)) {
const Bytes& b = PK_OBJ_GET(Bytes, args[0]); const Bytes& b = PK_OBJ_GET(Bytes, args[0]);
sv = std::string_view((char*)b.data(), b.size()); sv = std::string_view((char*)b.data(), b.size());
}else{ } else {
sv = CAST(Str&, args[0]).sv(); sv = CAST(Str&, args[0]).sv();
} }
CodeObject_ code = vm->compile(sv, "<json>", JSON_MODE); CodeObject_ code = vm->compile(sv, "<json>", JSON_MODE);
@ -117,10 +117,10 @@ void add_module_json(VM* vm){
} }
// https://docs.python.org/3.5/library/math.html // https://docs.python.org/3.5/library/math.html
void add_module_math(VM* vm){ void add_module_math(VM* vm) {
PyObject* mod = vm->new_module("math"); PyObject* mod = vm->new_module("math");
mod->attr().set("pi", VAR(3.1415926535897932384)); mod->attr().set("pi", VAR(3.1415926535897932384));
mod->attr().set("e" , VAR(2.7182818284590452354)); mod->attr().set("e", VAR(2.7182818284590452354));
mod->attr().set("inf", VAR(std::numeric_limits<double>::infinity())); mod->attr().set("inf", VAR(std::numeric_limits<double>::infinity()));
mod->attr().set("nan", VAR(std::numeric_limits<double>::quiet_NaN())); mod->attr().set("nan", VAR(std::numeric_limits<double>::quiet_NaN()));
@ -131,7 +131,7 @@ void add_module_math(VM* vm){
List& list = CAST(List&, args[0]); List& list = CAST(List&, args[0]);
double sum = 0; double sum = 0;
double c = 0; double c = 0;
for(PyVar arg : list){ for(PyVar arg: list) {
double x = CAST_F(arg); double x = CAST_F(arg);
double y = x - c; double y = x - c;
double t = sum + y; double t = sum + y;
@ -145,7 +145,7 @@ void add_module_math(VM* vm){
i64 b = CAST(i64, args[1]); i64 b = CAST(i64, args[1]);
if(a < 0) a = -a; if(a < 0) a = -a;
if(b < 0) b = -b; if(b < 0) b = -b;
while(b != 0){ while(b != 0) {
i64 t = b; i64 t = b;
b = a % b; b = a % b;
a = t; a = t;
@ -165,7 +165,7 @@ void add_module_math(VM* vm){
vm->bind_func(mod, "exp", 1, PK_LAMBDA(VAR(std::exp(CAST_F(args[0]))))); vm->bind_func(mod, "exp", 1, PK_LAMBDA(VAR(std::exp(CAST_F(args[0])))));
vm->bind(mod, "log(x, base=2.718281828459045)", [](VM* vm, ArgsView args){ vm->bind(mod, "log(x, base=2.718281828459045)", [](VM* vm, ArgsView args) {
f64 x = CAST_F(args[0]); f64 x = CAST_F(args[0]);
f64 base = CAST_F(args[1]); f64 base = CAST_F(args[1]);
return VAR(std::log(x) / std::log(base)); return VAR(std::log(x) / std::log(base));
@ -199,12 +199,13 @@ void add_module_math(VM* vm){
i64 n = CAST(i64, args[0]); i64 n = CAST(i64, args[0]);
if(n < 0) vm->ValueError("factorial() not defined for negative values"); if(n < 0) vm->ValueError("factorial() not defined for negative values");
i64 r = 1; i64 r = 1;
for(i64 i=2; i<=n; i++) r *= i; for(i64 i = 2; i <= n; i++)
r *= i;
return VAR(r); return VAR(r);
}); });
} }
void add_module_traceback(VM* vm){ void add_module_traceback(VM* vm) {
PyObject* mod = vm->new_module("traceback"); PyObject* mod = vm->new_module("traceback");
vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) { vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) {
if(vm->__last_exception == nullptr) vm->ValueError("no exception"); if(vm->__last_exception == nullptr) vm->ValueError("no exception");
@ -220,13 +221,13 @@ void add_module_traceback(VM* vm){
}); });
} }
void add_module_dis(VM* vm){ void add_module_dis(VM* vm) {
PyObject* mod = vm->new_module("dis"); PyObject* mod = vm->new_module("dis");
vm->bind_func(mod, "dis", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "dis", 1, [](VM* vm, ArgsView args) {
CodeObject_ code; CodeObject_ code;
PyVar obj = args[0]; PyVar obj = args[0];
if(is_type(obj, vm->tp_str)){ if(is_type(obj, vm->tp_str)) {
const Str& source = CAST(Str, obj); const Str& source = CAST(Str, obj);
code = vm->compile(source, "<dis>", EXEC_MODE); code = vm->compile(source, "<dis>", EXEC_MODE);
} }
@ -238,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"); PyObject* mod = vm->new_module("gc");
vm->bind_func(mod, "collect", 0, PK_LAMBDA(VAR(vm->heap.collect()))); vm->bind_func(mod, "collect", 0, PK_LAMBDA(VAR(vm->heap.collect())));
} }
void add_module_enum(VM* vm){ void add_module_enum(VM* vm) {
PyObject* mod = vm->new_module("enum"); PyObject* mod = vm->new_module("enum");
CodeObject_ code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE); CodeObject_ code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE);
vm->_exec(code, mod); vm->_exec(code, mod);
PyVar Enum = mod->attr("Enum"); PyVar Enum = mod->attr("Enum");
vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = \ vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = [](VM* vm, PyTypeInfo* new_ti) {
[](VM* vm, PyTypeInfo* new_ti){
new_ti->subclass_enabled = false; // Enum class cannot be subclassed twice new_ti->subclass_enabled = false; // Enum class cannot be subclassed twice
NameDict& attr = new_ti->obj->attr(); NameDict& attr = new_ti->obj->attr();
for(auto [k, v]: attr.items()){ for(auto [k, v]: attr.items()) {
// wrap every attribute // wrap every attribute
std::string_view k_sv = k.sv(); std::string_view k_sv = k.sv();
if(k_sv.empty() || k_sv[0] == '_') continue; if(k_sv.empty() || k_sv[0] == '_') continue;
@ -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"); PyObject* mod = vm->new_module("__builtins");
vm->bind_func(mod, "next", 1, [](VM* vm, ArgsView args){ vm->bind_func(mod, "next", 1, [](VM* vm, ArgsView args) {
return vm->py_next(args[0]); return vm->py_next(args[0]);
}); });
vm->bind_func(mod, "_enable_instance_dict", 1, [](VM* vm, ArgsView args){ vm->bind_func(mod, "_enable_instance_dict", 1, [](VM* vm, ArgsView args) {
PyVar self = args[0]; PyVar self = args[0];
if(is_tagged(self)) vm->TypeError("object: tagged object cannot enable instance dict"); if(is_tagged(self)) vm->TypeError("object: tagged object cannot enable instance dict");
if(self->is_attr_valid()) vm->RuntimeError("object: instance dict is already enabled"); if(self->is_attr_valid()) vm->RuntimeError("object: instance dict is already enabled");
@ -277,11 +277,11 @@ void add_module___builtins(VM* vm){
}); });
} }
/************************************************/ /************************************************/
#if PK_ENABLE_PROFILER #if PK_ENABLE_PROFILER
struct LineProfilerW; struct LineProfilerW;
struct _LpGuard{
struct _LpGuard {
PK_ALWAYS_PASS_BY_POINTER(_LpGuard) PK_ALWAYS_PASS_BY_POINTER(_LpGuard)
LineProfilerW* lp; LineProfilerW* lp;
VM* vm; VM* vm;
@ -290,16 +290,16 @@ struct _LpGuard{
}; };
// line_profiler wrapper // line_profiler wrapper
struct LineProfilerW{ struct LineProfilerW {
LineProfiler profiler; LineProfiler profiler;
static void _register(VM* vm, PyObject* mod, PyObject* type){ static void _register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args){ vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args) {
Type cls = PK_OBJ_GET(Type, args[0]); Type cls = PK_OBJ_GET(Type, args[0]);
return vm->new_object<LineProfilerW>(cls); return vm->new_object<LineProfilerW>(cls);
}); });
vm->bind(type, "add_function(self, func)", [](VM* vm, ArgsView args){ vm->bind(type, "add_function(self, func)", [](VM* vm, ArgsView args) {
LineProfilerW& self = PK_OBJ_GET(LineProfilerW, args[0]); LineProfilerW& self = PK_OBJ_GET(LineProfilerW, args[0]);
vm->check_type(args[1], VM::tp_function); vm->check_type(args[1], VM::tp_function);
auto decl = PK_OBJ_GET(Function, args[1]).decl.get(); auto decl = PK_OBJ_GET(Function, args[1]).decl.get();
@ -307,19 +307,20 @@ struct LineProfilerW{
return vm->None; return vm->None;
}); });
vm->bind(type, "runcall(self, func, *args)", [](VM* vm, ArgsView view){ vm->bind(type, "runcall(self, func, *args)", [](VM* vm, ArgsView view) {
LineProfilerW& self = PK_OBJ_GET(LineProfilerW, view[0]); LineProfilerW& self = PK_OBJ_GET(LineProfilerW, view[0]);
PyVar func = view[1]; PyVar func = view[1];
const Tuple& args = CAST(Tuple&, view[2]); const Tuple& args = CAST(Tuple&, view[2]);
vm->s_data.push(func); vm->s_data.push(func);
vm->s_data.push(PY_NULL); vm->s_data.push(PY_NULL);
for(PyVar arg : args) vm->s_data.push(arg); for(PyVar arg: args)
vm->s_data.push(arg);
_LpGuard guard(&self, vm); _LpGuard guard(&self, vm);
PyVar ret = vm->vectorcall(args.size()); PyVar ret = vm->vectorcall(args.size());
return ret; return ret;
}); });
vm->bind(type, "print_stats(self)", [](VM* vm, ArgsView args){ vm->bind(type, "print_stats(self)", [](VM* vm, ArgsView args) {
LineProfilerW& self = PK_OBJ_GET(LineProfilerW, args[0]); LineProfilerW& self = PK_OBJ_GET(LineProfilerW, args[0]);
vm->stdout_write(self.profiler.stats()); vm->stdout_write(self.profiler.stats());
return vm->None; return vm->None;
@ -327,28 +328,23 @@ struct LineProfilerW{
} }
}; };
_LpGuard::_LpGuard(LineProfilerW* lp, VM* vm) : lp(lp), vm(vm) {
_LpGuard::_LpGuard(LineProfilerW* lp, VM* vm): lp(lp), vm(vm) { if(vm->_profiler) { vm->ValueError("only one profiler can be enabled at a time"); }
if(vm->_profiler){
vm->ValueError("only one profiler can be enabled at a time");
}
vm->_profiler = &lp->profiler; vm->_profiler = &lp->profiler;
lp->profiler.begin(); lp->profiler.begin();
} }
_LpGuard::~_LpGuard(){ _LpGuard::~_LpGuard() {
vm->_profiler = nullptr; vm->_profiler = nullptr;
lp->profiler.end(); lp->profiler.end();
} }
void add_module_line_profiler(VM *vm){ void add_module_line_profiler(VM* vm) {
PyObject* mod = vm->new_module("line_profiler"); PyObject* mod = vm->new_module("line_profiler");
vm->register_user_class<LineProfilerW>(mod, "LineProfiler"); vm->register_user_class<LineProfilerW>(mod, "LineProfiler");
} }
#else #else
void add_module_line_profiler(VM* vm){ void add_module_line_profiler(VM* vm) { (void)vm; }
(void)vm;
}
#endif #endif
} // namespace pkpy } // namespace pkpy

View File

@ -36,23 +36,21 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
struct mt19937{ struct mt19937 {
static const int N = 624; const static int N = 624;
static const int M = 397; const static int M = 397;
const uint32_t MATRIX_A = 0x9908b0dfUL; /* constant vector a */ const uint32_t MATRIX_A = 0x9908b0dfUL; /* constant vector a */
const uint32_t UPPER_MASK = 0x80000000UL; /* most significant w-r bits */ const uint32_t UPPER_MASK = 0x80000000UL; /* most significant w-r bits */
const uint32_t LOWER_MASK = 0x7fffffffUL; /* least significant r bits */ const uint32_t LOWER_MASK = 0x7fffffffUL; /* least significant r bits */
uint32_t mt[N]; /* the array for the state vector */ uint32_t mt[N]; /* the array for the state vector */
int mti=N+1; /* mti==N+1 means mt[N] is not initialized */ int mti = N + 1; /* mti==N+1 means mt[N] is not initialized */
/* initializes mt[N] with a seed */ /* initializes mt[N] with a seed */
void seed(uint32_t s) void seed(uint32_t s) {
{ mt[0] = s & 0xffffffffUL;
mt[0]= s & 0xffffffffUL; for(mti = 1; mti < N; mti++) {
for (mti=1; mti<N; mti++) { mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
mt[mti] =
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */ /* In the previous versions, MSBs of the seed affect */
/* only MSBs of the array mt[]. */ /* only MSBs of the array mt[]. */
@ -63,28 +61,27 @@ struct mt19937{
} }
/* generates a random number on [0,0xffffffff]-interval */ /* generates a random number on [0,0xffffffff]-interval */
uint32_t next_uint32(void) uint32_t next_uint32(void) {
{
uint32_t y; uint32_t y;
static uint32_t mag01[2]={0x0UL, MATRIX_A}; static uint32_t mag01[2] = {0x0UL, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */ /* mag01[x] = x * MATRIX_A for x=0,1 */
if (mti >= N) { /* generate N words at one time */ if(mti >= N) { /* generate N words at one time */
int kk; int kk;
if (mti == N+1) /* if init_genrand() has not been called, */ if(mti == N + 1) /* if init_genrand() has not been called, */
seed(5489UL); /* a default initial seed is used */ seed(5489UL); /* a default initial seed is used */
for (kk=0;kk<N-M;kk++) { for(kk = 0; kk < N - M; kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL]; mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL];
} }
for (;kk<N-1;kk++) { for(; kk < N - 1; kk++) {
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
} }
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0; mti = 0;
} }
@ -100,44 +97,36 @@ struct mt19937{
return y; return y;
} }
uint64_t next_uint64(void){ uint64_t next_uint64(void) { return (uint64_t(next_uint32()) << 32) | next_uint32(); }
return (uint64_t(next_uint32()) << 32) | next_uint32();
}
/* generates a random number on [0,1)-real-interval */ /* generates a random number on [0,1)-real-interval */
float random(void) float random(void) { return next_uint32() * (1.0 / 4294967296.0); /* divided by 2^32 */ }
{
return next_uint32()*(1.0/4294967296.0); /* divided by 2^32 */
}
/* generates a random number on [a, b]-interval */ /* generates a random number on [a, b]-interval */
int64_t randint(int64_t a, int64_t b){ int64_t randint(int64_t a, int64_t b) {
uint64_t delta = b - a + 1; uint64_t delta = b - a + 1;
if(delta < 0x80000000UL){ if(delta < 0x80000000UL) {
return a + next_uint32() % (uint32_t)delta; return a + next_uint32() % (uint32_t)delta;
}else{ } else {
return a + next_uint64() % delta; return a + next_uint64() % delta;
} }
} }
float uniform(float a, float b){ float uniform(float a, float b) { return a + random() * (b - a); }
return a + random() * (b - a);
}
}; };
namespace pkpy {
namespace pkpy{ struct Random {
struct Random{
mt19937 gen; mt19937 gen;
Random(){ Random() {
auto count = std::chrono::high_resolution_clock::now().time_since_epoch().count(); auto count = std::chrono::high_resolution_clock::now().time_since_epoch().count();
gen.seed((uint32_t)count); gen.seed((uint32_t)count);
} }
static void _register(VM* vm, PyObject* mod, PyObject* type){ static void _register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args){ vm->bind_func(type, __new__, 1, [](VM* vm, ArgsView args) {
Type cls = PK_OBJ_GET(Type, args[0]); Type cls = PK_OBJ_GET(Type, args[0]);
return vm->new_object<Random>(cls); return vm->new_object<Random>(cls);
}); });
@ -152,7 +141,7 @@ struct Random{
Random& self = PK_OBJ_GET(Random, args[0]); Random& self = PK_OBJ_GET(Random, args[0]);
i64 a = CAST(i64, args[1]); i64 a = CAST(i64, args[1]);
i64 b = CAST(i64, args[2]); i64 b = CAST(i64, args[2]);
if (a > b) vm->ValueError("randint(a, b): a must be less than or equal to b"); if(a > b) vm->ValueError("randint(a, b): a must be less than or equal to b");
return VAR(self.gen.randint(a, b)); return VAR(self.gen.randint(a, b));
}); });
@ -165,14 +154,14 @@ struct Random{
Random& self = PK_OBJ_GET(Random, args[0]); Random& self = PK_OBJ_GET(Random, args[0]);
f64 a = CAST(f64, args[1]); f64 a = CAST(f64, args[1]);
f64 b = CAST(f64, args[2]); f64 b = CAST(f64, args[2]);
if (a > b) std::swap(a, b); if(a > b) std::swap(a, b);
return VAR(self.gen.uniform(a, b)); return VAR(self.gen.uniform(a, b));
}); });
vm->bind_func(type, "shuffle", 2, [](VM* vm, ArgsView args) { vm->bind_func(type, "shuffle", 2, [](VM* vm, ArgsView args) {
Random& self = PK_OBJ_GET(Random, args[0]); Random& self = PK_OBJ_GET(Random, args[0]);
List& L = CAST(List&, args[1]); List& L = CAST(List&, args[1]);
for(int i = L.size() - 1; i > 0; i--){ for(int i = L.size() - 1; i > 0; i--) {
int j = self.gen.randint(0, i); int j = self.gen.randint(0, i);
std::swap(L[i], L[j]); std::swap(L[i], L[j]);
} }
@ -183,7 +172,7 @@ struct Random{
Random& self = PK_OBJ_GET(Random, args[0]); Random& self = PK_OBJ_GET(Random, args[0]);
ArgsView view = vm->cast_array_view(args[1]); ArgsView view = vm->cast_array_view(args[1]);
if(view.empty()) vm->IndexError("cannot choose from an empty sequence"); if(view.empty()) vm->IndexError("cannot choose from an empty sequence");
int index = self.gen.randint(0, view.size()-1); int index = self.gen.randint(0, view.size() - 1);
return view[index]; return view[index];
}); });
@ -194,20 +183,21 @@ struct Random{
int size = view.size(); int size = view.size();
if(size == 0) vm->IndexError("cannot choose from an empty sequence"); if(size == 0) vm->IndexError("cannot choose from an empty sequence");
array<f64> cum_weights(size); array<f64> cum_weights(size);
if(args[2] == vm->None){ if(args[2] == vm->None) {
for(int i = 0; i < size; i++) cum_weights[i] = i + 1; for(int i = 0; i < size; i++)
}else{ cum_weights[i] = i + 1;
} else {
ArgsView weights = vm->cast_array_view(args[2]); ArgsView weights = vm->cast_array_view(args[2]);
if(weights.size() != size) vm->ValueError(_S("len(weights) != ", size)); if(weights.size() != size) vm->ValueError(_S("len(weights) != ", size));
cum_weights[0] = CAST(f64, weights[0]); cum_weights[0] = CAST(f64, weights[0]);
for(int i = 1; i < size; i++){ for(int i = 1; i < size; i++) {
cum_weights[i] = cum_weights[i - 1] + CAST(f64, weights[i]); cum_weights[i] = cum_weights[i - 1] + CAST(f64, weights[i]);
} }
} }
if(cum_weights[size - 1] <= 0) vm->ValueError("total of weights must be greater than zero"); if(cum_weights[size - 1] <= 0) vm->ValueError("total of weights must be greater than zero");
int k = CAST(int, args[3]); int k = CAST(int, args[3]);
List result(k); List result(k);
for(int i = 0; i < k; i++){ for(int i = 0; i < k; i++) {
f64 r = self.gen.uniform(0.0, cum_weights[size - 1]); f64 r = self.gen.uniform(0.0, cum_weights[size - 1]);
int idx = std::lower_bound(cum_weights.begin(), cum_weights.end(), r) - cum_weights.begin(); int idx = std::lower_bound(cum_weights.begin(), cum_weights.end(), r) - cum_weights.begin();
result[i] = data[idx]; result[i] = data[idx];
@ -217,7 +207,7 @@ struct Random{
} }
}; };
void add_module_random(VM* vm){ void add_module_random(VM* vm) {
PyObject* mod = vm->new_module("random"); PyObject* mod = vm->new_module("random");
vm->register_user_class<Random>(mod, "Random"); vm->register_user_class<Random>(mod, "Random");
PyVar instance = vm->new_user_object<Random>(); PyVar instance = vm->new_user_object<Random>();

View File

@ -1,6 +1,6 @@
#include "pocketpy/objects/builtins.hpp" #include "pocketpy/objects/builtins.hpp"
namespace pkpy{ namespace pkpy {
PyVar const PY_OP_CALL(Type(), new PyObject(Type())); const PyVar PY_OP_CALL(Type(), new PyObject(Type()));
PyVar const PY_OP_YIELD(Type(), new PyObject(Type())); const PyVar PY_OP_YIELD(Type(), new PyObject(Type()));
} // namespace pkpy } // namespace pkpy

View File

@ -1,9 +1,9 @@
#include "pocketpy/objects/codeobject.hpp" #include "pocketpy/objects/codeobject.hpp"
namespace pkpy{ namespace pkpy {
CodeObject::CodeObject(std::shared_ptr<SourceData> src, const Str& name): CodeObject::CodeObject(std::shared_ptr<SourceData> src, const Str& name) :
src(src), name(name), nlocals(0), start_line(-1), end_line(-1) { src(src), name(name), nlocals(0), start_line(-1), end_line(-1) {
blocks.push_back(CodeBlock(CodeBlockType::NO_BLOCK, -1, 0)); blocks.push_back(CodeBlock(CodeBlockType::NO_BLOCK, -1, 0));
} }
} // namespace pkpy } // namespace pkpy

View File

@ -1,24 +1,24 @@
#include "pocketpy/objects/dict.hpp" #include "pocketpy/objects/dict.hpp"
namespace pkpy{ namespace pkpy {
Dict::Dict(): _capacity(__Capacity), Dict::Dict() :
_mask(__Capacity-1), _capacity(__Capacity), _mask(__Capacity - 1), _size(0), _critical_size(__Capacity * __LoadFactor + 0.5f),
_size(0), _critical_size(__Capacity*__LoadFactor+0.5f), _head_idx(-1), _tail_idx(-1){ _head_idx(-1), _tail_idx(-1) {
__alloc_items(); __alloc_items();
} }
void Dict::__alloc_items(){ void Dict::__alloc_items() {
_items = (Item*)std::malloc(_capacity * sizeof(Item)); _items = (Item*)std::malloc(_capacity * sizeof(Item));
for(int i=0; i<_capacity; i++){ for(int i = 0; i < _capacity; i++) {
_items[i].first = nullptr; _items[i].first = nullptr;
_items[i].second = nullptr; _items[i].second = nullptr;
_items[i].prev = -1; _items[i].prev = -1;
_items[i].next = -1; _items[i].next = -1;
} }
} }
Dict::Dict(Dict&& other){ Dict::Dict(Dict&& other) {
_capacity = other._capacity; _capacity = other._capacity;
_mask = other._mask; _mask = other._mask;
_size = other._size; _size = other._size;
@ -27,9 +27,9 @@ namespace pkpy{
_tail_idx = other._tail_idx; _tail_idx = other._tail_idx;
_items = other._items; _items = other._items;
other._items = nullptr; other._items = nullptr;
} }
Dict::Dict(const Dict& other){ Dict::Dict(const Dict& other) {
_capacity = other._capacity; _capacity = other._capacity;
_mask = other._mask; _mask = other._mask;
_size = other._size; _size = other._size;
@ -39,38 +39,39 @@ namespace pkpy{
// copy items // copy items
_items = (Item*)std::malloc(_capacity * sizeof(Item)); _items = (Item*)std::malloc(_capacity * sizeof(Item));
std::memcpy(_items, other._items, _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 // do possible rehash
if(_size+1 > _critical_size) _rehash(vm); if(_size + 1 > _critical_size) _rehash(vm);
bool ok; int i; bool ok;
int i;
_probe_1(vm, key, ok, i); _probe_1(vm, key, ok, i);
if(!ok) { if(!ok) {
_size++; _size++;
_items[i].first = key; _items[i].first = key;
// append to tail // append to tail
if(_size == 0+1){ if(_size == 0 + 1) {
_head_idx = i; _head_idx = i;
_tail_idx = i; _tail_idx = i;
}else{ } else {
_items[i].prev = _tail_idx; _items[i].prev = _tail_idx;
_items[_tail_idx].next = i; _items[_tail_idx].next = i;
_tail_idx = i; _tail_idx = i;
} }
} }
_items[i].second = val; _items[i].second = val;
} }
void Dict::_rehash(VM* vm){ void Dict::_rehash(VM* vm) {
Item* old_items = _items; Item* old_items = _items;
int old_head_idx = _head_idx; int old_head_idx = _head_idx;
_capacity *= 4; _capacity *= 4;
_mask = _capacity - 1; _mask = _capacity - 1;
_size = 0; _size = 0;
_critical_size = _capacity*__LoadFactor+0.5f; _critical_size = _capacity * __LoadFactor + 0.5f;
_head_idx = -1; _head_idx = -1;
_tail_idx = -1; _tail_idx = -1;
@ -78,47 +79,50 @@ namespace pkpy{
// copy old items to new dict // copy old items to new dict
int i = old_head_idx; int i = old_head_idx;
while(i != -1){ while(i != -1) {
set(vm, old_items[i].first, old_items[i].second); set(vm, old_items[i].first, old_items[i].second);
i = old_items[i].next; i = old_items[i].next;
} }
std::free(old_items); std::free(old_items);
} }
PyVar Dict::try_get(VM* vm, PyVar key) const {
PyVar Dict::try_get(VM* vm, PyVar key) const{ bool ok;
bool ok; int i; int i;
_probe_0(vm, key, ok, i); _probe_0(vm, key, ok, i);
if(!ok) return nullptr; if(!ok) return nullptr;
return _items[i].second; return _items[i].second;
} }
bool Dict::contains(VM* vm, PyVar key) const{ bool Dict::contains(VM* vm, PyVar key) const {
bool ok; int i; bool ok;
int i;
_probe_0(vm, key, ok, i); _probe_0(vm, key, ok, i);
return ok; return ok;
} }
bool Dict::del(VM* vm, PyVar key){ bool Dict::del(VM* vm, PyVar key) {
bool ok; int i; bool ok;
int i;
_probe_0(vm, key, ok, i); _probe_0(vm, key, ok, i);
if(!ok) return false; if(!ok) return false;
_items[i].first = nullptr; _items[i].first = nullptr;
// _items[i].second = PY_DELETED_SLOT; // do not change .second if it is not NULL, it means the slot is occupied by a deleted item // _items[i].second = PY_DELETED_SLOT; // do not change .second if it is not NULL, it means the slot is occupied by
// a deleted item
_size--; _size--;
if(_size == 0){ if(_size == 0) {
_head_idx = -1; _head_idx = -1;
_tail_idx = -1; _tail_idx = -1;
}else{ } else {
if(_head_idx == i){ if(_head_idx == i) {
_head_idx = _items[i].next; _head_idx = _items[i].next;
_items[_head_idx].prev = -1; _items[_head_idx].prev = -1;
}else if(_tail_idx == i){ } else if(_tail_idx == i) {
_tail_idx = _items[i].prev; _tail_idx = _items[i].prev;
_items[_tail_idx].next = -1; _items[_tail_idx].next = -1;
}else{ } else {
_items[_items[i].prev].next = _items[i].next; _items[_items[i].prev].next = _items[i].next;
_items[_items[i].next].prev = _items[i].prev; _items[_items[i].next].prev = _items[i].prev;
} }
@ -126,49 +130,51 @@ namespace pkpy{
_items[i].prev = -1; _items[i].prev = -1;
_items[i].next = -1; _items[i].next = -1;
return true; return true;
} }
void Dict::update(VM* vm, const Dict& other){ void Dict::update(VM* vm, const Dict& other) {
other.apply([&](PyVar k, PyVar v){ set(vm, k, v); }); other.apply([&](PyVar k, PyVar v) {
} set(vm, k, v);
});
}
Tuple Dict::keys() const{ Tuple Dict::keys() const {
Tuple t(_size); Tuple t(_size);
int i = _head_idx; int i = _head_idx;
int j = 0; int j = 0;
while(i != -1){ while(i != -1) {
t[j++] = _items[i].first; t[j++] = _items[i].first;
i = _items[i].next; i = _items[i].next;
} }
assert(j == _size); assert(j == _size);
return t; return t;
} }
Tuple Dict::values() const{ Tuple Dict::values() const {
Tuple t(_size); Tuple t(_size);
int i = _head_idx; int i = _head_idx;
int j = 0; int j = 0;
while(i != -1){ while(i != -1) {
t[j++] = _items[i].second; t[j++] = _items[i].second;
i = _items[i].next; i = _items[i].next;
} }
assert(j == _size); assert(j == _size);
return t; return t;
} }
void Dict::clear(){ void Dict::clear() {
_size = 0; _size = 0;
_head_idx = -1; _head_idx = -1;
_tail_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].first = nullptr;
_items[i].second = nullptr; _items[i].second = nullptr;
_items[i].prev = -1; _items[i].prev = -1;
_items[i].next = -1; _items[i].next = -1;
} }
} }
Dict::~Dict(){ Dict::~Dict() {
if(_items) std::free(_items); if(_items) std::free(_items);
} }
} // namespace pkpy } // namespace pkpy

View File

@ -1,7 +1,7 @@
#include "pocketpy/objects/error.hpp" #include "pocketpy/objects/error.hpp"
namespace pkpy{ namespace pkpy {
Str Exception::summary() const { Str Exception::summary() const {
SStream ss; SStream ss;
if(is_re) ss << "Traceback (most recent call last):\n"; if(is_re) ss << "Traceback (most recent call last):\n";
// while(!st.empty()) { // while(!st.empty()) {
@ -9,12 +9,14 @@ namespace pkpy{
// st.pop(); // st.pop();
// } // }
const auto& container = stacktrace.container(); const auto& container = stacktrace.container();
for(int i=container.size()-1; i>=0; i--){ for(int i = container.size() - 1; i >= 0; i--) {
ss << container[i].snapshot() << '\n'; ss << container[i].snapshot() << '\n';
} }
if (!msg.empty()) ss << type.sv() << ": " << msg; if(!msg.empty())
else ss << type.sv(); ss << type.sv() << ": " << msg;
else
ss << type.sv();
return ss.str(); return ss.str();
} }
} // namespace pkpy } // namespace pkpy

View File

@ -1,5 +1,5 @@
#include "pocketpy/objects/object.hpp" #include "pocketpy/objects/object.hpp"
namespace pkpy{ namespace pkpy {
PyVar::PyVar(PyObject* p): PyVar(p->type, p) {} PyVar::PyVar(PyObject* p) : PyVar(p->type, p) {}
} // namespace pkpy } // namespace pkpy

View File

@ -1,66 +1,68 @@
#include "pocketpy/objects/sourcedata.hpp" #include "pocketpy/objects/sourcedata.hpp"
namespace pkpy{ namespace pkpy {
SourceData::SourceData(std::string_view source, const Str& filename, CompileMode mode): filename(filename), mode(mode) { SourceData::SourceData(std::string_view source, const Str& filename, CompileMode mode) :
filename(filename), mode(mode) {
int index = 0; int index = 0;
// Skip utf8 BOM if there is any. // 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' // Drop all '\r'
SStream ss(source.size() + 1); SStream ss(source.size() + 1);
while(index < source.size()){ while(index < source.size()) {
if(source[index] != '\r') ss << source[index]; if(source[index] != '\r') ss << source[index];
index++; index++;
} }
this->source = ss.str(); 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; this->is_precompiled = true;
}else{ } else {
this->is_precompiled = false; this->is_precompiled = false;
} }
line_starts.push_back(this->source.c_str()); 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()); 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}; if(is_precompiled || lineno == -1) return {nullptr, nullptr};
lineno -= 1; lineno -= 1;
if(lineno < 0) lineno = 0; if(lineno < 0) lineno = 0;
const char* _start = line_starts[lineno]; const char* _start = line_starts[lineno];
const char* i = _start; const char* i = _start;
// max 300 chars // max 300 chars
while(*i != '\n' && *i != '\0' && i-_start < 300) i++; while(*i != '\n' && *i != '\0' && i - _start < 300)
i++;
return {_start, 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); 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 "<?>"; 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; SStream ss;
ss << " " << "File \"" << filename << "\", line " << lineno; ss << " " << "File \"" << filename << "\", line " << lineno;
if(!name.empty()) ss << ", in " << name; if(!name.empty()) ss << ", in " << name;
if(!is_precompiled){ if(!is_precompiled) {
ss << '\n'; ss << '\n';
std::pair<const char*,const char*> pair = _get_line(lineno); std::pair<const char*, const char*> pair = _get_line(lineno);
Str line = "<?>"; Str line = "<?>";
int removed_spaces = 0; int removed_spaces = 0;
if(pair.first && pair.second){ if(pair.first && pair.second) {
line = Str(pair.first, pair.second-pair.first).lstrip(); line = Str(pair.first, pair.second - pair.first).lstrip();
removed_spaces = pair.second - pair.first - line.length(); removed_spaces = pair.second - pair.first - line.length();
if(line.empty()) line = "<?>"; if(line.empty()) line = "<?>";
} }
ss << " " << 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; auto column = cursor - pair.first - removed_spaces;
if(column >= 0) ss << "\n " << std::string(column, ' ') << "^"; if(column >= 0) ss << "\n " << std::string(column, ' ') << "^";
} }
} }
return ss.str(); return ss.str();
} }
} // namespace pkpy } // namespace pkpy

View File

@ -2,10 +2,10 @@
namespace pkpy { namespace pkpy {
Tuple::Tuple(int n){ Tuple::Tuple(int n) {
if(n <= INLINED_SIZE){ if(n <= INLINED_SIZE) {
this->_args = _inlined; this->_args = _inlined;
}else{ } else {
this->_args = (PyVar*)std::malloc(n * sizeof(PyVar)); this->_args = (PyVar*)std::malloc(n * sizeof(PyVar));
} }
this->_size = n; this->_size = n;
@ -13,38 +13,43 @@ Tuple::Tuple(int n){
Tuple::Tuple(Tuple&& other) noexcept { Tuple::Tuple(Tuple&& other) noexcept {
_size = other._size; _size = other._size;
if(other.is_inlined()){ if(other.is_inlined()) {
_args = _inlined; _args = _inlined;
for(int i=0; i<_size; i++) _args[i] = other._args[i]; for(int i = 0; i < _size; i++)
}else{ _args[i] = other._args[i];
} else {
_args = other._args; _args = other._args;
other._args = other._inlined; other._args = other._inlined;
other._size = 0; other._size = 0;
} }
} }
Tuple::Tuple(PyVar _0, PyVar _1): Tuple(2){ Tuple::Tuple(PyVar _0, PyVar _1) : Tuple(2) {
_args[0] = _0; _args[0] = _0;
_args[1] = _1; _args[1] = _1;
} }
Tuple::Tuple(PyVar _0, PyVar _1, PyVar _2): Tuple(3){ Tuple::Tuple(PyVar _0, PyVar _1, PyVar _2) : Tuple(3) {
_args[0] = _0; _args[0] = _0;
_args[1] = _1; _args[1] = _1;
_args[2] = _2; _args[2] = _2;
} }
Tuple::~Tuple(){ if(!is_inlined()) std::free(_args); } Tuple::~Tuple() {
if(!is_inlined()) std::free(_args);
}
List ArgsView::to_list() const{ List ArgsView::to_list() const {
List ret(size()); List ret(size());
for(int i=0; i<size(); i++) ret[i] = _begin[i]; for(int i = 0; i < size(); i++)
ret[i] = _begin[i];
return ret; return ret;
} }
Tuple ArgsView::to_tuple() const{ Tuple ArgsView::to_tuple() const {
Tuple ret(size()); Tuple ret(size());
for(int i=0; i<size(); i++) ret[i] = _begin[i]; for(int i = 0; i < size(); i++)
ret[i] = _begin[i];
return ret; return ret;
} }

File diff suppressed because it is too large Load Diff

View File

@ -9,30 +9,27 @@ using namespace pkpy;
#define PK_ASSERT_N_EXTRA_ELEMENTS(n) \ #define PK_ASSERT_N_EXTRA_ELEMENTS(n) \
int __ex_count = count_extra_elements(vm, n); \ int __ex_count = count_extra_elements(vm, n); \
if(__ex_count < n){ \ if(__ex_count < n) { \
Str msg = _S("expected at least ", n, " elements, got ", __ex_count); \ Str msg = _S("expected at least ", n, " elements, got ", __ex_count); \
pkpy_error(vm_handle, "StackError", pkpy_string(msg.c_str())); \ pkpy_error(vm_handle, "StackError", pkpy_string(msg.c_str())); \
return false; \ return false; \
} }
#define PK_ASSERT_NO_ERROR() \ #define PK_ASSERT_NO_ERROR() \
if(vm->__c.error != nullptr) \ if(vm->__c.error != nullptr) return false;
return false;
static int count_extra_elements(VM* vm, int n){ static int count_extra_elements(VM* vm, int n) {
if(vm->callstack.empty()){ if(vm->callstack.empty()) { return vm->s_data.size(); }
return vm->s_data.size();
}
assert(!vm->__c.s_view.empty()); assert(!vm->__c.s_view.empty());
return vm->s_data._sp - vm->__c.s_view.top().end(); return vm->s_data._sp - vm->__c.s_view.top().end();
} }
static PyVar stack_item(VM* vm, int index){ static PyVar stack_item(VM* vm, int index) {
PyVar* begin; PyVar* begin;
PyVar* end = vm->s_data.end(); PyVar* end = vm->s_data.end();
if(vm->callstack.empty()){ if(vm->callstack.empty()) {
begin = vm->s_data.begin(); begin = vm->s_data.begin();
}else{ } else {
assert(!vm->__c.s_view.empty()); assert(!vm->__c.s_view.empty());
begin = vm->__c.s_view.top().begin(); begin = vm->__c.s_view.top().begin();
} }
@ -43,26 +40,23 @@ static PyVar stack_item(VM* vm, int index){
} }
#define PK_PROTECTED(__B) \ #define PK_PROTECTED(__B) \
try{ __B } \ try { \
catch(TopLevelException e) { \ __B \
} catch(TopLevelException e) { \
vm->__c.error = e.ptr->self(); \ vm->__c.error = e.ptr->self(); \
return false; \ return false; \
} catch(const std::exception& re){ \ } catch(const std::exception& re) { \
PyObject* e_t = vm->_t(vm->tp_exception); \ PyObject* e_t = vm->_t(vm->tp_exception); \
vm->__c.error = vm->call(e_t, VAR(re.what())).get(); \ vm->__c.error = vm->call(e_t, VAR(re.what())).get(); \
return false; \ return false; \
} }
pkpy_vm* pkpy_new_vm(bool enable_os){ pkpy_vm* pkpy_new_vm(bool enable_os) { return (pkpy_vm*)new VM(enable_os); }
return (pkpy_vm*)new VM(enable_os);
}
void pkpy_delete_vm(pkpy_vm* vm){ void pkpy_delete_vm(pkpy_vm* vm) { return delete (VM*)vm; }
return delete (VM*)vm;
}
bool pkpy_exec(pkpy_vm* vm_handle, const char* source) { bool pkpy_exec(pkpy_vm* vm_handle, const char* source) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PyVar res; PyVar res;
PK_PROTECTED( PK_PROTECTED(
@ -72,14 +66,13 @@ bool pkpy_exec(pkpy_vm* vm_handle, const char* source) {
return res != nullptr; return res != nullptr;
} }
bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, const char* module){ bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, int mode, const char* module) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PyVar res; PyVar res;
PyObject* mod; PyObject* mod;
PK_PROTECTED( PK_PROTECTED(
if(module == nullptr){ if(module == nullptr){ mod = vm->_main;
mod = vm->_main;
}else{ }else{
mod = vm->_modules[module].get(); // may raise mod = vm->_modules[module].get(); // may raise
} }
@ -89,13 +82,13 @@ bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, i
return res != nullptr; return res != nullptr;
} }
void pkpy_set_main_argv(pkpy_vm* vm_handle, int argc, char** argv){ void pkpy_set_main_argv(pkpy_vm* vm_handle, int argc, char** argv) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
vm->set_main_argv(argc, argv); vm->set_main_argv(argc, argv);
} }
bool pkpy_dup(pkpy_vm* vm_handle, int n){ bool pkpy_dup(pkpy_vm* vm_handle, int n) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
PyVar item = stack_item(vm, n); PyVar item = stack_item(vm, n);
@ -104,15 +97,15 @@ bool pkpy_dup(pkpy_vm* vm_handle, int n){
return true; return true;
} }
bool pkpy_pop(pkpy_vm* vm_handle, int n){ bool pkpy_pop(pkpy_vm* vm_handle, int n) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_ASSERT_N_EXTRA_ELEMENTS(n) PK_ASSERT_N_EXTRA_ELEMENTS(n)
vm->s_data.shrink(n); vm->s_data.shrink(n);
return true; return true;
} }
bool pkpy_pop_top(pkpy_vm* vm_handle){ bool pkpy_pop_top(pkpy_vm* vm_handle) {
VM* vm = (VM*)vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_ASSERT_N_EXTRA_ELEMENTS(1) PK_ASSERT_N_EXTRA_ELEMENTS(1)
@ -120,7 +113,7 @@ bool pkpy_pop_top(pkpy_vm* vm_handle){
return true; return true;
} }
bool pkpy_dup_top(pkpy_vm* vm_handle){ bool pkpy_dup_top(pkpy_vm* vm_handle) {
VM* vm = (VM*)vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_ASSERT_N_EXTRA_ELEMENTS(1) PK_ASSERT_N_EXTRA_ELEMENTS(1)
@ -128,7 +121,7 @@ bool pkpy_dup_top(pkpy_vm* vm_handle){
return true; return true;
} }
bool pkpy_rot_two(pkpy_vm* vm_handle){ bool pkpy_rot_two(pkpy_vm* vm_handle) {
VM* vm = (VM*)vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_ASSERT_N_EXTRA_ELEMENTS(2) PK_ASSERT_N_EXTRA_ELEMENTS(2)
@ -136,19 +129,17 @@ bool pkpy_rot_two(pkpy_vm* vm_handle){
return true; return true;
} }
int pkpy_stack_size(pkpy_vm* vm_handle){ int pkpy_stack_size(pkpy_vm* vm_handle) {
VM* vm = (VM*)vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
if(vm->callstack.empty()){ if(vm->callstack.empty()) { return vm->s_data.size(); }
return vm->s_data.size();
}
if(vm->__c.s_view.empty()) exit(127); if(vm->__c.s_view.empty()) exit(127);
return vm->s_data._sp - vm->__c.s_view.top().begin(); return vm->s_data._sp - vm->__c.s_view.top().begin();
} }
// int // int
bool pkpy_push_int(pkpy_vm* vm_handle, int value) { bool pkpy_push_int(pkpy_vm* vm_handle, int value) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PyVar res; PyVar res;
PK_PROTECTED( PK_PROTECTED(
@ -159,16 +150,16 @@ bool pkpy_push_int(pkpy_vm* vm_handle, int value) {
return true; return true;
} }
bool pkpy_is_int(pkpy_vm* vm_handle, int i){ bool pkpy_is_int(pkpy_vm* vm_handle, int i) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
return is_int(stack_item(vm, i)); return is_int(stack_item(vm, i));
) )
} }
bool pkpy_to_int(pkpy_vm* vm_handle, int i, int* out){ bool pkpy_to_int(pkpy_vm* vm_handle, int i, int* out) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
PyVar item = stack_item(vm, i); PyVar item = stack_item(vm, i);
@ -179,15 +170,15 @@ bool pkpy_to_int(pkpy_vm* vm_handle, int i, int* out){
// float // float
bool pkpy_push_float(pkpy_vm* vm_handle, double value) { bool pkpy_push_float(pkpy_vm* vm_handle, double value) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PyVar res = py_var(vm, value); PyVar res = py_var(vm, value);
vm->s_data.push(res); vm->s_data.push(res);
return true; return true;
} }
bool pkpy_is_float(pkpy_vm* vm_handle, int i){ bool pkpy_is_float(pkpy_vm* vm_handle, int i) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
PyVar item = stack_item(vm, i); PyVar item = stack_item(vm, i);
@ -195,8 +186,8 @@ bool pkpy_is_float(pkpy_vm* vm_handle, int i){
) )
} }
bool pkpy_to_float(pkpy_vm* vm_handle, int i, double* out){ bool pkpy_to_float(pkpy_vm* vm_handle, int i, double* out) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
PyVar item = stack_item(vm, i); PyVar item = stack_item(vm, i);
@ -207,14 +198,14 @@ bool pkpy_to_float(pkpy_vm* vm_handle, int i, double* out){
// bool // bool
bool pkpy_push_bool(pkpy_vm* vm_handle, bool value) { bool pkpy_push_bool(pkpy_vm* vm_handle, bool value) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
vm->s_data.push(value ? vm->True : vm->False); vm->s_data.push(value ? vm->True : vm->False);
return true; return true;
} }
bool pkpy_is_bool(pkpy_vm* vm_handle, int i){ bool pkpy_is_bool(pkpy_vm* vm_handle, int i) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
PyVar item = stack_item(vm, i); PyVar item = stack_item(vm, i);
@ -222,8 +213,8 @@ bool pkpy_is_bool(pkpy_vm* vm_handle, int i){
) )
} }
bool pkpy_to_bool(pkpy_vm* vm_handle, int i, bool* out){ bool pkpy_to_bool(pkpy_vm* vm_handle, int i, bool* out) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
PyVar item = stack_item(vm, i); PyVar item = stack_item(vm, i);
@ -234,15 +225,15 @@ bool pkpy_to_bool(pkpy_vm* vm_handle, int i, bool* out){
// string // string
bool pkpy_push_string(pkpy_vm* vm_handle, pkpy_CString value) { bool pkpy_push_string(pkpy_vm* vm_handle, pkpy_CString value) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PyVar res = py_var(vm, value); PyVar res = py_var(vm, value);
vm->s_data.push(res); vm->s_data.push(res);
return true; return true;
} }
bool pkpy_is_string(pkpy_vm* vm_handle, int i){ bool pkpy_is_string(pkpy_vm* vm_handle, int i) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
PyVar item = stack_item(vm, i); PyVar item = stack_item(vm, i);
@ -250,8 +241,8 @@ bool pkpy_is_string(pkpy_vm* vm_handle, int i){
) )
} }
bool pkpy_to_string(pkpy_vm* vm_handle, int i, pkpy_CString* out){ bool pkpy_to_string(pkpy_vm* vm_handle, int i, pkpy_CString* out) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
PyVar item = stack_item(vm, i); PyVar item = stack_item(vm, i);
@ -263,15 +254,15 @@ bool pkpy_to_string(pkpy_vm* vm_handle, int i, pkpy_CString* out){
// void_p // void_p
bool pkpy_push_voidp(pkpy_vm* vm_handle, void* value) { bool pkpy_push_voidp(pkpy_vm* vm_handle, void* value) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PyVar res = py_var(vm, value); PyVar res = py_var(vm, value);
vm->s_data.push(res); vm->s_data.push(res);
return true; return true;
} }
bool pkpy_is_voidp(pkpy_vm* vm_handle, int i){ bool pkpy_is_voidp(pkpy_vm* vm_handle, int i) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
PyVar item = stack_item(vm, i); PyVar item = stack_item(vm, i);
@ -279,8 +270,8 @@ bool pkpy_is_voidp(pkpy_vm* vm_handle, int i){
) )
} }
bool pkpy_to_voidp(pkpy_vm* vm_handle, int i, void** out){ bool pkpy_to_voidp(pkpy_vm* vm_handle, int i, void** out) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
PyVar item = stack_item(vm, i); PyVar item = stack_item(vm, i);
@ -292,14 +283,14 @@ bool pkpy_to_voidp(pkpy_vm* vm_handle, int i, void** out){
// none // none
bool pkpy_push_none(pkpy_vm* vm_handle) { bool pkpy_push_none(pkpy_vm* vm_handle) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
vm->s_data.push(vm->None); vm->s_data.push(vm->None);
return true; return true;
} }
bool pkpy_is_none(pkpy_vm* vm_handle, int i){ bool pkpy_is_none(pkpy_vm* vm_handle, int i) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
PyVar item = stack_item(vm, i); PyVar item = stack_item(vm, i);
@ -309,25 +300,25 @@ bool pkpy_is_none(pkpy_vm* vm_handle, int i){
// null // null
bool pkpy_push_null(pkpy_vm* vm_handle) { bool pkpy_push_null(pkpy_vm* vm_handle) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
vm->s_data.push(PY_NULL); vm->s_data.push(PY_NULL);
return true; return true;
} }
struct TempViewPopper{ struct TempViewPopper {
VM* vm; VM* vm;
bool used; bool used;
TempViewPopper(VM* vm): vm(vm), used(false) {} TempViewPopper(VM* vm) : vm(vm), used(false) {}
void restore() noexcept{ void restore() noexcept {
if(used) return; if(used) return;
vm->__c.s_view.pop(); vm->__c.s_view.pop();
used = true; used = true;
} }
~TempViewPopper(){ restore(); } ~TempViewPopper() { restore(); }
}; };
// function // function
@ -341,21 +332,21 @@ static PyVar c_function_wrapper(VM* vm, ArgsView args) {
_tvp.restore(); _tvp.restore();
// propagate_if_errored // propagate_if_errored
if (vm->__c.error != nullptr){ if(vm->__c.error != nullptr) {
PyObject* e_obj = vm->__c.error; PyObject* e_obj = vm->__c.error;
vm->__c.error = nullptr; vm->__c.error = nullptr;
vm->_error(e_obj); vm->_error(e_obj);
return nullptr; return nullptr;
} }
assert(retc == vm->s_data._sp-curr_sp); assert(retc == vm->s_data._sp - curr_sp);
if(retc == 0) return vm->None; if(retc == 0) return vm->None;
if (retc == 1) return vm->s_data.popx(); if(retc == 1) return vm->s_data.popx();
ArgsView ret_view(curr_sp, vm->s_data._sp); ArgsView ret_view(curr_sp, vm->s_data._sp);
return py_var(vm, ret_view.to_tuple()); return py_var(vm, ret_view.to_tuple());
} }
bool pkpy_push_function(pkpy_vm* vm_handle, const char* sig, pkpy_CFunction f) { bool pkpy_push_function(pkpy_vm* vm_handle, const char* sig, pkpy_CFunction f) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PyVar f_obj; PyVar f_obj;
PK_PROTECTED( PK_PROTECTED(
@ -367,7 +358,7 @@ bool pkpy_push_function(pkpy_vm* vm_handle, const char* sig, pkpy_CFunction f) {
// special push // special push
bool pkpy_push_module(pkpy_vm* vm_handle, const char* name) { bool pkpy_push_module(pkpy_vm* vm_handle, const char* name) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
PyObject* module = vm->new_module(name); PyObject* module = vm->new_module(name);
@ -378,7 +369,7 @@ bool pkpy_push_module(pkpy_vm* vm_handle, const char* name) {
// some opt // some opt
bool pkpy_getattr(pkpy_vm* vm_handle, pkpy_CName name) { bool pkpy_getattr(pkpy_vm* vm_handle, pkpy_CName name) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_ASSERT_N_EXTRA_ELEMENTS(1) PK_ASSERT_N_EXTRA_ELEMENTS(1)
PyVar o = vm->s_data.top(); PyVar o = vm->s_data.top();
@ -389,7 +380,7 @@ bool pkpy_getattr(pkpy_vm* vm_handle, pkpy_CName name) {
} }
bool pkpy_setattr(pkpy_vm* vm_handle, pkpy_CName name) { bool pkpy_setattr(pkpy_vm* vm_handle, pkpy_CName name) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_ASSERT_N_EXTRA_ELEMENTS(2) PK_ASSERT_N_EXTRA_ELEMENTS(2)
PyVar a = vm->s_data.top(); PyVar a = vm->s_data.top();
@ -401,21 +392,21 @@ bool pkpy_setattr(pkpy_vm* vm_handle, pkpy_CName name) {
return true; return true;
} }
//get global will also get bulitins // get global will also get bulitins
bool pkpy_getglobal(pkpy_vm* vm_handle, pkpy_CName name) { bool pkpy_getglobal(pkpy_vm* vm_handle, pkpy_CName name) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PyVar o = vm->_main->attr().try_get(StrName(name)); PyVar o = vm->_main->attr().try_get(StrName(name));
if (o == nullptr) { if(o == nullptr) {
o = vm->builtins->attr().try_get(StrName(name)); o = vm->builtins->attr().try_get(StrName(name));
if (o == nullptr) return false; if(o == nullptr) return false;
} }
vm->s_data.push(o); vm->s_data.push(o);
return true; return true;
} }
bool pkpy_setglobal(pkpy_vm* vm_handle, pkpy_CName name) { bool pkpy_setglobal(pkpy_vm* vm_handle, pkpy_CName name) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_ASSERT_N_EXTRA_ELEMENTS(1) PK_ASSERT_N_EXTRA_ELEMENTS(1)
vm->_main->attr().set(StrName(name), vm->s_data.popx()); vm->_main->attr().set(StrName(name), vm->s_data.popx());
@ -423,7 +414,7 @@ bool pkpy_setglobal(pkpy_vm* vm_handle, pkpy_CName name) {
} }
bool pkpy_eval(pkpy_vm* vm_handle, const char* source) { bool pkpy_eval(pkpy_vm* vm_handle, const char* source) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
CodeObject_ co = vm->compile(source, "<eval>", EVAL_MODE); CodeObject_ co = vm->compile(source, "<eval>", EVAL_MODE);
@ -434,7 +425,7 @@ bool pkpy_eval(pkpy_vm* vm_handle, const char* source) {
} }
bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) { bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_ASSERT_N_EXTRA_ELEMENTS(1) PK_ASSERT_N_EXTRA_ELEMENTS(1)
auto _lock = vm->heap.gc_scope_lock(); auto _lock = vm->heap.gc_scope_lock();
@ -450,8 +441,8 @@ bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) {
return true; return true;
} }
bool pkpy_get_unbound_method(pkpy_vm* vm_handle, pkpy_CName name){ bool pkpy_get_unbound_method(pkpy_vm* vm_handle, pkpy_CName name) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_ASSERT_N_EXTRA_ELEMENTS(1) PK_ASSERT_N_EXTRA_ELEMENTS(1)
PyVar o = vm->s_data.top(); PyVar o = vm->s_data.top();
@ -466,7 +457,7 @@ bool pkpy_get_unbound_method(pkpy_vm* vm_handle, pkpy_CName name){
} }
bool pkpy_py_repr(pkpy_vm* vm_handle) { bool pkpy_py_repr(pkpy_vm* vm_handle) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_ASSERT_N_EXTRA_ELEMENTS(1) PK_ASSERT_N_EXTRA_ELEMENTS(1)
PyVar item = vm->s_data.top(); PyVar item = vm->s_data.top();
@ -478,7 +469,7 @@ bool pkpy_py_repr(pkpy_vm* vm_handle) {
} }
bool pkpy_py_str(pkpy_vm* vm_handle) { bool pkpy_py_str(pkpy_vm* vm_handle) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_ASSERT_N_EXTRA_ELEMENTS(1) PK_ASSERT_N_EXTRA_ELEMENTS(1)
PyVar item = vm->s_data.top(); PyVar item = vm->s_data.top();
@ -490,7 +481,7 @@ bool pkpy_py_str(pkpy_vm* vm_handle) {
} }
bool pkpy_py_import(pkpy_vm* vm_handle, pkpy_CString name) { bool pkpy_py_import(pkpy_vm* vm_handle, pkpy_CString name) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_PROTECTED( PK_PROTECTED(
PyVar module = vm->py_import(name); PyVar module = vm->py_import(name);
@ -501,14 +492,15 @@ bool pkpy_py_import(pkpy_vm* vm_handle, pkpy_CString name) {
/* Error Handling */ /* Error Handling */
bool pkpy_error(pkpy_vm* vm_handle, const char* name, pkpy_CString message) { bool pkpy_error(pkpy_vm* vm_handle, const char* name, pkpy_CString message) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PyVar e_t = vm->_main->attr().try_get_likely_found(name); PyVar e_t = vm->_main->attr().try_get_likely_found(name);
if(e_t == nullptr){ if(e_t == nullptr) {
e_t = vm->builtins->attr().try_get_likely_found(name); e_t = vm->builtins->attr().try_get_likely_found(name);
if(e_t == nullptr){ if(e_t == nullptr) {
e_t = vm->_t(vm->tp_exception); e_t = vm->_t(vm->tp_exception);
std::cerr << "[warning] pkpy_error(): " << Str(name).escape() << " not found, fallback to 'Exception'" << std::endl; std::cerr << "[warning] pkpy_error(): " << Str(name).escape() << " not found, fallback to 'Exception'"
<< std::endl;
} }
} }
vm->__c.error = vm->call(e_t, VAR(message)).get(); vm->__c.error = vm->call(e_t, VAR(message)).get();
@ -516,23 +508,23 @@ bool pkpy_error(pkpy_vm* vm_handle, const char* name, pkpy_CString message) {
} }
bool pkpy_check_error(pkpy_vm* vm_handle) { bool pkpy_check_error(pkpy_vm* vm_handle) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
return vm->__c.error != nullptr; return vm->__c.error != nullptr;
} }
bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) { bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
// no error // no error
if (vm->__c.error == nullptr) return false; if(vm->__c.error == nullptr) return false;
Exception& e = vm->__c.error->as<Exception>(); Exception& e = vm->__c.error->as<Exception>();
if (message != nullptr) if(message != nullptr)
*message = strdup(e.summary().c_str()); *message = strdup(e.summary().c_str());
else else
std::cout << e.summary() << std::endl; std::cout << e.summary() << std::endl;
vm->__c.error = nullptr; vm->__c.error = nullptr;
if(vm->callstack.empty()){ if(vm->callstack.empty()) {
vm->s_data.clear(); vm->s_data.clear();
}else{ } else {
if(vm->__c.s_view.empty()) exit(127); if(vm->__c.s_view.empty()) exit(127);
vm->s_data.reset(vm->__c.s_view.top().end()); vm->s_data.reset(vm->__c.s_view.top().end());
} }
@ -540,7 +532,7 @@ bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
} }
bool pkpy_vectorcall(pkpy_vm* vm_handle, int argc) { bool pkpy_vectorcall(pkpy_vm* vm_handle, int argc) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
PK_ASSERT_N_EXTRA_ELEMENTS(argc + 2) PK_ASSERT_N_EXTRA_ELEMENTS(argc + 2)
PyVar res; PyVar res;
@ -550,39 +542,28 @@ bool pkpy_vectorcall(pkpy_vm* vm_handle, int argc) {
vm->s_data.push(res); vm->s_data.push(res);
return true; return true;
} }
/*****************************************************************/ /*****************************************************************/
void pkpy_free(void* p){ void pkpy_free(void* p) { std::free(p); }
std::free(p);
}
pkpy_CName pkpy_name(const char* name){ pkpy_CName pkpy_name(const char* name) { return StrName(name).index; }
return StrName(name).index;
}
pkpy_CString pkpy_name_to_string(pkpy_CName name){ pkpy_CString pkpy_name_to_string(pkpy_CName name) { return StrName(name).c_str(); }
return StrName(name).c_str();
}
void pkpy_set_output_handler(pkpy_vm* vm_handle, pkpy_COutputHandler handler){ void pkpy_set_output_handler(pkpy_vm* vm_handle, pkpy_COutputHandler handler) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
vm->_stdout = handler; vm->_stdout = handler;
} }
void pkpy_set_import_handler(pkpy_vm* vm_handle, pkpy_CImportHandler handler){ void pkpy_set_import_handler(pkpy_vm* vm_handle, pkpy_CImportHandler handler) {
VM* vm = (VM*) vm_handle; VM* vm = (VM*)vm_handle;
vm->_import_handler = handler; vm->_import_handler = handler;
} }
void* pkpy_new_repl(pkpy_vm* vm_handle){ void* pkpy_new_repl(pkpy_vm* vm_handle) { return new REPL((VM*)vm_handle); }
return new REPL((VM*)vm_handle);
}
bool pkpy_repl_input(void* r, const char* line){ bool pkpy_repl_input(void* r, const char* line) { return ((REPL*)r)->input(line); }
return ((REPL*)r)->input(line);
}
void pkpy_delete_repl(void* repl){ void pkpy_delete_repl(void* repl) { delete (REPL*)repl; }
delete (REPL*)repl;
}
#endif // PK_NO_EXPORT_C_API #endif // PK_NO_EXPORT_C_API

View File

@ -4,21 +4,21 @@
#include "pocketpy/common/export.h" #include "pocketpy/common/export.h"
namespace pkpy { namespace pkpy {
REPL::REPL(VM* vm) : vm(vm){ REPL::REPL(VM* vm) : vm(vm) {
vm->stdout_write("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") "); vm->stdout_write("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ") ");
vm->stdout_write(_S("[", sizeof(void*)*8, " bit] on ", kPlatformStrings[PK_SYS_PLATFORM], "\n")); vm->stdout_write(_S("[", sizeof(void*) * 8, " bit] on ", kPlatformStrings[PK_SYS_PLATFORM], "\n"));
vm->stdout_write("https://github.com/pocketpy/pocketpy" "\n"); vm->stdout_write("https://github.com/pocketpy/pocketpy" "\n");
vm->stdout_write("Type \"exit()\" to exit." "\n"); vm->stdout_write("Type \"exit()\" to exit." "\n");
} }
bool REPL::input(std::string line){ bool REPL::input(std::string line) {
CompileMode mode = REPL_MODE; CompileMode mode = REPL_MODE;
if(need_more_lines){ if(need_more_lines) {
buffer += line; buffer += line;
buffer += '\n'; buffer += '\n';
int n = buffer.size(); int n = buffer.size();
if(n>=need_more_lines){ if(n >= need_more_lines) {
for(int i=buffer.size()-need_more_lines; i<buffer.size(); i++){ for(int i = buffer.size() - need_more_lines; i < buffer.size(); i++) {
// no enough lines // no enough lines
if(buffer[i] != '\n') return true; if(buffer[i] != '\n') return true;
} }
@ -26,20 +26,20 @@ namespace pkpy {
line = buffer; line = buffer;
buffer.clear(); buffer.clear();
mode = CELL_MODE; mode = CELL_MODE;
}else{ } else {
return true; return true;
} }
} }
try{ try {
vm->exec(line, "<stdin>", mode); vm->exec(line, "<stdin>", mode);
}catch(NeedMoreLines ne){ } catch(NeedMoreLines ne) {
buffer += line; buffer += line;
buffer += '\n'; buffer += '\n';
need_more_lines = ne.is_compiling_class ? 3 : 2; need_more_lines = ne.is_compiling_class ? 3 : 2;
if (need_more_lines) return true; if(need_more_lines) return true;
} }
return false; return false;
}
} }
} // namespace pkpy

View File

@ -4,34 +4,31 @@
#include <sstream> #include <sstream>
#if __has_include("pocketpy_c.h") #if __has_include("pocketpy_c.h")
#include "pocketpy_c.h" #include "pocketpy_c.h"
#else #else
// for amalgamated build // for amalgamated build
#include "pocketpy.h" #include "pocketpy.h"
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
std::string pkpy_platform_getline(bool* eof) { std::string pkpy_platform_getline(bool* eof) {
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
std::wstringstream wss; std::wstringstream wss;
WCHAR buf; WCHAR buf;
DWORD read; DWORD read;
while (ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') { while(ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') {
if (eof && buf == L'\x1A') *eof = true; // Ctrl+Z if(eof && buf == L'\x1A') *eof = true; // Ctrl+Z
wss << buf; wss << buf;
} }
std::wstring wideInput = wss.str(); std::wstring wideInput = wss.str();
int length = int length = WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(),
(int)wideInput.length(), NULL, 0, NULL, NULL);
std::string output; std::string output;
output.resize(length); output.resize(length);
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL);
&output[0], length, NULL, NULL); if(!output.empty() && output.back() == '\r') output.pop_back();
if (!output.empty() && output.back() == '\r') output.pop_back();
return output; return output;
} }
@ -39,8 +36,8 @@ std::string pkpy_platform_getline(bool* eof) {
std::string pkpy_platform_getline(bool* eof) { std::string pkpy_platform_getline(bool* eof) {
std::string output; std::string output;
if (!std::getline(std::cin, output)) { if(!std::getline(std::cin, output)) {
if (eof) *eof = true; if(eof) *eof = true;
} }
return output; return output;
} }
@ -48,10 +45,10 @@ std::string pkpy_platform_getline(bool* eof) {
#endif #endif
static int f_input(pkpy_vm* vm) { static int f_input(pkpy_vm* vm) {
if (!pkpy_is_none(vm, -1)) { if(!pkpy_is_none(vm, -1)) {
pkpy_CString prompt; pkpy_CString prompt;
bool ok = pkpy_to_string(vm, -1, &prompt); bool ok = pkpy_to_string(vm, -1, &prompt);
if (!ok) return 0; if(!ok) return 0;
std::cout << prompt << std::flush; std::cout << prompt << std::flush;
} }
bool eof; bool eof;
@ -71,44 +68,42 @@ int main(int argc, char** argv) {
pkpy_py_import(vm, "builtins"); pkpy_py_import(vm, "builtins");
pkpy_setattr(vm, pkpy_name("input")); pkpy_setattr(vm, pkpy_name("input"));
if (argc == 1) { if(argc == 1) {
void* repl = pkpy_new_repl(vm); void* repl = pkpy_new_repl(vm);
bool need_more_lines = false; bool need_more_lines = false;
while (true) { while(true) {
std::cout << (need_more_lines ? "... " : ">>> "); std::cout << (need_more_lines ? "... " : ">>> ");
bool eof = false; bool eof = false;
std::string line = pkpy_platform_getline(&eof); std::string line = pkpy_platform_getline(&eof);
if (eof) break; if(eof) break;
need_more_lines = pkpy_repl_input(repl, line.c_str()); need_more_lines = pkpy_repl_input(repl, line.c_str());
} }
pkpy_delete_vm(vm); pkpy_delete_vm(vm);
return 0; return 0;
} }
if (argc == 2) { if(argc == 2) {
std::string argv_1 = argv[1]; std::string argv_1 = argv[1];
if (argv_1 == "-h" || argv_1 == "--help") goto __HELP; if(argv_1 == "-h" || argv_1 == "--help") goto __HELP;
std::filesystem::path filepath(argv[1]); std::filesystem::path filepath(argv[1]);
filepath = std::filesystem::absolute(filepath); filepath = std::filesystem::absolute(filepath);
if (!std::filesystem::exists(filepath)) { if(!std::filesystem::exists(filepath)) {
std::cerr << "File not found: " << argv_1 << std::endl; std::cerr << "File not found: " << argv_1 << std::endl;
return 2; return 2;
} }
std::ifstream file(filepath); std::ifstream file(filepath);
if (!file.is_open()) { if(!file.is_open()) {
std::cerr << "Failed to open file: " << argv_1 << std::endl; std::cerr << "Failed to open file: " << argv_1 << std::endl;
return 3; return 3;
} }
std::string src((std::istreambuf_iterator<char>(file)), std::string src((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
std::istreambuf_iterator<char>());
file.close(); file.close();
pkpy_set_main_argv(vm, argc, argv); pkpy_set_main_argv(vm, argc, argv);
bool ok = pkpy_exec_2(vm, src.c_str(), bool ok = pkpy_exec_2(vm, src.c_str(), filepath.filename().string().c_str(), 0, NULL);
filepath.filename().string().c_str(), 0, NULL); if(!ok) pkpy_clear_error(vm, NULL);
if (!ok) pkpy_clear_error(vm, NULL);
pkpy_delete_vm(vm); pkpy_delete_vm(vm);
return ok ? 0 : 1; return ok ? 0 : 1;
} }