Format the world. (#259)

* add some clang-format offs.

* add formats.

* format the world.

* AllowShortIfStatementsOnASingleLine

* off REGION.

* Rollback vm.hpp

* Disable insert.
This commit is contained in:
ykiko 2024-06-04 22:55:17 +08:00 committed by GitHub
parent 0b404a51cb
commit 1c82060daf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
93 changed files with 10429 additions and 9836 deletions

View File

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

View File

@ -11,7 +11,7 @@
namespace pkpy {
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 vtable {
@ -25,7 +25,9 @@ struct any{
static vtable vt{typeid(T), nullptr};
return &vt;
} else {
static vtable vt{ typeid(T), [](void* ptr){ delete static_cast<T*>(ptr); } };
static vtable vt{typeid(T), [](void* ptr) {
delete static_cast<T*>(ptr);
}};
return &vt;
}
}
@ -54,14 +56,14 @@ struct any{
any(any&& other) noexcept;
any& operator= (any&& other) noexcept;
const std::type_index type_id() const{
return _vt ? _vt->type : typeid(void);
}
const std::type_index type_id() const { return _vt ? _vt->type : typeid(void); }
any(const any& other) = delete;
any& operator= (const any& other) = delete;
~any() { if(_vt && _vt->deleter) _vt->deleter(data); }
~any() {
if(_vt && _vt->deleter) _vt->deleter(data);
}
template <typename T>
T& _cast() const noexcept {

View File

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

View File

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

View File

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

View File

@ -8,8 +8,8 @@
namespace pkpy {
inline const int kPoolExprBlockSize = 128;
inline const int kPoolFrameBlockSize = 80;
const inline int kPoolExprBlockSize = 128;
const inline int kPoolFrameBlockSize = 80;
void* PoolExpr_alloc() noexcept;
void PoolExpr_dealloc(void*) noexcept;

View File

@ -10,8 +10,10 @@ namespace pkpy{
template <typename T>
constexpr T default_invalid_value() {
if constexpr(std::is_same_v<int, T>) return -1;
else return nullptr;
if constexpr(std::is_same_v<int, T>)
return -1;
else
return nullptr;
}
template <typename T>
@ -19,7 +21,7 @@ struct NameDictImpl {
PK_ALWAYS_PASS_BY_POINTER(NameDictImpl)
using Item = std::pair<StrName, T>;
static constexpr uint16_t kInitialCapacity = 16;
constexpr static uint16_t kInitialCapacity = 16;
static_assert(is_pod_v<T>);
float _load_factor;
@ -35,7 +37,10 @@ struct NameDictImpl {
ok = false; \
i = key.index & _mask; \
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; \
}
@ -48,6 +53,7 @@ while(!_items[i].first.empty()) { \
~NameDictImpl() { std::free(_items); }
uint16_t size() const { return _size; }
uint16_t capacity() const { return _capacity; }
void _set_capacity_and_alloc_items(uint16_t val) {
@ -60,7 +66,8 @@ while(!_items[i].first.empty()) { \
}
void set(StrName key, T val) {
bool ok; uint16_t i;
bool ok;
uint16_t i;
HASH_PROBE_1(key, ok, i);
if(!ok) {
_size++;
@ -79,7 +86,8 @@ while(!_items[i].first.empty()) { \
_set_capacity_and_alloc_items(_capacity * 2);
for(uint16_t i = 0; i < old_capacity; i++) {
if(old_items[i].first.empty()) continue;
bool ok; uint16_t j;
bool ok;
uint16_t j;
HASH_PROBE_1(old_items[i].first, ok, j);
assert(!ok);
_items[j] = old_items[i];
@ -88,14 +96,16 @@ while(!_items[i].first.empty()) { \
}
T try_get(StrName key) const {
bool ok; uint16_t i;
bool ok;
uint16_t i;
HASH_PROBE_0(key, ok, i);
if(!ok) return default_invalid_value<T>();
return _items[i].second;
}
T* try_get_2(StrName key) const {
bool ok; uint16_t i;
bool ok;
uint16_t i;
HASH_PROBE_0(key, ok, i);
if(!ok) return nullptr;
return &_items[i].second;
@ -118,7 +128,8 @@ while(!_items[i].first.empty()) { \
}
bool del(StrName key) {
bool ok; uint16_t i;
bool ok;
uint16_t i;
HASH_PROBE_0(key, ok, i);
if(!ok) return false;
_items[i].first = StrName();
@ -146,16 +157,15 @@ while(!_items[i].first.empty()) { \
}
bool contains(StrName key) const {
bool ok; uint16_t i;
bool ok;
uint16_t i;
HASH_PROBE_0(key, ok, i);
return ok;
}
T operator[] (StrName key) const {
T* val = try_get_2_likely_found(key);
if(val == nullptr){
throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str());
}
if(val == nullptr) { throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str()); }
return *val;
}
@ -185,6 +195,7 @@ while(!_items[i].first.empty()) { \
}
_size = 0;
}
#undef HASH_PROBE_0
#undef HASH_PROBE_1
};

View File

@ -33,10 +33,15 @@ struct Str{
operator std::string_view () const { return sv(); }
const char* begin() const { return data; }
const char* end() const { return data + size; }
char operator[] (int idx) const { return data[idx]; }
int length() const { return size; }
bool empty() const { return size == 0; }
size_t hash() const { return std::hash<std::string_view>()(sv()); }
Str& operator= (const Str&);
@ -64,15 +69,20 @@ struct Str{
friend std::ostream& operator<< (std::ostream& os, const Str& str);
const char* c_str() const { return data; }
std::string_view sv() const { return std::string_view(data, size); }
std::string str() const { return std::string(data, size); }
Str substr(int start, int len) const;
Str substr(int start) const;
Str strip(bool left, bool right, const Str& chars) const;
Str strip(bool left = true, bool right = true) const;
Str lstrip() const { return strip(true, false); }
Str rstrip() const { return strip(false, true); }
Str lower() const;
Str upper() const;
Str escape(bool single_quote = true) const;
@ -96,31 +106,28 @@ struct StrName {
uint16_t index;
StrName() : index(0) {}
explicit StrName(uint16_t index) : index(index) {}
StrName(const char* s) : index(get(s).index) {}
StrName(const Str& s) : index(get(s.sv()).index) {}
std::string_view sv() const { return _r_interned()[index]; }
const char* c_str() const { return _r_interned()[index].c_str(); }
bool empty() const { return index == 0; }
Str escape() const { return Str(sv()).escape(); }
bool operator==(const StrName& other) const noexcept {
return this->index == other.index;
}
bool operator== (const StrName& other) const noexcept { return this->index == other.index; }
bool operator!=(const StrName& other) const noexcept {
return this->index != other.index;
}
bool operator!= (const StrName& other) const noexcept { return this->index != other.index; }
bool operator<(const StrName& other) const noexcept {
return sv() < other.sv();
}
bool operator< (const StrName& other) const noexcept { return sv() < other.sv(); }
bool operator>(const StrName& other) const noexcept {
return sv() > other.sv();
}
bool operator> (const StrName& other) const noexcept { return sv() > other.sv(); }
static StrName get(std::string_view s);
static std::map<std::string_view, uint16_t>& _interned();
@ -135,9 +142,11 @@ struct SStream{
int _precision = -1;
bool empty() const { return buffer.empty(); }
void setprecision(int precision) { _precision = precision; }
SStream() {}
SStream(int guess_size) { buffer.reserve(guess_size); }
Str str();
@ -171,7 +180,9 @@ Str _S(Args&&... args) {
struct CString {
const char* ptr;
CString(const char* ptr) : ptr(ptr) {}
operator const char* () const { return ptr; }
};

View File

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

View File

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

View File

@ -13,9 +13,9 @@
namespace pkpy {
// global constants
inline const char* PK_HEX_TABLE = "0123456789abcdef";
const inline char* PK_HEX_TABLE = "0123456789abcdef";
inline const char* kPlatformStrings[] = {
const inline char* kPlatformStrings[] = {
"win32", // 0
"emscripten", // 1
"ios", // 2

View File

@ -18,17 +18,23 @@ struct array {
using size_type = int;
array() : _data(nullptr), _size(0) {}
array(int size) : _data((T*)std::malloc(sizeof(T) * size)), _size(size) {}
array(array&& other) noexcept : _data(other._data), _size(other._size) {
other._data = nullptr;
other._size = 0;
}
array(const array& other) = delete;
array(explicit_copy_t, const array& other) {
_data = (T*)std::malloc(sizeof(T) * other._size);
_size = other._size;
for (int i = 0; i < _size; i++) _data[i] = other._data[i];
for(int i = 0; i < _size; i++)
_data[i] = other._data[i];
}
array(T* data, int size) : _data(data), _size(size) {}
array& operator= (array&& other) noexcept {
@ -58,7 +64,9 @@ struct array {
int size() const { return _size; }
T* begin() const { return _data; }
T* end() const { return _data + _size; }
T* data() const { return _data; }
std::pair<T*, int> detach() noexcept {
@ -85,22 +93,21 @@ struct vector {
using size_type = int;
vector() : _data(nullptr), _capacity(0), _size(0) {}
vector(int size)
: _data((T*)std::malloc(sizeof(T) * size)),
_capacity(size),
_size(size) {}
vector(vector&& other) noexcept
: _data(other._data), _capacity(other._capacity), _size(other._size) {
vector(int size) : _data((T*)std::malloc(sizeof(T) * size)), _capacity(size), _size(size) {}
vector(vector&& other) noexcept : _data(other._data), _capacity(other._capacity), _size(other._size) {
other._data = nullptr;
other._capacity = 0;
other._size = 0;
}
vector(const vector& other) = delete;
vector(explicit_copy_t, const vector& other)
: _data((T*)std::malloc(sizeof(T) * other._size)),
_capacity(other._size),
_size(other._size) {
for (int i = 0; i < _size; i++) _data[i] = other._data[i];
vector(explicit_copy_t, const vector& other) :
_data((T*)std::malloc(sizeof(T) * other._size)), _capacity(other._size), _size(other._size) {
for(int i = 0; i < _size; i++)
_data[i] = other._data[i];
}
// allow move
@ -112,16 +119,22 @@ struct vector {
new (this) vector(std::move(other));
return *this;
}
// disallow copy
vector& operator= (const vector& other) = delete;
bool empty() const { return _size == 0; }
int size() const { return _size; }
int capacity() const { return _capacity; }
T& back() { return _data[_size - 1]; }
T* begin() const { return _data; }
T* end() const { return _data + _size; }
T* data() const { return _data; }
void reserve(int cap) {
@ -170,17 +183,20 @@ struct vector {
}
T& operator[] (int i) { return _data[i]; }
const T& operator[] (int i) const { return _data[i]; }
void extend(T* begin, T* end) {
int n = end - begin;
reserve(_size + n);
for (int i = 0; i < n; i++) new (&_data[_size++]) T(begin[i]);
for(int i = 0; i < n; i++)
new (&_data[_size++]) T(begin[i]);
}
void insert(int index, const T& t) {
if(_size == _capacity) reserve(_capacity * 2);
for (int i = _size; i > index; i--) _data[i] = std::move(_data[i - 1]);
for(int i = _size; i > index; i--)
_data[i] = std::move(_data[i - 1]);
_data[index] = t;
_size++;
}
@ -194,9 +210,7 @@ struct vector {
void pop_back() {
assert(_size > 0);
_size--;
if constexpr (!std::is_trivially_destructible_v<T>) {
_data[_size].~T();
}
if constexpr(!std::is_trivially_destructible_v<T>) { _data[_size].~T(); }
}
void clear() {
@ -232,24 +246,36 @@ class stack {
public:
void push(const T& t) { vec.push_back(t); }
void push(T&& t) { vec.push_back(std::move(t)); }
template <typename... Args>
void emplace(Args&&... args) {
vec.emplace_back(std::forward<Args>(args)...);
}
void pop() { vec.pop_back(); }
void clear() { vec.clear(); }
bool empty() const { return vec.empty(); }
typename Container::size_type size() const { return vec.size(); }
T& top() { return vec.back(); }
const T& top() const { return vec.back(); }
T popx() {
T t = std::move(vec.back());
vec.pop_back();
return t;
}
void reserve(int n) { vec.reserve(n); }
Container& container() { return vec; }
const Container& container() const { return vec; }
};
@ -286,33 +312,45 @@ class small_vector {
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
[[nodiscard]] bool is_small() const {
return m_begin == reinterpret_cast<const T*>(m_buffer);
}
[[nodiscard]] bool is_small() const { return m_begin == reinterpret_cast<const T*>(m_buffer); }
[[nodiscard]] size_type size() const { return m_end - m_begin; }
[[nodiscard]] size_type capacity() const { return m_max - m_begin; }
[[nodiscard]] bool empty() const { return m_begin == m_end; }
pointer data() { return m_begin; }
const_pointer data() const { return m_begin; }
reference operator[] (size_type index) { return m_begin[index]; }
const_reference operator[] (size_type index) const { return m_begin[index]; }
iterator begin() { return m_begin; }
const_iterator begin() const { return m_begin; }
iterator end() { return m_end; }
const_iterator end() const { return m_end; }
reference front() { return *begin(); }
const_reference front() const { return *begin(); }
reference back() { return *(end() - 1); }
const_reference back() const { return *(end() - 1); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
private:
static void uninitialized_copy_n(const void* src, size_type n, void* dest) {
@ -337,16 +375,12 @@ class small_vector {
}
public:
small_vector()
: m_begin(reinterpret_cast<T*>(m_buffer)),
m_end(m_begin),
m_max(m_begin + N) {}
small_vector() : m_begin(reinterpret_cast<T*>(m_buffer)), m_end(m_begin), m_max(m_begin + N) {}
small_vector(const small_vector& other) noexcept {
const auto size = other.size();
const auto capacity = other.capacity();
m_begin = reinterpret_cast<T*>(
other.is_small() ? m_buffer : std::malloc(sizeof(T) * capacity));
m_begin = reinterpret_cast<T*>(other.is_small() ? m_buffer : std::malloc(sizeof(T) * capacity));
uninitialized_copy_n(other.m_begin, size, this->m_begin);
m_end = m_begin + size;
m_max = m_begin + capacity;
@ -396,11 +430,9 @@ class small_vector {
const auto size = this->size();
if(!is_small()) {
if constexpr(is_trivially_relocatable_v<T>) {
m_begin = (pointer)std::realloc(m_begin,
sizeof(T) * new_capacity);
m_begin = (pointer)std::realloc(m_begin, sizeof(T) * new_capacity);
} else {
auto new_data =
(pointer)std::malloc(sizeof(T) * new_capacity);
auto new_data = (pointer)std::malloc(sizeof(T) * new_capacity);
uninitialized_relocate_n(m_begin, size, new_data);
std::free(m_begin);
m_begin = new_data;
@ -418,13 +450,12 @@ class small_vector {
}
void push_back(const T& value) { emplace_back(value); }
void push_back(T&& value) { emplace_back(std::move(value)); }
void pop_back() {
m_end--;
if constexpr (!std::is_trivially_destructible_v<T>) {
m_end->~T();
}
if constexpr(!std::is_trivially_destructible_v<T>) { m_end->~T(); }
}
void clear() {

View File

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

View File

@ -27,16 +27,22 @@ class Compiler {
vector<Token> tokens;
const Token& prev() const { return tokens[i - 1]; }
const Token& curr() const { return tokens[i]; }
const Token& next() const { return tokens[i + 1]; }
const Token& err() const {
if(i >= tokens.size()) return prev();
return curr();
}
void advance(int delta = 1) { i += delta; }
CodeEmitContext* ctx() { return &contexts.top(); }
CompileMode mode() const { return lexer.src->mode; }
NameScope name_scope() const;
CodeObject_ push_global_context();
FuncDecl_ push_f_context(Str name);
@ -114,7 +120,9 @@ class Compiler {
PyVar read_literal();
void SyntaxError(Str msg) { lexer.throw_err("SyntaxError", msg, err().line, err().start); }
void SyntaxError() { lexer.throw_err("SyntaxError", "invalid syntax", err().line, err().start); }
void IndentationError(Str msg) { lexer.throw_err("IndentationError", msg, err().line, err().start); }
public:
@ -129,8 +137,16 @@ struct TokenDeserializer{
const char* source;
TokenDeserializer(const char* source) : curr(source), source(source) {}
char read_char() { return *curr++; }
bool match_char(char c){ if(*curr == c) { curr++; return true; } return false; }
bool match_char(char c) {
if(*curr == c) {
curr++;
return true;
}
return false;
}
std::string_view read_string(char c);
Str read_string_from_hex(char c);

View File

@ -11,20 +11,35 @@ struct Expr;
template <typename T>
class unique_ptr_128 {
T* ptr;
public:
unique_ptr_128() : ptr(nullptr) {}
unique_ptr_128(T* ptr) : ptr(ptr) {}
T* operator->() const { return ptr; }
T* get() const { return ptr; }
T* detach() { T* p = ptr; ptr = nullptr; return p; }
T* detach() {
T* p = ptr;
ptr = nullptr;
return p;
}
unique_ptr_128(const unique_ptr_128&) = delete;
unique_ptr_128& operator= (const unique_ptr_128&) = delete;
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>
unique_ptr_128(unique_ptr_128<U>&& other) : ptr(other.detach()) {}
@ -33,13 +48,19 @@ public:
template <typename U>
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();
return *this;
}
unique_ptr_128& operator= (std::nullptr_t) {
if(ptr) { ptr->~T(); PoolExpr_dealloc(ptr); }
if(ptr) {
ptr->~T();
PoolExpr_dealloc(ptr);
}
ptr = nullptr;
return *this;
}
@ -55,33 +76,34 @@ struct Expr{
int line = 0;
virtual ~Expr() = default;
virtual void emit_(CodeEmitContext* ctx) = 0;
virtual bool is_literal() const { return false; }
virtual bool is_json_object() const { return false; }
virtual bool is_attrib() const { return false; }
virtual bool is_subscr() const { return false; }
virtual bool is_compare() const { return false; }
virtual int star_level() const { return 0; }
virtual bool is_tuple() const { return false; }
virtual bool is_name() const { return false; }
bool is_starred() const { return star_level() > 0; }
// for OP_DELETE_XXX
[[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) {
return false;
}
[[nodiscard]] virtual bool emit_del(CodeEmitContext* ctx) { return false; }
// for OP_STORE_XXX
[[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) {
return false;
}
[[nodiscard]] virtual bool emit_store(CodeEmitContext* ctx) { return false; }
virtual void emit_inplace(CodeEmitContext* ctx) {
emit_(ctx);
}
virtual void emit_inplace(CodeEmitContext* ctx) { emit_(ctx); }
[[nodiscard]] virtual bool emit_store_inplace(CodeEmitContext* ctx) {
return emit_store(ctx);
}
[[nodiscard]] virtual bool emit_store_inplace(CodeEmitContext* ctx) { return emit_store(ctx); }
};
struct CodeEmitContext {
@ -93,6 +115,7 @@ struct CodeEmitContext{
stack_no_copy<Expr_> s_expr;
int level;
vector<Str> global_names;
CodeEmitContext(VM* vm, CodeObject_ co, int level) : vm(vm), co(co), level(level) {}
int curr_iblock = 0;
@ -121,31 +144,41 @@ struct CodeEmitContext{
struct NameExpr : Expr {
StrName name;
NameScope scope;
NameExpr(StrName name, NameScope scope) : name(name), scope(scope) {}
void emit_(CodeEmitContext* ctx) override;
bool emit_del(CodeEmitContext* ctx) override;
bool emit_store(CodeEmitContext* ctx) override;
bool is_name() const override { return true; }
};
struct InvertExpr : Expr {
Expr_ child;
InvertExpr(Expr_&& child) : child(std::move(child)) {}
void emit_(CodeEmitContext* ctx) override;
};
struct StarredExpr : Expr {
int level;
Expr_ child;
StarredExpr(int level, Expr_&& child) : level(level), child(std::move(child)) {}
int star_level() const override { return level; }
void emit_(CodeEmitContext* ctx) override;
bool emit_store(CodeEmitContext* ctx) override;
};
struct NotExpr : Expr {
Expr_ child;
NotExpr(Expr_&& child) : child(std::move(child)) {}
void emit_(CodeEmitContext* ctx) override;
};
@ -164,7 +197,9 @@ struct OrExpr: Expr{
// [None, True, False, ...]
struct Literal0Expr : Expr {
TokenIndex token;
Literal0Expr(TokenIndex token) : token(token) {}
bool is_json_object() const override { return true; }
void emit_(CodeEmitContext* ctx) override;
@ -172,35 +207,48 @@ struct Literal0Expr: Expr{
struct LongExpr : Expr {
Str s;
LongExpr(const Str& s) : s(s) {}
void emit_(CodeEmitContext* ctx) override;
};
struct BytesExpr : Expr {
Str s;
BytesExpr(const Str& s) : s(s) {}
void emit_(CodeEmitContext* ctx) override;
};
struct ImagExpr : Expr {
f64 value;
ImagExpr(f64 value) : value(value) {}
void emit_(CodeEmitContext* ctx) override;
};
// @num, @str which needs to invoke OP_LOAD_CONST
struct LiteralExpr : Expr {
TokenValue value;
LiteralExpr(TokenValue value) : value(value) {}
void emit_(CodeEmitContext* ctx) override;
bool is_literal() const override { return true; }
bool is_json_object() const override { return true; }
};
struct NegatedExpr : Expr {
Expr_ child;
NegatedExpr(Expr_&& child) : child(std::move(child)) {}
void emit_(CodeEmitContext* ctx) override;
bool is_json_object() const override { return child->is_literal(); }
};
@ -214,25 +262,32 @@ struct SliceExpr: Expr{
struct DictItemExpr : Expr {
Expr_ key; // maybe nullptr if it is **kwargs
Expr_ value;
int star_level() const override { return value->star_level(); }
void emit_(CodeEmitContext* ctx) override;
};
struct SequenceExpr : Expr {
Expr_vector items;
SequenceExpr(Expr_vector&& items) : items(std::move(items)) {}
virtual Opcode opcode() const = 0;
void emit_(CodeEmitContext* ctx) override {
for(auto& item: items) item->emit_(ctx);
for(auto& item: items)
item->emit_(ctx);
ctx->emit_(opcode(), items.size(), line);
}
};
struct ListExpr : SequenceExpr {
using SequenceExpr::SequenceExpr;
Opcode opcode() const override {
for(auto& e: items) if(e->is_starred()) return OP_BUILD_LIST_UNPACK;
for(auto& e: items)
if(e->is_starred()) return OP_BUILD_LIST_UNPACK;
return OP_BUILD_LIST;
}
@ -241,8 +296,10 @@ struct ListExpr: SequenceExpr{
struct DictExpr : SequenceExpr {
using SequenceExpr::SequenceExpr;
Opcode opcode() const override {
for(auto& e: items) if(e->is_starred()) return OP_BUILD_DICT_UNPACK;
for(auto& e: items)
if(e->is_starred()) return OP_BUILD_DICT_UNPACK;
return OP_BUILD_DICT;
}
@ -251,17 +308,22 @@ struct DictExpr: SequenceExpr{
struct SetExpr : SequenceExpr {
using SequenceExpr::SequenceExpr;
Opcode opcode() const override {
for(auto& e: items) if(e->is_starred()) return OP_BUILD_SET_UNPACK;
for(auto& e: items)
if(e->is_starred()) return OP_BUILD_SET_UNPACK;
return OP_BUILD_SET;
}
};
struct TupleExpr : SequenceExpr {
using SequenceExpr::SequenceExpr;
bool is_tuple() const override { return true; }
Opcode opcode() const override {
for(auto& e: items) if(e->is_starred()) return OP_BUILD_TUPLE_UNPACK;
for(auto& e: items)
if(e->is_starred()) return OP_BUILD_TUPLE_UNPACK;
return OP_BUILD_TUPLE;
}
@ -283,16 +345,19 @@ struct CompExpr: Expr{
struct ListCompExpr : CompExpr {
Opcode op0() override { return OP_BUILD_LIST; }
Opcode op1() override { return OP_LIST_APPEND; }
};
struct DictCompExpr : CompExpr {
Opcode op0() override { return OP_BUILD_DICT; }
Opcode op1() override { return OP_DICT_ADD; }
};
struct SetCompExpr : CompExpr {
Opcode op0() override { return OP_BUILD_SET; }
Opcode op1() override { return OP_SET_ADD; }
};
@ -309,7 +374,9 @@ struct LambdaExpr: Expr{
struct FStringExpr : Expr {
Str src;
FStringExpr(const Str& src) : src(src) {}
void _load_simple_expr(CodeEmitContext* ctx, Str expr);
void emit_(CodeEmitContext* ctx) override;
};
@ -317,7 +384,9 @@ struct FStringExpr: Expr{
struct SubscrExpr : Expr {
Expr_ a;
Expr_ b;
bool is_subscr() const override { return true; }
void emit_(CodeEmitContext* ctx) override;
bool emit_del(CodeEmitContext* ctx) override;
bool emit_store(CodeEmitContext* ctx) override;
@ -329,6 +398,7 @@ struct SubscrExpr: Expr{
struct AttribExpr : Expr {
Expr_ a;
StrName b;
AttribExpr(Expr_ a, StrName b) : a(std::move(a)), b(b) {}
void emit_(CodeEmitContext* ctx) override;
@ -337,6 +407,7 @@ struct AttribExpr: Expr{
void emit_method(CodeEmitContext* ctx);
bool is_attrib() const override { return true; }
void emit_inplace(CodeEmitContext* ctx) override;
bool emit_store_inplace(CodeEmitContext* ctx) override;
};
@ -351,19 +422,14 @@ struct CallExpr: Expr{
struct GroupedExpr : Expr {
Expr_ a;
GroupedExpr(Expr_&& a) : a(std::move(a)) {}
void emit_(CodeEmitContext* ctx) override{
a->emit_(ctx);
}
void emit_(CodeEmitContext* ctx) override { a->emit_(ctx); }
bool emit_del(CodeEmitContext* ctx) override {
return a->emit_del(ctx);
}
bool emit_del(CodeEmitContext* ctx) override { return a->emit_del(ctx); }
bool emit_store(CodeEmitContext* ctx) override {
return a->emit_store(ctx);
}
bool emit_store(CodeEmitContext* ctx) override { return a->emit_store(ctx); }
};
struct BinaryExpr : Expr {
@ -373,12 +439,12 @@ struct BinaryExpr: Expr{
bool inplace;
BinaryExpr(bool inplace = false) : inplace(inplace) {}
bool is_compare() const override;
void _emit_compare(CodeEmitContext*, small_vector_2<int, 6>&);
void emit_(CodeEmitContext* ctx) override;
};
struct TernaryExpr : Expr {
Expr_ cond;
Expr_ true_expr;
@ -386,5 +452,4 @@ struct TernaryExpr: Expr{
void emit_(CodeEmitContext* ctx) override;
};
} // namespace pkpy

View File

@ -9,6 +9,7 @@ namespace pkpy{
typedef uint8_t TokenIndex;
// clang-format off
constexpr const char* kTokens[] = {
"is not", "not in", "yield from",
"@eof", "@eol", "@sof",
@ -28,6 +29,7 @@ constexpr const char* kTokens[] = {
"None", "in", "is", "and", "or", "not", "True", "False", "global", "try", "except", "finally",
"while", "for", "if", "elif", "else", "break", "continue", "return", "assert", "raise"
};
// clang-format on
using TokenValue = std::variant<std::monostate, i64, f64, Str>;
const int kTokenCount = sizeof(kTokens) / sizeof(kTokens[0]);
@ -36,20 +38,22 @@ constexpr TokenIndex TK(const char token[]) {
for(int k = 0; k < kTokenCount; k++) {
const char* i = kTokens[k];
const char* j = token;
while(*i && *j && *i == *j) { i++; j++;}
while(*i && *j && *i == *j) {
i++;
j++;
}
if(*i == *j) return k;
}
return 255;
}
inline constexpr bool is_raw_string_used(TokenIndex t){
return t == TK("@id") || t == TK("@long");
}
constexpr inline bool is_raw_string_used(TokenIndex t) { return t == TK("@id") || t == TK("@long"); }
#define TK_STR(t) kTokens[t]
const std::map<std::string_view, TokenIndex> kTokenKwMap = []() {
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;
}();
@ -62,6 +66,7 @@ struct Token{
TokenValue value;
Str str() const { return Str(start, length); }
std::string_view sv() const { return std::string_view(start, length); }
};
@ -104,6 +109,7 @@ struct Lexer {
int brackets_level = 0;
char peekchar() const { return *curr_char; }
bool match_n_chars(int n, char c0);
bool match_string(const char* s);
int eat_spaces();
@ -125,15 +131,17 @@ struct Lexer {
/***** Error Reporter *****/
[[noreturn]] void throw_err(StrName type, Str msg);
[[noreturn]] void throw_err(StrName type, Str msg, int lineno, const char* cursor);
[[noreturn]] void SyntaxError(Str msg) { throw_err("SyntaxError", msg); }
[[noreturn]] void SyntaxError() { throw_err("SyntaxError", "invalid syntax"); }
[[noreturn]] void IndentationError(Str msg) { throw_err("IndentationError", msg); }
Lexer(VM* vm, std::shared_ptr<SourceData> src);
vector<Token> run();
};
enum class IntParsingResult {
Success,
Failure,

View File

@ -9,9 +9,10 @@ struct NativeProxyFuncCBase {
template <typename Ret, typename... Params>
struct NativeProxyFuncC final : NativeProxyFuncCBase {
static constexpr int N = sizeof...(Params);
constexpr static int N = sizeof...(Params);
using _Fp = Ret (*)(Params...);
_Fp func;
NativeProxyFuncC(_Fp func) : func(func) {}
PyVar operator() (VM* vm, ArgsView args) override {
@ -33,9 +34,10 @@ struct NativeProxyFuncC final: NativeProxyFuncCBase {
template <typename Ret, typename T, typename... Params>
struct NativeProxyMethodC final : NativeProxyFuncCBase {
static constexpr int N = sizeof...(Params);
constexpr static int N = sizeof...(Params);
using _Fp = Ret (T::*)(Params...);
_Fp func;
NativeProxyMethodC(_Fp func) : func(func) {}
PyVar operator() (VM* vm, ArgsView args) override {
@ -55,6 +57,7 @@ struct NativeProxyMethodC final: NativeProxyFuncCBase {
}
}
};
/*****************************************************************/
inline PyVar __proxy_wrapper(VM* vm, ArgsView args) {
NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin());
@ -89,7 +92,8 @@ template<typename T, typename F, bool ReadOnly>
PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
static_assert(!std::is_reference_v<F>);
assert(is_type(obj, tp_type));
std::string_view name_sv(name); int pos = name_sv.find(':');
std::string_view name_sv(name);
int pos = name_sv.find(':');
if(pos > 0) name_sv = name_sv.substr(0, pos);
auto fget = [](VM* vm, ArgsView args) -> PyVar {
obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
@ -115,7 +119,9 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
/*****************************************************************/
#define PY_FIELD(T, NAME, EXPR) \
vm->bind_property(type, NAME, \
vm->bind_property( \
type, \
NAME, \
[](VM* vm, ArgsView args) { \
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
return VAR(self.EXPR); \
@ -127,14 +133,15 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
});
#define PY_READONLY_FIELD(T, NAME, EXPR) \
vm->bind_property(type, NAME, \
[](VM* vm, ArgsView args){ \
vm->bind_property(type, NAME, [](VM* vm, ArgsView args) { \
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
return VAR(self.EXPR); \
});
#define PY_PROPERTY(T, NAME, FGET, FSET) \
vm->bind_property(type, NAME, \
vm->bind_property( \
type, \
NAME, \
[](VM* vm, ArgsView args) { \
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
return VAR(self.FGET()); \
@ -147,8 +154,7 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
});
#define PY_READONLY_PROPERTY(T, NAME, FGET) \
vm->bind_property(type, NAME, \
[](VM* vm, ArgsView args){ \
vm->bind_property(type, NAME, [](VM* vm, ArgsView args) { \
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); \
return VAR(self.FGET()); \
});
@ -157,13 +163,19 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
static_assert(std::is_trivially_copyable<wT>::value); \
static_assert(!is_sso_v<wT>); \
type->attr().set("__struct__", vm->True); \
vm->bind_func(type, "fromstruct", 1, [](VM* vm, ArgsView args){ \
vm->bind_func( \
type, \
"fromstruct", \
1, \
[](VM* vm, ArgsView args) { \
Struct& s = CAST(Struct&, args[0]); \
if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \
PyVar obj = vm->new_user_object<wT>(); \
std::memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \
return obj; \
}, {}, BindType::STATICMETHOD); \
}, \
{}, \
BindType::STATICMETHOD); \
vm->bind_func(type, "tostruct", 1, [](VM* vm, ArgsView args) { \
wT& self = _CAST(wT&, args[0]); \
return vm->new_user_object<Struct>(&self, sizeof(wT)); \
@ -184,7 +196,7 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \
wT& other = _CAST(wT&, _1); \
return VAR(self == other); \
}); \
});
#define PY_POINTER_SETGETITEM(T) \
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
@ -198,10 +210,20 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
i64 i = CAST(i64, _1); \
T* tgt = reinterpret_cast<T*>(self.ptr); \
tgt[i] = CAST(T, _2); \
}); \
});
#define PK_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return x; })
#define PK_VAR_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return VAR(x); })
#define PK_ACTION(x) ([](VM* vm, ArgsView args) -> PyVar { x; return vm->None; })
#define PK_LAMBDA(x) \
([](VM* vm, ArgsView args) -> PyVar { \
return x; \
})
#define PK_VAR_LAMBDA(x) \
([](VM* vm, ArgsView args) -> PyVar { \
return VAR(x); \
})
#define PK_ACTION(x) \
([](VM* vm, ArgsView args) -> PyVar { \
x; \
return vm->None; \
})
} // namespace pkpy

View File

@ -12,17 +12,19 @@ namespace pkpy {
struct VoidP {
void* ptr;
VoidP(const void* ptr) : ptr(const_cast<void*>(ptr)) {}
bool operator==(const VoidP& other) const {
return ptr == other.ptr;
}
bool operator!=(const VoidP& other) const {
return ptr != other.ptr;
}
bool operator== (const VoidP& other) const { return ptr == other.ptr; }
bool operator!= (const VoidP& other) const { return ptr != other.ptr; }
bool operator< (const VoidP& other) const { return ptr < other.ptr; }
bool operator<= (const VoidP& other) const { return ptr <= other.ptr; }
bool operator> (const VoidP& other) const { return ptr > other.ptr; }
bool operator>= (const VoidP& other) const { return ptr >= other.ptr; }
Str hex() const {
@ -58,9 +60,8 @@ POINTER_VAR(const bool*, "bool_p")
#undef POINTER_VAR
struct Struct {
static constexpr int INLINE_SIZE = 24;
constexpr static int INLINE_SIZE = 24;
char _inlined[INLINE_SIZE];
char* p;
@ -81,7 +82,10 @@ struct Struct{
}
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);
};
@ -94,6 +98,7 @@ Tp to_void_p(VM* vm, PyVar var){
VoidP& p = CAST(VoidP&, var);
return reinterpret_cast<Tp>(p.ptr);
}
/*****************************************************************/
void add_module_c(VM* vm);

View File

@ -13,6 +13,7 @@ struct FastLocals{
int size() const { return co->nlocals; }
PyVar& operator[] (int i) { return a[i]; }
PyVar operator[] (int i) const { return a[i]; }
FastLocals(const CodeObject* co, PyVar* a) : co(co), a(a) {}
@ -21,6 +22,7 @@ struct FastLocals{
NameDict_ to_namedict();
PyVar* begin() const { return a; }
PyVar* end() const { return a + size(); }
};
@ -32,30 +34,53 @@ struct ValueStack {
PyVar* _sp;
PyVar* _max_end;
static constexpr size_t max_size() { return PK_VM_STACK_SIZE; }
constexpr static size_t max_size() { return PK_VM_STACK_SIZE; }
ValueStack() : _sp(_begin), _max_end(_begin + PK_VM_STACK_SIZE) {}
PyVar& top() { return _sp[-1]; }
PyVar top() const { return _sp[-1]; }
PyVar& second() { return _sp[-2]; }
PyVar second() const { return _sp[-2]; }
PyVar& third() { return _sp[-3]; }
PyVar third() const { return _sp[-3]; }
PyVar& peek(int n) { return _sp[-n]; }
PyVar peek(int n) const { return _sp[-n]; }
void push(PyVar v) { *_sp++ = v; }
void push(std::nullptr_t) { std::memset(_sp++, 0, sizeof(PyVar)); }
void pop() { --_sp; }
PyVar popx(){ --_sp; return *_sp; }
PyVar popx() {
--_sp;
return *_sp;
}
ArgsView view(int n) { return ArgsView(_sp - n, _sp); }
void shrink(int n) { _sp -= n; }
int size() const { return _sp - _begin; }
bool empty() const { return _sp == _begin; }
PyVar* begin() { return _begin; }
PyVar* end() { return _sp; }
void reset(PyVar* sp) { _sp = sp; }
void clear() { _sp = _begin; }
bool is_overflow() const { return _sp >= _max_end; }
template <typename... Args>
@ -89,22 +114,28 @@ struct Frame {
UnwindTarget* _uw_list;
NameDict& f_globals() { return _module->attr(); }
PyVar* f_closure_try_get(StrName name);
int ip() const { return _ip - co->codes.data(); }
// function scope
Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, PyVar* _locals_base)
: _ip(co->codes.data()-1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(co, _locals_base), _uw_list(nullptr) { }
Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, PyVar* _locals_base) :
_ip(co->codes.data() - 1), _sp_base(p0), co(co), _module(_module), _callable(_callable),
_locals(co, _locals_base), _uw_list(nullptr) {}
// exec/eval
Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, FastLocals _locals)
: _ip(co->codes.data()-1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals), _uw_list(nullptr) { }
Frame(PyVar* p0, const CodeObject* co, PyObject* _module, PyObject* _callable, FastLocals _locals) :
_ip(co->codes.data() - 1), _sp_base(p0), co(co), _module(_module), _callable(_callable), _locals(_locals),
_uw_list(nullptr) {}
// global scope
Frame(PyVar* p0, const CodeObject_& co, PyObject* _module)
: _ip(co->codes.data()-1), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr), _locals(co.get(), p0), _uw_list(nullptr) { }
Frame(PyVar* p0, const CodeObject_& co, PyObject* _module) :
_ip(co->codes.data() - 1), _sp_base(p0), co(co.get()), _module(_module), _callable(nullptr),
_locals(co.get(), p0), _uw_list(nullptr) {}
PyVar* actual_sp_base() const { return _locals.a; }
ArgsView stack_view(ValueStack* _s) const { return ArgsView(actual_sp_base(), _s->_sp); }
[[nodiscard]] int prepare_jump_exception_handler(ValueStack*);
@ -129,21 +160,27 @@ struct Frame {
struct LinkedFrame {
LinkedFrame* f_back;
Frame frame;
template <typename... Args>
LinkedFrame(LinkedFrame* f_back, Args&&... args) : f_back(f_back), frame(std::forward<Args>(args)...) {}
};
struct CallStack {
static_assert(sizeof(LinkedFrame) <= 128);
LinkedFrame* _tail;
int _size;
CallStack() : _tail(nullptr), _size(0) {}
int size() const { return _size; }
bool empty() const { return _size == 0; }
void clear(){ while(!empty()) pop(); }
void clear() {
while(!empty())
pop();
}
template <typename... Args>
void emplace(Args&&... args) {
@ -163,7 +200,8 @@ struct CallStack{
template <typename Func>
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(); }

View File

@ -20,21 +20,19 @@ struct ManagedHeap{
/********************/
int _gc_lock_counter = 0;
struct ScopeLock {
PK_ALWAYS_PASS_BY_POINTER(ScopeLock)
ManagedHeap* heap;
ScopeLock(ManagedHeap* heap): heap(heap){
heap->_gc_lock_counter++;
}
~ScopeLock(){
heap->_gc_lock_counter--;
}
ScopeLock(ManagedHeap* heap) : heap(heap) { heap->_gc_lock_counter++; }
~ScopeLock() { heap->_gc_lock_counter--; }
};
ScopeLock gc_scope_lock(){
return ScopeLock(this);
}
ScopeLock gc_scope_lock() { return ScopeLock(this); }
/********************/
template <typename T, typename... Args>
@ -67,7 +65,9 @@ struct ManagedHeap{
int sweep();
void _auto_collect();
bool _should_auto_collect() const { return gc_counter >= gc_threshold; }
int collect();
void mark();
};

View File

@ -7,6 +7,7 @@ namespace pkpy{
struct RangeIter { // step > 0
Range r;
i64 current;
RangeIter(Range r) : r(r), current(r.start) {}
static void _register(VM* vm, PyObject* mod, PyObject* type);
@ -15,6 +16,7 @@ struct RangeIter{ // step > 0
struct RangeIterR { // step < 0
Range r;
i64 current;
RangeIterR(Range r) : r(r), current(r.start) {}
static void _register(VM* vm, PyObject* mod, PyObject* type);
@ -25,18 +27,21 @@ struct ArrayIter{
PyVar* end;
PyVar* current;
ArrayIter(PyObject* ref, PyVar* begin, PyVar* end)
: ref(ref), end(end), current(begin) {}
ArrayIter(PyObject* ref, PyVar* begin, PyVar* end) : ref(ref), end(end), current(begin) {}
void _gc_mark(VM* vm) const { vm->__obj_gc_mark(ref); }
static void _register(VM* vm, PyObject* mod, PyObject* type);
};
struct StringIter {
PyVar ref;
int i; // byte index
StringIter(PyVar ref) : ref(ref), i(0) {}
void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
static void _register(VM* vm, PyObject* mod, PyObject* type);
};
@ -46,7 +51,8 @@ struct Generator{
List s_backup;
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) {
@ -69,10 +75,11 @@ struct Generator{
struct DictItemsIter {
PyVar ref;
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); }
static void _register(VM* vm, PyObject* mod, PyObject* type);
};

View File

@ -12,6 +12,7 @@ struct _LineRecord{
clock_t time;
_LineRecord() : line(-1), hits(0), time(0) {}
bool is_valid() const { return line != -1; }
};

View File

@ -32,9 +32,14 @@ struct NextBreakpoint{
int callstack_size;
int lineno;
bool should_step_into;
NextBreakpoint() : callstack_size(0) {}
NextBreakpoint(int callstack_size, int lineno, bool should_step_into): callstack_size(callstack_size), lineno(lineno), should_step_into(should_step_into) {}
NextBreakpoint(int callstack_size, int lineno, bool should_step_into) :
callstack_size(callstack_size), lineno(lineno), should_step_into(should_step_into) {}
void _step(VM* vm);
bool empty() const { return callstack_size == 0; }
};
#endif
@ -53,10 +58,14 @@ struct PyTypeInfo{
static_assert(std::is_same_v<T, std::decay_t<T>>);
Vt vt;
if constexpr(!std::is_trivially_destructible_v<T>) {
vt._dtor = [](void* p){ ((T*)p)->~T(); };
vt._dtor = [](void* p) {
((T*)p)->~T();
};
}
if constexpr(has_gc_marker<T>::value) {
vt._gc_mark = [](void* p, VM* vm){ ((T*)p)->_gc_mark(vm); };
vt._gc_mark = [](void* p, VM* vm) {
((T*)p)->_gc_mark(vm);
};
}
return vt;
}
@ -134,25 +143,26 @@ struct ImportContext{
PK_ALWAYS_PASS_BY_POINTER(Temp)
ImportContext* ctx;
Temp(ImportContext* ctx, Str name, bool is_init) : ctx(ctx) {
ctx->pending.push_back(name);
ctx->pending_is_init.push_back(is_init);
}
~Temp() {
ctx->pending.pop_back();
ctx->pending_is_init.pop_back();
}
};
Temp scope(Str name, bool is_init){
return {this, name, is_init};
}
Temp scope(Str name, bool is_init) { return {this, name, is_init}; }
};
class VM {
PK_ALWAYS_PASS_BY_POINTER(VM)
VM* vm; // self reference to simplify code
public:
ManagedHeap heap;
ValueStack s_data;
@ -199,26 +209,28 @@ public:
// function<unsigned char*(const char*, int*)> _import_handler;
// for quick access
static constexpr Type tp_object=Type(1), tp_type=Type(2);
static constexpr Type tp_int=Type(kTpIntIndex), tp_float=Type(kTpFloatIndex), tp_bool=Type(5), tp_str=Type(6);
static constexpr Type tp_list=Type(7), tp_tuple=Type(8);
static constexpr Type tp_slice=Type(9), tp_range=Type(10), tp_module=Type(11);
static constexpr Type tp_function=Type(12), tp_native_func=Type(13), tp_bound_method=Type(14);
static constexpr Type tp_super=Type(15), tp_exception=Type(16), tp_bytes=Type(17), tp_mappingproxy=Type(18);
static constexpr Type tp_dict=Type(19), tp_property=Type(20), tp_star_wrapper=Type(21);
static constexpr Type tp_staticmethod=Type(22), tp_classmethod=Type(23);
static constexpr Type tp_none_type=Type(24), tp_not_implemented=Type(25), tp_ellipsis=Type(26);
static constexpr Type tp_stack_memory=Type(kTpStackMemoryIndex);
constexpr static Type tp_object = Type(1), tp_type = Type(2);
constexpr static Type tp_int = Type(kTpIntIndex), tp_float = Type(kTpFloatIndex), tp_bool = Type(5),
tp_str = Type(6);
constexpr static Type tp_list = Type(7), tp_tuple = Type(8);
constexpr static Type tp_slice = Type(9), tp_range = Type(10), tp_module = Type(11);
constexpr static Type tp_function = Type(12), tp_native_func = Type(13), tp_bound_method = Type(14);
constexpr static Type tp_super = Type(15), tp_exception = Type(16), tp_bytes = Type(17), tp_mappingproxy = Type(18);
constexpr static Type tp_dict = Type(19), tp_property = Type(20), tp_star_wrapper = Type(21);
constexpr static Type tp_staticmethod = Type(22), tp_classmethod = Type(23);
constexpr static Type tp_none_type = Type(24), tp_not_implemented = Type(25), tp_ellipsis = Type(26);
constexpr static Type tp_stack_memory = Type(kTpStackMemoryIndex);
static constexpr PyVar True{const_sso_var(), tp_bool, 1};
static constexpr PyVar False{const_sso_var(), tp_bool, 0};
static constexpr PyVar None{const_sso_var(), tp_none_type, 0};
static constexpr PyVar NotImplemented{const_sso_var(), tp_not_implemented, 0};
static constexpr PyVar Ellipsis{const_sso_var(), tp_ellipsis, 0};
constexpr static PyVar True{const_sso_var(), tp_bool, 1};
constexpr static PyVar False{const_sso_var(), tp_bool, 0};
constexpr static PyVar None{const_sso_var(), tp_none_type, 0};
constexpr static PyVar NotImplemented{const_sso_var(), tp_not_implemented, 0};
constexpr static PyVar Ellipsis{const_sso_var(), tp_ellipsis, 0};
const bool enable_os;
VM(bool enable_os = true);
// clang-format off
#if PK_REGION("Python Equivalents")
Str py_str(PyVar obj); // x -> str(x)
Str py_repr(PyVar obj); // x -> repr(x)
@ -453,6 +465,7 @@ public:
vm->s_data.emplace(p->type, p);
}
#endif
// clang-format on
template <typename T>
Type _find_type_in_cxx_typeid_map() {
@ -491,11 +504,29 @@ public:
[[noreturn]] void __builtin_error(StrName type, const Str& msg);
void __init_builtin_types();
void __post_init_builtin_types();
void __push_varargs() {}
void __push_varargs(PyVar _0) { PUSH(_0); }
void __push_varargs(PyVar _0, PyVar _1){ PUSH(_0); PUSH(_1); }
void __push_varargs(PyVar _0, PyVar _1, PyVar _2){ PUSH(_0); PUSH(_1); PUSH(_2); }
void __push_varargs(PyVar _0, PyVar _1, PyVar _2, PyVar _3){ PUSH(_0); PUSH(_1); PUSH(_2); PUSH(_3); }
void __push_varargs(PyVar _0, PyVar _1) {
PUSH(_0);
PUSH(_1);
}
void __push_varargs(PyVar _0, PyVar _1, PyVar _2) {
PUSH(_0);
PUSH(_1);
PUSH(_2);
}
void __push_varargs(PyVar _0, PyVar _1, PyVar _2, PyVar _3) {
PUSH(_0);
PUSH(_1);
PUSH(_2);
PUSH(_3);
}
PyVar __pack_next_retval(unsigned);
PyVar __minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key);
bool __py_bool_non_trivial(PyVar);
@ -504,31 +535,101 @@ public:
void* __stack_alloc(int size);
};
template <typename T>
constexpr inline bool is_immutable_v =
is_integral_v<T> || is_floating_point_v<T> || std::is_same_v<T, Str> || std::is_same_v<T, Tuple> ||
std::is_same_v<T, Bytes> || std::is_same_v<T, bool> || std::is_same_v<T, Range> || std::is_same_v<T, Slice> ||
std::is_pointer_v<T> || std::is_enum_v<T>;
template <typename T>
inline constexpr bool is_immutable_v = is_integral_v<T> || is_floating_point_v<T>
|| std::is_same_v<T, Str> || std::is_same_v<T, Tuple> || std::is_same_v<T, Bytes> || std::is_same_v<T, bool>
|| std::is_same_v<T, Range> || std::is_same_v<T, Slice>
|| std::is_pointer_v<T> || std::is_enum_v<T>;
constexpr Type _find_type_in_const_cxx_typeid_map() {
return Type();
}
template<typename T> constexpr Type _find_type_in_const_cxx_typeid_map(){ return Type(); }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Str>(){ return VM::tp_str; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<List>(){ return VM::tp_list; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Tuple>(){ return VM::tp_tuple; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Function>(){ return VM::tp_function; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<NativeFunc>(){ return VM::tp_native_func; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<BoundMethod>(){ return VM::tp_bound_method; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Range>(){ return VM::tp_range; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Slice>(){ return VM::tp_slice; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Exception>(){ return VM::tp_exception; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Bytes>(){ return VM::tp_bytes; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<MappingProxy>(){ return VM::tp_mappingproxy; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Dict>(){ return VM::tp_dict; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<Property>(){ return VM::tp_property; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<StarWrapper>(){ return VM::tp_star_wrapper; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<StaticMethod>(){ return VM::tp_staticmethod; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<ClassMethod>(){ return VM::tp_classmethod; }
template<> constexpr Type _find_type_in_const_cxx_typeid_map<StackMemory>(){ return VM::tp_stack_memory; }
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Str>() {
return VM::tp_str;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<List>() {
return VM::tp_list;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Tuple>() {
return VM::tp_tuple;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Function>() {
return VM::tp_function;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<NativeFunc>() {
return VM::tp_native_func;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<BoundMethod>() {
return VM::tp_bound_method;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Range>() {
return VM::tp_range;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Slice>() {
return VM::tp_slice;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Exception>() {
return VM::tp_exception;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Bytes>() {
return VM::tp_bytes;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<MappingProxy>() {
return VM::tp_mappingproxy;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Dict>() {
return VM::tp_dict;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<Property>() {
return VM::tp_property;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<StarWrapper>() {
return VM::tp_star_wrapper;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<StaticMethod>() {
return VM::tp_staticmethod;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<ClassMethod>() {
return VM::tp_classmethod;
}
template <>
constexpr Type _find_type_in_const_cxx_typeid_map<StackMemory>() {
return VM::tp_stack_memory;
}
template <typename __T>
PyVar py_var(VM* vm, __T&& value) {
@ -536,7 +637,8 @@ PyVar py_var(VM* vm, __T&& value){
static_assert(!std::is_same_v<T, PyVar>, "py_var(VM*, PyVar) is not allowed");
if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>){
if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, std::string> ||
std::is_same_v<T, std::string_view>) {
// str (shortcuts)
return VAR(Str(std::forward<__T>(value)));
} else if constexpr(std::is_same_v<T, NoReturn>) {
@ -556,20 +658,22 @@ PyVar py_var(VM* vm, __T&& value){
} else {
constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
if constexpr((bool)const_type) {
if constexpr(is_sso_v<T>) return PyVar(const_type, value);
else return vm->heap.gcnew<T>(const_type, std::forward<__T>(value));
if constexpr(is_sso_v<T>)
return PyVar(const_type, value);
else
return vm->heap.gcnew<T>(const_type, std::forward<__T>(value));
} else {
Type type = vm->_find_type_in_cxx_typeid_map<T>();
if constexpr(is_sso_v<T>) return PyVar(type, value);
else return vm->heap.gcnew<T>(type, std::forward<__T>(value));
if constexpr(is_sso_v<T>)
return PyVar(type, value);
else
return vm->heap.gcnew<T>(type, std::forward<__T>(value));
}
}
}
// fast path for bool if py_var<> cannot be inlined
inline PyVar py_var(VM* vm, bool value){
return value ? vm->True : vm->False;
}
inline PyVar py_var(VM* vm, bool value) { return value ? vm->True : vm->False; }
template <typename __T, bool with_check>
__T _py_cast__internal(VM* vm, PyVar obj) {
@ -635,12 +739,18 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
}
template <typename __T>
__T py_cast(VM* vm, PyVar obj) { return _py_cast__internal<__T, true>(vm, obj); }
__T py_cast(VM* vm, PyVar obj) {
return _py_cast__internal<__T, true>(vm, obj);
}
template <typename __T>
__T _py_cast(VM* vm, PyVar obj) { return _py_cast__internal<__T, false>(vm, obj); }
__T _py_cast(VM* vm, PyVar obj) {
return _py_cast__internal<__T, false>(vm, obj);
}
template <typename T>
PyObject* VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _register, Type base, bool subclass_enabled){
PyObject*
VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _register, Type base, bool subclass_enabled) {
PyObject* type = new_type_object(mod, name, base, subclass_enabled, PyTypeInfo::Vt::get<T>());
mod->attr().set(name, type);
_cxx_typeid_map[typeid(T)] = type->as<Type>();

View File

@ -6,4 +6,4 @@ namespace pkpy{
unsigned char* _default_import_handler(const char*, int*);
void add_module_os(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);
float x, y;
Vec2() : x(0.0f), y(0.0f) {}
Vec2(float x, float y) : x(x), y(y) {}
Vec2 operator+ (const Vec2& v) const { return Vec2(x + v.x, y + v.y); }
Vec2 operator- (const Vec2& v) const { return Vec2(x - v.x, y - v.y); }
Vec2 operator* (float s) const { return Vec2(x * s, y * s); }
Vec2 operator* (const Vec2& v) const { return Vec2(x * v.x, y * v.y); }
Vec2 operator/ (float s) const { return Vec2(x / s, y / s); }
Vec2 operator- () const { return Vec2(-x, -y); }
bool operator== (const Vec2& v) const { return isclose(x, v.x) && isclose(y, v.y); }
bool operator!= (const Vec2& v) const { return !isclose(x, v.x) || !isclose(y, v.y); }
float operator[] (int i) const { return (&x)[i]; }
float dot(const Vec2& v) const { return x * v.x + y * v.y; }
float cross(const Vec2& v) const { return x * v.y - y * v.x; }
float length() const { return sqrtf(x * x + y * y); }
float length_squared() const { return x * x + y * y; }
Vec2 normalize() const { float l = length(); return Vec2(x / l, y / l); }
Vec2 rotate(float radian) const { float cr = cosf(radian), sr = sinf(radian); return Vec2(x * cr - y * sr, x * sr + y * cr); }
Vec2 normalize() const {
float l = length();
return Vec2(x / l, y / l);
}
Vec2 rotate(float radian) const {
float cr = cosf(radian), sr = sinf(radian);
return Vec2(x * cr - y * sr, x * sr + y * cr);
}
};
struct Vec3 {
static void _register(VM* vm, PyObject* mod, PyObject* type);
float x, y, z;
Vec3() : x(0.0f), y(0.0f), z(0.0f) {}
Vec3(float x, float y, float z) : x(x), y(y), z(z) {}
Vec3 operator+ (const Vec3& v) const { return Vec3(x + v.x, y + v.y, z + v.z); }
Vec3 operator- (const Vec3& v) const { return Vec3(x - v.x, y - v.y, z - v.z); }
Vec3 operator* (float s) const { return Vec3(x * s, y * s, z * s); }
Vec3 operator* (const Vec3& v) const { return Vec3(x * v.x, y * v.y, z * v.z); }
Vec3 operator/ (float s) const { return Vec3(x / s, y / s, z / s); }
Vec3 operator- () const { return Vec3(-x, -y, -z); }
bool operator== (const Vec3& v) const { return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z); }
bool operator!= (const Vec3& v) const { return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z); }
float operator[] (int i) const { return (&x)[i]; }
float dot(const Vec3& v) const { return x * v.x + y * v.y + z * v.z; }
Vec3 cross(const Vec3& v) const { return Vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); }
float length() const { return sqrtf(x * x + y * y + z * z); }
float length_squared() const { return x * x + y * y + z * z; }
Vec3 normalize() const { float l = length(); return Vec3(x / l, y / l, z / l); }
Vec3 normalize() const {
float l = length();
return Vec3(x / l, y / l, z / l);
}
};
struct Vec4 {
static void _register(VM* vm, PyObject* mod, PyObject* type);
float x, y, z, w;
Vec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) {}
Vec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
Vec4 operator+ (const Vec4& v) const { return Vec4(x + v.x, y + v.y, z + v.z, w + v.w); }
Vec4 operator- (const Vec4& v) const { return Vec4(x - v.x, y - v.y, z - v.z, w - v.w); }
Vec4 operator* (float s) const { return Vec4(x * s, y * s, z * s, w * s); }
Vec4 operator* (const Vec4& v) const { return Vec4(x * v.x, y * v.y, z * v.z, w * v.w); }
Vec4 operator/ (float s) const { return Vec4(x / s, y / s, z / s, w / s); }
Vec4 operator- () const { return Vec4(-x, -y, -z, -w); }
bool operator==(const Vec4& v) const { return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z) && isclose(w, v.w); }
bool operator!=(const Vec4& v) const { return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z) || !isclose(w, v.w); }
bool operator== (const Vec4& v) const {
return isclose(x, v.x) && isclose(y, v.y) && isclose(z, v.z) && isclose(w, v.w);
}
bool operator!= (const Vec4& v) const {
return !isclose(x, v.x) || !isclose(y, v.y) || !isclose(z, v.z) || !isclose(w, v.w);
}
float operator[] (int i) const { return (&x)[i]; }
float dot(const Vec4& v) const { return x * v.x + y * v.y + z * v.z + w * v.w; }
float length() const { return sqrtf(x * x + y * y + z * z + w * w); }
float length_squared() const { return x * x + y * y + z * z + w * w; }
Vec4 normalize() const { float l = length(); return Vec4(x / l, y / l, z / l, w / l); }
NoReturn normalize_() { float l = length(); x /= l; y /= l; z /= l; w /= l; return {}; }
NoReturn copy_(const Vec4& v) { x = v.x; y = v.y; z = v.z; w = v.w; return {}; }
Vec4 normalize() const {
float l = length();
return Vec4(x / l, y / l, z / l, w / l);
}
NoReturn normalize_() {
float l = length();
x /= l;
y /= l;
z /= l;
w /= l;
return {};
}
NoReturn copy_(const Vec4& v) {
x = v.x;
y = v.y;
z = v.z;
w = v.w;
return {};
}
};
struct Mat3x3 {
@ -89,6 +165,7 @@ struct Mat3x3{
float _21, _22, _23;
float _31, _32, _33;
};
float m[3][3];
float v[9];
};
@ -131,8 +208,8 @@ static_assert(is_pod_v<Vec4>);
static_assert(is_pod_v<Mat3x3>);
template <>
inline constexpr bool is_sso_v<Vec2> = true;
constexpr inline bool is_sso_v<Vec2> = true;
template <>
inline constexpr bool is_sso_v<Vec3> = true;
constexpr inline bool is_sso_v<Vec3> = true;
} // namespace pkpy

View File

@ -12,10 +12,15 @@ namespace pkpy{
struct Type {
int16_t index;
constexpr Type() : index(0) {}
explicit constexpr Type(int index) : index(index) {}
bool operator== (Type other) const { return this->index == other.index; }
bool operator!= (Type other) const { return this->index != other.index; }
constexpr operator int () const { return index; }
};
@ -26,7 +31,8 @@ struct PyVar final{
bool is_ptr;
uint8_t flags;
// 12 bytes SSO
int _0; i64 _1;
int _0;
i64 _1;
// uninitialized
PyVar() = default;
@ -36,11 +42,15 @@ struct PyVar final{
/* We must initialize all members to allow == operator to work correctly */
// constexpr initialized
constexpr PyVar(const const_sso_var&, Type type, int value): type(type), is_ptr(false), flags(0), _0(value), _1(0) {}
constexpr PyVar(const const_sso_var&, Type type, int value) :
type(type), is_ptr(false), flags(0), _0(value), _1(0) {}
// zero initialized
constexpr PyVar(std::nullptr_t) : type(0), is_ptr(false), flags(0), _0(0), _1(0) {}
// PyObject* initialized (is_sso = false)
PyVar(Type type, PyObject* p) : type(type), is_ptr(true), flags(0), _0(0), _1(reinterpret_cast<i64>(p)) {}
// SSO initialized (is_sso = true)
template <typename T>
PyVar(Type type, T value) : type(type), is_ptr(false), flags(0), _0(0), _1(0) {
@ -60,20 +70,21 @@ struct PyVar final{
explicit operator bool () const { return (bool)type; }
void set_null() { _qword(0) = 0; _qword(1) = 0; }
void set_null() {
_qword(0) = 0;
_qword(1) = 0;
}
i64 _qword(int i) const { return ((const i64*)this)[i]; }
i64& _qword(int i) { return ((i64*)this)[i]; }
bool operator==(const PyVar& other) const {
return _qword(0) == other._qword(0) && _qword(1) == other._qword(1);
}
bool operator== (const PyVar& other) const { return _qword(0) == other._qword(0) && _qword(1) == other._qword(1); }
bool operator!=(const PyVar& other) const {
return _qword(0) != other._qword(0) || _qword(1) != other._qword(1);
}
bool operator!= (const PyVar& other) const { return _qword(0) != other._qword(0) || _qword(1) != other._qword(1); }
bool operator== (std::nullptr_t) const { return !(bool)type; }
bool operator!= (std::nullptr_t) const { return (bool)type; }
PyObject* get() const {
@ -92,9 +103,7 @@ struct PyVar final{
obj_get_t<T> obj_get();
// for std::map<>
bool operator<(const PyVar& other) const {
return memcmp(this, &other, sizeof(PyVar)) < 0;
}
bool operator< (const PyVar& other) const { return memcmp(this, &other, sizeof(PyVar)) < 0; }
};
static_assert(sizeof(PyVar) == 16 && is_pod_v<PyVar>);

View File

@ -8,26 +8,34 @@ namespace pkpy{
struct BoundMethod {
PyVar self;
PyVar func;
BoundMethod(PyVar self, PyVar func) : self(self), func(func) {}
void _gc_mark(VM*) const;
};
struct StaticMethod {
PyVar func;
StaticMethod(PyVar func) : func(func) {}
void _gc_mark(VM*) const;
};
struct ClassMethod {
PyVar func;
ClassMethod(PyVar func) : func(func) {}
void _gc_mark(VM*) const;
};
struct Property {
PyVar getter;
PyVar setter;
Property(PyVar getter, PyVar setter) : getter(getter), setter(setter) {}
void _gc_mark(VM*) const;
};
@ -37,11 +45,12 @@ struct Range {
i64 step = 1;
};
struct StarWrapper {
int level; // either 1 or 2
PyVar obj;
StarWrapper(int level, PyVar obj) : level(level), obj(obj) {}
void _gc_mark(VM*) const;
};
@ -50,7 +59,9 @@ using Bytes = array<unsigned char>;
struct Super {
PyVar first;
Type second;
Super(PyVar first, Type second) : first(first), second(second) {}
void _gc_mark(VM*) const;
};
@ -58,16 +69,19 @@ struct Slice {
PyVar start;
PyVar stop;
PyVar step;
Slice(PyVar start, PyVar stop, PyVar step) : start(start), stop(stop), step(step) {}
void _gc_mark(VM*) const;
};
inline const int kTpIntIndex = 3;
inline const int kTpFloatIndex = 4;
const inline int kTpIntIndex = 3;
const inline int kTpFloatIndex = 4;
inline bool is_tagged(PyVar p) noexcept { return !p.is_ptr; }
inline bool is_float(PyVar p) noexcept { return p.type.index == kTpFloatIndex; }
inline bool is_int(PyVar p) noexcept { return p.type.index == kTpIntIndex; }
inline bool is_type(PyVar obj, Type type) {
@ -82,16 +96,19 @@ inline bool is_type(PyObject* p, Type type) {
struct MappingProxy {
PyObject* obj;
MappingProxy(PyObject* obj) : obj(obj) {}
NameDict& attr() { return obj->attr(); }
void _gc_mark(VM*) const;
};
StrName _type_name(VM* vm, Type type);
template<typename T> T to_void_p(VM*, PyVar);
template <typename T>
T to_void_p(VM*, PyVar);
PyVar from_void_p(VM*, void*);
template <typename T>
obj_get_t<T> PyVar::obj_get() {
if constexpr(is_sso_v<T>) {
@ -119,6 +136,6 @@ obj_get_t<T> PyVar::obj_get(){
#define PY_NULL nullptr
extern PyVar const PY_OP_CALL;
extern PyVar const PY_OP_YIELD;
extern const PyVar PY_OP_YIELD;
} // namespace pkpy

View File

@ -22,6 +22,7 @@ enum class BindType{
enum NameScope { NAME_LOCAL, NAME_GLOBAL, NAME_GLOBAL_UNKNOWN };
enum Opcode : uint8_t {
#define OPCODE(name) OP_##name,
#include "pocketpy/opcodes.h"
#undef OPCODE
@ -36,9 +37,7 @@ struct Bytecode{
this->arg = (int16_t)arg;
}
bool is_forward_jump() const{
return op >= OP_JUMP_FORWARD && op <= OP_LOOP_BREAK;
}
bool is_forward_jump() const { return op >= OP_JUMP_FORWARD && op <= OP_LOOP_BREAK; }
};
enum class CodeBlockType {
@ -49,8 +48,8 @@ enum class CodeBlockType {
TRY_EXCEPT,
};
inline const uint8_t BC_NOARG = 0;
inline const int BC_KEEPLINE = -1;
const inline uint8_t BC_NOARG = 0;
const inline int BC_KEEPLINE = -1;
struct CodeBlock {
CodeBlockType type;
@ -98,9 +97,7 @@ struct CodeObject {
int start_line;
int end_line;
const CodeBlock& _get_block_codei(int codei) const{
return blocks[lines[codei].iblock];
}
const CodeBlock& _get_block_codei(int codei) const { return blocks[lines[codei].iblock]; }
CodeObject(std::shared_ptr<SourceData> src, const Str& name);
void _gc_mark(VM*) const;
@ -120,6 +117,7 @@ struct FuncDecl {
StrName key; // name of this argument
PyVar value; // default value
};
CodeObject_ code; // code object of this function
small_vector_2<int, 6> args; // indices in co->varnames
@ -149,10 +147,14 @@ struct NativeFunc {
FuncDecl_ decl; // new style decl-based call
any _userdata;
NativeFunc(NativeFuncC f, int argc, any userdata={}): f(f), argc(argc), decl(nullptr), _userdata(std::move(userdata)) {}
NativeFunc(NativeFuncC f, FuncDecl_ decl, any userdata={}): f(f), argc(-1), decl(decl), _userdata(std::move(userdata)) {}
NativeFunc(NativeFuncC f, int argc, any userdata = {}) :
f(f), argc(argc), decl(nullptr), _userdata(std::move(userdata)) {}
NativeFunc(NativeFuncC f, FuncDecl_ decl, any userdata = {}) :
f(f), argc(-1), decl(decl), _userdata(std::move(userdata)) {}
PyVar call(VM* vm, ArgsView args) const { return f(vm, args); }
void _gc_mark(VM*) const;
};

View File

@ -13,8 +13,8 @@ struct Dict{
int next;
};
static constexpr int __Capacity = 8;
static constexpr float __LoadFactor = 0.67f;
constexpr static int __Capacity = 8;
constexpr static float __LoadFactor = 0.67f;
int _capacity;
int _mask;

View File

@ -7,17 +7,18 @@ namespace pkpy{
struct NeedMoreLines {
NeedMoreLines(bool is_compiling_class) : is_compiling_class(is_compiling_class) {}
bool is_compiling_class;
};
enum class InternalExceptionType: int{
Null, Handled, Unhandled, ToBeRaised
};
enum class InternalExceptionType : int { Null, Handled, Unhandled, ToBeRaised };
struct InternalException final {
InternalExceptionType type;
int arg;
InternalException() : type(InternalExceptionType::Null), arg(-1) {}
InternalException(InternalExceptionType type, int arg = -1) : type(type), arg(arg) {}
};
@ -44,6 +45,7 @@ struct Exception {
};
stack<Frame> stacktrace;
Exception(StrName type) : type(type), is_re(true), _ip_on_error(-1), _code_on_error(nullptr), _self(nullptr) {}
PyObject* self() const {
@ -63,6 +65,7 @@ struct Exception {
struct TopLevelException : std::exception {
VM* vm;
Exception* ptr;
TopLevelException(VM* vm, Exception* ptr) : vm(vm), ptr(ptr) {}
Str summary() const { return ptr->summary(); }

View File

@ -16,9 +16,11 @@ struct PyObject final{
NameDict* _attr; // gc will delete this on destruction
bool is_attr_valid() const noexcept { return _attr != nullptr; }
void* _value_ptr() noexcept { return (char*)this + 16; }
template<typename T> T& as() noexcept {
template <typename T>
T& as() noexcept {
static_assert(std::is_same_v<T, std::decay_t<T>>);
return *reinterpret_cast<T*>(_value_ptr());
}

View File

@ -5,13 +5,7 @@
namespace pkpy {
enum CompileMode {
EXEC_MODE,
EVAL_MODE,
REPL_MODE,
JSON_MODE,
CELL_MODE
};
enum CompileMode { EXEC_MODE, EVAL_MODE, REPL_MODE, JSON_MODE, CELL_MODE };
struct SourceData {
PK_ALWAYS_PASS_BY_POINTER(SourceData)

View File

@ -6,12 +6,13 @@ namespace pkpy{
struct StackMemory {
int count;
StackMemory(int count) : count(count) {}
};
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

View File

@ -6,7 +6,7 @@
namespace pkpy {
struct Tuple {
static const int INLINED_SIZE = 3;
const static int INLINED_SIZE = 3;
PyVar* _args;
PyVar _inlined[INLINED_SIZE];
@ -23,14 +23,19 @@ struct Tuple {
Tuple(PyVar, PyVar, PyVar);
bool is_inlined() const { return _args == _inlined; }
PyVar& operator[] (int i) { return _args[i]; }
PyVar operator[] (int i) const { return _args[i]; }
int size() const { return _size; }
PyVar* begin() const { return _args; }
PyVar* end() const { return _args + _size; }
PyVar* data() const { return _args; }
void _gc_mark(VM*) const;
};
@ -40,7 +45,8 @@ struct List: public vector<PyVar>{
Tuple to_tuple() const {
Tuple ret(size());
for(int i=0; i<size(); i++) ret[i] = (*this)[i];
for(int i = 0; i < size(); i++)
ret[i] = (*this)[i];
return ret;
}
};
@ -51,12 +57,17 @@ struct ArgsView{
PyVar* _end;
ArgsView(PyVar* begin, PyVar* end) : _begin(begin), _end(end) {}
ArgsView(const Tuple& t) : _begin(t.begin()), _end(t.end()) {}
PyVar* begin() const { return _begin; }
PyVar* end() const { return _end; }
int size() const { return _end - _begin; }
bool empty() const { return _begin == _end; }
PyVar operator[] (int i) const { return _begin[i]; }
List to_list() const;

View File

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

View File

@ -9,6 +9,7 @@ protected:
int need_more_lines = 0;
std::string buffer;
VM* vm;
public:
REPL(VM* vm);
bool input(std::string line);

View File

@ -13,9 +13,7 @@ namespace pybind11 {
return vm->getattr(obj.ptr(), key, false) != nullptr;
}
inline bool hasattr(const handle& obj, const char* name) {
return vm->getattr(obj.ptr(), name, false) != nullptr;
}
inline bool hasattr(const handle& obj, const char* name) { return vm->getattr(obj.ptr(), name, false) != nullptr; }
inline void delattr(const handle& obj, const handle& name) {
auto& key = _builtin_cast<pkpy::Str>(name);
@ -34,16 +32,12 @@ namespace pybind11 {
}
inline object getattr(const handle& obj, const handle& name, const handle& default_) {
if(!hasattr(obj, name)) {
return reinterpret_borrow<object>(default_);
}
if(!hasattr(obj, name)) { return reinterpret_borrow<object>(default_); }
return getattr(obj, name);
}
inline object getattr(const handle& obj, const char* name, const handle& default_) {
if(!hasattr(obj, name)) {
return reinterpret_borrow<object>(default_);
}
if(!hasattr(obj, name)) { return reinterpret_borrow<object>(default_); }
return getattr(obj, name);
}
@ -85,24 +79,21 @@ namespace pybind11 {
struct type_caster;
template <typename T>
handle _cast(T&& value,
return_value_policy policy = return_value_policy::automatic_reference,
handle parent = handle()) {
handle
_cast(T&& value, return_value_policy policy = return_value_policy::automatic_reference, handle parent = handle()) {
using U = std::remove_pointer_t<std::remove_cv_t<std::remove_reference_t<T>>>;
return type_caster<U>::cast(std::forward<T>(value), policy, parent);
}
template <typename T>
object cast(T&& value,
return_value_policy policy = return_value_policy::automatic_reference,
handle parent = handle()) {
object
cast(T&& value, return_value_policy policy = return_value_policy::automatic_reference, handle parent = handle()) {
return reinterpret_borrow<object>(_cast(std::forward<T>(value), policy, parent));
}
template <typename T>
T cast(handle obj, bool convert = false) {
using Caster =
type_caster<std::remove_pointer_t<std::remove_cv_t<std::remove_reference_t<T>>>>;
using Caster = type_caster<std::remove_pointer_t<std::remove_cv_t<std::remove_reference_t<T>>>>;
Caster caster;
if(caster.load(obj, convert)) {

View File

@ -10,8 +10,7 @@ namespace pybind11 {
using pkpy::is_integral_v;
template <typename T>
constexpr inline bool is_string_v =
std::is_same_v<T, char*> || std::is_same_v<T, const char*> ||
constexpr inline bool is_string_v = std::is_same_v<T, char*> || std::is_same_v<T, const char*> ||
std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>;
template <typename T>
@ -33,9 +32,7 @@ namespace pybind11 {
return false;
}
static handle cast(bool src, return_value_policy, handle) {
return src ? vm->True : vm->False;
}
static handle cast(bool src, return_value_policy, handle) { return src ? vm->True : vm->False; }
};
template <typename T>
@ -89,9 +86,7 @@ namespace pybind11 {
return false;
}
static handle cast(const std::string& src, return_value_policy, handle) {
return pkpy::py_var(vm, src);
}
static handle cast(const std::string& src, return_value_policy, handle) { return pkpy::py_var(vm, src); }
};
template <typename T>
@ -144,9 +139,7 @@ namespace pybind11 {
template <typename T>
struct type_caster<T, std::enable_if_t<std::is_pointer_v<T> || std::is_reference_v<T>>> {
using underlying = std::conditional_t<std::is_pointer_v<T>,
std::remove_pointer_t<T>,
std::remove_reference_t<T>>;
using underlying = std::conditional_t<std::is_pointer_v<T>, std::remove_pointer_t<T>, std::remove_reference_t<T>>;
struct wrapper {
type_caster<underlying> caster;

View File

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

View File

@ -10,8 +10,7 @@ namespace pybind11 {
template <typename T>
struct call_guard {
static_assert(std::is_default_constructible_v<T>,
"call_guard must be default constructible");
static_assert(std::is_default_constructible_v<T>, "call_guard must be default constructible");
};
// append the overload to the beginning of the overload list
@ -62,8 +61,7 @@ namespace pybind11 {
public:
template <typename Fn, typename... Extras>
function_record(Fn&& f, const char* name, const Extras&... extras) :
name(name), next(nullptr) {
function_record(Fn&& f, const char* name, const Extras&... extras) : name(name), next(nullptr) {
if constexpr(sizeof(f) <= sizeof(buffer)) {
new (buffer) auto(std::forward<Fn>(f));
@ -72,7 +70,9 @@ namespace pybind11 {
};
} else {
data = new auto(std::forward<Fn>(f));
destructor = [](function_record* self) { delete static_cast<Fn*>(self->data); };
destructor = [](function_record* self) {
delete static_cast<Fn*>(self->data);
};
}
using Generator = generator<std::decay_t<Fn>, std::tuple<Extras...>>;
@ -104,9 +104,7 @@ namespace pybind11 {
// foreach function record and call the function with not convert
while(p != nullptr) {
handle result = p->wrapper(*this, view, false, {});
if(result) {
return result;
}
if(result) { return result; }
p = p->next;
}
@ -114,9 +112,7 @@ namespace pybind11 {
// foreach function record and call the function with convert
while(p != nullptr) {
handle result = p->wrapper(*this, view, true, {});
if(result) {
return result;
}
if(result) { return result; }
p = p->next;
}
@ -176,13 +172,9 @@ namespace pybind11 {
// initialize the stack
if(!has_args && (view.size() != count)) {
return handle();
}
if(!has_args && (view.size() != count)) { return handle(); }
if(has_args && (view.size() < count)) {
return handle();
}
if(has_args && (view.size() < count)) { return handle(); }
for(std::size_t i = 0; i < count; ++i) {
stack[i] = view[i];
@ -206,8 +198,7 @@ namespace pybind11 {
for(std::size_t i = 0; i < n; i += 2) {
pkpy::i64 index = pkpy::_py_cast<pkpy::i64>(vm, view[count + i]);
pkpy::PyVar str =
vm->new_object<pkpy::Str>(vm->tp_str, pkpy::StrName(index).sv());
pkpy::PyVar str = vm->new_object<pkpy::Str>(vm->tp_str, pkpy::StrName(index).sv());
dict.set(vm, str, view[count + i + 1]);
}
@ -216,9 +207,7 @@ namespace pybind11 {
// check if all the arguments are not valid
for(std::size_t i = 0; i < sizeof...(Args); ++i) {
if(!stack[i]) {
return handle();
}
if(!stack[i]) { return handle(); }
}
// ok, all the arguments are valid, call the function
@ -226,11 +215,7 @@ namespace pybind11 {
// check type compatibility
if(((std::get<Is>(casters).load(stack[Is], convert)) && ...)) {
return invoke(self.cast<Fn>(),
std::index_sequence<Is...>{},
casters,
self.policy,
parent);
return invoke(self.cast<Fn>(), std::index_sequence<Is...>{}, casters, self.policy, parent);
}
return handle();
@ -254,11 +239,7 @@ namespace pybind11 {
};
template <typename Fn, typename... Extras>
handle bind_function(const handle& obj,
const char* name,
Fn&& fn,
pkpy::BindType type,
const Extras&... extras) {
handle bind_function(const handle& obj, const char* name, Fn&& fn, pkpy::BindType type, const Extras&... extras) {
// do not use cpp_function directly to avoid unnecessary reference count change
pkpy::PyVar var = obj.ptr();
pkpy::PyVar callable = var->attr().try_get(name);
@ -287,11 +268,8 @@ namespace pybind11 {
}
template <typename Getter_, typename Setter_, typename... Extras>
handle bind_property(const handle& obj,
const char* name,
Getter_&& getter_,
Setter_&& setter_,
const Extras&... extras) {
handle
bind_property(const handle& obj, const char* name, Getter_&& getter_, Setter_&& setter_, const Extras&... extras) {
pkpy::PyVar var = obj.ptr();
pkpy::PyVar getter = vm->None;
pkpy::PyVar setter = vm->None;
@ -308,14 +286,12 @@ namespace pybind11 {
auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
if constexpr(std::is_member_object_pointer_v<Getter>) {
return type_caster<member_type_t<Getter>>::cast(
self.*getter,
return type_caster<member_type_t<Getter>>::cast(self.*getter,
return_value_policy::reference_internal,
view[0])
.ptr();
} else {
return type_caster<callable_return_t<Getter>>::cast(
(self.*getter)(),
return type_caster<callable_return_t<Getter>>::cast((self.*getter)(),
return_value_policy::reference_internal,
view[0])
.ptr();
@ -325,8 +301,7 @@ namespace pybind11 {
using Self = std::tuple_element_t<0, callable_args_t<Getter>>;
auto& self = _builtin_cast<instance>(view[0]).cast<Self>();
return type_caster<callable_return_t<Getter>>::cast(
getter(self),
return type_caster<callable_return_t<Getter>>::cast(getter(self),
return_value_policy::reference_internal,
view[0])
.ptr();

View File

@ -24,8 +24,12 @@ namespace pybind11 {
((T*)ptr)->~T();
operator delete (ptr);
},
[](void* dst, const void* src) { new (dst) T(*(const T*)src); },
[](void* dst, void* src) { new (dst) T(std::move(*(T*)src)); },
[](void* dst, const void* src) {
new (dst) T(*(const T*)src);
},
[](void* dst, void* src) {
new (dst) T(std::move(*(T*)src));
},
&typeid(T),
};
return info;
@ -55,8 +59,7 @@ namespace pybind11 {
instance(const instance&) = delete;
instance(instance&& other) noexcept :
flag(other.flag), data(other.data), type(other.type), parent(other.parent) {
instance(instance&& other) noexcept : flag(other.flag), data(other.data), type(other.type), parent(other.parent) {
other.flag = Flag::None;
other.data = nullptr;
other.type = nullptr;
@ -73,8 +76,7 @@ namespace pybind11 {
}
template <typename T>
static pkpy::PyVar
create(T&& value,
static pkpy::PyVar create(T&& value,
pkpy::Type type,
return_value_policy policy = return_value_policy::automatic_reference,
pkpy::PyVar parent = nullptr) noexcept {
@ -128,15 +130,11 @@ namespace pybind11 {
}
~instance() {
if(flag & Flag::Own) {
type->destructor(data);
}
if(flag & Flag::Own) { type->destructor(data); }
}
void _gc_mark(pkpy::VM* vm) const noexcept {
if(parent && (flag & Flag::Ref)) {
PK_OBJ_MARK(parent);
}
if(parent && (flag & Flag::Ref)) { PK_OBJ_MARK(parent); }
}
template <typename T>

View File

@ -2,30 +2,23 @@
#include <pocketpy.h>
namespace pybind11
{
namespace pybind11 {
inline pkpy::VM* vm = nullptr;
inline std::map<pkpy::PyVar, int*>* _ref_counts_map = nullptr;
inline void initialize(bool enable_os = true)
{
inline void initialize(bool enable_os = true) {
vm = new pkpy::VM(enable_os);
_ref_counts_map = new std::map<pkpy::PyVar, int*>();
// use to keep alive PyObject, when the object is hold by C++ side.
vm->heap._gc_marker_ex = [](pkpy::VM* vm)
{
for(auto iter = _ref_counts_map->begin(); iter != _ref_counts_map->end();)
{
vm->heap._gc_marker_ex = [](pkpy::VM* vm) {
for(auto iter = _ref_counts_map->begin(); iter != _ref_counts_map->end();) {
auto ref_count = iter->second;
if(*ref_count != 0)
{
if(*ref_count != 0) {
// if ref count is not zero, then mark it.
PK_OBJ_MARK(iter->first);
++iter;
}
else
{
} else {
// if ref count is zero, then delete it.
iter = _ref_counts_map->erase(iter);
delete ref_count;
@ -34,14 +27,12 @@ namespace pybind11
};
}
inline void finalize()
{
inline void finalize() {
delete _ref_counts_map;
delete vm;
}
enum class return_value_policy : uint8_t
{
enum class return_value_policy : uint8_t {
/**
* This is the default return value policy, which falls back to the policy
* return_value_policy::take_ownership when the return value is a pointer.

View File

@ -191,16 +191,12 @@ namespace pybind11 {
}
~object() {
if(m_ptr != nullptr) {
dec_ref();
}
if(m_ptr != nullptr) { dec_ref(); }
}
protected:
object(const handle& h, bool borrow) : handle(h) {
if(borrow) {
inc_ref();
}
if(borrow) { inc_ref(); }
}
template <typename T>

View File

@ -111,16 +111,14 @@ namespace pybind11 {
template <typename T>
attr_accessor& operator= (T&& value) & {
static_assert(std::is_base_of_v<object, std::decay_t<T>>,
"T must be derived from object");
static_assert(std::is_base_of_v<object, std::decay_t<T>>, "T must be derived from object");
m_ptr = std::forward<T>(value);
return *this;
}
template <typename T>
attr_accessor& operator= (T&& value) && {
static_assert(std::is_base_of_v<object, std::decay_t<T>>,
"T must be derived from object");
static_assert(std::is_base_of_v<object, std::decay_t<T>>, "T must be derived from object");
setattr(*this, key, std::forward<T>(value));
return *this;
}
@ -148,15 +146,13 @@ namespace pybind11 {
template <typename T>
item_accessor& operator= (T&& value) & {
static_assert(std::is_base_of_v<object, std::decay_t<T>>,
"T must be derived from object");
static_assert(std::is_base_of_v<object, std::decay_t<T>>, "T must be derived from object");
m_ptr = std::forward<T>(value);
}
template <typename T>
item_accessor& operator= (object&& value) && {
static_assert(std::is_base_of_v<object, std::decay_t<T>>,
"T must be derived from object");
static_assert(std::is_base_of_v<object, std::decay_t<T>>, "T must be derived from object");
setitem(*this, key, std::forward<T>(value));
}
};
@ -187,13 +183,9 @@ namespace pybind11 {
template <typename T>
handle type::handle_of() {
if constexpr(std::is_same_v<T, object>) {
return vm->_t(vm->tp_object);
}
if constexpr(std::is_same_v<T, object>) { return vm->_t(vm->tp_object); }
#define PYBIND11_TYPE_MAPPER(type, tp) \
else if constexpr(std::is_same_v<T, type>) { \
return vm->_t(vm->tp); \
}
else if constexpr(std::is_same_v<T, type>) { return vm->_t(vm->tp); }
PYBIND11_TYPE_MAPPER(type, tp_type)
PYBIND11_TYPE_MAPPER(str, tp_str)
PYBIND11_TYPE_MAPPER(int_, tp_int)
@ -207,9 +199,7 @@ namespace pybind11 {
#undef PYBIND11_TYPE_MAPPER
else {
auto result = vm->_cxx_typeid_map.find(typeid(T));
if(result != vm->_cxx_typeid_map.end()) {
return vm->_t(result->second);
}
if(result != vm->_cxx_typeid_map.end()) { return vm->_t(result->second); }
vm->TypeError("Type not registered");
}

View File

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

View File

@ -73,9 +73,7 @@ struct DoubleLinkedList{
_size--;
}
bool empty() const {
return _size == 0;
}
bool empty() const { return _size == 0; }
int size() const { return _size; }
@ -92,8 +90,8 @@ struct DoubleLinkedList{
template <int __BlockSize>
struct MemoryPool {
static const int __MaxBlocks = 256*1024 / __BlockSize;
static const int __MinArenaCount = PK_GC_MIN_THRESHOLD*100 / (256*1024);
const static int __MaxBlocks = 256 * 1024 / __BlockSize;
const static int __MinArenaCount = PK_GC_MIN_THRESHOLD * 100 / (256 * 1024);
struct Block {
void* arena;
@ -113,11 +111,10 @@ struct MemoryPool{
}
bool empty() const { return _free_list_size == 0; }
bool full() const { return _free_list_size == __MaxBlocks; }
size_t allocated_size() const{
return __BlockSize * (__MaxBlocks - _free_list_size);
}
size_t allocated_size() const { return __BlockSize * (__MaxBlocks - _free_list_size); }
Block* alloc() {
assert(!empty());
@ -149,9 +146,7 @@ struct MemoryPool{
return (char*)p + sizeof(void*);
}
if(_arenas.empty()){
_arenas.push_back(new Arena());
}
if(_arenas.empty()) { _arenas.push_back(new Arena()); }
Arena* arena = _arenas.back();
void* p = arena->alloc()->data;
if(arena->empty()) {
@ -191,8 +186,12 @@ struct MemoryPool{
}
~MemoryPool() {
_arenas.apply([](Arena* arena){ delete arena; });
_empty_arenas.apply([](Arena* arena){ delete arena; });
_arenas.apply([](Arena* arena) {
delete arena;
});
_empty_arenas.apply([](Arena* arena) {
delete arena;
});
}
};
@ -216,9 +215,7 @@ struct FixedMemoryPool{
}
}
bool is_valid(void* p){
return p >= _blocks && p < _blocks + BlockCount;
}
bool is_valid(void* p) { return p >= _blocks && p < _blocks + BlockCount; }
void* alloc() {
PK_GLOBAL_SCOPE_LOCK()
@ -246,12 +243,17 @@ static FixedMemoryPool<kPoolFrameBlockSize, 128> PoolFrame;
static MemoryPool<80> PoolObject;
void* PoolExpr_alloc() noexcept { return PoolExpr.alloc(); }
void PoolExpr_dealloc(void* p) noexcept { PoolExpr.dealloc(p); }
void* PoolFrame_alloc() noexcept { return PoolFrame.alloc(); }
void PoolFrame_dealloc(void* p) noexcept { PoolFrame.dealloc(p); }
void* PoolObject_alloc(size_t size) noexcept { return PoolObject.alloc(size); }
void PoolObject_dealloc(void* p) noexcept { PoolObject.dealloc(p); }
void PoolObject_shrink_to_fit() noexcept { PoolObject.shrink_to_fit(); }
} // namespace pkpy

View File

@ -33,38 +33,30 @@ int utf8len(unsigned char c, bool suppress){
} \
this->data[this->size] = '\0';
Str::Str(): size(0), is_ascii(true), data(_inlined) {
_inlined[0] = '\0';
}
Str::Str() : size(0), is_ascii(true), data(_inlined) { _inlined[0] = '\0'; }
Str::Str(int size, bool is_ascii): size(size), is_ascii(is_ascii) {
PK_STR_ALLOCATE()
}
Str::Str(int size, bool is_ascii) :
size(size), is_ascii(is_ascii){PK_STR_ALLOCATE()}
Str::Str(const std::string& s): size(s.size()), is_ascii(true) {
PK_STR_ALLOCATE()
PK_STR_COPY_INIT(s)
}
Str::Str(const std::string& s) :
size(s.size()), is_ascii(true){PK_STR_ALLOCATE() PK_STR_COPY_INIT(s)}
Str::Str(std::string_view s): size(s.size()), is_ascii(true) {
PK_STR_ALLOCATE()
PK_STR_COPY_INIT(s)
}
Str::Str(std::string_view s) :
size(s.size()), is_ascii(true){PK_STR_ALLOCATE() PK_STR_COPY_INIT(s)}
Str::Str(const char* s): size(strlen(s)), is_ascii(true) {
PK_STR_ALLOCATE()
PK_STR_COPY_INIT(s)
}
Str::Str(const char* s) :
size(strlen(s)), is_ascii(true){PK_STR_ALLOCATE() PK_STR_COPY_INIT(s)}
Str::Str(const char* s, int len): size(len), is_ascii(true) {
PK_STR_ALLOCATE()
PK_STR_COPY_INIT(s)
}
Str::Str(const char* s, int len) :
size(len), is_ascii(true){PK_STR_ALLOCATE() PK_STR_COPY_INIT(s)}
Str::Str(std::pair<char*, int> detached) : size(detached.second), is_ascii(true) {
this->data = detached.first;
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');
}
@ -78,7 +70,8 @@ int utf8len(unsigned char c, bool suppress){
Str::Str(Str&& other) : size(other.size), is_ascii(other.is_ascii) {
if(other.is_inlined()) {
data = _inlined;
for(int i=0; i<size; i++) _inlined[i] = other._inlined[i];
for(int i = 0; i < size; i++)
_inlined[i] = other._inlined[i];
data[size] = '\0';
} else {
data = other.data;
@ -94,13 +87,9 @@ int utf8len(unsigned char c, bool suppress){
return other + str;
}
std::ostream& operator<<(std::ostream& os, const Str& str){
return os << str.sv();
}
std::ostream& operator<< (std::ostream& os, const Str& str) { return os << str.sv(); }
bool operator<(const std::string_view other, const Str& str){
return other < str.sv();
}
bool operator< (const std::string_view other, const Str& str) { return other < str.sv(); }
Str& Str::operator= (const Str& other) {
if(!is_inlined()) std::free(data);
@ -145,33 +134,19 @@ int utf8len(unsigned char c, bool suppress){
return memcmp(data, other.data(), size) != 0;
}
bool Str::operator==(const char* p) const {
return *this == std::string_view(p);
}
bool Str::operator== (const char* p) const { return *this == std::string_view(p); }
bool Str::operator!=(const char* p) const {
return *this != std::string_view(p);
}
bool Str::operator!= (const char* p) const { return *this != std::string_view(p); }
bool Str::operator<(const Str& other) const {
return this->sv() < other.sv();
}
bool Str::operator< (const Str& other) const { return this->sv() < other.sv(); }
bool Str::operator<(const std::string_view other) const {
return this->sv() < other;
}
bool Str::operator< (const std::string_view other) const { return this->sv() < other; }
bool Str::operator>(const Str& other) const {
return this->sv() > other.sv();
}
bool Str::operator> (const Str& other) const { return this->sv() > other.sv(); }
bool Str::operator<=(const Str& other) const {
return this->sv() <= other.sv();
}
bool Str::operator<= (const Str& other) const { return this->sv() <= other.sv(); }
bool Str::operator>=(const Str& other) const {
return this->sv() >= other.sv();
}
bool Str::operator>= (const Str& other) const { return this->sv() >= other.sv(); }
Str::~Str() {
if(!is_inlined()) std::free(data);
@ -184,18 +159,18 @@ int utf8len(unsigned char c, bool suppress){
return ret;
}
Str Str::substr(int start) const {
return substr(start, size - start);
}
Str Str::substr(int start) const { return substr(start, size - start); }
Str Str::strip(bool left, bool right, const Str& chars) const {
int L = 0;
int R = u8_length();
if(left) {
while(L < R && chars.index(u8_getitem(L)) != -1) L++;
while(L < R && chars.index(u8_getitem(L)) != -1)
L++;
}
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);
}
@ -205,10 +180,12 @@ int utf8len(unsigned char c, bool suppress){
int L = 0;
int R = size;
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) {
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);
} else {
@ -300,7 +277,6 @@ int utf8len(unsigned char c, bool suppress){
return ss.str();
}
int Str::_unicode_index_to_byte(int i) const {
if(is_ascii) return i;
int j = 0;
@ -335,9 +311,7 @@ int utf8len(unsigned char c, bool suppress){
return ss.str();
}
int Str::u8_length() const {
return _byte_index_to_unicode(size);
}
int Str::u8_length() const { return _byte_index_to_unicode(size); }
vector<std::string_view> Str::split(const Str& sep) const {
vector<std::string_view> result;
@ -417,22 +391,26 @@ int utf8len(unsigned char c, bool suppress){
}
SStream& SStream::operator<< (const Str& s) {
for(char c: s) buffer.push_back(c);
for(char c: s)
buffer.push_back(c);
return *this;
}
SStream& SStream::operator<< (const char* s) {
while(*s) buffer.push_back(*s++);
while(*s)
buffer.push_back(*s++);
return *this;
}
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;
}
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;
}
@ -441,18 +419,14 @@ int utf8len(unsigned char c, bool suppress){
return *this;
}
SStream& SStream::operator<<(StrName sn){
return *this << sn.sv();
}
SStream& SStream::operator<< (StrName sn) { return *this << sn.sv(); }
SStream& SStream::operator<< (size_t val) {
// size_t could be out of range of `i64`, use `std::to_string` instead
return (*this) << std::to_string(val);
}
SStream& SStream::operator<<(int val){
return (*this) << static_cast<i64>(val);
}
SStream& SStream::operator<< (int val) { return (*this) << static_cast<i64>(val); }
SStream& SStream::operator<< (i64 val) {
// str(-2**64).__len__() == 21
@ -475,12 +449,8 @@ int utf8len(unsigned char c, bool suppress){
}
SStream& SStream::operator<< (f64 val) {
if(std::isinf(val)){
return (*this) << (val > 0 ? "inf" : "-inf");
}
if(std::isnan(val)){
return (*this) << "nan";
}
if(std::isinf(val)) { return (*this) << (val > 0 ? "inf" : "-inf"); }
if(std::isnan(val)) { return (*this) << "nan"; }
char b[32];
if(_precision == -1) {
int prec = std::numeric_limits<f64>::max_digits10 - 1;
@ -542,8 +512,6 @@ int utf8len(unsigned char c, bool suppress){
#undef PK_STR_ALLOCATE
#undef PK_STR_COPY_INIT
// unary operators
const StrName __repr__ = StrName::get("__repr__");
const StrName __str__ = StrName::get("__str__");
@ -601,5 +569,4 @@ const StrName pk_id_set = StrName::get("set");
const StrName pk_id_long = StrName::get("long");
const StrName pk_id_complex = StrName::get("complex");
} // namespace pkpy

View File

@ -31,26 +31,21 @@ namespace pkpy{
}
void Compiler::pop_context() {
if(!ctx()->s_expr.empty()){
throw std::runtime_error("!ctx()->s_expr.empty()");
}
if(!ctx()->s_expr.empty()) { throw std::runtime_error("!ctx()->s_expr.empty()"); }
// add a `return None` in the end as a guard
// previously, we only do this if the last opcode is not a return
// however, this is buggy...since there may be a jump to the end (out of bound) even if the last opcode is a return
ctx()->emit_(OP_RETURN_VALUE, 1, BC_KEEPLINE, true);
// find the last valid token
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;
// some check here
auto& codes = ctx()->co->codes;
if(ctx()->co->nlocals > PK_MAX_CO_VARNAMES){
SyntaxError("maximum number of local variables exceeded");
}
if(ctx()->co->consts.size() > 65530){
SyntaxError("maximum number of constants exceeded");
}
if(ctx()->co->nlocals > PK_MAX_CO_VARNAMES) { SyntaxError("maximum number of local variables exceeded"); }
if(ctx()->co->consts.size() > 65530) { SyntaxError("maximum number of constants exceeded"); }
// pre-compute LOOP_BREAK and LOOP_CONTINUE
for(int i = 0; i < codes.size(); i++) {
Bytecode& bc = codes[i];
@ -87,13 +82,11 @@ namespace pkpy{
bool is_empty = false;
if(func->code->codes.size() == 1) {
Bytecode bc = func->code->codes[0];
if(bc.op == OP_RETURN_VALUE && bc.arg == 1){
is_empty = true;
}
if(bc.op == OP_RETURN_VALUE && bc.arg == 1) { is_empty = true; }
}
if(is_empty) func->type = FuncType::EMPTY;
}
else func->type = FuncType::NORMAL;
} else
func->type = FuncType::NORMAL;
}
assert(func->type != FuncType::UNSET);
@ -106,6 +99,7 @@ namespace pkpy{
if(initialized) return;
initialized = true;
// clang-format off
// http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
#define PK_METHOD(name) &Compiler::name
#define PK_NO_INFIX nullptr, PREC_LOWEST
@ -158,6 +152,7 @@ namespace pkpy{
#undef PK_METHOD
#undef PK_NO_INFIX
// clang-format on
}
bool Compiler::match(TokenIndex expected) {
@ -167,31 +162,27 @@ namespace pkpy{
}
void Compiler::consume(TokenIndex expected) {
if (!match(expected)){
SyntaxError(
_S("expected '", TK_STR(expected), "', got '", TK_STR(curr().type), "'")
);
}
if(!match(expected)) { SyntaxError(_S("expected '", TK_STR(expected), "', got '", TK_STR(curr().type), "'")); }
}
bool Compiler::match_newlines_repl(){
return match_newlines(mode()==REPL_MODE);
}
bool Compiler::match_newlines_repl() { return match_newlines(mode() == REPL_MODE); }
bool Compiler::match_newlines(bool repl_throw) {
bool consumed = false;
if(curr().type == TK("@eol")) {
while (curr().type == TK("@eol")) advance();
while(curr().type == TK("@eol"))
advance();
consumed = true;
}
if (repl_throw && curr().type == TK("@eof")){
throw NeedMoreLines(ctx()->is_compiling_class);
}
if(repl_throw && curr().type == TK("@eof")) { throw NeedMoreLines(ctx()->is_compiling_class); }
return consumed;
}
bool Compiler::match_end_stmt() {
if (match(TK(";"))) { match_newlines(); return true; }
if(match(TK(";"))) {
match_newlines();
return true;
}
if(match_newlines() || curr().type == TK("@eof")) return true;
if(curr().type == TK("@dedent")) return true;
return false;
@ -201,9 +192,7 @@ namespace pkpy{
if(!match_end_stmt()) SyntaxError("expected statement end");
}
void Compiler::EXPR() {
parse_expression(PREC_LOWEST+1);
}
void Compiler::EXPR() { parse_expression(PREC_LOWEST + 1); }
void Compiler::EXPR_TUPLE(bool allow_slice) {
parse_expression(PREC_LOWEST + 1, allow_slice);
@ -232,25 +221,15 @@ namespace pkpy{
return make_expr<TupleExpr>(std::move(items));
}
void Compiler::exprLiteral(){
ctx()->s_expr.push(make_expr<LiteralExpr>(prev().value));
}
void Compiler::exprLiteral() { ctx()->s_expr.push(make_expr<LiteralExpr>(prev().value)); }
void Compiler::exprLong(){
ctx()->s_expr.push(make_expr<LongExpr>(prev().str()));
}
void Compiler::exprLong() { ctx()->s_expr.push(make_expr<LongExpr>(prev().str())); }
void Compiler::exprImag(){
ctx()->s_expr.push(make_expr<ImagExpr>(std::get<f64>(prev().value)));
}
void Compiler::exprImag() { ctx()->s_expr.push(make_expr<ImagExpr>(std::get<f64>(prev().value))); }
void Compiler::exprBytes(){
ctx()->s_expr.push(make_expr<BytesExpr>(std::get<Str>(prev().value)));
}
void Compiler::exprBytes() { ctx()->s_expr.push(make_expr<BytesExpr>(std::get<Str>(prev().value))); }
void Compiler::exprFString(){
ctx()->s_expr.push(make_expr<FStringExpr>(std::get<Str>(prev().value)));
}
void Compiler::exprFString() { ctx()->s_expr.push(make_expr<FStringExpr>(std::get<Str>(prev().value))); }
void Compiler::exprLambda() {
FuncDecl_ decl = push_f_context("<lambda>");
@ -314,18 +293,10 @@ namespace pkpy{
TokenIndex op = prev().type;
parse_expression(PREC_UNARY + 1);
switch(op) {
case TK("-"):
ctx()->s_expr.push(make_expr<NegatedExpr>(ctx()->s_expr.popx()));
break;
case TK("~"):
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;
case TK("-"): ctx()->s_expr.push(make_expr<NegatedExpr>(ctx()->s_expr.popx())); break;
case TK("~"): 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);
}
}
@ -385,9 +356,7 @@ namespace pkpy{
if(curr().type == TK("}")) break;
EXPR();
int star_level = ctx()->s_expr.top()->star_level();
if(star_level==2 || curr().type == TK(":")){
parsing_dict = true;
}
if(star_level == 2 || curr().type == TK(":")) { parsing_dict = true; }
if(parsing_dict) {
auto dict_item = make_expr<DictItemExpr>();
if(star_level == 2) {
@ -405,8 +374,10 @@ namespace pkpy{
}
match_newlines_repl();
if(items.size() == 1 && match(TK("for"))) {
if(parsing_dict) consume_comp(make_expr<DictCompExpr>(), std::move(items[0]));
else consume_comp(make_expr<SetCompExpr>(), std::move(items[0]));
if(parsing_dict)
consume_comp(make_expr<DictCompExpr>(), std::move(items[0]));
else
consume_comp(make_expr<SetCompExpr>(), std::move(items[0]));
consume(TK("}"));
return;
}
@ -456,17 +427,13 @@ namespace pkpy{
void Compiler::exprName() {
Str name = prev().str();
NameScope scope = name_scope();
if(ctx()->global_names.contains(name)){
scope = NAME_GLOBAL;
}
if(ctx()->global_names.contains(name)) { scope = NAME_GLOBAL; }
ctx()->s_expr.push(make_expr<NameExpr>(name, scope));
}
void Compiler::exprAttrib() {
consume(TK("@id"));
ctx()->s_expr.push(
make_expr<AttribExpr>(ctx()->s_expr.popx(), StrName::get(prev().sv()))
);
ctx()->s_expr.push(make_expr<AttribExpr>(ctx()->s_expr.popx(), StrName::get(prev().sv())));
}
void Compiler::exprSlice0() {
@ -517,9 +484,7 @@ namespace pkpy{
ctx()->s_expr.push(std::move(e));
}
void Compiler::exprLiteral0() {
ctx()->s_expr.push(make_expr<Literal0Expr>(prev().type));
}
void Compiler::exprLiteral0() { ctx()->s_expr.push(make_expr<Literal0Expr>(prev().type)); }
void Compiler::compile_block_body(void (Compiler::*callback)()) {
if(callback == nullptr) callback = &Compiler::compile_stmt;
@ -532,9 +497,7 @@ namespace pkpy{
}
return;
}
if(!match_newlines(mode()==REPL_MODE)){
SyntaxError("expected a new line after ':'");
}
if(!match_newlines(mode() == REPL_MODE)) { SyntaxError("expected a new line after ':'"); }
consume(TK("@indent"));
while(curr().type != TK("@dedent")) {
match_newlines();
@ -581,7 +544,8 @@ namespace pkpy{
}
__EAT_DOTS_END:
SStream ss;
for(int i=0; i<dots; i++) ss << '.';
for(int i = 0; i < dots; i++)
ss << '.';
if(dots > 0) {
// @id is optional if dots > 0
@ -688,7 +652,8 @@ __EAT_DOTS_END:
void Compiler::compile_for_loop() {
Expr_ vars = EXPR_VARS();
consume(TK("in"));
EXPR_TUPLE(); ctx()->emit_expr();
EXPR_TUPLE();
ctx()->emit_expr();
ctx()->emit_(OP_GET_ITER_NEW, BC_NOARG, BC_KEEPLINE);
CodeBlock* block = ctx()->enter_block(CodeBlockType::FOR_LOOP);
int for_codei = ctx()->emit_(OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE);
@ -710,9 +675,7 @@ __EAT_DOTS_END:
ctx()->emit_(OP_TRY_ENTER, BC_NOARG, prev().line);
compile_block_body();
small_vector_2<int, 6> patches;
patches.push_back(
ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE)
);
patches.push_back(ctx()->emit_(OP_JUMP_FORWARD, BC_NOARG, BC_KEEPLINE));
ctx()->exit_block();
int finally_entry = -1;
@ -762,7 +725,8 @@ __EAT_DOTS_END:
ctx()->emit_(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE);
// 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) {
i64 target = ctx()->co->codes.size() + 2;
ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
@ -789,8 +753,17 @@ __EAT_DOTS_END:
bool Compiler::try_compile_assignment() {
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();
if(lhs_p->is_starred()) SyntaxError();
if(ctx()->is_compiling_class) SyntaxError("can't use inplace operator in class definition");
@ -806,7 +779,8 @@ __EAT_DOTS_END:
e->emit_(ctx());
bool ok = lhs_p->emit_store_inplace(ctx());
if(!ok) SyntaxError();
} return true;
}
return true;
case TK("="): {
int n = 0;
while(match(TK("="))) {
@ -816,14 +790,16 @@ __EAT_DOTS_END:
// stack size is n+1
Expr_ val = ctx()->s_expr.popx();
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++) {
auto e = ctx()->s_expr.popx();
if(e->is_starred()) SyntaxError();
bool ok = e->emit_store(ctx());
if(!ok) SyntaxError();
}
} return true;
}
return true;
default: return false;
}
}
@ -849,13 +825,15 @@ __EAT_DOTS_END:
break;
case TK("yield"):
if(contexts.size() <= 1) SyntaxError("'yield' outside function");
EXPR_TUPLE(); ctx()->emit_expr();
EXPR_TUPLE();
ctx()->emit_expr();
ctx()->emit_(OP_YIELD_VALUE, BC_NOARG, kw_line);
consume_end_stmt();
break;
case TK("yield from"):
if(contexts.size() <= 1) SyntaxError("'yield from' outside function");
EXPR_TUPLE(); ctx()->emit_expr();
EXPR_TUPLE();
ctx()->emit_expr();
ctx()->emit_(OP_GET_ITER_NEW, BC_NOARG, kw_line);
ctx()->enter_block(CodeBlockType::FOR_LOOP);
@ -869,7 +847,8 @@ __EAT_DOTS_END:
if(match_end_stmt()) {
ctx()->emit_(OP_RETURN_VALUE, 1, kw_line);
} else {
EXPR_TUPLE(); ctx()->emit_expr();
EXPR_TUPLE();
ctx()->emit_expr();
consume_end_stmt();
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, kw_line);
}
@ -892,12 +871,8 @@ __EAT_DOTS_END:
bool is_global = ctx()->global_names.contains(name.sv());
if(is_global) scope = NAME_GLOBAL;
switch(scope) {
case NAME_LOCAL:
ctx()->emit_(OP_INC_FAST, ctx()->add_varname(name), prev().line);
break;
case NAME_GLOBAL:
ctx()->emit_(OP_INC_GLOBAL, name.index, prev().line);
break;
case NAME_LOCAL: ctx()->emit_(OP_INC_FAST, ctx()->add_varname(name), prev().line); break;
case NAME_GLOBAL: ctx()->emit_(OP_INC_GLOBAL, name.index, prev().line); break;
default: SyntaxError(); break;
}
consume_end_stmt();
@ -907,12 +882,8 @@ __EAT_DOTS_END:
consume(TK("@id"));
StrName name(prev().sv());
switch(name_scope()) {
case NAME_LOCAL:
ctx()->emit_(OP_DEC_FAST, ctx()->add_varname(name), prev().line);
break;
case NAME_GLOBAL:
ctx()->emit_(OP_DEC_GLOBAL, name.index, prev().line);
break;
case NAME_LOCAL: ctx()->emit_(OP_DEC_FAST, ctx()->add_varname(name), prev().line); break;
case NAME_GLOBAL: ctx()->emit_(OP_DEC_GLOBAL, name.index, prev().line); break;
default: SyntaxError(); break;
}
consume_end_stmt();
@ -941,7 +912,8 @@ __EAT_DOTS_END:
consume_end_stmt();
break;
case TK("raise"): {
EXPR(); ctx()->emit_expr();
EXPR();
ctx()->emit_expr();
ctx()->emit_(OP_RAISE, BC_NOARG, kw_line);
consume_end_stmt();
} break;
@ -1008,9 +980,7 @@ __EAT_DOTS_END:
}
}
if(!try_compile_assignment()) {
if(!ctx()->s_expr.empty() && ctx()->s_expr.top()->is_starred()){
SyntaxError();
}
if(!ctx()->s_expr.empty() && ctx()->s_expr.top()->is_starred()) { SyntaxError(); }
if(!is_typed_name) {
ctx()->emit_expr();
if((mode() == CELL_MODE || mode() == REPL_MODE) && name_scope() == NAME_GLOBAL) {
@ -1063,9 +1033,7 @@ __EAT_DOTS_END:
ctx()->emit_(OP_BEGIN_CLASS, namei, BC_KEEPLINE);
for(auto& c: this->contexts.container()) {
if(c.is_compiling_class){
SyntaxError("nested class is not allowed");
}
if(c.is_compiling_class) { SyntaxError("nested class is not allowed"); }
}
ctx()->is_compiling_class = true;
compile_block_body();
@ -1087,10 +1055,11 @@ __EAT_DOTS_END:
if(state == 3) SyntaxError("**kwargs should be the last argument");
match_newlines();
if(match(TK("*"))) {
if(state < 1) state = 1;
else SyntaxError("*args should be placed before **kwargs");
}
else if(match(TK("**"))){
if(state < 1)
state = 1;
else
SyntaxError("*args should be placed before **kwargs");
} else if(match(TK("**"))) {
state = 3;
}
consume(TK("@id"));
@ -1098,14 +1067,10 @@ __EAT_DOTS_END:
// check duplicate argument name
for(int j: decl->args) {
if(decl->code->varnames[j] == name) {
SyntaxError("duplicate argument name");
}
if(decl->code->varnames[j] == name) { SyntaxError("duplicate argument name"); }
}
for(auto& kv: decl->kwargs) {
if(decl->code->varnames[kv.index] == name){
SyntaxError("duplicate argument name");
}
if(decl->code->varnames[kv.index] == name) { SyntaxError("duplicate argument name"); }
}
if(decl->starred_arg != -1 && decl->code->varnames[decl->starred_arg] == name) {
SyntaxError("duplicate argument name");
@ -1118,11 +1083,8 @@ __EAT_DOTS_END:
if(enable_type_hints && match(TK(":"))) consume_type_hints();
if(state == 0 && curr().type == TK("=")) state = 2;
int index = ctx()->add_varname(name);
switch (state)
{
case 0:
decl->args.push_back(index);
break;
switch(state) {
case 0: decl->args.push_back(index); break;
case 1:
decl->starred_arg = index;
state += 1;
@ -1130,9 +1092,7 @@ __EAT_DOTS_END:
case 2: {
consume(TK("="));
PyVar value = read_literal();
if(value == nullptr){
SyntaxError(Str("default argument must be a literal"));
}
if(value == nullptr) { SyntaxError(Str("default argument must be a literal")); }
decl->add_kwarg(index, name, value);
} break;
case 3:
@ -1157,7 +1117,8 @@ __EAT_DOTS_END:
pop_context();
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];
if(is_type(c, vm->tp_str)) {
decl->code->codes[0].op = OP_NO_OP;
@ -1180,15 +1141,9 @@ __EAT_DOTS_END:
PyVar Compiler::to_object(const TokenValue& value) {
PyVar obj = nullptr;
if(std::holds_alternative<i64>(value)){
obj = VAR(std::get<i64>(value));
}
if(std::holds_alternative<f64>(value)){
obj = VAR(std::get<f64>(value));
}
if(std::holds_alternative<Str>(value)){
obj = VAR(std::get<Str>(value));
}
if(std::holds_alternative<i64>(value)) { obj = VAR(std::get<i64>(value)); }
if(std::holds_alternative<f64>(value)) { obj = VAR(std::get<f64>(value)); }
if(std::holds_alternative<Str>(value)) { obj = VAR(std::get<Str>(value)); }
assert(obj != nullptr);
return obj;
}
@ -1223,8 +1178,8 @@ __EAT_DOTS_END:
return nullptr;
}
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)){
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)) {
this->vm = vm;
this->unknown_global_scope = unknown_global_scope;
init_pratt_rules();
@ -1243,7 +1198,8 @@ __EAT_DOTS_END:
if(it == token_indices.end()) {
token_indices[token.sv()] = 0;
// assert no '\n' in token.sv()
for(char c: token.sv()) assert(c!='\n');
for(char c: token.sv())
assert(c != '\n');
}
}
}
@ -1258,15 +1214,18 @@ __EAT_DOTS_END:
for(int i = 0; i < tokens.size(); i++) {
const Token& token = tokens[i];
ss << (int)token.type << ',';
if(is_raw_string_used(token.type)){
ss << token_indices[token.sv()] << ',';
}
if(i>0 && tokens[i-1].line == token.line) ss << ',';
else ss << token.line << ',';
if(i>0 && tokens[i-1].brackets_level == token.brackets_level) ss << ',';
else ss << token.brackets_level << ',';
if(is_raw_string_used(token.type)) { ss << token_indices[token.sv()] << ','; }
if(i > 0 && tokens[i - 1].line == token.line)
ss << ',';
else
ss << token.line << ',';
if(i > 0 && tokens[i - 1].brackets_level == token.brackets_level)
ss << ',';
else
ss << token.brackets_level << ',';
// visit token value
std::visit([&ss](auto&& arg){
std::visit(
[&ss](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr(std::is_same_v<T, i64>) {
ss << 'I' << arg;
@ -1274,10 +1233,12 @@ __EAT_DOTS_END:
ss << 'F' << arg;
} else if constexpr(std::is_same_v<T, Str>) {
ss << 'S';
for(char c: arg) ss.write_hex((unsigned char)c);
for(char c: arg)
ss.write_hex((unsigned char)c);
}
ss << '\n';
}, token.value);
},
token.value);
}
return ss.str();
}
@ -1291,9 +1252,7 @@ __EAT_DOTS_END:
Str error = _S("precompiled version mismatch: ", version, "!=" PK_VERSION);
throw std::runtime_error(error.c_str());
}
if(deserializer.read_uint('\n') != (i64)mode()){
throw std::runtime_error("precompiled mode mismatch");
}
if(deserializer.read_uint('\n') != (i64)mode()) { throw std::runtime_error("precompiled mode mismatch"); }
int count = deserializer.read_count();
vector<Str>& precompiled_tokens = lexer.src->_precompiled_tokens;
@ -1330,9 +1289,7 @@ __EAT_DOTS_END:
switch(type) {
case 'I': t.value = deserializer.read_uint('\n'); break;
case 'F': t.value = deserializer.read_float('\n'); break;
case 'S':
t.value = deserializer.read_string_from_hex('\n');
break;
case 'S': t.value = deserializer.read_string_from_hex('\n'); break;
default: t.value = {}; break;
}
tokens.push_back(t);
@ -1354,7 +1311,8 @@ __EAT_DOTS_END:
match_newlines(); // skip possible leading '\n'
if(mode() == EVAL_MODE) {
EXPR_TUPLE(); ctx()->emit_expr();
EXPR_TUPLE();
ctx()->emit_expr();
consume(TK("@eof"));
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
pop_context();
@ -1388,7 +1346,8 @@ __EAT_DOTS_END:
std::string_view TokenDeserializer::read_string(char c) {
const char* start = curr;
while(*curr != c) curr++;
while(*curr != c)
curr++;
std::string_view retval(start, curr - start);
curr++; // skip the delimiter
return retval;
@ -1399,13 +1358,19 @@ __EAT_DOTS_END:
char* buffer = (char*)std::malloc(s.size() / 2 + 1);
for(int i = 0; i < s.size(); i += 2) {
char c = 0;
if(s[i]>='0' && s[i]<='9') c += s[i]-'0';
else if(s[i]>='a' && s[i]<='f') c += s[i]-'a'+10;
else assert(false);
if(s[i] >= '0' && s[i] <= '9')
c += s[i] - '0';
else if(s[i] >= 'a' && s[i] <= 'f')
c += s[i] - 'a' + 10;
else
assert(false);
c <<= 4;
if(s[i+1]>='0' && s[i+1]<='9') c += s[i+1]-'0';
else if(s[i+1]>='a' && s[i+1]<='f') c += s[i+1]-'a'+10;
else assert(false);
if(s[i + 1] >= '0' && s[i + 1] <= '9')
c += s[i + 1] - '0';
else if(s[i + 1] >= 'a' && s[i + 1] <= 'f')
c += s[i + 1] - 'a' + 10;
else
assert(false);
buffer[i / 2] = c;
}
buffer[s.size() / 2] = 0;

View File

@ -6,13 +6,12 @@ namespace pkpy{
inline bool is_identifier(std::string_view s) {
if(s.empty()) return false;
if(!isalpha(s[0]) && s[0] != '_') return false;
for(char c: s) if(!isalnum(c) && c != '_') return false;
for(char c: s)
if(!isalnum(c) && c != '_') return false;
return true;
}
inline bool is_small_int(i64 value){
return value >= INT16_MIN && value <= INT16_MAX;
}
inline bool is_small_int(i64 value) { return value >= INT16_MIN && value <= INT16_MAX; }
int CodeEmitContext::get_loop() const {
int index = curr_iblock;
@ -53,8 +52,10 @@ namespace pkpy{
co->lines.push_back(CodeObject::LineInfo{line, is_virtual, curr_iblock});
int i = co->codes.size() - 1;
if(line == BC_KEEPLINE) {
if(i >= 1) co->lines[i].lineno = co->lines[i-1].lineno;
else co->lines[i].lineno = 1;
if(i >= 1)
co->lines[i].lineno = co->lines[i - 1].lineno;
else
co->lines[i].lineno = 1;
}
return i;
}
@ -147,20 +148,13 @@ namespace pkpy{
void CodeEmitContext::emit_store_name(NameScope scope, StrName name, int line) {
switch(scope) {
case NAME_LOCAL:
emit_(OP_STORE_FAST, add_varname(name), line);
break;
case NAME_GLOBAL:
emit_(OP_STORE_GLOBAL, StrName(name).index, line);
break;
case NAME_GLOBAL_UNKNOWN:
emit_(OP_STORE_NAME, StrName(name).index, line);
break;
case NAME_LOCAL: emit_(OP_STORE_FAST, add_varname(name), line); break;
case NAME_GLOBAL: emit_(OP_STORE_GLOBAL, StrName(name).index, line); break;
case NAME_GLOBAL_UNKNOWN: emit_(OP_STORE_NAME, StrName(name).index, line); break;
default: assert(false); break;
}
}
void NameExpr::emit_(CodeEmitContext* ctx) {
int index = ctx->co->varnames_inv.try_get(name);
if(scope == NAME_LOCAL && index >= 0) {
@ -182,15 +176,9 @@ namespace pkpy{
bool NameExpr::emit_del(CodeEmitContext* ctx) {
switch(scope) {
case NAME_LOCAL:
ctx->emit_(OP_DELETE_FAST, ctx->add_varname(name), line);
break;
case NAME_GLOBAL:
ctx->emit_(OP_DELETE_GLOBAL, StrName(name).index, line);
break;
case NAME_GLOBAL_UNKNOWN:
ctx->emit_(OP_DELETE_NAME, StrName(name).index, line);
break;
case NAME_LOCAL: ctx->emit_(OP_DELETE_FAST, ctx->add_varname(name), line); break;
case NAME_GLOBAL: ctx->emit_(OP_DELETE_GLOBAL, StrName(name).index, line); break;
case NAME_GLOBAL_UNKNOWN: ctx->emit_(OP_DELETE_NAME, StrName(name).index, line); break;
default: assert(false); break;
}
return true;
@ -305,7 +293,6 @@ namespace pkpy{
ctx->emit_(OP_UNARY_NEGATIVE, BC_NOARG, line);
}
void SliceExpr::emit_(CodeEmitContext* ctx) {
if(start) {
start->emit_(ctx);
@ -345,8 +332,10 @@ namespace pkpy{
int starred_i = -1;
for(int i = 0; i < items.size(); i++) {
if(!items[i]->is_starred()) continue;
if(starred_i == -1) starred_i = i;
else return false; // multiple StarredExpr not allowed
if(starred_i == -1)
starred_i = i;
else
return false; // multiple StarredExpr not allowed
}
if(starred_i == -1) {
@ -412,13 +401,18 @@ namespace pkpy{
ctx->exit_block();
}
void FStringExpr::_load_simple_expr(CodeEmitContext* ctx, Str expr) {
bool repr = false;
if(expr.size >= 2 && expr.end()[-2] == '!') {
switch(expr.end()[-1]) {
case 'r': repr = true; expr = expr.substr(0, expr.size-2); break;
case 's': repr = false; expr = expr.substr(0, expr.size-2); break;
case 'r':
repr = true;
expr = expr.substr(0, expr.size - 2);
break;
case 's':
repr = false;
expr = expr.substr(0, expr.size - 2);
break;
default: break; // nothing happens
}
}
@ -445,19 +439,19 @@ namespace pkpy{
ctx->emit_(OP_FSTRING_EVAL, index, line);
}
if(repr){
ctx->emit_(OP_REPR, BC_NOARG, line);
}
if(repr) { ctx->emit_(OP_REPR, BC_NOARG, line); }
}
static bool is_fmt_valid_char(char c) {
switch(c) {
// clang-format off
case '-': case '=': case '*': case '#': case '@': case '!': case '~':
case '<': case '>': case '^':
case '.': case 'f': case 'd': case 's':
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
return true;
default: return false;
// clang-format on
}
}
@ -478,7 +472,11 @@ namespace pkpy{
Str spec = expr.substr(conon + 1);
// filter some invalid spec
bool ok = true;
for(char c: spec) if(!is_fmt_valid_char(c)){ ok = false; break; }
for(char c: spec)
if(!is_fmt_valid_char(c)) {
ok = false;
break;
}
if(ok) {
_load_simple_expr(ctx, expr.substr(0, conon));
ctx->emit_(OP_FORMAT_STRING, ctx->add_const_string(spec.sv()), line);
@ -520,7 +518,8 @@ namespace pkpy{
} else {
// literal
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);
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(literal.sv()), line);
count++;
@ -540,7 +539,6 @@ namespace pkpy{
ctx->emit_(OP_BUILD_STRING, count, line);
}
void SubscrExpr::emit_(CodeEmitContext* ctx) {
a->emit_(ctx);
b->emit_(ctx);
@ -628,8 +626,10 @@ namespace pkpy{
void CallExpr::emit_(CodeEmitContext* ctx) {
bool vargs = false;
bool vkwargs = false;
for(auto& arg: args) if(arg->is_starred()) vargs = true;
for(auto& item: kwargs) if(item.second->is_starred()) vkwargs = true;
for(auto& arg: args)
if(arg->is_starred()) vargs = true;
for(auto& item: kwargs)
if(item.second->is_starred()) vkwargs = true;
// if callable is a AttrExpr, we should try to use `fast_call` instead of use `boundmethod` proxy
if(callable->is_attrib()) {
@ -641,7 +641,8 @@ namespace pkpy{
}
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);
if(!kwargs.empty()) {
@ -664,7 +665,8 @@ namespace pkpy{
}
} else {
// vectorcall protocol
for(auto& item: args) item->emit_(ctx);
for(auto& item: args)
item->emit_(ctx);
for(auto& item: kwargs) {
i64 _val = StrName(item.first.sv()).index;
ctx->emit_int(_val, line);
@ -676,11 +678,14 @@ namespace pkpy{
}
}
bool BinaryExpr::is_compare() const {
switch(op) {
case TK("<"): case TK("<="): case TK("=="):
case TK("!="): case TK(">"): case TK(">="): return true;
case TK("<"):
case TK("<="):
case TK("=="):
case TK("!="):
case TK(">"):
case TK(">="): return true;
default: return false;
}
}
@ -755,7 +760,8 @@ namespace pkpy{
default: assert(false);
}
for(int i: jmps) ctx->patch_jump(i);
for(int i: jmps)
ctx->patch_jump(i);
}
void TernaryExpr::emit_(CodeEmitContext* ctx) {

View File

@ -2,17 +2,21 @@
namespace pkpy {
// clang-format off
static const uint32_t kLoRangeA[] = {170,186,443,448,660,1488,1519,1568,1601,1646,1649,1749,1774,1786,1791,1808,1810,1869,1969,1994,2048,2112,2144,2208,2230,2308,2365,2384,2392,2418,2437,2447,2451,2474,2482,2486,2493,2510,2524,2527,2544,2556,2565,2575,2579,2602,2610,2613,2616,2649,2654,2674,2693,2703,2707,2730,2738,2741,2749,2768,2784,2809,2821,2831,2835,2858,2866,2869,2877,2908,2911,2929,2947,2949,2958,2962,2969,2972,2974,2979,2984,2990,3024,3077,3086,3090,3114,3133,3160,3168,3200,3205,3214,3218,3242,3253,3261,3294,3296,3313,3333,3342,3346,3389,3406,3412,3423,3450,3461,3482,3507,3517,3520,3585,3634,3648,3713,3716,3718,3724,3749,3751,3762,3773,3776,3804,3840,3904,3913,3976,4096,4159,4176,4186,4193,4197,4206,4213,4238,4352,4682,4688,4696,4698,4704,4746,4752,4786,4792,4800,4802,4808,4824,4882,4888,4992,5121,5743,5761,5792,5873,5888,5902,5920,5952,5984,5998,6016,6108,6176,6212,6272,6279,6314,6320,6400,6480,6512,6528,6576,6656,6688,6917,6981,7043,7086,7098,7168,7245,7258,7401,7406,7413,7418,8501,11568,11648,11680,11688,11696,11704,11712,11720,11728,11736,12294,12348,12353,12447,12449,12543,12549,12593,12704,12784,13312,19968,40960,40982,42192,42240,42512,42538,42606,42656,42895,42999,43003,43011,43015,43020,43072,43138,43250,43259,43261,43274,43312,43360,43396,43488,43495,43514,43520,43584,43588,43616,43633,43642,43646,43697,43701,43705,43712,43714,43739,43744,43762,43777,43785,43793,43808,43816,43968,44032,55216,55243,63744,64112,64285,64287,64298,64312,64318,64320,64323,64326,64467,64848,64914,65008,65136,65142,65382,65393,65440,65474,65482,65490,65498,65536,65549,65576,65596,65599,65616,65664,66176,66208,66304,66349,66370,66384,66432,66464,66504,66640,66816,66864,67072,67392,67424,67584,67592,67594,67639,67644,67647,67680,67712,67808,67828,67840,67872,67968,68030,68096,68112,68117,68121,68192,68224,68288,68297,68352,68416,68448,68480,68608,68864,69376,69415,69424,69600,69635,69763,69840,69891,69956,69968,70006,70019,70081,70106,70108,70144,70163,70272,70280,70282,70287,70303,70320,70405,70415,70419,70442,70450,70453,70461,70480,70493,70656,70727,70751,70784,70852,70855,71040,71128,71168,71236,71296,71352,71424,71680,71935,72096,72106,72161,72163,72192,72203,72250,72272,72284,72349,72384,72704,72714,72768,72818,72960,72968,72971,73030,73056,73063,73066,73112,73440,73728,74880,77824,82944,92160,92736,92880,92928,93027,93053,93952,94032,94208,100352,110592,110928,110948,110960,113664,113776,113792,113808,123136,123214,123584,124928,126464,126469,126497,126500,126503,126505,126516,126521,126523,126530,126535,126537,126539,126541,126545,126548,126551,126553,126555,126557,126559,126561,126564,126567,126572,126580,126585,126590,126592,126603,126625,126629,126635,131072,173824,177984,178208,183984,194560};
static const uint32_t kLoRangeB[] = {170,186,443,451,660,1514,1522,1599,1610,1647,1747,1749,1775,1788,1791,1808,1839,1957,1969,2026,2069,2136,2154,2228,2237,2361,2365,2384,2401,2432,2444,2448,2472,2480,2482,2489,2493,2510,2525,2529,2545,2556,2570,2576,2600,2608,2611,2614,2617,2652,2654,2676,2701,2705,2728,2736,2739,2745,2749,2768,2785,2809,2828,2832,2856,2864,2867,2873,2877,2909,2913,2929,2947,2954,2960,2965,2970,2972,2975,2980,2986,3001,3024,3084,3088,3112,3129,3133,3162,3169,3200,3212,3216,3240,3251,3257,3261,3294,3297,3314,3340,3344,3386,3389,3406,3414,3425,3455,3478,3505,3515,3517,3526,3632,3635,3653,3714,3716,3722,3747,3749,3760,3763,3773,3780,3807,3840,3911,3948,3980,4138,4159,4181,4189,4193,4198,4208,4225,4238,4680,4685,4694,4696,4701,4744,4749,4784,4789,4798,4800,4805,4822,4880,4885,4954,5007,5740,5759,5786,5866,5880,5900,5905,5937,5969,5996,6000,6067,6108,6210,6264,6276,6312,6314,6389,6430,6509,6516,6571,6601,6678,6740,6963,6987,7072,7087,7141,7203,7247,7287,7404,7411,7414,7418,8504,11623,11670,11686,11694,11702,11710,11718,11726,11734,11742,12294,12348,12438,12447,12538,12543,12591,12686,12730,12799,19893,40943,40980,42124,42231,42507,42527,42539,42606,42725,42895,42999,43009,43013,43018,43042,43123,43187,43255,43259,43262,43301,43334,43388,43442,43492,43503,43518,43560,43586,43595,43631,43638,43642,43695,43697,43702,43709,43712,43714,43740,43754,43762,43782,43790,43798,43814,43822,44002,55203,55238,55291,64109,64217,64285,64296,64310,64316,64318,64321,64324,64433,64829,64911,64967,65019,65140,65276,65391,65437,65470,65479,65487,65495,65500,65547,65574,65594,65597,65613,65629,65786,66204,66256,66335,66368,66377,66421,66461,66499,66511,66717,66855,66915,67382,67413,67431,67589,67592,67637,67640,67644,67669,67702,67742,67826,67829,67861,67897,68023,68031,68096,68115,68119,68149,68220,68252,68295,68324,68405,68437,68466,68497,68680,68899,69404,69415,69445,69622,69687,69807,69864,69926,69956,70002,70006,70066,70084,70106,70108,70161,70187,70278,70280,70285,70301,70312,70366,70412,70416,70440,70448,70451,70457,70461,70480,70497,70708,70730,70751,70831,70853,70855,71086,71131,71215,71236,71338,71352,71450,71723,71935,72103,72144,72161,72163,72192,72242,72250,72272,72329,72349,72440,72712,72750,72768,72847,72966,72969,73008,73030,73061,73064,73097,73112,73458,74649,75075,78894,83526,92728,92766,92909,92975,93047,93071,94026,94032,100343,101106,110878,110930,110951,111355,113770,113788,113800,113817,123180,123214,123627,125124,126467,126495,126498,126500,126503,126514,126519,126521,126523,126530,126535,126537,126539,126543,126546,126548,126551,126553,126555,126557,126559,126562,126564,126570,126578,126583,126588,126590,126601,126619,126627,126633,126651,173782,177972,178205,183969,191456,195101};
// clang-format on
static bool is_possible_number_char(char c) {
switch(c) {
// clang-format off
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
case '.': case 'L': case 'x': case 'o': case 'j':
return true;
default: return false;
// clang-format on
}
}
@ -33,14 +37,17 @@ static bool is_unicode_Lo_char(uint32_t c) {
if(*c != c0) return false;
c++;
}
for(int i=0; i<n; i++) eatchar_include_newline();
for(int i = 0; i < n; i++)
eatchar_include_newline();
return true;
}
bool Lexer::match_string(const char* s) {
int s_len = strlen(s);
bool ok = strncmp(curr_char, s, s_len) == 0;
if(ok) for(int i=0; i<s_len; i++) eatchar_include_newline();
if(ok)
for(int i = 0; i < s_len; i++)
eatchar_include_newline();
return ok;
}
@ -70,9 +77,7 @@ static bool is_unicode_Lo_char(uint32_t c) {
indents.pop();
nexts.push_back(Token{TK("@dedent"), token_start, 0, current_line, brackets_level, {}});
}
if(spaces != indents.top()){
return false;
}
if(spaces != indents.top()) { return false; }
}
return true;
}
@ -115,15 +120,20 @@ static bool is_unicode_Lo_char(uint32_t c) {
for(int k = 0; k < u8bytes; k++) {
uint8_t b = u8str[k];
if(k == 0) {
if(u8bytes == 2) value = (b & 0b00011111) << 6;
else if(u8bytes == 3) value = (b & 0b00001111) << 12;
else if(u8bytes == 4) value = (b & 0b00000111) << 18;
if(u8bytes == 2)
value = (b & 0b00011111) << 6;
else if(u8bytes == 3)
value = (b & 0b00001111) << 12;
else if(u8bytes == 4)
value = (b & 0b00000111) << 18;
} else {
value |= (b & 0b00111111) << (6 * (u8bytes - k - 1));
}
}
if(is_unicode_Lo_char(value)) curr_char += u8bytes;
else break;
if(is_unicode_Lo_char(value))
curr_char += u8bytes;
else
break;
}
int length = (int)(curr_char - token_start);
@ -167,17 +177,19 @@ static bool is_unicode_Lo_char(uint32_t c) {
void Lexer::add_token(TokenIndex type, TokenValue value) {
switch(type) {
case TK("{"): case TK("["): case TK("("): brackets_level++; break;
case TK(")"): case TK("]"): case TK("}"): brackets_level--; break;
case TK("{"):
case TK("["):
case TK("("): brackets_level++; break;
case TK(")"):
case TK("]"):
case TK("}"): brackets_level--; break;
}
auto token = Token{
type,
auto token = Token{type,
token_start,
(int)(curr_char - token_start),
current_line - ((type == TK("@eol")) ? 1 : 0),
brackets_level,
value
};
value};
// handle "not in", "is not", "yield from"
if(!nexts.empty()) {
auto& back = nexts.back();
@ -198,8 +210,10 @@ static bool is_unicode_Lo_char(uint32_t c) {
}
void Lexer::add_token_2(char c, TokenIndex one, TokenIndex two) {
if (matchchar(c)) add_token(two);
else add_token(one);
if(matchchar(c))
add_token(two);
else
add_token(one);
}
Str Lexer::eat_string_until(char quote, bool raw) {
@ -215,13 +229,12 @@ static bool is_unicode_Lo_char(uint32_t c) {
break;
}
if(c == '\0') {
if(quote3 && src->mode == REPL_MODE){
throw NeedMoreLines(false);
}
if(quote3 && src->mode == REPL_MODE) { throw NeedMoreLines(false); }
SyntaxError("EOL while scanning string literal");
}
if(c == '\n') {
if(!quote3) SyntaxError("EOL while scanning string literal");
if(!quote3)
SyntaxError("EOL while scanning string literal");
else {
buff.push_back(c);
continue;
@ -242,9 +255,7 @@ static bool is_unicode_Lo_char(uint32_t c) {
char code;
try {
code = (char)std::stoi(hex, &parsed, 16);
}catch(...){
SyntaxError("invalid hex char");
}
} catch(...) { SyntaxError("invalid hex char"); }
if(parsed != 2) SyntaxError("invalid hex char");
buff.push_back(code);
} break;
@ -272,12 +283,14 @@ static bool is_unicode_Lo_char(uint32_t c) {
void Lexer::eat_number() {
const char* i = token_start;
while(is_possible_number_char(*i)) i++;
while(is_possible_number_char(*i))
i++;
bool is_scientific_notation = false;
if(*(i - 1) == 'e' && (*i == '+' || *i == '-')) {
i++;
while(isdigit(*i) || *i=='j') i++;
while(isdigit(*i) || *i == 'j')
i++;
is_scientific_notation = true;
}
@ -293,14 +306,9 @@ static bool is_unicode_Lo_char(uint32_t c) {
// try integer
i64 int_out;
switch(parse_uint(text, &int_out, -1)) {
case IntParsingResult::Success:
add_token(TK("@num"), int_out);
return;
case IntParsingResult::Overflow:
SyntaxError("int literal is too large");
return;
case IntParsingResult::Failure:
break; // do nothing
case IntParsingResult::Success: add_token(TK("@num"), int_out); return;
case IntParsingResult::Overflow: SyntaxError("int literal is too large"); return;
case IntParsingResult::Failure: break; // do nothing
}
}
@ -309,9 +317,7 @@ static bool is_unicode_Lo_char(uint32_t c) {
char* p_end;
try {
float_out = std::strtod(text.data(), &p_end);
}catch(...){
SyntaxError("invalid number literal");
}
} catch(...) { SyntaxError("invalid number literal"); }
if(p_end == text.data() + text.size()) {
add_token(TK("@num"), (f64)float_out);
@ -331,7 +337,8 @@ static bool is_unicode_Lo_char(uint32_t c) {
token_start = curr_char;
char c = eatchar_include_newline();
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 '~': add_token(TK("~")); return true;
case '{': add_token(TK("{")); return true;
@ -384,30 +391,41 @@ static bool is_unicode_Lo_char(uint32_t c) {
}
return true;
case '>': {
if(matchchar('=')) add_token(TK(">="));
else if(matchchar('>')) add_token_2('=', TK(">>"), TK(">>="));
else add_token(TK(">"));
if(matchchar('='))
add_token(TK(">="));
else if(matchchar('>'))
add_token_2('=', TK(">>"), TK(">>="));
else
add_token(TK(">"));
return true;
}
case '<': {
if(matchchar('=')) add_token(TK("<="));
else if(matchchar('<')) add_token_2('=', TK("<<"), TK("<<="));
else add_token(TK("<"));
if(matchchar('='))
add_token(TK("<="));
else if(matchchar('<'))
add_token_2('=', TK("<<"), TK("<<="));
else
add_token(TK("<"));
return true;
}
case '-': {
if(matchchar('-')) {
add_token(TK("--"));
} else {
if(matchchar('=')) add_token(TK("-="));
else if(matchchar('>')) add_token(TK("->"));
else add_token(TK("-"));
if(matchchar('='))
add_token(TK("-="));
else if(matchchar('>'))
add_token(TK("->"));
else
add_token(TK("-"));
}
return true;
}
case '!':
if(matchchar('=')) add_token(TK("!="));
else SyntaxError("expected '=' after '!'");
if(matchchar('='))
add_token(TK("!="));
else
SyntaxError("expected '=' after '!'");
break;
case '*':
if(matchchar('*')) {
@ -423,7 +441,8 @@ static bool is_unicode_Lo_char(uint32_t c) {
add_token_2('=', TK("/"), TK("/="));
}
return true;
case ' ': case '\t': eat_spaces(); break;
case ' ':
case '\t': eat_spaces(); break;
case '\n': {
add_token(TK("@eol"));
if(!eat_indentation()) IndentationError("unindent does not match any outer indentation level");
@ -431,21 +450,38 @@ static bool is_unicode_Lo_char(uint32_t c) {
}
default: {
if(c == 'f') {
if(matchchar('\'')) {eat_string('\'', F_STRING); return true;}
if(matchchar('"')) {eat_string('"', F_STRING); return true;}
if(matchchar('\'')) {
eat_string('\'', F_STRING);
return true;
}
if(matchchar('"')) {
eat_string('"', F_STRING);
return true;
}
} else if(c == 'r') {
if(matchchar('\'')) {eat_string('\'', RAW_STRING); return true;}
if(matchchar('"')) {eat_string('"', RAW_STRING); return true;}
if(matchchar('\'')) {
eat_string('\'', RAW_STRING);
return true;
}
if(matchchar('"')) {
eat_string('"', RAW_STRING);
return true;
}
} else if(c == 'b') {
if(matchchar('\'')) {eat_string('\'', NORMAL_BYTES); return true;}
if(matchchar('"')) {eat_string('"', NORMAL_BYTES); return true;}
if(matchchar('\'')) {
eat_string('\'', NORMAL_BYTES);
return true;
}
if(matchchar('"')) {
eat_string('"', NORMAL_BYTES);
return true;
}
}
if(c >= '0' && c <= '9') {
eat_number();
return true;
}
switch (eat_name())
{
switch(eat_name()) {
case 0: break;
case 1: SyntaxError("invalid char: " + std::string(1, c)); break;
case 2: SyntaxError("invalid utf8 sequence: " + std::string(1, c)); break;
@ -487,11 +523,12 @@ static bool is_unicode_Lo_char(uint32_t c) {
vector<Token> Lexer::run() {
assert(curr_char == src->source.c_str());
while (lex_one_token());
while(lex_one_token())
;
return std::move(nexts);
}
inline constexpr bool f_startswith_2(std::string_view t, const char* prefix){
constexpr inline bool f_startswith_2(std::string_view t, const char* prefix) {
if(t.length() < 2) return false;
return t[0] == prefix[0] && t[1] == prefix[1];
}
@ -500,10 +537,14 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base){
*out = 0;
if(base == -1) {
if(f_startswith_2(text, "0b")) base = 2;
else if(f_startswith_2(text, "0o")) base = 8;
else if(f_startswith_2(text, "0x")) base = 16;
else base = 10;
if(f_startswith_2(text, "0b"))
base = 2;
else if(f_startswith_2(text, "0o"))
base = 8;
else if(f_startswith_2(text, "0x"))
base = 16;
else
base = 10;
}
if(base == 10) {

View File

@ -24,25 +24,29 @@ namespace pkpy{
} else { \
PyVar self; \
PyVar _2 = get_unbound_method(_0, func, &self, false); \
if(_2 != nullptr) ret = call_method(self, _2, _1); \
else ret = NotImplemented; \
if(_2 != nullptr) \
ret = call_method(self, _2, _1); \
else \
ret = NotImplemented; \
} \
if(is_not_implemented(ret)) { \
PyVar self; \
PyVar _2 = get_unbound_method(_1, rfunc, &self, false); \
if(_2 != nullptr) ret = call_method(self, _2, _0); \
else BinaryOptError(op, _0, _1); \
if(_2 != nullptr) \
ret = call_method(self, _2, _0); \
else \
BinaryOptError(op, _0, _1); \
if(is_not_implemented(ret)) BinaryOptError(op, _0, _1); \
}
void VM::__op_unpack_sequence(uint16_t arg) {
PyVar _0 = POPX();
if(is_type(_0, VM::tp_tuple)) {
// fast path for tuple
Tuple& tuple = PK_OBJ_GET(Tuple, _0);
if(tuple.size() == arg) {
for(PyVar obj: tuple) PUSH(obj);
for(PyVar obj: tuple)
PUSH(obj);
} else {
ValueError(_S("expected ", (int)arg, " values to unpack, got ", (int)tuple.size()));
}
@ -94,9 +98,21 @@ bool VM::py_ge(PyVar _0, PyVar _1){
}
#endif
#define DISPATCH() { frame->_ip++; goto __NEXT_STEP; }
#define DISPATCH_JUMP(__offset) { frame->_ip+=__offset; goto __NEXT_STEP; }
#define DISPATCH_JUMP_ABSOLUTE(__target) { frame->_ip=&frame->co->codes[__target]; goto __NEXT_STEP; }
#define DISPATCH() \
{ \
frame->_ip++; \
goto __NEXT_STEP; \
}
#define DISPATCH_JUMP(__offset) \
{ \
frame->_ip += __offset; \
goto __NEXT_STEP; \
}
#define DISPATCH_JUMP_ABSOLUTE(__target) \
{ \
frame->_ip = &frame->co->codes[__target]; \
goto __NEXT_STEP; \
}
PyVar VM::__run_top_frame() {
Frame* frame = &callstack.top();
@ -131,8 +147,7 @@ __NEXT_STEP:
#if PK_DEBUG_CEVAL_STEP
__log_s_data();
#endif
switch ((Opcode)byte.op)
{
switch((Opcode)byte.op) {
case OP_NO_OP: DISPATCH()
/*****************************************/
case OP_POP_TOP: POP(); DISPATCH()
@ -149,22 +164,19 @@ __NEXT_STEP:
TOP() = SECOND();
SECOND() = THIRD();
THIRD() = _0;
} DISPATCH()
}
DISPATCH()
case OP_PRINT_EXPR:
if(TOP() != None) stdout_write(py_repr(TOP()) + "\n");
POP();
DISPATCH()
/*****************************************/
case OP_LOAD_CONST:
PUSH(frame->co->consts[byte.arg]);
DISPATCH()
case OP_LOAD_CONST: PUSH(frame->co->consts[byte.arg]); DISPATCH()
case OP_LOAD_NONE: PUSH(None); DISPATCH()
case OP_LOAD_TRUE: PUSH(True); DISPATCH()
case OP_LOAD_FALSE: PUSH(False); DISPATCH()
/*****************************************/
case OP_LOAD_SMALL_INT:
s_data.emplace(tp_int, (i64)(int16_t)byte.arg);
DISPATCH()
case OP_LOAD_SMALL_INT: s_data.emplace(tp_int, (i64)(int16_t)byte.arg); DISPATCH()
/*****************************************/
case OP_LOAD_ELLIPSIS: PUSH(Ellipsis); DISPATCH()
case OP_LOAD_FUNCTION: {
@ -178,14 +190,16 @@ __NEXT_STEP:
obj = VAR(Function(decl, frame->_module, nullptr, nullptr));
}
PUSH(obj);
} DISPATCH()
}
DISPATCH()
case OP_LOAD_NULL: PUSH(PY_NULL); DISPATCH()
/*****************************************/
case OP_LOAD_FAST: {
PyVar _0 = frame->_locals[byte.arg];
if(_0 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
PUSH(_0);
} DISPATCH()
}
DISPATCH()
case OP_LOAD_NAME: {
StrName _name(byte.arg);
PyVar* slot = frame->_locals.try_get_name(_name);
@ -195,51 +209,90 @@ __NEXT_STEP:
DISPATCH()
}
PyVar* _0 = frame->f_closure_try_get(_name);
if(_0 != nullptr) { PUSH(*_0); DISPATCH() }
if(_0 != nullptr) {
PUSH(*_0);
DISPATCH()
}
_0 = frame->f_globals().try_get_2_likely_found(_name);
if(_0 != nullptr) { PUSH(*_0); DISPATCH() }
if(_0 != nullptr) {
PUSH(*_0);
DISPATCH()
}
_0 = vm->builtins->attr().try_get_2_likely_found(_name);
if(_0 != nullptr) { PUSH(*_0); DISPATCH() }
if(_0 != nullptr) {
PUSH(*_0);
DISPATCH()
}
vm->NameError(_name);
} DISPATCH()
}
DISPATCH()
case OP_LOAD_NONLOCAL: {
StrName _name(byte.arg);
PyVar* _0 = frame->f_closure_try_get(_name);
if(_0 != nullptr) { PUSH(*_0); DISPATCH() }
if(_0 != nullptr) {
PUSH(*_0);
DISPATCH()
}
_0 = frame->f_globals().try_get_2_likely_found(_name);
if(_0 != nullptr) { PUSH(*_0); DISPATCH() }
if(_0 != nullptr) {
PUSH(*_0);
DISPATCH()
}
_0 = vm->builtins->attr().try_get_2_likely_found(_name);
if(_0 != nullptr) { PUSH(*_0); DISPATCH() }
if(_0 != nullptr) {
PUSH(*_0);
DISPATCH()
}
vm->NameError(_name);
} DISPATCH()
}
DISPATCH()
case OP_LOAD_GLOBAL: {
StrName _name(byte.arg);
PyVar _0 = frame->f_globals().try_get_likely_found(_name);
if(_0 != nullptr) { PUSH(_0); DISPATCH() }
if(_0 != nullptr) {
PUSH(_0);
DISPATCH()
}
_0 = vm->builtins->attr().try_get_likely_found(_name);
if(_0 != nullptr) { PUSH(_0); DISPATCH() }
if(_0 != nullptr) {
PUSH(_0);
DISPATCH()
}
vm->NameError(_name);
} DISPATCH()
}
DISPATCH()
case OP_LOAD_ATTR: {
TOP() = getattr(TOP(), StrName(byte.arg));
} DISPATCH()
}
DISPATCH()
case OP_LOAD_CLASS_GLOBAL: {
assert(__curr_class != nullptr);
StrName _name(byte.arg);
PyVar _0 = getattr(__curr_class, _name, false);
if(_0 != nullptr) { PUSH(_0); DISPATCH() }
if(_0 != nullptr) {
PUSH(_0);
DISPATCH()
}
// load global if attribute not found
_0 = frame->f_globals().try_get_likely_found(_name);
if(_0 != nullptr) { PUSH(_0); DISPATCH() }
if(_0 != nullptr) {
PUSH(_0);
DISPATCH()
}
_0 = vm->builtins->attr().try_get_likely_found(_name);
if(_0 != nullptr) { PUSH(_0); DISPATCH() }
if(_0 != nullptr) {
PUSH(_0);
DISPATCH()
}
vm->NameError(_name);
} DISPATCH()
}
DISPATCH()
case OP_LOAD_METHOD: {
PyVar _0;
TOP() = get_unbound_method(TOP(), StrName(byte.arg), &_0, true, true);
PUSH(_0);
}DISPATCH()
}
DISPATCH()
case OP_LOAD_SUBSCR: {
PyVar _1 = POPX(); // b
PyVar _0 = TOP(); // a
@ -249,7 +302,8 @@ __NEXT_STEP:
} else {
TOP() = call_method(_0, __getitem__, _1);
}
} DISPATCH()
}
DISPATCH()
case OP_LOAD_SUBSCR_FAST: {
PyVar _1 = frame->_locals[byte.arg];
if(_1 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
@ -260,7 +314,8 @@ __NEXT_STEP:
} else {
TOP() = call_method(_0, __getitem__, _1);
}
} DISPATCH()
}
DISPATCH()
case OP_LOAD_SUBSCR_SMALL_INT: {
PyVar _1 = VAR((int16_t)byte.arg);
PyVar _0 = TOP(); // a
@ -270,10 +325,9 @@ __NEXT_STEP:
} else {
TOP() = call_method(_0, __getitem__, _1);
}
} DISPATCH()
case OP_STORE_FAST:
frame->_locals[byte.arg] = POPX();
}
DISPATCH()
case OP_STORE_FAST: frame->_locals[byte.arg] = POPX(); DISPATCH()
case OP_STORE_NAME: {
StrName _name(byte.arg);
PyVar _0 = POPX();
@ -293,16 +347,16 @@ __NEXT_STEP:
} else {
frame->f_globals().set(_name, _0);
}
} DISPATCH()
case OP_STORE_GLOBAL:
frame->f_globals().set(StrName(byte.arg), POPX());
}
DISPATCH()
case OP_STORE_GLOBAL: frame->f_globals().set(StrName(byte.arg), POPX()); DISPATCH()
case OP_STORE_ATTR: {
PyVar _0 = TOP(); // a
PyVar _1 = SECOND(); // val
setattr(_0, StrName(byte.arg), _1);
STACK_SHRINK(2);
} DISPATCH()
}
DISPATCH()
case OP_STORE_SUBSCR: {
PyVar _2 = POPX(); // b
PyVar _1 = POPX(); // a
@ -313,7 +367,8 @@ __NEXT_STEP:
} else {
call_method(_1, __setitem__, _2, _0);
}
}DISPATCH()
}
DISPATCH()
case OP_STORE_SUBSCR_FAST: {
PyVar _2 = frame->_locals[byte.arg]; // b
if(_2 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
@ -325,12 +380,14 @@ __NEXT_STEP:
} else {
call_method(_1, __setitem__, _2, _0);
}
}DISPATCH()
}
DISPATCH()
case OP_DELETE_FAST: {
PyVar _0 = frame->_locals[byte.arg];
if(_0 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
frame->_locals[byte.arg].set_null();
}DISPATCH()
}
DISPATCH()
case OP_DELETE_NAME: {
StrName _name(byte.arg);
if(frame->_callable != nullptr) {
@ -350,15 +407,18 @@ __NEXT_STEP:
} else {
if(!frame->f_globals().del(_name)) vm->NameError(_name);
}
} DISPATCH()
}
DISPATCH()
case OP_DELETE_GLOBAL: {
StrName _name(byte.arg);
if(!frame->f_globals().del(_name)) vm->NameError(_name);
}DISPATCH()
}
DISPATCH()
case OP_DELETE_ATTR: {
PyVar _0 = POPX();
delattr(_0, StrName(byte.arg));
} DISPATCH()
}
DISPATCH()
case OP_DELETE_SUBSCR: {
PyVar _1 = POPX();
PyVar _0 = POPX();
@ -368,34 +428,40 @@ __NEXT_STEP:
} else {
call_method(_0, __delitem__, _1);
}
}DISPATCH()
}
DISPATCH()
/*****************************************/
case OP_BUILD_LONG: {
PyVar _0 = builtins->attr().try_get_likely_found(pk_id_long);
if(_0 == nullptr) AttributeError(builtins, pk_id_long);
TOP() = call(_0, TOP());
} DISPATCH()
}
DISPATCH()
case OP_BUILD_IMAG: {
PyVar _0 = builtins->attr().try_get_likely_found(pk_id_complex);
if(_0 == nullptr) AttributeError(builtins, pk_id_long);
TOP() = call(_0, VAR(0), TOP());
} DISPATCH()
}
DISPATCH()
case OP_BUILD_BYTES: {
const Str& s = CAST(Str&, TOP());
unsigned char* p = (unsigned char*)std::malloc(s.size);
std::memcpy(p, s.data, s.size);
TOP() = VAR(Bytes(p, s.size));
} DISPATCH()
}
DISPATCH()
case OP_BUILD_TUPLE: {
PyVar _0 = VAR(STACK_VIEW(byte.arg).to_tuple());
STACK_SHRINK(byte.arg);
PUSH(_0);
} DISPATCH()
}
DISPATCH()
case OP_BUILD_LIST: {
PyVar _0 = VAR(STACK_VIEW(byte.arg).to_list());
STACK_SHRINK(byte.arg);
PUSH(_0);
} DISPATCH()
}
DISPATCH()
case OP_BUILD_DICT: {
if(byte.arg == 0) {
PUSH(VAR(Dict()));
@ -405,26 +471,31 @@ __NEXT_STEP:
_0 = call(_t(tp_dict), _0);
STACK_SHRINK(byte.arg);
PUSH(_0);
} DISPATCH()
}
DISPATCH()
case OP_BUILD_SET: {
PyVar _0 = VAR(STACK_VIEW(byte.arg).to_list());
_0 = call(builtins->attr(pk_id_set), _0);
STACK_SHRINK(byte.arg);
PUSH(_0);
} DISPATCH()
}
DISPATCH()
case OP_BUILD_SLICE: {
PyVar _2 = POPX(); // step
PyVar _1 = POPX(); // stop
PyVar _0 = POPX(); // start
PUSH(VAR(Slice(_0, _1, _2)));
} DISPATCH()
}
DISPATCH()
case OP_BUILD_STRING: {
SStream ss;
ArgsView view = STACK_VIEW(byte.arg);
for(PyVar obj : view) ss << py_str(obj);
for(PyVar obj: view)
ss << py_str(obj);
STACK_SHRINK(byte.arg);
PUSH(VAR(ss.str()));
} DISPATCH()
}
DISPATCH()
/*****************************************/
case OP_BUILD_TUPLE_UNPACK: {
List list;
@ -432,21 +503,24 @@ __NEXT_STEP:
STACK_SHRINK(byte.arg);
PyVar _0 = VAR(list.to_tuple());
PUSH(_0);
} DISPATCH()
}
DISPATCH()
case OP_BUILD_LIST_UNPACK: {
List list;
__unpack_as_list(STACK_VIEW(byte.arg), list);
STACK_SHRINK(byte.arg);
PyVar _0 = VAR(std::move(list));
PUSH(_0);
} DISPATCH()
}
DISPATCH()
case OP_BUILD_DICT_UNPACK: {
Dict dict;
__unpack_as_dict(STACK_VIEW(byte.arg), dict);
STACK_SHRINK(byte.arg);
PyVar _0 = VAR(std::move(dict));
PUSH(_0);
} DISPATCH()
}
DISPATCH()
case OP_BUILD_SET_UNPACK: {
List list;
__unpack_as_list(STACK_VIEW(byte.arg), list);
@ -454,7 +528,8 @@ __NEXT_STEP:
PyVar _0 = VAR(std::move(list));
_0 = call(builtins->attr(pk_id_set), _0);
PUSH(_0);
} DISPATCH()
}
DISPATCH()
/*****************************************/
#define BINARY_OP_SPECIAL(func) \
_ti = _tp_info(_0); \
@ -463,16 +538,20 @@ __NEXT_STEP:
} else { \
PyVar self; \
PyVar _2 = get_unbound_method(_0, func, &self, false); \
if(_2 != nullptr) TOP() = call_method(self, _2, _1); \
else TOP() = NotImplemented; \
if(_2 != nullptr) \
TOP() = call_method(self, _2, _1); \
else \
TOP() = NotImplemented; \
}
#define BINARY_OP_RSPECIAL(op, func) \
if(is_not_implemented(TOP())) { \
PyVar self; \
PyVar _2 = get_unbound_method(_1, func, &self, false); \
if(_2 != nullptr) TOP() = call_method(self, _2, _0); \
else BinaryOptError(op, _0, _1); \
if(_2 != nullptr) \
TOP() = call_method(self, _2, _0); \
else \
BinaryOptError(op, _0, _1); \
if(is_not_implemented(TOP())) BinaryOptError(op, _0, _1); \
}
@ -482,14 +561,16 @@ __NEXT_STEP:
const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__truediv__);
if(is_not_implemented(TOP())) BinaryOptError("/", _0, _1);
} DISPATCH()
}
DISPATCH()
case OP_BINARY_POW: {
PyVar _1 = POPX();
PyVar _0 = TOP();
const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__pow__);
if(is_not_implemented(TOP())) BinaryOptError("**", _0, _1);
} DISPATCH()
}
DISPATCH()
case OP_BINARY_ADD: {
PyVar _1 = POPX();
PyVar _0 = TOP();
@ -497,7 +578,8 @@ __NEXT_STEP:
const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__add__);
BINARY_OP_RSPECIAL("+", __radd__);
} DISPATCH()
}
DISPATCH()
case OP_BINARY_SUB: {
PyVar _1 = POPX();
PyVar _0 = TOP();
@ -505,7 +587,8 @@ __NEXT_STEP:
const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__sub__);
BINARY_OP_RSPECIAL("-", __rsub__);
} DISPATCH()
}
DISPATCH()
case OP_BINARY_MUL: {
PyVar _1 = POPX();
PyVar _0 = TOP();
@ -513,7 +596,8 @@ __NEXT_STEP:
const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__mul__);
BINARY_OP_RSPECIAL("*", __rmul__);
} DISPATCH()
}
DISPATCH()
case OP_BINARY_FLOORDIV: {
PyVar _1 = POPX();
PyVar _0 = TOP();
@ -521,7 +605,8 @@ __NEXT_STEP:
const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__floordiv__);
if(is_not_implemented(TOP())) BinaryOptError("//", _0, _1);
} DISPATCH()
}
DISPATCH()
case OP_BINARY_MOD: {
PyVar _1 = POPX();
PyVar _0 = TOP();
@ -529,41 +614,48 @@ __NEXT_STEP:
const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__mod__);
if(is_not_implemented(TOP())) BinaryOptError("%", _0, _1);
} DISPATCH()
}
DISPATCH()
case OP_COMPARE_LT: {
PyVar _1 = POPX();
PyVar _0 = TOP();
PREDICT_INT_OP(<)
TOP() = VAR(py_lt(_0, _1));
} DISPATCH()
}
DISPATCH()
case OP_COMPARE_LE: {
PyVar _1 = POPX();
PyVar _0 = TOP();
PREDICT_INT_OP(<=)
TOP() = VAR(py_le(_0, _1));
} DISPATCH()
}
DISPATCH()
case OP_COMPARE_EQ: {
PyVar _1 = POPX();
PyVar _0 = TOP();
TOP() = VAR(py_eq(_0, _1));
} DISPATCH()
}
DISPATCH()
case OP_COMPARE_NE: {
PyVar _1 = POPX();
PyVar _0 = TOP();
TOP() = VAR(py_ne(_0, _1));
} DISPATCH()
}
DISPATCH()
case OP_COMPARE_GT: {
PyVar _1 = POPX();
PyVar _0 = TOP();
PREDICT_INT_OP(>)
TOP() = VAR(py_gt(_0, _1));
} DISPATCH()
}
DISPATCH()
case OP_COMPARE_GE: {
PyVar _1 = POPX();
PyVar _0 = TOP();
PREDICT_INT_OP(>=)
TOP() = VAR(py_ge(_0, _1));
} DISPATCH()
}
DISPATCH()
case OP_BITWISE_LSHIFT: {
PyVar _1 = POPX();
PyVar _0 = TOP();
@ -571,7 +663,8 @@ __NEXT_STEP:
const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__lshift__);
if(is_not_implemented(TOP())) BinaryOptError("<<", _0, _1);
} DISPATCH()
}
DISPATCH()
case OP_BITWISE_RSHIFT: {
PyVar _1 = POPX();
PyVar _0 = TOP();
@ -579,7 +672,8 @@ __NEXT_STEP:
const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__rshift__);
if(is_not_implemented(TOP())) BinaryOptError(">>", _0, _1);
} DISPATCH()
}
DISPATCH()
case OP_BITWISE_AND: {
PyVar _1 = POPX();
PyVar _0 = TOP();
@ -587,7 +681,8 @@ __NEXT_STEP:
const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__and__);
if(is_not_implemented(TOP())) BinaryOptError("&", _0, _1);
} DISPATCH()
}
DISPATCH()
case OP_BITWISE_OR: {
PyVar _1 = POPX();
PyVar _0 = TOP();
@ -595,7 +690,8 @@ __NEXT_STEP:
const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__or__);
if(is_not_implemented(TOP())) BinaryOptError("|", _0, _1);
} DISPATCH()
}
DISPATCH()
case OP_BITWISE_XOR: {
PyVar _1 = POPX();
PyVar _0 = TOP();
@ -603,14 +699,16 @@ __NEXT_STEP:
const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__xor__);
if(is_not_implemented(TOP())) BinaryOptError("^", _0, _1);
} DISPATCH()
}
DISPATCH()
case OP_BINARY_MATMUL: {
PyVar _1 = POPX();
PyVar _0 = TOP();
const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__matmul__);
if(is_not_implemented(TOP())) BinaryOptError("@", _0, _1);
} DISPATCH()
}
DISPATCH()
#undef BINARY_OP_SPECIAL
#undef BINARY_OP_RSPECIAL
@ -620,12 +718,14 @@ __NEXT_STEP:
PyVar _1 = POPX(); // rhs
PyVar _0 = TOP(); // lhs
TOP() = _0 == _1 ? True : False;
} DISPATCH()
}
DISPATCH()
case OP_IS_NOT_OP: {
PyVar _1 = POPX(); // rhs
PyVar _0 = TOP(); // lhs
TOP() = _0 != _1 ? True : False;
} DISPATCH()
}
DISPATCH()
case OP_CONTAINS_OP: {
// a in b -> b __contains__ a
auto _ti = _tp_info(TOP());
@ -637,10 +737,10 @@ __NEXT_STEP:
}
POP();
TOP() = VAR(static_cast<bool>((int)CAST(bool, _0) ^ byte.arg));
} DISPATCH()
}
DISPATCH()
/*****************************************/
case OP_JUMP_FORWARD:
DISPATCH_JUMP((int16_t)byte.arg)
case OP_JUMP_FORWARD: DISPATCH_JUMP((int16_t)byte.arg)
case OP_POP_JUMP_IF_FALSE:
if(!py_bool(POPX())) DISPATCH_JUMP((int16_t)byte.arg)
DISPATCH()
@ -677,8 +777,7 @@ __NEXT_STEP:
frame->prepare_jump_break(&s_data, frame->ip() + byte.arg);
DISPATCH_JUMP((int16_t)byte.arg)
}
case OP_JUMP_ABSOLUTE_TOP:
DISPATCH_JUMP_ABSOLUTE(_CAST(int, POPX()))
case OP_JUMP_ABSOLUTE_TOP: DISPATCH_JUMP_ABSOLUTE(_CAST(int, POPX()))
case OP_GOTO: {
StrName _name(byte.arg);
int target = frame->co->labels.try_get_likely_found(_name);
@ -700,23 +799,21 @@ __NEXT_STEP:
}
_0 = vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals);
PUSH(_0);
} DISPATCH()
case OP_REPR:
TOP() = VAR(py_repr(TOP()));
}
DISPATCH()
case OP_REPR: TOP() = VAR(py_repr(TOP())); DISPATCH()
case OP_CALL: {
if(heap._should_auto_collect()) heap._auto_collect();
PyVar _0 = vectorcall(
byte.arg & 0xFF, // ARGC
PyVar _0 = vectorcall(byte.arg & 0xFF, // ARGC
(byte.arg >> 8) & 0xFF, // KWARGC
true
);
true);
if(_0 == PY_OP_CALL) {
frame = &callstack.top();
goto __NEXT_FRAME;
}
PUSH(_0);
} DISPATCH()
}
DISPATCH()
case OP_CALL_TP: {
if(heap._should_auto_collect()) heap._auto_collect();
PyVar _0;
@ -726,32 +823,31 @@ __NEXT_STEP:
if(byte.arg) {
_2 = POPX();
_1 = POPX();
for(PyVar obj: _CAST(Tuple&, _1)) PUSH(obj);
for(PyVar obj: _CAST(Tuple&, _1))
PUSH(obj);
_CAST(Dict&, _2).apply([this](PyVar k, PyVar v) {
PUSH(VAR(StrName(CAST(Str&, k)).index));
PUSH(v);
});
_0 = vectorcall(
_CAST(Tuple&, _1).size(), // ARGC
_0 = vectorcall(_CAST(Tuple&, _1).size(), // ARGC
_CAST(Dict&, _2).size(), // KWARGC
true
);
true);
} else {
// no **kwargs
_1 = POPX();
for(PyVar obj: _CAST(Tuple&, _1)) PUSH(obj);
_0 = vectorcall(
_CAST(Tuple&, _1).size(), // ARGC
for(PyVar obj: _CAST(Tuple&, _1))
PUSH(obj);
_0 = vectorcall(_CAST(Tuple&, _1).size(), // ARGC
0, // KWARGC
true
);
true);
}
if(_0 == PY_OP_CALL) {
frame = &callstack.top();
goto __NEXT_FRAME;
}
PUSH(_0);
} DISPATCH()
}
DISPATCH()
case OP_RETURN_VALUE: {
PyVar _0 = byte.arg == BC_NOARG ? POPX() : None;
__pop_frame();
@ -762,46 +858,51 @@ __NEXT_STEP:
PUSH(_0);
goto __NEXT_FRAME;
}
} DISPATCH()
}
DISPATCH()
case OP_YIELD_VALUE: return PY_OP_YIELD;
/*****************************************/
case OP_LIST_APPEND: {
PyVar _0 = POPX();
PK_OBJ_GET(List, SECOND()).push_back(_0);
} DISPATCH()
}
DISPATCH()
case OP_DICT_ADD: {
PyVar _0 = POPX();
const Tuple& t = PK_OBJ_GET(Tuple, _0);
PK_OBJ_GET(Dict, SECOND()).set(this, t[0], t[1]);
} DISPATCH()
}
DISPATCH()
case OP_SET_ADD: {
PyVar _0 = POPX();
call_method(SECOND(), pk_id_add, _0);
} DISPATCH()
/*****************************************/
case OP_UNARY_NEGATIVE:
TOP() = py_negate(TOP());
}
DISPATCH()
/*****************************************/
case OP_UNARY_NEGATIVE: TOP() = py_negate(TOP()); DISPATCH()
case OP_UNARY_NOT: {
PyVar _0 = TOP();
if(_0==True) TOP()=False;
else if(_0==False) TOP()=True;
else TOP() = VAR(!py_bool(_0));
} DISPATCH()
case OP_UNARY_STAR:
TOP() = VAR(StarWrapper(byte.arg, TOP()));
if(_0 == True)
TOP() = False;
else if(_0 == False)
TOP() = True;
else
TOP() = VAR(!py_bool(_0));
}
DISPATCH()
case OP_UNARY_STAR: TOP() = VAR(StarWrapper(byte.arg, TOP())); DISPATCH()
case OP_UNARY_INVERT: {
PyVar _0;
auto _ti = _tp_info(TOP());
if(_ti->m__invert__) _0 = _ti->m__invert__(this, TOP());
else _0 = call_method(TOP(), __invert__);
if(_ti->m__invert__)
_0 = _ti->m__invert__(this, TOP());
else
_0 = call_method(TOP(), __invert__);
TOP() = _0;
} DISPATCH()
/*****************************************/
case OP_GET_ITER:
TOP() = py_iter(TOP());
}
DISPATCH()
/*****************************************/
case OP_GET_ITER: TOP() = py_iter(TOP()); DISPATCH()
case OP_GET_ITER_NEW: {
// This opcode always creates a temporary iterator object
const PyTypeInfo* _ti = _tp_info(TOP());
@ -882,12 +983,14 @@ __NEXT_STEP:
DISPATCH_JUMP_ABSOLUTE(target)
}
}
} DISPATCH()
}
DISPATCH()
/*****************************************/
case OP_IMPORT_PATH: {
PyVar _0 = frame->co->consts[byte.arg];
PUSH(py_import(CAST(Str&, _0)));
} DISPATCH()
}
DISPATCH()
case OP_POP_IMPORT_STAR: {
PyVar _0 = POPX(); // pop the module
PyVar _1 = _0->attr().try_get(__all__);
@ -909,11 +1012,13 @@ __NEXT_STEP:
frame->f_globals().set(name, value);
}
}
} DISPATCH()
}
DISPATCH()
/*****************************************/
case OP_UNPACK_SEQUENCE: {
__op_unpack_sequence(byte.arg);
} DISPATCH()
}
DISPATCH()
case OP_UNPACK_EX: {
auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!!
PyVar _0 = py_iter(POPX());
@ -931,7 +1036,8 @@ __NEXT_STEP:
extras.push_back(_1);
}
PUSH(VAR(std::move(extras)));
} DISPATCH()
}
DISPATCH()
/*****************************************/
case OP_BEGIN_CLASS: {
StrName _name(byte.arg);
@ -939,7 +1045,8 @@ __NEXT_STEP:
if(_0 == None) _0 = _t(tp_object);
check_type(_0, tp_type);
__curr_class = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0), true);
} DISPATCH()
}
DISPATCH()
case OP_END_CLASS: {
assert(__curr_class != nullptr);
StrName _name(byte.arg);
@ -951,32 +1058,33 @@ __NEXT_STEP:
if(base_ti->on_end_subclass) base_ti->on_end_subclass(this, ti);
}
__curr_class = nullptr;
} DISPATCH()
}
DISPATCH()
case OP_STORE_CLASS_ATTR: {
assert(__curr_class != nullptr);
StrName _name(byte.arg);
PyVar _0 = POPX();
if(is_type(_0, tp_function)){
PK_OBJ_GET(Function, _0)._class = __curr_class;
}
if(is_type(_0, tp_function)) { PK_OBJ_GET(Function, _0)._class = __curr_class; }
__curr_class->attr().set(_name, _0);
} DISPATCH()
}
DISPATCH()
case OP_BEGIN_CLASS_DECORATION: {
PUSH(__curr_class);
} DISPATCH()
}
DISPATCH()
case OP_END_CLASS_DECORATION: {
__curr_class = POPX().get();
} DISPATCH()
}
DISPATCH()
case OP_ADD_CLASS_ANNOTATION: {
assert(__curr_class != nullptr);
StrName _name(byte.arg);
Type type = __curr_class->as<Type>();
_all_types[type].annotated_fields.push_back(_name);
} DISPATCH()
/*****************************************/
case OP_WITH_ENTER:
PUSH(call_method(TOP(), __enter__));
}
DISPATCH()
/*****************************************/
case OP_WITH_ENTER: PUSH(call_method(TOP(), __enter__)); DISPATCH()
case OP_WITH_EXIT:
call_method(TOP(), __exit__);
POP();
@ -992,16 +1100,14 @@ __NEXT_STEP:
PyVar e_obj = TOP();
bool ok = isinstance(e_obj, PK_OBJ_GET(Type, assumed_type));
PUSH(VAR(ok));
} DISPATCH()
}
DISPATCH()
case OP_RAISE: {
if(is_type(TOP(), tp_type)){
TOP() = call(TOP());
}
if(!isinstance(TOP(), tp_exception)){
TypeError("exceptions must derive from Exception");
}
if(is_type(TOP(), tp_type)) { TOP() = call(TOP()); }
if(!isinstance(TOP(), tp_exception)) { TypeError("exceptions must derive from Exception"); }
_error(POPX());
} DISPATCH()
}
DISPATCH()
case OP_RAISE_ASSERT:
if(byte.arg) {
Str msg = py_str(TOP());
@ -1018,30 +1124,35 @@ __NEXT_STEP:
PyVar _0 = POPX();
const Str& spec = CAST(Str&, frame->co->consts[byte.arg]);
PUSH(__format_object(_0, spec));
} DISPATCH()
}
DISPATCH()
/*****************************************/
case OP_INC_FAST: {
PyVar* p = &frame->_locals[byte.arg];
if(*p == PY_NULL) vm->NameError(frame->co->varnames[byte.arg]);
*p = VAR(CAST(i64, *p) + 1);
} DISPATCH()
}
DISPATCH()
case OP_DEC_FAST: {
PyVar* p = &frame->_locals[byte.arg];
if(*p == PY_NULL) vm->NameError(frame->co->varnames[byte.arg]);
*p = VAR(CAST(i64, *p) - 1);
} DISPATCH()
}
DISPATCH()
case OP_INC_GLOBAL: {
StrName _name(byte.arg);
PyVar* p = frame->f_globals().try_get_2_likely_found(_name);
if(p == nullptr) vm->NameError(_name);
*p = VAR(CAST(i64, *p) + 1);
} DISPATCH()
}
DISPATCH()
case OP_DEC_GLOBAL: {
StrName _name(byte.arg);
PyVar* p = frame->f_globals().try_get_2_likely_found(_name);
if(p == nullptr) vm->NameError(_name);
*p = VAR(CAST(i64, *p) - 1);
} DISPATCH()
}
DISPATCH()
/*****************************************/
default: PK_UNREACHABLE()
}
@ -1061,9 +1172,7 @@ __NEXT_STEP:
}
frame = &callstack.top();
PUSH(__last_exception);
if(is_base_frame_to_be_popped){
throw InternalException(InternalExceptionType::ToBeRaised);
}
if(is_base_frame_to_be_popped) { throw InternalException(InternalExceptionType::ToBeRaised); }
}
}
}

View File

@ -36,7 +36,6 @@ namespace pkpy{
#undef BIND_CMP
}
void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind_func(type, __new__, 2, [](VM* vm, ArgsView args) {
Type cls = PK_OBJ_GET(Type, args[0]);
@ -47,30 +46,45 @@ namespace pkpy{
vm->bind_func(type, "hex", 1, [](VM* vm, ArgsView args) {
const Struct& self = _CAST(Struct&, args[0]);
SStream ss;
for(int i=0; i<self.size; i++) ss.write_hex((unsigned char)self.p[i]);
for(int i = 0; i < self.size; i++)
ss.write_hex((unsigned char)self.p[i]);
return VAR(ss.str());
});
// @staticmethod
vm->bind_func(type, "fromhex", 1, [](VM* vm, ArgsView args){
vm->bind_func(
type,
"fromhex",
1,
[](VM* vm, ArgsView args) {
const Str& s = CAST(Str&, args[0]);
if(s.size < 2 || s.size % 2 != 0) vm->ValueError("invalid hex string");
Struct buffer(s.size / 2, false);
for(int i = 0; i < s.size; i += 2) {
char c = 0;
if(s[i]>='0' && s[i]<='9') c += s[i]-'0';
else if(s[i]>='A' && s[i]<='F') c += s[i]-'A'+10;
else if(s[i]>='a' && s[i]<='f') c += s[i]-'a'+10;
else vm->ValueError(_S("invalid hex char: '", s[i], "'"));
if(s[i] >= '0' && s[i] <= '9')
c += s[i] - '0';
else if(s[i] >= 'A' && s[i] <= 'F')
c += s[i] - 'A' + 10;
else if(s[i] >= 'a' && s[i] <= 'f')
c += s[i] - 'a' + 10;
else
vm->ValueError(_S("invalid hex char: '", s[i], "'"));
c <<= 4;
if(s[i+1]>='0' && s[i+1]<='9') c += s[i+1]-'0';
else if(s[i+1]>='A' && s[i+1]<='F') c += s[i+1]-'A'+10;
else if(s[i+1]>='a' && s[i+1]<='f') c += s[i+1]-'a'+10;
else vm->ValueError(_S("invalid hex char: '", s[i+1], "'"));
if(s[i + 1] >= '0' && s[i + 1] <= '9')
c += s[i + 1] - '0';
else if(s[i + 1] >= 'A' && s[i + 1] <= 'F')
c += s[i + 1] - 'A' + 10;
else if(s[i + 1] >= 'a' && s[i + 1] <= 'f')
c += s[i + 1] - 'a' + 10;
else
vm->ValueError(_S("invalid hex char: '", s[i + 1], "'"));
buffer.p[i / 2] = c;
}
return vm->new_user_object<Struct>(std::move(buffer));
}, {}, BindType::STATICMETHOD);
},
{},
BindType::STATICMETHOD);
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) {
Struct& self = _CAST(Struct&, obj);
@ -170,9 +184,7 @@ void add_module_c(VM* vm){
VoidP& ptr = CAST(VoidP&, args[0]);
vm->check_type(args[1], vm->tp_type);
Type cls = PK_OBJ_GET(Type, args[1]);
if(!vm->issubclass(cls, vm->_tp_user<VoidP>())){
vm->ValueError("expected a subclass of void_p");
}
if(!vm->issubclass(cls, vm->_tp_user<VoidP>())) { vm->ValueError("expected a subclass of void_p"); }
return vm->new_object<VoidP>(cls, ptr.ptr);
});
@ -237,7 +249,7 @@ void add_module_c(VM* vm){
vm->bind__repr__(type_t, [](VM* vm, PyVar obj) -> Str { \
VoidP& self = _CAST(VoidP&, obj); \
return _S("<", CNAME, "* at ", self.hex(), ">"); \
}); \
});
BIND_PRIMITIVE(char, "char")
BIND_PRIMITIVE(unsigned char, "uchar")
@ -272,8 +284,6 @@ void add_module_c(VM* vm){
});
}
PyVar from_void_p(VM* vm, void* p){
return vm->new_user_object<VoidP>(p);
}
PyVar from_void_p(VM* vm, void* p) { return vm->new_user_object<VoidP>(p); }
} // namespace pkpy

View File

@ -61,7 +61,8 @@ namespace pkpy{
void Frame::prepare_jump_break(ValueStack* _s, int target) {
int i = co->lines[ip()].iblock;
if(target >= co->codes.size()) {
while(i>=0) i = _exit_block(_s, i);
while(i >= 0)
i = _exit_block(_s, i);
} else {
// BUG (solved)
// for i in range(4):
@ -69,7 +70,8 @@ namespace pkpy{
// # if there is no op here, the block check will fail
// while i: --i
int next_block = co->lines[target].iblock;
while(i>=0 && i!=next_block) i = _exit_block(_s, i);
while(i >= 0 && i != next_block)
i = _exit_block(_s, i);
if(i != next_block) throw std::runtime_error("invalid jump");
}
}

View File

@ -19,7 +19,8 @@ namespace pkpy{
}
// clear _no_gc marked flag
for(PyObject* obj: _no_gc) obj->gc_marked = false;
for(PyObject* obj: _no_gc)
obj->gc_marked = false;
int freed = gen.size() - alive.size();

View File

@ -3,7 +3,9 @@
namespace pkpy {
void RangeIter::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; });
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
RangeIter& self = PK_OBJ_GET(RangeIter, _0);
if(self.current >= self.r.stop) return 0;
@ -14,7 +16,9 @@ namespace pkpy{
}
void RangeIterR::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; });
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
RangeIterR& self = PK_OBJ_GET(RangeIterR, _0);
if(self.current <= self.r.stop) return 0;
@ -25,7 +29,9 @@ namespace pkpy{
}
void ArrayIter::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; });
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
ArrayIter& self = _CAST(ArrayIter&, _0);
if(self.current == self.end) return 0;
@ -35,7 +41,9 @@ namespace pkpy{
}
void StringIter::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; });
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
StringIter& self = _CAST(StringIter&, _0);
Str& s = PK_OBJ_GET(Str, self.ref);
@ -54,7 +62,8 @@ namespace pkpy{
lf->frame._sp_base = vm->s_data._sp;
lf->frame._locals.a = vm->s_data._sp;
// restore the context
for(PyVar obj: s_backup) vm->s_data.push(obj);
for(PyVar obj: s_backup)
vm->s_data.push(obj);
// relocate stack objects (their addresses become invalid)
for(PyVar* p = lf->frame.actual_sp_base(); p != vm->s_data.end(); p++) {
if(p->type == VM::tp_stack_memory) {
@ -82,7 +91,8 @@ namespace pkpy{
// backup the context
lf = vm->callstack.popx();
ret = vm->s_data.popx();
for(PyVar obj: lf->frame.stack_view(&vm->s_data)) s_backup.push_back(obj);
for(PyVar obj: lf->frame.stack_view(&vm->s_data))
s_backup.push_back(obj);
vm->s_data.reset(lf->frame._sp_base);
// TODO: should we add this snippet here?
// #if PK_ENABLE_PROFILER
@ -100,7 +110,9 @@ namespace pkpy{
}
void Generator::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; });
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
Generator& self = _CAST(Generator&, _0);
PyVar retval = self.next(vm);
@ -111,7 +123,9 @@ namespace pkpy{
}
void DictItemsIter::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0){ return _0; });
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
DictItemsIter& self = _CAST(DictItemsIter&, _0);
Dict& d = PK_OBJ_GET(Dict, self.ref);

View File

@ -14,9 +14,7 @@ static std::string to_string_1f(f64 x){
return buf;
}
void LineProfiler::begin(){
frames.clear();
}
void LineProfiler::begin() { frames.clear(); }
void LineProfiler::_step(int callstack_size, Frame* frame) {
auto line_info = frame->co->lines[frame->ip()];

View File

@ -4,7 +4,7 @@
#include <cmath>
#include <stdexcept>
static const char* OP_NAMES[] = {
const static char* OP_NAMES[] = {
#define OPCODE(name) #name,
#include "pocketpy/opcodes.h"
#undef OPCODE
@ -80,12 +80,18 @@ namespace pkpy{
this->vm = this;
this->__c.error = nullptr;
_ceval_on_step = nullptr;
_stdout = [](const char* buf, int size) { std::cout.write(buf, size); };
_stderr = [](const char* buf, int size) { std::cerr.write(buf, size); };
_stdout = [](const char* buf, int size) {
std::cout.write(buf, size);
};
_stderr = [](const char* buf, int size) {
std::cerr.write(buf, size);
};
builtins = nullptr;
_main = nullptr;
__last_exception = nullptr;
_import_handler = [](const char* name, int* out_size) -> unsigned char*{ return nullptr; };
_import_handler = [](const char* name, int* out_size) -> unsigned char* {
return nullptr;
};
__init_builtin_types();
}
@ -96,9 +102,7 @@ namespace pkpy{
PyVar f = get_unbound_method(obj, __str__, &self, false);
if(self != PY_NULL) {
PyVar retval = call_method(self, f);
if(!is_type(retval, tp_str)){
throw std::runtime_error("object.__str__ must return str");
}
if(!is_type(retval, tp_str)) { throw std::runtime_error("object.__str__ must return str"); }
return PK_OBJ_GET(Str, retval);
}
return py_repr(obj);
@ -108,9 +112,7 @@ namespace pkpy{
const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__repr__) return ti->m__repr__(this, obj);
PyVar retval = call_method(obj, __repr__);
if(!is_type(retval, tp_str)){
throw std::runtime_error("object.__repr__ must return str");
}
if(!is_type(retval, tp_str)) { throw std::runtime_error("object.__repr__ must return str"); }
return PK_OBJ_GET(Str, retval);
}
@ -143,7 +145,8 @@ namespace pkpy{
void VM::set_main_argv(int argc, char** argv) {
PyVar mod = vm->_modules["sys"];
List argv_(argc);
for(int i=0; i<argc; i++) argv_[i] = VAR(std::string_view(argv[i]));
for(int i = 0; i < argc; i++)
argv_[i] = VAR(std::string_view(argv[i]));
mod->attr().set("argv", VAR(std::move(argv_)));
}
@ -158,9 +161,7 @@ namespace pkpy{
return nullptr;
}
bool VM::isinstance(PyVar obj, Type base){
return issubclass(_tp(obj), base);
}
bool VM::isinstance(PyVar obj, Type base) { return issubclass(_tp(obj), base); }
bool VM::issubclass(Type cls, Type base) {
do {
@ -181,18 +182,11 @@ namespace pkpy{
#endif
CodeObject_ code = compile(source, filename, mode);
return _exec(code, _module);
}catch (TopLevelException e){
stderr_write(e.summary() + "\n");
}
catch(const std::exception& e) {
} catch(TopLevelException e) { stderr_write(e.summary() + "\n"); } catch(const std::exception& e) {
Str msg = "An std::exception occurred! It could be a bug.\n";
msg = msg + e.what() + "\n";
stderr_write(msg);
}
catch(NeedMoreLines){
throw;
}
catch(...) {
} catch(NeedMoreLines) { throw; } catch(...) {
Str msg = "An unknown exception occurred! It could be a bug. Please report it to @blueloveTH on GitHub.\n";
stderr_write(msg);
}
@ -201,13 +195,9 @@ namespace pkpy{
return nullptr;
}
PyVar VM::exec(std::string_view source){
return exec(source, "main.py", EXEC_MODE);
}
PyVar VM::exec(std::string_view source) { return exec(source, "main.py", EXEC_MODE); }
PyVar VM::eval(std::string_view source){
return exec(source, "<eval>", EVAL_MODE);
}
PyVar VM::eval(std::string_view source) { return exec(source, "<eval>", EVAL_MODE); }
PyObject* VM::new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled, PyTypeInfo::Vt vt) {
PyObject* obj = heap._new<Type>(tp_type, Type(_all_types.size()));
@ -264,9 +254,7 @@ namespace pkpy{
i64 VM::normalized_index(i64 index, int size) {
if(index < 0) index += size;
if(index < 0 || index >= size){
IndexError(std::to_string(index) + " not in [0, " + std::to_string(size) + ")");
}
if(index < 0 || index >= size) { IndexError(std::to_string(index) + " not in [0, " + std::to_string(size) + ")"); }
return index;
}
@ -343,21 +331,22 @@ namespace pkpy{
};
if(path[0] == '.') {
if(__import_context.pending.empty()){
ImportError("relative import outside of package");
}
if(__import_context.pending.empty()) { ImportError("relative import outside of package"); }
Str curr_path = __import_context.pending.back();
bool curr_is_init = __import_context.pending_is_init.back();
// convert relative path to absolute path
vector<std::string_view> cpnts = curr_path.split('.');
int prefix = 0; // how many dots in the prefix
for(int i = 0; i < path.length(); i++) {
if(path[i] == '.') prefix++;
else break;
if(path[i] == '.')
prefix++;
else
break;
}
if(prefix > cpnts.size()) ImportError("attempted relative import beyond top-level package");
path = path.substr(prefix); // remove prefix
for(int i=(int)curr_is_init; i<prefix; i++) cpnts.pop_back();
for(int i = (int)curr_is_init; i < prefix; i++)
cpnts.pop_back();
if(!path.empty()) cpnts.push_back(path.sv());
path = f_join(cpnts);
}
@ -371,9 +360,7 @@ namespace pkpy{
vector<std::string_view> path_cpnts = path.split('.');
// check circular import
if(__import_context.pending.size() > 128){
ImportError("maximum recursion depth exceeded while importing");
}
if(__import_context.pending.size() > 128) { ImportError("maximum recursion depth exceeded while importing"); }
// try import
Str filename = path.replace('.', PK_PLATFORM_SEP) + ".py";
@ -389,8 +376,10 @@ namespace pkpy{
out = _import_handler(filename.c_str(), &out_size);
}
if(out == nullptr) {
if(throw_err) ImportError(_S("module ", path.escape(), " not found"));
else return nullptr;
if(throw_err)
ImportError(_S("module ", path.escape(), " not found"));
else
return nullptr;
}
assert(out_size >= 0);
source = Str(std::string_view((char*)out, out_size));
@ -411,8 +400,10 @@ namespace pkpy{
VM::~VM() {
// clear managed heap
for(PyObject* obj: heap.gen) heap._delete(obj);
for(PyObject* obj: heap._no_gc) heap._delete(obj);
for(PyObject* obj: heap.gen)
heap._delete(obj);
for(PyObject* obj: heap._no_gc)
heap._delete(obj);
// clear everything
callstack.clear();
s_data.clear();
@ -488,16 +479,16 @@ List VM::py_list(PyVar it){
return list;
}
void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step) {
auto clip = [](int value, int min, int max) {
if(value < min) return min;
if(value > max) return max;
return value;
};
if(s.step == None) step = 1;
else step = CAST(int, s.step);
if(s.step == None)
step = 1;
else
step = CAST(int, s.step);
if(step == 0) ValueError("slice step cannot be zero");
if(step > 0) {
if(s.start == None) {
@ -547,7 +538,8 @@ i64 VM::py_hash(PyVar obj){
if(ti == &_all_types[tp_object]) return obj.hash();
// otherwise, we check if it has a custom __eq__ other than object.__eq__
bool has_custom_eq = false;
if(ti->m__eq__) has_custom_eq = true;
if(ti->m__eq__)
has_custom_eq = true;
else {
f = get_unbound_method(obj, __eq__, &self, false);
has_custom_eq = f != _t(tp_object)->attr(__eq__);
@ -603,7 +595,8 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local
locals_dict->apply([&](PyVar k, PyVar v) {
locals_closure->set(CAST(Str&, k), v);
});
PyObject* _callable = heap.gcnew<Function>(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure);
PyObject* _callable =
heap.gcnew<Function>(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure);
retval = vm->_exec(code.get(), globals_obj, _callable, vm->s_data._sp);
}
@ -637,7 +630,9 @@ PyVar VM::__format_object(PyVar obj, Str spec){
if(spec.empty()) return VAR(py_str(obj));
char type;
switch(spec.end()[-1]) {
case 'f': case 'd': case 's':
case 'f':
case 'd':
case 's':
type = spec.end()[-1];
spec = spec.substr(0, spec.length() - 1);
break;
@ -663,8 +658,10 @@ PyVar VM::__format_object(PyVar obj, Str spec){
align = '<';
spec = spec.substr(1);
} else {
if(is_int(obj) || is_float(obj)) align = '>';
else align = '<';
if(is_int(obj) || is_float(obj))
align = '>';
else
align = '<';
}
int dot = spec.index(".");
@ -681,9 +678,7 @@ PyVar VM::__format_object(PyVar obj, Str spec){
width = std::stoi(spec.str());
precision = -1;
}
}catch(...){
ValueError("invalid format specifer");
}
} catch(...) { ValueError("invalid format specifer"); }
if(type != 'f' && dot >= 0) ValueError("precision not allowed in the format specifier");
Str ret;
@ -705,8 +700,10 @@ PyVar VM::__format_object(PyVar obj, Str spec){
int pad = width - ret.length();
if(align == '>' || align == '<') {
std::string padding(pad, pad_c);
if(align == '>') ret = padding.c_str() + ret;
else ret = ret + padding.c_str();
if(align == '>')
ret = padding.c_str() + ret;
else
ret = ret + padding.c_str();
} else { // ^
int pad_left = pad / 2;
int pad_right = pad - pad_left;
@ -728,9 +725,7 @@ PyObject* VM::new_module(Str name, Str package) {
// we do not allow override in order to avoid memory leak
// it is because Module objects are not garbage collected
if(_modules.contains(name)){
throw std::runtime_error(_S("module ", name.escape(), " already exists").str());
}
if(_modules.contains(name)) { throw std::runtime_error(_S("module ", name.escape(), " already exists").str()); }
// set it into _modules
_modules.set(name, obj);
return obj;
@ -746,22 +741,35 @@ static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject
}
ss << (i64)byte.arg;
switch(byte.op) {
case OP_LOAD_CONST: case OP_FORMAT_STRING: case OP_IMPORT_PATH:
case OP_LOAD_CONST:
case OP_FORMAT_STRING:
case OP_IMPORT_PATH:
if(vm != nullptr) ss << " (" << vm->py_repr(co->consts[byte.arg]) << ")";
break;
case OP_LOAD_NAME: case OP_LOAD_GLOBAL: case OP_LOAD_NONLOCAL: case OP_STORE_GLOBAL:
case OP_LOAD_ATTR: case OP_LOAD_METHOD: case OP_STORE_ATTR: case OP_DELETE_ATTR:
case OP_BEGIN_CLASS: case OP_GOTO:
case OP_DELETE_GLOBAL: case OP_INC_GLOBAL: case OP_DEC_GLOBAL: case OP_STORE_CLASS_ATTR: case OP_FOR_ITER_STORE_GLOBAL:
ss << " (" << StrName(byte.arg).sv() << ")";
break;
case OP_LOAD_FAST: case OP_STORE_FAST: case OP_DELETE_FAST: case OP_INC_FAST: case OP_DEC_FAST:
case OP_FOR_ITER_STORE_FAST: case OP_LOAD_SUBSCR_FAST: case OP_STORE_SUBSCR_FAST:
ss << " (" << co->varnames[byte.arg].sv() << ")";
break;
case OP_LOAD_FUNCTION:
ss << " (" << co->func_decls[byte.arg]->code->name << ")";
break;
case OP_LOAD_NAME:
case OP_LOAD_GLOBAL:
case OP_LOAD_NONLOCAL:
case OP_STORE_GLOBAL:
case OP_LOAD_ATTR:
case OP_LOAD_METHOD:
case OP_STORE_ATTR:
case OP_DELETE_ATTR:
case OP_BEGIN_CLASS:
case OP_GOTO:
case OP_DELETE_GLOBAL:
case OP_INC_GLOBAL:
case OP_DEC_GLOBAL:
case OP_STORE_CLASS_ATTR:
case OP_FOR_ITER_STORE_GLOBAL: ss << " (" << StrName(byte.arg).sv() << ")"; break;
case OP_LOAD_FAST:
case OP_STORE_FAST:
case OP_DELETE_FAST:
case OP_INC_FAST:
case OP_DEC_FAST:
case OP_FOR_ITER_STORE_FAST:
case OP_LOAD_SUBSCR_FAST:
case OP_STORE_SUBSCR_FAST: ss << " (" << co->varnames[byte.arg].sv() << ")"; break;
case OP_LOAD_FUNCTION: ss << " (" << co->func_decls[byte.arg]->code->name << ")"; break;
}
return ss.str().str();
}
@ -775,16 +783,15 @@ Str VM::disassemble(CodeObject_ co){
vector<int> jumpTargets;
for(int i = 0; i < co->codes.size(); i++) {
Bytecode byte = co->codes[i];
if(byte.is_forward_jump()){
jumpTargets.push_back((int16_t)byte.arg + i);
}
if(byte.is_forward_jump()) { jumpTargets.push_back((int16_t)byte.arg + i); }
}
SStream ss;
int prev_line = -1;
for(int i = 0; i < co->codes.size(); i++) {
const Bytecode& byte = co->codes[i];
Str line = std::to_string(co->lines[i].lineno);
if(co->lines[i].lineno == prev_line) line = "";
if(co->lines[i].lineno == prev_line)
line = "";
else {
if(prev_line != -1) ss << "\n";
prev_line = co->lines[i].lineno;
@ -806,7 +813,8 @@ Str VM::disassemble(CodeObject_ co){
}
for(auto& decl: co->func_decls) {
ss << "\n\n" << "Disassembly of " << decl->code->name << ":\n";
ss << "\n\n"
<< "Disassembly of " << decl->code->name << ":\n";
ss << disassemble(decl->code);
}
ss << "\n";
@ -830,7 +838,8 @@ void VM::__log_s_data(const char* title) {
for(PyVar* p = s_data.begin(); p != s_data.end(); p++) {
ss << std::string(sp_bases[p], '|');
if(sp_bases[p] > 0) ss << " ";
if(*p == PY_NULL) ss << "NULL";
if(*p == PY_NULL)
ss << "NULL";
else {
switch(p->type) {
case tp_none_type: ss << "None"; break;
@ -838,38 +847,30 @@ void VM::__log_s_data(const char* title) {
case tp_float: ss << _CAST(f64, *p); break;
case tp_bool: ss << ((*p == True) ? "True" : "False"); break;
case tp_str: ss << _CAST(Str, *p).escape(); break;
case tp_function:
ss << p->obj_get<Function>().decl->code->name << "()";
break;
case tp_type:
ss << "<class " + _type_name(this, p->obj_get<Type>()).escape() + ">";
break;
case tp_list:
ss << "list(size=" << p->obj_get<List>().size() << ")";
break;
case tp_tuple:
ss << "tuple(size=" << p->obj_get<Tuple>().size() << ")";
break;
case tp_function: ss << p->obj_get<Function>().decl->code->name << "()"; break;
case tp_type: ss << "<class " + _type_name(this, p->obj_get<Type>()).escape() + ">"; break;
case tp_list: ss << "list(size=" << p->obj_get<List>().size() << ")"; break;
case tp_tuple: ss << "tuple(size=" << p->obj_get<Tuple>().size() << ")"; break;
case tp_stack_memory: {
int count = p->obj_get<StackMemory>().count;
ss << "M[" << count << "]";
if(count > 0) p += count;
break;
}
default:
ss << "(" << _type_name(this, p->type) << ")";
break;
default: ss << "(" << _type_name(this, p->type) << ")"; break;
}
}
ss << ", ";
}
std::string output = ss.str().str();
if(!s_data.empty()) {
output.pop_back(); output.pop_back();
output.pop_back();
output.pop_back();
}
output.push_back(']');
Bytecode byte = *frame->_ip;
std::cout << output << " " << OP_NAMES[byte.op] << " " << _opcode_argstr(nullptr, frame->ip(), byte, frame->co) << std::endl;
std::cout << output << " " << OP_NAMES[byte.op] << " " << _opcode_argstr(nullptr, frame->ip(), byte, frame->co)
<< std::endl;
}
#endif
@ -982,23 +983,22 @@ void VM::__unpack_as_dict(ArgsView args, Dict& dict){
}
}
void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const FuncDecl_& decl) {
const CodeObject* co = decl->code.get();
int decl_argc = decl->args.size();
if(args.size() < decl_argc) {
vm->TypeError(_S(
co->name, "() takes ", decl_argc, " positional arguments but ", args.size(), " were given"
));
vm->TypeError(_S(co->name, "() takes ", decl_argc, " positional arguments but ", args.size(), " were given"));
}
int i = 0;
// prepare args
std::memset(buffer, 0, co->nlocals * sizeof(PyVar));
for(int index: decl->args) buffer[index] = args[i++];
for(int index: decl->args)
buffer[index] = args[i++];
// prepare kwdefaults
for(auto& kv: decl->kwargs) buffer[kv.index] = kv.value;
for(auto& kv: decl->kwargs)
buffer[kv.index] = kv.value;
// handle *args
if(decl->starred_arg != -1) {
@ -1077,10 +1077,17 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call){
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
// copy buffer back to stack
s_data.reset(_base + co->nlocals);
for(int j=0; j<co->nlocals; j++) _base[j] = __vectorcall_buffer[j];
for(int j = 0; j < co->nlocals; j++)
_base[j] = __vectorcall_buffer[j];
break;
case FuncType::SIMPLE:
if(args.size() != fn.decl->args.size()) TypeError(_S(co->name, "() takes ", fn.decl->args.size(), " positional arguments but ", args.size(), " were given"));
if(args.size() != fn.decl->args.size())
TypeError(_S(co->name,
"() takes ",
fn.decl->args.size(),
" positional arguments but ",
args.size(),
" were given"));
if(!kwargs.empty()) TypeError(_S(co->name, "() takes no keyword arguments"));
// [callable, <self>, args..., local_vars...]
// ^p0 ^p1 ^_sp
@ -1089,7 +1096,13 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call){
std::memset(p1, 0, (char*)s_data._sp - (char*)p1);
break;
case FuncType::EMPTY:
if(args.size() != fn.decl->args.size()) TypeError(_S(co->name, "() takes ", fn.decl->args.size(), " positional arguments but ", args.size(), " were given"));
if(args.size() != fn.decl->args.size())
TypeError(_S(co->name,
"() takes ",
fn.decl->args.size(),
" positional arguments but ",
args.size(),
" were given"));
if(!kwargs.empty()) TypeError(_S(co->name, "() takes no keyword arguments"));
s_data.reset(p0);
return None;
@ -1097,10 +1110,8 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call){
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
s_data.reset(p0);
callstack.emplace(nullptr, co, fn._module, callable.get(), nullptr);
return __py_generator(
callstack.popx(),
ArgsView(__vectorcall_buffer, __vectorcall_buffer + co->nlocals)
);
return __py_generator(callstack.popx(),
ArgsView(__vectorcall_buffer, __vectorcall_buffer + co->nlocals));
default: PK_UNREACHABLE()
};
@ -1119,14 +1130,15 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call){
__prepare_py_call(__vectorcall_buffer, args, kwargs, f.decl);
// copy buffer back to stack
s_data.reset(_base + co_nlocals);
for(int j=0; j<co_nlocals; j++) _base[j] = __vectorcall_buffer[j];
for(int j = 0; j < co_nlocals; j++)
_base[j] = __vectorcall_buffer[j];
ret = f.call(vm, ArgsView(s_data._sp - co_nlocals, s_data._sp));
} else {
if(f.argc != -1) {
if(KWARGC != 0) TypeError("old-style native_func does not accept keyword arguments. If you want to skip this check, specify `argc` to -1");
if(args.size() != f.argc){
vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size()));
}
if(KWARGC != 0)
TypeError(
"old-style native_func does not accept keyword arguments. If you want to skip this check, specify `argc` to -1");
if(args.size() != f.argc) { vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size())); }
}
ret = f.call(this, args);
}
@ -1146,8 +1158,10 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call){
PUSH(new_f);
PUSH(PY_NULL);
PUSH(callable); // cls
for(PyVar o: args) PUSH(o);
for(PyVar o: kwargs) PUSH(o);
for(PyVar o: args)
PUSH(o);
for(PyVar o: kwargs)
PUSH(o);
// if obj is not an instance of `cls`, the behavior is undefined
obj = vectorcall(ARGC + 1, KWARGC);
}
@ -1229,14 +1243,10 @@ PyVar VM::getattr(PyVar obj, StrName name, bool throw_err){
// bound method is non-data descriptor
if(!is_tagged(*cls_var)) {
switch(cls_var->type.index) {
case tp_function.index:
return VAR(BoundMethod(obj, *cls_var));
case tp_native_func.index:
return VAR(BoundMethod(obj, *cls_var));
case tp_staticmethod.index:
return PK_OBJ_GET(StaticMethod, *cls_var).func;
case tp_classmethod.index:
return VAR(BoundMethod(_t(objtype), PK_OBJ_GET(ClassMethod, *cls_var).func));
case tp_function.index: return VAR(BoundMethod(obj, *cls_var));
case tp_native_func.index: return VAR(BoundMethod(obj, *cls_var));
case tp_staticmethod.index: return PK_OBJ_GET(StaticMethod, *cls_var).func;
case tp_classmethod.index: return VAR(BoundMethod(_t(objtype), PK_OBJ_GET(ClassMethod, *cls_var).func));
}
}
return *cls_var;
@ -1296,18 +1306,10 @@ PyVar VM::get_unbound_method(PyVar obj, StrName name, PyVar* self, bool throw_er
if(cls_var != nullptr) {
if(!is_tagged(*cls_var)) {
switch(cls_var->type.index) {
case tp_function.index:
*self = obj;
break;
case tp_native_func.index:
*self = obj;
break;
case tp_staticmethod.index:
self->set_null();
return PK_OBJ_GET(StaticMethod, *cls_var).func;
case tp_classmethod.index:
*self = _t(objtype);
return PK_OBJ_GET(ClassMethod, *cls_var).func;
case tp_function.index: *self = obj; break;
case tp_native_func.index: *self = obj; break;
case tp_staticmethod.index: self->set_null(); return PK_OBJ_GET(StaticMethod, *cls_var).func;
case tp_classmethod.index: *self = _t(objtype); return PK_OBJ_GET(ClassMethod, *cls_var).func;
}
}
return *cls_var;
@ -1362,12 +1364,8 @@ PyObject* VM::bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, a
PyObject* nf = heap.gcnew<NativeFunc>(tp_native_func, fn, argc, std::move(userdata));
switch(bt) {
case BindType::DEFAULT: break;
case BindType::STATICMETHOD:
nf = heap.gcnew<StaticMethod>(tp_staticmethod, nf);
break;
case BindType::CLASSMETHOD:
nf = heap.gcnew<ClassMethod>(tp_classmethod, nf);
break;
case BindType::STATICMETHOD: nf = heap.gcnew<StaticMethod>(tp_staticmethod, nf); break;
case BindType::CLASSMETHOD: nf = heap.gcnew<ClassMethod>(tp_classmethod, nf); break;
}
if(obj != nullptr) obj->attr().set(name, nf);
return nf;
@ -1382,25 +1380,16 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
try {
// fn(a, b, *c, d=1) -> None
co = compile(_S("def ", sig, " : pass"), "<bind>", EXEC_MODE);
}catch(TopLevelException){
throw std::runtime_error("invalid signature: " + std::string(sig));
}
if(co->func_decls.size() != 1){
throw std::runtime_error("expected 1 function declaration");
}
} catch(TopLevelException) { throw std::runtime_error("invalid signature: " + std::string(sig)); }
if(co->func_decls.size() != 1) { throw std::runtime_error("expected 1 function declaration"); }
FuncDecl_ decl = co->func_decls[0];
decl->docstring = docstring;
PyObject* f_obj = heap.gcnew<NativeFunc>(tp_native_func, fn, decl, std::move(userdata));
switch(bt) {
case BindType::STATICMETHOD:
f_obj = heap.gcnew<StaticMethod>(tp_staticmethod, f_obj);
break;
case BindType::CLASSMETHOD:
f_obj = heap.gcnew<ClassMethod>(tp_classmethod, f_obj);
break;
case BindType::DEFAULT:
break;
case BindType::STATICMETHOD: f_obj = heap.gcnew<StaticMethod>(tp_staticmethod, f_obj); break;
case BindType::CLASSMETHOD: f_obj = heap.gcnew<ClassMethod>(tp_classmethod, f_obj); break;
case BindType::DEFAULT: break;
}
if(obj != nullptr) obj->attr().set(decl->code->name, f_obj);
return f_obj;
@ -1408,7 +1397,8 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
PyObject* VM::bind_property(PyObject* obj, const char* name, NativeFuncC fget, NativeFuncC fset) {
assert(is_type(obj, tp_type));
std::string_view name_sv(name); int pos = name_sv.find(':');
std::string_view name_sv(name);
int pos = name_sv.find(':');
if(pos > 0) name_sv = name_sv.substr(0, pos);
PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1);
PyVar _1 = vm->None;
@ -1419,7 +1409,9 @@ PyObject* VM::bind_property(PyObject* obj, const char* name, NativeFuncC fget, N
}
void VM::__builtin_error(StrName type) { _error(call(builtins->attr(type))); }
void VM::__builtin_error(StrName type, PyVar arg) { _error(call(builtins->attr(type), arg)); }
void VM::__builtin_error(StrName type, const Str& msg) { __builtin_error(type, VAR(msg)); }
void VM::BinaryOptError(const char* op, PyVar _0, PyVar _1) {
@ -1430,9 +1422,12 @@ void VM::BinaryOptError(const char* op, PyVar _0, PyVar _1) {
void VM::AttributeError(PyVar obj, StrName name) {
if(isinstance(obj, vm->tp_type)) {
__builtin_error("AttributeError", _S("type object ", _type_name(vm, PK_OBJ_GET(Type, obj)).escape(), " has no attribute ", name.escape()));
__builtin_error(
"AttributeError",
_S("type object ", _type_name(vm, PK_OBJ_GET(Type, obj)).escape(), " has no attribute ", name.escape()));
} else {
__builtin_error("AttributeError", _S(_type_name(vm, _tp(obj)).escape(), " object has no attribute ", name.escape()));
__builtin_error("AttributeError",
_S(_type_name(vm, _tp(obj)).escape(), " object has no attribute ", name.escape()));
}
}
@ -1471,33 +1466,44 @@ void VM::__raise_exc(bool re_raise){
}
}
StrName _type_name(VM *vm, Type type){
return vm->_all_types[type].name;
}
StrName _type_name(VM* vm, Type type) { return vm->_all_types[type].name; }
void VM::bind__getitem__(Type type, PyVar (*f)(VM*, PyVar, PyVar)) {
_all_types[type].m__getitem__ = f;
bind_func(type, __getitem__, 2, [](VM* vm, ArgsView args){
bind_func(
type,
__getitem__,
2,
[](VM* vm, ArgsView args) {
return lambda_get_userdata<decltype(f)>(args.begin())(vm, args[0], args[1]);
}, f);
},
f);
}
void VM::bind__setitem__(Type type, void (*f)(VM*, PyVar, PyVar, PyVar)) {
_all_types[type].m__setitem__ = f;
bind_func(type, __setitem__, 3, [](VM* vm, ArgsView args){
bind_func(
type,
__setitem__,
3,
[](VM* vm, ArgsView args) {
lambda_get_userdata<decltype(f)>(args.begin())(vm, args[0], args[1], args[2]);
return vm->None;
}, f);
},
f);
}
void VM::bind__delitem__(Type type, void (*f)(VM*, PyVar, PyVar)) {
_all_types[type].m__delitem__ = f;
bind_func(type, __delitem__, 2, [](VM* vm, ArgsView args){
bind_func(
type,
__delitem__,
2,
[](VM* vm, ArgsView args) {
lambda_get_userdata<decltype(f)>(args.begin())(vm, args[0], args[1]);
return vm->None;
}, f);
},
f);
}
PyVar VM::__pack_next_retval(unsigned n) {
@ -1510,25 +1516,40 @@ PyVar VM::__pack_next_retval(unsigned n){
void VM::bind__next__(Type type, unsigned (*f)(VM*, PyVar)) {
_all_types[type].op__next__ = f;
bind_func(type, __next__, 1, [](VM* vm, ArgsView args){
bind_func(
type,
__next__,
1,
[](VM* vm, ArgsView args) {
int n = lambda_get_userdata<decltype(f)>(args.begin())(vm, args[0]);
return vm->__pack_next_retval(n);
}, f);
},
f);
}
void VM::bind__next__(Type type, PyVar (*f)(VM*, PyVar)) {
bind_func(type, __next__, 1, [](VM* vm, ArgsView args){
bind_func(
type,
__next__,
1,
[](VM* vm, ArgsView args) {
auto f = lambda_get_userdata<PyVar (*)(VM*, PyVar)>(args.begin());
return f(vm, args[0]);
}, f);
},
f);
}
#define BIND_UNARY_SPECIAL(name) \
void VM::bind##name(Type type, PyVar (*f)(VM*, PyVar)) { \
_all_types[type].m##name = f; \
bind_func(type, name, 1, [](VM* vm, ArgsView args){ \
bind_func( \
type, \
name, \
1, \
[](VM* vm, ArgsView args) { \
return lambda_get_userdata<PyVar (*)(VM*, PyVar)>(args.begin())(vm, args[0]); \
}, f); \
}, \
f); \
}
BIND_UNARY_SPECIAL(__iter__)
BIND_UNARY_SPECIAL(__neg__)
@ -1537,43 +1558,67 @@ void VM::bind__next__(Type type, PyVar (*f)(VM*, PyVar)){
void VM::bind__str__(Type type, Str (*f)(VM*, PyVar)) {
_all_types[type].m__str__ = f;
bind_func(type, __str__, 1, [](VM* vm, ArgsView args){
bind_func(
type,
__str__,
1,
[](VM* vm, ArgsView args) {
Str s = lambda_get_userdata<decltype(f)>(args.begin())(vm, args[0]);
return VAR(s);
}, f);
},
f);
}
void VM::bind__repr__(Type type, Str (*f)(VM*, PyVar)) {
_all_types[type].m__repr__ = f;
bind_func(type, __repr__, 1, [](VM* vm, ArgsView args){
bind_func(
type,
__repr__,
1,
[](VM* vm, ArgsView args) {
Str s = lambda_get_userdata<decltype(f)>(args.begin())(vm, args[0]);
return VAR(s);
}, f);
},
f);
}
void VM::bind__hash__(Type type, i64 (*f)(VM*, PyVar)) {
_all_types[type].m__hash__ = f;
bind_func(type, __hash__, 1, [](VM* vm, ArgsView args){
bind_func(
type,
__hash__,
1,
[](VM* vm, ArgsView args) {
i64 ret = lambda_get_userdata<decltype(f)>(args.begin())(vm, args[0]);
return VAR(ret);
}, f);
},
f);
}
void VM::bind__len__(Type type, i64 (*f)(VM*, PyVar)) {
_all_types[type].m__len__ = f;
bind_func(type, __len__, 1, [](VM* vm, ArgsView args){
bind_func(
type,
__len__,
1,
[](VM* vm, ArgsView args) {
i64 ret = lambda_get_userdata<decltype(f)>(args.begin())(vm, args[0]);
return VAR(ret);
}, f);
},
f);
}
#define BIND_BINARY_SPECIAL(name) \
void VM::bind##name(Type type, BinaryFuncC f) { \
_all_types[type].m##name = f; \
bind_func(type, name, 2, [](VM* vm, ArgsView args){ \
bind_func( \
type, \
name, \
2, \
[](VM* vm, ArgsView args) { \
return lambda_get_userdata<BinaryFuncC>(args.begin())(vm, args[0], args[1]); \
}, f); \
}, \
f); \
}
BIND_BINARY_SPECIAL(__eq__)
@ -1600,14 +1645,16 @@ void VM::bind__len__(Type type, i64 (*f)(VM*, PyVar)){
#undef BIND_BINARY_SPECIAL
void Dict::_probe_0(VM* vm, PyVar key, bool& ok, int& i) const {
ok = false;
i64 hash = vm->py_hash(key);
i = hash & _mask;
for(int j = 0; j < _capacity; j++) {
if(_items[i].first != nullptr) {
if(vm->py_eq(_items[i].first, key)) { ok = true; break; }
if(vm->py_eq(_items[i].first, key)) {
ok = true;
break;
}
} else {
if(_items[i].second == nullptr) break;
}
@ -1620,21 +1667,21 @@ void Dict::_probe_1(VM* vm, PyVar key, bool &ok, int &i) const{
ok = false;
i = vm->py_hash(key) & _mask;
while(_items[i].first != nullptr) {
if(vm->py_eq(_items[i].first, key)) { ok = true; break; }
if(vm->py_eq(_items[i].first, key)) {
ok = true;
break;
}
// https://github.com/python/cpython/blob/3.8/Objects/dictobject.c#L166
i = ((5 * i) + 1) & _mask;
}
}
#if PK_ENABLE_PROFILER
void NextBreakpoint::_step(VM* vm) {
int curr_callstack_size = vm->callstack.size();
int curr_lineno = vm->callstack.top().curr_lineno();
if(should_step_into) {
if(curr_callstack_size != callstack_size || curr_lineno != lineno){
vm->__breakpoint();
}
if(curr_callstack_size != callstack_size || curr_lineno != lineno) { vm->__breakpoint(); }
} else {
if(curr_callstack_size == callstack_size) {
if(curr_lineno != lineno) vm->__breakpoint();
@ -1715,9 +1762,7 @@ void VM::__breakpoint(){
stdout_write("!: execute statement\n");
continue;
}
if(line == "q" || line == "quit") {
vm->RuntimeError("pdb quit");
}
if(line == "q" || line == "quit") { vm->RuntimeError("pdb quit"); }
if(line == "n" || line == "next") {
vm->_next_breakpoint = NextBreakpoint(vm->callstack.size(), frame_0->curr_lineno(), false);
break;
@ -1765,8 +1810,10 @@ void VM::__breakpoint(){
for(int i = start; i <= end; i++) {
int spaces = max_width - std::to_string(i).size();
ss << std::string(spaces, ' ') << std::to_string(i);
if(i == lineno) ss << " -> ";
else ss << " ";
if(i == lineno)
ss << " -> ";
else
ss << " ";
ss << frame_0->co->src->get_line(i) << '\n';
}
stdout_write(ss.str());
@ -1809,37 +1856,32 @@ void NativeFunc::_gc_mark(VM* vm) const{
void FuncDecl::_gc_mark(VM* vm) const {
code->_gc_mark(vm);
for(int i=0; i<kwargs.size(); i++) vm->obj_gc_mark(kwargs[i].value);
for(int i = 0; i < kwargs.size(); i++)
vm->obj_gc_mark(kwargs[i].value);
}
void List::_gc_mark(VM* vm) const {
for(PyVar obj: *this) vm->obj_gc_mark(obj);
for(PyVar obj: *this)
vm->obj_gc_mark(obj);
}
void Tuple::_gc_mark(VM* vm) const {
for(PyVar obj: *this) vm->obj_gc_mark(obj);
for(PyVar obj: *this)
vm->obj_gc_mark(obj);
}
void MappingProxy::_gc_mark(VM* vm) const{
vm->__obj_gc_mark(obj);
}
void MappingProxy::_gc_mark(VM* vm) const { vm->__obj_gc_mark(obj); }
void BoundMethod::_gc_mark(VM* vm) const {
vm->obj_gc_mark(func);
vm->obj_gc_mark(self);
}
void StarWrapper::_gc_mark(VM* vm) const{
vm->obj_gc_mark(obj);
}
void StarWrapper::_gc_mark(VM* vm) const { vm->obj_gc_mark(obj); }
void StaticMethod::_gc_mark(VM* vm) const{
vm->obj_gc_mark(func);
}
void StaticMethod::_gc_mark(VM* vm) const { vm->obj_gc_mark(func); }
void ClassMethod::_gc_mark(VM* vm) const{
vm->obj_gc_mark(func);
}
void ClassMethod::_gc_mark(VM* vm) const { vm->obj_gc_mark(func); }
void Property::_gc_mark(VM* vm) const {
vm->obj_gc_mark(getter);
@ -1852,9 +1894,7 @@ void Slice::_gc_mark(VM* vm) const{
vm->obj_gc_mark(step);
}
void Super::_gc_mark(VM* vm) const{
vm->obj_gc_mark(first);
}
void Super::_gc_mark(VM* vm) const { vm->obj_gc_mark(first); }
void Frame::_gc_mark(VM* vm) const {
vm->obj_gc_mark(_module);
@ -1864,9 +1904,13 @@ void Frame::_gc_mark(VM* vm) const {
}
void ManagedHeap::mark() {
for(PyObject* obj: _no_gc) vm->__obj_gc_mark(obj);
vm->callstack.apply([this](Frame& frame){ frame._gc_mark(vm); });
for(auto [_, co]: vm->__cached_codes) co->_gc_mark(vm);
for(PyObject* obj: _no_gc)
vm->__obj_gc_mark(obj);
vm->callstack.apply([this](Frame& frame) {
frame._gc_mark(vm);
});
for(auto [_, co]: vm->__cached_codes)
co->_gc_mark(vm);
vm->obj_gc_mark(vm->__last_exception);
vm->obj_gc_mark(vm->__curr_class);
vm->obj_gc_mark(vm->__c.error);
@ -1889,8 +1933,10 @@ void Dict::_gc_mark(VM* vm) const{
}
void CodeObject::_gc_mark(VM* vm) const {
for(PyVar v : consts) vm->obj_gc_mark(v);
for(auto& decl: func_decls) decl->_gc_mark(vm);
for(PyVar v: consts)
vm->obj_gc_mark(v);
for(auto& decl: func_decls)
decl->_gc_mark(vm);
}
} // namespace pkpy

View File

@ -25,22 +25,16 @@ struct Array2d{
this->data = new PyVar[numel];
}
bool is_valid(int col, int row) const{
return 0 <= col && col < n_cols && 0 <= row && row < n_rows;
}
bool is_valid(int col, int row) const { return 0 <= col && col < n_cols && 0 <= row && row < n_rows; }
void check_valid(VM* vm, int col, int row) const {
if(is_valid(col, row)) return;
vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')'));
}
PyVar _get(int col, int row){
return data[row * n_cols + col];
}
PyVar _get(int col, int row) { return data[row * n_cols + col]; }
void _set(int col, int row, PyVar value){
data[row * n_cols + col] = value;
}
void _set(int col, int row, PyVar value) { data[row * n_cols + col] = value; }
static void _register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind(type, "__new__(cls, *args, **kwargs)", [](VM* vm, ArgsView args) {
@ -52,14 +46,14 @@ struct Array2d{
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
int n_cols = CAST(int, args[1]);
int n_rows = CAST(int, args[2]);
if(n_cols <= 0 || n_rows <= 0){
vm->ValueError("n_cols and n_rows must be positive integers");
}
if(n_cols <= 0 || n_rows <= 0) { vm->ValueError("n_cols and n_rows must be positive integers"); }
self.init(n_cols, n_rows);
if(vm->py_callable(args[3])) {
for(int i = 0; i < self.numel; i++) self.data[i] = vm->call(args[3]);
for(int i = 0; i < self.numel; i++)
self.data[i] = vm->call(args[3]);
} else {
for(int i = 0; i < self.numel; i++) self.data[i] = args[3];
for(int i = 0; i < self.numel; i++)
self.data[i] = args[3];
}
return vm->None;
});
@ -193,7 +187,8 @@ struct Array2d{
List t(self.n_rows);
for(int j = 0; j < self.n_rows; j++) {
List row(self.n_cols);
for(int i = 0; i < self.n_cols; i++) row[i] = self._get(i, j);
for(int i = 0; i < self.n_cols; i++)
row[i] = self._get(i, j);
t[j] = VAR(std::move(row));
}
return VAR(std::move(t));
@ -327,7 +322,8 @@ struct Array2d{
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
PyVar value = args[1];
int count = 0;
for(int i = 0; i < self.numel; i++) count += vm->py_eq(self.data[i], value);
for(int i = 0; i < self.numel; i++)
count += vm->py_eq(self.data[i], value);
return VAR(count);
});
@ -361,15 +357,13 @@ struct Array2d{
}
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(){
delete[] data;
}
~Array2d() { delete[] data; }
};
struct Array2dIter {
PK_ALWAYS_PASS_BY_POINTER(Array2dIter)
@ -382,7 +376,9 @@ struct Array2dIter{
void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
static void _register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
Array2dIter& self = PK_OBJ_GET(Array2dIter, _0);
if(self.i == self.a->numel) return 0;
@ -410,5 +406,4 @@ void add_module_array2d(VM* vm){
};
}
} // namespace pkpy

View File

@ -9,6 +9,7 @@ const char BASE64_PAD = '=';
const char BASE64DE_FIRST = '+';
const char BASE64DE_LAST = 'z';
// clang-format off
/* BASE 64 encode table */
const char base64en[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
@ -71,10 +72,9 @@ const unsigned char base64de[] = {
/* 'x', 'y', 'z', '{', '|', '}', '~', del, */
49, 50, 51, 255, 255, 255, 255, 255
};
// clang-format on
static unsigned int
base64_encode(const unsigned char *in, unsigned int inlen, char *out)
{
static unsigned int base64_encode(const unsigned char* in, unsigned int inlen, char* out) {
int s;
unsigned int i;
unsigned int j;
@ -121,34 +121,22 @@ base64_encode(const unsigned char *in, unsigned int inlen, char *out)
return j;
}
static unsigned int
base64_decode(const char *in, unsigned int inlen, unsigned char *out)
{
static unsigned int base64_decode(const char* in, unsigned int inlen, unsigned char* out) {
unsigned int i;
unsigned int j;
unsigned char c;
if (inlen & 0x3) {
return 0;
}
if(inlen & 0x3) { return 0; }
for(i = j = 0; i < inlen; i++) {
if (in[i] == BASE64_PAD) {
break;
}
if (in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) {
return 0;
}
if(in[i] == BASE64_PAD) { break; }
if(in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) { return 0; }
c = base64de[(unsigned char)in[i]];
if (c == 255) {
return 0;
}
if(c == 255) { return 0; }
switch(i & 0x3) {
case 0:
out[j] = (c << 2) & 0xFF;
break;
case 0: out[j] = (c << 2) & 0xFF; break;
case 1:
out[j++] |= (c >> 4) & 0x3;
out[j] = (c & 0xF) << 4;
@ -157,9 +145,7 @@ base64_decode(const char *in, unsigned int inlen, unsigned char *out)
out[j++] |= (c >> 2) & 0xF;
out[j] = (c & 0x3) << 6;
break;
case 3:
out[j++] |= c;
break;
case 3: out[j++] |= c; break;
}
}

View File

@ -43,11 +43,8 @@ __NEXT_LINE:
buffer.clear();
}
break;
case '\r':
break; // ignore
default:
buffer += line[j];
break;
case '\r': break; // ignore
default: buffer += line[j]; break;
}
j++;
}
@ -71,16 +68,12 @@ __NEXT_LINE:
PyVar csv_reader = vm->_modules["csv"]->attr("reader");
PyVar ret_obj = vm->call(csv_reader, args[0]);
const List& ret = CAST(List&, ret_obj);
if(ret.size() == 0){
vm->ValueError("empty csvfile");
}
if(ret.size() == 0) { vm->ValueError("empty csvfile"); }
const List& header = CAST(List&, ret[0]);
List new_ret;
for(int i = 1; i < ret.size(); i++) {
const List& row = CAST(List&, ret[i]);
if(row.size() != header.size()){
vm->ValueError("row.size() != header.size()");
}
if(row.size() != header.size()) { vm->ValueError("row.size() != header.size()"); }
Dict row_dict;
for(int j = 0; j < header.size(); j++) {
row_dict.set(vm, header[j], row[j]);

View File

@ -35,7 +35,8 @@ static void patch__init__(VM* vm, Type cls){
}
}
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) {
StrName unexpected_key = kwargs.items()[0].first;
@ -54,8 +55,10 @@ static void patch__repr__(VM* vm, Type cls){
ss << cls_info->name << "(";
bool first = true;
for(StrName field: fields) {
if(first) first = false;
else ss << ", ";
if(first)
first = false;
else
ss << ", ";
ss << field << "=" << vm->py_repr(obj_d[field]);
}
ss << ")";

View File

@ -8,29 +8,17 @@ namespace pkpy{
const double kPi = 3.1415926545;
static double easeLinear( double x ) {
return x;
}
static double easeLinear(double x) { return x; }
static double easeInSine( double x ) {
return 1.0 - std::cos( x * kPi / 2 );
}
static double easeInSine(double x) { return 1.0 - std::cos(x * kPi / 2); }
static double easeOutSine( double x ) {
return std::sin( x * kPi / 2 );
}
static double easeOutSine(double x) { return std::sin(x * kPi / 2); }
static double easeInOutSine( double x ) {
return -( std::cos( kPi * x ) - 1 ) / 2;
}
static double easeInOutSine(double x) { return -(std::cos(kPi * x) - 1) / 2; }
static double easeInQuad( double x ) {
return x * x;
}
static double easeInQuad(double x) { return x * x; }
static double easeOutQuad( double x ) {
return 1 - std::pow( 1 - x, 2 );
}
static double easeOutQuad(double x) { return 1 - std::pow(1 - x, 2); }
static double easeInOutQuad(double x) {
if(x < 0.5) {
@ -40,13 +28,9 @@ static double easeInOutQuad( double x ) {
}
}
static double easeInCubic( double x ) {
return x * x * x;
}
static double easeInCubic(double x) { return x * x * x; }
static double easeOutCubic( double x ) {
return 1 - std::pow( 1 - x, 3 );
}
static double easeOutCubic(double x) { return 1 - std::pow(1 - x, 3); }
static double easeInOutCubic(double x) {
if(x < 0.5) {
@ -56,13 +40,9 @@ static double easeInOutCubic( double x ) {
}
}
static double easeInQuart( double x ) {
return std::pow( x, 4 );
}
static double easeInQuart(double x) { return std::pow(x, 4); }
static double easeOutQuart( double x ) {
return 1 - std::pow( 1 - x, 4 );
}
static double easeOutQuart(double x) { return 1 - std::pow(1 - x, 4); }
static double easeInOutQuart(double x) {
if(x < 0.5) {
@ -72,13 +52,9 @@ static double easeInOutQuart( double x ) {
}
}
static double easeInQuint( double x ) {
return std::pow( x, 5 );
}
static double easeInQuint(double x) { return std::pow(x, 5); }
static double easeOutQuint( double x ) {
return 1 - std::pow( 1 - x, 5 );
}
static double easeOutQuint(double x) { return 1 - std::pow(1 - x, 5); }
static double easeInOutQuint(double x) {
if(x < 0.5) {
@ -88,13 +64,9 @@ static double easeInOutQuint( double x ) {
}
}
static double easeInExpo( double x ) {
return x == 0 ? 0 : std::pow( 2, 10 * x - 10 );
}
static double easeInExpo(double x) { return x == 0 ? 0 : std::pow(2, 10 * x - 10); }
static double easeOutExpo( double x ) {
return x == 1 ? 1 : 1 - std::pow( 2, -10 * x );
}
static double easeOutExpo(double x) { return x == 1 ? 1 : 1 - std::pow(2, -10 * x); }
static double easeInOutExpo(double x) {
if(x == 0) {
@ -108,13 +80,9 @@ static double easeInOutExpo( double x ) {
}
}
static double easeInCirc( double x ) {
return 1 - std::sqrt( 1 - std::pow( x, 2 ) );
}
static double easeInCirc(double x) { return 1 - std::sqrt(1 - std::pow(x, 2)); }
static double easeOutCirc( double x ) {
return std::sqrt( 1 - std::pow( x - 1, 2 ) );
}
static double easeOutCirc(double x) { return std::sqrt(1 - std::pow(x - 1, 2)); }
static double easeInOutCirc(double x) {
if(x < 0.5) {
@ -198,14 +166,10 @@ static double easeOutBounce( double x ) {
}
}
static double easeInBounce( double x ) {
return 1 - easeOutBounce(1 - x);
}
static double easeInBounce(double x) { return 1 - easeOutBounce(1 - x); }
static double easeInOutBounce(double x) {
return x < 0.5
? (1 - easeOutBounce(1 - 2 * x)) / 2
: (1 + easeOutBounce(2 * x - 1)) / 2;
return x < 0.5 ? (1 - easeOutBounce(1 - 2 * x)) / 2 : (1 + easeOutBounce(2 * x - 1)) / 2;
}
void add_module_easing(VM* vm) {

View File

@ -57,9 +57,7 @@ unsigned char* _default_import_handler(const char* name, int* out_size){
void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind_func(type, __new__, 3, [](VM* vm, ArgsView args) {
Type cls = PK_OBJ_GET(Type, args[0]);
return vm->new_object<FileIO>(cls, vm,
py_cast<Str&>(vm, args[1]),
py_cast<Str&>(vm, args[2]));
return vm->new_object<FileIO>(cls, vm, py_cast<Str&>(vm, args[1]), py_cast<Str&>(vm, args[2]));
});
vm->bind(type, "read(self, size=-1)", [](VM* vm, ArgsView args) {
@ -79,9 +77,7 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type){
assert(actual_size <= buffer_size);
// in text mode, CR may be dropped, which may cause `actual_size < buffer_size`
Bytes b(buffer, actual_size);
if(io.is_text){
return VAR(std::string_view((char*)b.data(), b.size()));
}
if(io.is_text) { return VAR(std::string_view((char*)b.data(), b.size())); }
return VAR(std::move(b));
});
@ -174,11 +170,10 @@ void add_module_os(VM* vm){
std::filesystem::directory_iterator di;
try {
di = std::filesystem::directory_iterator(path);
}catch(std::filesystem::filesystem_error&){
vm->IOError(path.string());
}
} catch(std::filesystem::filesystem_error&) { vm->IOError(path.string()); }
List ret;
for(auto& p: di) ret.push_back(VAR(p.path().filename().string()));
for(auto& p: di)
ret.push_back(VAR(p.path().filename().string()));
return VAR(std::move(ret));
});
@ -242,10 +237,10 @@ void add_module_os(VM* vm){
#else
void add_module_io(VM* vm) {}
void add_module_os(VM* vm) {}
unsigned char* _default_import_handler(const char* name, int* out_size){
return nullptr;
}
unsigned char* _default_import_handler(const char* name, int* out_size) { return nullptr; }
#endif

View File

@ -69,13 +69,14 @@ namespace pkpy{
vm->bind_func(type, "__getnewargs__", 1, [](VM* vm, ArgsView args) { \
Vec##D self = _CAST(Vec##D, args[0]); \
Tuple t(D); \
for(int i=0; i<D; i++) t[i] = VAR(self[i]); \
for(int i = 0; i < D; i++) \
t[i] = VAR(self[i]); \
return VAR(std::move(t)); \
});
// https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Math/Vector2.cs#L289
static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float smoothTime, float maxSpeed, float deltaTime)
{
static Vec2
SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float smoothTime, float maxSpeed, float deltaTime) {
// Based on Game Programming Gems 4 Chapter 1.10
smoothTime = (std::max)(0.0001F, smoothTime);
float omega = 2.0F / smoothTime;
@ -92,8 +93,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
float maxChangeSq = maxChange * maxChange;
float sqDist = change_x * change_x + change_y * change_y;
if (sqDist > maxChangeSq)
{
if(sqDist > maxChangeSq) {
float mag = std::sqrt(sqDist);
change_x = change_x / mag * maxChange;
change_y = change_y / mag * maxChange;
@ -117,8 +117,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
float outMinusOrig_x = output_x - originalTo.x;
float outMinusOrig_y = output_y - originalTo.y;
if (origMinusCurrent_x * outMinusOrig_x + origMinusCurrent_y * outMinusOrig_y > 0)
{
if(origMinusCurrent_x * outMinusOrig_x + origMinusCurrent_y * outMinusOrig_y > 0) {
output_x = originalTo.x;
output_y = originalTo.y;
@ -139,7 +138,10 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
});
// @staticmethod
vm->bind(type, "smooth_damp(current: vec2, target: vec2, current_velocity_: vec2, smooth_time: float, max_speed: float, delta_time: float) -> vec2", [](VM* vm, ArgsView args){
vm->bind(
type,
"smooth_damp(current: vec2, target: vec2, current_velocity_: vec2, smooth_time: float, max_speed: float, delta_time: float) -> vec2",
[](VM* vm, ArgsView args) {
Vec2 current = CAST(Vec2, args[0]);
Vec2 target = CAST(Vec2, args[1]);
Vec2 current_velocity_ = CAST(Vec2, args[2]);
@ -148,10 +150,15 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
float delta_time = CAST_F(args[5]);
Vec2 ret = SmoothDamp(current, target, current_velocity_, smooth_time, max_speed, delta_time);
return VAR(Tuple(VAR(ret), VAR(current_velocity_)));
}, {}, BindType::STATICMETHOD);
},
{},
BindType::STATICMETHOD);
// @staticmethod
vm->bind(type, "angle(__from: vec2, __to: vec2) -> float", [](VM* vm, ArgsView args){
vm->bind(
type,
"angle(__from: vec2, __to: vec2) -> float",
[](VM* vm, ArgsView args) {
Vec2 __from = CAST(Vec2, args[0]);
Vec2 __to = CAST(Vec2, args[1]);
float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x);
@ -159,7 +166,9 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
if(val > PI) val -= 2 * PI;
if(val < -PI) val += 2 * PI;
return VAR(val);
}, {}, BindType::STATICMETHOD);
},
{},
BindType::STATICMETHOD);
vm->bind__repr__(type->as<Type>(), [](VM* vm, PyVar obj) -> Str {
Vec2 self = _CAST(Vec2, obj);
@ -280,12 +289,14 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
const List& list = CAST(List&, args[1]);
if(list.size() != 9) vm->TypeError("Mat3x3.__new__ takes a list of 9 floats");
Mat3x3 mat;
for(int i=0; i<9; i++) mat.v[i] = CAST_F(list[i]);
for(int i = 0; i < 9; i++)
mat.v[i] = CAST_F(list[i]);
return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
}
if(args.size() == 1 + 9) {
Mat3x3 mat;
for(int i=0; i<9; i++) mat.v[i] = CAST_F(args[1+i]);
for(int i = 0; i < 9; i++)
mat.v[i] = CAST_F(args[1 + i]);
return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
}
vm->TypeError(_S("Mat3x3.__new__ takes 0 or 1 or 9 arguments, got ", args.size() - 1));
@ -312,28 +323,20 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index) {
Mat3x3& self = _CAST(Mat3x3&, obj);
Tuple& t = CAST(Tuple&, index);
if(t.size() != 2){
vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers");
}
if(t.size() != 2) { vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers"); }
i64 i = CAST(i64, t[0]);
i64 j = CAST(i64, t[1]);
if(i < 0 || i >= 3 || j < 0 || j >= 3){
vm->IndexError("index out of range");
}
if(i < 0 || i >= 3 || j < 0 || j >= 3) { vm->IndexError("index out of range"); }
return VAR(self.m[i][j]);
});
vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index, PyVar value) {
Mat3x3& self = _CAST(Mat3x3&, obj);
const Tuple& t = CAST(Tuple&, index);
if(t.size() != 2){
vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers");
}
if(t.size() != 2) { vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers"); }
i64 i = CAST(i64, t[0]);
i64 j = CAST(i64, t[1]);
if(i < 0 || i >= 3 || j < 0 || j >= 3){
vm->IndexError("index out of range");
}
if(i < 0 || i >= 3 || j < 0 || j >= 3) { vm->IndexError("index out of range"); }
self.m[i][j] = CAST_F(value);
});
@ -441,28 +444,51 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
});
// @staticmethod
vm->bind_func(type, "zeros", 0, [](VM* vm, ArgsView args){
vm->bind_func(
type,
"zeros",
0,
[](VM* vm, ArgsView args) {
return vm->new_user_object<Mat3x3>(Mat3x3::zeros());
}, {}, BindType::STATICMETHOD);
},
{},
BindType::STATICMETHOD);
// @staticmethod
vm->bind_func(type, "ones", 0, [](VM* vm, ArgsView args){
vm->bind_func(
type,
"ones",
0,
[](VM* vm, ArgsView args) {
return vm->new_user_object<Mat3x3>(Mat3x3::ones());
}, {}, BindType::STATICMETHOD);
},
{},
BindType::STATICMETHOD);
// @staticmethod
vm->bind_func(type, "identity", 0, [](VM* vm, ArgsView args){
vm->bind_func(
type,
"identity",
0,
[](VM* vm, ArgsView args) {
return vm->new_user_object<Mat3x3>(Mat3x3::identity());
}, {}, BindType::STATICMETHOD);
},
{},
BindType::STATICMETHOD);
/*************** affine transformations ***************/
// @staticmethod
vm->bind(type, "trs(t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args){
vm->bind(
type,
"trs(t: vec2, r: float, s: vec2)",
[](VM* vm, ArgsView args) {
Vec2 t = CAST(Vec2, args[0]);
f64 r = CAST_F(args[1]);
Vec2 s = CAST(Vec2, args[2]);
return vm->new_user_object<Mat3x3>(Mat3x3::trs(t, r, s));
}, {}, BindType::STATICMETHOD);
},
{},
BindType::STATICMETHOD);
vm->bind(type, "copy_trs_(self, t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args) {
Mat3x3& self = _CAST(Mat3x3&, args[0]);
@ -547,7 +573,6 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s
});
}
void add_module_linalg(VM* vm) {
PyObject* linalg = vm->new_module("linalg");
@ -561,49 +586,43 @@ void add_module_linalg(VM* vm){
linalg->attr().set("mat3x3_p", float_p);
}
/////////////// 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(){
return Mat3x3(0, 0, 0, 0, 0, 0, 0, 0, 0);
}
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::ones(){
return Mat3x3(1, 1, 1, 1, 1, 1, 1, 1, 1);
}
Mat3x3 Mat3x3::zeros() { return Mat3x3(0, 0, 0, 0, 0, 0, 0, 0, 0); }
Mat3x3 Mat3x3::identity(){
return Mat3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
}
Mat3x3 Mat3x3::ones() { return Mat3x3(1, 1, 1, 1, 1, 1, 1, 1, 1); }
Mat3x3 Mat3x3::identity() { return Mat3x3(1, 0, 0, 0, 1, 0, 0, 0, 1); }
Mat3x3 Mat3x3::operator+ (const Mat3x3& other) const {
Mat3x3 ret;
for (int i=0; i<9; ++i) ret.v[i] = v[i] + other.v[i];
for(int i = 0; i < 9; ++i)
ret.v[i] = v[i] + other.v[i];
return ret;
}
Mat3x3 Mat3x3::operator- (const Mat3x3& other) const {
Mat3x3 ret;
for (int i=0; i<9; ++i) ret.v[i] = v[i] - other.v[i];
for(int i = 0; i < 9; ++i)
ret.v[i] = v[i] - other.v[i];
return ret;
}
Mat3x3 Mat3x3::operator* (float scalar) const {
Mat3x3 ret;
for (int i=0; i<9; ++i) ret.v[i] = v[i] * scalar;
for(int i = 0; i < 9; ++i)
ret.v[i] = v[i] * scalar;
return ret;
}
Mat3x3 Mat3x3::operator/ (float scalar) const {
Mat3x3 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;
}
@ -644,15 +663,20 @@ void add_module_linalg(VM* vm){
}
float Mat3x3::determinant() const {
return _11 * _22 * _33 + _12 * _23 * _31 + _13 * _21 * _32
- _11 * _23 * _32 - _12 * _21 * _33 - _13 * _22 * _31;
return _11 * _22 * _33 + _12 * _23 * _31 + _13 * _21 * _32 - _11 * _23 * _32 - _12 * _21 * _33 - _13 * _22 * _31;
}
Mat3x3 Mat3x3::transpose() const {
Mat3x3 ret;
ret._11 = _11; ret._12 = _21; ret._13 = _31;
ret._21 = _12; ret._22 = _22; ret._23 = _32;
ret._31 = _13; ret._32 = _23; ret._33 = _33;
ret._11 = _11;
ret._12 = _21;
ret._13 = _31;
ret._21 = _12;
ret._22 = _22;
ret._23 = _32;
ret._31 = _13;
ret._32 = _23;
ret._33 = _33;
return ret;
}
@ -675,9 +699,7 @@ void add_module_linalg(VM* vm){
Mat3x3 Mat3x3::trs(Vec2 t, float radian, Vec2 s) {
float cr = cosf(radian);
float sr = sinf(radian);
return Mat3x3(s.x * cr, -s.y * sr, t.x,
s.x * sr, s.y * cr, t.y,
0.0f, 0.0f, 1.0f);
return Mat3x3(s.x * cr, -s.y * sr, t.x, s.x * sr, s.y * cr, t.y, 0.0f, 0.0f, 1.0f);
}
bool Mat3x3::is_affine() const {
@ -687,12 +709,9 @@ void add_module_linalg(VM* vm){
}
Vec2 Mat3x3::_t() const { return Vec2(_13, _23); }
float Mat3x3::_r() const { return atan2f(_21, _11); }
Vec2 Mat3x3::_s() const {
return Vec2(
sqrtf(_11 * _11 + _21 * _21),
sqrtf(_12 * _12 + _22 * _22)
);
}
Vec2 Mat3x3::_s() const { return Vec2(sqrtf(_11 * _11 + _21 * _21), sqrtf(_12 * _12 + _22 * _22)); }
} // namespace pkpy

View File

@ -199,7 +199,8 @@ void add_module_math(VM* vm){
i64 n = CAST(i64, args[0]);
if(n < 0) vm->ValueError("factorial() not defined for negative values");
i64 r = 1;
for(i64 i=2; i<=n; i++) r *= i;
for(i64 i = 2; i <= n; i++)
r *= i;
return VAR(r);
});
}
@ -248,8 +249,7 @@ void add_module_enum(VM* vm){
CodeObject_ code = vm->compile(kPythonLibs__enum, "enum.py", EXEC_MODE);
vm->_exec(code, mod);
PyVar Enum = mod->attr("Enum");
vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = \
[](VM* vm, PyTypeInfo* new_ti){
vm->_all_types[PK_OBJ_GET(Type, Enum)].on_end_subclass = [](VM* vm, PyTypeInfo* new_ti) {
new_ti->subclass_enabled = false; // Enum class cannot be subclassed twice
NameDict& attr = new_ti->obj->attr();
for(auto [k, v]: attr.items()) {
@ -277,10 +277,10 @@ void add_module___builtins(VM* vm){
});
}
/************************************************/
#if PK_ENABLE_PROFILER
struct LineProfilerW;
struct _LpGuard {
PK_ALWAYS_PASS_BY_POINTER(_LpGuard)
LineProfilerW* lp;
@ -313,7 +313,8 @@ struct LineProfilerW{
const Tuple& args = CAST(Tuple&, view[2]);
vm->s_data.push(func);
vm->s_data.push(PY_NULL);
for(PyVar arg : args) vm->s_data.push(arg);
for(PyVar arg: args)
vm->s_data.push(arg);
_LpGuard guard(&self, vm);
PyVar ret = vm->vectorcall(args.size());
return ret;
@ -327,11 +328,8 @@ struct LineProfilerW{
}
};
_LpGuard::_LpGuard(LineProfilerW* lp, VM* vm) : lp(lp), vm(vm) {
if(vm->_profiler){
vm->ValueError("only one profiler can be enabled at a time");
}
if(vm->_profiler) { vm->ValueError("only one profiler can be enabled at a time"); }
vm->_profiler = &lp->profiler;
lp->profiler.begin();
}
@ -346,9 +344,7 @@ void add_module_line_profiler(VM *vm){
vm->register_user_class<LineProfilerW>(mod, "LineProfiler");
}
#else
void add_module_line_profiler(VM* vm){
(void)vm;
}
void add_module_line_profiler(VM* vm) { (void)vm; }
#endif
} // namespace pkpy

View File

@ -37,8 +37,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
struct mt19937 {
static const int N = 624;
static const int M = 397;
const static int N = 624;
const static int M = 397;
const uint32_t MATRIX_A = 0x9908b0dfUL; /* constant vector a */
const uint32_t UPPER_MASK = 0x80000000UL; /* most significant w-r bits */
const uint32_t LOWER_MASK = 0x7fffffffUL; /* least significant r bits */
@ -47,12 +47,10 @@ struct mt19937{
int mti = N + 1; /* mti==N+1 means mt[N] is not initialized */
/* initializes mt[N] with a seed */
void seed(uint32_t s)
{
void seed(uint32_t s) {
mt[0] = s & 0xffffffffUL;
for(mti = 1; mti < N; mti++) {
mt[mti] =
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */
/* only MSBs of the array mt[]. */
@ -63,8 +61,7 @@ struct mt19937{
}
/* generates a random number on [0,0xffffffff]-interval */
uint32_t next_uint32(void)
{
uint32_t next_uint32(void) {
uint32_t y;
static uint32_t mag01[2] = {0x0UL, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */
@ -100,15 +97,10 @@ struct mt19937{
return y;
}
uint64_t next_uint64(void){
return (uint64_t(next_uint32()) << 32) | next_uint32();
}
uint64_t next_uint64(void) { return (uint64_t(next_uint32()) << 32) | next_uint32(); }
/* generates a random number on [0,1)-real-interval */
float random(void)
{
return next_uint32()*(1.0/4294967296.0); /* divided by 2^32 */
}
float random(void) { return next_uint32() * (1.0 / 4294967296.0); /* divided by 2^32 */ }
/* generates a random number on [a, b]-interval */
int64_t randint(int64_t a, int64_t b) {
@ -120,12 +112,9 @@ struct mt19937{
}
}
float uniform(float a, float b){
return a + random() * (b - a);
}
float uniform(float a, float b) { return a + random() * (b - a); }
};
namespace pkpy {
struct Random {
@ -195,7 +184,8 @@ struct Random{
if(size == 0) vm->IndexError("cannot choose from an empty sequence");
array<f64> cum_weights(size);
if(args[2] == vm->None) {
for(int i = 0; i < size; i++) cum_weights[i] = i + 1;
for(int i = 0; i < size; i++)
cum_weights[i] = i + 1;
} else {
ArgsView weights = vm->cast_array_view(args[2]);
if(weights.size() != size) vm->ValueError(_S("len(weights) != ", size));

View File

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

View File

@ -2,9 +2,9 @@
namespace pkpy {
Dict::Dict(): _capacity(__Capacity),
_mask(__Capacity-1),
_size(0), _critical_size(__Capacity*__LoadFactor+0.5f), _head_idx(-1), _tail_idx(-1){
Dict::Dict() :
_capacity(__Capacity), _mask(__Capacity - 1), _size(0), _critical_size(__Capacity * __LoadFactor + 0.5f),
_head_idx(-1), _tail_idx(-1) {
__alloc_items();
}
@ -44,7 +44,8 @@ namespace pkpy{
void Dict::set(VM* vm, PyVar key, PyVar val) {
// do possible rehash
if(_size + 1 > _critical_size) _rehash(vm);
bool ok; int i;
bool ok;
int i;
_probe_1(vm, key, ok, i);
if(!ok) {
_size++;
@ -86,26 +87,29 @@ namespace pkpy{
std::free(old_items);
}
PyVar Dict::try_get(VM* vm, PyVar key) const {
bool ok; int i;
bool ok;
int i;
_probe_0(vm, key, ok, i);
if(!ok) return nullptr;
return _items[i].second;
}
bool Dict::contains(VM* vm, PyVar key) const {
bool ok; int i;
bool ok;
int i;
_probe_0(vm, key, ok, i);
return ok;
}
bool Dict::del(VM* vm, PyVar key) {
bool ok; int i;
bool ok;
int i;
_probe_0(vm, key, ok, i);
if(!ok) return false;
_items[i].first = nullptr;
// _items[i].second = PY_DELETED_SLOT; // do not change .second if it is not NULL, it means the slot is occupied by a deleted item
// _items[i].second = PY_DELETED_SLOT; // do not change .second if it is not NULL, it means the slot is occupied by
// a deleted item
_size--;
if(_size == 0) {
@ -129,7 +133,9 @@ namespace pkpy{
}
void Dict::update(VM* vm, const Dict& other) {
other.apply([&](PyVar k, PyVar v){ set(vm, k, v); });
other.apply([&](PyVar k, PyVar v) {
set(vm, k, v);
});
}
Tuple Dict::keys() const {

View File

@ -12,8 +12,10 @@ namespace pkpy{
for(int i = container.size() - 1; i >= 0; i--) {
ss << container[i].snapshot() << '\n';
}
if (!msg.empty()) ss << type.sv() << ": " << msg;
else ss << type.sv();
if(!msg.empty())
ss << type.sv() << ": " << msg;
else
ss << type.sv();
return ss.str();
}

View File

@ -1,7 +1,8 @@
#include "pocketpy/objects/sourcedata.hpp"
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;
// Skip utf8 BOM if there is any.
if(strncmp(source.data(), "\xEF\xBB\xBF", 3) == 0) index += 3;
@ -31,7 +32,8 @@ namespace pkpy{
const char* _start = line_starts[lineno];
const char* i = _start;
// max 300 chars
while(*i != '\n' && *i != '\0' && i-_start < 300) i++;
while(*i != '\n' && *i != '\0' && i - _start < 300)
i++;
return {_start, i};
}

View File

@ -15,7 +15,8 @@ Tuple::Tuple(Tuple&& other) noexcept {
_size = other._size;
if(other.is_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 {
_args = other._args;
other._args = other._inlined;
@ -34,17 +35,21 @@ Tuple::Tuple(PyVar _0, PyVar _1, PyVar _2): Tuple(3){
_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 ret(size());
for(int i=0; i<size(); i++) ret[i] = _begin[i];
for(int i = 0; i < size(); i++)
ret[i] = _begin[i];
return ret;
}
Tuple ArgsView::to_tuple() const {
Tuple 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;
}

View File

@ -313,7 +313,10 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(_vm->builtins, "bin", 1, [](VM* vm, ArgsView args) {
SStream ss;
i64 x = CAST(i64, args[0]);
if(x < 0){ ss << "-"; x = -x; }
if(x < 0) {
ss << "-";
x = -x;
}
ss << "0b";
std::string bits;
while(x) {
@ -374,8 +377,15 @@ void __init_builtins(VM* _vm) {
Range r;
switch(args.size()) {
case 1: r.stop = CAST(i64, args[0]); break;
case 2: r.start = CAST(i64, args[0]); r.stop = CAST(i64, args[1]); break;
case 3: r.start = CAST(i64, args[0]); r.stop = CAST(i64, args[1]); r.step = CAST(i64, args[2]); break;
case 2:
r.start = CAST(i64, args[0]);
r.stop = CAST(i64, args[1]);
break;
case 3:
r.start = CAST(i64, args[0]);
r.stop = CAST(i64, args[1]);
r.step = CAST(i64, args[2]);
break;
default: vm->TypeError("expected 1-3 arguments, got " + std::to_string(args.size()));
}
if(r.step == 0) vm->ValueError("range() arg 3 must not be zero");
@ -442,16 +452,11 @@ void __init_builtins(VM* _vm) {
// 1 arg
if(args.size() == 1 + 1) {
switch(vm->_tp(args[1])) {
case VM::tp_float:
return VAR((i64)_CAST(f64, args[1]));
case VM::tp_int:
return args[1];
case VM::tp_bool:
return VAR(args[1]==vm->True ? 1 : 0);
case VM::tp_str:
break;
default:
vm->TypeError("invalid arguments for int()");
case VM::tp_float: return VAR((i64)_CAST(f64, args[1]));
case VM::tp_int: return args[1];
case VM::tp_bool: return VAR(args[1] == vm->True ? 1 : 0);
case VM::tp_str: break;
default: vm->TypeError("invalid arguments for int()");
}
}
// 2+ args -> error
@ -490,16 +495,25 @@ void __init_builtins(VM* _vm) {
i64 x = _CAST(i64, args[0]);
if(x < 0) x = -x;
int bits = 0;
while(x){ x >>= 1; bits++; }
while(x) {
x >>= 1;
bits++;
}
return VAR(bits);
});
_vm->bind__repr__(VM::tp_int, [](VM* vm, PyVar obj) -> Str {
return std::to_string(_CAST(i64, obj));
});
_vm->bind__neg__(VM::tp_int, [](VM* vm, PyVar obj) { return VAR(-_CAST(i64, obj)); });
_vm->bind__hash__(VM::tp_int, [](VM* vm, PyVar obj) { return _CAST(i64, obj); });
_vm->bind__invert__(VM::tp_int, [](VM* vm, PyVar obj) { return VAR(~_CAST(i64, obj)); });
_vm->bind__neg__(VM::tp_int, [](VM* vm, PyVar obj) {
return VAR(-_CAST(i64, obj));
});
_vm->bind__hash__(VM::tp_int, [](VM* vm, PyVar obj) {
return _CAST(i64, obj);
});
_vm->bind__invert__(VM::tp_int, [](VM* vm, PyVar obj) {
return VAR(~_CAST(i64, obj));
});
#define INT_BITWISE_OP(name, op) \
_vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { \
@ -519,16 +533,11 @@ void __init_builtins(VM* _vm) {
if(args.size() > 1 + 1) vm->TypeError("float() takes at most 1 argument");
// 1 arg
switch(vm->_tp(args[1])) {
case VM::tp_int:
return VAR((f64)CAST(i64, args[1]));
case VM::tp_float:
return args[1];
case VM::tp_bool:
return VAR(args[1]==vm->True ? 1.0 : 0.0);
case VM::tp_str:
break;
default:
vm->TypeError("invalid arguments for float()");
case VM::tp_int: return VAR((f64)CAST(i64, args[1]));
case VM::tp_float: return args[1];
case VM::tp_bool: return VAR(args[1] == vm->True ? 1.0 : 0.0);
case VM::tp_str: break;
default: vm->TypeError("invalid arguments for float()");
}
// str to float
const Str& s = PK_OBJ_GET(Str, args[1]);
@ -540,9 +549,7 @@ void __init_builtins(VM* _vm) {
try {
float_out = std::strtod(s.data, &p_end);
if(p_end != s.end()) throw 1;
}catch(...){
vm->ValueError("invalid literal for float(): " + s.escape());
}
} catch(...) { vm->ValueError("invalid literal for float(): " + s.escape()); }
return VAR(float_out);
});
@ -551,7 +558,9 @@ void __init_builtins(VM* _vm) {
return (i64)std::hash<f64>()(val);
});
_vm->bind__neg__(VM::tp_float, [](VM* vm, PyVar _0) { return VAR(-_CAST(f64, _0)); });
_vm->bind__neg__(VM::tp_float, [](VM* vm, PyVar _0) {
return VAR(-_CAST(f64, _0));
});
_vm->bind__repr__(VM::tp_float, [](VM* vm, PyVar _0) -> Str {
f64 val = _CAST(f64, _0);
@ -581,14 +590,16 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, _0);
i64 n = CAST(i64, _1);
SStream ss;
for(i64 i = 0; i < n; i++) ss << self.sv();
for(i64 i = 0; i < n; i++)
ss << self.sv();
return VAR(ss.str());
});
_vm->bind_func(VM::tp_str, "__rmul__", 2, [](VM* vm, ArgsView args) {
const Str& self = _CAST(Str&, args[0]);
i64 n = CAST(i64, args[1]);
SStream ss;
for(i64 i = 0; i < n; i++) ss << self.sv();
for(i64 i = 0; i < n; i++)
ss << self.sv();
return VAR(ss.str());
});
_vm->bind__contains__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) {
@ -596,8 +607,12 @@ void __init_builtins(VM* _vm) {
return VAR(self.index(CAST(Str&, _1)) != -1);
});
_vm->bind_func(VM::tp_str, __str__, 1, [](VM* vm, ArgsView args) { return args[0]; });
_vm->bind__iter__(VM::tp_str, [](VM* vm, PyVar _0) { return vm->new_user_object<StringIter>(_0); });
_vm->bind_func(VM::tp_str, __str__, 1, [](VM* vm, ArgsView args) {
return args[0];
});
_vm->bind__iter__(VM::tp_str, [](VM* vm, PyVar _0) {
return vm->new_user_object<StringIter>(_0);
});
_vm->bind__repr__(VM::tp_str, [](VM* vm, PyVar _0) -> Str {
const Str& self = _CAST(Str&, _0);
return self.escape();
@ -649,7 +664,8 @@ void __init_builtins(VM* _vm) {
parts = self.split(sep);
}
List ret(parts.size());
for(int i=0; i<parts.size(); i++) ret[i] = VAR(Str(parts[i]));
for(int i = 0; i < parts.size(); i++)
ret[i] = VAR(Str(parts[i]));
return VAR(std::move(ret));
});
@ -657,7 +673,8 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]);
vector<std::string_view> parts = self.split('\n');
List ret(parts.size());
for(int i=0; i<parts.size(); i++) ret[i] = VAR(Str(parts[i]));
for(int i = 0; i < parts.size(); i++)
ret[i] = VAR(Str(parts[i]));
return VAR(std::move(ret));
});
@ -769,7 +786,8 @@ void __init_builtins(VM* _vm) {
int delta = width - self.u8_length();
if(delta <= 0) return args[0];
SStream ss;
for(int i=0; i<delta; i++) ss << '0';
for(int i = 0; i < delta; i++)
ss << '0';
ss << self;
return VAR(ss.str());
});
@ -784,7 +802,8 @@ void __init_builtins(VM* _vm) {
if(fillchar.u8_length() != 1) vm->TypeError("The fill character must be exactly one character long");
SStream ss;
ss << self;
for(int i=0; i<delta; i++) ss << fillchar;
for(int i = 0; i < delta; i++)
ss << fillchar;
return VAR(ss.str());
});
@ -797,7 +816,8 @@ void __init_builtins(VM* _vm) {
const Str& fillchar = CAST(Str&, args[2]);
if(fillchar.u8_length() != 1) vm->TypeError("The fill character must be exactly one character long");
SStream ss;
for(int i=0; i<delta; i++) ss << fillchar;
for(int i = 0; i < delta; i++)
ss << fillchar;
ss << self;
return VAR(ss.str());
});
@ -816,9 +836,7 @@ void __init_builtins(VM* _vm) {
});
}
bool reverse = CAST(bool, args[2]);
if(reverse){
std::reverse(self.begin(), self.end());
}
if(reverse) { std::reverse(self.begin(), self.end()); }
return vm->None;
});
@ -863,14 +881,16 @@ void __init_builtins(VM* _vm) {
_vm->bind__contains__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
List& self = _CAST(List&, _0);
for(PyVar i: self) if(vm->py_eq(i, _1)) return vm->True;
for(PyVar i: self)
if(vm->py_eq(i, _1)) return vm->True;
return vm->False;
});
_vm->bind_func(VM::tp_list, "count", 2, [](VM* vm, ArgsView args) {
List& self = _CAST(List&, args[0]);
int count = 0;
for(PyVar i: self) if(vm->py_eq(i, args[1])) count++;
for(PyVar i: self)
if(vm->py_eq(i, args[1])) count++;
return VAR(count);
});
@ -959,7 +979,8 @@ void __init_builtins(VM* _vm) {
int n = _CAST(int, _1);
List result;
result.reserve(self.size() * n);
for(int i = 0; i < n; i++) result.extend(self.begin(), self.end());
for(int i = 0; i < n; i++)
result.extend(self.begin(), self.end());
return VAR(std::move(result));
});
_vm->bind_func(VM::tp_list, "__rmul__", 2, [](VM* vm, ArgsView args) {
@ -968,7 +989,8 @@ void __init_builtins(VM* _vm) {
int n = _CAST(int, args[1]);
List result;
result.reserve(self.size() * n);
for(int i = 0; i < n; i++) result.extend(self.begin(), self.end());
for(int i = 0; i < n; i++)
result.extend(self.begin(), self.end());
return VAR(std::move(result));
});
@ -1062,14 +1084,16 @@ void __init_builtins(VM* _vm) {
_vm->bind__contains__(VM::tp_tuple, [](VM* vm, PyVar obj, PyVar item) {
Tuple& self = _CAST(Tuple&, obj);
for(PyVar i: self) if(vm->py_eq(i, item)) return vm->True;
for(PyVar i: self)
if(vm->py_eq(i, item)) return vm->True;
return vm->False;
});
_vm->bind_func(VM::tp_tuple, "count", 2, [](VM* vm, ArgsView args) {
Tuple& self = _CAST(Tuple&, args[0]);
int count = 0;
for(PyVar i: self) if(vm->py_eq(i, args[1])) count++;
for(PyVar i: self)
if(vm->py_eq(i, args[1])) count++;
return VAR(count);
});
@ -1243,14 +1267,16 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(VM::tp_mappingproxy, "keys", 1, [](VM* vm, ArgsView args) {
MappingProxy& self = _CAST(MappingProxy&, args[0]);
List keys;
for(StrName name : self.attr().keys()) keys.push_back(VAR(name.sv()));
for(StrName name: self.attr().keys())
keys.push_back(VAR(name.sv()));
return VAR(std::move(keys));
});
_vm->bind_func(VM::tp_mappingproxy, "values", 1, [](VM* vm, ArgsView args) {
MappingProxy& self = _CAST(MappingProxy&, args[0]);
List values;
for(auto [k, v] : self.attr().items()) values.push_back(v);
for(auto [k, v]: self.attr().items())
values.push_back(v);
return VAR(std::move(values));
});
@ -1358,9 +1384,7 @@ void __init_builtins(VM* _vm) {
// try __missing__
PyVar self;
PyVar f_missing = vm->get_unbound_method(_0, __missing__, &self, false);
if(f_missing != nullptr){
return vm->call_method(self, f_missing, _1);
}
if(f_missing != nullptr) { return vm->call_method(self, f_missing, _1); }
vm->KeyError(_1);
}
return ret;
@ -1386,9 +1410,7 @@ void __init_builtins(VM* _vm) {
PyVar value = self.try_get(vm, args[1]);
if(value == nullptr) {
if(args.size() == 2) vm->KeyError(args[1]);
if(args.size() == 3){
return args[2];
}
if(args.size() == 3) { return args[2]; }
}
self.del(vm, args[1]);
return value;

View File

@ -16,13 +16,10 @@ using namespace pkpy;
}
#define PK_ASSERT_NO_ERROR() \
if(vm->__c.error != nullptr) \
return false;
if(vm->__c.error != nullptr) return false;
static int count_extra_elements(VM* vm, int n) {
if(vm->callstack.empty()){
return vm->s_data.size();
}
if(vm->callstack.empty()) { return vm->s_data.size(); }
assert(!vm->__c.s_view.empty());
return vm->s_data._sp - vm->__c.s_view.top().end();
}
@ -43,8 +40,9 @@ static PyVar stack_item(VM* vm, int index){
}
#define PK_PROTECTED(__B) \
try{ __B } \
catch(TopLevelException e) { \
try { \
__B \
} catch(TopLevelException e) { \
vm->__c.error = e.ptr->self(); \
return false; \
} catch(const std::exception& re) { \
@ -53,13 +51,9 @@ static PyVar stack_item(VM* vm, int index){
return false; \
}
pkpy_vm* pkpy_new_vm(bool enable_os){
return (pkpy_vm*)new VM(enable_os);
}
pkpy_vm* pkpy_new_vm(bool enable_os) { return (pkpy_vm*)new VM(enable_os); }
void pkpy_delete_vm(pkpy_vm* vm){
return delete (VM*)vm;
}
void pkpy_delete_vm(pkpy_vm* vm) { return delete (VM*)vm; }
bool pkpy_exec(pkpy_vm* vm_handle, const char* source) {
VM* vm = (VM*)vm_handle;
@ -78,8 +72,7 @@ bool pkpy_exec_2(pkpy_vm* vm_handle, const char* source, const char* filename, i
PyVar res;
PyObject* mod;
PK_PROTECTED(
if(module == nullptr){
mod = vm->_main;
if(module == nullptr){ mod = vm->_main;
}else{
mod = vm->_modules[module].get(); // may raise
}
@ -139,9 +132,7 @@ bool pkpy_rot_two(pkpy_vm* vm_handle){
int pkpy_stack_size(pkpy_vm* vm_handle) {
VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR()
if(vm->callstack.empty()){
return vm->s_data.size();
}
if(vm->callstack.empty()) { return vm->s_data.size(); }
if(vm->__c.s_view.empty()) exit(127);
return vm->s_data._sp - vm->__c.s_view.top().begin();
}
@ -508,7 +499,8 @@ bool pkpy_error(pkpy_vm* vm_handle, const char* name, pkpy_CString message) {
e_t = vm->builtins->attr().try_get_likely_found(name);
if(e_t == nullptr) {
e_t = vm->_t(vm->tp_exception);
std::cerr << "[warning] pkpy_error(): " << Str(name).escape() << " not found, fallback to 'Exception'" << std::endl;
std::cerr << "[warning] pkpy_error(): " << Str(name).escape() << " not found, fallback to 'Exception'"
<< std::endl;
}
}
vm->__c.error = vm->call(e_t, VAR(message)).get();
@ -550,18 +542,13 @@ bool pkpy_vectorcall(pkpy_vm* vm_handle, int argc) {
vm->s_data.push(res);
return true;
}
/*****************************************************************/
void pkpy_free(void* p){
std::free(p);
}
void pkpy_free(void* p) { std::free(p); }
pkpy_CName pkpy_name(const char* name){
return StrName(name).index;
}
pkpy_CName pkpy_name(const char* name) { return StrName(name).index; }
pkpy_CString pkpy_name_to_string(pkpy_CName name){
return StrName(name).c_str();
}
pkpy_CString pkpy_name_to_string(pkpy_CName name) { return StrName(name).c_str(); }
void pkpy_set_output_handler(pkpy_vm* vm_handle, pkpy_COutputHandler handler) {
VM* vm = (VM*)vm_handle;
@ -573,16 +560,10 @@ void pkpy_set_import_handler(pkpy_vm* vm_handle, pkpy_CImportHandler handler){
vm->_import_handler = handler;
}
void* pkpy_new_repl(pkpy_vm* vm_handle){
return new REPL((VM*)vm_handle);
}
void* pkpy_new_repl(pkpy_vm* vm_handle) { return new REPL((VM*)vm_handle); }
bool pkpy_repl_input(void* r, const char* line){
return ((REPL*)r)->input(line);
}
bool pkpy_repl_input(void* r, const char* line) { return ((REPL*)r)->input(line); }
void pkpy_delete_repl(void* repl){
delete (REPL*)repl;
}
void pkpy_delete_repl(void* repl) { delete (REPL*)repl; }
#endif // PK_NO_EXPORT_C_API

View File

@ -42,4 +42,4 @@ namespace pkpy {
return false;
}
}
} // namespace pkpy

View File

@ -24,13 +24,10 @@ std::string pkpy_platform_getline(bool* eof) {
wss << buf;
}
std::wstring wideInput = wss.str();
int length =
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(),
(int)wideInput.length(), NULL, 0, NULL, NULL);
int length = WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), NULL, 0, NULL, NULL);
std::string output;
output.resize(length);
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(),
&output[0], length, NULL, NULL);
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL);
if(!output.empty() && output.back() == '\r') output.pop_back();
return output;
}
@ -100,14 +97,12 @@ int main(int argc, char** argv) {
std::cerr << "Failed to open file: " << argv_1 << std::endl;
return 3;
}
std::string src((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
std::string src((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
pkpy_set_main_argv(vm, argc, argv);
bool ok = pkpy_exec_2(vm, src.c_str(),
filepath.filename().string().c_str(), 0, NULL);
bool ok = pkpy_exec_2(vm, src.c_str(), filepath.filename().string().c_str(), 0, NULL);
if(!ok) pkpy_clear_error(vm, NULL);
pkpy_delete_vm(vm);
return ok ? 0 : 1;