format the world.

This commit is contained in:
ykiko 2024-06-04 18:28:15 +08:00
parent d37c11090d
commit 2603ca7741
88 changed files with 12060 additions and 10233 deletions

View File

@ -11,7 +11,7 @@
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 {
@ -54,14 +54,16 @@ struct any{
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 {
@ -76,7 +78,9 @@ struct any{
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>();
} }

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

@ -8,8 +8,8 @@
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

@ -10,8 +10,11 @@ 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>
@ -19,7 +22,7 @@ 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;
@ -35,7 +38,10 @@ struct NameDictImpl {
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; \
} }
@ -48,6 +54,7 @@ while(!_items[i].first.empty()) { \
~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) {
@ -60,7 +67,8 @@ while(!_items[i].first.empty()) { \
} }
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++;
@ -78,8 +86,11 @@ while(!_items[i].first.empty()) { \
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()) {
bool ok; uint16_t j; continue;
}
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];
@ -88,39 +99,56 @@ while(!_items[i].first.empty()) { \
} }
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;
if(_items[i].first == key) return _items[i].second; if(_items[i].first == key) {
return _items[i].second;
}
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;
if(_items[i].first == key) return &_items[i].second; if(_items[i].first == key) {
return &_items[i].second;
}
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();
_items[i].second = nullptr; _items[i].second = nullptr;
_size--; _size--;
@ -129,7 +157,9 @@ while(!_items[i].first.empty()) { \
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]);
pre_z = z; pre_z = z;
z = (z + 1) & _mask; z = (z + 1) & _mask;
@ -140,13 +170,16 @@ while(!_items[i].first.empty()) { \
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;
} }
@ -163,7 +196,9 @@ while(!_items[i].first.empty()) { \
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;
@ -172,9 +207,7 @@ while(!_items[i].first.empty()) { \
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;
} }
@ -185,6 +218,7 @@ while(!_items[i].first.empty()) { \
} }
_size = 0; _size = 0;
} }
#undef HASH_PROBE_0 #undef HASH_PROBE_0
#undef HASH_PROBE_1 #undef HASH_PROBE_1
}; };

View File

@ -33,10 +33,15 @@ struct Str{
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()); } size_t hash() const { return std::hash<std::string_view>()(sv()); }
Str& operator= (const Str&); Str& operator= (const Str&);
@ -64,15 +69,20 @@ struct 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;
@ -96,31 +106,28 @@ struct StrName {
uint16_t index; uint16_t index;
StrName() : index(0) {} StrName() : index(0) {}
explicit StrName(uint16_t index) : index(index) {} explicit StrName(uint16_t index) : index(index) {}
StrName(const char* s) : index(get(s).index) {} StrName(const char* s) : index(get(s).index) {}
StrName(const Str& s) : index(get(s.sv()).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();
@ -135,9 +142,11 @@ struct SStream{
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();
@ -171,7 +180,9 @@ Str _S(Args&&... args) {
struct CString { struct CString {
const char* ptr; const char* ptr;
CString(const char* ptr) : ptr(ptr) {} CString(const char* ptr) : ptr(ptr) {}
operator const char* () const { return ptr; } operator const char* () const { return ptr; }
}; };

View File

@ -6,31 +6,35 @@ 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

@ -17,7 +17,9 @@ struct explicit_copy_t {
// Dummy types // Dummy types
struct DummyInstance {}; struct DummyInstance {};
struct DummyModule {}; struct DummyModule {};
struct NoReturn {}; struct NoReturn {};
// Forward declarations // Forward declarations

View File

@ -13,9 +13,9 @@
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,17 +18,24 @@ 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 {
@ -58,7 +65,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 {
@ -85,22 +94,22 @@ 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
@ -112,21 +121,31 @@ struct vector {
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) {
if (cap <= capacity()) return; cap = 4; // minimum capacity
}
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);
@ -136,7 +155,9 @@ struct vector {
_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,47 +168,63 @@ 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) {
for (int i = _size; i > index; i--) _data[i] = std::move(_data[i - 1]); reserve(_capacity * 2);
}
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--;
} }
@ -232,24 +269,36 @@ class stack {
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; }
}; };
@ -286,33 +335,45 @@ 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; } const_pointer data() const { return m_begin; }
reference operator[] (size_type index) { return m_begin[index]; } reference operator[] (size_type index) { return m_begin[index]; }
const_reference operator[] (size_type index) const { return m_begin[index]; } const_reference operator[] (size_type index) const { return m_begin[index]; }
iterator begin() { return m_begin; } iterator begin() { return m_begin; }
const_iterator begin() const { return m_begin; } const_iterator begin() const { return m_begin; }
iterator end() { return m_end; } iterator end() { return m_end; }
const_iterator end() const { return m_end; } const_iterator end() const { return m_end; }
reference front() { return *begin(); } reference front() { return *begin(); }
const_reference front() const { return *begin(); } const_reference front() const { return *begin(); }
reference back() { return *(end() - 1); } reference back() { return *(end() - 1); }
const_reference back() const { return *(end() - 1); } const_reference back() const { return *(end() - 1); }
reverse_iterator rbegin() { return reverse_iterator(end()); } reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end()); const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
}
reverse_iterator rend() { return reverse_iterator(begin()); } reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const {
return const_reverse_iterator(begin()); const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
}
private: 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) {
@ -337,16 +398,12 @@ class small_vector {
} }
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;
@ -386,7 +443,9 @@ 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>
@ -396,11 +455,9 @@ class small_vector {
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,6 +475,7 @@ 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() {

View File

@ -27,16 +27,24 @@ class Compiler {
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& curr() const { return tokens[i]; }
const Token& next() const { return tokens[i + 1]; } const Token& next() const { return tokens[i + 1]; }
const Token& err() const { 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);
@ -114,7 +122,9 @@ class Compiler {
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 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 IndentationError(Str msg) { lexer.throw_err("IndentationError", msg, err().line, err().start); }
public: public:
@ -129,8 +139,16 @@ struct TokenDeserializer{
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++; } char read_char() { return *curr++; }
bool match_char(char c){ if(*curr == c) { curr++; return true; } return false; }
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

@ -11,20 +11,35 @@ 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; } bool operator!= (std::nullptr_t) const { return ptr != nullptr; }
~unique_ptr_128(){ if(ptr) { ptr->~T(); PoolExpr_dealloc(ptr); } } ~unique_ptr_128() {
if(ptr) {
ptr->~T();
PoolExpr_dealloc(ptr);
}
}
template <typename U> template <typename U>
unique_ptr_128(unique_ptr_128<U>&& other) : ptr(other.detach()) {} unique_ptr_128(unique_ptr_128<U>&& other) : ptr(other.detach()) {}
@ -33,13 +48,19 @@ public:
template <typename U> template <typename U>
unique_ptr_128& operator= (unique_ptr_128<U>&& other) { unique_ptr_128& operator= (unique_ptr_128<U>&& other) {
if(ptr) { ptr->~T(); PoolExpr_dealloc(ptr); }; 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;
} }
@ -55,33 +76,34 @@ 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 {
@ -93,6 +115,7 @@ 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;
@ -121,31 +144,41 @@ struct CodeEmitContext{
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;
}; };
@ -164,7 +197,9 @@ struct OrExpr: Expr{
// [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;
@ -172,35 +207,48 @@ struct Literal0Expr: Expr{
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(); }
}; };
@ -214,25 +262,36 @@ struct SliceExpr: Expr{
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;
} }
@ -241,8 +300,13 @@ struct ListExpr: SequenceExpr{
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;
} }
@ -251,17 +315,28 @@ struct DictExpr: SequenceExpr{
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;
} }
@ -283,16 +358,19 @@ struct CompExpr: Expr{
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; }
}; };
@ -309,7 +387,9 @@ 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;
}; };
@ -317,7 +397,9 @@ struct FStringExpr: Expr{
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;
@ -329,6 +411,7 @@ struct SubscrExpr: Expr{
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;
@ -337,6 +420,7 @@ 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;
}; };
@ -351,19 +435,14 @@ struct CallExpr: Expr{
struct GroupedExpr : Expr { struct GroupedExpr : Expr {
Expr_ a; Expr_ a;
GroupedExpr(Expr_&& a) : a(std::move(a)) {} GroupedExpr(Expr_&& a) : a(std::move(a)) {}
void emit_(CodeEmitContext* ctx) override{ void emit_(CodeEmitContext* ctx) override { a->emit_(ctx); }
a->emit_(ctx);
}
bool emit_del(CodeEmitContext* ctx) override { bool emit_del(CodeEmitContext* ctx) override { return a->emit_del(ctx); }
return a->emit_del(ctx);
}
bool emit_store(CodeEmitContext* ctx) override { bool emit_store(CodeEmitContext* ctx) override { return a->emit_store(ctx); }
return a->emit_store(ctx);
}
}; };
struct BinaryExpr : Expr { struct BinaryExpr : Expr {
@ -373,12 +452,12 @@ struct BinaryExpr: Expr{
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;
@ -386,5 +465,4 @@ struct TernaryExpr: Expr{
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };
} // namespace pkpy } // namespace pkpy

View File

@ -38,20 +38,25 @@ 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) {
if(*i == *j) return k; i++;
j++;
}
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;
}(); }();
@ -64,6 +69,7 @@ struct Token{
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); }
}; };
@ -106,6 +112,7 @@ struct Lexer {
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();
@ -127,15 +134,17 @@ 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(Str msg) { throw_err("SyntaxError", msg); }
[[noreturn]] void SyntaxError() { throw_err("SyntaxError", "invalid syntax"); } [[noreturn]] void SyntaxError() { throw_err("SyntaxError", "invalid syntax"); }
[[noreturn]] void IndentationError(Str msg) { throw_err("IndentationError", msg); } [[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,

View File

@ -9,9 +9,10 @@ struct NativeProxyFuncCBase {
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 {
@ -33,9 +34,10 @@ struct NativeProxyFuncC final: NativeProxyFuncCBase {
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 {
@ -55,6 +57,7 @@ struct NativeProxyMethodC final: NativeProxyFuncCBase {
} }
} }
}; };
/*****************************************************************/ /*****************************************************************/
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());
@ -89,8 +92,11 @@ 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);
if(pos > 0) name_sv = name_sv.substr(0, pos); int pos = name_sv.find(':');
if(pos > 0) {
name_sv = name_sv.substr(0, pos);
}
auto fget = [](VM* vm, ArgsView args) -> PyVar { auto fget = [](VM* vm, ArgsView args) -> PyVar {
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); 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());
@ -115,7 +121,9 @@ 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( \
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); \
@ -127,14 +135,15 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
}); });
#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( \
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()); \
@ -147,8 +156,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,13 +165,20 @@ 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); \ }, \
{}, \
BindType::STATICMETHOD); \
vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args) { \ 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)); \
@ -176,15 +191,14 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
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) { \
@ -198,10 +212,14 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
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) ([](VM* vm, ArgsView args) -> PyVar { return x; })
#define PK_VAR_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return VAR(x); }) #define PK_VAR_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return VAR(x); })
#define PK_ACTION(x) ([](VM* vm, ArgsView args) -> PyVar { x; return vm->None; }) #define PK_ACTION(x) \
([](VM* vm, ArgsView args) -> PyVar { \
x; \
return vm->None; \
})
} // namespace pkpy } // namespace pkpy

View File

@ -12,17 +12,19 @@ namespace pkpy {
struct VoidP { struct VoidP {
void* ptr; void* ptr;
VoidP(const void* ptr) : ptr(const_cast<void*>(ptr)) {} VoidP(const void* ptr) : ptr(const_cast<void*>(ptr)) {}
bool operator==(const VoidP& other) const { bool operator== (const VoidP& other) const { return ptr == other.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; } 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 { Str hex() const {
@ -58,9 +60,8 @@ POINTER_VAR(const bool*, "bool_p")
#undef POINTER_VAR #undef POINTER_VAR
struct Struct { struct Struct {
static constexpr int INLINE_SIZE = 24; constexpr static int INLINE_SIZE = 24;
char _inlined[INLINE_SIZE]; char _inlined[INLINE_SIZE];
char* p; char* p;
@ -73,15 +74,24 @@ struct Struct{
} 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);
}; };
@ -90,10 +100,13 @@ struct Struct{
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

@ -13,6 +13,7 @@ struct FastLocals{
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]; } PyVar operator[] (int i) const { return a[i]; }
FastLocals(const CodeObject* co, PyVar* a) : co(co), a(a) {} FastLocals(const CodeObject* co, PyVar* a) : co(co), a(a) {}
@ -21,6 +22,7 @@ struct FastLocals{
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(); }
}; };
@ -32,30 +34,53 @@ struct ValueStack {
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; } void pop() { --_sp; }
PyVar popx(){ --_sp; return *_sp; }
PyVar popx() {
--_sp;
return *_sp;
}
ArgsView view(int n) { return ArgsView(_sp - n, _sp); } ArgsView view(int n) { return ArgsView(_sp - n, _sp); }
void shrink(int n) { _sp -= n; } 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>
@ -89,22 +114,28 @@ 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*);
@ -129,21 +160,28 @@ struct 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; } bool empty() const { return _size == 0; }
void clear(){ while(!empty()) pop(); }
void clear() {
while(!empty()) {
pop();
}
}
template <typename... Args> template <typename... Args>
void emplace(Args&&... args) { void emplace(Args&&... args) {
@ -163,7 +201,9 @@ struct CallStack{
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(); }

View File

@ -20,21 +20,19 @@ struct ManagedHeap{
/********************/ /********************/
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>
@ -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

@ -7,6 +7,7 @@ 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);
@ -15,6 +16,7 @@ struct RangeIter{ // step > 0
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);
@ -25,18 +27,21 @@ struct ArrayIter{
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);
}; };
@ -46,11 +51,15 @@ struct Generator{
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) {
if(lf == nullptr) return; if(lf == nullptr) {
return;
}
lf->frame._gc_mark(vm); lf->frame._gc_mark(vm);
vm->__stack_gc_mark(s_backup.begin(), s_backup.end()); vm->__stack_gc_mark(s_backup.begin(), s_backup.end());
} }
@ -69,10 +78,11 @@ struct Generator{
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

@ -12,6 +12,7 @@ struct _LineRecord{
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; }
}; };

View File

@ -32,9 +32,14 @@ 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() : 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(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
@ -134,25 +139,26 @@ struct ImportContext{
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;
@ -199,22 +205,23 @@ public:
// 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);
@ -232,10 +239,14 @@ public:
List py_list(PyVar); // x -> list(x) List py_list(PyVar); // x -> list(x)
bool py_callable(PyVar obj); // x -> callable(x) bool py_callable(PyVar obj); // x -> callable(x)
bool py_bool(PyVar obj) { // x -> bool(x) bool py_bool(PyVar obj) { // x -> bool(x)
if(obj.type == tp_bool) return obj._0; if(obj.type == tp_bool) {
return obj._0;
}
return __py_bool_non_trivial(obj); return __py_bool_non_trivial(obj);
} }
i64 py_hash(PyVar obj); // x -> hash(x) i64 py_hash(PyVar obj); // x -> hash(x)
bool py_eq(PyVar lhs, PyVar rhs); // (lhs, rhs) -> lhs == rhs bool py_eq(PyVar lhs, PyVar rhs); // (lhs, rhs) -> lhs == rhs
@ -243,6 +254,7 @@ public:
bool py_le(PyVar lhs, PyVar rhs); // (lhs, rhs) -> lhs <= rhs bool py_le(PyVar lhs, PyVar rhs); // (lhs, rhs) -> lhs <= rhs
bool py_gt(PyVar lhs, PyVar rhs); // (lhs, rhs) -> lhs > rhs bool py_gt(PyVar lhs, PyVar rhs); // (lhs, rhs) -> lhs > rhs
bool py_ge(PyVar lhs, PyVar rhs); // (lhs, rhs) -> lhs >= rhs bool py_ge(PyVar lhs, PyVar rhs); // (lhs, rhs) -> lhs >= rhs
bool py_ne(PyVar lhs, PyVar rhs) { // (lhs, rhs) -> lhs != rhs bool py_ne(PyVar lhs, PyVar rhs) { // (lhs, rhs) -> lhs != rhs
return !py_eq(lhs, rhs); return !py_eq(lhs, rhs);
} }
@ -259,8 +271,18 @@ public:
i64 normalized_index(i64 index, int size); i64 normalized_index(i64 index, int size);
Str disassemble(CodeObject_ co); Str disassemble(CodeObject_ co);
void parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step); void parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step);
void obj_gc_mark(PyVar obj) { if(obj.is_ptr) __obj_gc_mark(obj.get()); }
void obj_gc_mark(PyObject* p) { if(p) __obj_gc_mark(p); } void obj_gc_mark(PyVar obj) {
if(obj.is_ptr) {
__obj_gc_mark(obj.get());
}
}
void obj_gc_mark(PyObject* p) {
if(p) {
__obj_gc_mark(p);
}
}
#endif #endif
#if PK_REGION("Name Lookup Methods") #if PK_REGION("Name Lookup Methods")
@ -272,7 +294,8 @@ public:
#endif #endif
#if PK_REGION("Source Execution Methods") #if PK_REGION("Source Execution Methods")
CodeObject_ compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope=false); CodeObject_
compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope = false);
Str precompile(std::string_view source, const Str& filename, CompileMode mode); Str precompile(std::string_view source, const Str& filename, CompileMode mode);
PyVar exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module = nullptr); PyVar exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module = nullptr);
PyVar exec(std::string_view source); PyVar exec(std::string_view source);
@ -290,14 +313,16 @@ public:
template <typename... Args> template <typename... Args>
PyVar call(PyVar callable, Args&&... args) { PyVar call(PyVar callable, Args&&... args) {
PUSH(callable); PUSH(PY_NULL); PUSH(callable);
PUSH(PY_NULL);
__push_varargs(args...); __push_varargs(args...);
return vectorcall(sizeof...(args)); return vectorcall(sizeof...(args));
} }
template <typename... Args> template <typename... Args>
PyVar call_method(PyVar self, PyVar callable, Args&&... args) { PyVar call_method(PyVar self, PyVar callable, Args&&... args) {
PUSH(callable); PUSH(self); PUSH(callable);
PUSH(self);
__push_varargs(args...); __push_varargs(args...);
return vectorcall(sizeof...(args)); return vectorcall(sizeof...(args));
} }
@ -311,6 +336,7 @@ public:
#if PK_REGION("Logging Methods") #if PK_REGION("Logging Methods")
virtual void stdout_write(const Str& s) { _stdout(s.data, s.size); } virtual void stdout_write(const Str& s) { _stdout(s.data, s.size); }
virtual void stderr_write(const Str& s) { _stderr(s.data, s.size); } virtual void stderr_write(const Str& s) { _stderr(s.data, s.size); }
#endif #endif
@ -354,10 +380,22 @@ public:
#endif #endif
#if PK_REGION("General Bindings") #if PK_REGION("General Bindings")
PyObject* bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, any userdata={}, BindType bt=BindType::DEFAULT); PyObject* bind_func(PyObject* obj,
PyObject* bind_func(Type type, StrName name, int argc, NativeFuncC fn, any userdata={}, BindType bt=BindType::DEFAULT){ StrName name,
int argc,
NativeFuncC fn,
any userdata = {},
BindType bt = BindType::DEFAULT);
PyObject* bind_func(Type type,
StrName name,
int argc,
NativeFuncC fn,
any userdata = {},
BindType bt = BindType::DEFAULT) {
return bind_func(_t(type), name, argc, fn, std::move(userdata), bt); return bind_func(_t(type), name, argc, fn, std::move(userdata), bt);
} }
PyObject* bind_property(PyObject*, const char*, NativeFuncC fget, NativeFuncC fset = nullptr); PyObject* bind_property(PyObject*, const char*, NativeFuncC fget, NativeFuncC fset = nullptr);
template <typename T, typename F, bool ReadOnly = false> template <typename T, typename F, bool ReadOnly = false>
PyObject* bind_field(PyObject*, const char*, F T::*); PyObject* bind_field(PyObject*, const char*, F T::*);
@ -368,7 +406,8 @@ public:
template <typename Ret, typename T, typename... Params> template <typename Ret, typename T, typename... Params>
PyObject* bind(PyObject*, const char*, Ret (T::*)(Params...), BindType bt = BindType::DEFAULT); PyObject* bind(PyObject*, const char*, Ret (T::*)(Params...), BindType bt = BindType::DEFAULT);
PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, any userdata={}, BindType bt=BindType::DEFAULT); PyObject*
bind(PyObject*, const char*, const char*, NativeFuncC, any userdata = {}, BindType bt = BindType::DEFAULT);
template <typename Ret, typename... Params> template <typename Ret, typename... Params>
PyObject* bind(PyObject*, const char*, const char*, Ret (*)(Params...), BindType bt = BindType::DEFAULT); PyObject* bind(PyObject*, const char*, const char*, Ret (*)(Params...), BindType bt = BindType::DEFAULT);
template <typename Ret, typename T, typename... Params> template <typename Ret, typename T, typename... Params>
@ -377,37 +416,75 @@ public:
#if PK_REGION("Error Reporting Methods") #if PK_REGION("Error Reporting Methods")
[[noreturn]] void _error(PyVar); [[noreturn]] void _error(PyVar);
[[noreturn]] void StackOverflowError() { __builtin_error("StackOverflowError"); } [[noreturn]] void StackOverflowError() { __builtin_error("StackOverflowError"); }
[[noreturn]] void IOError(const Str& msg) { __builtin_error("IOError", msg); } [[noreturn]] void IOError(const Str& msg) { __builtin_error("IOError", msg); }
[[noreturn]] void NotImplementedError() { __builtin_error("NotImplementedError"); } [[noreturn]] void NotImplementedError() { __builtin_error("NotImplementedError"); }
[[noreturn]] void TypeError(const Str& msg) { __builtin_error("TypeError", msg); } [[noreturn]] void TypeError(const Str& msg) { __builtin_error("TypeError", msg); }
[[noreturn]] void TypeError(Type expected, Type actual) { TypeError("expected " + _type_name(vm, expected).escape() + ", got " + _type_name(vm, actual).escape()); }
[[noreturn]] void TypeError(Type expected, Type actual) {
TypeError("expected " + _type_name(vm, expected).escape() + ", got " + _type_name(vm, actual).escape());
}
[[noreturn]] void IndexError(const Str& msg) { __builtin_error("IndexError", msg); } [[noreturn]] void IndexError(const Str& msg) { __builtin_error("IndexError", msg); }
[[noreturn]] void ValueError(const Str& msg) { __builtin_error("ValueError", msg); } [[noreturn]] void ValueError(const Str& msg) { __builtin_error("ValueError", msg); }
[[noreturn]] void RuntimeError(const Str& msg) { __builtin_error("RuntimeError", msg); } [[noreturn]] void RuntimeError(const Str& msg) { __builtin_error("RuntimeError", msg); }
[[noreturn]] void ZeroDivisionError(const Str& msg) { __builtin_error("ZeroDivisionError", msg); } [[noreturn]] void ZeroDivisionError(const Str& msg) { __builtin_error("ZeroDivisionError", msg); }
[[noreturn]] void ZeroDivisionError() { __builtin_error("ZeroDivisionError", "division by zero"); } [[noreturn]] void ZeroDivisionError() { __builtin_error("ZeroDivisionError", "division by zero"); }
[[noreturn]] void NameError(StrName name){ __builtin_error("NameError", _S("name ", name.escape() + " is not defined")); }
[[noreturn]] void UnboundLocalError(StrName name){ __builtin_error("UnboundLocalError", _S("local variable ", name.escape() + " referenced before assignment")); } [[noreturn]] void NameError(StrName name) {
__builtin_error("NameError", _S("name ", name.escape() + " is not defined"));
}
[[noreturn]] void UnboundLocalError(StrName name) {
__builtin_error("UnboundLocalError", _S("local variable ", name.escape() + " referenced before assignment"));
}
[[noreturn]] void KeyError(PyVar obj) { __builtin_error("KeyError", obj); } [[noreturn]] void KeyError(PyVar obj) { __builtin_error("KeyError", obj); }
[[noreturn]] void ImportError(const Str& msg) { __builtin_error("ImportError", msg); } [[noreturn]] void ImportError(const Str& msg) { __builtin_error("ImportError", msg); }
[[noreturn]] void AssertionError(const Str& msg) { __builtin_error("AssertionError", msg); } [[noreturn]] void AssertionError(const Str& msg) { __builtin_error("AssertionError", msg); }
[[noreturn]] void AssertionError() { __builtin_error("AssertionError"); } [[noreturn]] void AssertionError() { __builtin_error("AssertionError"); }
[[noreturn]] void BinaryOptError(const char* op, PyVar _0, PyVar _1); [[noreturn]] void BinaryOptError(const char* op, PyVar _0, PyVar _1);
[[noreturn]] void AttributeError(PyVar obj, StrName name); [[noreturn]] void AttributeError(PyVar obj, StrName name);
[[noreturn]] void AttributeError(const Str& msg) { __builtin_error("AttributeError", msg); } [[noreturn]] void AttributeError(const Str& msg) { __builtin_error("AttributeError", msg); }
#endif #endif
#if PK_REGION("Type Checking Methods") #if PK_REGION("Type Checking Methods")
bool isinstance(PyVar obj, Type base); bool isinstance(PyVar obj, Type base);
bool issubclass(Type cls, Type base); bool issubclass(Type cls, Type base);
void check_type(PyVar obj, Type type){ if(!is_type(obj, type)) TypeError(type, _tp(obj)); }
void check_compatible_type(PyVar obj, Type type){ if(!isinstance(obj, type)) TypeError(type, _tp(obj)); } void check_type(PyVar obj, Type type) {
if(!is_type(obj, type)) {
TypeError(type, _tp(obj));
}
}
void check_compatible_type(PyVar obj, Type type) {
if(!isinstance(obj, type)) {
TypeError(type, _tp(obj));
}
}
Type _tp(PyVar obj) { return obj.type; } Type _tp(PyVar obj) { return obj.type; }
const PyTypeInfo* _tp_info(PyVar obj) { return &_all_types[_tp(obj)]; } const PyTypeInfo* _tp_info(PyVar obj) { return &_all_types[_tp(obj)]; }
const PyTypeInfo* _tp_info(Type type) { return &_all_types[type]; } const PyTypeInfo* _tp_info(Type type) { return &_all_types[type]; }
PyObject* _t(PyVar obj) { return _all_types[_tp(obj)].obj; } PyObject* _t(PyVar obj) { return _all_types[_tp(obj)].obj; }
PyObject* _t(Type type) { return _all_types[type].obj; } PyObject* _t(Type type) { return _all_types[type].obj; }
// equivalent to `obj == NotImplemented` but faster // equivalent to `obj == NotImplemented` but faster
@ -424,12 +501,18 @@ public:
} }
template <typename T> template <typename T>
Type _tp_user(){ return _find_type_in_cxx_typeid_map<T>(); } Type _tp_user() {
template<typename T> return _find_type_in_cxx_typeid_map<T>();
bool is_user_type(PyVar obj){ return _tp(obj) == _tp_user<T>(); } }
template <typename T> template <typename T>
PyObject* register_user_class(PyObject*, StrName, RegisterFunc, Type base=tp_object, bool subclass_enabled=false); bool is_user_type(PyVar obj) {
return _tp(obj) == _tp_user<T>();
}
template <typename T>
PyObject*
register_user_class(PyObject*, StrName, RegisterFunc, Type base = tp_object, bool subclass_enabled = false);
template <typename T> template <typename T>
PyObject* register_user_class(PyObject*, StrName, Type base = tp_object, bool subclass_enabled = false); PyObject* register_user_class(PyObject*, StrName, Type base = tp_object, bool subclass_enabled = false);
@ -440,8 +523,11 @@ public:
template <typename T, typename... Args> template <typename T, typename... Args>
PyVar new_object(Type type, Args&&... args) { PyVar new_object(Type type, Args&&... args) {
if constexpr(is_sso_v<T>) return PyVar(type, T(std::forward<Args>(args)...)); if constexpr(is_sso_v<T>) {
else return heap.gcnew<T>(type, std::forward<Args>(args)...); return PyVar(type, T(std::forward<Args>(args)...));
} else {
return heap.gcnew<T>(type, std::forward<Args>(args)...);
}
} }
template <typename T, typename... Args> template <typename T, typename... Args>
@ -491,11 +577,29 @@ public:
[[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() {}
void __push_varargs(PyVar _0) { PUSH(_0); } void __push_varargs(PyVar _0) { PUSH(_0); }
void __push_varargs(PyVar _0, PyVar _1){ PUSH(_0); PUSH(_1); }
void __push_varargs(PyVar _0, PyVar _1, PyVar _2){ PUSH(_0); PUSH(_1); PUSH(_2); } void __push_varargs(PyVar _0, PyVar _1) {
void __push_varargs(PyVar _0, PyVar _1, PyVar _2, PyVar _3){ PUSH(_0); PUSH(_1); PUSH(_2); PUSH(_3); } 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,31 +608,101 @@ 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 <>
template<> constexpr Type _find_type_in_const_cxx_typeid_map<BoundMethod>(){ return VM::tp_bound_method; } constexpr Type _find_type_in_const_cxx_typeid_map<List>() {
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Range>(){ return VM::tp_range; } return VM::tp_list;
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 <>
template<> constexpr Type _find_type_in_const_cxx_typeid_map<MappingProxy>(){ return VM::tp_mappingproxy; } constexpr Type _find_type_in_const_cxx_typeid_map<Tuple>() {
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Dict>(){ return VM::tp_dict; } return VM::tp_tuple;
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 <>
template<> constexpr Type _find_type_in_const_cxx_typeid_map<ClassMethod>(){ return VM::tp_classmethod; } constexpr Type _find_type_in_const_cxx_typeid_map<Function>() {
template<> constexpr Type _find_type_in_const_cxx_typeid_map<StackMemory>(){ return VM::tp_stack_memory; } 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 <typename __T>
PyVar py_var(VM* vm, __T&& value) { PyVar py_var(VM* vm, __T&& value) {
@ -536,7 +710,8 @@ PyVar py_var(VM* vm, __T&& value){
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>) {
@ -556,20 +731,24 @@ PyVar py_var(VM* vm, __T&& 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 {
return vm->heap.gcnew<T>(const_type, std::forward<__T>(value));
}
} else { } 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) {
@ -580,15 +759,23 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
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) {
if constexpr(with_check) vm->check_type(obj, vm->tp_str); return nullptr;
}
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) {
if(obj == vm->False) return false; return true;
}
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;
@ -596,14 +783,20 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
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)) {
if(is_int(obj)) return (T)obj.as<i64>(); return (T)obj.as<f64>();
}
if(is_int(obj)) {
return (T)obj.as<i64>();
}
vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape()); 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>) {
@ -635,12 +828,18 @@ __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) {
return _py_cast__internal<__T, true>(vm, obj);
}
template <typename __T> template <typename __T>
__T _py_cast(VM* vm, PyVar obj) { return _py_cast__internal<__T, false>(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){ 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>();

View File

@ -6,4 +6,4 @@ 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

@ -13,71 +13,147 @@ 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- (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 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); } 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); }
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 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- (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 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); } 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); }
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 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- (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 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); } 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); } 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 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 {
@ -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];
}; };
@ -131,8 +208,8 @@ 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

@ -12,10 +12,15 @@ namespace pkpy{
struct Type { struct Type {
int16_t index; int16_t index;
constexpr Type() : index(0) {} constexpr Type() : index(0) {}
explicit constexpr Type(int index) : index(index) {} explicit constexpr Type(int index) : index(index) {}
bool operator== (Type other) const { return this->index == other.index; } bool operator== (Type other) const { return this->index == other.index; }
bool operator!= (Type other) const { return this->index != other.index; } bool operator!= (Type other) const { return this->index != other.index; }
constexpr operator int () const { return index; } constexpr operator int () const { return index; }
}; };
@ -26,7 +31,8 @@ struct PyVar final{
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,11 +42,15 @@ 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) {
@ -60,20 +70,21 @@ struct PyVar final{
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 {
@ -92,9 +103,7 @@ struct PyVar final{
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

@ -8,26 +8,34 @@ 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,11 +45,12 @@ 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;
}; };
@ -50,7 +59,9 @@ 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) {
@ -82,16 +96,19 @@ inline bool is_type(PyObject* 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>) {
@ -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

@ -22,6 +22,7 @@ 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, #define OPCODE(name) OP_##name,
#include "pocketpy/opcodes.h" #include "pocketpy/opcodes.h"
#undef OPCODE #undef OPCODE
@ -36,9 +37,7 @@ struct Bytecode{
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;
@ -63,7 +62,9 @@ struct CodeBlock {
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;
} }
}; };
@ -98,9 +99,7 @@ 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;
@ -120,6 +119,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
@ -149,10 +149,14 @@ 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;
}; };

View File

@ -13,8 +13,8 @@ struct Dict{
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;

View File

@ -7,17 +7,18 @@ 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() : type(InternalExceptionType::Null), arg(-1) {}
InternalException(InternalExceptionType type, int arg = -1) : type(type), arg(arg) {} InternalException(InternalExceptionType type, int arg = -1) : type(type), arg(arg) {}
}; };
@ -44,6 +45,7 @@ struct Exception {
}; };
stack<Frame> stacktrace; stack<Frame> stacktrace;
Exception(StrName type) : type(type), is_re(true), _ip_on_error(-1), _code_on_error(nullptr), _self(nullptr) {} Exception(StrName type) : type(type), is_re(true), _ip_on_error(-1), _code_on_error(nullptr), _self(nullptr) {}
PyObject* self() const { PyObject* self() const {
@ -53,7 +55,9 @@ struct Exception {
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)...);
} }
@ -63,6 +67,7 @@ struct Exception {
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

@ -16,9 +16,11 @@ struct PyObject final{
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());
} }

View File

@ -5,13 +5,7 @@
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)

View File

@ -6,12 +6,13 @@ 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];
@ -23,14 +23,19 @@ struct Tuple {
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) { return _args[i]; }
PyVar operator[] (int i) const { 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;
}; };
@ -40,7 +45,9 @@ struct List: public vector<PyVar>{
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;
} }
}; };
@ -51,12 +58,17 @@ struct ArgsView{
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;

View File

@ -103,5 +103,4 @@ PK_EXPORT void pkpy_delete_repl(void* repl);
} }
#endif #endif
#endif #endif

View File

@ -9,6 +9,7 @@ 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

@ -13,9 +13,7 @@ namespace pybind11 {
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);
@ -85,24 +83,21 @@ namespace pybind11 {
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)) {

View File

@ -10,8 +10,7 @@ namespace pybind11 {
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>
@ -33,9 +32,7 @@ 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>
@ -89,9 +86,7 @@ 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>
@ -144,9 +139,7 @@ namespace pybind11 {
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;

View File

@ -30,11 +30,7 @@ namespace pybind11 {
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);
@ -65,12 +61,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 +92,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 +102,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,8 +138,7 @@ 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.");

View File

@ -10,8 +10,7 @@ namespace pybind11 {
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
@ -62,14 +61,11 @@ namespace pybind11 {
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));
destructor = [](function_record* self) { destructor = [](function_record* self) { reinterpret_cast<Fn*>(self->buffer)->~Fn(); };
reinterpret_cast<Fn*>(self->buffer)->~Fn();
};
} 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); };
@ -206,8 +202,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]);
} }
@ -226,11 +221,7 @@ 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();
@ -254,11 +245,7 @@ namespace pybind11 {
}; };
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);
@ -287,11 +274,8 @@ namespace pybind11 {
} }
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 +292,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 +307,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();

View File

@ -55,8 +55,7 @@ namespace pybind11 {
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 +72,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 {

View File

@ -2,30 +2,23 @@
#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;
@ -34,14 +27,12 @@ namespace pybind11
}; };
} }
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.

View File

@ -111,16 +111,14 @@ namespace pybind11 {
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;
} }
@ -148,15 +146,13 @@ namespace pybind11 {
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));
} }
}; };

View File

@ -17,7 +17,9 @@ any::any(any&& other) noexcept: data(other.data), _vt(other._vt){
} }
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;
other.data = nullptr; other.data = nullptr;

View File

@ -73,9 +73,7 @@ struct DoubleLinkedList{
_size--; _size--;
} }
bool empty() const { bool empty() const { return _size == 0; }
return _size == 0;
}
int size() const { return _size; } int size() const { return _size; }
@ -92,8 +90,8 @@ 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;
@ -113,11 +111,10 @@ struct MemoryPool{
} }
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());
@ -181,7 +178,9 @@ struct MemoryPool{
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);
@ -216,9 +215,7 @@ struct FixedMemoryPool{
} }
} }
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()
@ -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

@ -9,13 +9,27 @@
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) {
if((c & 0b11100000) == 0b11000000) return 2; return 1;
if((c & 0b11110000) == 0b11100000) return 3; }
if((c & 0b11111000) == 0b11110000) return 4; if((c & 0b11100000) == 0b11000000) {
if((c & 0b11111100) == 0b11111000) return 5; return 2;
if((c & 0b11111110) == 0b11111100) return 6; }
if(!suppress) throw std::runtime_error("invalid utf8 char: " + std::to_string(c)); if((c & 0b11110000) == 0b11100000) {
return 3;
}
if((c & 0b11111000) == 0b11110000) {
return 4;
}
if((c & 0b11111100) == 0b11111000) {
return 5;
}
if((c & 0b11111110) == 0b11111100) {
return 6;
}
if(!suppress) {
throw std::runtime_error("invalid utf8 char: " + std::to_string(c));
}
return 0; return 0;
} }
@ -29,42 +43,35 @@ int utf8len(unsigned char c, bool suppress){
#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');
} }
@ -78,7 +85,9 @@ int utf8len(unsigned char c, bool suppress){
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;
@ -94,16 +103,14 @@ int utf8len(unsigned char c, bool suppress){
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;
PK_STR_ALLOCATE() PK_STR_ALLOCATE()
@ -126,55 +133,51 @@ int utf8len(unsigned char c, bool suppress){
} }
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 {
@ -184,18 +187,20 @@ int utf8len(unsigned char c, bool suppress){
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);
} }
@ -205,10 +210,14 @@ int utf8len(unsigned char c, bool suppress){
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 {
@ -219,7 +228,9 @@ int utf8len(unsigned char c, bool suppress){
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);
@ -228,7 +239,9 @@ int utf8len(unsigned char c, bool suppress){
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);
@ -246,11 +259,15 @@ int utf8len(unsigned char c, bool suppress){
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 << '"';
break; break;
case '\'': case '\'':
if(single_quote) ss << '\\'; if(single_quote) {
ss << '\\';
}
ss << '\''; ss << '\'';
break; break;
case '\\': ss << '\\' << '\\'; break; case '\\': ss << '\\' << '\\'; break;
@ -273,14 +290,18 @@ int utf8len(unsigned char c, bool suppress){
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;
} }
@ -290,19 +311,24 @@ int utf8len(unsigned char c, bool suppress){
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);
ss << new_; ss << new_;
start = i + old.size; start = i + old.size;
if(count != -1 && --count == 0) break; if(count != -1 && --count == 0) {
break;
}
} }
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]);
@ -312,10 +338,14 @@ int utf8len(unsigned char c, bool suppress){
} }
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;
} }
@ -335,9 +365,7 @@ int utf8len(unsigned char c, bool suppress){
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;
@ -345,13 +373,19 @@ int utf8len(unsigned char c, bool suppress){
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);
if(!tmp.empty()) result.push_back(tmp); if(!tmp.empty()) {
result.push_back(tmp);
}
start = i + sep.size; start = i + sep.size;
} }
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;
} }
@ -360,22 +394,30 @@ int utf8len(unsigned char c, bool suppress){
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;
} }
@ -396,11 +438,15 @@ int utf8len(unsigned char c, bool suppress){
StrName StrName::get(std::string_view s) { StrName StrName::get(std::string_view s) {
auto it = _interned().find(s); auto it = _interned().find(s);
if(it != _interned().end()) return StrName(it->second); if(it != _interned().end()) {
return StrName(it->second);
}
// generate new index // generate new index
// https://github.com/python/cpython/blob/3.12/Objects/dictobject.c#L175 // https://github.com/python/cpython/blob/3.12/Objects/dictobject.c#L175
uint16_t index = ((_pesudo_random_index * 5) + 1) & 65535; uint16_t index = ((_pesudo_random_index * 5) + 1) & 65535;
if(index == 0) throw std::runtime_error("StrName index overflow"); if(index == 0) {
throw std::runtime_error("StrName index overflow");
}
auto res = _r_interned().emplace(index, s); auto res = _r_interned().emplace(index, s);
assert(res.second); assert(res.second);
s = std::string_view(res.first->second); s = std::string_view(res.first->second);
@ -417,22 +463,30 @@ int utf8len(unsigned char c, bool suppress){
} }
SStream& SStream::operator<< (const Str& s) { SStream& SStream::operator<< (const Str& s) {
for(char c: s) buffer.push_back(c); for(char c: s) {
buffer.push_back(c);
}
return *this; return *this;
} }
SStream& SStream::operator<< (const char* s) { SStream& SStream::operator<< (const char* s) {
while(*s) buffer.push_back(*s++); while(*s) {
buffer.push_back(*s++);
}
return *this; return *this;
} }
SStream& SStream::operator<< (const std::string& s) { SStream& SStream::operator<< (const std::string& s) {
for(char c: s) buffer.push_back(c); for(char c: s) {
buffer.push_back(c);
}
return *this; return *this;
} }
SStream& SStream::operator<< (std::string_view s) { SStream& SStream::operator<< (std::string_view s) {
for(char c: s) buffer.push_back(c); for(char c: s) {
buffer.push_back(c);
}
return *this; return *this;
} }
@ -441,18 +495,14 @@ int utf8len(unsigned char c, bool suppress){
return *this; return *this;
} }
SStream& SStream::operator<<(StrName sn){ SStream& SStream::operator<< (StrName sn) { return *this << sn.sv(); }
return *this << sn.sv();
}
SStream& SStream::operator<< (size_t val) { 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
@ -490,7 +540,9 @@ int utf8len(unsigned char c, bool suppress){
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;
} }
@ -498,8 +550,12 @@ int utf8len(unsigned char c, bool suppress){
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) {
if(high || low) (*this) << PK_HEX_TABLE[low]; (*this) << PK_HEX_TABLE[high];
}
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];
@ -517,7 +573,9 @@ int utf8len(unsigned char c, bool suppress){
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;
}
} }
} }
@ -535,15 +593,15 @@ int utf8len(unsigned char c, bool suppress){
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 +659,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

View File

@ -9,7 +9,9 @@ namespace pkpy{
NameScope Compiler::name_scope() const { NameScope Compiler::name_scope() const {
auto s = contexts.size() > 1 ? NAME_LOCAL : NAME_GLOBAL; auto s = contexts.size() > 1 ? NAME_LOCAL : NAME_GLOBAL;
if(unknown_global_scope && s == NAME_GLOBAL) s = NAME_GLOBAL_UNKNOWN; if(unknown_global_scope && s == NAME_GLOBAL) {
s = NAME_GLOBAL_UNKNOWN;
}
return s; return s;
} }
@ -40,7 +42,9 @@ namespace pkpy{
ctx()->emit_(OP_RETURN_VALUE, 1, BC_KEEPLINE, true); ctx()->emit_(OP_RETURN_VALUE, 1, BC_KEEPLINE, true);
// find the last valid token // find the last valid token
int j = i - 1; int j = i - 1;
while(tokens[j].type == TK("@eol") || tokens[j].type == TK("@dedent") || tokens[j].type == TK("@eof")) j--; while(tokens[j].type == TK("@eol") || tokens[j].type == TK("@dedent") || tokens[j].type == TK("@eof")) {
j--;
}
ctx()->co->end_line = tokens[j].line; ctx()->co->end_line = tokens[j].line;
// some check here // some check here
@ -77,9 +81,15 @@ namespace pkpy{
} }
if(func->type == FuncType::UNSET) { if(func->type == FuncType::UNSET) {
bool is_simple = true; bool is_simple = true;
if(func->kwargs.size() > 0) is_simple = false; if(func->kwargs.size() > 0) {
if(func->starred_arg >= 0) is_simple = false; is_simple = false;
if(func->starred_kwarg >= 0) is_simple = false; }
if(func->starred_arg >= 0) {
is_simple = false;
}
if(func->starred_kwarg >= 0) {
is_simple = false;
}
if(is_simple) { if(is_simple) {
func->type = FuncType::SIMPLE; func->type = FuncType::SIMPLE;
@ -91,9 +101,12 @@ namespace pkpy{
is_empty = true; is_empty = true;
} }
} }
if(is_empty) func->type = FuncType::EMPTY; if(is_empty) {
func->type = FuncType::EMPTY;
}
} else {
func->type = FuncType::NORMAL;
} }
else func->type = FuncType::NORMAL;
} }
assert(func->type != FuncType::UNSET); assert(func->type != FuncType::UNSET);
@ -103,7 +116,9 @@ namespace pkpy{
void Compiler::init_pratt_rules() { void Compiler::init_pratt_rules() {
static bool initialized = false; static bool initialized = false;
if(initialized) return; if(initialized) {
return;
}
initialized = true; initialized = true;
// clang-format off // clang-format off
@ -163,27 +178,27 @@ namespace pkpy{
} }
bool Compiler::match(TokenIndex expected) { bool Compiler::match(TokenIndex expected) {
if (curr().type != expected) return false; if(curr().type != expected) {
return false;
}
advance(); advance();
return true; return true;
} }
void Compiler::consume(TokenIndex expected) { void Compiler::consume(TokenIndex expected) {
if(!match(expected)) { if(!match(expected)) {
SyntaxError( SyntaxError(_S("expected '", TK_STR(expected), "', got '", TK_STR(curr().type), "'"));
_S("expected '", TK_STR(expected), "', got '", TK_STR(curr().type), "'")
);
} }
} }
bool Compiler::match_newlines_repl(){ bool Compiler::match_newlines_repl() { return match_newlines(mode() == REPL_MODE); }
return match_newlines(mode()==REPL_MODE);
}
bool Compiler::match_newlines(bool repl_throw) { bool Compiler::match_newlines(bool repl_throw) {
bool consumed = false; bool consumed = false;
if(curr().type == TK("@eol")) { if(curr().type == TK("@eol")) {
while (curr().type == TK("@eol")) advance(); while(curr().type == TK("@eol")) {
advance();
}
consumed = true; consumed = true;
} }
if(repl_throw && curr().type == TK("@eof")) { if(repl_throw && curr().type == TK("@eof")) {
@ -193,32 +208,47 @@ namespace pkpy{
} }
bool Compiler::match_end_stmt() { bool Compiler::match_end_stmt() {
if (match(TK(";"))) { match_newlines(); return true; } if(match(TK(";"))) {
if (match_newlines() || curr().type == TK("@eof")) return true; match_newlines();
if (curr().type == TK("@dedent")) return true; return true;
}
if(match_newlines() || curr().type == TK("@eof")) {
return true;
}
if(curr().type == TK("@dedent")) {
return true;
}
return false; return false;
} }
void Compiler::consume_end_stmt() { void Compiler::consume_end_stmt() {
if (!match_end_stmt()) SyntaxError("expected statement end"); if(!match_end_stmt()) {
SyntaxError("expected statement end");
}
} }
void Compiler::EXPR() { void Compiler::EXPR() { parse_expression(PREC_LOWEST + 1); }
parse_expression(PREC_LOWEST+1);
}
void Compiler::EXPR_TUPLE(bool allow_slice) { void Compiler::EXPR_TUPLE(bool allow_slice) {
parse_expression(PREC_LOWEST + 1, allow_slice); parse_expression(PREC_LOWEST + 1, allow_slice);
if(!match(TK(","))) return; if(!match(TK(","))) {
return;
}
// tuple expression // tuple expression
Expr_vector items; Expr_vector items;
items.push_back(ctx()->s_expr.popx()); items.push_back(ctx()->s_expr.popx());
do { do {
if(curr().brackets_level) match_newlines_repl(); if(curr().brackets_level) {
if(!is_expression(allow_slice)) break; match_newlines_repl();
}
if(!is_expression(allow_slice)) {
break;
}
parse_expression(PREC_LOWEST + 1, allow_slice); parse_expression(PREC_LOWEST + 1, allow_slice);
items.push_back(ctx()->s_expr.popx()); items.push_back(ctx()->s_expr.popx());
if(curr().brackets_level) match_newlines_repl(); if(curr().brackets_level) {
match_newlines_repl();
}
} while(match(TK(","))); } while(match(TK(",")));
ctx()->s_expr.push(make_expr<TupleExpr>(std::move(items))); ctx()->s_expr.push(make_expr<TupleExpr>(std::move(items)));
} }
@ -230,29 +260,21 @@ namespace pkpy{
consume(TK("@id")); consume(TK("@id"));
items.push_back(make_expr<NameExpr>(prev().str(), name_scope())); items.push_back(make_expr<NameExpr>(prev().str(), name_scope()));
} while(match(TK(","))); } while(match(TK(",")));
if(items.size()==1) return std::move(items[0]); if(items.size() == 1) {
return std::move(items[0]);
}
return make_expr<TupleExpr>(std::move(items)); return make_expr<TupleExpr>(std::move(items));
} }
void Compiler::exprLiteral(){ void Compiler::exprLiteral() { ctx()->s_expr.push(make_expr<LiteralExpr>(prev().value)); }
ctx()->s_expr.push(make_expr<LiteralExpr>(prev().value));
}
void Compiler::exprLong(){ void Compiler::exprLong() { ctx()->s_expr.push(make_expr<LongExpr>(prev().str())); }
ctx()->s_expr.push(make_expr<LongExpr>(prev().str()));
}
void Compiler::exprImag(){ void Compiler::exprImag() { ctx()->s_expr.push(make_expr<ImagExpr>(std::get<f64>(prev().value))); }
ctx()->s_expr.push(make_expr<ImagExpr>(std::get<f64>(prev().value)));
}
void Compiler::exprBytes(){ void Compiler::exprBytes() { ctx()->s_expr.push(make_expr<BytesExpr>(std::get<Str>(prev().value))); }
ctx()->s_expr.push(make_expr<BytesExpr>(std::get<Str>(prev().value)));
}
void Compiler::exprFString(){ void Compiler::exprFString() { ctx()->s_expr.push(make_expr<FStringExpr>(std::get<Str>(prev().value))); }
ctx()->s_expr.push(make_expr<FStringExpr>(std::get<Str>(prev().value)));
}
void Compiler::exprLambda() { void Compiler::exprLambda() {
FuncDecl_ decl = push_f_context("<lambda>"); FuncDecl_ decl = push_f_context("<lambda>");
@ -316,18 +338,10 @@ namespace pkpy{
TokenIndex op = prev().type; TokenIndex op = prev().type;
parse_expression(PREC_UNARY + 1); parse_expression(PREC_UNARY + 1);
switch(op) { switch(op) {
case TK("-"): case TK("-"): ctx()->s_expr.push(make_expr<NegatedExpr>(ctx()->s_expr.popx())); break;
ctx()->s_expr.push(make_expr<NegatedExpr>(ctx()->s_expr.popx())); case TK("~"): ctx()->s_expr.push(make_expr<InvertExpr>(ctx()->s_expr.popx())); break;
break; case TK("*"): ctx()->s_expr.push(make_expr<StarredExpr>(1, ctx()->s_expr.popx())); break;
case TK("~"): case TK("**"): ctx()->s_expr.push(make_expr<StarredExpr>(2, ctx()->s_expr.popx())); break;
ctx()->s_expr.push(make_expr<InvertExpr>(ctx()->s_expr.popx()));
break;
case TK("*"):
ctx()->s_expr.push(make_expr<StarredExpr>(1, ctx()->s_expr.popx()));
break;
case TK("**"):
ctx()->s_expr.push(make_expr<StarredExpr>(2, ctx()->s_expr.popx()));
break;
default: assert(false); default: assert(false);
} }
} }
@ -337,7 +351,9 @@ namespace pkpy{
EXPR_TUPLE(); // () is just for change precedence EXPR_TUPLE(); // () is just for change precedence
match_newlines_repl(); match_newlines_repl();
consume(TK(")")); consume(TK(")"));
if(ctx()->s_expr.top()->is_tuple()) return; if(ctx()->s_expr.top()->is_tuple()) {
return;
}
Expr_ g = make_expr<GroupedExpr>(ctx()->s_expr.popx()); Expr_ g = make_expr<GroupedExpr>(ctx()->s_expr.popx());
ctx()->s_expr.push(std::move(g)); ctx()->s_expr.push(std::move(g));
} }
@ -362,7 +378,9 @@ namespace pkpy{
Expr_vector items; Expr_vector items;
do { do {
match_newlines_repl(); match_newlines_repl();
if (curr().type == TK("]")) break; if(curr().type == TK("]")) {
break;
}
EXPR(); EXPR();
items.push_back(ctx()->s_expr.popx()); items.push_back(ctx()->s_expr.popx());
match_newlines_repl(); match_newlines_repl();
@ -384,7 +402,9 @@ namespace pkpy{
Expr_vector items; Expr_vector items;
do { do {
match_newlines_repl(); match_newlines_repl();
if (curr().type == TK("}")) break; if(curr().type == TK("}")) {
break;
}
EXPR(); EXPR();
int star_level = ctx()->s_expr.top()->star_level(); int star_level = ctx()->s_expr.top()->star_level();
if(star_level == 2 || curr().type == TK(":")) { if(star_level == 2 || curr().type == TK(":")) {
@ -407,8 +427,11 @@ namespace pkpy{
} }
match_newlines_repl(); match_newlines_repl();
if(items.size() == 1 && match(TK("for"))) { if(items.size() == 1 && match(TK("for"))) {
if(parsing_dict) consume_comp(make_expr<DictCompExpr>(), std::move(items[0])); if(parsing_dict) {
else consume_comp(make_expr<SetCompExpr>(), std::move(items[0])); consume_comp(make_expr<DictCompExpr>(), std::move(items[0]));
} else {
consume_comp(make_expr<SetCompExpr>(), std::move(items[0]));
}
consume(TK("}")); consume(TK("}"));
return; return;
} }
@ -429,7 +452,9 @@ namespace pkpy{
e->callable = ctx()->s_expr.popx(); e->callable = ctx()->s_expr.popx();
do { do {
match_newlines_repl(); match_newlines_repl();
if (curr().type==TK(")")) break; if(curr().type == TK(")")) {
break;
}
if(curr().type == TK("@id") && next().type == TK("=")) { if(curr().type == TK("@id") && next().type == TK("=")) {
consume(TK("@id")); consume(TK("@id"));
Str key = prev().str(); Str key = prev().str();
@ -443,15 +468,21 @@ namespace pkpy{
e->kwargs.push_back({"**", ctx()->s_expr.popx()}); e->kwargs.push_back({"**", ctx()->s_expr.popx()});
} else { } else {
// positional argument // positional argument
if(!e->kwargs.empty()) SyntaxError("positional argument follows keyword argument"); if(!e->kwargs.empty()) {
SyntaxError("positional argument follows keyword argument");
}
e->args.push_back(ctx()->s_expr.popx()); e->args.push_back(ctx()->s_expr.popx());
} }
} }
match_newlines_repl(); match_newlines_repl();
} while(match(TK(","))); } while(match(TK(",")));
consume(TK(")")); consume(TK(")"));
if(e->args.size() > 32767) SyntaxError("too many positional arguments"); if(e->args.size() > 32767) {
if(e->kwargs.size() > 32767) SyntaxError("too many keyword arguments"); SyntaxError("too many positional arguments");
}
if(e->kwargs.size() > 32767) {
SyntaxError("too many keyword arguments");
}
ctx()->s_expr.push(std::move(e)); ctx()->s_expr.push(std::move(e));
} }
@ -466,9 +497,7 @@ namespace pkpy{
void Compiler::exprAttrib() { void Compiler::exprAttrib() {
consume(TK("@id")); consume(TK("@id"));
ctx()->s_expr.push( ctx()->s_expr.push(make_expr<AttribExpr>(ctx()->s_expr.popx(), StrName::get(prev().sv())));
make_expr<AttribExpr>(ctx()->s_expr.popx(), StrName::get(prev().sv()))
);
} }
void Compiler::exprSlice0() { void Compiler::exprSlice0() {
@ -519,18 +548,20 @@ namespace pkpy{
ctx()->s_expr.push(std::move(e)); ctx()->s_expr.push(std::move(e));
} }
void Compiler::exprLiteral0() { void Compiler::exprLiteral0() { ctx()->s_expr.push(make_expr<Literal0Expr>(prev().type)); }
ctx()->s_expr.push(make_expr<Literal0Expr>(prev().type));
}
void Compiler::compile_block_body(void (Compiler::*callback)()) { void Compiler::compile_block_body(void (Compiler::*callback)()) {
if(callback == nullptr) callback = &Compiler::compile_stmt; if(callback == nullptr) {
callback = &Compiler::compile_stmt;
}
consume(TK(":")); consume(TK(":"));
if(curr().type != TK("@eol") && curr().type != TK("@eof")) { if(curr().type != TK("@eol") && curr().type != TK("@eof")) {
while(true) { while(true) {
compile_stmt(); compile_stmt();
bool possible = curr().type != TK("@eol") && curr().type != TK("@eof"); bool possible = curr().type != TK("@eol") && curr().type != TK("@eof");
if(prev().type != TK(";") || !possible) break; if(prev().type != TK(";") || !possible) {
break;
}
} }
return; return;
} }
@ -583,7 +614,9 @@ namespace pkpy{
} }
__EAT_DOTS_END: __EAT_DOTS_END:
SStream ss; SStream ss;
for(int i=0; i<dots; i++) ss << '.'; for(int i = 0; i < dots; i++) {
ss << '.';
}
if(dots > 0) { if(dots > 0) {
// @id is optional if dots > 0 // @id is optional if dots > 0
@ -608,7 +641,9 @@ __EAT_DOTS_END:
consume(TK("import")); consume(TK("import"));
if(match(TK("*"))) { if(match(TK("*"))) {
if(name_scope() != NAME_GLOBAL) SyntaxError("from <module> import * can only be used in global scope"); if(name_scope() != NAME_GLOBAL) {
SyntaxError("from <module> import * can only be used in global scope");
}
// pop the module and import __all__ // pop the module and import __all__
ctx()->emit_(OP_POP_IMPORT_STAR, BC_NOARG, prev().line); ctx()->emit_(OP_POP_IMPORT_STAR, BC_NOARG, prev().line);
consume_end_stmt(); consume_end_stmt();
@ -690,12 +725,15 @@ __EAT_DOTS_END:
void Compiler::compile_for_loop() { void Compiler::compile_for_loop() {
Expr_ vars = EXPR_VARS(); Expr_ vars = EXPR_VARS();
consume(TK("in")); consume(TK("in"));
EXPR_TUPLE(); ctx()->emit_expr(); EXPR_TUPLE();
ctx()->emit_expr();
ctx()->emit_(OP_GET_ITER_NEW, BC_NOARG, BC_KEEPLINE); ctx()->emit_(OP_GET_ITER_NEW, BC_NOARG, BC_KEEPLINE);
CodeBlock* block = ctx()->enter_block(CodeBlockType::FOR_LOOP); CodeBlock* block = ctx()->enter_block(CodeBlockType::FOR_LOOP);
int for_codei = ctx()->emit_(OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE); int for_codei = ctx()->emit_(OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE);
bool ok = vars->emit_store(ctx()); bool ok = vars->emit_store(ctx());
if(!ok) SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind if(!ok) {
SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind
}
ctx()->try_merge_for_iter_store(for_codei); ctx()->try_merge_for_iter_store(for_codei);
compile_block_body(); compile_block_body();
ctx()->emit_(OP_LOOP_CONTINUE, ctx()->get_loop(), BC_KEEPLINE, true); ctx()->emit_(OP_LOOP_CONTINUE, ctx()->get_loop(), BC_KEEPLINE, true);
@ -712,9 +750,7 @@ __EAT_DOTS_END:
ctx()->emit_(OP_TRY_ENTER, BC_NOARG, prev().line); ctx()->emit_(OP_TRY_ENTER, BC_NOARG, prev().line);
compile_block_body(); compile_block_body();
small_vector_2<int, 6> patches; small_vector_2<int, 6> patches;
patches.push_back( patches.push_back(ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE));
ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE)
);
ctx()->exit_block(); ctx()->exit_block();
int finally_entry = -1; int finally_entry = -1;
@ -764,7 +800,9 @@ __EAT_DOTS_END:
ctx()->emit_(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE); ctx()->emit_(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE);
// no exception or no match, jump to the end // no exception or no match, jump to the end
for (int patch : patches) ctx()->patch_jump(patch); for(int patch: patches) {
ctx()->patch_jump(patch);
}
if(finally_entry != -1) { if(finally_entry != -1) {
i64 target = ctx()->co->codes.size() + 2; i64 target = ctx()->co->codes.size() + 2;
ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE); ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
@ -778,7 +816,9 @@ __EAT_DOTS_END:
do { do {
EXPR(); EXPR();
decorators.push_back(ctx()->s_expr.popx()); decorators.push_back(ctx()->s_expr.popx());
if(!match_newlines_repl()) SyntaxError(); if(!match_newlines_repl()) {
SyntaxError();
}
} while(match(TK("@"))); } while(match(TK("@")));
if(match(TK("class"))) { if(match(TK("class"))) {
@ -791,11 +831,24 @@ __EAT_DOTS_END:
bool Compiler::try_compile_assignment() { bool Compiler::try_compile_assignment() {
switch(curr().type) { switch(curr().type) {
case TK("+="): case TK("-="): case TK("*="): case TK("/="): case TK("//="): case TK("%="): case TK("+="):
case TK("<<="): case TK(">>="): case TK("&="): case TK("|="): case TK("^="): { case TK("-="):
case TK("*="):
case TK("/="):
case TK("//="):
case TK("%="):
case TK("<<="):
case TK(">>="):
case TK("&="):
case TK("|="):
case TK("^="): {
Expr* lhs_p = ctx()->s_expr.top().get(); Expr* lhs_p = ctx()->s_expr.top().get();
if(lhs_p->is_starred()) SyntaxError(); if(lhs_p->is_starred()) {
if(ctx()->is_compiling_class) SyntaxError("can't use inplace operator in class definition"); SyntaxError();
}
if(ctx()->is_compiling_class) {
SyntaxError("can't use inplace operator in class definition");
}
advance(); advance();
// a[x] += 1; a and x should be evaluated only once // a[x] += 1; a and x should be evaluated only once
// a.x += 1; a should be evaluated only once // a.x += 1; a should be evaluated only once
@ -804,11 +857,16 @@ __EAT_DOTS_END:
e->lhs = ctx()->s_expr.popx(); e->lhs = ctx()->s_expr.popx();
EXPR_TUPLE(); EXPR_TUPLE();
e->rhs = ctx()->s_expr.popx(); e->rhs = ctx()->s_expr.popx();
if(e->rhs->is_starred()) SyntaxError(); if(e->rhs->is_starred()) {
SyntaxError();
}
e->emit_(ctx()); e->emit_(ctx());
bool ok = lhs_p->emit_store_inplace(ctx()); bool ok = lhs_p->emit_store_inplace(ctx());
if(!ok) SyntaxError(); if(!ok) {
} return true; SyntaxError();
}
}
return true;
case TK("="): { case TK("="): {
int n = 0; int n = 0;
while(match(TK("="))) { while(match(TK("="))) {
@ -818,14 +876,21 @@ __EAT_DOTS_END:
// stack size is n+1 // stack size is n+1
Expr_ val = ctx()->s_expr.popx(); Expr_ val = ctx()->s_expr.popx();
val->emit_(ctx()); val->emit_(ctx());
for(int j=1; j<n; j++) ctx()->emit_(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE); for(int j = 1; j < n; j++) {
ctx()->emit_(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
}
for(int j = 0; j < n; j++) { for(int j = 0; j < n; j++) {
auto e = ctx()->s_expr.popx(); auto e = ctx()->s_expr.popx();
if(e->is_starred()) SyntaxError(); if(e->is_starred()) {
bool ok = e->emit_store(ctx()); SyntaxError();
if(!ok) SyntaxError();
} }
} return true; bool ok = e->emit_store(ctx());
if(!ok) {
SyntaxError();
}
}
}
return true;
default: return false; default: return false;
} }
} }
@ -840,24 +905,34 @@ __EAT_DOTS_END:
int curr_loop_block = ctx()->get_loop(); int curr_loop_block = ctx()->get_loop();
switch(prev().type) { switch(prev().type) {
case TK("break"): case TK("break"):
if (curr_loop_block < 0) SyntaxError("'break' outside loop"); if(curr_loop_block < 0) {
SyntaxError("'break' outside loop");
}
ctx()->emit_(OP_LOOP_BREAK, curr_loop_block, kw_line); ctx()->emit_(OP_LOOP_BREAK, curr_loop_block, kw_line);
consume_end_stmt(); consume_end_stmt();
break; break;
case TK("continue"): case TK("continue"):
if (curr_loop_block < 0) SyntaxError("'continue' not properly in loop"); if(curr_loop_block < 0) {
SyntaxError("'continue' not properly in loop");
}
ctx()->emit_(OP_LOOP_CONTINUE, curr_loop_block, kw_line); ctx()->emit_(OP_LOOP_CONTINUE, curr_loop_block, kw_line);
consume_end_stmt(); consume_end_stmt();
break; break;
case TK("yield"): case TK("yield"):
if (contexts.size() <= 1) SyntaxError("'yield' outside function"); if(contexts.size() <= 1) {
EXPR_TUPLE(); ctx()->emit_expr(); SyntaxError("'yield' outside function");
}
EXPR_TUPLE();
ctx()->emit_expr();
ctx()->emit_(OP_YIELD_VALUE, BC_NOARG, kw_line); ctx()->emit_(OP_YIELD_VALUE, BC_NOARG, kw_line);
consume_end_stmt(); consume_end_stmt();
break; break;
case TK("yield from"): case TK("yield from"):
if (contexts.size() <= 1) SyntaxError("'yield from' outside function"); if(contexts.size() <= 1) {
EXPR_TUPLE(); ctx()->emit_expr(); SyntaxError("'yield from' outside function");
}
EXPR_TUPLE();
ctx()->emit_expr();
ctx()->emit_(OP_GET_ITER_NEW, BC_NOARG, kw_line); ctx()->emit_(OP_GET_ITER_NEW, BC_NOARG, kw_line);
ctx()->enter_block(CodeBlockType::FOR_LOOP); ctx()->enter_block(CodeBlockType::FOR_LOOP);
@ -867,11 +942,14 @@ __EAT_DOTS_END:
consume_end_stmt(); consume_end_stmt();
break; break;
case TK("return"): case TK("return"):
if (contexts.size() <= 1) SyntaxError("'return' outside function"); if(contexts.size() <= 1) {
SyntaxError("'return' outside function");
}
if(match_end_stmt()) { if(match_end_stmt()) {
ctx()->emit_(OP_RETURN_VALUE, 1, kw_line); ctx()->emit_(OP_RETURN_VALUE, 1, kw_line);
} else { } else {
EXPR_TUPLE(); ctx()->emit_expr(); EXPR_TUPLE();
ctx()->emit_expr();
consume_end_stmt(); consume_end_stmt();
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, kw_line); ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, kw_line);
} }
@ -892,14 +970,12 @@ __EAT_DOTS_END:
StrName name(prev().sv()); StrName name(prev().sv());
NameScope scope = name_scope(); NameScope scope = name_scope();
bool is_global = ctx()->global_names.contains(name.sv()); bool is_global = ctx()->global_names.contains(name.sv());
if(is_global) scope = NAME_GLOBAL; if(is_global) {
scope = NAME_GLOBAL;
}
switch(scope) { switch(scope) {
case NAME_LOCAL: case NAME_LOCAL: ctx()->emit_(OP_INC_FAST, ctx()->add_varname(name), prev().line); break;
ctx()->emit_(OP_INC_FAST, ctx()->add_varname(name), prev().line); case NAME_GLOBAL: ctx()->emit_(OP_INC_GLOBAL, name.index, prev().line); break;
break;
case NAME_GLOBAL:
ctx()->emit_(OP_INC_GLOBAL, name.index, prev().line);
break;
default: SyntaxError(); break; default: SyntaxError(); break;
} }
consume_end_stmt(); consume_end_stmt();
@ -909,12 +985,8 @@ __EAT_DOTS_END:
consume(TK("@id")); consume(TK("@id"));
StrName name(prev().sv()); StrName name(prev().sv());
switch(name_scope()) { switch(name_scope()) {
case NAME_LOCAL: case NAME_LOCAL: ctx()->emit_(OP_DEC_FAST, ctx()->add_varname(name), prev().line); break;
ctx()->emit_(OP_DEC_FAST, ctx()->add_varname(name), prev().line); case NAME_GLOBAL: ctx()->emit_(OP_DEC_GLOBAL, name.index, prev().line); break;
break;
case NAME_GLOBAL:
ctx()->emit_(OP_DEC_GLOBAL, name.index, prev().line);
break;
default: SyntaxError(); break; default: SyntaxError(); break;
} }
consume_end_stmt(); consume_end_stmt();
@ -943,7 +1015,8 @@ __EAT_DOTS_END:
consume_end_stmt(); consume_end_stmt();
break; break;
case TK("raise"): { case TK("raise"): {
EXPR(); ctx()->emit_expr(); EXPR();
ctx()->emit_expr();
ctx()->emit_(OP_RAISE, BC_NOARG, kw_line); ctx()->emit_(OP_RAISE, BC_NOARG, kw_line);
consume_end_stmt(); consume_end_stmt();
} break; } break;
@ -951,7 +1024,9 @@ __EAT_DOTS_END:
EXPR_TUPLE(); EXPR_TUPLE();
Expr_ e = ctx()->s_expr.popx(); Expr_ e = ctx()->s_expr.popx();
bool ok = e->emit_del(ctx()); bool ok = e->emit_del(ctx());
if(!ok) SyntaxError(); if(!ok) {
SyntaxError();
}
consume_end_stmt(); consume_end_stmt();
} break; } break;
case TK("with"): { case TK("with"): {
@ -967,7 +1042,9 @@ __EAT_DOTS_END:
// [ <expr> <expr>.__enter__() ] // [ <expr> <expr>.__enter__() ]
if(as_name != nullptr) { if(as_name != nullptr) {
bool ok = as_name->emit_store(ctx()); bool ok = as_name->emit_store(ctx());
if(!ok) SyntaxError(); if(!ok) {
SyntaxError();
}
} else { } else {
ctx()->emit_(OP_POP_TOP, BC_NOARG, BC_KEEPLINE); ctx()->emit_(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
} }
@ -978,15 +1055,21 @@ __EAT_DOTS_END:
/*************************************************/ /*************************************************/
case TK("=="): { case TK("=="): {
consume(TK("@id")); consume(TK("@id"));
if(mode()!=EXEC_MODE) SyntaxError("'label' is only available in EXEC_MODE"); if(mode() != EXEC_MODE) {
SyntaxError("'label' is only available in EXEC_MODE");
}
bool ok = ctx()->add_label(prev().str()); bool ok = ctx()->add_label(prev().str());
consume(TK("==")); consume(TK("=="));
if(!ok) SyntaxError("label " + prev().str().escape() + " already exists"); if(!ok) {
SyntaxError("label " + prev().str().escape() + " already exists");
}
consume_end_stmt(); consume_end_stmt();
} break; } break;
case TK("->"): case TK("->"):
consume(TK("@id")); consume(TK("@id"));
if(mode()!=EXEC_MODE) SyntaxError("'goto' is only available in EXEC_MODE"); if(mode() != EXEC_MODE) {
SyntaxError("'goto' is only available in EXEC_MODE");
}
ctx()->emit_(OP_GOTO, StrName(prev().sv()).index, prev().line); ctx()->emit_(OP_GOTO, StrName(prev().sv()).index, prev().line);
consume_end_stmt(); consume_end_stmt();
break; break;
@ -1085,14 +1168,20 @@ __EAT_DOTS_END:
void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) { void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) {
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
do { do {
if(state > 3) SyntaxError(); if(state > 3) {
if(state == 3) SyntaxError("**kwargs should be the last argument"); SyntaxError();
}
if(state == 3) {
SyntaxError("**kwargs should be the last argument");
}
match_newlines(); match_newlines();
if(match(TK("*"))) { if(match(TK("*"))) {
if(state < 1) state = 1; if(state < 1) {
else SyntaxError("*args should be placed before **kwargs"); state = 1;
} else {
SyntaxError("*args should be placed before **kwargs");
} }
else if(match(TK("**"))){ } else if(match(TK("**"))) {
state = 3; state = 3;
} }
consume(TK("@id")); consume(TK("@id"));
@ -1117,14 +1206,15 @@ __EAT_DOTS_END:
} }
// eat type hints // eat type hints
if(enable_type_hints && match(TK(":"))) consume_type_hints(); if(enable_type_hints && match(TK(":"))) {
if(state == 0 && curr().type == TK("=")) state = 2; consume_type_hints();
}
if(state == 0 && curr().type == TK("=")) {
state = 2;
}
int index = ctx()->add_varname(name); int index = ctx()->add_varname(name);
switch (state) switch(state) {
{ case 0: decl->args.push_back(index); break;
case 0:
decl->args.push_back(index);
break;
case 1: case 1:
decl->starred_arg = index; decl->starred_arg = index;
state += 1; state += 1;
@ -1154,12 +1244,15 @@ __EAT_DOTS_END:
_compile_f_args(decl, true); _compile_f_args(decl, true);
consume(TK(")")); consume(TK(")"));
} }
if(match(TK("->"))) consume_type_hints(); if(match(TK("->"))) {
consume_type_hints();
}
compile_block_body(); compile_block_body();
pop_context(); pop_context();
decl->docstring = nullptr; decl->docstring = nullptr;
if(decl->code->codes.size()>=2 && decl->code->codes[0].op == OP_LOAD_CONST && decl->code->codes[1].op == OP_POP_TOP){ if(decl->code->codes.size() >= 2 && decl->code->codes[0].op == OP_LOAD_CONST &&
decl->code->codes[1].op == OP_POP_TOP) {
PyVar c = decl->code->consts[decl->code->codes[0].arg]; PyVar c = decl->code->consts[decl->code->codes[0].arg];
if(is_type(c, vm->tp_str)) { if(is_type(c, vm->tp_str)) {
decl->code->codes[0].op = OP_NO_OP; decl->code->codes[0].op = OP_NO_OP;
@ -1213,9 +1306,13 @@ __EAT_DOTS_END:
List cpnts; List cpnts;
while(true) { while(true) {
cpnts.push_back(read_literal()); cpnts.push_back(read_literal());
if(curr().type == TK(")")) break; if(curr().type == TK(")")) {
break;
}
consume(TK(",")); consume(TK(","));
if(curr().type == TK(")")) break; if(curr().type == TK(")")) {
break;
}
} }
consume(TK(")")); consume(TK(")"));
return VAR(cpnts.to_tuple()); return VAR(cpnts.to_tuple());
@ -1225,8 +1322,8 @@ __EAT_DOTS_END:
return nullptr; return nullptr;
} }
Compiler::Compiler(VM* vm, std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope) Compiler::Compiler(VM* vm, std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope) :
:lexer(vm, std::make_shared<SourceData>(source, filename, mode)){ lexer(vm, std::make_shared<SourceData>(source, filename, mode)) {
this->vm = vm; this->vm = vm;
this->unknown_global_scope = unknown_global_scope; this->unknown_global_scope = unknown_global_scope;
init_pratt_rules(); init_pratt_rules();
@ -1245,7 +1342,9 @@ __EAT_DOTS_END:
if(it == token_indices.end()) { if(it == token_indices.end()) {
token_indices[token.sv()] = 0; token_indices[token.sv()] = 0;
// assert no '\n' in token.sv() // assert no '\n' in token.sv()
for(char c: token.sv()) assert(c!='\n'); for(char c: token.sv()) {
assert(c != '\n');
}
} }
} }
} }
@ -1263,12 +1362,19 @@ __EAT_DOTS_END:
if(is_raw_string_used(token.type)) { if(is_raw_string_used(token.type)) {
ss << token_indices[token.sv()] << ','; ss << token_indices[token.sv()] << ',';
} }
if(i>0 && tokens[i-1].line == token.line) ss << ','; if(i > 0 && tokens[i - 1].line == token.line) {
else ss << token.line << ','; ss << ',';
if(i>0 && tokens[i-1].brackets_level == token.brackets_level) ss << ','; } else {
else ss << token.brackets_level << ','; ss << token.line << ',';
}
if(i > 0 && tokens[i - 1].brackets_level == token.brackets_level) {
ss << ',';
} else {
ss << token.brackets_level << ',';
}
// visit token value // visit token value
std::visit([&ss](auto&& arg){ std::visit(
[&ss](auto&& arg) {
using T = std::decay_t<decltype(arg)>; using T = std::decay_t<decltype(arg)>;
if constexpr(std::is_same_v<T, i64>) { if constexpr(std::is_same_v<T, i64>) {
ss << 'I' << arg; ss << 'I' << arg;
@ -1276,10 +1382,13 @@ __EAT_DOTS_END:
ss << 'F' << arg; ss << 'F' << arg;
} else if constexpr(std::is_same_v<T, Str>) { } else if constexpr(std::is_same_v<T, Str>) {
ss << 'S'; ss << 'S';
for(char c: arg) ss.write_hex((unsigned char)c); for(char c: arg) {
ss.write_hex((unsigned char)c);
}
} }
ss << '\n'; ss << '\n';
}, token.value); },
token.value);
} }
return ss.str(); return ss.str();
} }
@ -1332,9 +1441,7 @@ __EAT_DOTS_END:
switch(type) { switch(type) {
case 'I': t.value = deserializer.read_uint('\n'); break; case 'I': t.value = deserializer.read_uint('\n'); break;
case 'F': t.value = deserializer.read_float('\n'); break; case 'F': t.value = deserializer.read_float('\n'); break;
case 'S': case 'S': t.value = deserializer.read_string_from_hex('\n'); break;
t.value = deserializer.read_string_from_hex('\n');
break;
default: t.value = {}; break; default: t.value = {}; break;
} }
tokens.push_back(t); tokens.push_back(t);
@ -1356,7 +1463,8 @@ __EAT_DOTS_END:
match_newlines(); // skip possible leading '\n' match_newlines(); // skip possible leading '\n'
if(mode() == EVAL_MODE) { if(mode() == EVAL_MODE) {
EXPR_TUPLE(); ctx()->emit_expr(); EXPR_TUPLE();
ctx()->emit_expr();
consume(TK("@eof")); consume(TK("@eof"));
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
pop_context(); pop_context();
@ -1364,7 +1472,9 @@ __EAT_DOTS_END:
} else if(mode() == JSON_MODE) { } else if(mode() == JSON_MODE) {
EXPR(); EXPR();
Expr_ e = ctx()->s_expr.popx(); Expr_ e = ctx()->s_expr.popx();
if(!e->is_json_object()) SyntaxError("expect a JSON object, literal or array"); if(!e->is_json_object()) {
SyntaxError("expect a JSON object, literal or array");
}
consume(TK("@eof")); consume(TK("@eof"));
e->emit_(ctx()); e->emit_(ctx());
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
@ -1390,7 +1500,9 @@ __EAT_DOTS_END:
std::string_view TokenDeserializer::read_string(char c) { std::string_view TokenDeserializer::read_string(char c) {
const char* start = curr; const char* start = curr;
while(*curr != c) curr++; while(*curr != c) {
curr++;
}
std::string_view retval(start, curr - start); std::string_view retval(start, curr - start);
curr++; // skip the delimiter curr++; // skip the delimiter
return retval; return retval;
@ -1401,13 +1513,21 @@ __EAT_DOTS_END:
char* buffer = (char*)std::malloc(s.size() / 2 + 1); char* buffer = (char*)std::malloc(s.size() / 2 + 1);
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 assert(false); } else if(s[i] >= 'a' && s[i] <= 'f') {
c += s[i] - 'a' + 10;
} else {
assert(false);
}
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 assert(false); } else if(s[i + 1] >= 'a' && s[i + 1] <= 'f') {
c += s[i + 1] - 'a' + 10;
} else {
assert(false);
}
buffer[i / 2] = c; buffer[i / 2] = c;
} }
buffer[s.size() / 2] = 0; buffer[s.size() / 2] = 0;

View File

@ -4,21 +4,31 @@
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()) {
if(!isalpha(s[0]) && s[0] != '_') return false; return false;
for(char c: s) if(!isalnum(c) && c != '_') return false; }
if(!isalpha(s[0]) && s[0] != '_') {
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) {
if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) break; break;
}
if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) {
break;
}
index = co->blocks[index].parent; index = co->blocks[index].parent;
} }
return index; return index;
@ -53,8 +63,11 @@ namespace pkpy{
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;
} }
@ -66,8 +79,12 @@ namespace pkpy{
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) {
if(co->codes.size() - i != 2) return; 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_();
@ -97,7 +114,9 @@ namespace pkpy{
} }
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;
} }
@ -105,7 +124,9 @@ namespace pkpy{
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;
}
co->varnames.push_back(name); co->varnames.push_back(name);
co->nlocals++; co->nlocals++;
index = co->varnames.size() - 1; index = co->varnames.size() - 1;
@ -147,20 +168,13 @@ namespace pkpy{
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) {
@ -174,7 +188,9 @@ namespace pkpy{
// 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);
} }
@ -182,15 +198,9 @@ namespace pkpy{
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;
@ -216,7 +226,9 @@ namespace pkpy{
} }
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);
} }
@ -305,7 +317,6 @@ namespace pkpy{
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);
@ -344,9 +355,14 @@ namespace pkpy{
// 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()) {
if(starred_i == -1) starred_i = i; continue;
else return false; // multiple StarredExpr not allowed }
if(starred_i == -1) {
starred_i = i;
} else {
return false; // multiple StarredExpr not allowed
}
} }
if(starred_i == -1) { if(starred_i == -1) {
@ -364,9 +380,13 @@ namespace pkpy{
} }
} 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);
@ -374,7 +394,9 @@ namespace pkpy{
// 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;
} }
@ -382,7 +404,9 @@ namespace pkpy{
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;
} }
@ -412,13 +436,18 @@ namespace pkpy{
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
} }
} }
@ -480,7 +509,12 @@ namespace pkpy{
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(!is_fmt_valid_char(c)) {
ok = false;
break;
}
}
if(ok) { 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);
@ -522,7 +556,9 @@ namespace pkpy{
} 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] != '}') {
j++;
}
Str literal = src.substr(i, j - i); 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++;
@ -542,7 +578,6 @@ namespace pkpy{
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);
@ -630,8 +665,16 @@ namespace pkpy{
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()) {
@ -643,7 +686,9 @@ namespace pkpy{
} }
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()) {
@ -666,7 +711,9 @@ namespace pkpy{
} }
} else { } else {
// vectorcall protocol // vectorcall protocol
for(auto& item: args) item->emit_(ctx); for(auto& item: args) {
item->emit_(ctx);
}
for(auto& item: kwargs) { 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);
@ -678,11 +725,14 @@ namespace pkpy{
} }
} }
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(">="): return true; case TK("<="):
case TK("=="):
case TK("!="):
case TK(">"):
case TK(">="): return true;
default: return false; default: return false;
} }
} }
@ -757,7 +807,9 @@ 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) {

View File

@ -22,29 +22,45 @@ static bool is_possible_number_char(char c){
static bool is_unicode_Lo_char(uint32_t c) { static bool is_unicode_Lo_char(uint32_t c) {
// open a hole for carrot // open a hole for carrot
if(c == U'🥕') return true; if(c == U'🥕') {
return true;
}
auto index = std::lower_bound(kLoRangeA, kLoRangeA + 476, c) - kLoRangeA; auto index = std::lower_bound(kLoRangeA, kLoRangeA + 476, c) - kLoRangeA;
if(c == kLoRangeA[index]) return true; if(c == kLoRangeA[index]) {
return true;
}
index -= 1; index -= 1;
if(index < 0) return false; if(index < 0) {
return false;
}
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') {
if(*c != c0) return false; 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;
} }
@ -61,10 +77,16 @@ static bool is_unicode_Lo_char(uint32_t c) {
} }
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() == '#') {
if(peekchar() == '\0' || peekchar() == '\n') return true; skip_line_comment();
}
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);
@ -103,7 +125,9 @@ static bool is_unicode_Lo_char(uint32_t c) {
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++;
@ -114,24 +138,35 @@ static bool is_unicode_Lo_char(uint32_t c) {
} }
// handle multibyte char // handle multibyte char
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) {
value = (b & 0b00001111) << 12;
} else if(u8bytes == 4) {
value = (b & 0b00000111) << 18;
}
} else { } else {
value |= (b & 0b00111111) << (6 * (u8bytes - k - 1)); 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) {
@ -158,30 +193,36 @@ static bool is_unicode_Lo_char(uint32_t c) {
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();
@ -202,8 +243,11 @@ static bool is_unicode_Lo_char(uint32_t c) {
} }
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) {
@ -225,8 +269,9 @@ static bool is_unicode_Lo_char(uint32_t c) {
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;
} }
@ -246,10 +291,10 @@ static bool is_unicode_Lo_char(uint32_t c) {
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"); }
if(parsed != 2) {
SyntaxError("invalid hex char"); 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");
@ -276,12 +321,16 @@ static bool is_unicode_Lo_char(uint32_t c) {
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++; i++;
while(isdigit(*i) || *i=='j') i++; while(isdigit(*i) || *i == 'j') {
i++;
}
is_scientific_notation = true; is_scientific_notation = true;
} }
@ -297,14 +346,9 @@ static bool is_unicode_Lo_char(uint32_t c) {
// 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
} }
} }
@ -313,9 +357,7 @@ static bool is_unicode_Lo_char(uint32_t c) {
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);
@ -335,7 +377,8 @@ static bool is_unicode_Lo_char(uint32_t c) {
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;
@ -352,7 +395,9 @@ static bool is_unicode_Lo_char(uint32_t c) {
// 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");
} }
eat_spaces(); eat_spaces();
@ -388,30 +433,45 @@ static bool is_unicode_Lo_char(uint32_t c) {
} }
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('*')) {
@ -427,29 +487,49 @@ 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);
return true;
}
if(matchchar('"')) {
eat_string('"', F_STRING);
return true;
}
} else if(c == 'r') { } else if(c == 'r') {
if(matchchar('\'')) {eat_string('\'', RAW_STRING); return true;} if(matchchar('\'')) {
if(matchchar('"')) {eat_string('"', RAW_STRING); return true;} eat_string('\'', RAW_STRING);
return true;
}
if(matchchar('"')) {
eat_string('"', RAW_STRING);
return true;
}
} else if(c == 'b') { } else if(c == 'b') {
if(matchchar('\'')) {eat_string('\'', NORMAL_BYTES); return true;} if(matchchar('\'')) {
if(matchchar('"')) {eat_string('"', NORMAL_BYTES); return true;} eat_string('\'', NORMAL_BYTES);
return true;
}
if(matchchar('"')) {
eat_string('"', NORMAL_BYTES);
return true;
}
} }
if(c >= '0' && c <= '9') { 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;
@ -491,12 +571,15 @@ static bool is_unicode_Lo_char(uint32_t c) {
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];
} }
@ -504,20 +587,29 @@ 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;
} }
@ -525,13 +617,19 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base){
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")) {
if(text.length() == 0) return IntParsingResult::Failure; text.remove_prefix(2);
}
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;
} }
@ -539,13 +637,19 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base){
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")) {
if(text.length() == 0) return IntParsingResult::Failure; text.remove_prefix(2);
}
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;
} }
@ -553,19 +657,29 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base){
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")) {
if(text.length() == 0) return IntParsingResult::Failure; text.remove_prefix(2);
}
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

@ -21,7 +21,8 @@ namespace pkpy{
#define BIND_CMP(name, op) \ #define BIND_CMP(name, op) \
vm->bind##name(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) { \ vm->bind##name(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) { \
if(!vm->isinstance(rhs, vm->_tp_user<VoidP>())) return vm->NotImplemented; \ if(!vm->isinstance(rhs, vm->_tp_user<VoidP>())) \
return vm->NotImplemented; \
void* _0 = PK_OBJ_GET(VoidP, lhs).ptr; \ void* _0 = PK_OBJ_GET(VoidP, lhs).ptr; \
void* _1 = PK_OBJ_GET(VoidP, rhs).ptr; \ void* _1 = PK_OBJ_GET(VoidP, rhs).ptr; \
return VAR(_0 op _1); \ return VAR(_0 op _1); \
@ -36,7 +37,6 @@ namespace pkpy{
#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]);
@ -47,30 +47,50 @@ namespace pkpy{
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;
} 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; 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);
@ -96,7 +116,9 @@ namespace pkpy{
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) { vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) {
Struct& self = _CAST(Struct&, lhs); Struct& self = _CAST(Struct&, lhs);
if(!vm->is_user_type<Struct>(rhs)) return vm->NotImplemented; if(!vm->is_user_type<Struct>(rhs)) {
return vm->NotImplemented;
}
Struct& other = _CAST(Struct&, rhs); Struct& other = _CAST(Struct&, rhs);
bool ok = self.size == other.size && memcmp(self.p, other.p, self.size) == 0; bool ok = self.size == other.size && memcmp(self.p, other.p, self.size) == 0;
return VAR(ok); return VAR(ok);
@ -237,7 +259,7 @@ void add_module_c(VM* vm){
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")
@ -272,8 +294,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

@ -6,7 +6,9 @@
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];
} }
@ -14,15 +16,21 @@ namespace pkpy{
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);
} }
@ -30,10 +38,14 @@ namespace pkpy{
// try to find a parent try block // try to find a parent try block
int i = co->lines[ip()].iblock; int i = co->lines[ip()].iblock;
while(i >= 0) { while(i >= 0) {
if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) break; if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) {
break;
}
i = co->blocks[i].parent; i = co->blocks[i].parent;
} }
if(i < 0) return -1; if(i < 0) {
return -1;
}
PyVar obj = _s->popx(); // pop exception object PyVar obj = _s->popx(); // pop exception object
UnwindTarget* uw = find_unwind_target(i); UnwindTarget* uw = find_unwind_target(i);
_s->reset(actual_sp_base() + uw->offset); // unwind the stack _s->reset(actual_sp_base() + uw->offset); // unwind the stack
@ -61,7 +73,9 @@ namespace pkpy{
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) {
i = _exit_block(_s, i);
}
} else { } else {
// BUG (solved) // BUG (solved)
// for i in range(4): // for i in range(4):
@ -69,8 +83,12 @@ namespace pkpy{
// # 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");
}
} }
} }
@ -89,7 +107,9 @@ namespace pkpy{
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;
} }

View File

@ -13,13 +13,17 @@ namespace pkpy{
#if PK_DEBUG_GC_STATS #if PK_DEBUG_GC_STATS
deleted[obj->type] += 1; deleted[obj->type] += 1;
#endif #endif
if(_gc_on_delete) _gc_on_delete(vm, obj); if(_gc_on_delete) {
_gc_on_delete(vm, obj);
}
_delete(obj); _delete(obj);
} }
} }
// clear _no_gc marked flag // 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();
@ -38,11 +42,15 @@ namespace pkpy{
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;
collect(); collect();
gc_threshold = gen.size() * 2; gc_threshold = gen.size() * 2;
if(gc_threshold < PK_GC_MIN_THRESHOLD) gc_threshold = PK_GC_MIN_THRESHOLD; if(gc_threshold < PK_GC_MIN_THRESHOLD) {
gc_threshold = PK_GC_MIN_THRESHOLD;
}
#endif #endif
} }

View File

@ -6,7 +6,9 @@ namespace pkpy{
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { 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;
@ -17,7 +19,9 @@ namespace pkpy{
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { 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;
@ -28,7 +32,9 @@ namespace pkpy{
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { 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;
}); });
@ -39,7 +45,9 @@ namespace pkpy{
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { 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;
}
int start = self.i; int start = self.i;
int len = utf8len(s.data[self.i]); int len = utf8len(s.data[self.i]);
self.i += len; self.i += len;
@ -49,12 +57,16 @@ namespace pkpy{
} }
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) {
@ -82,7 +94,9 @@ namespace pkpy{
// 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
@ -91,7 +105,9 @@ namespace pkpy{
// } // }
// #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;
@ -104,7 +120,9 @@ namespace pkpy{
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { 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;
}); });
@ -115,7 +133,9 @@ namespace pkpy{
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { 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;
}
vm->s_data.push(d._items[self.i].first); vm->s_data.push(d._items[self.i].first);
vm->s_data.push(d._items[self.i].second); vm->s_data.push(d._items[self.i].second);
self.i = d._items[self.i].next; self.i = d._items[self.i].next;

View File

@ -4,7 +4,9 @@ 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;
} }
@ -14,13 +16,13 @@ static std::string to_string_1f(f64 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;
@ -55,14 +57,18 @@ void LineProfiler::_step_end(int callstack_size, Frame* frame, int line){
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();
}
} }
} }
@ -85,10 +91,14 @@ Str LineProfiler::stats(){
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;
}
std::string_view filename = decl->code->src->filename.sv(); std::string_view filename = decl->code->src->filename.sv();
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;
@ -100,7 +110,9 @@ Str LineProfiler::stats(){
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, ' ');

File diff suppressed because it is too large Load Diff

View File

@ -25,22 +25,18 @@ struct Array2d{
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) {
@ -57,9 +53,13 @@ struct Array2d{
} }
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++) {
self.data[i] = vm->call(args[3]);
}
} else { } else {
for(int i = 0; i < self.numel; i++) self.data[i] = args[3]; for(int i = 0; i < self.numel; i++) {
self.data[i] = args[3];
}
} }
return vm->None; return vm->None;
}); });
@ -100,7 +100,9 @@ struct Array2d{
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]);
if(!self.is_valid(col, row)) return args[3]; if(!self.is_valid(col, row)) {
return args[3];
}
return self._get(col, row); return self._get(col, row);
}); });
@ -109,10 +111,12 @@ struct Array2d{
int start_row, stop_row, step_row; \ int start_row, stop_row, step_row; \
vm->parse_int_slice(PK_OBJ_GET(Slice, xy[0]), self.n_cols, start_col, stop_col, step_col); \ vm->parse_int_slice(PK_OBJ_GET(Slice, xy[0]), self.n_cols, start_col, stop_col, step_col); \
vm->parse_int_slice(PK_OBJ_GET(Slice, xy[1]), self.n_rows, start_row, stop_row, step_row); \ vm->parse_int_slice(PK_OBJ_GET(Slice, xy[1]), self.n_rows, start_row, stop_row, step_row); \
if(step_col != 1 || step_row != 1) vm->ValueError("slice step must be 1"); \ if(step_col != 1 || step_row != 1) \
vm->ValueError("slice step must be 1"); \
int slice_width = stop_col - start_col; \ int slice_width = stop_col - start_col; \
int slice_height = stop_row - start_row; \ int slice_height = stop_row - start_row; \
if(slice_width <= 0 || slice_height <= 0) vm->ValueError("slice width and height must be positive"); if(slice_width <= 0 || slice_height <= 0) \
vm->ValueError("slice width and height must be positive");
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
Array2d& self = PK_OBJ_GET(Array2d, _0); Array2d& self = PK_OBJ_GET(Array2d, _0);
@ -164,9 +168,11 @@ struct Array2d{
} }
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;
} }
@ -178,9 +184,11 @@ struct Array2d{
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++) {
for(int i = 0; i < slice_width; i++) for(int i = 0; i < slice_width; i++) {
self._set(i + start_col, j + start_row, other._get(i, j)); self._set(i + start_col, j + start_row, other._get(i, j));
}
}
return; return;
} }
vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index"); vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index");
@ -193,7 +201,9 @@ struct Array2d{
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));
@ -275,11 +285,17 @@ struct Array2d{
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;
}); });
@ -327,7 +343,9 @@ struct Array2d{
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);
}); });
@ -350,7 +368,9 @@ struct Array2d{
} }
int width = right - left + 1; int width = right - left + 1;
int height = bottom - top + 1; int height = bottom - top + 1;
if(width <= 0 || height <= 0) return vm->None; if(width <= 0 || height <= 0) {
return vm->None;
}
Tuple t(4); Tuple t(4);
t[0] = VAR(left); t[0] = VAR(left);
t[1] = VAR(top); t[1] = VAR(top);
@ -361,15 +381,14 @@ 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)
@ -385,7 +404,9 @@ struct Array2dIter{
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { 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);
vm->s_data.emplace(VM::tp_int, res.rem); vm->s_data.emplace(VM::tp_int, res.rem);
vm->s_data.emplace(VM::tp_int, res.quot); vm->s_data.emplace(VM::tp_int, res.quot);
@ -402,13 +423,11 @@ void add_module_array2d(VM* vm){
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,
return vm->new_user_object<Array2dIter>(_0, &_0.obj_get<Array2d>()); [](VM* vm, PyVar _0) { return vm->new_user_object<Array2dIter>(_0, &_0.obj_get<Array2d>()); });
});
vm->_all_types[array2d_iter_t].op__iter__ = [](VM* vm, PyVar _0) { vm->_all_types[array2d_iter_t].op__iter__ = [](VM* vm, PyVar _0) {
vm->new_stack_object<Array2dIter>(vm->_tp_user<Array2dIter>(), _0, &_0.obj_get<Array2d>()); vm->new_stack_object<Array2dIter>(vm->_tp_user<Array2dIter>(), _0, &_0.obj_get<Array2d>());
}; };
} }
} // namespace pkpy } // namespace pkpy

View File

@ -74,9 +74,7 @@ const unsigned char base64de[] = {
}; };
// clang-format on // 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;
@ -123,9 +121,7 @@ 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;
@ -148,9 +144,7 @@ base64_decode(const char *in, unsigned int inlen, unsigned char *out)
} }
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;
@ -159,9 +153,7 @@ 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;
} }
} }

View File

@ -13,7 +13,9 @@ void add_module_csv(VM *vm){
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;
@ -43,11 +45,8 @@ __NEXT_LINE:
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++;
} }

View File

@ -9,9 +9,7 @@ static void patch__init__(VM* vm, Type cls){
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);
});
Type cls = vm->_tp(self); Type cls = vm->_tp(self);
const PyTypeInfo* cls_info = &vm->_all_types[cls]; const PyTypeInfo* cls_info = &vm->_all_types[cls];
@ -35,7 +33,8 @@ static void patch__init__(VM* vm, Type cls){
} }
} }
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;
@ -54,8 +53,11 @@ static void patch__repr__(VM* vm, Type cls){
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 << ")";
@ -65,13 +67,17 @@ 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;
}
} }
return vm->True; return vm->True;
}); });
@ -85,9 +91,15 @@ void add_module_dataclasses(VM* vm){
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();
if(!cls_d.contains(__init__)) patch__init__(vm, cls); if(!cls_d.contains(__init__)) {
if(!cls_d.contains(__repr__)) patch__repr__(vm, cls); patch__init__(vm, cls);
if(!cls_d.contains(__eq__)) patch__eq__(vm, cls); }
if(!cls_d.contains(__repr__)) {
patch__repr__(vm, cls);
}
if(!cls_d.contains(__eq__)) {
patch__eq__(vm, cls);
}
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;

View File

@ -8,29 +8,17 @@ namespace pkpy{
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) {
@ -40,13 +28,9 @@ static double easeInOutQuad( double x ) {
} }
} }
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) {
@ -56,13 +40,9 @@ static double easeInOutCubic( double x ) {
} }
} }
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) {
@ -72,13 +52,9 @@ static double easeInOutQuart( double x ) {
} }
} }
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) {
@ -88,13 +64,9 @@ static double easeInOutQuint( double x ) {
} }
} }
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) {
@ -108,13 +80,9 @@ static double easeInOutExpo( double x ) {
} }
} }
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) {
@ -198,14 +166,10 @@ 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) { static double easeInOutBounce(double x) {
return x < 0.5 return x < 0.5 ? (1 - easeOutBounce(1 - 2 * x)) / 2 : (1 + easeOutBounce(2 * x - 1)) / 2;
? (1 - easeOutBounce(1 - 2 * x)) / 2
: (1 + easeOutBounce(2 * x - 1)) / 2;
} }
void add_module_easing(VM* vm) { void add_module_easing(VM* vm) {

View File

@ -23,7 +23,9 @@ 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);
if(err != 0) return nullptr; if(err != 0) {
return nullptr;
}
return fp; return fp;
#else #else
return fopen(name, mode); return fopen(name, mode);
@ -40,9 +42,13 @@ static size_t io_fread(void* buffer, size_t size, size_t count, FILE* fp){
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");
if(!fp) return nullptr; if(!fp) {
return nullptr;
}
fseek(fp, 0, SEEK_END); fseek(fp, 0, SEEK_END);
int buffer_size = ftell(fp); int buffer_size = ftell(fp);
unsigned char* buffer = new unsigned char[buffer_size]; unsigned char* buffer = new unsigned char[buffer_size];
@ -57,9 +63,7 @@ unsigned char* _default_import_handler(const char* name, int* out_size){
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) {
@ -100,7 +104,9 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){
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);
}); });
@ -109,7 +115,9 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){
long offset = CAST(long, args[1]); long offset = CAST(long, args[1]);
int whence = CAST(int, args[2]); int whence = CAST(int, args[2]);
int ret = fseek(io.fp, offset, whence); int ret = fseek(io.fp, offset, whence);
if(ret != 0) vm->IOError(strerror(errno)); if(ret != 0) {
vm->IOError(strerror(errno));
}
return vm->None; return vm->None;
}); });
@ -131,11 +139,15 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){
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;
} }
@ -174,32 +186,38 @@ void add_module_os(VM* vm){
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;
}); });
@ -242,10 +260,10 @@ void add_module_os(VM* vm){
#else #else
void add_module_io(VM* vm) {} void add_module_io(VM* vm) {}
void add_module_os(VM* vm) {} void add_module_os(VM* vm) {}
unsigned char* _default_import_handler(const char* name, int* out_size){
return nullptr; unsigned char* _default_import_handler(const char* name, int* out_size) { return nullptr; }
}
#endif #endif

View File

@ -55,27 +55,30 @@ namespace pkpy{
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"); \
return VAR(self[i]); \ return VAR(self[i]); \
}); });
#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 +95,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 +119,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;
@ -139,7 +140,10 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
}); });
// @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,18 +152,29 @@ 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) {
if(val < -PI) val += 2*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);
@ -275,17 +290,25 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
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));
@ -415,21 +438,27 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
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");
}
self = ret; self = ret;
return vm->None; return vm->None;
}); });
@ -441,28 +470,45 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
}); });
// @staticmethod // @staticmethod
vm->bind_func(type, "zeros", 0, [](VM* vm, ArgsView args){ vm->bind_func(
return vm->new_user_object<Mat3x3>(Mat3x3::zeros()); type,
}, {}, BindType::STATICMETHOD); "zeros",
0,
[](VM* vm, ArgsView args) { return vm->new_user_object<Mat3x3>(Mat3x3::zeros()); },
{},
BindType::STATICMETHOD);
// @staticmethod // @staticmethod
vm->bind_func(type, "ones", 0, [](VM* vm, ArgsView args){ vm->bind_func(
return vm->new_user_object<Mat3x3>(Mat3x3::ones()); type,
}, {}, BindType::STATICMETHOD); "ones",
0,
[](VM* vm, ArgsView args) { return vm->new_user_object<Mat3x3>(Mat3x3::ones()); },
{},
BindType::STATICMETHOD);
// @staticmethod // @staticmethod
vm->bind_func(type, "identity", 0, [](VM* vm, ArgsView args){ vm->bind_func(
return vm->new_user_object<Mat3x3>(Mat3x3::identity()); type,
}, {}, BindType::STATICMETHOD); "identity",
0,
[](VM* vm, ArgsView args) { return vm->new_user_object<Mat3x3>(Mat3x3::identity()); },
{},
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]);
@ -525,7 +571,9 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
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;
if(!self.inverse(inv)) vm->ValueError("matrix is not invertible"); if(!self.inverse(inv)) {
vm->ValueError("matrix is not invertible");
}
Vec2 res(inv._11 * v.x + inv._12 * v.y + inv._13, inv._21 * v.x + inv._22 * v.y + inv._23); Vec2 res(inv._11 * v.x + inv._12 * v.y + inv._13, inv._21 * v.x + inv._22 * v.y + inv._23);
return vm->new_user_object<Vec2>(res); return vm->new_user_object<Vec2>(res);
}); });
@ -541,13 +589,14 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
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;
if(!self.inverse(inv)) vm->ValueError("matrix is not invertible"); if(!self.inverse(inv)) {
vm->ValueError("matrix is not invertible");
}
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");
@ -561,62 +610,64 @@ 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() {}
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(float _11, float _12, float _13, float _21, float _22, float _23, float _31, float _32, float _33) :
return Mat3x3(0, 0, 0, 0, 0, 0, 0, 0, 0); _11(_11), _12(_12), _13(_13), _21(_21), _22(_22), _23(_23), _31(_31), _32(_32), _33(_33) {}
}
Mat3x3 Mat3x3::ones(){ Mat3x3 Mat3x3::zeros() { return Mat3x3(0, 0, 0, 0, 0, 0, 0, 0, 0); }
return Mat3x3(1, 1, 1, 1, 1, 1, 1, 1, 1);
}
Mat3x3 Mat3x3::identity(){ Mat3x3 Mat3x3::ones() { return Mat3x3(1, 1, 1, 1, 1, 1, 1, 1, 1); }
return Mat3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
} Mat3x3 Mat3x3::identity() { return Mat3x3(1, 0, 0, 0, 1, 0, 0, 0, 1); }
Mat3x3 Mat3x3::operator+ (const Mat3x3& other) const { Mat3x3 Mat3x3::operator+ (const Mat3x3& other) const {
Mat3x3 ret; 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;
} }
@ -644,21 +695,28 @@ void add_module_linalg(VM* vm){
} }
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;
@ -675,24 +733,21 @@ void add_module_linalg(VM* vm){
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); } float Mat3x3::_r() const { return atan2f(_21, _11); }
Vec2 Mat3x3::_s() const {
return Vec2( Vec2 Mat3x3::_s() const { return Vec2(sqrtf(_11 * _11 + _21 * _21), sqrtf(_12 * _12 + _22 * _22)); }
sqrtf(_11 * _11 + _21 * _21),
sqrtf(_12 * _12 + _22 * _22)
);
}
} // namespace pkpy } // namespace pkpy

View File

@ -62,7 +62,9 @@ void add_module_time(VM* vm){
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;
}
} }
return vm->None; return vm->None;
}); });
@ -111,9 +113,7 @@ void add_module_json(VM* vm){
return vm->_exec(code, vm->callstack.top()._module); return vm->_exec(code, vm->callstack.top()._module);
}); });
vm->bind_func(mod, "dumps", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "dumps", 1, [](VM* vm, ArgsView args) { return VAR(vm->py_json(args[0])); });
return VAR(vm->py_json(args[0]));
});
} }
// https://docs.python.org/3.5/library/math.html // https://docs.python.org/3.5/library/math.html
@ -143,8 +143,12 @@ void add_module_math(VM* vm){
vm->bind_func(mod, "gcd", 2, [](VM* vm, ArgsView args) { vm->bind_func(mod, "gcd", 2, [](VM* vm, ArgsView args) {
i64 a = CAST(i64, args[0]); i64 a = CAST(i64, args[0]);
i64 b = CAST(i64, args[1]); i64 b = CAST(i64, args[1]);
if(a < 0) a = -a; if(a < 0) {
if(b < 0) b = -b; a = -a;
}
if(b < 0) {
b = -b;
}
while(b != 0) { while(b != 0) {
i64 t = b; i64 t = b;
b = a % b; b = a % b;
@ -197,9 +201,13 @@ void add_module_math(VM* vm){
vm->bind_func(mod, "factorial", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "factorial", 1, [](VM* vm, ArgsView args) {
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);
}); });
} }
@ -207,14 +215,18 @@ void add_module_math(VM* vm){
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");
}
Exception& e = vm->__last_exception->as<Exception>(); Exception& e = vm->__last_exception->as<Exception>();
vm->stdout_write(e.summary()); vm->stdout_write(e.summary());
return vm->None; return vm->None;
}); });
vm->bind_func(mod, "format_exc", 0, [](VM* vm, ArgsView args) { vm->bind_func(mod, "format_exc", 0, [](VM* vm, ArgsView args) {
if(vm->__last_exception == nullptr) vm->ValueError("no exception"); if(vm->__last_exception == nullptr) {
vm->ValueError("no exception");
}
Exception& e = vm->__last_exception->as<Exception>(); Exception& e = vm->__last_exception->as<Exception>();
return VAR(e.summary()); return VAR(e.summary());
}); });
@ -231,7 +243,9 @@ void add_module_dis(VM* vm){
code = vm->compile(source, "<dis>", EXEC_MODE); code = vm->compile(source, "<dis>", EXEC_MODE);
} }
PyVar f = obj; PyVar f = obj;
if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, obj).func; if(is_type(f, vm->tp_bound_method)) {
f = CAST(BoundMethod, obj).func;
}
code = CAST(Function&, f).decl->code; code = CAST(Function&, f).decl->code;
vm->stdout_write(vm->disassemble(code)); vm->stdout_write(vm->disassemble(code));
return vm->None; return vm->None;
@ -248,14 +262,15 @@ void add_module_enum(VM* vm){
CodeObject_ code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE); CodeObject_ code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE);
vm->_exec(code, mod); vm->_exec(code, mod);
PyVar Enum = mod->attr("Enum"); PyVar Enum = mod->attr("Enum");
vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = \ vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = [](VM* vm, PyTypeInfo* new_ti) {
[](VM* vm, PyTypeInfo* new_ti){
new_ti->subclass_enabled = false; // Enum class cannot be subclassed twice new_ti->subclass_enabled = false; // Enum class cannot be subclassed twice
NameDict& attr = new_ti->obj->attr(); NameDict& attr = new_ti->obj->attr();
for(auto [k, v]: attr.items()) { for(auto [k, v]: attr.items()) {
// wrap every attribute // wrap every attribute
std::string_view k_sv = k.sv(); std::string_view k_sv = k.sv();
if(k_sv.empty() || k_sv[0] == '_') continue; if(k_sv.empty() || k_sv[0] == '_') {
continue;
}
attr.set(k, vm->call(new_ti->obj, VAR(k_sv), v)); attr.set(k, vm->call(new_ti->obj, VAR(k_sv), v));
} }
}; };
@ -264,23 +279,25 @@ 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)) {
if(self->is_attr_valid()) vm->RuntimeError("object: instance dict is already enabled"); vm->TypeError("object: tagged object cannot enable instance dict");
}
if(self->is_attr_valid()) {
vm->RuntimeError("object: instance dict is already enabled");
}
self->_attr = new NameDict(); self->_attr = new NameDict();
return vm->None; return vm->None;
}); });
} }
/************************************************/ /************************************************/
#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;
@ -313,7 +330,9 @@ struct LineProfilerW{
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;
@ -327,7 +346,6 @@ 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) { if(vm->_profiler) {
vm->ValueError("only one profiler can be enabled at a time"); vm->ValueError("only one profiler can be enabled at a time");
@ -346,9 +364,7 @@ void add_module_line_profiler(VM *vm){
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

@ -37,8 +37,8 @@ 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 */
@ -47,12 +47,10 @@ struct mt19937{
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] = mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + 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,8 +61,7 @@ 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 */
@ -72,8 +69,9 @@ struct mt19937{
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);
@ -100,15 +98,10 @@ 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) {
@ -120,12 +113,9 @@ struct mt19937{
} }
} }
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 {
@ -152,7 +142,9 @@ 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,7 +157,9 @@ 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));
}); });
@ -182,7 +176,9 @@ struct Random{
vm->bind_func(type, "choice", 2, [](VM* vm, ArgsView args) { vm->bind_func(type, "choice", 2, [](VM* vm, ArgsView args) {
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];
}); });
@ -192,19 +188,27 @@ struct Random{
ArgsView view = vm->cast_array_view(args[1]); ArgsView view = vm->cast_array_view(args[1]);
PyVar* data = view.begin(); PyVar* data = view.begin();
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++) {
cum_weights[i] = i + 1;
}
} else { } 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++) {

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

@ -2,9 +2,9 @@
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();
} }
@ -43,8 +43,11 @@ namespace pkpy{
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) {
bool ok; int i; _rehash(vm);
}
bool ok;
int i;
_probe_1(vm, key, ok, i); _probe_1(vm, key, ok, i);
if(!ok) { if(!ok) {
_size++; _size++;
@ -86,26 +89,33 @@ namespace pkpy{
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; int i; bool ok;
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) {
@ -169,6 +179,8 @@ namespace pkpy{
} }
Dict::~Dict() { Dict::~Dict() {
if(_items) std::free(_items); if(_items) {
std::free(_items);
}
} }
} // namespace pkpy } // namespace pkpy

View File

@ -3,7 +3,9 @@
namespace pkpy { namespace pkpy {
Str Exception::summary() const { Str Exception::summary() const {
SStream ss; SStream ss;
if(is_re) ss << "Traceback (most recent call last):\n"; if(is_re) {
ss << "Traceback (most recent call last):\n";
}
// while(!st.empty()) { // while(!st.empty()) {
// ss << st.top().snapshot() << '\n'; // ss << st.top().snapshot() << '\n';
// st.pop(); // st.pop();
@ -12,8 +14,11 @@ namespace pkpy{
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();
} }

View File

@ -1,14 +1,19 @@
#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();
@ -25,26 +30,36 @@ namespace pkpy{
} }
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);
@ -53,12 +68,16 @@ namespace pkpy{
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();

View File

@ -15,7 +15,9 @@ 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++) {
_args[i] = other._args[i];
}
} else { } else {
_args = other._args; _args = other._args;
other._args = other._inlined; other._args = other._inlined;
@ -34,17 +36,25 @@ Tuple::Tuple(PyVar _0, PyVar _1, PyVar _2): Tuple(3){
_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

@ -37,14 +37,17 @@ static PyVar stack_item(VM* vm, int index){
begin = vm->__c.s_view.top().begin(); begin = vm->__c.s_view.top().begin();
} }
int size = end - begin; int size = end - begin;
if(index < 0) index += size; if(index < 0) {
index += size;
}
assert(index >= 0 && index < size); assert(index >= 0 && index < size);
return begin[index]; return begin[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) { \
@ -53,13 +56,9 @@ static PyVar stack_item(VM* vm, int index){
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;
@ -78,8 +77,7 @@ bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, i
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
} }
@ -142,7 +140,9 @@ int pkpy_stack_size(pkpy_vm* vm_handle){
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();
} }
@ -322,7 +322,9 @@ struct TempViewPopper{
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;
} }
@ -348,8 +350,12 @@ static PyVar c_function_wrapper(VM* vm, ArgsView args) {
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) {
if (retc == 1) return vm->s_data.popx(); return vm->None;
}
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());
} }
@ -383,7 +389,9 @@ bool pkpy_getattr(pkpy_vm* vm_handle, pkpy_CName name) {
PK_ASSERT_N_EXTRA_ELEMENTS(1) PK_ASSERT_N_EXTRA_ELEMENTS(1)
PyVar o = vm->s_data.top(); PyVar o = vm->s_data.top();
o = vm->getattr(o, StrName(name), false); o = vm->getattr(o, StrName(name), false);
if(o == nullptr) return false; if(o == nullptr) {
return false;
}
vm->s_data.top() = o; vm->s_data.top() = o;
return true; return true;
} }
@ -408,7 +416,9 @@ bool pkpy_getglobal(pkpy_vm* vm_handle, pkpy_CName name) {
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;
@ -442,7 +452,8 @@ bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) {
PyVar _0 = vm->py_iter(vm->s_data.popx()); PyVar _0 = vm->py_iter(vm->s_data.popx());
for(int i=0; i<n; i++){ for(int i=0; i<n; i++){
PyVar _1 = vm->py_next(_0); PyVar _1 = vm->py_next(_0);
if(_1 == vm->StopIteration) vm->ValueError("not enough values to unpack"); if(_1 == vm->StopIteration){ vm->ValueError("not enough values to unpack");
}
vm->s_data.push(_1); vm->s_data.push(_1);
} }
if(vm->py_next(_0) != vm->StopIteration) vm->ValueError("too many values to unpack"); if(vm->py_next(_0) != vm->StopIteration) vm->ValueError("too many values to unpack");
@ -508,7 +519,8 @@ bool pkpy_error(pkpy_vm* vm_handle, const char* name, pkpy_CString message) {
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();
@ -523,17 +535,22 @@ bool pkpy_check_error(pkpy_vm* vm_handle) {
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());
} }
return true; return true;
@ -550,18 +567,13 @@ 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;
@ -573,16 +585,10 @@ void pkpy_set_import_handler(pkpy_vm* vm_handle, pkpy_CImportHandler handler){
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

@ -20,7 +20,9 @@ namespace pkpy {
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;
}
} }
need_more_lines = 0; need_more_lines = 0;
line = buffer; line = buffer;
@ -37,9 +39,11 @@ namespace pkpy {
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

@ -20,18 +20,19 @@ std::string pkpy_platform_getline(bool* eof) {
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') {
if (!output.empty() && output.back() == '\r') output.pop_back(); output.pop_back();
}
return output; return output;
} }
@ -40,7 +41,9 @@ 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;
} }
@ -51,7 +54,9 @@ 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;
@ -78,7 +83,9 @@ int main(int argc, char** argv) {
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);
@ -87,7 +94,9 @@ int main(int argc, char** argv) {
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);
@ -100,15 +109,15 @@ int main(int argc, char** argv) {
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) {
if (!ok) pkpy_clear_error(vm, NULL); pkpy_clear_error(vm, NULL);
}
pkpy_delete_vm(vm); pkpy_delete_vm(vm);
return ok ? 0 : 1; return ok ? 0 : 1;
} }