AllowShortIfStatementsOnASingleLine

This commit is contained in:
ykiko 2024-06-04 18:36:46 +08:00
parent 2603ca7741
commit 7cadf364eb
47 changed files with 642 additions and 1898 deletions

View File

@ -54,7 +54,7 @@ AllowShortCaseLabelsOnASingleLine: true
AllowShortCompoundRequirementOnASingleLine: true AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLambdasOnASingleLine: All AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None AlwaysBreakAfterReturnType: None

View File

@ -60,9 +60,7 @@ struct any {
any& operator= (const any& other) = delete; any& operator= (const any& other) = delete;
~any() { ~any() {
if(_vt && _vt->deleter) { if(_vt && _vt->deleter) { _vt->deleter(data); }
_vt->deleter(data);
}
} }
template <typename T> template <typename T>
@ -78,9 +76,7 @@ struct any {
template <typename T> template <typename T>
T& cast() const { T& cast() const {
static_assert(std::is_same_v<T, std::decay_t<T>>); static_assert(std::is_same_v<T, std::decay_t<T>>);
if(type_id() != typeid(T)) { if(type_id() != typeid(T)) { __bad_any_cast(typeid(T), type_id()); }
__bad_any_cast(typeid(T), type_id());
}
return _cast<T>(); return _cast<T>();
} }

View File

@ -86,9 +86,7 @@ struct NameDictImpl {
uint16_t old_capacity = _capacity; uint16_t old_capacity = _capacity;
_set_capacity_and_alloc_items(_capacity * 2); _set_capacity_and_alloc_items(_capacity * 2);
for(uint16_t i = 0; i < old_capacity; i++) { for(uint16_t i = 0; i < old_capacity; i++) {
if(old_items[i].first.empty()) { if(old_items[i].first.empty()) { continue; }
continue;
}
bool ok; bool ok;
uint16_t j; uint16_t j;
HASH_PROBE_1(old_items[i].first, ok, j); HASH_PROBE_1(old_items[i].first, ok, j);
@ -102,9 +100,7 @@ struct NameDictImpl {
bool ok; bool ok;
uint16_t i; uint16_t i;
HASH_PROBE_0(key, ok, i); HASH_PROBE_0(key, ok, i);
if(!ok) { if(!ok) { return default_invalid_value<T>(); }
return default_invalid_value<T>();
}
return _items[i].second; return _items[i].second;
} }
@ -112,33 +108,23 @@ struct NameDictImpl {
bool ok; bool ok;
uint16_t i; uint16_t i;
HASH_PROBE_0(key, ok, i); HASH_PROBE_0(key, ok, i);
if(!ok) { if(!ok) { return nullptr; }
return nullptr;
}
return &_items[i].second; return &_items[i].second;
} }
T try_get_likely_found(StrName key) const { T try_get_likely_found(StrName key) const {
uint16_t i = key.index & _mask; uint16_t i = key.index & _mask;
if(_items[i].first == key) { if(_items[i].first == key) { return _items[i].second; }
return _items[i].second;
}
i = (i + 1) & _mask; i = (i + 1) & _mask;
if(_items[i].first == key) { if(_items[i].first == key) { return _items[i].second; }
return _items[i].second;
}
return try_get(key); return try_get(key);
} }
T* try_get_2_likely_found(StrName key) const { T* try_get_2_likely_found(StrName key) const {
uint16_t i = key.index & _mask; uint16_t i = key.index & _mask;
if(_items[i].first == key) { if(_items[i].first == key) { return &_items[i].second; }
return &_items[i].second;
}
i = (i + 1) & _mask; i = (i + 1) & _mask;
if(_items[i].first == key) { if(_items[i].first == key) { return &_items[i].second; }
return &_items[i].second;
}
return try_get_2(key); return try_get_2(key);
} }
@ -146,9 +132,7 @@ struct NameDictImpl {
bool ok; bool ok;
uint16_t i; uint16_t i;
HASH_PROBE_0(key, ok, i); HASH_PROBE_0(key, ok, i);
if(!ok) { if(!ok) { return false; }
return false;
}
_items[i].first = StrName(); _items[i].first = StrName();
_items[i].second = nullptr; _items[i].second = nullptr;
_size--; _size--;
@ -157,9 +141,7 @@ struct NameDictImpl {
uint16_t z = (i + 1) & _mask; uint16_t z = (i + 1) & _mask;
while(!_items[z].first.empty()) { while(!_items[z].first.empty()) {
uint16_t h = _items[z].first.index & _mask; uint16_t h = _items[z].first.index & _mask;
if(h != i) { if(h != i) { break; }
break;
}
std::swap(_items[pre_z], _items[z]); std::swap(_items[pre_z], _items[z]);
pre_z = z; pre_z = z;
z = (z + 1) & _mask; z = (z + 1) & _mask;
@ -170,9 +152,7 @@ struct NameDictImpl {
template <typename __Func> template <typename __Func>
void apply(__Func func) const { void apply(__Func func) const {
for(uint16_t i = 0; i < _capacity; i++) { for(uint16_t i = 0; i < _capacity; i++) {
if(_items[i].first.empty()) { if(_items[i].first.empty()) { continue; }
continue;
}
func(_items[i].first, _items[i].second); func(_items[i].first, _items[i].second);
} }
} }
@ -186,9 +166,7 @@ struct NameDictImpl {
T operator[] (StrName key) const { T operator[] (StrName key) const {
T* val = try_get_2_likely_found(key); T* val = try_get_2_likely_found(key);
if(val == nullptr) { if(val == nullptr) { throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str()); }
throw std::runtime_error(_S("NameDict key not found: ", key.escape()).str());
}
return *val; return *val;
} }
@ -196,9 +174,7 @@ struct NameDictImpl {
array<StrName> v(_size); array<StrName> v(_size);
int j = 0; int j = 0;
for(uint16_t i = 0; i < _capacity; i++) { for(uint16_t i = 0; i < _capacity; i++) {
if(_items[i].first.empty()) { if(_items[i].first.empty()) { continue; }
continue;
}
new (&v[j++]) StrName(_items[i].first); new (&v[j++]) StrName(_items[i].first);
} }
return v; return v;

View File

@ -143,9 +143,7 @@ struct vector {
if(cap < 4) { if(cap < 4) {
cap = 4; // minimum capacity cap = 4; // minimum capacity
} }
if(cap <= capacity()) { if(cap <= capacity()) { return; }
return;
}
T* new_data = (T*)std::malloc(sizeof(T) * cap); T* new_data = (T*)std::malloc(sizeof(T) * cap);
if constexpr(is_trivially_relocatable_v<T>) { if constexpr(is_trivially_relocatable_v<T>) {
std::memcpy(new_data, _data, sizeof(T) * _size); std::memcpy(new_data, _data, sizeof(T) * _size);
@ -155,9 +153,7 @@ struct vector {
_data[i].~T(); _data[i].~T();
} }
} }
if(_data) { if(_data) { std::free(_data); }
std::free(_data);
}
_data = new_data; _data = new_data;
_capacity = cap; _capacity = cap;
} }
@ -168,33 +164,25 @@ struct vector {
} }
void push_back(const T& t) { void push_back(const T& t) {
if(_size == _capacity) { if(_size == _capacity) { reserve(_capacity * 2); }
reserve(_capacity * 2);
}
new (&_data[_size++]) T(t); new (&_data[_size++]) T(t);
} }
void push_back(T&& t) { void push_back(T&& t) {
if(_size == _capacity) { if(_size == _capacity) { reserve(_capacity * 2); }
reserve(_capacity * 2);
}
new (&_data[_size++]) T(std::move(t)); new (&_data[_size++]) T(std::move(t));
} }
bool contains(const T& t) const { bool contains(const T& t) const {
for(int i = 0; i < _size; i++) { for(int i = 0; i < _size; i++) {
if(_data[i] == t) { if(_data[i] == t) { return true; }
return true;
}
} }
return false; return false;
} }
template <typename... Args> template <typename... Args>
void emplace_back(Args&&... args) { void emplace_back(Args&&... args) {
if(_size == _capacity) { if(_size == _capacity) { reserve(_capacity * 2); }
reserve(_capacity * 2);
}
new (&_data[_size++]) T(std::forward<Args>(args)...); new (&_data[_size++]) T(std::forward<Args>(args)...);
} }
@ -211,9 +199,7 @@ struct vector {
} }
void insert(int index, const T& t) { void insert(int index, const T& t) {
if(_size == _capacity) { if(_size == _capacity) { reserve(_capacity * 2); }
reserve(_capacity * 2);
}
for(int i = _size; i > index; i--) { for(int i = _size; i > index; i--) {
_data[i] = std::move(_data[i - 1]); _data[i] = std::move(_data[i - 1]);
} }
@ -231,9 +217,7 @@ struct vector {
void pop_back() { void pop_back() {
assert(_size > 0); assert(_size > 0);
_size--; _size--;
if constexpr(!std::is_trivially_destructible_v<T>) { if constexpr(!std::is_trivially_destructible_v<T>) { _data[_size].~T(); }
_data[_size].~T();
}
} }
void clear() { void clear() {
@ -443,9 +427,7 @@ public:
~small_vector() { ~small_vector() {
std::destroy(m_begin, m_end); std::destroy(m_begin, m_end);
if(!is_small()) { if(!is_small()) { std::free(m_begin); }
std::free(m_begin);
}
} }
template <typename... Args> template <typename... Args>
@ -480,9 +462,7 @@ public:
void pop_back() { void pop_back() {
m_end--; m_end--;
if constexpr(!std::is_trivially_destructible_v<T>) { if constexpr(!std::is_trivially_destructible_v<T>) { m_end->~T(); }
m_end->~T();
}
} }
void clear() { void clear() {

View File

@ -33,9 +33,7 @@ class Compiler {
const Token& next() const { return tokens[i + 1]; } const Token& next() const { return tokens[i + 1]; }
const Token& err() const { const Token& err() const {
if(i >= tokens.size()) { if(i >= tokens.size()) { return prev(); }
return prev();
}
return curr(); return curr();
} }

View File

@ -288,9 +288,7 @@ struct ListExpr : SequenceExpr {
Opcode opcode() const override { Opcode opcode() const override {
for(auto& e: items) { for(auto& e: items) {
if(e->is_starred()) { if(e->is_starred()) { return OP_BUILD_LIST_UNPACK; }
return OP_BUILD_LIST_UNPACK;
}
} }
return OP_BUILD_LIST; return OP_BUILD_LIST;
} }
@ -303,9 +301,7 @@ struct DictExpr : SequenceExpr {
Opcode opcode() const override { Opcode opcode() const override {
for(auto& e: items) { for(auto& e: items) {
if(e->is_starred()) { if(e->is_starred()) { return OP_BUILD_DICT_UNPACK; }
return OP_BUILD_DICT_UNPACK;
}
} }
return OP_BUILD_DICT; return OP_BUILD_DICT;
} }
@ -318,9 +314,7 @@ struct SetExpr : SequenceExpr {
Opcode opcode() const override { Opcode opcode() const override {
for(auto& e: items) { for(auto& e: items) {
if(e->is_starred()) { if(e->is_starred()) { return OP_BUILD_SET_UNPACK; }
return OP_BUILD_SET_UNPACK;
}
} }
return OP_BUILD_SET; return OP_BUILD_SET;
} }
@ -333,9 +327,7 @@ struct TupleExpr : SequenceExpr {
Opcode opcode() const override { Opcode opcode() const override {
for(auto& e: items) { for(auto& e: items) {
if(e->is_starred()) { if(e->is_starred()) { return OP_BUILD_TUPLE_UNPACK; }
return OP_BUILD_TUPLE_UNPACK;
}
} }
return OP_BUILD_TUPLE; return OP_BUILD_TUPLE;
} }

View File

@ -42,9 +42,7 @@ constexpr TokenIndex TK(const char token[]) {
i++; i++;
j++; j++;
} }
if(*i == *j) { if(*i == *j) { return k; }
return k;
}
} }
return 255; return 255;
} }

View File

@ -94,9 +94,7 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
assert(is_type(obj, tp_type)); assert(is_type(obj, tp_type));
std::string_view name_sv(name); std::string_view name_sv(name);
int pos = name_sv.find(':'); int pos = name_sv.find(':');
if(pos > 0) { if(pos > 0) { name_sv = name_sv.substr(0, pos); }
name_sv = name_sv.substr(0, pos);
}
auto fget = [](VM* vm, ArgsView args) -> PyVar { auto fget = [](VM* vm, ArgsView args) -> PyVar {
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
F T::*field = lambda_get_userdata<F T::*>(args.begin()); F T::*field = lambda_get_userdata<F T::*>(args.begin());
@ -171,8 +169,7 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
1, \ 1, \
[](VM* vm, ArgsView args) { \ [](VM* vm, ArgsView args) { \
Struct& s = CAST(Struct&, args[0]); \ Struct& s = CAST(Struct&, args[0]); \
if(s.size != sizeof(wT)) \ if(s.size != sizeof(wT)) vm->ValueError("size mismatch"); \
vm->ValueError("size mismatch"); \
PyVar obj = vm->new_user_object<wT>(); \ PyVar obj = vm->new_user_object<wT>(); \
std::memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \ std::memcpy(&_CAST(wT&, obj), s.p, sizeof(wT)); \
return obj; \ return obj; \
@ -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_func(type, "sizeof", 1, [](VM* vm, ArgsView args) { return VAR(sizeof(wT)); }); \
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \ vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
wT& self = _CAST(wT&, _0); \ wT& self = _CAST(wT&, _0); \
if(!vm->isinstance(_1, vm->_tp_user<wT>())) \ if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \
return vm->NotImplemented; \
wT& other = _CAST(wT&, _1); \ wT& other = _CAST(wT&, _1); \
return VAR(self == other); \ return VAR(self == other); \
}); });

View File

@ -74,23 +74,17 @@ struct Struct {
} else { } else {
p = (char*)std::malloc(size); p = (char*)std::malloc(size);
} }
if(zero_init) { if(zero_init) { std::memset(p, 0, size); }
std::memset(p, 0, size);
}
} }
Struct(void* p, int size) : Struct(size, false) { Struct(void* p, int size) : Struct(size, false) {
if(p != nullptr) { if(p != nullptr) { std::memcpy(this->p, p, size); }
std::memcpy(this->p, p, size);
}
} }
Struct(const Struct& other) : Struct(other.p, other.size) {} Struct(const Struct& other) : Struct(other.p, other.size) {}
~Struct() { ~Struct() {
if(p != _inlined) { if(p != _inlined) { std::free(p); }
std::free(p);
}
} }
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);

View File

@ -57,9 +57,7 @@ struct Generator {
} }
void _gc_mark(VM* vm) { void _gc_mark(VM* vm) {
if(lf == nullptr) { if(lf == nullptr) { return; }
return;
}
lf->frame._gc_mark(vm); lf->frame._gc_mark(vm);
vm->__stack_gc_mark(s_backup.begin(), s_backup.end()); vm->__stack_gc_mark(s_backup.begin(), s_backup.end());
} }

View File

@ -241,9 +241,7 @@ public:
bool py_callable(PyVar obj); // x -> callable(x) bool py_callable(PyVar obj); // x -> callable(x)
bool py_bool(PyVar obj) { // x -> bool(x) bool py_bool(PyVar obj) { // x -> bool(x)
if(obj.type == tp_bool) { if(obj.type == tp_bool) { return obj._0; }
return obj._0;
}
return __py_bool_non_trivial(obj); 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 parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step);
void obj_gc_mark(PyVar obj) { void obj_gc_mark(PyVar obj) {
if(obj.is_ptr) { if(obj.is_ptr) { __obj_gc_mark(obj.get()); }
__obj_gc_mark(obj.get());
}
} }
void obj_gc_mark(PyObject* p) { void obj_gc_mark(PyObject* p) {
if(p) { if(p) { __obj_gc_mark(p); }
__obj_gc_mark(p);
}
} }
#endif #endif
@ -466,15 +460,11 @@ public:
bool issubclass(Type cls, Type base); bool issubclass(Type cls, Type base);
void check_type(PyVar obj, Type type) { void check_type(PyVar obj, Type type) {
if(!is_type(obj, type)) { if(!is_type(obj, type)) { TypeError(type, _tp(obj)); }
TypeError(type, _tp(obj));
}
} }
void check_compatible_type(PyVar obj, Type type) { void check_compatible_type(PyVar obj, Type type) {
if(!isinstance(obj, type)) { if(!isinstance(obj, type)) { TypeError(type, _tp(obj)); }
TypeError(type, _tp(obj));
}
} }
Type _tp(PyVar obj) { return obj.type; } 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>) { if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, CString>) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
// str (shortcuts) // str (shortcuts)
if(obj == vm->None) { if(obj == vm->None) { return nullptr; }
return nullptr; if constexpr(with_check) { vm->check_type(obj, vm->tp_str); }
}
if constexpr(with_check) {
vm->check_type(obj, vm->tp_str);
}
return PK_OBJ_GET(Str, obj).c_str(); return PK_OBJ_GET(Str, obj).c_str();
} else if constexpr(std::is_same_v<T, bool>) { } else if constexpr(std::is_same_v<T, bool>) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
// bool // bool
if constexpr(with_check) { if constexpr(with_check) {
if(obj == vm->True) { if(obj == vm->True) { return true; }
return true; if(obj == vm->False) { return false; }
}
if(obj == vm->False) {
return false;
}
vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape()); vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
} }
return obj == vm->True; return obj == vm->True;
@ -783,20 +765,14 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
// int // int
if constexpr(with_check) { if constexpr(with_check) {
if(is_int(obj)) { if(is_int(obj)) { return (T)obj.as<i64>(); }
return (T)obj.as<i64>();
}
vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape()); vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
} }
return (T)obj.as<i64>(); return (T)obj.as<i64>();
} else if constexpr(is_floating_point_v<T>) { } else if constexpr(is_floating_point_v<T>) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
if(is_float(obj)) { if(is_float(obj)) { return (T)obj.as<f64>(); }
return (T)obj.as<f64>(); if(is_int(obj)) { return (T)obj.as<i64>(); }
}
if(is_int(obj)) {
return (T)obj.as<i64>();
}
vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape()); vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape());
return 0.0f; return 0.0f;
} else if constexpr(std::is_enum_v<T>) { } else if constexpr(std::is_enum_v<T>) {

View File

@ -62,9 +62,7 @@ struct CodeBlock {
type(type), parent(parent), start(start), end(-1), end2(-1) {} type(type), parent(parent), start(start), end(-1), end2(-1) {}
int get_break_end() const { int get_break_end() const {
if(end2 != -1) { if(end2 != -1) { return end2; }
return end2;
}
return end; return end;
} }
}; };

View File

@ -55,9 +55,7 @@ struct Exception {
template <typename... Args> template <typename... Args>
void st_push(Args&&... args) { void st_push(Args&&... args) {
if(stacktrace.size() >= 7) { if(stacktrace.size() >= 7) { return; }
return;
}
stacktrace.emplace(std::forward<Args>(args)...); stacktrace.emplace(std::forward<Args>(args)...);
} }

View File

@ -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_) { inline object getattr(const handle& obj, const handle& name, const handle& default_) {
if(!hasattr(obj, name)) { if(!hasattr(obj, name)) { return reinterpret_borrow<object>(default_); }
return reinterpret_borrow<object>(default_);
}
return getattr(obj, name); return getattr(obj, name);
} }
inline object getattr(const handle& obj, const char* name, const handle& default_) { inline object getattr(const handle& obj, const char* name, const handle& default_) {
if(!hasattr(obj, name)) { if(!hasattr(obj, name)) { return reinterpret_borrow<object>(default_); }
return reinterpret_borrow<object>(default_);
}
return getattr(obj, name); return getattr(obj, name);
} }

View File

@ -100,9 +100,7 @@ public:
// foreach function record and call the function with not convert // foreach function record and call the function with not convert
while(p != nullptr) { while(p != nullptr) {
handle result = p->wrapper(*this, view, false, {}); handle result = p->wrapper(*this, view, false, {});
if(result) { if(result) { return result; }
return result;
}
p = p->next; p = p->next;
} }
@ -110,9 +108,7 @@ public:
// foreach function record and call the function with convert // foreach function record and call the function with convert
while(p != nullptr) { while(p != nullptr) {
handle result = p->wrapper(*this, view, true, {}); handle result = p->wrapper(*this, view, true, {});
if(result) { if(result) { return result; }
return result;
}
p = p->next; p = p->next;
} }
@ -172,13 +168,9 @@ struct generator<Fn, std::tuple<Extras...>, std::tuple<Args...>, std::index_sequ
// initialize the stack // initialize the stack
if(!has_args && (view.size() != count)) { if(!has_args && (view.size() != count)) { return handle(); }
return handle();
}
if(has_args && (view.size() < count)) { if(has_args && (view.size() < count)) { return handle(); }
return handle();
}
for(std::size_t i = 0; i < count; ++i) { for(std::size_t i = 0; i < count; ++i) {
stack[i] = view[i]; stack[i] = view[i];
@ -211,9 +203,7 @@ struct generator<Fn, std::tuple<Extras...>, std::tuple<Args...>, std::index_sequ
// check if all the arguments are not valid // check if all the arguments are not valid
for(std::size_t i = 0; i < sizeof...(Args); ++i) { for(std::size_t i = 0; i < sizeof...(Args); ++i) {
if(!stack[i]) { if(!stack[i]) { return handle(); }
return handle();
}
} }
// ok, all the arguments are valid, call the function // ok, all the arguments are valid, call the function

View File

@ -126,15 +126,11 @@ public:
} }
~instance() { ~instance() {
if(flag & Flag::Own) { if(flag & Flag::Own) { type->destructor(data); }
type->destructor(data);
}
} }
void _gc_mark(pkpy::VM* vm) const noexcept { void _gc_mark(pkpy::VM* vm) const noexcept {
if(parent && (flag & Flag::Ref)) { if(parent && (flag & Flag::Ref)) { PK_OBJ_MARK(parent); }
PK_OBJ_MARK(parent);
}
} }
template <typename T> template <typename T>

View File

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

View File

@ -183,13 +183,9 @@ class kwargs : public dict {
template <typename T> template <typename T>
handle type::handle_of() { handle type::handle_of() {
if constexpr(std::is_same_v<T, object>) { if constexpr(std::is_same_v<T, object>) { return vm->_t(vm->tp_object); }
return vm->_t(vm->tp_object);
}
#define PYBIND11_TYPE_MAPPER(type, tp) \ #define PYBIND11_TYPE_MAPPER(type, tp) \
else if constexpr(std::is_same_v<T, type>) { \ else if constexpr(std::is_same_v<T, type>) { return vm->_t(vm->tp); }
return vm->_t(vm->tp); \
}
PYBIND11_TYPE_MAPPER(type, tp_type) PYBIND11_TYPE_MAPPER(type, tp_type)
PYBIND11_TYPE_MAPPER(str, tp_str) PYBIND11_TYPE_MAPPER(str, tp_str)
PYBIND11_TYPE_MAPPER(int_, tp_int) PYBIND11_TYPE_MAPPER(int_, tp_int)
@ -203,9 +199,7 @@ handle type::handle_of() {
#undef PYBIND11_TYPE_MAPPER #undef PYBIND11_TYPE_MAPPER
else { else {
auto result = vm->_cxx_typeid_map.find(typeid(T)); auto result = vm->_cxx_typeid_map.find(typeid(T));
if(result != vm->_cxx_typeid_map.end()) { if(result != vm->_cxx_typeid_map.end()) { return vm->_t(result->second); }
return vm->_t(result->second);
}
vm->TypeError("Type not registered"); vm->TypeError("Type not registered");
} }

View File

@ -17,9 +17,7 @@ any::any(any&& other) noexcept : data(other.data), _vt(other._vt) {
} }
any& any::operator= (any&& other) noexcept { any& any::operator= (any&& other) noexcept {
if(data) { if(data) { _vt->deleter(data); }
_vt->deleter(data);
}
data = other.data; data = other.data;
_vt = other._vt; _vt = other._vt;
other.data = nullptr; other.data = nullptr;

View File

@ -146,9 +146,7 @@ struct MemoryPool {
return (char*)p + sizeof(void*); return (char*)p + sizeof(void*);
} }
if(_arenas.empty()) { if(_arenas.empty()) { _arenas.push_back(new Arena()); }
_arenas.push_back(new Arena());
}
Arena* arena = _arenas.back(); Arena* arena = _arenas.back();
void* p = arena->alloc()->data; void* p = arena->alloc()->data;
if(arena->empty()) { if(arena->empty()) {
@ -178,9 +176,7 @@ struct MemoryPool {
void shrink_to_fit() { void shrink_to_fit() {
PK_GLOBAL_SCOPE_LOCK(); PK_GLOBAL_SCOPE_LOCK();
if(_arenas.size() < __MinArenaCount) { if(_arenas.size() < __MinArenaCount) { return; }
return;
}
_arenas.apply([this](Arena* arena) { _arenas.apply([this](Arena* arena) {
if(arena->full()) { if(arena->full()) {
_arenas.erase(arena); _arenas.erase(arena);

View File

@ -9,27 +9,13 @@
namespace pkpy { namespace pkpy {
int utf8len(unsigned char c, bool suppress) { int utf8len(unsigned char c, bool suppress) {
if((c & 0b10000000) == 0) { if((c & 0b10000000) == 0) { return 1; }
return 1; if((c & 0b11100000) == 0b11000000) { return 2; }
} if((c & 0b11110000) == 0b11100000) { return 3; }
if((c & 0b11100000) == 0b11000000) { if((c & 0b11111000) == 0b11110000) { return 4; }
return 2; if((c & 0b11111100) == 0b11111000) { return 5; }
} if((c & 0b11111110) == 0b11111100) { return 6; }
if((c & 0b11110000) == 0b11100000) { if(!suppress) { throw std::runtime_error("invalid utf8 char: " + std::to_string(c)); }
return 3;
}
if((c & 0b11111000) == 0b11110000) {
return 4;
}
if((c & 0b11111100) == 0b11111000) {
return 5;
}
if((c & 0b11111110) == 0b11111100) {
return 6;
}
if(!suppress) {
throw std::runtime_error("invalid utf8 char: " + std::to_string(c));
}
return 0; return 0;
} }
@ -43,8 +29,7 @@ int utf8len(unsigned char c, bool suppress) {
#define PK_STR_COPY_INIT(__s) \ #define PK_STR_COPY_INIT(__s) \
for(int i = 0; i < this->size; i++) { \ for(int i = 0; i < this->size; i++) { \
this->data[i] = __s[i]; \ this->data[i] = __s[i]; \
if(!isascii(__s[i])) \ if(!isascii(__s[i])) is_ascii = false; \
is_ascii = false; \
} \ } \
this->data[this->size] = '\0'; 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(); } bool operator< (const std::string_view other, const Str& str) { return other < str.sv(); }
Str& Str::operator= (const Str& other) { Str& Str::operator= (const Str& other) {
if(!is_inlined()) { if(!is_inlined()) { std::free(data); }
std::free(data);
}
size = other.size; size = other.size;
is_ascii = other.is_ascii; is_ascii = other.is_ascii;
PK_STR_ALLOCATE() PK_STR_ALLOCATE()
@ -133,30 +116,22 @@ Str Str::operator+ (const char* p) const {
} }
bool Str::operator== (const Str& other) const { bool Str::operator== (const Str& other) const {
if(size != other.size) { if(size != other.size) { return false; }
return false;
}
return memcmp(data, other.data, size) == 0; return memcmp(data, other.data, size) == 0;
} }
bool Str::operator!= (const Str& other) const { bool Str::operator!= (const Str& other) const {
if(size != other.size) { if(size != other.size) { return true; }
return true;
}
return memcmp(data, other.data, size) != 0; return memcmp(data, other.data, size) != 0;
} }
bool Str::operator== (const std::string_view other) const { bool Str::operator== (const std::string_view other) const {
if(size != (int)other.size()) { if(size != (int)other.size()) { return false; }
return false;
}
return memcmp(data, other.data(), size) == 0; return memcmp(data, other.data(), size) == 0;
} }
bool Str::operator!= (const std::string_view other) const { bool Str::operator!= (const std::string_view other) const {
if(size != (int)other.size()) { if(size != (int)other.size()) { return true; }
return true;
}
return memcmp(data, other.data(), size) != 0; 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(); } bool Str::operator>= (const Str& other) const { return this->sv() >= other.sv(); }
Str::~Str() { Str::~Str() {
if(!is_inlined()) { if(!is_inlined()) { std::free(data); }
std::free(data);
}
} }
Str Str::substr(int start, int len) const { Str Str::substr(int start, int len) const {
@ -228,9 +201,7 @@ Str Str::strip(bool left, bool right) const {
Str Str::lower() const { Str Str::lower() const {
std::string copy(data, size); std::string copy(data, size);
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) { std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) {
if('A' <= c && c <= 'Z') { if('A' <= c && c <= 'Z') { return c + ('a' - 'A'); }
return c + ('a' - 'A');
}
return (int)c; return (int)c;
}); });
return Str(copy); return Str(copy);
@ -239,9 +210,7 @@ Str Str::lower() const {
Str Str::upper() const { Str Str::upper() const {
std::string copy(data, size); std::string copy(data, size);
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) { std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) {
if('a' <= c && c <= 'z') { if('a' <= c && c <= 'z') { return c - ('a' - 'A'); }
return c - ('a' - 'A');
}
return (int)c; return (int)c;
}); });
return Str(copy); return Str(copy);
@ -259,15 +228,11 @@ void Str::escape_(SStream& ss, bool single_quote) const {
char c = this->operator[] (i); char c = this->operator[] (i);
switch(c) { switch(c) {
case '"': case '"':
if(!single_quote) { if(!single_quote) { ss << '\\'; }
ss << '\\';
}
ss << '"'; ss << '"';
break; break;
case '\'': case '\'':
if(single_quote) { if(single_quote) { ss << '\\'; }
ss << '\\';
}
ss << '\''; ss << '\'';
break; break;
case '\\': 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 { int Str::index(const Str& sub, int start) const {
auto p = std::search(data + start, data + size, sub.data, sub.data + sub.size); auto p = std::search(data + start, data + size, sub.data, sub.data + sub.size);
if(p == data + size) { if(p == data + size) { return -1; }
return -1;
}
return p - data; return p - data;
} }
Str Str::replace(char old, char new_) const { Str Str::replace(char old, char new_) const {
Str copied = *this; Str copied = *this;
for(int i = 0; i < copied.size; i++) { for(int i = 0; i < copied.size; i++) {
if(copied.data[i] == old) { if(copied.data[i] == old) { copied.data[i] = new_; }
copied.data[i] = new_;
}
} }
return copied; return copied;
} }
@ -311,24 +272,18 @@ Str Str::replace(const Str& old, const Str& new_, int count) const {
int start = 0; int start = 0;
while(true) { while(true) {
int i = index(old, start); int i = index(old, start);
if(i == -1) { if(i == -1) { break; }
break;
}
ss << substr(start, i - start); ss << substr(start, i - start);
ss << new_; ss << new_;
start = i + old.size; start = i + old.size;
if(count != -1 && --count == 0) { if(count != -1 && --count == 0) { break; }
break;
}
} }
ss << substr(start, size - start); ss << substr(start, size - start);
return ss.str(); return ss.str();
} }
int Str::_unicode_index_to_byte(int i) const { int Str::_unicode_index_to_byte(int i) const {
if(is_ascii) { if(is_ascii) { return i; }
return i;
}
int j = 0; int j = 0;
while(i > 0) { while(i > 0) {
j += utf8len(data[j]); 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 { int Str::_byte_index_to_unicode(int n) const {
if(is_ascii) { if(is_ascii) { return n; }
return n;
}
int cnt = 0; int cnt = 0;
for(int i = 0; i < n; i++) { for(int i = 0; i < n; i++) {
if((data[i] & 0xC0) != 0x80) { if((data[i] & 0xC0) != 0x80) { cnt++; }
cnt++;
}
} }
return cnt; return cnt;
} }
@ -373,19 +324,13 @@ vector<std::string_view> Str::split(const Str& sep) const {
int start = 0; int start = 0;
while(true) { while(true) {
int i = index(sep, start); int i = index(sep, start);
if(i == -1) { if(i == -1) { break; }
break;
}
tmp = sv().substr(start, i - start); tmp = sv().substr(start, i - start);
if(!tmp.empty()) { if(!tmp.empty()) { result.push_back(tmp); }
result.push_back(tmp);
}
start = i + sep.size; start = i + sep.size;
} }
tmp = sv().substr(start, size - start); tmp = sv().substr(start, size - start);
if(!tmp.empty()) { if(!tmp.empty()) { result.push_back(tmp); }
result.push_back(tmp);
}
return result; return result;
} }
@ -394,30 +339,22 @@ vector<std::string_view> Str::split(char sep) const {
int i = 0; int i = 0;
for(int j = 0; j < size; j++) { for(int j = 0; j < size; j++) {
if(data[j] == sep) { if(data[j] == sep) {
if(j > i) { if(j > i) { result.emplace_back(data + i, j - i); }
result.emplace_back(data + i, j - i);
}
i = j + 1; i = j + 1;
continue; continue;
} }
} }
if(size > i) { if(size > i) { result.emplace_back(data + i, size - i); }
result.emplace_back(data + i, size - i);
}
return result; return result;
} }
int Str::count(const Str& sub) const { int Str::count(const Str& sub) const {
if(sub.empty()) { if(sub.empty()) { return size + 1; }
return size + 1;
}
int cnt = 0; int cnt = 0;
int start = 0; int start = 0;
while(true) { while(true) {
int i = index(sub, start); int i = index(sub, start);
if(i == -1) { if(i == -1) { break; }
break;
}
cnt++; cnt++;
start = i + sub.size; start = i + sub.size;
} }
@ -438,15 +375,11 @@ uint32_t StrName::_pesudo_random_index = 0;
StrName StrName::get(std::string_view s) { StrName StrName::get(std::string_view s) {
auto it = _interned().find(s); auto it = _interned().find(s);
if(it != _interned().end()) { if(it != _interned().end()) { return StrName(it->second); }
return StrName(it->second);
}
// generate new index // generate new index
// https://github.com/python/cpython/blob/3.12/Objects/dictobject.c#L175 // https://github.com/python/cpython/blob/3.12/Objects/dictobject.c#L175
uint16_t index = ((_pesudo_random_index * 5) + 1) & 65535; uint16_t index = ((_pesudo_random_index * 5) + 1) & 65535;
if(index == 0) { if(index == 0) { throw std::runtime_error("StrName index overflow"); }
throw std::runtime_error("StrName index overflow");
}
auto res = _r_interned().emplace(index, s); auto res = _r_interned().emplace(index, s);
assert(res.second); assert(res.second);
s = std::string_view(res.first->second); s = std::string_view(res.first->second);
@ -525,12 +458,8 @@ SStream& SStream::operator<< (i64 val) {
} }
SStream& SStream::operator<< (f64 val) { SStream& SStream::operator<< (f64 val) {
if(std::isinf(val)) { if(std::isinf(val)) { return (*this) << (val > 0 ? "inf" : "-inf"); }
return (*this) << (val > 0 ? "inf" : "-inf"); if(std::isnan(val)) { return (*this) << "nan"; }
}
if(std::isnan(val)) {
return (*this) << "nan";
}
char b[32]; char b[32];
if(_precision == -1) { if(_precision == -1) {
int prec = std::numeric_limits<f64>::max_digits10 - 1; int prec = std::numeric_limits<f64>::max_digits10 - 1;
@ -540,9 +469,7 @@ SStream& SStream::operator<< (f64 val) {
snprintf(b, sizeof(b), "%.*f", prec, val); snprintf(b, sizeof(b), "%.*f", prec, val);
} }
(*this) << b; (*this) << b;
if(std::all_of(b + 1, b + strlen(b), isdigit)) { if(std::all_of(b + 1, b + strlen(b), isdigit)) { (*this) << ".0"; }
(*this) << ".0";
}
return *this; return *this;
} }
@ -550,12 +477,8 @@ void SStream::write_hex(unsigned char c, bool non_zero) {
unsigned char high = c >> 4; unsigned char high = c >> 4;
unsigned char low = c & 0xf; unsigned char low = c & 0xf;
if(non_zero) { if(non_zero) {
if(high) { if(high) { (*this) << PK_HEX_TABLE[high]; }
(*this) << PK_HEX_TABLE[high]; if(high || low) { (*this) << PK_HEX_TABLE[low]; }
}
if(high || low) {
(*this) << PK_HEX_TABLE[low];
}
} else { } else {
(*this) << PK_HEX_TABLE[high]; (*this) << PK_HEX_TABLE[high];
(*this) << PK_HEX_TABLE[low]; (*this) << PK_HEX_TABLE[low];
@ -573,9 +496,7 @@ void SStream::write_hex(void* p) {
for(int i = sizeof(void*) - 1; i >= 0; i--) { for(int i = sizeof(void*) - 1; i >= 0; i--) {
unsigned char cpnt = (p_t >> (i * 8)) & 0xff; unsigned char cpnt = (p_t >> (i * 8)) & 0xff;
write_hex(cpnt, non_zero); write_hex(cpnt, non_zero);
if(cpnt != 0) { if(cpnt != 0) { non_zero = false; }
non_zero = false;
}
} }
} }
@ -593,9 +514,7 @@ void SStream::write_hex(i64 val) {
for(int i = 56; i >= 0; i -= 8) { for(int i = 56; i >= 0; i -= 8) {
unsigned char cpnt = (val >> i) & 0xff; unsigned char cpnt = (val >> i) & 0xff;
write_hex(cpnt, non_zero); write_hex(cpnt, non_zero);
if(cpnt != 0) { if(cpnt != 0) { non_zero = false; }
non_zero = false;
}
} }
} }

View File

@ -9,9 +9,7 @@ PrattRule Compiler::rules[kTokenCount];
NameScope Compiler::name_scope() const { NameScope Compiler::name_scope() const {
auto s = contexts.size() > 1 ? NAME_LOCAL : NAME_GLOBAL; auto s = contexts.size() > 1 ? NAME_LOCAL : NAME_GLOBAL;
if(unknown_global_scope && s == NAME_GLOBAL) { if(unknown_global_scope && s == NAME_GLOBAL) { s = NAME_GLOBAL_UNKNOWN; }
s = NAME_GLOBAL_UNKNOWN;
}
return s; return s;
} }
@ -33,9 +31,7 @@ FuncDecl_ Compiler::push_f_context(Str name) {
} }
void Compiler::pop_context() { void Compiler::pop_context() {
if(!ctx()->s_expr.empty()) { if(!ctx()->s_expr.empty()) { throw std::runtime_error("!ctx()->s_expr.empty()"); }
throw std::runtime_error("!ctx()->s_expr.empty()");
}
// add a `return None` in the end as a guard // add a `return None` in the end as a guard
// previously, we only do this if the last opcode is not a return // 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 // 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 // some check here
auto& codes = ctx()->co->codes; auto& codes = ctx()->co->codes;
if(ctx()->co->nlocals > PK_MAX_CO_VARNAMES) { if(ctx()->co->nlocals > PK_MAX_CO_VARNAMES) { SyntaxError("maximum number of local variables exceeded"); }
SyntaxError("maximum number of local variables exceeded"); if(ctx()->co->consts.size() > 65530) { SyntaxError("maximum number of constants exceeded"); }
}
if(ctx()->co->consts.size() > 65530) {
SyntaxError("maximum number of constants exceeded");
}
// pre-compute LOOP_BREAK and LOOP_CONTINUE // pre-compute LOOP_BREAK and LOOP_CONTINUE
for(int i = 0; i < codes.size(); i++) { for(int i = 0; i < codes.size(); i++) {
Bytecode& bc = codes[i]; Bytecode& bc = codes[i];
@ -81,15 +73,9 @@ void Compiler::pop_context() {
} }
if(func->type == FuncType::UNSET) { if(func->type == FuncType::UNSET) {
bool is_simple = true; bool is_simple = true;
if(func->kwargs.size() > 0) { if(func->kwargs.size() > 0) { is_simple = false; }
is_simple = false; if(func->starred_arg >= 0) { is_simple = false; }
} if(func->starred_kwarg >= 0) { is_simple = false; }
if(func->starred_arg >= 0) {
is_simple = false;
}
if(func->starred_kwarg >= 0) {
is_simple = false;
}
if(is_simple) { if(is_simple) {
func->type = FuncType::SIMPLE; func->type = FuncType::SIMPLE;
@ -97,13 +83,9 @@ void Compiler::pop_context() {
bool is_empty = false; bool is_empty = false;
if(func->code->codes.size() == 1) { if(func->code->codes.size() == 1) {
Bytecode bc = func->code->codes[0]; Bytecode bc = func->code->codes[0];
if(bc.op == OP_RETURN_VALUE && bc.arg == 1) { if(bc.op == OP_RETURN_VALUE && bc.arg == 1) { is_empty = true; }
is_empty = true;
}
}
if(is_empty) {
func->type = FuncType::EMPTY;
} }
if(is_empty) { func->type = FuncType::EMPTY; }
} else { } else {
func->type = FuncType::NORMAL; func->type = FuncType::NORMAL;
} }
@ -116,9 +98,7 @@ void Compiler::pop_context() {
void Compiler::init_pratt_rules() { void Compiler::init_pratt_rules() {
static bool initialized = false; static bool initialized = false;
if(initialized) { if(initialized) { return; }
return;
}
initialized = true; initialized = true;
// clang-format off // clang-format off
@ -178,17 +158,13 @@ void Compiler::init_pratt_rules() {
} }
bool Compiler::match(TokenIndex expected) { bool Compiler::match(TokenIndex expected) {
if(curr().type != expected) { if(curr().type != expected) { return false; }
return false;
}
advance(); advance();
return true; return true;
} }
void Compiler::consume(TokenIndex expected) { void Compiler::consume(TokenIndex expected) {
if(!match(expected)) { if(!match(expected)) { SyntaxError(_S("expected '", TK_STR(expected), "', got '", TK_STR(curr().type), "'")); }
SyntaxError(_S("expected '", TK_STR(expected), "', got '", TK_STR(curr().type), "'"));
}
} }
bool Compiler::match_newlines_repl() { return match_newlines(mode() == REPL_MODE); } bool Compiler::match_newlines_repl() { return match_newlines(mode() == REPL_MODE); }
@ -201,9 +177,7 @@ bool Compiler::match_newlines(bool repl_throw) {
} }
consumed = true; consumed = true;
} }
if(repl_throw && curr().type == TK("@eof")) { if(repl_throw && curr().type == TK("@eof")) { throw NeedMoreLines(ctx()->is_compiling_class); }
throw NeedMoreLines(ctx()->is_compiling_class);
}
return consumed; return consumed;
} }
@ -212,43 +186,29 @@ bool Compiler::match_end_stmt() {
match_newlines(); match_newlines();
return true; return true;
} }
if(match_newlines() || curr().type == TK("@eof")) { if(match_newlines() || curr().type == TK("@eof")) { return true; }
return true; if(curr().type == TK("@dedent")) { return true; }
}
if(curr().type == TK("@dedent")) {
return true;
}
return false; return false;
} }
void Compiler::consume_end_stmt() { void Compiler::consume_end_stmt() {
if(!match_end_stmt()) { if(!match_end_stmt()) { SyntaxError("expected statement end"); }
SyntaxError("expected statement end");
}
} }
void Compiler::EXPR() { parse_expression(PREC_LOWEST + 1); } void Compiler::EXPR() { parse_expression(PREC_LOWEST + 1); }
void Compiler::EXPR_TUPLE(bool allow_slice) { void Compiler::EXPR_TUPLE(bool allow_slice) {
parse_expression(PREC_LOWEST + 1, allow_slice); parse_expression(PREC_LOWEST + 1, allow_slice);
if(!match(TK(","))) { if(!match(TK(","))) { return; }
return;
}
// tuple expression // tuple expression
Expr_vector items; Expr_vector items;
items.push_back(ctx()->s_expr.popx()); items.push_back(ctx()->s_expr.popx());
do { do {
if(curr().brackets_level) { if(curr().brackets_level) { match_newlines_repl(); }
match_newlines_repl(); if(!is_expression(allow_slice)) { break; }
}
if(!is_expression(allow_slice)) {
break;
}
parse_expression(PREC_LOWEST + 1, allow_slice); parse_expression(PREC_LOWEST + 1, allow_slice);
items.push_back(ctx()->s_expr.popx()); items.push_back(ctx()->s_expr.popx());
if(curr().brackets_level) { if(curr().brackets_level) { match_newlines_repl(); }
match_newlines_repl();
}
} while(match(TK(","))); } while(match(TK(",")));
ctx()->s_expr.push(make_expr<TupleExpr>(std::move(items))); ctx()->s_expr.push(make_expr<TupleExpr>(std::move(items)));
} }
@ -260,9 +220,7 @@ Expr_ Compiler::EXPR_VARS() {
consume(TK("@id")); consume(TK("@id"));
items.push_back(make_expr<NameExpr>(prev().str(), name_scope())); items.push_back(make_expr<NameExpr>(prev().str(), name_scope()));
} while(match(TK(","))); } while(match(TK(",")));
if(items.size() == 1) { if(items.size() == 1) { return std::move(items[0]); }
return std::move(items[0]);
}
return make_expr<TupleExpr>(std::move(items)); return make_expr<TupleExpr>(std::move(items));
} }
@ -351,9 +309,7 @@ void Compiler::exprGroup() {
EXPR_TUPLE(); // () is just for change precedence EXPR_TUPLE(); // () is just for change precedence
match_newlines_repl(); match_newlines_repl();
consume(TK(")")); consume(TK(")"));
if(ctx()->s_expr.top()->is_tuple()) { if(ctx()->s_expr.top()->is_tuple()) { return; }
return;
}
Expr_ g = make_expr<GroupedExpr>(ctx()->s_expr.popx()); Expr_ g = make_expr<GroupedExpr>(ctx()->s_expr.popx());
ctx()->s_expr.push(std::move(g)); ctx()->s_expr.push(std::move(g));
} }
@ -378,9 +334,7 @@ void Compiler::exprList() {
Expr_vector items; Expr_vector items;
do { do {
match_newlines_repl(); match_newlines_repl();
if(curr().type == TK("]")) { if(curr().type == TK("]")) { break; }
break;
}
EXPR(); EXPR();
items.push_back(ctx()->s_expr.popx()); items.push_back(ctx()->s_expr.popx());
match_newlines_repl(); match_newlines_repl();
@ -402,14 +356,10 @@ void Compiler::exprMap() {
Expr_vector items; Expr_vector items;
do { do {
match_newlines_repl(); match_newlines_repl();
if(curr().type == TK("}")) { if(curr().type == TK("}")) { break; }
break;
}
EXPR(); EXPR();
int star_level = ctx()->s_expr.top()->star_level(); int star_level = ctx()->s_expr.top()->star_level();
if(star_level == 2 || curr().type == TK(":")) { if(star_level == 2 || curr().type == TK(":")) { parsing_dict = true; }
parsing_dict = true;
}
if(parsing_dict) { if(parsing_dict) {
auto dict_item = make_expr<DictItemExpr>(); auto dict_item = make_expr<DictItemExpr>();
if(star_level == 2) { if(star_level == 2) {
@ -452,9 +402,7 @@ void Compiler::exprCall() {
e->callable = ctx()->s_expr.popx(); e->callable = ctx()->s_expr.popx();
do { do {
match_newlines_repl(); match_newlines_repl();
if(curr().type == TK(")")) { if(curr().type == TK(")")) { break; }
break;
}
if(curr().type == TK("@id") && next().type == TK("=")) { if(curr().type == TK("@id") && next().type == TK("=")) {
consume(TK("@id")); consume(TK("@id"));
Str key = prev().str(); Str key = prev().str();
@ -468,30 +416,22 @@ void Compiler::exprCall() {
e->kwargs.push_back({"**", ctx()->s_expr.popx()}); e->kwargs.push_back({"**", ctx()->s_expr.popx()});
} else { } else {
// positional argument // positional argument
if(!e->kwargs.empty()) { if(!e->kwargs.empty()) { SyntaxError("positional argument follows keyword argument"); }
SyntaxError("positional argument follows keyword argument");
}
e->args.push_back(ctx()->s_expr.popx()); e->args.push_back(ctx()->s_expr.popx());
} }
} }
match_newlines_repl(); match_newlines_repl();
} while(match(TK(","))); } while(match(TK(",")));
consume(TK(")")); consume(TK(")"));
if(e->args.size() > 32767) { if(e->args.size() > 32767) { SyntaxError("too many positional arguments"); }
SyntaxError("too many positional arguments"); if(e->kwargs.size() > 32767) { SyntaxError("too many keyword arguments"); }
}
if(e->kwargs.size() > 32767) {
SyntaxError("too many keyword arguments");
}
ctx()->s_expr.push(std::move(e)); ctx()->s_expr.push(std::move(e));
} }
void Compiler::exprName() { void Compiler::exprName() {
Str name = prev().str(); Str name = prev().str();
NameScope scope = name_scope(); NameScope scope = name_scope();
if(ctx()->global_names.contains(name)) { if(ctx()->global_names.contains(name)) { scope = NAME_GLOBAL; }
scope = NAME_GLOBAL;
}
ctx()->s_expr.push(make_expr<NameExpr>(name, scope)); 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::exprLiteral0() { ctx()->s_expr.push(make_expr<Literal0Expr>(prev().type)); }
void Compiler::compile_block_body(void (Compiler::*callback)()) { void Compiler::compile_block_body(void (Compiler::*callback)()) {
if(callback == nullptr) { if(callback == nullptr) { callback = &Compiler::compile_stmt; }
callback = &Compiler::compile_stmt;
}
consume(TK(":")); consume(TK(":"));
if(curr().type != TK("@eol") && curr().type != TK("@eof")) { if(curr().type != TK("@eol") && curr().type != TK("@eof")) {
while(true) { while(true) {
compile_stmt(); compile_stmt();
bool possible = curr().type != TK("@eol") && curr().type != TK("@eof"); bool possible = curr().type != TK("@eol") && curr().type != TK("@eof");
if(prev().type != TK(";") || !possible) { if(prev().type != TK(";") || !possible) { break; }
break;
}
} }
return; return;
} }
if(!match_newlines(mode() == REPL_MODE)) { if(!match_newlines(mode() == REPL_MODE)) { SyntaxError("expected a new line after ':'"); }
SyntaxError("expected a new line after ':'");
}
consume(TK("@indent")); consume(TK("@indent"));
while(curr().type != TK("@dedent")) { while(curr().type != TK("@dedent")) {
match_newlines(); match_newlines();
@ -641,9 +575,7 @@ __EAT_DOTS_END:
consume(TK("import")); consume(TK("import"));
if(match(TK("*"))) { if(match(TK("*"))) {
if(name_scope() != NAME_GLOBAL) { if(name_scope() != NAME_GLOBAL) { SyntaxError("from <module> import * can only be used in global scope"); }
SyntaxError("from <module> import * can only be used in global scope");
}
// pop the module and import __all__ // pop the module and import __all__
ctx()->emit_(OP_POP_IMPORT_STAR, BC_NOARG, prev().line); ctx()->emit_(OP_POP_IMPORT_STAR, BC_NOARG, prev().line);
consume_end_stmt(); consume_end_stmt();
@ -816,9 +748,7 @@ void Compiler::compile_decorated() {
do { do {
EXPR(); EXPR();
decorators.push_back(ctx()->s_expr.popx()); decorators.push_back(ctx()->s_expr.popx());
if(!match_newlines_repl()) { if(!match_newlines_repl()) { SyntaxError(); }
SyntaxError();
}
} while(match(TK("@"))); } while(match(TK("@")));
if(match(TK("class"))) { if(match(TK("class"))) {
@ -843,12 +773,8 @@ bool Compiler::try_compile_assignment() {
case TK("|="): case TK("|="):
case TK("^="): { case TK("^="): {
Expr* lhs_p = ctx()->s_expr.top().get(); Expr* lhs_p = ctx()->s_expr.top().get();
if(lhs_p->is_starred()) { if(lhs_p->is_starred()) { SyntaxError(); }
SyntaxError(); if(ctx()->is_compiling_class) { SyntaxError("can't use inplace operator in class definition"); }
}
if(ctx()->is_compiling_class) {
SyntaxError("can't use inplace operator in class definition");
}
advance(); advance();
// a[x] += 1; a and x should be evaluated only once // a[x] += 1; a and x should be evaluated only once
// a.x += 1; a should be evaluated only once // a.x += 1; a should be evaluated only once
@ -857,14 +783,10 @@ bool Compiler::try_compile_assignment() {
e->lhs = ctx()->s_expr.popx(); e->lhs = ctx()->s_expr.popx();
EXPR_TUPLE(); EXPR_TUPLE();
e->rhs = ctx()->s_expr.popx(); e->rhs = ctx()->s_expr.popx();
if(e->rhs->is_starred()) { if(e->rhs->is_starred()) { SyntaxError(); }
SyntaxError();
}
e->emit_(ctx()); e->emit_(ctx());
bool ok = lhs_p->emit_store_inplace(ctx()); bool ok = lhs_p->emit_store_inplace(ctx());
if(!ok) { if(!ok) { SyntaxError(); }
SyntaxError();
}
} }
return true; return true;
case TK("="): { case TK("="): {
@ -881,13 +803,9 @@ bool Compiler::try_compile_assignment() {
} }
for(int j = 0; j < n; j++) { for(int j = 0; j < n; j++) {
auto e = ctx()->s_expr.popx(); auto e = ctx()->s_expr.popx();
if(e->is_starred()) { if(e->is_starred()) { SyntaxError(); }
SyntaxError();
}
bool ok = e->emit_store(ctx()); bool ok = e->emit_store(ctx());
if(!ok) { if(!ok) { SyntaxError(); }
SyntaxError();
}
} }
} }
return true; return true;
@ -905,32 +823,24 @@ void Compiler::compile_stmt() {
int curr_loop_block = ctx()->get_loop(); int curr_loop_block = ctx()->get_loop();
switch(prev().type) { switch(prev().type) {
case TK("break"): case TK("break"):
if(curr_loop_block < 0) { if(curr_loop_block < 0) { SyntaxError("'break' outside loop"); }
SyntaxError("'break' outside loop");
}
ctx()->emit_(OP_LOOP_BREAK, curr_loop_block, kw_line); ctx()->emit_(OP_LOOP_BREAK, curr_loop_block, kw_line);
consume_end_stmt(); consume_end_stmt();
break; break;
case TK("continue"): case TK("continue"):
if(curr_loop_block < 0) { if(curr_loop_block < 0) { SyntaxError("'continue' not properly in loop"); }
SyntaxError("'continue' not properly in loop");
}
ctx()->emit_(OP_LOOP_CONTINUE, curr_loop_block, kw_line); ctx()->emit_(OP_LOOP_CONTINUE, curr_loop_block, kw_line);
consume_end_stmt(); consume_end_stmt();
break; break;
case TK("yield"): case TK("yield"):
if(contexts.size() <= 1) { if(contexts.size() <= 1) { SyntaxError("'yield' outside function"); }
SyntaxError("'yield' outside function");
}
EXPR_TUPLE(); EXPR_TUPLE();
ctx()->emit_expr(); ctx()->emit_expr();
ctx()->emit_(OP_YIELD_VALUE, BC_NOARG, kw_line); ctx()->emit_(OP_YIELD_VALUE, BC_NOARG, kw_line);
consume_end_stmt(); consume_end_stmt();
break; break;
case TK("yield from"): case TK("yield from"):
if(contexts.size() <= 1) { if(contexts.size() <= 1) { SyntaxError("'yield from' outside function"); }
SyntaxError("'yield from' outside function");
}
EXPR_TUPLE(); EXPR_TUPLE();
ctx()->emit_expr(); ctx()->emit_expr();
@ -942,9 +852,7 @@ void Compiler::compile_stmt() {
consume_end_stmt(); consume_end_stmt();
break; break;
case TK("return"): case TK("return"):
if(contexts.size() <= 1) { if(contexts.size() <= 1) { SyntaxError("'return' outside function"); }
SyntaxError("'return' outside function");
}
if(match_end_stmt()) { if(match_end_stmt()) {
ctx()->emit_(OP_RETURN_VALUE, 1, kw_line); ctx()->emit_(OP_RETURN_VALUE, 1, kw_line);
} else { } else {
@ -970,9 +878,7 @@ void Compiler::compile_stmt() {
StrName name(prev().sv()); StrName name(prev().sv());
NameScope scope = name_scope(); NameScope scope = name_scope();
bool is_global = ctx()->global_names.contains(name.sv()); bool is_global = ctx()->global_names.contains(name.sv());
if(is_global) { if(is_global) { scope = NAME_GLOBAL; }
scope = NAME_GLOBAL;
}
switch(scope) { switch(scope) {
case NAME_LOCAL: ctx()->emit_(OP_INC_FAST, ctx()->add_varname(name), prev().line); break; case NAME_LOCAL: ctx()->emit_(OP_INC_FAST, ctx()->add_varname(name), prev().line); break;
case NAME_GLOBAL: ctx()->emit_(OP_INC_GLOBAL, name.index, prev().line); break; case NAME_GLOBAL: ctx()->emit_(OP_INC_GLOBAL, name.index, prev().line); break;
@ -1024,9 +930,7 @@ void Compiler::compile_stmt() {
EXPR_TUPLE(); EXPR_TUPLE();
Expr_ e = ctx()->s_expr.popx(); Expr_ e = ctx()->s_expr.popx();
bool ok = e->emit_del(ctx()); bool ok = e->emit_del(ctx());
if(!ok) { if(!ok) { SyntaxError(); }
SyntaxError();
}
consume_end_stmt(); consume_end_stmt();
} break; } break;
case TK("with"): { case TK("with"): {
@ -1042,9 +946,7 @@ void Compiler::compile_stmt() {
// [ <expr> <expr>.__enter__() ] // [ <expr> <expr>.__enter__() ]
if(as_name != nullptr) { if(as_name != nullptr) {
bool ok = as_name->emit_store(ctx()); bool ok = as_name->emit_store(ctx());
if(!ok) { if(!ok) { SyntaxError(); }
SyntaxError();
}
} else { } else {
ctx()->emit_(OP_POP_TOP, BC_NOARG, BC_KEEPLINE); ctx()->emit_(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
} }
@ -1055,21 +957,15 @@ void Compiler::compile_stmt() {
/*************************************************/ /*************************************************/
case TK("=="): { case TK("=="): {
consume(TK("@id")); consume(TK("@id"));
if(mode() != EXEC_MODE) { if(mode() != EXEC_MODE) { SyntaxError("'label' is only available in EXEC_MODE"); }
SyntaxError("'label' is only available in EXEC_MODE");
}
bool ok = ctx()->add_label(prev().str()); bool ok = ctx()->add_label(prev().str());
consume(TK("==")); consume(TK("=="));
if(!ok) { if(!ok) { SyntaxError("label " + prev().str().escape() + " already exists"); }
SyntaxError("label " + prev().str().escape() + " already exists");
}
consume_end_stmt(); consume_end_stmt();
} break; } break;
case TK("->"): case TK("->"):
consume(TK("@id")); consume(TK("@id"));
if(mode() != EXEC_MODE) { if(mode() != EXEC_MODE) { SyntaxError("'goto' is only available in EXEC_MODE"); }
SyntaxError("'goto' is only available in EXEC_MODE");
}
ctx()->emit_(OP_GOTO, StrName(prev().sv()).index, prev().line); ctx()->emit_(OP_GOTO, StrName(prev().sv()).index, prev().line);
consume_end_stmt(); consume_end_stmt();
break; break;
@ -1093,9 +989,7 @@ void Compiler::compile_stmt() {
} }
} }
if(!try_compile_assignment()) { if(!try_compile_assignment()) {
if(!ctx()->s_expr.empty() && ctx()->s_expr.top()->is_starred()) { if(!ctx()->s_expr.empty() && ctx()->s_expr.top()->is_starred()) { SyntaxError(); }
SyntaxError();
}
if(!is_typed_name) { if(!is_typed_name) {
ctx()->emit_expr(); ctx()->emit_expr();
if((mode() == CELL_MODE || mode() == REPL_MODE) && name_scope() == NAME_GLOBAL) { 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); ctx()->emit_(OP_BEGIN_CLASS, namei, BC_KEEPLINE);
for(auto& c: this->contexts.container()) { for(auto& c: this->contexts.container()) {
if(c.is_compiling_class) { if(c.is_compiling_class) { SyntaxError("nested class is not allowed"); }
SyntaxError("nested class is not allowed");
}
} }
ctx()->is_compiling_class = true; ctx()->is_compiling_class = true;
compile_block_body(); 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) { void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) {
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
do { do {
if(state > 3) { if(state > 3) { SyntaxError(); }
SyntaxError(); if(state == 3) { SyntaxError("**kwargs should be the last argument"); }
}
if(state == 3) {
SyntaxError("**kwargs should be the last argument");
}
match_newlines(); match_newlines();
if(match(TK("*"))) { if(match(TK("*"))) {
if(state < 1) { if(state < 1) {
@ -1189,14 +1077,10 @@ void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) {
// check duplicate argument name // check duplicate argument name
for(int j: decl->args) { for(int j: decl->args) {
if(decl->code->varnames[j] == name) { if(decl->code->varnames[j] == name) { SyntaxError("duplicate argument name"); }
SyntaxError("duplicate argument name");
}
} }
for(auto& kv: decl->kwargs) { for(auto& kv: decl->kwargs) {
if(decl->code->varnames[kv.index] == name) { if(decl->code->varnames[kv.index] == name) { SyntaxError("duplicate argument name"); }
SyntaxError("duplicate argument name");
}
} }
if(decl->starred_arg != -1 && decl->code->varnames[decl->starred_arg] == name) { if(decl->starred_arg != -1 && decl->code->varnames[decl->starred_arg] == name) {
SyntaxError("duplicate argument name"); SyntaxError("duplicate argument name");
@ -1206,12 +1090,8 @@ void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) {
} }
// eat type hints // eat type hints
if(enable_type_hints && match(TK(":"))) { if(enable_type_hints && match(TK(":"))) { consume_type_hints(); }
consume_type_hints(); if(state == 0 && curr().type == TK("=")) { state = 2; }
}
if(state == 0 && curr().type == TK("=")) {
state = 2;
}
int index = ctx()->add_varname(name); int index = ctx()->add_varname(name);
switch(state) { switch(state) {
case 0: decl->args.push_back(index); break; case 0: decl->args.push_back(index); break;
@ -1222,9 +1102,7 @@ void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) {
case 2: { case 2: {
consume(TK("=")); consume(TK("="));
PyVar value = read_literal(); PyVar value = read_literal();
if(value == nullptr) { if(value == nullptr) { SyntaxError(Str("default argument must be a literal")); }
SyntaxError(Str("default argument must be a literal"));
}
decl->add_kwarg(index, name, value); decl->add_kwarg(index, name, value);
} break; } break;
case 3: case 3:
@ -1244,9 +1122,7 @@ void Compiler::compile_function(const Expr_vector& decorators) {
_compile_f_args(decl, true); _compile_f_args(decl, true);
consume(TK(")")); consume(TK(")"));
} }
if(match(TK("->"))) { if(match(TK("->"))) { consume_type_hints(); }
consume_type_hints();
}
compile_block_body(); compile_block_body();
pop_context(); pop_context();
@ -1275,15 +1151,9 @@ void Compiler::compile_function(const Expr_vector& decorators) {
PyVar Compiler::to_object(const TokenValue& value) { PyVar Compiler::to_object(const TokenValue& value) {
PyVar obj = nullptr; PyVar obj = nullptr;
if(std::holds_alternative<i64>(value)) { if(std::holds_alternative<i64>(value)) { obj = VAR(std::get<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<f64>(value)) {
obj = VAR(std::get<f64>(value));
}
if(std::holds_alternative<Str>(value)) {
obj = VAR(std::get<Str>(value));
}
assert(obj != nullptr); assert(obj != nullptr);
return obj; return obj;
} }
@ -1306,13 +1176,9 @@ PyVar Compiler::read_literal() {
List cpnts; List cpnts;
while(true) { while(true) {
cpnts.push_back(read_literal()); cpnts.push_back(read_literal());
if(curr().type == TK(")")) { if(curr().type == TK(")")) { break; }
break;
}
consume(TK(",")); consume(TK(","));
if(curr().type == TK(")")) { if(curr().type == TK(")")) { break; }
break;
}
} }
consume(TK(")")); consume(TK(")"));
return VAR(cpnts.to_tuple()); return VAR(cpnts.to_tuple());
@ -1359,9 +1225,7 @@ Str Compiler::precompile() {
for(int i = 0; i < tokens.size(); i++) { for(int i = 0; i < tokens.size(); i++) {
const Token& token = tokens[i]; const Token& token = tokens[i];
ss << (int)token.type << ','; ss << (int)token.type << ',';
if(is_raw_string_used(token.type)) { if(is_raw_string_used(token.type)) { ss << token_indices[token.sv()] << ','; }
ss << token_indices[token.sv()] << ',';
}
if(i > 0 && tokens[i - 1].line == token.line) { if(i > 0 && tokens[i - 1].line == token.line) {
ss << ','; ss << ',';
} else { } else {
@ -1402,9 +1266,7 @@ void Compiler::from_precompiled(const char* source) {
Str error = _S("precompiled version mismatch: ", version, "!=" PK_VERSION); Str error = _S("precompiled version mismatch: ", version, "!=" PK_VERSION);
throw std::runtime_error(error.c_str()); throw std::runtime_error(error.c_str());
} }
if(deserializer.read_uint('\n') != (i64)mode()) { if(deserializer.read_uint('\n') != (i64)mode()) { throw std::runtime_error("precompiled mode mismatch"); }
throw std::runtime_error("precompiled mode mismatch");
}
int count = deserializer.read_count(); int count = deserializer.read_count();
vector<Str>& precompiled_tokens = lexer.src->_precompiled_tokens; vector<Str>& precompiled_tokens = lexer.src->_precompiled_tokens;
@ -1472,9 +1334,7 @@ CodeObject_ Compiler::compile() {
} else if(mode() == JSON_MODE) { } else if(mode() == JSON_MODE) {
EXPR(); EXPR();
Expr_ e = ctx()->s_expr.popx(); Expr_ e = ctx()->s_expr.popx();
if(!e->is_json_object()) { if(!e->is_json_object()) { SyntaxError("expect a JSON object, literal or array"); }
SyntaxError("expect a JSON object, literal or array");
}
consume(TK("@eof")); consume(TK("@eof"));
e->emit_(ctx()); e->emit_(ctx());
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);

View File

@ -4,16 +4,10 @@
namespace pkpy { namespace pkpy {
inline bool is_identifier(std::string_view s) { inline bool is_identifier(std::string_view s) {
if(s.empty()) { if(s.empty()) { return false; }
return false; if(!isalpha(s[0]) && s[0] != '_') { return false; }
}
if(!isalpha(s[0]) && s[0] != '_') {
return false;
}
for(char c: s) { for(char c: s) {
if(!isalnum(c) && c != '_') { if(!isalnum(c) && c != '_') { return false; }
return false;
}
} }
return true; 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 CodeEmitContext::get_loop() const {
int index = curr_iblock; int index = curr_iblock;
while(index >= 0) { while(index >= 0) {
if(co->blocks[index].type == CodeBlockType::FOR_LOOP) { if(co->blocks[index].type == CodeBlockType::FOR_LOOP) { break; }
break; if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) { break; }
}
if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) {
break;
}
index = co->blocks[index].parent; index = co->blocks[index].parent;
} }
return index; return index;
@ -79,12 +69,8 @@ void CodeEmitContext::revert_last_emit_() {
void CodeEmitContext::try_merge_for_iter_store(int i) { void CodeEmitContext::try_merge_for_iter_store(int i) {
// [FOR_ITER, STORE_?, ] // [FOR_ITER, STORE_?, ]
if(co->codes[i].op != OP_FOR_ITER) { if(co->codes[i].op != OP_FOR_ITER) { return; }
return; if(co->codes.size() - i != 2) { return; }
}
if(co->codes.size() - i != 2) {
return;
}
uint16_t arg = co->codes[i + 1].arg; uint16_t arg = co->codes[i + 1].arg;
if(co->codes[i + 1].op == OP_STORE_FAST) { if(co->codes[i + 1].op == OP_STORE_FAST) {
revert_last_emit_(); revert_last_emit_();
@ -114,9 +100,7 @@ void CodeEmitContext::patch_jump(int index) {
} }
bool CodeEmitContext::add_label(StrName name) { bool CodeEmitContext::add_label(StrName name) {
if(co->labels.contains(name)) { if(co->labels.contains(name)) { return false; }
return false;
}
co->labels.set(name, co->codes.size()); co->labels.set(name, co->codes.size());
return true; return true;
} }
@ -124,9 +108,7 @@ bool CodeEmitContext::add_label(StrName name) {
int CodeEmitContext::add_varname(StrName name) { int CodeEmitContext::add_varname(StrName name) {
// PK_MAX_CO_VARNAMES will be checked when pop_context(), not here // PK_MAX_CO_VARNAMES will be checked when pop_context(), not here
int index = co->varnames_inv.try_get(name); int index = co->varnames_inv.try_get(name);
if(index >= 0) { if(index >= 0) { return index; }
return index;
}
co->varnames.push_back(name); co->varnames.push_back(name);
co->nlocals++; co->nlocals++;
index = co->varnames.size() - 1; index = co->varnames.size() - 1;
@ -188,9 +170,7 @@ void NameExpr::emit_(CodeEmitContext* ctx) {
// exec()/eval() won't work with OP_LOAD_ATTR_GLOBAL in class body // exec()/eval() won't work with OP_LOAD_ATTR_GLOBAL in class body
} else { } else {
// we cannot determine the scope when calling exec()/eval() // we cannot determine the scope when calling exec()/eval()
if(scope == NAME_GLOBAL_UNKNOWN) { if(scope == NAME_GLOBAL_UNKNOWN) { op = OP_LOAD_NAME; }
op = OP_LOAD_NAME;
}
} }
ctx->emit_(op, StrName(name).index, line); ctx->emit_(op, StrName(name).index, line);
} }
@ -226,9 +206,7 @@ void StarredExpr::emit_(CodeEmitContext* ctx) {
} }
bool StarredExpr::emit_store(CodeEmitContext* ctx) { bool StarredExpr::emit_store(CodeEmitContext* ctx) {
if(level != 1) { if(level != 1) { return false; }
return false;
}
// simply proxy to child // simply proxy to child
return child->emit_store(ctx); return child->emit_store(ctx);
} }
@ -355,9 +333,7 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
// items may contain StarredExpr, we should check it // items may contain StarredExpr, we should check it
int starred_i = -1; int starred_i = -1;
for(int i = 0; i < items.size(); i++) { for(int i = 0; i < items.size(); i++) {
if(!items[i]->is_starred()) { if(!items[i]->is_starred()) { continue; }
continue;
}
if(starred_i == -1) { if(starred_i == -1) {
starred_i = i; starred_i = i;
} else { } else {
@ -380,13 +356,9 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
} }
} else { } else {
// starred assignment target must be in a tuple // starred assignment target must be in a tuple
if(items.size() == 1) { if(items.size() == 1) { return false; }
return false;
}
// starred assignment target must be the last one (differ from cpython) // starred assignment target must be the last one (differ from cpython)
if(starred_i != items.size() - 1) { if(starred_i != items.size() - 1) { return false; }
return false;
}
// a,*b = [1,2,3] // a,*b = [1,2,3]
// stack is [1,2,3] -> [1,[2,3]] // stack is [1,2,3] -> [1,[2,3]]
ctx->emit_(OP_UNPACK_EX, items.size() - 1, line); ctx->emit_(OP_UNPACK_EX, items.size() - 1, line);
@ -394,9 +366,7 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
// do reverse emit // do reverse emit
for(int i = items.size() - 1; i >= 0; i--) { for(int i = items.size() - 1; i >= 0; i--) {
bool ok = items[i]->emit_store(ctx); bool ok = items[i]->emit_store(ctx);
if(!ok) { if(!ok) { return false; }
return false;
}
} }
return true; return true;
} }
@ -404,9 +374,7 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
bool TupleExpr::emit_del(CodeEmitContext* ctx) { bool TupleExpr::emit_del(CodeEmitContext* ctx) {
for(auto& e: items) { for(auto& e: items) {
bool ok = e->emit_del(ctx); bool ok = e->emit_del(ctx);
if(!ok) { if(!ok) { return false; }
return false;
}
} }
return true; return true;
} }
@ -474,9 +442,7 @@ void FStringExpr::_load_simple_expr(CodeEmitContext* ctx, Str expr) {
ctx->emit_(OP_FSTRING_EVAL, index, line); ctx->emit_(OP_FSTRING_EVAL, index, line);
} }
if(repr) { if(repr) { ctx->emit_(OP_REPR, BC_NOARG, line); }
ctx->emit_(OP_REPR, BC_NOARG, line);
}
} }
static bool is_fmt_valid_char(char c) { static bool is_fmt_valid_char(char c) {
@ -666,14 +632,10 @@ void CallExpr::emit_(CodeEmitContext* ctx) {
bool vargs = false; bool vargs = false;
bool vkwargs = false; bool vkwargs = false;
for(auto& arg: args) { for(auto& arg: args) {
if(arg->is_starred()) { if(arg->is_starred()) { vargs = true; }
vargs = true;
}
} }
for(auto& item: kwargs) { for(auto& item: kwargs) {
if(item.second->is_starred()) { if(item.second->is_starred()) { vkwargs = true; }
vkwargs = true;
}
} }
// if callable is a AttrExpr, we should try to use `fast_call` instead of use `boundmethod` proxy // if callable is a AttrExpr, we should try to use `fast_call` instead of use `boundmethod` proxy

View File

@ -22,29 +22,19 @@ static bool is_possible_number_char(char c) {
static bool is_unicode_Lo_char(uint32_t c) { static bool is_unicode_Lo_char(uint32_t c) {
// open a hole for carrot // open a hole for carrot
if(c == U'🥕') { if(c == U'🥕') { return true; }
return true;
}
auto index = std::lower_bound(kLoRangeA, kLoRangeA + 476, c) - kLoRangeA; auto index = std::lower_bound(kLoRangeA, kLoRangeA + 476, c) - kLoRangeA;
if(c == kLoRangeA[index]) { if(c == kLoRangeA[index]) { return true; }
return true;
}
index -= 1; index -= 1;
if(index < 0) { if(index < 0) { return false; }
return false;
}
return c >= kLoRangeA[index] && c <= kLoRangeB[index]; return c >= kLoRangeA[index] && c <= kLoRangeB[index];
} }
bool Lexer::match_n_chars(int n, char c0) { bool Lexer::match_n_chars(int n, char c0) {
const char* c = curr_char; const char* c = curr_char;
for(int i = 0; i < n; i++) { for(int i = 0; i < n; i++) {
if(*c == '\0') { if(*c == '\0') { return false; }
return false; if(*c != c0) { return false; }
}
if(*c != c0) {
return false;
}
c++; c++;
} }
for(int i = 0; i < n; i++) { for(int i = 0; i < n; i++) {
@ -77,16 +67,10 @@ int Lexer::eat_spaces() {
} }
bool Lexer::eat_indentation() { bool Lexer::eat_indentation() {
if(brackets_level > 0) { if(brackets_level > 0) { return true; }
return true;
}
int spaces = eat_spaces(); int spaces = eat_spaces();
if(peekchar() == '#') { if(peekchar() == '#') { skip_line_comment(); }
skip_line_comment(); if(peekchar() == '\0' || peekchar() == '\n') { return true; }
}
if(peekchar() == '\0' || peekchar() == '\n') {
return true;
}
// https://docs.python.org/3/reference/lexical_analysis.html#indentation // https://docs.python.org/3/reference/lexical_analysis.html#indentation
if(spaces > indents.top()) { if(spaces > indents.top()) {
indents.push(spaces); indents.push(spaces);
@ -96,9 +80,7 @@ bool Lexer::eat_indentation() {
indents.pop(); indents.pop();
nexts.push_back(Token{TK("@dedent"), token_start, 0, current_line, brackets_level, {}}); nexts.push_back(Token{TK("@dedent"), token_start, 0, current_line, brackets_level, {}});
} }
if(spaces != indents.top()) { if(spaces != indents.top()) { return false; }
return false;
}
} }
return true; return true;
} }
@ -125,9 +107,7 @@ int Lexer::eat_name() {
while(true) { while(true) {
unsigned char c = peekchar(); unsigned char c = peekchar();
int u8bytes = utf8len(c, true); int u8bytes = utf8len(c, true);
if(u8bytes == 0) { if(u8bytes == 0) { return 1; }
return 1;
}
if(u8bytes == 1) { if(u8bytes == 1) {
if(isalpha(c) || c == '_' || isdigit(c)) { if(isalpha(c) || c == '_' || isdigit(c)) {
curr_char++; curr_char++;
@ -138,9 +118,7 @@ int Lexer::eat_name() {
} }
// handle multibyte char // handle multibyte char
Str u8str(curr_char, u8bytes); Str u8str(curr_char, u8bytes);
if(u8str.size != u8bytes) { if(u8str.size != u8bytes) { return 2; }
return 2;
}
uint32_t value = 0; uint32_t value = 0;
for(int k = 0; k < u8bytes; k++) { for(int k = 0; k < u8bytes; k++) {
uint8_t b = u8str[k]; uint8_t b = u8str[k];
@ -164,9 +142,7 @@ int Lexer::eat_name() {
} }
int length = (int)(curr_char - token_start); int length = (int)(curr_char - token_start);
if(length == 0) { if(length == 0) { return 3; }
return 3;
}
std::string_view name(token_start, length); std::string_view name(token_start, length);
if(src->mode == JSON_MODE) { if(src->mode == JSON_MODE) {
@ -193,17 +169,13 @@ int Lexer::eat_name() {
void Lexer::skip_line_comment() { void Lexer::skip_line_comment() {
char c; char c;
while((c = peekchar()) != '\0') { while((c = peekchar()) != '\0') {
if(c == '\n') { if(c == '\n') { return; }
return;
}
eatchar(); eatchar();
} }
} }
bool Lexer::matchchar(char c) { bool Lexer::matchchar(char c) {
if(peekchar() != c) { if(peekchar() != c) { return false; }
return false;
}
eatchar_include_newline(); eatchar_include_newline();
return true; return true;
} }
@ -263,9 +235,7 @@ Str Lexer::eat_string_until(char quote, bool raw) {
break; break;
} }
if(c == '\0') { if(c == '\0') {
if(quote3 && src->mode == REPL_MODE) { if(quote3 && src->mode == REPL_MODE) { throw NeedMoreLines(false); }
throw NeedMoreLines(false);
}
SyntaxError("EOL while scanning string literal"); SyntaxError("EOL while scanning string literal");
} }
if(c == '\n') { if(c == '\n') {
@ -292,9 +262,7 @@ Str Lexer::eat_string_until(char quote, bool raw) {
try { try {
code = (char)std::stoi(hex, &parsed, 16); code = (char)std::stoi(hex, &parsed, 16);
} catch(...) { SyntaxError("invalid hex char"); } } catch(...) { SyntaxError("invalid hex char"); }
if(parsed != 2) { if(parsed != 2) { SyntaxError("invalid hex char"); }
SyntaxError("invalid hex char");
}
buff.push_back(code); buff.push_back(code);
} break; } break;
default: SyntaxError("invalid escape char"); default: SyntaxError("invalid escape char");
@ -395,9 +363,7 @@ bool Lexer::lex_one_token() {
// line continuation character // line continuation character
char c = eatchar_include_newline(); char c = eatchar_include_newline();
if(c != '\n') { if(c != '\n') {
if(src->mode == REPL_MODE && c == '\0') { if(src->mode == REPL_MODE && c == '\0') { throw NeedMoreLines(false); }
throw NeedMoreLines(false);
}
SyntaxError("expected newline after line continuation character"); SyntaxError("expected newline after line continuation character");
} }
eat_spaces(); eat_spaces();
@ -491,9 +457,7 @@ bool Lexer::lex_one_token() {
case '\t': eat_spaces(); break; case '\t': eat_spaces(); break;
case '\n': { case '\n': {
add_token(TK("@eol")); add_token(TK("@eol"));
if(!eat_indentation()) { if(!eat_indentation()) { IndentationError("unindent does not match any outer indentation level"); }
IndentationError("unindent does not match any outer indentation level");
}
return true; return true;
} }
default: { default: {
@ -577,9 +541,7 @@ vector<Token> Lexer::run() {
} }
constexpr inline bool f_startswith_2(std::string_view t, const char* prefix) { constexpr inline bool f_startswith_2(std::string_view t, const char* prefix) {
if(t.length() < 2) { if(t.length() < 2) { return false; }
return false;
}
return t[0] == prefix[0] && t[1] == prefix[1]; 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) { if(base == 10) {
// 10-base 12334 // 10-base 12334
if(text.length() == 0) { if(text.length() == 0) { return IntParsingResult::Failure; }
return IntParsingResult::Failure;
}
for(char c: text) { for(char c: text) {
if(c >= '0' && c <= '9') { if(c >= '0' && c <= '9') {
i64 prev_out = *out; i64 prev_out = *out;
*out = (*out * 10) + (c - '0'); *out = (*out * 10) + (c - '0');
if(*out < prev_out) { if(*out < prev_out) { return IntParsingResult::Overflow; }
return IntParsingResult::Overflow;
}
} else { } else {
return IntParsingResult::Failure; return IntParsingResult::Failure;
} }
@ -617,19 +575,13 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
return IntParsingResult::Success; return IntParsingResult::Success;
} else if(base == 2) { } else if(base == 2) {
// 2-base 0b101010 // 2-base 0b101010
if(f_startswith_2(text, "0b")) { if(f_startswith_2(text, "0b")) { text.remove_prefix(2); }
text.remove_prefix(2); if(text.length() == 0) { return IntParsingResult::Failure; }
}
if(text.length() == 0) {
return IntParsingResult::Failure;
}
for(char c: text) { for(char c: text) {
if(c == '0' || c == '1') { if(c == '0' || c == '1') {
i64 prev_out = *out; i64 prev_out = *out;
*out = (*out << 1) | (c - '0'); *out = (*out << 1) | (c - '0');
if(*out < prev_out) { if(*out < prev_out) { return IntParsingResult::Overflow; }
return IntParsingResult::Overflow;
}
} else { } else {
return IntParsingResult::Failure; return IntParsingResult::Failure;
} }
@ -637,19 +589,13 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
return IntParsingResult::Success; return IntParsingResult::Success;
} else if(base == 8) { } else if(base == 8) {
// 8-base 0o123 // 8-base 0o123
if(f_startswith_2(text, "0o")) { if(f_startswith_2(text, "0o")) { text.remove_prefix(2); }
text.remove_prefix(2); if(text.length() == 0) { return IntParsingResult::Failure; }
}
if(text.length() == 0) {
return IntParsingResult::Failure;
}
for(char c: text) { for(char c: text) {
if(c >= '0' && c <= '7') { if(c >= '0' && c <= '7') {
i64 prev_out = *out; i64 prev_out = *out;
*out = (*out << 3) | (c - '0'); *out = (*out << 3) | (c - '0');
if(*out < prev_out) { if(*out < prev_out) { return IntParsingResult::Overflow; }
return IntParsingResult::Overflow;
}
} else { } else {
return IntParsingResult::Failure; return IntParsingResult::Failure;
} }
@ -657,29 +603,19 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
return IntParsingResult::Success; return IntParsingResult::Success;
} else if(base == 16) { } else if(base == 16) {
// 16-base 0x123 // 16-base 0x123
if(f_startswith_2(text, "0x")) { if(f_startswith_2(text, "0x")) { text.remove_prefix(2); }
text.remove_prefix(2); if(text.length() == 0) { return IntParsingResult::Failure; }
}
if(text.length() == 0) {
return IntParsingResult::Failure;
}
for(char c: text) { for(char c: text) {
i64 prev_out = *out; i64 prev_out = *out;
if(c >= '0' && c <= '9') { if(c >= '0' && c <= '9') {
*out = (*out << 4) | (c - '0'); *out = (*out << 4) | (c - '0');
if(*out < prev_out) { if(*out < prev_out) { return IntParsingResult::Overflow; }
return IntParsingResult::Overflow;
}
} else if(c >= 'a' && c <= 'f') { } else if(c >= 'a' && c <= 'f') {
*out = (*out << 4) | (c - 'a' + 10); *out = (*out << 4) | (c - 'a' + 10);
if(*out < prev_out) { if(*out < prev_out) { return IntParsingResult::Overflow; }
return IntParsingResult::Overflow;
}
} else if(c >= 'A' && c <= 'F') { } else if(c >= 'A' && c <= 'F') {
*out = (*out << 4) | (c - 'A' + 10); *out = (*out << 4) | (c - 'A' + 10);
if(*out < prev_out) { if(*out < prev_out) { return IntParsingResult::Overflow; }
return IntParsingResult::Overflow;
}
} else { } else {
return IntParsingResult::Failure; return IntParsingResult::Failure;
} }

View File

@ -11,8 +11,7 @@ namespace pkpy {
#define PREDICT_INT_DIV_OP(op) \ #define PREDICT_INT_DIV_OP(op) \
if(is_int(_0) && is_int(_1)) { \ if(is_int(_0) && is_int(_1)) { \
i64 divisor = _1.as<i64>(); \ i64 divisor = _1.as<i64>(); \
if(divisor == 0) \ if(divisor == 0) ZeroDivisionError(); \
ZeroDivisionError(); \
TOP() = VAR(_0.as<i64>() op divisor); \ TOP() = VAR(_0.as<i64>() op divisor); \
DISPATCH() \ DISPATCH() \
} }
@ -37,8 +36,7 @@ namespace pkpy {
ret = call_method(self, _2, _0); \ ret = call_method(self, _2, _0); \
else \ else \
BinaryOptError(op, _0, _1); \ BinaryOptError(op, _0, _1); \
if(is_not_implemented(ret)) \ if(is_not_implemented(ret)) BinaryOptError(op, _0, _1); \
BinaryOptError(op, _0, _1); \
} }
void VM::__op_unpack_sequence(uint16_t arg) { 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); const PyTypeInfo* ti = _tp_info(_0);
for(int i = 0; i < arg; i++) { for(int i = 0; i < arg; i++) {
PyVar _1 = _py_next(ti, _0); PyVar _1 = _py_next(ti, _0);
if(_1 == StopIteration) { if(_1 == StopIteration) { ValueError("not enough values to unpack"); }
ValueError("not enough values to unpack");
}
PUSH(_1); PUSH(_1);
} }
if(_py_next(ti, _0) != StopIteration) { if(_py_next(ti, _0) != StopIteration) { ValueError("too many values to unpack"); }
ValueError("too many values to unpack");
}
} }
} }
@ -94,19 +88,14 @@ bool VM::py_ge(PyVar _0, PyVar _1) {
#if PK_ENABLE_PROFILER #if PK_ENABLE_PROFILER
#define CEVAL_STEP_CALLBACK() \ #define CEVAL_STEP_CALLBACK() \
if(_ceval_on_step) \ if(_ceval_on_step) _ceval_on_step(this, frame, byte); \
_ceval_on_step(this, frame, byte); \ if(_profiler) _profiler->_step(callstack.size(), frame); \
if(_profiler) \ if(!_next_breakpoint.empty()) { _next_breakpoint._step(this); }
_profiler->_step(callstack.size(), frame); \
if(!_next_breakpoint.empty()) { \
_next_breakpoint._step(this); \
}
#else #else
#define CEVAL_STEP_CALLBACK() \ #define CEVAL_STEP_CALLBACK() \
if(_ceval_on_step && _ceval_on_step) { \ if(_ceval_on_step && _ceval_on_step) { \
if(_ceval_on_step) \ if(_ceval_on_step) \
if(_ceval_on_step) \ if(_ceval_on_step) _ceval_on_step(this, frame, byte); \
_ceval_on_step(this, frame, byte); \
} }
#endif #endif
@ -179,9 +168,7 @@ PyVar VM::__run_top_frame() {
} }
DISPATCH() DISPATCH()
case OP_PRINT_EXPR: case OP_PRINT_EXPR:
if(TOP() != None) { if(TOP() != None) { stdout_write(py_repr(TOP()) + "\n"); }
stdout_write(py_repr(TOP()) + "\n");
}
POP(); POP();
DISPATCH() DISPATCH()
/*****************************************/ /*****************************************/
@ -210,9 +197,7 @@ PyVar VM::__run_top_frame() {
/*****************************************/ /*****************************************/
case OP_LOAD_FAST: { case OP_LOAD_FAST: {
PyVar _0 = frame->_locals[byte.arg]; PyVar _0 = frame->_locals[byte.arg];
if(_0 == PY_NULL) { if(_0 == PY_NULL) { vm->UnboundLocalError(frame->co->varnames[byte.arg]); }
vm->UnboundLocalError(frame->co->varnames[byte.arg]);
}
PUSH(_0); PUSH(_0);
} }
DISPATCH() DISPATCH()
@ -220,9 +205,7 @@ PyVar VM::__run_top_frame() {
StrName _name(byte.arg); StrName _name(byte.arg);
PyVar* slot = frame->_locals.try_get_name(_name); PyVar* slot = frame->_locals.try_get_name(_name);
if(slot != nullptr) { if(slot != nullptr) {
if(*slot == PY_NULL) { if(*slot == PY_NULL) { vm->UnboundLocalError(_name); }
vm->UnboundLocalError(_name);
}
PUSH(*slot); PUSH(*slot);
DISPATCH() DISPATCH()
} }
@ -324,9 +307,7 @@ PyVar VM::__run_top_frame() {
DISPATCH() DISPATCH()
case OP_LOAD_SUBSCR_FAST: { case OP_LOAD_SUBSCR_FAST: {
PyVar _1 = frame->_locals[byte.arg]; PyVar _1 = frame->_locals[byte.arg];
if(_1 == PY_NULL) { if(_1 == PY_NULL) { vm->UnboundLocalError(frame->co->varnames[byte.arg]); }
vm->UnboundLocalError(frame->co->varnames[byte.arg]);
}
PyVar _0 = TOP(); // a PyVar _0 = TOP(); // a
auto _ti = _tp_info(_0); auto _ti = _tp_info(_0);
if(_ti->m__getitem__) { if(_ti->m__getitem__) {
@ -391,9 +372,7 @@ PyVar VM::__run_top_frame() {
DISPATCH() DISPATCH()
case OP_STORE_SUBSCR_FAST: { case OP_STORE_SUBSCR_FAST: {
PyVar _2 = frame->_locals[byte.arg]; // b PyVar _2 = frame->_locals[byte.arg]; // b
if(_2 == PY_NULL) { if(_2 == PY_NULL) { vm->UnboundLocalError(frame->co->varnames[byte.arg]); }
vm->UnboundLocalError(frame->co->varnames[byte.arg]);
}
PyVar _1 = POPX(); // a PyVar _1 = POPX(); // a
PyVar _0 = POPX(); // val PyVar _0 = POPX(); // val
auto _ti = _tp_info(_1); auto _ti = _tp_info(_1);
@ -406,9 +385,7 @@ PyVar VM::__run_top_frame() {
DISPATCH() DISPATCH()
case OP_DELETE_FAST: { case OP_DELETE_FAST: {
PyVar _0 = frame->_locals[byte.arg]; PyVar _0 = frame->_locals[byte.arg];
if(_0 == PY_NULL) { if(_0 == PY_NULL) { vm->UnboundLocalError(frame->co->varnames[byte.arg]); }
vm->UnboundLocalError(frame->co->varnames[byte.arg]);
}
frame->_locals[byte.arg].set_null(); frame->_locals[byte.arg].set_null();
} }
DISPATCH() DISPATCH()
@ -423,25 +400,19 @@ PyVar VM::__run_top_frame() {
if(func.decl == __dynamic_func_decl) { if(func.decl == __dynamic_func_decl) {
assert(func._closure != nullptr); assert(func._closure != nullptr);
bool ok = func._closure->del(_name); bool ok = func._closure->del(_name);
if(!ok) { if(!ok) { vm->NameError(_name); }
vm->NameError(_name);
}
} else { } else {
vm->NameError(_name); vm->NameError(_name);
} }
} }
} else { } else {
if(!frame->f_globals().del(_name)) { if(!frame->f_globals().del(_name)) { vm->NameError(_name); }
vm->NameError(_name);
}
} }
} }
DISPATCH() DISPATCH()
case OP_DELETE_GLOBAL: { case OP_DELETE_GLOBAL: {
StrName _name(byte.arg); StrName _name(byte.arg);
if(!frame->f_globals().del(_name)) { if(!frame->f_globals().del(_name)) { vm->NameError(_name); }
vm->NameError(_name);
}
} }
DISPATCH() DISPATCH()
case OP_DELETE_ATTR: { case OP_DELETE_ATTR: {
@ -463,17 +434,13 @@ PyVar VM::__run_top_frame() {
/*****************************************/ /*****************************************/
case OP_BUILD_LONG: { case OP_BUILD_LONG: {
PyVar _0 = builtins->attr().try_get_likely_found(pk_id_long); PyVar _0 = builtins->attr().try_get_likely_found(pk_id_long);
if(_0 == nullptr) { if(_0 == nullptr) { AttributeError(builtins, pk_id_long); }
AttributeError(builtins, pk_id_long);
}
TOP() = call(_0, TOP()); TOP() = call(_0, TOP());
} }
DISPATCH() DISPATCH()
case OP_BUILD_IMAG: { case OP_BUILD_IMAG: {
PyVar _0 = builtins->attr().try_get_likely_found(pk_id_complex); PyVar _0 = builtins->attr().try_get_likely_found(pk_id_complex);
if(_0 == nullptr) { if(_0 == nullptr) { AttributeError(builtins, pk_id_long); }
AttributeError(builtins, pk_id_long);
}
TOP() = call(_0, VAR(0), TOP()); TOP() = call(_0, VAR(0), TOP());
} }
DISPATCH() DISPATCH()
@ -587,8 +554,7 @@ PyVar VM::__run_top_frame() {
TOP() = call_method(self, _2, _0); \ TOP() = call_method(self, _2, _0); \
else \ else \
BinaryOptError(op, _0, _1); \ BinaryOptError(op, _0, _1); \
if(is_not_implemented(TOP())) \ if(is_not_implemented(TOP())) BinaryOptError(op, _0, _1); \
BinaryOptError(op, _0, _1); \
} }
case OP_BINARY_TRUEDIV: { case OP_BINARY_TRUEDIV: {
@ -596,9 +562,7 @@ PyVar VM::__run_top_frame() {
PyVar _0 = TOP(); PyVar _0 = TOP();
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__truediv__); BINARY_OP_SPECIAL(__truediv__);
if(is_not_implemented(TOP())) { if(is_not_implemented(TOP())) { BinaryOptError("/", _0, _1); }
BinaryOptError("/", _0, _1);
}
} }
DISPATCH() DISPATCH()
case OP_BINARY_POW: { case OP_BINARY_POW: {
@ -606,9 +570,7 @@ PyVar VM::__run_top_frame() {
PyVar _0 = TOP(); PyVar _0 = TOP();
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__pow__); BINARY_OP_SPECIAL(__pow__);
if(is_not_implemented(TOP())) { if(is_not_implemented(TOP())) { BinaryOptError("**", _0, _1); }
BinaryOptError("**", _0, _1);
}
} }
DISPATCH() DISPATCH()
case OP_BINARY_ADD: { case OP_BINARY_ADD: {
@ -644,9 +606,7 @@ PyVar VM::__run_top_frame() {
PREDICT_INT_DIV_OP(/) PREDICT_INT_DIV_OP(/)
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__floordiv__); BINARY_OP_SPECIAL(__floordiv__);
if(is_not_implemented(TOP())) { if(is_not_implemented(TOP())) { BinaryOptError("//", _0, _1); }
BinaryOptError("//", _0, _1);
}
} }
DISPATCH() DISPATCH()
case OP_BINARY_MOD: { case OP_BINARY_MOD: {
@ -655,9 +615,7 @@ PyVar VM::__run_top_frame() {
PREDICT_INT_DIV_OP(%) PREDICT_INT_DIV_OP(%)
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__mod__); BINARY_OP_SPECIAL(__mod__);
if(is_not_implemented(TOP())) { if(is_not_implemented(TOP())) { BinaryOptError("%", _0, _1); }
BinaryOptError("%", _0, _1);
}
} }
DISPATCH() DISPATCH()
case OP_COMPARE_LT: { case OP_COMPARE_LT: {
@ -706,9 +664,7 @@ PyVar VM::__run_top_frame() {
PREDICT_INT_OP(<<) PREDICT_INT_OP(<<)
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__lshift__); BINARY_OP_SPECIAL(__lshift__);
if(is_not_implemented(TOP())) { if(is_not_implemented(TOP())) { BinaryOptError("<<", _0, _1); }
BinaryOptError("<<", _0, _1);
}
} }
DISPATCH() DISPATCH()
case OP_BITWISE_RSHIFT: { case OP_BITWISE_RSHIFT: {
@ -717,9 +673,7 @@ PyVar VM::__run_top_frame() {
PREDICT_INT_OP(>>) PREDICT_INT_OP(>>)
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__rshift__); BINARY_OP_SPECIAL(__rshift__);
if(is_not_implemented(TOP())) { if(is_not_implemented(TOP())) { BinaryOptError(">>", _0, _1); }
BinaryOptError(">>", _0, _1);
}
} }
DISPATCH() DISPATCH()
case OP_BITWISE_AND: { case OP_BITWISE_AND: {
@ -728,9 +682,7 @@ PyVar VM::__run_top_frame() {
PREDICT_INT_OP(&) PREDICT_INT_OP(&)
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__and__); BINARY_OP_SPECIAL(__and__);
if(is_not_implemented(TOP())) { if(is_not_implemented(TOP())) { BinaryOptError("&", _0, _1); }
BinaryOptError("&", _0, _1);
}
} }
DISPATCH() DISPATCH()
case OP_BITWISE_OR: { case OP_BITWISE_OR: {
@ -739,9 +691,7 @@ PyVar VM::__run_top_frame() {
PREDICT_INT_OP(|) PREDICT_INT_OP(|)
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__or__); BINARY_OP_SPECIAL(__or__);
if(is_not_implemented(TOP())) { if(is_not_implemented(TOP())) { BinaryOptError("|", _0, _1); }
BinaryOptError("|", _0, _1);
}
} }
DISPATCH() DISPATCH()
case OP_BITWISE_XOR: { case OP_BITWISE_XOR: {
@ -750,9 +700,7 @@ PyVar VM::__run_top_frame() {
PREDICT_INT_OP(^) PREDICT_INT_OP(^)
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__xor__); BINARY_OP_SPECIAL(__xor__);
if(is_not_implemented(TOP())) { if(is_not_implemented(TOP())) { BinaryOptError("^", _0, _1); }
BinaryOptError("^", _0, _1);
}
} }
DISPATCH() DISPATCH()
case OP_BINARY_MATMUL: { case OP_BINARY_MATMUL: {
@ -760,9 +708,7 @@ PyVar VM::__run_top_frame() {
PyVar _0 = TOP(); PyVar _0 = TOP();
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__matmul__); BINARY_OP_SPECIAL(__matmul__);
if(is_not_implemented(TOP())) { if(is_not_implemented(TOP())) { BinaryOptError("@", _0, _1); }
BinaryOptError("@", _0, _1);
}
} }
DISPATCH() DISPATCH()
@ -798,14 +744,10 @@ PyVar VM::__run_top_frame() {
/*****************************************/ /*****************************************/
case OP_JUMP_FORWARD: DISPATCH_JUMP((int16_t)byte.arg) case OP_JUMP_FORWARD: DISPATCH_JUMP((int16_t)byte.arg)
case OP_POP_JUMP_IF_FALSE: case OP_POP_JUMP_IF_FALSE:
if(!py_bool(POPX())) { if(!py_bool(POPX())) { DISPATCH_JUMP((int16_t)byte.arg) }
DISPATCH_JUMP((int16_t)byte.arg)
}
DISPATCH() DISPATCH()
case OP_POP_JUMP_IF_TRUE: case OP_POP_JUMP_IF_TRUE:
if(py_bool(POPX())) { if(py_bool(POPX())) { DISPATCH_JUMP((int16_t)byte.arg) }
DISPATCH_JUMP((int16_t)byte.arg)
}
DISPATCH() DISPATCH()
case OP_JUMP_IF_TRUE_OR_POP: case OP_JUMP_IF_TRUE_OR_POP:
if(py_bool(TOP())) { if(py_bool(TOP())) {
@ -841,9 +783,7 @@ PyVar VM::__run_top_frame() {
case OP_GOTO: { case OP_GOTO: {
StrName _name(byte.arg); StrName _name(byte.arg);
int target = frame->co->labels.try_get_likely_found(_name); int target = frame->co->labels.try_get_likely_found(_name);
if(target < 0) { if(target < 0) { RuntimeError(_S("label ", _name.escape(), " not found")); }
RuntimeError(_S("label ", _name.escape(), " not found"));
}
frame->prepare_jump_break(&s_data, target); frame->prepare_jump_break(&s_data, target);
DISPATCH_JUMP_ABSOLUTE(target) DISPATCH_JUMP_ABSOLUTE(target)
} }
@ -865,9 +805,7 @@ PyVar VM::__run_top_frame() {
DISPATCH() DISPATCH()
case OP_REPR: TOP() = VAR(py_repr(TOP())); DISPATCH() case OP_REPR: TOP() = VAR(py_repr(TOP())); DISPATCH()
case OP_CALL: { case OP_CALL: {
if(heap._should_auto_collect()) { if(heap._should_auto_collect()) { heap._auto_collect(); }
heap._auto_collect();
}
PyVar _0 = vectorcall(byte.arg & 0xFF, // ARGC PyVar _0 = vectorcall(byte.arg & 0xFF, // ARGC
(byte.arg >> 8) & 0xFF, // KWARGC (byte.arg >> 8) & 0xFF, // KWARGC
true); true);
@ -879,9 +817,7 @@ PyVar VM::__run_top_frame() {
} }
DISPATCH() DISPATCH()
case OP_CALL_TP: { case OP_CALL_TP: {
if(heap._should_auto_collect()) { if(heap._should_auto_collect()) { heap._auto_collect(); }
heap._auto_collect();
}
PyVar _0; PyVar _0;
PyVar _1; PyVar _1;
PyVar _2; PyVar _2;
@ -1078,9 +1014,7 @@ PyVar VM::__run_top_frame() {
} else { } else {
for(auto& [name, value]: _0->attr().items()) { for(auto& [name, value]: _0->attr().items()) {
std::string_view s = name.sv(); std::string_view s = name.sv();
if(s.empty() || s[0] == '_') { if(s.empty() || s[0] == '_') { continue; }
continue;
}
frame->f_globals().set(name, value); frame->f_globals().set(name, value);
} }
} }
@ -1098,17 +1032,13 @@ PyVar VM::__run_top_frame() {
PyVar _1; PyVar _1;
for(int i = 0; i < byte.arg; i++) { for(int i = 0; i < byte.arg; i++) {
_1 = _py_next(_ti, _0); _1 = _py_next(_ti, _0);
if(_1 == StopIteration) { if(_1 == StopIteration) { ValueError("not enough values to unpack"); }
ValueError("not enough values to unpack");
}
PUSH(_1); PUSH(_1);
} }
List extras; List extras;
while(true) { while(true) {
_1 = _py_next(_ti, _0); _1 = _py_next(_ti, _0);
if(_1 == StopIteration) { if(_1 == StopIteration) { break; }
break;
}
extras.push_back(_1); extras.push_back(_1);
} }
PUSH(VAR(std::move(extras))); PUSH(VAR(std::move(extras)));
@ -1118,9 +1048,7 @@ PyVar VM::__run_top_frame() {
case OP_BEGIN_CLASS: { case OP_BEGIN_CLASS: {
StrName _name(byte.arg); StrName _name(byte.arg);
PyVar _0 = POPX(); // super PyVar _0 = POPX(); // super
if(_0 == None) { if(_0 == None) { _0 = _t(tp_object); }
_0 = _t(tp_object);
}
check_type(_0, tp_type); check_type(_0, tp_type);
__curr_class = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0), true); __curr_class = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0), true);
} }
@ -1133,9 +1061,7 @@ PyVar VM::__run_top_frame() {
PyTypeInfo* ti = &_all_types[__curr_class->as<Type>()]; PyTypeInfo* ti = &_all_types[__curr_class->as<Type>()];
if(ti->base != tp_object) { if(ti->base != tp_object) {
PyTypeInfo* base_ti = &_all_types[ti->base]; PyTypeInfo* base_ti = &_all_types[ti->base];
if(base_ti->on_end_subclass) { if(base_ti->on_end_subclass) { base_ti->on_end_subclass(this, ti); }
base_ti->on_end_subclass(this, ti);
}
} }
__curr_class = nullptr; __curr_class = nullptr;
} }
@ -1144,9 +1070,7 @@ PyVar VM::__run_top_frame() {
assert(__curr_class != nullptr); assert(__curr_class != nullptr);
StrName _name(byte.arg); StrName _name(byte.arg);
PyVar _0 = POPX(); PyVar _0 = POPX();
if(is_type(_0, tp_function)) { if(is_type(_0, tp_function)) { PK_OBJ_GET(Function, _0)._class = __curr_class; }
PK_OBJ_GET(Function, _0)._class = __curr_class;
}
__curr_class->attr().set(_name, _0); __curr_class->attr().set(_name, _0);
} }
DISPATCH() DISPATCH()
@ -1185,12 +1109,8 @@ PyVar VM::__run_top_frame() {
} }
DISPATCH() DISPATCH()
case OP_RAISE: { case OP_RAISE: {
if(is_type(TOP(), tp_type)) { if(is_type(TOP(), tp_type)) { TOP() = call(TOP()); }
TOP() = call(TOP()); if(!isinstance(TOP(), tp_exception)) { TypeError("exceptions must derive from Exception"); }
}
if(!isinstance(TOP(), tp_exception)) {
TypeError("exceptions must derive from Exception");
}
_error(POPX()); _error(POPX());
} }
DISPATCH() DISPATCH()
@ -1215,35 +1135,27 @@ PyVar VM::__run_top_frame() {
/*****************************************/ /*****************************************/
case OP_INC_FAST: { case OP_INC_FAST: {
PyVar* p = &frame->_locals[byte.arg]; PyVar* p = &frame->_locals[byte.arg];
if(*p == PY_NULL) { if(*p == PY_NULL) { vm->NameError(frame->co->varnames[byte.arg]); }
vm->NameError(frame->co->varnames[byte.arg]);
}
*p = VAR(CAST(i64, *p) + 1); *p = VAR(CAST(i64, *p) + 1);
} }
DISPATCH() DISPATCH()
case OP_DEC_FAST: { case OP_DEC_FAST: {
PyVar* p = &frame->_locals[byte.arg]; PyVar* p = &frame->_locals[byte.arg];
if(*p == PY_NULL) { if(*p == PY_NULL) { vm->NameError(frame->co->varnames[byte.arg]); }
vm->NameError(frame->co->varnames[byte.arg]);
}
*p = VAR(CAST(i64, *p) - 1); *p = VAR(CAST(i64, *p) - 1);
} }
DISPATCH() DISPATCH()
case OP_INC_GLOBAL: { case OP_INC_GLOBAL: {
StrName _name(byte.arg); StrName _name(byte.arg);
PyVar* p = frame->f_globals().try_get_2_likely_found(_name); PyVar* p = frame->f_globals().try_get_2_likely_found(_name);
if(p == nullptr) { if(p == nullptr) { vm->NameError(_name); }
vm->NameError(_name);
}
*p = VAR(CAST(i64, *p) + 1); *p = VAR(CAST(i64, *p) + 1);
} }
DISPATCH() DISPATCH()
case OP_DEC_GLOBAL: { case OP_DEC_GLOBAL: {
StrName _name(byte.arg); StrName _name(byte.arg);
PyVar* p = frame->f_globals().try_get_2_likely_found(_name); PyVar* p = frame->f_globals().try_get_2_likely_found(_name);
if(p == nullptr) { if(p == nullptr) { vm->NameError(_name); }
vm->NameError(_name);
}
*p = VAR(CAST(i64, *p) - 1); *p = VAR(CAST(i64, *p) - 1);
} }
DISPATCH() DISPATCH()
@ -1266,9 +1178,7 @@ PyVar VM::__run_top_frame() {
} }
frame = &callstack.top(); frame = &callstack.top();
PUSH(__last_exception); PUSH(__last_exception);
if(is_base_frame_to_be_popped) { if(is_base_frame_to_be_popped) { throw InternalException(InternalExceptionType::ToBeRaised); }
throw InternalException(InternalExceptionType::ToBeRaised);
}
} }
} }
} }

View File

@ -21,8 +21,7 @@ void VoidP::_register(VM* vm, PyObject* mod, PyObject* type) {
#define BIND_CMP(name, op) \ #define BIND_CMP(name, op) \
vm->bind##name(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) { \ vm->bind##name(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) { \
if(!vm->isinstance(rhs, vm->_tp_user<VoidP>())) \ if(!vm->isinstance(rhs, vm->_tp_user<VoidP>())) return vm->NotImplemented; \
return vm->NotImplemented; \
void* _0 = PK_OBJ_GET(VoidP, lhs).ptr; \ void* _0 = PK_OBJ_GET(VoidP, lhs).ptr; \
void* _1 = PK_OBJ_GET(VoidP, rhs).ptr; \ void* _1 = PK_OBJ_GET(VoidP, rhs).ptr; \
return VAR(_0 op _1); \ return VAR(_0 op _1); \
@ -60,9 +59,7 @@ void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
1, 1,
[](VM* vm, ArgsView args) { [](VM* vm, ArgsView args) {
const Str& s = CAST(Str&, args[0]); const Str& s = CAST(Str&, args[0]);
if(s.size < 2 || s.size % 2 != 0) { if(s.size < 2 || s.size % 2 != 0) { vm->ValueError("invalid hex string"); }
vm->ValueError("invalid hex string");
}
Struct buffer(s.size / 2, false); Struct buffer(s.size / 2, false);
for(int i = 0; i < s.size; i += 2) { for(int i = 0; i < s.size; i += 2) {
char c = 0; char c = 0;
@ -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) { vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) {
Struct& self = _CAST(Struct&, lhs); Struct& self = _CAST(Struct&, lhs);
if(!vm->is_user_type<Struct>(rhs)) { if(!vm->is_user_type<Struct>(rhs)) { return vm->NotImplemented; }
return vm->NotImplemented;
}
Struct& other = _CAST(Struct&, rhs); Struct& other = _CAST(Struct&, rhs);
bool ok = self.size == other.size && memcmp(self.p, other.p, self.size) == 0; bool ok = self.size == other.size && memcmp(self.p, other.p, self.size) == 0;
return VAR(ok); return VAR(ok);
@ -192,9 +187,7 @@ void add_module_c(VM* vm) {
VoidP& ptr = CAST(VoidP&, args[0]); VoidP& ptr = CAST(VoidP&, args[0]);
vm->check_type(args[1], vm->tp_type); vm->check_type(args[1], vm->tp_type);
Type cls = PK_OBJ_GET(Type, args[1]); Type cls = PK_OBJ_GET(Type, args[1]);
if(!vm->issubclass(cls, vm->_tp_user<VoidP>())) { if(!vm->issubclass(cls, vm->_tp_user<VoidP>())) { vm->ValueError("expected a subclass of void_p"); }
vm->ValueError("expected a subclass of void_p");
}
return vm->new_object<VoidP>(cls, ptr.ptr); return vm->new_object<VoidP>(cls, ptr.ptr);
}); });

View File

@ -6,9 +6,7 @@
namespace pkpy { namespace pkpy {
PyVar* FastLocals::try_get_name(StrName name) { PyVar* FastLocals::try_get_name(StrName name) {
int index = co->varnames_inv.try_get(name); int index = co->varnames_inv.try_get(name);
if(index == -1) { if(index == -1) { return nullptr; }
return nullptr;
}
return &a[index]; return &a[index];
} }
@ -16,21 +14,15 @@ NameDict_ FastLocals::to_namedict() {
NameDict_ dict = std::make_shared<NameDict>(); NameDict_ dict = std::make_shared<NameDict>();
co->varnames_inv.apply([&](StrName name, int index) { co->varnames_inv.apply([&](StrName name, int index) {
PyVar value = a[index]; PyVar value = a[index];
if(value) { if(value) { dict->set(name, value); }
dict->set(name, value);
}
}); });
return dict; return dict;
} }
PyVar* Frame::f_closure_try_get(StrName name) { PyVar* Frame::f_closure_try_get(StrName name) {
if(_callable == nullptr) { if(_callable == nullptr) { return nullptr; }
return nullptr;
}
Function& fn = _callable->as<Function>(); Function& fn = _callable->as<Function>();
if(fn._closure == nullptr) { if(fn._closure == nullptr) { return nullptr; }
return nullptr;
}
return fn._closure->try_get_2(name); 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 // try to find a parent try block
int i = co->lines[ip()].iblock; int i = co->lines[ip()].iblock;
while(i >= 0) { while(i >= 0) {
if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) { if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) { break; }
break;
}
i = co->blocks[i].parent; i = co->blocks[i].parent;
} }
if(i < 0) { if(i < 0) { return -1; }
return -1;
}
PyVar obj = _s->popx(); // pop exception object PyVar obj = _s->popx(); // pop exception object
UnwindTarget* uw = find_unwind_target(i); UnwindTarget* uw = find_unwind_target(i);
_s->reset(actual_sp_base() + uw->offset); // unwind the stack _s->reset(actual_sp_base() + uw->offset); // unwind the stack
@ -86,9 +74,7 @@ void Frame::prepare_jump_break(ValueStack* _s, int target) {
while(i >= 0 && i != next_block) { while(i >= 0 && i != next_block) {
i = _exit_block(_s, i); i = _exit_block(_s, i);
} }
if(i != next_block) { if(i != next_block) { throw std::runtime_error("invalid jump"); }
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* Frame::find_unwind_target(int iblock) {
UnwindTarget* p; UnwindTarget* p;
for(p = _uw_list; p != nullptr; p = p->next) { for(p = _uw_list; p != nullptr; p = p->next) {
if(p->iblock == iblock) { if(p->iblock == iblock) { return p; }
return p;
}
} }
return nullptr; return nullptr;
} }

View File

@ -13,9 +13,7 @@ int ManagedHeap::sweep() {
#if PK_DEBUG_GC_STATS #if PK_DEBUG_GC_STATS
deleted[obj->type] += 1; deleted[obj->type] += 1;
#endif #endif
if(_gc_on_delete) { if(_gc_on_delete) { _gc_on_delete(vm, obj); }
_gc_on_delete(vm, obj);
}
_delete(obj); _delete(obj);
} }
} }
@ -42,15 +40,11 @@ int ManagedHeap::sweep() {
void ManagedHeap::_auto_collect() { void ManagedHeap::_auto_collect() {
#if !PK_DEBUG_NO_AUTO_GC #if !PK_DEBUG_NO_AUTO_GC
if(_gc_lock_counter > 0) { if(_gc_lock_counter > 0) { return; }
return;
}
gc_counter = 0; gc_counter = 0;
collect(); collect();
gc_threshold = gen.size() * 2; gc_threshold = gen.size() * 2;
if(gc_threshold < PK_GC_MIN_THRESHOLD) { if(gc_threshold < PK_GC_MIN_THRESHOLD) { gc_threshold = PK_GC_MIN_THRESHOLD; }
gc_threshold = PK_GC_MIN_THRESHOLD;
}
#endif #endif
} }

View File

@ -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__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
RangeIter& self = PK_OBJ_GET(RangeIter, _0); RangeIter& self = PK_OBJ_GET(RangeIter, _0);
if(self.current >= self.r.stop) { if(self.current >= self.r.stop) { return 0; }
return 0;
}
vm->s_data.emplace(VM::tp_int, self.current); vm->s_data.emplace(VM::tp_int, self.current);
self.current += self.r.step; self.current += self.r.step;
return 1; return 1;
@ -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__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
RangeIterR& self = PK_OBJ_GET(RangeIterR, _0); RangeIterR& self = PK_OBJ_GET(RangeIterR, _0);
if(self.current <= self.r.stop) { if(self.current <= self.r.stop) { return 0; }
return 0;
}
vm->s_data.emplace(VM::tp_int, self.current); vm->s_data.emplace(VM::tp_int, self.current);
self.current += self.r.step; self.current += self.r.step;
return 1; return 1;
@ -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__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
ArrayIter& self = _CAST(ArrayIter&, _0); ArrayIter& self = _CAST(ArrayIter&, _0);
if(self.current == self.end) { if(self.current == self.end) { return 0; }
return 0;
}
vm->s_data.push(*self.current++); vm->s_data.push(*self.current++);
return 1; 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 { vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
StringIter& self = _CAST(StringIter&, _0); StringIter& self = _CAST(StringIter&, _0);
Str& s = PK_OBJ_GET(Str, self.ref); Str& s = PK_OBJ_GET(Str, self.ref);
if(self.i == s.size) { if(self.i == s.size) { return 0; }
return 0;
}
int start = self.i; int start = self.i;
int len = utf8len(s.data[self.i]); int len = utf8len(s.data[self.i]);
self.i += len; self.i += len;
@ -57,9 +49,7 @@ void StringIter::_register(VM* vm, PyObject* mod, PyObject* type) {
} }
PyVar Generator::next(VM* vm) { PyVar Generator::next(VM* vm) {
if(state == 2) { if(state == 2) { return vm->StopIteration; }
return vm->StopIteration;
}
// reset frame._sp_base // reset frame._sp_base
lf->frame._sp_base = vm->s_data._sp; lf->frame._sp_base = vm->s_data._sp;
lf->frame._locals.a = vm->s_data._sp; lf->frame._locals.a = vm->s_data._sp;
@ -105,9 +95,7 @@ PyVar Generator::next(VM* vm) {
// } // }
// #endif // #endif
state = 1; state = 1;
if(ret == vm->StopIteration) { if(ret == vm->StopIteration) { state = 2; }
state = 2;
}
return ret; return ret;
} else { } else {
state = 2; 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 { vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
Generator& self = _CAST(Generator&, _0); Generator& self = _CAST(Generator&, _0);
PyVar retval = self.next(vm); PyVar retval = self.next(vm);
if(retval == vm->StopIteration) { if(retval == vm->StopIteration) { return 0; }
return 0;
}
vm->s_data.push(retval); vm->s_data.push(retval);
return 1; 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 { vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
DictItemsIter& self = _CAST(DictItemsIter&, _0); DictItemsIter& self = _CAST(DictItemsIter&, _0);
Dict& d = PK_OBJ_GET(Dict, self.ref); Dict& d = PK_OBJ_GET(Dict, self.ref);
if(self.i == -1) { if(self.i == -1) { return 0; }
return 0;
}
vm->s_data.push(d._items[self.i].first); vm->s_data.push(d._items[self.i].first);
vm->s_data.push(d._items[self.i].second); vm->s_data.push(d._items[self.i].second);
self.i = d._items[self.i].next; self.i = d._items[self.i].next;

View File

@ -4,9 +4,7 @@ namespace pkpy {
static std::string left_pad(std::string s, int width) { static std::string left_pad(std::string s, int width) {
int n = width - s.size(); int n = width - s.size();
if(n <= 0) { if(n <= 0) { return s; }
return s;
}
return std::string(n, ' ') + s; return std::string(n, ' ') + s;
} }
@ -20,9 +18,7 @@ void LineProfiler::begin() { frames.clear(); }
void LineProfiler::_step(int callstack_size, Frame* frame) { void LineProfiler::_step(int callstack_size, Frame* frame) {
auto line_info = frame->co->lines[frame->ip()]; auto line_info = frame->co->lines[frame->ip()];
if(line_info.is_virtual) { if(line_info.is_virtual) { return; }
return;
}
std::string_view filename = frame->co->src->filename.sv(); std::string_view filename = frame->co->src->filename.sv();
int line = line_info.lineno; int line = line_info.lineno;
@ -57,18 +53,14 @@ void LineProfiler::_step_end(int callstack_size, Frame* frame, int line) {
if(prev_record->line != line) { if(prev_record->line != line) {
clock_t delta = now - top_frame_record.prev_time; clock_t delta = now - top_frame_record.prev_time;
top_frame_record.prev_time = now; top_frame_record.prev_time = now;
if(id_delta != 1) { if(id_delta != 1) { prev_record->hits++; }
prev_record->hits++;
}
prev_record->time += delta; prev_record->time += delta;
} }
if(id_delta == 1) { if(id_delta == 1) {
frames.push({callstack_size, frame, now, nullptr}); frames.push({callstack_size, frame, now, nullptr});
} else { } else {
if(id_delta == -1) { if(id_delta == -1) { frames.pop(); }
frames.pop();
}
} }
} }
@ -91,14 +83,10 @@ Str LineProfiler::stats() {
for(FuncDecl* decl: functions) { for(FuncDecl* decl: functions) {
int start_line = decl->code->start_line; int start_line = decl->code->start_line;
int end_line = decl->code->end_line; int end_line = decl->code->end_line;
if(start_line == -1 || end_line == -1) { if(start_line == -1 || end_line == -1) { continue; }
continue;
}
std::string_view filename = decl->code->src->filename.sv(); std::string_view filename = decl->code->src->filename.sv();
vector<_LineRecord>& file_records = records[filename]; vector<_LineRecord>& file_records = records[filename];
if(file_records.empty()) { if(file_records.empty()) { continue; }
continue;
}
clock_t total_time = 0; clock_t total_time = 0;
for(int line = start_line; line <= end_line; line++) { for(int line = start_line; line <= end_line; line++) {
total_time += file_records[line].time; total_time += file_records[line].time;
@ -110,9 +98,7 @@ Str LineProfiler::stats() {
ss << "==============================================================\n"; ss << "==============================================================\n";
for(int line = start_line; line <= end_line; line++) { for(int line = start_line; line <= end_line; line++) {
const _LineRecord& record = file_records[line]; const _LineRecord& record = file_records[line];
if(!record.is_valid()) { if(!record.is_valid()) { continue; }
continue;
}
ss << left_pad(std::to_string(line), 6); ss << left_pad(std::to_string(line), 6);
if(record.hits == 0) { if(record.hits == 0) {
ss << std::string(10 + 13 + 9 + 9, ' '); ss << std::string(10 + 13 + 9 + 9, ' ');

View File

@ -23,9 +23,7 @@ struct JsonSerializer {
void write_array(T& arr) { void write_array(T& arr) {
ss << '['; ss << '[';
for(int i = 0; i < arr.size(); i++) { for(int i = 0; i < arr.size(); i++) {
if(i != 0) { if(i != 0) { ss << ", "; }
ss << ", ";
}
write_object(arr[i]); write_object(arr[i]);
} }
ss << ']'; ss << ']';
@ -35,9 +33,7 @@ struct JsonSerializer {
ss << '{'; ss << '{';
bool first = true; bool first = true;
dict.apply([&](PyVar k, PyVar v) { dict.apply([&](PyVar k, PyVar v) {
if(!first) { if(!first) { ss << ", "; }
ss << ", ";
}
first = false; first = false;
if(!is_type(k, VM::tp_str)) { if(!is_type(k, VM::tp_str)) {
vm->TypeError(_S("json keys must be string, got ", _type_name(vm, vm->_tp(k)))); vm->TypeError(_S("json keys must be string, got ", _type_name(vm, vm->_tp(k))));
@ -56,9 +52,7 @@ struct JsonSerializer {
ss << _CAST(i64, obj); ss << _CAST(i64, obj);
} else if(obj_t == vm->tp_float) { } else if(obj_t == vm->tp_float) {
f64 val = _CAST(f64, obj); f64 val = _CAST(f64, obj);
if(std::isinf(val) || std::isnan(val)) { if(std::isinf(val) || std::isnan(val)) { vm->ValueError("cannot jsonify 'nan' or 'inf'"); }
vm->ValueError("cannot jsonify 'nan' or 'inf'");
}
ss << val; ss << val;
} else if(obj_t == vm->tp_bool) { } else if(obj_t == vm->tp_bool) {
ss << (obj == vm->True ? "true" : "false"); ss << (obj == vm->True ? "true" : "false");
@ -97,16 +91,12 @@ VM::VM(bool enable_os) : heap(this), enable_os(enable_os) {
Str VM::py_str(PyVar obj) { Str VM::py_str(PyVar obj) {
const PyTypeInfo* ti = _tp_info(obj); const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__str__) { if(ti->m__str__) { return ti->m__str__(this, obj); }
return ti->m__str__(this, obj);
}
PyVar self; PyVar self;
PyVar f = get_unbound_method(obj, __str__, &self, false); PyVar f = get_unbound_method(obj, __str__, &self, false);
if(self != PY_NULL) { if(self != PY_NULL) {
PyVar retval = call_method(self, f); PyVar retval = call_method(self, f);
if(!is_type(retval, tp_str)) { if(!is_type(retval, tp_str)) { throw std::runtime_error("object.__str__ must return str"); }
throw std::runtime_error("object.__str__ must return str");
}
return PK_OBJ_GET(Str, retval); return PK_OBJ_GET(Str, retval);
} }
return py_repr(obj); return py_repr(obj);
@ -114,13 +104,9 @@ Str VM::py_str(PyVar obj) {
Str VM::py_repr(PyVar obj) { Str VM::py_repr(PyVar obj) {
const PyTypeInfo* ti = _tp_info(obj); const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__repr__) { if(ti->m__repr__) { return ti->m__repr__(this, obj); }
return ti->m__repr__(this, obj);
}
PyVar retval = call_method(obj, __repr__); PyVar retval = call_method(obj, __repr__);
if(!is_type(retval, tp_str)) { if(!is_type(retval, tp_str)) { throw std::runtime_error("object.__repr__ must return str"); }
throw std::runtime_error("object.__repr__ must return str");
}
return PK_OBJ_GET(Str, retval); return PK_OBJ_GET(Str, retval);
} }
@ -131,14 +117,10 @@ Str VM::py_json(PyVar obj) {
PyVar VM::py_iter(PyVar obj) { PyVar VM::py_iter(PyVar obj) {
const PyTypeInfo* ti = _tp_info(obj); const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__iter__) { if(ti->m__iter__) { return ti->m__iter__(this, obj); }
return ti->m__iter__(this, obj);
}
PyVar self; PyVar self;
PyVar iter_f = get_unbound_method(obj, __iter__, &self, false); PyVar iter_f = get_unbound_method(obj, __iter__, &self, false);
if(self != PY_NULL) { if(self != PY_NULL) { return call_method(self, iter_f); }
return call_method(self, iter_f);
}
TypeError(_type_name(vm, _tp(obj)).escape() + " object is not iterable"); TypeError(_type_name(vm, _tp(obj)).escape() + " object is not iterable");
return nullptr; return nullptr;
} }
@ -167,13 +149,9 @@ PyVar* VM::find_name_in_mro(Type cls, StrName name) {
PyVar* val; PyVar* val;
do { do {
val = _t(cls)->attr().try_get_2(name); val = _t(cls)->attr().try_get_2(name);
if(val != nullptr) { if(val != nullptr) { return val; }
return val;
}
cls = _all_types[cls].base; cls = _all_types[cls].base;
if(!cls) { if(!cls) { break; }
break;
}
} while(true); } while(true);
return nullptr; 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) { bool VM::issubclass(Type cls, Type base) {
do { do {
if(cls == base) { if(cls == base) { return true; }
return true;
}
Type next = _all_types[cls].base; Type next = _all_types[cls].base;
if(!next) { if(!next) { break; }
break;
}
cls = next; cls = next;
} while(true); } while(true);
return false; return false;
} }
PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module) { PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module) {
if(_module == nullptr) { if(_module == nullptr) { _module = _main; }
_module = _main;
}
try { try {
#if PK_DEBUG_PRECOMPILED_EXEC == 1 #if PK_DEBUG_PRECOMPILED_EXEC == 1
Str precompiled = vm->precompile(source, filename, mode); Str precompiled = vm->precompile(source, filename, mode);
@ -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) { bool VM::py_eq(PyVar lhs, PyVar rhs) {
if(is_int(lhs) && is_int(rhs)) { if(is_int(lhs) && is_int(rhs)) { return lhs.as<i64>() == rhs.as<i64>(); }
return lhs.as<i64>() == rhs.as<i64>();
}
const PyTypeInfo* ti = _tp_info(lhs); const PyTypeInfo* ti = _tp_info(lhs);
PyVar res; PyVar res;
if(ti->m__eq__) { if(ti->m__eq__) {
res = ti->m__eq__(this, lhs, rhs); res = ti->m__eq__(this, lhs, rhs);
if(!is_not_implemented(res)) { if(!is_not_implemented(res)) { return res == vm->True; }
return res == vm->True;
}
} }
res = call_method(lhs, __eq__, rhs); res = call_method(lhs, __eq__, rhs);
if(!is_not_implemented(res)) { if(!is_not_implemented(res)) { return res == vm->True; }
return res == vm->True;
}
ti = _tp_info(rhs); ti = _tp_info(rhs);
if(ti->m__eq__) { if(ti->m__eq__) {
res = ti->m__eq__(this, rhs, lhs); res = ti->m__eq__(this, rhs, lhs);
if(!is_not_implemented(res)) { if(!is_not_implemented(res)) { return res == vm->True; }
return res == vm->True;
}
} }
res = call_method(rhs, __eq__, lhs); res = call_method(rhs, __eq__, lhs);
if(!is_not_implemented(res)) { if(!is_not_implemented(res)) { return res == vm->True; }
return res == vm->True;
}
return false; return false;
} }
@ -286,12 +248,8 @@ PyVar VM::py_op(std::string_view name) {
} }
i64 VM::normalized_index(i64 index, int size) { i64 VM::normalized_index(i64 index, int size) {
if(index < 0) { if(index < 0) { index += size; }
index += size; if(index < 0 || index >= size) { IndexError(std::to_string(index) + " not in [0, " + std::to_string(size) + ")"); }
}
if(index < 0 || index >= size) {
IndexError(std::to_string(index) + " not in [0, " + std::to_string(size) + ")");
}
return index; return index;
} }
@ -329,9 +287,7 @@ PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) {
return (this->*op)(a, b) ? a : b; return (this->*op)(a, b) ? a : b;
} }
if(args_tuple.size() == 0) { if(args_tuple.size() == 0) { TypeError("expected at least 1 argument, got 0"); }
TypeError("expected at least 1 argument, got 0");
}
ArgsView view(nullptr, nullptr); ArgsView view(nullptr, nullptr);
if(args_tuple.size() == 1) { if(args_tuple.size() == 1) {
@ -340,49 +296,37 @@ PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) {
view = ArgsView(args_tuple); view = ArgsView(args_tuple);
} }
if(view.empty()) { if(view.empty()) { ValueError("arg is an empty sequence"); }
ValueError("arg is an empty sequence");
}
PyVar res = view[0]; PyVar res = view[0];
if(key == vm->None) { if(key == vm->None) {
for(int i = 1; i < view.size(); i++) { for(int i = 1; i < view.size(); i++) {
if((this->*op)(view[i], res)) { if((this->*op)(view[i], res)) { res = view[i]; }
res = view[i];
}
} }
} else { } else {
auto _lock = heap.gc_scope_lock(); auto _lock = heap.gc_scope_lock();
for(int i = 1; i < view.size(); i++) { for(int i = 1; i < view.size(); i++) {
PyVar a = call(key, view[i]); PyVar a = call(key, view[i]);
PyVar b = call(key, res); PyVar b = call(key, res);
if((this->*op)(a, b)) { if((this->*op)(a, b)) { res = view[i]; }
res = view[i];
}
} }
} }
return res; return res;
} }
PyObject* VM::py_import(Str path, bool throw_err) { PyObject* VM::py_import(Str path, bool throw_err) {
if(path.empty()) { if(path.empty()) { vm->ValueError("empty module name"); }
vm->ValueError("empty module name");
}
static auto f_join = [](const vector<std::string_view>& cpnts) { static auto f_join = [](const vector<std::string_view>& cpnts) {
SStream ss; SStream ss;
for(int i = 0; i < cpnts.size(); i++) { for(int i = 0; i < cpnts.size(); i++) {
if(i != 0) { if(i != 0) { ss << "."; }
ss << ".";
}
ss << cpnts[i]; ss << cpnts[i];
} }
return ss.str(); return ss.str();
}; };
if(path[0] == '.') { if(path[0] == '.') {
if(__import_context.pending.empty()) { if(__import_context.pending.empty()) { ImportError("relative import outside of package"); }
ImportError("relative import outside of package");
}
Str curr_path = __import_context.pending.back(); Str curr_path = __import_context.pending.back();
bool curr_is_init = __import_context.pending_is_init.back(); bool curr_is_init = __import_context.pending_is_init.back();
// convert relative path to absolute path // convert relative path to absolute path
@ -395,16 +339,12 @@ PyObject* VM::py_import(Str path, bool throw_err) {
break; break;
} }
} }
if(prefix > cpnts.size()) { if(prefix > cpnts.size()) { ImportError("attempted relative import beyond top-level package"); }
ImportError("attempted relative import beyond top-level package");
}
path = path.substr(prefix); // remove prefix path = path.substr(prefix); // remove prefix
for(int i = (int)curr_is_init; i < prefix; i++) { for(int i = (int)curr_is_init; i < prefix; i++) {
cpnts.pop_back(); cpnts.pop_back();
} }
if(!path.empty()) { if(!path.empty()) { cpnts.push_back(path.sv()); }
cpnts.push_back(path.sv());
}
path = f_join(cpnts); path = f_join(cpnts);
} }
@ -413,15 +353,11 @@ PyObject* VM::py_import(Str path, bool throw_err) {
// check existing module // check existing module
StrName name(path); StrName name(path);
PyVar ext_mod = _modules.try_get(name); PyVar ext_mod = _modules.try_get(name);
if(ext_mod != nullptr) { if(ext_mod != nullptr) { return ext_mod.get(); }
return ext_mod.get();
}
vector<std::string_view> path_cpnts = path.split('.'); vector<std::string_view> path_cpnts = path.split('.');
// check circular import // check circular import
if(__import_context.pending.size() > 128) { if(__import_context.pending.size() > 128) { ImportError("maximum recursion depth exceeded while importing"); }
ImportError("maximum recursion depth exceeded while importing");
}
// try import // try import
Str filename = path.replace('.', PK_PLATFORM_SEP) + ".py"; Str filename = path.replace('.', PK_PLATFORM_SEP) + ".py";
@ -478,22 +414,14 @@ VM::~VM() {
PyVar VM::py_negate(PyVar obj) { PyVar VM::py_negate(PyVar obj) {
const PyTypeInfo* ti = _tp_info(obj); const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__neg__) { if(ti->m__neg__) { return ti->m__neg__(this, obj); }
return ti->m__neg__(this, obj);
}
return call_method(obj, __neg__); return call_method(obj, __neg__);
} }
bool VM::__py_bool_non_trivial(PyVar obj) { bool VM::__py_bool_non_trivial(PyVar obj) {
if(obj == None) { if(obj == None) { return false; }
return false; if(is_int(obj)) { return _CAST(i64, obj) != 0; }
} if(is_float(obj)) { return _CAST(f64, obj) != 0.0; }
if(is_int(obj)) {
return _CAST(i64, obj) != 0;
}
if(is_float(obj)) {
return _CAST(f64, obj) != 0.0;
}
PyVar self; PyVar self;
PyVar len_f = get_unbound_method(obj, __len__, &self, false); PyVar len_f = get_unbound_method(obj, __len__, &self, false);
if(self != PY_NULL) { if(self != PY_NULL) {
@ -504,19 +432,13 @@ bool VM::__py_bool_non_trivial(PyVar obj) {
} }
void VM::__obj_gc_mark(PyObject* obj) { void VM::__obj_gc_mark(PyObject* obj) {
if(obj->gc_marked) { if(obj->gc_marked) { return; }
return;
}
obj->gc_marked = true; obj->gc_marked = true;
const PyTypeInfo* ti = _tp_info(obj->type); const PyTypeInfo* ti = _tp_info(obj->type);
if(ti->vt._gc_mark) { if(ti->vt._gc_mark) { ti->vt._gc_mark(obj->_value_ptr(), this); }
ti->vt._gc_mark(obj->_value_ptr(), this);
}
if(obj->is_attr_valid()) { if(obj->is_attr_valid()) {
obj->attr().apply([this](StrName _, PyVar obj) { obj->attr().apply([this](StrName _, PyVar obj) {
if(obj.is_ptr) { if(obj.is_ptr) { vm->__obj_gc_mark((obj).get()); }
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) { if(it->type == tp_stack_memory) {
// [sm:3, _0, _1, _2, sm:-3] // [sm:3, _0, _1, _2, sm:-3]
int count = it->as<StackMemory>().count; int count = it->as<StackMemory>().count;
if(count > 0) { if(count > 0) { it += count; }
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) { void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step) {
auto clip = [](int value, int min, int max) { auto clip = [](int value, int min, int max) {
if(value < min) { if(value < min) { return min; }
return min; if(value > max) { return max; }
}
if(value > max) {
return max;
}
return value; return value;
}; };
if(s.step == None) { if(s.step == None) {
@ -574,26 +490,20 @@ void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int&
} else { } else {
step = CAST(int, s.step); step = CAST(int, s.step);
} }
if(step == 0) { if(step == 0) { ValueError("slice step cannot be zero"); }
ValueError("slice step cannot be zero");
}
if(step > 0) { if(step > 0) {
if(s.start == None) { if(s.start == None) {
start = 0; start = 0;
} else { } else {
start = CAST(int, s.start); start = CAST(int, s.start);
if(start < 0) { if(start < 0) { start += length; }
start += length;
}
start = clip(start, 0, length); start = clip(start, 0, length);
} }
if(s.stop == None) { if(s.stop == None) {
stop = length; stop = length;
} else { } else {
stop = CAST(int, s.stop); stop = CAST(int, s.stop);
if(stop < 0) { if(stop < 0) { stop += length; }
stop += length;
}
stop = clip(stop, 0, length); stop = clip(stop, 0, length);
} }
} else { } else {
@ -601,18 +511,14 @@ void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int&
start = length - 1; start = length - 1;
} else { } else {
start = CAST(int, s.start); start = CAST(int, s.start);
if(start < 0) { if(start < 0) { start += length; }
start += length;
}
start = clip(start, -1, length - 1); start = clip(start, -1, length - 1);
} }
if(s.stop == None) { if(s.stop == None) {
stop = -1; stop = -1;
} else { } else {
stop = CAST(int, s.stop); stop = CAST(int, s.stop);
if(stop < 0) { if(stop < 0) { stop += length; }
stop += length;
}
stop = clip(stop, -1, length - 1); 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) { i64 VM::py_hash(PyVar obj) {
// https://docs.python.org/3.10/reference/datamodel.html#object.__hash__ // https://docs.python.org/3.10/reference/datamodel.html#object.__hash__
const PyTypeInfo* ti = _tp_info(obj); const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__hash__) { if(ti->m__hash__) { return ti->m__hash__(this, obj); }
return ti->m__hash__(this, obj);
}
PyVar self; PyVar self;
PyVar f = get_unbound_method(obj, __hash__, &self, false); PyVar f = get_unbound_method(obj, __hash__, &self, false);
@ -632,9 +536,7 @@ i64 VM::py_hash(PyVar obj) {
return CAST(i64, ret); return CAST(i64, ret);
} }
// if it is trivial `object`, return PK_BITS // if it is trivial `object`, return PK_BITS
if(ti == &_all_types[tp_object]) { if(ti == &_all_types[tp_object]) { return obj.hash(); }
return obj.hash();
}
// otherwise, we check if it has a custom __eq__ other than object.__eq__ // otherwise, we check if it has a custom __eq__ other than object.__eq__
bool has_custom_eq = false; bool has_custom_eq = false;
if(ti->m__eq__) { if(ti->m__eq__) {
@ -718,9 +620,7 @@ PyVar VM::py_eval(std::string_view source, PyVar globals, PyVar locals) {
} }
PyVar VM::__format_object(PyVar obj, Str spec) { PyVar VM::__format_object(PyVar obj, Str spec) {
if(spec.empty()) { if(spec.empty()) { return VAR(py_str(obj)); }
return VAR(py_str(obj));
}
char type; char type;
switch(spec.end()[-1]) { switch(spec.end()[-1]) {
case 'f': case 'f':
@ -774,15 +674,11 @@ PyVar VM::__format_object(PyVar obj, Str spec) {
} }
} catch(...) { ValueError("invalid format specifer"); } } catch(...) { ValueError("invalid format specifer"); }
if(type != 'f' && dot >= 0) { if(type != 'f' && dot >= 0) { ValueError("precision not allowed in the format specifier"); }
ValueError("precision not allowed in the format specifier");
}
Str ret; Str ret;
if(type == 'f') { if(type == 'f') {
f64 val = CAST(f64, obj); f64 val = CAST(f64, obj);
if(precision < 0) { if(precision < 0) { precision = 6; }
precision = 6;
}
SStream ss; SStream ss;
ss.setprecision(precision); ss.setprecision(precision);
ss << val; ss << val;
@ -819,16 +715,12 @@ PyObject* VM::new_module(Str name, Str package) {
obj->attr().set(__name__, VAR(name)); obj->attr().set(__name__, VAR(name));
obj->attr().set(__package__, VAR(package)); obj->attr().set(__package__, VAR(package));
// convert to fullname // convert to fullname
if(!package.empty()) { if(!package.empty()) { name = package + "." + name; }
name = package + "." + name;
}
obj->attr().set(__path__, VAR(name)); obj->attr().set(__path__, VAR(name));
// we do not allow override in order to avoid memory leak // we do not allow override in order to avoid memory leak
// it is because Module objects are not garbage collected // it is because Module objects are not garbage collected
if(_modules.contains(name)) { if(_modules.contains(name)) { throw std::runtime_error(_S("module ", name.escape(), " already exists").str()); }
throw std::runtime_error(_S("module ", name.escape(), " already exists").str());
}
// set it into _modules // set it into _modules
_modules.set(name, obj); _modules.set(name, obj);
return 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_LOAD_CONST:
case OP_FORMAT_STRING: case OP_FORMAT_STRING:
case OP_IMPORT_PATH: case OP_IMPORT_PATH:
if(vm != nullptr) { if(vm != nullptr) { ss << " (" << vm->py_repr(co->consts[byte.arg]) << ")"; }
ss << " (" << vm->py_repr(co->consts[byte.arg]) << ")";
}
break; break;
case OP_LOAD_NAME: case OP_LOAD_NAME:
case OP_LOAD_GLOBAL: case OP_LOAD_GLOBAL:
@ -881,18 +771,14 @@ static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject
Str VM::disassemble(CodeObject_ co) { Str VM::disassemble(CodeObject_ co) {
auto pad = [](const Str& s, const int n) { auto pad = [](const Str& s, const int n) {
if(s.length() >= n) { if(s.length() >= n) { return s.substr(0, n); }
return s.substr(0, n);
}
return s + std::string(n - s.length(), ' '); return s + std::string(n - s.length(), ' ');
}; };
vector<int> jumpTargets; vector<int> jumpTargets;
for(int i = 0; i < co->codes.size(); i++) { for(int i = 0; i < co->codes.size(); i++) {
Bytecode byte = co->codes[i]; Bytecode byte = co->codes[i];
if(byte.is_forward_jump()) { if(byte.is_forward_jump()) { jumpTargets.push_back((int16_t)byte.arg + i); }
jumpTargets.push_back((int16_t)byte.arg + i);
}
} }
SStream ss; SStream ss;
int prev_line = -1; int prev_line = -1;
@ -902,9 +788,7 @@ Str VM::disassemble(CodeObject_ co) {
if(co->lines[i].lineno == prev_line) { if(co->lines[i].lineno == prev_line) {
line = ""; line = "";
} else { } else {
if(prev_line != -1) { if(prev_line != -1) { ss << "\n"; }
ss << "\n";
}
prev_line = co->lines[i].lineno; 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); ss << pad(line, 8) << pointer << pad(std::to_string(i), 3);
std::string bc_name(OP_NAMES[byte.op]); std::string bc_name(OP_NAMES[byte.op]);
if(co->lines[i].is_virtual) { if(co->lines[i].is_virtual) { bc_name += '*'; }
bc_name += '*';
}
ss << " " << pad(bc_name, 25) << " "; ss << " " << pad(bc_name, 25) << " ";
std::string argStr = _opcode_argstr(this, i, byte, co.get()); std::string argStr = _opcode_argstr(this, i, byte, co.get());
ss << argStr; ss << argStr;
if(i != co->codes.size() - 1) { if(i != co->codes.size() - 1) { ss << '\n'; }
ss << '\n';
}
} }
for(auto& decl: co->func_decls) { for(auto& decl: co->func_decls) {
@ -938,16 +818,10 @@ Str VM::disassemble(CodeObject_ co) {
#if PK_DEBUG_CEVAL_STEP #if PK_DEBUG_CEVAL_STEP
void VM::__log_s_data(const char* title) { void VM::__log_s_data(const char* title) {
if(_main == nullptr) { if(_main == nullptr) { return; }
return; if(callstack.empty()) { return; }
}
if(callstack.empty()) {
return;
}
SStream ss; SStream ss;
if(title) { if(title) { ss << title << " | "; }
ss << title << " | ";
}
std::map<PyVar*, int> sp_bases; std::map<PyVar*, int> sp_bases;
callstack.apply([&](Frame& f) { callstack.apply([&](Frame& f) {
assert(f._sp_base != nullptr); assert(f._sp_base != nullptr);
@ -958,9 +832,7 @@ void VM::__log_s_data(const char* title) {
ss << frame->co->name << ":" << line << " ["; ss << frame->co->name << ":" << line << " [";
for(PyVar* p = s_data.begin(); p != s_data.end(); p++) { for(PyVar* p = s_data.begin(); p != s_data.end(); p++) {
ss << std::string(sp_bases[p], '|'); ss << std::string(sp_bases[p], '|');
if(sp_bases[p] > 0) { if(sp_bases[p] > 0) { ss << " "; }
ss << " ";
}
if(*p == PY_NULL) { if(*p == PY_NULL) {
ss << "NULL"; ss << "NULL";
} else { } else {
@ -977,9 +849,7 @@ void VM::__log_s_data(const char* title) {
case tp_stack_memory: { case tp_stack_memory: {
int count = p->obj_get<StackMemory>().count; int count = p->obj_get<StackMemory>().count;
ss << "M[" << count << "]"; ss << "M[" << count << "]";
if(count > 0) { if(count > 0) { p += count; }
p += count;
}
break; break;
} }
default: ss << "(" << _type_name(this, p->type) << ")"; break; default: ss << "(" << _type_name(this, p->type) << ")"; break;
@ -1006,9 +876,7 @@ void VM::__init_builtin_types() {
auto validate = [](Type type, PyObject* ret) { auto validate = [](Type type, PyObject* ret) {
Type ret_t = ret->as<Type>(); Type ret_t = ret->as<Type>();
if(ret_t != type) { if(ret_t != type) { exit(-3); }
exit(-3);
}
}; };
validate(tp_int, new_type_object(nullptr, "int", tp_object, false)); 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)) { if(is_type(obj, tp_star_wrapper)) {
const StarWrapper& w = _CAST(StarWrapper&, obj); const StarWrapper& w = _CAST(StarWrapper&, obj);
// maybe this check should be done in the compile time // maybe this check should be done in the compile time
if(w.level != 1) { if(w.level != 1) { TypeError("expected level 1 star wrapper"); }
TypeError("expected level 1 star wrapper");
}
PyVar _0 = py_iter(w.obj); PyVar _0 = py_iter(w.obj);
const PyTypeInfo* info = _tp_info(_0); const PyTypeInfo* info = _tp_info(_0);
PyVar _1 = _py_next(info, _0); PyVar _1 = _py_next(info, _0);
@ -1101,16 +967,12 @@ void VM::__unpack_as_dict(ArgsView args, Dict& dict) {
if(is_type(obj, tp_star_wrapper)) { if(is_type(obj, tp_star_wrapper)) {
const StarWrapper& w = _CAST(StarWrapper&, obj); const StarWrapper& w = _CAST(StarWrapper&, obj);
// maybe this check should be done in the compile time // maybe this check should be done in the compile time
if(w.level != 2) { if(w.level != 2) { TypeError("expected level 2 star wrapper"); }
TypeError("expected level 2 star wrapper");
}
const Dict& other = CAST(Dict&, w.obj); const Dict& other = CAST(Dict&, w.obj);
dict.update(this, other); dict.update(this, other);
} else { } else {
const Tuple& t = CAST(Tuple&, obj); const Tuple& t = CAST(Tuple&, obj);
if(t.size() != 2) { if(t.size() != 2) { TypeError("expected tuple of length 2"); }
TypeError("expected tuple of length 2");
}
dict.set(this, t[0], t[1]); dict.set(this, t[0], t[1]);
} }
} }
@ -1143,14 +1005,10 @@ void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const
} else { } else {
// kwdefaults override // kwdefaults override
for(auto& kv: decl->kwargs) { for(auto& kv: decl->kwargs) {
if(i >= args.size()) { if(i >= args.size()) { break; }
break;
}
buffer[kv.index] = args[i++]; buffer[kv.index] = args[i++];
} }
if(i < args.size()) { if(i < args.size()) { TypeError(_S("too many arguments", " (", decl->code->name, ')')); }
TypeError(_S("too many arguments", " (", decl->code->name, ')'));
}
} }
PyVar vkwargs; PyVar vkwargs;
@ -1206,9 +1064,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
if(callable_t == tp_function) { if(callable_t == tp_function) {
/*****************_py_call*****************/ /*****************_py_call*****************/
// check stack overflow // check stack overflow
if(s_data.is_overflow()) { if(s_data.is_overflow()) { StackOverflowError(); }
StackOverflowError();
}
const Function& fn = PK_OBJ_GET(Function, callable); const Function& fn = PK_OBJ_GET(Function, callable);
const CodeObject* co = fn.decl->code.get(); const CodeObject* co = fn.decl->code.get();
@ -1231,9 +1087,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
args.size(), args.size(),
" were given")); " were given"));
} }
if(!kwargs.empty()) { if(!kwargs.empty()) { TypeError(_S(co->name, "() takes no keyword arguments")); }
TypeError(_S(co->name, "() takes no keyword arguments"));
}
// [callable, <self>, args..., local_vars...] // [callable, <self>, args..., local_vars...]
// ^p0 ^p1 ^_sp // ^p0 ^p1 ^_sp
s_data.reset(_base + co->nlocals); s_data.reset(_base + co->nlocals);
@ -1249,9 +1103,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
args.size(), args.size(),
" were given")); " were given"));
} }
if(!kwargs.empty()) { if(!kwargs.empty()) { TypeError(_S(co->name, "() takes no keyword arguments")); }
TypeError(_S(co->name, "() takes no keyword arguments"));
}
s_data.reset(p0); s_data.reset(p0);
return None; return None;
case FuncType::GENERATOR: case FuncType::GENERATOR:
@ -1265,9 +1117,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
// simple or normal // simple or normal
callstack.emplace(p0, co, fn._module, callable.get(), args.begin()); callstack.emplace(p0, co, fn._module, callable.get(), args.begin());
if(op_call) { if(op_call) { return PY_OP_CALL; }
return PY_OP_CALL;
}
return __run_top_frame(); return __run_top_frame();
/*****************_py_call*****************/ /*****************_py_call*****************/
} }
@ -1290,9 +1140,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
TypeError( TypeError(
"old-style native_func does not accept keyword arguments. If you want to skip this check, specify `argc` to -1"); "old-style native_func does not accept keyword arguments. If you want to skip this check, specify `argc` to -1");
} }
if(args.size() != f.argc) { if(args.size() != f.argc) { vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size())); }
vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size()));
}
} }
ret = f.call(this, args); 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) { void VM::delattr(PyVar _0, StrName _name) {
const PyTypeInfo* ti = _tp_info(_0); const PyTypeInfo* ti = _tp_info(_0);
if(ti->m__delattr__ && ti->m__delattr__(this, _0, _name)) { if(ti->m__delattr__ && ti->m__delattr__(this, _0, _name)) { return; }
return; if(is_tagged(_0) || !_0->is_attr_valid()) { TypeError("cannot delete attribute"); }
} if(!_0->attr().del(_name)) { AttributeError(_0, _name); }
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 // 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) { if(obj.type == tp_type) {
val = find_name_in_mro(PK_OBJ_GET(Type, obj), name); val = find_name_in_mro(PK_OBJ_GET(Type, obj), name);
if(val != nullptr) { if(val != nullptr) {
if(is_tagged(*val)) { if(is_tagged(*val)) { return *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(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; return *val;
} }
} else { } else {
val = obj->attr().try_get_2_likely_found(name); val = obj->attr().try_get_2_likely_found(name);
if(val != nullptr) { if(val != nullptr) { return *val; }
return *val;
}
} }
} }
if(cls_var != nullptr) { if(cls_var != nullptr) {
@ -1425,14 +1259,10 @@ PyVar VM::getattr(PyVar obj, StrName name, bool throw_err) {
const PyTypeInfo* ti = &_all_types[objtype]; const PyTypeInfo* ti = &_all_types[objtype];
if(ti->m__getattr__) { if(ti->m__getattr__) {
PyVar ret = ti->m__getattr__(this, obj, name); PyVar ret = ti->m__getattr__(this, obj, name);
if(ret) { if(ret) { return ret; }
return ret;
}
} }
if(throw_err) { if(throw_err) { AttributeError(obj, name); }
AttributeError(obj, name);
}
return nullptr; 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) { if(obj.type == tp_type) {
val = find_name_in_mro(PK_OBJ_GET(Type, obj), name); val = find_name_in_mro(PK_OBJ_GET(Type, obj), name);
if(val != nullptr) { if(val != nullptr) {
if(is_tagged(*val)) { if(is_tagged(*val)) { return *val; }
return *val; if(val->type == tp_staticmethod) { return PK_OBJ_GET(StaticMethod, *val).func; }
}
if(val->type == tp_staticmethod) {
return PK_OBJ_GET(StaticMethod, *val).func;
}
if(val->type == tp_classmethod) { if(val->type == tp_classmethod) {
return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, *val).func)); return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, *val).func));
} }
@ -1478,9 +1304,7 @@ PyVar VM::get_unbound_method(PyVar obj, StrName name, PyVar* self, bool throw_er
} }
} else { } else {
val = obj->attr().try_get_2_likely_found(name); val = obj->attr().try_get_2_likely_found(name);
if(val != nullptr) { if(val != nullptr) { return *val; }
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]; const PyTypeInfo* ti = &_all_types[objtype];
if(fallback && ti->m__getattr__) { if(fallback && ti->m__getattr__) {
PyVar ret = ti->m__getattr__(this, obj, name); PyVar ret = ti->m__getattr__(this, obj, name);
if(ret) { if(ret) { return ret; }
return ret;
}
} }
if(throw_err) { if(throw_err) { AttributeError(obj, name); }
AttributeError(obj, name);
}
return nullptr; return nullptr;
} }
@ -1542,9 +1362,7 @@ void VM::setattr(PyVar obj, StrName name, PyVar value) {
} }
// handle instance __dict__ // handle instance __dict__
if(is_tagged(obj) || !obj->is_attr_valid()) { if(is_tagged(obj) || !obj->is_attr_valid()) { TypeError("cannot set attribute"); }
TypeError("cannot set attribute");
}
obj->attr().set(name, value); 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::STATICMETHOD: nf = heap.gcnew<StaticMethod>(tp_staticmethod, nf); break;
case BindType::CLASSMETHOD: nf = heap.gcnew<ClassMethod>(tp_classmethod, nf); break; case BindType::CLASSMETHOD: nf = heap.gcnew<ClassMethod>(tp_classmethod, nf); break;
} }
if(obj != nullptr) { if(obj != nullptr) { obj->attr().set(name, nf); }
obj->attr().set(name, nf);
}
return 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 // fn(a, b, *c, d=1) -> None
co = compile(_S("def ", sig, " : pass"), "<bind>", EXEC_MODE); co = compile(_S("def ", sig, " : pass"), "<bind>", EXEC_MODE);
} catch(TopLevelException) { throw std::runtime_error("invalid signature: " + std::string(sig)); } } catch(TopLevelException) { throw std::runtime_error("invalid signature: " + std::string(sig)); }
if(co->func_decls.size() != 1) { if(co->func_decls.size() != 1) { throw std::runtime_error("expected 1 function declaration"); }
throw std::runtime_error("expected 1 function declaration");
}
FuncDecl_ decl = co->func_decls[0]; FuncDecl_ decl = co->func_decls[0];
decl->docstring = docstring; decl->docstring = docstring;
PyObject* f_obj = heap.gcnew<NativeFunc>(tp_native_func, fn, decl, std::move(userdata)); 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::CLASSMETHOD: f_obj = heap.gcnew<ClassMethod>(tp_classmethod, f_obj); break;
case BindType::DEFAULT: break; case BindType::DEFAULT: break;
} }
if(obj != nullptr) { if(obj != nullptr) { obj->attr().set(decl->code->name, f_obj); }
obj->attr().set(decl->code->name, f_obj);
}
return 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)); assert(is_type(obj, tp_type));
std::string_view name_sv(name); std::string_view name_sv(name);
int pos = name_sv.find(':'); int pos = name_sv.find(':');
if(pos > 0) { if(pos > 0) { name_sv = name_sv.substr(0, pos); }
name_sv = name_sv.substr(0, pos);
}
PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1); PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1);
PyVar _1 = vm->None; PyVar _1 = vm->None;
if(fset != nullptr) { if(fset != nullptr) { _1 = new_object<NativeFunc>(tp_native_func, fset, 2); }
_1 = new_object<NativeFunc>(tp_native_func, fset, 2);
}
PyObject* prop = heap.gcnew<Property>(tp_property, _0, _1); PyObject* prop = heap.gcnew<Property>(tp_property, _0, _1);
obj->attr().set(StrName(name_sv), prop); obj->attr().set(StrName(name_sv), prop);
return prop; return prop;
@ -1651,9 +1459,7 @@ void VM::__raise_exc(bool re_raise) {
int next_ip = frame->prepare_jump_exception_handler(&s_data); int next_ip = frame->prepare_jump_exception_handler(&s_data);
int actual_ip = frame->ip(); int actual_ip = frame->ip();
if(e._ip_on_error >= 0 && e._code_on_error == (void*)frame->co) { if(e._ip_on_error >= 0 && e._code_on_error == (void*)frame->co) { actual_ip = e._ip_on_error; }
actual_ip = e._ip_on_error;
}
int current_line = frame->co->lines[actual_ip].lineno; // current line int current_line = frame->co->lines[actual_ip].lineno; // current line
auto current_f_name = frame->co->name.sv(); // current function name auto current_f_name = frame->co->name.sv(); // current function name
if(frame->_callable == nullptr) { if(frame->_callable == nullptr) {
@ -1707,12 +1513,8 @@ void VM::bind__delitem__(Type type, void (*f)(VM*, PyVar, PyVar)) {
} }
PyVar VM::__pack_next_retval(unsigned n) { PyVar VM::__pack_next_retval(unsigned n) {
if(n == 0) { if(n == 0) { return StopIteration; }
return StopIteration; if(n == 1) { return s_data.popx(); }
}
if(n == 1) {
return s_data.popx();
}
PyVar retval = VAR(s_data.view(n).to_tuple()); PyVar retval = VAR(s_data.view(n).to_tuple());
s_data._sp -= n; s_data._sp -= n;
return retval; return retval;
@ -1860,9 +1662,7 @@ void Dict::_probe_0(VM* vm, PyVar key, bool& ok, int& i) const {
break; break;
} }
} else { } else {
if(_items[i].second == nullptr) { if(_items[i].second == nullptr) { break; }
break;
}
} }
// https://github.com/python/cpython/blob/3.8/Objects/dictobject.c#L166 // https://github.com/python/cpython/blob/3.8/Objects/dictobject.c#L166
i = ((5 * i) + 1) & _mask; i = ((5 * i) + 1) & _mask;
@ -1887,14 +1687,10 @@ void NextBreakpoint::_step(VM* vm) {
int curr_callstack_size = vm->callstack.size(); int curr_callstack_size = vm->callstack.size();
int curr_lineno = vm->callstack.top().curr_lineno(); int curr_lineno = vm->callstack.top().curr_lineno();
if(should_step_into) { if(should_step_into) {
if(curr_callstack_size != callstack_size || curr_lineno != lineno) { if(curr_callstack_size != callstack_size || curr_lineno != lineno) { vm->__breakpoint(); }
vm->__breakpoint();
}
} else { } else {
if(curr_callstack_size == callstack_size) { if(curr_callstack_size == callstack_size) {
if(curr_lineno != lineno) { if(curr_lineno != lineno) { vm->__breakpoint(); }
vm->__breakpoint();
}
} else if(curr_callstack_size < callstack_size) { } else if(curr_callstack_size < callstack_size) {
// returning // returning
vm->__breakpoint(); vm->__breakpoint();
@ -1927,16 +1723,12 @@ void VM::__breakpoint() {
while(lf != nullptr) { while(lf != nullptr) {
frames.push_back(lf); frames.push_back(lf);
lf = lf->f_back; lf = lf->f_back;
if(frames.size() >= 4) { if(frames.size() >= 4) { break; }
break;
}
} }
if(show_headers) { if(show_headers) {
for(int i = frames.size() - 1; i >= 0; i--) { for(int i = frames.size() - 1; i >= 0; i--) {
if(!show_where && i != 0) { if(!show_where && i != 0) { continue; }
continue;
}
SStream ss; SStream ss;
Frame* frame = &frames[i]->frame; Frame* frame = &frames[i]->frame;
@ -1976,9 +1768,7 @@ void VM::__breakpoint() {
stdout_write("!: execute statement\n"); stdout_write("!: execute statement\n");
continue; continue;
} }
if(line == "q" || line == "quit") { if(line == "q" || line == "quit") { vm->RuntimeError("pdb quit"); }
vm->RuntimeError("pdb quit");
}
if(line == "n" || line == "next") { if(line == "n" || line == "next") {
vm->_next_breakpoint = NextBreakpoint(vm->callstack.size(), frame_0->curr_lineno(), false); vm->_next_breakpoint = NextBreakpoint(vm->callstack.size(), frame_0->curr_lineno(), false);
break; break;
@ -1992,15 +1782,11 @@ void VM::__breakpoint() {
show_headers = true; show_headers = true;
continue; continue;
} }
if(line == "c" || line == "continue") { if(line == "c" || line == "continue") { break; }
break;
}
if(line == "a" || line == "args") { if(line == "a" || line == "args") {
int i = 0; int i = 0;
for(PyVar obj: frame_0->_locals) { for(PyVar obj: frame_0->_locals) {
if(obj == PY_NULL) { if(obj == PY_NULL) { continue; }
continue;
}
StrName name = frame_0->co->varnames[i++]; StrName name = frame_0->co->varnames[i++];
stdout_write(_S(name.sv(), " = ", vm->py_repr(obj), '\n')); stdout_write(_S(name.sv(), " = ", vm->py_repr(obj), '\n'));
} }
@ -2011,9 +1797,7 @@ void VM::__breakpoint() {
bool is_longlist = line == "ll" || line == "longlist"; bool is_longlist = line == "ll" || line == "longlist";
if(is_list || is_longlist) { if(is_list || is_longlist) {
if(frame_0->co->src->is_precompiled) { if(frame_0->co->src->is_precompiled) { continue; }
continue;
}
int lineno = frame_0->curr_lineno(); int lineno = frame_0->curr_lineno();
int start, end; int start, end;
@ -2024,9 +1808,7 @@ void VM::__breakpoint() {
} else { } else {
start = frame_0->co->start_line; start = frame_0->co->start_line;
end = frame_0->co->end_line; end = frame_0->co->end_line;
if(start == -1 || end == -1) { if(start == -1 || end == -1) { continue; }
continue;
}
} }
SStream ss; SStream ss;
@ -2076,9 +1858,7 @@ void Function::_gc_mark(VM* vm) const {
} }
void NativeFunc::_gc_mark(VM* vm) const { void NativeFunc::_gc_mark(VM* vm) const {
if(decl) { if(decl) { decl->_gc_mark(vm); }
decl->_gc_mark(vm);
}
} }
void FuncDecl::_gc_mark(VM* vm) const { 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->__curr_class);
vm->obj_gc_mark(vm->__c.error); vm->obj_gc_mark(vm->__c.error);
vm->__stack_gc_mark(vm->s_data.begin(), vm->s_data.end()); vm->__stack_gc_mark(vm->s_data.begin(), vm->s_data.end());
if(_gc_marker_ex) { if(_gc_marker_ex) { _gc_marker_ex(vm); }
_gc_marker_ex(vm);
}
} }
void ManagedHeap::_delete(PyObject* obj) { void ManagedHeap::_delete(PyObject* obj) {
const PyTypeInfo* ti = vm->_tp_info(obj->type); const PyTypeInfo* ti = vm->_tp_info(obj->type);
if(ti->vt._dtor) { if(ti->vt._dtor) { ti->vt._dtor(obj->_value_ptr()); }
ti->vt._dtor(obj->_value_ptr());
}
delete obj->_attr; // delete __dict__ if exists delete obj->_attr; // delete __dict__ if exists
PoolObject_dealloc(obj); PoolObject_dealloc(obj);
} }

View File

@ -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; } bool is_valid(int col, int row) const { return 0 <= col && col < n_cols && 0 <= row && row < n_rows; }
void check_valid(VM* vm, int col, int row) const { void check_valid(VM* vm, int col, int row) const {
if(is_valid(col, row)) { if(is_valid(col, row)) { return; }
return;
}
vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')')); vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')'));
} }
@ -48,9 +46,7 @@ struct Array2d {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
int n_cols = CAST(int, args[1]); int n_cols = CAST(int, args[1]);
int n_rows = CAST(int, args[2]); int n_rows = CAST(int, args[2]);
if(n_cols <= 0 || n_rows <= 0) { if(n_cols <= 0 || n_rows <= 0) { vm->ValueError("n_cols and n_rows must be positive integers"); }
vm->ValueError("n_cols and n_rows must be positive integers");
}
self.init(n_cols, n_rows); self.init(n_cols, n_rows);
if(vm->py_callable(args[3])) { if(vm->py_callable(args[3])) {
for(int i = 0; i < self.numel; i++) { for(int i = 0; i < self.numel; i++) {
@ -100,9 +96,7 @@ struct Array2d {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
int col = CAST(int, args[1]); int col = CAST(int, args[1]);
int row = CAST(int, args[2]); int row = CAST(int, args[2]);
if(!self.is_valid(col, row)) { if(!self.is_valid(col, row)) { return args[3]; }
return args[3];
}
return self._get(col, row); return self._get(col, row);
}); });
@ -111,12 +105,10 @@ struct Array2d {
int start_row, stop_row, step_row; \ int start_row, stop_row, step_row; \
vm->parse_int_slice(PK_OBJ_GET(Slice, xy[0]), self.n_cols, start_col, stop_col, step_col); \ vm->parse_int_slice(PK_OBJ_GET(Slice, xy[0]), self.n_cols, start_col, stop_col, step_col); \
vm->parse_int_slice(PK_OBJ_GET(Slice, xy[1]), self.n_rows, start_row, stop_row, step_row); \ vm->parse_int_slice(PK_OBJ_GET(Slice, xy[1]), self.n_rows, start_row, stop_row, step_row); \
if(step_col != 1 || step_row != 1) \ if(step_col != 1 || step_row != 1) vm->ValueError("slice step must be 1"); \
vm->ValueError("slice step must be 1"); \
int slice_width = stop_col - start_col; \ int slice_width = stop_col - start_col; \
int slice_height = stop_row - start_row; \ int slice_height = stop_row - start_row; \
if(slice_width <= 0 || slice_height <= 0) \ if(slice_width <= 0 || slice_height <= 0) vm->ValueError("slice width and height must be positive");
vm->ValueError("slice width and height must be positive");
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
Array2d& self = PK_OBJ_GET(Array2d, _0); Array2d& self = PK_OBJ_GET(Array2d, _0);
@ -285,17 +277,11 @@ struct Array2d {
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
Array2d& self = PK_OBJ_GET(Array2d, _0); Array2d& self = PK_OBJ_GET(Array2d, _0);
if(!vm->is_user_type<Array2d>(_1)) { if(!vm->is_user_type<Array2d>(_1)) { return vm->NotImplemented; }
return vm->NotImplemented;
}
Array2d& other = PK_OBJ_GET(Array2d, _1); Array2d& other = PK_OBJ_GET(Array2d, _1);
if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) { if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) { return vm->False; }
return vm->False;
}
for(int i = 0; i < self.numel; i++) { for(int i = 0; i < self.numel; i++) {
if(vm->py_ne(self.data[i], other.data[i])) { if(vm->py_ne(self.data[i], other.data[i])) { return vm->False; }
return vm->False;
}
} }
return vm->True; return vm->True;
}); });
@ -368,9 +354,7 @@ struct Array2d {
} }
int width = right - left + 1; int width = right - left + 1;
int height = bottom - top + 1; int height = bottom - top + 1;
if(width <= 0 || height <= 0) { if(width <= 0 || height <= 0) { return vm->None; }
return vm->None;
}
Tuple t(4); Tuple t(4);
t[0] = VAR(left); t[0] = VAR(left);
t[1] = VAR(top); t[1] = VAR(top);
@ -404,9 +388,7 @@ struct Array2dIter {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; });
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
Array2dIter& self = PK_OBJ_GET(Array2dIter, _0); Array2dIter& self = PK_OBJ_GET(Array2dIter, _0);
if(self.i == self.a->numel) { if(self.i == self.a->numel) { return 0; }
return 0;
}
std::div_t res = std::div(self.i, self.a->n_cols); std::div_t res = std::div(self.i, self.a->n_cols);
vm->s_data.emplace(VM::tp_int, res.rem); vm->s_data.emplace(VM::tp_int, res.rem);
vm->s_data.emplace(VM::tp_int, res.quot); vm->s_data.emplace(VM::tp_int, res.quot);

View File

@ -126,22 +126,14 @@ static unsigned int base64_decode(const char* in, unsigned int inlen, unsigned c
unsigned int j; unsigned int j;
unsigned char c; unsigned char c;
if(inlen & 0x3) { if(inlen & 0x3) { return 0; }
return 0;
}
for(i = j = 0; i < inlen; i++) { for(i = j = 0; i < inlen; i++) {
if(in[i] == BASE64_PAD) { if(in[i] == BASE64_PAD) { break; }
break; if(in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) { return 0; }
}
if(in[i] < BASE64DE_FIRST || in[i] > BASE64DE_LAST) {
return 0;
}
c = base64de[(unsigned char)in[i]]; c = base64de[(unsigned char)in[i]];
if(c == 255) { if(c == 255) { return 0; }
return 0;
}
switch(i & 0x3) { switch(i & 0x3) {
case 0: out[j] = (c << 2) & 0xFF; break; case 0: out[j] = (c << 2) & 0xFF; break;

View File

@ -13,9 +13,7 @@ void add_module_csv(VM* vm) {
std::string_view line = CAST(Str&, csvfile[i]).sv(); std::string_view line = CAST(Str&, csvfile[i]).sv();
if(i == 0) { if(i == 0) {
// Skip utf8 BOM if there is any. // Skip utf8 BOM if there is any.
if(strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) { if(strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) { line = line.substr(3); }
line = line.substr(3);
}
} }
List row; List row;
int j; int j;
@ -70,16 +68,12 @@ void add_module_csv(VM* vm) {
PyVar csv_reader = vm->_modules["csv"]->attr("reader"); PyVar csv_reader = vm->_modules["csv"]->attr("reader");
PyVar ret_obj = vm->call(csv_reader, args[0]); PyVar ret_obj = vm->call(csv_reader, args[0]);
const List& ret = CAST(List&, ret_obj); const List& ret = CAST(List&, ret_obj);
if(ret.size() == 0) { if(ret.size() == 0) { vm->ValueError("empty csvfile"); }
vm->ValueError("empty csvfile");
}
const List& header = CAST(List&, ret[0]); const List& header = CAST(List&, ret[0]);
List new_ret; List new_ret;
for(int i = 1; i < ret.size(); i++) { for(int i = 1; i < ret.size(); i++) {
const List& row = CAST(List&, ret[i]); const List& row = CAST(List&, ret[i]);
if(row.size() != header.size()) { if(row.size() != header.size()) { vm->ValueError("row.size() != header.size()"); }
vm->ValueError("row.size() != header.size()");
}
Dict row_dict; Dict row_dict;
for(int j = 0; j < header.size(); j++) { for(int j = 0; j < header.size(); j++) {
row_dict.set(vm, header[j], row[j]); row_dict.set(vm, header[j], row[j]);

View File

@ -67,17 +67,13 @@ static void patch__repr__(VM* vm, Type cls) {
static void patch__eq__(VM* vm, Type cls) { static void patch__eq__(VM* vm, Type cls) {
vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1) { vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1) {
if(vm->_tp(_0) != vm->_tp(_1)) { if(vm->_tp(_0) != vm->_tp(_1)) { return vm->NotImplemented; }
return vm->NotImplemented;
}
const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)]; const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)];
const auto& fields = cls_info->annotated_fields; const auto& fields = cls_info->annotated_fields;
for(StrName field: fields) { for(StrName field: fields) {
PyVar lhs = _0->attr(field); PyVar lhs = _0->attr(field);
PyVar rhs = _1->attr(field); PyVar rhs = _1->attr(field);
if(vm->py_ne(lhs, rhs)) { if(vm->py_ne(lhs, rhs)) { return vm->False; }
return vm->False;
}
} }
return vm->True; return vm->True;
}); });
@ -91,15 +87,9 @@ void add_module_dataclasses(VM* vm) {
Type cls = PK_OBJ_GET(Type, args[0]); Type cls = PK_OBJ_GET(Type, args[0]);
NameDict& cls_d = args[0]->attr(); NameDict& cls_d = args[0]->attr();
if(!cls_d.contains(__init__)) { if(!cls_d.contains(__init__)) { patch__init__(vm, cls); }
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(__repr__)) {
patch__repr__(vm, cls);
}
if(!cls_d.contains(__eq__)) {
patch__eq__(vm, cls);
}
const auto& fields = vm->_all_types[cls].annotated_fields; const auto& fields = vm->_all_types[cls].annotated_fields;
bool has_default = false; bool has_default = false;

View File

@ -23,9 +23,7 @@ static FILE* io_fopen(const char* name, const char* mode) {
#if _MSC_VER #if _MSC_VER
FILE* fp; FILE* fp;
errno_t err = fopen_s(&fp, name, mode); errno_t err = fopen_s(&fp, name, mode);
if(err != 0) { if(err != 0) { return nullptr; }
return nullptr;
}
return fp; return fp;
#else #else
return fopen(name, mode); 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) { unsigned char* _default_import_handler(const char* name, int* out_size) {
bool exists = std::filesystem::exists(std::filesystem::path(name)); bool exists = std::filesystem::exists(std::filesystem::path(name));
if(!exists) { if(!exists) { return nullptr; }
return nullptr;
}
FILE* fp = io_fopen(name, "rb"); FILE* fp = io_fopen(name, "rb");
if(!fp) { if(!fp) { return nullptr; }
return nullptr;
}
fseek(fp, 0, SEEK_END); fseek(fp, 0, SEEK_END);
int buffer_size = ftell(fp); int buffer_size = ftell(fp);
unsigned char* buffer = new unsigned char[buffer_size]; unsigned char* buffer = new unsigned char[buffer_size];
@ -83,9 +77,7 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
assert(actual_size <= buffer_size); assert(actual_size <= buffer_size);
// in text mode, CR may be dropped, which may cause `actual_size < buffer_size` // in text mode, CR may be dropped, which may cause `actual_size < buffer_size`
Bytes b(buffer, actual_size); Bytes b(buffer, actual_size);
if(io.is_text) { if(io.is_text) { return VAR(std::string_view((char*)b.data(), b.size())); }
return VAR(std::string_view((char*)b.data(), b.size()));
}
return VAR(std::move(b)); return VAR(std::move(b));
}); });
@ -104,9 +96,7 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind_func(type, "tell", 1, [](VM* vm, ArgsView args) { vm->bind_func(type, "tell", 1, [](VM* vm, ArgsView args) {
FileIO& io = PK_OBJ_GET(FileIO, args[0]); FileIO& io = PK_OBJ_GET(FileIO, args[0]);
long pos = ftell(io.fp); long pos = ftell(io.fp);
if(pos == -1) { if(pos == -1) { vm->IOError(strerror(errno)); }
vm->IOError(strerror(errno));
}
return VAR(pos); return VAR(pos);
}); });
@ -115,9 +105,7 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
long offset = CAST(long, args[1]); long offset = CAST(long, args[1]);
int whence = CAST(int, args[2]); int whence = CAST(int, args[2]);
int ret = fseek(io.fp, offset, whence); int ret = fseek(io.fp, offset, whence);
if(ret != 0) { if(ret != 0) { vm->IOError(strerror(errno)); }
vm->IOError(strerror(errno));
}
return vm->None; 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) { FileIO::FileIO(VM* vm, const Str& file, const Str& mode) {
this->is_text = mode.sv().find("b") == std::string::npos; this->is_text = mode.sv().find("b") == std::string::npos;
fp = io_fopen(file.c_str(), mode.c_str()); fp = io_fopen(file.c_str(), mode.c_str());
if(!fp) { if(!fp) { vm->IOError(strerror(errno)); }
vm->IOError(strerror(errno));
}
} }
void FileIO::close() { void FileIO::close() {
if(fp == nullptr) { if(fp == nullptr) { return; }
return;
}
fclose(fp); fclose(fp);
fp = nullptr; fp = nullptr;
} }
@ -197,27 +181,21 @@ void add_module_os(VM* vm) {
vm->bind_func(mod, "remove", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "remove", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
bool ok = std::filesystem::remove(path); bool ok = std::filesystem::remove(path);
if(!ok) { if(!ok) { vm->IOError("operation failed"); }
vm->IOError("operation failed");
}
return vm->None; return vm->None;
}); });
vm->bind_func(mod, "mkdir", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "mkdir", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
bool ok = std::filesystem::create_directory(path); bool ok = std::filesystem::create_directory(path);
if(!ok) { if(!ok) { vm->IOError("operation failed"); }
vm->IOError("operation failed");
}
return vm->None; return vm->None;
}); });
vm->bind_func(mod, "rmdir", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "rmdir", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
bool ok = std::filesystem::remove(path); bool ok = std::filesystem::remove(path);
if(!ok) { if(!ok) { vm->IOError("operation failed"); }
vm->IOError("operation failed");
}
return vm->None; return vm->None;
}); });

View File

@ -55,16 +55,14 @@ namespace pkpy {
vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index) { \ vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index) { \
Vec##D self = _CAST(Vec##D, obj); \ Vec##D self = _CAST(Vec##D, obj); \
i64 i = CAST(i64, index); \ i64 i = CAST(i64, index); \
if(i < 0 || i >= D) \ if(i < 0 || i >= D) vm->IndexError("index out of range"); \
vm->IndexError("index out of range"); \
return VAR(self[i]); \ return VAR(self[i]); \
}); });
#define BIND_SSO_VEC_COMMON(D) \ #define BIND_SSO_VEC_COMMON(D) \
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \ vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
Vec##D self = _CAST(Vec##D, _0); \ Vec##D self = _CAST(Vec##D, _0); \
if(!vm->is_user_type<Vec##D>(_1)) \ if(!vm->is_user_type<Vec##D>(_1)) return vm->NotImplemented; \
return vm->NotImplemented; \
Vec##D other = _CAST(Vec##D, _1); \ Vec##D other = _CAST(Vec##D, _1); \
return VAR(self == other); \ return VAR(self == other); \
}); \ }); \
@ -165,12 +163,8 @@ void Vec2::_register(VM* vm, PyObject* mod, PyObject* type) {
Vec2 __to = CAST(Vec2, args[1]); Vec2 __to = CAST(Vec2, args[1]);
float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x); float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x);
const float PI = 3.1415926535897932384f; const float PI = 3.1415926535897932384f;
if(val > PI) { if(val > PI) { val -= 2 * PI; }
val -= 2 * PI; if(val < -PI) { val += 2 * PI; }
}
if(val < -PI) {
val += 2 * PI;
}
return VAR(val); return VAR(val);
}, },
{}, {},
@ -290,14 +284,10 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
PY_STRUCT_LIKE(Mat3x3) PY_STRUCT_LIKE(Mat3x3)
vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args) { vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1 + 0) { if(args.size() == 1 + 0) { return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros()); }
return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros());
}
if(args.size() == 1 + 1) { if(args.size() == 1 + 1) {
const List& list = CAST(List&, args[1]); const List& list = CAST(List&, args[1]);
if(list.size() != 9) { if(list.size() != 9) { vm->TypeError("Mat3x3.__new__ takes a list of 9 floats"); }
vm->TypeError("Mat3x3.__new__ takes a list of 9 floats");
}
Mat3x3 mat; Mat3x3 mat;
for(int i = 0; i < 9; i++) { for(int i = 0; i < 9; i++) {
mat.v[i] = CAST_F(list[i]); mat.v[i] = CAST_F(list[i]);
@ -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) { vm->bind__getitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index) {
Mat3x3& self = _CAST(Mat3x3&, obj); Mat3x3& self = _CAST(Mat3x3&, obj);
Tuple& t = CAST(Tuple&, index); Tuple& t = CAST(Tuple&, index);
if(t.size() != 2) { if(t.size() != 2) { vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers"); }
vm->TypeError("Mat3x3.__getitem__ takes a tuple of 2 integers");
}
i64 i = CAST(i64, t[0]); i64 i = CAST(i64, t[0]);
i64 j = CAST(i64, t[1]); i64 j = CAST(i64, t[1]);
if(i < 0 || i >= 3 || j < 0 || j >= 3) { if(i < 0 || i >= 3 || j < 0 || j >= 3) { vm->IndexError("index out of range"); }
vm->IndexError("index out of range");
}
return VAR(self.m[i][j]); return VAR(self.m[i][j]);
}); });
vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index, PyVar value) { vm->bind__setitem__(type->as<Type>(), [](VM* vm, PyVar obj, PyVar index, PyVar value) {
Mat3x3& self = _CAST(Mat3x3&, obj); Mat3x3& self = _CAST(Mat3x3&, obj);
const Tuple& t = CAST(Tuple&, index); const Tuple& t = CAST(Tuple&, index);
if(t.size() != 2) { if(t.size() != 2) { vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers"); }
vm->TypeError("Mat3x3.__setitem__ takes a tuple of 2 integers");
}
i64 i = CAST(i64, t[0]); i64 i = CAST(i64, t[0]);
i64 j = CAST(i64, t[1]); i64 j = CAST(i64, t[1]);
if(i < 0 || i >= 3 || j < 0 || j >= 3) { if(i < 0 || i >= 3 || j < 0 || j >= 3) { vm->IndexError("index out of range"); }
vm->IndexError("index out of range");
}
self.m[i][j] = CAST_F(value); self.m[i][j] = CAST_F(value);
}); });
@ -438,27 +420,21 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__invert__(type->as<Type>(), [](VM* vm, PyVar obj) { vm->bind__invert__(type->as<Type>(), [](VM* vm, PyVar obj) {
Mat3x3& self = _CAST(Mat3x3&, obj); Mat3x3& self = _CAST(Mat3x3&, obj);
Mat3x3 ret; Mat3x3 ret;
if(!self.inverse(ret)) { if(!self.inverse(ret)) { vm->ValueError("matrix is not invertible"); }
vm->ValueError("matrix is not invertible");
}
return vm->new_user_object<Mat3x3>(ret); return vm->new_user_object<Mat3x3>(ret);
}); });
vm->bind_func(type, "inverse", 1, [](VM* vm, ArgsView args) { vm->bind_func(type, "inverse", 1, [](VM* vm, ArgsView args) {
Mat3x3& self = _CAST(Mat3x3&, args[0]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
Mat3x3 ret; Mat3x3 ret;
if(!self.inverse(ret)) { if(!self.inverse(ret)) { vm->ValueError("matrix is not invertible"); }
vm->ValueError("matrix is not invertible");
}
return vm->new_user_object<Mat3x3>(ret); return vm->new_user_object<Mat3x3>(ret);
}); });
vm->bind_func(type, "inverse_", 1, [](VM* vm, ArgsView args) { vm->bind_func(type, "inverse_", 1, [](VM* vm, ArgsView args) {
Mat3x3& self = _CAST(Mat3x3&, args[0]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
Mat3x3 ret; Mat3x3 ret;
if(!self.inverse(ret)) { if(!self.inverse(ret)) { vm->ValueError("matrix is not invertible"); }
vm->ValueError("matrix is not invertible");
}
self = ret; self = ret;
return vm->None; return vm->None;
}); });
@ -571,9 +547,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
const Mat3x3& self = _CAST(Mat3x3&, args[0]); const Mat3x3& self = _CAST(Mat3x3&, args[0]);
Vec2 v = CAST(Vec2, args[1]); Vec2 v = CAST(Vec2, args[1]);
Mat3x3 inv; Mat3x3 inv;
if(!self.inverse(inv)) { if(!self.inverse(inv)) { vm->ValueError("matrix is not invertible"); }
vm->ValueError("matrix is not invertible");
}
Vec2 res(inv._11 * v.x + inv._12 * v.y + inv._13, inv._21 * v.x + inv._22 * v.y + inv._23); Vec2 res(inv._11 * v.x + inv._12 * v.y + inv._13, inv._21 * v.x + inv._22 * v.y + inv._23);
return vm->new_user_object<Vec2>(res); return vm->new_user_object<Vec2>(res);
}); });
@ -589,9 +563,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
const Mat3x3& self = _CAST(Mat3x3&, args[0]); const Mat3x3& self = _CAST(Mat3x3&, args[0]);
Vec2 v = CAST(Vec2, args[1]); Vec2 v = CAST(Vec2, args[1]);
Mat3x3 inv; Mat3x3 inv;
if(!self.inverse(inv)) { if(!self.inverse(inv)) { vm->ValueError("matrix is not invertible"); }
vm->ValueError("matrix is not invertible");
}
Vec2 res(inv._11 * v.x + inv._12 * v.y, inv._21 * v.x + inv._22 * v.y); Vec2 res(inv._11 * v.x + inv._12 * v.y, inv._21 * v.x + inv._22 * v.y);
return vm->new_user_object<Vec2>(res); return vm->new_user_object<Vec2>(res);
}); });
@ -656,18 +628,14 @@ Mat3x3 Mat3x3::operator/ (float scalar) const {
bool Mat3x3::operator== (const Mat3x3& other) const { bool Mat3x3::operator== (const Mat3x3& other) const {
for(int i = 0; i < 9; ++i) { for(int i = 0; i < 9; ++i) {
if(!isclose(v[i], other.v[i])) { if(!isclose(v[i], other.v[i])) { return false; }
return false;
}
} }
return true; return true;
} }
bool Mat3x3::operator!= (const Mat3x3& other) const { bool Mat3x3::operator!= (const Mat3x3& other) const {
for(int i = 0; i < 9; ++i) { for(int i = 0; i < 9; ++i) {
if(!isclose(v[i], other.v[i])) { if(!isclose(v[i], other.v[i])) { return true; }
return true;
}
} }
return false; return false;
} }
@ -714,9 +682,7 @@ Mat3x3 Mat3x3::transpose() const {
bool Mat3x3::inverse(Mat3x3& out) const { bool Mat3x3::inverse(Mat3x3& out) const {
float det = determinant(); float det = determinant();
if(isclose(det, 0)) { if(isclose(det, 0)) { return false; }
return false;
}
float inv_det = 1.0f / det; float inv_det = 1.0f / det;
out._11 = (_22 * _33 - _23 * _32) * inv_det; out._11 = (_22 * _33 - _23 * _32) * inv_det;
out._12 = (_13 * _32 - _12 * _33) * inv_det; out._12 = (_13 * _32 - _12 * _33) * inv_det;
@ -738,9 +704,7 @@ Mat3x3 Mat3x3::trs(Vec2 t, float radian, Vec2 s) {
bool Mat3x3::is_affine() const { bool Mat3x3::is_affine() const {
float det = _11 * _22 - _12 * _21; float det = _11 * _22 - _12 * _21;
if(isclose(det, 0)) { if(isclose(det, 0)) { return false; }
return false;
}
return _31 == 0.0f && _32 == 0.0f && _33 == 1.0f; return _31 == 0.0f && _32 == 0.0f && _33 == 1.0f;
} }

View File

@ -62,9 +62,7 @@ void add_module_time(VM* vm) {
while(true) { while(true) {
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
f64 elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - begin).count() / 1000.0; f64 elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - begin).count() / 1000.0;
if(elapsed >= seconds) { if(elapsed >= seconds) { break; }
break;
}
} }
return vm->None; return vm->None;
}); });
@ -143,12 +141,8 @@ void add_module_math(VM* vm) {
vm->bind_func(mod, "gcd", 2, [](VM* vm, ArgsView args) { vm->bind_func(mod, "gcd", 2, [](VM* vm, ArgsView args) {
i64 a = CAST(i64, args[0]); i64 a = CAST(i64, args[0]);
i64 b = CAST(i64, args[1]); i64 b = CAST(i64, args[1]);
if(a < 0) { if(a < 0) { a = -a; }
a = -a; if(b < 0) { b = -b; }
}
if(b < 0) {
b = -b;
}
while(b != 0) { while(b != 0) {
i64 t = b; i64 t = b;
b = a % b; b = a % b;
@ -201,9 +195,7 @@ void add_module_math(VM* vm) {
vm->bind_func(mod, "factorial", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "factorial", 1, [](VM* vm, ArgsView args) {
i64 n = CAST(i64, args[0]); i64 n = CAST(i64, args[0]);
if(n < 0) { if(n < 0) { vm->ValueError("factorial() not defined for negative values"); }
vm->ValueError("factorial() not defined for negative values");
}
i64 r = 1; i64 r = 1;
for(i64 i = 2; i <= n; i++) { for(i64 i = 2; i <= n; i++) {
r *= i; r *= i;
@ -215,18 +207,14 @@ void add_module_math(VM* vm) {
void add_module_traceback(VM* vm) { void add_module_traceback(VM* vm) {
PyObject* mod = vm->new_module("traceback"); PyObject* mod = vm->new_module("traceback");
vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) { vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) {
if(vm->__last_exception == nullptr) { if(vm->__last_exception == nullptr) { vm->ValueError("no exception"); }
vm->ValueError("no exception");
}
Exception& e = vm->__last_exception->as<Exception>(); Exception& e = vm->__last_exception->as<Exception>();
vm->stdout_write(e.summary()); vm->stdout_write(e.summary());
return vm->None; return vm->None;
}); });
vm->bind_func(mod, "format_exc", 0, [](VM* vm, ArgsView args) { vm->bind_func(mod, "format_exc", 0, [](VM* vm, ArgsView args) {
if(vm->__last_exception == nullptr) { if(vm->__last_exception == nullptr) { vm->ValueError("no exception"); }
vm->ValueError("no exception");
}
Exception& e = vm->__last_exception->as<Exception>(); Exception& e = vm->__last_exception->as<Exception>();
return VAR(e.summary()); return VAR(e.summary());
}); });
@ -243,9 +231,7 @@ void add_module_dis(VM* vm) {
code = vm->compile(source, "<dis>", EXEC_MODE); code = vm->compile(source, "<dis>", EXEC_MODE);
} }
PyVar f = obj; PyVar f = obj;
if(is_type(f, vm->tp_bound_method)) { if(is_type(f, vm->tp_bound_method)) { f = CAST(BoundMethod, obj).func; }
f = CAST(BoundMethod, obj).func;
}
code = CAST(Function&, f).decl->code; code = CAST(Function&, f).decl->code;
vm->stdout_write(vm->disassemble(code)); vm->stdout_write(vm->disassemble(code));
return vm->None; return vm->None;
@ -268,9 +254,7 @@ void add_module_enum(VM* vm) {
for(auto [k, v]: attr.items()) { for(auto [k, v]: attr.items()) {
// wrap every attribute // wrap every attribute
std::string_view k_sv = k.sv(); std::string_view k_sv = k.sv();
if(k_sv.empty() || k_sv[0] == '_') { if(k_sv.empty() || k_sv[0] == '_') { continue; }
continue;
}
attr.set(k, vm->call(new_ti->obj, VAR(k_sv), v)); attr.set(k, vm->call(new_ti->obj, VAR(k_sv), v));
} }
}; };
@ -283,12 +267,8 @@ void add_module___builtins(VM* vm) {
vm->bind_func(mod, "_enable_instance_dict", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "_enable_instance_dict", 1, [](VM* vm, ArgsView args) {
PyVar self = args[0]; PyVar self = args[0];
if(is_tagged(self)) { if(is_tagged(self)) { vm->TypeError("object: tagged object cannot enable instance dict"); }
vm->TypeError("object: tagged object cannot enable instance dict"); if(self->is_attr_valid()) { vm->RuntimeError("object: instance dict is already enabled"); }
}
if(self->is_attr_valid()) {
vm->RuntimeError("object: instance dict is already enabled");
}
self->_attr = new NameDict(); self->_attr = new NameDict();
return vm->None; return vm->None;
}); });
@ -347,9 +327,7 @@ struct LineProfilerW {
}; };
_LpGuard::_LpGuard(LineProfilerW* lp, VM* vm) : lp(lp), vm(vm) { _LpGuard::_LpGuard(LineProfilerW* lp, VM* vm) : lp(lp), vm(vm) {
if(vm->_profiler) { if(vm->_profiler) { vm->ValueError("only one profiler can be enabled at a time"); }
vm->ValueError("only one profiler can be enabled at a time");
}
vm->_profiler = &lp->profiler; vm->_profiler = &lp->profiler;
lp->profiler.begin(); lp->profiler.begin();
} }

View File

@ -142,9 +142,7 @@ struct Random {
Random& self = PK_OBJ_GET(Random, args[0]); Random& self = PK_OBJ_GET(Random, args[0]);
i64 a = CAST(i64, args[1]); i64 a = CAST(i64, args[1]);
i64 b = CAST(i64, args[2]); i64 b = CAST(i64, args[2]);
if(a > b) { if(a > b) { vm->ValueError("randint(a, b): a must be less than or equal to b"); }
vm->ValueError("randint(a, b): a must be less than or equal to b");
}
return VAR(self.gen.randint(a, b)); return VAR(self.gen.randint(a, b));
}); });
@ -157,9 +155,7 @@ struct Random {
Random& self = PK_OBJ_GET(Random, args[0]); Random& self = PK_OBJ_GET(Random, args[0]);
f64 a = CAST(f64, args[1]); f64 a = CAST(f64, args[1]);
f64 b = CAST(f64, args[2]); f64 b = CAST(f64, args[2]);
if(a > b) { if(a > b) { std::swap(a, b); }
std::swap(a, b);
}
return VAR(self.gen.uniform(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) { vm->bind_func(type, "choice", 2, [](VM* vm, ArgsView args) {
Random& self = PK_OBJ_GET(Random, args[0]); Random& self = PK_OBJ_GET(Random, args[0]);
ArgsView view = vm->cast_array_view(args[1]); ArgsView view = vm->cast_array_view(args[1]);
if(view.empty()) { if(view.empty()) { vm->IndexError("cannot choose from an empty sequence"); }
vm->IndexError("cannot choose from an empty sequence");
}
int index = self.gen.randint(0, view.size() - 1); int index = self.gen.randint(0, view.size() - 1);
return view[index]; return view[index];
}); });
@ -188,9 +182,7 @@ struct Random {
ArgsView view = vm->cast_array_view(args[1]); ArgsView view = vm->cast_array_view(args[1]);
PyVar* data = view.begin(); PyVar* data = view.begin();
int size = view.size(); int size = view.size();
if(size == 0) { if(size == 0) { vm->IndexError("cannot choose from an empty sequence"); }
vm->IndexError("cannot choose from an empty sequence");
}
array<f64> cum_weights(size); array<f64> cum_weights(size);
if(args[2] == vm->None) { if(args[2] == vm->None) {
for(int i = 0; i < size; i++) { for(int i = 0; i < size; i++) {
@ -198,17 +190,13 @@ struct Random {
} }
} else { } else {
ArgsView weights = vm->cast_array_view(args[2]); ArgsView weights = vm->cast_array_view(args[2]);
if(weights.size() != size) { if(weights.size() != size) { vm->ValueError(_S("len(weights) != ", size)); }
vm->ValueError(_S("len(weights) != ", size));
}
cum_weights[0] = CAST(f64, weights[0]); cum_weights[0] = CAST(f64, weights[0]);
for(int i = 1; i < size; i++) { for(int i = 1; i < size; i++) {
cum_weights[i] = cum_weights[i - 1] + CAST(f64, weights[i]); cum_weights[i] = cum_weights[i - 1] + CAST(f64, weights[i]);
} }
} }
if(cum_weights[size - 1] <= 0) { if(cum_weights[size - 1] <= 0) { vm->ValueError("total of weights must be greater than zero"); }
vm->ValueError("total of weights must be greater than zero");
}
int k = CAST(int, args[3]); int k = CAST(int, args[3]);
List result(k); List result(k);
for(int i = 0; i < k; i++) { for(int i = 0; i < k; i++) {

View File

@ -43,9 +43,7 @@ Dict::Dict(const Dict& other) {
void Dict::set(VM* vm, PyVar key, PyVar val) { void Dict::set(VM* vm, PyVar key, PyVar val) {
// do possible rehash // do possible rehash
if(_size + 1 > _critical_size) { if(_size + 1 > _critical_size) { _rehash(vm); }
_rehash(vm);
}
bool ok; bool ok;
int i; int i;
_probe_1(vm, key, ok, i); _probe_1(vm, key, ok, i);
@ -93,9 +91,7 @@ PyVar Dict::try_get(VM* vm, PyVar key) const {
bool ok; bool ok;
int i; int i;
_probe_0(vm, key, ok, i); _probe_0(vm, key, ok, i);
if(!ok) { if(!ok) { return nullptr; }
return nullptr;
}
return _items[i].second; return _items[i].second;
} }
@ -110,9 +106,7 @@ bool Dict::del(VM* vm, PyVar key) {
bool ok; bool ok;
int i; int i;
_probe_0(vm, key, ok, i); _probe_0(vm, key, ok, i);
if(!ok) { if(!ok) { return false; }
return false;
}
_items[i].first = nullptr; _items[i].first = nullptr;
// _items[i].second = PY_DELETED_SLOT; // do not change .second if it is not NULL, it means the slot is occupied by // _items[i].second = PY_DELETED_SLOT; // do not change .second if it is not NULL, it means the slot is occupied by
// a deleted item // a deleted item
@ -179,8 +173,6 @@ void Dict::clear() {
} }
Dict::~Dict() { Dict::~Dict() {
if(_items) { if(_items) { std::free(_items); }
std::free(_items);
}
} }
} // namespace pkpy } // namespace pkpy

View File

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

View File

@ -5,15 +5,11 @@ SourceData::SourceData(std::string_view source, const Str& filename, CompileMode
filename(filename), mode(mode) { filename(filename), mode(mode) {
int index = 0; int index = 0;
// Skip utf8 BOM if there is any. // Skip utf8 BOM if there is any.
if(strncmp(source.data(), "\xEF\xBB\xBF", 3) == 0) { if(strncmp(source.data(), "\xEF\xBB\xBF", 3) == 0) { index += 3; }
index += 3;
}
// Drop all '\r' // Drop all '\r'
SStream ss(source.size() + 1); SStream ss(source.size() + 1);
while(index < source.size()) { while(index < source.size()) {
if(source[index] != '\r') { if(source[index] != '\r') { ss << source[index]; }
ss << source[index];
}
index++; index++;
} }
this->source = ss.str(); 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 { std::pair<const char*, const char*> SourceData::_get_line(int lineno) const {
if(is_precompiled || lineno == -1) { if(is_precompiled || lineno == -1) { return {nullptr, nullptr}; }
return {nullptr, nullptr};
}
lineno -= 1; lineno -= 1;
if(lineno < 0) { if(lineno < 0) { lineno = 0; }
lineno = 0;
}
const char* _start = line_starts[lineno]; const char* _start = line_starts[lineno];
const char* i = _start; const char* i = _start;
// max 300 chars // max 300 chars
@ -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 { std::string_view SourceData::get_line(int lineno) const {
auto [_0, _1] = _get_line(lineno); auto [_0, _1] = _get_line(lineno);
if(_0 && _1) { if(_0 && _1) { return std::string_view(_0, _1 - _0); }
return std::string_view(_0, _1 - _0);
}
return "<?>"; return "<?>";
} }
Str SourceData::snapshot(int lineno, const char* cursor, std::string_view name) const { Str SourceData::snapshot(int lineno, const char* cursor, std::string_view name) const {
SStream ss; SStream ss;
ss << " " << "File \"" << filename << "\", line " << lineno; ss << " " << "File \"" << filename << "\", line " << lineno;
if(!name.empty()) { if(!name.empty()) { ss << ", in " << name; }
ss << ", in " << name;
}
if(!is_precompiled) { if(!is_precompiled) {
ss << '\n'; ss << '\n';
std::pair<const char*, const char*> pair = _get_line(lineno); std::pair<const char*, const char*> pair = _get_line(lineno);
@ -68,16 +56,12 @@ Str SourceData::snapshot(int lineno, const char* cursor, std::string_view name)
if(pair.first && pair.second) { if(pair.first && pair.second) {
line = Str(pair.first, pair.second - pair.first).lstrip(); line = Str(pair.first, pair.second - pair.first).lstrip();
removed_spaces = pair.second - pair.first - line.length(); removed_spaces = pair.second - pair.first - line.length();
if(line.empty()) { if(line.empty()) { line = "<?>"; }
line = "<?>";
}
} }
ss << " " << line; ss << " " << line;
if(cursor && line != "<?>" && cursor >= pair.first && cursor <= pair.second) { if(cursor && line != "<?>" && cursor >= pair.first && cursor <= pair.second) {
auto column = cursor - pair.first - removed_spaces; auto column = cursor - pair.first - removed_spaces;
if(column >= 0) { if(column >= 0) { ss << "\n " << std::string(column, ' ') << "^"; }
ss << "\n " << std::string(column, ' ') << "^";
}
} }
} }
return ss.str(); return ss.str();

View File

@ -37,9 +37,7 @@ Tuple::Tuple(PyVar _0, PyVar _1, PyVar _2) : Tuple(3) {
} }
Tuple::~Tuple() { Tuple::~Tuple() {
if(!is_inlined()) { if(!is_inlined()) { std::free(_args); }
std::free(_args);
}
} }
List ArgsView::to_list() const { List ArgsView::to_list() const {

View File

@ -49,17 +49,13 @@ PyVar PyArrayGetItem(VM* vm, PyVar _0, PyVar _1) {
void __init_builtins(VM* _vm) { void __init_builtins(VM* _vm) {
#define BIND_NUM_ARITH_OPT(name, op) \ #define BIND_NUM_ARITH_OPT(name, op) \
_vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { \ _vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { \
if(is_int(rhs)) \ if(is_int(rhs)) return VAR(_CAST(i64, lhs) op _CAST(i64, 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_float(rhs)) \
return VAR(_CAST(i64, lhs) op _CAST(f64, rhs)); \
return vm->NotImplemented; \ return vm->NotImplemented; \
}); \ }); \
_vm->bind##name(VM::tp_float, [](VM* vm, PyVar lhs, PyVar rhs) { \ _vm->bind##name(VM::tp_float, [](VM* vm, PyVar lhs, PyVar rhs) { \
if(is_int(rhs)) \ if(is_int(rhs)) return VAR(_CAST(f64, lhs) op _CAST(i64, 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_float(rhs)) \
return VAR(_CAST(f64, lhs) op _CAST(f64, rhs)); \
return vm->NotImplemented; \ return vm->NotImplemented; \
}); });
@ -71,17 +67,13 @@ void __init_builtins(VM* _vm) {
#define BIND_NUM_LOGICAL_OPT(name, op) \ #define BIND_NUM_LOGICAL_OPT(name, op) \
_vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { \ _vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { \
if(is_int(rhs)) \ if(is_int(rhs)) return VAR(_CAST(i64, lhs) op _CAST(i64, 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_float(rhs)) \
return VAR(_CAST(i64, lhs) op _CAST(f64, rhs)); \
return vm->NotImplemented; \ return vm->NotImplemented; \
}); \ }); \
_vm->bind##name(VM::tp_float, [](VM* vm, PyVar lhs, PyVar rhs) { \ _vm->bind##name(VM::tp_float, [](VM* vm, PyVar lhs, PyVar rhs) { \
if(is_int(rhs)) \ if(is_int(rhs)) return VAR(_CAST(f64, lhs) op _CAST(i64, 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_float(rhs)) \
return VAR(_CAST(f64, lhs) op _CAST(f64, rhs)); \
return vm->NotImplemented; \ return vm->NotImplemented; \
}); });
@ -112,9 +104,7 @@ void __init_builtins(VM* _vm) {
Frame* frame = &vm->callstack.top(); Frame* frame = &vm->callstack.top();
if(frame->_callable != nullptr) { if(frame->_callable != nullptr) {
class_arg = frame->_callable->as<Function>()._class; class_arg = frame->_callable->as<Function>()._class;
if(frame->_locals.size() > 0) { if(frame->_locals.size() > 0) { self_arg = frame->_locals[0]; }
self_arg = frame->_locals[0];
}
} }
if(class_arg == nullptr || self_arg == nullptr) { if(class_arg == nullptr || self_arg == nullptr) {
vm->TypeError("super(): unable to determine the class context, use super(class, self) instead"); vm->TypeError("super(): unable to determine the class context, use super(class, self) instead");
@ -149,9 +139,7 @@ void __init_builtins(VM* _vm) {
Tuple& types = _CAST(Tuple&, args[1]); Tuple& types = _CAST(Tuple&, args[1]);
for(PyVar type: types) { for(PyVar type: types) {
vm->check_type(type, vm->tp_type); vm->check_type(type, vm->tp_type);
if(vm->isinstance(args[0], type->as<Type>())) { if(vm->isinstance(args[0], type->as<Type>())) { return vm->True; }
return vm->True;
}
} }
return vm->False; return vm->False;
} }
@ -172,29 +160,19 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind(_vm->builtins, "round(x, ndigits=None)", [](VM* vm, ArgsView args) { _vm->bind(_vm->builtins, "round(x, ndigits=None)", [](VM* vm, ArgsView args) {
if(is_int(args[0])) { if(is_int(args[0])) { return args[0]; }
return args[0];
}
f64 x = CAST(f64, args[0]); f64 x = CAST(f64, args[0]);
f64 offset = x >= 0 ? 0.5 : -0.5; f64 offset = x >= 0 ? 0.5 : -0.5;
if(args[1] == vm->None) { if(args[1] == vm->None) { return VAR((i64)(x + offset)); }
return VAR((i64)(x + offset));
}
int ndigits = CAST(int, args[1]); int ndigits = CAST(int, args[1]);
if(ndigits < 0) { if(ndigits < 0) { vm->ValueError("ndigits should be non-negative"); }
vm->ValueError("ndigits should be non-negative");
}
// ndigits > 0 // ndigits > 0
return VAR((i64)(x * std::pow(10, ndigits) + offset) / std::pow(10, ndigits)); return VAR((i64)(x * std::pow(10, ndigits) + offset) / std::pow(10, ndigits));
}); });
_vm->bind_func(_vm->builtins, "abs", 1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "abs", 1, [](VM* vm, ArgsView args) {
if(is_int(args[0])) { if(is_int(args[0])) { return VAR(std::abs(_CAST(i64, args[0]))); }
return VAR(std::abs(_CAST(i64, args[0]))); if(is_float(args[0])) { return VAR(std::abs(_CAST(f64, args[0]))); }
}
if(is_float(args[0])) {
return VAR(std::abs(_CAST(f64, args[0])));
}
vm->TypeError("bad operand type for abs()"); vm->TypeError("bad operand type for abs()");
return vm->None; return vm->None;
}); });
@ -209,9 +187,7 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(_vm->builtins, "id", 1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "id", 1, [](VM* vm, ArgsView args) {
PyVar obj = args[0]; PyVar obj = args[0];
if(is_tagged(obj)) { if(is_tagged(obj)) { return vm->None; }
return vm->None;
}
return VAR(reinterpret_cast<i64>(obj.get())); return VAR(reinterpret_cast<i64>(obj.get()));
}); });
@ -226,9 +202,7 @@ void __init_builtins(VM* _vm) {
if(is_int(args[0])) { if(is_int(args[0])) {
i64 lhs = _CAST(i64, args[0]); i64 lhs = _CAST(i64, args[0]);
i64 rhs = CAST(i64, args[1]); i64 rhs = CAST(i64, args[1]);
if(rhs == 0) { if(rhs == 0) { vm->ZeroDivisionError(); }
vm->ZeroDivisionError();
}
auto res = std::div(lhs, rhs); auto res = std::div(lhs, rhs);
return VAR(Tuple(VAR(res.quot), VAR(res.rem))); return VAR(Tuple(VAR(res.quot), VAR(res.rem)));
} else { } else {
@ -271,9 +245,7 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(_vm->builtins, "len", 1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "len", 1, [](VM* vm, ArgsView args) {
const PyTypeInfo* ti = vm->_tp_info(args[0]); const PyTypeInfo* ti = vm->_tp_info(args[0]);
if(ti->m__len__) { if(ti->m__len__) { return VAR(ti->m__len__(vm, args[0])); }
return VAR(ti->m__len__(vm, args[0]));
}
return vm->call_method(args[0], __len__); 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) { _vm->bind_func(_vm->builtins, "chr", 1, [](VM* vm, ArgsView args) {
i64 i = CAST(i64, args[0]); i64 i = CAST(i64, args[0]);
if(i < 0 || i >= 128) { if(i < 0 || i >= 128) { vm->ValueError("chr() arg not in [0, 128)"); }
vm->ValueError("chr() arg not in [0, 128)");
}
return VAR(std::string(1, (char)i)); return VAR(std::string(1, (char)i));
}); });
_vm->bind_func(_vm->builtins, "ord", 1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "ord", 1, [](VM* vm, ArgsView args) {
const Str& s = CAST(Str&, args[0]); const Str& s = CAST(Str&, args[0]);
if(s.length() != 1) { if(s.length() != 1) { vm->TypeError("ord() expected an ASCII character"); }
vm->TypeError("ord() expected an ASCII character");
}
return VAR((i64)(s[0])); 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) { _vm->bind_func(_vm->builtins, "getattr", -1, [](VM* vm, ArgsView args) {
if(args.size() != 2 && args.size() != 3) { if(args.size() != 2 && args.size() != 3) { vm->TypeError("getattr() takes 2 or 3 arguments"); }
vm->TypeError("getattr() takes 2 or 3 arguments");
}
StrName name = CAST(Str&, args[1]); StrName name = CAST(Str&, args[1]);
PyVar val = vm->getattr(args[0], name, false); PyVar val = vm->getattr(args[0], name, false);
if(val == nullptr) { if(val == nullptr) {
if(args.size() == 2) { if(args.size() == 2) { vm->AttributeError(args[0], name); }
vm->AttributeError(args[0], name);
}
return args[2]; return args[2];
} }
return val; return val;
@ -337,9 +301,7 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(_vm->builtins, "next", 1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "next", 1, [](VM* vm, ArgsView args) {
PyVar retval = vm->py_next(args[0]); PyVar retval = vm->py_next(args[0]);
if(retval == vm->StopIteration) { if(retval == vm->StopIteration) { vm->_error(vm->call(vm->StopIteration)); }
vm->_error(vm->call(vm->StopIteration));
}
return retval; return retval;
}); });
@ -357,9 +319,7 @@ void __init_builtins(VM* _vm) {
x >>= 1; x >>= 1;
} }
std::reverse(bits.begin(), bits.end()); std::reverse(bits.begin(), bits.end());
if(bits.empty()) { if(bits.empty()) { bits = "0"; }
bits = "0";
}
ss << bits; ss << bits;
return VAR(ss.str()); return VAR(ss.str());
}); });
@ -377,9 +337,7 @@ void __init_builtins(VM* _vm) {
List ret; List ret;
for(int i = 0; i < names.size(); i++) { for(int i = 0; i < names.size(); i++) {
// remove duplicates // remove duplicates
if(i > 0 && names[i] == names[i - 1]) { if(i > 0 && names[i] == names[i - 1]) { continue; }
continue;
}
ret.push_back(VAR(names[i].sv())); ret.push_back(VAR(names[i].sv()));
} }
return VAR(std::move(ret)); return VAR(std::move(ret));
@ -423,9 +381,7 @@ void __init_builtins(VM* _vm) {
break; break;
default: vm->TypeError("expected 1-3 arguments, got " + std::to_string(args.size())); default: vm->TypeError("expected 1-3 arguments, got " + std::to_string(args.size()));
} }
if(r.step == 0) { if(r.step == 0) { vm->ValueError("range() arg 3 must not be zero"); }
vm->ValueError("range() arg 3 must not be zero");
}
return VAR(r); return VAR(r);
}); });
@ -464,16 +420,12 @@ void __init_builtins(VM* _vm) {
i64 lhs = _CAST(i64, _0); i64 lhs = _CAST(i64, _0);
i64 rhs = _CAST(i64, _1); i64 rhs = _CAST(i64, _1);
if(rhs < 0) { if(rhs < 0) {
if(lhs == 0) { if(lhs == 0) { vm->ZeroDivisionError("0.0 cannot be raised to a negative power"); }
vm->ZeroDivisionError("0.0 cannot be raised to a negative power");
}
return VAR((f64)std::pow(lhs, rhs)); return VAR((f64)std::pow(lhs, rhs));
} }
i64 ret = 1; i64 ret = 1;
while(rhs) { while(rhs) {
if(rhs & 1) { if(rhs & 1) { ret *= lhs; }
ret *= lhs;
}
lhs *= lhs; lhs *= lhs;
rhs >>= 1; rhs >>= 1;
} }
@ -487,9 +439,7 @@ void __init_builtins(VM* _vm) {
_vm->bind__pow__(VM::tp_float, py_number_pow); _vm->bind__pow__(VM::tp_float, py_number_pow);
_vm->bind_func(VM::tp_int, __new__, -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_int, __new__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1 + 0) { if(args.size() == 1 + 0) { return VAR(0); }
return VAR(0);
}
// 1 arg // 1 arg
if(args.size() == 1 + 1) { if(args.size() == 1 + 1) {
switch(vm->_tp(args[1])) { switch(vm->_tp(args[1])) {
@ -501,14 +451,10 @@ void __init_builtins(VM* _vm) {
} }
} }
// 2+ args -> error // 2+ args -> error
if(args.size() > 1 + 2) { if(args.size() > 1 + 2) { vm->TypeError("int() takes at most 2 arguments"); }
vm->TypeError("int() takes at most 2 arguments");
}
// 1 or 2 args with str // 1 or 2 args with str
int base = 10; int base = 10;
if(args.size() == 1 + 2) { if(args.size() == 1 + 2) { base = CAST(i64, args[2]); }
base = CAST(i64, args[2]);
}
const Str& s = CAST(Str&, args[1]); const Str& s = CAST(Str&, args[1]);
std::string_view sv = s.sv(); std::string_view sv = s.sv();
bool negative = false; bool negative = false;
@ -520,33 +466,25 @@ void __init_builtins(VM* _vm) {
if(parse_uint(sv, &val, base) != IntParsingResult::Success) { if(parse_uint(sv, &val, base) != IntParsingResult::Success) {
vm->ValueError(_S("invalid literal for int() with base ", base, ": ", s.escape())); vm->ValueError(_S("invalid literal for int() with base ", base, ": ", s.escape()));
} }
if(negative) { if(negative) { val = -val; }
val = -val;
}
return VAR(val); return VAR(val);
}); });
_vm->bind__floordiv__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__floordiv__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) {
i64 rhs = CAST(i64, _1); i64 rhs = CAST(i64, _1);
if(rhs == 0) { if(rhs == 0) { vm->ZeroDivisionError(); }
vm->ZeroDivisionError();
}
return VAR(_CAST(i64, _0) / rhs); return VAR(_CAST(i64, _0) / rhs);
}); });
_vm->bind__mod__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__mod__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) {
i64 rhs = CAST(i64, _1); i64 rhs = CAST(i64, _1);
if(rhs == 0) { if(rhs == 0) { vm->ZeroDivisionError(); }
vm->ZeroDivisionError();
}
return VAR(_CAST(i64, _0) % rhs); return VAR(_CAST(i64, _0) % rhs);
}); });
_vm->bind_func(VM::tp_int, "bit_length", 1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_int, "bit_length", 1, [](VM* vm, ArgsView args) {
i64 x = _CAST(i64, args[0]); i64 x = _CAST(i64, args[0]);
if(x < 0) { if(x < 0) { x = -x; }
x = -x;
}
int bits = 0; int bits = 0;
while(x) { while(x) {
x >>= 1; x >>= 1;
@ -572,12 +510,8 @@ void __init_builtins(VM* _vm) {
#undef INT_BITWISE_OP #undef INT_BITWISE_OP
_vm->bind_func(VM::tp_float, __new__, -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_float, __new__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1 + 0) { if(args.size() == 1 + 0) { return VAR(0.0); }
return VAR(0.0); if(args.size() > 1 + 1) { vm->TypeError("float() takes at most 1 argument"); }
}
if(args.size() > 1 + 1) {
vm->TypeError("float() takes at most 1 argument");
}
// 1 arg // 1 arg
switch(vm->_tp(args[1])) { switch(vm->_tp(args[1])) {
case VM::tp_int: return VAR((f64)CAST(i64, args[1])); case VM::tp_int: return VAR((f64)CAST(i64, args[1]));
@ -588,20 +522,14 @@ void __init_builtins(VM* _vm) {
} }
// str to float // str to float
const Str& s = PK_OBJ_GET(Str, args[1]); const Str& s = PK_OBJ_GET(Str, args[1]);
if(s == "inf") { if(s == "inf") { return VAR(INFINITY); }
return VAR(INFINITY); if(s == "-inf") { return VAR(-INFINITY); }
}
if(s == "-inf") {
return VAR(-INFINITY);
}
double float_out; double float_out;
char* p_end; char* p_end;
try { try {
float_out = std::strtod(s.data, &p_end); float_out = std::strtod(s.data, &p_end);
if(p_end != s.end()) { if(p_end != s.end()) { throw 1; }
throw 1;
}
} catch(...) { vm->ValueError("invalid literal for float(): " + s.escape()); } } catch(...) { vm->ValueError("invalid literal for float(): " + s.escape()); }
return VAR(float_out); return VAR(float_out);
}); });
@ -622,12 +550,8 @@ void __init_builtins(VM* _vm) {
// tp_str // tp_str
_vm->bind_func(VM::tp_str, __new__, -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_str, __new__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1) { if(args.size() == 1) { return VAR(Str()); }
return VAR(Str()); if(args.size() > 2) { vm->TypeError("str() takes at most 1 argument"); }
}
if(args.size() > 2) {
vm->TypeError("str() takes at most 1 argument");
}
return VAR(vm->py_str(args[1])); return VAR(vm->py_str(args[1]));
}); });
@ -667,8 +591,7 @@ void __init_builtins(VM* _vm) {
#define BIND_CMP_STR(name, op) \ #define BIND_CMP_STR(name, op) \
_vm->bind##name(VM::tp_str, [](VM* vm, PyVar lhs, PyVar rhs) { \ _vm->bind##name(VM::tp_str, [](VM* vm, PyVar lhs, PyVar rhs) { \
if(!is_type(rhs, vm->tp_str)) \ if(!is_type(rhs, vm->tp_str)) return vm->NotImplemented; \
return vm->NotImplemented; \
return VAR(_CAST(Str&, lhs) op _CAST(Str&, rhs)); \ 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) { _vm->bind(_vm->_t(VM::tp_str), "replace(self, old, new, count=-1)", [](VM* vm, ArgsView args) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
const Str& old = CAST(Str&, args[1]); const Str& old = CAST(Str&, args[1]);
if(old.empty()) { if(old.empty()) { vm->ValueError("empty substring"); }
vm->ValueError("empty substring");
}
const Str& new_ = CAST(Str&, args[2]); const Str& new_ = CAST(Str&, args[2]);
int count = CAST(int, args[3]); int count = CAST(int, args[3]);
return VAR(self.replace(old, new_, count)); return VAR(self.replace(old, new_, count));
@ -706,9 +627,7 @@ void __init_builtins(VM* _vm) {
_vm->bind(_vm->_t(VM::tp_str), "split(self, sep=' ')", [](VM* vm, ArgsView args) { _vm->bind(_vm->_t(VM::tp_str), "split(self, sep=' ')", [](VM* vm, ArgsView args) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
const Str& sep = CAST(Str&, args[1]); const Str& sep = CAST(Str&, args[1]);
if(sep.empty()) { if(sep.empty()) { vm->ValueError("empty separator"); }
vm->ValueError("empty separator");
}
vector<std::string_view> parts; vector<std::string_view> parts;
if(sep.size == 1) { if(sep.size == 1) {
parts = self.split(sep[0]); parts = self.split(sep[0]);
@ -742,13 +661,9 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
const Str& value = CAST(Str&, args[1]); const Str& value = CAST(Str&, args[1]);
int start = CAST(int, args[2]); int start = CAST(int, args[2]);
if(start < 0) { if(start < 0) { vm->ValueError("argument 'start' can't be negative"); }
vm->ValueError("argument 'start' can't be negative");
}
int index = self.index(value, start); int index = self.index(value, start);
if(index < 0) { if(index < 0) { vm->ValueError("substring not found"); }
vm->ValueError("substring not found");
}
return VAR(index); return VAR(index);
}); });
@ -756,9 +671,7 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
const Str& value = CAST(Str&, args[1]); const Str& value = CAST(Str&, args[1]);
int start = CAST(int, args[2]); int start = CAST(int, args[2]);
if(start < 0) { if(start < 0) { vm->ValueError("argument 'start' can't be negative"); }
vm->ValueError("argument 'start' can't be negative");
}
return VAR(self.index(value, start)); return VAR(self.index(value, start));
}); });
@ -772,9 +685,7 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
const Str& suffix = CAST(Str&, args[1]); const Str& suffix = CAST(Str&, args[1]);
int offset = self.length() - suffix.length(); int offset = self.length() - suffix.length();
if(offset < 0) { if(offset < 0) { return vm->False; }
return vm->False;
}
bool ok = memcmp(self.data + offset, suffix.data, suffix.length()) == 0; bool ok = memcmp(self.data + offset, suffix.data, suffix.length()) == 0;
return VAR(ok); return VAR(ok);
}); });
@ -794,9 +705,7 @@ void __init_builtins(VM* _vm) {
const PyTypeInfo* info = vm->_tp_info(args[1]); const PyTypeInfo* info = vm->_tp_info(args[1]);
PyVar obj = vm->_py_next(info, it); PyVar obj = vm->_py_next(info, it);
while(obj != vm->StopIteration) { while(obj != vm->StopIteration) {
if(!ss.empty()) { if(!ss.empty()) { ss << self; }
ss << self;
}
ss << CAST(Str&, obj); ss << CAST(Str&, obj);
obj = vm->_py_next(info, it); obj = vm->_py_next(info, it);
} }
@ -848,9 +757,7 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
int width = CAST(int, args[1]); int width = CAST(int, args[1]);
int delta = width - self.u8_length(); int delta = width - self.u8_length();
if(delta <= 0) { if(delta <= 0) { return args[0]; }
return args[0];
}
SStream ss; SStream ss;
for(int i = 0; i < delta; i++) { for(int i = 0; i < delta; i++) {
ss << '0'; ss << '0';
@ -864,13 +771,9 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
int width = CAST(int, args[1]); int width = CAST(int, args[1]);
int delta = width - self.u8_length(); int delta = width - self.u8_length();
if(delta <= 0) { if(delta <= 0) { return args[0]; }
return args[0];
}
const Str& fillchar = CAST(Str&, args[2]); const Str& fillchar = CAST(Str&, args[2]);
if(fillchar.u8_length() != 1) { if(fillchar.u8_length() != 1) { vm->TypeError("The fill character must be exactly one character long"); }
vm->TypeError("The fill character must be exactly one character long");
}
SStream ss; SStream ss;
ss << self; ss << self;
for(int i = 0; i < delta; i++) { for(int i = 0; i < delta; i++) {
@ -884,13 +787,9 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
int width = CAST(int, args[1]); int width = CAST(int, args[1]);
int delta = width - self.u8_length(); int delta = width - self.u8_length();
if(delta <= 0) { if(delta <= 0) { return args[0]; }
return args[0];
}
const Str& fillchar = CAST(Str&, args[2]); const Str& fillchar = CAST(Str&, args[2]);
if(fillchar.u8_length() != 1) { if(fillchar.u8_length() != 1) { vm->TypeError("The fill character must be exactly one character long"); }
vm->TypeError("The fill character must be exactly one character long");
}
SStream ss; SStream ss;
for(int i = 0; i < delta; i++) { for(int i = 0; i < delta; i++) {
ss << fillchar; ss << fillchar;
@ -911,25 +810,19 @@ void __init_builtins(VM* _vm) {
}); });
} }
bool reverse = CAST(bool, args[2]); bool reverse = CAST(bool, args[2]);
if(reverse) { if(reverse) { std::reverse(self.begin(), self.end()); }
std::reverse(self.begin(), self.end());
}
return vm->None; return vm->None;
}); });
_vm->bind__repr__(VM::tp_list, [](VM* vm, PyVar _0) -> Str { _vm->bind__repr__(VM::tp_list, [](VM* vm, PyVar _0) -> Str {
if(vm->_repr_recursion_set.contains(_0)) { if(vm->_repr_recursion_set.contains(_0)) { return "[...]"; }
return "[...]";
}
List& iterable = _CAST(List&, _0); List& iterable = _CAST(List&, _0);
SStream ss; SStream ss;
ss << '['; ss << '[';
vm->_repr_recursion_set.push_back(_0); vm->_repr_recursion_set.push_back(_0);
for(int i = 0; i < iterable.size(); i++) { for(int i = 0; i < iterable.size(); i++) {
ss << vm->py_repr(iterable[i]); ss << vm->py_repr(iterable[i]);
if(i != iterable.size() - 1) { if(i != iterable.size() - 1) { ss << ", "; }
ss << ", ";
}
} }
vm->_repr_recursion_set.pop_back(); vm->_repr_recursion_set.pop_back();
ss << ']'; ss << ']';
@ -946,9 +839,7 @@ void __init_builtins(VM* _vm) {
} else { } else {
for(int i = 0; i < iterable.size(); i++) { for(int i = 0; i < iterable.size(); i++) {
ss << vm->py_repr(iterable[i]); ss << vm->py_repr(iterable[i]);
if(i != iterable.size() - 1) { if(i != iterable.size() - 1) { ss << ", "; }
ss << ", ";
}
} }
} }
ss << ')'; ss << ')';
@ -956,12 +847,8 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind_func(VM::tp_list, __new__, -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_list, __new__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1 + 0) { if(args.size() == 1 + 0) { return VAR(List()); }
return VAR(List()); if(args.size() == 1 + 1) { return VAR(vm->py_list(args[1])); }
}
if(args.size() == 1 + 1) {
return VAR(vm->py_list(args[1]));
}
vm->TypeError("list() takes 0 or 1 arguments"); vm->TypeError("list() takes 0 or 1 arguments");
return vm->None; return vm->None;
}); });
@ -969,9 +856,7 @@ void __init_builtins(VM* _vm) {
_vm->bind__contains__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__contains__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
List& self = _CAST(List&, _0); List& self = _CAST(List&, _0);
for(PyVar i: self) { for(PyVar i: self) {
if(vm->py_eq(i, _1)) { if(vm->py_eq(i, _1)) { return vm->True; }
return vm->True;
}
} }
return vm->False; return vm->False;
}); });
@ -980,26 +865,18 @@ void __init_builtins(VM* _vm) {
List& self = _CAST(List&, args[0]); List& self = _CAST(List&, args[0]);
int count = 0; int count = 0;
for(PyVar i: self) { for(PyVar i: self) {
if(vm->py_eq(i, args[1])) { if(vm->py_eq(i, args[1])) { count++; }
count++;
}
} }
return VAR(count); return VAR(count);
}); });
_vm->bind__eq__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__eq__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
List& a = _CAST(List&, _0); List& a = _CAST(List&, _0);
if(!is_type(_1, vm->tp_list)) { if(!is_type(_1, vm->tp_list)) { return vm->NotImplemented; }
return vm->NotImplemented;
}
List& b = _CAST(List&, _1); List& b = _CAST(List&, _1);
if(a.size() != b.size()) { if(a.size() != b.size()) { return vm->False; }
return vm->False;
}
for(int i = 0; i < a.size(); i++) { for(int i = 0; i < a.size(); i++) {
if(!vm->py_eq(a[i], b[i])) { if(!vm->py_eq(a[i], b[i])) { return vm->False; }
return vm->False;
}
} }
return vm->True; return vm->True;
}); });
@ -1009,9 +886,7 @@ void __init_builtins(VM* _vm) {
PyVar obj = args[1]; PyVar obj = args[1];
int start = CAST(int, args[2]); int start = CAST(int, args[2]);
for(int i = start; i < self.size(); i++) { for(int i = start; i < self.size(); i++) {
if(vm->py_eq(self[i], obj)) { if(vm->py_eq(self[i], obj)) { return VAR(i); }
return VAR(i);
}
} }
vm->ValueError(vm->py_repr(obj) + " is not in list"); vm->ValueError(vm->py_repr(obj) + " is not in list");
return vm->None; return vm->None;
@ -1033,9 +908,7 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(VM::tp_list, "pop", -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_list, "pop", -1, [](VM* vm, ArgsView args) {
List& self = _CAST(List&, args[0]); List& self = _CAST(List&, args[0]);
if(args.size() == 1 + 0) { if(args.size() == 1 + 0) {
if(self.empty()) { if(self.empty()) { vm->IndexError("pop from empty list"); }
vm->IndexError("pop from empty list");
}
PyVar retval = self.back(); PyVar retval = self.back();
self.pop_back(); self.pop_back();
return retval; return retval;
@ -1078,9 +951,7 @@ void __init_builtins(VM* _vm) {
_vm->bind__mul__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__mul__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
const List& self = _CAST(List&, _0); const List& self = _CAST(List&, _0);
if(!is_int(_1)) { if(!is_int(_1)) { return vm->NotImplemented; }
return vm->NotImplemented;
}
int n = _CAST(int, _1); int n = _CAST(int, _1);
List result; List result;
result.reserve(self.size() * n); result.reserve(self.size() * n);
@ -1091,9 +962,7 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind_func(VM::tp_list, "__rmul__", 2, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_list, "__rmul__", 2, [](VM* vm, ArgsView args) {
const List& self = _CAST(List&, args[0]); const List& self = _CAST(List&, args[0]);
if(!is_int(args[1])) { if(!is_int(args[1])) { return vm->NotImplemented; }
return vm->NotImplemented;
}
int n = _CAST(int, args[1]); int n = _CAST(int, args[1]);
List result; List result;
result.reserve(self.size() * n); result.reserve(self.size() * n);
@ -1106,15 +975,9 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(VM::tp_list, "insert", 3, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_list, "insert", 3, [](VM* vm, ArgsView args) {
List& self = _CAST(List&, args[0]); List& self = _CAST(List&, args[0]);
int index = CAST(int, args[1]); int index = CAST(int, args[1]);
if(index < 0) { if(index < 0) { index += self.size(); }
index += self.size(); if(index < 0) { index = 0; }
} if(index > self.size()) { index = self.size(); }
if(index < 0) {
index = 0;
}
if(index > self.size()) {
index = self.size();
}
self.insert(index, args[2]); self.insert(index, args[2]);
return vm->None; return vm->None;
}); });
@ -1131,13 +994,11 @@ void __init_builtins(VM* _vm) {
#define BIND_RICH_CMP(name, op, _t, _T) \ #define BIND_RICH_CMP(name, op, _t, _T) \
_vm->bind__##name##__(_vm->_t, [](VM* vm, PyVar lhs, PyVar rhs) { \ _vm->bind__##name##__(_vm->_t, [](VM* vm, PyVar lhs, PyVar rhs) { \
if(!is_type(rhs, vm->_t)) \ if(!is_type(rhs, vm->_t)) return vm->NotImplemented; \
return vm->NotImplemented; \
auto& a = _CAST(_T&, lhs); \ auto& a = _CAST(_T&, lhs); \
auto& b = _CAST(_T&, rhs); \ auto& b = _CAST(_T&, rhs); \
for(int i = 0; i < a.size() && i < b.size(); i++) { \ for(int i = 0; i < a.size() && i < b.size(); i++) { \
if(vm->py_eq(a[i], b[i])) \ if(vm->py_eq(a[i], b[i])) continue; \
continue; \
return VAR(vm->py_##name(a[i], b[i])); \ return VAR(vm->py_##name(a[i], b[i])); \
} \ } \
return VAR(a.size() op b.size()); \ 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) { _vm->bind_func(VM::tp_tuple, __new__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1 + 0) { if(args.size() == 1 + 0) { return VAR(Tuple(0)); }
return VAR(Tuple(0));
}
if(args.size() == 1 + 1) { if(args.size() == 1 + 1) {
List list = vm->py_list(args[1]); List list = vm->py_list(args[1]);
return VAR(list.to_tuple()); return VAR(list.to_tuple());
@ -1202,9 +1061,7 @@ void __init_builtins(VM* _vm) {
_vm->bind__contains__(VM::tp_tuple, [](VM* vm, PyVar obj, PyVar item) { _vm->bind__contains__(VM::tp_tuple, [](VM* vm, PyVar obj, PyVar item) {
Tuple& self = _CAST(Tuple&, obj); Tuple& self = _CAST(Tuple&, obj);
for(PyVar i: self) { for(PyVar i: self) {
if(vm->py_eq(i, item)) { if(vm->py_eq(i, item)) { return vm->True; }
return vm->True;
}
} }
return vm->False; return vm->False;
}); });
@ -1213,26 +1070,18 @@ void __init_builtins(VM* _vm) {
Tuple& self = _CAST(Tuple&, args[0]); Tuple& self = _CAST(Tuple&, args[0]);
int count = 0; int count = 0;
for(PyVar i: self) { for(PyVar i: self) {
if(vm->py_eq(i, args[1])) { if(vm->py_eq(i, args[1])) { count++; }
count++;
}
} }
return VAR(count); return VAR(count);
}); });
_vm->bind__eq__(VM::tp_tuple, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__eq__(VM::tp_tuple, [](VM* vm, PyVar _0, PyVar _1) {
const Tuple& self = _CAST(Tuple&, _0); const Tuple& self = _CAST(Tuple&, _0);
if(!is_type(_1, vm->tp_tuple)) { if(!is_type(_1, vm->tp_tuple)) { return vm->NotImplemented; }
return vm->NotImplemented;
}
const Tuple& other = _CAST(Tuple&, _1); const Tuple& other = _CAST(Tuple&, _1);
if(self.size() != other.size()) { if(self.size() != other.size()) { return vm->False; }
return vm->False;
}
for(int i = 0; i < self.size(); i++) { for(int i = 0; i < self.size(); i++) {
if(!vm->py_eq(self[i], other[i])) { if(!vm->py_eq(self[i], other[i])) { return vm->False; }
return vm->False;
}
} }
return vm->True; 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__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__xor__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) { return VAR(_CAST(bool, _0) != CAST(bool, _1)); });
_vm->bind__eq__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__eq__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) {
if(is_type(_1, vm->tp_bool)) { if(is_type(_1, vm->tp_bool)) { return VAR(_0 == _1); }
return VAR(_0 == _1); if(is_int(_1)) { return VAR(_CAST(bool, _0) == (bool)CAST(i64, _1)); }
}
if(is_int(_1)) {
return VAR(_CAST(bool, _0) == (bool)CAST(i64, _1));
}
return vm->NotImplemented; return vm->NotImplemented;
}); });
@ -1290,9 +1135,7 @@ void __init_builtins(VM* _vm) {
Bytes retval(list.size()); Bytes retval(list.size());
for(int i = 0; i < list.size(); i++) { for(int i = 0; i < list.size(); i++) {
i64 b = CAST(i64, list[i]); i64 b = CAST(i64, list[i]);
if(b < 0 || b > 255) { if(b < 0 || b > 255) { vm->ValueError("byte must be in range[0, 256)"); }
vm->ValueError("byte must be in range[0, 256)");
}
retval[i] = (char)b; retval[i] = (char)b;
} }
return VAR(std::move(retval)); return VAR(std::move(retval));
@ -1305,9 +1148,7 @@ void __init_builtins(VM* _vm) {
int start, stop, step; int start, stop, step;
vm->parse_int_slice(s, self.size(), start, stop, step); vm->parse_int_slice(s, self.size(), start, stop, step);
int guess_max_size = abs(stop - start) / abs(step) + 1; int guess_max_size = abs(stop - start) / abs(step) + 1;
if(guess_max_size > self.size()) { if(guess_max_size > self.size()) { guess_max_size = self.size(); }
guess_max_size = self.size();
}
unsigned char* buffer = (unsigned char*)std::malloc(guess_max_size); unsigned char* buffer = (unsigned char*)std::malloc(guess_max_size);
int j = 0; // actual size int j = 0; // actual size
PK_SLICE_LOOP(i, start, stop, step) buffer[j++] = self[i]; PK_SLICE_LOOP(i, start, stop, step) buffer[j++] = self[i];
@ -1352,14 +1193,10 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind__eq__(VM::tp_bytes, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__eq__(VM::tp_bytes, [](VM* vm, PyVar _0, PyVar _1) {
if(!is_type(_1, vm->tp_bytes)) { if(!is_type(_1, vm->tp_bytes)) { return vm->NotImplemented; }
return vm->NotImplemented;
}
const Bytes& lhs = _CAST(Bytes&, _0); const Bytes& lhs = _CAST(Bytes&, _0);
const Bytes& rhs = _CAST(Bytes&, _1); const Bytes& rhs = _CAST(Bytes&, _1);
if(lhs.size() != rhs.size()) { if(lhs.size() != rhs.size()) { return vm->False; }
return vm->False;
}
return VAR(memcmp(lhs.data(), rhs.data(), lhs.size()) == 0); 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) { _vm->bind__eq__(VM::tp_slice, [](VM* vm, PyVar _0, PyVar _1) {
const Slice& self = _CAST(Slice&, _0); const Slice& self = _CAST(Slice&, _0);
if(!is_type(_1, vm->tp_slice)) { if(!is_type(_1, vm->tp_slice)) { return vm->NotImplemented; }
return vm->NotImplemented;
}
const Slice& other = _CAST(Slice&, _1); const Slice& other = _CAST(Slice&, _1);
if(vm->py_ne(self.start, other.start)) { if(vm->py_ne(self.start, other.start)) { return vm->False; }
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.stop, other.stop)) {
return vm->False;
}
if(vm->py_ne(self.step, other.step)) {
return vm->False;
}
return vm->True; return vm->True;
}); });
@ -1429,9 +1258,7 @@ void __init_builtins(VM* _vm) {
_vm->bind__eq__(VM::tp_mappingproxy, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__eq__(VM::tp_mappingproxy, [](VM* vm, PyVar _0, PyVar _1) {
const MappingProxy& a = _CAST(MappingProxy&, _0); const MappingProxy& a = _CAST(MappingProxy&, _0);
if(!is_type(_1, VM::tp_mappingproxy)) { if(!is_type(_1, VM::tp_mappingproxy)) { return vm->NotImplemented; }
return vm->NotImplemented;
}
const MappingProxy& b = _CAST(MappingProxy&, _1); const MappingProxy& b = _CAST(MappingProxy&, _1);
return VAR(a.obj == b.obj); return VAR(a.obj == b.obj);
}); });
@ -1440,9 +1267,7 @@ void __init_builtins(VM* _vm) {
MappingProxy& self = _CAST(MappingProxy&, _0); MappingProxy& self = _CAST(MappingProxy&, _0);
StrName key = CAST(Str&, _1); StrName key = CAST(Str&, _1);
PyVar ret = self.attr().try_get_likely_found(key); PyVar ret = self.attr().try_get_likely_found(key);
if(ret == nullptr) { if(ret == nullptr) { vm->KeyError(_1); }
vm->KeyError(_1);
}
return ret; return ret;
}); });
@ -1450,25 +1275,19 @@ void __init_builtins(VM* _vm) {
MappingProxy& self = _CAST(MappingProxy&, args[0]); MappingProxy& self = _CAST(MappingProxy&, args[0]);
StrName key = CAST(Str&, args[1]); StrName key = CAST(Str&, args[1]);
PyVar ret = self.attr().try_get(key); PyVar ret = self.attr().try_get(key);
if(ret == nullptr) { if(ret == nullptr) { return args[2]; }
return args[2];
}
return ret; return ret;
}); });
_vm->bind__repr__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) -> Str { _vm->bind__repr__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) -> Str {
if(vm->_repr_recursion_set.contains(_0)) { if(vm->_repr_recursion_set.contains(_0)) { return "{...}"; }
return "{...}";
}
MappingProxy& self = _CAST(MappingProxy&, _0); MappingProxy& self = _CAST(MappingProxy&, _0);
SStream ss; SStream ss;
ss << "mappingproxy({"; ss << "mappingproxy({";
bool first = true; bool first = true;
vm->_repr_recursion_set.push_back(_0); vm->_repr_recursion_set.push_back(_0);
for(auto [k, v]: self.attr().items()) { for(auto [k, v]: self.attr().items()) {
if(!first) { if(!first) { ss << ", "; }
ss << ", ";
}
first = false; first = false;
ss << k.escape() << ": "; ss << k.escape() << ": ";
ss << vm->py_repr(v); 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) { _vm->bind_func(VM::tp_dict, __init__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1 + 0) { if(args.size() == 1 + 0) { return vm->None; }
return vm->None;
}
if(args.size() == 1 + 1) { if(args.size() == 1 + 1) {
auto _lock = vm->heap.gc_scope_lock(); auto _lock = vm->heap.gc_scope_lock();
Dict& self = PK_OBJ_GET(Dict, args[0]); Dict& self = PK_OBJ_GET(Dict, args[0]);
@ -1527,9 +1344,7 @@ void __init_builtins(VM* _vm) {
// try __missing__ // try __missing__
PyVar self; PyVar self;
PyVar f_missing = vm->get_unbound_method(_0, __missing__, &self, false); PyVar f_missing = vm->get_unbound_method(_0, __missing__, &self, false);
if(f_missing != nullptr) { if(f_missing != nullptr) { return vm->call_method(self, f_missing, _1); }
return vm->call_method(self, f_missing, _1);
}
vm->KeyError(_1); vm->KeyError(_1);
} }
return ret; return ret;
@ -1543,9 +1358,7 @@ void __init_builtins(VM* _vm) {
_vm->bind__delitem__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__delitem__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) {
Dict& self = _CAST(Dict&, _0); Dict& self = _CAST(Dict&, _0);
bool ok = self.del(vm, _1); bool ok = self.del(vm, _1);
if(!ok) { if(!ok) { vm->KeyError(_1); }
vm->KeyError(_1);
}
}); });
_vm->bind_func(VM::tp_dict, "pop", -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_dict, "pop", -1, [](VM* vm, ArgsView args) {
@ -1556,12 +1369,8 @@ void __init_builtins(VM* _vm) {
Dict& self = _CAST(Dict&, args[0]); Dict& self = _CAST(Dict&, args[0]);
PyVar value = self.try_get(vm, args[1]); PyVar value = self.try_get(vm, args[1]);
if(value == nullptr) { if(value == nullptr) {
if(args.size() == 2) { if(args.size() == 2) { vm->KeyError(args[1]); }
vm->KeyError(args[1]); if(args.size() == 3) { return args[2]; }
}
if(args.size() == 3) {
return args[2];
}
} }
self.del(vm, args[1]); self.del(vm, args[1]);
return value; return value;
@ -1581,15 +1390,11 @@ void __init_builtins(VM* _vm) {
Dict& self = _CAST(Dict&, args[0]); Dict& self = _CAST(Dict&, args[0]);
if(args.size() == 1 + 1) { if(args.size() == 1 + 1) {
PyVar ret = self.try_get(vm, args[1]); PyVar ret = self.try_get(vm, args[1]);
if(ret != nullptr) { if(ret != nullptr) { return ret; }
return ret;
}
return vm->None; return vm->None;
} else if(args.size() == 1 + 2) { } else if(args.size() == 1 + 2) {
PyVar ret = self.try_get(vm, args[1]); PyVar ret = self.try_get(vm, args[1]);
if(ret != nullptr) { if(ret != nullptr) { return ret; }
return ret;
}
return args[2]; return args[2];
} }
vm->TypeError("get() takes at most 2 arguments"); 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 { _vm->bind__repr__(VM::tp_dict, [](VM* vm, PyVar _0) -> Str {
if(vm->_repr_recursion_set.contains(_0)) { if(vm->_repr_recursion_set.contains(_0)) { return "{...}"; }
return "{...}";
}
Dict& self = _CAST(Dict&, _0); Dict& self = _CAST(Dict&, _0);
SStream ss; SStream ss;
ss << "{"; ss << "{";
bool first = true; bool first = true;
vm->_repr_recursion_set.push_back(_0); vm->_repr_recursion_set.push_back(_0);
self.apply([&](PyVar k, PyVar v) { self.apply([&](PyVar k, PyVar v) {
if(!first) { if(!first) { ss << ", "; }
ss << ", ";
}
first = false; first = false;
ss << vm->py_repr(k) << ": " << vm->py_repr(v); 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) { _vm->bind__eq__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) {
Dict& self = _CAST(Dict&, _0); Dict& self = _CAST(Dict&, _0);
if(!vm->isinstance(_1, vm->tp_dict)) { if(!vm->isinstance(_1, vm->tp_dict)) { return vm->NotImplemented; }
return vm->NotImplemented;
}
Dict& other = _CAST(Dict&, _1); Dict& other = _CAST(Dict&, _1);
if(self.size() != other.size()) { if(self.size() != other.size()) { return vm->False; }
return vm->False;
}
for(int i = 0; i < self._capacity; i++) { for(int i = 0; i < self._capacity; i++) {
auto item = self._items[i]; auto item = self._items[i];
if(item.first == nullptr) { if(item.first == nullptr) { continue; }
continue;
}
PyVar value = other.try_get(vm, item.first); PyVar value = other.try_get(vm, item.first);
if(value == nullptr) { if(value == nullptr) { return vm->False; }
return vm->False; if(!vm->py_eq(item.second, value)) { return vm->False; }
}
if(!vm->py_eq(item.second, value)) {
return vm->False;
}
} }
return vm->True; return vm->True;
}); });
@ -1692,20 +1483,14 @@ void __init_builtins(VM* _vm) {
_vm->bind_property(_vm->_t(VM::tp_function), "__doc__", [](VM* vm, ArgsView args) { _vm->bind_property(_vm->_t(VM::tp_function), "__doc__", [](VM* vm, ArgsView args) {
Function& func = _CAST(Function&, args[0]); Function& func = _CAST(Function&, args[0]);
if(!func.decl->docstring) { if(!func.decl->docstring) { return vm->None; }
return vm->None;
}
return VAR(func.decl->docstring); return VAR(func.decl->docstring);
}); });
_vm->bind_property(_vm->_t(VM::tp_native_func), "__doc__", [](VM* vm, ArgsView args) { _vm->bind_property(_vm->_t(VM::tp_native_func), "__doc__", [](VM* vm, ArgsView args) {
NativeFunc& func = _CAST(NativeFunc&, args[0]); NativeFunc& func = _CAST(NativeFunc&, args[0]);
if(func.decl == nullptr) { if(func.decl == nullptr) { return vm->None; }
return vm->None; if(!func.decl->docstring) { return vm->None; }
}
if(!func.decl->docstring) {
return vm->None;
}
return VAR(func.decl->docstring); return VAR(func.decl->docstring);
}); });
@ -1755,9 +1540,7 @@ void VM::__post_init_builtin_types() {
_all_types[tp_module].m__getattr__ = [](VM* vm, PyVar obj, StrName name) -> PyVar { _all_types[tp_module].m__getattr__ = [](VM* vm, PyVar obj, StrName name) -> PyVar {
const Str& path = CAST(Str&, obj->attr(__path__)); const Str& path = CAST(Str&, obj->attr(__path__));
PyObject* retval = vm->py_import(_S(path, ".", name.sv()), false); PyObject* retval = vm->py_import(_S(path, ".", name.sv()), false);
if(retval) { if(retval) { return retval; }
return retval;
}
return nullptr; return nullptr;
}; };
@ -1792,9 +1575,7 @@ void VM::__post_init_builtin_types() {
}); });
bind_property(_t(tp_type), "__module__", [](VM* vm, ArgsView args) -> PyVar { bind_property(_t(tp_type), "__module__", [](VM* vm, ArgsView args) -> PyVar {
const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])]; const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])];
if(info.mod == nullptr) { if(info.mod == nullptr) { return vm->None; }
return vm->None;
}
return info.mod; return info.mod;
}); });
bind_property(_t(tp_bound_method), "__self__", [](VM* vm, ArgsView args) { bind_property(_t(tp_bound_method), "__self__", [](VM* vm, ArgsView args) {
@ -1805,9 +1586,7 @@ void VM::__post_init_builtin_types() {
}); });
bind__eq__(tp_bound_method, [](VM* vm, PyVar lhs, PyVar rhs) { bind__eq__(tp_bound_method, [](VM* vm, PyVar lhs, PyVar rhs) {
if(!is_type(rhs, vm->tp_bound_method)) { if(!is_type(rhs, vm->tp_bound_method)) { return vm->NotImplemented; }
return vm->NotImplemented;
}
const BoundMethod& _0 = PK_OBJ_GET(BoundMethod, lhs); const BoundMethod& _0 = PK_OBJ_GET(BoundMethod, lhs);
const BoundMethod& _1 = PK_OBJ_GET(BoundMethod, rhs); const BoundMethod& _1 = PK_OBJ_GET(BoundMethod, rhs);
return VAR(_0.self == _1.self && _0.func == _1.func); return VAR(_0.self == _1.self && _0.func == _1.func);
@ -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_slice), "step", [](VM* vm, ArgsView args) { return CAST(Slice&, args[0]).step; });
bind_property(_t(tp_object), "__dict__", [](VM* vm, ArgsView args) { bind_property(_t(tp_object), "__dict__", [](VM* vm, ArgsView args) {
if(is_tagged(args[0]) || !args[0]->is_attr_valid()) { if(is_tagged(args[0]) || !args[0]->is_attr_valid()) { return vm->None; }
return vm->None;
}
return VAR(MappingProxy(args[0].get())); return VAR(MappingProxy(args[0].get()));
}); });
@ -1831,9 +1608,7 @@ void VM::__post_init_builtin_types() {
SStream ss; SStream ss;
for(int i = 0; i < _0.size(); i++) { for(int i = 0; i < _0.size(); i++) {
ss << vm->py_str(_0[i]); ss << vm->py_str(_0[i]);
if(i != _0.size() - 1) { if(i != _0.size() - 1) { ss << _1; }
ss << _1;
}
} }
ss << _2; ss << _2;
vm->stdout_write(ss.str()); vm->stdout_write(ss.str());

View File

@ -16,13 +16,10 @@ using namespace pkpy;
} }
#define PK_ASSERT_NO_ERROR() \ #define PK_ASSERT_NO_ERROR() \
if(vm->__c.error != nullptr) \ if(vm->__c.error != nullptr) return false;
return false;
static int count_extra_elements(VM* vm, int n) { static int count_extra_elements(VM* vm, int n) {
if(vm->callstack.empty()) { if(vm->callstack.empty()) { return vm->s_data.size(); }
return vm->s_data.size();
}
assert(!vm->__c.s_view.empty()); assert(!vm->__c.s_view.empty());
return vm->s_data._sp - vm->__c.s_view.top().end(); return vm->s_data._sp - vm->__c.s_view.top().end();
} }
@ -37,9 +34,7 @@ static PyVar stack_item(VM* vm, int index) {
begin = vm->__c.s_view.top().begin(); begin = vm->__c.s_view.top().begin();
} }
int size = end - begin; int size = end - begin;
if(index < 0) { if(index < 0) { index += size; }
index += size;
}
assert(index >= 0 && index < size); assert(index >= 0 && index < size);
return begin[index]; return begin[index];
} }
@ -137,12 +132,8 @@ bool pkpy_rot_two(pkpy_vm* vm_handle) {
int pkpy_stack_size(pkpy_vm* vm_handle) { int pkpy_stack_size(pkpy_vm* vm_handle) {
VM* vm = (VM*)vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
if(vm->callstack.empty()) { if(vm->callstack.empty()) { return vm->s_data.size(); }
return vm->s_data.size(); if(vm->__c.s_view.empty()) { exit(127); }
}
if(vm->__c.s_view.empty()) {
exit(127);
}
return vm->s_data._sp - vm->__c.s_view.top().begin(); return vm->s_data._sp - vm->__c.s_view.top().begin();
} }
@ -322,9 +313,7 @@ struct TempViewPopper {
TempViewPopper(VM* vm) : vm(vm), used(false) {} TempViewPopper(VM* vm) : vm(vm), used(false) {}
void restore() noexcept { void restore() noexcept {
if(used) { if(used) { return; }
return;
}
vm->__c.s_view.pop(); vm->__c.s_view.pop();
used = true; used = true;
} }
@ -350,12 +339,8 @@ static PyVar c_function_wrapper(VM* vm, ArgsView args) {
return nullptr; return nullptr;
} }
assert(retc == vm->s_data._sp - curr_sp); assert(retc == vm->s_data._sp - curr_sp);
if(retc == 0) { if(retc == 0) { return vm->None; }
return vm->None; if(retc == 1) { return vm->s_data.popx(); }
}
if(retc == 1) {
return vm->s_data.popx();
}
ArgsView ret_view(curr_sp, vm->s_data._sp); ArgsView ret_view(curr_sp, vm->s_data._sp);
return py_var(vm, ret_view.to_tuple()); return py_var(vm, ret_view.to_tuple());
} }
@ -389,9 +374,7 @@ bool pkpy_getattr(pkpy_vm* vm_handle, pkpy_CName name) {
PK_ASSERT_N_EXTRA_ELEMENTS(1) PK_ASSERT_N_EXTRA_ELEMENTS(1)
PyVar o = vm->s_data.top(); PyVar o = vm->s_data.top();
o = vm->getattr(o, StrName(name), false); o = vm->getattr(o, StrName(name), false);
if(o == nullptr) { if(o == nullptr) { return false; }
return false;
}
vm->s_data.top() = o; vm->s_data.top() = o;
return true; 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)); PyVar o = vm->_main->attr().try_get(StrName(name));
if(o == nullptr) { if(o == nullptr) {
o = vm->builtins->attr().try_get(StrName(name)); o = vm->builtins->attr().try_get(StrName(name));
if(o == nullptr) { if(o == nullptr) { return false; }
return false;
}
} }
vm->s_data.push(o); vm->s_data.push(o);
return true; return true;
@ -535,9 +516,7 @@ bool pkpy_check_error(pkpy_vm* vm_handle) {
bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) { bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
VM* vm = (VM*)vm_handle; VM* vm = (VM*)vm_handle;
// no error // no error
if(vm->__c.error == nullptr) { if(vm->__c.error == nullptr) { return false; }
return false;
}
Exception& e = vm->__c.error->as<Exception>(); Exception& e = vm->__c.error->as<Exception>();
if(message != nullptr) { if(message != nullptr) {
*message = strdup(e.summary().c_str()); *message = strdup(e.summary().c_str());
@ -548,9 +527,7 @@ bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
if(vm->callstack.empty()) { if(vm->callstack.empty()) {
vm->s_data.clear(); vm->s_data.clear();
} else { } else {
if(vm->__c.s_view.empty()) { if(vm->__c.s_view.empty()) { exit(127); }
exit(127);
}
vm->s_data.reset(vm->__c.s_view.top().end()); vm->s_data.reset(vm->__c.s_view.top().end());
} }
return true; return true;

View File

@ -20,9 +20,7 @@ bool REPL::input(std::string line) {
if(n >= need_more_lines) { if(n >= need_more_lines) {
for(int i = buffer.size() - need_more_lines; i < buffer.size(); i++) { for(int i = buffer.size() - need_more_lines; i < buffer.size(); i++) {
// no enough lines // no enough lines
if(buffer[i] != '\n') { if(buffer[i] != '\n') { return true; }
return true;
}
} }
need_more_lines = 0; need_more_lines = 0;
line = buffer; line = buffer;
@ -39,9 +37,7 @@ bool REPL::input(std::string line) {
buffer += line; buffer += line;
buffer += '\n'; buffer += '\n';
need_more_lines = ne.is_compiling_class ? 3 : 2; need_more_lines = ne.is_compiling_class ? 3 : 2;
if(need_more_lines) { if(need_more_lines) { return true; }
return true;
}
} }
return false; return false;
} }

View File

@ -30,9 +30,7 @@ std::string pkpy_platform_getline(bool* eof) {
std::string output; std::string output;
output.resize(length); output.resize(length);
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL); WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL);
if(!output.empty() && output.back() == '\r') { if(!output.empty() && output.back() == '\r') { output.pop_back(); }
output.pop_back();
}
return output; return output;
} }
@ -41,9 +39,7 @@ std::string pkpy_platform_getline(bool* eof) {
std::string pkpy_platform_getline(bool* eof) { std::string pkpy_platform_getline(bool* eof) {
std::string output; std::string output;
if(!std::getline(std::cin, output)) { if(!std::getline(std::cin, output)) {
if(eof) { if(eof) { *eof = true; }
*eof = true;
}
} }
return output; return output;
} }
@ -54,9 +50,7 @@ static int f_input(pkpy_vm* vm) {
if(!pkpy_is_none(vm, -1)) { if(!pkpy_is_none(vm, -1)) {
pkpy_CString prompt; pkpy_CString prompt;
bool ok = pkpy_to_string(vm, -1, &prompt); bool ok = pkpy_to_string(vm, -1, &prompt);
if(!ok) { if(!ok) { return 0; }
return 0;
}
std::cout << prompt << std::flush; std::cout << prompt << std::flush;
} }
bool eof; bool eof;
@ -83,9 +77,7 @@ int main(int argc, char** argv) {
std::cout << (need_more_lines ? "... " : ">>> "); std::cout << (need_more_lines ? "... " : ">>> ");
bool eof = false; bool eof = false;
std::string line = pkpy_platform_getline(&eof); std::string line = pkpy_platform_getline(&eof);
if(eof) { if(eof) { break; }
break;
}
need_more_lines = pkpy_repl_input(repl, line.c_str()); need_more_lines = pkpy_repl_input(repl, line.c_str());
} }
pkpy_delete_vm(vm); pkpy_delete_vm(vm);
@ -94,9 +86,7 @@ int main(int argc, char** argv) {
if(argc == 2) { if(argc == 2) {
std::string argv_1 = argv[1]; std::string argv_1 = argv[1];
if(argv_1 == "-h" || argv_1 == "--help") { if(argv_1 == "-h" || argv_1 == "--help") { goto __HELP; }
goto __HELP;
}
std::filesystem::path filepath(argv[1]); std::filesystem::path filepath(argv[1]);
filepath = std::filesystem::absolute(filepath); filepath = std::filesystem::absolute(filepath);
@ -115,9 +105,7 @@ int main(int argc, char** argv) {
pkpy_set_main_argv(vm, argc, argv); pkpy_set_main_argv(vm, argc, argv);
bool ok = pkpy_exec_2(vm, src.c_str(), filepath.filename().string().c_str(), 0, NULL); bool ok = pkpy_exec_2(vm, src.c_str(), filepath.filename().string().c_str(), 0, NULL);
if(!ok) { if(!ok) { pkpy_clear_error(vm, NULL); }
pkpy_clear_error(vm, NULL);
}
pkpy_delete_vm(vm); pkpy_delete_vm(vm);
return ok ? 0 : 1; return ok ? 0 : 1;
} }