mirror of
https://github.com/pocketpy/pocketpy
synced 2025-11-08 20:50:16 +00:00
Disable insert.
This commit is contained in:
parent
8ba1a9d245
commit
cc664a54c7
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# clang-format configuration
|
# clang-format configuration
|
||||||
# compatible with clang-format 18
|
# compatible with clang-format 18
|
||||||
|
|
||||||
@ -20,7 +19,7 @@ LambdaBodyIndentation: Signature
|
|||||||
BitFieldColonSpacing: Both
|
BitFieldColonSpacing: Both
|
||||||
|
|
||||||
# Insert
|
# Insert
|
||||||
InsertBraces: true
|
InsertBraces: false
|
||||||
InsertNewlineAtEOF: true
|
InsertNewlineAtEOF: true
|
||||||
KeepEmptyLinesAtEOF: true
|
KeepEmptyLinesAtEOF: true
|
||||||
|
|
||||||
@ -55,7 +54,7 @@ AllowShortCompoundRequirementOnASingleLine: true
|
|||||||
AllowShortEnumsOnASingleLine: true
|
AllowShortEnumsOnASingleLine: true
|
||||||
AllowShortFunctionsOnASingleLine: All
|
AllowShortFunctionsOnASingleLine: All
|
||||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||||
AllowShortLambdasOnASingleLine: All
|
AllowShortLambdasOnASingleLine: None
|
||||||
AllowShortLoopsOnASingleLine: false
|
AllowShortLoopsOnASingleLine: false
|
||||||
AlwaysBreakAfterReturnType: None
|
AlwaysBreakAfterReturnType: None
|
||||||
AlwaysBreakBeforeMultilineStrings: true
|
AlwaysBreakBeforeMultilineStrings: true
|
||||||
@ -100,4 +99,4 @@ SortIncludes: Never
|
|||||||
SortUsingDeclarations: LexicographicNumeric
|
SortUsingDeclarations: LexicographicNumeric
|
||||||
IncludeBlocks: Merge
|
IncludeBlocks: Merge
|
||||||
|
|
||||||
WhitespaceSensitiveMacros: ["PK_PROTECTED"]
|
WhitespaceSensitiveMacros: ["PK_PROTECTED", "LUA_PROTECTED"]
|
||||||
|
|||||||
@ -25,7 +25,9 @@ struct any {
|
|||||||
static vtable vt{typeid(T), nullptr};
|
static vtable vt{typeid(T), nullptr};
|
||||||
return &vt;
|
return &vt;
|
||||||
} else {
|
} else {
|
||||||
static vtable vt{typeid(T), [](void* ptr) { delete static_cast<T*>(ptr); }};
|
static vtable vt{typeid(T), [](void* ptr) {
|
||||||
|
delete static_cast<T*>(ptr);
|
||||||
|
}};
|
||||||
return &vt;
|
return &vt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,7 +62,7 @@ struct any {
|
|||||||
any& operator= (const any& other) = delete;
|
any& operator= (const any& other) = delete;
|
||||||
|
|
||||||
~any() {
|
~any() {
|
||||||
if(_vt && _vt->deleter) { _vt->deleter(data); }
|
if(_vt && _vt->deleter) _vt->deleter(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -76,7 +78,7 @@ struct any {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
T& cast() const {
|
T& cast() const {
|
||||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||||
if(type_id() != typeid(T)) { __bad_any_cast(typeid(T), type_id()); }
|
if(type_id() != typeid(T)) __bad_any_cast(typeid(T), type_id());
|
||||||
return _cast<T>();
|
return _cast<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,11 +10,10 @@ namespace pkpy {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr T default_invalid_value() {
|
constexpr T default_invalid_value() {
|
||||||
if constexpr(std::is_same_v<int, T>) {
|
if constexpr(std::is_same_v<int, T>)
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -86,7 +85,7 @@ struct NameDictImpl {
|
|||||||
uint16_t old_capacity = _capacity;
|
uint16_t old_capacity = _capacity;
|
||||||
_set_capacity_and_alloc_items(_capacity * 2);
|
_set_capacity_and_alloc_items(_capacity * 2);
|
||||||
for(uint16_t i = 0; i < old_capacity; i++) {
|
for(uint16_t i = 0; i < old_capacity; i++) {
|
||||||
if(old_items[i].first.empty()) { continue; }
|
if(old_items[i].first.empty()) continue;
|
||||||
bool ok;
|
bool ok;
|
||||||
uint16_t j;
|
uint16_t j;
|
||||||
HASH_PROBE_1(old_items[i].first, ok, j);
|
HASH_PROBE_1(old_items[i].first, ok, j);
|
||||||
@ -100,7 +99,7 @@ struct NameDictImpl {
|
|||||||
bool ok;
|
bool ok;
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
HASH_PROBE_0(key, ok, i);
|
HASH_PROBE_0(key, ok, i);
|
||||||
if(!ok) { return default_invalid_value<T>(); }
|
if(!ok) return default_invalid_value<T>();
|
||||||
return _items[i].second;
|
return _items[i].second;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,23 +107,23 @@ struct NameDictImpl {
|
|||||||
bool ok;
|
bool ok;
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
HASH_PROBE_0(key, ok, i);
|
HASH_PROBE_0(key, ok, i);
|
||||||
if(!ok) { return nullptr; }
|
if(!ok) return nullptr;
|
||||||
return &_items[i].second;
|
return &_items[i].second;
|
||||||
}
|
}
|
||||||
|
|
||||||
T try_get_likely_found(StrName key) const {
|
T try_get_likely_found(StrName key) const {
|
||||||
uint16_t i = key.index & _mask;
|
uint16_t i = key.index & _mask;
|
||||||
if(_items[i].first == key) { return _items[i].second; }
|
if(_items[i].first == key) return _items[i].second;
|
||||||
i = (i + 1) & _mask;
|
i = (i + 1) & _mask;
|
||||||
if(_items[i].first == key) { return _items[i].second; }
|
if(_items[i].first == key) return _items[i].second;
|
||||||
return try_get(key);
|
return try_get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
T* try_get_2_likely_found(StrName key) const {
|
T* try_get_2_likely_found(StrName key) const {
|
||||||
uint16_t i = key.index & _mask;
|
uint16_t i = key.index & _mask;
|
||||||
if(_items[i].first == key) { return &_items[i].second; }
|
if(_items[i].first == key) return &_items[i].second;
|
||||||
i = (i + 1) & _mask;
|
i = (i + 1) & _mask;
|
||||||
if(_items[i].first == key) { return &_items[i].second; }
|
if(_items[i].first == key) return &_items[i].second;
|
||||||
return try_get_2(key);
|
return try_get_2(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +131,7 @@ struct NameDictImpl {
|
|||||||
bool ok;
|
bool ok;
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
HASH_PROBE_0(key, ok, i);
|
HASH_PROBE_0(key, ok, i);
|
||||||
if(!ok) { return false; }
|
if(!ok) return false;
|
||||||
_items[i].first = StrName();
|
_items[i].first = StrName();
|
||||||
_items[i].second = nullptr;
|
_items[i].second = nullptr;
|
||||||
_size--;
|
_size--;
|
||||||
@ -141,7 +140,7 @@ struct NameDictImpl {
|
|||||||
uint16_t z = (i + 1) & _mask;
|
uint16_t z = (i + 1) & _mask;
|
||||||
while(!_items[z].first.empty()) {
|
while(!_items[z].first.empty()) {
|
||||||
uint16_t h = _items[z].first.index & _mask;
|
uint16_t h = _items[z].first.index & _mask;
|
||||||
if(h != i) { break; }
|
if(h != i) break;
|
||||||
std::swap(_items[pre_z], _items[z]);
|
std::swap(_items[pre_z], _items[z]);
|
||||||
pre_z = z;
|
pre_z = z;
|
||||||
z = (z + 1) & _mask;
|
z = (z + 1) & _mask;
|
||||||
@ -152,7 +151,7 @@ struct NameDictImpl {
|
|||||||
template <typename __Func>
|
template <typename __Func>
|
||||||
void apply(__Func func) const {
|
void apply(__Func func) const {
|
||||||
for(uint16_t i = 0; i < _capacity; i++) {
|
for(uint16_t i = 0; i < _capacity; i++) {
|
||||||
if(_items[i].first.empty()) { continue; }
|
if(_items[i].first.empty()) continue;
|
||||||
func(_items[i].first, _items[i].second);
|
func(_items[i].first, _items[i].second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,7 +173,7 @@ struct NameDictImpl {
|
|||||||
array<StrName> v(_size);
|
array<StrName> v(_size);
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for(uint16_t i = 0; i < _capacity; i++) {
|
for(uint16_t i = 0; i < _capacity; i++) {
|
||||||
if(_items[i].first.empty()) { continue; }
|
if(_items[i].first.empty()) continue;
|
||||||
new (&v[j++]) StrName(_items[i].first);
|
new (&v[j++]) StrName(_items[i].first);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
@ -183,7 +182,9 @@ struct NameDictImpl {
|
|||||||
array<Item> items() const {
|
array<Item> items() const {
|
||||||
array<Item> v(_size);
|
array<Item> v(_size);
|
||||||
int j = 0;
|
int j = 0;
|
||||||
apply([&](StrName key, T val) { new (&v[j++]) Item(key, val); });
|
apply([&](StrName key, T val) {
|
||||||
|
new (&v[j++]) Item(key, val);
|
||||||
|
});
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -31,9 +31,8 @@ struct array {
|
|||||||
array(explicit_copy_t, const array& other) {
|
array(explicit_copy_t, const array& other) {
|
||||||
_data = (T*)std::malloc(sizeof(T) * other._size);
|
_data = (T*)std::malloc(sizeof(T) * other._size);
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
for(int i = 0; i < _size; i++) {
|
for(int i = 0; i < _size; i++)
|
||||||
_data[i] = other._data[i];
|
_data[i] = other._data[i];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
array(T* data, int size) : _data(data), _size(size) {}
|
array(T* data, int size) : _data(data), _size(size) {}
|
||||||
@ -107,9 +106,8 @@ struct vector {
|
|||||||
|
|
||||||
vector(explicit_copy_t, const vector& other) :
|
vector(explicit_copy_t, const vector& other) :
|
||||||
_data((T*)std::malloc(sizeof(T) * other._size)), _capacity(other._size), _size(other._size) {
|
_data((T*)std::malloc(sizeof(T) * other._size)), _capacity(other._size), _size(other._size) {
|
||||||
for(int i = 0; i < _size; i++) {
|
for(int i = 0; i < _size; i++)
|
||||||
_data[i] = other._data[i];
|
_data[i] = other._data[i];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow move
|
// allow move
|
||||||
@ -140,10 +138,8 @@ struct vector {
|
|||||||
T* data() const { return _data; }
|
T* data() const { return _data; }
|
||||||
|
|
||||||
void reserve(int cap) {
|
void reserve(int cap) {
|
||||||
if(cap < 4) {
|
if(cap < 4) cap = 4; // minimum capacity
|
||||||
cap = 4; // minimum capacity
|
if(cap <= capacity()) return;
|
||||||
}
|
|
||||||
if(cap <= capacity()) { return; }
|
|
||||||
T* new_data = (T*)std::malloc(sizeof(T) * cap);
|
T* new_data = (T*)std::malloc(sizeof(T) * cap);
|
||||||
if constexpr(is_trivially_relocatable_v<T>) {
|
if constexpr(is_trivially_relocatable_v<T>) {
|
||||||
std::memcpy(new_data, _data, sizeof(T) * _size);
|
std::memcpy(new_data, _data, sizeof(T) * _size);
|
||||||
@ -153,7 +149,7 @@ struct vector {
|
|||||||
_data[i].~T();
|
_data[i].~T();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(_data) { std::free(_data); }
|
if(_data) std::free(_data);
|
||||||
_data = new_data;
|
_data = new_data;
|
||||||
_capacity = cap;
|
_capacity = cap;
|
||||||
}
|
}
|
||||||
@ -164,25 +160,25 @@ struct vector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void push_back(const T& t) {
|
void push_back(const T& t) {
|
||||||
if(_size == _capacity) { reserve(_capacity * 2); }
|
if(_size == _capacity) reserve(_capacity * 2);
|
||||||
new (&_data[_size++]) T(t);
|
new (&_data[_size++]) T(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_back(T&& t) {
|
void push_back(T&& t) {
|
||||||
if(_size == _capacity) { reserve(_capacity * 2); }
|
if(_size == _capacity) reserve(_capacity * 2);
|
||||||
new (&_data[_size++]) T(std::move(t));
|
new (&_data[_size++]) T(std::move(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool contains(const T& t) const {
|
bool contains(const T& t) const {
|
||||||
for(int i = 0; i < _size; i++) {
|
for(int i = 0; i < _size; i++) {
|
||||||
if(_data[i] == t) { return true; }
|
if(_data[i] == t) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void emplace_back(Args&&... args) {
|
void emplace_back(Args&&... args) {
|
||||||
if(_size == _capacity) { reserve(_capacity * 2); }
|
if(_size == _capacity) reserve(_capacity * 2);
|
||||||
new (&_data[_size++]) T(std::forward<Args>(args)...);
|
new (&_data[_size++]) T(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,24 +189,21 @@ struct vector {
|
|||||||
void extend(T* begin, T* end) {
|
void extend(T* begin, T* end) {
|
||||||
int n = end - begin;
|
int n = end - begin;
|
||||||
reserve(_size + n);
|
reserve(_size + n);
|
||||||
for(int i = 0; i < n; i++) {
|
for(int i = 0; i < n; i++)
|
||||||
new (&_data[_size++]) T(begin[i]);
|
new (&_data[_size++]) T(begin[i]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void insert(int index, const T& t) {
|
void insert(int index, const T& t) {
|
||||||
if(_size == _capacity) { reserve(_capacity * 2); }
|
if(_size == _capacity) reserve(_capacity * 2);
|
||||||
for(int i = _size; i > index; i--) {
|
for(int i = _size; i > index; i--)
|
||||||
_data[i] = std::move(_data[i - 1]);
|
_data[i] = std::move(_data[i - 1]);
|
||||||
}
|
|
||||||
_data[index] = t;
|
_data[index] = t;
|
||||||
_size++;
|
_size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void erase(int index) {
|
void erase(int index) {
|
||||||
for(int i = index; i < _size - 1; i++) {
|
for(int i = index; i < _size - 1; i++)
|
||||||
_data[i] = std::move(_data[i + 1]);
|
_data[i] = std::move(_data[i + 1]);
|
||||||
}
|
|
||||||
_size--;
|
_size--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,7 +420,7 @@ public:
|
|||||||
|
|
||||||
~small_vector() {
|
~small_vector() {
|
||||||
std::destroy(m_begin, m_end);
|
std::destroy(m_begin, m_end);
|
||||||
if(!is_small()) { std::free(m_begin); }
|
if(!is_small()) std::free(m_begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
|
|||||||
@ -33,7 +33,7 @@ class Compiler {
|
|||||||
const Token& next() const { return tokens[i + 1]; }
|
const Token& next() const { return tokens[i + 1]; }
|
||||||
|
|
||||||
const Token& err() const {
|
const Token& err() const {
|
||||||
if(i >= tokens.size()) { return prev(); }
|
if(i >= tokens.size()) return prev();
|
||||||
return curr();
|
return curr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -276,9 +276,8 @@ struct SequenceExpr : Expr {
|
|||||||
virtual Opcode opcode() const = 0;
|
virtual Opcode opcode() const = 0;
|
||||||
|
|
||||||
void emit_(CodeEmitContext* ctx) override {
|
void emit_(CodeEmitContext* ctx) override {
|
||||||
for(auto& item: items) {
|
for(auto& item: items)
|
||||||
item->emit_(ctx);
|
item->emit_(ctx);
|
||||||
}
|
|
||||||
ctx->emit_(opcode(), items.size(), line);
|
ctx->emit_(opcode(), items.size(), line);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -287,9 +286,8 @@ struct ListExpr : SequenceExpr {
|
|||||||
using SequenceExpr::SequenceExpr;
|
using SequenceExpr::SequenceExpr;
|
||||||
|
|
||||||
Opcode opcode() const override {
|
Opcode opcode() const override {
|
||||||
for(auto& e: items) {
|
for(auto& e: items)
|
||||||
if(e->is_starred()) { return OP_BUILD_LIST_UNPACK; }
|
if(e->is_starred()) return OP_BUILD_LIST_UNPACK;
|
||||||
}
|
|
||||||
return OP_BUILD_LIST;
|
return OP_BUILD_LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,9 +298,8 @@ struct DictExpr : SequenceExpr {
|
|||||||
using SequenceExpr::SequenceExpr;
|
using SequenceExpr::SequenceExpr;
|
||||||
|
|
||||||
Opcode opcode() const override {
|
Opcode opcode() const override {
|
||||||
for(auto& e: items) {
|
for(auto& e: items)
|
||||||
if(e->is_starred()) { return OP_BUILD_DICT_UNPACK; }
|
if(e->is_starred()) return OP_BUILD_DICT_UNPACK;
|
||||||
}
|
|
||||||
return OP_BUILD_DICT;
|
return OP_BUILD_DICT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,9 +310,8 @@ struct SetExpr : SequenceExpr {
|
|||||||
using SequenceExpr::SequenceExpr;
|
using SequenceExpr::SequenceExpr;
|
||||||
|
|
||||||
Opcode opcode() const override {
|
Opcode opcode() const override {
|
||||||
for(auto& e: items) {
|
for(auto& e: items)
|
||||||
if(e->is_starred()) { return OP_BUILD_SET_UNPACK; }
|
if(e->is_starred()) return OP_BUILD_SET_UNPACK;
|
||||||
}
|
|
||||||
return OP_BUILD_SET;
|
return OP_BUILD_SET;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -326,9 +322,8 @@ struct TupleExpr : SequenceExpr {
|
|||||||
bool is_tuple() const override { return true; }
|
bool is_tuple() const override { return true; }
|
||||||
|
|
||||||
Opcode opcode() const override {
|
Opcode opcode() const override {
|
||||||
for(auto& e: items) {
|
for(auto& e: items)
|
||||||
if(e->is_starred()) { return OP_BUILD_TUPLE_UNPACK; }
|
if(e->is_starred()) return OP_BUILD_TUPLE_UNPACK;
|
||||||
}
|
|
||||||
return OP_BUILD_TUPLE;
|
return OP_BUILD_TUPLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -42,7 +42,7 @@ constexpr TokenIndex TK(const char token[]) {
|
|||||||
i++;
|
i++;
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
if(*i == *j) { return k; }
|
if(*i == *j) return k;
|
||||||
}
|
}
|
||||||
return 255;
|
return 255;
|
||||||
}
|
}
|
||||||
@ -52,9 +52,8 @@ constexpr inline bool is_raw_string_used(TokenIndex t) { return t == TK("@id") |
|
|||||||
#define TK_STR(t) kTokens[t]
|
#define TK_STR(t) kTokens[t]
|
||||||
const std::map<std::string_view, TokenIndex> kTokenKwMap = []() {
|
const std::map<std::string_view, TokenIndex> kTokenKwMap = []() {
|
||||||
std::map<std::string_view, TokenIndex> map;
|
std::map<std::string_view, TokenIndex> map;
|
||||||
for(int k = TK("class"); k < kTokenCount; k++) {
|
for(int k = TK("class"); k < kTokenCount; k++)
|
||||||
map[kTokens[k]] = k;
|
map[kTokens[k]] = k;
|
||||||
}
|
|
||||||
return map;
|
return map;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
|||||||
@ -94,7 +94,7 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
|
|||||||
assert(is_type(obj, tp_type));
|
assert(is_type(obj, tp_type));
|
||||||
std::string_view name_sv(name);
|
std::string_view name_sv(name);
|
||||||
int pos = name_sv.find(':');
|
int pos = name_sv.find(':');
|
||||||
if(pos > 0) { name_sv = name_sv.substr(0, pos); }
|
if(pos > 0) name_sv = name_sv.substr(0, pos);
|
||||||
auto fget = [](VM* vm, ArgsView args) -> PyVar {
|
auto fget = [](VM* vm, ArgsView args) -> PyVar {
|
||||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
|
obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
|
||||||
F T::*field = lambda_get_userdata<F T::*>(args.begin());
|
F T::*field = lambda_get_userdata<F T::*>(args.begin());
|
||||||
@ -188,7 +188,9 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
|
|||||||
wT& self = _CAST(wT&, args[0]); \
|
wT& self = _CAST(wT&, args[0]); \
|
||||||
return vm->new_user_object<wT>(self); \
|
return vm->new_user_object<wT>(self); \
|
||||||
}); \
|
}); \
|
||||||
vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args) { return VAR(sizeof(wT)); }); \
|
vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args) { \
|
||||||
|
return VAR(sizeof(wT)); \
|
||||||
|
}); \
|
||||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||||
wT& self = _CAST(wT&, _0); \
|
wT& self = _CAST(wT&, _0); \
|
||||||
if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \
|
if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \
|
||||||
@ -210,8 +212,14 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
|
|||||||
tgt[i] = CAST(T, _2); \
|
tgt[i] = CAST(T, _2); \
|
||||||
});
|
});
|
||||||
|
|
||||||
#define PK_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return x; })
|
#define PK_LAMBDA(x) \
|
||||||
#define PK_VAR_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return VAR(x); })
|
([](VM* vm, ArgsView args) -> PyVar { \
|
||||||
|
return x; \
|
||||||
|
})
|
||||||
|
#define PK_VAR_LAMBDA(x) \
|
||||||
|
([](VM* vm, ArgsView args) -> PyVar { \
|
||||||
|
return VAR(x); \
|
||||||
|
})
|
||||||
#define PK_ACTION(x) \
|
#define PK_ACTION(x) \
|
||||||
([](VM* vm, ArgsView args) -> PyVar { \
|
([](VM* vm, ArgsView args) -> PyVar { \
|
||||||
x; \
|
x; \
|
||||||
|
|||||||
@ -74,17 +74,17 @@ struct Struct {
|
|||||||
} else {
|
} else {
|
||||||
p = (char*)std::malloc(size);
|
p = (char*)std::malloc(size);
|
||||||
}
|
}
|
||||||
if(zero_init) { std::memset(p, 0, size); }
|
if(zero_init) std::memset(p, 0, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Struct(void* p, int size) : Struct(size, false) {
|
Struct(void* p, int size) : Struct(size, false) {
|
||||||
if(p != nullptr) { std::memcpy(this->p, p, size); }
|
if(p != nullptr) std::memcpy(this->p, p, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Struct(const Struct& other) : Struct(other.p, other.size) {}
|
Struct(const Struct& other) : Struct(other.p, other.size) {}
|
||||||
|
|
||||||
~Struct() {
|
~Struct() {
|
||||||
if(p != _inlined) { std::free(p); }
|
if(p != _inlined) std::free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||||
@ -94,9 +94,7 @@ struct Struct {
|
|||||||
template <typename Tp>
|
template <typename Tp>
|
||||||
Tp to_void_p(VM* vm, PyVar var) {
|
Tp to_void_p(VM* vm, PyVar var) {
|
||||||
static_assert(std::is_pointer_v<Tp>);
|
static_assert(std::is_pointer_v<Tp>);
|
||||||
if(var == vm->None) {
|
if(var == vm->None) return nullptr; // None can be casted to any pointer implicitly
|
||||||
return nullptr; // None can be casted to any pointer implicitly
|
|
||||||
}
|
|
||||||
VoidP& p = CAST(VoidP&, var);
|
VoidP& p = CAST(VoidP&, var);
|
||||||
return reinterpret_cast<Tp>(p.ptr);
|
return reinterpret_cast<Tp>(p.ptr);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -178,9 +178,8 @@ struct CallStack {
|
|||||||
bool empty() const { return _size == 0; }
|
bool empty() const { return _size == 0; }
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
while(!empty()) {
|
while(!empty())
|
||||||
pop();
|
pop();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
@ -201,9 +200,8 @@ struct CallStack {
|
|||||||
|
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
void apply(Func&& f) {
|
void apply(Func&& f) {
|
||||||
for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back) {
|
for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back)
|
||||||
f(p->frame);
|
f(p->frame);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~CallStack() { clear(); }
|
~CallStack() { clear(); }
|
||||||
|
|||||||
@ -51,13 +51,12 @@ struct Generator {
|
|||||||
List s_backup;
|
List s_backup;
|
||||||
|
|
||||||
Generator(LinkedFrame* lf, ArgsView buffer) : lf(lf), state(0) {
|
Generator(LinkedFrame* lf, ArgsView buffer) : lf(lf), state(0) {
|
||||||
for(PyVar obj: buffer) {
|
for(PyVar obj: buffer)
|
||||||
s_backup.push_back(obj);
|
s_backup.push_back(obj);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _gc_mark(VM* vm) {
|
void _gc_mark(VM* vm) {
|
||||||
if(lf == nullptr) { return; }
|
if(lf == nullptr) return;
|
||||||
lf->frame._gc_mark(vm);
|
lf->frame._gc_mark(vm);
|
||||||
vm->__stack_gc_mark(s_backup.begin(), s_backup.end());
|
vm->__stack_gc_mark(s_backup.begin(), s_backup.end());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pocketpy/interpreter/frame.hpp"
|
#include "pocketpy/objects/object.hpp"
|
||||||
#include "pocketpy/interpreter/gc.hpp"
|
|
||||||
#include "pocketpy/interpreter/profiler.hpp"
|
|
||||||
#include "pocketpy/objects/builtins.hpp"
|
|
||||||
#include "pocketpy/objects/dict.hpp"
|
#include "pocketpy/objects/dict.hpp"
|
||||||
#include "pocketpy/objects/error.hpp"
|
#include "pocketpy/objects/error.hpp"
|
||||||
#include "pocketpy/objects/object.hpp"
|
|
||||||
#include "pocketpy/objects/stackmemory.hpp"
|
#include "pocketpy/objects/stackmemory.hpp"
|
||||||
|
#include "pocketpy/objects/builtins.hpp"
|
||||||
|
#include "pocketpy/interpreter/gc.hpp"
|
||||||
|
#include "pocketpy/interpreter/frame.hpp"
|
||||||
|
#include "pocketpy/interpreter/profiler.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
@ -58,10 +58,14 @@ struct PyTypeInfo {
|
|||||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||||
Vt vt;
|
Vt vt;
|
||||||
if constexpr(!std::is_trivially_destructible_v<T>) {
|
if constexpr(!std::is_trivially_destructible_v<T>) {
|
||||||
vt._dtor = [](void* p) { ((T*)p)->~T(); };
|
vt._dtor = [](void* p) {
|
||||||
|
((T*)p)->~T();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if constexpr(has_gc_marker<T>::value) {
|
if constexpr(has_gc_marker<T>::value) {
|
||||||
vt._gc_mark = [](void* p, VM* vm) { ((T*)p)->_gc_mark(vm); };
|
vt._gc_mark = [](void* p, VM* vm) {
|
||||||
|
((T*)p)->_gc_mark(vm);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return vt;
|
return vt;
|
||||||
}
|
}
|
||||||
@ -654,18 +658,16 @@ PyVar py_var(VM* vm, __T&& value) {
|
|||||||
} else {
|
} else {
|
||||||
constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
|
constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
|
||||||
if constexpr((bool)const_type) {
|
if constexpr((bool)const_type) {
|
||||||
if constexpr(is_sso_v<T>) {
|
if constexpr(is_sso_v<T>)
|
||||||
return PyVar(const_type, value);
|
return PyVar(const_type, value);
|
||||||
} else {
|
else
|
||||||
return vm->heap.gcnew<T>(const_type, std::forward<__T>(value));
|
return vm->heap.gcnew<T>(const_type, std::forward<__T>(value));
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Type type = vm->_find_type_in_cxx_typeid_map<T>();
|
Type type = vm->_find_type_in_cxx_typeid_map<T>();
|
||||||
if constexpr(is_sso_v<T>) {
|
if constexpr(is_sso_v<T>)
|
||||||
return PyVar(type, value);
|
return PyVar(type, value);
|
||||||
} else {
|
else
|
||||||
return vm->heap.gcnew<T>(type, std::forward<__T>(value));
|
return vm->heap.gcnew<T>(type, std::forward<__T>(value));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -682,15 +684,15 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
|
|||||||
if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, CString>) {
|
if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, CString>) {
|
||||||
static_assert(!std::is_reference_v<__T>);
|
static_assert(!std::is_reference_v<__T>);
|
||||||
// str (shortcuts)
|
// str (shortcuts)
|
||||||
if(obj == vm->None) { return nullptr; }
|
if(obj == vm->None) return nullptr;
|
||||||
if constexpr(with_check) { vm->check_type(obj, vm->tp_str); }
|
if constexpr(with_check) vm->check_type(obj, vm->tp_str);
|
||||||
return PK_OBJ_GET(Str, obj).c_str();
|
return PK_OBJ_GET(Str, obj).c_str();
|
||||||
} else if constexpr(std::is_same_v<T, bool>) {
|
} else if constexpr(std::is_same_v<T, bool>) {
|
||||||
static_assert(!std::is_reference_v<__T>);
|
static_assert(!std::is_reference_v<__T>);
|
||||||
// bool
|
// bool
|
||||||
if constexpr(with_check) {
|
if constexpr(with_check) {
|
||||||
if(obj == vm->True) { return true; }
|
if(obj == vm->True) return true;
|
||||||
if(obj == vm->False) { return false; }
|
if(obj == vm->False) return false;
|
||||||
vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
|
vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||||
}
|
}
|
||||||
return obj == vm->True;
|
return obj == vm->True;
|
||||||
@ -698,14 +700,14 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
|
|||||||
static_assert(!std::is_reference_v<__T>);
|
static_assert(!std::is_reference_v<__T>);
|
||||||
// int
|
// int
|
||||||
if constexpr(with_check) {
|
if constexpr(with_check) {
|
||||||
if(is_int(obj)) { return (T)obj.as<i64>(); }
|
if(is_int(obj)) return (T)obj.as<i64>();
|
||||||
vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
|
vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||||
}
|
}
|
||||||
return (T)obj.as<i64>();
|
return (T)obj.as<i64>();
|
||||||
} else if constexpr(is_floating_point_v<T>) {
|
} else if constexpr(is_floating_point_v<T>) {
|
||||||
static_assert(!std::is_reference_v<__T>);
|
static_assert(!std::is_reference_v<__T>);
|
||||||
if(is_float(obj)) { return (T)obj.as<f64>(); }
|
if(is_float(obj)) return (T)obj.as<f64>();
|
||||||
if(is_int(obj)) { return (T)obj.as<i64>(); }
|
if(is_int(obj)) return (T)obj.as<i64>();
|
||||||
vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape());
|
vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
} else if constexpr(std::is_enum_v<T>) {
|
} else if constexpr(std::is_enum_v<T>) {
|
||||||
|
|||||||
@ -62,7 +62,7 @@ struct CodeBlock {
|
|||||||
type(type), parent(parent), start(start), end(-1), end2(-1) {}
|
type(type), parent(parent), start(start), end(-1), end2(-1) {}
|
||||||
|
|
||||||
int get_break_end() const {
|
int get_break_end() const {
|
||||||
if(end2 != -1) { return end2; }
|
if(end2 != -1) return end2;
|
||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -55,7 +55,7 @@ struct Exception {
|
|||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void st_push(Args&&... args) {
|
void st_push(Args&&... args) {
|
||||||
if(stacktrace.size() >= 7) { return; }
|
if(stacktrace.size() >= 7) return;
|
||||||
stacktrace.emplace(std::forward<Args>(args)...);
|
stacktrace.emplace(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,9 +45,8 @@ struct List : public vector<PyVar> {
|
|||||||
|
|
||||||
Tuple to_tuple() const {
|
Tuple to_tuple() const {
|
||||||
Tuple ret(size());
|
Tuple ret(size());
|
||||||
for(int i = 0; i < size(); i++) {
|
for(int i = 0; i < size(); i++)
|
||||||
ret[i] = (*this)[i];
|
ret[i] = (*this)[i];
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -50,7 +50,9 @@ public:
|
|||||||
bind_function(
|
bind_function(
|
||||||
*this,
|
*this,
|
||||||
"__init__",
|
"__init__",
|
||||||
[](T* self, Args... args) { new (self) T(args...); },
|
[](T* self, Args... args) {
|
||||||
|
new (self) T(args...);
|
||||||
|
},
|
||||||
pkpy::BindType::DEFAULT,
|
pkpy::BindType::DEFAULT,
|
||||||
extra...);
|
extra...);
|
||||||
return *this;
|
return *this;
|
||||||
|
|||||||
@ -65,10 +65,14 @@ public:
|
|||||||
|
|
||||||
if constexpr(sizeof(f) <= sizeof(buffer)) {
|
if constexpr(sizeof(f) <= sizeof(buffer)) {
|
||||||
new (buffer) auto(std::forward<Fn>(f));
|
new (buffer) auto(std::forward<Fn>(f));
|
||||||
destructor = [](function_record* self) { reinterpret_cast<Fn*>(self->buffer)->~Fn(); };
|
destructor = [](function_record* self) {
|
||||||
|
reinterpret_cast<Fn*>(self->buffer)->~Fn();
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
data = new auto(std::forward<Fn>(f));
|
data = new auto(std::forward<Fn>(f));
|
||||||
destructor = [](function_record* self) { delete static_cast<Fn*>(self->data); };
|
destructor = [](function_record* self) {
|
||||||
|
delete static_cast<Fn*>(self->data);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
using Generator = generator<std::decay_t<Fn>, std::tuple<Extras...>>;
|
using Generator = generator<std::decay_t<Fn>, std::tuple<Extras...>>;
|
||||||
|
|||||||
@ -24,8 +24,12 @@ struct type_info {
|
|||||||
((T*)ptr)->~T();
|
((T*)ptr)->~T();
|
||||||
operator delete (ptr);
|
operator delete (ptr);
|
||||||
},
|
},
|
||||||
[](void* dst, const void* src) { new (dst) T(*(const T*)src); },
|
[](void* dst, const void* src) {
|
||||||
[](void* dst, void* src) { new (dst) T(std::move(*(T*)src)); },
|
new (dst) T(*(const T*)src);
|
||||||
|
},
|
||||||
|
[](void* dst, void* src) {
|
||||||
|
new (dst) T(std::move(*(T*)src));
|
||||||
|
},
|
||||||
&typeid(T),
|
&typeid(T),
|
||||||
};
|
};
|
||||||
return info;
|
return info;
|
||||||
|
|||||||
@ -17,7 +17,7 @@ any::any(any&& other) noexcept : data(other.data), _vt(other._vt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
any& any::operator= (any&& other) noexcept {
|
any& any::operator= (any&& other) noexcept {
|
||||||
if(data) { _vt->deleter(data); }
|
if(data) _vt->deleter(data);
|
||||||
data = other.data;
|
data = other.data;
|
||||||
_vt = other._vt;
|
_vt = other._vt;
|
||||||
other.data = nullptr;
|
other.data = nullptr;
|
||||||
|
|||||||
@ -176,7 +176,7 @@ struct MemoryPool {
|
|||||||
|
|
||||||
void shrink_to_fit() {
|
void shrink_to_fit() {
|
||||||
PK_GLOBAL_SCOPE_LOCK();
|
PK_GLOBAL_SCOPE_LOCK();
|
||||||
if(_arenas.size() < __MinArenaCount) { return; }
|
if(_arenas.size() < __MinArenaCount) return;
|
||||||
_arenas.apply([this](Arena* arena) {
|
_arenas.apply([this](Arena* arena) {
|
||||||
if(arena->full()) {
|
if(arena->full()) {
|
||||||
_arenas.erase(arena);
|
_arenas.erase(arena);
|
||||||
@ -186,8 +186,12 @@ struct MemoryPool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
~MemoryPool() {
|
~MemoryPool() {
|
||||||
_arenas.apply([](Arena* arena) { delete arena; });
|
_arenas.apply([](Arena* arena) {
|
||||||
_empty_arenas.apply([](Arena* arena) { delete arena; });
|
delete arena;
|
||||||
|
});
|
||||||
|
_empty_arenas.apply([](Arena* arena) {
|
||||||
|
delete arena;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -9,13 +9,13 @@
|
|||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
int utf8len(unsigned char c, bool suppress) {
|
int utf8len(unsigned char c, bool suppress) {
|
||||||
if((c & 0b10000000) == 0) { return 1; }
|
if((c & 0b10000000) == 0) return 1;
|
||||||
if((c & 0b11100000) == 0b11000000) { return 2; }
|
if((c & 0b11100000) == 0b11000000) return 2;
|
||||||
if((c & 0b11110000) == 0b11100000) { return 3; }
|
if((c & 0b11110000) == 0b11100000) return 3;
|
||||||
if((c & 0b11111000) == 0b11110000) { return 4; }
|
if((c & 0b11111000) == 0b11110000) return 4;
|
||||||
if((c & 0b11111100) == 0b11111000) { return 5; }
|
if((c & 0b11111100) == 0b11111000) return 5;
|
||||||
if((c & 0b11111110) == 0b11111100) { return 6; }
|
if((c & 0b11111110) == 0b11111100) return 6;
|
||||||
if(!suppress) { throw std::runtime_error("invalid utf8 char: " + std::to_string(c)); }
|
if(!suppress) throw std::runtime_error("invalid utf8 char: " + std::to_string(c));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,9 +70,8 @@ Str::Str(const Str& other) : size(other.size), is_ascii(other.is_ascii) {
|
|||||||
Str::Str(Str&& other) : size(other.size), is_ascii(other.is_ascii) {
|
Str::Str(Str&& other) : size(other.size), is_ascii(other.is_ascii) {
|
||||||
if(other.is_inlined()) {
|
if(other.is_inlined()) {
|
||||||
data = _inlined;
|
data = _inlined;
|
||||||
for(int i = 0; i < size; i++) {
|
for(int i = 0; i < size; i++)
|
||||||
_inlined[i] = other._inlined[i];
|
_inlined[i] = other._inlined[i];
|
||||||
}
|
|
||||||
data[size] = '\0';
|
data[size] = '\0';
|
||||||
} else {
|
} else {
|
||||||
data = other.data;
|
data = other.data;
|
||||||
@ -93,7 +92,7 @@ std::ostream& operator<< (std::ostream& os, const Str& str) { return os << str.s
|
|||||||
bool operator< (const std::string_view other, const Str& str) { return other < str.sv(); }
|
bool operator< (const std::string_view other, const Str& str) { return other < str.sv(); }
|
||||||
|
|
||||||
Str& Str::operator= (const Str& other) {
|
Str& Str::operator= (const Str& other) {
|
||||||
if(!is_inlined()) { std::free(data); }
|
if(!is_inlined()) std::free(data);
|
||||||
size = other.size;
|
size = other.size;
|
||||||
is_ascii = other.is_ascii;
|
is_ascii = other.is_ascii;
|
||||||
PK_STR_ALLOCATE()
|
PK_STR_ALLOCATE()
|
||||||
@ -116,22 +115,22 @@ Str Str::operator+ (const char* p) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Str::operator== (const Str& other) const {
|
bool Str::operator== (const Str& other) const {
|
||||||
if(size != other.size) { return false; }
|
if(size != other.size) return false;
|
||||||
return memcmp(data, other.data, size) == 0;
|
return memcmp(data, other.data, size) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Str::operator!= (const Str& other) const {
|
bool Str::operator!= (const Str& other) const {
|
||||||
if(size != other.size) { return true; }
|
if(size != other.size) return true;
|
||||||
return memcmp(data, other.data, size) != 0;
|
return memcmp(data, other.data, size) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Str::operator== (const std::string_view other) const {
|
bool Str::operator== (const std::string_view other) const {
|
||||||
if(size != (int)other.size()) { return false; }
|
if(size != (int)other.size()) return false;
|
||||||
return memcmp(data, other.data(), size) == 0;
|
return memcmp(data, other.data(), size) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Str::operator!= (const std::string_view other) const {
|
bool Str::operator!= (const std::string_view other) const {
|
||||||
if(size != (int)other.size()) { return true; }
|
if(size != (int)other.size()) return true;
|
||||||
return memcmp(data, other.data(), size) != 0;
|
return memcmp(data, other.data(), size) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +149,7 @@ bool Str::operator<= (const Str& other) const { return this->sv() <= other.sv();
|
|||||||
bool Str::operator>= (const Str& other) const { return this->sv() >= other.sv(); }
|
bool Str::operator>= (const Str& other) const { return this->sv() >= other.sv(); }
|
||||||
|
|
||||||
Str::~Str() {
|
Str::~Str() {
|
||||||
if(!is_inlined()) { std::free(data); }
|
if(!is_inlined()) std::free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
Str Str::substr(int start, int len) const {
|
Str Str::substr(int start, int len) const {
|
||||||
@ -166,14 +165,12 @@ Str Str::strip(bool left, bool right, const Str& chars) const {
|
|||||||
int L = 0;
|
int L = 0;
|
||||||
int R = u8_length();
|
int R = u8_length();
|
||||||
if(left) {
|
if(left) {
|
||||||
while(L < R && chars.index(u8_getitem(L)) != -1) {
|
while(L < R && chars.index(u8_getitem(L)) != -1)
|
||||||
L++;
|
L++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(right) {
|
if(right) {
|
||||||
while(L < R && chars.index(u8_getitem(R - 1)) != -1) {
|
while(L < R && chars.index(u8_getitem(R - 1)) != -1)
|
||||||
R--;
|
R--;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return u8_slice(L, R, 1);
|
return u8_slice(L, R, 1);
|
||||||
}
|
}
|
||||||
@ -183,14 +180,12 @@ Str Str::strip(bool left, bool right) const {
|
|||||||
int L = 0;
|
int L = 0;
|
||||||
int R = size;
|
int R = size;
|
||||||
if(left) {
|
if(left) {
|
||||||
while(L < R && (data[L] == ' ' || data[L] == '\t' || data[L] == '\n' || data[L] == '\r')) {
|
while(L < R && (data[L] == ' ' || data[L] == '\t' || data[L] == '\n' || data[L] == '\r'))
|
||||||
L++;
|
L++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(right) {
|
if(right) {
|
||||||
while(L < R && (data[R - 1] == ' ' || data[R - 1] == '\t' || data[R - 1] == '\n' || data[R - 1] == '\r')) {
|
while(L < R && (data[R - 1] == ' ' || data[R - 1] == '\t' || data[R - 1] == '\n' || data[R - 1] == '\r'))
|
||||||
R--;
|
R--;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return substr(L, R - L);
|
return substr(L, R - L);
|
||||||
} else {
|
} else {
|
||||||
@ -201,7 +196,7 @@ Str Str::strip(bool left, bool right) const {
|
|||||||
Str Str::lower() const {
|
Str Str::lower() const {
|
||||||
std::string copy(data, size);
|
std::string copy(data, size);
|
||||||
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) {
|
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) {
|
||||||
if('A' <= c && c <= 'Z') { return c + ('a' - 'A'); }
|
if('A' <= c && c <= 'Z') return c + ('a' - 'A');
|
||||||
return (int)c;
|
return (int)c;
|
||||||
});
|
});
|
||||||
return Str(copy);
|
return Str(copy);
|
||||||
@ -210,7 +205,7 @@ Str Str::lower() const {
|
|||||||
Str Str::upper() const {
|
Str Str::upper() const {
|
||||||
std::string copy(data, size);
|
std::string copy(data, size);
|
||||||
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) {
|
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) {
|
||||||
if('a' <= c && c <= 'z') { return c - ('a' - 'A'); }
|
if('a' <= c && c <= 'z') return c - ('a' - 'A');
|
||||||
return (int)c;
|
return (int)c;
|
||||||
});
|
});
|
||||||
return Str(copy);
|
return Str(copy);
|
||||||
@ -228,11 +223,11 @@ void Str::escape_(SStream& ss, bool single_quote) const {
|
|||||||
char c = this->operator[] (i);
|
char c = this->operator[] (i);
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case '"':
|
case '"':
|
||||||
if(!single_quote) { ss << '\\'; }
|
if(!single_quote) ss << '\\';
|
||||||
ss << '"';
|
ss << '"';
|
||||||
break;
|
break;
|
||||||
case '\'':
|
case '\'':
|
||||||
if(single_quote) { ss << '\\'; }
|
if(single_quote) ss << '\\';
|
||||||
ss << '\'';
|
ss << '\'';
|
||||||
break;
|
break;
|
||||||
case '\\': ss << '\\' << '\\'; break;
|
case '\\': ss << '\\' << '\\'; break;
|
||||||
@ -255,14 +250,14 @@ void Str::escape_(SStream& ss, bool single_quote) const {
|
|||||||
|
|
||||||
int Str::index(const Str& sub, int start) const {
|
int Str::index(const Str& sub, int start) const {
|
||||||
auto p = std::search(data + start, data + size, sub.data, sub.data + sub.size);
|
auto p = std::search(data + start, data + size, sub.data, sub.data + sub.size);
|
||||||
if(p == data + size) { return -1; }
|
if(p == data + size) return -1;
|
||||||
return p - data;
|
return p - data;
|
||||||
}
|
}
|
||||||
|
|
||||||
Str Str::replace(char old, char new_) const {
|
Str Str::replace(char old, char new_) const {
|
||||||
Str copied = *this;
|
Str copied = *this;
|
||||||
for(int i = 0; i < copied.size; i++) {
|
for(int i = 0; i < copied.size; i++) {
|
||||||
if(copied.data[i] == old) { copied.data[i] = new_; }
|
if(copied.data[i] == old) copied.data[i] = new_;
|
||||||
}
|
}
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
@ -272,18 +267,18 @@ Str Str::replace(const Str& old, const Str& new_, int count) const {
|
|||||||
int start = 0;
|
int start = 0;
|
||||||
while(true) {
|
while(true) {
|
||||||
int i = index(old, start);
|
int i = index(old, start);
|
||||||
if(i == -1) { break; }
|
if(i == -1) break;
|
||||||
ss << substr(start, i - start);
|
ss << substr(start, i - start);
|
||||||
ss << new_;
|
ss << new_;
|
||||||
start = i + old.size;
|
start = i + old.size;
|
||||||
if(count != -1 && --count == 0) { break; }
|
if(count != -1 && --count == 0) break;
|
||||||
}
|
}
|
||||||
ss << substr(start, size - start);
|
ss << substr(start, size - start);
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Str::_unicode_index_to_byte(int i) const {
|
int Str::_unicode_index_to_byte(int i) const {
|
||||||
if(is_ascii) { return i; }
|
if(is_ascii) return i;
|
||||||
int j = 0;
|
int j = 0;
|
||||||
while(i > 0) {
|
while(i > 0) {
|
||||||
j += utf8len(data[j]);
|
j += utf8len(data[j]);
|
||||||
@ -293,10 +288,10 @@ int Str::_unicode_index_to_byte(int i) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int Str::_byte_index_to_unicode(int n) const {
|
int Str::_byte_index_to_unicode(int n) const {
|
||||||
if(is_ascii) { return n; }
|
if(is_ascii) return n;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
for(int i = 0; i < n; i++) {
|
for(int i = 0; i < n; i++) {
|
||||||
if((data[i] & 0xC0) != 0x80) { cnt++; }
|
if((data[i] & 0xC0) != 0x80) cnt++;
|
||||||
}
|
}
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
@ -324,13 +319,13 @@ vector<std::string_view> Str::split(const Str& sep) const {
|
|||||||
int start = 0;
|
int start = 0;
|
||||||
while(true) {
|
while(true) {
|
||||||
int i = index(sep, start);
|
int i = index(sep, start);
|
||||||
if(i == -1) { break; }
|
if(i == -1) break;
|
||||||
tmp = sv().substr(start, i - start);
|
tmp = sv().substr(start, i - start);
|
||||||
if(!tmp.empty()) { result.push_back(tmp); }
|
if(!tmp.empty()) result.push_back(tmp);
|
||||||
start = i + sep.size;
|
start = i + sep.size;
|
||||||
}
|
}
|
||||||
tmp = sv().substr(start, size - start);
|
tmp = sv().substr(start, size - start);
|
||||||
if(!tmp.empty()) { result.push_back(tmp); }
|
if(!tmp.empty()) result.push_back(tmp);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,22 +334,22 @@ vector<std::string_view> Str::split(char sep) const {
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
for(int j = 0; j < size; j++) {
|
for(int j = 0; j < size; j++) {
|
||||||
if(data[j] == sep) {
|
if(data[j] == sep) {
|
||||||
if(j > i) { result.emplace_back(data + i, j - i); }
|
if(j > i) result.emplace_back(data + i, j - i);
|
||||||
i = j + 1;
|
i = j + 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(size > i) { result.emplace_back(data + i, size - i); }
|
if(size > i) result.emplace_back(data + i, size - i);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Str::count(const Str& sub) const {
|
int Str::count(const Str& sub) const {
|
||||||
if(sub.empty()) { return size + 1; }
|
if(sub.empty()) return size + 1;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
int start = 0;
|
int start = 0;
|
||||||
while(true) {
|
while(true) {
|
||||||
int i = index(sub, start);
|
int i = index(sub, start);
|
||||||
if(i == -1) { break; }
|
if(i == -1) break;
|
||||||
cnt++;
|
cnt++;
|
||||||
start = i + sub.size;
|
start = i + sub.size;
|
||||||
}
|
}
|
||||||
@ -375,11 +370,11 @@ uint32_t StrName::_pesudo_random_index = 0;
|
|||||||
|
|
||||||
StrName StrName::get(std::string_view s) {
|
StrName StrName::get(std::string_view s) {
|
||||||
auto it = _interned().find(s);
|
auto it = _interned().find(s);
|
||||||
if(it != _interned().end()) { return StrName(it->second); }
|
if(it != _interned().end()) return StrName(it->second);
|
||||||
// generate new index
|
// generate new index
|
||||||
// https://github.com/python/cpython/blob/3.12/Objects/dictobject.c#L175
|
// https://github.com/python/cpython/blob/3.12/Objects/dictobject.c#L175
|
||||||
uint16_t index = ((_pesudo_random_index * 5) + 1) & 65535;
|
uint16_t index = ((_pesudo_random_index * 5) + 1) & 65535;
|
||||||
if(index == 0) { throw std::runtime_error("StrName index overflow"); }
|
if(index == 0) throw std::runtime_error("StrName index overflow");
|
||||||
auto res = _r_interned().emplace(index, s);
|
auto res = _r_interned().emplace(index, s);
|
||||||
assert(res.second);
|
assert(res.second);
|
||||||
s = std::string_view(res.first->second);
|
s = std::string_view(res.first->second);
|
||||||
@ -396,30 +391,26 @@ Str SStream::str() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SStream& SStream::operator<< (const Str& s) {
|
SStream& SStream::operator<< (const Str& s) {
|
||||||
for(char c: s) {
|
for(char c: s)
|
||||||
buffer.push_back(c);
|
buffer.push_back(c);
|
||||||
}
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
SStream& SStream::operator<< (const char* s) {
|
SStream& SStream::operator<< (const char* s) {
|
||||||
while(*s) {
|
while(*s)
|
||||||
buffer.push_back(*s++);
|
buffer.push_back(*s++);
|
||||||
}
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
SStream& SStream::operator<< (const std::string& s) {
|
SStream& SStream::operator<< (const std::string& s) {
|
||||||
for(char c: s) {
|
for(char c: s)
|
||||||
buffer.push_back(c);
|
buffer.push_back(c);
|
||||||
}
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
SStream& SStream::operator<< (std::string_view s) {
|
SStream& SStream::operator<< (std::string_view s) {
|
||||||
for(char c: s) {
|
for(char c: s)
|
||||||
buffer.push_back(c);
|
buffer.push_back(c);
|
||||||
}
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,7 +460,7 @@ SStream& SStream::operator<< (f64 val) {
|
|||||||
snprintf(b, sizeof(b), "%.*f", prec, val);
|
snprintf(b, sizeof(b), "%.*f", prec, val);
|
||||||
}
|
}
|
||||||
(*this) << b;
|
(*this) << b;
|
||||||
if(std::all_of(b + 1, b + strlen(b), isdigit)) { (*this) << ".0"; }
|
if(std::all_of(b + 1, b + strlen(b), isdigit)) (*this) << ".0";
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,8 +468,8 @@ void SStream::write_hex(unsigned char c, bool non_zero) {
|
|||||||
unsigned char high = c >> 4;
|
unsigned char high = c >> 4;
|
||||||
unsigned char low = c & 0xf;
|
unsigned char low = c & 0xf;
|
||||||
if(non_zero) {
|
if(non_zero) {
|
||||||
if(high) { (*this) << PK_HEX_TABLE[high]; }
|
if(high) (*this) << PK_HEX_TABLE[high];
|
||||||
if(high || low) { (*this) << PK_HEX_TABLE[low]; }
|
if(high || low) (*this) << PK_HEX_TABLE[low];
|
||||||
} else {
|
} else {
|
||||||
(*this) << PK_HEX_TABLE[high];
|
(*this) << PK_HEX_TABLE[high];
|
||||||
(*this) << PK_HEX_TABLE[low];
|
(*this) << PK_HEX_TABLE[low];
|
||||||
@ -496,7 +487,7 @@ void SStream::write_hex(void* p) {
|
|||||||
for(int i = sizeof(void*) - 1; i >= 0; i--) {
|
for(int i = sizeof(void*) - 1; i >= 0; i--) {
|
||||||
unsigned char cpnt = (p_t >> (i * 8)) & 0xff;
|
unsigned char cpnt = (p_t >> (i * 8)) & 0xff;
|
||||||
write_hex(cpnt, non_zero);
|
write_hex(cpnt, non_zero);
|
||||||
if(cpnt != 0) { non_zero = false; }
|
if(cpnt != 0) non_zero = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,7 +505,7 @@ void SStream::write_hex(i64 val) {
|
|||||||
for(int i = 56; i >= 0; i -= 8) {
|
for(int i = 56; i >= 0; i -= 8) {
|
||||||
unsigned char cpnt = (val >> i) & 0xff;
|
unsigned char cpnt = (val >> i) & 0xff;
|
||||||
write_hex(cpnt, non_zero);
|
write_hex(cpnt, non_zero);
|
||||||
if(cpnt != 0) { non_zero = false; }
|
if(cpnt != 0) non_zero = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ PrattRule Compiler::rules[kTokenCount];
|
|||||||
|
|
||||||
NameScope Compiler::name_scope() const {
|
NameScope Compiler::name_scope() const {
|
||||||
auto s = contexts.size() > 1 ? NAME_LOCAL : NAME_GLOBAL;
|
auto s = contexts.size() > 1 ? NAME_LOCAL : NAME_GLOBAL;
|
||||||
if(unknown_global_scope && s == NAME_GLOBAL) { s = NAME_GLOBAL_UNKNOWN; }
|
if(unknown_global_scope && s == NAME_GLOBAL) s = NAME_GLOBAL_UNKNOWN;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,9 +38,8 @@ void Compiler::pop_context() {
|
|||||||
ctx()->emit_(OP_RETURN_VALUE, 1, BC_KEEPLINE, true);
|
ctx()->emit_(OP_RETURN_VALUE, 1, BC_KEEPLINE, true);
|
||||||
// find the last valid token
|
// find the last valid token
|
||||||
int j = i - 1;
|
int j = i - 1;
|
||||||
while(tokens[j].type == TK("@eol") || tokens[j].type == TK("@dedent") || tokens[j].type == TK("@eof")) {
|
while(tokens[j].type == TK("@eol") || tokens[j].type == TK("@dedent") || tokens[j].type == TK("@eof"))
|
||||||
j--;
|
j--;
|
||||||
}
|
|
||||||
ctx()->co->end_line = tokens[j].line;
|
ctx()->co->end_line = tokens[j].line;
|
||||||
|
|
||||||
// some check here
|
// some check here
|
||||||
@ -73,9 +72,9 @@ void Compiler::pop_context() {
|
|||||||
}
|
}
|
||||||
if(func->type == FuncType::UNSET) {
|
if(func->type == FuncType::UNSET) {
|
||||||
bool is_simple = true;
|
bool is_simple = true;
|
||||||
if(func->kwargs.size() > 0) { is_simple = false; }
|
if(func->kwargs.size() > 0) is_simple = false;
|
||||||
if(func->starred_arg >= 0) { is_simple = false; }
|
if(func->starred_arg >= 0) is_simple = false;
|
||||||
if(func->starred_kwarg >= 0) { is_simple = false; }
|
if(func->starred_kwarg >= 0) is_simple = false;
|
||||||
|
|
||||||
if(is_simple) {
|
if(is_simple) {
|
||||||
func->type = FuncType::SIMPLE;
|
func->type = FuncType::SIMPLE;
|
||||||
@ -85,10 +84,9 @@ void Compiler::pop_context() {
|
|||||||
Bytecode bc = func->code->codes[0];
|
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; }
|
if(is_empty) func->type = FuncType::EMPTY;
|
||||||
} else {
|
} else
|
||||||
func->type = FuncType::NORMAL;
|
func->type = FuncType::NORMAL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(func->type != FuncType::UNSET);
|
assert(func->type != FuncType::UNSET);
|
||||||
@ -98,7 +96,7 @@ void Compiler::pop_context() {
|
|||||||
|
|
||||||
void Compiler::init_pratt_rules() {
|
void Compiler::init_pratt_rules() {
|
||||||
static bool initialized = false;
|
static bool initialized = false;
|
||||||
if(initialized) { return; }
|
if(initialized) return;
|
||||||
initialized = true;
|
initialized = true;
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@ -158,7 +156,7 @@ void Compiler::init_pratt_rules() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Compiler::match(TokenIndex expected) {
|
bool Compiler::match(TokenIndex expected) {
|
||||||
if(curr().type != expected) { return false; }
|
if(curr().type != expected) return false;
|
||||||
advance();
|
advance();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -172,9 +170,8 @@ bool Compiler::match_newlines_repl() { return match_newlines(mode() == REPL_MODE
|
|||||||
bool Compiler::match_newlines(bool repl_throw) {
|
bool Compiler::match_newlines(bool repl_throw) {
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
if(curr().type == TK("@eol")) {
|
if(curr().type == TK("@eol")) {
|
||||||
while(curr().type == TK("@eol")) {
|
while(curr().type == TK("@eol"))
|
||||||
advance();
|
advance();
|
||||||
}
|
|
||||||
consumed = true;
|
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); }
|
||||||
@ -186,29 +183,29 @@ bool Compiler::match_end_stmt() {
|
|||||||
match_newlines();
|
match_newlines();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(match_newlines() || curr().type == TK("@eof")) { return true; }
|
if(match_newlines() || curr().type == TK("@eof")) return true;
|
||||||
if(curr().type == TK("@dedent")) { return true; }
|
if(curr().type == TK("@dedent")) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::consume_end_stmt() {
|
void Compiler::consume_end_stmt() {
|
||||||
if(!match_end_stmt()) { SyntaxError("expected statement end"); }
|
if(!match_end_stmt()) SyntaxError("expected statement end");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::EXPR() { parse_expression(PREC_LOWEST + 1); }
|
void Compiler::EXPR() { parse_expression(PREC_LOWEST + 1); }
|
||||||
|
|
||||||
void Compiler::EXPR_TUPLE(bool allow_slice) {
|
void Compiler::EXPR_TUPLE(bool allow_slice) {
|
||||||
parse_expression(PREC_LOWEST + 1, allow_slice);
|
parse_expression(PREC_LOWEST + 1, allow_slice);
|
||||||
if(!match(TK(","))) { return; }
|
if(!match(TK(","))) return;
|
||||||
// tuple expression
|
// tuple expression
|
||||||
Expr_vector items;
|
Expr_vector items;
|
||||||
items.push_back(ctx()->s_expr.popx());
|
items.push_back(ctx()->s_expr.popx());
|
||||||
do {
|
do {
|
||||||
if(curr().brackets_level) { match_newlines_repl(); }
|
if(curr().brackets_level) match_newlines_repl();
|
||||||
if(!is_expression(allow_slice)) { break; }
|
if(!is_expression(allow_slice)) break;
|
||||||
parse_expression(PREC_LOWEST + 1, allow_slice);
|
parse_expression(PREC_LOWEST + 1, allow_slice);
|
||||||
items.push_back(ctx()->s_expr.popx());
|
items.push_back(ctx()->s_expr.popx());
|
||||||
if(curr().brackets_level) { match_newlines_repl(); }
|
if(curr().brackets_level) match_newlines_repl();
|
||||||
} while(match(TK(",")));
|
} while(match(TK(",")));
|
||||||
ctx()->s_expr.push(make_expr<TupleExpr>(std::move(items)));
|
ctx()->s_expr.push(make_expr<TupleExpr>(std::move(items)));
|
||||||
}
|
}
|
||||||
@ -220,7 +217,7 @@ Expr_ Compiler::EXPR_VARS() {
|
|||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
items.push_back(make_expr<NameExpr>(prev().str(), name_scope()));
|
items.push_back(make_expr<NameExpr>(prev().str(), name_scope()));
|
||||||
} while(match(TK(",")));
|
} while(match(TK(",")));
|
||||||
if(items.size() == 1) { return std::move(items[0]); }
|
if(items.size() == 1) return std::move(items[0]);
|
||||||
return make_expr<TupleExpr>(std::move(items));
|
return make_expr<TupleExpr>(std::move(items));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,7 +306,7 @@ void Compiler::exprGroup() {
|
|||||||
EXPR_TUPLE(); // () is just for change precedence
|
EXPR_TUPLE(); // () is just for change precedence
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
consume(TK(")"));
|
consume(TK(")"));
|
||||||
if(ctx()->s_expr.top()->is_tuple()) { return; }
|
if(ctx()->s_expr.top()->is_tuple()) return;
|
||||||
Expr_ g = make_expr<GroupedExpr>(ctx()->s_expr.popx());
|
Expr_ g = make_expr<GroupedExpr>(ctx()->s_expr.popx());
|
||||||
ctx()->s_expr.push(std::move(g));
|
ctx()->s_expr.push(std::move(g));
|
||||||
}
|
}
|
||||||
@ -334,7 +331,7 @@ void Compiler::exprList() {
|
|||||||
Expr_vector items;
|
Expr_vector items;
|
||||||
do {
|
do {
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
if(curr().type == TK("]")) { break; }
|
if(curr().type == TK("]")) break;
|
||||||
EXPR();
|
EXPR();
|
||||||
items.push_back(ctx()->s_expr.popx());
|
items.push_back(ctx()->s_expr.popx());
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
@ -356,7 +353,7 @@ void Compiler::exprMap() {
|
|||||||
Expr_vector items;
|
Expr_vector items;
|
||||||
do {
|
do {
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
if(curr().type == TK("}")) { break; }
|
if(curr().type == TK("}")) break;
|
||||||
EXPR();
|
EXPR();
|
||||||
int star_level = ctx()->s_expr.top()->star_level();
|
int star_level = ctx()->s_expr.top()->star_level();
|
||||||
if(star_level == 2 || curr().type == TK(":")) { parsing_dict = true; }
|
if(star_level == 2 || curr().type == TK(":")) { parsing_dict = true; }
|
||||||
@ -377,11 +374,10 @@ void Compiler::exprMap() {
|
|||||||
}
|
}
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
if(items.size() == 1 && match(TK("for"))) {
|
if(items.size() == 1 && match(TK("for"))) {
|
||||||
if(parsing_dict) {
|
if(parsing_dict)
|
||||||
consume_comp(make_expr<DictCompExpr>(), std::move(items[0]));
|
consume_comp(make_expr<DictCompExpr>(), std::move(items[0]));
|
||||||
} else {
|
else
|
||||||
consume_comp(make_expr<SetCompExpr>(), std::move(items[0]));
|
consume_comp(make_expr<SetCompExpr>(), std::move(items[0]));
|
||||||
}
|
|
||||||
consume(TK("}"));
|
consume(TK("}"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -402,7 +398,7 @@ void Compiler::exprCall() {
|
|||||||
e->callable = ctx()->s_expr.popx();
|
e->callable = ctx()->s_expr.popx();
|
||||||
do {
|
do {
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
if(curr().type == TK(")")) { break; }
|
if(curr().type == TK(")")) break;
|
||||||
if(curr().type == TK("@id") && next().type == TK("=")) {
|
if(curr().type == TK("@id") && next().type == TK("=")) {
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
Str key = prev().str();
|
Str key = prev().str();
|
||||||
@ -416,15 +412,15 @@ void Compiler::exprCall() {
|
|||||||
e->kwargs.push_back({"**", ctx()->s_expr.popx()});
|
e->kwargs.push_back({"**", ctx()->s_expr.popx()});
|
||||||
} else {
|
} else {
|
||||||
// positional argument
|
// positional argument
|
||||||
if(!e->kwargs.empty()) { SyntaxError("positional argument follows keyword argument"); }
|
if(!e->kwargs.empty()) SyntaxError("positional argument follows keyword argument");
|
||||||
e->args.push_back(ctx()->s_expr.popx());
|
e->args.push_back(ctx()->s_expr.popx());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match_newlines_repl();
|
match_newlines_repl();
|
||||||
} while(match(TK(",")));
|
} while(match(TK(",")));
|
||||||
consume(TK(")"));
|
consume(TK(")"));
|
||||||
if(e->args.size() > 32767) { SyntaxError("too many positional arguments"); }
|
if(e->args.size() > 32767) SyntaxError("too many positional arguments");
|
||||||
if(e->kwargs.size() > 32767) { SyntaxError("too many keyword arguments"); }
|
if(e->kwargs.size() > 32767) SyntaxError("too many keyword arguments");
|
||||||
ctx()->s_expr.push(std::move(e));
|
ctx()->s_expr.push(std::move(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,13 +487,13 @@ void Compiler::exprSubscr() {
|
|||||||
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)()) {
|
void Compiler::compile_block_body(void (Compiler::*callback)()) {
|
||||||
if(callback == nullptr) { callback = &Compiler::compile_stmt; }
|
if(callback == nullptr) callback = &Compiler::compile_stmt;
|
||||||
consume(TK(":"));
|
consume(TK(":"));
|
||||||
if(curr().type != TK("@eol") && curr().type != TK("@eof")) {
|
if(curr().type != TK("@eol") && curr().type != TK("@eof")) {
|
||||||
while(true) {
|
while(true) {
|
||||||
compile_stmt();
|
compile_stmt();
|
||||||
bool possible = curr().type != TK("@eol") && curr().type != TK("@eof");
|
bool possible = curr().type != TK("@eol") && curr().type != TK("@eof");
|
||||||
if(prev().type != TK(";") || !possible) { break; }
|
if(prev().type != TK(";") || !possible) break;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -548,9 +544,8 @@ void Compiler::compile_from_import() {
|
|||||||
}
|
}
|
||||||
__EAT_DOTS_END:
|
__EAT_DOTS_END:
|
||||||
SStream ss;
|
SStream ss;
|
||||||
for(int i = 0; i < dots; i++) {
|
for(int i = 0; i < dots; i++)
|
||||||
ss << '.';
|
ss << '.';
|
||||||
}
|
|
||||||
|
|
||||||
if(dots > 0) {
|
if(dots > 0) {
|
||||||
// @id is optional if dots > 0
|
// @id is optional if dots > 0
|
||||||
@ -575,7 +570,7 @@ __EAT_DOTS_END:
|
|||||||
consume(TK("import"));
|
consume(TK("import"));
|
||||||
|
|
||||||
if(match(TK("*"))) {
|
if(match(TK("*"))) {
|
||||||
if(name_scope() != NAME_GLOBAL) { SyntaxError("from <module> import * can only be used in global scope"); }
|
if(name_scope() != NAME_GLOBAL) SyntaxError("from <module> import * can only be used in global scope");
|
||||||
// pop the module and import __all__
|
// pop the module and import __all__
|
||||||
ctx()->emit_(OP_POP_IMPORT_STAR, BC_NOARG, prev().line);
|
ctx()->emit_(OP_POP_IMPORT_STAR, BC_NOARG, prev().line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
@ -663,9 +658,7 @@ void Compiler::compile_for_loop() {
|
|||||||
CodeBlock* block = ctx()->enter_block(CodeBlockType::FOR_LOOP);
|
CodeBlock* block = ctx()->enter_block(CodeBlockType::FOR_LOOP);
|
||||||
int for_codei = ctx()->emit_(OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE);
|
int for_codei = ctx()->emit_(OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE);
|
||||||
bool ok = vars->emit_store(ctx());
|
bool ok = vars->emit_store(ctx());
|
||||||
if(!ok) {
|
if(!ok) SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind
|
||||||
SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind
|
|
||||||
}
|
|
||||||
ctx()->try_merge_for_iter_store(for_codei);
|
ctx()->try_merge_for_iter_store(for_codei);
|
||||||
compile_block_body();
|
compile_block_body();
|
||||||
ctx()->emit_(OP_LOOP_CONTINUE, ctx()->get_loop(), BC_KEEPLINE, true);
|
ctx()->emit_(OP_LOOP_CONTINUE, ctx()->get_loop(), BC_KEEPLINE, true);
|
||||||
@ -732,9 +725,8 @@ void Compiler::compile_try_except() {
|
|||||||
ctx()->emit_(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE);
|
||||||
|
|
||||||
// no exception or no match, jump to the end
|
// no exception or no match, jump to the end
|
||||||
for(int patch: patches) {
|
for(int patch: patches)
|
||||||
ctx()->patch_jump(patch);
|
ctx()->patch_jump(patch);
|
||||||
}
|
|
||||||
if(finally_entry != -1) {
|
if(finally_entry != -1) {
|
||||||
i64 target = ctx()->co->codes.size() + 2;
|
i64 target = ctx()->co->codes.size() + 2;
|
||||||
ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
|
ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
|
||||||
@ -748,7 +740,7 @@ void Compiler::compile_decorated() {
|
|||||||
do {
|
do {
|
||||||
EXPR();
|
EXPR();
|
||||||
decorators.push_back(ctx()->s_expr.popx());
|
decorators.push_back(ctx()->s_expr.popx());
|
||||||
if(!match_newlines_repl()) { SyntaxError(); }
|
if(!match_newlines_repl()) SyntaxError();
|
||||||
} while(match(TK("@")));
|
} while(match(TK("@")));
|
||||||
|
|
||||||
if(match(TK("class"))) {
|
if(match(TK("class"))) {
|
||||||
@ -773,8 +765,8 @@ bool Compiler::try_compile_assignment() {
|
|||||||
case TK("|="):
|
case TK("|="):
|
||||||
case TK("^="): {
|
case TK("^="): {
|
||||||
Expr* lhs_p = ctx()->s_expr.top().get();
|
Expr* lhs_p = ctx()->s_expr.top().get();
|
||||||
if(lhs_p->is_starred()) { SyntaxError(); }
|
if(lhs_p->is_starred()) SyntaxError();
|
||||||
if(ctx()->is_compiling_class) { SyntaxError("can't use inplace operator in class definition"); }
|
if(ctx()->is_compiling_class) SyntaxError("can't use inplace operator in class definition");
|
||||||
advance();
|
advance();
|
||||||
// a[x] += 1; a and x should be evaluated only once
|
// a[x] += 1; a and x should be evaluated only once
|
||||||
// a.x += 1; a should be evaluated only once
|
// a.x += 1; a should be evaluated only once
|
||||||
@ -783,10 +775,10 @@ bool Compiler::try_compile_assignment() {
|
|||||||
e->lhs = ctx()->s_expr.popx();
|
e->lhs = ctx()->s_expr.popx();
|
||||||
EXPR_TUPLE();
|
EXPR_TUPLE();
|
||||||
e->rhs = ctx()->s_expr.popx();
|
e->rhs = ctx()->s_expr.popx();
|
||||||
if(e->rhs->is_starred()) { SyntaxError(); }
|
if(e->rhs->is_starred()) SyntaxError();
|
||||||
e->emit_(ctx());
|
e->emit_(ctx());
|
||||||
bool ok = lhs_p->emit_store_inplace(ctx());
|
bool ok = lhs_p->emit_store_inplace(ctx());
|
||||||
if(!ok) { SyntaxError(); }
|
if(!ok) SyntaxError();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case TK("="): {
|
case TK("="): {
|
||||||
@ -798,14 +790,13 @@ bool Compiler::try_compile_assignment() {
|
|||||||
// stack size is n+1
|
// stack size is n+1
|
||||||
Expr_ val = ctx()->s_expr.popx();
|
Expr_ val = ctx()->s_expr.popx();
|
||||||
val->emit_(ctx());
|
val->emit_(ctx());
|
||||||
for(int j = 1; j < n; j++) {
|
for(int j = 1; j < n; j++)
|
||||||
ctx()->emit_(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||||
}
|
|
||||||
for(int j = 0; j < n; j++) {
|
for(int j = 0; j < n; j++) {
|
||||||
auto e = ctx()->s_expr.popx();
|
auto e = ctx()->s_expr.popx();
|
||||||
if(e->is_starred()) { SyntaxError(); }
|
if(e->is_starred()) SyntaxError();
|
||||||
bool ok = e->emit_store(ctx());
|
bool ok = e->emit_store(ctx());
|
||||||
if(!ok) { SyntaxError(); }
|
if(!ok) SyntaxError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -823,24 +814,24 @@ void Compiler::compile_stmt() {
|
|||||||
int curr_loop_block = ctx()->get_loop();
|
int curr_loop_block = ctx()->get_loop();
|
||||||
switch(prev().type) {
|
switch(prev().type) {
|
||||||
case TK("break"):
|
case TK("break"):
|
||||||
if(curr_loop_block < 0) { SyntaxError("'break' outside loop"); }
|
if(curr_loop_block < 0) SyntaxError("'break' outside loop");
|
||||||
ctx()->emit_(OP_LOOP_BREAK, curr_loop_block, kw_line);
|
ctx()->emit_(OP_LOOP_BREAK, curr_loop_block, kw_line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
case TK("continue"):
|
case TK("continue"):
|
||||||
if(curr_loop_block < 0) { SyntaxError("'continue' not properly in loop"); }
|
if(curr_loop_block < 0) SyntaxError("'continue' not properly in loop");
|
||||||
ctx()->emit_(OP_LOOP_CONTINUE, curr_loop_block, kw_line);
|
ctx()->emit_(OP_LOOP_CONTINUE, curr_loop_block, kw_line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
case TK("yield"):
|
case TK("yield"):
|
||||||
if(contexts.size() <= 1) { SyntaxError("'yield' outside function"); }
|
if(contexts.size() <= 1) SyntaxError("'yield' outside function");
|
||||||
EXPR_TUPLE();
|
EXPR_TUPLE();
|
||||||
ctx()->emit_expr();
|
ctx()->emit_expr();
|
||||||
ctx()->emit_(OP_YIELD_VALUE, BC_NOARG, kw_line);
|
ctx()->emit_(OP_YIELD_VALUE, BC_NOARG, kw_line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
case TK("yield from"):
|
case TK("yield from"):
|
||||||
if(contexts.size() <= 1) { SyntaxError("'yield from' outside function"); }
|
if(contexts.size() <= 1) SyntaxError("'yield from' outside function");
|
||||||
EXPR_TUPLE();
|
EXPR_TUPLE();
|
||||||
ctx()->emit_expr();
|
ctx()->emit_expr();
|
||||||
|
|
||||||
@ -852,7 +843,7 @@ void Compiler::compile_stmt() {
|
|||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
case TK("return"):
|
case TK("return"):
|
||||||
if(contexts.size() <= 1) { SyntaxError("'return' outside function"); }
|
if(contexts.size() <= 1) SyntaxError("'return' outside function");
|
||||||
if(match_end_stmt()) {
|
if(match_end_stmt()) {
|
||||||
ctx()->emit_(OP_RETURN_VALUE, 1, kw_line);
|
ctx()->emit_(OP_RETURN_VALUE, 1, kw_line);
|
||||||
} else {
|
} else {
|
||||||
@ -878,7 +869,7 @@ void Compiler::compile_stmt() {
|
|||||||
StrName name(prev().sv());
|
StrName name(prev().sv());
|
||||||
NameScope scope = name_scope();
|
NameScope scope = name_scope();
|
||||||
bool is_global = ctx()->global_names.contains(name.sv());
|
bool is_global = ctx()->global_names.contains(name.sv());
|
||||||
if(is_global) { scope = NAME_GLOBAL; }
|
if(is_global) scope = NAME_GLOBAL;
|
||||||
switch(scope) {
|
switch(scope) {
|
||||||
case NAME_LOCAL: ctx()->emit_(OP_INC_FAST, ctx()->add_varname(name), 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;
|
case NAME_GLOBAL: ctx()->emit_(OP_INC_GLOBAL, name.index, prev().line); break;
|
||||||
@ -930,7 +921,7 @@ void Compiler::compile_stmt() {
|
|||||||
EXPR_TUPLE();
|
EXPR_TUPLE();
|
||||||
Expr_ e = ctx()->s_expr.popx();
|
Expr_ e = ctx()->s_expr.popx();
|
||||||
bool ok = e->emit_del(ctx());
|
bool ok = e->emit_del(ctx());
|
||||||
if(!ok) { SyntaxError(); }
|
if(!ok) SyntaxError();
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
} break;
|
} break;
|
||||||
case TK("with"): {
|
case TK("with"): {
|
||||||
@ -946,7 +937,7 @@ void Compiler::compile_stmt() {
|
|||||||
// [ <expr> <expr>.__enter__() ]
|
// [ <expr> <expr>.__enter__() ]
|
||||||
if(as_name != nullptr) {
|
if(as_name != nullptr) {
|
||||||
bool ok = as_name->emit_store(ctx());
|
bool ok = as_name->emit_store(ctx());
|
||||||
if(!ok) { SyntaxError(); }
|
if(!ok) SyntaxError();
|
||||||
} else {
|
} else {
|
||||||
ctx()->emit_(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||||
}
|
}
|
||||||
@ -957,15 +948,15 @@ void Compiler::compile_stmt() {
|
|||||||
/*************************************************/
|
/*************************************************/
|
||||||
case TK("=="): {
|
case TK("=="): {
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
if(mode() != EXEC_MODE) { SyntaxError("'label' is only available in EXEC_MODE"); }
|
if(mode() != EXEC_MODE) SyntaxError("'label' is only available in EXEC_MODE");
|
||||||
bool ok = ctx()->add_label(prev().str());
|
bool ok = ctx()->add_label(prev().str());
|
||||||
consume(TK("=="));
|
consume(TK("=="));
|
||||||
if(!ok) { SyntaxError("label " + prev().str().escape() + " already exists"); }
|
if(!ok) SyntaxError("label " + prev().str().escape() + " already exists");
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
} break;
|
} break;
|
||||||
case TK("->"):
|
case TK("->"):
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
if(mode() != EXEC_MODE) { SyntaxError("'goto' is only available in EXEC_MODE"); }
|
if(mode() != EXEC_MODE) SyntaxError("'goto' is only available in EXEC_MODE");
|
||||||
ctx()->emit_(OP_GOTO, StrName(prev().sv()).index, prev().line);
|
ctx()->emit_(OP_GOTO, StrName(prev().sv()).index, prev().line);
|
||||||
consume_end_stmt();
|
consume_end_stmt();
|
||||||
break;
|
break;
|
||||||
@ -1060,15 +1051,14 @@ void Compiler::compile_class(const Expr_vector& decorators) {
|
|||||||
void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) {
|
void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) {
|
||||||
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
|
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
|
||||||
do {
|
do {
|
||||||
if(state > 3) { SyntaxError(); }
|
if(state > 3) SyntaxError();
|
||||||
if(state == 3) { SyntaxError("**kwargs should be the last argument"); }
|
if(state == 3) SyntaxError("**kwargs should be the last argument");
|
||||||
match_newlines();
|
match_newlines();
|
||||||
if(match(TK("*"))) {
|
if(match(TK("*"))) {
|
||||||
if(state < 1) {
|
if(state < 1)
|
||||||
state = 1;
|
state = 1;
|
||||||
} else {
|
else
|
||||||
SyntaxError("*args should be placed before **kwargs");
|
SyntaxError("*args should be placed before **kwargs");
|
||||||
}
|
|
||||||
} else if(match(TK("**"))) {
|
} else if(match(TK("**"))) {
|
||||||
state = 3;
|
state = 3;
|
||||||
}
|
}
|
||||||
@ -1090,8 +1080,8 @@ void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// eat type hints
|
// eat type hints
|
||||||
if(enable_type_hints && match(TK(":"))) { consume_type_hints(); }
|
if(enable_type_hints && match(TK(":"))) consume_type_hints();
|
||||||
if(state == 0 && curr().type == TK("=")) { state = 2; }
|
if(state == 0 && curr().type == TK("=")) state = 2;
|
||||||
int index = ctx()->add_varname(name);
|
int index = ctx()->add_varname(name);
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case 0: decl->args.push_back(index); break;
|
case 0: decl->args.push_back(index); break;
|
||||||
@ -1122,7 +1112,7 @@ void Compiler::compile_function(const Expr_vector& decorators) {
|
|||||||
_compile_f_args(decl, true);
|
_compile_f_args(decl, true);
|
||||||
consume(TK(")"));
|
consume(TK(")"));
|
||||||
}
|
}
|
||||||
if(match(TK("->"))) { consume_type_hints(); }
|
if(match(TK("->"))) consume_type_hints();
|
||||||
compile_block_body();
|
compile_block_body();
|
||||||
pop_context();
|
pop_context();
|
||||||
|
|
||||||
@ -1176,9 +1166,9 @@ PyVar Compiler::read_literal() {
|
|||||||
List cpnts;
|
List cpnts;
|
||||||
while(true) {
|
while(true) {
|
||||||
cpnts.push_back(read_literal());
|
cpnts.push_back(read_literal());
|
||||||
if(curr().type == TK(")")) { break; }
|
if(curr().type == TK(")")) break;
|
||||||
consume(TK(","));
|
consume(TK(","));
|
||||||
if(curr().type == TK(")")) { break; }
|
if(curr().type == TK(")")) break;
|
||||||
}
|
}
|
||||||
consume(TK(")"));
|
consume(TK(")"));
|
||||||
return VAR(cpnts.to_tuple());
|
return VAR(cpnts.to_tuple());
|
||||||
@ -1208,9 +1198,8 @@ Str Compiler::precompile() {
|
|||||||
if(it == token_indices.end()) {
|
if(it == token_indices.end()) {
|
||||||
token_indices[token.sv()] = 0;
|
token_indices[token.sv()] = 0;
|
||||||
// assert no '\n' in token.sv()
|
// assert no '\n' in token.sv()
|
||||||
for(char c: token.sv()) {
|
for(char c: token.sv())
|
||||||
assert(c != '\n');
|
assert(c != '\n');
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1226,16 +1215,14 @@ Str Compiler::precompile() {
|
|||||||
const Token& token = tokens[i];
|
const Token& token = tokens[i];
|
||||||
ss << (int)token.type << ',';
|
ss << (int)token.type << ',';
|
||||||
if(is_raw_string_used(token.type)) { ss << token_indices[token.sv()] << ','; }
|
if(is_raw_string_used(token.type)) { ss << token_indices[token.sv()] << ','; }
|
||||||
if(i > 0 && tokens[i - 1].line == token.line) {
|
if(i > 0 && tokens[i - 1].line == token.line)
|
||||||
ss << ',';
|
ss << ',';
|
||||||
} else {
|
else
|
||||||
ss << token.line << ',';
|
ss << token.line << ',';
|
||||||
}
|
if(i > 0 && tokens[i - 1].brackets_level == token.brackets_level)
|
||||||
if(i > 0 && tokens[i - 1].brackets_level == token.brackets_level) {
|
|
||||||
ss << ',';
|
ss << ',';
|
||||||
} else {
|
else
|
||||||
ss << token.brackets_level << ',';
|
ss << token.brackets_level << ',';
|
||||||
}
|
|
||||||
// visit token value
|
// visit token value
|
||||||
std::visit(
|
std::visit(
|
||||||
[&ss](auto&& arg) {
|
[&ss](auto&& arg) {
|
||||||
@ -1246,9 +1233,8 @@ Str Compiler::precompile() {
|
|||||||
ss << 'F' << arg;
|
ss << 'F' << arg;
|
||||||
} else if constexpr(std::is_same_v<T, Str>) {
|
} else if constexpr(std::is_same_v<T, Str>) {
|
||||||
ss << 'S';
|
ss << 'S';
|
||||||
for(char c: arg) {
|
for(char c: arg)
|
||||||
ss.write_hex((unsigned char)c);
|
ss.write_hex((unsigned char)c);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ss << '\n';
|
ss << '\n';
|
||||||
},
|
},
|
||||||
@ -1334,7 +1320,7 @@ CodeObject_ Compiler::compile() {
|
|||||||
} else if(mode() == JSON_MODE) {
|
} else if(mode() == JSON_MODE) {
|
||||||
EXPR();
|
EXPR();
|
||||||
Expr_ e = ctx()->s_expr.popx();
|
Expr_ e = ctx()->s_expr.popx();
|
||||||
if(!e->is_json_object()) { SyntaxError("expect a JSON object, literal or array"); }
|
if(!e->is_json_object()) SyntaxError("expect a JSON object, literal or array");
|
||||||
consume(TK("@eof"));
|
consume(TK("@eof"));
|
||||||
e->emit_(ctx());
|
e->emit_(ctx());
|
||||||
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
||||||
@ -1360,9 +1346,8 @@ void Lexer::throw_err(StrName type, Str msg, int lineno, const char* cursor) {
|
|||||||
|
|
||||||
std::string_view TokenDeserializer::read_string(char c) {
|
std::string_view TokenDeserializer::read_string(char c) {
|
||||||
const char* start = curr;
|
const char* start = curr;
|
||||||
while(*curr != c) {
|
while(*curr != c)
|
||||||
curr++;
|
curr++;
|
||||||
}
|
|
||||||
std::string_view retval(start, curr - start);
|
std::string_view retval(start, curr - start);
|
||||||
curr++; // skip the delimiter
|
curr++; // skip the delimiter
|
||||||
return retval;
|
return retval;
|
||||||
@ -1373,21 +1358,19 @@ Str TokenDeserializer::read_string_from_hex(char c) {
|
|||||||
char* buffer = (char*)std::malloc(s.size() / 2 + 1);
|
char* buffer = (char*)std::malloc(s.size() / 2 + 1);
|
||||||
for(int i = 0; i < s.size(); i += 2) {
|
for(int i = 0; i < s.size(); i += 2) {
|
||||||
char c = 0;
|
char c = 0;
|
||||||
if(s[i] >= '0' && s[i] <= '9') {
|
if(s[i] >= '0' && s[i] <= '9')
|
||||||
c += s[i] - '0';
|
c += s[i] - '0';
|
||||||
} else if(s[i] >= 'a' && s[i] <= 'f') {
|
else if(s[i] >= 'a' && s[i] <= 'f')
|
||||||
c += s[i] - 'a' + 10;
|
c += s[i] - 'a' + 10;
|
||||||
} else {
|
else
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
|
||||||
c <<= 4;
|
c <<= 4;
|
||||||
if(s[i + 1] >= '0' && s[i + 1] <= '9') {
|
if(s[i + 1] >= '0' && s[i + 1] <= '9')
|
||||||
c += s[i + 1] - '0';
|
c += s[i + 1] - '0';
|
||||||
} else if(s[i + 1] >= 'a' && s[i + 1] <= 'f') {
|
else if(s[i + 1] >= 'a' && s[i + 1] <= 'f')
|
||||||
c += s[i + 1] - 'a' + 10;
|
c += s[i + 1] - 'a' + 10;
|
||||||
} else {
|
else
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
|
||||||
buffer[i / 2] = c;
|
buffer[i / 2] = c;
|
||||||
}
|
}
|
||||||
buffer[s.size() / 2] = 0;
|
buffer[s.size() / 2] = 0;
|
||||||
|
|||||||
@ -4,11 +4,10 @@
|
|||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
inline bool is_identifier(std::string_view s) {
|
inline bool is_identifier(std::string_view s) {
|
||||||
if(s.empty()) { return false; }
|
if(s.empty()) return false;
|
||||||
if(!isalpha(s[0]) && s[0] != '_') { return false; }
|
if(!isalpha(s[0]) && s[0] != '_') return false;
|
||||||
for(char c: s) {
|
for(char c: s)
|
||||||
if(!isalnum(c) && c != '_') { return false; }
|
if(!isalnum(c) && c != '_') return false;
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,8 +16,8 @@ inline bool is_small_int(i64 value) { return value >= INT16_MIN && value <= INT1
|
|||||||
int CodeEmitContext::get_loop() const {
|
int CodeEmitContext::get_loop() const {
|
||||||
int index = curr_iblock;
|
int index = curr_iblock;
|
||||||
while(index >= 0) {
|
while(index >= 0) {
|
||||||
if(co->blocks[index].type == CodeBlockType::FOR_LOOP) { break; }
|
if(co->blocks[index].type == CodeBlockType::FOR_LOOP) break;
|
||||||
if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) { break; }
|
if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) break;
|
||||||
index = co->blocks[index].parent;
|
index = co->blocks[index].parent;
|
||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
@ -53,11 +52,10 @@ int CodeEmitContext::emit_(Opcode opcode, uint16_t arg, int line, bool is_virtua
|
|||||||
co->lines.push_back(CodeObject::LineInfo{line, is_virtual, curr_iblock});
|
co->lines.push_back(CodeObject::LineInfo{line, is_virtual, curr_iblock});
|
||||||
int i = co->codes.size() - 1;
|
int i = co->codes.size() - 1;
|
||||||
if(line == BC_KEEPLINE) {
|
if(line == BC_KEEPLINE) {
|
||||||
if(i >= 1) {
|
if(i >= 1)
|
||||||
co->lines[i].lineno = co->lines[i - 1].lineno;
|
co->lines[i].lineno = co->lines[i - 1].lineno;
|
||||||
} else {
|
else
|
||||||
co->lines[i].lineno = 1;
|
co->lines[i].lineno = 1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@ -69,8 +67,8 @@ void CodeEmitContext::revert_last_emit_() {
|
|||||||
|
|
||||||
void CodeEmitContext::try_merge_for_iter_store(int i) {
|
void CodeEmitContext::try_merge_for_iter_store(int i) {
|
||||||
// [FOR_ITER, STORE_?, ]
|
// [FOR_ITER, STORE_?, ]
|
||||||
if(co->codes[i].op != OP_FOR_ITER) { return; }
|
if(co->codes[i].op != OP_FOR_ITER) return;
|
||||||
if(co->codes.size() - i != 2) { return; }
|
if(co->codes.size() - i != 2) return;
|
||||||
uint16_t arg = co->codes[i + 1].arg;
|
uint16_t arg = co->codes[i + 1].arg;
|
||||||
if(co->codes[i + 1].op == OP_STORE_FAST) {
|
if(co->codes[i + 1].op == OP_STORE_FAST) {
|
||||||
revert_last_emit_();
|
revert_last_emit_();
|
||||||
@ -100,7 +98,7 @@ void CodeEmitContext::patch_jump(int index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CodeEmitContext::add_label(StrName name) {
|
bool CodeEmitContext::add_label(StrName name) {
|
||||||
if(co->labels.contains(name)) { return false; }
|
if(co->labels.contains(name)) return false;
|
||||||
co->labels.set(name, co->codes.size());
|
co->labels.set(name, co->codes.size());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -108,7 +106,7 @@ bool CodeEmitContext::add_label(StrName name) {
|
|||||||
int CodeEmitContext::add_varname(StrName name) {
|
int CodeEmitContext::add_varname(StrName name) {
|
||||||
// PK_MAX_CO_VARNAMES will be checked when pop_context(), not here
|
// PK_MAX_CO_VARNAMES will be checked when pop_context(), not here
|
||||||
int index = co->varnames_inv.try_get(name);
|
int index = co->varnames_inv.try_get(name);
|
||||||
if(index >= 0) { return index; }
|
if(index >= 0) return index;
|
||||||
co->varnames.push_back(name);
|
co->varnames.push_back(name);
|
||||||
co->nlocals++;
|
co->nlocals++;
|
||||||
index = co->varnames.size() - 1;
|
index = co->varnames.size() - 1;
|
||||||
@ -170,7 +168,7 @@ void NameExpr::emit_(CodeEmitContext* ctx) {
|
|||||||
// exec()/eval() won't work with OP_LOAD_ATTR_GLOBAL in class body
|
// exec()/eval() won't work with OP_LOAD_ATTR_GLOBAL in class body
|
||||||
} else {
|
} else {
|
||||||
// we cannot determine the scope when calling exec()/eval()
|
// we cannot determine the scope when calling exec()/eval()
|
||||||
if(scope == NAME_GLOBAL_UNKNOWN) { op = OP_LOAD_NAME; }
|
if(scope == NAME_GLOBAL_UNKNOWN) op = OP_LOAD_NAME;
|
||||||
}
|
}
|
||||||
ctx->emit_(op, StrName(name).index, line);
|
ctx->emit_(op, StrName(name).index, line);
|
||||||
}
|
}
|
||||||
@ -206,7 +204,7 @@ void StarredExpr::emit_(CodeEmitContext* ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool StarredExpr::emit_store(CodeEmitContext* ctx) {
|
bool StarredExpr::emit_store(CodeEmitContext* ctx) {
|
||||||
if(level != 1) { return false; }
|
if(level != 1) return false;
|
||||||
// simply proxy to child
|
// simply proxy to child
|
||||||
return child->emit_store(ctx);
|
return child->emit_store(ctx);
|
||||||
}
|
}
|
||||||
@ -333,12 +331,11 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
|
|||||||
// items may contain StarredExpr, we should check it
|
// items may contain StarredExpr, we should check it
|
||||||
int starred_i = -1;
|
int starred_i = -1;
|
||||||
for(int i = 0; i < items.size(); i++) {
|
for(int i = 0; i < items.size(); i++) {
|
||||||
if(!items[i]->is_starred()) { continue; }
|
if(!items[i]->is_starred()) continue;
|
||||||
if(starred_i == -1) {
|
if(starred_i == -1)
|
||||||
starred_i = i;
|
starred_i = i;
|
||||||
} else {
|
else
|
||||||
return false; // multiple StarredExpr not allowed
|
return false; // multiple StarredExpr not allowed
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(starred_i == -1) {
|
if(starred_i == -1) {
|
||||||
@ -356,9 +353,9 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// starred assignment target must be in a tuple
|
// starred assignment target must be in a tuple
|
||||||
if(items.size() == 1) { return false; }
|
if(items.size() == 1) return false;
|
||||||
// starred assignment target must be the last one (differ from cpython)
|
// starred assignment target must be the last one (differ from cpython)
|
||||||
if(starred_i != items.size() - 1) { return false; }
|
if(starred_i != items.size() - 1) return false;
|
||||||
// a,*b = [1,2,3]
|
// a,*b = [1,2,3]
|
||||||
// stack is [1,2,3] -> [1,[2,3]]
|
// stack is [1,2,3] -> [1,[2,3]]
|
||||||
ctx->emit_(OP_UNPACK_EX, items.size() - 1, line);
|
ctx->emit_(OP_UNPACK_EX, items.size() - 1, line);
|
||||||
@ -366,7 +363,7 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
|
|||||||
// do reverse emit
|
// do reverse emit
|
||||||
for(int i = items.size() - 1; i >= 0; i--) {
|
for(int i = items.size() - 1; i >= 0; i--) {
|
||||||
bool ok = items[i]->emit_store(ctx);
|
bool ok = items[i]->emit_store(ctx);
|
||||||
if(!ok) { return false; }
|
if(!ok) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -374,7 +371,7 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
|
|||||||
bool TupleExpr::emit_del(CodeEmitContext* ctx) {
|
bool TupleExpr::emit_del(CodeEmitContext* ctx) {
|
||||||
for(auto& e: items) {
|
for(auto& e: items) {
|
||||||
bool ok = e->emit_del(ctx);
|
bool ok = e->emit_del(ctx);
|
||||||
if(!ok) { return false; }
|
if(!ok) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -475,12 +472,11 @@ void FStringExpr::emit_(CodeEmitContext* ctx) {
|
|||||||
Str spec = expr.substr(conon + 1);
|
Str spec = expr.substr(conon + 1);
|
||||||
// filter some invalid spec
|
// filter some invalid spec
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
for(char c: spec) {
|
for(char c: spec)
|
||||||
if(!is_fmt_valid_char(c)) {
|
if(!is_fmt_valid_char(c)) {
|
||||||
ok = false;
|
ok = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(ok) {
|
if(ok) {
|
||||||
_load_simple_expr(ctx, expr.substr(0, conon));
|
_load_simple_expr(ctx, expr.substr(0, conon));
|
||||||
ctx->emit_(OP_FORMAT_STRING, ctx->add_const_string(spec.sv()), line);
|
ctx->emit_(OP_FORMAT_STRING, ctx->add_const_string(spec.sv()), line);
|
||||||
@ -522,9 +518,8 @@ void FStringExpr::emit_(CodeEmitContext* ctx) {
|
|||||||
} else {
|
} else {
|
||||||
// literal
|
// literal
|
||||||
i = j;
|
i = j;
|
||||||
while(j < src.size && src[j] != '{' && src[j] != '}') {
|
while(j < src.size && src[j] != '{' && src[j] != '}')
|
||||||
j++;
|
j++;
|
||||||
}
|
|
||||||
Str literal = src.substr(i, j - i);
|
Str literal = src.substr(i, j - i);
|
||||||
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(literal.sv()), line);
|
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(literal.sv()), line);
|
||||||
count++;
|
count++;
|
||||||
@ -631,12 +626,10 @@ bool AttribExpr::emit_store_inplace(CodeEmitContext* ctx) {
|
|||||||
void CallExpr::emit_(CodeEmitContext* ctx) {
|
void CallExpr::emit_(CodeEmitContext* ctx) {
|
||||||
bool vargs = false;
|
bool vargs = false;
|
||||||
bool vkwargs = false;
|
bool vkwargs = false;
|
||||||
for(auto& arg: args) {
|
for(auto& arg: args)
|
||||||
if(arg->is_starred()) { vargs = true; }
|
if(arg->is_starred()) vargs = true;
|
||||||
}
|
for(auto& item: kwargs)
|
||||||
for(auto& item: kwargs) {
|
if(item.second->is_starred()) vkwargs = true;
|
||||||
if(item.second->is_starred()) { vkwargs = true; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// if callable is a AttrExpr, we should try to use `fast_call` instead of use `boundmethod` proxy
|
// if callable is a AttrExpr, we should try to use `fast_call` instead of use `boundmethod` proxy
|
||||||
if(callable->is_attrib()) {
|
if(callable->is_attrib()) {
|
||||||
@ -648,9 +641,8 @@ void CallExpr::emit_(CodeEmitContext* ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(vargs || vkwargs) {
|
if(vargs || vkwargs) {
|
||||||
for(auto& item: args) {
|
for(auto& item: args)
|
||||||
item->emit_(ctx);
|
item->emit_(ctx);
|
||||||
}
|
|
||||||
ctx->emit_(OP_BUILD_TUPLE_UNPACK, (uint16_t)args.size(), line);
|
ctx->emit_(OP_BUILD_TUPLE_UNPACK, (uint16_t)args.size(), line);
|
||||||
|
|
||||||
if(!kwargs.empty()) {
|
if(!kwargs.empty()) {
|
||||||
@ -673,9 +665,8 @@ void CallExpr::emit_(CodeEmitContext* ctx) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// vectorcall protocol
|
// vectorcall protocol
|
||||||
for(auto& item: args) {
|
for(auto& item: args)
|
||||||
item->emit_(ctx);
|
item->emit_(ctx);
|
||||||
}
|
|
||||||
for(auto& item: kwargs) {
|
for(auto& item: kwargs) {
|
||||||
i64 _val = StrName(item.first.sv()).index;
|
i64 _val = StrName(item.first.sv()).index;
|
||||||
ctx->emit_int(_val, line);
|
ctx->emit_int(_val, line);
|
||||||
@ -769,9 +760,8 @@ void BinaryExpr::emit_(CodeEmitContext* ctx) {
|
|||||||
default: assert(false);
|
default: assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i: jmps) {
|
for(int i: jmps)
|
||||||
ctx->patch_jump(i);
|
ctx->patch_jump(i);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TernaryExpr::emit_(CodeEmitContext* ctx) {
|
void TernaryExpr::emit_(CodeEmitContext* ctx) {
|
||||||
|
|||||||
@ -22,35 +22,32 @@ static bool is_possible_number_char(char c) {
|
|||||||
|
|
||||||
static bool is_unicode_Lo_char(uint32_t c) {
|
static bool is_unicode_Lo_char(uint32_t c) {
|
||||||
// open a hole for carrot
|
// open a hole for carrot
|
||||||
if(c == U'🥕') { return true; }
|
if(c == U'🥕') return true;
|
||||||
auto index = std::lower_bound(kLoRangeA, kLoRangeA + 476, c) - kLoRangeA;
|
auto index = std::lower_bound(kLoRangeA, kLoRangeA + 476, c) - kLoRangeA;
|
||||||
if(c == kLoRangeA[index]) { return true; }
|
if(c == kLoRangeA[index]) return true;
|
||||||
index -= 1;
|
index -= 1;
|
||||||
if(index < 0) { return false; }
|
if(index < 0) return false;
|
||||||
return c >= kLoRangeA[index] && c <= kLoRangeB[index];
|
return c >= kLoRangeA[index] && c <= kLoRangeB[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lexer::match_n_chars(int n, char c0) {
|
bool Lexer::match_n_chars(int n, char c0) {
|
||||||
const char* c = curr_char;
|
const char* c = curr_char;
|
||||||
for(int i = 0; i < n; i++) {
|
for(int i = 0; i < n; i++) {
|
||||||
if(*c == '\0') { return false; }
|
if(*c == '\0') return false;
|
||||||
if(*c != c0) { return false; }
|
if(*c != c0) return false;
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
for(int i = 0; i < n; i++) {
|
for(int i = 0; i < n; i++)
|
||||||
eatchar_include_newline();
|
eatchar_include_newline();
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lexer::match_string(const char* s) {
|
bool Lexer::match_string(const char* s) {
|
||||||
int s_len = strlen(s);
|
int s_len = strlen(s);
|
||||||
bool ok = strncmp(curr_char, s, s_len) == 0;
|
bool ok = strncmp(curr_char, s, s_len) == 0;
|
||||||
if(ok) {
|
if(ok)
|
||||||
for(int i = 0; i < s_len; i++) {
|
for(int i = 0; i < s_len; i++)
|
||||||
eatchar_include_newline();
|
eatchar_include_newline();
|
||||||
}
|
|
||||||
}
|
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,10 +64,10 @@ int Lexer::eat_spaces() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Lexer::eat_indentation() {
|
bool Lexer::eat_indentation() {
|
||||||
if(brackets_level > 0) { return true; }
|
if(brackets_level > 0) return true;
|
||||||
int spaces = eat_spaces();
|
int spaces = eat_spaces();
|
||||||
if(peekchar() == '#') { skip_line_comment(); }
|
if(peekchar() == '#') skip_line_comment();
|
||||||
if(peekchar() == '\0' || peekchar() == '\n') { return true; }
|
if(peekchar() == '\0' || peekchar() == '\n') return true;
|
||||||
// https://docs.python.org/3/reference/lexical_analysis.html#indentation
|
// https://docs.python.org/3/reference/lexical_analysis.html#indentation
|
||||||
if(spaces > indents.top()) {
|
if(spaces > indents.top()) {
|
||||||
indents.push(spaces);
|
indents.push(spaces);
|
||||||
@ -107,7 +104,7 @@ int Lexer::eat_name() {
|
|||||||
while(true) {
|
while(true) {
|
||||||
unsigned char c = peekchar();
|
unsigned char c = peekchar();
|
||||||
int u8bytes = utf8len(c, true);
|
int u8bytes = utf8len(c, true);
|
||||||
if(u8bytes == 0) { return 1; }
|
if(u8bytes == 0) return 1;
|
||||||
if(u8bytes == 1) {
|
if(u8bytes == 1) {
|
||||||
if(isalpha(c) || c == '_' || isdigit(c)) {
|
if(isalpha(c) || c == '_' || isdigit(c)) {
|
||||||
curr_char++;
|
curr_char++;
|
||||||
@ -118,31 +115,29 @@ int Lexer::eat_name() {
|
|||||||
}
|
}
|
||||||
// handle multibyte char
|
// handle multibyte char
|
||||||
Str u8str(curr_char, u8bytes);
|
Str u8str(curr_char, u8bytes);
|
||||||
if(u8str.size != u8bytes) { return 2; }
|
if(u8str.size != u8bytes) return 2;
|
||||||
uint32_t value = 0;
|
uint32_t value = 0;
|
||||||
for(int k = 0; k < u8bytes; k++) {
|
for(int k = 0; k < u8bytes; k++) {
|
||||||
uint8_t b = u8str[k];
|
uint8_t b = u8str[k];
|
||||||
if(k == 0) {
|
if(k == 0) {
|
||||||
if(u8bytes == 2) {
|
if(u8bytes == 2)
|
||||||
value = (b & 0b00011111) << 6;
|
value = (b & 0b00011111) << 6;
|
||||||
} else if(u8bytes == 3) {
|
else if(u8bytes == 3)
|
||||||
value = (b & 0b00001111) << 12;
|
value = (b & 0b00001111) << 12;
|
||||||
} else if(u8bytes == 4) {
|
else if(u8bytes == 4)
|
||||||
value = (b & 0b00000111) << 18;
|
value = (b & 0b00000111) << 18;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
value |= (b & 0b00111111) << (6 * (u8bytes - k - 1));
|
value |= (b & 0b00111111) << (6 * (u8bytes - k - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(is_unicode_Lo_char(value)) {
|
if(is_unicode_Lo_char(value))
|
||||||
curr_char += u8bytes;
|
curr_char += u8bytes;
|
||||||
} else {
|
else
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int length = (int)(curr_char - token_start);
|
int length = (int)(curr_char - token_start);
|
||||||
if(length == 0) { return 3; }
|
if(length == 0) return 3;
|
||||||
std::string_view name(token_start, length);
|
std::string_view name(token_start, length);
|
||||||
|
|
||||||
if(src->mode == JSON_MODE) {
|
if(src->mode == JSON_MODE) {
|
||||||
@ -169,13 +164,13 @@ int Lexer::eat_name() {
|
|||||||
void Lexer::skip_line_comment() {
|
void Lexer::skip_line_comment() {
|
||||||
char c;
|
char c;
|
||||||
while((c = peekchar()) != '\0') {
|
while((c = peekchar()) != '\0') {
|
||||||
if(c == '\n') { return; }
|
if(c == '\n') return;
|
||||||
eatchar();
|
eatchar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lexer::matchchar(char c) {
|
bool Lexer::matchchar(char c) {
|
||||||
if(peekchar() != c) { return false; }
|
if(peekchar() != c) return false;
|
||||||
eatchar_include_newline();
|
eatchar_include_newline();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -215,11 +210,10 @@ void Lexer::add_token(TokenIndex type, TokenValue value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Lexer::add_token_2(char c, TokenIndex one, TokenIndex two) {
|
void Lexer::add_token_2(char c, TokenIndex one, TokenIndex two) {
|
||||||
if(matchchar(c)) {
|
if(matchchar(c))
|
||||||
add_token(two);
|
add_token(two);
|
||||||
} else {
|
else
|
||||||
add_token(one);
|
add_token(one);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Str Lexer::eat_string_until(char quote, bool raw) {
|
Str Lexer::eat_string_until(char quote, bool raw) {
|
||||||
@ -239,9 +233,9 @@ Str Lexer::eat_string_until(char quote, bool raw) {
|
|||||||
SyntaxError("EOL while scanning string literal");
|
SyntaxError("EOL while scanning string literal");
|
||||||
}
|
}
|
||||||
if(c == '\n') {
|
if(c == '\n') {
|
||||||
if(!quote3) {
|
if(!quote3)
|
||||||
SyntaxError("EOL while scanning string literal");
|
SyntaxError("EOL while scanning string literal");
|
||||||
} else {
|
else {
|
||||||
buff.push_back(c);
|
buff.push_back(c);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -262,7 +256,7 @@ Str Lexer::eat_string_until(char quote, bool raw) {
|
|||||||
try {
|
try {
|
||||||
code = (char)std::stoi(hex, &parsed, 16);
|
code = (char)std::stoi(hex, &parsed, 16);
|
||||||
} catch(...) { SyntaxError("invalid hex char"); }
|
} catch(...) { SyntaxError("invalid hex char"); }
|
||||||
if(parsed != 2) { SyntaxError("invalid hex char"); }
|
if(parsed != 2) SyntaxError("invalid hex char");
|
||||||
buff.push_back(code);
|
buff.push_back(code);
|
||||||
} break;
|
} break;
|
||||||
default: SyntaxError("invalid escape char");
|
default: SyntaxError("invalid escape char");
|
||||||
@ -289,16 +283,14 @@ void Lexer::eat_string(char quote, StringType type) {
|
|||||||
|
|
||||||
void Lexer::eat_number() {
|
void Lexer::eat_number() {
|
||||||
const char* i = token_start;
|
const char* i = token_start;
|
||||||
while(is_possible_number_char(*i)) {
|
while(is_possible_number_char(*i))
|
||||||
i++;
|
i++;
|
||||||
}
|
|
||||||
|
|
||||||
bool is_scientific_notation = false;
|
bool is_scientific_notation = false;
|
||||||
if(*(i - 1) == 'e' && (*i == '+' || *i == '-')) {
|
if(*(i - 1) == 'e' && (*i == '+' || *i == '-')) {
|
||||||
i++;
|
i++;
|
||||||
while(isdigit(*i) || *i == 'j') {
|
while(isdigit(*i) || *i == 'j')
|
||||||
i++;
|
i++;
|
||||||
}
|
|
||||||
is_scientific_notation = true;
|
is_scientific_notation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,7 +355,7 @@ bool Lexer::lex_one_token() {
|
|||||||
// line continuation character
|
// line continuation character
|
||||||
char c = eatchar_include_newline();
|
char c = eatchar_include_newline();
|
||||||
if(c != '\n') {
|
if(c != '\n') {
|
||||||
if(src->mode == REPL_MODE && c == '\0') { throw NeedMoreLines(false); }
|
if(src->mode == REPL_MODE && c == '\0') throw NeedMoreLines(false);
|
||||||
SyntaxError("expected newline after line continuation character");
|
SyntaxError("expected newline after line continuation character");
|
||||||
}
|
}
|
||||||
eat_spaces();
|
eat_spaces();
|
||||||
@ -399,45 +391,41 @@ bool Lexer::lex_one_token() {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case '>': {
|
case '>': {
|
||||||
if(matchchar('=')) {
|
if(matchchar('='))
|
||||||
add_token(TK(">="));
|
add_token(TK(">="));
|
||||||
} else if(matchchar('>')) {
|
else if(matchchar('>'))
|
||||||
add_token_2('=', TK(">>"), TK(">>="));
|
add_token_2('=', TK(">>"), TK(">>="));
|
||||||
} else {
|
else
|
||||||
add_token(TK(">"));
|
add_token(TK(">"));
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case '<': {
|
case '<': {
|
||||||
if(matchchar('=')) {
|
if(matchchar('='))
|
||||||
add_token(TK("<="));
|
add_token(TK("<="));
|
||||||
} else if(matchchar('<')) {
|
else if(matchchar('<'))
|
||||||
add_token_2('=', TK("<<"), TK("<<="));
|
add_token_2('=', TK("<<"), TK("<<="));
|
||||||
} else {
|
else
|
||||||
add_token(TK("<"));
|
add_token(TK("<"));
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case '-': {
|
case '-': {
|
||||||
if(matchchar('-')) {
|
if(matchchar('-')) {
|
||||||
add_token(TK("--"));
|
add_token(TK("--"));
|
||||||
} else {
|
} else {
|
||||||
if(matchchar('=')) {
|
if(matchchar('='))
|
||||||
add_token(TK("-="));
|
add_token(TK("-="));
|
||||||
} else if(matchchar('>')) {
|
else if(matchchar('>'))
|
||||||
add_token(TK("->"));
|
add_token(TK("->"));
|
||||||
} else {
|
else
|
||||||
add_token(TK("-"));
|
add_token(TK("-"));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case '!':
|
case '!':
|
||||||
if(matchchar('=')) {
|
if(matchchar('='))
|
||||||
add_token(TK("!="));
|
add_token(TK("!="));
|
||||||
} else {
|
else
|
||||||
SyntaxError("expected '=' after '!'");
|
SyntaxError("expected '=' after '!'");
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case '*':
|
case '*':
|
||||||
if(matchchar('*')) {
|
if(matchchar('*')) {
|
||||||
@ -457,7 +445,7 @@ bool Lexer::lex_one_token() {
|
|||||||
case '\t': eat_spaces(); break;
|
case '\t': eat_spaces(); break;
|
||||||
case '\n': {
|
case '\n': {
|
||||||
add_token(TK("@eol"));
|
add_token(TK("@eol"));
|
||||||
if(!eat_indentation()) { IndentationError("unindent does not match any outer indentation level"); }
|
if(!eat_indentation()) IndentationError("unindent does not match any outer indentation level");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@ -541,7 +529,7 @@ vector<Token> Lexer::run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline bool f_startswith_2(std::string_view t, const char* prefix) {
|
constexpr inline bool f_startswith_2(std::string_view t, const char* prefix) {
|
||||||
if(t.length() < 2) { return false; }
|
if(t.length() < 2) return false;
|
||||||
return t[0] == prefix[0] && t[1] == prefix[1];
|
return t[0] == prefix[0] && t[1] == prefix[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,25 +537,24 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
|
|||||||
*out = 0;
|
*out = 0;
|
||||||
|
|
||||||
if(base == -1) {
|
if(base == -1) {
|
||||||
if(f_startswith_2(text, "0b")) {
|
if(f_startswith_2(text, "0b"))
|
||||||
base = 2;
|
base = 2;
|
||||||
} else if(f_startswith_2(text, "0o")) {
|
else if(f_startswith_2(text, "0o"))
|
||||||
base = 8;
|
base = 8;
|
||||||
} else if(f_startswith_2(text, "0x")) {
|
else if(f_startswith_2(text, "0x"))
|
||||||
base = 16;
|
base = 16;
|
||||||
} else {
|
else
|
||||||
base = 10;
|
base = 10;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(base == 10) {
|
if(base == 10) {
|
||||||
// 10-base 12334
|
// 10-base 12334
|
||||||
if(text.length() == 0) { return IntParsingResult::Failure; }
|
if(text.length() == 0) return IntParsingResult::Failure;
|
||||||
for(char c: text) {
|
for(char c: text) {
|
||||||
if(c >= '0' && c <= '9') {
|
if(c >= '0' && c <= '9') {
|
||||||
i64 prev_out = *out;
|
i64 prev_out = *out;
|
||||||
*out = (*out * 10) + (c - '0');
|
*out = (*out * 10) + (c - '0');
|
||||||
if(*out < prev_out) { return IntParsingResult::Overflow; }
|
if(*out < prev_out) return IntParsingResult::Overflow;
|
||||||
} else {
|
} else {
|
||||||
return IntParsingResult::Failure;
|
return IntParsingResult::Failure;
|
||||||
}
|
}
|
||||||
@ -575,13 +562,13 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
|
|||||||
return IntParsingResult::Success;
|
return IntParsingResult::Success;
|
||||||
} else if(base == 2) {
|
} else if(base == 2) {
|
||||||
// 2-base 0b101010
|
// 2-base 0b101010
|
||||||
if(f_startswith_2(text, "0b")) { text.remove_prefix(2); }
|
if(f_startswith_2(text, "0b")) text.remove_prefix(2);
|
||||||
if(text.length() == 0) { return IntParsingResult::Failure; }
|
if(text.length() == 0) return IntParsingResult::Failure;
|
||||||
for(char c: text) {
|
for(char c: text) {
|
||||||
if(c == '0' || c == '1') {
|
if(c == '0' || c == '1') {
|
||||||
i64 prev_out = *out;
|
i64 prev_out = *out;
|
||||||
*out = (*out << 1) | (c - '0');
|
*out = (*out << 1) | (c - '0');
|
||||||
if(*out < prev_out) { return IntParsingResult::Overflow; }
|
if(*out < prev_out) return IntParsingResult::Overflow;
|
||||||
} else {
|
} else {
|
||||||
return IntParsingResult::Failure;
|
return IntParsingResult::Failure;
|
||||||
}
|
}
|
||||||
@ -589,13 +576,13 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
|
|||||||
return IntParsingResult::Success;
|
return IntParsingResult::Success;
|
||||||
} else if(base == 8) {
|
} else if(base == 8) {
|
||||||
// 8-base 0o123
|
// 8-base 0o123
|
||||||
if(f_startswith_2(text, "0o")) { text.remove_prefix(2); }
|
if(f_startswith_2(text, "0o")) text.remove_prefix(2);
|
||||||
if(text.length() == 0) { return IntParsingResult::Failure; }
|
if(text.length() == 0) return IntParsingResult::Failure;
|
||||||
for(char c: text) {
|
for(char c: text) {
|
||||||
if(c >= '0' && c <= '7') {
|
if(c >= '0' && c <= '7') {
|
||||||
i64 prev_out = *out;
|
i64 prev_out = *out;
|
||||||
*out = (*out << 3) | (c - '0');
|
*out = (*out << 3) | (c - '0');
|
||||||
if(*out < prev_out) { return IntParsingResult::Overflow; }
|
if(*out < prev_out) return IntParsingResult::Overflow;
|
||||||
} else {
|
} else {
|
||||||
return IntParsingResult::Failure;
|
return IntParsingResult::Failure;
|
||||||
}
|
}
|
||||||
@ -603,19 +590,19 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
|
|||||||
return IntParsingResult::Success;
|
return IntParsingResult::Success;
|
||||||
} else if(base == 16) {
|
} else if(base == 16) {
|
||||||
// 16-base 0x123
|
// 16-base 0x123
|
||||||
if(f_startswith_2(text, "0x")) { text.remove_prefix(2); }
|
if(f_startswith_2(text, "0x")) text.remove_prefix(2);
|
||||||
if(text.length() == 0) { return IntParsingResult::Failure; }
|
if(text.length() == 0) return IntParsingResult::Failure;
|
||||||
for(char c: text) {
|
for(char c: text) {
|
||||||
i64 prev_out = *out;
|
i64 prev_out = *out;
|
||||||
if(c >= '0' && c <= '9') {
|
if(c >= '0' && c <= '9') {
|
||||||
*out = (*out << 4) | (c - '0');
|
*out = (*out << 4) | (c - '0');
|
||||||
if(*out < prev_out) { return IntParsingResult::Overflow; }
|
if(*out < prev_out) return IntParsingResult::Overflow;
|
||||||
} else if(c >= 'a' && c <= 'f') {
|
} else if(c >= 'a' && c <= 'f') {
|
||||||
*out = (*out << 4) | (c - 'a' + 10);
|
*out = (*out << 4) | (c - 'a' + 10);
|
||||||
if(*out < prev_out) { return IntParsingResult::Overflow; }
|
if(*out < prev_out) return IntParsingResult::Overflow;
|
||||||
} else if(c >= 'A' && c <= 'F') {
|
} else if(c >= 'A' && c <= 'F') {
|
||||||
*out = (*out << 4) | (c - 'A' + 10);
|
*out = (*out << 4) | (c - 'A' + 10);
|
||||||
if(*out < prev_out) { return IntParsingResult::Overflow; }
|
if(*out < prev_out) return IntParsingResult::Overflow;
|
||||||
} else {
|
} else {
|
||||||
return IntParsingResult::Failure;
|
return IntParsingResult::Failure;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,9 +45,8 @@ void VM::__op_unpack_sequence(uint16_t arg) {
|
|||||||
// fast path for tuple
|
// fast path for tuple
|
||||||
Tuple& tuple = PK_OBJ_GET(Tuple, _0);
|
Tuple& tuple = PK_OBJ_GET(Tuple, _0);
|
||||||
if(tuple.size() == arg) {
|
if(tuple.size() == arg) {
|
||||||
for(PyVar obj: tuple) {
|
for(PyVar obj: tuple)
|
||||||
PUSH(obj);
|
PUSH(obj);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ValueError(_S("expected ", (int)arg, " values to unpack, got ", (int)tuple.size()));
|
ValueError(_S("expected ", (int)arg, " values to unpack, got ", (int)tuple.size()));
|
||||||
}
|
}
|
||||||
@ -57,10 +56,10 @@ void VM::__op_unpack_sequence(uint16_t arg) {
|
|||||||
const PyTypeInfo* ti = _tp_info(_0);
|
const PyTypeInfo* ti = _tp_info(_0);
|
||||||
for(int i = 0; i < arg; i++) {
|
for(int i = 0; i < arg; i++) {
|
||||||
PyVar _1 = _py_next(ti, _0);
|
PyVar _1 = _py_next(ti, _0);
|
||||||
if(_1 == StopIteration) { ValueError("not enough values to unpack"); }
|
if(_1 == StopIteration) ValueError("not enough values to unpack");
|
||||||
PUSH(_1);
|
PUSH(_1);
|
||||||
}
|
}
|
||||||
if(_py_next(ti, _0) != StopIteration) { ValueError("too many values to unpack"); }
|
if(_py_next(ti, _0) != StopIteration) ValueError("too many values to unpack");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +167,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_PRINT_EXPR:
|
case OP_PRINT_EXPR:
|
||||||
if(TOP() != None) { stdout_write(py_repr(TOP()) + "\n"); }
|
if(TOP() != None) stdout_write(py_repr(TOP()) + "\n");
|
||||||
POP();
|
POP();
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
@ -197,7 +196,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
/*****************************************/
|
/*****************************************/
|
||||||
case OP_LOAD_FAST: {
|
case OP_LOAD_FAST: {
|
||||||
PyVar _0 = frame->_locals[byte.arg];
|
PyVar _0 = frame->_locals[byte.arg];
|
||||||
if(_0 == PY_NULL) { vm->UnboundLocalError(frame->co->varnames[byte.arg]); }
|
if(_0 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
|
||||||
PUSH(_0);
|
PUSH(_0);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
@ -205,7 +204,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
StrName _name(byte.arg);
|
StrName _name(byte.arg);
|
||||||
PyVar* slot = frame->_locals.try_get_name(_name);
|
PyVar* slot = frame->_locals.try_get_name(_name);
|
||||||
if(slot != nullptr) {
|
if(slot != nullptr) {
|
||||||
if(*slot == PY_NULL) { vm->UnboundLocalError(_name); }
|
if(*slot == PY_NULL) vm->UnboundLocalError(_name);
|
||||||
PUSH(*slot);
|
PUSH(*slot);
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
}
|
}
|
||||||
@ -307,7 +306,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_LOAD_SUBSCR_FAST: {
|
case OP_LOAD_SUBSCR_FAST: {
|
||||||
PyVar _1 = frame->_locals[byte.arg];
|
PyVar _1 = frame->_locals[byte.arg];
|
||||||
if(_1 == PY_NULL) { vm->UnboundLocalError(frame->co->varnames[byte.arg]); }
|
if(_1 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
|
||||||
PyVar _0 = TOP(); // a
|
PyVar _0 = TOP(); // a
|
||||||
auto _ti = _tp_info(_0);
|
auto _ti = _tp_info(_0);
|
||||||
if(_ti->m__getitem__) {
|
if(_ti->m__getitem__) {
|
||||||
@ -372,7 +371,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_STORE_SUBSCR_FAST: {
|
case OP_STORE_SUBSCR_FAST: {
|
||||||
PyVar _2 = frame->_locals[byte.arg]; // b
|
PyVar _2 = frame->_locals[byte.arg]; // b
|
||||||
if(_2 == PY_NULL) { vm->UnboundLocalError(frame->co->varnames[byte.arg]); }
|
if(_2 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
|
||||||
PyVar _1 = POPX(); // a
|
PyVar _1 = POPX(); // a
|
||||||
PyVar _0 = POPX(); // val
|
PyVar _0 = POPX(); // val
|
||||||
auto _ti = _tp_info(_1);
|
auto _ti = _tp_info(_1);
|
||||||
@ -385,7 +384,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_DELETE_FAST: {
|
case OP_DELETE_FAST: {
|
||||||
PyVar _0 = frame->_locals[byte.arg];
|
PyVar _0 = frame->_locals[byte.arg];
|
||||||
if(_0 == PY_NULL) { vm->UnboundLocalError(frame->co->varnames[byte.arg]); }
|
if(_0 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
|
||||||
frame->_locals[byte.arg].set_null();
|
frame->_locals[byte.arg].set_null();
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
@ -400,19 +399,19 @@ PyVar VM::__run_top_frame() {
|
|||||||
if(func.decl == __dynamic_func_decl) {
|
if(func.decl == __dynamic_func_decl) {
|
||||||
assert(func._closure != nullptr);
|
assert(func._closure != nullptr);
|
||||||
bool ok = func._closure->del(_name);
|
bool ok = func._closure->del(_name);
|
||||||
if(!ok) { vm->NameError(_name); }
|
if(!ok) vm->NameError(_name);
|
||||||
} else {
|
} else {
|
||||||
vm->NameError(_name);
|
vm->NameError(_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(!frame->f_globals().del(_name)) { vm->NameError(_name); }
|
if(!frame->f_globals().del(_name)) vm->NameError(_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_DELETE_GLOBAL: {
|
case OP_DELETE_GLOBAL: {
|
||||||
StrName _name(byte.arg);
|
StrName _name(byte.arg);
|
||||||
if(!frame->f_globals().del(_name)) { vm->NameError(_name); }
|
if(!frame->f_globals().del(_name)) vm->NameError(_name);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_DELETE_ATTR: {
|
case OP_DELETE_ATTR: {
|
||||||
@ -434,13 +433,13 @@ PyVar VM::__run_top_frame() {
|
|||||||
/*****************************************/
|
/*****************************************/
|
||||||
case OP_BUILD_LONG: {
|
case OP_BUILD_LONG: {
|
||||||
PyVar _0 = builtins->attr().try_get_likely_found(pk_id_long);
|
PyVar _0 = builtins->attr().try_get_likely_found(pk_id_long);
|
||||||
if(_0 == nullptr) { AttributeError(builtins, pk_id_long); }
|
if(_0 == nullptr) AttributeError(builtins, pk_id_long);
|
||||||
TOP() = call(_0, TOP());
|
TOP() = call(_0, TOP());
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_BUILD_IMAG: {
|
case OP_BUILD_IMAG: {
|
||||||
PyVar _0 = builtins->attr().try_get_likely_found(pk_id_complex);
|
PyVar _0 = builtins->attr().try_get_likely_found(pk_id_complex);
|
||||||
if(_0 == nullptr) { AttributeError(builtins, pk_id_long); }
|
if(_0 == nullptr) AttributeError(builtins, pk_id_long);
|
||||||
TOP() = call(_0, VAR(0), TOP());
|
TOP() = call(_0, VAR(0), TOP());
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
@ -491,9 +490,8 @@ PyVar VM::__run_top_frame() {
|
|||||||
case OP_BUILD_STRING: {
|
case OP_BUILD_STRING: {
|
||||||
SStream ss;
|
SStream ss;
|
||||||
ArgsView view = STACK_VIEW(byte.arg);
|
ArgsView view = STACK_VIEW(byte.arg);
|
||||||
for(PyVar obj: view) {
|
for(PyVar obj: view)
|
||||||
ss << py_str(obj);
|
ss << py_str(obj);
|
||||||
}
|
|
||||||
STACK_SHRINK(byte.arg);
|
STACK_SHRINK(byte.arg);
|
||||||
PUSH(VAR(ss.str()));
|
PUSH(VAR(ss.str()));
|
||||||
}
|
}
|
||||||
@ -562,7 +560,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
PyVar _0 = TOP();
|
PyVar _0 = TOP();
|
||||||
const PyTypeInfo* _ti;
|
const PyTypeInfo* _ti;
|
||||||
BINARY_OP_SPECIAL(__truediv__);
|
BINARY_OP_SPECIAL(__truediv__);
|
||||||
if(is_not_implemented(TOP())) { BinaryOptError("/", _0, _1); }
|
if(is_not_implemented(TOP())) BinaryOptError("/", _0, _1);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_BINARY_POW: {
|
case OP_BINARY_POW: {
|
||||||
@ -570,7 +568,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
PyVar _0 = TOP();
|
PyVar _0 = TOP();
|
||||||
const PyTypeInfo* _ti;
|
const PyTypeInfo* _ti;
|
||||||
BINARY_OP_SPECIAL(__pow__);
|
BINARY_OP_SPECIAL(__pow__);
|
||||||
if(is_not_implemented(TOP())) { BinaryOptError("**", _0, _1); }
|
if(is_not_implemented(TOP())) BinaryOptError("**", _0, _1);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_BINARY_ADD: {
|
case OP_BINARY_ADD: {
|
||||||
@ -606,7 +604,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
PREDICT_INT_DIV_OP(/)
|
PREDICT_INT_DIV_OP(/)
|
||||||
const PyTypeInfo* _ti;
|
const PyTypeInfo* _ti;
|
||||||
BINARY_OP_SPECIAL(__floordiv__);
|
BINARY_OP_SPECIAL(__floordiv__);
|
||||||
if(is_not_implemented(TOP())) { BinaryOptError("//", _0, _1); }
|
if(is_not_implemented(TOP())) BinaryOptError("//", _0, _1);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_BINARY_MOD: {
|
case OP_BINARY_MOD: {
|
||||||
@ -615,7 +613,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
PREDICT_INT_DIV_OP(%)
|
PREDICT_INT_DIV_OP(%)
|
||||||
const PyTypeInfo* _ti;
|
const PyTypeInfo* _ti;
|
||||||
BINARY_OP_SPECIAL(__mod__);
|
BINARY_OP_SPECIAL(__mod__);
|
||||||
if(is_not_implemented(TOP())) { BinaryOptError("%", _0, _1); }
|
if(is_not_implemented(TOP())) BinaryOptError("%", _0, _1);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_COMPARE_LT: {
|
case OP_COMPARE_LT: {
|
||||||
@ -664,7 +662,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
PREDICT_INT_OP(<<)
|
PREDICT_INT_OP(<<)
|
||||||
const PyTypeInfo* _ti;
|
const PyTypeInfo* _ti;
|
||||||
BINARY_OP_SPECIAL(__lshift__);
|
BINARY_OP_SPECIAL(__lshift__);
|
||||||
if(is_not_implemented(TOP())) { BinaryOptError("<<", _0, _1); }
|
if(is_not_implemented(TOP())) BinaryOptError("<<", _0, _1);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_BITWISE_RSHIFT: {
|
case OP_BITWISE_RSHIFT: {
|
||||||
@ -673,7 +671,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
PREDICT_INT_OP(>>)
|
PREDICT_INT_OP(>>)
|
||||||
const PyTypeInfo* _ti;
|
const PyTypeInfo* _ti;
|
||||||
BINARY_OP_SPECIAL(__rshift__);
|
BINARY_OP_SPECIAL(__rshift__);
|
||||||
if(is_not_implemented(TOP())) { BinaryOptError(">>", _0, _1); }
|
if(is_not_implemented(TOP())) BinaryOptError(">>", _0, _1);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_BITWISE_AND: {
|
case OP_BITWISE_AND: {
|
||||||
@ -682,7 +680,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
PREDICT_INT_OP(&)
|
PREDICT_INT_OP(&)
|
||||||
const PyTypeInfo* _ti;
|
const PyTypeInfo* _ti;
|
||||||
BINARY_OP_SPECIAL(__and__);
|
BINARY_OP_SPECIAL(__and__);
|
||||||
if(is_not_implemented(TOP())) { BinaryOptError("&", _0, _1); }
|
if(is_not_implemented(TOP())) BinaryOptError("&", _0, _1);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_BITWISE_OR: {
|
case OP_BITWISE_OR: {
|
||||||
@ -691,7 +689,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
PREDICT_INT_OP(|)
|
PREDICT_INT_OP(|)
|
||||||
const PyTypeInfo* _ti;
|
const PyTypeInfo* _ti;
|
||||||
BINARY_OP_SPECIAL(__or__);
|
BINARY_OP_SPECIAL(__or__);
|
||||||
if(is_not_implemented(TOP())) { BinaryOptError("|", _0, _1); }
|
if(is_not_implemented(TOP())) BinaryOptError("|", _0, _1);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_BITWISE_XOR: {
|
case OP_BITWISE_XOR: {
|
||||||
@ -700,7 +698,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
PREDICT_INT_OP(^)
|
PREDICT_INT_OP(^)
|
||||||
const PyTypeInfo* _ti;
|
const PyTypeInfo* _ti;
|
||||||
BINARY_OP_SPECIAL(__xor__);
|
BINARY_OP_SPECIAL(__xor__);
|
||||||
if(is_not_implemented(TOP())) { BinaryOptError("^", _0, _1); }
|
if(is_not_implemented(TOP())) BinaryOptError("^", _0, _1);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_BINARY_MATMUL: {
|
case OP_BINARY_MATMUL: {
|
||||||
@ -708,7 +706,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
PyVar _0 = TOP();
|
PyVar _0 = TOP();
|
||||||
const PyTypeInfo* _ti;
|
const PyTypeInfo* _ti;
|
||||||
BINARY_OP_SPECIAL(__matmul__);
|
BINARY_OP_SPECIAL(__matmul__);
|
||||||
if(is_not_implemented(TOP())) { BinaryOptError("@", _0, _1); }
|
if(is_not_implemented(TOP())) BinaryOptError("@", _0, _1);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
|
|
||||||
@ -744,10 +742,10 @@ PyVar VM::__run_top_frame() {
|
|||||||
/*****************************************/
|
/*****************************************/
|
||||||
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:
|
case OP_POP_JUMP_IF_FALSE:
|
||||||
if(!py_bool(POPX())) { DISPATCH_JUMP((int16_t)byte.arg) }
|
if(!py_bool(POPX())) DISPATCH_JUMP((int16_t)byte.arg)
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_POP_JUMP_IF_TRUE:
|
case OP_POP_JUMP_IF_TRUE:
|
||||||
if(py_bool(POPX())) { DISPATCH_JUMP((int16_t)byte.arg) }
|
if(py_bool(POPX())) DISPATCH_JUMP((int16_t)byte.arg)
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_JUMP_IF_TRUE_OR_POP:
|
case OP_JUMP_IF_TRUE_OR_POP:
|
||||||
if(py_bool(TOP())) {
|
if(py_bool(TOP())) {
|
||||||
@ -783,7 +781,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
case OP_GOTO: {
|
case OP_GOTO: {
|
||||||
StrName _name(byte.arg);
|
StrName _name(byte.arg);
|
||||||
int target = frame->co->labels.try_get_likely_found(_name);
|
int target = frame->co->labels.try_get_likely_found(_name);
|
||||||
if(target < 0) { RuntimeError(_S("label ", _name.escape(), " not found")); }
|
if(target < 0) RuntimeError(_S("label ", _name.escape(), " not found"));
|
||||||
frame->prepare_jump_break(&s_data, target);
|
frame->prepare_jump_break(&s_data, target);
|
||||||
DISPATCH_JUMP_ABSOLUTE(target)
|
DISPATCH_JUMP_ABSOLUTE(target)
|
||||||
}
|
}
|
||||||
@ -805,7 +803,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_REPR: TOP() = VAR(py_repr(TOP())); DISPATCH()
|
case OP_REPR: TOP() = VAR(py_repr(TOP())); DISPATCH()
|
||||||
case OP_CALL: {
|
case OP_CALL: {
|
||||||
if(heap._should_auto_collect()) { heap._auto_collect(); }
|
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
|
(byte.arg >> 8) & 0xFF, // KWARGC
|
||||||
true);
|
true);
|
||||||
@ -817,7 +815,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_CALL_TP: {
|
case OP_CALL_TP: {
|
||||||
if(heap._should_auto_collect()) { heap._auto_collect(); }
|
if(heap._should_auto_collect()) heap._auto_collect();
|
||||||
PyVar _0;
|
PyVar _0;
|
||||||
PyVar _1;
|
PyVar _1;
|
||||||
PyVar _2;
|
PyVar _2;
|
||||||
@ -825,9 +823,8 @@ PyVar VM::__run_top_frame() {
|
|||||||
if(byte.arg) {
|
if(byte.arg) {
|
||||||
_2 = POPX();
|
_2 = POPX();
|
||||||
_1 = POPX();
|
_1 = POPX();
|
||||||
for(PyVar obj: _CAST(Tuple&, _1)) {
|
for(PyVar obj: _CAST(Tuple&, _1))
|
||||||
PUSH(obj);
|
PUSH(obj);
|
||||||
}
|
|
||||||
_CAST(Dict&, _2).apply([this](PyVar k, PyVar v) {
|
_CAST(Dict&, _2).apply([this](PyVar k, PyVar v) {
|
||||||
PUSH(VAR(StrName(CAST(Str&, k)).index));
|
PUSH(VAR(StrName(CAST(Str&, k)).index));
|
||||||
PUSH(v);
|
PUSH(v);
|
||||||
@ -838,9 +835,8 @@ PyVar VM::__run_top_frame() {
|
|||||||
} else {
|
} else {
|
||||||
// no **kwargs
|
// no **kwargs
|
||||||
_1 = POPX();
|
_1 = POPX();
|
||||||
for(PyVar obj: _CAST(Tuple&, _1)) {
|
for(PyVar obj: _CAST(Tuple&, _1))
|
||||||
PUSH(obj);
|
PUSH(obj);
|
||||||
}
|
|
||||||
_0 = vectorcall(_CAST(Tuple&, _1).size(), // ARGC
|
_0 = vectorcall(_CAST(Tuple&, _1).size(), // ARGC
|
||||||
0, // KWARGC
|
0, // KWARGC
|
||||||
true);
|
true);
|
||||||
@ -886,24 +882,22 @@ PyVar VM::__run_top_frame() {
|
|||||||
case OP_UNARY_NEGATIVE: TOP() = py_negate(TOP()); DISPATCH()
|
case OP_UNARY_NEGATIVE: TOP() = py_negate(TOP()); DISPATCH()
|
||||||
case OP_UNARY_NOT: {
|
case OP_UNARY_NOT: {
|
||||||
PyVar _0 = TOP();
|
PyVar _0 = TOP();
|
||||||
if(_0 == True) {
|
if(_0 == True)
|
||||||
TOP() = False;
|
TOP() = False;
|
||||||
} else if(_0 == False) {
|
else if(_0 == False)
|
||||||
TOP() = True;
|
TOP() = True;
|
||||||
} else {
|
else
|
||||||
TOP() = VAR(!py_bool(_0));
|
TOP() = VAR(!py_bool(_0));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_UNARY_STAR: TOP() = VAR(StarWrapper(byte.arg, TOP())); DISPATCH()
|
case OP_UNARY_STAR: TOP() = VAR(StarWrapper(byte.arg, TOP())); DISPATCH()
|
||||||
case OP_UNARY_INVERT: {
|
case OP_UNARY_INVERT: {
|
||||||
PyVar _0;
|
PyVar _0;
|
||||||
auto _ti = _tp_info(TOP());
|
auto _ti = _tp_info(TOP());
|
||||||
if(_ti->m__invert__) {
|
if(_ti->m__invert__)
|
||||||
_0 = _ti->m__invert__(this, TOP());
|
_0 = _ti->m__invert__(this, TOP());
|
||||||
} else {
|
else
|
||||||
_0 = call_method(TOP(), __invert__);
|
_0 = call_method(TOP(), __invert__);
|
||||||
}
|
|
||||||
TOP() = _0;
|
TOP() = _0;
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
@ -1014,7 +1008,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
} else {
|
} else {
|
||||||
for(auto& [name, value]: _0->attr().items()) {
|
for(auto& [name, value]: _0->attr().items()) {
|
||||||
std::string_view s = name.sv();
|
std::string_view s = name.sv();
|
||||||
if(s.empty() || s[0] == '_') { continue; }
|
if(s.empty() || s[0] == '_') continue;
|
||||||
frame->f_globals().set(name, value);
|
frame->f_globals().set(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1032,13 +1026,13 @@ PyVar VM::__run_top_frame() {
|
|||||||
PyVar _1;
|
PyVar _1;
|
||||||
for(int i = 0; i < byte.arg; i++) {
|
for(int i = 0; i < byte.arg; i++) {
|
||||||
_1 = _py_next(_ti, _0);
|
_1 = _py_next(_ti, _0);
|
||||||
if(_1 == StopIteration) { ValueError("not enough values to unpack"); }
|
if(_1 == StopIteration) ValueError("not enough values to unpack");
|
||||||
PUSH(_1);
|
PUSH(_1);
|
||||||
}
|
}
|
||||||
List extras;
|
List extras;
|
||||||
while(true) {
|
while(true) {
|
||||||
_1 = _py_next(_ti, _0);
|
_1 = _py_next(_ti, _0);
|
||||||
if(_1 == StopIteration) { break; }
|
if(_1 == StopIteration) break;
|
||||||
extras.push_back(_1);
|
extras.push_back(_1);
|
||||||
}
|
}
|
||||||
PUSH(VAR(std::move(extras)));
|
PUSH(VAR(std::move(extras)));
|
||||||
@ -1048,7 +1042,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
case OP_BEGIN_CLASS: {
|
case OP_BEGIN_CLASS: {
|
||||||
StrName _name(byte.arg);
|
StrName _name(byte.arg);
|
||||||
PyVar _0 = POPX(); // super
|
PyVar _0 = POPX(); // super
|
||||||
if(_0 == None) { _0 = _t(tp_object); }
|
if(_0 == None) _0 = _t(tp_object);
|
||||||
check_type(_0, tp_type);
|
check_type(_0, tp_type);
|
||||||
__curr_class = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0), true);
|
__curr_class = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0), true);
|
||||||
}
|
}
|
||||||
@ -1061,7 +1055,7 @@ PyVar VM::__run_top_frame() {
|
|||||||
PyTypeInfo* ti = &_all_types[__curr_class->as<Type>()];
|
PyTypeInfo* ti = &_all_types[__curr_class->as<Type>()];
|
||||||
if(ti->base != tp_object) {
|
if(ti->base != tp_object) {
|
||||||
PyTypeInfo* base_ti = &_all_types[ti->base];
|
PyTypeInfo* base_ti = &_all_types[ti->base];
|
||||||
if(base_ti->on_end_subclass) { base_ti->on_end_subclass(this, ti); }
|
if(base_ti->on_end_subclass) base_ti->on_end_subclass(this, ti);
|
||||||
}
|
}
|
||||||
__curr_class = nullptr;
|
__curr_class = nullptr;
|
||||||
}
|
}
|
||||||
@ -1135,27 +1129,27 @@ PyVar VM::__run_top_frame() {
|
|||||||
/*****************************************/
|
/*****************************************/
|
||||||
case OP_INC_FAST: {
|
case OP_INC_FAST: {
|
||||||
PyVar* p = &frame->_locals[byte.arg];
|
PyVar* p = &frame->_locals[byte.arg];
|
||||||
if(*p == PY_NULL) { vm->NameError(frame->co->varnames[byte.arg]); }
|
if(*p == PY_NULL) vm->NameError(frame->co->varnames[byte.arg]);
|
||||||
*p = VAR(CAST(i64, *p) + 1);
|
*p = VAR(CAST(i64, *p) + 1);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_DEC_FAST: {
|
case OP_DEC_FAST: {
|
||||||
PyVar* p = &frame->_locals[byte.arg];
|
PyVar* p = &frame->_locals[byte.arg];
|
||||||
if(*p == PY_NULL) { vm->NameError(frame->co->varnames[byte.arg]); }
|
if(*p == PY_NULL) vm->NameError(frame->co->varnames[byte.arg]);
|
||||||
*p = VAR(CAST(i64, *p) - 1);
|
*p = VAR(CAST(i64, *p) - 1);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_INC_GLOBAL: {
|
case OP_INC_GLOBAL: {
|
||||||
StrName _name(byte.arg);
|
StrName _name(byte.arg);
|
||||||
PyVar* p = frame->f_globals().try_get_2_likely_found(_name);
|
PyVar* p = frame->f_globals().try_get_2_likely_found(_name);
|
||||||
if(p == nullptr) { vm->NameError(_name); }
|
if(p == nullptr) vm->NameError(_name);
|
||||||
*p = VAR(CAST(i64, *p) + 1);
|
*p = VAR(CAST(i64, *p) + 1);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
case OP_DEC_GLOBAL: {
|
case OP_DEC_GLOBAL: {
|
||||||
StrName _name(byte.arg);
|
StrName _name(byte.arg);
|
||||||
PyVar* p = frame->f_globals().try_get_2_likely_found(_name);
|
PyVar* p = frame->f_globals().try_get_2_likely_found(_name);
|
||||||
if(p == nullptr) { vm->NameError(_name); }
|
if(p == nullptr) vm->NameError(_name);
|
||||||
*p = VAR(CAST(i64, *p) - 1);
|
*p = VAR(CAST(i64, *p) - 1);
|
||||||
}
|
}
|
||||||
DISPATCH()
|
DISPATCH()
|
||||||
|
|||||||
@ -46,9 +46,8 @@ void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
vm->bind_func(type, "hex", 1, [](VM* vm, ArgsView args) {
|
vm->bind_func(type, "hex", 1, [](VM* vm, ArgsView args) {
|
||||||
const Struct& self = _CAST(Struct&, args[0]);
|
const Struct& self = _CAST(Struct&, args[0]);
|
||||||
SStream ss;
|
SStream ss;
|
||||||
for(int i = 0; i < self.size; i++) {
|
for(int i = 0; i < self.size; i++)
|
||||||
ss.write_hex((unsigned char)self.p[i]);
|
ss.write_hex((unsigned char)self.p[i]);
|
||||||
}
|
|
||||||
return VAR(ss.str());
|
return VAR(ss.str());
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -59,29 +58,27 @@ void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
1,
|
1,
|
||||||
[](VM* vm, ArgsView args) {
|
[](VM* vm, ArgsView args) {
|
||||||
const Str& s = CAST(Str&, args[0]);
|
const Str& s = CAST(Str&, args[0]);
|
||||||
if(s.size < 2 || s.size % 2 != 0) { vm->ValueError("invalid hex string"); }
|
if(s.size < 2 || s.size % 2 != 0) vm->ValueError("invalid hex string");
|
||||||
Struct buffer(s.size / 2, false);
|
Struct buffer(s.size / 2, false);
|
||||||
for(int i = 0; i < s.size; i += 2) {
|
for(int i = 0; i < s.size; i += 2) {
|
||||||
char c = 0;
|
char c = 0;
|
||||||
if(s[i] >= '0' && s[i] <= '9') {
|
if(s[i] >= '0' && s[i] <= '9')
|
||||||
c += s[i] - '0';
|
c += s[i] - '0';
|
||||||
} else if(s[i] >= 'A' && s[i] <= 'F') {
|
else if(s[i] >= 'A' && s[i] <= 'F')
|
||||||
c += s[i] - 'A' + 10;
|
c += s[i] - 'A' + 10;
|
||||||
} else if(s[i] >= 'a' && s[i] <= 'f') {
|
else if(s[i] >= 'a' && s[i] <= 'f')
|
||||||
c += s[i] - 'a' + 10;
|
c += s[i] - 'a' + 10;
|
||||||
} else {
|
else
|
||||||
vm->ValueError(_S("invalid hex char: '", s[i], "'"));
|
vm->ValueError(_S("invalid hex char: '", s[i], "'"));
|
||||||
}
|
|
||||||
c <<= 4;
|
c <<= 4;
|
||||||
if(s[i + 1] >= '0' && s[i + 1] <= '9') {
|
if(s[i + 1] >= '0' && s[i + 1] <= '9')
|
||||||
c += s[i + 1] - '0';
|
c += s[i + 1] - '0';
|
||||||
} else if(s[i + 1] >= 'A' && s[i + 1] <= 'F') {
|
else if(s[i + 1] >= 'A' && s[i + 1] <= 'F')
|
||||||
c += s[i + 1] - 'A' + 10;
|
c += s[i + 1] - 'A' + 10;
|
||||||
} else if(s[i + 1] >= 'a' && s[i + 1] <= 'f') {
|
else if(s[i + 1] >= 'a' && s[i + 1] <= 'f')
|
||||||
c += s[i + 1] - 'a' + 10;
|
c += s[i + 1] - 'a' + 10;
|
||||||
} else {
|
else
|
||||||
vm->ValueError(_S("invalid hex char: '", s[i + 1], "'"));
|
vm->ValueError(_S("invalid hex char: '", s[i + 1], "'"));
|
||||||
}
|
|
||||||
buffer.p[i / 2] = c;
|
buffer.p[i / 2] = c;
|
||||||
}
|
}
|
||||||
return vm->new_user_object<Struct>(std::move(buffer));
|
return vm->new_user_object<Struct>(std::move(buffer));
|
||||||
@ -113,7 +110,7 @@ void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
|
|
||||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) {
|
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) {
|
||||||
Struct& self = _CAST(Struct&, lhs);
|
Struct& self = _CAST(Struct&, lhs);
|
||||||
if(!vm->is_user_type<Struct>(rhs)) { return vm->NotImplemented; }
|
if(!vm->is_user_type<Struct>(rhs)) return vm->NotImplemented;
|
||||||
Struct& other = _CAST(Struct&, rhs);
|
Struct& other = _CAST(Struct&, rhs);
|
||||||
bool ok = self.size == other.size && memcmp(self.p, other.p, self.size) == 0;
|
bool ok = self.size == other.size && memcmp(self.p, other.p, self.size) == 0;
|
||||||
return VAR(ok);
|
return VAR(ok);
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
PyVar* FastLocals::try_get_name(StrName name) {
|
PyVar* FastLocals::try_get_name(StrName name) {
|
||||||
int index = co->varnames_inv.try_get(name);
|
int index = co->varnames_inv.try_get(name);
|
||||||
if(index == -1) { return nullptr; }
|
if(index == -1) return nullptr;
|
||||||
return &a[index];
|
return &a[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,15 +14,15 @@ NameDict_ FastLocals::to_namedict() {
|
|||||||
NameDict_ dict = std::make_shared<NameDict>();
|
NameDict_ dict = std::make_shared<NameDict>();
|
||||||
co->varnames_inv.apply([&](StrName name, int index) {
|
co->varnames_inv.apply([&](StrName name, int index) {
|
||||||
PyVar value = a[index];
|
PyVar value = a[index];
|
||||||
if(value) { dict->set(name, value); }
|
if(value) dict->set(name, value);
|
||||||
});
|
});
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar* Frame::f_closure_try_get(StrName name) {
|
PyVar* Frame::f_closure_try_get(StrName name) {
|
||||||
if(_callable == nullptr) { return nullptr; }
|
if(_callable == nullptr) return nullptr;
|
||||||
Function& fn = _callable->as<Function>();
|
Function& fn = _callable->as<Function>();
|
||||||
if(fn._closure == nullptr) { return nullptr; }
|
if(fn._closure == nullptr) return nullptr;
|
||||||
return fn._closure->try_get_2(name);
|
return fn._closure->try_get_2(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,10 +30,10 @@ int Frame::prepare_jump_exception_handler(ValueStack* _s) {
|
|||||||
// try to find a parent try block
|
// try to find a parent try block
|
||||||
int i = co->lines[ip()].iblock;
|
int i = co->lines[ip()].iblock;
|
||||||
while(i >= 0) {
|
while(i >= 0) {
|
||||||
if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) { break; }
|
if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) break;
|
||||||
i = co->blocks[i].parent;
|
i = co->blocks[i].parent;
|
||||||
}
|
}
|
||||||
if(i < 0) { return -1; }
|
if(i < 0) return -1;
|
||||||
PyVar obj = _s->popx(); // pop exception object
|
PyVar obj = _s->popx(); // pop exception object
|
||||||
UnwindTarget* uw = find_unwind_target(i);
|
UnwindTarget* uw = find_unwind_target(i);
|
||||||
_s->reset(actual_sp_base() + uw->offset); // unwind the stack
|
_s->reset(actual_sp_base() + uw->offset); // unwind the stack
|
||||||
@ -61,9 +61,8 @@ int Frame::_exit_block(ValueStack* _s, int i) {
|
|||||||
void Frame::prepare_jump_break(ValueStack* _s, int target) {
|
void Frame::prepare_jump_break(ValueStack* _s, int target) {
|
||||||
int i = co->lines[ip()].iblock;
|
int i = co->lines[ip()].iblock;
|
||||||
if(target >= co->codes.size()) {
|
if(target >= co->codes.size()) {
|
||||||
while(i >= 0) {
|
while(i >= 0)
|
||||||
i = _exit_block(_s, i);
|
i = _exit_block(_s, i);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// BUG (solved)
|
// BUG (solved)
|
||||||
// for i in range(4):
|
// for i in range(4):
|
||||||
@ -71,10 +70,9 @@ void Frame::prepare_jump_break(ValueStack* _s, int target) {
|
|||||||
// # if there is no op here, the block check will fail
|
// # if there is no op here, the block check will fail
|
||||||
// while i: --i
|
// while i: --i
|
||||||
int next_block = co->lines[target].iblock;
|
int next_block = co->lines[target].iblock;
|
||||||
while(i >= 0 && i != next_block) {
|
while(i >= 0 && i != next_block)
|
||||||
i = _exit_block(_s, i);
|
i = _exit_block(_s, i);
|
||||||
}
|
if(i != next_block) throw std::runtime_error("invalid jump");
|
||||||
if(i != next_block) { throw std::runtime_error("invalid jump"); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +91,7 @@ void Frame::set_unwind_target(PyVar* _sp) {
|
|||||||
UnwindTarget* Frame::find_unwind_target(int iblock) {
|
UnwindTarget* Frame::find_unwind_target(int iblock) {
|
||||||
UnwindTarget* p;
|
UnwindTarget* p;
|
||||||
for(p = _uw_list; p != nullptr; p = p->next) {
|
for(p = _uw_list; p != nullptr; p = p->next) {
|
||||||
if(p->iblock == iblock) { return p; }
|
if(p->iblock == iblock) return p;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,15 +13,14 @@ int ManagedHeap::sweep() {
|
|||||||
#if PK_DEBUG_GC_STATS
|
#if PK_DEBUG_GC_STATS
|
||||||
deleted[obj->type] += 1;
|
deleted[obj->type] += 1;
|
||||||
#endif
|
#endif
|
||||||
if(_gc_on_delete) { _gc_on_delete(vm, obj); }
|
if(_gc_on_delete) _gc_on_delete(vm, obj);
|
||||||
_delete(obj);
|
_delete(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear _no_gc marked flag
|
// clear _no_gc marked flag
|
||||||
for(PyObject* obj: _no_gc) {
|
for(PyObject* obj: _no_gc)
|
||||||
obj->gc_marked = false;
|
obj->gc_marked = false;
|
||||||
}
|
|
||||||
|
|
||||||
int freed = gen.size() - alive.size();
|
int freed = gen.size() - alive.size();
|
||||||
|
|
||||||
@ -40,11 +39,11 @@ int ManagedHeap::sweep() {
|
|||||||
|
|
||||||
void ManagedHeap::_auto_collect() {
|
void ManagedHeap::_auto_collect() {
|
||||||
#if !PK_DEBUG_NO_AUTO_GC
|
#if !PK_DEBUG_NO_AUTO_GC
|
||||||
if(_gc_lock_counter > 0) { return; }
|
if(_gc_lock_counter > 0) return;
|
||||||
gc_counter = 0;
|
gc_counter = 0;
|
||||||
collect();
|
collect();
|
||||||
gc_threshold = gen.size() * 2;
|
gc_threshold = gen.size() * 2;
|
||||||
if(gc_threshold < PK_GC_MIN_THRESHOLD) { gc_threshold = PK_GC_MIN_THRESHOLD; }
|
if(gc_threshold < PK_GC_MIN_THRESHOLD) gc_threshold = PK_GC_MIN_THRESHOLD;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,12 @@
|
|||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
|
|
||||||
void RangeIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
void RangeIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
|
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
|
return _0;
|
||||||
|
});
|
||||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||||
RangeIter& self = PK_OBJ_GET(RangeIter, _0);
|
RangeIter& self = PK_OBJ_GET(RangeIter, _0);
|
||||||
if(self.current >= self.r.stop) { return 0; }
|
if(self.current >= self.r.stop) return 0;
|
||||||
vm->s_data.emplace(VM::tp_int, self.current);
|
vm->s_data.emplace(VM::tp_int, self.current);
|
||||||
self.current += self.r.step;
|
self.current += self.r.step;
|
||||||
return 1;
|
return 1;
|
||||||
@ -14,10 +16,12 @@ void RangeIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RangeIterR::_register(VM* vm, PyObject* mod, PyObject* type) {
|
void RangeIterR::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
|
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
|
return _0;
|
||||||
|
});
|
||||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||||
RangeIterR& self = PK_OBJ_GET(RangeIterR, _0);
|
RangeIterR& self = PK_OBJ_GET(RangeIterR, _0);
|
||||||
if(self.current <= self.r.stop) { return 0; }
|
if(self.current <= self.r.stop) return 0;
|
||||||
vm->s_data.emplace(VM::tp_int, self.current);
|
vm->s_data.emplace(VM::tp_int, self.current);
|
||||||
self.current += self.r.step;
|
self.current += self.r.step;
|
||||||
return 1;
|
return 1;
|
||||||
@ -25,21 +29,25 @@ void RangeIterR::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ArrayIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
void ArrayIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
|
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
|
return _0;
|
||||||
|
});
|
||||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||||
ArrayIter& self = _CAST(ArrayIter&, _0);
|
ArrayIter& self = _CAST(ArrayIter&, _0);
|
||||||
if(self.current == self.end) { return 0; }
|
if(self.current == self.end) return 0;
|
||||||
vm->s_data.push(*self.current++);
|
vm->s_data.push(*self.current++);
|
||||||
return 1;
|
return 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
void StringIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
|
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
|
return _0;
|
||||||
|
});
|
||||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||||
StringIter& self = _CAST(StringIter&, _0);
|
StringIter& self = _CAST(StringIter&, _0);
|
||||||
Str& s = PK_OBJ_GET(Str, self.ref);
|
Str& s = PK_OBJ_GET(Str, self.ref);
|
||||||
if(self.i == s.size) { return 0; }
|
if(self.i == s.size) return 0;
|
||||||
int start = self.i;
|
int start = self.i;
|
||||||
int len = utf8len(s.data[self.i]);
|
int len = utf8len(s.data[self.i]);
|
||||||
self.i += len;
|
self.i += len;
|
||||||
@ -49,14 +57,13 @@ void StringIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyVar Generator::next(VM* vm) {
|
PyVar Generator::next(VM* vm) {
|
||||||
if(state == 2) { return vm->StopIteration; }
|
if(state == 2) return vm->StopIteration;
|
||||||
// reset frame._sp_base
|
// reset frame._sp_base
|
||||||
lf->frame._sp_base = vm->s_data._sp;
|
lf->frame._sp_base = vm->s_data._sp;
|
||||||
lf->frame._locals.a = vm->s_data._sp;
|
lf->frame._locals.a = vm->s_data._sp;
|
||||||
// restore the context
|
// restore the context
|
||||||
for(PyVar obj: s_backup) {
|
for(PyVar obj: s_backup)
|
||||||
vm->s_data.push(obj);
|
vm->s_data.push(obj);
|
||||||
}
|
|
||||||
// relocate stack objects (their addresses become invalid)
|
// relocate stack objects (their addresses become invalid)
|
||||||
for(PyVar* p = lf->frame.actual_sp_base(); p != vm->s_data.end(); p++) {
|
for(PyVar* p = lf->frame.actual_sp_base(); p != vm->s_data.end(); p++) {
|
||||||
if(p->type == VM::tp_stack_memory) {
|
if(p->type == VM::tp_stack_memory) {
|
||||||
@ -84,9 +91,8 @@ PyVar Generator::next(VM* vm) {
|
|||||||
// backup the context
|
// backup the context
|
||||||
lf = vm->callstack.popx();
|
lf = vm->callstack.popx();
|
||||||
ret = vm->s_data.popx();
|
ret = vm->s_data.popx();
|
||||||
for(PyVar obj: lf->frame.stack_view(&vm->s_data)) {
|
for(PyVar obj: lf->frame.stack_view(&vm->s_data))
|
||||||
s_backup.push_back(obj);
|
s_backup.push_back(obj);
|
||||||
}
|
|
||||||
vm->s_data.reset(lf->frame._sp_base);
|
vm->s_data.reset(lf->frame._sp_base);
|
||||||
// TODO: should we add this snippet here?
|
// TODO: should we add this snippet here?
|
||||||
// #if PK_ENABLE_PROFILER
|
// #if PK_ENABLE_PROFILER
|
||||||
@ -95,7 +101,7 @@ PyVar Generator::next(VM* vm) {
|
|||||||
// }
|
// }
|
||||||
// #endif
|
// #endif
|
||||||
state = 1;
|
state = 1;
|
||||||
if(ret == vm->StopIteration) { state = 2; }
|
if(ret == vm->StopIteration) state = 2;
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
state = 2;
|
state = 2;
|
||||||
@ -104,22 +110,26 @@ PyVar Generator::next(VM* vm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Generator::_register(VM* vm, PyObject* mod, PyObject* type) {
|
void Generator::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
|
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
|
return _0;
|
||||||
|
});
|
||||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||||
Generator& self = _CAST(Generator&, _0);
|
Generator& self = _CAST(Generator&, _0);
|
||||||
PyVar retval = self.next(vm);
|
PyVar retval = self.next(vm);
|
||||||
if(retval == vm->StopIteration) { return 0; }
|
if(retval == vm->StopIteration) return 0;
|
||||||
vm->s_data.push(retval);
|
vm->s_data.push(retval);
|
||||||
return 1;
|
return 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void DictItemsIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
void DictItemsIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
|
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
|
return _0;
|
||||||
|
});
|
||||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||||
DictItemsIter& self = _CAST(DictItemsIter&, _0);
|
DictItemsIter& self = _CAST(DictItemsIter&, _0);
|
||||||
Dict& d = PK_OBJ_GET(Dict, self.ref);
|
Dict& d = PK_OBJ_GET(Dict, self.ref);
|
||||||
if(self.i == -1) { return 0; }
|
if(self.i == -1) return 0;
|
||||||
vm->s_data.push(d._items[self.i].first);
|
vm->s_data.push(d._items[self.i].first);
|
||||||
vm->s_data.push(d._items[self.i].second);
|
vm->s_data.push(d._items[self.i].second);
|
||||||
self.i = d._items[self.i].next;
|
self.i = d._items[self.i].next;
|
||||||
|
|||||||
@ -4,7 +4,7 @@ namespace pkpy {
|
|||||||
|
|
||||||
static std::string left_pad(std::string s, int width) {
|
static std::string left_pad(std::string s, int width) {
|
||||||
int n = width - s.size();
|
int n = width - s.size();
|
||||||
if(n <= 0) { return s; }
|
if(n <= 0) return s;
|
||||||
return std::string(n, ' ') + s;
|
return std::string(n, ' ') + s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ void LineProfiler::begin() { frames.clear(); }
|
|||||||
|
|
||||||
void LineProfiler::_step(int callstack_size, Frame* frame) {
|
void LineProfiler::_step(int callstack_size, Frame* frame) {
|
||||||
auto line_info = frame->co->lines[frame->ip()];
|
auto line_info = frame->co->lines[frame->ip()];
|
||||||
if(line_info.is_virtual) { return; }
|
if(line_info.is_virtual) return;
|
||||||
std::string_view filename = frame->co->src->filename.sv();
|
std::string_view filename = frame->co->src->filename.sv();
|
||||||
int line = line_info.lineno;
|
int line = line_info.lineno;
|
||||||
|
|
||||||
@ -53,14 +53,14 @@ void LineProfiler::_step_end(int callstack_size, Frame* frame, int line) {
|
|||||||
if(prev_record->line != line) {
|
if(prev_record->line != line) {
|
||||||
clock_t delta = now - top_frame_record.prev_time;
|
clock_t delta = now - top_frame_record.prev_time;
|
||||||
top_frame_record.prev_time = now;
|
top_frame_record.prev_time = now;
|
||||||
if(id_delta != 1) { prev_record->hits++; }
|
if(id_delta != 1) prev_record->hits++;
|
||||||
prev_record->time += delta;
|
prev_record->time += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id_delta == 1) {
|
if(id_delta == 1) {
|
||||||
frames.push({callstack_size, frame, now, nullptr});
|
frames.push({callstack_size, frame, now, nullptr});
|
||||||
} else {
|
} else {
|
||||||
if(id_delta == -1) { frames.pop(); }
|
if(id_delta == -1) frames.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,10 +83,10 @@ Str LineProfiler::stats() {
|
|||||||
for(FuncDecl* decl: functions) {
|
for(FuncDecl* decl: functions) {
|
||||||
int start_line = decl->code->start_line;
|
int start_line = decl->code->start_line;
|
||||||
int end_line = decl->code->end_line;
|
int end_line = decl->code->end_line;
|
||||||
if(start_line == -1 || end_line == -1) { continue; }
|
if(start_line == -1 || end_line == -1) continue;
|
||||||
std::string_view filename = decl->code->src->filename.sv();
|
std::string_view filename = decl->code->src->filename.sv();
|
||||||
vector<_LineRecord>& file_records = records[filename];
|
vector<_LineRecord>& file_records = records[filename];
|
||||||
if(file_records.empty()) { continue; }
|
if(file_records.empty()) continue;
|
||||||
clock_t total_time = 0;
|
clock_t total_time = 0;
|
||||||
for(int line = start_line; line <= end_line; line++) {
|
for(int line = start_line; line <= end_line; line++) {
|
||||||
total_time += file_records[line].time;
|
total_time += file_records[line].time;
|
||||||
@ -98,7 +98,7 @@ Str LineProfiler::stats() {
|
|||||||
ss << "==============================================================\n";
|
ss << "==============================================================\n";
|
||||||
for(int line = start_line; line <= end_line; line++) {
|
for(int line = start_line; line <= end_line; line++) {
|
||||||
const _LineRecord& record = file_records[line];
|
const _LineRecord& record = file_records[line];
|
||||||
if(!record.is_valid()) { continue; }
|
if(!record.is_valid()) continue;
|
||||||
ss << left_pad(std::to_string(line), 6);
|
ss << left_pad(std::to_string(line), 6);
|
||||||
if(record.hits == 0) {
|
if(record.hits == 0) {
|
||||||
ss << std::string(10 + 13 + 9 + 9, ' ');
|
ss << std::string(10 + 13 + 9 + 9, ' ');
|
||||||
|
|||||||
@ -23,7 +23,7 @@ struct JsonSerializer {
|
|||||||
void write_array(T& arr) {
|
void write_array(T& arr) {
|
||||||
ss << '[';
|
ss << '[';
|
||||||
for(int i = 0; i < arr.size(); i++) {
|
for(int i = 0; i < arr.size(); i++) {
|
||||||
if(i != 0) { ss << ", "; }
|
if(i != 0) ss << ", ";
|
||||||
write_object(arr[i]);
|
write_object(arr[i]);
|
||||||
}
|
}
|
||||||
ss << ']';
|
ss << ']';
|
||||||
@ -33,7 +33,7 @@ struct JsonSerializer {
|
|||||||
ss << '{';
|
ss << '{';
|
||||||
bool first = true;
|
bool first = true;
|
||||||
dict.apply([&](PyVar k, PyVar v) {
|
dict.apply([&](PyVar k, PyVar v) {
|
||||||
if(!first) { ss << ", "; }
|
if(!first) ss << ", ";
|
||||||
first = false;
|
first = false;
|
||||||
if(!is_type(k, VM::tp_str)) {
|
if(!is_type(k, VM::tp_str)) {
|
||||||
vm->TypeError(_S("json keys must be string, got ", _type_name(vm, vm->_tp(k))));
|
vm->TypeError(_S("json keys must be string, got ", _type_name(vm, vm->_tp(k))));
|
||||||
@ -52,7 +52,7 @@ struct JsonSerializer {
|
|||||||
ss << _CAST(i64, obj);
|
ss << _CAST(i64, obj);
|
||||||
} else if(obj_t == vm->tp_float) {
|
} else if(obj_t == vm->tp_float) {
|
||||||
f64 val = _CAST(f64, obj);
|
f64 val = _CAST(f64, obj);
|
||||||
if(std::isinf(val) || std::isnan(val)) { vm->ValueError("cannot jsonify 'nan' or 'inf'"); }
|
if(std::isinf(val) || std::isnan(val)) vm->ValueError("cannot jsonify 'nan' or 'inf'");
|
||||||
ss << val;
|
ss << val;
|
||||||
} else if(obj_t == vm->tp_bool) {
|
} else if(obj_t == vm->tp_bool) {
|
||||||
ss << (obj == vm->True ? "true" : "false");
|
ss << (obj == vm->True ? "true" : "false");
|
||||||
@ -80,18 +80,24 @@ VM::VM(bool enable_os) : heap(this), enable_os(enable_os) {
|
|||||||
this->vm = this;
|
this->vm = this;
|
||||||
this->__c.error = nullptr;
|
this->__c.error = nullptr;
|
||||||
_ceval_on_step = nullptr;
|
_ceval_on_step = nullptr;
|
||||||
_stdout = [](const char* buf, int size) { std::cout.write(buf, size); };
|
_stdout = [](const char* buf, int size) {
|
||||||
_stderr = [](const char* buf, int size) { std::cerr.write(buf, size); };
|
std::cout.write(buf, size);
|
||||||
|
};
|
||||||
|
_stderr = [](const char* buf, int size) {
|
||||||
|
std::cerr.write(buf, size);
|
||||||
|
};
|
||||||
builtins = nullptr;
|
builtins = nullptr;
|
||||||
_main = nullptr;
|
_main = nullptr;
|
||||||
__last_exception = 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();
|
__init_builtin_types();
|
||||||
}
|
}
|
||||||
|
|
||||||
Str VM::py_str(PyVar obj) {
|
Str VM::py_str(PyVar obj) {
|
||||||
const PyTypeInfo* ti = _tp_info(obj);
|
const PyTypeInfo* ti = _tp_info(obj);
|
||||||
if(ti->m__str__) { return ti->m__str__(this, obj); }
|
if(ti->m__str__) return ti->m__str__(this, obj);
|
||||||
PyVar self;
|
PyVar self;
|
||||||
PyVar f = get_unbound_method(obj, __str__, &self, false);
|
PyVar f = get_unbound_method(obj, __str__, &self, false);
|
||||||
if(self != PY_NULL) {
|
if(self != PY_NULL) {
|
||||||
@ -104,7 +110,7 @@ Str VM::py_str(PyVar obj) {
|
|||||||
|
|
||||||
Str VM::py_repr(PyVar obj) {
|
Str VM::py_repr(PyVar obj) {
|
||||||
const PyTypeInfo* ti = _tp_info(obj);
|
const PyTypeInfo* ti = _tp_info(obj);
|
||||||
if(ti->m__repr__) { return ti->m__repr__(this, obj); }
|
if(ti->m__repr__) return ti->m__repr__(this, obj);
|
||||||
PyVar retval = call_method(obj, __repr__);
|
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);
|
return PK_OBJ_GET(Str, retval);
|
||||||
@ -117,10 +123,10 @@ Str VM::py_json(PyVar obj) {
|
|||||||
|
|
||||||
PyVar VM::py_iter(PyVar obj) {
|
PyVar VM::py_iter(PyVar obj) {
|
||||||
const PyTypeInfo* ti = _tp_info(obj);
|
const PyTypeInfo* ti = _tp_info(obj);
|
||||||
if(ti->m__iter__) { return ti->m__iter__(this, obj); }
|
if(ti->m__iter__) return ti->m__iter__(this, obj);
|
||||||
PyVar self;
|
PyVar self;
|
||||||
PyVar iter_f = get_unbound_method(obj, __iter__, &self, false);
|
PyVar iter_f = get_unbound_method(obj, __iter__, &self, false);
|
||||||
if(self != PY_NULL) { return call_method(self, iter_f); }
|
if(self != PY_NULL) return call_method(self, iter_f);
|
||||||
TypeError(_type_name(vm, _tp(obj)).escape() + " object is not iterable");
|
TypeError(_type_name(vm, _tp(obj)).escape() + " object is not iterable");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -139,9 +145,8 @@ ArgsView VM::cast_array_view(PyVar obj) {
|
|||||||
void VM::set_main_argv(int argc, char** argv) {
|
void VM::set_main_argv(int argc, char** argv) {
|
||||||
PyVar mod = vm->_modules["sys"];
|
PyVar mod = vm->_modules["sys"];
|
||||||
List argv_(argc);
|
List argv_(argc);
|
||||||
for(int i = 0; i < argc; i++) {
|
for(int i = 0; i < argc; i++)
|
||||||
argv_[i] = VAR(std::string_view(argv[i]));
|
argv_[i] = VAR(std::string_view(argv[i]));
|
||||||
}
|
|
||||||
mod->attr().set("argv", VAR(std::move(argv_)));
|
mod->attr().set("argv", VAR(std::move(argv_)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,9 +154,9 @@ PyVar* VM::find_name_in_mro(Type cls, StrName name) {
|
|||||||
PyVar* val;
|
PyVar* val;
|
||||||
do {
|
do {
|
||||||
val = _t(cls)->attr().try_get_2(name);
|
val = _t(cls)->attr().try_get_2(name);
|
||||||
if(val != nullptr) { return val; }
|
if(val != nullptr) return val;
|
||||||
cls = _all_types[cls].base;
|
cls = _all_types[cls].base;
|
||||||
if(!cls) { break; }
|
if(!cls) break;
|
||||||
} while(true);
|
} while(true);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -160,16 +165,16 @@ bool VM::isinstance(PyVar obj, Type base) { return issubclass(_tp(obj), base); }
|
|||||||
|
|
||||||
bool VM::issubclass(Type cls, Type base) {
|
bool VM::issubclass(Type cls, Type base) {
|
||||||
do {
|
do {
|
||||||
if(cls == base) { return true; }
|
if(cls == base) return true;
|
||||||
Type next = _all_types[cls].base;
|
Type next = _all_types[cls].base;
|
||||||
if(!next) { break; }
|
if(!next) break;
|
||||||
cls = next;
|
cls = next;
|
||||||
} while(true);
|
} while(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module) {
|
PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module) {
|
||||||
if(_module == nullptr) { _module = _main; }
|
if(_module == nullptr) _module = _main;
|
||||||
try {
|
try {
|
||||||
#if PK_DEBUG_PRECOMPILED_EXEC == 1
|
#if PK_DEBUG_PRECOMPILED_EXEC == 1
|
||||||
Str precompiled = vm->precompile(source, filename, mode);
|
Str precompiled = vm->precompile(source, filename, mode);
|
||||||
@ -215,23 +220,23 @@ PyObject* VM::new_type_object(PyObject* mod, StrName name, Type base, bool subcl
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool VM::py_eq(PyVar lhs, PyVar rhs) {
|
bool VM::py_eq(PyVar lhs, PyVar rhs) {
|
||||||
if(is_int(lhs) && is_int(rhs)) { return lhs.as<i64>() == rhs.as<i64>(); }
|
if(is_int(lhs) && is_int(rhs)) return lhs.as<i64>() == rhs.as<i64>();
|
||||||
const PyTypeInfo* ti = _tp_info(lhs);
|
const PyTypeInfo* ti = _tp_info(lhs);
|
||||||
PyVar res;
|
PyVar res;
|
||||||
if(ti->m__eq__) {
|
if(ti->m__eq__) {
|
||||||
res = ti->m__eq__(this, lhs, rhs);
|
res = ti->m__eq__(this, lhs, rhs);
|
||||||
if(!is_not_implemented(res)) { return res == vm->True; }
|
if(!is_not_implemented(res)) return res == vm->True;
|
||||||
}
|
}
|
||||||
res = call_method(lhs, __eq__, rhs);
|
res = call_method(lhs, __eq__, rhs);
|
||||||
if(!is_not_implemented(res)) { return res == vm->True; }
|
if(!is_not_implemented(res)) return res == vm->True;
|
||||||
|
|
||||||
ti = _tp_info(rhs);
|
ti = _tp_info(rhs);
|
||||||
if(ti->m__eq__) {
|
if(ti->m__eq__) {
|
||||||
res = ti->m__eq__(this, rhs, lhs);
|
res = ti->m__eq__(this, rhs, lhs);
|
||||||
if(!is_not_implemented(res)) { return res == vm->True; }
|
if(!is_not_implemented(res)) return res == vm->True;
|
||||||
}
|
}
|
||||||
res = call_method(rhs, __eq__, lhs);
|
res = call_method(rhs, __eq__, lhs);
|
||||||
if(!is_not_implemented(res)) { return res == vm->True; }
|
if(!is_not_implemented(res)) return res == vm->True;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,7 +253,7 @@ PyVar VM::py_op(std::string_view name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
i64 VM::normalized_index(i64 index, int size) {
|
i64 VM::normalized_index(i64 index, int size) {
|
||||||
if(index < 0) { index += 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;
|
return index;
|
||||||
}
|
}
|
||||||
@ -287,7 +292,7 @@ PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) {
|
|||||||
return (this->*op)(a, b) ? a : b;
|
return (this->*op)(a, b) ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(args_tuple.size() == 0) { TypeError("expected at least 1 argument, got 0"); }
|
if(args_tuple.size() == 0) TypeError("expected at least 1 argument, got 0");
|
||||||
|
|
||||||
ArgsView view(nullptr, nullptr);
|
ArgsView view(nullptr, nullptr);
|
||||||
if(args_tuple.size() == 1) {
|
if(args_tuple.size() == 1) {
|
||||||
@ -296,30 +301,30 @@ PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) {
|
|||||||
view = ArgsView(args_tuple);
|
view = ArgsView(args_tuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(view.empty()) { ValueError("arg is an empty sequence"); }
|
if(view.empty()) ValueError("arg is an empty sequence");
|
||||||
PyVar res = view[0];
|
PyVar res = view[0];
|
||||||
|
|
||||||
if(key == vm->None) {
|
if(key == vm->None) {
|
||||||
for(int i = 1; i < view.size(); i++) {
|
for(int i = 1; i < view.size(); i++) {
|
||||||
if((this->*op)(view[i], res)) { res = view[i]; }
|
if((this->*op)(view[i], res)) res = view[i];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto _lock = heap.gc_scope_lock();
|
auto _lock = heap.gc_scope_lock();
|
||||||
for(int i = 1; i < view.size(); i++) {
|
for(int i = 1; i < view.size(); i++) {
|
||||||
PyVar a = call(key, view[i]);
|
PyVar a = call(key, view[i]);
|
||||||
PyVar b = call(key, res);
|
PyVar b = call(key, res);
|
||||||
if((this->*op)(a, b)) { res = view[i]; }
|
if((this->*op)(a, b)) res = view[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* VM::py_import(Str path, bool throw_err) {
|
PyObject* VM::py_import(Str path, bool throw_err) {
|
||||||
if(path.empty()) { vm->ValueError("empty module name"); }
|
if(path.empty()) vm->ValueError("empty module name");
|
||||||
static auto f_join = [](const vector<std::string_view>& cpnts) {
|
static auto f_join = [](const vector<std::string_view>& cpnts) {
|
||||||
SStream ss;
|
SStream ss;
|
||||||
for(int i = 0; i < cpnts.size(); i++) {
|
for(int i = 0; i < cpnts.size(); i++) {
|
||||||
if(i != 0) { ss << "."; }
|
if(i != 0) ss << ".";
|
||||||
ss << cpnts[i];
|
ss << cpnts[i];
|
||||||
}
|
}
|
||||||
return ss.str();
|
return ss.str();
|
||||||
@ -333,18 +338,16 @@ PyObject* VM::py_import(Str path, bool throw_err) {
|
|||||||
vector<std::string_view> cpnts = curr_path.split('.');
|
vector<std::string_view> cpnts = curr_path.split('.');
|
||||||
int prefix = 0; // how many dots in the prefix
|
int prefix = 0; // how many dots in the prefix
|
||||||
for(int i = 0; i < path.length(); i++) {
|
for(int i = 0; i < path.length(); i++) {
|
||||||
if(path[i] == '.') {
|
if(path[i] == '.')
|
||||||
prefix++;
|
prefix++;
|
||||||
} else {
|
else
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(prefix > cpnts.size()) { ImportError("attempted relative import beyond top-level package"); }
|
if(prefix > cpnts.size()) ImportError("attempted relative import beyond top-level package");
|
||||||
path = path.substr(prefix); // remove prefix
|
path = path.substr(prefix); // remove prefix
|
||||||
for(int i = (int)curr_is_init; i < prefix; i++) {
|
for(int i = (int)curr_is_init; i < prefix; i++)
|
||||||
cpnts.pop_back();
|
cpnts.pop_back();
|
||||||
}
|
if(!path.empty()) cpnts.push_back(path.sv());
|
||||||
if(!path.empty()) { cpnts.push_back(path.sv()); }
|
|
||||||
path = f_join(cpnts);
|
path = f_join(cpnts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,7 +356,7 @@ PyObject* VM::py_import(Str path, bool throw_err) {
|
|||||||
// check existing module
|
// check existing module
|
||||||
StrName name(path);
|
StrName name(path);
|
||||||
PyVar ext_mod = _modules.try_get(name);
|
PyVar ext_mod = _modules.try_get(name);
|
||||||
if(ext_mod != nullptr) { return ext_mod.get(); }
|
if(ext_mod != nullptr) return ext_mod.get();
|
||||||
|
|
||||||
vector<std::string_view> path_cpnts = path.split('.');
|
vector<std::string_view> path_cpnts = path.split('.');
|
||||||
// check circular import
|
// check circular import
|
||||||
@ -373,11 +376,10 @@ PyObject* VM::py_import(Str path, bool throw_err) {
|
|||||||
out = _import_handler(filename.c_str(), &out_size);
|
out = _import_handler(filename.c_str(), &out_size);
|
||||||
}
|
}
|
||||||
if(out == nullptr) {
|
if(out == nullptr) {
|
||||||
if(throw_err) {
|
if(throw_err)
|
||||||
ImportError(_S("module ", path.escape(), " not found"));
|
ImportError(_S("module ", path.escape(), " not found"));
|
||||||
} else {
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert(out_size >= 0);
|
assert(out_size >= 0);
|
||||||
source = Str(std::string_view((char*)out, out_size));
|
source = Str(std::string_view((char*)out, out_size));
|
||||||
@ -398,12 +400,10 @@ PyObject* VM::py_import(Str path, bool throw_err) {
|
|||||||
|
|
||||||
VM::~VM() {
|
VM::~VM() {
|
||||||
// clear managed heap
|
// clear managed heap
|
||||||
for(PyObject* obj: heap.gen) {
|
for(PyObject* obj: heap.gen)
|
||||||
heap._delete(obj);
|
heap._delete(obj);
|
||||||
}
|
for(PyObject* obj: heap._no_gc)
|
||||||
for(PyObject* obj: heap._no_gc) {
|
|
||||||
heap._delete(obj);
|
heap._delete(obj);
|
||||||
}
|
|
||||||
// clear everything
|
// clear everything
|
||||||
callstack.clear();
|
callstack.clear();
|
||||||
s_data.clear();
|
s_data.clear();
|
||||||
@ -414,14 +414,14 @@ VM::~VM() {
|
|||||||
|
|
||||||
PyVar VM::py_negate(PyVar obj) {
|
PyVar VM::py_negate(PyVar obj) {
|
||||||
const PyTypeInfo* ti = _tp_info(obj);
|
const PyTypeInfo* ti = _tp_info(obj);
|
||||||
if(ti->m__neg__) { return ti->m__neg__(this, obj); }
|
if(ti->m__neg__) return ti->m__neg__(this, obj);
|
||||||
return call_method(obj, __neg__);
|
return call_method(obj, __neg__);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VM::__py_bool_non_trivial(PyVar obj) {
|
bool VM::__py_bool_non_trivial(PyVar obj) {
|
||||||
if(obj == None) { return false; }
|
if(obj == None) return false;
|
||||||
if(is_int(obj)) { return _CAST(i64, obj) != 0; }
|
if(is_int(obj)) return _CAST(i64, obj) != 0;
|
||||||
if(is_float(obj)) { return _CAST(f64, obj) != 0.0; }
|
if(is_float(obj)) return _CAST(f64, obj) != 0.0;
|
||||||
PyVar self;
|
PyVar self;
|
||||||
PyVar len_f = get_unbound_method(obj, __len__, &self, false);
|
PyVar len_f = get_unbound_method(obj, __len__, &self, false);
|
||||||
if(self != PY_NULL) {
|
if(self != PY_NULL) {
|
||||||
@ -432,13 +432,13 @@ bool VM::__py_bool_non_trivial(PyVar obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VM::__obj_gc_mark(PyObject* obj) {
|
void VM::__obj_gc_mark(PyObject* obj) {
|
||||||
if(obj->gc_marked) { return; }
|
if(obj->gc_marked) return;
|
||||||
obj->gc_marked = true;
|
obj->gc_marked = true;
|
||||||
const PyTypeInfo* ti = _tp_info(obj->type);
|
const PyTypeInfo* ti = _tp_info(obj->type);
|
||||||
if(ti->vt._gc_mark) { ti->vt._gc_mark(obj->_value_ptr(), this); }
|
if(ti->vt._gc_mark) ti->vt._gc_mark(obj->_value_ptr(), this);
|
||||||
if(obj->is_attr_valid()) {
|
if(obj->is_attr_valid()) {
|
||||||
obj->attr().apply([this](StrName _, PyVar obj) {
|
obj->attr().apply([this](StrName _, PyVar obj) {
|
||||||
if(obj.is_ptr) { vm->__obj_gc_mark((obj).get()); }
|
if(obj.is_ptr) vm->__obj_gc_mark((obj).get());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -451,7 +451,7 @@ void VM::__stack_gc_mark(PyVar* begin, PyVar* end) {
|
|||||||
if(it->type == tp_stack_memory) {
|
if(it->type == tp_stack_memory) {
|
||||||
// [sm:3, _0, _1, _2, sm:-3]
|
// [sm:3, _0, _1, _2, sm:-3]
|
||||||
int count = it->as<StackMemory>().count;
|
int count = it->as<StackMemory>().count;
|
||||||
if(count > 0) { it += count; }
|
if(count > 0) it += count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -481,29 +481,28 @@ List VM::py_list(PyVar it) {
|
|||||||
|
|
||||||
void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step) {
|
void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step) {
|
||||||
auto clip = [](int value, int min, int max) {
|
auto clip = [](int value, int min, int max) {
|
||||||
if(value < min) { return min; }
|
if(value < min) return min;
|
||||||
if(value > max) { return max; }
|
if(value > max) return max;
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
if(s.step == None) {
|
if(s.step == None)
|
||||||
step = 1;
|
step = 1;
|
||||||
} else {
|
else
|
||||||
step = CAST(int, s.step);
|
step = CAST(int, s.step);
|
||||||
}
|
if(step == 0) ValueError("slice step cannot be zero");
|
||||||
if(step == 0) { ValueError("slice step cannot be zero"); }
|
|
||||||
if(step > 0) {
|
if(step > 0) {
|
||||||
if(s.start == None) {
|
if(s.start == None) {
|
||||||
start = 0;
|
start = 0;
|
||||||
} else {
|
} else {
|
||||||
start = CAST(int, s.start);
|
start = CAST(int, s.start);
|
||||||
if(start < 0) { start += length; }
|
if(start < 0) start += length;
|
||||||
start = clip(start, 0, length);
|
start = clip(start, 0, length);
|
||||||
}
|
}
|
||||||
if(s.stop == None) {
|
if(s.stop == None) {
|
||||||
stop = length;
|
stop = length;
|
||||||
} else {
|
} else {
|
||||||
stop = CAST(int, s.stop);
|
stop = CAST(int, s.stop);
|
||||||
if(stop < 0) { stop += length; }
|
if(stop < 0) stop += length;
|
||||||
stop = clip(stop, 0, length);
|
stop = clip(stop, 0, length);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -511,14 +510,14 @@ void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int&
|
|||||||
start = length - 1;
|
start = length - 1;
|
||||||
} else {
|
} else {
|
||||||
start = CAST(int, s.start);
|
start = CAST(int, s.start);
|
||||||
if(start < 0) { start += length; }
|
if(start < 0) start += length;
|
||||||
start = clip(start, -1, length - 1);
|
start = clip(start, -1, length - 1);
|
||||||
}
|
}
|
||||||
if(s.stop == None) {
|
if(s.stop == None) {
|
||||||
stop = -1;
|
stop = -1;
|
||||||
} else {
|
} else {
|
||||||
stop = CAST(int, s.stop);
|
stop = CAST(int, s.stop);
|
||||||
if(stop < 0) { stop += length; }
|
if(stop < 0) stop += length;
|
||||||
stop = clip(stop, -1, length - 1);
|
stop = clip(stop, -1, length - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -527,7 +526,7 @@ void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int&
|
|||||||
i64 VM::py_hash(PyVar obj) {
|
i64 VM::py_hash(PyVar obj) {
|
||||||
// https://docs.python.org/3.10/reference/datamodel.html#object.__hash__
|
// https://docs.python.org/3.10/reference/datamodel.html#object.__hash__
|
||||||
const PyTypeInfo* ti = _tp_info(obj);
|
const PyTypeInfo* ti = _tp_info(obj);
|
||||||
if(ti->m__hash__) { return ti->m__hash__(this, obj); }
|
if(ti->m__hash__) return ti->m__hash__(this, obj);
|
||||||
|
|
||||||
PyVar self;
|
PyVar self;
|
||||||
PyVar f = get_unbound_method(obj, __hash__, &self, false);
|
PyVar f = get_unbound_method(obj, __hash__, &self, false);
|
||||||
@ -536,12 +535,12 @@ i64 VM::py_hash(PyVar obj) {
|
|||||||
return CAST(i64, ret);
|
return CAST(i64, ret);
|
||||||
}
|
}
|
||||||
// if it is trivial `object`, return PK_BITS
|
// if it is trivial `object`, return PK_BITS
|
||||||
if(ti == &_all_types[tp_object]) { return obj.hash(); }
|
if(ti == &_all_types[tp_object]) return obj.hash();
|
||||||
// otherwise, we check if it has a custom __eq__ other than object.__eq__
|
// otherwise, we check if it has a custom __eq__ other than object.__eq__
|
||||||
bool has_custom_eq = false;
|
bool has_custom_eq = false;
|
||||||
if(ti->m__eq__) {
|
if(ti->m__eq__)
|
||||||
has_custom_eq = true;
|
has_custom_eq = true;
|
||||||
} else {
|
else {
|
||||||
f = get_unbound_method(obj, __eq__, &self, false);
|
f = get_unbound_method(obj, __eq__, &self, false);
|
||||||
has_custom_eq = f != _t(tp_object)->attr(__eq__);
|
has_custom_eq = f != _t(tp_object)->attr(__eq__);
|
||||||
}
|
}
|
||||||
@ -579,7 +578,9 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local
|
|||||||
globals_obj = new_object<DummyInstance>(VM::tp_object).get();
|
globals_obj = new_object<DummyInstance>(VM::tp_object).get();
|
||||||
globals_obj->_attr = new NameDict();
|
globals_obj->_attr = new NameDict();
|
||||||
globals_dict = &PK_OBJ_GET(Dict, globals);
|
globals_dict = &PK_OBJ_GET(Dict, globals);
|
||||||
globals_dict->apply([&](PyVar k, PyVar v) { globals_obj->attr().set(CAST(Str&, k), v); });
|
globals_dict->apply([&](PyVar k, PyVar v) {
|
||||||
|
globals_obj->attr().set(CAST(Str&, k), v);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,7 +592,9 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local
|
|||||||
check_compatible_type(locals, VM::tp_dict);
|
check_compatible_type(locals, VM::tp_dict);
|
||||||
locals_dict = &PK_OBJ_GET(Dict, locals);
|
locals_dict = &PK_OBJ_GET(Dict, locals);
|
||||||
locals_closure = std::make_shared<NameDict>();
|
locals_closure = std::make_shared<NameDict>();
|
||||||
locals_dict->apply([&](PyVar k, PyVar v) { locals_closure->set(CAST(Str&, k), v); });
|
locals_dict->apply([&](PyVar k, PyVar v) {
|
||||||
|
locals_closure->set(CAST(Str&, k), v);
|
||||||
|
});
|
||||||
PyObject* _callable =
|
PyObject* _callable =
|
||||||
heap.gcnew<Function>(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure);
|
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);
|
retval = vm->_exec(code.get(), globals_obj, _callable, vm->s_data._sp);
|
||||||
@ -599,12 +602,16 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local
|
|||||||
|
|
||||||
if(globals_dict) {
|
if(globals_dict) {
|
||||||
globals_dict->clear();
|
globals_dict->clear();
|
||||||
globals_obj->attr().apply([&](StrName k, PyVar v) { globals_dict->set(vm, VAR(k.sv()), v); });
|
globals_obj->attr().apply([&](StrName k, PyVar v) {
|
||||||
|
globals_dict->set(vm, VAR(k.sv()), v);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(locals_dict) {
|
if(locals_dict) {
|
||||||
locals_dict->clear();
|
locals_dict->clear();
|
||||||
locals_closure->apply([&](StrName k, PyVar v) { locals_dict->set(vm, VAR(k.sv()), v); });
|
locals_closure->apply([&](StrName k, PyVar v) {
|
||||||
|
locals_dict->set(vm, VAR(k.sv()), v);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -620,7 +627,7 @@ PyVar VM::py_eval(std::string_view source, PyVar globals, PyVar locals) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyVar VM::__format_object(PyVar obj, Str spec) {
|
PyVar VM::__format_object(PyVar obj, Str spec) {
|
||||||
if(spec.empty()) { return VAR(py_str(obj)); }
|
if(spec.empty()) return VAR(py_str(obj));
|
||||||
char type;
|
char type;
|
||||||
switch(spec.end()[-1]) {
|
switch(spec.end()[-1]) {
|
||||||
case 'f':
|
case 'f':
|
||||||
@ -651,11 +658,10 @@ PyVar VM::__format_object(PyVar obj, Str spec) {
|
|||||||
align = '<';
|
align = '<';
|
||||||
spec = spec.substr(1);
|
spec = spec.substr(1);
|
||||||
} else {
|
} else {
|
||||||
if(is_int(obj) || is_float(obj)) {
|
if(is_int(obj) || is_float(obj))
|
||||||
align = '>';
|
align = '>';
|
||||||
} else {
|
else
|
||||||
align = '<';
|
align = '<';
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int dot = spec.index(".");
|
int dot = spec.index(".");
|
||||||
@ -674,11 +680,11 @@ PyVar VM::__format_object(PyVar obj, Str spec) {
|
|||||||
}
|
}
|
||||||
} catch(...) { ValueError("invalid format specifer"); }
|
} catch(...) { ValueError("invalid format specifer"); }
|
||||||
|
|
||||||
if(type != 'f' && dot >= 0) { ValueError("precision not allowed in the format specifier"); }
|
if(type != 'f' && dot >= 0) ValueError("precision not allowed in the format specifier");
|
||||||
Str ret;
|
Str ret;
|
||||||
if(type == 'f') {
|
if(type == 'f') {
|
||||||
f64 val = CAST(f64, obj);
|
f64 val = CAST(f64, obj);
|
||||||
if(precision < 0) { precision = 6; }
|
if(precision < 0) precision = 6;
|
||||||
SStream ss;
|
SStream ss;
|
||||||
ss.setprecision(precision);
|
ss.setprecision(precision);
|
||||||
ss << val;
|
ss << val;
|
||||||
@ -694,11 +700,10 @@ PyVar VM::__format_object(PyVar obj, Str spec) {
|
|||||||
int pad = width - ret.length();
|
int pad = width - ret.length();
|
||||||
if(align == '>' || align == '<') {
|
if(align == '>' || align == '<') {
|
||||||
std::string padding(pad, pad_c);
|
std::string padding(pad, pad_c);
|
||||||
if(align == '>') {
|
if(align == '>')
|
||||||
ret = padding.c_str() + ret;
|
ret = padding.c_str() + ret;
|
||||||
} else {
|
else
|
||||||
ret = ret + padding.c_str();
|
ret = ret + padding.c_str();
|
||||||
}
|
|
||||||
} else { // ^
|
} else { // ^
|
||||||
int pad_left = pad / 2;
|
int pad_left = pad / 2;
|
||||||
int pad_right = pad - pad_left;
|
int pad_right = pad - pad_left;
|
||||||
@ -715,7 +720,7 @@ PyObject* VM::new_module(Str name, Str package) {
|
|||||||
obj->attr().set(__name__, VAR(name));
|
obj->attr().set(__name__, VAR(name));
|
||||||
obj->attr().set(__package__, VAR(package));
|
obj->attr().set(__package__, VAR(package));
|
||||||
// convert to fullname
|
// convert to fullname
|
||||||
if(!package.empty()) { name = package + "." + name; }
|
if(!package.empty()) name = package + "." + name;
|
||||||
obj->attr().set(__path__, VAR(name));
|
obj->attr().set(__path__, VAR(name));
|
||||||
|
|
||||||
// we do not allow override in order to avoid memory leak
|
// we do not allow override in order to avoid memory leak
|
||||||
@ -739,7 +744,7 @@ static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject
|
|||||||
case OP_LOAD_CONST:
|
case OP_LOAD_CONST:
|
||||||
case OP_FORMAT_STRING:
|
case OP_FORMAT_STRING:
|
||||||
case OP_IMPORT_PATH:
|
case OP_IMPORT_PATH:
|
||||||
if(vm != nullptr) { ss << " (" << vm->py_repr(co->consts[byte.arg]) << ")"; }
|
if(vm != nullptr) ss << " (" << vm->py_repr(co->consts[byte.arg]) << ")";
|
||||||
break;
|
break;
|
||||||
case OP_LOAD_NAME:
|
case OP_LOAD_NAME:
|
||||||
case OP_LOAD_GLOBAL:
|
case OP_LOAD_GLOBAL:
|
||||||
@ -771,7 +776,7 @@ static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject
|
|||||||
|
|
||||||
Str VM::disassemble(CodeObject_ co) {
|
Str VM::disassemble(CodeObject_ co) {
|
||||||
auto pad = [](const Str& s, const int n) {
|
auto pad = [](const Str& s, const int n) {
|
||||||
if(s.length() >= n) { return s.substr(0, n); }
|
if(s.length() >= n) return s.substr(0, n);
|
||||||
return s + std::string(n - s.length(), ' ');
|
return s + std::string(n - s.length(), ' ');
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -785,10 +790,10 @@ Str VM::disassemble(CodeObject_ co) {
|
|||||||
for(int i = 0; i < co->codes.size(); i++) {
|
for(int i = 0; i < co->codes.size(); i++) {
|
||||||
const Bytecode& byte = co->codes[i];
|
const Bytecode& byte = co->codes[i];
|
||||||
Str line = std::to_string(co->lines[i].lineno);
|
Str line = std::to_string(co->lines[i].lineno);
|
||||||
if(co->lines[i].lineno == prev_line) {
|
if(co->lines[i].lineno == prev_line)
|
||||||
line = "";
|
line = "";
|
||||||
} else {
|
else {
|
||||||
if(prev_line != -1) { ss << "\n"; }
|
if(prev_line != -1) ss << "\n";
|
||||||
prev_line = co->lines[i].lineno;
|
prev_line = co->lines[i].lineno;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -800,11 +805,11 @@ Str VM::disassemble(CodeObject_ co) {
|
|||||||
}
|
}
|
||||||
ss << pad(line, 8) << pointer << pad(std::to_string(i), 3);
|
ss << pad(line, 8) << pointer << pad(std::to_string(i), 3);
|
||||||
std::string bc_name(OP_NAMES[byte.op]);
|
std::string bc_name(OP_NAMES[byte.op]);
|
||||||
if(co->lines[i].is_virtual) { bc_name += '*'; }
|
if(co->lines[i].is_virtual) bc_name += '*';
|
||||||
ss << " " << pad(bc_name, 25) << " ";
|
ss << " " << pad(bc_name, 25) << " ";
|
||||||
std::string argStr = _opcode_argstr(this, i, byte, co.get());
|
std::string argStr = _opcode_argstr(this, i, byte, co.get());
|
||||||
ss << argStr;
|
ss << argStr;
|
||||||
if(i != co->codes.size() - 1) { ss << '\n'; }
|
if(i != co->codes.size() - 1) ss << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& decl: co->func_decls) {
|
for(auto& decl: co->func_decls) {
|
||||||
@ -818,10 +823,10 @@ Str VM::disassemble(CodeObject_ co) {
|
|||||||
|
|
||||||
#if PK_DEBUG_CEVAL_STEP
|
#if PK_DEBUG_CEVAL_STEP
|
||||||
void VM::__log_s_data(const char* title) {
|
void VM::__log_s_data(const char* title) {
|
||||||
if(_main == nullptr) { return; }
|
if(_main == nullptr) return;
|
||||||
if(callstack.empty()) { return; }
|
if(callstack.empty()) return;
|
||||||
SStream ss;
|
SStream ss;
|
||||||
if(title) { ss << title << " | "; }
|
if(title) ss << title << " | ";
|
||||||
std::map<PyVar*, int> sp_bases;
|
std::map<PyVar*, int> sp_bases;
|
||||||
callstack.apply([&](Frame& f) {
|
callstack.apply([&](Frame& f) {
|
||||||
assert(f._sp_base != nullptr);
|
assert(f._sp_base != nullptr);
|
||||||
@ -832,10 +837,10 @@ void VM::__log_s_data(const char* title) {
|
|||||||
ss << frame->co->name << ":" << line << " [";
|
ss << frame->co->name << ":" << line << " [";
|
||||||
for(PyVar* p = s_data.begin(); p != s_data.end(); p++) {
|
for(PyVar* p = s_data.begin(); p != s_data.end(); p++) {
|
||||||
ss << std::string(sp_bases[p], '|');
|
ss << std::string(sp_bases[p], '|');
|
||||||
if(sp_bases[p] > 0) { ss << " "; }
|
if(sp_bases[p] > 0) ss << " ";
|
||||||
if(*p == PY_NULL) {
|
if(*p == PY_NULL)
|
||||||
ss << "NULL";
|
ss << "NULL";
|
||||||
} else {
|
else {
|
||||||
switch(p->type) {
|
switch(p->type) {
|
||||||
case tp_none_type: ss << "None"; break;
|
case tp_none_type: ss << "None"; break;
|
||||||
case tp_int: ss << _CAST(i64, *p); break;
|
case tp_int: ss << _CAST(i64, *p); break;
|
||||||
@ -849,7 +854,7 @@ void VM::__log_s_data(const char* title) {
|
|||||||
case tp_stack_memory: {
|
case tp_stack_memory: {
|
||||||
int count = p->obj_get<StackMemory>().count;
|
int count = p->obj_get<StackMemory>().count;
|
||||||
ss << "M[" << count << "]";
|
ss << "M[" << count << "]";
|
||||||
if(count > 0) { p += count; }
|
if(count > 0) p += count;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: ss << "(" << _type_name(this, p->type) << ")"; break;
|
default: ss << "(" << _type_name(this, p->type) << ")"; break;
|
||||||
@ -876,7 +881,7 @@ void VM::__init_builtin_types() {
|
|||||||
|
|
||||||
auto validate = [](Type type, PyObject* ret) {
|
auto validate = [](Type type, PyObject* ret) {
|
||||||
Type ret_t = ret->as<Type>();
|
Type ret_t = ret->as<Type>();
|
||||||
if(ret_t != type) { exit(-3); }
|
if(ret_t != type) exit(-3);
|
||||||
};
|
};
|
||||||
|
|
||||||
validate(tp_int, new_type_object(nullptr, "int", tp_object, false));
|
validate(tp_int, new_type_object(nullptr, "int", tp_object, false));
|
||||||
@ -947,7 +952,7 @@ void VM::__unpack_as_list(ArgsView args, List& list) {
|
|||||||
if(is_type(obj, tp_star_wrapper)) {
|
if(is_type(obj, tp_star_wrapper)) {
|
||||||
const StarWrapper& w = _CAST(StarWrapper&, obj);
|
const StarWrapper& w = _CAST(StarWrapper&, obj);
|
||||||
// maybe this check should be done in the compile time
|
// maybe this check should be done in the compile time
|
||||||
if(w.level != 1) { TypeError("expected level 1 star wrapper"); }
|
if(w.level != 1) TypeError("expected level 1 star wrapper");
|
||||||
PyVar _0 = py_iter(w.obj);
|
PyVar _0 = py_iter(w.obj);
|
||||||
const PyTypeInfo* info = _tp_info(_0);
|
const PyTypeInfo* info = _tp_info(_0);
|
||||||
PyVar _1 = _py_next(info, _0);
|
PyVar _1 = _py_next(info, _0);
|
||||||
@ -967,12 +972,12 @@ void VM::__unpack_as_dict(ArgsView args, Dict& dict) {
|
|||||||
if(is_type(obj, tp_star_wrapper)) {
|
if(is_type(obj, tp_star_wrapper)) {
|
||||||
const StarWrapper& w = _CAST(StarWrapper&, obj);
|
const StarWrapper& w = _CAST(StarWrapper&, obj);
|
||||||
// maybe this check should be done in the compile time
|
// maybe this check should be done in the compile time
|
||||||
if(w.level != 2) { TypeError("expected level 2 star wrapper"); }
|
if(w.level != 2) TypeError("expected level 2 star wrapper");
|
||||||
const Dict& other = CAST(Dict&, w.obj);
|
const Dict& other = CAST(Dict&, w.obj);
|
||||||
dict.update(this, other);
|
dict.update(this, other);
|
||||||
} else {
|
} else {
|
||||||
const Tuple& t = CAST(Tuple&, obj);
|
const Tuple& t = CAST(Tuple&, obj);
|
||||||
if(t.size() != 2) { TypeError("expected tuple of length 2"); }
|
if(t.size() != 2) TypeError("expected tuple of length 2");
|
||||||
dict.set(this, t[0], t[1]);
|
dict.set(this, t[0], t[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -989,13 +994,11 @@ void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
// prepare args
|
// prepare args
|
||||||
std::memset(buffer, 0, co->nlocals * sizeof(PyVar));
|
std::memset(buffer, 0, co->nlocals * sizeof(PyVar));
|
||||||
for(int index: decl->args) {
|
for(int index: decl->args)
|
||||||
buffer[index] = args[i++];
|
buffer[index] = args[i++];
|
||||||
}
|
|
||||||
// prepare kwdefaults
|
// prepare kwdefaults
|
||||||
for(auto& kv: decl->kwargs) {
|
for(auto& kv: decl->kwargs)
|
||||||
buffer[kv.index] = kv.value;
|
buffer[kv.index] = kv.value;
|
||||||
}
|
|
||||||
|
|
||||||
// handle *args
|
// handle *args
|
||||||
if(decl->starred_arg != -1) {
|
if(decl->starred_arg != -1) {
|
||||||
@ -1005,10 +1008,10 @@ void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const
|
|||||||
} else {
|
} else {
|
||||||
// kwdefaults override
|
// kwdefaults override
|
||||||
for(auto& kv: decl->kwargs) {
|
for(auto& kv: decl->kwargs) {
|
||||||
if(i >= args.size()) { break; }
|
if(i >= args.size()) break;
|
||||||
buffer[kv.index] = args[i++];
|
buffer[kv.index] = args[i++];
|
||||||
}
|
}
|
||||||
if(i < args.size()) { TypeError(_S("too many arguments", " (", decl->code->name, ')')); }
|
if(i < args.size()) TypeError(_S("too many arguments", " (", decl->code->name, ')'));
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar vkwargs;
|
PyVar vkwargs;
|
||||||
@ -1064,7 +1067,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
|||||||
if(callable_t == tp_function) {
|
if(callable_t == tp_function) {
|
||||||
/*****************_py_call*****************/
|
/*****************_py_call*****************/
|
||||||
// check stack overflow
|
// check stack overflow
|
||||||
if(s_data.is_overflow()) { StackOverflowError(); }
|
if(s_data.is_overflow()) StackOverflowError();
|
||||||
|
|
||||||
const Function& fn = PK_OBJ_GET(Function, callable);
|
const Function& fn = PK_OBJ_GET(Function, callable);
|
||||||
const CodeObject* co = fn.decl->code.get();
|
const CodeObject* co = fn.decl->code.get();
|
||||||
@ -1074,20 +1077,18 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
|||||||
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
|
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
|
||||||
// copy buffer back to stack
|
// copy buffer back to stack
|
||||||
s_data.reset(_base + co->nlocals);
|
s_data.reset(_base + co->nlocals);
|
||||||
for(int j = 0; j < co->nlocals; j++) {
|
for(int j = 0; j < co->nlocals; j++)
|
||||||
_base[j] = __vectorcall_buffer[j];
|
_base[j] = __vectorcall_buffer[j];
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case FuncType::SIMPLE:
|
case FuncType::SIMPLE:
|
||||||
if(args.size() != fn.decl->args.size()) {
|
if(args.size() != fn.decl->args.size())
|
||||||
TypeError(_S(co->name,
|
TypeError(_S(co->name,
|
||||||
"() takes ",
|
"() takes ",
|
||||||
fn.decl->args.size(),
|
fn.decl->args.size(),
|
||||||
" positional arguments but ",
|
" positional arguments but ",
|
||||||
args.size(),
|
args.size(),
|
||||||
" were given"));
|
" were given"));
|
||||||
}
|
if(!kwargs.empty()) TypeError(_S(co->name, "() takes no keyword arguments"));
|
||||||
if(!kwargs.empty()) { TypeError(_S(co->name, "() takes no keyword arguments")); }
|
|
||||||
// [callable, <self>, args..., local_vars...]
|
// [callable, <self>, args..., local_vars...]
|
||||||
// ^p0 ^p1 ^_sp
|
// ^p0 ^p1 ^_sp
|
||||||
s_data.reset(_base + co->nlocals);
|
s_data.reset(_base + co->nlocals);
|
||||||
@ -1095,15 +1096,14 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
|||||||
std::memset(p1, 0, (char*)s_data._sp - (char*)p1);
|
std::memset(p1, 0, (char*)s_data._sp - (char*)p1);
|
||||||
break;
|
break;
|
||||||
case FuncType::EMPTY:
|
case FuncType::EMPTY:
|
||||||
if(args.size() != fn.decl->args.size()) {
|
if(args.size() != fn.decl->args.size())
|
||||||
TypeError(_S(co->name,
|
TypeError(_S(co->name,
|
||||||
"() takes ",
|
"() takes ",
|
||||||
fn.decl->args.size(),
|
fn.decl->args.size(),
|
||||||
" positional arguments but ",
|
" positional arguments but ",
|
||||||
args.size(),
|
args.size(),
|
||||||
" were given"));
|
" were given"));
|
||||||
}
|
if(!kwargs.empty()) TypeError(_S(co->name, "() takes no keyword arguments"));
|
||||||
if(!kwargs.empty()) { TypeError(_S(co->name, "() takes no keyword arguments")); }
|
|
||||||
s_data.reset(p0);
|
s_data.reset(p0);
|
||||||
return None;
|
return None;
|
||||||
case FuncType::GENERATOR:
|
case FuncType::GENERATOR:
|
||||||
@ -1117,7 +1117,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
|||||||
|
|
||||||
// simple or normal
|
// simple or normal
|
||||||
callstack.emplace(p0, co, fn._module, callable.get(), args.begin());
|
callstack.emplace(p0, co, fn._module, callable.get(), args.begin());
|
||||||
if(op_call) { return PY_OP_CALL; }
|
if(op_call) return PY_OP_CALL;
|
||||||
return __run_top_frame();
|
return __run_top_frame();
|
||||||
/*****************_py_call*****************/
|
/*****************_py_call*****************/
|
||||||
}
|
}
|
||||||
@ -1130,16 +1130,14 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
|||||||
__prepare_py_call(__vectorcall_buffer, args, kwargs, f.decl);
|
__prepare_py_call(__vectorcall_buffer, args, kwargs, f.decl);
|
||||||
// copy buffer back to stack
|
// copy buffer back to stack
|
||||||
s_data.reset(_base + co_nlocals);
|
s_data.reset(_base + co_nlocals);
|
||||||
for(int j = 0; j < co_nlocals; j++) {
|
for(int j = 0; j < co_nlocals; j++)
|
||||||
_base[j] = __vectorcall_buffer[j];
|
_base[j] = __vectorcall_buffer[j];
|
||||||
}
|
|
||||||
ret = f.call(vm, ArgsView(s_data._sp - co_nlocals, s_data._sp));
|
ret = f.call(vm, ArgsView(s_data._sp - co_nlocals, s_data._sp));
|
||||||
} else {
|
} else {
|
||||||
if(f.argc != -1) {
|
if(f.argc != -1) {
|
||||||
if(KWARGC != 0) {
|
if(KWARGC != 0)
|
||||||
TypeError(
|
TypeError(
|
||||||
"old-style native_func does not accept keyword arguments. If you want to skip this check, specify `argc` to -1");
|
"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(args.size() != f.argc) { vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size())); }
|
||||||
}
|
}
|
||||||
ret = f.call(this, args);
|
ret = f.call(this, args);
|
||||||
@ -1160,12 +1158,10 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
|||||||
PUSH(new_f);
|
PUSH(new_f);
|
||||||
PUSH(PY_NULL);
|
PUSH(PY_NULL);
|
||||||
PUSH(callable); // cls
|
PUSH(callable); // cls
|
||||||
for(PyVar o: args) {
|
for(PyVar o: args)
|
||||||
PUSH(o);
|
PUSH(o);
|
||||||
}
|
for(PyVar o: kwargs)
|
||||||
for(PyVar o: kwargs) {
|
|
||||||
PUSH(o);
|
PUSH(o);
|
||||||
}
|
|
||||||
// if obj is not an instance of `cls`, the behavior is undefined
|
// if obj is not an instance of `cls`, the behavior is undefined
|
||||||
obj = vectorcall(ARGC + 1, KWARGC);
|
obj = vectorcall(ARGC + 1, KWARGC);
|
||||||
}
|
}
|
||||||
@ -1203,9 +1199,9 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
|||||||
|
|
||||||
void VM::delattr(PyVar _0, StrName _name) {
|
void VM::delattr(PyVar _0, StrName _name) {
|
||||||
const PyTypeInfo* ti = _tp_info(_0);
|
const PyTypeInfo* ti = _tp_info(_0);
|
||||||
if(ti->m__delattr__ && ti->m__delattr__(this, _0, _name)) { return; }
|
if(ti->m__delattr__ && ti->m__delattr__(this, _0, _name)) return;
|
||||||
if(is_tagged(_0) || !_0->is_attr_valid()) { TypeError("cannot delete attribute"); }
|
if(is_tagged(_0) || !_0->is_attr_valid()) TypeError("cannot delete attribute");
|
||||||
if(!_0->attr().del(_name)) { AttributeError(_0, _name); }
|
if(!_0->attr().del(_name)) AttributeError(_0, _name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
|
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
|
||||||
@ -1233,14 +1229,14 @@ PyVar VM::getattr(PyVar obj, StrName name, bool throw_err) {
|
|||||||
if(obj.type == tp_type) {
|
if(obj.type == tp_type) {
|
||||||
val = find_name_in_mro(PK_OBJ_GET(Type, obj), name);
|
val = find_name_in_mro(PK_OBJ_GET(Type, obj), name);
|
||||||
if(val != nullptr) {
|
if(val != nullptr) {
|
||||||
if(is_tagged(*val)) { return *val; }
|
if(is_tagged(*val)) return *val;
|
||||||
if(val->type == tp_staticmethod) { return PK_OBJ_GET(StaticMethod, *val).func; }
|
if(val->type == tp_staticmethod) return PK_OBJ_GET(StaticMethod, *val).func;
|
||||||
if(val->type == tp_classmethod) { return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, *val).func)); }
|
if(val->type == tp_classmethod) return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, *val).func));
|
||||||
return *val;
|
return *val;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val = obj->attr().try_get_2_likely_found(name);
|
val = obj->attr().try_get_2_likely_found(name);
|
||||||
if(val != nullptr) { return *val; }
|
if(val != nullptr) return *val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(cls_var != nullptr) {
|
if(cls_var != nullptr) {
|
||||||
@ -1259,10 +1255,10 @@ PyVar VM::getattr(PyVar obj, StrName name, bool throw_err) {
|
|||||||
const PyTypeInfo* ti = &_all_types[objtype];
|
const PyTypeInfo* ti = &_all_types[objtype];
|
||||||
if(ti->m__getattr__) {
|
if(ti->m__getattr__) {
|
||||||
PyVar ret = ti->m__getattr__(this, obj, name);
|
PyVar ret = ti->m__getattr__(this, obj, name);
|
||||||
if(ret) { return ret; }
|
if(ret) return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(throw_err) { AttributeError(obj, name); }
|
if(throw_err) AttributeError(obj, name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1295,16 +1291,14 @@ PyVar VM::get_unbound_method(PyVar obj, StrName name, PyVar* self, bool throw_er
|
|||||||
if(obj.type == tp_type) {
|
if(obj.type == tp_type) {
|
||||||
val = find_name_in_mro(PK_OBJ_GET(Type, obj), name);
|
val = find_name_in_mro(PK_OBJ_GET(Type, obj), name);
|
||||||
if(val != nullptr) {
|
if(val != nullptr) {
|
||||||
if(is_tagged(*val)) { return *val; }
|
if(is_tagged(*val)) return *val;
|
||||||
if(val->type == tp_staticmethod) { return PK_OBJ_GET(StaticMethod, *val).func; }
|
if(val->type == tp_staticmethod) return PK_OBJ_GET(StaticMethod, *val).func;
|
||||||
if(val->type == tp_classmethod) {
|
if(val->type == tp_classmethod) return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, *val).func));
|
||||||
return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, *val).func));
|
|
||||||
}
|
|
||||||
return *val;
|
return *val;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val = obj->attr().try_get_2_likely_found(name);
|
val = obj->attr().try_get_2_likely_found(name);
|
||||||
if(val != nullptr) { return *val; }
|
if(val != nullptr) return *val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1324,10 +1318,10 @@ PyVar VM::get_unbound_method(PyVar obj, StrName name, PyVar* self, bool throw_er
|
|||||||
const PyTypeInfo* ti = &_all_types[objtype];
|
const PyTypeInfo* ti = &_all_types[objtype];
|
||||||
if(fallback && ti->m__getattr__) {
|
if(fallback && ti->m__getattr__) {
|
||||||
PyVar ret = ti->m__getattr__(this, obj, name);
|
PyVar ret = ti->m__getattr__(this, obj, name);
|
||||||
if(ret) { return ret; }
|
if(ret) return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(throw_err) { AttributeError(obj, name); }
|
if(throw_err) AttributeError(obj, name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1362,7 +1356,7 @@ void VM::setattr(PyVar obj, StrName name, PyVar value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle instance __dict__
|
// handle instance __dict__
|
||||||
if(is_tagged(obj) || !obj->is_attr_valid()) { TypeError("cannot set attribute"); }
|
if(is_tagged(obj) || !obj->is_attr_valid()) TypeError("cannot set attribute");
|
||||||
obj->attr().set(name, value);
|
obj->attr().set(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1373,7 +1367,7 @@ PyObject* VM::bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, a
|
|||||||
case BindType::STATICMETHOD: nf = heap.gcnew<StaticMethod>(tp_staticmethod, nf); 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::CLASSMETHOD: nf = heap.gcnew<ClassMethod>(tp_classmethod, nf); break;
|
||||||
}
|
}
|
||||||
if(obj != nullptr) { obj->attr().set(name, nf); }
|
if(obj != nullptr) obj->attr().set(name, nf);
|
||||||
return nf;
|
return nf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1397,7 +1391,7 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
|
|||||||
case BindType::CLASSMETHOD: f_obj = heap.gcnew<ClassMethod>(tp_classmethod, f_obj); break;
|
case BindType::CLASSMETHOD: f_obj = heap.gcnew<ClassMethod>(tp_classmethod, f_obj); break;
|
||||||
case BindType::DEFAULT: break;
|
case BindType::DEFAULT: break;
|
||||||
}
|
}
|
||||||
if(obj != nullptr) { obj->attr().set(decl->code->name, f_obj); }
|
if(obj != nullptr) obj->attr().set(decl->code->name, f_obj);
|
||||||
return f_obj;
|
return f_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1405,10 +1399,10 @@ PyObject* VM::bind_property(PyObject* obj, const char* name, NativeFuncC fget, N
|
|||||||
assert(is_type(obj, tp_type));
|
assert(is_type(obj, tp_type));
|
||||||
std::string_view name_sv(name);
|
std::string_view name_sv(name);
|
||||||
int pos = name_sv.find(':');
|
int pos = name_sv.find(':');
|
||||||
if(pos > 0) { name_sv = name_sv.substr(0, pos); }
|
if(pos > 0) name_sv = name_sv.substr(0, pos);
|
||||||
PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1);
|
PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1);
|
||||||
PyVar _1 = vm->None;
|
PyVar _1 = vm->None;
|
||||||
if(fset != nullptr) { _1 = new_object<NativeFunc>(tp_native_func, fset, 2); }
|
if(fset != nullptr) _1 = new_object<NativeFunc>(tp_native_func, fset, 2);
|
||||||
PyObject* prop = heap.gcnew<Property>(tp_property, _0, _1);
|
PyObject* prop = heap.gcnew<Property>(tp_property, _0, _1);
|
||||||
obj->attr().set(StrName(name_sv), prop);
|
obj->attr().set(StrName(name_sv), prop);
|
||||||
return prop;
|
return prop;
|
||||||
@ -1459,12 +1453,10 @@ void VM::__raise_exc(bool re_raise) {
|
|||||||
int next_ip = frame->prepare_jump_exception_handler(&s_data);
|
int next_ip = frame->prepare_jump_exception_handler(&s_data);
|
||||||
|
|
||||||
int actual_ip = frame->ip();
|
int actual_ip = frame->ip();
|
||||||
if(e._ip_on_error >= 0 && e._code_on_error == (void*)frame->co) { actual_ip = e._ip_on_error; }
|
if(e._ip_on_error >= 0 && e._code_on_error == (void*)frame->co) actual_ip = e._ip_on_error;
|
||||||
int current_line = frame->co->lines[actual_ip].lineno; // current line
|
int current_line = frame->co->lines[actual_ip].lineno; // current line
|
||||||
auto current_f_name = frame->co->name.sv(); // current function name
|
auto current_f_name = frame->co->name.sv(); // current function name
|
||||||
if(frame->_callable == nullptr) {
|
if(frame->_callable == nullptr) current_f_name = ""; // not in a function
|
||||||
current_f_name = ""; // not in a function
|
|
||||||
}
|
|
||||||
e.st_push(frame->co->src, current_line, nullptr, current_f_name);
|
e.st_push(frame->co->src, current_line, nullptr, current_f_name);
|
||||||
|
|
||||||
if(next_ip >= 0) {
|
if(next_ip >= 0) {
|
||||||
@ -1482,7 +1474,9 @@ void VM::bind__getitem__(Type type, PyVar (*f)(VM*, PyVar, PyVar)) {
|
|||||||
type,
|
type,
|
||||||
__getitem__,
|
__getitem__,
|
||||||
2,
|
2,
|
||||||
[](VM* vm, ArgsView args) { return lambda_get_userdata<decltype(f)>(args.begin())(vm, args[0], args[1]); },
|
[](VM* vm, ArgsView args) {
|
||||||
|
return lambda_get_userdata<decltype(f)>(args.begin())(vm, args[0], args[1]);
|
||||||
|
},
|
||||||
f);
|
f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1513,8 +1507,8 @@ void VM::bind__delitem__(Type type, void (*f)(VM*, PyVar, PyVar)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyVar VM::__pack_next_retval(unsigned n) {
|
PyVar VM::__pack_next_retval(unsigned n) {
|
||||||
if(n == 0) { return StopIteration; }
|
if(n == 0) return StopIteration;
|
||||||
if(n == 1) { return s_data.popx(); }
|
if(n == 1) return s_data.popx();
|
||||||
PyVar retval = VAR(s_data.view(n).to_tuple());
|
PyVar retval = VAR(s_data.view(n).to_tuple());
|
||||||
s_data._sp -= n;
|
s_data._sp -= n;
|
||||||
return retval;
|
return retval;
|
||||||
@ -1662,7 +1656,7 @@ void Dict::_probe_0(VM* vm, PyVar key, bool& ok, int& i) const {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(_items[i].second == nullptr) { break; }
|
if(_items[i].second == nullptr) break;
|
||||||
}
|
}
|
||||||
// https://github.com/python/cpython/blob/3.8/Objects/dictobject.c#L166
|
// https://github.com/python/cpython/blob/3.8/Objects/dictobject.c#L166
|
||||||
i = ((5 * i) + 1) & _mask;
|
i = ((5 * i) + 1) & _mask;
|
||||||
@ -1690,7 +1684,7 @@ void NextBreakpoint::_step(VM* vm) {
|
|||||||
if(curr_callstack_size != callstack_size || curr_lineno != lineno) { vm->__breakpoint(); }
|
if(curr_callstack_size != callstack_size || curr_lineno != lineno) { vm->__breakpoint(); }
|
||||||
} else {
|
} else {
|
||||||
if(curr_callstack_size == callstack_size) {
|
if(curr_callstack_size == callstack_size) {
|
||||||
if(curr_lineno != lineno) { vm->__breakpoint(); }
|
if(curr_lineno != lineno) vm->__breakpoint();
|
||||||
} else if(curr_callstack_size < callstack_size) {
|
} else if(curr_callstack_size < callstack_size) {
|
||||||
// returning
|
// returning
|
||||||
vm->__breakpoint();
|
vm->__breakpoint();
|
||||||
@ -1723,12 +1717,12 @@ void VM::__breakpoint() {
|
|||||||
while(lf != nullptr) {
|
while(lf != nullptr) {
|
||||||
frames.push_back(lf);
|
frames.push_back(lf);
|
||||||
lf = lf->f_back;
|
lf = lf->f_back;
|
||||||
if(frames.size() >= 4) { break; }
|
if(frames.size() >= 4) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(show_headers) {
|
if(show_headers) {
|
||||||
for(int i = frames.size() - 1; i >= 0; i--) {
|
for(int i = frames.size() - 1; i >= 0; i--) {
|
||||||
if(!show_where && i != 0) { continue; }
|
if(!show_where && i != 0) continue;
|
||||||
|
|
||||||
SStream ss;
|
SStream ss;
|
||||||
Frame* frame = &frames[i]->frame;
|
Frame* frame = &frames[i]->frame;
|
||||||
@ -1782,11 +1776,11 @@ void VM::__breakpoint() {
|
|||||||
show_headers = true;
|
show_headers = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(line == "c" || line == "continue") { break; }
|
if(line == "c" || line == "continue") break;
|
||||||
if(line == "a" || line == "args") {
|
if(line == "a" || line == "args") {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for(PyVar obj: frame_0->_locals) {
|
for(PyVar obj: frame_0->_locals) {
|
||||||
if(obj == PY_NULL) { continue; }
|
if(obj == PY_NULL) continue;
|
||||||
StrName name = frame_0->co->varnames[i++];
|
StrName name = frame_0->co->varnames[i++];
|
||||||
stdout_write(_S(name.sv(), " = ", vm->py_repr(obj), '\n'));
|
stdout_write(_S(name.sv(), " = ", vm->py_repr(obj), '\n'));
|
||||||
}
|
}
|
||||||
@ -1797,7 +1791,7 @@ void VM::__breakpoint() {
|
|||||||
bool is_longlist = line == "ll" || line == "longlist";
|
bool is_longlist = line == "ll" || line == "longlist";
|
||||||
|
|
||||||
if(is_list || is_longlist) {
|
if(is_list || is_longlist) {
|
||||||
if(frame_0->co->src->is_precompiled) { continue; }
|
if(frame_0->co->src->is_precompiled) continue;
|
||||||
int lineno = frame_0->curr_lineno();
|
int lineno = frame_0->curr_lineno();
|
||||||
int start, end;
|
int start, end;
|
||||||
|
|
||||||
@ -1808,7 +1802,7 @@ void VM::__breakpoint() {
|
|||||||
} else {
|
} else {
|
||||||
start = frame_0->co->start_line;
|
start = frame_0->co->start_line;
|
||||||
end = frame_0->co->end_line;
|
end = frame_0->co->end_line;
|
||||||
if(start == -1 || end == -1) { continue; }
|
if(start == -1 || end == -1) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SStream ss;
|
SStream ss;
|
||||||
@ -1816,11 +1810,10 @@ void VM::__breakpoint() {
|
|||||||
for(int i = start; i <= end; i++) {
|
for(int i = start; i <= end; i++) {
|
||||||
int spaces = max_width - std::to_string(i).size();
|
int spaces = max_width - std::to_string(i).size();
|
||||||
ss << std::string(spaces, ' ') << std::to_string(i);
|
ss << std::string(spaces, ' ') << std::to_string(i);
|
||||||
if(i == lineno) {
|
if(i == lineno)
|
||||||
ss << " -> ";
|
ss << " -> ";
|
||||||
} else {
|
else
|
||||||
ss << " ";
|
ss << " ";
|
||||||
}
|
|
||||||
ss << frame_0->co->src->get_line(i) << '\n';
|
ss << frame_0->co->src->get_line(i) << '\n';
|
||||||
}
|
}
|
||||||
stdout_write(ss.str());
|
stdout_write(ss.str());
|
||||||
@ -1831,9 +1824,7 @@ void VM::__breakpoint() {
|
|||||||
if(space != -1) {
|
if(space != -1) {
|
||||||
std::string cmd = line.substr(0, space);
|
std::string cmd = line.substr(0, space);
|
||||||
std::string arg = line.substr(space + 1);
|
std::string arg = line.substr(space + 1);
|
||||||
if(arg.empty()) {
|
if(arg.empty()) continue; // ignore empty command
|
||||||
continue; // ignore empty command
|
|
||||||
}
|
|
||||||
if(cmd == "p" || cmd == "print") {
|
if(cmd == "p" || cmd == "print") {
|
||||||
CodeObject_ code = compile(arg, "<stdin>", EVAL_MODE, true);
|
CodeObject_ code = compile(arg, "<stdin>", EVAL_MODE, true);
|
||||||
PyVar retval = vm->_exec(code.get(), frame_0->_module, frame_0->_callable, frame_0->_locals);
|
PyVar retval = vm->_exec(code.get(), frame_0->_module, frame_0->_callable, frame_0->_locals);
|
||||||
@ -1853,31 +1844,30 @@ void VM::__breakpoint() {
|
|||||||
void Function::_gc_mark(VM* vm) const {
|
void Function::_gc_mark(VM* vm) const {
|
||||||
decl->_gc_mark(vm);
|
decl->_gc_mark(vm);
|
||||||
if(_closure) {
|
if(_closure) {
|
||||||
_closure->apply([=](StrName _, PyVar obj) { vm->obj_gc_mark(obj); });
|
_closure->apply([=](StrName _, PyVar obj) {
|
||||||
|
vm->obj_gc_mark(obj);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeFunc::_gc_mark(VM* vm) const {
|
void NativeFunc::_gc_mark(VM* vm) const {
|
||||||
if(decl) { decl->_gc_mark(vm); }
|
if(decl) decl->_gc_mark(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FuncDecl::_gc_mark(VM* vm) const {
|
void FuncDecl::_gc_mark(VM* vm) const {
|
||||||
code->_gc_mark(vm);
|
code->_gc_mark(vm);
|
||||||
for(int i = 0; i < kwargs.size(); i++) {
|
for(int i = 0; i < kwargs.size(); i++)
|
||||||
vm->obj_gc_mark(kwargs[i].value);
|
vm->obj_gc_mark(kwargs[i].value);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void List::_gc_mark(VM* vm) const {
|
void List::_gc_mark(VM* vm) const {
|
||||||
for(PyVar obj: *this) {
|
for(PyVar obj: *this)
|
||||||
vm->obj_gc_mark(obj);
|
vm->obj_gc_mark(obj);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tuple::_gc_mark(VM* vm) const {
|
void Tuple::_gc_mark(VM* vm) const {
|
||||||
for(PyVar obj: *this) {
|
for(PyVar obj: *this)
|
||||||
vm->obj_gc_mark(obj);
|
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); }
|
||||||
@ -1914,23 +1904,23 @@ void Frame::_gc_mark(VM* vm) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ManagedHeap::mark() {
|
void ManagedHeap::mark() {
|
||||||
for(PyObject* obj: _no_gc) {
|
for(PyObject* obj: _no_gc)
|
||||||
vm->__obj_gc_mark(obj);
|
vm->__obj_gc_mark(obj);
|
||||||
}
|
vm->callstack.apply([this](Frame& frame) {
|
||||||
vm->callstack.apply([this](Frame& frame) { frame._gc_mark(vm); });
|
frame._gc_mark(vm);
|
||||||
for(auto [_, co]: vm->__cached_codes) {
|
});
|
||||||
|
for(auto [_, co]: vm->__cached_codes)
|
||||||
co->_gc_mark(vm);
|
co->_gc_mark(vm);
|
||||||
}
|
|
||||||
vm->obj_gc_mark(vm->__last_exception);
|
vm->obj_gc_mark(vm->__last_exception);
|
||||||
vm->obj_gc_mark(vm->__curr_class);
|
vm->obj_gc_mark(vm->__curr_class);
|
||||||
vm->obj_gc_mark(vm->__c.error);
|
vm->obj_gc_mark(vm->__c.error);
|
||||||
vm->__stack_gc_mark(vm->s_data.begin(), vm->s_data.end());
|
vm->__stack_gc_mark(vm->s_data.begin(), vm->s_data.end());
|
||||||
if(_gc_marker_ex) { _gc_marker_ex(vm); }
|
if(_gc_marker_ex) _gc_marker_ex(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ManagedHeap::_delete(PyObject* obj) {
|
void ManagedHeap::_delete(PyObject* obj) {
|
||||||
const PyTypeInfo* ti = vm->_tp_info(obj->type);
|
const PyTypeInfo* ti = vm->_tp_info(obj->type);
|
||||||
if(ti->vt._dtor) { ti->vt._dtor(obj->_value_ptr()); }
|
if(ti->vt._dtor) ti->vt._dtor(obj->_value_ptr());
|
||||||
delete obj->_attr; // delete __dict__ if exists
|
delete obj->_attr; // delete __dict__ if exists
|
||||||
PoolObject_dealloc(obj);
|
PoolObject_dealloc(obj);
|
||||||
}
|
}
|
||||||
@ -1943,12 +1933,10 @@ void Dict::_gc_mark(VM* vm) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CodeObject::_gc_mark(VM* vm) const {
|
void CodeObject::_gc_mark(VM* vm) const {
|
||||||
for(PyVar v: consts) {
|
for(PyVar v: consts)
|
||||||
vm->obj_gc_mark(v);
|
vm->obj_gc_mark(v);
|
||||||
}
|
for(auto& decl: func_decls)
|
||||||
for(auto& decl: func_decls) {
|
|
||||||
decl->_gc_mark(vm);
|
decl->_gc_mark(vm);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -28,7 +28,7 @@ struct Array2d {
|
|||||||
bool is_valid(int col, int row) const { return 0 <= col && col < n_cols && 0 <= row && row < n_rows; }
|
bool is_valid(int col, int row) const { return 0 <= col && col < n_cols && 0 <= row && row < n_rows; }
|
||||||
|
|
||||||
void check_valid(VM* vm, int col, int row) const {
|
void check_valid(VM* vm, int col, int row) const {
|
||||||
if(is_valid(col, row)) { return; }
|
if(is_valid(col, row)) return;
|
||||||
vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')'));
|
vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,13 +49,11 @@ struct Array2d {
|
|||||||
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);
|
self.init(n_cols, n_rows);
|
||||||
if(vm->py_callable(args[3])) {
|
if(vm->py_callable(args[3])) {
|
||||||
for(int i = 0; i < self.numel; i++) {
|
for(int i = 0; i < self.numel; i++)
|
||||||
self.data[i] = vm->call(args[3]);
|
self.data[i] = vm->call(args[3]);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for(int i = 0; i < self.numel; i++) {
|
for(int i = 0; i < self.numel; i++)
|
||||||
self.data[i] = args[3];
|
self.data[i] = args[3];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
@ -96,7 +94,7 @@ struct Array2d {
|
|||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
int col = CAST(int, args[1]);
|
int col = CAST(int, args[1]);
|
||||||
int row = CAST(int, args[2]);
|
int row = CAST(int, args[2]);
|
||||||
if(!self.is_valid(col, row)) { return args[3]; }
|
if(!self.is_valid(col, row)) return args[3];
|
||||||
return self._get(col, row);
|
return self._get(col, row);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -160,11 +158,9 @@ struct Array2d {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(is_basic_type) {
|
if(is_basic_type) {
|
||||||
for(int j = 0; j < slice_height; j++) {
|
for(int j = 0; j < slice_height; j++)
|
||||||
for(int i = 0; i < slice_width; i++) {
|
for(int i = 0; i < slice_width; i++)
|
||||||
self._set(i + start_col, j + start_row, _2);
|
self._set(i + start_col, j + start_row, _2);
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,11 +172,9 @@ struct Array2d {
|
|||||||
if(slice_width != other.n_cols || slice_height != other.n_rows) {
|
if(slice_width != other.n_cols || slice_height != other.n_rows) {
|
||||||
vm->ValueError("array2d size does not match the slice size");
|
vm->ValueError("array2d size does not match the slice size");
|
||||||
}
|
}
|
||||||
for(int j = 0; j < slice_height; j++) {
|
for(int j = 0; j < slice_height; j++)
|
||||||
for(int i = 0; i < slice_width; i++) {
|
for(int i = 0; i < slice_width; i++)
|
||||||
self._set(i + start_col, j + start_row, other._get(i, j));
|
self._set(i + start_col, j + start_row, other._get(i, j));
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index");
|
vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index");
|
||||||
@ -193,9 +187,8 @@ struct Array2d {
|
|||||||
List t(self.n_rows);
|
List t(self.n_rows);
|
||||||
for(int j = 0; j < self.n_rows; j++) {
|
for(int j = 0; j < self.n_rows; j++) {
|
||||||
List row(self.n_cols);
|
List row(self.n_cols);
|
||||||
for(int i = 0; i < self.n_cols; i++) {
|
for(int i = 0; i < self.n_cols; i++)
|
||||||
row[i] = self._get(i, j);
|
row[i] = self._get(i, j);
|
||||||
}
|
|
||||||
t[j] = VAR(std::move(row));
|
t[j] = VAR(std::move(row));
|
||||||
}
|
}
|
||||||
return VAR(std::move(t));
|
return VAR(std::move(t));
|
||||||
@ -277,11 +270,11 @@ struct Array2d {
|
|||||||
|
|
||||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
||||||
if(!vm->is_user_type<Array2d>(_1)) { return vm->NotImplemented; }
|
if(!vm->is_user_type<Array2d>(_1)) return vm->NotImplemented;
|
||||||
Array2d& other = PK_OBJ_GET(Array2d, _1);
|
Array2d& other = PK_OBJ_GET(Array2d, _1);
|
||||||
if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) { return vm->False; }
|
if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) return vm->False;
|
||||||
for(int i = 0; i < self.numel; i++) {
|
for(int i = 0; i < self.numel; i++) {
|
||||||
if(vm->py_ne(self.data[i], other.data[i])) { return vm->False; }
|
if(vm->py_ne(self.data[i], other.data[i])) return vm->False;
|
||||||
}
|
}
|
||||||
return vm->True;
|
return vm->True;
|
||||||
});
|
});
|
||||||
@ -329,9 +322,8 @@ struct Array2d {
|
|||||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||||
PyVar value = args[1];
|
PyVar value = args[1];
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for(int i = 0; i < self.numel; i++) {
|
for(int i = 0; i < self.numel; i++)
|
||||||
count += vm->py_eq(self.data[i], value);
|
count += vm->py_eq(self.data[i], value);
|
||||||
}
|
|
||||||
return VAR(count);
|
return VAR(count);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -354,7 +346,7 @@ struct Array2d {
|
|||||||
}
|
}
|
||||||
int width = right - left + 1;
|
int width = right - left + 1;
|
||||||
int height = bottom - top + 1;
|
int height = bottom - top + 1;
|
||||||
if(width <= 0 || height <= 0) { return vm->None; }
|
if(width <= 0 || height <= 0) return vm->None;
|
||||||
Tuple t(4);
|
Tuple t(4);
|
||||||
t[0] = VAR(left);
|
t[0] = VAR(left);
|
||||||
t[1] = VAR(top);
|
t[1] = VAR(top);
|
||||||
@ -365,9 +357,8 @@ struct Array2d {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _gc_mark(VM* vm) const {
|
void _gc_mark(VM* vm) const {
|
||||||
for(int i = 0; i < numel; i++) {
|
for(int i = 0; i < numel; i++)
|
||||||
vm->obj_gc_mark(data[i]);
|
vm->obj_gc_mark(data[i]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~Array2d() { delete[] data; }
|
~Array2d() { delete[] data; }
|
||||||
@ -385,10 +376,12 @@ struct Array2dIter {
|
|||||||
void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
|
void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
|
||||||
|
|
||||||
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
static void _register(VM* vm, PyObject* mod, PyObject* type) {
|
||||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
|
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
|
||||||
|
return _0;
|
||||||
|
});
|
||||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||||
Array2dIter& self = PK_OBJ_GET(Array2dIter, _0);
|
Array2dIter& self = PK_OBJ_GET(Array2dIter, _0);
|
||||||
if(self.i == self.a->numel) { return 0; }
|
if(self.i == self.a->numel) return 0;
|
||||||
std::div_t res = std::div(self.i, self.a->n_cols);
|
std::div_t res = std::div(self.i, self.a->n_cols);
|
||||||
vm->s_data.emplace(VM::tp_int, res.rem);
|
vm->s_data.emplace(VM::tp_int, res.rem);
|
||||||
vm->s_data.emplace(VM::tp_int, res.quot);
|
vm->s_data.emplace(VM::tp_int, res.quot);
|
||||||
@ -405,8 +398,9 @@ void add_module_array2d(VM* vm) {
|
|||||||
vm->register_user_class<Array2dIter>(mod, "_array2d_iter");
|
vm->register_user_class<Array2dIter>(mod, "_array2d_iter");
|
||||||
|
|
||||||
Type array2d_iter_t = vm->_tp_user<Array2d>();
|
Type array2d_iter_t = vm->_tp_user<Array2d>();
|
||||||
vm->bind__iter__(array2d_iter_t,
|
vm->bind__iter__(array2d_iter_t, [](VM* vm, PyVar _0) {
|
||||||
[](VM* vm, PyVar _0) { return vm->new_user_object<Array2dIter>(_0, &_0.obj_get<Array2d>()); });
|
return vm->new_user_object<Array2dIter>(_0, &_0.obj_get<Array2d>());
|
||||||
|
});
|
||||||
vm->_all_types[array2d_iter_t].op__iter__ = [](VM* vm, PyVar _0) {
|
vm->_all_types[array2d_iter_t].op__iter__ = [](VM* vm, PyVar _0) {
|
||||||
vm->new_stack_object<Array2dIter>(vm->_tp_user<Array2dIter>(), _0, &_0.obj_get<Array2d>());
|
vm->new_stack_object<Array2dIter>(vm->_tp_user<Array2dIter>(), _0, &_0.obj_get<Array2d>());
|
||||||
};
|
};
|
||||||
|
|||||||
@ -13,7 +13,7 @@ void add_module_csv(VM* vm) {
|
|||||||
std::string_view line = CAST(Str&, csvfile[i]).sv();
|
std::string_view line = CAST(Str&, csvfile[i]).sv();
|
||||||
if(i == 0) {
|
if(i == 0) {
|
||||||
// Skip utf8 BOM if there is any.
|
// Skip utf8 BOM if there is any.
|
||||||
if(strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) { line = line.substr(3); }
|
if(strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) line = line.substr(3);
|
||||||
}
|
}
|
||||||
List row;
|
List row;
|
||||||
int j;
|
int j;
|
||||||
|
|||||||
@ -9,7 +9,9 @@ static void patch__init__(VM* vm, Type cls) {
|
|||||||
const Tuple& args = CAST(Tuple&, _view[1]);
|
const Tuple& args = CAST(Tuple&, _view[1]);
|
||||||
const Dict& kwargs_ = CAST(Dict&, _view[2]);
|
const Dict& kwargs_ = CAST(Dict&, _view[2]);
|
||||||
NameDict kwargs;
|
NameDict kwargs;
|
||||||
kwargs_.apply([&](PyVar k, PyVar v) { kwargs.set(CAST(Str&, k), v); });
|
kwargs_.apply([&](PyVar k, PyVar v) {
|
||||||
|
kwargs.set(CAST(Str&, k), v);
|
||||||
|
});
|
||||||
|
|
||||||
Type cls = vm->_tp(self);
|
Type cls = vm->_tp(self);
|
||||||
const PyTypeInfo* cls_info = &vm->_all_types[cls];
|
const PyTypeInfo* cls_info = &vm->_all_types[cls];
|
||||||
@ -53,11 +55,10 @@ static void patch__repr__(VM* vm, Type cls) {
|
|||||||
ss << cls_info->name << "(";
|
ss << cls_info->name << "(";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for(StrName field: fields) {
|
for(StrName field: fields) {
|
||||||
if(first) {
|
if(first)
|
||||||
first = false;
|
first = false;
|
||||||
} else {
|
else
|
||||||
ss << ", ";
|
ss << ", ";
|
||||||
}
|
|
||||||
ss << field << "=" << vm->py_repr(obj_d[field]);
|
ss << field << "=" << vm->py_repr(obj_d[field]);
|
||||||
}
|
}
|
||||||
ss << ")";
|
ss << ")";
|
||||||
@ -67,13 +68,13 @@ static void patch__repr__(VM* vm, Type cls) {
|
|||||||
|
|
||||||
static void patch__eq__(VM* vm, Type cls) {
|
static void patch__eq__(VM* vm, Type cls) {
|
||||||
vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1) {
|
vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
if(vm->_tp(_0) != vm->_tp(_1)) { return vm->NotImplemented; }
|
if(vm->_tp(_0) != vm->_tp(_1)) return vm->NotImplemented;
|
||||||
const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)];
|
const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)];
|
||||||
const auto& fields = cls_info->annotated_fields;
|
const auto& fields = cls_info->annotated_fields;
|
||||||
for(StrName field: fields) {
|
for(StrName field: fields) {
|
||||||
PyVar lhs = _0->attr(field);
|
PyVar lhs = _0->attr(field);
|
||||||
PyVar rhs = _1->attr(field);
|
PyVar rhs = _1->attr(field);
|
||||||
if(vm->py_ne(lhs, rhs)) { return vm->False; }
|
if(vm->py_ne(lhs, rhs)) return vm->False;
|
||||||
}
|
}
|
||||||
return vm->True;
|
return vm->True;
|
||||||
});
|
});
|
||||||
@ -87,9 +88,9 @@ void add_module_dataclasses(VM* vm) {
|
|||||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||||
NameDict& cls_d = args[0]->attr();
|
NameDict& cls_d = args[0]->attr();
|
||||||
|
|
||||||
if(!cls_d.contains(__init__)) { patch__init__(vm, cls); }
|
if(!cls_d.contains(__init__)) patch__init__(vm, cls);
|
||||||
if(!cls_d.contains(__repr__)) { patch__repr__(vm, cls); }
|
if(!cls_d.contains(__repr__)) patch__repr__(vm, cls);
|
||||||
if(!cls_d.contains(__eq__)) { patch__eq__(vm, cls); }
|
if(!cls_d.contains(__eq__)) patch__eq__(vm, cls);
|
||||||
|
|
||||||
const auto& fields = vm->_all_types[cls].annotated_fields;
|
const auto& fields = vm->_all_types[cls].annotated_fields;
|
||||||
bool has_default = false;
|
bool has_default = false;
|
||||||
|
|||||||
@ -23,7 +23,7 @@ static FILE* io_fopen(const char* name, const char* mode) {
|
|||||||
#if _MSC_VER
|
#if _MSC_VER
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
errno_t err = fopen_s(&fp, name, mode);
|
errno_t err = fopen_s(&fp, name, mode);
|
||||||
if(err != 0) { return nullptr; }
|
if(err != 0) return nullptr;
|
||||||
return fp;
|
return fp;
|
||||||
#else
|
#else
|
||||||
return fopen(name, mode);
|
return fopen(name, mode);
|
||||||
@ -40,9 +40,9 @@ static size_t io_fread(void* buffer, size_t size, size_t count, FILE* fp) {
|
|||||||
|
|
||||||
unsigned char* _default_import_handler(const char* name, int* out_size) {
|
unsigned char* _default_import_handler(const char* name, int* out_size) {
|
||||||
bool exists = std::filesystem::exists(std::filesystem::path(name));
|
bool exists = std::filesystem::exists(std::filesystem::path(name));
|
||||||
if(!exists) { return nullptr; }
|
if(!exists) return nullptr;
|
||||||
FILE* fp = io_fopen(name, "rb");
|
FILE* fp = io_fopen(name, "rb");
|
||||||
if(!fp) { return nullptr; }
|
if(!fp) return nullptr;
|
||||||
fseek(fp, 0, SEEK_END);
|
fseek(fp, 0, SEEK_END);
|
||||||
int buffer_size = ftell(fp);
|
int buffer_size = ftell(fp);
|
||||||
unsigned char* buffer = new unsigned char[buffer_size];
|
unsigned char* buffer = new unsigned char[buffer_size];
|
||||||
@ -96,7 +96,7 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
vm->bind_func(type, "tell", 1, [](VM* vm, ArgsView args) {
|
vm->bind_func(type, "tell", 1, [](VM* vm, ArgsView args) {
|
||||||
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
||||||
long pos = ftell(io.fp);
|
long pos = ftell(io.fp);
|
||||||
if(pos == -1) { vm->IOError(strerror(errno)); }
|
if(pos == -1) vm->IOError(strerror(errno));
|
||||||
return VAR(pos);
|
return VAR(pos);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
long offset = CAST(long, args[1]);
|
long offset = CAST(long, args[1]);
|
||||||
int whence = CAST(int, args[2]);
|
int whence = CAST(int, args[2]);
|
||||||
int ret = fseek(io.fp, offset, whence);
|
int ret = fseek(io.fp, offset, whence);
|
||||||
if(ret != 0) { vm->IOError(strerror(errno)); }
|
if(ret != 0) vm->IOError(strerror(errno));
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -127,11 +127,11 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
FileIO::FileIO(VM* vm, const Str& file, const Str& mode) {
|
FileIO::FileIO(VM* vm, const Str& file, const Str& mode) {
|
||||||
this->is_text = mode.sv().find("b") == std::string::npos;
|
this->is_text = mode.sv().find("b") == std::string::npos;
|
||||||
fp = io_fopen(file.c_str(), mode.c_str());
|
fp = io_fopen(file.c_str(), mode.c_str());
|
||||||
if(!fp) { vm->IOError(strerror(errno)); }
|
if(!fp) vm->IOError(strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileIO::close() {
|
void FileIO::close() {
|
||||||
if(fp == nullptr) { return; }
|
if(fp == nullptr) return;
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
fp = nullptr;
|
fp = nullptr;
|
||||||
}
|
}
|
||||||
@ -172,30 +172,29 @@ void add_module_os(VM* vm) {
|
|||||||
di = std::filesystem::directory_iterator(path);
|
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;
|
List ret;
|
||||||
for(auto& p: di) {
|
for(auto& p: di)
|
||||||
ret.push_back(VAR(p.path().filename().string()));
|
ret.push_back(VAR(p.path().filename().string()));
|
||||||
}
|
|
||||||
return VAR(std::move(ret));
|
return VAR(std::move(ret));
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "remove", 1, [](VM* vm, ArgsView args) {
|
vm->bind_func(mod, "remove", 1, [](VM* vm, ArgsView args) {
|
||||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||||
bool ok = std::filesystem::remove(path);
|
bool ok = std::filesystem::remove(path);
|
||||||
if(!ok) { vm->IOError("operation failed"); }
|
if(!ok) vm->IOError("operation failed");
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "mkdir", 1, [](VM* vm, ArgsView args) {
|
vm->bind_func(mod, "mkdir", 1, [](VM* vm, ArgsView args) {
|
||||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||||
bool ok = std::filesystem::create_directory(path);
|
bool ok = std::filesystem::create_directory(path);
|
||||||
if(!ok) { vm->IOError("operation failed"); }
|
if(!ok) vm->IOError("operation failed");
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "rmdir", 1, [](VM* vm, ArgsView args) {
|
vm->bind_func(mod, "rmdir", 1, [](VM* vm, ArgsView args) {
|
||||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||||
bool ok = std::filesystem::remove(path);
|
bool ok = std::filesystem::remove(path);
|
||||||
if(!ok) { vm->IOError("operation failed"); }
|
if(!ok) vm->IOError("operation failed");
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -163,8 +163,8 @@ void Vec2::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
Vec2 __to = CAST(Vec2, args[1]);
|
Vec2 __to = CAST(Vec2, args[1]);
|
||||||
float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x);
|
float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x);
|
||||||
const float PI = 3.1415926535897932384f;
|
const float PI = 3.1415926535897932384f;
|
||||||
if(val > PI) { val -= 2 * PI; }
|
if(val > PI) val -= 2 * PI;
|
||||||
if(val < -PI) { val += 2 * PI; }
|
if(val < -PI) val += 2 * PI;
|
||||||
return VAR(val);
|
return VAR(val);
|
||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
@ -284,21 +284,19 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
PY_STRUCT_LIKE(Mat3x3)
|
PY_STRUCT_LIKE(Mat3x3)
|
||||||
|
|
||||||
vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
|
vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
|
||||||
if(args.size() == 1 + 0) { return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros()); }
|
if(args.size() == 1 + 0) return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros());
|
||||||
if(args.size() == 1 + 1) {
|
if(args.size() == 1 + 1) {
|
||||||
const List& list = CAST(List&, args[1]);
|
const List& list = CAST(List&, args[1]);
|
||||||
if(list.size() != 9) { vm->TypeError("Mat3x3.__new__ takes a list of 9 floats"); }
|
if(list.size() != 9) vm->TypeError("Mat3x3.__new__ takes a list of 9 floats");
|
||||||
Mat3x3 mat;
|
Mat3x3 mat;
|
||||||
for(int i = 0; i < 9; i++) {
|
for(int i = 0; i < 9; i++)
|
||||||
mat.v[i] = CAST_F(list[i]);
|
mat.v[i] = CAST_F(list[i]);
|
||||||
}
|
|
||||||
return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
|
return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
|
||||||
}
|
}
|
||||||
if(args.size() == 1 + 9) {
|
if(args.size() == 1 + 9) {
|
||||||
Mat3x3 mat;
|
Mat3x3 mat;
|
||||||
for(int i = 0; i < 9; i++) {
|
for(int i = 0; i < 9; i++)
|
||||||
mat.v[i] = CAST_F(args[1 + i]);
|
mat.v[i] = CAST_F(args[1 + i]);
|
||||||
}
|
|
||||||
return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
|
return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
|
||||||
}
|
}
|
||||||
vm->TypeError(_S("Mat3x3.__new__ takes 0 or 1 or 9 arguments, got ", args.size() - 1));
|
vm->TypeError(_S("Mat3x3.__new__ takes 0 or 1 or 9 arguments, got ", args.size() - 1));
|
||||||
@ -420,21 +418,21 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
vm->bind__invert__(type->as<Type>(), [](VM* vm, PyVar obj) {
|
vm->bind__invert__(type->as<Type>(), [](VM* vm, PyVar obj) {
|
||||||
Mat3x3& self = _CAST(Mat3x3&, obj);
|
Mat3x3& self = _CAST(Mat3x3&, obj);
|
||||||
Mat3x3 ret;
|
Mat3x3 ret;
|
||||||
if(!self.inverse(ret)) { vm->ValueError("matrix is not invertible"); }
|
if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
|
||||||
return vm->new_user_object<Mat3x3>(ret);
|
return vm->new_user_object<Mat3x3>(ret);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "inverse", 1, [](VM* vm, ArgsView args) {
|
vm->bind_func(type, "inverse", 1, [](VM* vm, ArgsView args) {
|
||||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||||
Mat3x3 ret;
|
Mat3x3 ret;
|
||||||
if(!self.inverse(ret)) { vm->ValueError("matrix is not invertible"); }
|
if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
|
||||||
return vm->new_user_object<Mat3x3>(ret);
|
return vm->new_user_object<Mat3x3>(ret);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(type, "inverse_", 1, [](VM* vm, ArgsView args) {
|
vm->bind_func(type, "inverse_", 1, [](VM* vm, ArgsView args) {
|
||||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||||
Mat3x3 ret;
|
Mat3x3 ret;
|
||||||
if(!self.inverse(ret)) { vm->ValueError("matrix is not invertible"); }
|
if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
|
||||||
self = ret;
|
self = ret;
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
@ -450,7 +448,9 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
type,
|
type,
|
||||||
"zeros",
|
"zeros",
|
||||||
0,
|
0,
|
||||||
[](VM* vm, ArgsView args) { return vm->new_user_object<Mat3x3>(Mat3x3::zeros()); },
|
[](VM* vm, ArgsView args) {
|
||||||
|
return vm->new_user_object<Mat3x3>(Mat3x3::zeros());
|
||||||
|
},
|
||||||
{},
|
{},
|
||||||
BindType::STATICMETHOD);
|
BindType::STATICMETHOD);
|
||||||
|
|
||||||
@ -459,7 +459,9 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
type,
|
type,
|
||||||
"ones",
|
"ones",
|
||||||
0,
|
0,
|
||||||
[](VM* vm, ArgsView args) { return vm->new_user_object<Mat3x3>(Mat3x3::ones()); },
|
[](VM* vm, ArgsView args) {
|
||||||
|
return vm->new_user_object<Mat3x3>(Mat3x3::ones());
|
||||||
|
},
|
||||||
{},
|
{},
|
||||||
BindType::STATICMETHOD);
|
BindType::STATICMETHOD);
|
||||||
|
|
||||||
@ -468,7 +470,9 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
type,
|
type,
|
||||||
"identity",
|
"identity",
|
||||||
0,
|
0,
|
||||||
[](VM* vm, ArgsView args) { return vm->new_user_object<Mat3x3>(Mat3x3::identity()); },
|
[](VM* vm, ArgsView args) {
|
||||||
|
return vm->new_user_object<Mat3x3>(Mat3x3::identity());
|
||||||
|
},
|
||||||
{},
|
{},
|
||||||
BindType::STATICMETHOD);
|
BindType::STATICMETHOD);
|
||||||
|
|
||||||
@ -547,7 +551,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||||
Vec2 v = CAST(Vec2, args[1]);
|
Vec2 v = CAST(Vec2, args[1]);
|
||||||
Mat3x3 inv;
|
Mat3x3 inv;
|
||||||
if(!self.inverse(inv)) { vm->ValueError("matrix is not invertible"); }
|
if(!self.inverse(inv)) vm->ValueError("matrix is not invertible");
|
||||||
Vec2 res(inv._11 * v.x + inv._12 * v.y + inv._13, inv._21 * v.x + inv._22 * v.y + inv._23);
|
Vec2 res(inv._11 * v.x + inv._12 * v.y + inv._13, inv._21 * v.x + inv._22 * v.y + inv._23);
|
||||||
return vm->new_user_object<Vec2>(res);
|
return vm->new_user_object<Vec2>(res);
|
||||||
});
|
});
|
||||||
@ -563,7 +567,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
|||||||
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||||
Vec2 v = CAST(Vec2, args[1]);
|
Vec2 v = CAST(Vec2, args[1]);
|
||||||
Mat3x3 inv;
|
Mat3x3 inv;
|
||||||
if(!self.inverse(inv)) { vm->ValueError("matrix is not invertible"); }
|
if(!self.inverse(inv)) vm->ValueError("matrix is not invertible");
|
||||||
Vec2 res(inv._11 * v.x + inv._12 * v.y, inv._21 * v.x + inv._22 * v.y);
|
Vec2 res(inv._11 * v.x + inv._12 * v.y, inv._21 * v.x + inv._22 * v.y);
|
||||||
return vm->new_user_object<Vec2>(res);
|
return vm->new_user_object<Vec2>(res);
|
||||||
});
|
});
|
||||||
@ -596,46 +600,42 @@ Mat3x3 Mat3x3::identity() { return Mat3x3(1, 0, 0, 0, 1, 0, 0, 0, 1); }
|
|||||||
|
|
||||||
Mat3x3 Mat3x3::operator+ (const Mat3x3& other) const {
|
Mat3x3 Mat3x3::operator+ (const Mat3x3& other) const {
|
||||||
Mat3x3 ret;
|
Mat3x3 ret;
|
||||||
for(int i = 0; i < 9; ++i) {
|
for(int i = 0; i < 9; ++i)
|
||||||
ret.v[i] = v[i] + other.v[i];
|
ret.v[i] = v[i] + other.v[i];
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mat3x3 Mat3x3::operator- (const Mat3x3& other) const {
|
Mat3x3 Mat3x3::operator- (const Mat3x3& other) const {
|
||||||
Mat3x3 ret;
|
Mat3x3 ret;
|
||||||
for(int i = 0; i < 9; ++i) {
|
for(int i = 0; i < 9; ++i)
|
||||||
ret.v[i] = v[i] - other.v[i];
|
ret.v[i] = v[i] - other.v[i];
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mat3x3 Mat3x3::operator* (float scalar) const {
|
Mat3x3 Mat3x3::operator* (float scalar) const {
|
||||||
Mat3x3 ret;
|
Mat3x3 ret;
|
||||||
for(int i = 0; i < 9; ++i) {
|
for(int i = 0; i < 9; ++i)
|
||||||
ret.v[i] = v[i] * scalar;
|
ret.v[i] = v[i] * scalar;
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mat3x3 Mat3x3::operator/ (float scalar) const {
|
Mat3x3 Mat3x3::operator/ (float scalar) const {
|
||||||
Mat3x3 ret;
|
Mat3x3 ret;
|
||||||
for(int i = 0; i < 9; ++i) {
|
for(int i = 0; i < 9; ++i)
|
||||||
ret.v[i] = v[i] / scalar;
|
ret.v[i] = v[i] / scalar;
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mat3x3::operator== (const Mat3x3& other) const {
|
bool Mat3x3::operator== (const Mat3x3& other) const {
|
||||||
for(int i = 0; i < 9; ++i) {
|
for(int i = 0; i < 9; ++i) {
|
||||||
if(!isclose(v[i], other.v[i])) { return false; }
|
if(!isclose(v[i], other.v[i])) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mat3x3::operator!= (const Mat3x3& other) const {
|
bool Mat3x3::operator!= (const Mat3x3& other) const {
|
||||||
for(int i = 0; i < 9; ++i) {
|
for(int i = 0; i < 9; ++i) {
|
||||||
if(!isclose(v[i], other.v[i])) { return true; }
|
if(!isclose(v[i], other.v[i])) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -682,7 +682,7 @@ Mat3x3 Mat3x3::transpose() const {
|
|||||||
|
|
||||||
bool Mat3x3::inverse(Mat3x3& out) const {
|
bool Mat3x3::inverse(Mat3x3& out) const {
|
||||||
float det = determinant();
|
float det = determinant();
|
||||||
if(isclose(det, 0)) { return false; }
|
if(isclose(det, 0)) return false;
|
||||||
float inv_det = 1.0f / det;
|
float inv_det = 1.0f / det;
|
||||||
out._11 = (_22 * _33 - _23 * _32) * inv_det;
|
out._11 = (_22 * _33 - _23 * _32) * inv_det;
|
||||||
out._12 = (_13 * _32 - _12 * _33) * inv_det;
|
out._12 = (_13 * _32 - _12 * _33) * inv_det;
|
||||||
@ -704,7 +704,7 @@ Mat3x3 Mat3x3::trs(Vec2 t, float radian, Vec2 s) {
|
|||||||
|
|
||||||
bool Mat3x3::is_affine() const {
|
bool Mat3x3::is_affine() const {
|
||||||
float det = _11 * _22 - _12 * _21;
|
float det = _11 * _22 - _12 * _21;
|
||||||
if(isclose(det, 0)) { return false; }
|
if(isclose(det, 0)) return false;
|
||||||
return _31 == 0.0f && _32 == 0.0f && _33 == 1.0f;
|
return _31 == 0.0f && _32 == 0.0f && _33 == 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -62,7 +62,7 @@ void add_module_time(VM* vm) {
|
|||||||
while(true) {
|
while(true) {
|
||||||
auto now = std::chrono::system_clock::now();
|
auto now = std::chrono::system_clock::now();
|
||||||
f64 elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - begin).count() / 1000.0;
|
f64 elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - begin).count() / 1000.0;
|
||||||
if(elapsed >= seconds) { break; }
|
if(elapsed >= seconds) break;
|
||||||
}
|
}
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
@ -111,7 +111,9 @@ void add_module_json(VM* vm) {
|
|||||||
return vm->_exec(code, vm->callstack.top()._module);
|
return vm->_exec(code, vm->callstack.top()._module);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "dumps", 1, [](VM* vm, ArgsView args) { return VAR(vm->py_json(args[0])); });
|
vm->bind_func(mod, "dumps", 1, [](VM* vm, ArgsView args) {
|
||||||
|
return VAR(vm->py_json(args[0]));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://docs.python.org/3.5/library/math.html
|
// https://docs.python.org/3.5/library/math.html
|
||||||
@ -141,8 +143,8 @@ void add_module_math(VM* vm) {
|
|||||||
vm->bind_func(mod, "gcd", 2, [](VM* vm, ArgsView args) {
|
vm->bind_func(mod, "gcd", 2, [](VM* vm, ArgsView args) {
|
||||||
i64 a = CAST(i64, args[0]);
|
i64 a = CAST(i64, args[0]);
|
||||||
i64 b = CAST(i64, args[1]);
|
i64 b = CAST(i64, args[1]);
|
||||||
if(a < 0) { a = -a; }
|
if(a < 0) a = -a;
|
||||||
if(b < 0) { b = -b; }
|
if(b < 0) b = -b;
|
||||||
while(b != 0) {
|
while(b != 0) {
|
||||||
i64 t = b;
|
i64 t = b;
|
||||||
b = a % b;
|
b = a % b;
|
||||||
@ -195,11 +197,10 @@ void add_module_math(VM* vm) {
|
|||||||
|
|
||||||
vm->bind_func(mod, "factorial", 1, [](VM* vm, ArgsView args) {
|
vm->bind_func(mod, "factorial", 1, [](VM* vm, ArgsView args) {
|
||||||
i64 n = CAST(i64, args[0]);
|
i64 n = CAST(i64, args[0]);
|
||||||
if(n < 0) { vm->ValueError("factorial() not defined for negative values"); }
|
if(n < 0) vm->ValueError("factorial() not defined for negative values");
|
||||||
i64 r = 1;
|
i64 r = 1;
|
||||||
for(i64 i = 2; i <= n; i++) {
|
for(i64 i = 2; i <= n; i++)
|
||||||
r *= i;
|
r *= i;
|
||||||
}
|
|
||||||
return VAR(r);
|
return VAR(r);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -207,14 +208,14 @@ void add_module_math(VM* vm) {
|
|||||||
void add_module_traceback(VM* vm) {
|
void add_module_traceback(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("traceback");
|
PyObject* mod = vm->new_module("traceback");
|
||||||
vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) {
|
vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) {
|
||||||
if(vm->__last_exception == nullptr) { vm->ValueError("no exception"); }
|
if(vm->__last_exception == nullptr) vm->ValueError("no exception");
|
||||||
Exception& e = vm->__last_exception->as<Exception>();
|
Exception& e = vm->__last_exception->as<Exception>();
|
||||||
vm->stdout_write(e.summary());
|
vm->stdout_write(e.summary());
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "format_exc", 0, [](VM* vm, ArgsView args) {
|
vm->bind_func(mod, "format_exc", 0, [](VM* vm, ArgsView args) {
|
||||||
if(vm->__last_exception == nullptr) { vm->ValueError("no exception"); }
|
if(vm->__last_exception == nullptr) vm->ValueError("no exception");
|
||||||
Exception& e = vm->__last_exception->as<Exception>();
|
Exception& e = vm->__last_exception->as<Exception>();
|
||||||
return VAR(e.summary());
|
return VAR(e.summary());
|
||||||
});
|
});
|
||||||
@ -231,7 +232,7 @@ void add_module_dis(VM* vm) {
|
|||||||
code = vm->compile(source, "<dis>", EXEC_MODE);
|
code = vm->compile(source, "<dis>", EXEC_MODE);
|
||||||
}
|
}
|
||||||
PyVar f = obj;
|
PyVar f = obj;
|
||||||
if(is_type(f, vm->tp_bound_method)) { f = CAST(BoundMethod, obj).func; }
|
if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, obj).func;
|
||||||
code = CAST(Function&, f).decl->code;
|
code = CAST(Function&, f).decl->code;
|
||||||
vm->stdout_write(vm->disassemble(code));
|
vm->stdout_write(vm->disassemble(code));
|
||||||
return vm->None;
|
return vm->None;
|
||||||
@ -254,7 +255,7 @@ void add_module_enum(VM* vm) {
|
|||||||
for(auto [k, v]: attr.items()) {
|
for(auto [k, v]: attr.items()) {
|
||||||
// wrap every attribute
|
// wrap every attribute
|
||||||
std::string_view k_sv = k.sv();
|
std::string_view k_sv = k.sv();
|
||||||
if(k_sv.empty() || k_sv[0] == '_') { continue; }
|
if(k_sv.empty() || k_sv[0] == '_') continue;
|
||||||
attr.set(k, vm->call(new_ti->obj, VAR(k_sv), v));
|
attr.set(k, vm->call(new_ti->obj, VAR(k_sv), v));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -263,12 +264,14 @@ void add_module_enum(VM* vm) {
|
|||||||
void add_module___builtins(VM* vm) {
|
void add_module___builtins(VM* vm) {
|
||||||
PyObject* mod = vm->new_module("__builtins");
|
PyObject* mod = vm->new_module("__builtins");
|
||||||
|
|
||||||
vm->bind_func(mod, "next", 1, [](VM* vm, ArgsView args) { return vm->py_next(args[0]); });
|
vm->bind_func(mod, "next", 1, [](VM* vm, ArgsView args) {
|
||||||
|
return vm->py_next(args[0]);
|
||||||
|
});
|
||||||
|
|
||||||
vm->bind_func(mod, "_enable_instance_dict", 1, [](VM* vm, ArgsView args) {
|
vm->bind_func(mod, "_enable_instance_dict", 1, [](VM* vm, ArgsView args) {
|
||||||
PyVar self = args[0];
|
PyVar self = args[0];
|
||||||
if(is_tagged(self)) { vm->TypeError("object: tagged object cannot enable instance dict"); }
|
if(is_tagged(self)) vm->TypeError("object: tagged object cannot enable instance dict");
|
||||||
if(self->is_attr_valid()) { vm->RuntimeError("object: instance dict is already enabled"); }
|
if(self->is_attr_valid()) vm->RuntimeError("object: instance dict is already enabled");
|
||||||
self->_attr = new NameDict();
|
self->_attr = new NameDict();
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
@ -310,9 +313,8 @@ struct LineProfilerW {
|
|||||||
const Tuple& args = CAST(Tuple&, view[2]);
|
const Tuple& args = CAST(Tuple&, view[2]);
|
||||||
vm->s_data.push(func);
|
vm->s_data.push(func);
|
||||||
vm->s_data.push(PY_NULL);
|
vm->s_data.push(PY_NULL);
|
||||||
for(PyVar arg: args) {
|
for(PyVar arg: args)
|
||||||
vm->s_data.push(arg);
|
vm->s_data.push(arg);
|
||||||
}
|
|
||||||
_LpGuard guard(&self, vm);
|
_LpGuard guard(&self, vm);
|
||||||
PyVar ret = vm->vectorcall(args.size());
|
PyVar ret = vm->vectorcall(args.size());
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@ -69,9 +69,8 @@ struct mt19937 {
|
|||||||
if(mti >= N) { /* generate N words at one time */
|
if(mti >= N) { /* generate N words at one time */
|
||||||
int kk;
|
int kk;
|
||||||
|
|
||||||
if(mti == N + 1) { /* if init_genrand() has not been called, */
|
if(mti == N + 1) /* if init_genrand() has not been called, */
|
||||||
seed(5489UL); /* a default initial seed is used */
|
seed(5489UL); /* a default initial seed is used */
|
||||||
}
|
|
||||||
|
|
||||||
for(kk = 0; kk < N - M; kk++) {
|
for(kk = 0; kk < N - M; kk++) {
|
||||||
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
|
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
|
||||||
@ -142,7 +141,7 @@ struct Random {
|
|||||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||||
i64 a = CAST(i64, args[1]);
|
i64 a = CAST(i64, args[1]);
|
||||||
i64 b = CAST(i64, args[2]);
|
i64 b = CAST(i64, args[2]);
|
||||||
if(a > b) { vm->ValueError("randint(a, b): a must be less than or equal to b"); }
|
if(a > b) vm->ValueError("randint(a, b): a must be less than or equal to b");
|
||||||
return VAR(self.gen.randint(a, b));
|
return VAR(self.gen.randint(a, b));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -155,7 +154,7 @@ struct Random {
|
|||||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||||
f64 a = CAST(f64, args[1]);
|
f64 a = CAST(f64, args[1]);
|
||||||
f64 b = CAST(f64, args[2]);
|
f64 b = CAST(f64, args[2]);
|
||||||
if(a > b) { std::swap(a, b); }
|
if(a > b) std::swap(a, b);
|
||||||
return VAR(self.gen.uniform(a, b));
|
return VAR(self.gen.uniform(a, b));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -172,7 +171,7 @@ struct Random {
|
|||||||
vm->bind_func(type, "choice", 2, [](VM* vm, ArgsView args) {
|
vm->bind_func(type, "choice", 2, [](VM* vm, ArgsView args) {
|
||||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||||
ArgsView view = vm->cast_array_view(args[1]);
|
ArgsView view = vm->cast_array_view(args[1]);
|
||||||
if(view.empty()) { vm->IndexError("cannot choose from an empty sequence"); }
|
if(view.empty()) vm->IndexError("cannot choose from an empty sequence");
|
||||||
int index = self.gen.randint(0, view.size() - 1);
|
int index = self.gen.randint(0, view.size() - 1);
|
||||||
return view[index];
|
return view[index];
|
||||||
});
|
});
|
||||||
@ -182,21 +181,20 @@ struct Random {
|
|||||||
ArgsView view = vm->cast_array_view(args[1]);
|
ArgsView view = vm->cast_array_view(args[1]);
|
||||||
PyVar* data = view.begin();
|
PyVar* data = view.begin();
|
||||||
int size = view.size();
|
int size = view.size();
|
||||||
if(size == 0) { vm->IndexError("cannot choose from an empty sequence"); }
|
if(size == 0) vm->IndexError("cannot choose from an empty sequence");
|
||||||
array<f64> cum_weights(size);
|
array<f64> cum_weights(size);
|
||||||
if(args[2] == vm->None) {
|
if(args[2] == vm->None) {
|
||||||
for(int i = 0; i < size; i++) {
|
for(int i = 0; i < size; i++)
|
||||||
cum_weights[i] = i + 1;
|
cum_weights[i] = i + 1;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ArgsView weights = vm->cast_array_view(args[2]);
|
ArgsView weights = vm->cast_array_view(args[2]);
|
||||||
if(weights.size() != size) { vm->ValueError(_S("len(weights) != ", size)); }
|
if(weights.size() != size) vm->ValueError(_S("len(weights) != ", size));
|
||||||
cum_weights[0] = CAST(f64, weights[0]);
|
cum_weights[0] = CAST(f64, weights[0]);
|
||||||
for(int i = 1; i < size; i++) {
|
for(int i = 1; i < size; i++) {
|
||||||
cum_weights[i] = cum_weights[i - 1] + CAST(f64, weights[i]);
|
cum_weights[i] = cum_weights[i - 1] + CAST(f64, weights[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(cum_weights[size - 1] <= 0) { vm->ValueError("total of weights must be greater than zero"); }
|
if(cum_weights[size - 1] <= 0) vm->ValueError("total of weights must be greater than zero");
|
||||||
int k = CAST(int, args[3]);
|
int k = CAST(int, args[3]);
|
||||||
List result(k);
|
List result(k);
|
||||||
for(int i = 0; i < k; i++) {
|
for(int i = 0; i < k; i++) {
|
||||||
|
|||||||
@ -43,7 +43,7 @@ Dict::Dict(const Dict& other) {
|
|||||||
|
|
||||||
void Dict::set(VM* vm, PyVar key, PyVar val) {
|
void Dict::set(VM* vm, PyVar key, PyVar val) {
|
||||||
// do possible rehash
|
// do possible rehash
|
||||||
if(_size + 1 > _critical_size) { _rehash(vm); }
|
if(_size + 1 > _critical_size) _rehash(vm);
|
||||||
bool ok;
|
bool ok;
|
||||||
int i;
|
int i;
|
||||||
_probe_1(vm, key, ok, i);
|
_probe_1(vm, key, ok, i);
|
||||||
@ -91,7 +91,7 @@ PyVar Dict::try_get(VM* vm, PyVar key) const {
|
|||||||
bool ok;
|
bool ok;
|
||||||
int i;
|
int i;
|
||||||
_probe_0(vm, key, ok, i);
|
_probe_0(vm, key, ok, i);
|
||||||
if(!ok) { return nullptr; }
|
if(!ok) return nullptr;
|
||||||
return _items[i].second;
|
return _items[i].second;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ bool Dict::del(VM* vm, PyVar key) {
|
|||||||
bool ok;
|
bool ok;
|
||||||
int i;
|
int i;
|
||||||
_probe_0(vm, key, ok, i);
|
_probe_0(vm, key, ok, i);
|
||||||
if(!ok) { return false; }
|
if(!ok) return false;
|
||||||
_items[i].first = nullptr;
|
_items[i].first = nullptr;
|
||||||
// _items[i].second = PY_DELETED_SLOT; // do not change .second if it is not NULL, it means the slot is occupied by
|
// _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
|
// a deleted item
|
||||||
@ -133,7 +133,9 @@ bool Dict::del(VM* vm, PyVar key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Dict::update(VM* vm, const Dict& other) {
|
void Dict::update(VM* vm, const Dict& other) {
|
||||||
other.apply([&](PyVar k, PyVar v) { set(vm, k, v); });
|
other.apply([&](PyVar k, PyVar v) {
|
||||||
|
set(vm, k, v);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple Dict::keys() const {
|
Tuple Dict::keys() const {
|
||||||
@ -173,6 +175,6 @@ void Dict::clear() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Dict::~Dict() {
|
Dict::~Dict() {
|
||||||
if(_items) { std::free(_items); }
|
if(_items) std::free(_items);
|
||||||
}
|
}
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
namespace pkpy {
|
namespace pkpy {
|
||||||
Str Exception::summary() const {
|
Str Exception::summary() const {
|
||||||
SStream ss;
|
SStream ss;
|
||||||
if(is_re) { ss << "Traceback (most recent call last):\n"; }
|
if(is_re) ss << "Traceback (most recent call last):\n";
|
||||||
// while(!st.empty()) {
|
// while(!st.empty()) {
|
||||||
// ss << st.top().snapshot() << '\n';
|
// ss << st.top().snapshot() << '\n';
|
||||||
// st.pop();
|
// st.pop();
|
||||||
@ -12,11 +12,10 @@ Str Exception::summary() const {
|
|||||||
for(int i = container.size() - 1; i >= 0; i--) {
|
for(int i = container.size() - 1; i >= 0; i--) {
|
||||||
ss << container[i].snapshot() << '\n';
|
ss << container[i].snapshot() << '\n';
|
||||||
}
|
}
|
||||||
if(!msg.empty()) {
|
if(!msg.empty())
|
||||||
ss << type.sv() << ": " << msg;
|
ss << type.sv() << ": " << msg;
|
||||||
} else {
|
else
|
||||||
ss << type.sv();
|
ss << type.sv();
|
||||||
}
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,11 +5,11 @@ SourceData::SourceData(std::string_view source, const Str& filename, CompileMode
|
|||||||
filename(filename), mode(mode) {
|
filename(filename), mode(mode) {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
// Skip utf8 BOM if there is any.
|
// Skip utf8 BOM if there is any.
|
||||||
if(strncmp(source.data(), "\xEF\xBB\xBF", 3) == 0) { index += 3; }
|
if(strncmp(source.data(), "\xEF\xBB\xBF", 3) == 0) index += 3;
|
||||||
// Drop all '\r'
|
// Drop all '\r'
|
||||||
SStream ss(source.size() + 1);
|
SStream ss(source.size() + 1);
|
||||||
while(index < source.size()) {
|
while(index < source.size()) {
|
||||||
if(source[index] != '\r') { ss << source[index]; }
|
if(source[index] != '\r') ss << source[index];
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
this->source = ss.str();
|
this->source = ss.str();
|
||||||
@ -26,28 +26,27 @@ SourceData::SourceData(const Str& filename, CompileMode mode) : filename(filenam
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::pair<const char*, const char*> SourceData::_get_line(int lineno) const {
|
std::pair<const char*, const char*> SourceData::_get_line(int lineno) const {
|
||||||
if(is_precompiled || lineno == -1) { return {nullptr, nullptr}; }
|
if(is_precompiled || lineno == -1) return {nullptr, nullptr};
|
||||||
lineno -= 1;
|
lineno -= 1;
|
||||||
if(lineno < 0) { lineno = 0; }
|
if(lineno < 0) lineno = 0;
|
||||||
const char* _start = line_starts[lineno];
|
const char* _start = line_starts[lineno];
|
||||||
const char* i = _start;
|
const char* i = _start;
|
||||||
// max 300 chars
|
// max 300 chars
|
||||||
while(*i != '\n' && *i != '\0' && i - _start < 300) {
|
while(*i != '\n' && *i != '\0' && i - _start < 300)
|
||||||
i++;
|
i++;
|
||||||
}
|
|
||||||
return {_start, i};
|
return {_start, i};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view SourceData::get_line(int lineno) const {
|
std::string_view SourceData::get_line(int lineno) const {
|
||||||
auto [_0, _1] = _get_line(lineno);
|
auto [_0, _1] = _get_line(lineno);
|
||||||
if(_0 && _1) { return std::string_view(_0, _1 - _0); }
|
if(_0 && _1) return std::string_view(_0, _1 - _0);
|
||||||
return "<?>";
|
return "<?>";
|
||||||
}
|
}
|
||||||
|
|
||||||
Str SourceData::snapshot(int lineno, const char* cursor, std::string_view name) const {
|
Str SourceData::snapshot(int lineno, const char* cursor, std::string_view name) const {
|
||||||
SStream ss;
|
SStream ss;
|
||||||
ss << " " << "File \"" << filename << "\", line " << lineno;
|
ss << " " << "File \"" << filename << "\", line " << lineno;
|
||||||
if(!name.empty()) { ss << ", in " << name; }
|
if(!name.empty()) ss << ", in " << name;
|
||||||
if(!is_precompiled) {
|
if(!is_precompiled) {
|
||||||
ss << '\n';
|
ss << '\n';
|
||||||
std::pair<const char*, const char*> pair = _get_line(lineno);
|
std::pair<const char*, const char*> pair = _get_line(lineno);
|
||||||
@ -56,12 +55,12 @@ Str SourceData::snapshot(int lineno, const char* cursor, std::string_view name)
|
|||||||
if(pair.first && pair.second) {
|
if(pair.first && pair.second) {
|
||||||
line = Str(pair.first, pair.second - pair.first).lstrip();
|
line = Str(pair.first, pair.second - pair.first).lstrip();
|
||||||
removed_spaces = pair.second - pair.first - line.length();
|
removed_spaces = pair.second - pair.first - line.length();
|
||||||
if(line.empty()) { line = "<?>"; }
|
if(line.empty()) line = "<?>";
|
||||||
}
|
}
|
||||||
ss << " " << line;
|
ss << " " << line;
|
||||||
if(cursor && line != "<?>" && cursor >= pair.first && cursor <= pair.second) {
|
if(cursor && line != "<?>" && cursor >= pair.first && cursor <= pair.second) {
|
||||||
auto column = cursor - pair.first - removed_spaces;
|
auto column = cursor - pair.first - removed_spaces;
|
||||||
if(column >= 0) { ss << "\n " << std::string(column, ' ') << "^"; }
|
if(column >= 0) ss << "\n " << std::string(column, ' ') << "^";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ss.str();
|
return ss.str();
|
||||||
|
|||||||
@ -15,9 +15,8 @@ Tuple::Tuple(Tuple&& other) noexcept {
|
|||||||
_size = other._size;
|
_size = other._size;
|
||||||
if(other.is_inlined()) {
|
if(other.is_inlined()) {
|
||||||
_args = _inlined;
|
_args = _inlined;
|
||||||
for(int i = 0; i < _size; i++) {
|
for(int i = 0; i < _size; i++)
|
||||||
_args[i] = other._args[i];
|
_args[i] = other._args[i];
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
_args = other._args;
|
_args = other._args;
|
||||||
other._args = other._inlined;
|
other._args = other._inlined;
|
||||||
@ -37,22 +36,20 @@ Tuple::Tuple(PyVar _0, PyVar _1, PyVar _2) : Tuple(3) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Tuple::~Tuple() {
|
Tuple::~Tuple() {
|
||||||
if(!is_inlined()) { std::free(_args); }
|
if(!is_inlined()) std::free(_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
List ArgsView::to_list() const {
|
List ArgsView::to_list() const {
|
||||||
List ret(size());
|
List ret(size());
|
||||||
for(int i = 0; i < size(); i++) {
|
for(int i = 0; i < size(); i++)
|
||||||
ret[i] = _begin[i];
|
ret[i] = _begin[i];
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple ArgsView::to_tuple() const {
|
Tuple ArgsView::to_tuple() const {
|
||||||
Tuple ret(size());
|
Tuple ret(size());
|
||||||
for(int i = 0; i < size(); i++) {
|
for(int i = 0; i < size(); i++)
|
||||||
ret[i] = _begin[i];
|
ret[i] = _begin[i];
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
382
src/pocketpy.cpp
382
src/pocketpy.cpp
@ -37,11 +37,10 @@ PyVar PyArrayGetItem(VM* vm, PyVar _0, PyVar _1) {
|
|||||||
List new_list;
|
List new_list;
|
||||||
PK_SLICE_LOOP(i, start, stop, step) new_list.push_back(self[i]);
|
PK_SLICE_LOOP(i, start, stop, step) new_list.push_back(self[i]);
|
||||||
|
|
||||||
if constexpr(std::is_same_v<T, List>) {
|
if constexpr(std::is_same_v<T, List>)
|
||||||
return VAR(std::move(new_list));
|
return VAR(std::move(new_list));
|
||||||
} else {
|
else
|
||||||
return VAR(new_list.to_tuple());
|
return VAR(new_list.to_tuple());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
vm->TypeError("indices must be integers or slices");
|
vm->TypeError("indices must be integers or slices");
|
||||||
}
|
}
|
||||||
@ -104,7 +103,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
Frame* frame = &vm->callstack.top();
|
Frame* frame = &vm->callstack.top();
|
||||||
if(frame->_callable != nullptr) {
|
if(frame->_callable != nullptr) {
|
||||||
class_arg = frame->_callable->as<Function>()._class;
|
class_arg = frame->_callable->as<Function>()._class;
|
||||||
if(frame->_locals.size() > 0) { self_arg = frame->_locals[0]; }
|
if(frame->_locals.size() > 0) self_arg = frame->_locals[0];
|
||||||
}
|
}
|
||||||
if(class_arg == nullptr || self_arg == nullptr) {
|
if(class_arg == nullptr || self_arg == nullptr) {
|
||||||
vm->TypeError("super(): unable to determine the class context, use super(class, self) instead");
|
vm->TypeError("super(): unable to determine the class context, use super(class, self) instead");
|
||||||
@ -139,7 +138,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
Tuple& types = _CAST(Tuple&, args[1]);
|
Tuple& types = _CAST(Tuple&, args[1]);
|
||||||
for(PyVar type: types) {
|
for(PyVar type: types) {
|
||||||
vm->check_type(type, vm->tp_type);
|
vm->check_type(type, vm->tp_type);
|
||||||
if(vm->isinstance(args[0], type->as<Type>())) { return vm->True; }
|
if(vm->isinstance(args[0], type->as<Type>())) return vm->True;
|
||||||
}
|
}
|
||||||
return vm->False;
|
return vm->False;
|
||||||
}
|
}
|
||||||
@ -160,19 +159,19 @@ void __init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind(_vm->builtins, "round(x, ndigits=None)", [](VM* vm, ArgsView args) {
|
_vm->bind(_vm->builtins, "round(x, ndigits=None)", [](VM* vm, ArgsView args) {
|
||||||
if(is_int(args[0])) { return args[0]; }
|
if(is_int(args[0])) return args[0];
|
||||||
f64 x = CAST(f64, args[0]);
|
f64 x = CAST(f64, args[0]);
|
||||||
f64 offset = x >= 0 ? 0.5 : -0.5;
|
f64 offset = x >= 0 ? 0.5 : -0.5;
|
||||||
if(args[1] == vm->None) { return VAR((i64)(x + offset)); }
|
if(args[1] == vm->None) return VAR((i64)(x + offset));
|
||||||
int ndigits = CAST(int, args[1]);
|
int ndigits = CAST(int, args[1]);
|
||||||
if(ndigits < 0) { vm->ValueError("ndigits should be non-negative"); }
|
if(ndigits < 0) vm->ValueError("ndigits should be non-negative");
|
||||||
// ndigits > 0
|
// ndigits > 0
|
||||||
return VAR((i64)(x * std::pow(10, ndigits) + offset) / std::pow(10, ndigits));
|
return VAR((i64)(x * std::pow(10, ndigits) + offset) / std::pow(10, ndigits));
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(_vm->builtins, "abs", 1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(_vm->builtins, "abs", 1, [](VM* vm, ArgsView args) {
|
||||||
if(is_int(args[0])) { return VAR(std::abs(_CAST(i64, args[0]))); }
|
if(is_int(args[0])) return VAR(std::abs(_CAST(i64, args[0])));
|
||||||
if(is_float(args[0])) { return VAR(std::abs(_CAST(f64, args[0]))); }
|
if(is_float(args[0])) return VAR(std::abs(_CAST(f64, args[0])));
|
||||||
vm->TypeError("bad operand type for abs()");
|
vm->TypeError("bad operand type for abs()");
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
@ -187,11 +186,13 @@ void __init_builtins(VM* _vm) {
|
|||||||
|
|
||||||
_vm->bind_func(_vm->builtins, "id", 1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(_vm->builtins, "id", 1, [](VM* vm, ArgsView args) {
|
||||||
PyVar obj = args[0];
|
PyVar obj = args[0];
|
||||||
if(is_tagged(obj)) { return vm->None; }
|
if(is_tagged(obj)) return vm->None;
|
||||||
return VAR(reinterpret_cast<i64>(obj.get()));
|
return VAR(reinterpret_cast<i64>(obj.get()));
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(_vm->builtins, "callable", 1, [](VM* vm, ArgsView args) { return VAR(vm->py_callable(args[0])); });
|
_vm->bind_func(_vm->builtins, "callable", 1, [](VM* vm, ArgsView args) {
|
||||||
|
return VAR(vm->py_callable(args[0]));
|
||||||
|
});
|
||||||
|
|
||||||
_vm->bind_func(_vm->builtins, "__import__", 1, [](VM* vm, ArgsView args) -> PyVar {
|
_vm->bind_func(_vm->builtins, "__import__", 1, [](VM* vm, ArgsView args) -> PyVar {
|
||||||
const Str& name = CAST(Str&, args[0]);
|
const Str& name = CAST(Str&, args[0]);
|
||||||
@ -202,7 +203,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
if(is_int(args[0])) {
|
if(is_int(args[0])) {
|
||||||
i64 lhs = _CAST(i64, args[0]);
|
i64 lhs = _CAST(i64, args[0]);
|
||||||
i64 rhs = CAST(i64, args[1]);
|
i64 rhs = CAST(i64, args[1]);
|
||||||
if(rhs == 0) { vm->ZeroDivisionError(); }
|
if(rhs == 0) vm->ZeroDivisionError();
|
||||||
auto res = std::div(lhs, rhs);
|
auto res = std::div(lhs, rhs);
|
||||||
return VAR(Tuple(VAR(res.quot), VAR(res.rem)));
|
return VAR(Tuple(VAR(res.quot), VAR(res.rem)));
|
||||||
} else {
|
} else {
|
||||||
@ -241,11 +242,13 @@ void __init_builtins(VM* _vm) {
|
|||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(_vm->builtins, "repr", 1, [](VM* vm, ArgsView args) { return VAR(vm->py_repr(args[0])); });
|
_vm->bind_func(_vm->builtins, "repr", 1, [](VM* vm, ArgsView args) {
|
||||||
|
return VAR(vm->py_repr(args[0]));
|
||||||
|
});
|
||||||
|
|
||||||
_vm->bind_func(_vm->builtins, "len", 1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(_vm->builtins, "len", 1, [](VM* vm, ArgsView args) {
|
||||||
const PyTypeInfo* ti = vm->_tp_info(args[0]);
|
const PyTypeInfo* ti = vm->_tp_info(args[0]);
|
||||||
if(ti->m__len__) { return VAR(ti->m__len__(vm, args[0])); }
|
if(ti->m__len__) return VAR(ti->m__len__(vm, args[0]));
|
||||||
return vm->call_method(args[0], __len__);
|
return vm->call_method(args[0], __len__);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -256,13 +259,13 @@ void __init_builtins(VM* _vm) {
|
|||||||
|
|
||||||
_vm->bind_func(_vm->builtins, "chr", 1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(_vm->builtins, "chr", 1, [](VM* vm, ArgsView args) {
|
||||||
i64 i = CAST(i64, args[0]);
|
i64 i = CAST(i64, args[0]);
|
||||||
if(i < 0 || i >= 128) { vm->ValueError("chr() arg not in [0, 128)"); }
|
if(i < 0 || i >= 128) vm->ValueError("chr() arg not in [0, 128)");
|
||||||
return VAR(std::string(1, (char)i));
|
return VAR(std::string(1, (char)i));
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(_vm->builtins, "ord", 1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(_vm->builtins, "ord", 1, [](VM* vm, ArgsView args) {
|
||||||
const Str& s = CAST(Str&, args[0]);
|
const Str& s = CAST(Str&, args[0]);
|
||||||
if(s.length() != 1) { vm->TypeError("ord() expected an ASCII character"); }
|
if(s.length() != 1) vm->TypeError("ord() expected an ASCII character");
|
||||||
return VAR((i64)(s[0]));
|
return VAR((i64)(s[0]));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -276,11 +279,11 @@ void __init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(_vm->builtins, "getattr", -1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(_vm->builtins, "getattr", -1, [](VM* vm, ArgsView args) {
|
||||||
if(args.size() != 2 && args.size() != 3) { vm->TypeError("getattr() takes 2 or 3 arguments"); }
|
if(args.size() != 2 && args.size() != 3) vm->TypeError("getattr() takes 2 or 3 arguments");
|
||||||
StrName name = CAST(Str&, args[1]);
|
StrName name = CAST(Str&, args[1]);
|
||||||
PyVar val = vm->getattr(args[0], name, false);
|
PyVar val = vm->getattr(args[0], name, false);
|
||||||
if(val == nullptr) {
|
if(val == nullptr) {
|
||||||
if(args.size() == 2) { vm->AttributeError(args[0], name); }
|
if(args.size() == 2) vm->AttributeError(args[0], name);
|
||||||
return args[2];
|
return args[2];
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
@ -297,11 +300,13 @@ void __init_builtins(VM* _vm) {
|
|||||||
return VAR(ss.str());
|
return VAR(ss.str());
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(_vm->builtins, "iter", 1, [](VM* vm, ArgsView args) { return vm->py_iter(args[0]); });
|
_vm->bind_func(_vm->builtins, "iter", 1, [](VM* vm, ArgsView args) {
|
||||||
|
return vm->py_iter(args[0]);
|
||||||
|
});
|
||||||
|
|
||||||
_vm->bind_func(_vm->builtins, "next", 1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(_vm->builtins, "next", 1, [](VM* vm, ArgsView args) {
|
||||||
PyVar retval = vm->py_next(args[0]);
|
PyVar retval = vm->py_next(args[0]);
|
||||||
if(retval == vm->StopIteration) { vm->_error(vm->call(vm->StopIteration)); }
|
if(retval == vm->StopIteration) vm->_error(vm->call(vm->StopIteration));
|
||||||
return retval;
|
return retval;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -319,7 +324,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
x >>= 1;
|
x >>= 1;
|
||||||
}
|
}
|
||||||
std::reverse(bits.begin(), bits.end());
|
std::reverse(bits.begin(), bits.end());
|
||||||
if(bits.empty()) { bits = "0"; }
|
if(bits.empty()) bits = "0";
|
||||||
ss << bits;
|
ss << bits;
|
||||||
return VAR(ss.str());
|
return VAR(ss.str());
|
||||||
});
|
});
|
||||||
@ -337,7 +342,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
List ret;
|
List ret;
|
||||||
for(int i = 0; i < names.size(); i++) {
|
for(int i = 0; i < names.size(); i++) {
|
||||||
// remove duplicates
|
// remove duplicates
|
||||||
if(i > 0 && names[i] == names[i - 1]) { continue; }
|
if(i > 0 && names[i] == names[i - 1]) continue;
|
||||||
ret.push_back(VAR(names[i].sv()));
|
ret.push_back(VAR(names[i].sv()));
|
||||||
}
|
}
|
||||||
return VAR(std::move(ret));
|
return VAR(std::move(ret));
|
||||||
@ -353,7 +358,9 @@ void __init_builtins(VM* _vm) {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__eq__(VM::tp_object, [](VM* vm, PyVar _0, PyVar _1) { return VAR(_0 == _1); });
|
_vm->bind__eq__(VM::tp_object, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
|
return VAR(_0 == _1);
|
||||||
|
});
|
||||||
|
|
||||||
_vm->__cached_object_new = _vm->bind_func(VM::tp_object, __new__, 1, [](VM* vm, ArgsView args) {
|
_vm->__cached_object_new = _vm->bind_func(VM::tp_object, __new__, 1, [](VM* vm, ArgsView args) {
|
||||||
vm->check_type(args[0], vm->tp_type);
|
vm->check_type(args[0], vm->tp_type);
|
||||||
@ -381,7 +388,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
break;
|
break;
|
||||||
default: vm->TypeError("expected 1-3 arguments, got " + std::to_string(args.size()));
|
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"); }
|
if(r.step == 0) vm->ValueError("range() arg 3 must not be zero");
|
||||||
return VAR(r);
|
return VAR(r);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -403,7 +410,9 @@ void __init_builtins(VM* _vm) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// tp_nonetype
|
// tp_nonetype
|
||||||
_vm->bind__repr__(_vm->_tp(_vm->None), [](VM* vm, PyVar _0) -> Str { return "None"; });
|
_vm->bind__repr__(_vm->_tp(_vm->None), [](VM* vm, PyVar _0) -> Str {
|
||||||
|
return "None";
|
||||||
|
});
|
||||||
|
|
||||||
// tp_float / tp_float
|
// tp_float / tp_float
|
||||||
_vm->bind__truediv__(VM::tp_float, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__truediv__(VM::tp_float, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
@ -420,12 +429,12 @@ void __init_builtins(VM* _vm) {
|
|||||||
i64 lhs = _CAST(i64, _0);
|
i64 lhs = _CAST(i64, _0);
|
||||||
i64 rhs = _CAST(i64, _1);
|
i64 rhs = _CAST(i64, _1);
|
||||||
if(rhs < 0) {
|
if(rhs < 0) {
|
||||||
if(lhs == 0) { vm->ZeroDivisionError("0.0 cannot be raised to a negative power"); }
|
if(lhs == 0) vm->ZeroDivisionError("0.0 cannot be raised to a negative power");
|
||||||
return VAR((f64)std::pow(lhs, rhs));
|
return VAR((f64)std::pow(lhs, rhs));
|
||||||
}
|
}
|
||||||
i64 ret = 1;
|
i64 ret = 1;
|
||||||
while(rhs) {
|
while(rhs) {
|
||||||
if(rhs & 1) { ret *= lhs; }
|
if(rhs & 1) ret *= lhs;
|
||||||
lhs *= lhs;
|
lhs *= lhs;
|
||||||
rhs >>= 1;
|
rhs >>= 1;
|
||||||
}
|
}
|
||||||
@ -439,7 +448,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
_vm->bind__pow__(VM::tp_float, py_number_pow);
|
_vm->bind__pow__(VM::tp_float, py_number_pow);
|
||||||
|
|
||||||
_vm->bind_func(VM::tp_int, __new__, -1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_int, __new__, -1, [](VM* vm, ArgsView args) {
|
||||||
if(args.size() == 1 + 0) { return VAR(0); }
|
if(args.size() == 1 + 0) return VAR(0);
|
||||||
// 1 arg
|
// 1 arg
|
||||||
if(args.size() == 1 + 1) {
|
if(args.size() == 1 + 1) {
|
||||||
switch(vm->_tp(args[1])) {
|
switch(vm->_tp(args[1])) {
|
||||||
@ -451,10 +460,10 @@ void __init_builtins(VM* _vm) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 2+ args -> error
|
// 2+ args -> error
|
||||||
if(args.size() > 1 + 2) { vm->TypeError("int() takes at most 2 arguments"); }
|
if(args.size() > 1 + 2) vm->TypeError("int() takes at most 2 arguments");
|
||||||
// 1 or 2 args with str
|
// 1 or 2 args with str
|
||||||
int base = 10;
|
int base = 10;
|
||||||
if(args.size() == 1 + 2) { base = CAST(i64, args[2]); }
|
if(args.size() == 1 + 2) base = CAST(i64, args[2]);
|
||||||
const Str& s = CAST(Str&, args[1]);
|
const Str& s = CAST(Str&, args[1]);
|
||||||
std::string_view sv = s.sv();
|
std::string_view sv = s.sv();
|
||||||
bool negative = false;
|
bool negative = false;
|
||||||
@ -466,25 +475,25 @@ void __init_builtins(VM* _vm) {
|
|||||||
if(parse_uint(sv, &val, base) != IntParsingResult::Success) {
|
if(parse_uint(sv, &val, base) != IntParsingResult::Success) {
|
||||||
vm->ValueError(_S("invalid literal for int() with base ", base, ": ", s.escape()));
|
vm->ValueError(_S("invalid literal for int() with base ", base, ": ", s.escape()));
|
||||||
}
|
}
|
||||||
if(negative) { val = -val; }
|
if(negative) val = -val;
|
||||||
return VAR(val);
|
return VAR(val);
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__floordiv__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__floordiv__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
i64 rhs = CAST(i64, _1);
|
i64 rhs = CAST(i64, _1);
|
||||||
if(rhs == 0) { vm->ZeroDivisionError(); }
|
if(rhs == 0) vm->ZeroDivisionError();
|
||||||
return VAR(_CAST(i64, _0) / rhs);
|
return VAR(_CAST(i64, _0) / rhs);
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__mod__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__mod__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
i64 rhs = CAST(i64, _1);
|
i64 rhs = CAST(i64, _1);
|
||||||
if(rhs == 0) { vm->ZeroDivisionError(); }
|
if(rhs == 0) vm->ZeroDivisionError();
|
||||||
return VAR(_CAST(i64, _0) % rhs);
|
return VAR(_CAST(i64, _0) % rhs);
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(VM::tp_int, "bit_length", 1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_int, "bit_length", 1, [](VM* vm, ArgsView args) {
|
||||||
i64 x = _CAST(i64, args[0]);
|
i64 x = _CAST(i64, args[0]);
|
||||||
if(x < 0) { x = -x; }
|
if(x < 0) x = -x;
|
||||||
int bits = 0;
|
int bits = 0;
|
||||||
while(x) {
|
while(x) {
|
||||||
x >>= 1;
|
x >>= 1;
|
||||||
@ -493,13 +502,23 @@ void __init_builtins(VM* _vm) {
|
|||||||
return VAR(bits);
|
return VAR(bits);
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__repr__(VM::tp_int, [](VM* vm, PyVar obj) -> Str { return std::to_string(_CAST(i64, obj)); });
|
_vm->bind__repr__(VM::tp_int, [](VM* vm, PyVar obj) -> Str {
|
||||||
_vm->bind__neg__(VM::tp_int, [](VM* vm, PyVar obj) { return VAR(-_CAST(i64, obj)); });
|
return std::to_string(_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) \
|
#define INT_BITWISE_OP(name, op) \
|
||||||
_vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { return VAR(_CAST(i64, lhs) op CAST(i64, rhs)); });
|
_vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { \
|
||||||
|
return VAR(_CAST(i64, lhs) op CAST(i64, rhs)); \
|
||||||
|
});
|
||||||
|
|
||||||
INT_BITWISE_OP(__lshift__, <<)
|
INT_BITWISE_OP(__lshift__, <<)
|
||||||
INT_BITWISE_OP(__rshift__, >>)
|
INT_BITWISE_OP(__rshift__, >>)
|
||||||
@ -510,8 +529,8 @@ void __init_builtins(VM* _vm) {
|
|||||||
#undef INT_BITWISE_OP
|
#undef INT_BITWISE_OP
|
||||||
|
|
||||||
_vm->bind_func(VM::tp_float, __new__, -1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_float, __new__, -1, [](VM* vm, ArgsView args) {
|
||||||
if(args.size() == 1 + 0) { return VAR(0.0); }
|
if(args.size() == 1 + 0) return VAR(0.0);
|
||||||
if(args.size() > 1 + 1) { vm->TypeError("float() takes at most 1 argument"); }
|
if(args.size() > 1 + 1) vm->TypeError("float() takes at most 1 argument");
|
||||||
// 1 arg
|
// 1 arg
|
||||||
switch(vm->_tp(args[1])) {
|
switch(vm->_tp(args[1])) {
|
||||||
case VM::tp_int: return VAR((f64)CAST(i64, args[1]));
|
case VM::tp_int: return VAR((f64)CAST(i64, args[1]));
|
||||||
@ -522,14 +541,14 @@ void __init_builtins(VM* _vm) {
|
|||||||
}
|
}
|
||||||
// str to float
|
// str to float
|
||||||
const Str& s = PK_OBJ_GET(Str, args[1]);
|
const Str& s = PK_OBJ_GET(Str, args[1]);
|
||||||
if(s == "inf") { return VAR(INFINITY); }
|
if(s == "inf") return VAR(INFINITY);
|
||||||
if(s == "-inf") { return VAR(-INFINITY); }
|
if(s == "-inf") return VAR(-INFINITY);
|
||||||
|
|
||||||
double float_out;
|
double float_out;
|
||||||
char* p_end;
|
char* p_end;
|
||||||
try {
|
try {
|
||||||
float_out = std::strtod(s.data, &p_end);
|
float_out = std::strtod(s.data, &p_end);
|
||||||
if(p_end != s.end()) { throw 1; }
|
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);
|
return VAR(float_out);
|
||||||
});
|
});
|
||||||
@ -539,7 +558,9 @@ void __init_builtins(VM* _vm) {
|
|||||||
return (i64)std::hash<f64>()(val);
|
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 {
|
_vm->bind__repr__(VM::tp_float, [](VM* vm, PyVar _0) -> Str {
|
||||||
f64 val = _CAST(f64, _0);
|
f64 val = _CAST(f64, _0);
|
||||||
@ -550,31 +571,35 @@ void __init_builtins(VM* _vm) {
|
|||||||
|
|
||||||
// tp_str
|
// tp_str
|
||||||
_vm->bind_func(VM::tp_str, __new__, -1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_str, __new__, -1, [](VM* vm, ArgsView args) {
|
||||||
if(args.size() == 1) { return VAR(Str()); }
|
if(args.size() == 1) return VAR(Str());
|
||||||
if(args.size() > 2) { vm->TypeError("str() takes at most 1 argument"); }
|
if(args.size() > 2) vm->TypeError("str() takes at most 1 argument");
|
||||||
return VAR(vm->py_str(args[1]));
|
return VAR(vm->py_str(args[1]));
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__hash__(VM::tp_str, [](VM* vm, PyVar _0) { return (i64)_CAST(Str&, _0).hash(); });
|
_vm->bind__hash__(VM::tp_str, [](VM* vm, PyVar _0) {
|
||||||
|
return (i64)_CAST(Str&, _0).hash();
|
||||||
|
});
|
||||||
|
|
||||||
_vm->bind__add__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) { return VAR(_CAST(Str&, _0) + CAST(Str&, _1)); });
|
_vm->bind__add__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
_vm->bind__len__(VM::tp_str, [](VM* vm, PyVar _0) { return (i64)_CAST(Str&, _0).u8_length(); });
|
return VAR(_CAST(Str&, _0) + CAST(Str&, _1));
|
||||||
|
});
|
||||||
|
_vm->bind__len__(VM::tp_str, [](VM* vm, PyVar _0) {
|
||||||
|
return (i64)_CAST(Str&, _0).u8_length();
|
||||||
|
});
|
||||||
_vm->bind__mul__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__mul__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
const Str& self = _CAST(Str&, _0);
|
const Str& self = _CAST(Str&, _0);
|
||||||
i64 n = CAST(i64, _1);
|
i64 n = CAST(i64, _1);
|
||||||
SStream ss;
|
SStream ss;
|
||||||
for(i64 i = 0; i < n; i++) {
|
for(i64 i = 0; i < n; i++)
|
||||||
ss << self.sv();
|
ss << self.sv();
|
||||||
}
|
|
||||||
return VAR(ss.str());
|
return VAR(ss.str());
|
||||||
});
|
});
|
||||||
_vm->bind_func(VM::tp_str, "__rmul__", 2, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_str, "__rmul__", 2, [](VM* vm, ArgsView args) {
|
||||||
const Str& self = _CAST(Str&, args[0]);
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
i64 n = CAST(i64, args[1]);
|
i64 n = CAST(i64, args[1]);
|
||||||
SStream ss;
|
SStream ss;
|
||||||
for(i64 i = 0; i < n; i++) {
|
for(i64 i = 0; i < n; i++)
|
||||||
ss << self.sv();
|
ss << self.sv();
|
||||||
}
|
|
||||||
return VAR(ss.str());
|
return VAR(ss.str());
|
||||||
});
|
});
|
||||||
_vm->bind__contains__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__contains__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
@ -582,8 +607,12 @@ void __init_builtins(VM* _vm) {
|
|||||||
return VAR(self.index(CAST(Str&, _1)) != -1);
|
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_func(VM::tp_str, __str__, 1, [](VM* vm, ArgsView args) {
|
||||||
_vm->bind__iter__(VM::tp_str, [](VM* vm, PyVar _0) { return vm->new_user_object<StringIter>(_0); });
|
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 {
|
_vm->bind__repr__(VM::tp_str, [](VM* vm, PyVar _0) -> Str {
|
||||||
const Str& self = _CAST(Str&, _0);
|
const Str& self = _CAST(Str&, _0);
|
||||||
return self.escape();
|
return self.escape();
|
||||||
@ -618,7 +647,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
_vm->bind(_vm->_t(VM::tp_str), "replace(self, old, new, count=-1)", [](VM* vm, ArgsView args) {
|
_vm->bind(_vm->_t(VM::tp_str), "replace(self, old, new, count=-1)", [](VM* vm, ArgsView args) {
|
||||||
const Str& self = _CAST(Str&, args[0]);
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
const Str& old = CAST(Str&, args[1]);
|
const Str& old = CAST(Str&, args[1]);
|
||||||
if(old.empty()) { vm->ValueError("empty substring"); }
|
if(old.empty()) vm->ValueError("empty substring");
|
||||||
const Str& new_ = CAST(Str&, args[2]);
|
const Str& new_ = CAST(Str&, args[2]);
|
||||||
int count = CAST(int, args[3]);
|
int count = CAST(int, args[3]);
|
||||||
return VAR(self.replace(old, new_, count));
|
return VAR(self.replace(old, new_, count));
|
||||||
@ -627,7 +656,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
_vm->bind(_vm->_t(VM::tp_str), "split(self, sep=' ')", [](VM* vm, ArgsView args) {
|
_vm->bind(_vm->_t(VM::tp_str), "split(self, sep=' ')", [](VM* vm, ArgsView args) {
|
||||||
const Str& self = _CAST(Str&, args[0]);
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
const Str& sep = CAST(Str&, args[1]);
|
const Str& sep = CAST(Str&, args[1]);
|
||||||
if(sep.empty()) { vm->ValueError("empty separator"); }
|
if(sep.empty()) vm->ValueError("empty separator");
|
||||||
vector<std::string_view> parts;
|
vector<std::string_view> parts;
|
||||||
if(sep.size == 1) {
|
if(sep.size == 1) {
|
||||||
parts = self.split(sep[0]);
|
parts = self.split(sep[0]);
|
||||||
@ -635,9 +664,8 @@ void __init_builtins(VM* _vm) {
|
|||||||
parts = self.split(sep);
|
parts = self.split(sep);
|
||||||
}
|
}
|
||||||
List ret(parts.size());
|
List ret(parts.size());
|
||||||
for(int i = 0; i < parts.size(); i++) {
|
for(int i = 0; i < parts.size(); i++)
|
||||||
ret[i] = VAR(Str(parts[i]));
|
ret[i] = VAR(Str(parts[i]));
|
||||||
}
|
|
||||||
return VAR(std::move(ret));
|
return VAR(std::move(ret));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -645,9 +673,8 @@ void __init_builtins(VM* _vm) {
|
|||||||
const Str& self = _CAST(Str&, args[0]);
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
vector<std::string_view> parts = self.split('\n');
|
vector<std::string_view> parts = self.split('\n');
|
||||||
List ret(parts.size());
|
List ret(parts.size());
|
||||||
for(int i = 0; i < parts.size(); i++) {
|
for(int i = 0; i < parts.size(); i++)
|
||||||
ret[i] = VAR(Str(parts[i]));
|
ret[i] = VAR(Str(parts[i]));
|
||||||
}
|
|
||||||
return VAR(std::move(ret));
|
return VAR(std::move(ret));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -661,9 +688,9 @@ void __init_builtins(VM* _vm) {
|
|||||||
const Str& self = _CAST(Str&, args[0]);
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
const Str& value = CAST(Str&, args[1]);
|
const Str& value = CAST(Str&, args[1]);
|
||||||
int start = CAST(int, args[2]);
|
int start = CAST(int, args[2]);
|
||||||
if(start < 0) { vm->ValueError("argument 'start' can't be negative"); }
|
if(start < 0) vm->ValueError("argument 'start' can't be negative");
|
||||||
int index = self.index(value, start);
|
int index = self.index(value, start);
|
||||||
if(index < 0) { vm->ValueError("substring not found"); }
|
if(index < 0) vm->ValueError("substring not found");
|
||||||
return VAR(index);
|
return VAR(index);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -671,7 +698,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
const Str& self = _CAST(Str&, args[0]);
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
const Str& value = CAST(Str&, args[1]);
|
const Str& value = CAST(Str&, args[1]);
|
||||||
int start = CAST(int, args[2]);
|
int start = CAST(int, args[2]);
|
||||||
if(start < 0) { vm->ValueError("argument 'start' can't be negative"); }
|
if(start < 0) vm->ValueError("argument 'start' can't be negative");
|
||||||
return VAR(self.index(value, start));
|
return VAR(self.index(value, start));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -685,7 +712,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
const Str& self = _CAST(Str&, args[0]);
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
const Str& suffix = CAST(Str&, args[1]);
|
const Str& suffix = CAST(Str&, args[1]);
|
||||||
int offset = self.length() - suffix.length();
|
int offset = self.length() - suffix.length();
|
||||||
if(offset < 0) { return vm->False; }
|
if(offset < 0) return vm->False;
|
||||||
bool ok = memcmp(self.data + offset, suffix.data, suffix.length()) == 0;
|
bool ok = memcmp(self.data + offset, suffix.data, suffix.length()) == 0;
|
||||||
return VAR(ok);
|
return VAR(ok);
|
||||||
});
|
});
|
||||||
@ -705,7 +732,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
const PyTypeInfo* info = vm->_tp_info(args[1]);
|
const PyTypeInfo* info = vm->_tp_info(args[1]);
|
||||||
PyVar obj = vm->_py_next(info, it);
|
PyVar obj = vm->_py_next(info, it);
|
||||||
while(obj != vm->StopIteration) {
|
while(obj != vm->StopIteration) {
|
||||||
if(!ss.empty()) { ss << self; }
|
if(!ss.empty()) ss << self;
|
||||||
ss << CAST(Str&, obj);
|
ss << CAST(Str&, obj);
|
||||||
obj = vm->_py_next(info, it);
|
obj = vm->_py_next(info, it);
|
||||||
}
|
}
|
||||||
@ -757,11 +784,10 @@ void __init_builtins(VM* _vm) {
|
|||||||
const Str& self = _CAST(Str&, args[0]);
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
int width = CAST(int, args[1]);
|
int width = CAST(int, args[1]);
|
||||||
int delta = width - self.u8_length();
|
int delta = width - self.u8_length();
|
||||||
if(delta <= 0) { return args[0]; }
|
if(delta <= 0) return args[0];
|
||||||
SStream ss;
|
SStream ss;
|
||||||
for(int i = 0; i < delta; i++) {
|
for(int i = 0; i < delta; i++)
|
||||||
ss << '0';
|
ss << '0';
|
||||||
}
|
|
||||||
ss << self;
|
ss << self;
|
||||||
return VAR(ss.str());
|
return VAR(ss.str());
|
||||||
});
|
});
|
||||||
@ -771,14 +797,13 @@ void __init_builtins(VM* _vm) {
|
|||||||
const Str& self = _CAST(Str&, args[0]);
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
int width = CAST(int, args[1]);
|
int width = CAST(int, args[1]);
|
||||||
int delta = width - self.u8_length();
|
int delta = width - self.u8_length();
|
||||||
if(delta <= 0) { return args[0]; }
|
if(delta <= 0) return args[0];
|
||||||
const Str& fillchar = CAST(Str&, args[2]);
|
const Str& fillchar = CAST(Str&, args[2]);
|
||||||
if(fillchar.u8_length() != 1) { vm->TypeError("The fill character must be exactly one character long"); }
|
if(fillchar.u8_length() != 1) vm->TypeError("The fill character must be exactly one character long");
|
||||||
SStream ss;
|
SStream ss;
|
||||||
ss << self;
|
ss << self;
|
||||||
for(int i = 0; i < delta; i++) {
|
for(int i = 0; i < delta; i++)
|
||||||
ss << fillchar;
|
ss << fillchar;
|
||||||
}
|
|
||||||
return VAR(ss.str());
|
return VAR(ss.str());
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -787,13 +812,12 @@ void __init_builtins(VM* _vm) {
|
|||||||
const Str& self = _CAST(Str&, args[0]);
|
const Str& self = _CAST(Str&, args[0]);
|
||||||
int width = CAST(int, args[1]);
|
int width = CAST(int, args[1]);
|
||||||
int delta = width - self.u8_length();
|
int delta = width - self.u8_length();
|
||||||
if(delta <= 0) { return args[0]; }
|
if(delta <= 0) return args[0];
|
||||||
const Str& fillchar = CAST(Str&, args[2]);
|
const Str& fillchar = CAST(Str&, args[2]);
|
||||||
if(fillchar.u8_length() != 1) { vm->TypeError("The fill character must be exactly one character long"); }
|
if(fillchar.u8_length() != 1) vm->TypeError("The fill character must be exactly one character long");
|
||||||
SStream ss;
|
SStream ss;
|
||||||
for(int i = 0; i < delta; i++) {
|
for(int i = 0; i < delta; i++)
|
||||||
ss << fillchar;
|
ss << fillchar;
|
||||||
}
|
|
||||||
ss << self;
|
ss << self;
|
||||||
return VAR(ss.str());
|
return VAR(ss.str());
|
||||||
});
|
});
|
||||||
@ -803,7 +827,9 @@ void __init_builtins(VM* _vm) {
|
|||||||
List& self = _CAST(List&, args[0]);
|
List& self = _CAST(List&, args[0]);
|
||||||
PyVar key = args[1];
|
PyVar key = args[1];
|
||||||
if(key == vm->None) {
|
if(key == vm->None) {
|
||||||
std::stable_sort(self.begin(), self.end(), [vm](PyVar a, PyVar b) { return vm->py_lt(a, b); });
|
std::stable_sort(self.begin(), self.end(), [vm](PyVar a, PyVar b) {
|
||||||
|
return vm->py_lt(a, b);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
std::stable_sort(self.begin(), self.end(), [vm, key](PyVar a, PyVar b) {
|
std::stable_sort(self.begin(), self.end(), [vm, key](PyVar a, PyVar b) {
|
||||||
return vm->py_lt(vm->call(key, a), vm->call(key, b));
|
return vm->py_lt(vm->call(key, a), vm->call(key, b));
|
||||||
@ -815,14 +841,14 @@ void __init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__repr__(VM::tp_list, [](VM* vm, PyVar _0) -> Str {
|
_vm->bind__repr__(VM::tp_list, [](VM* vm, PyVar _0) -> Str {
|
||||||
if(vm->_repr_recursion_set.contains(_0)) { return "[...]"; }
|
if(vm->_repr_recursion_set.contains(_0)) return "[...]";
|
||||||
List& iterable = _CAST(List&, _0);
|
List& iterable = _CAST(List&, _0);
|
||||||
SStream ss;
|
SStream ss;
|
||||||
ss << '[';
|
ss << '[';
|
||||||
vm->_repr_recursion_set.push_back(_0);
|
vm->_repr_recursion_set.push_back(_0);
|
||||||
for(int i = 0; i < iterable.size(); i++) {
|
for(int i = 0; i < iterable.size(); i++) {
|
||||||
ss << vm->py_repr(iterable[i]);
|
ss << vm->py_repr(iterable[i]);
|
||||||
if(i != iterable.size() - 1) { ss << ", "; }
|
if(i != iterable.size() - 1) ss << ", ";
|
||||||
}
|
}
|
||||||
vm->_repr_recursion_set.pop_back();
|
vm->_repr_recursion_set.pop_back();
|
||||||
ss << ']';
|
ss << ']';
|
||||||
@ -839,7 +865,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
} else {
|
} else {
|
||||||
for(int i = 0; i < iterable.size(); i++) {
|
for(int i = 0; i < iterable.size(); i++) {
|
||||||
ss << vm->py_repr(iterable[i]);
|
ss << vm->py_repr(iterable[i]);
|
||||||
if(i != iterable.size() - 1) { ss << ", "; }
|
if(i != iterable.size() - 1) ss << ", ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ss << ')';
|
ss << ')';
|
||||||
@ -847,36 +873,34 @@ void __init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(VM::tp_list, __new__, -1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_list, __new__, -1, [](VM* vm, ArgsView args) {
|
||||||
if(args.size() == 1 + 0) { return VAR(List()); }
|
if(args.size() == 1 + 0) return VAR(List());
|
||||||
if(args.size() == 1 + 1) { return VAR(vm->py_list(args[1])); }
|
if(args.size() == 1 + 1) return VAR(vm->py_list(args[1]));
|
||||||
vm->TypeError("list() takes 0 or 1 arguments");
|
vm->TypeError("list() takes 0 or 1 arguments");
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__contains__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__contains__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
List& self = _CAST(List&, _0);
|
List& self = _CAST(List&, _0);
|
||||||
for(PyVar i: self) {
|
for(PyVar i: self)
|
||||||
if(vm->py_eq(i, _1)) { return vm->True; }
|
if(vm->py_eq(i, _1)) return vm->True;
|
||||||
}
|
|
||||||
return vm->False;
|
return vm->False;
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(VM::tp_list, "count", 2, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_list, "count", 2, [](VM* vm, ArgsView args) {
|
||||||
List& self = _CAST(List&, args[0]);
|
List& self = _CAST(List&, args[0]);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for(PyVar i: self) {
|
for(PyVar i: self)
|
||||||
if(vm->py_eq(i, args[1])) { count++; }
|
if(vm->py_eq(i, args[1])) count++;
|
||||||
}
|
|
||||||
return VAR(count);
|
return VAR(count);
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__eq__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__eq__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
List& a = _CAST(List&, _0);
|
List& a = _CAST(List&, _0);
|
||||||
if(!is_type(_1, vm->tp_list)) { return vm->NotImplemented; }
|
if(!is_type(_1, vm->tp_list)) return vm->NotImplemented;
|
||||||
List& b = _CAST(List&, _1);
|
List& b = _CAST(List&, _1);
|
||||||
if(a.size() != b.size()) { return vm->False; }
|
if(a.size() != b.size()) return vm->False;
|
||||||
for(int i = 0; i < a.size(); i++) {
|
for(int i = 0; i < a.size(); i++) {
|
||||||
if(!vm->py_eq(a[i], b[i])) { return vm->False; }
|
if(!vm->py_eq(a[i], b[i])) return vm->False;
|
||||||
}
|
}
|
||||||
return vm->True;
|
return vm->True;
|
||||||
});
|
});
|
||||||
@ -886,7 +910,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
PyVar obj = args[1];
|
PyVar obj = args[1];
|
||||||
int start = CAST(int, args[2]);
|
int start = CAST(int, args[2]);
|
||||||
for(int i = start; i < self.size(); i++) {
|
for(int i = start; i < self.size(); i++) {
|
||||||
if(vm->py_eq(self[i], obj)) { return VAR(i); }
|
if(vm->py_eq(self[i], obj)) return VAR(i);
|
||||||
}
|
}
|
||||||
vm->ValueError(vm->py_repr(obj) + " is not in list");
|
vm->ValueError(vm->py_repr(obj) + " is not in list");
|
||||||
return vm->None;
|
return vm->None;
|
||||||
@ -908,7 +932,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
_vm->bind_func(VM::tp_list, "pop", -1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_list, "pop", -1, [](VM* vm, ArgsView args) {
|
||||||
List& self = _CAST(List&, args[0]);
|
List& self = _CAST(List&, args[0]);
|
||||||
if(args.size() == 1 + 0) {
|
if(args.size() == 1 + 0) {
|
||||||
if(self.empty()) { vm->IndexError("pop from empty list"); }
|
if(self.empty()) vm->IndexError("pop from empty list");
|
||||||
PyVar retval = self.back();
|
PyVar retval = self.back();
|
||||||
self.pop_back();
|
self.pop_back();
|
||||||
return retval;
|
return retval;
|
||||||
@ -951,33 +975,31 @@ void __init_builtins(VM* _vm) {
|
|||||||
|
|
||||||
_vm->bind__mul__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__mul__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
const List& self = _CAST(List&, _0);
|
const List& self = _CAST(List&, _0);
|
||||||
if(!is_int(_1)) { return vm->NotImplemented; }
|
if(!is_int(_1)) return vm->NotImplemented;
|
||||||
int n = _CAST(int, _1);
|
int n = _CAST(int, _1);
|
||||||
List result;
|
List result;
|
||||||
result.reserve(self.size() * n);
|
result.reserve(self.size() * n);
|
||||||
for(int i = 0; i < n; i++) {
|
for(int i = 0; i < n; i++)
|
||||||
result.extend(self.begin(), self.end());
|
result.extend(self.begin(), self.end());
|
||||||
}
|
|
||||||
return VAR(std::move(result));
|
return VAR(std::move(result));
|
||||||
});
|
});
|
||||||
_vm->bind_func(VM::tp_list, "__rmul__", 2, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_list, "__rmul__", 2, [](VM* vm, ArgsView args) {
|
||||||
const List& self = _CAST(List&, args[0]);
|
const List& self = _CAST(List&, args[0]);
|
||||||
if(!is_int(args[1])) { return vm->NotImplemented; }
|
if(!is_int(args[1])) return vm->NotImplemented;
|
||||||
int n = _CAST(int, args[1]);
|
int n = _CAST(int, args[1]);
|
||||||
List result;
|
List result;
|
||||||
result.reserve(self.size() * n);
|
result.reserve(self.size() * n);
|
||||||
for(int i = 0; i < n; i++) {
|
for(int i = 0; i < n; i++)
|
||||||
result.extend(self.begin(), self.end());
|
result.extend(self.begin(), self.end());
|
||||||
}
|
|
||||||
return VAR(std::move(result));
|
return VAR(std::move(result));
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(VM::tp_list, "insert", 3, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_list, "insert", 3, [](VM* vm, ArgsView args) {
|
||||||
List& self = _CAST(List&, args[0]);
|
List& self = _CAST(List&, args[0]);
|
||||||
int index = CAST(int, args[1]);
|
int index = CAST(int, args[1]);
|
||||||
if(index < 0) { index += self.size(); }
|
if(index < 0) index += self.size();
|
||||||
if(index < 0) { index = 0; }
|
if(index < 0) index = 0;
|
||||||
if(index > self.size()) { index = self.size(); }
|
if(index > self.size()) index = self.size();
|
||||||
self.insert(index, args[2]);
|
self.insert(index, args[2]);
|
||||||
return vm->None;
|
return vm->None;
|
||||||
});
|
});
|
||||||
@ -1024,7 +1046,9 @@ void __init_builtins(VM* _vm) {
|
|||||||
return VAR(std::move(new_list));
|
return VAR(std::move(new_list));
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__len__(VM::tp_list, [](VM* vm, PyVar _0) { return (i64)_CAST(List&, _0).size(); });
|
_vm->bind__len__(VM::tp_list, [](VM* vm, PyVar _0) {
|
||||||
|
return (i64)_CAST(List&, _0).size();
|
||||||
|
});
|
||||||
_vm->bind__iter__(VM::tp_list, [](VM* vm, PyVar _0) {
|
_vm->bind__iter__(VM::tp_list, [](VM* vm, PyVar _0) {
|
||||||
List& self = _CAST(List&, _0);
|
List& self = _CAST(List&, _0);
|
||||||
return vm->new_user_object<ArrayIter>(_0.get(), self.begin(), self.end());
|
return vm->new_user_object<ArrayIter>(_0.get(), self.begin(), self.end());
|
||||||
@ -1049,7 +1073,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(VM::tp_tuple, __new__, -1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_tuple, __new__, -1, [](VM* vm, ArgsView args) {
|
||||||
if(args.size() == 1 + 0) { return VAR(Tuple(0)); }
|
if(args.size() == 1 + 0) return VAR(Tuple(0));
|
||||||
if(args.size() == 1 + 1) {
|
if(args.size() == 1 + 1) {
|
||||||
List list = vm->py_list(args[1]);
|
List list = vm->py_list(args[1]);
|
||||||
return VAR(list.to_tuple());
|
return VAR(list.to_tuple());
|
||||||
@ -1060,28 +1084,26 @@ void __init_builtins(VM* _vm) {
|
|||||||
|
|
||||||
_vm->bind__contains__(VM::tp_tuple, [](VM* vm, PyVar obj, PyVar item) {
|
_vm->bind__contains__(VM::tp_tuple, [](VM* vm, PyVar obj, PyVar item) {
|
||||||
Tuple& self = _CAST(Tuple&, obj);
|
Tuple& self = _CAST(Tuple&, obj);
|
||||||
for(PyVar i: self) {
|
for(PyVar i: self)
|
||||||
if(vm->py_eq(i, item)) { return vm->True; }
|
if(vm->py_eq(i, item)) return vm->True;
|
||||||
}
|
|
||||||
return vm->False;
|
return vm->False;
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(VM::tp_tuple, "count", 2, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_tuple, "count", 2, [](VM* vm, ArgsView args) {
|
||||||
Tuple& self = _CAST(Tuple&, args[0]);
|
Tuple& self = _CAST(Tuple&, args[0]);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for(PyVar i: self) {
|
for(PyVar i: self)
|
||||||
if(vm->py_eq(i, args[1])) { count++; }
|
if(vm->py_eq(i, args[1])) count++;
|
||||||
}
|
|
||||||
return VAR(count);
|
return VAR(count);
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__eq__(VM::tp_tuple, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__eq__(VM::tp_tuple, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
const Tuple& self = _CAST(Tuple&, _0);
|
const Tuple& self = _CAST(Tuple&, _0);
|
||||||
if(!is_type(_1, vm->tp_tuple)) { return vm->NotImplemented; }
|
if(!is_type(_1, vm->tp_tuple)) return vm->NotImplemented;
|
||||||
const Tuple& other = _CAST(Tuple&, _1);
|
const Tuple& other = _CAST(Tuple&, _1);
|
||||||
if(self.size() != other.size()) { return vm->False; }
|
if(self.size() != other.size()) return vm->False;
|
||||||
for(int i = 0; i < self.size(); i++) {
|
for(int i = 0; i < self.size(); i++) {
|
||||||
if(!vm->py_eq(self[i], other[i])) { return vm->False; }
|
if(!vm->py_eq(self[i], other[i])) return vm->False;
|
||||||
}
|
}
|
||||||
return vm->True;
|
return vm->True;
|
||||||
});
|
});
|
||||||
@ -1106,28 +1128,42 @@ void __init_builtins(VM* _vm) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
_vm->bind__getitem__(VM::tp_tuple, PyArrayGetItem<Tuple>);
|
_vm->bind__getitem__(VM::tp_tuple, PyArrayGetItem<Tuple>);
|
||||||
_vm->bind__len__(VM::tp_tuple, [](VM* vm, PyVar obj) { return (i64)_CAST(Tuple&, obj).size(); });
|
_vm->bind__len__(VM::tp_tuple, [](VM* vm, PyVar obj) {
|
||||||
|
return (i64)_CAST(Tuple&, obj).size();
|
||||||
|
});
|
||||||
|
|
||||||
// tp_bool
|
// tp_bool
|
||||||
_vm->bind_func(VM::tp_bool, __new__, 2, PK_LAMBDA(VAR(vm->py_bool(args[1]))));
|
_vm->bind_func(VM::tp_bool, __new__, 2, PK_LAMBDA(VAR(vm->py_bool(args[1]))));
|
||||||
_vm->bind__hash__(VM::tp_bool, [](VM* vm, PyVar _0) { return (i64)_CAST(bool, _0); });
|
_vm->bind__hash__(VM::tp_bool, [](VM* vm, PyVar _0) {
|
||||||
|
return (i64)_CAST(bool, _0);
|
||||||
|
});
|
||||||
_vm->bind__repr__(VM::tp_bool, [](VM* vm, PyVar _0) -> Str {
|
_vm->bind__repr__(VM::tp_bool, [](VM* vm, PyVar _0) -> Str {
|
||||||
bool val = _CAST(bool, _0);
|
bool val = _CAST(bool, _0);
|
||||||
return val ? "True" : "False";
|
return val ? "True" : "False";
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__and__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) { return VAR(_CAST(bool, _0) && CAST(bool, _1)); });
|
_vm->bind__and__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
_vm->bind__or__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) { return VAR(_CAST(bool, _0) || CAST(bool, _1)); });
|
return VAR(_CAST(bool, _0) && CAST(bool, _1));
|
||||||
_vm->bind__xor__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) { return VAR(_CAST(bool, _0) != CAST(bool, _1)); });
|
});
|
||||||
|
_vm->bind__or__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
|
return VAR(_CAST(bool, _0) || CAST(bool, _1));
|
||||||
|
});
|
||||||
|
_vm->bind__xor__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
|
return VAR(_CAST(bool, _0) != CAST(bool, _1));
|
||||||
|
});
|
||||||
_vm->bind__eq__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__eq__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
if(is_type(_1, vm->tp_bool)) { return VAR(_0 == _1); }
|
if(is_type(_1, vm->tp_bool)) return VAR(_0 == _1);
|
||||||
if(is_int(_1)) { return VAR(_CAST(bool, _0) == (bool)CAST(i64, _1)); }
|
if(is_int(_1)) return VAR(_CAST(bool, _0) == (bool)CAST(i64, _1));
|
||||||
return vm->NotImplemented;
|
return vm->NotImplemented;
|
||||||
});
|
});
|
||||||
|
|
||||||
// tp_ellipsis / tp_NotImplementedType
|
// tp_ellipsis / tp_NotImplementedType
|
||||||
_vm->bind__repr__(_vm->_tp(_vm->Ellipsis), [](VM* vm, PyVar _0) -> Str { return "..."; });
|
_vm->bind__repr__(_vm->_tp(_vm->Ellipsis), [](VM* vm, PyVar _0) -> Str {
|
||||||
_vm->bind__repr__(_vm->_tp(_vm->NotImplemented), [](VM* vm, PyVar _0) -> Str { return "NotImplemented"; });
|
return "...";
|
||||||
|
});
|
||||||
|
_vm->bind__repr__(_vm->_tp(_vm->NotImplemented), [](VM* vm, PyVar _0) -> Str {
|
||||||
|
return "NotImplemented";
|
||||||
|
});
|
||||||
|
|
||||||
// tp_bytes
|
// tp_bytes
|
||||||
_vm->bind_func(VM::tp_bytes, __new__, 2, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_bytes, __new__, 2, [](VM* vm, ArgsView args) {
|
||||||
@ -1135,7 +1171,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
Bytes retval(list.size());
|
Bytes retval(list.size());
|
||||||
for(int i = 0; i < list.size(); i++) {
|
for(int i = 0; i < list.size(); i++) {
|
||||||
i64 b = CAST(i64, list[i]);
|
i64 b = CAST(i64, list[i]);
|
||||||
if(b < 0 || b > 255) { vm->ValueError("byte must be in range[0, 256)"); }
|
if(b < 0 || b > 255) vm->ValueError("byte must be in range[0, 256)");
|
||||||
retval[i] = (char)b;
|
retval[i] = (char)b;
|
||||||
}
|
}
|
||||||
return VAR(std::move(retval));
|
return VAR(std::move(retval));
|
||||||
@ -1148,7 +1184,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
int start, stop, step;
|
int start, stop, step;
|
||||||
vm->parse_int_slice(s, self.size(), start, stop, step);
|
vm->parse_int_slice(s, self.size(), start, stop, step);
|
||||||
int guess_max_size = abs(stop - start) / abs(step) + 1;
|
int guess_max_size = abs(stop - start) / abs(step) + 1;
|
||||||
if(guess_max_size > self.size()) { guess_max_size = self.size(); }
|
if(guess_max_size > self.size()) guess_max_size = self.size();
|
||||||
unsigned char* buffer = (unsigned char*)std::malloc(guess_max_size);
|
unsigned char* buffer = (unsigned char*)std::malloc(guess_max_size);
|
||||||
int j = 0; // actual size
|
int j = 0; // actual size
|
||||||
PK_SLICE_LOOP(i, start, stop, step) buffer[j++] = self[i];
|
PK_SLICE_LOOP(i, start, stop, step) buffer[j++] = self[i];
|
||||||
@ -1185,7 +1221,9 @@ void __init_builtins(VM* _vm) {
|
|||||||
ss << "'";
|
ss << "'";
|
||||||
return ss.str();
|
return ss.str();
|
||||||
});
|
});
|
||||||
_vm->bind__len__(VM::tp_bytes, [](VM* vm, PyVar _0) { return (i64)_CAST(Bytes&, _0).size(); });
|
_vm->bind__len__(VM::tp_bytes, [](VM* vm, PyVar _0) {
|
||||||
|
return (i64)_CAST(Bytes&, _0).size();
|
||||||
|
});
|
||||||
|
|
||||||
_vm->bind_func(VM::tp_bytes, "decode", 1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_bytes, "decode", 1, [](VM* vm, ArgsView args) {
|
||||||
const Bytes& self = _CAST(Bytes&, args[0]);
|
const Bytes& self = _CAST(Bytes&, args[0]);
|
||||||
@ -1193,10 +1231,10 @@ void __init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__eq__(VM::tp_bytes, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__eq__(VM::tp_bytes, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
if(!is_type(_1, vm->tp_bytes)) { return vm->NotImplemented; }
|
if(!is_type(_1, vm->tp_bytes)) return vm->NotImplemented;
|
||||||
const Bytes& lhs = _CAST(Bytes&, _0);
|
const Bytes& lhs = _CAST(Bytes&, _0);
|
||||||
const Bytes& rhs = _CAST(Bytes&, _1);
|
const Bytes& rhs = _CAST(Bytes&, _1);
|
||||||
if(lhs.size() != rhs.size()) { return vm->False; }
|
if(lhs.size() != rhs.size()) return vm->False;
|
||||||
return VAR(memcmp(lhs.data(), rhs.data(), lhs.size()) == 0);
|
return VAR(memcmp(lhs.data(), rhs.data(), lhs.size()) == 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1207,11 +1245,11 @@ void __init_builtins(VM* _vm) {
|
|||||||
|
|
||||||
_vm->bind__eq__(VM::tp_slice, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__eq__(VM::tp_slice, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
const Slice& self = _CAST(Slice&, _0);
|
const Slice& self = _CAST(Slice&, _0);
|
||||||
if(!is_type(_1, vm->tp_slice)) { return vm->NotImplemented; }
|
if(!is_type(_1, vm->tp_slice)) return vm->NotImplemented;
|
||||||
const Slice& other = _CAST(Slice&, _1);
|
const Slice& other = _CAST(Slice&, _1);
|
||||||
if(vm->py_ne(self.start, other.start)) { return vm->False; }
|
if(vm->py_ne(self.start, other.start)) return vm->False;
|
||||||
if(vm->py_ne(self.stop, other.stop)) { return vm->False; }
|
if(vm->py_ne(self.stop, other.stop)) return vm->False;
|
||||||
if(vm->py_ne(self.step, other.step)) { return vm->False; }
|
if(vm->py_ne(self.step, other.step)) return vm->False;
|
||||||
return vm->True;
|
return vm->True;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1229,18 +1267,16 @@ void __init_builtins(VM* _vm) {
|
|||||||
_vm->bind_func(VM::tp_mappingproxy, "keys", 1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_mappingproxy, "keys", 1, [](VM* vm, ArgsView args) {
|
||||||
MappingProxy& self = _CAST(MappingProxy&, args[0]);
|
MappingProxy& self = _CAST(MappingProxy&, args[0]);
|
||||||
List keys;
|
List keys;
|
||||||
for(StrName name: self.attr().keys()) {
|
for(StrName name: self.attr().keys())
|
||||||
keys.push_back(VAR(name.sv()));
|
keys.push_back(VAR(name.sv()));
|
||||||
}
|
|
||||||
return VAR(std::move(keys));
|
return VAR(std::move(keys));
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(VM::tp_mappingproxy, "values", 1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_mappingproxy, "values", 1, [](VM* vm, ArgsView args) {
|
||||||
MappingProxy& self = _CAST(MappingProxy&, args[0]);
|
MappingProxy& self = _CAST(MappingProxy&, args[0]);
|
||||||
List values;
|
List values;
|
||||||
for(auto [k, v]: self.attr().items()) {
|
for(auto [k, v]: self.attr().items())
|
||||||
values.push_back(v);
|
values.push_back(v);
|
||||||
}
|
|
||||||
return VAR(std::move(values));
|
return VAR(std::move(values));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1254,11 +1290,13 @@ void __init_builtins(VM* _vm) {
|
|||||||
return VAR(std::move(items));
|
return VAR(std::move(items));
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__len__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) { return (i64)_CAST(MappingProxy&, _0).attr().size(); });
|
_vm->bind__len__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) {
|
||||||
|
return (i64)_CAST(MappingProxy&, _0).attr().size();
|
||||||
|
});
|
||||||
|
|
||||||
_vm->bind__eq__(VM::tp_mappingproxy, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__eq__(VM::tp_mappingproxy, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
const MappingProxy& a = _CAST(MappingProxy&, _0);
|
const MappingProxy& a = _CAST(MappingProxy&, _0);
|
||||||
if(!is_type(_1, VM::tp_mappingproxy)) { return vm->NotImplemented; }
|
if(!is_type(_1, VM::tp_mappingproxy)) return vm->NotImplemented;
|
||||||
const MappingProxy& b = _CAST(MappingProxy&, _1);
|
const MappingProxy& b = _CAST(MappingProxy&, _1);
|
||||||
return VAR(a.obj == b.obj);
|
return VAR(a.obj == b.obj);
|
||||||
});
|
});
|
||||||
@ -1267,7 +1305,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
MappingProxy& self = _CAST(MappingProxy&, _0);
|
MappingProxy& self = _CAST(MappingProxy&, _0);
|
||||||
StrName key = CAST(Str&, _1);
|
StrName key = CAST(Str&, _1);
|
||||||
PyVar ret = self.attr().try_get_likely_found(key);
|
PyVar ret = self.attr().try_get_likely_found(key);
|
||||||
if(ret == nullptr) { vm->KeyError(_1); }
|
if(ret == nullptr) vm->KeyError(_1);
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1275,19 +1313,19 @@ void __init_builtins(VM* _vm) {
|
|||||||
MappingProxy& self = _CAST(MappingProxy&, args[0]);
|
MappingProxy& self = _CAST(MappingProxy&, args[0]);
|
||||||
StrName key = CAST(Str&, args[1]);
|
StrName key = CAST(Str&, args[1]);
|
||||||
PyVar ret = self.attr().try_get(key);
|
PyVar ret = self.attr().try_get(key);
|
||||||
if(ret == nullptr) { return args[2]; }
|
if(ret == nullptr) return args[2];
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__repr__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) -> Str {
|
_vm->bind__repr__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) -> Str {
|
||||||
if(vm->_repr_recursion_set.contains(_0)) { return "{...}"; }
|
if(vm->_repr_recursion_set.contains(_0)) return "{...}";
|
||||||
MappingProxy& self = _CAST(MappingProxy&, _0);
|
MappingProxy& self = _CAST(MappingProxy&, _0);
|
||||||
SStream ss;
|
SStream ss;
|
||||||
ss << "mappingproxy({";
|
ss << "mappingproxy({";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
vm->_repr_recursion_set.push_back(_0);
|
vm->_repr_recursion_set.push_back(_0);
|
||||||
for(auto [k, v]: self.attr().items()) {
|
for(auto [k, v]: self.attr().items()) {
|
||||||
if(!first) { ss << ", "; }
|
if(!first) ss << ", ";
|
||||||
first = false;
|
first = false;
|
||||||
ss << k.escape() << ": ";
|
ss << k.escape() << ": ";
|
||||||
ss << vm->py_repr(v);
|
ss << vm->py_repr(v);
|
||||||
@ -1309,7 +1347,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(VM::tp_dict, __init__, -1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_dict, __init__, -1, [](VM* vm, ArgsView args) {
|
||||||
if(args.size() == 1 + 0) { return vm->None; }
|
if(args.size() == 1 + 0) return vm->None;
|
||||||
if(args.size() == 1 + 1) {
|
if(args.size() == 1 + 1) {
|
||||||
auto _lock = vm->heap.gc_scope_lock();
|
auto _lock = vm->heap.gc_scope_lock();
|
||||||
Dict& self = PK_OBJ_GET(Dict, args[0]);
|
Dict& self = PK_OBJ_GET(Dict, args[0]);
|
||||||
@ -1335,7 +1373,9 @@ void __init_builtins(VM* _vm) {
|
|||||||
vm->TypeError("dict() takes at most 1 argument");
|
vm->TypeError("dict() takes at most 1 argument");
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__len__(VM::tp_dict, [](VM* vm, PyVar _0) { return (i64)PK_OBJ_GET(Dict, _0).size(); });
|
_vm->bind__len__(VM::tp_dict, [](VM* vm, PyVar _0) {
|
||||||
|
return (i64)PK_OBJ_GET(Dict, _0).size();
|
||||||
|
});
|
||||||
|
|
||||||
_vm->bind__getitem__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__getitem__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
Dict& self = PK_OBJ_GET(Dict, _0);
|
Dict& self = PK_OBJ_GET(Dict, _0);
|
||||||
@ -1358,7 +1398,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
_vm->bind__delitem__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__delitem__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
Dict& self = _CAST(Dict&, _0);
|
Dict& self = _CAST(Dict&, _0);
|
||||||
bool ok = self.del(vm, _1);
|
bool ok = self.del(vm, _1);
|
||||||
if(!ok) { vm->KeyError(_1); }
|
if(!ok) vm->KeyError(_1);
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_func(VM::tp_dict, "pop", -1, [](VM* vm, ArgsView args) {
|
_vm->bind_func(VM::tp_dict, "pop", -1, [](VM* vm, ArgsView args) {
|
||||||
@ -1369,7 +1409,7 @@ void __init_builtins(VM* _vm) {
|
|||||||
Dict& self = _CAST(Dict&, args[0]);
|
Dict& self = _CAST(Dict&, args[0]);
|
||||||
PyVar value = self.try_get(vm, args[1]);
|
PyVar value = self.try_get(vm, args[1]);
|
||||||
if(value == nullptr) {
|
if(value == nullptr) {
|
||||||
if(args.size() == 2) { vm->KeyError(args[1]); }
|
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]);
|
self.del(vm, args[1]);
|
||||||
@ -1390,11 +1430,11 @@ void __init_builtins(VM* _vm) {
|
|||||||
Dict& self = _CAST(Dict&, args[0]);
|
Dict& self = _CAST(Dict&, args[0]);
|
||||||
if(args.size() == 1 + 1) {
|
if(args.size() == 1 + 1) {
|
||||||
PyVar ret = self.try_get(vm, args[1]);
|
PyVar ret = self.try_get(vm, args[1]);
|
||||||
if(ret != nullptr) { return ret; }
|
if(ret != nullptr) return ret;
|
||||||
return vm->None;
|
return vm->None;
|
||||||
} else if(args.size() == 1 + 2) {
|
} else if(args.size() == 1 + 2) {
|
||||||
PyVar ret = self.try_get(vm, args[1]);
|
PyVar ret = self.try_get(vm, args[1]);
|
||||||
if(ret != nullptr) { return ret; }
|
if(ret != nullptr) return ret;
|
||||||
return args[2];
|
return args[2];
|
||||||
}
|
}
|
||||||
vm->TypeError("get() takes at most 2 arguments");
|
vm->TypeError("get() takes at most 2 arguments");
|
||||||
@ -1434,14 +1474,14 @@ void __init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind__repr__(VM::tp_dict, [](VM* vm, PyVar _0) -> Str {
|
_vm->bind__repr__(VM::tp_dict, [](VM* vm, PyVar _0) -> Str {
|
||||||
if(vm->_repr_recursion_set.contains(_0)) { return "{...}"; }
|
if(vm->_repr_recursion_set.contains(_0)) return "{...}";
|
||||||
Dict& self = _CAST(Dict&, _0);
|
Dict& self = _CAST(Dict&, _0);
|
||||||
SStream ss;
|
SStream ss;
|
||||||
ss << "{";
|
ss << "{";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
vm->_repr_recursion_set.push_back(_0);
|
vm->_repr_recursion_set.push_back(_0);
|
||||||
self.apply([&](PyVar k, PyVar v) {
|
self.apply([&](PyVar k, PyVar v) {
|
||||||
if(!first) { ss << ", "; }
|
if(!first) ss << ", ";
|
||||||
first = false;
|
first = false;
|
||||||
ss << vm->py_repr(k) << ": " << vm->py_repr(v);
|
ss << vm->py_repr(k) << ": " << vm->py_repr(v);
|
||||||
});
|
});
|
||||||
@ -1452,15 +1492,15 @@ void __init_builtins(VM* _vm) {
|
|||||||
|
|
||||||
_vm->bind__eq__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) {
|
_vm->bind__eq__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) {
|
||||||
Dict& self = _CAST(Dict&, _0);
|
Dict& self = _CAST(Dict&, _0);
|
||||||
if(!vm->isinstance(_1, vm->tp_dict)) { return vm->NotImplemented; }
|
if(!vm->isinstance(_1, vm->tp_dict)) return vm->NotImplemented;
|
||||||
Dict& other = _CAST(Dict&, _1);
|
Dict& other = _CAST(Dict&, _1);
|
||||||
if(self.size() != other.size()) { return vm->False; }
|
if(self.size() != other.size()) return vm->False;
|
||||||
for(int i = 0; i < self._capacity; i++) {
|
for(int i = 0; i < self._capacity; i++) {
|
||||||
auto item = self._items[i];
|
auto item = self._items[i];
|
||||||
if(item.first == nullptr) { continue; }
|
if(item.first == nullptr) continue;
|
||||||
PyVar value = other.try_get(vm, item.first);
|
PyVar value = other.try_get(vm, item.first);
|
||||||
if(value == nullptr) { return vm->False; }
|
if(value == nullptr) return vm->False;
|
||||||
if(!vm->py_eq(item.second, value)) { return vm->False; }
|
if(!vm->py_eq(item.second, value)) return vm->False;
|
||||||
}
|
}
|
||||||
return vm->True;
|
return vm->True;
|
||||||
});
|
});
|
||||||
@ -1483,14 +1523,14 @@ void __init_builtins(VM* _vm) {
|
|||||||
|
|
||||||
_vm->bind_property(_vm->_t(VM::tp_function), "__doc__", [](VM* vm, ArgsView args) {
|
_vm->bind_property(_vm->_t(VM::tp_function), "__doc__", [](VM* vm, ArgsView args) {
|
||||||
Function& func = _CAST(Function&, args[0]);
|
Function& func = _CAST(Function&, args[0]);
|
||||||
if(!func.decl->docstring) { return vm->None; }
|
if(!func.decl->docstring) return vm->None;
|
||||||
return VAR(func.decl->docstring);
|
return VAR(func.decl->docstring);
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_property(_vm->_t(VM::tp_native_func), "__doc__", [](VM* vm, ArgsView args) {
|
_vm->bind_property(_vm->_t(VM::tp_native_func), "__doc__", [](VM* vm, ArgsView args) {
|
||||||
NativeFunc& func = _CAST(NativeFunc&, args[0]);
|
NativeFunc& func = _CAST(NativeFunc&, args[0]);
|
||||||
if(func.decl == nullptr) { return vm->None; }
|
if(func.decl == nullptr) return vm->None;
|
||||||
if(!func.decl->docstring) { return vm->None; }
|
if(!func.decl->docstring) return vm->None;
|
||||||
return VAR(func.decl->docstring);
|
return VAR(func.decl->docstring);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1540,7 +1580,7 @@ void VM::__post_init_builtin_types() {
|
|||||||
_all_types[tp_module].m__getattr__ = [](VM* vm, PyVar obj, StrName name) -> PyVar {
|
_all_types[tp_module].m__getattr__ = [](VM* vm, PyVar obj, StrName name) -> PyVar {
|
||||||
const Str& path = CAST(Str&, obj->attr(__path__));
|
const Str& path = CAST(Str&, obj->attr(__path__));
|
||||||
PyObject* retval = vm->py_import(_S(path, ".", name.sv()), false);
|
PyObject* retval = vm->py_import(_S(path, ".", name.sv()), false);
|
||||||
if(retval) { return retval; }
|
if(retval) return retval;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1575,7 +1615,7 @@ void VM::__post_init_builtin_types() {
|
|||||||
});
|
});
|
||||||
bind_property(_t(tp_type), "__module__", [](VM* vm, ArgsView args) -> PyVar {
|
bind_property(_t(tp_type), "__module__", [](VM* vm, ArgsView args) -> PyVar {
|
||||||
const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])];
|
const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])];
|
||||||
if(info.mod == nullptr) { return vm->None; }
|
if(info.mod == nullptr) return vm->None;
|
||||||
return info.mod;
|
return info.mod;
|
||||||
});
|
});
|
||||||
bind_property(_t(tp_bound_method), "__self__", [](VM* vm, ArgsView args) {
|
bind_property(_t(tp_bound_method), "__self__", [](VM* vm, ArgsView args) {
|
||||||
@ -1586,18 +1626,24 @@ void VM::__post_init_builtin_types() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
bind__eq__(tp_bound_method, [](VM* vm, PyVar lhs, PyVar rhs) {
|
bind__eq__(tp_bound_method, [](VM* vm, PyVar lhs, PyVar rhs) {
|
||||||
if(!is_type(rhs, vm->tp_bound_method)) { return vm->NotImplemented; }
|
if(!is_type(rhs, vm->tp_bound_method)) return vm->NotImplemented;
|
||||||
const BoundMethod& _0 = PK_OBJ_GET(BoundMethod, lhs);
|
const BoundMethod& _0 = PK_OBJ_GET(BoundMethod, lhs);
|
||||||
const BoundMethod& _1 = PK_OBJ_GET(BoundMethod, rhs);
|
const BoundMethod& _1 = PK_OBJ_GET(BoundMethod, rhs);
|
||||||
return VAR(_0.self == _1.self && _0.func == _1.func);
|
return VAR(_0.self == _1.self && _0.func == _1.func);
|
||||||
});
|
});
|
||||||
|
|
||||||
bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args) { return CAST(Slice&, args[0]).start; });
|
bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args) {
|
||||||
bind_property(_t(tp_slice), "stop", [](VM* vm, ArgsView args) { return CAST(Slice&, args[0]).stop; });
|
return CAST(Slice&, args[0]).start;
|
||||||
bind_property(_t(tp_slice), "step", [](VM* vm, ArgsView args) { return CAST(Slice&, args[0]).step; });
|
});
|
||||||
|
bind_property(_t(tp_slice), "stop", [](VM* vm, ArgsView args) {
|
||||||
|
return CAST(Slice&, args[0]).stop;
|
||||||
|
});
|
||||||
|
bind_property(_t(tp_slice), "step", [](VM* vm, ArgsView args) {
|
||||||
|
return CAST(Slice&, args[0]).step;
|
||||||
|
});
|
||||||
|
|
||||||
bind_property(_t(tp_object), "__dict__", [](VM* vm, ArgsView args) {
|
bind_property(_t(tp_object), "__dict__", [](VM* vm, ArgsView args) {
|
||||||
if(is_tagged(args[0]) || !args[0]->is_attr_valid()) { return vm->None; }
|
if(is_tagged(args[0]) || !args[0]->is_attr_valid()) return vm->None;
|
||||||
return VAR(MappingProxy(args[0].get()));
|
return VAR(MappingProxy(args[0].get()));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1608,7 +1654,7 @@ void VM::__post_init_builtin_types() {
|
|||||||
SStream ss;
|
SStream ss;
|
||||||
for(int i = 0; i < _0.size(); i++) {
|
for(int i = 0; i < _0.size(); i++) {
|
||||||
ss << vm->py_str(_0[i]);
|
ss << vm->py_str(_0[i]);
|
||||||
if(i != _0.size() - 1) { ss << _1; }
|
if(i != _0.size() - 1) ss << _1;
|
||||||
}
|
}
|
||||||
ss << _2;
|
ss << _2;
|
||||||
vm->stdout_write(ss.str());
|
vm->stdout_write(ss.str());
|
||||||
|
|||||||
@ -34,7 +34,7 @@ static PyVar stack_item(VM* vm, int index) {
|
|||||||
begin = vm->__c.s_view.top().begin();
|
begin = vm->__c.s_view.top().begin();
|
||||||
}
|
}
|
||||||
int size = end - begin;
|
int size = end - begin;
|
||||||
if(index < 0) { index += size; }
|
if(index < 0) index += size;
|
||||||
assert(index >= 0 && index < size);
|
assert(index >= 0 && index < size);
|
||||||
return begin[index];
|
return begin[index];
|
||||||
}
|
}
|
||||||
@ -133,7 +133,7 @@ int pkpy_stack_size(pkpy_vm* vm_handle) {
|
|||||||
VM* vm = (VM*)vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
PK_ASSERT_NO_ERROR()
|
PK_ASSERT_NO_ERROR()
|
||||||
if(vm->callstack.empty()) { return vm->s_data.size(); }
|
if(vm->callstack.empty()) { return vm->s_data.size(); }
|
||||||
if(vm->__c.s_view.empty()) { exit(127); }
|
if(vm->__c.s_view.empty()) exit(127);
|
||||||
return vm->s_data._sp - vm->__c.s_view.top().begin();
|
return vm->s_data._sp - vm->__c.s_view.top().begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,7 +313,7 @@ struct TempViewPopper {
|
|||||||
TempViewPopper(VM* vm) : vm(vm), used(false) {}
|
TempViewPopper(VM* vm) : vm(vm), used(false) {}
|
||||||
|
|
||||||
void restore() noexcept {
|
void restore() noexcept {
|
||||||
if(used) { return; }
|
if(used) return;
|
||||||
vm->__c.s_view.pop();
|
vm->__c.s_view.pop();
|
||||||
used = true;
|
used = true;
|
||||||
}
|
}
|
||||||
@ -339,8 +339,8 @@ static PyVar c_function_wrapper(VM* vm, ArgsView args) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
assert(retc == vm->s_data._sp - curr_sp);
|
assert(retc == vm->s_data._sp - curr_sp);
|
||||||
if(retc == 0) { return vm->None; }
|
if(retc == 0) return vm->None;
|
||||||
if(retc == 1) { return vm->s_data.popx(); }
|
if(retc == 1) return vm->s_data.popx();
|
||||||
ArgsView ret_view(curr_sp, vm->s_data._sp);
|
ArgsView ret_view(curr_sp, vm->s_data._sp);
|
||||||
return py_var(vm, ret_view.to_tuple());
|
return py_var(vm, ret_view.to_tuple());
|
||||||
}
|
}
|
||||||
@ -374,7 +374,7 @@ bool pkpy_getattr(pkpy_vm* vm_handle, pkpy_CName name) {
|
|||||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||||
PyVar o = vm->s_data.top();
|
PyVar o = vm->s_data.top();
|
||||||
o = vm->getattr(o, StrName(name), false);
|
o = vm->getattr(o, StrName(name), false);
|
||||||
if(o == nullptr) { return false; }
|
if(o == nullptr) return false;
|
||||||
vm->s_data.top() = o;
|
vm->s_data.top() = o;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -399,7 +399,7 @@ bool pkpy_getglobal(pkpy_vm* vm_handle, pkpy_CName name) {
|
|||||||
PyVar o = vm->_main->attr().try_get(StrName(name));
|
PyVar o = vm->_main->attr().try_get(StrName(name));
|
||||||
if(o == nullptr) {
|
if(o == nullptr) {
|
||||||
o = vm->builtins->attr().try_get(StrName(name));
|
o = vm->builtins->attr().try_get(StrName(name));
|
||||||
if(o == nullptr) { return false; }
|
if(o == nullptr) return false;
|
||||||
}
|
}
|
||||||
vm->s_data.push(o);
|
vm->s_data.push(o);
|
||||||
return true;
|
return true;
|
||||||
@ -433,8 +433,7 @@ bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) {
|
|||||||
PyVar _0 = vm->py_iter(vm->s_data.popx());
|
PyVar _0 = vm->py_iter(vm->s_data.popx());
|
||||||
for(int i=0; i<n; i++){
|
for(int i=0; i<n; i++){
|
||||||
PyVar _1 = vm->py_next(_0);
|
PyVar _1 = vm->py_next(_0);
|
||||||
if(_1 == vm->StopIteration){ vm->ValueError("not enough values to unpack");
|
if(_1 == vm->StopIteration) vm->ValueError("not enough values to unpack");
|
||||||
}
|
|
||||||
vm->s_data.push(_1);
|
vm->s_data.push(_1);
|
||||||
}
|
}
|
||||||
if(vm->py_next(_0) != vm->StopIteration) vm->ValueError("too many values to unpack");
|
if(vm->py_next(_0) != vm->StopIteration) vm->ValueError("too many values to unpack");
|
||||||
@ -516,18 +515,17 @@ bool pkpy_check_error(pkpy_vm* vm_handle) {
|
|||||||
bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
|
bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
|
||||||
VM* vm = (VM*)vm_handle;
|
VM* vm = (VM*)vm_handle;
|
||||||
// no error
|
// no error
|
||||||
if(vm->__c.error == nullptr) { return false; }
|
if(vm->__c.error == nullptr) return false;
|
||||||
Exception& e = vm->__c.error->as<Exception>();
|
Exception& e = vm->__c.error->as<Exception>();
|
||||||
if(message != nullptr) {
|
if(message != nullptr)
|
||||||
*message = strdup(e.summary().c_str());
|
*message = strdup(e.summary().c_str());
|
||||||
} else {
|
else
|
||||||
std::cout << e.summary() << std::endl;
|
std::cout << e.summary() << std::endl;
|
||||||
}
|
|
||||||
vm->__c.error = nullptr;
|
vm->__c.error = nullptr;
|
||||||
if(vm->callstack.empty()) {
|
if(vm->callstack.empty()) {
|
||||||
vm->s_data.clear();
|
vm->s_data.clear();
|
||||||
} else {
|
} else {
|
||||||
if(vm->__c.s_view.empty()) { exit(127); }
|
if(vm->__c.s_view.empty()) exit(127);
|
||||||
vm->s_data.reset(vm->__c.s_view.top().end());
|
vm->s_data.reset(vm->__c.s_view.top().end());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -20,7 +20,7 @@ bool REPL::input(std::string line) {
|
|||||||
if(n >= need_more_lines) {
|
if(n >= need_more_lines) {
|
||||||
for(int i = buffer.size() - need_more_lines; i < buffer.size(); i++) {
|
for(int i = buffer.size() - need_more_lines; i < buffer.size(); i++) {
|
||||||
// no enough lines
|
// no enough lines
|
||||||
if(buffer[i] != '\n') { return true; }
|
if(buffer[i] != '\n') return true;
|
||||||
}
|
}
|
||||||
need_more_lines = 0;
|
need_more_lines = 0;
|
||||||
line = buffer;
|
line = buffer;
|
||||||
@ -37,7 +37,7 @@ bool REPL::input(std::string line) {
|
|||||||
buffer += line;
|
buffer += line;
|
||||||
buffer += '\n';
|
buffer += '\n';
|
||||||
need_more_lines = ne.is_compiling_class ? 3 : 2;
|
need_more_lines = ne.is_compiling_class ? 3 : 2;
|
||||||
if(need_more_lines) { return true; }
|
if(need_more_lines) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,9 +20,7 @@ std::string pkpy_platform_getline(bool* eof) {
|
|||||||
WCHAR buf;
|
WCHAR buf;
|
||||||
DWORD read;
|
DWORD read;
|
||||||
while(ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') {
|
while(ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') {
|
||||||
if(eof && buf == L'\x1A') {
|
if(eof && buf == L'\x1A') *eof = true; // Ctrl+Z
|
||||||
*eof = true; // Ctrl+Z
|
|
||||||
}
|
|
||||||
wss << buf;
|
wss << buf;
|
||||||
}
|
}
|
||||||
std::wstring wideInput = wss.str();
|
std::wstring wideInput = wss.str();
|
||||||
@ -30,7 +28,7 @@ std::string pkpy_platform_getline(bool* eof) {
|
|||||||
std::string output;
|
std::string output;
|
||||||
output.resize(length);
|
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(); }
|
if(!output.empty() && output.back() == '\r') output.pop_back();
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +37,7 @@ std::string pkpy_platform_getline(bool* eof) {
|
|||||||
std::string pkpy_platform_getline(bool* eof) {
|
std::string pkpy_platform_getline(bool* eof) {
|
||||||
std::string output;
|
std::string output;
|
||||||
if(!std::getline(std::cin, output)) {
|
if(!std::getline(std::cin, output)) {
|
||||||
if(eof) { *eof = true; }
|
if(eof) *eof = true;
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@ -50,7 +48,7 @@ static int f_input(pkpy_vm* vm) {
|
|||||||
if(!pkpy_is_none(vm, -1)) {
|
if(!pkpy_is_none(vm, -1)) {
|
||||||
pkpy_CString prompt;
|
pkpy_CString prompt;
|
||||||
bool ok = pkpy_to_string(vm, -1, &prompt);
|
bool ok = pkpy_to_string(vm, -1, &prompt);
|
||||||
if(!ok) { return 0; }
|
if(!ok) return 0;
|
||||||
std::cout << prompt << std::flush;
|
std::cout << prompt << std::flush;
|
||||||
}
|
}
|
||||||
bool eof;
|
bool eof;
|
||||||
@ -77,7 +75,7 @@ int main(int argc, char** argv) {
|
|||||||
std::cout << (need_more_lines ? "... " : ">>> ");
|
std::cout << (need_more_lines ? "... " : ">>> ");
|
||||||
bool eof = false;
|
bool eof = false;
|
||||||
std::string line = pkpy_platform_getline(&eof);
|
std::string line = pkpy_platform_getline(&eof);
|
||||||
if(eof) { break; }
|
if(eof) break;
|
||||||
need_more_lines = pkpy_repl_input(repl, line.c_str());
|
need_more_lines = pkpy_repl_input(repl, line.c_str());
|
||||||
}
|
}
|
||||||
pkpy_delete_vm(vm);
|
pkpy_delete_vm(vm);
|
||||||
@ -86,7 +84,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
if(argc == 2) {
|
if(argc == 2) {
|
||||||
std::string argv_1 = argv[1];
|
std::string argv_1 = argv[1];
|
||||||
if(argv_1 == "-h" || argv_1 == "--help") { goto __HELP; }
|
if(argv_1 == "-h" || argv_1 == "--help") goto __HELP;
|
||||||
|
|
||||||
std::filesystem::path filepath(argv[1]);
|
std::filesystem::path filepath(argv[1]);
|
||||||
filepath = std::filesystem::absolute(filepath);
|
filepath = std::filesystem::absolute(filepath);
|
||||||
@ -105,7 +103,7 @@ int main(int argc, char** argv) {
|
|||||||
pkpy_set_main_argv(vm, argc, argv);
|
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); }
|
if(!ok) pkpy_clear_error(vm, NULL);
|
||||||
pkpy_delete_vm(vm);
|
pkpy_delete_vm(vm);
|
||||||
return ok ? 0 : 1;
|
return ok ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user