mirror of
https://github.com/pocketpy/pocketpy
synced 2025-11-08 20:50:16 +00:00
AllowShortIfStatementsOnASingleLine
This commit is contained in:
parent
2603ca7741
commit
7cadf364eb
@ -54,7 +54,7 @@ AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortCompoundRequirementOnASingleLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
|
||||
@ -60,9 +60,7 @@ struct any {
|
||||
any& operator= (const any& other) = delete;
|
||||
|
||||
~any() {
|
||||
if(_vt && _vt->deleter) {
|
||||
_vt->deleter(data);
|
||||
}
|
||||
if(_vt && _vt->deleter) { _vt->deleter(data); }
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -78,9 +76,7 @@ struct any {
|
||||
template <typename T>
|
||||
T& cast() const {
|
||||
static_assert(std::is_same_v<T, std::decay_t<T>>);
|
||||
if(type_id() != typeid(T)) {
|
||||
__bad_any_cast(typeid(T), type_id());
|
||||
}
|
||||
if(type_id() != typeid(T)) { __bad_any_cast(typeid(T), type_id()); }
|
||||
return _cast<T>();
|
||||
}
|
||||
|
||||
|
||||
@ -86,9 +86,7 @@ struct NameDictImpl {
|
||||
uint16_t old_capacity = _capacity;
|
||||
_set_capacity_and_alloc_items(_capacity * 2);
|
||||
for(uint16_t i = 0; i < old_capacity; i++) {
|
||||
if(old_items[i].first.empty()) {
|
||||
continue;
|
||||
}
|
||||
if(old_items[i].first.empty()) { continue; }
|
||||
bool ok;
|
||||
uint16_t j;
|
||||
HASH_PROBE_1(old_items[i].first, ok, j);
|
||||
@ -102,9 +100,7 @@ struct NameDictImpl {
|
||||
bool ok;
|
||||
uint16_t 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;
|
||||
}
|
||||
|
||||
@ -112,33 +108,23 @@ struct NameDictImpl {
|
||||
bool ok;
|
||||
uint16_t i;
|
||||
HASH_PROBE_0(key, ok, i);
|
||||
if(!ok) {
|
||||
return nullptr;
|
||||
}
|
||||
if(!ok) { return nullptr; }
|
||||
return &_items[i].second;
|
||||
}
|
||||
|
||||
T try_get_likely_found(StrName key) const {
|
||||
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;
|
||||
if(_items[i].first == key) {
|
||||
return _items[i].second;
|
||||
}
|
||||
if(_items[i].first == key) { return _items[i].second; }
|
||||
return try_get(key);
|
||||
}
|
||||
|
||||
T* try_get_2_likely_found(StrName key) const {
|
||||
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;
|
||||
if(_items[i].first == key) {
|
||||
return &_items[i].second;
|
||||
}
|
||||
if(_items[i].first == key) { return &_items[i].second; }
|
||||
return try_get_2(key);
|
||||
}
|
||||
|
||||
@ -146,9 +132,7 @@ struct NameDictImpl {
|
||||
bool ok;
|
||||
uint16_t i;
|
||||
HASH_PROBE_0(key, ok, i);
|
||||
if(!ok) {
|
||||
return false;
|
||||
}
|
||||
if(!ok) { return false; }
|
||||
_items[i].first = StrName();
|
||||
_items[i].second = nullptr;
|
||||
_size--;
|
||||
@ -157,9 +141,7 @@ struct NameDictImpl {
|
||||
uint16_t z = (i + 1) & _mask;
|
||||
while(!_items[z].first.empty()) {
|
||||
uint16_t h = _items[z].first.index & _mask;
|
||||
if(h != i) {
|
||||
break;
|
||||
}
|
||||
if(h != i) { break; }
|
||||
std::swap(_items[pre_z], _items[z]);
|
||||
pre_z = z;
|
||||
z = (z + 1) & _mask;
|
||||
@ -170,9 +152,7 @@ struct NameDictImpl {
|
||||
template <typename __Func>
|
||||
void apply(__Func func) const {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -186,9 +166,7 @@ struct NameDictImpl {
|
||||
|
||||
T operator[] (StrName key) const {
|
||||
T* val = try_get_2_likely_found(key);
|
||||
if(val == nullptr) {
|
||||
throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str());
|
||||
}
|
||||
if(val == nullptr) { throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str()); }
|
||||
return *val;
|
||||
}
|
||||
|
||||
@ -196,9 +174,7 @@ struct NameDictImpl {
|
||||
array<StrName> v(_size);
|
||||
int j = 0;
|
||||
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);
|
||||
}
|
||||
return v;
|
||||
|
||||
@ -143,9 +143,7 @@ struct vector {
|
||||
if(cap < 4) {
|
||||
cap = 4; // minimum capacity
|
||||
}
|
||||
if(cap <= capacity()) {
|
||||
return;
|
||||
}
|
||||
if(cap <= capacity()) { return; }
|
||||
T* new_data = (T*)std::malloc(sizeof(T) * cap);
|
||||
if constexpr(is_trivially_relocatable_v<T>) {
|
||||
std::memcpy(new_data, _data, sizeof(T) * _size);
|
||||
@ -155,9 +153,7 @@ struct vector {
|
||||
_data[i].~T();
|
||||
}
|
||||
}
|
||||
if(_data) {
|
||||
std::free(_data);
|
||||
}
|
||||
if(_data) { std::free(_data); }
|
||||
_data = new_data;
|
||||
_capacity = cap;
|
||||
}
|
||||
@ -168,33 +164,25 @@ struct vector {
|
||||
}
|
||||
|
||||
void push_back(const T& t) {
|
||||
if(_size == _capacity) {
|
||||
reserve(_capacity * 2);
|
||||
}
|
||||
if(_size == _capacity) { reserve(_capacity * 2); }
|
||||
new (&_data[_size++]) T(t);
|
||||
}
|
||||
|
||||
void push_back(T&& t) {
|
||||
if(_size == _capacity) {
|
||||
reserve(_capacity * 2);
|
||||
}
|
||||
if(_size == _capacity) { reserve(_capacity * 2); }
|
||||
new (&_data[_size++]) T(std::move(t));
|
||||
}
|
||||
|
||||
bool contains(const T& t) const {
|
||||
for(int i = 0; i < _size; i++) {
|
||||
if(_data[i] == t) {
|
||||
return true;
|
||||
}
|
||||
if(_data[i] == t) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void emplace_back(Args&&... args) {
|
||||
if(_size == _capacity) {
|
||||
reserve(_capacity * 2);
|
||||
}
|
||||
if(_size == _capacity) { reserve(_capacity * 2); }
|
||||
new (&_data[_size++]) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
@ -211,9 +199,7 @@ struct vector {
|
||||
}
|
||||
|
||||
void insert(int index, const T& t) {
|
||||
if(_size == _capacity) {
|
||||
reserve(_capacity * 2);
|
||||
}
|
||||
if(_size == _capacity) { reserve(_capacity * 2); }
|
||||
for(int i = _size; i > index; i--) {
|
||||
_data[i] = std::move(_data[i - 1]);
|
||||
}
|
||||
@ -231,9 +217,7 @@ struct vector {
|
||||
void pop_back() {
|
||||
assert(_size > 0);
|
||||
_size--;
|
||||
if constexpr(!std::is_trivially_destructible_v<T>) {
|
||||
_data[_size].~T();
|
||||
}
|
||||
if constexpr(!std::is_trivially_destructible_v<T>) { _data[_size].~T(); }
|
||||
}
|
||||
|
||||
void clear() {
|
||||
@ -443,9 +427,7 @@ public:
|
||||
|
||||
~small_vector() {
|
||||
std::destroy(m_begin, m_end);
|
||||
if(!is_small()) {
|
||||
std::free(m_begin);
|
||||
}
|
||||
if(!is_small()) { std::free(m_begin); }
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
@ -480,9 +462,7 @@ public:
|
||||
|
||||
void pop_back() {
|
||||
m_end--;
|
||||
if constexpr(!std::is_trivially_destructible_v<T>) {
|
||||
m_end->~T();
|
||||
}
|
||||
if constexpr(!std::is_trivially_destructible_v<T>) { m_end->~T(); }
|
||||
}
|
||||
|
||||
void clear() {
|
||||
|
||||
@ -33,9 +33,7 @@ class Compiler {
|
||||
const Token& next() const { return tokens[i + 1]; }
|
||||
|
||||
const Token& err() const {
|
||||
if(i >= tokens.size()) {
|
||||
return prev();
|
||||
}
|
||||
if(i >= tokens.size()) { return prev(); }
|
||||
return curr();
|
||||
}
|
||||
|
||||
|
||||
@ -288,9 +288,7 @@ struct ListExpr : SequenceExpr {
|
||||
|
||||
Opcode opcode() const override {
|
||||
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;
|
||||
}
|
||||
@ -303,9 +301,7 @@ struct DictExpr : SequenceExpr {
|
||||
|
||||
Opcode opcode() const override {
|
||||
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;
|
||||
}
|
||||
@ -318,9 +314,7 @@ struct SetExpr : SequenceExpr {
|
||||
|
||||
Opcode opcode() const override {
|
||||
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;
|
||||
}
|
||||
@ -333,9 +327,7 @@ struct TupleExpr : SequenceExpr {
|
||||
|
||||
Opcode opcode() const override {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -42,9 +42,7 @@ constexpr TokenIndex TK(const char token[]) {
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
if(*i == *j) {
|
||||
return k;
|
||||
}
|
||||
if(*i == *j) { return k; }
|
||||
}
|
||||
return 255;
|
||||
}
|
||||
|
||||
@ -94,9 +94,7 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
|
||||
assert(is_type(obj, tp_type));
|
||||
std::string_view name_sv(name);
|
||||
int pos = name_sv.find(':');
|
||||
if(pos > 0) {
|
||||
name_sv = name_sv.substr(0, pos);
|
||||
}
|
||||
if(pos > 0) { name_sv = name_sv.substr(0, pos); }
|
||||
auto fget = [](VM* vm, ArgsView args) -> PyVar {
|
||||
obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
|
||||
F T::*field = lambda_get_userdata<F T::*>(args.begin());
|
||||
@ -171,8 +169,7 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
|
||||
1, \
|
||||
[](VM* vm, ArgsView args) { \
|
||||
Struct& s = CAST(Struct&, args[0]); \
|
||||
if(s.size != sizeof(wT)) \
|
||||
vm->ValueError("size mismatch"); \
|
||||
if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \
|
||||
PyVar obj = vm->new_user_object<wT>(); \
|
||||
std::memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \
|
||||
return obj; \
|
||||
@ -194,8 +191,7 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
|
||||
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) { \
|
||||
wT& self = _CAST(wT&, _0); \
|
||||
if(!vm->isinstance(_1, vm->_tp_user<wT>())) \
|
||||
return vm->NotImplemented; \
|
||||
if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \
|
||||
wT& other = _CAST(wT&, _1); \
|
||||
return VAR(self == other); \
|
||||
});
|
||||
|
||||
@ -74,23 +74,17 @@ struct Struct {
|
||||
} else {
|
||||
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) {
|
||||
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() {
|
||||
if(p != _inlined) {
|
||||
std::free(p);
|
||||
}
|
||||
if(p != _inlined) { std::free(p); }
|
||||
}
|
||||
|
||||
static void _register(VM* vm, PyObject* mod, PyObject* type);
|
||||
|
||||
@ -57,9 +57,7 @@ struct Generator {
|
||||
}
|
||||
|
||||
void _gc_mark(VM* vm) {
|
||||
if(lf == nullptr) {
|
||||
return;
|
||||
}
|
||||
if(lf == nullptr) { return; }
|
||||
lf->frame._gc_mark(vm);
|
||||
vm->__stack_gc_mark(s_backup.begin(), s_backup.end());
|
||||
}
|
||||
|
||||
@ -241,9 +241,7 @@ public:
|
||||
bool py_callable(PyVar obj); // x -> callable(x)
|
||||
|
||||
bool py_bool(PyVar obj) { // x -> bool(x)
|
||||
if(obj.type == tp_bool) {
|
||||
return obj._0;
|
||||
}
|
||||
if(obj.type == tp_bool) { return obj._0; }
|
||||
return __py_bool_non_trivial(obj);
|
||||
}
|
||||
|
||||
@ -273,15 +271,11 @@ public:
|
||||
void parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step);
|
||||
|
||||
void obj_gc_mark(PyVar obj) {
|
||||
if(obj.is_ptr) {
|
||||
__obj_gc_mark(obj.get());
|
||||
}
|
||||
if(obj.is_ptr) { __obj_gc_mark(obj.get()); }
|
||||
}
|
||||
|
||||
void obj_gc_mark(PyObject* p) {
|
||||
if(p) {
|
||||
__obj_gc_mark(p);
|
||||
}
|
||||
if(p) { __obj_gc_mark(p); }
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -466,15 +460,11 @@ public:
|
||||
bool issubclass(Type cls, Type base);
|
||||
|
||||
void check_type(PyVar obj, Type type) {
|
||||
if(!is_type(obj, type)) {
|
||||
TypeError(type, _tp(obj));
|
||||
}
|
||||
if(!is_type(obj, type)) { TypeError(type, _tp(obj)); }
|
||||
}
|
||||
|
||||
void check_compatible_type(PyVar obj, Type type) {
|
||||
if(!isinstance(obj, type)) {
|
||||
TypeError(type, _tp(obj));
|
||||
}
|
||||
if(!isinstance(obj, type)) { TypeError(type, _tp(obj)); }
|
||||
}
|
||||
|
||||
Type _tp(PyVar obj) { return obj.type; }
|
||||
@ -759,23 +749,15 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
|
||||
if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, CString>) {
|
||||
static_assert(!std::is_reference_v<__T>);
|
||||
// str (shortcuts)
|
||||
if(obj == vm->None) {
|
||||
return nullptr;
|
||||
}
|
||||
if constexpr(with_check) {
|
||||
vm->check_type(obj, vm->tp_str);
|
||||
}
|
||||
if(obj == vm->None) { return nullptr; }
|
||||
if constexpr(with_check) { vm->check_type(obj, vm->tp_str); }
|
||||
return PK_OBJ_GET(Str, obj).c_str();
|
||||
} else if constexpr(std::is_same_v<T, bool>) {
|
||||
static_assert(!std::is_reference_v<__T>);
|
||||
// bool
|
||||
if constexpr(with_check) {
|
||||
if(obj == vm->True) {
|
||||
return true;
|
||||
}
|
||||
if(obj == vm->False) {
|
||||
return false;
|
||||
}
|
||||
if(obj == vm->True) { return true; }
|
||||
if(obj == vm->False) { return false; }
|
||||
vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||
}
|
||||
return obj == vm->True;
|
||||
@ -783,20 +765,14 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
|
||||
static_assert(!std::is_reference_v<__T>);
|
||||
// int
|
||||
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());
|
||||
}
|
||||
return (T)obj.as<i64>();
|
||||
} else if constexpr(is_floating_point_v<T>) {
|
||||
static_assert(!std::is_reference_v<__T>);
|
||||
if(is_float(obj)) {
|
||||
return (T)obj.as<f64>();
|
||||
}
|
||||
if(is_int(obj)) {
|
||||
return (T)obj.as<i64>();
|
||||
}
|
||||
if(is_float(obj)) { return (T)obj.as<f64>(); }
|
||||
if(is_int(obj)) { return (T)obj.as<i64>(); }
|
||||
vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||
return 0.0f;
|
||||
} else if constexpr(std::is_enum_v<T>) {
|
||||
|
||||
@ -62,9 +62,7 @@ struct CodeBlock {
|
||||
type(type), parent(parent), start(start), end(-1), end2(-1) {}
|
||||
|
||||
int get_break_end() const {
|
||||
if(end2 != -1) {
|
||||
return end2;
|
||||
}
|
||||
if(end2 != -1) { return end2; }
|
||||
return end;
|
||||
}
|
||||
};
|
||||
|
||||
@ -55,9 +55,7 @@ struct Exception {
|
||||
|
||||
template <typename... Args>
|
||||
void st_push(Args&&... args) {
|
||||
if(stacktrace.size() >= 7) {
|
||||
return;
|
||||
}
|
||||
if(stacktrace.size() >= 7) { return; }
|
||||
stacktrace.emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
|
||||
@ -32,16 +32,12 @@ inline object getattr(const handle& obj, const char* name) {
|
||||
}
|
||||
|
||||
inline object getattr(const handle& obj, const handle& name, const handle& default_) {
|
||||
if(!hasattr(obj, name)) {
|
||||
return reinterpret_borrow<object>(default_);
|
||||
}
|
||||
if(!hasattr(obj, name)) { return reinterpret_borrow<object>(default_); }
|
||||
return getattr(obj, name);
|
||||
}
|
||||
|
||||
inline object getattr(const handle& obj, const char* name, const handle& default_) {
|
||||
if(!hasattr(obj, name)) {
|
||||
return reinterpret_borrow<object>(default_);
|
||||
}
|
||||
if(!hasattr(obj, name)) { return reinterpret_borrow<object>(default_); }
|
||||
return getattr(obj, name);
|
||||
}
|
||||
|
||||
|
||||
@ -100,9 +100,7 @@ public:
|
||||
// foreach function record and call the function with not convert
|
||||
while(p != nullptr) {
|
||||
handle result = p->wrapper(*this, view, false, {});
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
if(result) { return result; }
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
@ -110,9 +108,7 @@ public:
|
||||
// foreach function record and call the function with convert
|
||||
while(p != nullptr) {
|
||||
handle result = p->wrapper(*this, view, true, {});
|
||||
if(result) {
|
||||
return result;
|
||||
}
|
||||
if(result) { return result; }
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
@ -172,13 +168,9 @@ struct generator<Fn, std::tuple<Extras...>, std::tuple<Args...>, std::index_sequ
|
||||
|
||||
// initialize the stack
|
||||
|
||||
if(!has_args && (view.size() != count)) {
|
||||
return handle();
|
||||
}
|
||||
if(!has_args && (view.size() != count)) { return handle(); }
|
||||
|
||||
if(has_args && (view.size() < count)) {
|
||||
return handle();
|
||||
}
|
||||
if(has_args && (view.size() < count)) { return handle(); }
|
||||
|
||||
for(std::size_t i = 0; i < count; ++i) {
|
||||
stack[i] = view[i];
|
||||
@ -211,9 +203,7 @@ struct generator<Fn, std::tuple<Extras...>, std::tuple<Args...>, std::index_sequ
|
||||
|
||||
// check if all the arguments are not valid
|
||||
for(std::size_t i = 0; i < sizeof...(Args); ++i) {
|
||||
if(!stack[i]) {
|
||||
return handle();
|
||||
}
|
||||
if(!stack[i]) { return handle(); }
|
||||
}
|
||||
|
||||
// ok, all the arguments are valid, call the function
|
||||
|
||||
@ -126,15 +126,11 @@ public:
|
||||
}
|
||||
|
||||
~instance() {
|
||||
if(flag & Flag::Own) {
|
||||
type->destructor(data);
|
||||
}
|
||||
if(flag & Flag::Own) { type->destructor(data); }
|
||||
}
|
||||
|
||||
void _gc_mark(pkpy::VM* vm) const noexcept {
|
||||
if(parent && (flag & Flag::Ref)) {
|
||||
PK_OBJ_MARK(parent);
|
||||
}
|
||||
if(parent && (flag & Flag::Ref)) { PK_OBJ_MARK(parent); }
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@ -191,16 +191,12 @@ public:
|
||||
}
|
||||
|
||||
~object() {
|
||||
if(m_ptr != nullptr) {
|
||||
dec_ref();
|
||||
}
|
||||
if(m_ptr != nullptr) { dec_ref(); }
|
||||
}
|
||||
|
||||
protected:
|
||||
object(const handle& h, bool borrow) : handle(h) {
|
||||
if(borrow) {
|
||||
inc_ref();
|
||||
}
|
||||
if(borrow) { inc_ref(); }
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@ -183,13 +183,9 @@ class kwargs : public dict {
|
||||
|
||||
template <typename T>
|
||||
handle type::handle_of() {
|
||||
if constexpr(std::is_same_v<T, object>) {
|
||||
return vm->_t(vm->tp_object);
|
||||
}
|
||||
if constexpr(std::is_same_v<T, object>) { return vm->_t(vm->tp_object); }
|
||||
#define PYBIND11_TYPE_MAPPER(type, tp) \
|
||||
else if constexpr(std::is_same_v<T, type>) { \
|
||||
return vm->_t(vm->tp); \
|
||||
}
|
||||
else if constexpr(std::is_same_v<T, type>) { return vm->_t(vm->tp); }
|
||||
PYBIND11_TYPE_MAPPER(type, tp_type)
|
||||
PYBIND11_TYPE_MAPPER(str, tp_str)
|
||||
PYBIND11_TYPE_MAPPER(int_, tp_int)
|
||||
@ -203,9 +199,7 @@ handle type::handle_of() {
|
||||
#undef PYBIND11_TYPE_MAPPER
|
||||
else {
|
||||
auto result = vm->_cxx_typeid_map.find(typeid(T));
|
||||
if(result != vm->_cxx_typeid_map.end()) {
|
||||
return vm->_t(result->second);
|
||||
}
|
||||
if(result != vm->_cxx_typeid_map.end()) { return vm->_t(result->second); }
|
||||
|
||||
vm->TypeError("Type not registered");
|
||||
}
|
||||
|
||||
@ -17,9 +17,7 @@ any::any(any&& other) noexcept : data(other.data), _vt(other._vt) {
|
||||
}
|
||||
|
||||
any& any::operator= (any&& other) noexcept {
|
||||
if(data) {
|
||||
_vt->deleter(data);
|
||||
}
|
||||
if(data) { _vt->deleter(data); }
|
||||
data = other.data;
|
||||
_vt = other._vt;
|
||||
other.data = nullptr;
|
||||
|
||||
@ -146,9 +146,7 @@ struct MemoryPool {
|
||||
return (char*)p + sizeof(void*);
|
||||
}
|
||||
|
||||
if(_arenas.empty()) {
|
||||
_arenas.push_back(new Arena());
|
||||
}
|
||||
if(_arenas.empty()) { _arenas.push_back(new Arena()); }
|
||||
Arena* arena = _arenas.back();
|
||||
void* p = arena->alloc()->data;
|
||||
if(arena->empty()) {
|
||||
@ -178,9 +176,7 @@ struct MemoryPool {
|
||||
|
||||
void shrink_to_fit() {
|
||||
PK_GLOBAL_SCOPE_LOCK();
|
||||
if(_arenas.size() < __MinArenaCount) {
|
||||
return;
|
||||
}
|
||||
if(_arenas.size() < __MinArenaCount) { return; }
|
||||
_arenas.apply([this](Arena* arena) {
|
||||
if(arena->full()) {
|
||||
_arenas.erase(arena);
|
||||
|
||||
@ -9,27 +9,13 @@
|
||||
namespace pkpy {
|
||||
|
||||
int utf8len(unsigned char c, bool suppress) {
|
||||
if((c & 0b10000000) == 0) {
|
||||
return 1;
|
||||
}
|
||||
if((c & 0b11100000) == 0b11000000) {
|
||||
return 2;
|
||||
}
|
||||
if((c & 0b11110000) == 0b11100000) {
|
||||
return 3;
|
||||
}
|
||||
if((c & 0b11111000) == 0b11110000) {
|
||||
return 4;
|
||||
}
|
||||
if((c & 0b11111100) == 0b11111000) {
|
||||
return 5;
|
||||
}
|
||||
if((c & 0b11111110) == 0b11111100) {
|
||||
return 6;
|
||||
}
|
||||
if(!suppress) {
|
||||
throw std::runtime_error("invalid utf8 char: " + std::to_string(c));
|
||||
}
|
||||
if((c & 0b10000000) == 0) { return 1; }
|
||||
if((c & 0b11100000) == 0b11000000) { return 2; }
|
||||
if((c & 0b11110000) == 0b11100000) { return 3; }
|
||||
if((c & 0b11111000) == 0b11110000) { return 4; }
|
||||
if((c & 0b11111100) == 0b11111000) { return 5; }
|
||||
if((c & 0b11111110) == 0b11111100) { return 6; }
|
||||
if(!suppress) { throw std::runtime_error("invalid utf8 char: " + std::to_string(c)); }
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -43,8 +29,7 @@ int utf8len(unsigned char c, bool suppress) {
|
||||
#define PK_STR_COPY_INIT(__s) \
|
||||
for(int i = 0; i < this->size; i++) { \
|
||||
this->data[i] = __s[i]; \
|
||||
if(!isascii(__s[i])) \
|
||||
is_ascii = false; \
|
||||
if(!isascii(__s[i])) is_ascii = false; \
|
||||
} \
|
||||
this->data[this->size] = '\0';
|
||||
|
||||
@ -108,9 +93,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(); }
|
||||
|
||||
Str& Str::operator= (const Str& other) {
|
||||
if(!is_inlined()) {
|
||||
std::free(data);
|
||||
}
|
||||
if(!is_inlined()) { std::free(data); }
|
||||
size = other.size;
|
||||
is_ascii = other.is_ascii;
|
||||
PK_STR_ALLOCATE()
|
||||
@ -133,30 +116,22 @@ Str Str::operator+ (const char* p) 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -175,9 +150,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(); }
|
||||
|
||||
Str::~Str() {
|
||||
if(!is_inlined()) {
|
||||
std::free(data);
|
||||
}
|
||||
if(!is_inlined()) { std::free(data); }
|
||||
}
|
||||
|
||||
Str Str::substr(int start, int len) const {
|
||||
@ -228,9 +201,7 @@ Str Str::strip(bool left, bool right) const {
|
||||
Str Str::lower() const {
|
||||
std::string copy(data, size);
|
||||
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 Str(copy);
|
||||
@ -239,9 +210,7 @@ Str Str::lower() const {
|
||||
Str Str::upper() const {
|
||||
std::string copy(data, size);
|
||||
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 Str(copy);
|
||||
@ -259,15 +228,11 @@ void Str::escape_(SStream& ss, bool single_quote) const {
|
||||
char c = this->operator[] (i);
|
||||
switch(c) {
|
||||
case '"':
|
||||
if(!single_quote) {
|
||||
ss << '\\';
|
||||
}
|
||||
if(!single_quote) { ss << '\\'; }
|
||||
ss << '"';
|
||||
break;
|
||||
case '\'':
|
||||
if(single_quote) {
|
||||
ss << '\\';
|
||||
}
|
||||
if(single_quote) { ss << '\\'; }
|
||||
ss << '\'';
|
||||
break;
|
||||
case '\\': ss << '\\' << '\\'; break;
|
||||
@ -290,18 +255,14 @@ void Str::escape_(SStream& ss, bool single_quote) const {
|
||||
|
||||
int Str::index(const Str& sub, int start) const {
|
||||
auto p = std::search(data + start, data + size, sub.data, sub.data + sub.size);
|
||||
if(p == data + size) {
|
||||
return -1;
|
||||
}
|
||||
if(p == data + size) { return -1; }
|
||||
return p - data;
|
||||
}
|
||||
|
||||
Str Str::replace(char old, char new_) const {
|
||||
Str copied = *this;
|
||||
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;
|
||||
}
|
||||
@ -311,24 +272,18 @@ Str Str::replace(const Str& old, const Str& new_, int count) const {
|
||||
int start = 0;
|
||||
while(true) {
|
||||
int i = index(old, start);
|
||||
if(i == -1) {
|
||||
break;
|
||||
}
|
||||
if(i == -1) { break; }
|
||||
ss << substr(start, i - start);
|
||||
ss << new_;
|
||||
start = i + old.size;
|
||||
if(count != -1 && --count == 0) {
|
||||
break;
|
||||
}
|
||||
if(count != -1 && --count == 0) { break; }
|
||||
}
|
||||
ss << substr(start, size - start);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
int Str::_unicode_index_to_byte(int i) const {
|
||||
if(is_ascii) {
|
||||
return i;
|
||||
}
|
||||
if(is_ascii) { return i; }
|
||||
int j = 0;
|
||||
while(i > 0) {
|
||||
j += utf8len(data[j]);
|
||||
@ -338,14 +293,10 @@ int Str::_unicode_index_to_byte(int i) const {
|
||||
}
|
||||
|
||||
int Str::_byte_index_to_unicode(int n) const {
|
||||
if(is_ascii) {
|
||||
return n;
|
||||
}
|
||||
if(is_ascii) { return n; }
|
||||
int cnt = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
if((data[i] & 0xC0) != 0x80) {
|
||||
cnt++;
|
||||
}
|
||||
if((data[i] & 0xC0) != 0x80) { cnt++; }
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
@ -373,19 +324,13 @@ vector<std::string_view> Str::split(const Str& sep) const {
|
||||
int start = 0;
|
||||
while(true) {
|
||||
int i = index(sep, start);
|
||||
if(i == -1) {
|
||||
break;
|
||||
}
|
||||
if(i == -1) { break; }
|
||||
tmp = sv().substr(start, i - start);
|
||||
if(!tmp.empty()) {
|
||||
result.push_back(tmp);
|
||||
}
|
||||
if(!tmp.empty()) { result.push_back(tmp); }
|
||||
start = i + sep.size;
|
||||
}
|
||||
tmp = sv().substr(start, size - start);
|
||||
if(!tmp.empty()) {
|
||||
result.push_back(tmp);
|
||||
}
|
||||
if(!tmp.empty()) { result.push_back(tmp); }
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -394,30 +339,22 @@ vector<std::string_view> Str::split(char sep) const {
|
||||
int i = 0;
|
||||
for(int j = 0; j < size; j++) {
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(size > i) {
|
||||
result.emplace_back(data + i, size - i);
|
||||
}
|
||||
if(size > i) { result.emplace_back(data + i, size - i); }
|
||||
return result;
|
||||
}
|
||||
|
||||
int Str::count(const Str& sub) const {
|
||||
if(sub.empty()) {
|
||||
return size + 1;
|
||||
}
|
||||
if(sub.empty()) { return size + 1; }
|
||||
int cnt = 0;
|
||||
int start = 0;
|
||||
while(true) {
|
||||
int i = index(sub, start);
|
||||
if(i == -1) {
|
||||
break;
|
||||
}
|
||||
if(i == -1) { break; }
|
||||
cnt++;
|
||||
start = i + sub.size;
|
||||
}
|
||||
@ -438,15 +375,11 @@ uint32_t StrName::_pesudo_random_index = 0;
|
||||
|
||||
StrName StrName::get(std::string_view 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
|
||||
// https://github.com/python/cpython/blob/3.12/Objects/dictobject.c#L175
|
||||
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);
|
||||
assert(res.second);
|
||||
s = std::string_view(res.first->second);
|
||||
@ -525,12 +458,8 @@ SStream& SStream::operator<< (i64 val) {
|
||||
}
|
||||
|
||||
SStream& SStream::operator<< (f64 val) {
|
||||
if(std::isinf(val)) {
|
||||
return (*this) << (val > 0 ? "inf" : "-inf");
|
||||
}
|
||||
if(std::isnan(val)) {
|
||||
return (*this) << "nan";
|
||||
}
|
||||
if(std::isinf(val)) { return (*this) << (val > 0 ? "inf" : "-inf"); }
|
||||
if(std::isnan(val)) { return (*this) << "nan"; }
|
||||
char b[32];
|
||||
if(_precision == -1) {
|
||||
int prec = std::numeric_limits<f64>::max_digits10 - 1;
|
||||
@ -540,9 +469,7 @@ SStream& SStream::operator<< (f64 val) {
|
||||
snprintf(b, sizeof(b), "%.*f", prec, val);
|
||||
}
|
||||
(*this) << b;
|
||||
if(std::all_of(b + 1, b + strlen(b), isdigit)) {
|
||||
(*this) << ".0";
|
||||
}
|
||||
if(std::all_of(b + 1, b + strlen(b), isdigit)) { (*this) << ".0"; }
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -550,12 +477,8 @@ void SStream::write_hex(unsigned char c, bool non_zero) {
|
||||
unsigned char high = c >> 4;
|
||||
unsigned char low = c & 0xf;
|
||||
if(non_zero) {
|
||||
if(high) {
|
||||
(*this) << PK_HEX_TABLE[high];
|
||||
}
|
||||
if(high || low) {
|
||||
(*this) << PK_HEX_TABLE[low];
|
||||
}
|
||||
if(high) { (*this) << PK_HEX_TABLE[high]; }
|
||||
if(high || low) { (*this) << PK_HEX_TABLE[low]; }
|
||||
} else {
|
||||
(*this) << PK_HEX_TABLE[high];
|
||||
(*this) << PK_HEX_TABLE[low];
|
||||
@ -573,9 +496,7 @@ void SStream::write_hex(void* p) {
|
||||
for(int i = sizeof(void*) - 1; i >= 0; i--) {
|
||||
unsigned char cpnt = (p_t >> (i * 8)) & 0xff;
|
||||
write_hex(cpnt, non_zero);
|
||||
if(cpnt != 0) {
|
||||
non_zero = false;
|
||||
}
|
||||
if(cpnt != 0) { non_zero = false; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -593,9 +514,7 @@ void SStream::write_hex(i64 val) {
|
||||
for(int i = 56; i >= 0; i -= 8) {
|
||||
unsigned char cpnt = (val >> i) & 0xff;
|
||||
write_hex(cpnt, non_zero);
|
||||
if(cpnt != 0) {
|
||||
non_zero = false;
|
||||
}
|
||||
if(cpnt != 0) { non_zero = false; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,9 +9,7 @@ PrattRule Compiler::rules[kTokenCount];
|
||||
|
||||
NameScope Compiler::name_scope() const {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -33,9 +31,7 @@ FuncDecl_ Compiler::push_f_context(Str name) {
|
||||
}
|
||||
|
||||
void Compiler::pop_context() {
|
||||
if(!ctx()->s_expr.empty()) {
|
||||
throw std::runtime_error("!ctx()->s_expr.empty()");
|
||||
}
|
||||
if(!ctx()->s_expr.empty()) { throw std::runtime_error("!ctx()->s_expr.empty()"); }
|
||||
// add a `return None` in the end as a guard
|
||||
// previously, we only do this if the last opcode is not a return
|
||||
// however, this is buggy...since there may be a jump to the end (out of bound) even if the last opcode is a return
|
||||
@ -49,12 +45,8 @@ void Compiler::pop_context() {
|
||||
|
||||
// some check here
|
||||
auto& codes = ctx()->co->codes;
|
||||
if(ctx()->co->nlocals > PK_MAX_CO_VARNAMES) {
|
||||
SyntaxError("maximum number of local variables exceeded");
|
||||
}
|
||||
if(ctx()->co->consts.size() > 65530) {
|
||||
SyntaxError("maximum number of constants exceeded");
|
||||
}
|
||||
if(ctx()->co->nlocals > PK_MAX_CO_VARNAMES) { SyntaxError("maximum number of local variables exceeded"); }
|
||||
if(ctx()->co->consts.size() > 65530) { SyntaxError("maximum number of constants exceeded"); }
|
||||
// pre-compute LOOP_BREAK and LOOP_CONTINUE
|
||||
for(int i = 0; i < codes.size(); i++) {
|
||||
Bytecode& bc = codes[i];
|
||||
@ -81,15 +73,9 @@ void Compiler::pop_context() {
|
||||
}
|
||||
if(func->type == FuncType::UNSET) {
|
||||
bool is_simple = true;
|
||||
if(func->kwargs.size() > 0) {
|
||||
is_simple = false;
|
||||
}
|
||||
if(func->starred_arg >= 0) {
|
||||
is_simple = false;
|
||||
}
|
||||
if(func->starred_kwarg >= 0) {
|
||||
is_simple = false;
|
||||
}
|
||||
if(func->kwargs.size() > 0) { is_simple = false; }
|
||||
if(func->starred_arg >= 0) { is_simple = false; }
|
||||
if(func->starred_kwarg >= 0) { is_simple = false; }
|
||||
|
||||
if(is_simple) {
|
||||
func->type = FuncType::SIMPLE;
|
||||
@ -97,13 +83,9 @@ void Compiler::pop_context() {
|
||||
bool is_empty = false;
|
||||
if(func->code->codes.size() == 1) {
|
||||
Bytecode bc = func->code->codes[0];
|
||||
if(bc.op == OP_RETURN_VALUE && bc.arg == 1) {
|
||||
is_empty = true;
|
||||
}
|
||||
}
|
||||
if(is_empty) {
|
||||
func->type = FuncType::EMPTY;
|
||||
if(bc.op == OP_RETURN_VALUE && bc.arg == 1) { is_empty = true; }
|
||||
}
|
||||
if(is_empty) { func->type = FuncType::EMPTY; }
|
||||
} else {
|
||||
func->type = FuncType::NORMAL;
|
||||
}
|
||||
@ -116,9 +98,7 @@ void Compiler::pop_context() {
|
||||
|
||||
void Compiler::init_pratt_rules() {
|
||||
static bool initialized = false;
|
||||
if(initialized) {
|
||||
return;
|
||||
}
|
||||
if(initialized) { return; }
|
||||
initialized = true;
|
||||
|
||||
// clang-format off
|
||||
@ -178,17 +158,13 @@ void Compiler::init_pratt_rules() {
|
||||
}
|
||||
|
||||
bool Compiler::match(TokenIndex expected) {
|
||||
if(curr().type != expected) {
|
||||
return false;
|
||||
}
|
||||
if(curr().type != expected) { return false; }
|
||||
advance();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Compiler::consume(TokenIndex expected) {
|
||||
if(!match(expected)) {
|
||||
SyntaxError(_S("expected '", TK_STR(expected), "', got '", TK_STR(curr().type), "'"));
|
||||
}
|
||||
if(!match(expected)) { SyntaxError(_S("expected '", TK_STR(expected), "', got '", TK_STR(curr().type), "'")); }
|
||||
}
|
||||
|
||||
bool Compiler::match_newlines_repl() { return match_newlines(mode() == REPL_MODE); }
|
||||
@ -201,9 +177,7 @@ bool Compiler::match_newlines(bool repl_throw) {
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
if(repl_throw && curr().type == TK("@eof")) {
|
||||
throw NeedMoreLines(ctx()->is_compiling_class);
|
||||
}
|
||||
if(repl_throw && curr().type == TK("@eof")) { throw NeedMoreLines(ctx()->is_compiling_class); }
|
||||
return consumed;
|
||||
}
|
||||
|
||||
@ -212,43 +186,29 @@ bool Compiler::match_end_stmt() {
|
||||
match_newlines();
|
||||
return true;
|
||||
}
|
||||
if(match_newlines() || curr().type == TK("@eof")) {
|
||||
return true;
|
||||
}
|
||||
if(curr().type == TK("@dedent")) {
|
||||
return true;
|
||||
}
|
||||
if(match_newlines() || curr().type == TK("@eof")) { return true; }
|
||||
if(curr().type == TK("@dedent")) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
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_TUPLE(bool allow_slice) {
|
||||
parse_expression(PREC_LOWEST + 1, allow_slice);
|
||||
if(!match(TK(","))) {
|
||||
return;
|
||||
}
|
||||
if(!match(TK(","))) { return; }
|
||||
// tuple expression
|
||||
Expr_vector items;
|
||||
items.push_back(ctx()->s_expr.popx());
|
||||
do {
|
||||
if(curr().brackets_level) {
|
||||
match_newlines_repl();
|
||||
}
|
||||
if(!is_expression(allow_slice)) {
|
||||
break;
|
||||
}
|
||||
if(curr().brackets_level) { match_newlines_repl(); }
|
||||
if(!is_expression(allow_slice)) { break; }
|
||||
parse_expression(PREC_LOWEST + 1, allow_slice);
|
||||
items.push_back(ctx()->s_expr.popx());
|
||||
if(curr().brackets_level) {
|
||||
match_newlines_repl();
|
||||
}
|
||||
if(curr().brackets_level) { match_newlines_repl(); }
|
||||
} while(match(TK(",")));
|
||||
ctx()->s_expr.push(make_expr<TupleExpr>(std::move(items)));
|
||||
}
|
||||
@ -260,9 +220,7 @@ Expr_ Compiler::EXPR_VARS() {
|
||||
consume(TK("@id"));
|
||||
items.push_back(make_expr<NameExpr>(prev().str(), name_scope()));
|
||||
} 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));
|
||||
}
|
||||
|
||||
@ -351,9 +309,7 @@ void Compiler::exprGroup() {
|
||||
EXPR_TUPLE(); // () is just for change precedence
|
||||
match_newlines_repl();
|
||||
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());
|
||||
ctx()->s_expr.push(std::move(g));
|
||||
}
|
||||
@ -378,9 +334,7 @@ void Compiler::exprList() {
|
||||
Expr_vector items;
|
||||
do {
|
||||
match_newlines_repl();
|
||||
if(curr().type == TK("]")) {
|
||||
break;
|
||||
}
|
||||
if(curr().type == TK("]")) { break; }
|
||||
EXPR();
|
||||
items.push_back(ctx()->s_expr.popx());
|
||||
match_newlines_repl();
|
||||
@ -402,14 +356,10 @@ void Compiler::exprMap() {
|
||||
Expr_vector items;
|
||||
do {
|
||||
match_newlines_repl();
|
||||
if(curr().type == TK("}")) {
|
||||
break;
|
||||
}
|
||||
if(curr().type == TK("}")) { break; }
|
||||
EXPR();
|
||||
int star_level = ctx()->s_expr.top()->star_level();
|
||||
if(star_level == 2 || curr().type == TK(":")) {
|
||||
parsing_dict = true;
|
||||
}
|
||||
if(star_level == 2 || curr().type == TK(":")) { parsing_dict = true; }
|
||||
if(parsing_dict) {
|
||||
auto dict_item = make_expr<DictItemExpr>();
|
||||
if(star_level == 2) {
|
||||
@ -452,9 +402,7 @@ void Compiler::exprCall() {
|
||||
e->callable = ctx()->s_expr.popx();
|
||||
do {
|
||||
match_newlines_repl();
|
||||
if(curr().type == TK(")")) {
|
||||
break;
|
||||
}
|
||||
if(curr().type == TK(")")) { break; }
|
||||
if(curr().type == TK("@id") && next().type == TK("=")) {
|
||||
consume(TK("@id"));
|
||||
Str key = prev().str();
|
||||
@ -468,30 +416,22 @@ void Compiler::exprCall() {
|
||||
e->kwargs.push_back({"**", ctx()->s_expr.popx()});
|
||||
} else {
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
match_newlines_repl();
|
||||
} while(match(TK(",")));
|
||||
consume(TK(")"));
|
||||
if(e->args.size() > 32767) {
|
||||
SyntaxError("too many positional arguments");
|
||||
}
|
||||
if(e->kwargs.size() > 32767) {
|
||||
SyntaxError("too many keyword arguments");
|
||||
}
|
||||
if(e->args.size() > 32767) { SyntaxError("too many positional arguments"); }
|
||||
if(e->kwargs.size() > 32767) { SyntaxError("too many keyword arguments"); }
|
||||
ctx()->s_expr.push(std::move(e));
|
||||
}
|
||||
|
||||
void Compiler::exprName() {
|
||||
Str name = prev().str();
|
||||
NameScope scope = name_scope();
|
||||
if(ctx()->global_names.contains(name)) {
|
||||
scope = NAME_GLOBAL;
|
||||
}
|
||||
if(ctx()->global_names.contains(name)) { scope = NAME_GLOBAL; }
|
||||
ctx()->s_expr.push(make_expr<NameExpr>(name, scope));
|
||||
}
|
||||
|
||||
@ -551,23 +491,17 @@ void Compiler::exprSubscr() {
|
||||
void Compiler::exprLiteral0() { ctx()->s_expr.push(make_expr<Literal0Expr>(prev().type)); }
|
||||
|
||||
void Compiler::compile_block_body(void (Compiler::*callback)()) {
|
||||
if(callback == nullptr) {
|
||||
callback = &Compiler::compile_stmt;
|
||||
}
|
||||
if(callback == nullptr) { callback = &Compiler::compile_stmt; }
|
||||
consume(TK(":"));
|
||||
if(curr().type != TK("@eol") && curr().type != TK("@eof")) {
|
||||
while(true) {
|
||||
compile_stmt();
|
||||
bool possible = curr().type != TK("@eol") && curr().type != TK("@eof");
|
||||
if(prev().type != TK(";") || !possible) {
|
||||
break;
|
||||
}
|
||||
if(prev().type != TK(";") || !possible) { break; }
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(!match_newlines(mode() == REPL_MODE)) {
|
||||
SyntaxError("expected a new line after ':'");
|
||||
}
|
||||
if(!match_newlines(mode() == REPL_MODE)) { SyntaxError("expected a new line after ':'"); }
|
||||
consume(TK("@indent"));
|
||||
while(curr().type != TK("@dedent")) {
|
||||
match_newlines();
|
||||
@ -641,9 +575,7 @@ __EAT_DOTS_END:
|
||||
consume(TK("import"));
|
||||
|
||||
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__
|
||||
ctx()->emit_(OP_POP_IMPORT_STAR, BC_NOARG, prev().line);
|
||||
consume_end_stmt();
|
||||
@ -816,9 +748,7 @@ void Compiler::compile_decorated() {
|
||||
do {
|
||||
EXPR();
|
||||
decorators.push_back(ctx()->s_expr.popx());
|
||||
if(!match_newlines_repl()) {
|
||||
SyntaxError();
|
||||
}
|
||||
if(!match_newlines_repl()) { SyntaxError(); }
|
||||
} while(match(TK("@")));
|
||||
|
||||
if(match(TK("class"))) {
|
||||
@ -843,12 +773,8 @@ bool Compiler::try_compile_assignment() {
|
||||
case TK("|="):
|
||||
case TK("^="): {
|
||||
Expr* lhs_p = ctx()->s_expr.top().get();
|
||||
if(lhs_p->is_starred()) {
|
||||
SyntaxError();
|
||||
}
|
||||
if(ctx()->is_compiling_class) {
|
||||
SyntaxError("can't use inplace operator in class definition");
|
||||
}
|
||||
if(lhs_p->is_starred()) { SyntaxError(); }
|
||||
if(ctx()->is_compiling_class) { SyntaxError("can't use inplace operator in class definition"); }
|
||||
advance();
|
||||
// a[x] += 1; a and x should be evaluated only once
|
||||
// a.x += 1; a should be evaluated only once
|
||||
@ -857,14 +783,10 @@ bool Compiler::try_compile_assignment() {
|
||||
e->lhs = ctx()->s_expr.popx();
|
||||
EXPR_TUPLE();
|
||||
e->rhs = ctx()->s_expr.popx();
|
||||
if(e->rhs->is_starred()) {
|
||||
SyntaxError();
|
||||
}
|
||||
if(e->rhs->is_starred()) { SyntaxError(); }
|
||||
e->emit_(ctx());
|
||||
bool ok = lhs_p->emit_store_inplace(ctx());
|
||||
if(!ok) {
|
||||
SyntaxError();
|
||||
}
|
||||
if(!ok) { SyntaxError(); }
|
||||
}
|
||||
return true;
|
||||
case TK("="): {
|
||||
@ -881,13 +803,9 @@ bool Compiler::try_compile_assignment() {
|
||||
}
|
||||
for(int j = 0; j < n; j++) {
|
||||
auto e = ctx()->s_expr.popx();
|
||||
if(e->is_starred()) {
|
||||
SyntaxError();
|
||||
}
|
||||
if(e->is_starred()) { SyntaxError(); }
|
||||
bool ok = e->emit_store(ctx());
|
||||
if(!ok) {
|
||||
SyntaxError();
|
||||
}
|
||||
if(!ok) { SyntaxError(); }
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -905,32 +823,24 @@ void Compiler::compile_stmt() {
|
||||
int curr_loop_block = ctx()->get_loop();
|
||||
switch(prev().type) {
|
||||
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);
|
||||
consume_end_stmt();
|
||||
break;
|
||||
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);
|
||||
consume_end_stmt();
|
||||
break;
|
||||
case TK("yield"):
|
||||
if(contexts.size() <= 1) {
|
||||
SyntaxError("'yield' outside function");
|
||||
}
|
||||
if(contexts.size() <= 1) { SyntaxError("'yield' outside function"); }
|
||||
EXPR_TUPLE();
|
||||
ctx()->emit_expr();
|
||||
ctx()->emit_(OP_YIELD_VALUE, BC_NOARG, kw_line);
|
||||
consume_end_stmt();
|
||||
break;
|
||||
case TK("yield from"):
|
||||
if(contexts.size() <= 1) {
|
||||
SyntaxError("'yield from' outside function");
|
||||
}
|
||||
if(contexts.size() <= 1) { SyntaxError("'yield from' outside function"); }
|
||||
EXPR_TUPLE();
|
||||
ctx()->emit_expr();
|
||||
|
||||
@ -942,9 +852,7 @@ void Compiler::compile_stmt() {
|
||||
consume_end_stmt();
|
||||
break;
|
||||
case TK("return"):
|
||||
if(contexts.size() <= 1) {
|
||||
SyntaxError("'return' outside function");
|
||||
}
|
||||
if(contexts.size() <= 1) { SyntaxError("'return' outside function"); }
|
||||
if(match_end_stmt()) {
|
||||
ctx()->emit_(OP_RETURN_VALUE, 1, kw_line);
|
||||
} else {
|
||||
@ -970,9 +878,7 @@ void Compiler::compile_stmt() {
|
||||
StrName name(prev().sv());
|
||||
NameScope scope = name_scope();
|
||||
bool is_global = ctx()->global_names.contains(name.sv());
|
||||
if(is_global) {
|
||||
scope = NAME_GLOBAL;
|
||||
}
|
||||
if(is_global) { scope = NAME_GLOBAL; }
|
||||
switch(scope) {
|
||||
case NAME_LOCAL: ctx()->emit_(OP_INC_FAST, ctx()->add_varname(name), prev().line); break;
|
||||
case NAME_GLOBAL: ctx()->emit_(OP_INC_GLOBAL, name.index, prev().line); break;
|
||||
@ -1024,9 +930,7 @@ void Compiler::compile_stmt() {
|
||||
EXPR_TUPLE();
|
||||
Expr_ e = ctx()->s_expr.popx();
|
||||
bool ok = e->emit_del(ctx());
|
||||
if(!ok) {
|
||||
SyntaxError();
|
||||
}
|
||||
if(!ok) { SyntaxError(); }
|
||||
consume_end_stmt();
|
||||
} break;
|
||||
case TK("with"): {
|
||||
@ -1042,9 +946,7 @@ void Compiler::compile_stmt() {
|
||||
// [ <expr> <expr>.__enter__() ]
|
||||
if(as_name != nullptr) {
|
||||
bool ok = as_name->emit_store(ctx());
|
||||
if(!ok) {
|
||||
SyntaxError();
|
||||
}
|
||||
if(!ok) { SyntaxError(); }
|
||||
} else {
|
||||
ctx()->emit_(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
|
||||
}
|
||||
@ -1055,21 +957,15 @@ void Compiler::compile_stmt() {
|
||||
/*************************************************/
|
||||
case TK("=="): {
|
||||
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());
|
||||
consume(TK("=="));
|
||||
if(!ok) {
|
||||
SyntaxError("label " + prev().str().escape() + " already exists");
|
||||
}
|
||||
if(!ok) { SyntaxError("label " + prev().str().escape() + " already exists"); }
|
||||
consume_end_stmt();
|
||||
} break;
|
||||
case TK("->"):
|
||||
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);
|
||||
consume_end_stmt();
|
||||
break;
|
||||
@ -1093,9 +989,7 @@ void Compiler::compile_stmt() {
|
||||
}
|
||||
}
|
||||
if(!try_compile_assignment()) {
|
||||
if(!ctx()->s_expr.empty() && ctx()->s_expr.top()->is_starred()) {
|
||||
SyntaxError();
|
||||
}
|
||||
if(!ctx()->s_expr.empty() && ctx()->s_expr.top()->is_starred()) { SyntaxError(); }
|
||||
if(!is_typed_name) {
|
||||
ctx()->emit_expr();
|
||||
if((mode() == CELL_MODE || mode() == REPL_MODE) && name_scope() == NAME_GLOBAL) {
|
||||
@ -1148,9 +1042,7 @@ void Compiler::compile_class(const Expr_vector& decorators) {
|
||||
ctx()->emit_(OP_BEGIN_CLASS, namei, BC_KEEPLINE);
|
||||
|
||||
for(auto& c: this->contexts.container()) {
|
||||
if(c.is_compiling_class) {
|
||||
SyntaxError("nested class is not allowed");
|
||||
}
|
||||
if(c.is_compiling_class) { SyntaxError("nested class is not allowed"); }
|
||||
}
|
||||
ctx()->is_compiling_class = true;
|
||||
compile_block_body();
|
||||
@ -1168,12 +1060,8 @@ void Compiler::compile_class(const Expr_vector& decorators) {
|
||||
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
|
||||
do {
|
||||
if(state > 3) {
|
||||
SyntaxError();
|
||||
}
|
||||
if(state == 3) {
|
||||
SyntaxError("**kwargs should be the last argument");
|
||||
}
|
||||
if(state > 3) { SyntaxError(); }
|
||||
if(state == 3) { SyntaxError("**kwargs should be the last argument"); }
|
||||
match_newlines();
|
||||
if(match(TK("*"))) {
|
||||
if(state < 1) {
|
||||
@ -1189,14 +1077,10 @@ void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) {
|
||||
|
||||
// check duplicate argument name
|
||||
for(int j: decl->args) {
|
||||
if(decl->code->varnames[j] == name) {
|
||||
SyntaxError("duplicate argument name");
|
||||
}
|
||||
if(decl->code->varnames[j] == name) { SyntaxError("duplicate argument name"); }
|
||||
}
|
||||
for(auto& kv: decl->kwargs) {
|
||||
if(decl->code->varnames[kv.index] == name) {
|
||||
SyntaxError("duplicate argument name");
|
||||
}
|
||||
if(decl->code->varnames[kv.index] == name) { SyntaxError("duplicate argument name"); }
|
||||
}
|
||||
if(decl->starred_arg != -1 && decl->code->varnames[decl->starred_arg] == name) {
|
||||
SyntaxError("duplicate argument name");
|
||||
@ -1206,12 +1090,8 @@ void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) {
|
||||
}
|
||||
|
||||
// eat type hints
|
||||
if(enable_type_hints && match(TK(":"))) {
|
||||
consume_type_hints();
|
||||
}
|
||||
if(state == 0 && curr().type == TK("=")) {
|
||||
state = 2;
|
||||
}
|
||||
if(enable_type_hints && match(TK(":"))) { consume_type_hints(); }
|
||||
if(state == 0 && curr().type == TK("=")) { state = 2; }
|
||||
int index = ctx()->add_varname(name);
|
||||
switch(state) {
|
||||
case 0: decl->args.push_back(index); break;
|
||||
@ -1222,9 +1102,7 @@ void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) {
|
||||
case 2: {
|
||||
consume(TK("="));
|
||||
PyVar value = read_literal();
|
||||
if(value == nullptr) {
|
||||
SyntaxError(Str("default argument must be a literal"));
|
||||
}
|
||||
if(value == nullptr) { SyntaxError(Str("default argument must be a literal")); }
|
||||
decl->add_kwarg(index, name, value);
|
||||
} break;
|
||||
case 3:
|
||||
@ -1244,9 +1122,7 @@ void Compiler::compile_function(const Expr_vector& decorators) {
|
||||
_compile_f_args(decl, true);
|
||||
consume(TK(")"));
|
||||
}
|
||||
if(match(TK("->"))) {
|
||||
consume_type_hints();
|
||||
}
|
||||
if(match(TK("->"))) { consume_type_hints(); }
|
||||
compile_block_body();
|
||||
pop_context();
|
||||
|
||||
@ -1275,15 +1151,9 @@ void Compiler::compile_function(const Expr_vector& decorators) {
|
||||
|
||||
PyVar Compiler::to_object(const TokenValue& value) {
|
||||
PyVar obj = nullptr;
|
||||
if(std::holds_alternative<i64>(value)) {
|
||||
obj = VAR(std::get<i64>(value));
|
||||
}
|
||||
if(std::holds_alternative<f64>(value)) {
|
||||
obj = VAR(std::get<f64>(value));
|
||||
}
|
||||
if(std::holds_alternative<Str>(value)) {
|
||||
obj = VAR(std::get<Str>(value));
|
||||
}
|
||||
if(std::holds_alternative<i64>(value)) { obj = VAR(std::get<i64>(value)); }
|
||||
if(std::holds_alternative<f64>(value)) { obj = VAR(std::get<f64>(value)); }
|
||||
if(std::holds_alternative<Str>(value)) { obj = VAR(std::get<Str>(value)); }
|
||||
assert(obj != nullptr);
|
||||
return obj;
|
||||
}
|
||||
@ -1306,13 +1176,9 @@ PyVar Compiler::read_literal() {
|
||||
List cpnts;
|
||||
while(true) {
|
||||
cpnts.push_back(read_literal());
|
||||
if(curr().type == TK(")")) {
|
||||
break;
|
||||
}
|
||||
if(curr().type == TK(")")) { break; }
|
||||
consume(TK(","));
|
||||
if(curr().type == TK(")")) {
|
||||
break;
|
||||
}
|
||||
if(curr().type == TK(")")) { break; }
|
||||
}
|
||||
consume(TK(")"));
|
||||
return VAR(cpnts.to_tuple());
|
||||
@ -1359,9 +1225,7 @@ Str Compiler::precompile() {
|
||||
for(int i = 0; i < tokens.size(); i++) {
|
||||
const Token& token = tokens[i];
|
||||
ss << (int)token.type << ',';
|
||||
if(is_raw_string_used(token.type)) {
|
||||
ss << token_indices[token.sv()] << ',';
|
||||
}
|
||||
if(is_raw_string_used(token.type)) { ss << token_indices[token.sv()] << ','; }
|
||||
if(i > 0 && tokens[i - 1].line == token.line) {
|
||||
ss << ',';
|
||||
} else {
|
||||
@ -1402,9 +1266,7 @@ void Compiler::from_precompiled(const char* source) {
|
||||
Str error = _S("precompiled version mismatch: ", version, "!=" PK_VERSION);
|
||||
throw std::runtime_error(error.c_str());
|
||||
}
|
||||
if(deserializer.read_uint('\n') != (i64)mode()) {
|
||||
throw std::runtime_error("precompiled mode mismatch");
|
||||
}
|
||||
if(deserializer.read_uint('\n') != (i64)mode()) { throw std::runtime_error("precompiled mode mismatch"); }
|
||||
|
||||
int count = deserializer.read_count();
|
||||
vector<Str>& precompiled_tokens = lexer.src->_precompiled_tokens;
|
||||
@ -1472,9 +1334,7 @@ CodeObject_ Compiler::compile() {
|
||||
} else if(mode() == JSON_MODE) {
|
||||
EXPR();
|
||||
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"));
|
||||
e->emit_(ctx());
|
||||
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
|
||||
|
||||
@ -4,16 +4,10 @@
|
||||
namespace pkpy {
|
||||
|
||||
inline bool is_identifier(std::string_view s) {
|
||||
if(s.empty()) {
|
||||
return false;
|
||||
}
|
||||
if(!isalpha(s[0]) && s[0] != '_') {
|
||||
return false;
|
||||
}
|
||||
if(s.empty()) { return false; }
|
||||
if(!isalpha(s[0]) && s[0] != '_') { return false; }
|
||||
for(char c: s) {
|
||||
if(!isalnum(c) && c != '_') {
|
||||
return false;
|
||||
}
|
||||
if(!isalnum(c) && c != '_') { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -23,12 +17,8 @@ inline bool is_small_int(i64 value) { return value >= INT16_MIN && value <= INT1
|
||||
int CodeEmitContext::get_loop() const {
|
||||
int index = curr_iblock;
|
||||
while(index >= 0) {
|
||||
if(co->blocks[index].type == CodeBlockType::FOR_LOOP) {
|
||||
break;
|
||||
}
|
||||
if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) {
|
||||
break;
|
||||
}
|
||||
if(co->blocks[index].type == CodeBlockType::FOR_LOOP) { break; }
|
||||
if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) { break; }
|
||||
index = co->blocks[index].parent;
|
||||
}
|
||||
return index;
|
||||
@ -79,12 +69,8 @@ void CodeEmitContext::revert_last_emit_() {
|
||||
|
||||
void CodeEmitContext::try_merge_for_iter_store(int i) {
|
||||
// [FOR_ITER, STORE_?, ]
|
||||
if(co->codes[i].op != OP_FOR_ITER) {
|
||||
return;
|
||||
}
|
||||
if(co->codes.size() - i != 2) {
|
||||
return;
|
||||
}
|
||||
if(co->codes[i].op != OP_FOR_ITER) { return; }
|
||||
if(co->codes.size() - i != 2) { return; }
|
||||
uint16_t arg = co->codes[i + 1].arg;
|
||||
if(co->codes[i + 1].op == OP_STORE_FAST) {
|
||||
revert_last_emit_();
|
||||
@ -114,9 +100,7 @@ void CodeEmitContext::patch_jump(int index) {
|
||||
}
|
||||
|
||||
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());
|
||||
return true;
|
||||
}
|
||||
@ -124,9 +108,7 @@ bool CodeEmitContext::add_label(StrName name) {
|
||||
int CodeEmitContext::add_varname(StrName name) {
|
||||
// PK_MAX_CO_VARNAMES will be checked when pop_context(), not here
|
||||
int index = co->varnames_inv.try_get(name);
|
||||
if(index >= 0) {
|
||||
return index;
|
||||
}
|
||||
if(index >= 0) { return index; }
|
||||
co->varnames.push_back(name);
|
||||
co->nlocals++;
|
||||
index = co->varnames.size() - 1;
|
||||
@ -188,9 +170,7 @@ void NameExpr::emit_(CodeEmitContext* ctx) {
|
||||
// exec()/eval() won't work with OP_LOAD_ATTR_GLOBAL in class body
|
||||
} else {
|
||||
// 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);
|
||||
}
|
||||
@ -226,9 +206,7 @@ void StarredExpr::emit_(CodeEmitContext* ctx) {
|
||||
}
|
||||
|
||||
bool StarredExpr::emit_store(CodeEmitContext* ctx) {
|
||||
if(level != 1) {
|
||||
return false;
|
||||
}
|
||||
if(level != 1) { return false; }
|
||||
// simply proxy to child
|
||||
return child->emit_store(ctx);
|
||||
}
|
||||
@ -355,9 +333,7 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
|
||||
// items may contain StarredExpr, we should check it
|
||||
int starred_i = -1;
|
||||
for(int i = 0; i < items.size(); i++) {
|
||||
if(!items[i]->is_starred()) {
|
||||
continue;
|
||||
}
|
||||
if(!items[i]->is_starred()) { continue; }
|
||||
if(starred_i == -1) {
|
||||
starred_i = i;
|
||||
} else {
|
||||
@ -380,13 +356,9 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
|
||||
}
|
||||
} else {
|
||||
// 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)
|
||||
if(starred_i != items.size() - 1) {
|
||||
return false;
|
||||
}
|
||||
if(starred_i != items.size() - 1) { return false; }
|
||||
// a,*b = [1,2,3]
|
||||
// stack is [1,2,3] -> [1,[2,3]]
|
||||
ctx->emit_(OP_UNPACK_EX, items.size() - 1, line);
|
||||
@ -394,9 +366,7 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
|
||||
// do reverse emit
|
||||
for(int i = items.size() - 1; i >= 0; i--) {
|
||||
bool ok = items[i]->emit_store(ctx);
|
||||
if(!ok) {
|
||||
return false;
|
||||
}
|
||||
if(!ok) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -404,9 +374,7 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
|
||||
bool TupleExpr::emit_del(CodeEmitContext* ctx) {
|
||||
for(auto& e: items) {
|
||||
bool ok = e->emit_del(ctx);
|
||||
if(!ok) {
|
||||
return false;
|
||||
}
|
||||
if(!ok) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -474,9 +442,7 @@ void FStringExpr::_load_simple_expr(CodeEmitContext* ctx, Str expr) {
|
||||
ctx->emit_(OP_FSTRING_EVAL, index, line);
|
||||
}
|
||||
|
||||
if(repr) {
|
||||
ctx->emit_(OP_REPR, BC_NOARG, line);
|
||||
}
|
||||
if(repr) { ctx->emit_(OP_REPR, BC_NOARG, line); }
|
||||
}
|
||||
|
||||
static bool is_fmt_valid_char(char c) {
|
||||
@ -666,14 +632,10 @@ void CallExpr::emit_(CodeEmitContext* ctx) {
|
||||
bool vargs = false;
|
||||
bool vkwargs = false;
|
||||
for(auto& arg: args) {
|
||||
if(arg->is_starred()) {
|
||||
vargs = true;
|
||||
}
|
||||
if(arg->is_starred()) { vargs = true; }
|
||||
}
|
||||
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
|
||||
|
||||
@ -22,29 +22,19 @@ static bool is_possible_number_char(char c) {
|
||||
|
||||
static bool is_unicode_Lo_char(uint32_t c) {
|
||||
// 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;
|
||||
if(c == kLoRangeA[index]) {
|
||||
return true;
|
||||
}
|
||||
if(c == kLoRangeA[index]) { return true; }
|
||||
index -= 1;
|
||||
if(index < 0) {
|
||||
return false;
|
||||
}
|
||||
if(index < 0) { return false; }
|
||||
return c >= kLoRangeA[index] && c <= kLoRangeB[index];
|
||||
}
|
||||
|
||||
bool Lexer::match_n_chars(int n, char c0) {
|
||||
const char* c = curr_char;
|
||||
for(int i = 0; i < n; i++) {
|
||||
if(*c == '\0') {
|
||||
return false;
|
||||
}
|
||||
if(*c != c0) {
|
||||
return false;
|
||||
}
|
||||
if(*c == '\0') { return false; }
|
||||
if(*c != c0) { return false; }
|
||||
c++;
|
||||
}
|
||||
for(int i = 0; i < n; i++) {
|
||||
@ -77,16 +67,10 @@ int Lexer::eat_spaces() {
|
||||
}
|
||||
|
||||
bool Lexer::eat_indentation() {
|
||||
if(brackets_level > 0) {
|
||||
return true;
|
||||
}
|
||||
if(brackets_level > 0) { return true; }
|
||||
int spaces = eat_spaces();
|
||||
if(peekchar() == '#') {
|
||||
skip_line_comment();
|
||||
}
|
||||
if(peekchar() == '\0' || peekchar() == '\n') {
|
||||
return true;
|
||||
}
|
||||
if(peekchar() == '#') { skip_line_comment(); }
|
||||
if(peekchar() == '\0' || peekchar() == '\n') { return true; }
|
||||
// https://docs.python.org/3/reference/lexical_analysis.html#indentation
|
||||
if(spaces > indents.top()) {
|
||||
indents.push(spaces);
|
||||
@ -96,9 +80,7 @@ bool Lexer::eat_indentation() {
|
||||
indents.pop();
|
||||
nexts.push_back(Token{TK("@dedent"), token_start, 0, current_line, brackets_level, {}});
|
||||
}
|
||||
if(spaces != indents.top()) {
|
||||
return false;
|
||||
}
|
||||
if(spaces != indents.top()) { return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -125,9 +107,7 @@ int Lexer::eat_name() {
|
||||
while(true) {
|
||||
unsigned char c = peekchar();
|
||||
int u8bytes = utf8len(c, true);
|
||||
if(u8bytes == 0) {
|
||||
return 1;
|
||||
}
|
||||
if(u8bytes == 0) { return 1; }
|
||||
if(u8bytes == 1) {
|
||||
if(isalpha(c) || c == '_' || isdigit(c)) {
|
||||
curr_char++;
|
||||
@ -138,9 +118,7 @@ int Lexer::eat_name() {
|
||||
}
|
||||
// handle multibyte char
|
||||
Str u8str(curr_char, u8bytes);
|
||||
if(u8str.size != u8bytes) {
|
||||
return 2;
|
||||
}
|
||||
if(u8str.size != u8bytes) { return 2; }
|
||||
uint32_t value = 0;
|
||||
for(int k = 0; k < u8bytes; k++) {
|
||||
uint8_t b = u8str[k];
|
||||
@ -164,9 +142,7 @@ int Lexer::eat_name() {
|
||||
}
|
||||
|
||||
int length = (int)(curr_char - token_start);
|
||||
if(length == 0) {
|
||||
return 3;
|
||||
}
|
||||
if(length == 0) { return 3; }
|
||||
std::string_view name(token_start, length);
|
||||
|
||||
if(src->mode == JSON_MODE) {
|
||||
@ -193,17 +169,13 @@ int Lexer::eat_name() {
|
||||
void Lexer::skip_line_comment() {
|
||||
char c;
|
||||
while((c = peekchar()) != '\0') {
|
||||
if(c == '\n') {
|
||||
return;
|
||||
}
|
||||
if(c == '\n') { return; }
|
||||
eatchar();
|
||||
}
|
||||
}
|
||||
|
||||
bool Lexer::matchchar(char c) {
|
||||
if(peekchar() != c) {
|
||||
return false;
|
||||
}
|
||||
if(peekchar() != c) { return false; }
|
||||
eatchar_include_newline();
|
||||
return true;
|
||||
}
|
||||
@ -263,9 +235,7 @@ Str Lexer::eat_string_until(char quote, bool raw) {
|
||||
break;
|
||||
}
|
||||
if(c == '\0') {
|
||||
if(quote3 && src->mode == REPL_MODE) {
|
||||
throw NeedMoreLines(false);
|
||||
}
|
||||
if(quote3 && src->mode == REPL_MODE) { throw NeedMoreLines(false); }
|
||||
SyntaxError("EOL while scanning string literal");
|
||||
}
|
||||
if(c == '\n') {
|
||||
@ -292,9 +262,7 @@ Str Lexer::eat_string_until(char quote, bool raw) {
|
||||
try {
|
||||
code = (char)std::stoi(hex, &parsed, 16);
|
||||
} catch(...) { SyntaxError("invalid hex char"); }
|
||||
if(parsed != 2) {
|
||||
SyntaxError("invalid hex char");
|
||||
}
|
||||
if(parsed != 2) { SyntaxError("invalid hex char"); }
|
||||
buff.push_back(code);
|
||||
} break;
|
||||
default: SyntaxError("invalid escape char");
|
||||
@ -395,9 +363,7 @@ bool Lexer::lex_one_token() {
|
||||
// line continuation character
|
||||
char c = eatchar_include_newline();
|
||||
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");
|
||||
}
|
||||
eat_spaces();
|
||||
@ -491,9 +457,7 @@ bool Lexer::lex_one_token() {
|
||||
case '\t': eat_spaces(); break;
|
||||
case '\n': {
|
||||
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;
|
||||
}
|
||||
default: {
|
||||
@ -577,9 +541,7 @@ vector<Token> Lexer::run() {
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
@ -600,16 +562,12 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
|
||||
|
||||
if(base == 10) {
|
||||
// 10-base 12334
|
||||
if(text.length() == 0) {
|
||||
return IntParsingResult::Failure;
|
||||
}
|
||||
if(text.length() == 0) { return IntParsingResult::Failure; }
|
||||
for(char c: text) {
|
||||
if(c >= '0' && c <= '9') {
|
||||
i64 prev_out = *out;
|
||||
*out = (*out * 10) + (c - '0');
|
||||
if(*out < prev_out) {
|
||||
return IntParsingResult::Overflow;
|
||||
}
|
||||
if(*out < prev_out) { return IntParsingResult::Overflow; }
|
||||
} else {
|
||||
return IntParsingResult::Failure;
|
||||
}
|
||||
@ -617,19 +575,13 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
|
||||
return IntParsingResult::Success;
|
||||
} else if(base == 2) {
|
||||
// 2-base 0b101010
|
||||
if(f_startswith_2(text, "0b")) {
|
||||
text.remove_prefix(2);
|
||||
}
|
||||
if(text.length() == 0) {
|
||||
return IntParsingResult::Failure;
|
||||
}
|
||||
if(f_startswith_2(text, "0b")) { text.remove_prefix(2); }
|
||||
if(text.length() == 0) { return IntParsingResult::Failure; }
|
||||
for(char c: text) {
|
||||
if(c == '0' || c == '1') {
|
||||
i64 prev_out = *out;
|
||||
*out = (*out << 1) | (c - '0');
|
||||
if(*out < prev_out) {
|
||||
return IntParsingResult::Overflow;
|
||||
}
|
||||
if(*out < prev_out) { return IntParsingResult::Overflow; }
|
||||
} else {
|
||||
return IntParsingResult::Failure;
|
||||
}
|
||||
@ -637,19 +589,13 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
|
||||
return IntParsingResult::Success;
|
||||
} else if(base == 8) {
|
||||
// 8-base 0o123
|
||||
if(f_startswith_2(text, "0o")) {
|
||||
text.remove_prefix(2);
|
||||
}
|
||||
if(text.length() == 0) {
|
||||
return IntParsingResult::Failure;
|
||||
}
|
||||
if(f_startswith_2(text, "0o")) { text.remove_prefix(2); }
|
||||
if(text.length() == 0) { return IntParsingResult::Failure; }
|
||||
for(char c: text) {
|
||||
if(c >= '0' && c <= '7') {
|
||||
i64 prev_out = *out;
|
||||
*out = (*out << 3) | (c - '0');
|
||||
if(*out < prev_out) {
|
||||
return IntParsingResult::Overflow;
|
||||
}
|
||||
if(*out < prev_out) { return IntParsingResult::Overflow; }
|
||||
} else {
|
||||
return IntParsingResult::Failure;
|
||||
}
|
||||
@ -657,29 +603,19 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
|
||||
return IntParsingResult::Success;
|
||||
} else if(base == 16) {
|
||||
// 16-base 0x123
|
||||
if(f_startswith_2(text, "0x")) {
|
||||
text.remove_prefix(2);
|
||||
}
|
||||
if(text.length() == 0) {
|
||||
return IntParsingResult::Failure;
|
||||
}
|
||||
if(f_startswith_2(text, "0x")) { text.remove_prefix(2); }
|
||||
if(text.length() == 0) { return IntParsingResult::Failure; }
|
||||
for(char c: text) {
|
||||
i64 prev_out = *out;
|
||||
if(c >= '0' && c <= '9') {
|
||||
*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') {
|
||||
*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') {
|
||||
*out = (*out << 4) | (c - 'A' + 10);
|
||||
if(*out < prev_out) {
|
||||
return IntParsingResult::Overflow;
|
||||
}
|
||||
if(*out < prev_out) { return IntParsingResult::Overflow; }
|
||||
} else {
|
||||
return IntParsingResult::Failure;
|
||||
}
|
||||
|
||||
@ -11,8 +11,7 @@ namespace pkpy {
|
||||
#define PREDICT_INT_DIV_OP(op) \
|
||||
if(is_int(_0) && is_int(_1)) { \
|
||||
i64 divisor = _1.as<i64>(); \
|
||||
if(divisor == 0) \
|
||||
ZeroDivisionError(); \
|
||||
if(divisor == 0) ZeroDivisionError(); \
|
||||
TOP() = VAR(_0.as<i64>() op divisor); \
|
||||
DISPATCH() \
|
||||
}
|
||||
@ -37,8 +36,7 @@ namespace pkpy {
|
||||
ret = call_method(self, _2, _0); \
|
||||
else \
|
||||
BinaryOptError(op, _0, _1); \
|
||||
if(is_not_implemented(ret)) \
|
||||
BinaryOptError(op, _0, _1); \
|
||||
if(is_not_implemented(ret)) BinaryOptError(op, _0, _1); \
|
||||
}
|
||||
|
||||
void VM::__op_unpack_sequence(uint16_t arg) {
|
||||
@ -59,14 +57,10 @@ void VM::__op_unpack_sequence(uint16_t arg) {
|
||||
const PyTypeInfo* ti = _tp_info(_0);
|
||||
for(int i = 0; i < arg; i++) {
|
||||
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);
|
||||
}
|
||||
if(_py_next(ti, _0) != StopIteration) {
|
||||
ValueError("too many values to unpack");
|
||||
}
|
||||
if(_py_next(ti, _0) != StopIteration) { ValueError("too many values to unpack"); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,19 +88,14 @@ bool VM::py_ge(PyVar _0, PyVar _1) {
|
||||
|
||||
#if PK_ENABLE_PROFILER
|
||||
#define CEVAL_STEP_CALLBACK() \
|
||||
if(_ceval_on_step) \
|
||||
_ceval_on_step(this, frame, byte); \
|
||||
if(_profiler) \
|
||||
_profiler->_step(callstack.size(), frame); \
|
||||
if(!_next_breakpoint.empty()) { \
|
||||
_next_breakpoint._step(this); \
|
||||
}
|
||||
if(_ceval_on_step) _ceval_on_step(this, frame, byte); \
|
||||
if(_profiler) _profiler->_step(callstack.size(), frame); \
|
||||
if(!_next_breakpoint.empty()) { _next_breakpoint._step(this); }
|
||||
#else
|
||||
#define CEVAL_STEP_CALLBACK() \
|
||||
if(_ceval_on_step && _ceval_on_step) { \
|
||||
if(_ceval_on_step) \
|
||||
if(_ceval_on_step) \
|
||||
_ceval_on_step(this, frame, byte); \
|
||||
if(_ceval_on_step) _ceval_on_step(this, frame, byte); \
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -179,9 +168,7 @@ PyVar VM::__run_top_frame() {
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_PRINT_EXPR:
|
||||
if(TOP() != None) {
|
||||
stdout_write(py_repr(TOP()) + "\n");
|
||||
}
|
||||
if(TOP() != None) { stdout_write(py_repr(TOP()) + "\n"); }
|
||||
POP();
|
||||
DISPATCH()
|
||||
/*****************************************/
|
||||
@ -210,9 +197,7 @@ PyVar VM::__run_top_frame() {
|
||||
/*****************************************/
|
||||
case OP_LOAD_FAST: {
|
||||
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);
|
||||
}
|
||||
DISPATCH()
|
||||
@ -220,9 +205,7 @@ PyVar VM::__run_top_frame() {
|
||||
StrName _name(byte.arg);
|
||||
PyVar* slot = frame->_locals.try_get_name(_name);
|
||||
if(slot != nullptr) {
|
||||
if(*slot == PY_NULL) {
|
||||
vm->UnboundLocalError(_name);
|
||||
}
|
||||
if(*slot == PY_NULL) { vm->UnboundLocalError(_name); }
|
||||
PUSH(*slot);
|
||||
DISPATCH()
|
||||
}
|
||||
@ -324,9 +307,7 @@ PyVar VM::__run_top_frame() {
|
||||
DISPATCH()
|
||||
case OP_LOAD_SUBSCR_FAST: {
|
||||
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
|
||||
auto _ti = _tp_info(_0);
|
||||
if(_ti->m__getitem__) {
|
||||
@ -391,9 +372,7 @@ PyVar VM::__run_top_frame() {
|
||||
DISPATCH()
|
||||
case OP_STORE_SUBSCR_FAST: {
|
||||
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 _0 = POPX(); // val
|
||||
auto _ti = _tp_info(_1);
|
||||
@ -406,9 +385,7 @@ PyVar VM::__run_top_frame() {
|
||||
DISPATCH()
|
||||
case OP_DELETE_FAST: {
|
||||
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();
|
||||
}
|
||||
DISPATCH()
|
||||
@ -423,25 +400,19 @@ PyVar VM::__run_top_frame() {
|
||||
if(func.decl == __dynamic_func_decl) {
|
||||
assert(func._closure != nullptr);
|
||||
bool ok = func._closure->del(_name);
|
||||
if(!ok) {
|
||||
vm->NameError(_name);
|
||||
}
|
||||
if(!ok) { vm->NameError(_name); }
|
||||
} else {
|
||||
vm->NameError(_name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(!frame->f_globals().del(_name)) {
|
||||
vm->NameError(_name);
|
||||
}
|
||||
if(!frame->f_globals().del(_name)) { vm->NameError(_name); }
|
||||
}
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_DELETE_GLOBAL: {
|
||||
StrName _name(byte.arg);
|
||||
if(!frame->f_globals().del(_name)) {
|
||||
vm->NameError(_name);
|
||||
}
|
||||
if(!frame->f_globals().del(_name)) { vm->NameError(_name); }
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_DELETE_ATTR: {
|
||||
@ -463,17 +434,13 @@ PyVar VM::__run_top_frame() {
|
||||
/*****************************************/
|
||||
case OP_BUILD_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());
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_BUILD_IMAG: {
|
||||
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());
|
||||
}
|
||||
DISPATCH()
|
||||
@ -587,8 +554,7 @@ PyVar VM::__run_top_frame() {
|
||||
TOP() = call_method(self, _2, _0); \
|
||||
else \
|
||||
BinaryOptError(op, _0, _1); \
|
||||
if(is_not_implemented(TOP())) \
|
||||
BinaryOptError(op, _0, _1); \
|
||||
if(is_not_implemented(TOP())) BinaryOptError(op, _0, _1); \
|
||||
}
|
||||
|
||||
case OP_BINARY_TRUEDIV: {
|
||||
@ -596,9 +562,7 @@ PyVar VM::__run_top_frame() {
|
||||
PyVar _0 = TOP();
|
||||
const PyTypeInfo* _ti;
|
||||
BINARY_OP_SPECIAL(__truediv__);
|
||||
if(is_not_implemented(TOP())) {
|
||||
BinaryOptError("/", _0, _1);
|
||||
}
|
||||
if(is_not_implemented(TOP())) { BinaryOptError("/", _0, _1); }
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_BINARY_POW: {
|
||||
@ -606,9 +570,7 @@ PyVar VM::__run_top_frame() {
|
||||
PyVar _0 = TOP();
|
||||
const PyTypeInfo* _ti;
|
||||
BINARY_OP_SPECIAL(__pow__);
|
||||
if(is_not_implemented(TOP())) {
|
||||
BinaryOptError("**", _0, _1);
|
||||
}
|
||||
if(is_not_implemented(TOP())) { BinaryOptError("**", _0, _1); }
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_BINARY_ADD: {
|
||||
@ -644,9 +606,7 @@ PyVar VM::__run_top_frame() {
|
||||
PREDICT_INT_DIV_OP(/)
|
||||
const PyTypeInfo* _ti;
|
||||
BINARY_OP_SPECIAL(__floordiv__);
|
||||
if(is_not_implemented(TOP())) {
|
||||
BinaryOptError("//", _0, _1);
|
||||
}
|
||||
if(is_not_implemented(TOP())) { BinaryOptError("//", _0, _1); }
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_BINARY_MOD: {
|
||||
@ -655,9 +615,7 @@ PyVar VM::__run_top_frame() {
|
||||
PREDICT_INT_DIV_OP(%)
|
||||
const PyTypeInfo* _ti;
|
||||
BINARY_OP_SPECIAL(__mod__);
|
||||
if(is_not_implemented(TOP())) {
|
||||
BinaryOptError("%", _0, _1);
|
||||
}
|
||||
if(is_not_implemented(TOP())) { BinaryOptError("%", _0, _1); }
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_COMPARE_LT: {
|
||||
@ -706,9 +664,7 @@ PyVar VM::__run_top_frame() {
|
||||
PREDICT_INT_OP(<<)
|
||||
const PyTypeInfo* _ti;
|
||||
BINARY_OP_SPECIAL(__lshift__);
|
||||
if(is_not_implemented(TOP())) {
|
||||
BinaryOptError("<<", _0, _1);
|
||||
}
|
||||
if(is_not_implemented(TOP())) { BinaryOptError("<<", _0, _1); }
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_BITWISE_RSHIFT: {
|
||||
@ -717,9 +673,7 @@ PyVar VM::__run_top_frame() {
|
||||
PREDICT_INT_OP(>>)
|
||||
const PyTypeInfo* _ti;
|
||||
BINARY_OP_SPECIAL(__rshift__);
|
||||
if(is_not_implemented(TOP())) {
|
||||
BinaryOptError(">>", _0, _1);
|
||||
}
|
||||
if(is_not_implemented(TOP())) { BinaryOptError(">>", _0, _1); }
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_BITWISE_AND: {
|
||||
@ -728,9 +682,7 @@ PyVar VM::__run_top_frame() {
|
||||
PREDICT_INT_OP(&)
|
||||
const PyTypeInfo* _ti;
|
||||
BINARY_OP_SPECIAL(__and__);
|
||||
if(is_not_implemented(TOP())) {
|
||||
BinaryOptError("&", _0, _1);
|
||||
}
|
||||
if(is_not_implemented(TOP())) { BinaryOptError("&", _0, _1); }
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_BITWISE_OR: {
|
||||
@ -739,9 +691,7 @@ PyVar VM::__run_top_frame() {
|
||||
PREDICT_INT_OP(|)
|
||||
const PyTypeInfo* _ti;
|
||||
BINARY_OP_SPECIAL(__or__);
|
||||
if(is_not_implemented(TOP())) {
|
||||
BinaryOptError("|", _0, _1);
|
||||
}
|
||||
if(is_not_implemented(TOP())) { BinaryOptError("|", _0, _1); }
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_BITWISE_XOR: {
|
||||
@ -750,9 +700,7 @@ PyVar VM::__run_top_frame() {
|
||||
PREDICT_INT_OP(^)
|
||||
const PyTypeInfo* _ti;
|
||||
BINARY_OP_SPECIAL(__xor__);
|
||||
if(is_not_implemented(TOP())) {
|
||||
BinaryOptError("^", _0, _1);
|
||||
}
|
||||
if(is_not_implemented(TOP())) { BinaryOptError("^", _0, _1); }
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_BINARY_MATMUL: {
|
||||
@ -760,9 +708,7 @@ PyVar VM::__run_top_frame() {
|
||||
PyVar _0 = TOP();
|
||||
const PyTypeInfo* _ti;
|
||||
BINARY_OP_SPECIAL(__matmul__);
|
||||
if(is_not_implemented(TOP())) {
|
||||
BinaryOptError("@", _0, _1);
|
||||
}
|
||||
if(is_not_implemented(TOP())) { BinaryOptError("@", _0, _1); }
|
||||
}
|
||||
DISPATCH()
|
||||
|
||||
@ -798,14 +744,10 @@ PyVar VM::__run_top_frame() {
|
||||
/*****************************************/
|
||||
case OP_JUMP_FORWARD: DISPATCH_JUMP((int16_t)byte.arg)
|
||||
case OP_POP_JUMP_IF_FALSE:
|
||||
if(!py_bool(POPX())) {
|
||||
DISPATCH_JUMP((int16_t)byte.arg)
|
||||
}
|
||||
if(!py_bool(POPX())) { DISPATCH_JUMP((int16_t)byte.arg) }
|
||||
DISPATCH()
|
||||
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()
|
||||
case OP_JUMP_IF_TRUE_OR_POP:
|
||||
if(py_bool(TOP())) {
|
||||
@ -841,9 +783,7 @@ PyVar VM::__run_top_frame() {
|
||||
case OP_GOTO: {
|
||||
StrName _name(byte.arg);
|
||||
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);
|
||||
DISPATCH_JUMP_ABSOLUTE(target)
|
||||
}
|
||||
@ -865,9 +805,7 @@ PyVar VM::__run_top_frame() {
|
||||
DISPATCH()
|
||||
case OP_REPR: TOP() = VAR(py_repr(TOP())); DISPATCH()
|
||||
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
|
||||
(byte.arg >> 8) & 0xFF, // KWARGC
|
||||
true);
|
||||
@ -879,9 +817,7 @@ PyVar VM::__run_top_frame() {
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_CALL_TP: {
|
||||
if(heap._should_auto_collect()) {
|
||||
heap._auto_collect();
|
||||
}
|
||||
if(heap._should_auto_collect()) { heap._auto_collect(); }
|
||||
PyVar _0;
|
||||
PyVar _1;
|
||||
PyVar _2;
|
||||
@ -1078,9 +1014,7 @@ PyVar VM::__run_top_frame() {
|
||||
} else {
|
||||
for(auto& [name, value]: _0->attr().items()) {
|
||||
std::string_view s = name.sv();
|
||||
if(s.empty() || s[0] == '_') {
|
||||
continue;
|
||||
}
|
||||
if(s.empty() || s[0] == '_') { continue; }
|
||||
frame->f_globals().set(name, value);
|
||||
}
|
||||
}
|
||||
@ -1098,17 +1032,13 @@ PyVar VM::__run_top_frame() {
|
||||
PyVar _1;
|
||||
for(int i = 0; i < byte.arg; i++) {
|
||||
_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);
|
||||
}
|
||||
List extras;
|
||||
while(true) {
|
||||
_1 = _py_next(_ti, _0);
|
||||
if(_1 == StopIteration) {
|
||||
break;
|
||||
}
|
||||
if(_1 == StopIteration) { break; }
|
||||
extras.push_back(_1);
|
||||
}
|
||||
PUSH(VAR(std::move(extras)));
|
||||
@ -1118,9 +1048,7 @@ PyVar VM::__run_top_frame() {
|
||||
case OP_BEGIN_CLASS: {
|
||||
StrName _name(byte.arg);
|
||||
PyVar _0 = POPX(); // super
|
||||
if(_0 == None) {
|
||||
_0 = _t(tp_object);
|
||||
}
|
||||
if(_0 == None) { _0 = _t(tp_object); }
|
||||
check_type(_0, tp_type);
|
||||
__curr_class = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0), true);
|
||||
}
|
||||
@ -1133,9 +1061,7 @@ PyVar VM::__run_top_frame() {
|
||||
PyTypeInfo* ti = &_all_types[__curr_class->as<Type>()];
|
||||
if(ti->base != tp_object) {
|
||||
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;
|
||||
}
|
||||
@ -1144,9 +1070,7 @@ PyVar VM::__run_top_frame() {
|
||||
assert(__curr_class != nullptr);
|
||||
StrName _name(byte.arg);
|
||||
PyVar _0 = POPX();
|
||||
if(is_type(_0, tp_function)) {
|
||||
PK_OBJ_GET(Function, _0)._class = __curr_class;
|
||||
}
|
||||
if(is_type(_0, tp_function)) { PK_OBJ_GET(Function, _0)._class = __curr_class; }
|
||||
__curr_class->attr().set(_name, _0);
|
||||
}
|
||||
DISPATCH()
|
||||
@ -1185,12 +1109,8 @@ PyVar VM::__run_top_frame() {
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_RAISE: {
|
||||
if(is_type(TOP(), tp_type)) {
|
||||
TOP() = call(TOP());
|
||||
}
|
||||
if(!isinstance(TOP(), tp_exception)) {
|
||||
TypeError("exceptions must derive from Exception");
|
||||
}
|
||||
if(is_type(TOP(), tp_type)) { TOP() = call(TOP()); }
|
||||
if(!isinstance(TOP(), tp_exception)) { TypeError("exceptions must derive from Exception"); }
|
||||
_error(POPX());
|
||||
}
|
||||
DISPATCH()
|
||||
@ -1215,35 +1135,27 @@ PyVar VM::__run_top_frame() {
|
||||
/*****************************************/
|
||||
case OP_INC_FAST: {
|
||||
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);
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_DEC_FAST: {
|
||||
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);
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_INC_GLOBAL: {
|
||||
StrName _name(byte.arg);
|
||||
PyVar* p = frame->f_globals().try_get_2_likely_found(_name);
|
||||
if(p == nullptr) {
|
||||
vm->NameError(_name);
|
||||
}
|
||||
if(p == nullptr) { vm->NameError(_name); }
|
||||
*p = VAR(CAST(i64, *p) + 1);
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_DEC_GLOBAL: {
|
||||
StrName _name(byte.arg);
|
||||
PyVar* p = frame->f_globals().try_get_2_likely_found(_name);
|
||||
if(p == nullptr) {
|
||||
vm->NameError(_name);
|
||||
}
|
||||
if(p == nullptr) { vm->NameError(_name); }
|
||||
*p = VAR(CAST(i64, *p) - 1);
|
||||
}
|
||||
DISPATCH()
|
||||
@ -1266,9 +1178,7 @@ PyVar VM::__run_top_frame() {
|
||||
}
|
||||
frame = &callstack.top();
|
||||
PUSH(__last_exception);
|
||||
if(is_base_frame_to_be_popped) {
|
||||
throw InternalException(InternalExceptionType::ToBeRaised);
|
||||
}
|
||||
if(is_base_frame_to_be_popped) { throw InternalException(InternalExceptionType::ToBeRaised); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,8 +21,7 @@ void VoidP::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
|
||||
#define BIND_CMP(name, op) \
|
||||
vm->bind##name(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) { \
|
||||
if(!vm->isinstance(rhs, vm->_tp_user<VoidP>())) \
|
||||
return vm->NotImplemented; \
|
||||
if(!vm->isinstance(rhs, vm->_tp_user<VoidP>())) return vm->NotImplemented; \
|
||||
void* _0 = PK_OBJ_GET(VoidP, lhs).ptr; \
|
||||
void* _1 = PK_OBJ_GET(VoidP, rhs).ptr; \
|
||||
return VAR(_0 op _1); \
|
||||
@ -60,9 +59,7 @@ void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
1,
|
||||
[](VM* vm, ArgsView args) {
|
||||
const Str& s = CAST(Str&, args[0]);
|
||||
if(s.size < 2 || s.size % 2 != 0) {
|
||||
vm->ValueError("invalid hex string");
|
||||
}
|
||||
if(s.size < 2 || s.size % 2 != 0) { vm->ValueError("invalid hex string"); }
|
||||
Struct buffer(s.size / 2, false);
|
||||
for(int i = 0; i < s.size; i += 2) {
|
||||
char c = 0;
|
||||
@ -116,9 +113,7 @@ void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
|
||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) {
|
||||
Struct& self = _CAST(Struct&, lhs);
|
||||
if(!vm->is_user_type<Struct>(rhs)) {
|
||||
return vm->NotImplemented;
|
||||
}
|
||||
if(!vm->is_user_type<Struct>(rhs)) { return vm->NotImplemented; }
|
||||
Struct& other = _CAST(Struct&, rhs);
|
||||
bool ok = self.size == other.size && memcmp(self.p, other.p, self.size) == 0;
|
||||
return VAR(ok);
|
||||
@ -192,9 +187,7 @@ void add_module_c(VM* vm) {
|
||||
VoidP& ptr = CAST(VoidP&, args[0]);
|
||||
vm->check_type(args[1], vm->tp_type);
|
||||
Type cls = PK_OBJ_GET(Type, args[1]);
|
||||
if(!vm->issubclass(cls, vm->_tp_user<VoidP>())) {
|
||||
vm->ValueError("expected a subclass of void_p");
|
||||
}
|
||||
if(!vm->issubclass(cls, vm->_tp_user<VoidP>())) { vm->ValueError("expected a subclass of void_p"); }
|
||||
return vm->new_object<VoidP>(cls, ptr.ptr);
|
||||
});
|
||||
|
||||
|
||||
@ -6,9 +6,7 @@
|
||||
namespace pkpy {
|
||||
PyVar* FastLocals::try_get_name(StrName name) {
|
||||
int index = co->varnames_inv.try_get(name);
|
||||
if(index == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
if(index == -1) { return nullptr; }
|
||||
return &a[index];
|
||||
}
|
||||
|
||||
@ -16,21 +14,15 @@ NameDict_ FastLocals::to_namedict() {
|
||||
NameDict_ dict = std::make_shared<NameDict>();
|
||||
co->varnames_inv.apply([&](StrName name, int index) {
|
||||
PyVar value = a[index];
|
||||
if(value) {
|
||||
dict->set(name, value);
|
||||
}
|
||||
if(value) { dict->set(name, value); }
|
||||
});
|
||||
return dict;
|
||||
}
|
||||
|
||||
PyVar* Frame::f_closure_try_get(StrName name) {
|
||||
if(_callable == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if(_callable == nullptr) { return nullptr; }
|
||||
Function& fn = _callable->as<Function>();
|
||||
if(fn._closure == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if(fn._closure == nullptr) { return nullptr; }
|
||||
return fn._closure->try_get_2(name);
|
||||
}
|
||||
|
||||
@ -38,14 +30,10 @@ int Frame::prepare_jump_exception_handler(ValueStack* _s) {
|
||||
// try to find a parent try block
|
||||
int i = co->lines[ip()].iblock;
|
||||
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;
|
||||
}
|
||||
if(i < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(i < 0) { return -1; }
|
||||
PyVar obj = _s->popx(); // pop exception object
|
||||
UnwindTarget* uw = find_unwind_target(i);
|
||||
_s->reset(actual_sp_base() + uw->offset); // unwind the stack
|
||||
@ -86,9 +74,7 @@ void Frame::prepare_jump_break(ValueStack* _s, int target) {
|
||||
while(i >= 0 && i != next_block) {
|
||||
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"); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,9 +93,7 @@ void Frame::set_unwind_target(PyVar* _sp) {
|
||||
UnwindTarget* Frame::find_unwind_target(int iblock) {
|
||||
UnwindTarget* p;
|
||||
for(p = _uw_list; p != nullptr; p = p->next) {
|
||||
if(p->iblock == iblock) {
|
||||
return p;
|
||||
}
|
||||
if(p->iblock == iblock) { return p; }
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -13,9 +13,7 @@ int ManagedHeap::sweep() {
|
||||
#if PK_DEBUG_GC_STATS
|
||||
deleted[obj->type] += 1;
|
||||
#endif
|
||||
if(_gc_on_delete) {
|
||||
_gc_on_delete(vm, obj);
|
||||
}
|
||||
if(_gc_on_delete) { _gc_on_delete(vm, obj); }
|
||||
_delete(obj);
|
||||
}
|
||||
}
|
||||
@ -42,15 +40,11 @@ int ManagedHeap::sweep() {
|
||||
|
||||
void ManagedHeap::_auto_collect() {
|
||||
#if !PK_DEBUG_NO_AUTO_GC
|
||||
if(_gc_lock_counter > 0) {
|
||||
return;
|
||||
}
|
||||
if(_gc_lock_counter > 0) { return; }
|
||||
gc_counter = 0;
|
||||
collect();
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@ -6,9 +6,7 @@ void RangeIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||
RangeIter& self = PK_OBJ_GET(RangeIter, _0);
|
||||
if(self.current >= self.r.stop) {
|
||||
return 0;
|
||||
}
|
||||
if(self.current >= self.r.stop) { return 0; }
|
||||
vm->s_data.emplace(VM::tp_int, self.current);
|
||||
self.current += self.r.step;
|
||||
return 1;
|
||||
@ -19,9 +17,7 @@ void RangeIterR::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||
RangeIterR& self = PK_OBJ_GET(RangeIterR, _0);
|
||||
if(self.current <= self.r.stop) {
|
||||
return 0;
|
||||
}
|
||||
if(self.current <= self.r.stop) { return 0; }
|
||||
vm->s_data.emplace(VM::tp_int, self.current);
|
||||
self.current += self.r.step;
|
||||
return 1;
|
||||
@ -32,9 +28,7 @@ void ArrayIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||
ArrayIter& self = _CAST(ArrayIter&, _0);
|
||||
if(self.current == self.end) {
|
||||
return 0;
|
||||
}
|
||||
if(self.current == self.end) { return 0; }
|
||||
vm->s_data.push(*self.current++);
|
||||
return 1;
|
||||
});
|
||||
@ -45,9 +39,7 @@ void StringIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||
StringIter& self = _CAST(StringIter&, _0);
|
||||
Str& s = PK_OBJ_GET(Str, self.ref);
|
||||
if(self.i == s.size) {
|
||||
return 0;
|
||||
}
|
||||
if(self.i == s.size) { return 0; }
|
||||
int start = self.i;
|
||||
int len = utf8len(s.data[self.i]);
|
||||
self.i += len;
|
||||
@ -57,9 +49,7 @@ void StringIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
}
|
||||
|
||||
PyVar Generator::next(VM* vm) {
|
||||
if(state == 2) {
|
||||
return vm->StopIteration;
|
||||
}
|
||||
if(state == 2) { return vm->StopIteration; }
|
||||
// reset frame._sp_base
|
||||
lf->frame._sp_base = vm->s_data._sp;
|
||||
lf->frame._locals.a = vm->s_data._sp;
|
||||
@ -105,9 +95,7 @@ PyVar Generator::next(VM* vm) {
|
||||
// }
|
||||
// #endif
|
||||
state = 1;
|
||||
if(ret == vm->StopIteration) {
|
||||
state = 2;
|
||||
}
|
||||
if(ret == vm->StopIteration) { state = 2; }
|
||||
return ret;
|
||||
} else {
|
||||
state = 2;
|
||||
@ -120,9 +108,7 @@ void Generator::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||
Generator& self = _CAST(Generator&, _0);
|
||||
PyVar retval = self.next(vm);
|
||||
if(retval == vm->StopIteration) {
|
||||
return 0;
|
||||
}
|
||||
if(retval == vm->StopIteration) { return 0; }
|
||||
vm->s_data.push(retval);
|
||||
return 1;
|
||||
});
|
||||
@ -133,9 +119,7 @@ void DictItemsIter::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||
DictItemsIter& self = _CAST(DictItemsIter&, _0);
|
||||
Dict& d = PK_OBJ_GET(Dict, self.ref);
|
||||
if(self.i == -1) {
|
||||
return 0;
|
||||
}
|
||||
if(self.i == -1) { return 0; }
|
||||
vm->s_data.push(d._items[self.i].first);
|
||||
vm->s_data.push(d._items[self.i].second);
|
||||
self.i = d._items[self.i].next;
|
||||
|
||||
@ -4,9 +4,7 @@ namespace pkpy {
|
||||
|
||||
static std::string left_pad(std::string s, int width) {
|
||||
int n = width - s.size();
|
||||
if(n <= 0) {
|
||||
return s;
|
||||
}
|
||||
if(n <= 0) { return s; }
|
||||
return std::string(n, ' ') + s;
|
||||
}
|
||||
|
||||
@ -20,9 +18,7 @@ void LineProfiler::begin() { frames.clear(); }
|
||||
|
||||
void LineProfiler::_step(int callstack_size, Frame* frame) {
|
||||
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();
|
||||
int line = line_info.lineno;
|
||||
|
||||
@ -57,18 +53,14 @@ void LineProfiler::_step_end(int callstack_size, Frame* frame, int line) {
|
||||
if(prev_record->line != line) {
|
||||
clock_t delta = now - top_frame_record.prev_time;
|
||||
top_frame_record.prev_time = now;
|
||||
if(id_delta != 1) {
|
||||
prev_record->hits++;
|
||||
}
|
||||
if(id_delta != 1) { prev_record->hits++; }
|
||||
prev_record->time += delta;
|
||||
}
|
||||
|
||||
if(id_delta == 1) {
|
||||
frames.push({callstack_size, frame, now, nullptr});
|
||||
} else {
|
||||
if(id_delta == -1) {
|
||||
frames.pop();
|
||||
}
|
||||
if(id_delta == -1) { frames.pop(); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,14 +83,10 @@ Str LineProfiler::stats() {
|
||||
for(FuncDecl* decl: functions) {
|
||||
int start_line = decl->code->start_line;
|
||||
int end_line = decl->code->end_line;
|
||||
if(start_line == -1 || end_line == -1) {
|
||||
continue;
|
||||
}
|
||||
if(start_line == -1 || end_line == -1) { continue; }
|
||||
std::string_view filename = decl->code->src->filename.sv();
|
||||
vector<_LineRecord>& file_records = records[filename];
|
||||
if(file_records.empty()) {
|
||||
continue;
|
||||
}
|
||||
if(file_records.empty()) { continue; }
|
||||
clock_t total_time = 0;
|
||||
for(int line = start_line; line <= end_line; line++) {
|
||||
total_time += file_records[line].time;
|
||||
@ -110,9 +98,7 @@ Str LineProfiler::stats() {
|
||||
ss << "==============================================================\n";
|
||||
for(int line = start_line; line <= end_line; 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);
|
||||
if(record.hits == 0) {
|
||||
ss << std::string(10 + 13 + 9 + 9, ' ');
|
||||
|
||||
@ -23,9 +23,7 @@ struct JsonSerializer {
|
||||
void write_array(T& arr) {
|
||||
ss << '[';
|
||||
for(int i = 0; i < arr.size(); i++) {
|
||||
if(i != 0) {
|
||||
ss << ", ";
|
||||
}
|
||||
if(i != 0) { ss << ", "; }
|
||||
write_object(arr[i]);
|
||||
}
|
||||
ss << ']';
|
||||
@ -35,9 +33,7 @@ struct JsonSerializer {
|
||||
ss << '{';
|
||||
bool first = true;
|
||||
dict.apply([&](PyVar k, PyVar v) {
|
||||
if(!first) {
|
||||
ss << ", ";
|
||||
}
|
||||
if(!first) { ss << ", "; }
|
||||
first = false;
|
||||
if(!is_type(k, VM::tp_str)) {
|
||||
vm->TypeError(_S("json keys must be string, got ", _type_name(vm, vm->_tp(k))));
|
||||
@ -56,9 +52,7 @@ struct JsonSerializer {
|
||||
ss << _CAST(i64, obj);
|
||||
} else if(obj_t == vm->tp_float) {
|
||||
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;
|
||||
} else if(obj_t == vm->tp_bool) {
|
||||
ss << (obj == vm->True ? "true" : "false");
|
||||
@ -97,16 +91,12 @@ VM::VM(bool enable_os) : heap(this), enable_os(enable_os) {
|
||||
|
||||
Str VM::py_str(PyVar 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 f = get_unbound_method(obj, __str__, &self, false);
|
||||
if(self != PY_NULL) {
|
||||
PyVar retval = call_method(self, f);
|
||||
if(!is_type(retval, tp_str)) {
|
||||
throw std::runtime_error("object.__str__ must return str");
|
||||
}
|
||||
if(!is_type(retval, tp_str)) { throw std::runtime_error("object.__str__ must return str"); }
|
||||
return PK_OBJ_GET(Str, retval);
|
||||
}
|
||||
return py_repr(obj);
|
||||
@ -114,13 +104,9 @@ Str VM::py_str(PyVar obj) {
|
||||
|
||||
Str VM::py_repr(PyVar 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__);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -131,14 +117,10 @@ Str VM::py_json(PyVar obj) {
|
||||
|
||||
PyVar VM::py_iter(PyVar 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 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");
|
||||
return nullptr;
|
||||
}
|
||||
@ -167,13 +149,9 @@ PyVar* VM::find_name_in_mro(Type cls, StrName name) {
|
||||
PyVar* val;
|
||||
do {
|
||||
val = _t(cls)->attr().try_get_2(name);
|
||||
if(val != nullptr) {
|
||||
return val;
|
||||
}
|
||||
if(val != nullptr) { return val; }
|
||||
cls = _all_types[cls].base;
|
||||
if(!cls) {
|
||||
break;
|
||||
}
|
||||
if(!cls) { break; }
|
||||
} while(true);
|
||||
return nullptr;
|
||||
}
|
||||
@ -182,22 +160,16 @@ bool VM::isinstance(PyVar obj, Type base) { return issubclass(_tp(obj), base); }
|
||||
|
||||
bool VM::issubclass(Type cls, Type base) {
|
||||
do {
|
||||
if(cls == base) {
|
||||
return true;
|
||||
}
|
||||
if(cls == base) { return true; }
|
||||
Type next = _all_types[cls].base;
|
||||
if(!next) {
|
||||
break;
|
||||
}
|
||||
if(!next) { break; }
|
||||
cls = next;
|
||||
} while(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module) {
|
||||
if(_module == nullptr) {
|
||||
_module = _main;
|
||||
}
|
||||
if(_module == nullptr) { _module = _main; }
|
||||
try {
|
||||
#if PK_DEBUG_PRECOMPILED_EXEC == 1
|
||||
Str precompiled = vm->precompile(source, filename, mode);
|
||||
@ -243,33 +215,23 @@ PyObject* VM::new_type_object(PyObject* mod, StrName name, Type base, bool subcl
|
||||
}
|
||||
|
||||
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);
|
||||
PyVar res;
|
||||
if(ti->m__eq__) {
|
||||
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);
|
||||
if(!is_not_implemented(res)) {
|
||||
return res == vm->True;
|
||||
}
|
||||
if(!is_not_implemented(res)) { return res == vm->True; }
|
||||
|
||||
ti = _tp_info(rhs);
|
||||
if(ti->m__eq__) {
|
||||
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);
|
||||
if(!is_not_implemented(res)) {
|
||||
return res == vm->True;
|
||||
}
|
||||
if(!is_not_implemented(res)) { return res == vm->True; }
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -286,12 +248,8 @@ PyVar VM::py_op(std::string_view name) {
|
||||
}
|
||||
|
||||
i64 VM::normalized_index(i64 index, int size) {
|
||||
if(index < 0) {
|
||||
index += size;
|
||||
}
|
||||
if(index < 0 || index >= size) {
|
||||
IndexError(std::to_string(index) + " not in [0, " + std::to_string(size) + ")");
|
||||
}
|
||||
if(index < 0) { index += size; }
|
||||
if(index < 0 || index >= size) { IndexError(std::to_string(index) + " not in [0, " + std::to_string(size) + ")"); }
|
||||
return index;
|
||||
}
|
||||
|
||||
@ -329,9 +287,7 @@ PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) {
|
||||
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);
|
||||
if(args_tuple.size() == 1) {
|
||||
@ -340,49 +296,37 @@ PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) {
|
||||
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];
|
||||
|
||||
if(key == vm->None) {
|
||||
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 {
|
||||
auto _lock = heap.gc_scope_lock();
|
||||
for(int i = 1; i < view.size(); i++) {
|
||||
PyVar a = call(key, view[i]);
|
||||
PyVar b = call(key, res);
|
||||
if((this->*op)(a, b)) {
|
||||
res = view[i];
|
||||
}
|
||||
if((this->*op)(a, b)) { res = view[i]; }
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
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) {
|
||||
SStream ss;
|
||||
for(int i = 0; i < cpnts.size(); i++) {
|
||||
if(i != 0) {
|
||||
ss << ".";
|
||||
}
|
||||
if(i != 0) { ss << "."; }
|
||||
ss << cpnts[i];
|
||||
}
|
||||
return ss.str();
|
||||
};
|
||||
|
||||
if(path[0] == '.') {
|
||||
if(__import_context.pending.empty()) {
|
||||
ImportError("relative import outside of package");
|
||||
}
|
||||
if(__import_context.pending.empty()) { ImportError("relative import outside of package"); }
|
||||
Str curr_path = __import_context.pending.back();
|
||||
bool curr_is_init = __import_context.pending_is_init.back();
|
||||
// convert relative path to absolute path
|
||||
@ -395,16 +339,12 @@ PyObject* VM::py_import(Str path, bool throw_err) {
|
||||
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
|
||||
for(int i = (int)curr_is_init; i < prefix; i++) {
|
||||
cpnts.pop_back();
|
||||
}
|
||||
if(!path.empty()) {
|
||||
cpnts.push_back(path.sv());
|
||||
}
|
||||
if(!path.empty()) { cpnts.push_back(path.sv()); }
|
||||
path = f_join(cpnts);
|
||||
}
|
||||
|
||||
@ -413,15 +353,11 @@ PyObject* VM::py_import(Str path, bool throw_err) {
|
||||
// check existing module
|
||||
StrName name(path);
|
||||
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('.');
|
||||
// check circular import
|
||||
if(__import_context.pending.size() > 128) {
|
||||
ImportError("maximum recursion depth exceeded while importing");
|
||||
}
|
||||
if(__import_context.pending.size() > 128) { ImportError("maximum recursion depth exceeded while importing"); }
|
||||
|
||||
// try import
|
||||
Str filename = path.replace('.', PK_PLATFORM_SEP) + ".py";
|
||||
@ -478,22 +414,14 @@ VM::~VM() {
|
||||
|
||||
PyVar VM::py_negate(PyVar 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__);
|
||||
}
|
||||
|
||||
bool VM::__py_bool_non_trivial(PyVar obj) {
|
||||
if(obj == None) {
|
||||
return false;
|
||||
}
|
||||
if(is_int(obj)) {
|
||||
return _CAST(i64, obj) != 0;
|
||||
}
|
||||
if(is_float(obj)) {
|
||||
return _CAST(f64, obj) != 0.0;
|
||||
}
|
||||
if(obj == None) { return false; }
|
||||
if(is_int(obj)) { return _CAST(i64, obj) != 0; }
|
||||
if(is_float(obj)) { return _CAST(f64, obj) != 0.0; }
|
||||
PyVar self;
|
||||
PyVar len_f = get_unbound_method(obj, __len__, &self, false);
|
||||
if(self != PY_NULL) {
|
||||
@ -504,19 +432,13 @@ bool VM::__py_bool_non_trivial(PyVar obj) {
|
||||
}
|
||||
|
||||
void VM::__obj_gc_mark(PyObject* obj) {
|
||||
if(obj->gc_marked) {
|
||||
return;
|
||||
}
|
||||
if(obj->gc_marked) { return; }
|
||||
obj->gc_marked = true;
|
||||
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()) {
|
||||
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()); }
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -529,9 +451,7 @@ void VM::__stack_gc_mark(PyVar* begin, PyVar* end) {
|
||||
if(it->type == tp_stack_memory) {
|
||||
// [sm:3, _0, _1, _2, sm:-3]
|
||||
int count = it->as<StackMemory>().count;
|
||||
if(count > 0) {
|
||||
it += count;
|
||||
}
|
||||
if(count > 0) { it += count; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -561,12 +481,8 @@ List VM::py_list(PyVar it) {
|
||||
|
||||
void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step) {
|
||||
auto clip = [](int value, int min, int max) {
|
||||
if(value < min) {
|
||||
return min;
|
||||
}
|
||||
if(value > max) {
|
||||
return max;
|
||||
}
|
||||
if(value < min) { return min; }
|
||||
if(value > max) { return max; }
|
||||
return value;
|
||||
};
|
||||
if(s.step == None) {
|
||||
@ -574,26 +490,20 @@ void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int&
|
||||
} else {
|
||||
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(s.start == None) {
|
||||
start = 0;
|
||||
} else {
|
||||
start = CAST(int, s.start);
|
||||
if(start < 0) {
|
||||
start += length;
|
||||
}
|
||||
if(start < 0) { start += length; }
|
||||
start = clip(start, 0, length);
|
||||
}
|
||||
if(s.stop == None) {
|
||||
stop = length;
|
||||
} else {
|
||||
stop = CAST(int, s.stop);
|
||||
if(stop < 0) {
|
||||
stop += length;
|
||||
}
|
||||
if(stop < 0) { stop += length; }
|
||||
stop = clip(stop, 0, length);
|
||||
}
|
||||
} else {
|
||||
@ -601,18 +511,14 @@ void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int&
|
||||
start = length - 1;
|
||||
} else {
|
||||
start = CAST(int, s.start);
|
||||
if(start < 0) {
|
||||
start += length;
|
||||
}
|
||||
if(start < 0) { start += length; }
|
||||
start = clip(start, -1, length - 1);
|
||||
}
|
||||
if(s.stop == None) {
|
||||
stop = -1;
|
||||
} else {
|
||||
stop = CAST(int, s.stop);
|
||||
if(stop < 0) {
|
||||
stop += length;
|
||||
}
|
||||
if(stop < 0) { stop += length; }
|
||||
stop = clip(stop, -1, length - 1);
|
||||
}
|
||||
}
|
||||
@ -621,9 +527,7 @@ void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int&
|
||||
i64 VM::py_hash(PyVar obj) {
|
||||
// https://docs.python.org/3.10/reference/datamodel.html#object.__hash__
|
||||
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 f = get_unbound_method(obj, __hash__, &self, false);
|
||||
@ -632,9 +536,7 @@ i64 VM::py_hash(PyVar obj) {
|
||||
return CAST(i64, ret);
|
||||
}
|
||||
// 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__
|
||||
bool has_custom_eq = false;
|
||||
if(ti->m__eq__) {
|
||||
@ -718,9 +620,7 @@ PyVar VM::py_eval(std::string_view source, PyVar globals, PyVar locals) {
|
||||
}
|
||||
|
||||
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;
|
||||
switch(spec.end()[-1]) {
|
||||
case 'f':
|
||||
@ -774,15 +674,11 @@ PyVar VM::__format_object(PyVar obj, Str spec) {
|
||||
}
|
||||
} 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;
|
||||
if(type == 'f') {
|
||||
f64 val = CAST(f64, obj);
|
||||
if(precision < 0) {
|
||||
precision = 6;
|
||||
}
|
||||
if(precision < 0) { precision = 6; }
|
||||
SStream ss;
|
||||
ss.setprecision(precision);
|
||||
ss << val;
|
||||
@ -819,16 +715,12 @@ PyObject* VM::new_module(Str name, Str package) {
|
||||
obj->attr().set(__name__, VAR(name));
|
||||
obj->attr().set(__package__, VAR(package));
|
||||
// convert to fullname
|
||||
if(!package.empty()) {
|
||||
name = package + "." + name;
|
||||
}
|
||||
if(!package.empty()) { name = package + "." + name; }
|
||||
obj->attr().set(__path__, VAR(name));
|
||||
|
||||
// we do not allow override in order to avoid memory leak
|
||||
// it is because Module objects are not garbage collected
|
||||
if(_modules.contains(name)) {
|
||||
throw std::runtime_error(_S("module ", name.escape(), " already exists").str());
|
||||
}
|
||||
if(_modules.contains(name)) { throw std::runtime_error(_S("module ", name.escape(), " already exists").str()); }
|
||||
// set it into _modules
|
||||
_modules.set(name, obj);
|
||||
return obj;
|
||||
@ -847,9 +739,7 @@ static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject
|
||||
case OP_LOAD_CONST:
|
||||
case OP_FORMAT_STRING:
|
||||
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;
|
||||
case OP_LOAD_NAME:
|
||||
case OP_LOAD_GLOBAL:
|
||||
@ -881,18 +771,14 @@ static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject
|
||||
|
||||
Str VM::disassemble(CodeObject_ co) {
|
||||
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(), ' ');
|
||||
};
|
||||
|
||||
vector<int> jumpTargets;
|
||||
for(int i = 0; i < co->codes.size(); i++) {
|
||||
Bytecode byte = co->codes[i];
|
||||
if(byte.is_forward_jump()) {
|
||||
jumpTargets.push_back((int16_t)byte.arg + i);
|
||||
}
|
||||
if(byte.is_forward_jump()) { jumpTargets.push_back((int16_t)byte.arg + i); }
|
||||
}
|
||||
SStream ss;
|
||||
int prev_line = -1;
|
||||
@ -902,9 +788,7 @@ Str VM::disassemble(CodeObject_ co) {
|
||||
if(co->lines[i].lineno == prev_line) {
|
||||
line = "";
|
||||
} else {
|
||||
if(prev_line != -1) {
|
||||
ss << "\n";
|
||||
}
|
||||
if(prev_line != -1) { ss << "\n"; }
|
||||
prev_line = co->lines[i].lineno;
|
||||
}
|
||||
|
||||
@ -916,15 +800,11 @@ Str VM::disassemble(CodeObject_ co) {
|
||||
}
|
||||
ss << pad(line, 8) << pointer << pad(std::to_string(i), 3);
|
||||
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) << " ";
|
||||
std::string argStr = _opcode_argstr(this, i, byte, co.get());
|
||||
ss << argStr;
|
||||
if(i != co->codes.size() - 1) {
|
||||
ss << '\n';
|
||||
}
|
||||
if(i != co->codes.size() - 1) { ss << '\n'; }
|
||||
}
|
||||
|
||||
for(auto& decl: co->func_decls) {
|
||||
@ -938,16 +818,10 @@ Str VM::disassemble(CodeObject_ co) {
|
||||
|
||||
#if PK_DEBUG_CEVAL_STEP
|
||||
void VM::__log_s_data(const char* title) {
|
||||
if(_main == nullptr) {
|
||||
return;
|
||||
}
|
||||
if(callstack.empty()) {
|
||||
return;
|
||||
}
|
||||
if(_main == nullptr) { return; }
|
||||
if(callstack.empty()) { return; }
|
||||
SStream ss;
|
||||
if(title) {
|
||||
ss << title << " | ";
|
||||
}
|
||||
if(title) { ss << title << " | "; }
|
||||
std::map<PyVar*, int> sp_bases;
|
||||
callstack.apply([&](Frame& f) {
|
||||
assert(f._sp_base != nullptr);
|
||||
@ -958,9 +832,7 @@ void VM::__log_s_data(const char* title) {
|
||||
ss << frame->co->name << ":" << line << " [";
|
||||
for(PyVar* p = s_data.begin(); p != s_data.end(); p++) {
|
||||
ss << std::string(sp_bases[p], '|');
|
||||
if(sp_bases[p] > 0) {
|
||||
ss << " ";
|
||||
}
|
||||
if(sp_bases[p] > 0) { ss << " "; }
|
||||
if(*p == PY_NULL) {
|
||||
ss << "NULL";
|
||||
} else {
|
||||
@ -977,9 +849,7 @@ void VM::__log_s_data(const char* title) {
|
||||
case tp_stack_memory: {
|
||||
int count = p->obj_get<StackMemory>().count;
|
||||
ss << "M[" << count << "]";
|
||||
if(count > 0) {
|
||||
p += count;
|
||||
}
|
||||
if(count > 0) { p += count; }
|
||||
break;
|
||||
}
|
||||
default: ss << "(" << _type_name(this, p->type) << ")"; break;
|
||||
@ -1006,9 +876,7 @@ void VM::__init_builtin_types() {
|
||||
|
||||
auto validate = [](Type type, PyObject* ret) {
|
||||
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));
|
||||
@ -1079,9 +947,7 @@ void VM::__unpack_as_list(ArgsView args, List& list) {
|
||||
if(is_type(obj, tp_star_wrapper)) {
|
||||
const StarWrapper& w = _CAST(StarWrapper&, obj);
|
||||
// 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);
|
||||
const PyTypeInfo* info = _tp_info(_0);
|
||||
PyVar _1 = _py_next(info, _0);
|
||||
@ -1101,16 +967,12 @@ void VM::__unpack_as_dict(ArgsView args, Dict& dict) {
|
||||
if(is_type(obj, tp_star_wrapper)) {
|
||||
const StarWrapper& w = _CAST(StarWrapper&, obj);
|
||||
// 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);
|
||||
dict.update(this, other);
|
||||
} else {
|
||||
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]);
|
||||
}
|
||||
}
|
||||
@ -1143,14 +1005,10 @@ void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const
|
||||
} else {
|
||||
// kwdefaults override
|
||||
for(auto& kv: decl->kwargs) {
|
||||
if(i >= args.size()) {
|
||||
break;
|
||||
}
|
||||
if(i >= args.size()) { break; }
|
||||
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;
|
||||
@ -1206,9 +1064,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
if(callable_t == tp_function) {
|
||||
/*****************_py_call*****************/
|
||||
// check stack overflow
|
||||
if(s_data.is_overflow()) {
|
||||
StackOverflowError();
|
||||
}
|
||||
if(s_data.is_overflow()) { StackOverflowError(); }
|
||||
|
||||
const Function& fn = PK_OBJ_GET(Function, callable);
|
||||
const CodeObject* co = fn.decl->code.get();
|
||||
@ -1231,9 +1087,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
args.size(),
|
||||
" 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...]
|
||||
// ^p0 ^p1 ^_sp
|
||||
s_data.reset(_base + co->nlocals);
|
||||
@ -1249,9 +1103,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
args.size(),
|
||||
" 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);
|
||||
return None;
|
||||
case FuncType::GENERATOR:
|
||||
@ -1265,9 +1117,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
|
||||
// simple or normal
|
||||
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();
|
||||
/*****************_py_call*****************/
|
||||
}
|
||||
@ -1290,9 +1140,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
TypeError(
|
||||
"old-style native_func does not accept keyword arguments. If you want to skip this check, specify `argc` to -1");
|
||||
}
|
||||
if(args.size() != f.argc) {
|
||||
vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size()));
|
||||
}
|
||||
if(args.size() != f.argc) { vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size())); }
|
||||
}
|
||||
ret = f.call(this, args);
|
||||
}
|
||||
@ -1355,15 +1203,9 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
|
||||
void VM::delattr(PyVar _0, StrName _name) {
|
||||
const PyTypeInfo* ti = _tp_info(_0);
|
||||
if(ti->m__delattr__ && ti->m__delattr__(this, _0, _name)) {
|
||||
return;
|
||||
}
|
||||
if(is_tagged(_0) || !_0->is_attr_valid()) {
|
||||
TypeError("cannot delete attribute");
|
||||
}
|
||||
if(!_0->attr().del(_name)) {
|
||||
AttributeError(_0, _name);
|
||||
}
|
||||
if(ti->m__delattr__ && ti->m__delattr__(this, _0, _name)) { return; }
|
||||
if(is_tagged(_0) || !_0->is_attr_valid()) { TypeError("cannot delete attribute"); }
|
||||
if(!_0->attr().del(_name)) { AttributeError(_0, _name); }
|
||||
}
|
||||
|
||||
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
|
||||
@ -1391,22 +1233,14 @@ PyVar VM::getattr(PyVar obj, StrName name, bool throw_err) {
|
||||
if(obj.type == tp_type) {
|
||||
val = find_name_in_mro(PK_OBJ_GET(Type, obj), name);
|
||||
if(val != nullptr) {
|
||||
if(is_tagged(*val)) {
|
||||
return *val;
|
||||
}
|
||||
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(is_tagged(*val)) { return *val; }
|
||||
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)); }
|
||||
return *val;
|
||||
}
|
||||
} else {
|
||||
val = obj->attr().try_get_2_likely_found(name);
|
||||
if(val != nullptr) {
|
||||
return *val;
|
||||
}
|
||||
if(val != nullptr) { return *val; }
|
||||
}
|
||||
}
|
||||
if(cls_var != nullptr) {
|
||||
@ -1425,14 +1259,10 @@ PyVar VM::getattr(PyVar obj, StrName name, bool throw_err) {
|
||||
const PyTypeInfo* ti = &_all_types[objtype];
|
||||
if(ti->m__getattr__) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1465,12 +1295,8 @@ PyVar VM::get_unbound_method(PyVar obj, StrName name, PyVar* self, bool throw_er
|
||||
if(obj.type == tp_type) {
|
||||
val = find_name_in_mro(PK_OBJ_GET(Type, obj), name);
|
||||
if(val != nullptr) {
|
||||
if(is_tagged(*val)) {
|
||||
return *val;
|
||||
}
|
||||
if(val->type == tp_staticmethod) {
|
||||
return PK_OBJ_GET(StaticMethod, *val).func;
|
||||
}
|
||||
if(is_tagged(*val)) { return *val; }
|
||||
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));
|
||||
}
|
||||
@ -1478,9 +1304,7 @@ PyVar VM::get_unbound_method(PyVar obj, StrName name, PyVar* self, bool throw_er
|
||||
}
|
||||
} else {
|
||||
val = obj->attr().try_get_2_likely_found(name);
|
||||
if(val != nullptr) {
|
||||
return *val;
|
||||
}
|
||||
if(val != nullptr) { return *val; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1500,14 +1324,10 @@ PyVar VM::get_unbound_method(PyVar obj, StrName name, PyVar* self, bool throw_er
|
||||
const PyTypeInfo* ti = &_all_types[objtype];
|
||||
if(fallback && ti->m__getattr__) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1542,9 +1362,7 @@ void VM::setattr(PyVar obj, StrName name, PyVar value) {
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@ -1555,9 +1373,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::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;
|
||||
}
|
||||
|
||||
@ -1571,9 +1387,7 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
|
||||
// fn(a, b, *c, d=1) -> None
|
||||
co = compile(_S("def ", sig, " : pass"), "<bind>", EXEC_MODE);
|
||||
} catch(TopLevelException) { throw std::runtime_error("invalid signature: " + std::string(sig)); }
|
||||
if(co->func_decls.size() != 1) {
|
||||
throw std::runtime_error("expected 1 function declaration");
|
||||
}
|
||||
if(co->func_decls.size() != 1) { throw std::runtime_error("expected 1 function declaration"); }
|
||||
FuncDecl_ decl = co->func_decls[0];
|
||||
decl->docstring = docstring;
|
||||
PyObject* f_obj = heap.gcnew<NativeFunc>(tp_native_func, fn, decl, std::move(userdata));
|
||||
@ -1583,9 +1397,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::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;
|
||||
}
|
||||
|
||||
@ -1593,14 +1405,10 @@ PyObject* VM::bind_property(PyObject* obj, const char* name, NativeFuncC fget, N
|
||||
assert(is_type(obj, tp_type));
|
||||
std::string_view name_sv(name);
|
||||
int pos = name_sv.find(':');
|
||||
if(pos > 0) {
|
||||
name_sv = name_sv.substr(0, pos);
|
||||
}
|
||||
if(pos > 0) { name_sv = name_sv.substr(0, pos); }
|
||||
PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1);
|
||||
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);
|
||||
obj->attr().set(StrName(name_sv), prop);
|
||||
return prop;
|
||||
@ -1651,9 +1459,7 @@ void VM::__raise_exc(bool re_raise) {
|
||||
int next_ip = frame->prepare_jump_exception_handler(&s_data);
|
||||
|
||||
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
|
||||
auto current_f_name = frame->co->name.sv(); // current function name
|
||||
if(frame->_callable == nullptr) {
|
||||
@ -1707,12 +1513,8 @@ void VM::bind__delitem__(Type type, void (*f)(VM*, PyVar, PyVar)) {
|
||||
}
|
||||
|
||||
PyVar VM::__pack_next_retval(unsigned n) {
|
||||
if(n == 0) {
|
||||
return StopIteration;
|
||||
}
|
||||
if(n == 1) {
|
||||
return s_data.popx();
|
||||
}
|
||||
if(n == 0) { return StopIteration; }
|
||||
if(n == 1) { return s_data.popx(); }
|
||||
PyVar retval = VAR(s_data.view(n).to_tuple());
|
||||
s_data._sp -= n;
|
||||
return retval;
|
||||
@ -1860,9 +1662,7 @@ void Dict::_probe_0(VM* vm, PyVar key, bool& ok, int& i) const {
|
||||
break;
|
||||
}
|
||||
} 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
|
||||
i = ((5 * i) + 1) & _mask;
|
||||
@ -1887,14 +1687,10 @@ void NextBreakpoint::_step(VM* vm) {
|
||||
int curr_callstack_size = vm->callstack.size();
|
||||
int curr_lineno = vm->callstack.top().curr_lineno();
|
||||
if(should_step_into) {
|
||||
if(curr_callstack_size != callstack_size || curr_lineno != lineno) {
|
||||
vm->__breakpoint();
|
||||
}
|
||||
if(curr_callstack_size != callstack_size || curr_lineno != lineno) { vm->__breakpoint(); }
|
||||
} else {
|
||||
if(curr_callstack_size == callstack_size) {
|
||||
if(curr_lineno != lineno) {
|
||||
vm->__breakpoint();
|
||||
}
|
||||
if(curr_lineno != lineno) { vm->__breakpoint(); }
|
||||
} else if(curr_callstack_size < callstack_size) {
|
||||
// returning
|
||||
vm->__breakpoint();
|
||||
@ -1927,16 +1723,12 @@ void VM::__breakpoint() {
|
||||
while(lf != nullptr) {
|
||||
frames.push_back(lf);
|
||||
lf = lf->f_back;
|
||||
if(frames.size() >= 4) {
|
||||
break;
|
||||
}
|
||||
if(frames.size() >= 4) { break; }
|
||||
}
|
||||
|
||||
if(show_headers) {
|
||||
for(int i = frames.size() - 1; i >= 0; i--) {
|
||||
if(!show_where && i != 0) {
|
||||
continue;
|
||||
}
|
||||
if(!show_where && i != 0) { continue; }
|
||||
|
||||
SStream ss;
|
||||
Frame* frame = &frames[i]->frame;
|
||||
@ -1976,9 +1768,7 @@ void VM::__breakpoint() {
|
||||
stdout_write("!: execute statement\n");
|
||||
continue;
|
||||
}
|
||||
if(line == "q" || line == "quit") {
|
||||
vm->RuntimeError("pdb quit");
|
||||
}
|
||||
if(line == "q" || line == "quit") { vm->RuntimeError("pdb quit"); }
|
||||
if(line == "n" || line == "next") {
|
||||
vm->_next_breakpoint = NextBreakpoint(vm->callstack.size(), frame_0->curr_lineno(), false);
|
||||
break;
|
||||
@ -1992,15 +1782,11 @@ void VM::__breakpoint() {
|
||||
show_headers = true;
|
||||
continue;
|
||||
}
|
||||
if(line == "c" || line == "continue") {
|
||||
break;
|
||||
}
|
||||
if(line == "c" || line == "continue") { break; }
|
||||
if(line == "a" || line == "args") {
|
||||
int i = 0;
|
||||
for(PyVar obj: frame_0->_locals) {
|
||||
if(obj == PY_NULL) {
|
||||
continue;
|
||||
}
|
||||
if(obj == PY_NULL) { continue; }
|
||||
StrName name = frame_0->co->varnames[i++];
|
||||
stdout_write(_S(name.sv(), " = ", vm->py_repr(obj), '\n'));
|
||||
}
|
||||
@ -2011,9 +1797,7 @@ void VM::__breakpoint() {
|
||||
bool is_longlist = line == "ll" || line == "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 start, end;
|
||||
|
||||
@ -2024,9 +1808,7 @@ void VM::__breakpoint() {
|
||||
} else {
|
||||
start = frame_0->co->start_line;
|
||||
end = frame_0->co->end_line;
|
||||
if(start == -1 || end == -1) {
|
||||
continue;
|
||||
}
|
||||
if(start == -1 || end == -1) { continue; }
|
||||
}
|
||||
|
||||
SStream ss;
|
||||
@ -2076,9 +1858,7 @@ void Function::_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 {
|
||||
@ -2145,16 +1925,12 @@ void ManagedHeap::mark() {
|
||||
vm->obj_gc_mark(vm->__curr_class);
|
||||
vm->obj_gc_mark(vm->__c.error);
|
||||
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) {
|
||||
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
|
||||
PoolObject_dealloc(obj);
|
||||
}
|
||||
|
||||
@ -28,9 +28,7 @@ struct Array2d {
|
||||
bool is_valid(int col, int row) const { return 0 <= col && col < n_cols && 0 <= row && row < n_rows; }
|
||||
|
||||
void check_valid(VM* vm, int col, int row) const {
|
||||
if(is_valid(col, row)) {
|
||||
return;
|
||||
}
|
||||
if(is_valid(col, row)) { return; }
|
||||
vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')'));
|
||||
}
|
||||
|
||||
@ -48,9 +46,7 @@ struct Array2d {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
int n_cols = CAST(int, args[1]);
|
||||
int n_rows = CAST(int, args[2]);
|
||||
if(n_cols <= 0 || n_rows <= 0) {
|
||||
vm->ValueError("n_cols and n_rows must be positive integers");
|
||||
}
|
||||
if(n_cols <= 0 || n_rows <= 0) { vm->ValueError("n_cols and n_rows must be positive integers"); }
|
||||
self.init(n_cols, n_rows);
|
||||
if(vm->py_callable(args[3])) {
|
||||
for(int i = 0; i < self.numel; i++) {
|
||||
@ -100,9 +96,7 @@ struct Array2d {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, args[0]);
|
||||
int col = CAST(int, args[1]);
|
||||
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);
|
||||
});
|
||||
|
||||
@ -111,12 +105,10 @@ struct Array2d {
|
||||
int start_row, stop_row, step_row; \
|
||||
vm->parse_int_slice(PK_OBJ_GET(Slice, xy[0]), self.n_cols, start_col, stop_col, step_col); \
|
||||
vm->parse_int_slice(PK_OBJ_GET(Slice, xy[1]), self.n_rows, start_row, stop_row, step_row); \
|
||||
if(step_col != 1 || step_row != 1) \
|
||||
vm->ValueError("slice step must be 1"); \
|
||||
if(step_col != 1 || step_row != 1) vm->ValueError("slice step must be 1"); \
|
||||
int slice_width = stop_col - start_col; \
|
||||
int slice_height = stop_row - start_row; \
|
||||
if(slice_width <= 0 || slice_height <= 0) \
|
||||
vm->ValueError("slice width and height must be positive");
|
||||
if(slice_width <= 0 || slice_height <= 0) vm->ValueError("slice width and height must be positive");
|
||||
|
||||
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
||||
@ -285,17 +277,11 @@ struct Array2d {
|
||||
|
||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
||||
if(!vm->is_user_type<Array2d>(_1)) {
|
||||
return vm->NotImplemented;
|
||||
}
|
||||
if(!vm->is_user_type<Array2d>(_1)) { return vm->NotImplemented; }
|
||||
Array2d& other = PK_OBJ_GET(Array2d, _1);
|
||||
if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) {
|
||||
return vm->False;
|
||||
}
|
||||
if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) { return vm->False; }
|
||||
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;
|
||||
});
|
||||
@ -368,9 +354,7 @@ struct Array2d {
|
||||
}
|
||||
int width = right - left + 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);
|
||||
t[0] = VAR(left);
|
||||
t[1] = VAR(top);
|
||||
@ -404,9 +388,7 @@ struct Array2dIter {
|
||||
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
|
||||
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
|
||||
Array2dIter& self = PK_OBJ_GET(Array2dIter, _0);
|
||||
if(self.i == self.a->numel) {
|
||||
return 0;
|
||||
}
|
||||
if(self.i == self.a->numel) { return 0; }
|
||||
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.quot);
|
||||
|
||||
@ -126,22 +126,14 @@ static unsigned int base64_decode(const char* in, unsigned int inlen, unsigned c
|
||||
unsigned int j;
|
||||
unsigned char c;
|
||||
|
||||
if(inlen & 0x3) {
|
||||
return 0;
|
||||
}
|
||||
if(inlen & 0x3) { return 0; }
|
||||
|
||||
for(i = j = 0; i < inlen; i++) {
|
||||
if(in[i] == BASE64_PAD) {
|
||||
break;
|
||||
}
|
||||
if(in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) {
|
||||
return 0;
|
||||
}
|
||||
if(in[i] == BASE64_PAD) { break; }
|
||||
if(in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) { return 0; }
|
||||
|
||||
c = base64de[(unsigned char)in[i]];
|
||||
if(c == 255) {
|
||||
return 0;
|
||||
}
|
||||
if(c == 255) { return 0; }
|
||||
|
||||
switch(i & 0x3) {
|
||||
case 0: out[j] = (c << 2) & 0xFF; break;
|
||||
|
||||
@ -13,9 +13,7 @@ void add_module_csv(VM* vm) {
|
||||
std::string_view line = CAST(Str&, csvfile[i]).sv();
|
||||
if(i == 0) {
|
||||
// Skip utf8 BOM if there is any.
|
||||
if(strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) {
|
||||
line = line.substr(3);
|
||||
}
|
||||
if(strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) { line = line.substr(3); }
|
||||
}
|
||||
List row;
|
||||
int j;
|
||||
@ -70,16 +68,12 @@ void add_module_csv(VM* vm) {
|
||||
PyVar csv_reader = vm->_modules["csv"]->attr("reader");
|
||||
PyVar ret_obj = vm->call(csv_reader, args[0]);
|
||||
const List& ret = CAST(List&, ret_obj);
|
||||
if(ret.size() == 0) {
|
||||
vm->ValueError("empty csvfile");
|
||||
}
|
||||
if(ret.size() == 0) { vm->ValueError("empty csvfile"); }
|
||||
const List& header = CAST(List&, ret[0]);
|
||||
List new_ret;
|
||||
for(int i = 1; i < ret.size(); i++) {
|
||||
const List& row = CAST(List&, ret[i]);
|
||||
if(row.size() != header.size()) {
|
||||
vm->ValueError("row.size() != header.size()");
|
||||
}
|
||||
if(row.size() != header.size()) { vm->ValueError("row.size() != header.size()"); }
|
||||
Dict row_dict;
|
||||
for(int j = 0; j < header.size(); j++) {
|
||||
row_dict.set(vm, header[j], row[j]);
|
||||
|
||||
@ -67,17 +67,13 @@ static void patch__repr__(VM* vm, Type cls) {
|
||||
|
||||
static void patch__eq__(VM* vm, Type cls) {
|
||||
vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
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 auto& fields = cls_info->annotated_fields;
|
||||
for(StrName field: fields) {
|
||||
PyVar lhs = _0->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;
|
||||
});
|
||||
@ -91,15 +87,9 @@ void add_module_dataclasses(VM* vm) {
|
||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||
NameDict& cls_d = args[0]->attr();
|
||||
|
||||
if(!cls_d.contains(__init__)) {
|
||||
patch__init__(vm, cls);
|
||||
}
|
||||
if(!cls_d.contains(__repr__)) {
|
||||
patch__repr__(vm, cls);
|
||||
}
|
||||
if(!cls_d.contains(__eq__)) {
|
||||
patch__eq__(vm, cls);
|
||||
}
|
||||
if(!cls_d.contains(__init__)) { patch__init__(vm, cls); }
|
||||
if(!cls_d.contains(__repr__)) { patch__repr__(vm, cls); }
|
||||
if(!cls_d.contains(__eq__)) { patch__eq__(vm, cls); }
|
||||
|
||||
const auto& fields = vm->_all_types[cls].annotated_fields;
|
||||
bool has_default = false;
|
||||
|
||||
@ -23,9 +23,7 @@ static FILE* io_fopen(const char* name, const char* mode) {
|
||||
#if _MSC_VER
|
||||
FILE* fp;
|
||||
errno_t err = fopen_s(&fp, name, mode);
|
||||
if(err != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
if(err != 0) { return nullptr; }
|
||||
return fp;
|
||||
#else
|
||||
return fopen(name, mode);
|
||||
@ -42,13 +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) {
|
||||
bool exists = std::filesystem::exists(std::filesystem::path(name));
|
||||
if(!exists) {
|
||||
return nullptr;
|
||||
}
|
||||
if(!exists) { return nullptr; }
|
||||
FILE* fp = io_fopen(name, "rb");
|
||||
if(!fp) {
|
||||
return nullptr;
|
||||
}
|
||||
if(!fp) { return nullptr; }
|
||||
fseek(fp, 0, SEEK_END);
|
||||
int buffer_size = ftell(fp);
|
||||
unsigned char* buffer = new unsigned char[buffer_size];
|
||||
@ -83,9 +77,7 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
assert(actual_size <= buffer_size);
|
||||
// in text mode, CR may be dropped, which may cause `actual_size < buffer_size`
|
||||
Bytes b(buffer, actual_size);
|
||||
if(io.is_text) {
|
||||
return VAR(std::string_view((char*)b.data(), b.size()));
|
||||
}
|
||||
if(io.is_text) { return VAR(std::string_view((char*)b.data(), b.size())); }
|
||||
return VAR(std::move(b));
|
||||
});
|
||||
|
||||
@ -104,9 +96,7 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind_func(type, "tell", 1, [](VM* vm, ArgsView args) {
|
||||
FileIO& io = PK_OBJ_GET(FileIO, args[0]);
|
||||
long pos = ftell(io.fp);
|
||||
if(pos == -1) {
|
||||
vm->IOError(strerror(errno));
|
||||
}
|
||||
if(pos == -1) { vm->IOError(strerror(errno)); }
|
||||
return VAR(pos);
|
||||
});
|
||||
|
||||
@ -115,9 +105,7 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
long offset = CAST(long, args[1]);
|
||||
int whence = CAST(int, args[2]);
|
||||
int ret = fseek(io.fp, offset, whence);
|
||||
if(ret != 0) {
|
||||
vm->IOError(strerror(errno));
|
||||
}
|
||||
if(ret != 0) { vm->IOError(strerror(errno)); }
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
@ -139,15 +127,11 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
FileIO::FileIO(VM* vm, const Str& file, const Str& mode) {
|
||||
this->is_text = mode.sv().find("b") == std::string::npos;
|
||||
fp = io_fopen(file.c_str(), mode.c_str());
|
||||
if(!fp) {
|
||||
vm->IOError(strerror(errno));
|
||||
}
|
||||
if(!fp) { vm->IOError(strerror(errno)); }
|
||||
}
|
||||
|
||||
void FileIO::close() {
|
||||
if(fp == nullptr) {
|
||||
return;
|
||||
}
|
||||
if(fp == nullptr) { return; }
|
||||
fclose(fp);
|
||||
fp = nullptr;
|
||||
}
|
||||
@ -197,27 +181,21 @@ void add_module_os(VM* vm) {
|
||||
vm->bind_func(mod, "remove", 1, [](VM* vm, ArgsView args) {
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
bool ok = std::filesystem::remove(path);
|
||||
if(!ok) {
|
||||
vm->IOError("operation failed");
|
||||
}
|
||||
if(!ok) { vm->IOError("operation failed"); }
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "mkdir", 1, [](VM* vm, ArgsView args) {
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
bool ok = std::filesystem::create_directory(path);
|
||||
if(!ok) {
|
||||
vm->IOError("operation failed");
|
||||
}
|
||||
if(!ok) { vm->IOError("operation failed"); }
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_func(mod, "rmdir", 1, [](VM* vm, ArgsView args) {
|
||||
std::filesystem::path path(CAST(Str&, args[0]).sv());
|
||||
bool ok = std::filesystem::remove(path);
|
||||
if(!ok) {
|
||||
vm->IOError("operation failed");
|
||||
}
|
||||
if(!ok) { vm->IOError("operation failed"); }
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
|
||||
@ -55,16 +55,14 @@ namespace pkpy {
|
||||
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index) { \
|
||||
Vec##D self = _CAST(Vec##D, obj); \
|
||||
i64 i = CAST(i64, index); \
|
||||
if(i < 0 || i >= D) \
|
||||
vm->IndexError("index out of range"); \
|
||||
if(i < 0 || i >= D) vm->IndexError("index out of range"); \
|
||||
return VAR(self[i]); \
|
||||
});
|
||||
|
||||
#define BIND_SSO_VEC_COMMON(D) \
|
||||
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
|
||||
Vec##D self = _CAST(Vec##D, _0); \
|
||||
if(!vm->is_user_type<Vec##D>(_1)) \
|
||||
return vm->NotImplemented; \
|
||||
if(!vm->is_user_type<Vec##D>(_1)) return vm->NotImplemented; \
|
||||
Vec##D other = _CAST(Vec##D, _1); \
|
||||
return VAR(self == other); \
|
||||
}); \
|
||||
@ -165,12 +163,8 @@ void Vec2::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
Vec2 __to = CAST(Vec2, args[1]);
|
||||
float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x);
|
||||
const float PI = 3.1415926535897932384f;
|
||||
if(val > PI) {
|
||||
val -= 2 * PI;
|
||||
}
|
||||
if(val < -PI) {
|
||||
val += 2 * PI;
|
||||
}
|
||||
if(val > PI) { val -= 2 * PI; }
|
||||
if(val < -PI) { val += 2 * PI; }
|
||||
return VAR(val);
|
||||
},
|
||||
{},
|
||||
@ -290,14 +284,10 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
PY_STRUCT_LIKE(Mat3x3)
|
||||
|
||||
vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
|
||||
if(args.size() == 1 + 0) {
|
||||
return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros());
|
||||
}
|
||||
if(args.size() == 1 + 0) { return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros()); }
|
||||
if(args.size() == 1 + 1) {
|
||||
const List& list = CAST(List&, args[1]);
|
||||
if(list.size() != 9) {
|
||||
vm->TypeError("Mat3x3.__new__ takes a list of 9 floats");
|
||||
}
|
||||
if(list.size() != 9) { vm->TypeError("Mat3x3.__new__ takes a list of 9 floats"); }
|
||||
Mat3x3 mat;
|
||||
for(int i = 0; i < 9; i++) {
|
||||
mat.v[i] = CAST_F(list[i]);
|
||||
@ -335,28 +325,20 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, obj);
|
||||
Tuple& t = CAST(Tuple&, index);
|
||||
if(t.size() != 2) {
|
||||
vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers");
|
||||
}
|
||||
if(t.size() != 2) { vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers"); }
|
||||
i64 i = CAST(i64, t[0]);
|
||||
i64 j = CAST(i64, t[1]);
|
||||
if(i < 0 || i >= 3 || j < 0 || j >= 3) {
|
||||
vm->IndexError("index out of range");
|
||||
}
|
||||
if(i < 0 || i >= 3 || j < 0 || j >= 3) { vm->IndexError("index out of range"); }
|
||||
return VAR(self.m[i][j]);
|
||||
});
|
||||
|
||||
vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index, PyVar value) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, obj);
|
||||
const Tuple& t = CAST(Tuple&, index);
|
||||
if(t.size() != 2) {
|
||||
vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers");
|
||||
}
|
||||
if(t.size() != 2) { vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers"); }
|
||||
i64 i = CAST(i64, t[0]);
|
||||
i64 j = CAST(i64, t[1]);
|
||||
if(i < 0 || i >= 3 || j < 0 || j >= 3) {
|
||||
vm->IndexError("index out of range");
|
||||
}
|
||||
if(i < 0 || i >= 3 || j < 0 || j >= 3) { vm->IndexError("index out of range"); }
|
||||
self.m[i][j] = CAST_F(value);
|
||||
});
|
||||
|
||||
@ -438,27 +420,21 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
vm->bind__invert__(type->as<Type>(), [](VM* vm, PyVar obj) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, obj);
|
||||
Mat3x3 ret;
|
||||
if(!self.inverse(ret)) {
|
||||
vm->ValueError("matrix is not invertible");
|
||||
}
|
||||
if(!self.inverse(ret)) { vm->ValueError("matrix is not invertible"); }
|
||||
return vm->new_user_object<Mat3x3>(ret);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "inverse", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
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);
|
||||
});
|
||||
|
||||
vm->bind_func(type, "inverse_", 1, [](VM* vm, ArgsView args) {
|
||||
Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Mat3x3 ret;
|
||||
if(!self.inverse(ret)) {
|
||||
vm->ValueError("matrix is not invertible");
|
||||
}
|
||||
if(!self.inverse(ret)) { vm->ValueError("matrix is not invertible"); }
|
||||
self = ret;
|
||||
return vm->None;
|
||||
});
|
||||
@ -571,9 +547,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 v = CAST(Vec2, args[1]);
|
||||
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);
|
||||
return vm->new_user_object<Vec2>(res);
|
||||
});
|
||||
@ -589,9 +563,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
|
||||
const Mat3x3& self = _CAST(Mat3x3&, args[0]);
|
||||
Vec2 v = CAST(Vec2, args[1]);
|
||||
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);
|
||||
return vm->new_user_object<Vec2>(res);
|
||||
});
|
||||
@ -656,18 +628,14 @@ Mat3x3 Mat3x3::operator/ (float scalar) const {
|
||||
|
||||
bool Mat3x3::operator== (const Mat3x3& other) const {
|
||||
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;
|
||||
}
|
||||
|
||||
bool Mat3x3::operator!= (const Mat3x3& other) const {
|
||||
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;
|
||||
}
|
||||
@ -714,9 +682,7 @@ Mat3x3 Mat3x3::transpose() const {
|
||||
|
||||
bool Mat3x3::inverse(Mat3x3& out) const {
|
||||
float det = determinant();
|
||||
if(isclose(det, 0)) {
|
||||
return false;
|
||||
}
|
||||
if(isclose(det, 0)) { return false; }
|
||||
float inv_det = 1.0f / det;
|
||||
out._11 = (_22 * _33 - _23 * _32) * inv_det;
|
||||
out._12 = (_13 * _32 - _12 * _33) * inv_det;
|
||||
@ -738,9 +704,7 @@ Mat3x3 Mat3x3::trs(Vec2 t, float radian, Vec2 s) {
|
||||
|
||||
bool Mat3x3::is_affine() const {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -62,9 +62,7 @@ void add_module_time(VM* vm) {
|
||||
while(true) {
|
||||
auto now = std::chrono::system_clock::now();
|
||||
f64 elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - begin).count() / 1000.0;
|
||||
if(elapsed >= seconds) {
|
||||
break;
|
||||
}
|
||||
if(elapsed >= seconds) { break; }
|
||||
}
|
||||
return vm->None;
|
||||
});
|
||||
@ -143,12 +141,8 @@ void add_module_math(VM* vm) {
|
||||
vm->bind_func(mod, "gcd", 2, [](VM* vm, ArgsView args) {
|
||||
i64 a = CAST(i64, args[0]);
|
||||
i64 b = CAST(i64, args[1]);
|
||||
if(a < 0) {
|
||||
a = -a;
|
||||
}
|
||||
if(b < 0) {
|
||||
b = -b;
|
||||
}
|
||||
if(a < 0) { a = -a; }
|
||||
if(b < 0) { b = -b; }
|
||||
while(b != 0) {
|
||||
i64 t = b;
|
||||
b = a % b;
|
||||
@ -201,9 +195,7 @@ void add_module_math(VM* vm) {
|
||||
|
||||
vm->bind_func(mod, "factorial", 1, [](VM* vm, ArgsView args) {
|
||||
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;
|
||||
for(i64 i = 2; i <= n; i++) {
|
||||
r *= i;
|
||||
@ -215,18 +207,14 @@ void add_module_math(VM* vm) {
|
||||
void add_module_traceback(VM* vm) {
|
||||
PyObject* mod = vm->new_module("traceback");
|
||||
vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) {
|
||||
if(vm->__last_exception == nullptr) {
|
||||
vm->ValueError("no exception");
|
||||
}
|
||||
if(vm->__last_exception == nullptr) { vm->ValueError("no exception"); }
|
||||
Exception& e = vm->__last_exception->as<Exception>();
|
||||
vm->stdout_write(e.summary());
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
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>();
|
||||
return VAR(e.summary());
|
||||
});
|
||||
@ -243,9 +231,7 @@ void add_module_dis(VM* vm) {
|
||||
code = vm->compile(source, "<dis>", EXEC_MODE);
|
||||
}
|
||||
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;
|
||||
vm->stdout_write(vm->disassemble(code));
|
||||
return vm->None;
|
||||
@ -268,9 +254,7 @@ void add_module_enum(VM* vm) {
|
||||
for(auto [k, v]: attr.items()) {
|
||||
// wrap every attribute
|
||||
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));
|
||||
}
|
||||
};
|
||||
@ -283,12 +267,8 @@ void add_module___builtins(VM* vm) {
|
||||
|
||||
vm->bind_func(mod, "_enable_instance_dict", 1, [](VM* vm, ArgsView args) {
|
||||
PyVar self = args[0];
|
||||
if(is_tagged(self)) {
|
||||
vm->TypeError("object: tagged object cannot enable instance dict");
|
||||
}
|
||||
if(self->is_attr_valid()) {
|
||||
vm->RuntimeError("object: instance dict is already enabled");
|
||||
}
|
||||
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"); }
|
||||
self->_attr = new NameDict();
|
||||
return vm->None;
|
||||
});
|
||||
@ -347,9 +327,7 @@ struct LineProfilerW {
|
||||
};
|
||||
|
||||
_LpGuard::_LpGuard(LineProfilerW* lp, VM* vm) : lp(lp), vm(vm) {
|
||||
if(vm->_profiler) {
|
||||
vm->ValueError("only one profiler can be enabled at a time");
|
||||
}
|
||||
if(vm->_profiler) { vm->ValueError("only one profiler can be enabled at a time"); }
|
||||
vm->_profiler = &lp->profiler;
|
||||
lp->profiler.begin();
|
||||
}
|
||||
|
||||
@ -142,9 +142,7 @@ struct Random {
|
||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||
i64 a = CAST(i64, args[1]);
|
||||
i64 b = CAST(i64, args[2]);
|
||||
if(a > b) {
|
||||
vm->ValueError("randint(a, b): a must be less than or equal to b");
|
||||
}
|
||||
if(a > b) { vm->ValueError("randint(a, b): a must be less than or equal to b"); }
|
||||
return VAR(self.gen.randint(a, b));
|
||||
});
|
||||
|
||||
@ -157,9 +155,7 @@ struct Random {
|
||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||
f64 a = CAST(f64, args[1]);
|
||||
f64 b = CAST(f64, args[2]);
|
||||
if(a > b) {
|
||||
std::swap(a, b);
|
||||
}
|
||||
if(a > b) { std::swap(a, b); }
|
||||
return VAR(self.gen.uniform(a, b));
|
||||
});
|
||||
|
||||
@ -176,9 +172,7 @@ struct Random {
|
||||
vm->bind_func(type, "choice", 2, [](VM* vm, ArgsView args) {
|
||||
Random& self = PK_OBJ_GET(Random, args[0]);
|
||||
ArgsView view = vm->cast_array_view(args[1]);
|
||||
if(view.empty()) {
|
||||
vm->IndexError("cannot choose from an empty sequence");
|
||||
}
|
||||
if(view.empty()) { vm->IndexError("cannot choose from an empty sequence"); }
|
||||
int index = self.gen.randint(0, view.size() - 1);
|
||||
return view[index];
|
||||
});
|
||||
@ -188,9 +182,7 @@ struct Random {
|
||||
ArgsView view = vm->cast_array_view(args[1]);
|
||||
PyVar* data = view.begin();
|
||||
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);
|
||||
if(args[2] == vm->None) {
|
||||
for(int i = 0; i < size; i++) {
|
||||
@ -198,17 +190,13 @@ struct Random {
|
||||
}
|
||||
} else {
|
||||
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]);
|
||||
for(int i = 1; i < size; i++) {
|
||||
cum_weights[i] = cum_weights[i - 1] + CAST(f64, weights[i]);
|
||||
}
|
||||
}
|
||||
if(cum_weights[size - 1] <= 0) {
|
||||
vm->ValueError("total of weights must be greater than zero");
|
||||
}
|
||||
if(cum_weights[size - 1] <= 0) { vm->ValueError("total of weights must be greater than zero"); }
|
||||
int k = CAST(int, args[3]);
|
||||
List result(k);
|
||||
for(int i = 0; i < k; i++) {
|
||||
|
||||
@ -43,9 +43,7 @@ Dict::Dict(const Dict& other) {
|
||||
|
||||
void Dict::set(VM* vm, PyVar key, PyVar val) {
|
||||
// do possible rehash
|
||||
if(_size + 1 > _critical_size) {
|
||||
_rehash(vm);
|
||||
}
|
||||
if(_size + 1 > _critical_size) { _rehash(vm); }
|
||||
bool ok;
|
||||
int i;
|
||||
_probe_1(vm, key, ok, i);
|
||||
@ -93,9 +91,7 @@ PyVar Dict::try_get(VM* vm, PyVar key) const {
|
||||
bool ok;
|
||||
int i;
|
||||
_probe_0(vm, key, ok, i);
|
||||
if(!ok) {
|
||||
return nullptr;
|
||||
}
|
||||
if(!ok) { return nullptr; }
|
||||
return _items[i].second;
|
||||
}
|
||||
|
||||
@ -110,9 +106,7 @@ bool Dict::del(VM* vm, PyVar key) {
|
||||
bool ok;
|
||||
int i;
|
||||
_probe_0(vm, key, ok, i);
|
||||
if(!ok) {
|
||||
return false;
|
||||
}
|
||||
if(!ok) { return false; }
|
||||
_items[i].first = nullptr;
|
||||
// _items[i].second = PY_DELETED_SLOT; // do not change .second if it is not NULL, it means the slot is occupied by
|
||||
// a deleted item
|
||||
@ -179,8 +173,6 @@ void Dict::clear() {
|
||||
}
|
||||
|
||||
Dict::~Dict() {
|
||||
if(_items) {
|
||||
std::free(_items);
|
||||
}
|
||||
if(_items) { std::free(_items); }
|
||||
}
|
||||
} // namespace pkpy
|
||||
|
||||
@ -3,9 +3,7 @@
|
||||
namespace pkpy {
|
||||
Str Exception::summary() const {
|
||||
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()) {
|
||||
// ss << st.top().snapshot() << '\n';
|
||||
// st.pop();
|
||||
|
||||
@ -5,15 +5,11 @@ SourceData::SourceData(std::string_view source, const Str& filename, CompileMode
|
||||
filename(filename), mode(mode) {
|
||||
int index = 0;
|
||||
// Skip utf8 BOM if there is any.
|
||||
if(strncmp(source.data(), "\xEF\xBB\xBF", 3) == 0) {
|
||||
index += 3;
|
||||
}
|
||||
if(strncmp(source.data(), "\xEF\xBB\xBF", 3) == 0) { index += 3; }
|
||||
// Drop all '\r'
|
||||
SStream ss(source.size() + 1);
|
||||
while(index < source.size()) {
|
||||
if(source[index] != '\r') {
|
||||
ss << source[index];
|
||||
}
|
||||
if(source[index] != '\r') { ss << source[index]; }
|
||||
index++;
|
||||
}
|
||||
this->source = ss.str();
|
||||
@ -30,13 +26,9 @@ SourceData::SourceData(const Str& filename, CompileMode mode) : filename(filenam
|
||||
}
|
||||
|
||||
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;
|
||||
if(lineno < 0) {
|
||||
lineno = 0;
|
||||
}
|
||||
if(lineno < 0) { lineno = 0; }
|
||||
const char* _start = line_starts[lineno];
|
||||
const char* i = _start;
|
||||
// max 300 chars
|
||||
@ -48,18 +40,14 @@ std::pair<const char*, const char*> SourceData::_get_line(int lineno) const {
|
||||
|
||||
std::string_view SourceData::get_line(int lineno) const {
|
||||
auto [_0, _1] = _get_line(lineno);
|
||||
if(_0 && _1) {
|
||||
return std::string_view(_0, _1 - _0);
|
||||
}
|
||||
if(_0 && _1) { return std::string_view(_0, _1 - _0); }
|
||||
return "<?>";
|
||||
}
|
||||
|
||||
Str SourceData::snapshot(int lineno, const char* cursor, std::string_view name) const {
|
||||
SStream ss;
|
||||
ss << " " << "File \"" << filename << "\", line " << lineno;
|
||||
if(!name.empty()) {
|
||||
ss << ", in " << name;
|
||||
}
|
||||
if(!name.empty()) { ss << ", in " << name; }
|
||||
if(!is_precompiled) {
|
||||
ss << '\n';
|
||||
std::pair<const char*, const char*> pair = _get_line(lineno);
|
||||
@ -68,16 +56,12 @@ Str SourceData::snapshot(int lineno, const char* cursor, std::string_view name)
|
||||
if(pair.first && pair.second) {
|
||||
line = Str(pair.first, pair.second - pair.first).lstrip();
|
||||
removed_spaces = pair.second - pair.first - line.length();
|
||||
if(line.empty()) {
|
||||
line = "<?>";
|
||||
}
|
||||
if(line.empty()) { line = "<?>"; }
|
||||
}
|
||||
ss << " " << line;
|
||||
if(cursor && line != "<?>" && cursor >= pair.first && cursor <= pair.second) {
|
||||
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();
|
||||
|
||||
@ -37,9 +37,7 @@ Tuple::Tuple(PyVar _0, PyVar _1, PyVar _2) : Tuple(3) {
|
||||
}
|
||||
|
||||
Tuple::~Tuple() {
|
||||
if(!is_inlined()) {
|
||||
std::free(_args);
|
||||
}
|
||||
if(!is_inlined()) { std::free(_args); }
|
||||
}
|
||||
|
||||
List ArgsView::to_list() const {
|
||||
|
||||
461
src/pocketpy.cpp
461
src/pocketpy.cpp
@ -49,17 +49,13 @@ PyVar PyArrayGetItem(VM* vm, PyVar _0, PyVar _1) {
|
||||
void __init_builtins(VM* _vm) {
|
||||
#define BIND_NUM_ARITH_OPT(name, op) \
|
||||
_vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { \
|
||||
if(is_int(rhs)) \
|
||||
return VAR(_CAST(i64, lhs) op _CAST(i64, rhs)); \
|
||||
if(is_float(rhs)) \
|
||||
return VAR(_CAST(i64, lhs) op _CAST(f64, rhs)); \
|
||||
if(is_int(rhs)) return VAR(_CAST(i64, lhs) op _CAST(i64, rhs)); \
|
||||
if(is_float(rhs)) return VAR(_CAST(i64, lhs) op _CAST(f64, rhs)); \
|
||||
return vm->NotImplemented; \
|
||||
}); \
|
||||
_vm->bind##name(VM::tp_float, [](VM* vm, PyVar lhs, PyVar rhs) { \
|
||||
if(is_int(rhs)) \
|
||||
return VAR(_CAST(f64, lhs) op _CAST(i64, rhs)); \
|
||||
if(is_float(rhs)) \
|
||||
return VAR(_CAST(f64, lhs) op _CAST(f64, rhs)); \
|
||||
if(is_int(rhs)) return VAR(_CAST(f64, lhs) op _CAST(i64, rhs)); \
|
||||
if(is_float(rhs)) return VAR(_CAST(f64, lhs) op _CAST(f64, rhs)); \
|
||||
return vm->NotImplemented; \
|
||||
});
|
||||
|
||||
@ -71,17 +67,13 @@ void __init_builtins(VM* _vm) {
|
||||
|
||||
#define BIND_NUM_LOGICAL_OPT(name, op) \
|
||||
_vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { \
|
||||
if(is_int(rhs)) \
|
||||
return VAR(_CAST(i64, lhs) op _CAST(i64, rhs)); \
|
||||
if(is_float(rhs)) \
|
||||
return VAR(_CAST(i64, lhs) op _CAST(f64, rhs)); \
|
||||
if(is_int(rhs)) return VAR(_CAST(i64, lhs) op _CAST(i64, rhs)); \
|
||||
if(is_float(rhs)) return VAR(_CAST(i64, lhs) op _CAST(f64, rhs)); \
|
||||
return vm->NotImplemented; \
|
||||
}); \
|
||||
_vm->bind##name(VM::tp_float, [](VM* vm, PyVar lhs, PyVar rhs) { \
|
||||
if(is_int(rhs)) \
|
||||
return VAR(_CAST(f64, lhs) op _CAST(i64, rhs)); \
|
||||
if(is_float(rhs)) \
|
||||
return VAR(_CAST(f64, lhs) op _CAST(f64, rhs)); \
|
||||
if(is_int(rhs)) return VAR(_CAST(f64, lhs) op _CAST(i64, rhs)); \
|
||||
if(is_float(rhs)) return VAR(_CAST(f64, lhs) op _CAST(f64, rhs)); \
|
||||
return vm->NotImplemented; \
|
||||
});
|
||||
|
||||
@ -112,9 +104,7 @@ void __init_builtins(VM* _vm) {
|
||||
Frame* frame = &vm->callstack.top();
|
||||
if(frame->_callable != nullptr) {
|
||||
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) {
|
||||
vm->TypeError("super(): unable to determine the class context, use super(class, self) instead");
|
||||
@ -149,9 +139,7 @@ void __init_builtins(VM* _vm) {
|
||||
Tuple& types = _CAST(Tuple&, args[1]);
|
||||
for(PyVar type: types) {
|
||||
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;
|
||||
}
|
||||
@ -172,29 +160,19 @@ void __init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_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 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]);
|
||||
if(ndigits < 0) {
|
||||
vm->ValueError("ndigits should be non-negative");
|
||||
}
|
||||
if(ndigits < 0) { vm->ValueError("ndigits should be non-negative"); }
|
||||
// ndigits > 0
|
||||
return VAR((i64)(x * std::pow(10, ndigits) + offset) / std::pow(10, ndigits));
|
||||
});
|
||||
|
||||
_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_float(args[0])) {
|
||||
return VAR(std::abs(_CAST(f64, 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]))); }
|
||||
vm->TypeError("bad operand type for abs()");
|
||||
return vm->None;
|
||||
});
|
||||
@ -209,9 +187,7 @@ void __init_builtins(VM* _vm) {
|
||||
|
||||
_vm->bind_func(_vm->builtins, "id", 1, [](VM* vm, ArgsView args) {
|
||||
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()));
|
||||
});
|
||||
|
||||
@ -226,9 +202,7 @@ void __init_builtins(VM* _vm) {
|
||||
if(is_int(args[0])) {
|
||||
i64 lhs = _CAST(i64, args[0]);
|
||||
i64 rhs = CAST(i64, args[1]);
|
||||
if(rhs == 0) {
|
||||
vm->ZeroDivisionError();
|
||||
}
|
||||
if(rhs == 0) { vm->ZeroDivisionError(); }
|
||||
auto res = std::div(lhs, rhs);
|
||||
return VAR(Tuple(VAR(res.quot), VAR(res.rem)));
|
||||
} else {
|
||||
@ -271,9 +245,7 @@ void __init_builtins(VM* _vm) {
|
||||
|
||||
_vm->bind_func(_vm->builtins, "len", 1, [](VM* vm, ArgsView args) {
|
||||
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__);
|
||||
});
|
||||
|
||||
@ -284,17 +256,13 @@ void __init_builtins(VM* _vm) {
|
||||
|
||||
_vm->bind_func(_vm->builtins, "chr", 1, [](VM* vm, ArgsView args) {
|
||||
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));
|
||||
});
|
||||
|
||||
_vm->bind_func(_vm->builtins, "ord", 1, [](VM* vm, ArgsView args) {
|
||||
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]));
|
||||
});
|
||||
|
||||
@ -308,15 +276,11 @@ void __init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_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]);
|
||||
PyVar val = vm->getattr(args[0], name, false);
|
||||
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 val;
|
||||
@ -337,9 +301,7 @@ void __init_builtins(VM* _vm) {
|
||||
|
||||
_vm->bind_func(_vm->builtins, "next", 1, [](VM* vm, ArgsView args) {
|
||||
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;
|
||||
});
|
||||
|
||||
@ -357,9 +319,7 @@ void __init_builtins(VM* _vm) {
|
||||
x >>= 1;
|
||||
}
|
||||
std::reverse(bits.begin(), bits.end());
|
||||
if(bits.empty()) {
|
||||
bits = "0";
|
||||
}
|
||||
if(bits.empty()) { bits = "0"; }
|
||||
ss << bits;
|
||||
return VAR(ss.str());
|
||||
});
|
||||
@ -377,9 +337,7 @@ void __init_builtins(VM* _vm) {
|
||||
List ret;
|
||||
for(int i = 0; i < names.size(); i++) {
|
||||
// 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()));
|
||||
}
|
||||
return VAR(std::move(ret));
|
||||
@ -423,9 +381,7 @@ void __init_builtins(VM* _vm) {
|
||||
break;
|
||||
default: vm->TypeError("expected 1-3 arguments, got " + std::to_string(args.size()));
|
||||
}
|
||||
if(r.step == 0) {
|
||||
vm->ValueError("range() arg 3 must not be zero");
|
||||
}
|
||||
if(r.step == 0) { vm->ValueError("range() arg 3 must not be zero"); }
|
||||
return VAR(r);
|
||||
});
|
||||
|
||||
@ -464,16 +420,12 @@ void __init_builtins(VM* _vm) {
|
||||
i64 lhs = _CAST(i64, _0);
|
||||
i64 rhs = _CAST(i64, _1);
|
||||
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));
|
||||
}
|
||||
i64 ret = 1;
|
||||
while(rhs) {
|
||||
if(rhs & 1) {
|
||||
ret *= lhs;
|
||||
}
|
||||
if(rhs & 1) { ret *= lhs; }
|
||||
lhs *= lhs;
|
||||
rhs >>= 1;
|
||||
}
|
||||
@ -487,9 +439,7 @@ void __init_builtins(VM* _vm) {
|
||||
_vm->bind__pow__(VM::tp_float, py_number_pow);
|
||||
|
||||
_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
|
||||
if(args.size() == 1 + 1) {
|
||||
switch(vm->_tp(args[1])) {
|
||||
@ -501,14 +451,10 @@ void __init_builtins(VM* _vm) {
|
||||
}
|
||||
}
|
||||
// 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
|
||||
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]);
|
||||
std::string_view sv = s.sv();
|
||||
bool negative = false;
|
||||
@ -520,33 +466,25 @@ void __init_builtins(VM* _vm) {
|
||||
if(parse_uint(sv, &val, base) != IntParsingResult::Success) {
|
||||
vm->ValueError(_S("invalid literal for int() with base ", base, ": ", s.escape()));
|
||||
}
|
||||
if(negative) {
|
||||
val = -val;
|
||||
}
|
||||
if(negative) { val = -val; }
|
||||
return VAR(val);
|
||||
});
|
||||
|
||||
_vm->bind__floordiv__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
i64 rhs = CAST(i64, _1);
|
||||
if(rhs == 0) {
|
||||
vm->ZeroDivisionError();
|
||||
}
|
||||
if(rhs == 0) { vm->ZeroDivisionError(); }
|
||||
return VAR(_CAST(i64, _0) / rhs);
|
||||
});
|
||||
|
||||
_vm->bind__mod__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
i64 rhs = CAST(i64, _1);
|
||||
if(rhs == 0) {
|
||||
vm->ZeroDivisionError();
|
||||
}
|
||||
if(rhs == 0) { vm->ZeroDivisionError(); }
|
||||
return VAR(_CAST(i64, _0) % rhs);
|
||||
});
|
||||
|
||||
_vm->bind_func(VM::tp_int, "bit_length", 1, [](VM* vm, ArgsView args) {
|
||||
i64 x = _CAST(i64, args[0]);
|
||||
if(x < 0) {
|
||||
x = -x;
|
||||
}
|
||||
if(x < 0) { x = -x; }
|
||||
int bits = 0;
|
||||
while(x) {
|
||||
x >>= 1;
|
||||
@ -572,12 +510,8 @@ void __init_builtins(VM* _vm) {
|
||||
#undef INT_BITWISE_OP
|
||||
|
||||
_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 + 1) {
|
||||
vm->TypeError("float() takes at most 1 argument");
|
||||
}
|
||||
if(args.size() == 1 + 0) { return VAR(0.0); }
|
||||
if(args.size() > 1 + 1) { vm->TypeError("float() takes at most 1 argument"); }
|
||||
// 1 arg
|
||||
switch(vm->_tp(args[1])) {
|
||||
case VM::tp_int: return VAR((f64)CAST(i64, args[1]));
|
||||
@ -588,20 +522,14 @@ void __init_builtins(VM* _vm) {
|
||||
}
|
||||
// str to float
|
||||
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;
|
||||
char* p_end;
|
||||
try {
|
||||
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()); }
|
||||
return VAR(float_out);
|
||||
});
|
||||
@ -622,12 +550,8 @@ void __init_builtins(VM* _vm) {
|
||||
|
||||
// tp_str
|
||||
_vm->bind_func(VM::tp_str, __new__, -1, [](VM* vm, ArgsView args) {
|
||||
if(args.size() == 1) {
|
||||
return VAR(Str());
|
||||
}
|
||||
if(args.size() > 2) {
|
||||
vm->TypeError("str() takes at most 1 argument");
|
||||
}
|
||||
if(args.size() == 1) { return VAR(Str()); }
|
||||
if(args.size() > 2) { vm->TypeError("str() takes at most 1 argument"); }
|
||||
return VAR(vm->py_str(args[1]));
|
||||
});
|
||||
|
||||
@ -667,8 +591,7 @@ void __init_builtins(VM* _vm) {
|
||||
|
||||
#define BIND_CMP_STR(name, op) \
|
||||
_vm->bind##name(VM::tp_str, [](VM* vm, PyVar lhs, PyVar rhs) { \
|
||||
if(!is_type(rhs, vm->tp_str)) \
|
||||
return vm->NotImplemented; \
|
||||
if(!is_type(rhs, vm->tp_str)) return vm->NotImplemented; \
|
||||
return VAR(_CAST(Str&, lhs) op _CAST(Str&, rhs)); \
|
||||
});
|
||||
|
||||
@ -695,9 +618,7 @@ void __init_builtins(VM* _vm) {
|
||||
_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& 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]);
|
||||
int count = CAST(int, args[3]);
|
||||
return VAR(self.replace(old, new_, count));
|
||||
@ -706,9 +627,7 @@ void __init_builtins(VM* _vm) {
|
||||
_vm->bind(_vm->_t(VM::tp_str), "split(self, sep=' ')", [](VM* vm, ArgsView args) {
|
||||
const Str& self = _CAST(Str&, args[0]);
|
||||
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;
|
||||
if(sep.size == 1) {
|
||||
parts = self.split(sep[0]);
|
||||
@ -742,13 +661,9 @@ void __init_builtins(VM* _vm) {
|
||||
const Str& self = _CAST(Str&, args[0]);
|
||||
const Str& value = CAST(Str&, args[1]);
|
||||
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);
|
||||
if(index < 0) {
|
||||
vm->ValueError("substring not found");
|
||||
}
|
||||
if(index < 0) { vm->ValueError("substring not found"); }
|
||||
return VAR(index);
|
||||
});
|
||||
|
||||
@ -756,9 +671,7 @@ void __init_builtins(VM* _vm) {
|
||||
const Str& self = _CAST(Str&, args[0]);
|
||||
const Str& value = CAST(Str&, args[1]);
|
||||
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));
|
||||
});
|
||||
|
||||
@ -772,9 +685,7 @@ void __init_builtins(VM* _vm) {
|
||||
const Str& self = _CAST(Str&, args[0]);
|
||||
const Str& suffix = CAST(Str&, args[1]);
|
||||
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;
|
||||
return VAR(ok);
|
||||
});
|
||||
@ -794,9 +705,7 @@ void __init_builtins(VM* _vm) {
|
||||
const PyTypeInfo* info = vm->_tp_info(args[1]);
|
||||
PyVar obj = vm->_py_next(info, it);
|
||||
while(obj != vm->StopIteration) {
|
||||
if(!ss.empty()) {
|
||||
ss << self;
|
||||
}
|
||||
if(!ss.empty()) { ss << self; }
|
||||
ss << CAST(Str&, obj);
|
||||
obj = vm->_py_next(info, it);
|
||||
}
|
||||
@ -848,9 +757,7 @@ void __init_builtins(VM* _vm) {
|
||||
const Str& self = _CAST(Str&, args[0]);
|
||||
int width = CAST(int, args[1]);
|
||||
int delta = width - self.u8_length();
|
||||
if(delta <= 0) {
|
||||
return args[0];
|
||||
}
|
||||
if(delta <= 0) { return args[0]; }
|
||||
SStream ss;
|
||||
for(int i = 0; i < delta; i++) {
|
||||
ss << '0';
|
||||
@ -864,13 +771,9 @@ void __init_builtins(VM* _vm) {
|
||||
const Str& self = _CAST(Str&, args[0]);
|
||||
int width = CAST(int, args[1]);
|
||||
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]);
|
||||
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;
|
||||
ss << self;
|
||||
for(int i = 0; i < delta; i++) {
|
||||
@ -884,13 +787,9 @@ void __init_builtins(VM* _vm) {
|
||||
const Str& self = _CAST(Str&, args[0]);
|
||||
int width = CAST(int, args[1]);
|
||||
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]);
|
||||
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;
|
||||
for(int i = 0; i < delta; i++) {
|
||||
ss << fillchar;
|
||||
@ -911,25 +810,19 @@ void __init_builtins(VM* _vm) {
|
||||
});
|
||||
}
|
||||
bool reverse = CAST(bool, args[2]);
|
||||
if(reverse) {
|
||||
std::reverse(self.begin(), self.end());
|
||||
}
|
||||
if(reverse) { std::reverse(self.begin(), self.end()); }
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
_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);
|
||||
SStream ss;
|
||||
ss << '[';
|
||||
vm->_repr_recursion_set.push_back(_0);
|
||||
for(int i = 0; i < iterable.size(); 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();
|
||||
ss << ']';
|
||||
@ -946,9 +839,7 @@ void __init_builtins(VM* _vm) {
|
||||
} else {
|
||||
for(int i = 0; i < iterable.size(); i++) {
|
||||
ss << vm->py_repr(iterable[i]);
|
||||
if(i != iterable.size() - 1) {
|
||||
ss << ", ";
|
||||
}
|
||||
if(i != iterable.size() - 1) { ss << ", "; }
|
||||
}
|
||||
}
|
||||
ss << ')';
|
||||
@ -956,12 +847,8 @@ void __init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_vm->bind_func(VM::tp_list, __new__, -1, [](VM* vm, ArgsView args) {
|
||||
if(args.size() == 1 + 0) {
|
||||
return VAR(List());
|
||||
}
|
||||
if(args.size() == 1 + 1) {
|
||||
return VAR(vm->py_list(args[1]));
|
||||
}
|
||||
if(args.size() == 1 + 0) { return VAR(List()); }
|
||||
if(args.size() == 1 + 1) { return VAR(vm->py_list(args[1])); }
|
||||
vm->TypeError("list() takes 0 or 1 arguments");
|
||||
return vm->None;
|
||||
});
|
||||
@ -969,9 +856,7 @@ void __init_builtins(VM* _vm) {
|
||||
_vm->bind__contains__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
List& self = _CAST(List&, _0);
|
||||
for(PyVar i: self) {
|
||||
if(vm->py_eq(i, _1)) {
|
||||
return vm->True;
|
||||
}
|
||||
if(vm->py_eq(i, _1)) { return vm->True; }
|
||||
}
|
||||
return vm->False;
|
||||
});
|
||||
@ -980,26 +865,18 @@ void __init_builtins(VM* _vm) {
|
||||
List& self = _CAST(List&, args[0]);
|
||||
int count = 0;
|
||||
for(PyVar i: self) {
|
||||
if(vm->py_eq(i, args[1])) {
|
||||
count++;
|
||||
}
|
||||
if(vm->py_eq(i, args[1])) { count++; }
|
||||
}
|
||||
return VAR(count);
|
||||
});
|
||||
|
||||
_vm->bind__eq__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
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);
|
||||
if(a.size() != b.size()) {
|
||||
return vm->False;
|
||||
}
|
||||
if(a.size() != b.size()) { return vm->False; }
|
||||
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;
|
||||
});
|
||||
@ -1009,9 +886,7 @@ void __init_builtins(VM* _vm) {
|
||||
PyVar obj = args[1];
|
||||
int start = CAST(int, args[2]);
|
||||
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");
|
||||
return vm->None;
|
||||
@ -1033,9 +908,7 @@ void __init_builtins(VM* _vm) {
|
||||
_vm->bind_func(VM::tp_list, "pop", -1, [](VM* vm, ArgsView args) {
|
||||
List& self = _CAST(List&, args[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();
|
||||
self.pop_back();
|
||||
return retval;
|
||||
@ -1078,9 +951,7 @@ void __init_builtins(VM* _vm) {
|
||||
|
||||
_vm->bind__mul__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
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);
|
||||
List result;
|
||||
result.reserve(self.size() * n);
|
||||
@ -1091,9 +962,7 @@ void __init_builtins(VM* _vm) {
|
||||
});
|
||||
_vm->bind_func(VM::tp_list, "__rmul__", 2, [](VM* vm, ArgsView args) {
|
||||
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]);
|
||||
List result;
|
||||
result.reserve(self.size() * n);
|
||||
@ -1106,15 +975,9 @@ void __init_builtins(VM* _vm) {
|
||||
_vm->bind_func(VM::tp_list, "insert", 3, [](VM* vm, ArgsView args) {
|
||||
List& self = _CAST(List&, args[0]);
|
||||
int index = CAST(int, args[1]);
|
||||
if(index < 0) {
|
||||
index += self.size();
|
||||
}
|
||||
if(index < 0) {
|
||||
index = 0;
|
||||
}
|
||||
if(index > self.size()) {
|
||||
index = self.size();
|
||||
}
|
||||
if(index < 0) { index += self.size(); }
|
||||
if(index < 0) { index = 0; }
|
||||
if(index > self.size()) { index = self.size(); }
|
||||
self.insert(index, args[2]);
|
||||
return vm->None;
|
||||
});
|
||||
@ -1131,13 +994,11 @@ void __init_builtins(VM* _vm) {
|
||||
|
||||
#define BIND_RICH_CMP(name, op, _t, _T) \
|
||||
_vm->bind__##name##__(_vm->_t, [](VM* vm, PyVar lhs, PyVar rhs) { \
|
||||
if(!is_type(rhs, vm->_t)) \
|
||||
return vm->NotImplemented; \
|
||||
if(!is_type(rhs, vm->_t)) return vm->NotImplemented; \
|
||||
auto& a = _CAST(_T&, lhs); \
|
||||
auto& b = _CAST(_T&, rhs); \
|
||||
for(int i = 0; i < a.size() && i < b.size(); i++) { \
|
||||
if(vm->py_eq(a[i], b[i])) \
|
||||
continue; \
|
||||
if(vm->py_eq(a[i], b[i])) continue; \
|
||||
return VAR(vm->py_##name(a[i], b[i])); \
|
||||
} \
|
||||
return VAR(a.size() op b.size()); \
|
||||
@ -1188,9 +1049,7 @@ void __init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_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) {
|
||||
List list = vm->py_list(args[1]);
|
||||
return VAR(list.to_tuple());
|
||||
@ -1202,9 +1061,7 @@ void __init_builtins(VM* _vm) {
|
||||
_vm->bind__contains__(VM::tp_tuple, [](VM* vm, PyVar obj, PyVar item) {
|
||||
Tuple& self = _CAST(Tuple&, obj);
|
||||
for(PyVar i: self) {
|
||||
if(vm->py_eq(i, item)) {
|
||||
return vm->True;
|
||||
}
|
||||
if(vm->py_eq(i, item)) { return vm->True; }
|
||||
}
|
||||
return vm->False;
|
||||
});
|
||||
@ -1213,26 +1070,18 @@ void __init_builtins(VM* _vm) {
|
||||
Tuple& self = _CAST(Tuple&, args[0]);
|
||||
int count = 0;
|
||||
for(PyVar i: self) {
|
||||
if(vm->py_eq(i, args[1])) {
|
||||
count++;
|
||||
}
|
||||
if(vm->py_eq(i, args[1])) { count++; }
|
||||
}
|
||||
return VAR(count);
|
||||
});
|
||||
|
||||
_vm->bind__eq__(VM::tp_tuple, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
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);
|
||||
if(self.size() != other.size()) {
|
||||
return vm->False;
|
||||
}
|
||||
if(self.size() != other.size()) { return vm->False; }
|
||||
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;
|
||||
});
|
||||
@ -1271,12 +1120,8 @@ void __init_builtins(VM* _vm) {
|
||||
_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) {
|
||||
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_type(_1, vm->tp_bool)) { return VAR(_0 == _1); }
|
||||
if(is_int(_1)) { return VAR(_CAST(bool, _0) == (bool)CAST(i64, _1)); }
|
||||
return vm->NotImplemented;
|
||||
});
|
||||
|
||||
@ -1290,9 +1135,7 @@ void __init_builtins(VM* _vm) {
|
||||
Bytes retval(list.size());
|
||||
for(int i = 0; i < list.size(); 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;
|
||||
}
|
||||
return VAR(std::move(retval));
|
||||
@ -1305,9 +1148,7 @@ void __init_builtins(VM* _vm) {
|
||||
int start, stop, step;
|
||||
vm->parse_int_slice(s, self.size(), start, stop, step);
|
||||
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);
|
||||
int j = 0; // actual size
|
||||
PK_SLICE_LOOP(i, start, stop, step) buffer[j++] = self[i];
|
||||
@ -1352,14 +1193,10 @@ void __init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_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& 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);
|
||||
});
|
||||
|
||||
@ -1370,19 +1207,11 @@ void __init_builtins(VM* _vm) {
|
||||
|
||||
_vm->bind__eq__(VM::tp_slice, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
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);
|
||||
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.step, other.step)) {
|
||||
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.step, other.step)) { return vm->False; }
|
||||
return vm->True;
|
||||
});
|
||||
|
||||
@ -1429,9 +1258,7 @@ void __init_builtins(VM* _vm) {
|
||||
|
||||
_vm->bind__eq__(VM::tp_mappingproxy, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
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);
|
||||
return VAR(a.obj == b.obj);
|
||||
});
|
||||
@ -1440,9 +1267,7 @@ void __init_builtins(VM* _vm) {
|
||||
MappingProxy& self = _CAST(MappingProxy&, _0);
|
||||
StrName key = CAST(Str&, _1);
|
||||
PyVar ret = self.attr().try_get_likely_found(key);
|
||||
if(ret == nullptr) {
|
||||
vm->KeyError(_1);
|
||||
}
|
||||
if(ret == nullptr) { vm->KeyError(_1); }
|
||||
return ret;
|
||||
});
|
||||
|
||||
@ -1450,25 +1275,19 @@ void __init_builtins(VM* _vm) {
|
||||
MappingProxy& self = _CAST(MappingProxy&, args[0]);
|
||||
StrName key = CAST(Str&, args[1]);
|
||||
PyVar ret = self.attr().try_get(key);
|
||||
if(ret == nullptr) {
|
||||
return args[2];
|
||||
}
|
||||
if(ret == nullptr) { return args[2]; }
|
||||
return ret;
|
||||
});
|
||||
|
||||
_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);
|
||||
SStream ss;
|
||||
ss << "mappingproxy({";
|
||||
bool first = true;
|
||||
vm->_repr_recursion_set.push_back(_0);
|
||||
for(auto [k, v]: self.attr().items()) {
|
||||
if(!first) {
|
||||
ss << ", ";
|
||||
}
|
||||
if(!first) { ss << ", "; }
|
||||
first = false;
|
||||
ss << k.escape() << ": ";
|
||||
ss << vm->py_repr(v);
|
||||
@ -1490,9 +1309,7 @@ void __init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_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) {
|
||||
auto _lock = vm->heap.gc_scope_lock();
|
||||
Dict& self = PK_OBJ_GET(Dict, args[0]);
|
||||
@ -1527,9 +1344,7 @@ void __init_builtins(VM* _vm) {
|
||||
// try __missing__
|
||||
PyVar self;
|
||||
PyVar f_missing = vm->get_unbound_method(_0, __missing__, &self, false);
|
||||
if(f_missing != nullptr) {
|
||||
return vm->call_method(self, f_missing, _1);
|
||||
}
|
||||
if(f_missing != nullptr) { return vm->call_method(self, f_missing, _1); }
|
||||
vm->KeyError(_1);
|
||||
}
|
||||
return ret;
|
||||
@ -1543,9 +1358,7 @@ void __init_builtins(VM* _vm) {
|
||||
_vm->bind__delitem__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
Dict& self = _CAST(Dict&, _0);
|
||||
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) {
|
||||
@ -1556,12 +1369,8 @@ void __init_builtins(VM* _vm) {
|
||||
Dict& self = _CAST(Dict&, args[0]);
|
||||
PyVar value = self.try_get(vm, args[1]);
|
||||
if(value == nullptr) {
|
||||
if(args.size() == 2) {
|
||||
vm->KeyError(args[1]);
|
||||
}
|
||||
if(args.size() == 3) {
|
||||
return args[2];
|
||||
}
|
||||
if(args.size() == 2) { vm->KeyError(args[1]); }
|
||||
if(args.size() == 3) { return args[2]; }
|
||||
}
|
||||
self.del(vm, args[1]);
|
||||
return value;
|
||||
@ -1581,15 +1390,11 @@ void __init_builtins(VM* _vm) {
|
||||
Dict& self = _CAST(Dict&, args[0]);
|
||||
if(args.size() == 1 + 1) {
|
||||
PyVar ret = self.try_get(vm, args[1]);
|
||||
if(ret != nullptr) {
|
||||
return ret;
|
||||
}
|
||||
if(ret != nullptr) { return ret; }
|
||||
return vm->None;
|
||||
} else if(args.size() == 1 + 2) {
|
||||
PyVar ret = self.try_get(vm, args[1]);
|
||||
if(ret != nullptr) {
|
||||
return ret;
|
||||
}
|
||||
if(ret != nullptr) { return ret; }
|
||||
return args[2];
|
||||
}
|
||||
vm->TypeError("get() takes at most 2 arguments");
|
||||
@ -1629,18 +1434,14 @@ void __init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_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);
|
||||
SStream ss;
|
||||
ss << "{";
|
||||
bool first = true;
|
||||
vm->_repr_recursion_set.push_back(_0);
|
||||
self.apply([&](PyVar k, PyVar v) {
|
||||
if(!first) {
|
||||
ss << ", ";
|
||||
}
|
||||
if(!first) { ss << ", "; }
|
||||
first = false;
|
||||
ss << vm->py_repr(k) << ": " << vm->py_repr(v);
|
||||
});
|
||||
@ -1651,25 +1452,15 @@ void __init_builtins(VM* _vm) {
|
||||
|
||||
_vm->bind__eq__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
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);
|
||||
if(self.size() != other.size()) {
|
||||
return vm->False;
|
||||
}
|
||||
if(self.size() != other.size()) { return vm->False; }
|
||||
for(int i = 0; i < self._capacity; i++) {
|
||||
auto item = self._items[i];
|
||||
if(item.first == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if(item.first == nullptr) { continue; }
|
||||
PyVar value = other.try_get(vm, item.first);
|
||||
if(value == nullptr) {
|
||||
return vm->False;
|
||||
}
|
||||
if(!vm->py_eq(item.second, value)) {
|
||||
return vm->False;
|
||||
}
|
||||
if(value == nullptr) { return vm->False; }
|
||||
if(!vm->py_eq(item.second, value)) { return vm->False; }
|
||||
}
|
||||
return vm->True;
|
||||
});
|
||||
@ -1692,20 +1483,14 @@ void __init_builtins(VM* _vm) {
|
||||
|
||||
_vm->bind_property(_vm->_t(VM::tp_function), "__doc__", [](VM* vm, ArgsView args) {
|
||||
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);
|
||||
});
|
||||
|
||||
_vm->bind_property(_vm->_t(VM::tp_native_func), "__doc__", [](VM* vm, ArgsView args) {
|
||||
NativeFunc& func = _CAST(NativeFunc&, args[0]);
|
||||
if(func.decl == nullptr) {
|
||||
return vm->None;
|
||||
}
|
||||
if(!func.decl->docstring) {
|
||||
return vm->None;
|
||||
}
|
||||
if(func.decl == nullptr) { return vm->None; }
|
||||
if(!func.decl->docstring) { return vm->None; }
|
||||
return VAR(func.decl->docstring);
|
||||
});
|
||||
|
||||
@ -1755,9 +1540,7 @@ void VM::__post_init_builtin_types() {
|
||||
_all_types[tp_module].m__getattr__ = [](VM* vm, PyVar obj, StrName name) -> PyVar {
|
||||
const Str& path = CAST(Str&, obj->attr(__path__));
|
||||
PyObject* retval = vm->py_import(_S(path, ".", name.sv()), false);
|
||||
if(retval) {
|
||||
return retval;
|
||||
}
|
||||
if(retval) { return retval; }
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
@ -1792,9 +1575,7 @@ void VM::__post_init_builtin_types() {
|
||||
});
|
||||
bind_property(_t(tp_type), "__module__", [](VM* vm, ArgsView args) -> PyVar {
|
||||
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;
|
||||
});
|
||||
bind_property(_t(tp_bound_method), "__self__", [](VM* vm, ArgsView args) {
|
||||
@ -1805,9 +1586,7 @@ void VM::__post_init_builtin_types() {
|
||||
});
|
||||
|
||||
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& _1 = PK_OBJ_GET(BoundMethod, rhs);
|
||||
return VAR(_0.self == _1.self && _0.func == _1.func);
|
||||
@ -1818,9 +1597,7 @@ void VM::__post_init_builtin_types() {
|
||||
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) {
|
||||
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()));
|
||||
});
|
||||
|
||||
@ -1831,9 +1608,7 @@ void VM::__post_init_builtin_types() {
|
||||
SStream ss;
|
||||
for(int i = 0; i < _0.size(); i++) {
|
||||
ss << vm->py_str(_0[i]);
|
||||
if(i != _0.size() - 1) {
|
||||
ss << _1;
|
||||
}
|
||||
if(i != _0.size() - 1) { ss << _1; }
|
||||
}
|
||||
ss << _2;
|
||||
vm->stdout_write(ss.str());
|
||||
|
||||
@ -16,13 +16,10 @@ using namespace pkpy;
|
||||
}
|
||||
|
||||
#define PK_ASSERT_NO_ERROR() \
|
||||
if(vm->__c.error != nullptr) \
|
||||
return false;
|
||||
if(vm->__c.error != nullptr) return false;
|
||||
|
||||
static int count_extra_elements(VM* vm, int n) {
|
||||
if(vm->callstack.empty()) {
|
||||
return vm->s_data.size();
|
||||
}
|
||||
if(vm->callstack.empty()) { return vm->s_data.size(); }
|
||||
assert(!vm->__c.s_view.empty());
|
||||
return vm->s_data._sp - vm->__c.s_view.top().end();
|
||||
}
|
||||
@ -37,9 +34,7 @@ static PyVar stack_item(VM* vm, int index) {
|
||||
begin = vm->__c.s_view.top().begin();
|
||||
}
|
||||
int size = end - begin;
|
||||
if(index < 0) {
|
||||
index += size;
|
||||
}
|
||||
if(index < 0) { index += size; }
|
||||
assert(index >= 0 && index < size);
|
||||
return begin[index];
|
||||
}
|
||||
@ -137,12 +132,8 @@ bool pkpy_rot_two(pkpy_vm* vm_handle) {
|
||||
int pkpy_stack_size(pkpy_vm* vm_handle) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
PK_ASSERT_NO_ERROR()
|
||||
if(vm->callstack.empty()) {
|
||||
return vm->s_data.size();
|
||||
}
|
||||
if(vm->__c.s_view.empty()) {
|
||||
exit(127);
|
||||
}
|
||||
if(vm->callstack.empty()) { return vm->s_data.size(); }
|
||||
if(vm->__c.s_view.empty()) { exit(127); }
|
||||
return vm->s_data._sp - vm->__c.s_view.top().begin();
|
||||
}
|
||||
|
||||
@ -322,9 +313,7 @@ struct TempViewPopper {
|
||||
TempViewPopper(VM* vm) : vm(vm), used(false) {}
|
||||
|
||||
void restore() noexcept {
|
||||
if(used) {
|
||||
return;
|
||||
}
|
||||
if(used) { return; }
|
||||
vm->__c.s_view.pop();
|
||||
used = true;
|
||||
}
|
||||
@ -350,12 +339,8 @@ static PyVar c_function_wrapper(VM* vm, ArgsView args) {
|
||||
return nullptr;
|
||||
}
|
||||
assert(retc == vm->s_data._sp - curr_sp);
|
||||
if(retc == 0) {
|
||||
return vm->None;
|
||||
}
|
||||
if(retc == 1) {
|
||||
return vm->s_data.popx();
|
||||
}
|
||||
if(retc == 0) { return vm->None; }
|
||||
if(retc == 1) { return vm->s_data.popx(); }
|
||||
ArgsView ret_view(curr_sp, vm->s_data._sp);
|
||||
return py_var(vm, ret_view.to_tuple());
|
||||
}
|
||||
@ -389,9 +374,7 @@ bool pkpy_getattr(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||
PK_ASSERT_N_EXTRA_ELEMENTS(1)
|
||||
PyVar o = vm->s_data.top();
|
||||
o = vm->getattr(o, StrName(name), false);
|
||||
if(o == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if(o == nullptr) { return false; }
|
||||
vm->s_data.top() = o;
|
||||
return true;
|
||||
}
|
||||
@ -416,9 +399,7 @@ bool pkpy_getglobal(pkpy_vm* vm_handle, pkpy_CName name) {
|
||||
PyVar o = vm->_main->attr().try_get(StrName(name));
|
||||
if(o == nullptr) {
|
||||
o = vm->builtins->attr().try_get(StrName(name));
|
||||
if(o == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if(o == nullptr) { return false; }
|
||||
}
|
||||
vm->s_data.push(o);
|
||||
return true;
|
||||
@ -535,9 +516,7 @@ bool pkpy_check_error(pkpy_vm* vm_handle) {
|
||||
bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
|
||||
VM* vm = (VM*)vm_handle;
|
||||
// no error
|
||||
if(vm->__c.error == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if(vm->__c.error == nullptr) { return false; }
|
||||
Exception& e = vm->__c.error->as<Exception>();
|
||||
if(message != nullptr) {
|
||||
*message = strdup(e.summary().c_str());
|
||||
@ -548,9 +527,7 @@ bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
|
||||
if(vm->callstack.empty()) {
|
||||
vm->s_data.clear();
|
||||
} 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());
|
||||
}
|
||||
return true;
|
||||
|
||||
@ -20,9 +20,7 @@ bool REPL::input(std::string line) {
|
||||
if(n >= need_more_lines) {
|
||||
for(int i = buffer.size() - need_more_lines; i < buffer.size(); i++) {
|
||||
// no enough lines
|
||||
if(buffer[i] != '\n') {
|
||||
return true;
|
||||
}
|
||||
if(buffer[i] != '\n') { return true; }
|
||||
}
|
||||
need_more_lines = 0;
|
||||
line = buffer;
|
||||
@ -39,9 +37,7 @@ bool REPL::input(std::string line) {
|
||||
buffer += line;
|
||||
buffer += '\n';
|
||||
need_more_lines = ne.is_compiling_class ? 3 : 2;
|
||||
if(need_more_lines) {
|
||||
return true;
|
||||
}
|
||||
if(need_more_lines) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -30,9 +30,7 @@ std::string pkpy_platform_getline(bool* eof) {
|
||||
std::string output;
|
||||
output.resize(length);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL);
|
||||
if(!output.empty() && output.back() == '\r') {
|
||||
output.pop_back();
|
||||
}
|
||||
if(!output.empty() && output.back() == '\r') { output.pop_back(); }
|
||||
return output;
|
||||
}
|
||||
|
||||
@ -41,9 +39,7 @@ std::string pkpy_platform_getline(bool* eof) {
|
||||
std::string pkpy_platform_getline(bool* eof) {
|
||||
std::string output;
|
||||
if(!std::getline(std::cin, output)) {
|
||||
if(eof) {
|
||||
*eof = true;
|
||||
}
|
||||
if(eof) { *eof = true; }
|
||||
}
|
||||
return output;
|
||||
}
|
||||
@ -54,9 +50,7 @@ static int f_input(pkpy_vm* vm) {
|
||||
if(!pkpy_is_none(vm, -1)) {
|
||||
pkpy_CString prompt;
|
||||
bool ok = pkpy_to_string(vm, -1, &prompt);
|
||||
if(!ok) {
|
||||
return 0;
|
||||
}
|
||||
if(!ok) { return 0; }
|
||||
std::cout << prompt << std::flush;
|
||||
}
|
||||
bool eof;
|
||||
@ -83,9 +77,7 @@ int main(int argc, char** argv) {
|
||||
std::cout << (need_more_lines ? "... " : ">>> ");
|
||||
bool eof = false;
|
||||
std::string line = pkpy_platform_getline(&eof);
|
||||
if(eof) {
|
||||
break;
|
||||
}
|
||||
if(eof) { break; }
|
||||
need_more_lines = pkpy_repl_input(repl, line.c_str());
|
||||
}
|
||||
pkpy_delete_vm(vm);
|
||||
@ -94,9 +86,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
if(argc == 2) {
|
||||
std::string argv_1 = argv[1];
|
||||
if(argv_1 == "-h" || argv_1 == "--help") {
|
||||
goto __HELP;
|
||||
}
|
||||
if(argv_1 == "-h" || argv_1 == "--help") { goto __HELP; }
|
||||
|
||||
std::filesystem::path filepath(argv[1]);
|
||||
filepath = std::filesystem::absolute(filepath);
|
||||
@ -115,9 +105,7 @@ int main(int argc, char** argv) {
|
||||
pkpy_set_main_argv(vm, argc, argv);
|
||||
|
||||
bool ok = pkpy_exec_2(vm, src.c_str(), filepath.filename().string().c_str(), 0, NULL);
|
||||
if(!ok) {
|
||||
pkpy_clear_error(vm, NULL);
|
||||
}
|
||||
if(!ok) { pkpy_clear_error(vm, NULL); }
|
||||
pkpy_delete_vm(vm);
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user