Disable insert.

This commit is contained in:
ykiko 2024-06-04 20:23:57 +08:00
parent 8ba1a9d245
commit cc664a54c7
46 changed files with 964 additions and 987 deletions

View File

@ -1,4 +1,3 @@
# clang-format configuration # clang-format configuration
# compatible with clang-format 18 # compatible with clang-format 18
@ -20,7 +19,7 @@ LambdaBodyIndentation: Signature
BitFieldColonSpacing: Both BitFieldColonSpacing: Both
# Insert # Insert
InsertBraces: true InsertBraces: false
InsertNewlineAtEOF: true InsertNewlineAtEOF: true
KeepEmptyLinesAtEOF: true KeepEmptyLinesAtEOF: true
@ -55,7 +54,7 @@ AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLambdasOnASingleLine: All AllowShortLambdasOnASingleLine: None
AllowShortLoopsOnASingleLine: false AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true AlwaysBreakBeforeMultilineStrings: true
@ -100,4 +99,4 @@ SortIncludes: Never
SortUsingDeclarations: LexicographicNumeric SortUsingDeclarations: LexicographicNumeric
IncludeBlocks: Merge IncludeBlocks: Merge
WhitespaceSensitiveMacros: ["PK_PROTECTED"] WhitespaceSensitiveMacros: ["PK_PROTECTED", "LUA_PROTECTED"]

View File

@ -25,7 +25,9 @@ struct any {
static vtable vt{typeid(T), nullptr}; static vtable vt{typeid(T), nullptr};
return &vt; return &vt;
} else { } else {
static vtable vt{typeid(T), [](void* ptr) { delete static_cast<T*>(ptr); }}; static vtable vt{typeid(T), [](void* ptr) {
delete static_cast<T*>(ptr);
}};
return &vt; return &vt;
} }
} }
@ -60,7 +62,7 @@ struct any {
any& operator= (const any& other) = delete; any& operator= (const any& other) = delete;
~any() { ~any() {
if(_vt && _vt->deleter) { _vt->deleter(data); } if(_vt && _vt->deleter) _vt->deleter(data);
} }
template <typename T> template <typename T>
@ -76,7 +78,7 @@ struct any {
template <typename T> template <typename T>
T& cast() const { T& cast() const {
static_assert(std::is_same_v<T, std::decay_t<T>>); static_assert(std::is_same_v<T, std::decay_t<T>>);
if(type_id() != typeid(T)) { __bad_any_cast(typeid(T), type_id()); } if(type_id() != typeid(T)) __bad_any_cast(typeid(T), type_id());
return _cast<T>(); return _cast<T>();
} }

View File

@ -10,11 +10,10 @@ namespace pkpy {
template <typename T> template <typename T>
constexpr T default_invalid_value() { constexpr T default_invalid_value() {
if constexpr(std::is_same_v<int, T>) { if constexpr(std::is_same_v<int, T>)
return -1; return -1;
} else { else
return nullptr; return nullptr;
}
} }
template <typename T> template <typename T>
@ -86,7 +85,7 @@ struct NameDictImpl {
uint16_t old_capacity = _capacity; uint16_t old_capacity = _capacity;
_set_capacity_and_alloc_items(_capacity * 2); _set_capacity_and_alloc_items(_capacity * 2);
for(uint16_t i = 0; i < old_capacity; i++) { for(uint16_t i = 0; i < old_capacity; i++) {
if(old_items[i].first.empty()) { continue; } if(old_items[i].first.empty()) continue;
bool ok; bool ok;
uint16_t j; uint16_t j;
HASH_PROBE_1(old_items[i].first, ok, j); HASH_PROBE_1(old_items[i].first, ok, j);
@ -100,7 +99,7 @@ struct NameDictImpl {
bool ok; bool ok;
uint16_t i; uint16_t i;
HASH_PROBE_0(key, ok, i); HASH_PROBE_0(key, ok, i);
if(!ok) { return default_invalid_value<T>(); } if(!ok) return default_invalid_value<T>();
return _items[i].second; return _items[i].second;
} }
@ -108,23 +107,23 @@ struct NameDictImpl {
bool ok; bool ok;
uint16_t i; uint16_t i;
HASH_PROBE_0(key, ok, i); HASH_PROBE_0(key, ok, i);
if(!ok) { return nullptr; } if(!ok) return nullptr;
return &_items[i].second; return &_items[i].second;
} }
T try_get_likely_found(StrName key) const { T try_get_likely_found(StrName key) const {
uint16_t i = key.index & _mask; uint16_t i = key.index & _mask;
if(_items[i].first == key) { return _items[i].second; } if(_items[i].first == key) return _items[i].second;
i = (i + 1) & _mask; i = (i + 1) & _mask;
if(_items[i].first == key) { return _items[i].second; } if(_items[i].first == key) return _items[i].second;
return try_get(key); return try_get(key);
} }
T* try_get_2_likely_found(StrName key) const { T* try_get_2_likely_found(StrName key) const {
uint16_t i = key.index & _mask; uint16_t i = key.index & _mask;
if(_items[i].first == key) { return &_items[i].second; } if(_items[i].first == key) return &_items[i].second;
i = (i + 1) & _mask; i = (i + 1) & _mask;
if(_items[i].first == key) { return &_items[i].second; } if(_items[i].first == key) return &_items[i].second;
return try_get_2(key); return try_get_2(key);
} }
@ -132,7 +131,7 @@ struct NameDictImpl {
bool ok; bool ok;
uint16_t i; uint16_t i;
HASH_PROBE_0(key, ok, i); HASH_PROBE_0(key, ok, i);
if(!ok) { return false; } if(!ok) return false;
_items[i].first = StrName(); _items[i].first = StrName();
_items[i].second = nullptr; _items[i].second = nullptr;
_size--; _size--;
@ -141,7 +140,7 @@ struct NameDictImpl {
uint16_t z = (i + 1) & _mask; uint16_t z = (i + 1) & _mask;
while(!_items[z].first.empty()) { while(!_items[z].first.empty()) {
uint16_t h = _items[z].first.index & _mask; uint16_t h = _items[z].first.index & _mask;
if(h != i) { break; } if(h != i) break;
std::swap(_items[pre_z], _items[z]); std::swap(_items[pre_z], _items[z]);
pre_z = z; pre_z = z;
z = (z + 1) & _mask; z = (z + 1) & _mask;
@ -152,7 +151,7 @@ struct NameDictImpl {
template <typename __Func> template <typename __Func>
void apply(__Func func) const { void apply(__Func func) const {
for(uint16_t i = 0; i < _capacity; i++) { for(uint16_t i = 0; i < _capacity; i++) {
if(_items[i].first.empty()) { continue; } if(_items[i].first.empty()) continue;
func(_items[i].first, _items[i].second); func(_items[i].first, _items[i].second);
} }
} }
@ -174,7 +173,7 @@ struct NameDictImpl {
array<StrName> v(_size); array<StrName> v(_size);
int j = 0; int j = 0;
for(uint16_t i = 0; i < _capacity; i++) { for(uint16_t i = 0; i < _capacity; i++) {
if(_items[i].first.empty()) { continue; } if(_items[i].first.empty()) continue;
new (&v[j++]) StrName(_items[i].first); new (&v[j++]) StrName(_items[i].first);
} }
return v; return v;
@ -183,7 +182,9 @@ struct NameDictImpl {
array<Item> items() const { array<Item> items() const {
array<Item> v(_size); array<Item> v(_size);
int j = 0; int j = 0;
apply([&](StrName key, T val) { new (&v[j++]) Item(key, val); }); apply([&](StrName key, T val) {
new (&v[j++]) Item(key, val);
});
return v; return v;
} }

View File

@ -31,9 +31,8 @@ struct array {
array(explicit_copy_t, const array& other) { array(explicit_copy_t, const array& other) {
_data = (T*)std::malloc(sizeof(T) * other._size); _data = (T*)std::malloc(sizeof(T) * other._size);
_size = other._size; _size = other._size;
for(int i = 0; i < _size; i++) { for(int i = 0; i < _size; i++)
_data[i] = other._data[i]; _data[i] = other._data[i];
}
} }
array(T* data, int size) : _data(data), _size(size) {} array(T* data, int size) : _data(data), _size(size) {}
@ -107,9 +106,8 @@ struct vector {
vector(explicit_copy_t, const vector& other) : vector(explicit_copy_t, const vector& other) :
_data((T*)std::malloc(sizeof(T) * other._size)), _capacity(other._size), _size(other._size) { _data((T*)std::malloc(sizeof(T) * other._size)), _capacity(other._size), _size(other._size) {
for(int i = 0; i < _size; i++) { for(int i = 0; i < _size; i++)
_data[i] = other._data[i]; _data[i] = other._data[i];
}
} }
// allow move // allow move
@ -140,10 +138,8 @@ struct vector {
T* data() const { return _data; } T* data() const { return _data; }
void reserve(int cap) { void reserve(int cap) {
if(cap < 4) { if(cap < 4) cap = 4; // minimum capacity
cap = 4; // minimum capacity if(cap <= capacity()) return;
}
if(cap <= capacity()) { return; }
T* new_data = (T*)std::malloc(sizeof(T) * cap); T* new_data = (T*)std::malloc(sizeof(T) * cap);
if constexpr(is_trivially_relocatable_v<T>) { if constexpr(is_trivially_relocatable_v<T>) {
std::memcpy(new_data, _data, sizeof(T) * _size); std::memcpy(new_data, _data, sizeof(T) * _size);
@ -153,7 +149,7 @@ struct vector {
_data[i].~T(); _data[i].~T();
} }
} }
if(_data) { std::free(_data); } if(_data) std::free(_data);
_data = new_data; _data = new_data;
_capacity = cap; _capacity = cap;
} }
@ -164,25 +160,25 @@ struct vector {
} }
void push_back(const T& t) { void push_back(const T& t) {
if(_size == _capacity) { reserve(_capacity * 2); } if(_size == _capacity) reserve(_capacity * 2);
new (&_data[_size++]) T(t); new (&_data[_size++]) T(t);
} }
void push_back(T&& t) { void push_back(T&& t) {
if(_size == _capacity) { reserve(_capacity * 2); } if(_size == _capacity) reserve(_capacity * 2);
new (&_data[_size++]) T(std::move(t)); new (&_data[_size++]) T(std::move(t));
} }
bool contains(const T& t) const { bool contains(const T& t) const {
for(int i = 0; i < _size; i++) { for(int i = 0; i < _size; i++) {
if(_data[i] == t) { return true; } if(_data[i] == t) return true;
} }
return false; return false;
} }
template <typename... Args> template <typename... Args>
void emplace_back(Args&&... args) { void emplace_back(Args&&... args) {
if(_size == _capacity) { reserve(_capacity * 2); } if(_size == _capacity) reserve(_capacity * 2);
new (&_data[_size++]) T(std::forward<Args>(args)...); new (&_data[_size++]) T(std::forward<Args>(args)...);
} }
@ -193,24 +189,21 @@ struct vector {
void extend(T* begin, T* end) { void extend(T* begin, T* end) {
int n = end - begin; int n = end - begin;
reserve(_size + n); reserve(_size + n);
for(int i = 0; i < n; i++) { for(int i = 0; i < n; i++)
new (&_data[_size++]) T(begin[i]); new (&_data[_size++]) T(begin[i]);
}
} }
void insert(int index, const T& t) { void insert(int index, const T& t) {
if(_size == _capacity) { reserve(_capacity * 2); } if(_size == _capacity) reserve(_capacity * 2);
for(int i = _size; i > index; i--) { for(int i = _size; i > index; i--)
_data[i] = std::move(_data[i - 1]); _data[i] = std::move(_data[i - 1]);
}
_data[index] = t; _data[index] = t;
_size++; _size++;
} }
void erase(int index) { void erase(int index) {
for(int i = index; i < _size - 1; i++) { for(int i = index; i < _size - 1; i++)
_data[i] = std::move(_data[i + 1]); _data[i] = std::move(_data[i + 1]);
}
_size--; _size--;
} }
@ -427,7 +420,7 @@ public:
~small_vector() { ~small_vector() {
std::destroy(m_begin, m_end); std::destroy(m_begin, m_end);
if(!is_small()) { std::free(m_begin); } if(!is_small()) std::free(m_begin);
} }
template <typename... Args> template <typename... Args>

View File

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

View File

@ -276,9 +276,8 @@ struct SequenceExpr : Expr {
virtual Opcode opcode() const = 0; virtual Opcode opcode() const = 0;
void emit_(CodeEmitContext* ctx) override { void emit_(CodeEmitContext* ctx) override {
for(auto& item: items) { for(auto& item: items)
item->emit_(ctx); item->emit_(ctx);
}
ctx->emit_(opcode(), items.size(), line); ctx->emit_(opcode(), items.size(), line);
} }
}; };
@ -287,9 +286,8 @@ struct ListExpr : SequenceExpr {
using SequenceExpr::SequenceExpr; using SequenceExpr::SequenceExpr;
Opcode opcode() const override { Opcode opcode() const override {
for(auto& e: items) { for(auto& e: items)
if(e->is_starred()) { return OP_BUILD_LIST_UNPACK; } if(e->is_starred()) return OP_BUILD_LIST_UNPACK;
}
return OP_BUILD_LIST; return OP_BUILD_LIST;
} }
@ -300,9 +298,8 @@ struct DictExpr : SequenceExpr {
using SequenceExpr::SequenceExpr; using SequenceExpr::SequenceExpr;
Opcode opcode() const override { Opcode opcode() const override {
for(auto& e: items) { for(auto& e: items)
if(e->is_starred()) { return OP_BUILD_DICT_UNPACK; } if(e->is_starred()) return OP_BUILD_DICT_UNPACK;
}
return OP_BUILD_DICT; return OP_BUILD_DICT;
} }
@ -313,9 +310,8 @@ struct SetExpr : SequenceExpr {
using SequenceExpr::SequenceExpr; using SequenceExpr::SequenceExpr;
Opcode opcode() const override { Opcode opcode() const override {
for(auto& e: items) { for(auto& e: items)
if(e->is_starred()) { return OP_BUILD_SET_UNPACK; } if(e->is_starred()) return OP_BUILD_SET_UNPACK;
}
return OP_BUILD_SET; return OP_BUILD_SET;
} }
}; };
@ -326,9 +322,8 @@ struct TupleExpr : SequenceExpr {
bool is_tuple() const override { return true; } bool is_tuple() const override { return true; }
Opcode opcode() const override { Opcode opcode() const override {
for(auto& e: items) { for(auto& e: items)
if(e->is_starred()) { return OP_BUILD_TUPLE_UNPACK; } if(e->is_starred()) return OP_BUILD_TUPLE_UNPACK;
}
return OP_BUILD_TUPLE; return OP_BUILD_TUPLE;
} }

View File

@ -42,7 +42,7 @@ constexpr TokenIndex TK(const char token[]) {
i++; i++;
j++; j++;
} }
if(*i == *j) { return k; } if(*i == *j) return k;
} }
return 255; return 255;
} }
@ -52,9 +52,8 @@ constexpr inline bool is_raw_string_used(TokenIndex t) { return t == TK("@id") |
#define TK_STR(t) kTokens[t] #define TK_STR(t) kTokens[t]
const std::map<std::string_view, TokenIndex> kTokenKwMap = []() { const std::map<std::string_view, TokenIndex> kTokenKwMap = []() {
std::map<std::string_view, TokenIndex> map; std::map<std::string_view, TokenIndex> map;
for(int k = TK("class"); k < kTokenCount; k++) { for(int k = TK("class"); k < kTokenCount; k++)
map[kTokens[k]] = k; map[kTokens[k]] = k;
}
return map; return map;
}(); }();

View File

@ -94,7 +94,7 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
assert(is_type(obj, tp_type)); assert(is_type(obj, tp_type));
std::string_view name_sv(name); std::string_view name_sv(name);
int pos = name_sv.find(':'); int pos = name_sv.find(':');
if(pos > 0) { name_sv = name_sv.substr(0, pos); } if(pos > 0) name_sv = name_sv.substr(0, pos);
auto fget = [](VM* vm, ArgsView args) -> PyVar { auto fget = [](VM* vm, ArgsView args) -> PyVar {
obj_get_t<T> self = PK_OBJ_GET(T, args[0]); obj_get_t<T> self = PK_OBJ_GET(T, args[0]);
F T::*field = lambda_get_userdata<F T::*>(args.begin()); F T::*field = lambda_get_userdata<F T::*>(args.begin());
@ -188,7 +188,9 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
wT& self = _CAST(wT&, args[0]); \ wT& self = _CAST(wT&, args[0]); \
return vm->new_user_object<wT>(self); \ return vm->new_user_object<wT>(self); \
}); \ }); \
vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args) { return VAR(sizeof(wT)); }); \ vm->bind_func(type, "sizeof", 1, [](VM* vm, ArgsView args) { \
return VAR(sizeof(wT)); \
}); \
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \ vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { \
wT& self = _CAST(wT&, _0); \ wT& self = _CAST(wT&, _0); \
if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \ if(!vm->isinstance(_1, vm->_tp_user<wT>())) return vm->NotImplemented; \
@ -210,8 +212,14 @@ PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field) {
tgt[i] = CAST(T, _2); \ tgt[i] = CAST(T, _2); \
}); });
#define PK_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return x; }) #define PK_LAMBDA(x) \
#define PK_VAR_LAMBDA(x) ([](VM* vm, ArgsView args) -> PyVar { return VAR(x); }) ([](VM* vm, ArgsView args) -> PyVar { \
return x; \
})
#define PK_VAR_LAMBDA(x) \
([](VM* vm, ArgsView args) -> PyVar { \
return VAR(x); \
})
#define PK_ACTION(x) \ #define PK_ACTION(x) \
([](VM* vm, ArgsView args) -> PyVar { \ ([](VM* vm, ArgsView args) -> PyVar { \
x; \ x; \

View File

@ -74,17 +74,17 @@ struct Struct {
} else { } else {
p = (char*)std::malloc(size); p = (char*)std::malloc(size);
} }
if(zero_init) { std::memset(p, 0, size); } if(zero_init) std::memset(p, 0, size);
} }
Struct(void* p, int size) : Struct(size, false) { Struct(void* p, int size) : Struct(size, false) {
if(p != nullptr) { std::memcpy(this->p, p, size); } if(p != nullptr) std::memcpy(this->p, p, size);
} }
Struct(const Struct& other) : Struct(other.p, other.size) {} Struct(const Struct& other) : Struct(other.p, other.size) {}
~Struct() { ~Struct() {
if(p != _inlined) { std::free(p); } if(p != _inlined) std::free(p);
} }
static void _register(VM* vm, PyObject* mod, PyObject* type); static void _register(VM* vm, PyObject* mod, PyObject* type);
@ -94,9 +94,7 @@ struct Struct {
template <typename Tp> template <typename Tp>
Tp to_void_p(VM* vm, PyVar var) { Tp to_void_p(VM* vm, PyVar var) {
static_assert(std::is_pointer_v<Tp>); static_assert(std::is_pointer_v<Tp>);
if(var == vm->None) { if(var == vm->None) return nullptr; // None can be casted to any pointer implicitly
return nullptr; // None can be casted to any pointer implicitly
}
VoidP& p = CAST(VoidP&, var); VoidP& p = CAST(VoidP&, var);
return reinterpret_cast<Tp>(p.ptr); return reinterpret_cast<Tp>(p.ptr);
} }

View File

@ -178,9 +178,8 @@ struct CallStack {
bool empty() const { return _size == 0; } bool empty() const { return _size == 0; }
void clear() { void clear() {
while(!empty()) { while(!empty())
pop(); pop();
}
} }
template <typename... Args> template <typename... Args>
@ -201,9 +200,8 @@ struct CallStack {
template <typename Func> template <typename Func>
void apply(Func&& f) { void apply(Func&& f) {
for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back) { for(LinkedFrame* p = _tail; p != nullptr; p = p->f_back)
f(p->frame); f(p->frame);
}
} }
~CallStack() { clear(); } ~CallStack() { clear(); }

View File

@ -51,13 +51,12 @@ struct Generator {
List s_backup; List s_backup;
Generator(LinkedFrame* lf, ArgsView buffer) : lf(lf), state(0) { Generator(LinkedFrame* lf, ArgsView buffer) : lf(lf), state(0) {
for(PyVar obj: buffer) { for(PyVar obj: buffer)
s_backup.push_back(obj); s_backup.push_back(obj);
}
} }
void _gc_mark(VM* vm) { void _gc_mark(VM* vm) {
if(lf == nullptr) { return; } if(lf == nullptr) return;
lf->frame._gc_mark(vm); lf->frame._gc_mark(vm);
vm->__stack_gc_mark(s_backup.begin(), s_backup.end()); vm->__stack_gc_mark(s_backup.begin(), s_backup.end());
} }

View File

@ -1,13 +1,13 @@
#pragma once #pragma once
#include "pocketpy/interpreter/frame.hpp" #include "pocketpy/objects/object.hpp"
#include "pocketpy/interpreter/gc.hpp"
#include "pocketpy/interpreter/profiler.hpp"
#include "pocketpy/objects/builtins.hpp"
#include "pocketpy/objects/dict.hpp" #include "pocketpy/objects/dict.hpp"
#include "pocketpy/objects/error.hpp" #include "pocketpy/objects/error.hpp"
#include "pocketpy/objects/object.hpp"
#include "pocketpy/objects/stackmemory.hpp" #include "pocketpy/objects/stackmemory.hpp"
#include "pocketpy/objects/builtins.hpp"
#include "pocketpy/interpreter/gc.hpp"
#include "pocketpy/interpreter/frame.hpp"
#include "pocketpy/interpreter/profiler.hpp"
#include <stdexcept> #include <stdexcept>
@ -58,10 +58,14 @@ struct PyTypeInfo {
static_assert(std::is_same_v<T, std::decay_t<T>>); static_assert(std::is_same_v<T, std::decay_t<T>>);
Vt vt; Vt vt;
if constexpr(!std::is_trivially_destructible_v<T>) { if constexpr(!std::is_trivially_destructible_v<T>) {
vt._dtor = [](void* p) { ((T*)p)->~T(); }; vt._dtor = [](void* p) {
((T*)p)->~T();
};
} }
if constexpr(has_gc_marker<T>::value) { if constexpr(has_gc_marker<T>::value) {
vt._gc_mark = [](void* p, VM* vm) { ((T*)p)->_gc_mark(vm); }; vt._gc_mark = [](void* p, VM* vm) {
((T*)p)->_gc_mark(vm);
};
} }
return vt; return vt;
} }
@ -654,18 +658,16 @@ PyVar py_var(VM* vm, __T&& value) {
} else { } else {
constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>(); constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
if constexpr((bool)const_type) { if constexpr((bool)const_type) {
if constexpr(is_sso_v<T>) { if constexpr(is_sso_v<T>)
return PyVar(const_type, value); return PyVar(const_type, value);
} else { else
return vm->heap.gcnew<T>(const_type, std::forward<__T>(value)); return vm->heap.gcnew<T>(const_type, std::forward<__T>(value));
}
} else { } else {
Type type = vm->_find_type_in_cxx_typeid_map<T>(); Type type = vm->_find_type_in_cxx_typeid_map<T>();
if constexpr(is_sso_v<T>) { if constexpr(is_sso_v<T>)
return PyVar(type, value); return PyVar(type, value);
} else { else
return vm->heap.gcnew<T>(type, std::forward<__T>(value)); return vm->heap.gcnew<T>(type, std::forward<__T>(value));
}
} }
} }
} }
@ -682,15 +684,15 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, CString>) { if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, CString>) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
// str (shortcuts) // str (shortcuts)
if(obj == vm->None) { return nullptr; } if(obj == vm->None) return nullptr;
if constexpr(with_check) { vm->check_type(obj, vm->tp_str); } if constexpr(with_check) vm->check_type(obj, vm->tp_str);
return PK_OBJ_GET(Str, obj).c_str(); return PK_OBJ_GET(Str, obj).c_str();
} else if constexpr(std::is_same_v<T, bool>) { } else if constexpr(std::is_same_v<T, bool>) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
// bool // bool
if constexpr(with_check) { if constexpr(with_check) {
if(obj == vm->True) { return true; } if(obj == vm->True) return true;
if(obj == vm->False) { return false; } if(obj == vm->False) return false;
vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape()); vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
} }
return obj == vm->True; return obj == vm->True;
@ -698,14 +700,14 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
// int // int
if constexpr(with_check) { if constexpr(with_check) {
if(is_int(obj)) { return (T)obj.as<i64>(); } if(is_int(obj)) return (T)obj.as<i64>();
vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape()); vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
} }
return (T)obj.as<i64>(); return (T)obj.as<i64>();
} else if constexpr(is_floating_point_v<T>) { } else if constexpr(is_floating_point_v<T>) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
if(is_float(obj)) { return (T)obj.as<f64>(); } if(is_float(obj)) return (T)obj.as<f64>();
if(is_int(obj)) { return (T)obj.as<i64>(); } if(is_int(obj)) return (T)obj.as<i64>();
vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape()); vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape());
return 0.0f; return 0.0f;
} else if constexpr(std::is_enum_v<T>) { } else if constexpr(std::is_enum_v<T>) {

View File

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

View File

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

View File

@ -45,9 +45,8 @@ struct List : public vector<PyVar> {
Tuple to_tuple() const { Tuple to_tuple() const {
Tuple ret(size()); Tuple ret(size());
for(int i = 0; i < size(); i++) { for(int i = 0; i < size(); i++)
ret[i] = (*this)[i]; ret[i] = (*this)[i];
}
return ret; return ret;
} }
}; };

View File

@ -50,7 +50,9 @@ public:
bind_function( bind_function(
*this, *this,
"__init__", "__init__",
[](T* self, Args... args) { new (self) T(args...); }, [](T* self, Args... args) {
new (self) T(args...);
},
pkpy::BindType::DEFAULT, pkpy::BindType::DEFAULT,
extra...); extra...);
return *this; return *this;

View File

@ -65,10 +65,14 @@ public:
if constexpr(sizeof(f) <= sizeof(buffer)) { if constexpr(sizeof(f) <= sizeof(buffer)) {
new (buffer) auto(std::forward<Fn>(f)); new (buffer) auto(std::forward<Fn>(f));
destructor = [](function_record* self) { reinterpret_cast<Fn*>(self->buffer)->~Fn(); }; destructor = [](function_record* self) {
reinterpret_cast<Fn*>(self->buffer)->~Fn();
};
} else { } else {
data = new auto(std::forward<Fn>(f)); data = new auto(std::forward<Fn>(f));
destructor = [](function_record* self) { delete static_cast<Fn*>(self->data); }; destructor = [](function_record* self) {
delete static_cast<Fn*>(self->data);
};
} }
using Generator = generator<std::decay_t<Fn>, std::tuple<Extras...>>; using Generator = generator<std::decay_t<Fn>, std::tuple<Extras...>>;

View File

@ -24,8 +24,12 @@ struct type_info {
((T*)ptr)->~T(); ((T*)ptr)->~T();
operator delete (ptr); operator delete (ptr);
}, },
[](void* dst, const void* src) { new (dst) T(*(const T*)src); }, [](void* dst, const void* src) {
[](void* dst, void* src) { new (dst) T(std::move(*(T*)src)); }, new (dst) T(*(const T*)src);
},
[](void* dst, void* src) {
new (dst) T(std::move(*(T*)src));
},
&typeid(T), &typeid(T),
}; };
return info; return info;

View File

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

View File

@ -176,7 +176,7 @@ struct MemoryPool {
void shrink_to_fit() { void shrink_to_fit() {
PK_GLOBAL_SCOPE_LOCK(); PK_GLOBAL_SCOPE_LOCK();
if(_arenas.size() < __MinArenaCount) { return; } if(_arenas.size() < __MinArenaCount) return;
_arenas.apply([this](Arena* arena) { _arenas.apply([this](Arena* arena) {
if(arena->full()) { if(arena->full()) {
_arenas.erase(arena); _arenas.erase(arena);
@ -186,8 +186,12 @@ struct MemoryPool {
} }
~MemoryPool() { ~MemoryPool() {
_arenas.apply([](Arena* arena) { delete arena; }); _arenas.apply([](Arena* arena) {
_empty_arenas.apply([](Arena* arena) { delete arena; }); delete arena;
});
_empty_arenas.apply([](Arena* arena) {
delete arena;
});
} }
}; };

View File

@ -9,13 +9,13 @@
namespace pkpy { namespace pkpy {
int utf8len(unsigned char c, bool suppress) { int utf8len(unsigned char c, bool suppress) {
if((c & 0b10000000) == 0) { return 1; } if((c & 0b10000000) == 0) return 1;
if((c & 0b11100000) == 0b11000000) { return 2; } if((c & 0b11100000) == 0b11000000) return 2;
if((c & 0b11110000) == 0b11100000) { return 3; } if((c & 0b11110000) == 0b11100000) return 3;
if((c & 0b11111000) == 0b11110000) { return 4; } if((c & 0b11111000) == 0b11110000) return 4;
if((c & 0b11111100) == 0b11111000) { return 5; } if((c & 0b11111100) == 0b11111000) return 5;
if((c & 0b11111110) == 0b11111100) { return 6; } if((c & 0b11111110) == 0b11111100) return 6;
if(!suppress) { throw std::runtime_error("invalid utf8 char: " + std::to_string(c)); } if(!suppress) throw std::runtime_error("invalid utf8 char: " + std::to_string(c));
return 0; return 0;
} }
@ -70,9 +70,8 @@ Str::Str(const Str& other) : size(other.size), is_ascii(other.is_ascii) {
Str::Str(Str&& other) : size(other.size), is_ascii(other.is_ascii) { Str::Str(Str&& other) : size(other.size), is_ascii(other.is_ascii) {
if(other.is_inlined()) { if(other.is_inlined()) {
data = _inlined; data = _inlined;
for(int i = 0; i < size; i++) { for(int i = 0; i < size; i++)
_inlined[i] = other._inlined[i]; _inlined[i] = other._inlined[i];
}
data[size] = '\0'; data[size] = '\0';
} else { } else {
data = other.data; data = other.data;
@ -93,7 +92,7 @@ std::ostream& operator<< (std::ostream& os, const Str& str) { return os << str.s
bool operator< (const std::string_view other, const Str& str) { return other < str.sv(); } bool operator< (const std::string_view other, const Str& str) { return other < str.sv(); }
Str& Str::operator= (const Str& other) { Str& Str::operator= (const Str& other) {
if(!is_inlined()) { std::free(data); } if(!is_inlined()) std::free(data);
size = other.size; size = other.size;
is_ascii = other.is_ascii; is_ascii = other.is_ascii;
PK_STR_ALLOCATE() PK_STR_ALLOCATE()
@ -116,22 +115,22 @@ Str Str::operator+ (const char* p) const {
} }
bool Str::operator== (const Str& other) const { bool Str::operator== (const Str& other) const {
if(size != other.size) { return false; } if(size != other.size) return false;
return memcmp(data, other.data, size) == 0; return memcmp(data, other.data, size) == 0;
} }
bool Str::operator!= (const Str& other) const { bool Str::operator!= (const Str& other) const {
if(size != other.size) { return true; } if(size != other.size) return true;
return memcmp(data, other.data, size) != 0; return memcmp(data, other.data, size) != 0;
} }
bool Str::operator== (const std::string_view other) const { bool Str::operator== (const std::string_view other) const {
if(size != (int)other.size()) { return false; } if(size != (int)other.size()) return false;
return memcmp(data, other.data(), size) == 0; return memcmp(data, other.data(), size) == 0;
} }
bool Str::operator!= (const std::string_view other) const { bool Str::operator!= (const std::string_view other) const {
if(size != (int)other.size()) { return true; } if(size != (int)other.size()) return true;
return memcmp(data, other.data(), size) != 0; return memcmp(data, other.data(), size) != 0;
} }
@ -150,7 +149,7 @@ bool Str::operator<= (const Str& other) const { return this->sv() <= other.sv();
bool Str::operator>= (const Str& other) const { return this->sv() >= other.sv(); } bool Str::operator>= (const Str& other) const { return this->sv() >= other.sv(); }
Str::~Str() { Str::~Str() {
if(!is_inlined()) { std::free(data); } if(!is_inlined()) std::free(data);
} }
Str Str::substr(int start, int len) const { Str Str::substr(int start, int len) const {
@ -166,14 +165,12 @@ Str Str::strip(bool left, bool right, const Str& chars) const {
int L = 0; int L = 0;
int R = u8_length(); int R = u8_length();
if(left) { if(left) {
while(L < R && chars.index(u8_getitem(L)) != -1) { while(L < R && chars.index(u8_getitem(L)) != -1)
L++; L++;
}
} }
if(right) { if(right) {
while(L < R && chars.index(u8_getitem(R - 1)) != -1) { while(L < R && chars.index(u8_getitem(R - 1)) != -1)
R--; R--;
}
} }
return u8_slice(L, R, 1); return u8_slice(L, R, 1);
} }
@ -183,14 +180,12 @@ Str Str::strip(bool left, bool right) const {
int L = 0; int L = 0;
int R = size; int R = size;
if(left) { if(left) {
while(L < R && (data[L] == ' ' || data[L] == '\t' || data[L] == '\n' || data[L] == '\r')) { while(L < R && (data[L] == ' ' || data[L] == '\t' || data[L] == '\n' || data[L] == '\r'))
L++; L++;
}
} }
if(right) { if(right) {
while(L < R && (data[R - 1] == ' ' || data[R - 1] == '\t' || data[R - 1] == '\n' || data[R - 1] == '\r')) { while(L < R && (data[R - 1] == ' ' || data[R - 1] == '\t' || data[R - 1] == '\n' || data[R - 1] == '\r'))
R--; R--;
}
} }
return substr(L, R - L); return substr(L, R - L);
} else { } else {
@ -201,7 +196,7 @@ Str Str::strip(bool left, bool right) const {
Str Str::lower() const { Str Str::lower() const {
std::string copy(data, size); std::string copy(data, size);
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) { std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) {
if('A' <= c && c <= 'Z') { return c + ('a' - 'A'); } if('A' <= c && c <= 'Z') return c + ('a' - 'A');
return (int)c; return (int)c;
}); });
return Str(copy); return Str(copy);
@ -210,7 +205,7 @@ Str Str::lower() const {
Str Str::upper() const { Str Str::upper() const {
std::string copy(data, size); std::string copy(data, size);
std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) { std::transform(copy.begin(), copy.end(), copy.begin(), [](unsigned char c) {
if('a' <= c && c <= 'z') { return c - ('a' - 'A'); } if('a' <= c && c <= 'z') return c - ('a' - 'A');
return (int)c; return (int)c;
}); });
return Str(copy); return Str(copy);
@ -228,11 +223,11 @@ void Str::escape_(SStream& ss, bool single_quote) const {
char c = this->operator[] (i); char c = this->operator[] (i);
switch(c) { switch(c) {
case '"': case '"':
if(!single_quote) { ss << '\\'; } if(!single_quote) ss << '\\';
ss << '"'; ss << '"';
break; break;
case '\'': case '\'':
if(single_quote) { ss << '\\'; } if(single_quote) ss << '\\';
ss << '\''; ss << '\'';
break; break;
case '\\': ss << '\\' << '\\'; break; case '\\': ss << '\\' << '\\'; break;
@ -255,14 +250,14 @@ void Str::escape_(SStream& ss, bool single_quote) const {
int Str::index(const Str& sub, int start) const { int Str::index(const Str& sub, int start) const {
auto p = std::search(data + start, data + size, sub.data, sub.data + sub.size); auto p = std::search(data + start, data + size, sub.data, sub.data + sub.size);
if(p == data + size) { return -1; } if(p == data + size) return -1;
return p - data; return p - data;
} }
Str Str::replace(char old, char new_) const { Str Str::replace(char old, char new_) const {
Str copied = *this; Str copied = *this;
for(int i = 0; i < copied.size; i++) { for(int i = 0; i < copied.size; i++) {
if(copied.data[i] == old) { copied.data[i] = new_; } if(copied.data[i] == old) copied.data[i] = new_;
} }
return copied; return copied;
} }
@ -272,18 +267,18 @@ Str Str::replace(const Str& old, const Str& new_, int count) const {
int start = 0; int start = 0;
while(true) { while(true) {
int i = index(old, start); int i = index(old, start);
if(i == -1) { break; } if(i == -1) break;
ss << substr(start, i - start); ss << substr(start, i - start);
ss << new_; ss << new_;
start = i + old.size; start = i + old.size;
if(count != -1 && --count == 0) { break; } if(count != -1 && --count == 0) break;
} }
ss << substr(start, size - start); ss << substr(start, size - start);
return ss.str(); return ss.str();
} }
int Str::_unicode_index_to_byte(int i) const { int Str::_unicode_index_to_byte(int i) const {
if(is_ascii) { return i; } if(is_ascii) return i;
int j = 0; int j = 0;
while(i > 0) { while(i > 0) {
j += utf8len(data[j]); j += utf8len(data[j]);
@ -293,10 +288,10 @@ int Str::_unicode_index_to_byte(int i) const {
} }
int Str::_byte_index_to_unicode(int n) const { int Str::_byte_index_to_unicode(int n) const {
if(is_ascii) { return n; } if(is_ascii) return n;
int cnt = 0; int cnt = 0;
for(int i = 0; i < n; i++) { for(int i = 0; i < n; i++) {
if((data[i] & 0xC0) != 0x80) { cnt++; } if((data[i] & 0xC0) != 0x80) cnt++;
} }
return cnt; return cnt;
} }
@ -324,13 +319,13 @@ vector<std::string_view> Str::split(const Str& sep) const {
int start = 0; int start = 0;
while(true) { while(true) {
int i = index(sep, start); int i = index(sep, start);
if(i == -1) { break; } if(i == -1) break;
tmp = sv().substr(start, i - start); tmp = sv().substr(start, i - start);
if(!tmp.empty()) { result.push_back(tmp); } if(!tmp.empty()) result.push_back(tmp);
start = i + sep.size; start = i + sep.size;
} }
tmp = sv().substr(start, size - start); tmp = sv().substr(start, size - start);
if(!tmp.empty()) { result.push_back(tmp); } if(!tmp.empty()) result.push_back(tmp);
return result; return result;
} }
@ -339,22 +334,22 @@ vector<std::string_view> Str::split(char sep) const {
int i = 0; int i = 0;
for(int j = 0; j < size; j++) { for(int j = 0; j < size; j++) {
if(data[j] == sep) { if(data[j] == sep) {
if(j > i) { result.emplace_back(data + i, j - i); } if(j > i) result.emplace_back(data + i, j - i);
i = j + 1; i = j + 1;
continue; continue;
} }
} }
if(size > i) { result.emplace_back(data + i, size - i); } if(size > i) result.emplace_back(data + i, size - i);
return result; return result;
} }
int Str::count(const Str& sub) const { int Str::count(const Str& sub) const {
if(sub.empty()) { return size + 1; } if(sub.empty()) return size + 1;
int cnt = 0; int cnt = 0;
int start = 0; int start = 0;
while(true) { while(true) {
int i = index(sub, start); int i = index(sub, start);
if(i == -1) { break; } if(i == -1) break;
cnt++; cnt++;
start = i + sub.size; start = i + sub.size;
} }
@ -375,11 +370,11 @@ uint32_t StrName::_pesudo_random_index = 0;
StrName StrName::get(std::string_view s) { StrName StrName::get(std::string_view s) {
auto it = _interned().find(s); auto it = _interned().find(s);
if(it != _interned().end()) { return StrName(it->second); } if(it != _interned().end()) return StrName(it->second);
// generate new index // generate new index
// https://github.com/python/cpython/blob/3.12/Objects/dictobject.c#L175 // https://github.com/python/cpython/blob/3.12/Objects/dictobject.c#L175
uint16_t index = ((_pesudo_random_index * 5) + 1) & 65535; uint16_t index = ((_pesudo_random_index * 5) + 1) & 65535;
if(index == 0) { throw std::runtime_error("StrName index overflow"); } if(index == 0) throw std::runtime_error("StrName index overflow");
auto res = _r_interned().emplace(index, s); auto res = _r_interned().emplace(index, s);
assert(res.second); assert(res.second);
s = std::string_view(res.first->second); s = std::string_view(res.first->second);
@ -396,30 +391,26 @@ Str SStream::str() {
} }
SStream& SStream::operator<< (const Str& s) { SStream& SStream::operator<< (const Str& s) {
for(char c: s) { for(char c: s)
buffer.push_back(c); buffer.push_back(c);
}
return *this; return *this;
} }
SStream& SStream::operator<< (const char* s) { SStream& SStream::operator<< (const char* s) {
while(*s) { while(*s)
buffer.push_back(*s++); buffer.push_back(*s++);
}
return *this; return *this;
} }
SStream& SStream::operator<< (const std::string& s) { SStream& SStream::operator<< (const std::string& s) {
for(char c: s) { for(char c: s)
buffer.push_back(c); buffer.push_back(c);
}
return *this; return *this;
} }
SStream& SStream::operator<< (std::string_view s) { SStream& SStream::operator<< (std::string_view s) {
for(char c: s) { for(char c: s)
buffer.push_back(c); buffer.push_back(c);
}
return *this; return *this;
} }
@ -469,7 +460,7 @@ SStream& SStream::operator<< (f64 val) {
snprintf(b, sizeof(b), "%.*f", prec, val); snprintf(b, sizeof(b), "%.*f", prec, val);
} }
(*this) << b; (*this) << b;
if(std::all_of(b + 1, b + strlen(b), isdigit)) { (*this) << ".0"; } if(std::all_of(b + 1, b + strlen(b), isdigit)) (*this) << ".0";
return *this; return *this;
} }
@ -477,8 +468,8 @@ void SStream::write_hex(unsigned char c, bool non_zero) {
unsigned char high = c >> 4; unsigned char high = c >> 4;
unsigned char low = c & 0xf; unsigned char low = c & 0xf;
if(non_zero) { if(non_zero) {
if(high) { (*this) << PK_HEX_TABLE[high]; } if(high) (*this) << PK_HEX_TABLE[high];
if(high || low) { (*this) << PK_HEX_TABLE[low]; } if(high || low) (*this) << PK_HEX_TABLE[low];
} else { } else {
(*this) << PK_HEX_TABLE[high]; (*this) << PK_HEX_TABLE[high];
(*this) << PK_HEX_TABLE[low]; (*this) << PK_HEX_TABLE[low];
@ -496,7 +487,7 @@ void SStream::write_hex(void* p) {
for(int i = sizeof(void*) - 1; i >= 0; i--) { for(int i = sizeof(void*) - 1; i >= 0; i--) {
unsigned char cpnt = (p_t >> (i * 8)) & 0xff; unsigned char cpnt = (p_t >> (i * 8)) & 0xff;
write_hex(cpnt, non_zero); write_hex(cpnt, non_zero);
if(cpnt != 0) { non_zero = false; } if(cpnt != 0) non_zero = false;
} }
} }
@ -514,7 +505,7 @@ void SStream::write_hex(i64 val) {
for(int i = 56; i >= 0; i -= 8) { for(int i = 56; i >= 0; i -= 8) {
unsigned char cpnt = (val >> i) & 0xff; unsigned char cpnt = (val >> i) & 0xff;
write_hex(cpnt, non_zero); write_hex(cpnt, non_zero);
if(cpnt != 0) { non_zero = false; } if(cpnt != 0) non_zero = false;
} }
} }

View File

@ -9,7 +9,7 @@ PrattRule Compiler::rules[kTokenCount];
NameScope Compiler::name_scope() const { NameScope Compiler::name_scope() const {
auto s = contexts.size() > 1 ? NAME_LOCAL : NAME_GLOBAL; auto s = contexts.size() > 1 ? NAME_LOCAL : NAME_GLOBAL;
if(unknown_global_scope && s == NAME_GLOBAL) { s = NAME_GLOBAL_UNKNOWN; } if(unknown_global_scope && s == NAME_GLOBAL) s = NAME_GLOBAL_UNKNOWN;
return s; return s;
} }
@ -38,9 +38,8 @@ void Compiler::pop_context() {
ctx()->emit_(OP_RETURN_VALUE, 1, BC_KEEPLINE, true); ctx()->emit_(OP_RETURN_VALUE, 1, BC_KEEPLINE, true);
// find the last valid token // find the last valid token
int j = i - 1; int j = i - 1;
while(tokens[j].type == TK("@eol") || tokens[j].type == TK("@dedent") || tokens[j].type == TK("@eof")) { while(tokens[j].type == TK("@eol") || tokens[j].type == TK("@dedent") || tokens[j].type == TK("@eof"))
j--; j--;
}
ctx()->co->end_line = tokens[j].line; ctx()->co->end_line = tokens[j].line;
// some check here // some check here
@ -73,9 +72,9 @@ void Compiler::pop_context() {
} }
if(func->type == FuncType::UNSET) { if(func->type == FuncType::UNSET) {
bool is_simple = true; bool is_simple = true;
if(func->kwargs.size() > 0) { is_simple = false; } if(func->kwargs.size() > 0) is_simple = false;
if(func->starred_arg >= 0) { is_simple = false; } if(func->starred_arg >= 0) is_simple = false;
if(func->starred_kwarg >= 0) { is_simple = false; } if(func->starred_kwarg >= 0) is_simple = false;
if(is_simple) { if(is_simple) {
func->type = FuncType::SIMPLE; func->type = FuncType::SIMPLE;
@ -85,10 +84,9 @@ void Compiler::pop_context() {
Bytecode bc = func->code->codes[0]; Bytecode bc = func->code->codes[0];
if(bc.op == OP_RETURN_VALUE && bc.arg == 1) { is_empty = true; } if(bc.op == OP_RETURN_VALUE && bc.arg == 1) { is_empty = true; }
} }
if(is_empty) { func->type = FuncType::EMPTY; } if(is_empty) func->type = FuncType::EMPTY;
} else { } else
func->type = FuncType::NORMAL; func->type = FuncType::NORMAL;
}
} }
assert(func->type != FuncType::UNSET); assert(func->type != FuncType::UNSET);
@ -98,7 +96,7 @@ void Compiler::pop_context() {
void Compiler::init_pratt_rules() { void Compiler::init_pratt_rules() {
static bool initialized = false; static bool initialized = false;
if(initialized) { return; } if(initialized) return;
initialized = true; initialized = true;
// clang-format off // clang-format off
@ -158,7 +156,7 @@ void Compiler::init_pratt_rules() {
} }
bool Compiler::match(TokenIndex expected) { bool Compiler::match(TokenIndex expected) {
if(curr().type != expected) { return false; } if(curr().type != expected) return false;
advance(); advance();
return true; return true;
} }
@ -172,9 +170,8 @@ bool Compiler::match_newlines_repl() { return match_newlines(mode() == REPL_MODE
bool Compiler::match_newlines(bool repl_throw) { bool Compiler::match_newlines(bool repl_throw) {
bool consumed = false; bool consumed = false;
if(curr().type == TK("@eol")) { if(curr().type == TK("@eol")) {
while(curr().type == TK("@eol")) { while(curr().type == TK("@eol"))
advance(); advance();
}
consumed = true; consumed = true;
} }
if(repl_throw && curr().type == TK("@eof")) { throw NeedMoreLines(ctx()->is_compiling_class); } if(repl_throw && curr().type == TK("@eof")) { throw NeedMoreLines(ctx()->is_compiling_class); }
@ -186,29 +183,29 @@ bool Compiler::match_end_stmt() {
match_newlines(); match_newlines();
return true; return true;
} }
if(match_newlines() || curr().type == TK("@eof")) { return true; } if(match_newlines() || curr().type == TK("@eof")) return true;
if(curr().type == TK("@dedent")) { return true; } if(curr().type == TK("@dedent")) return true;
return false; return false;
} }
void Compiler::consume_end_stmt() { void Compiler::consume_end_stmt() {
if(!match_end_stmt()) { SyntaxError("expected statement end"); } if(!match_end_stmt()) SyntaxError("expected statement end");
} }
void Compiler::EXPR() { parse_expression(PREC_LOWEST + 1); } void Compiler::EXPR() { parse_expression(PREC_LOWEST + 1); }
void Compiler::EXPR_TUPLE(bool allow_slice) { void Compiler::EXPR_TUPLE(bool allow_slice) {
parse_expression(PREC_LOWEST + 1, allow_slice); parse_expression(PREC_LOWEST + 1, allow_slice);
if(!match(TK(","))) { return; } if(!match(TK(","))) return;
// tuple expression // tuple expression
Expr_vector items; Expr_vector items;
items.push_back(ctx()->s_expr.popx()); items.push_back(ctx()->s_expr.popx());
do { do {
if(curr().brackets_level) { match_newlines_repl(); } if(curr().brackets_level) match_newlines_repl();
if(!is_expression(allow_slice)) { break; } if(!is_expression(allow_slice)) break;
parse_expression(PREC_LOWEST + 1, allow_slice); parse_expression(PREC_LOWEST + 1, allow_slice);
items.push_back(ctx()->s_expr.popx()); items.push_back(ctx()->s_expr.popx());
if(curr().brackets_level) { match_newlines_repl(); } if(curr().brackets_level) match_newlines_repl();
} while(match(TK(","))); } while(match(TK(",")));
ctx()->s_expr.push(make_expr<TupleExpr>(std::move(items))); ctx()->s_expr.push(make_expr<TupleExpr>(std::move(items)));
} }
@ -220,7 +217,7 @@ Expr_ Compiler::EXPR_VARS() {
consume(TK("@id")); consume(TK("@id"));
items.push_back(make_expr<NameExpr>(prev().str(), name_scope())); items.push_back(make_expr<NameExpr>(prev().str(), name_scope()));
} while(match(TK(","))); } while(match(TK(",")));
if(items.size() == 1) { return std::move(items[0]); } if(items.size() == 1) return std::move(items[0]);
return make_expr<TupleExpr>(std::move(items)); return make_expr<TupleExpr>(std::move(items));
} }
@ -309,7 +306,7 @@ void Compiler::exprGroup() {
EXPR_TUPLE(); // () is just for change precedence EXPR_TUPLE(); // () is just for change precedence
match_newlines_repl(); match_newlines_repl();
consume(TK(")")); consume(TK(")"));
if(ctx()->s_expr.top()->is_tuple()) { return; } if(ctx()->s_expr.top()->is_tuple()) return;
Expr_ g = make_expr<GroupedExpr>(ctx()->s_expr.popx()); Expr_ g = make_expr<GroupedExpr>(ctx()->s_expr.popx());
ctx()->s_expr.push(std::move(g)); ctx()->s_expr.push(std::move(g));
} }
@ -334,7 +331,7 @@ void Compiler::exprList() {
Expr_vector items; Expr_vector items;
do { do {
match_newlines_repl(); match_newlines_repl();
if(curr().type == TK("]")) { break; } if(curr().type == TK("]")) break;
EXPR(); EXPR();
items.push_back(ctx()->s_expr.popx()); items.push_back(ctx()->s_expr.popx());
match_newlines_repl(); match_newlines_repl();
@ -356,7 +353,7 @@ void Compiler::exprMap() {
Expr_vector items; Expr_vector items;
do { do {
match_newlines_repl(); match_newlines_repl();
if(curr().type == TK("}")) { break; } if(curr().type == TK("}")) break;
EXPR(); EXPR();
int star_level = ctx()->s_expr.top()->star_level(); int star_level = ctx()->s_expr.top()->star_level();
if(star_level == 2 || curr().type == TK(":")) { parsing_dict = true; } if(star_level == 2 || curr().type == TK(":")) { parsing_dict = true; }
@ -377,11 +374,10 @@ void Compiler::exprMap() {
} }
match_newlines_repl(); match_newlines_repl();
if(items.size() == 1 && match(TK("for"))) { if(items.size() == 1 && match(TK("for"))) {
if(parsing_dict) { if(parsing_dict)
consume_comp(make_expr<DictCompExpr>(), std::move(items[0])); consume_comp(make_expr<DictCompExpr>(), std::move(items[0]));
} else { else
consume_comp(make_expr<SetCompExpr>(), std::move(items[0])); consume_comp(make_expr<SetCompExpr>(), std::move(items[0]));
}
consume(TK("}")); consume(TK("}"));
return; return;
} }
@ -402,7 +398,7 @@ void Compiler::exprCall() {
e->callable = ctx()->s_expr.popx(); e->callable = ctx()->s_expr.popx();
do { do {
match_newlines_repl(); match_newlines_repl();
if(curr().type == TK(")")) { break; } if(curr().type == TK(")")) break;
if(curr().type == TK("@id") && next().type == TK("=")) { if(curr().type == TK("@id") && next().type == TK("=")) {
consume(TK("@id")); consume(TK("@id"));
Str key = prev().str(); Str key = prev().str();
@ -416,15 +412,15 @@ void Compiler::exprCall() {
e->kwargs.push_back({"**", ctx()->s_expr.popx()}); e->kwargs.push_back({"**", ctx()->s_expr.popx()});
} else { } else {
// positional argument // positional argument
if(!e->kwargs.empty()) { SyntaxError("positional argument follows keyword argument"); } if(!e->kwargs.empty()) SyntaxError("positional argument follows keyword argument");
e->args.push_back(ctx()->s_expr.popx()); e->args.push_back(ctx()->s_expr.popx());
} }
} }
match_newlines_repl(); match_newlines_repl();
} while(match(TK(","))); } while(match(TK(",")));
consume(TK(")")); consume(TK(")"));
if(e->args.size() > 32767) { SyntaxError("too many positional arguments"); } if(e->args.size() > 32767) SyntaxError("too many positional arguments");
if(e->kwargs.size() > 32767) { SyntaxError("too many keyword arguments"); } if(e->kwargs.size() > 32767) SyntaxError("too many keyword arguments");
ctx()->s_expr.push(std::move(e)); ctx()->s_expr.push(std::move(e));
} }
@ -491,13 +487,13 @@ void Compiler::exprSubscr() {
void Compiler::exprLiteral0() { ctx()->s_expr.push(make_expr<Literal0Expr>(prev().type)); } void Compiler::exprLiteral0() { ctx()->s_expr.push(make_expr<Literal0Expr>(prev().type)); }
void Compiler::compile_block_body(void (Compiler::*callback)()) { void Compiler::compile_block_body(void (Compiler::*callback)()) {
if(callback == nullptr) { callback = &Compiler::compile_stmt; } if(callback == nullptr) callback = &Compiler::compile_stmt;
consume(TK(":")); consume(TK(":"));
if(curr().type != TK("@eol") && curr().type != TK("@eof")) { if(curr().type != TK("@eol") && curr().type != TK("@eof")) {
while(true) { while(true) {
compile_stmt(); compile_stmt();
bool possible = curr().type != TK("@eol") && curr().type != TK("@eof"); bool possible = curr().type != TK("@eol") && curr().type != TK("@eof");
if(prev().type != TK(";") || !possible) { break; } if(prev().type != TK(";") || !possible) break;
} }
return; return;
} }
@ -548,9 +544,8 @@ void Compiler::compile_from_import() {
} }
__EAT_DOTS_END: __EAT_DOTS_END:
SStream ss; SStream ss;
for(int i = 0; i < dots; i++) { for(int i = 0; i < dots; i++)
ss << '.'; ss << '.';
}
if(dots > 0) { if(dots > 0) {
// @id is optional if dots > 0 // @id is optional if dots > 0
@ -575,7 +570,7 @@ __EAT_DOTS_END:
consume(TK("import")); consume(TK("import"));
if(match(TK("*"))) { if(match(TK("*"))) {
if(name_scope() != NAME_GLOBAL) { SyntaxError("from <module> import * can only be used in global scope"); } if(name_scope() != NAME_GLOBAL) SyntaxError("from <module> import * can only be used in global scope");
// pop the module and import __all__ // pop the module and import __all__
ctx()->emit_(OP_POP_IMPORT_STAR, BC_NOARG, prev().line); ctx()->emit_(OP_POP_IMPORT_STAR, BC_NOARG, prev().line);
consume_end_stmt(); consume_end_stmt();
@ -663,9 +658,7 @@ void Compiler::compile_for_loop() {
CodeBlock* block = ctx()->enter_block(CodeBlockType::FOR_LOOP); CodeBlock* block = ctx()->enter_block(CodeBlockType::FOR_LOOP);
int for_codei = ctx()->emit_(OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE); int for_codei = ctx()->emit_(OP_FOR_ITER, ctx()->curr_iblock, BC_KEEPLINE);
bool ok = vars->emit_store(ctx()); bool ok = vars->emit_store(ctx());
if(!ok) { if(!ok) SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind
SyntaxError(); // this error occurs in `vars` instead of this line, but...nevermind
}
ctx()->try_merge_for_iter_store(for_codei); ctx()->try_merge_for_iter_store(for_codei);
compile_block_body(); compile_block_body();
ctx()->emit_(OP_LOOP_CONTINUE, ctx()->get_loop(), BC_KEEPLINE, true); ctx()->emit_(OP_LOOP_CONTINUE, ctx()->get_loop(), BC_KEEPLINE, true);
@ -732,9 +725,8 @@ void Compiler::compile_try_except() {
ctx()->emit_(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE); ctx()->emit_(OP_RE_RAISE, BC_NOARG, BC_KEEPLINE);
// no exception or no match, jump to the end // no exception or no match, jump to the end
for(int patch: patches) { for(int patch: patches)
ctx()->patch_jump(patch); ctx()->patch_jump(patch);
}
if(finally_entry != -1) { if(finally_entry != -1) {
i64 target = ctx()->co->codes.size() + 2; i64 target = ctx()->co->codes.size() + 2;
ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE); ctx()->emit_(OP_LOAD_CONST, ctx()->add_const(VAR(target)), BC_KEEPLINE);
@ -748,7 +740,7 @@ void Compiler::compile_decorated() {
do { do {
EXPR(); EXPR();
decorators.push_back(ctx()->s_expr.popx()); decorators.push_back(ctx()->s_expr.popx());
if(!match_newlines_repl()) { SyntaxError(); } if(!match_newlines_repl()) SyntaxError();
} while(match(TK("@"))); } while(match(TK("@")));
if(match(TK("class"))) { if(match(TK("class"))) {
@ -773,8 +765,8 @@ bool Compiler::try_compile_assignment() {
case TK("|="): case TK("|="):
case TK("^="): { case TK("^="): {
Expr* lhs_p = ctx()->s_expr.top().get(); Expr* lhs_p = ctx()->s_expr.top().get();
if(lhs_p->is_starred()) { SyntaxError(); } if(lhs_p->is_starred()) SyntaxError();
if(ctx()->is_compiling_class) { SyntaxError("can't use inplace operator in class definition"); } if(ctx()->is_compiling_class) SyntaxError("can't use inplace operator in class definition");
advance(); advance();
// a[x] += 1; a and x should be evaluated only once // a[x] += 1; a and x should be evaluated only once
// a.x += 1; a should be evaluated only once // a.x += 1; a should be evaluated only once
@ -783,10 +775,10 @@ bool Compiler::try_compile_assignment() {
e->lhs = ctx()->s_expr.popx(); e->lhs = ctx()->s_expr.popx();
EXPR_TUPLE(); EXPR_TUPLE();
e->rhs = ctx()->s_expr.popx(); e->rhs = ctx()->s_expr.popx();
if(e->rhs->is_starred()) { SyntaxError(); } if(e->rhs->is_starred()) SyntaxError();
e->emit_(ctx()); e->emit_(ctx());
bool ok = lhs_p->emit_store_inplace(ctx()); bool ok = lhs_p->emit_store_inplace(ctx());
if(!ok) { SyntaxError(); } if(!ok) SyntaxError();
} }
return true; return true;
case TK("="): { case TK("="): {
@ -798,14 +790,13 @@ bool Compiler::try_compile_assignment() {
// stack size is n+1 // stack size is n+1
Expr_ val = ctx()->s_expr.popx(); Expr_ val = ctx()->s_expr.popx();
val->emit_(ctx()); val->emit_(ctx());
for(int j = 1; j < n; j++) { for(int j = 1; j < n; j++)
ctx()->emit_(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE); ctx()->emit_(OP_DUP_TOP, BC_NOARG, BC_KEEPLINE);
}
for(int j = 0; j < n; j++) { for(int j = 0; j < n; j++) {
auto e = ctx()->s_expr.popx(); auto e = ctx()->s_expr.popx();
if(e->is_starred()) { SyntaxError(); } if(e->is_starred()) SyntaxError();
bool ok = e->emit_store(ctx()); bool ok = e->emit_store(ctx());
if(!ok) { SyntaxError(); } if(!ok) SyntaxError();
} }
} }
return true; return true;
@ -823,24 +814,24 @@ void Compiler::compile_stmt() {
int curr_loop_block = ctx()->get_loop(); int curr_loop_block = ctx()->get_loop();
switch(prev().type) { switch(prev().type) {
case TK("break"): case TK("break"):
if(curr_loop_block < 0) { SyntaxError("'break' outside loop"); } if(curr_loop_block < 0) SyntaxError("'break' outside loop");
ctx()->emit_(OP_LOOP_BREAK, curr_loop_block, kw_line); ctx()->emit_(OP_LOOP_BREAK, curr_loop_block, kw_line);
consume_end_stmt(); consume_end_stmt();
break; break;
case TK("continue"): case TK("continue"):
if(curr_loop_block < 0) { SyntaxError("'continue' not properly in loop"); } if(curr_loop_block < 0) SyntaxError("'continue' not properly in loop");
ctx()->emit_(OP_LOOP_CONTINUE, curr_loop_block, kw_line); ctx()->emit_(OP_LOOP_CONTINUE, curr_loop_block, kw_line);
consume_end_stmt(); consume_end_stmt();
break; break;
case TK("yield"): case TK("yield"):
if(contexts.size() <= 1) { SyntaxError("'yield' outside function"); } if(contexts.size() <= 1) SyntaxError("'yield' outside function");
EXPR_TUPLE(); EXPR_TUPLE();
ctx()->emit_expr(); ctx()->emit_expr();
ctx()->emit_(OP_YIELD_VALUE, BC_NOARG, kw_line); ctx()->emit_(OP_YIELD_VALUE, BC_NOARG, kw_line);
consume_end_stmt(); consume_end_stmt();
break; break;
case TK("yield from"): case TK("yield from"):
if(contexts.size() <= 1) { SyntaxError("'yield from' outside function"); } if(contexts.size() <= 1) SyntaxError("'yield from' outside function");
EXPR_TUPLE(); EXPR_TUPLE();
ctx()->emit_expr(); ctx()->emit_expr();
@ -852,7 +843,7 @@ void Compiler::compile_stmt() {
consume_end_stmt(); consume_end_stmt();
break; break;
case TK("return"): case TK("return"):
if(contexts.size() <= 1) { SyntaxError("'return' outside function"); } if(contexts.size() <= 1) SyntaxError("'return' outside function");
if(match_end_stmt()) { if(match_end_stmt()) {
ctx()->emit_(OP_RETURN_VALUE, 1, kw_line); ctx()->emit_(OP_RETURN_VALUE, 1, kw_line);
} else { } else {
@ -878,7 +869,7 @@ void Compiler::compile_stmt() {
StrName name(prev().sv()); StrName name(prev().sv());
NameScope scope = name_scope(); NameScope scope = name_scope();
bool is_global = ctx()->global_names.contains(name.sv()); bool is_global = ctx()->global_names.contains(name.sv());
if(is_global) { scope = NAME_GLOBAL; } if(is_global) scope = NAME_GLOBAL;
switch(scope) { switch(scope) {
case NAME_LOCAL: ctx()->emit_(OP_INC_FAST, ctx()->add_varname(name), prev().line); break; case NAME_LOCAL: ctx()->emit_(OP_INC_FAST, ctx()->add_varname(name), prev().line); break;
case NAME_GLOBAL: ctx()->emit_(OP_INC_GLOBAL, name.index, prev().line); break; case NAME_GLOBAL: ctx()->emit_(OP_INC_GLOBAL, name.index, prev().line); break;
@ -930,7 +921,7 @@ void Compiler::compile_stmt() {
EXPR_TUPLE(); EXPR_TUPLE();
Expr_ e = ctx()->s_expr.popx(); Expr_ e = ctx()->s_expr.popx();
bool ok = e->emit_del(ctx()); bool ok = e->emit_del(ctx());
if(!ok) { SyntaxError(); } if(!ok) SyntaxError();
consume_end_stmt(); consume_end_stmt();
} break; } break;
case TK("with"): { case TK("with"): {
@ -946,7 +937,7 @@ void Compiler::compile_stmt() {
// [ <expr> <expr>.__enter__() ] // [ <expr> <expr>.__enter__() ]
if(as_name != nullptr) { if(as_name != nullptr) {
bool ok = as_name->emit_store(ctx()); bool ok = as_name->emit_store(ctx());
if(!ok) { SyntaxError(); } if(!ok) SyntaxError();
} else { } else {
ctx()->emit_(OP_POP_TOP, BC_NOARG, BC_KEEPLINE); ctx()->emit_(OP_POP_TOP, BC_NOARG, BC_KEEPLINE);
} }
@ -957,15 +948,15 @@ void Compiler::compile_stmt() {
/*************************************************/ /*************************************************/
case TK("=="): { case TK("=="): {
consume(TK("@id")); consume(TK("@id"));
if(mode() != EXEC_MODE) { SyntaxError("'label' is only available in EXEC_MODE"); } if(mode() != EXEC_MODE) SyntaxError("'label' is only available in EXEC_MODE");
bool ok = ctx()->add_label(prev().str()); bool ok = ctx()->add_label(prev().str());
consume(TK("==")); consume(TK("=="));
if(!ok) { SyntaxError("label " + prev().str().escape() + " already exists"); } if(!ok) SyntaxError("label " + prev().str().escape() + " already exists");
consume_end_stmt(); consume_end_stmt();
} break; } break;
case TK("->"): case TK("->"):
consume(TK("@id")); consume(TK("@id"));
if(mode() != EXEC_MODE) { SyntaxError("'goto' is only available in EXEC_MODE"); } if(mode() != EXEC_MODE) SyntaxError("'goto' is only available in EXEC_MODE");
ctx()->emit_(OP_GOTO, StrName(prev().sv()).index, prev().line); ctx()->emit_(OP_GOTO, StrName(prev().sv()).index, prev().line);
consume_end_stmt(); consume_end_stmt();
break; break;
@ -1060,15 +1051,14 @@ void Compiler::compile_class(const Expr_vector& decorators) {
void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) { void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) {
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
do { do {
if(state > 3) { SyntaxError(); } if(state > 3) SyntaxError();
if(state == 3) { SyntaxError("**kwargs should be the last argument"); } if(state == 3) SyntaxError("**kwargs should be the last argument");
match_newlines(); match_newlines();
if(match(TK("*"))) { if(match(TK("*"))) {
if(state < 1) { if(state < 1)
state = 1; state = 1;
} else { else
SyntaxError("*args should be placed before **kwargs"); SyntaxError("*args should be placed before **kwargs");
}
} else if(match(TK("**"))) { } else if(match(TK("**"))) {
state = 3; state = 3;
} }
@ -1090,8 +1080,8 @@ void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints) {
} }
// eat type hints // eat type hints
if(enable_type_hints && match(TK(":"))) { consume_type_hints(); } if(enable_type_hints && match(TK(":"))) consume_type_hints();
if(state == 0 && curr().type == TK("=")) { state = 2; } if(state == 0 && curr().type == TK("=")) state = 2;
int index = ctx()->add_varname(name); int index = ctx()->add_varname(name);
switch(state) { switch(state) {
case 0: decl->args.push_back(index); break; case 0: decl->args.push_back(index); break;
@ -1122,7 +1112,7 @@ void Compiler::compile_function(const Expr_vector& decorators) {
_compile_f_args(decl, true); _compile_f_args(decl, true);
consume(TK(")")); consume(TK(")"));
} }
if(match(TK("->"))) { consume_type_hints(); } if(match(TK("->"))) consume_type_hints();
compile_block_body(); compile_block_body();
pop_context(); pop_context();
@ -1176,9 +1166,9 @@ PyVar Compiler::read_literal() {
List cpnts; List cpnts;
while(true) { while(true) {
cpnts.push_back(read_literal()); cpnts.push_back(read_literal());
if(curr().type == TK(")")) { break; } if(curr().type == TK(")")) break;
consume(TK(",")); consume(TK(","));
if(curr().type == TK(")")) { break; } if(curr().type == TK(")")) break;
} }
consume(TK(")")); consume(TK(")"));
return VAR(cpnts.to_tuple()); return VAR(cpnts.to_tuple());
@ -1208,9 +1198,8 @@ Str Compiler::precompile() {
if(it == token_indices.end()) { if(it == token_indices.end()) {
token_indices[token.sv()] = 0; token_indices[token.sv()] = 0;
// assert no '\n' in token.sv() // assert no '\n' in token.sv()
for(char c: token.sv()) { for(char c: token.sv())
assert(c != '\n'); assert(c != '\n');
}
} }
} }
} }
@ -1226,16 +1215,14 @@ Str Compiler::precompile() {
const Token& token = tokens[i]; const Token& token = tokens[i];
ss << (int)token.type << ','; ss << (int)token.type << ',';
if(is_raw_string_used(token.type)) { ss << token_indices[token.sv()] << ','; } if(is_raw_string_used(token.type)) { ss << token_indices[token.sv()] << ','; }
if(i > 0 && tokens[i - 1].line == token.line) { if(i > 0 && tokens[i - 1].line == token.line)
ss << ','; ss << ',';
} else { else
ss << token.line << ','; ss << token.line << ',';
} if(i > 0 && tokens[i - 1].brackets_level == token.brackets_level)
if(i > 0 && tokens[i - 1].brackets_level == token.brackets_level) {
ss << ','; ss << ',';
} else { else
ss << token.brackets_level << ','; ss << token.brackets_level << ',';
}
// visit token value // visit token value
std::visit( std::visit(
[&ss](auto&& arg) { [&ss](auto&& arg) {
@ -1246,9 +1233,8 @@ Str Compiler::precompile() {
ss << 'F' << arg; ss << 'F' << arg;
} else if constexpr(std::is_same_v<T, Str>) { } else if constexpr(std::is_same_v<T, Str>) {
ss << 'S'; ss << 'S';
for(char c: arg) { for(char c: arg)
ss.write_hex((unsigned char)c); ss.write_hex((unsigned char)c);
}
} }
ss << '\n'; ss << '\n';
}, },
@ -1334,7 +1320,7 @@ CodeObject_ Compiler::compile() {
} else if(mode() == JSON_MODE) { } else if(mode() == JSON_MODE) {
EXPR(); EXPR();
Expr_ e = ctx()->s_expr.popx(); Expr_ e = ctx()->s_expr.popx();
if(!e->is_json_object()) { SyntaxError("expect a JSON object, literal or array"); } if(!e->is_json_object()) SyntaxError("expect a JSON object, literal or array");
consume(TK("@eof")); consume(TK("@eof"));
e->emit_(ctx()); e->emit_(ctx());
ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE); ctx()->emit_(OP_RETURN_VALUE, BC_NOARG, BC_KEEPLINE);
@ -1360,9 +1346,8 @@ void Lexer::throw_err(StrName type, Str msg, int lineno, const char* cursor) {
std::string_view TokenDeserializer::read_string(char c) { std::string_view TokenDeserializer::read_string(char c) {
const char* start = curr; const char* start = curr;
while(*curr != c) { while(*curr != c)
curr++; curr++;
}
std::string_view retval(start, curr - start); std::string_view retval(start, curr - start);
curr++; // skip the delimiter curr++; // skip the delimiter
return retval; return retval;
@ -1373,21 +1358,19 @@ Str TokenDeserializer::read_string_from_hex(char c) {
char* buffer = (char*)std::malloc(s.size() / 2 + 1); char* buffer = (char*)std::malloc(s.size() / 2 + 1);
for(int i = 0; i < s.size(); i += 2) { for(int i = 0; i < s.size(); i += 2) {
char c = 0; char c = 0;
if(s[i] >= '0' && s[i] <= '9') { if(s[i] >= '0' && s[i] <= '9')
c += s[i] - '0'; c += s[i] - '0';
} else if(s[i] >= 'a' && s[i] <= 'f') { else if(s[i] >= 'a' && s[i] <= 'f')
c += s[i] - 'a' + 10; c += s[i] - 'a' + 10;
} else { else
assert(false); assert(false);
}
c <<= 4; c <<= 4;
if(s[i + 1] >= '0' && s[i + 1] <= '9') { if(s[i + 1] >= '0' && s[i + 1] <= '9')
c += s[i + 1] - '0'; c += s[i + 1] - '0';
} else if(s[i + 1] >= 'a' && s[i + 1] <= 'f') { else if(s[i + 1] >= 'a' && s[i + 1] <= 'f')
c += s[i + 1] - 'a' + 10; c += s[i + 1] - 'a' + 10;
} else { else
assert(false); assert(false);
}
buffer[i / 2] = c; buffer[i / 2] = c;
} }
buffer[s.size() / 2] = 0; buffer[s.size() / 2] = 0;

View File

@ -4,11 +4,10 @@
namespace pkpy { namespace pkpy {
inline bool is_identifier(std::string_view s) { inline bool is_identifier(std::string_view s) {
if(s.empty()) { return false; } if(s.empty()) return false;
if(!isalpha(s[0]) && s[0] != '_') { return false; } if(!isalpha(s[0]) && s[0] != '_') return false;
for(char c: s) { for(char c: s)
if(!isalnum(c) && c != '_') { return false; } if(!isalnum(c) && c != '_') return false;
}
return true; return true;
} }
@ -17,8 +16,8 @@ inline bool is_small_int(i64 value) { return value >= INT16_MIN && value <= INT1
int CodeEmitContext::get_loop() const { int CodeEmitContext::get_loop() const {
int index = curr_iblock; int index = curr_iblock;
while(index >= 0) { while(index >= 0) {
if(co->blocks[index].type == CodeBlockType::FOR_LOOP) { break; } if(co->blocks[index].type == CodeBlockType::FOR_LOOP) break;
if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) { break; } if(co->blocks[index].type == CodeBlockType::WHILE_LOOP) break;
index = co->blocks[index].parent; index = co->blocks[index].parent;
} }
return index; return index;
@ -53,11 +52,10 @@ int CodeEmitContext::emit_(Opcode opcode, uint16_t arg, int line, bool is_virtua
co->lines.push_back(CodeObject::LineInfo{line, is_virtual, curr_iblock}); co->lines.push_back(CodeObject::LineInfo{line, is_virtual, curr_iblock});
int i = co->codes.size() - 1; int i = co->codes.size() - 1;
if(line == BC_KEEPLINE) { if(line == BC_KEEPLINE) {
if(i >= 1) { if(i >= 1)
co->lines[i].lineno = co->lines[i - 1].lineno; co->lines[i].lineno = co->lines[i - 1].lineno;
} else { else
co->lines[i].lineno = 1; co->lines[i].lineno = 1;
}
} }
return i; return i;
} }
@ -69,8 +67,8 @@ void CodeEmitContext::revert_last_emit_() {
void CodeEmitContext::try_merge_for_iter_store(int i) { void CodeEmitContext::try_merge_for_iter_store(int i) {
// [FOR_ITER, STORE_?, ] // [FOR_ITER, STORE_?, ]
if(co->codes[i].op != OP_FOR_ITER) { return; } if(co->codes[i].op != OP_FOR_ITER) return;
if(co->codes.size() - i != 2) { return; } if(co->codes.size() - i != 2) return;
uint16_t arg = co->codes[i + 1].arg; uint16_t arg = co->codes[i + 1].arg;
if(co->codes[i + 1].op == OP_STORE_FAST) { if(co->codes[i + 1].op == OP_STORE_FAST) {
revert_last_emit_(); revert_last_emit_();
@ -100,7 +98,7 @@ void CodeEmitContext::patch_jump(int index) {
} }
bool CodeEmitContext::add_label(StrName name) { bool CodeEmitContext::add_label(StrName name) {
if(co->labels.contains(name)) { return false; } if(co->labels.contains(name)) return false;
co->labels.set(name, co->codes.size()); co->labels.set(name, co->codes.size());
return true; return true;
} }
@ -108,7 +106,7 @@ bool CodeEmitContext::add_label(StrName name) {
int CodeEmitContext::add_varname(StrName name) { int CodeEmitContext::add_varname(StrName name) {
// PK_MAX_CO_VARNAMES will be checked when pop_context(), not here // PK_MAX_CO_VARNAMES will be checked when pop_context(), not here
int index = co->varnames_inv.try_get(name); int index = co->varnames_inv.try_get(name);
if(index >= 0) { return index; } if(index >= 0) return index;
co->varnames.push_back(name); co->varnames.push_back(name);
co->nlocals++; co->nlocals++;
index = co->varnames.size() - 1; index = co->varnames.size() - 1;
@ -170,7 +168,7 @@ void NameExpr::emit_(CodeEmitContext* ctx) {
// exec()/eval() won't work with OP_LOAD_ATTR_GLOBAL in class body // exec()/eval() won't work with OP_LOAD_ATTR_GLOBAL in class body
} else { } else {
// we cannot determine the scope when calling exec()/eval() // we cannot determine the scope when calling exec()/eval()
if(scope == NAME_GLOBAL_UNKNOWN) { op = OP_LOAD_NAME; } if(scope == NAME_GLOBAL_UNKNOWN) op = OP_LOAD_NAME;
} }
ctx->emit_(op, StrName(name).index, line); ctx->emit_(op, StrName(name).index, line);
} }
@ -206,7 +204,7 @@ void StarredExpr::emit_(CodeEmitContext* ctx) {
} }
bool StarredExpr::emit_store(CodeEmitContext* ctx) { bool StarredExpr::emit_store(CodeEmitContext* ctx) {
if(level != 1) { return false; } if(level != 1) return false;
// simply proxy to child // simply proxy to child
return child->emit_store(ctx); return child->emit_store(ctx);
} }
@ -333,12 +331,11 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
// items may contain StarredExpr, we should check it // items may contain StarredExpr, we should check it
int starred_i = -1; int starred_i = -1;
for(int i = 0; i < items.size(); i++) { for(int i = 0; i < items.size(); i++) {
if(!items[i]->is_starred()) { continue; } if(!items[i]->is_starred()) continue;
if(starred_i == -1) { if(starred_i == -1)
starred_i = i; starred_i = i;
} else { else
return false; // multiple StarredExpr not allowed return false; // multiple StarredExpr not allowed
}
} }
if(starred_i == -1) { if(starred_i == -1) {
@ -356,9 +353,9 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
} }
} else { } else {
// starred assignment target must be in a tuple // starred assignment target must be in a tuple
if(items.size() == 1) { return false; } if(items.size() == 1) return false;
// starred assignment target must be the last one (differ from cpython) // starred assignment target must be the last one (differ from cpython)
if(starred_i != items.size() - 1) { return false; } if(starred_i != items.size() - 1) return false;
// a,*b = [1,2,3] // a,*b = [1,2,3]
// stack is [1,2,3] -> [1,[2,3]] // stack is [1,2,3] -> [1,[2,3]]
ctx->emit_(OP_UNPACK_EX, items.size() - 1, line); ctx->emit_(OP_UNPACK_EX, items.size() - 1, line);
@ -366,7 +363,7 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
// do reverse emit // do reverse emit
for(int i = items.size() - 1; i >= 0; i--) { for(int i = items.size() - 1; i >= 0; i--) {
bool ok = items[i]->emit_store(ctx); bool ok = items[i]->emit_store(ctx);
if(!ok) { return false; } if(!ok) return false;
} }
return true; return true;
} }
@ -374,7 +371,7 @@ bool TupleExpr::emit_store(CodeEmitContext* ctx) {
bool TupleExpr::emit_del(CodeEmitContext* ctx) { bool TupleExpr::emit_del(CodeEmitContext* ctx) {
for(auto& e: items) { for(auto& e: items) {
bool ok = e->emit_del(ctx); bool ok = e->emit_del(ctx);
if(!ok) { return false; } if(!ok) return false;
} }
return true; return true;
} }
@ -475,12 +472,11 @@ void FStringExpr::emit_(CodeEmitContext* ctx) {
Str spec = expr.substr(conon + 1); Str spec = expr.substr(conon + 1);
// filter some invalid spec // filter some invalid spec
bool ok = true; bool ok = true;
for(char c: spec) { for(char c: spec)
if(!is_fmt_valid_char(c)) { if(!is_fmt_valid_char(c)) {
ok = false; ok = false;
break; break;
} }
}
if(ok) { if(ok) {
_load_simple_expr(ctx, expr.substr(0, conon)); _load_simple_expr(ctx, expr.substr(0, conon));
ctx->emit_(OP_FORMAT_STRING, ctx->add_const_string(spec.sv()), line); ctx->emit_(OP_FORMAT_STRING, ctx->add_const_string(spec.sv()), line);
@ -522,9 +518,8 @@ void FStringExpr::emit_(CodeEmitContext* ctx) {
} else { } else {
// literal // literal
i = j; i = j;
while(j < src.size && src[j] != '{' && src[j] != '}') { while(j < src.size && src[j] != '{' && src[j] != '}')
j++; j++;
}
Str literal = src.substr(i, j - i); Str literal = src.substr(i, j - i);
ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(literal.sv()), line); ctx->emit_(OP_LOAD_CONST, ctx->add_const_string(literal.sv()), line);
count++; count++;
@ -631,12 +626,10 @@ bool AttribExpr::emit_store_inplace(CodeEmitContext* ctx) {
void CallExpr::emit_(CodeEmitContext* ctx) { void CallExpr::emit_(CodeEmitContext* ctx) {
bool vargs = false; bool vargs = false;
bool vkwargs = false; bool vkwargs = false;
for(auto& arg: args) { for(auto& arg: args)
if(arg->is_starred()) { vargs = true; } if(arg->is_starred()) vargs = true;
} for(auto& item: kwargs)
for(auto& item: kwargs) { if(item.second->is_starred()) vkwargs = true;
if(item.second->is_starred()) { vkwargs = true; }
}
// if callable is a AttrExpr, we should try to use `fast_call` instead of use `boundmethod` proxy // if callable is a AttrExpr, we should try to use `fast_call` instead of use `boundmethod` proxy
if(callable->is_attrib()) { if(callable->is_attrib()) {
@ -648,9 +641,8 @@ void CallExpr::emit_(CodeEmitContext* ctx) {
} }
if(vargs || vkwargs) { if(vargs || vkwargs) {
for(auto& item: args) { for(auto& item: args)
item->emit_(ctx); item->emit_(ctx);
}
ctx->emit_(OP_BUILD_TUPLE_UNPACK, (uint16_t)args.size(), line); ctx->emit_(OP_BUILD_TUPLE_UNPACK, (uint16_t)args.size(), line);
if(!kwargs.empty()) { if(!kwargs.empty()) {
@ -673,9 +665,8 @@ void CallExpr::emit_(CodeEmitContext* ctx) {
} }
} else { } else {
// vectorcall protocol // vectorcall protocol
for(auto& item: args) { for(auto& item: args)
item->emit_(ctx); item->emit_(ctx);
}
for(auto& item: kwargs) { for(auto& item: kwargs) {
i64 _val = StrName(item.first.sv()).index; i64 _val = StrName(item.first.sv()).index;
ctx->emit_int(_val, line); ctx->emit_int(_val, line);
@ -769,9 +760,8 @@ void BinaryExpr::emit_(CodeEmitContext* ctx) {
default: assert(false); default: assert(false);
} }
for(int i: jmps) { for(int i: jmps)
ctx->patch_jump(i); ctx->patch_jump(i);
}
} }
void TernaryExpr::emit_(CodeEmitContext* ctx) { void TernaryExpr::emit_(CodeEmitContext* ctx) {

View File

@ -22,35 +22,32 @@ static bool is_possible_number_char(char c) {
static bool is_unicode_Lo_char(uint32_t c) { static bool is_unicode_Lo_char(uint32_t c) {
// open a hole for carrot // open a hole for carrot
if(c == U'🥕') { return true; } if(c == U'🥕') return true;
auto index = std::lower_bound(kLoRangeA, kLoRangeA + 476, c) - kLoRangeA; auto index = std::lower_bound(kLoRangeA, kLoRangeA + 476, c) - kLoRangeA;
if(c == kLoRangeA[index]) { return true; } if(c == kLoRangeA[index]) return true;
index -= 1; index -= 1;
if(index < 0) { return false; } if(index < 0) return false;
return c >= kLoRangeA[index] && c <= kLoRangeB[index]; return c >= kLoRangeA[index] && c <= kLoRangeB[index];
} }
bool Lexer::match_n_chars(int n, char c0) { bool Lexer::match_n_chars(int n, char c0) {
const char* c = curr_char; const char* c = curr_char;
for(int i = 0; i < n; i++) { for(int i = 0; i < n; i++) {
if(*c == '\0') { return false; } if(*c == '\0') return false;
if(*c != c0) { return false; } if(*c != c0) return false;
c++; c++;
} }
for(int i = 0; i < n; i++) { for(int i = 0; i < n; i++)
eatchar_include_newline(); eatchar_include_newline();
}
return true; return true;
} }
bool Lexer::match_string(const char* s) { bool Lexer::match_string(const char* s) {
int s_len = strlen(s); int s_len = strlen(s);
bool ok = strncmp(curr_char, s, s_len) == 0; bool ok = strncmp(curr_char, s, s_len) == 0;
if(ok) { if(ok)
for(int i = 0; i < s_len; i++) { for(int i = 0; i < s_len; i++)
eatchar_include_newline(); eatchar_include_newline();
}
}
return ok; return ok;
} }
@ -67,10 +64,10 @@ int Lexer::eat_spaces() {
} }
bool Lexer::eat_indentation() { bool Lexer::eat_indentation() {
if(brackets_level > 0) { return true; } if(brackets_level > 0) return true;
int spaces = eat_spaces(); int spaces = eat_spaces();
if(peekchar() == '#') { skip_line_comment(); } if(peekchar() == '#') skip_line_comment();
if(peekchar() == '\0' || peekchar() == '\n') { return true; } if(peekchar() == '\0' || peekchar() == '\n') return true;
// https://docs.python.org/3/reference/lexical_analysis.html#indentation // https://docs.python.org/3/reference/lexical_analysis.html#indentation
if(spaces > indents.top()) { if(spaces > indents.top()) {
indents.push(spaces); indents.push(spaces);
@ -107,7 +104,7 @@ int Lexer::eat_name() {
while(true) { while(true) {
unsigned char c = peekchar(); unsigned char c = peekchar();
int u8bytes = utf8len(c, true); int u8bytes = utf8len(c, true);
if(u8bytes == 0) { return 1; } if(u8bytes == 0) return 1;
if(u8bytes == 1) { if(u8bytes == 1) {
if(isalpha(c) || c == '_' || isdigit(c)) { if(isalpha(c) || c == '_' || isdigit(c)) {
curr_char++; curr_char++;
@ -118,31 +115,29 @@ int Lexer::eat_name() {
} }
// handle multibyte char // handle multibyte char
Str u8str(curr_char, u8bytes); Str u8str(curr_char, u8bytes);
if(u8str.size != u8bytes) { return 2; } if(u8str.size != u8bytes) return 2;
uint32_t value = 0; uint32_t value = 0;
for(int k = 0; k < u8bytes; k++) { for(int k = 0; k < u8bytes; k++) {
uint8_t b = u8str[k]; uint8_t b = u8str[k];
if(k == 0) { if(k == 0) {
if(u8bytes == 2) { if(u8bytes == 2)
value = (b & 0b00011111) << 6; value = (b & 0b00011111) << 6;
} else if(u8bytes == 3) { else if(u8bytes == 3)
value = (b & 0b00001111) << 12; value = (b & 0b00001111) << 12;
} else if(u8bytes == 4) { else if(u8bytes == 4)
value = (b & 0b00000111) << 18; value = (b & 0b00000111) << 18;
}
} else { } else {
value |= (b & 0b00111111) << (6 * (u8bytes - k - 1)); value |= (b & 0b00111111) << (6 * (u8bytes - k - 1));
} }
} }
if(is_unicode_Lo_char(value)) { if(is_unicode_Lo_char(value))
curr_char += u8bytes; curr_char += u8bytes;
} else { else
break; break;
}
} }
int length = (int)(curr_char - token_start); int length = (int)(curr_char - token_start);
if(length == 0) { return 3; } if(length == 0) return 3;
std::string_view name(token_start, length); std::string_view name(token_start, length);
if(src->mode == JSON_MODE) { if(src->mode == JSON_MODE) {
@ -169,13 +164,13 @@ int Lexer::eat_name() {
void Lexer::skip_line_comment() { void Lexer::skip_line_comment() {
char c; char c;
while((c = peekchar()) != '\0') { while((c = peekchar()) != '\0') {
if(c == '\n') { return; } if(c == '\n') return;
eatchar(); eatchar();
} }
} }
bool Lexer::matchchar(char c) { bool Lexer::matchchar(char c) {
if(peekchar() != c) { return false; } if(peekchar() != c) return false;
eatchar_include_newline(); eatchar_include_newline();
return true; return true;
} }
@ -215,11 +210,10 @@ void Lexer::add_token(TokenIndex type, TokenValue value) {
} }
void Lexer::add_token_2(char c, TokenIndex one, TokenIndex two) { void Lexer::add_token_2(char c, TokenIndex one, TokenIndex two) {
if(matchchar(c)) { if(matchchar(c))
add_token(two); add_token(two);
} else { else
add_token(one); add_token(one);
}
} }
Str Lexer::eat_string_until(char quote, bool raw) { Str Lexer::eat_string_until(char quote, bool raw) {
@ -239,9 +233,9 @@ Str Lexer::eat_string_until(char quote, bool raw) {
SyntaxError("EOL while scanning string literal"); SyntaxError("EOL while scanning string literal");
} }
if(c == '\n') { if(c == '\n') {
if(!quote3) { if(!quote3)
SyntaxError("EOL while scanning string literal"); SyntaxError("EOL while scanning string literal");
} else { else {
buff.push_back(c); buff.push_back(c);
continue; continue;
} }
@ -262,7 +256,7 @@ Str Lexer::eat_string_until(char quote, bool raw) {
try { try {
code = (char)std::stoi(hex, &parsed, 16); code = (char)std::stoi(hex, &parsed, 16);
} catch(...) { SyntaxError("invalid hex char"); } } catch(...) { SyntaxError("invalid hex char"); }
if(parsed != 2) { SyntaxError("invalid hex char"); } if(parsed != 2) SyntaxError("invalid hex char");
buff.push_back(code); buff.push_back(code);
} break; } break;
default: SyntaxError("invalid escape char"); default: SyntaxError("invalid escape char");
@ -289,16 +283,14 @@ void Lexer::eat_string(char quote, StringType type) {
void Lexer::eat_number() { void Lexer::eat_number() {
const char* i = token_start; const char* i = token_start;
while(is_possible_number_char(*i)) { while(is_possible_number_char(*i))
i++; i++;
}
bool is_scientific_notation = false; bool is_scientific_notation = false;
if(*(i - 1) == 'e' && (*i == '+' || *i == '-')) { if(*(i - 1) == 'e' && (*i == '+' || *i == '-')) {
i++; i++;
while(isdigit(*i) || *i == 'j') { while(isdigit(*i) || *i == 'j')
i++; i++;
}
is_scientific_notation = true; is_scientific_notation = true;
} }
@ -363,7 +355,7 @@ bool Lexer::lex_one_token() {
// line continuation character // line continuation character
char c = eatchar_include_newline(); char c = eatchar_include_newline();
if(c != '\n') { if(c != '\n') {
if(src->mode == REPL_MODE && c == '\0') { throw NeedMoreLines(false); } if(src->mode == REPL_MODE && c == '\0') throw NeedMoreLines(false);
SyntaxError("expected newline after line continuation character"); SyntaxError("expected newline after line continuation character");
} }
eat_spaces(); eat_spaces();
@ -399,45 +391,41 @@ bool Lexer::lex_one_token() {
} }
return true; return true;
case '>': { case '>': {
if(matchchar('=')) { if(matchchar('='))
add_token(TK(">=")); add_token(TK(">="));
} else if(matchchar('>')) { else if(matchchar('>'))
add_token_2('=', TK(">>"), TK(">>=")); add_token_2('=', TK(">>"), TK(">>="));
} else { else
add_token(TK(">")); add_token(TK(">"));
}
return true; return true;
} }
case '<': { case '<': {
if(matchchar('=')) { if(matchchar('='))
add_token(TK("<=")); add_token(TK("<="));
} else if(matchchar('<')) { else if(matchchar('<'))
add_token_2('=', TK("<<"), TK("<<=")); add_token_2('=', TK("<<"), TK("<<="));
} else { else
add_token(TK("<")); add_token(TK("<"));
}
return true; return true;
} }
case '-': { case '-': {
if(matchchar('-')) { if(matchchar('-')) {
add_token(TK("--")); add_token(TK("--"));
} else { } else {
if(matchchar('=')) { if(matchchar('='))
add_token(TK("-=")); add_token(TK("-="));
} else if(matchchar('>')) { else if(matchchar('>'))
add_token(TK("->")); add_token(TK("->"));
} else { else
add_token(TK("-")); add_token(TK("-"));
}
} }
return true; return true;
} }
case '!': case '!':
if(matchchar('=')) { if(matchchar('='))
add_token(TK("!=")); add_token(TK("!="));
} else { else
SyntaxError("expected '=' after '!'"); SyntaxError("expected '=' after '!'");
}
break; break;
case '*': case '*':
if(matchchar('*')) { if(matchchar('*')) {
@ -457,7 +445,7 @@ bool Lexer::lex_one_token() {
case '\t': eat_spaces(); break; case '\t': eat_spaces(); break;
case '\n': { case '\n': {
add_token(TK("@eol")); add_token(TK("@eol"));
if(!eat_indentation()) { IndentationError("unindent does not match any outer indentation level"); } if(!eat_indentation()) IndentationError("unindent does not match any outer indentation level");
return true; return true;
} }
default: { default: {
@ -541,7 +529,7 @@ vector<Token> Lexer::run() {
} }
constexpr inline bool f_startswith_2(std::string_view t, const char* prefix) { constexpr inline bool f_startswith_2(std::string_view t, const char* prefix) {
if(t.length() < 2) { return false; } if(t.length() < 2) return false;
return t[0] == prefix[0] && t[1] == prefix[1]; return t[0] == prefix[0] && t[1] == prefix[1];
} }
@ -549,25 +537,24 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
*out = 0; *out = 0;
if(base == -1) { if(base == -1) {
if(f_startswith_2(text, "0b")) { if(f_startswith_2(text, "0b"))
base = 2; base = 2;
} else if(f_startswith_2(text, "0o")) { else if(f_startswith_2(text, "0o"))
base = 8; base = 8;
} else if(f_startswith_2(text, "0x")) { else if(f_startswith_2(text, "0x"))
base = 16; base = 16;
} else { else
base = 10; base = 10;
}
} }
if(base == 10) { if(base == 10) {
// 10-base 12334 // 10-base 12334
if(text.length() == 0) { return IntParsingResult::Failure; } if(text.length() == 0) return IntParsingResult::Failure;
for(char c: text) { for(char c: text) {
if(c >= '0' && c <= '9') { if(c >= '0' && c <= '9') {
i64 prev_out = *out; i64 prev_out = *out;
*out = (*out * 10) + (c - '0'); *out = (*out * 10) + (c - '0');
if(*out < prev_out) { return IntParsingResult::Overflow; } if(*out < prev_out) return IntParsingResult::Overflow;
} else { } else {
return IntParsingResult::Failure; return IntParsingResult::Failure;
} }
@ -575,13 +562,13 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
return IntParsingResult::Success; return IntParsingResult::Success;
} else if(base == 2) { } else if(base == 2) {
// 2-base 0b101010 // 2-base 0b101010
if(f_startswith_2(text, "0b")) { text.remove_prefix(2); } if(f_startswith_2(text, "0b")) text.remove_prefix(2);
if(text.length() == 0) { return IntParsingResult::Failure; } if(text.length() == 0) return IntParsingResult::Failure;
for(char c: text) { for(char c: text) {
if(c == '0' || c == '1') { if(c == '0' || c == '1') {
i64 prev_out = *out; i64 prev_out = *out;
*out = (*out << 1) | (c - '0'); *out = (*out << 1) | (c - '0');
if(*out < prev_out) { return IntParsingResult::Overflow; } if(*out < prev_out) return IntParsingResult::Overflow;
} else { } else {
return IntParsingResult::Failure; return IntParsingResult::Failure;
} }
@ -589,13 +576,13 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
return IntParsingResult::Success; return IntParsingResult::Success;
} else if(base == 8) { } else if(base == 8) {
// 8-base 0o123 // 8-base 0o123
if(f_startswith_2(text, "0o")) { text.remove_prefix(2); } if(f_startswith_2(text, "0o")) text.remove_prefix(2);
if(text.length() == 0) { return IntParsingResult::Failure; } if(text.length() == 0) return IntParsingResult::Failure;
for(char c: text) { for(char c: text) {
if(c >= '0' && c <= '7') { if(c >= '0' && c <= '7') {
i64 prev_out = *out; i64 prev_out = *out;
*out = (*out << 3) | (c - '0'); *out = (*out << 3) | (c - '0');
if(*out < prev_out) { return IntParsingResult::Overflow; } if(*out < prev_out) return IntParsingResult::Overflow;
} else { } else {
return IntParsingResult::Failure; return IntParsingResult::Failure;
} }
@ -603,19 +590,19 @@ IntParsingResult parse_uint(std::string_view text, i64* out, int base) {
return IntParsingResult::Success; return IntParsingResult::Success;
} else if(base == 16) { } else if(base == 16) {
// 16-base 0x123 // 16-base 0x123
if(f_startswith_2(text, "0x")) { text.remove_prefix(2); } if(f_startswith_2(text, "0x")) text.remove_prefix(2);
if(text.length() == 0) { return IntParsingResult::Failure; } if(text.length() == 0) return IntParsingResult::Failure;
for(char c: text) { for(char c: text) {
i64 prev_out = *out; i64 prev_out = *out;
if(c >= '0' && c <= '9') { if(c >= '0' && c <= '9') {
*out = (*out << 4) | (c - '0'); *out = (*out << 4) | (c - '0');
if(*out < prev_out) { return IntParsingResult::Overflow; } if(*out < prev_out) return IntParsingResult::Overflow;
} else if(c >= 'a' && c <= 'f') { } else if(c >= 'a' && c <= 'f') {
*out = (*out << 4) | (c - 'a' + 10); *out = (*out << 4) | (c - 'a' + 10);
if(*out < prev_out) { return IntParsingResult::Overflow; } if(*out < prev_out) return IntParsingResult::Overflow;
} else if(c >= 'A' && c <= 'F') { } else if(c >= 'A' && c <= 'F') {
*out = (*out << 4) | (c - 'A' + 10); *out = (*out << 4) | (c - 'A' + 10);
if(*out < prev_out) { return IntParsingResult::Overflow; } if(*out < prev_out) return IntParsingResult::Overflow;
} else { } else {
return IntParsingResult::Failure; return IntParsingResult::Failure;
} }

View File

@ -45,9 +45,8 @@ void VM::__op_unpack_sequence(uint16_t arg) {
// fast path for tuple // fast path for tuple
Tuple& tuple = PK_OBJ_GET(Tuple, _0); Tuple& tuple = PK_OBJ_GET(Tuple, _0);
if(tuple.size() == arg) { if(tuple.size() == arg) {
for(PyVar obj: tuple) { for(PyVar obj: tuple)
PUSH(obj); PUSH(obj);
}
} else { } else {
ValueError(_S("expected ", (int)arg, " values to unpack, got ", (int)tuple.size())); ValueError(_S("expected ", (int)arg, " values to unpack, got ", (int)tuple.size()));
} }
@ -57,10 +56,10 @@ void VM::__op_unpack_sequence(uint16_t arg) {
const PyTypeInfo* ti = _tp_info(_0); const PyTypeInfo* ti = _tp_info(_0);
for(int i = 0; i < arg; i++) { for(int i = 0; i < arg; i++) {
PyVar _1 = _py_next(ti, _0); PyVar _1 = _py_next(ti, _0);
if(_1 == StopIteration) { ValueError("not enough values to unpack"); } if(_1 == StopIteration) ValueError("not enough values to unpack");
PUSH(_1); PUSH(_1);
} }
if(_py_next(ti, _0) != StopIteration) { ValueError("too many values to unpack"); } if(_py_next(ti, _0) != StopIteration) ValueError("too many values to unpack");
} }
} }
@ -168,7 +167,7 @@ PyVar VM::__run_top_frame() {
} }
DISPATCH() DISPATCH()
case OP_PRINT_EXPR: case OP_PRINT_EXPR:
if(TOP() != None) { stdout_write(py_repr(TOP()) + "\n"); } if(TOP() != None) stdout_write(py_repr(TOP()) + "\n");
POP(); POP();
DISPATCH() DISPATCH()
/*****************************************/ /*****************************************/
@ -197,7 +196,7 @@ PyVar VM::__run_top_frame() {
/*****************************************/ /*****************************************/
case OP_LOAD_FAST: { case OP_LOAD_FAST: {
PyVar _0 = frame->_locals[byte.arg]; PyVar _0 = frame->_locals[byte.arg];
if(_0 == PY_NULL) { vm->UnboundLocalError(frame->co->varnames[byte.arg]); } if(_0 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
PUSH(_0); PUSH(_0);
} }
DISPATCH() DISPATCH()
@ -205,7 +204,7 @@ PyVar VM::__run_top_frame() {
StrName _name(byte.arg); StrName _name(byte.arg);
PyVar* slot = frame->_locals.try_get_name(_name); PyVar* slot = frame->_locals.try_get_name(_name);
if(slot != nullptr) { if(slot != nullptr) {
if(*slot == PY_NULL) { vm->UnboundLocalError(_name); } if(*slot == PY_NULL) vm->UnboundLocalError(_name);
PUSH(*slot); PUSH(*slot);
DISPATCH() DISPATCH()
} }
@ -307,7 +306,7 @@ PyVar VM::__run_top_frame() {
DISPATCH() DISPATCH()
case OP_LOAD_SUBSCR_FAST: { case OP_LOAD_SUBSCR_FAST: {
PyVar _1 = frame->_locals[byte.arg]; PyVar _1 = frame->_locals[byte.arg];
if(_1 == PY_NULL) { vm->UnboundLocalError(frame->co->varnames[byte.arg]); } if(_1 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
PyVar _0 = TOP(); // a PyVar _0 = TOP(); // a
auto _ti = _tp_info(_0); auto _ti = _tp_info(_0);
if(_ti->m__getitem__) { if(_ti->m__getitem__) {
@ -372,7 +371,7 @@ PyVar VM::__run_top_frame() {
DISPATCH() DISPATCH()
case OP_STORE_SUBSCR_FAST: { case OP_STORE_SUBSCR_FAST: {
PyVar _2 = frame->_locals[byte.arg]; // b PyVar _2 = frame->_locals[byte.arg]; // b
if(_2 == PY_NULL) { vm->UnboundLocalError(frame->co->varnames[byte.arg]); } if(_2 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
PyVar _1 = POPX(); // a PyVar _1 = POPX(); // a
PyVar _0 = POPX(); // val PyVar _0 = POPX(); // val
auto _ti = _tp_info(_1); auto _ti = _tp_info(_1);
@ -385,7 +384,7 @@ PyVar VM::__run_top_frame() {
DISPATCH() DISPATCH()
case OP_DELETE_FAST: { case OP_DELETE_FAST: {
PyVar _0 = frame->_locals[byte.arg]; PyVar _0 = frame->_locals[byte.arg];
if(_0 == PY_NULL) { vm->UnboundLocalError(frame->co->varnames[byte.arg]); } if(_0 == PY_NULL) vm->UnboundLocalError(frame->co->varnames[byte.arg]);
frame->_locals[byte.arg].set_null(); frame->_locals[byte.arg].set_null();
} }
DISPATCH() DISPATCH()
@ -400,19 +399,19 @@ PyVar VM::__run_top_frame() {
if(func.decl == __dynamic_func_decl) { if(func.decl == __dynamic_func_decl) {
assert(func._closure != nullptr); assert(func._closure != nullptr);
bool ok = func._closure->del(_name); bool ok = func._closure->del(_name);
if(!ok) { vm->NameError(_name); } if(!ok) vm->NameError(_name);
} else { } else {
vm->NameError(_name); vm->NameError(_name);
} }
} }
} else { } else {
if(!frame->f_globals().del(_name)) { vm->NameError(_name); } if(!frame->f_globals().del(_name)) vm->NameError(_name);
} }
} }
DISPATCH() DISPATCH()
case OP_DELETE_GLOBAL: { case OP_DELETE_GLOBAL: {
StrName _name(byte.arg); StrName _name(byte.arg);
if(!frame->f_globals().del(_name)) { vm->NameError(_name); } if(!frame->f_globals().del(_name)) vm->NameError(_name);
} }
DISPATCH() DISPATCH()
case OP_DELETE_ATTR: { case OP_DELETE_ATTR: {
@ -434,13 +433,13 @@ PyVar VM::__run_top_frame() {
/*****************************************/ /*****************************************/
case OP_BUILD_LONG: { case OP_BUILD_LONG: {
PyVar _0 = builtins->attr().try_get_likely_found(pk_id_long); PyVar _0 = builtins->attr().try_get_likely_found(pk_id_long);
if(_0 == nullptr) { AttributeError(builtins, pk_id_long); } if(_0 == nullptr) AttributeError(builtins, pk_id_long);
TOP() = call(_0, TOP()); TOP() = call(_0, TOP());
} }
DISPATCH() DISPATCH()
case OP_BUILD_IMAG: { case OP_BUILD_IMAG: {
PyVar _0 = builtins->attr().try_get_likely_found(pk_id_complex); PyVar _0 = builtins->attr().try_get_likely_found(pk_id_complex);
if(_0 == nullptr) { AttributeError(builtins, pk_id_long); } if(_0 == nullptr) AttributeError(builtins, pk_id_long);
TOP() = call(_0, VAR(0), TOP()); TOP() = call(_0, VAR(0), TOP());
} }
DISPATCH() DISPATCH()
@ -491,9 +490,8 @@ PyVar VM::__run_top_frame() {
case OP_BUILD_STRING: { case OP_BUILD_STRING: {
SStream ss; SStream ss;
ArgsView view = STACK_VIEW(byte.arg); ArgsView view = STACK_VIEW(byte.arg);
for(PyVar obj: view) { for(PyVar obj: view)
ss << py_str(obj); ss << py_str(obj);
}
STACK_SHRINK(byte.arg); STACK_SHRINK(byte.arg);
PUSH(VAR(ss.str())); PUSH(VAR(ss.str()));
} }
@ -562,7 +560,7 @@ PyVar VM::__run_top_frame() {
PyVar _0 = TOP(); PyVar _0 = TOP();
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__truediv__); BINARY_OP_SPECIAL(__truediv__);
if(is_not_implemented(TOP())) { BinaryOptError("/", _0, _1); } if(is_not_implemented(TOP())) BinaryOptError("/", _0, _1);
} }
DISPATCH() DISPATCH()
case OP_BINARY_POW: { case OP_BINARY_POW: {
@ -570,7 +568,7 @@ PyVar VM::__run_top_frame() {
PyVar _0 = TOP(); PyVar _0 = TOP();
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__pow__); BINARY_OP_SPECIAL(__pow__);
if(is_not_implemented(TOP())) { BinaryOptError("**", _0, _1); } if(is_not_implemented(TOP())) BinaryOptError("**", _0, _1);
} }
DISPATCH() DISPATCH()
case OP_BINARY_ADD: { case OP_BINARY_ADD: {
@ -606,7 +604,7 @@ PyVar VM::__run_top_frame() {
PREDICT_INT_DIV_OP(/) PREDICT_INT_DIV_OP(/)
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__floordiv__); BINARY_OP_SPECIAL(__floordiv__);
if(is_not_implemented(TOP())) { BinaryOptError("//", _0, _1); } if(is_not_implemented(TOP())) BinaryOptError("//", _0, _1);
} }
DISPATCH() DISPATCH()
case OP_BINARY_MOD: { case OP_BINARY_MOD: {
@ -615,7 +613,7 @@ PyVar VM::__run_top_frame() {
PREDICT_INT_DIV_OP(%) PREDICT_INT_DIV_OP(%)
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__mod__); BINARY_OP_SPECIAL(__mod__);
if(is_not_implemented(TOP())) { BinaryOptError("%", _0, _1); } if(is_not_implemented(TOP())) BinaryOptError("%", _0, _1);
} }
DISPATCH() DISPATCH()
case OP_COMPARE_LT: { case OP_COMPARE_LT: {
@ -664,7 +662,7 @@ PyVar VM::__run_top_frame() {
PREDICT_INT_OP(<<) PREDICT_INT_OP(<<)
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__lshift__); BINARY_OP_SPECIAL(__lshift__);
if(is_not_implemented(TOP())) { BinaryOptError("<<", _0, _1); } if(is_not_implemented(TOP())) BinaryOptError("<<", _0, _1);
} }
DISPATCH() DISPATCH()
case OP_BITWISE_RSHIFT: { case OP_BITWISE_RSHIFT: {
@ -673,7 +671,7 @@ PyVar VM::__run_top_frame() {
PREDICT_INT_OP(>>) PREDICT_INT_OP(>>)
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__rshift__); BINARY_OP_SPECIAL(__rshift__);
if(is_not_implemented(TOP())) { BinaryOptError(">>", _0, _1); } if(is_not_implemented(TOP())) BinaryOptError(">>", _0, _1);
} }
DISPATCH() DISPATCH()
case OP_BITWISE_AND: { case OP_BITWISE_AND: {
@ -682,7 +680,7 @@ PyVar VM::__run_top_frame() {
PREDICT_INT_OP(&) PREDICT_INT_OP(&)
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__and__); BINARY_OP_SPECIAL(__and__);
if(is_not_implemented(TOP())) { BinaryOptError("&", _0, _1); } if(is_not_implemented(TOP())) BinaryOptError("&", _0, _1);
} }
DISPATCH() DISPATCH()
case OP_BITWISE_OR: { case OP_BITWISE_OR: {
@ -691,7 +689,7 @@ PyVar VM::__run_top_frame() {
PREDICT_INT_OP(|) PREDICT_INT_OP(|)
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__or__); BINARY_OP_SPECIAL(__or__);
if(is_not_implemented(TOP())) { BinaryOptError("|", _0, _1); } if(is_not_implemented(TOP())) BinaryOptError("|", _0, _1);
} }
DISPATCH() DISPATCH()
case OP_BITWISE_XOR: { case OP_BITWISE_XOR: {
@ -700,7 +698,7 @@ PyVar VM::__run_top_frame() {
PREDICT_INT_OP(^) PREDICT_INT_OP(^)
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__xor__); BINARY_OP_SPECIAL(__xor__);
if(is_not_implemented(TOP())) { BinaryOptError("^", _0, _1); } if(is_not_implemented(TOP())) BinaryOptError("^", _0, _1);
} }
DISPATCH() DISPATCH()
case OP_BINARY_MATMUL: { case OP_BINARY_MATMUL: {
@ -708,7 +706,7 @@ PyVar VM::__run_top_frame() {
PyVar _0 = TOP(); PyVar _0 = TOP();
const PyTypeInfo* _ti; const PyTypeInfo* _ti;
BINARY_OP_SPECIAL(__matmul__); BINARY_OP_SPECIAL(__matmul__);
if(is_not_implemented(TOP())) { BinaryOptError("@", _0, _1); } if(is_not_implemented(TOP())) BinaryOptError("@", _0, _1);
} }
DISPATCH() DISPATCH()
@ -744,10 +742,10 @@ PyVar VM::__run_top_frame() {
/*****************************************/ /*****************************************/
case OP_JUMP_FORWARD: DISPATCH_JUMP((int16_t)byte.arg) case OP_JUMP_FORWARD: DISPATCH_JUMP((int16_t)byte.arg)
case OP_POP_JUMP_IF_FALSE: case OP_POP_JUMP_IF_FALSE:
if(!py_bool(POPX())) { DISPATCH_JUMP((int16_t)byte.arg) } if(!py_bool(POPX())) DISPATCH_JUMP((int16_t)byte.arg)
DISPATCH() DISPATCH()
case OP_POP_JUMP_IF_TRUE: case OP_POP_JUMP_IF_TRUE:
if(py_bool(POPX())) { DISPATCH_JUMP((int16_t)byte.arg) } if(py_bool(POPX())) DISPATCH_JUMP((int16_t)byte.arg)
DISPATCH() DISPATCH()
case OP_JUMP_IF_TRUE_OR_POP: case OP_JUMP_IF_TRUE_OR_POP:
if(py_bool(TOP())) { if(py_bool(TOP())) {
@ -783,7 +781,7 @@ PyVar VM::__run_top_frame() {
case OP_GOTO: { case OP_GOTO: {
StrName _name(byte.arg); StrName _name(byte.arg);
int target = frame->co->labels.try_get_likely_found(_name); int target = frame->co->labels.try_get_likely_found(_name);
if(target < 0) { RuntimeError(_S("label ", _name.escape(), " not found")); } if(target < 0) RuntimeError(_S("label ", _name.escape(), " not found"));
frame->prepare_jump_break(&s_data, target); frame->prepare_jump_break(&s_data, target);
DISPATCH_JUMP_ABSOLUTE(target) DISPATCH_JUMP_ABSOLUTE(target)
} }
@ -805,7 +803,7 @@ PyVar VM::__run_top_frame() {
DISPATCH() DISPATCH()
case OP_REPR: TOP() = VAR(py_repr(TOP())); DISPATCH() case OP_REPR: TOP() = VAR(py_repr(TOP())); DISPATCH()
case OP_CALL: { case OP_CALL: {
if(heap._should_auto_collect()) { heap._auto_collect(); } if(heap._should_auto_collect()) heap._auto_collect();
PyVar _0 = vectorcall(byte.arg & 0xFF, // ARGC PyVar _0 = vectorcall(byte.arg & 0xFF, // ARGC
(byte.arg >> 8) & 0xFF, // KWARGC (byte.arg >> 8) & 0xFF, // KWARGC
true); true);
@ -817,7 +815,7 @@ PyVar VM::__run_top_frame() {
} }
DISPATCH() DISPATCH()
case OP_CALL_TP: { case OP_CALL_TP: {
if(heap._should_auto_collect()) { heap._auto_collect(); } if(heap._should_auto_collect()) heap._auto_collect();
PyVar _0; PyVar _0;
PyVar _1; PyVar _1;
PyVar _2; PyVar _2;
@ -825,9 +823,8 @@ PyVar VM::__run_top_frame() {
if(byte.arg) { if(byte.arg) {
_2 = POPX(); _2 = POPX();
_1 = POPX(); _1 = POPX();
for(PyVar obj: _CAST(Tuple&, _1)) { for(PyVar obj: _CAST(Tuple&, _1))
PUSH(obj); PUSH(obj);
}
_CAST(Dict&, _2).apply([this](PyVar k, PyVar v) { _CAST(Dict&, _2).apply([this](PyVar k, PyVar v) {
PUSH(VAR(StrName(CAST(Str&, k)).index)); PUSH(VAR(StrName(CAST(Str&, k)).index));
PUSH(v); PUSH(v);
@ -838,9 +835,8 @@ PyVar VM::__run_top_frame() {
} else { } else {
// no **kwargs // no **kwargs
_1 = POPX(); _1 = POPX();
for(PyVar obj: _CAST(Tuple&, _1)) { for(PyVar obj: _CAST(Tuple&, _1))
PUSH(obj); PUSH(obj);
}
_0 = vectorcall(_CAST(Tuple&, _1).size(), // ARGC _0 = vectorcall(_CAST(Tuple&, _1).size(), // ARGC
0, // KWARGC 0, // KWARGC
true); true);
@ -886,24 +882,22 @@ PyVar VM::__run_top_frame() {
case OP_UNARY_NEGATIVE: TOP() = py_negate(TOP()); DISPATCH() case OP_UNARY_NEGATIVE: TOP() = py_negate(TOP()); DISPATCH()
case OP_UNARY_NOT: { case OP_UNARY_NOT: {
PyVar _0 = TOP(); PyVar _0 = TOP();
if(_0 == True) { if(_0 == True)
TOP() = False; TOP() = False;
} else if(_0 == False) { else if(_0 == False)
TOP() = True; TOP() = True;
} else { else
TOP() = VAR(!py_bool(_0)); TOP() = VAR(!py_bool(_0));
}
} }
DISPATCH() DISPATCH()
case OP_UNARY_STAR: TOP() = VAR(StarWrapper(byte.arg, TOP())); DISPATCH() case OP_UNARY_STAR: TOP() = VAR(StarWrapper(byte.arg, TOP())); DISPATCH()
case OP_UNARY_INVERT: { case OP_UNARY_INVERT: {
PyVar _0; PyVar _0;
auto _ti = _tp_info(TOP()); auto _ti = _tp_info(TOP());
if(_ti->m__invert__) { if(_ti->m__invert__)
_0 = _ti->m__invert__(this, TOP()); _0 = _ti->m__invert__(this, TOP());
} else { else
_0 = call_method(TOP(), __invert__); _0 = call_method(TOP(), __invert__);
}
TOP() = _0; TOP() = _0;
} }
DISPATCH() DISPATCH()
@ -1014,7 +1008,7 @@ PyVar VM::__run_top_frame() {
} else { } else {
for(auto& [name, value]: _0->attr().items()) { for(auto& [name, value]: _0->attr().items()) {
std::string_view s = name.sv(); std::string_view s = name.sv();
if(s.empty() || s[0] == '_') { continue; } if(s.empty() || s[0] == '_') continue;
frame->f_globals().set(name, value); frame->f_globals().set(name, value);
} }
} }
@ -1032,13 +1026,13 @@ PyVar VM::__run_top_frame() {
PyVar _1; PyVar _1;
for(int i = 0; i < byte.arg; i++) { for(int i = 0; i < byte.arg; i++) {
_1 = _py_next(_ti, _0); _1 = _py_next(_ti, _0);
if(_1 == StopIteration) { ValueError("not enough values to unpack"); } if(_1 == StopIteration) ValueError("not enough values to unpack");
PUSH(_1); PUSH(_1);
} }
List extras; List extras;
while(true) { while(true) {
_1 = _py_next(_ti, _0); _1 = _py_next(_ti, _0);
if(_1 == StopIteration) { break; } if(_1 == StopIteration) break;
extras.push_back(_1); extras.push_back(_1);
} }
PUSH(VAR(std::move(extras))); PUSH(VAR(std::move(extras)));
@ -1048,7 +1042,7 @@ PyVar VM::__run_top_frame() {
case OP_BEGIN_CLASS: { case OP_BEGIN_CLASS: {
StrName _name(byte.arg); StrName _name(byte.arg);
PyVar _0 = POPX(); // super PyVar _0 = POPX(); // super
if(_0 == None) { _0 = _t(tp_object); } if(_0 == None) _0 = _t(tp_object);
check_type(_0, tp_type); check_type(_0, tp_type);
__curr_class = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0), true); __curr_class = new_type_object(frame->_module, _name, PK_OBJ_GET(Type, _0), true);
} }
@ -1061,7 +1055,7 @@ PyVar VM::__run_top_frame() {
PyTypeInfo* ti = &_all_types[__curr_class->as<Type>()]; PyTypeInfo* ti = &_all_types[__curr_class->as<Type>()];
if(ti->base != tp_object) { if(ti->base != tp_object) {
PyTypeInfo* base_ti = &_all_types[ti->base]; PyTypeInfo* base_ti = &_all_types[ti->base];
if(base_ti->on_end_subclass) { base_ti->on_end_subclass(this, ti); } if(base_ti->on_end_subclass) base_ti->on_end_subclass(this, ti);
} }
__curr_class = nullptr; __curr_class = nullptr;
} }
@ -1135,27 +1129,27 @@ PyVar VM::__run_top_frame() {
/*****************************************/ /*****************************************/
case OP_INC_FAST: { case OP_INC_FAST: {
PyVar* p = &frame->_locals[byte.arg]; PyVar* p = &frame->_locals[byte.arg];
if(*p == PY_NULL) { vm->NameError(frame->co->varnames[byte.arg]); } if(*p == PY_NULL) vm->NameError(frame->co->varnames[byte.arg]);
*p = VAR(CAST(i64, *p) + 1); *p = VAR(CAST(i64, *p) + 1);
} }
DISPATCH() DISPATCH()
case OP_DEC_FAST: { case OP_DEC_FAST: {
PyVar* p = &frame->_locals[byte.arg]; PyVar* p = &frame->_locals[byte.arg];
if(*p == PY_NULL) { vm->NameError(frame->co->varnames[byte.arg]); } if(*p == PY_NULL) vm->NameError(frame->co->varnames[byte.arg]);
*p = VAR(CAST(i64, *p) - 1); *p = VAR(CAST(i64, *p) - 1);
} }
DISPATCH() DISPATCH()
case OP_INC_GLOBAL: { case OP_INC_GLOBAL: {
StrName _name(byte.arg); StrName _name(byte.arg);
PyVar* p = frame->f_globals().try_get_2_likely_found(_name); PyVar* p = frame->f_globals().try_get_2_likely_found(_name);
if(p == nullptr) { vm->NameError(_name); } if(p == nullptr) vm->NameError(_name);
*p = VAR(CAST(i64, *p) + 1); *p = VAR(CAST(i64, *p) + 1);
} }
DISPATCH() DISPATCH()
case OP_DEC_GLOBAL: { case OP_DEC_GLOBAL: {
StrName _name(byte.arg); StrName _name(byte.arg);
PyVar* p = frame->f_globals().try_get_2_likely_found(_name); PyVar* p = frame->f_globals().try_get_2_likely_found(_name);
if(p == nullptr) { vm->NameError(_name); } if(p == nullptr) vm->NameError(_name);
*p = VAR(CAST(i64, *p) - 1); *p = VAR(CAST(i64, *p) - 1);
} }
DISPATCH() DISPATCH()

View File

@ -46,9 +46,8 @@ void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind_func(type, "hex", 1, [](VM* vm, ArgsView args) { vm->bind_func(type, "hex", 1, [](VM* vm, ArgsView args) {
const Struct& self = _CAST(Struct&, args[0]); const Struct& self = _CAST(Struct&, args[0]);
SStream ss; SStream ss;
for(int i = 0; i < self.size; i++) { for(int i = 0; i < self.size; i++)
ss.write_hex((unsigned char)self.p[i]); ss.write_hex((unsigned char)self.p[i]);
}
return VAR(ss.str()); return VAR(ss.str());
}); });
@ -59,29 +58,27 @@ void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
1, 1,
[](VM* vm, ArgsView args) { [](VM* vm, ArgsView args) {
const Str& s = CAST(Str&, args[0]); const Str& s = CAST(Str&, args[0]);
if(s.size < 2 || s.size % 2 != 0) { vm->ValueError("invalid hex string"); } if(s.size < 2 || s.size % 2 != 0) vm->ValueError("invalid hex string");
Struct buffer(s.size / 2, false); Struct buffer(s.size / 2, false);
for(int i = 0; i < s.size; i += 2) { for(int i = 0; i < s.size; i += 2) {
char c = 0; char c = 0;
if(s[i] >= '0' && s[i] <= '9') { if(s[i] >= '0' && s[i] <= '9')
c += s[i] - '0'; c += s[i] - '0';
} else if(s[i] >= 'A' && s[i] <= 'F') { else if(s[i] >= 'A' && s[i] <= 'F')
c += s[i] - 'A' + 10; c += s[i] - 'A' + 10;
} else if(s[i] >= 'a' && s[i] <= 'f') { else if(s[i] >= 'a' && s[i] <= 'f')
c += s[i] - 'a' + 10; c += s[i] - 'a' + 10;
} else { else
vm->ValueError(_S("invalid hex char: '", s[i], "'")); vm->ValueError(_S("invalid hex char: '", s[i], "'"));
}
c <<= 4; c <<= 4;
if(s[i + 1] >= '0' && s[i + 1] <= '9') { if(s[i + 1] >= '0' && s[i + 1] <= '9')
c += s[i + 1] - '0'; c += s[i + 1] - '0';
} else if(s[i + 1] >= 'A' && s[i + 1] <= 'F') { else if(s[i + 1] >= 'A' && s[i + 1] <= 'F')
c += s[i + 1] - 'A' + 10; c += s[i + 1] - 'A' + 10;
} else if(s[i + 1] >= 'a' && s[i + 1] <= 'f') { else if(s[i + 1] >= 'a' && s[i + 1] <= 'f')
c += s[i + 1] - 'a' + 10; c += s[i + 1] - 'a' + 10;
} else { else
vm->ValueError(_S("invalid hex char: '", s[i + 1], "'")); vm->ValueError(_S("invalid hex char: '", s[i + 1], "'"));
}
buffer.p[i / 2] = c; buffer.p[i / 2] = c;
} }
return vm->new_user_object<Struct>(std::move(buffer)); return vm->new_user_object<Struct>(std::move(buffer));
@ -113,7 +110,7 @@ void Struct::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) { vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar lhs, PyVar rhs) {
Struct& self = _CAST(Struct&, lhs); Struct& self = _CAST(Struct&, lhs);
if(!vm->is_user_type<Struct>(rhs)) { return vm->NotImplemented; } if(!vm->is_user_type<Struct>(rhs)) return vm->NotImplemented;
Struct& other = _CAST(Struct&, rhs); Struct& other = _CAST(Struct&, rhs);
bool ok = self.size == other.size && memcmp(self.p, other.p, self.size) == 0; bool ok = self.size == other.size && memcmp(self.p, other.p, self.size) == 0;
return VAR(ok); return VAR(ok);

View File

@ -6,7 +6,7 @@
namespace pkpy { namespace pkpy {
PyVar* FastLocals::try_get_name(StrName name) { PyVar* FastLocals::try_get_name(StrName name) {
int index = co->varnames_inv.try_get(name); int index = co->varnames_inv.try_get(name);
if(index == -1) { return nullptr; } if(index == -1) return nullptr;
return &a[index]; return &a[index];
} }
@ -14,15 +14,15 @@ NameDict_ FastLocals::to_namedict() {
NameDict_ dict = std::make_shared<NameDict>(); NameDict_ dict = std::make_shared<NameDict>();
co->varnames_inv.apply([&](StrName name, int index) { co->varnames_inv.apply([&](StrName name, int index) {
PyVar value = a[index]; PyVar value = a[index];
if(value) { dict->set(name, value); } if(value) dict->set(name, value);
}); });
return dict; return dict;
} }
PyVar* Frame::f_closure_try_get(StrName name) { PyVar* Frame::f_closure_try_get(StrName name) {
if(_callable == nullptr) { return nullptr; } if(_callable == nullptr) return nullptr;
Function& fn = _callable->as<Function>(); Function& fn = _callable->as<Function>();
if(fn._closure == nullptr) { return nullptr; } if(fn._closure == nullptr) return nullptr;
return fn._closure->try_get_2(name); return fn._closure->try_get_2(name);
} }
@ -30,10 +30,10 @@ int Frame::prepare_jump_exception_handler(ValueStack* _s) {
// try to find a parent try block // try to find a parent try block
int i = co->lines[ip()].iblock; int i = co->lines[ip()].iblock;
while(i >= 0) { while(i >= 0) {
if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) { break; } if(co->blocks[i].type == CodeBlockType::TRY_EXCEPT) break;
i = co->blocks[i].parent; i = co->blocks[i].parent;
} }
if(i < 0) { return -1; } if(i < 0) return -1;
PyVar obj = _s->popx(); // pop exception object PyVar obj = _s->popx(); // pop exception object
UnwindTarget* uw = find_unwind_target(i); UnwindTarget* uw = find_unwind_target(i);
_s->reset(actual_sp_base() + uw->offset); // unwind the stack _s->reset(actual_sp_base() + uw->offset); // unwind the stack
@ -61,9 +61,8 @@ int Frame::_exit_block(ValueStack* _s, int i) {
void Frame::prepare_jump_break(ValueStack* _s, int target) { void Frame::prepare_jump_break(ValueStack* _s, int target) {
int i = co->lines[ip()].iblock; int i = co->lines[ip()].iblock;
if(target >= co->codes.size()) { if(target >= co->codes.size()) {
while(i >= 0) { while(i >= 0)
i = _exit_block(_s, i); i = _exit_block(_s, i);
}
} else { } else {
// BUG (solved) // BUG (solved)
// for i in range(4): // for i in range(4):
@ -71,10 +70,9 @@ void Frame::prepare_jump_break(ValueStack* _s, int target) {
// # if there is no op here, the block check will fail // # if there is no op here, the block check will fail
// while i: --i // while i: --i
int next_block = co->lines[target].iblock; int next_block = co->lines[target].iblock;
while(i >= 0 && i != next_block) { while(i >= 0 && i != next_block)
i = _exit_block(_s, i); i = _exit_block(_s, i);
} if(i != next_block) throw std::runtime_error("invalid jump");
if(i != next_block) { throw std::runtime_error("invalid jump"); }
} }
} }
@ -93,7 +91,7 @@ void Frame::set_unwind_target(PyVar* _sp) {
UnwindTarget* Frame::find_unwind_target(int iblock) { UnwindTarget* Frame::find_unwind_target(int iblock) {
UnwindTarget* p; UnwindTarget* p;
for(p = _uw_list; p != nullptr; p = p->next) { for(p = _uw_list; p != nullptr; p = p->next) {
if(p->iblock == iblock) { return p; } if(p->iblock == iblock) return p;
} }
return nullptr; return nullptr;
} }

View File

@ -13,15 +13,14 @@ int ManagedHeap::sweep() {
#if PK_DEBUG_GC_STATS #if PK_DEBUG_GC_STATS
deleted[obj->type] += 1; deleted[obj->type] += 1;
#endif #endif
if(_gc_on_delete) { _gc_on_delete(vm, obj); } if(_gc_on_delete) _gc_on_delete(vm, obj);
_delete(obj); _delete(obj);
} }
} }
// clear _no_gc marked flag // clear _no_gc marked flag
for(PyObject* obj: _no_gc) { for(PyObject* obj: _no_gc)
obj->gc_marked = false; obj->gc_marked = false;
}
int freed = gen.size() - alive.size(); int freed = gen.size() - alive.size();
@ -40,11 +39,11 @@ int ManagedHeap::sweep() {
void ManagedHeap::_auto_collect() { void ManagedHeap::_auto_collect() {
#if !PK_DEBUG_NO_AUTO_GC #if !PK_DEBUG_NO_AUTO_GC
if(_gc_lock_counter > 0) { return; } if(_gc_lock_counter > 0) return;
gc_counter = 0; gc_counter = 0;
collect(); collect();
gc_threshold = gen.size() * 2; gc_threshold = gen.size() * 2;
if(gc_threshold < PK_GC_MIN_THRESHOLD) { gc_threshold = PK_GC_MIN_THRESHOLD; } if(gc_threshold < PK_GC_MIN_THRESHOLD) gc_threshold = PK_GC_MIN_THRESHOLD;
#endif #endif
} }

View File

@ -3,10 +3,12 @@
namespace pkpy { namespace pkpy {
void RangeIter::_register(VM* vm, PyObject* mod, PyObject* type) { void RangeIter::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
RangeIter& self = PK_OBJ_GET(RangeIter, _0); RangeIter& self = PK_OBJ_GET(RangeIter, _0);
if(self.current >= self.r.stop) { return 0; } if(self.current >= self.r.stop) return 0;
vm->s_data.emplace(VM::tp_int, self.current); vm->s_data.emplace(VM::tp_int, self.current);
self.current += self.r.step; self.current += self.r.step;
return 1; return 1;
@ -14,10 +16,12 @@ void RangeIter::_register(VM* vm, PyObject* mod, PyObject* type) {
} }
void RangeIterR::_register(VM* vm, PyObject* mod, PyObject* type) { void RangeIterR::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
RangeIterR& self = PK_OBJ_GET(RangeIterR, _0); RangeIterR& self = PK_OBJ_GET(RangeIterR, _0);
if(self.current <= self.r.stop) { return 0; } if(self.current <= self.r.stop) return 0;
vm->s_data.emplace(VM::tp_int, self.current); vm->s_data.emplace(VM::tp_int, self.current);
self.current += self.r.step; self.current += self.r.step;
return 1; return 1;
@ -25,21 +29,25 @@ void RangeIterR::_register(VM* vm, PyObject* mod, PyObject* type) {
} }
void ArrayIter::_register(VM* vm, PyObject* mod, PyObject* type) { void ArrayIter::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
ArrayIter& self = _CAST(ArrayIter&, _0); ArrayIter& self = _CAST(ArrayIter&, _0);
if(self.current == self.end) { return 0; } if(self.current == self.end) return 0;
vm->s_data.push(*self.current++); vm->s_data.push(*self.current++);
return 1; return 1;
}); });
} }
void StringIter::_register(VM* vm, PyObject* mod, PyObject* type) { void StringIter::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
StringIter& self = _CAST(StringIter&, _0); StringIter& self = _CAST(StringIter&, _0);
Str& s = PK_OBJ_GET(Str, self.ref); Str& s = PK_OBJ_GET(Str, self.ref);
if(self.i == s.size) { return 0; } if(self.i == s.size) return 0;
int start = self.i; int start = self.i;
int len = utf8len(s.data[self.i]); int len = utf8len(s.data[self.i]);
self.i += len; self.i += len;
@ -49,14 +57,13 @@ void StringIter::_register(VM* vm, PyObject* mod, PyObject* type) {
} }
PyVar Generator::next(VM* vm) { PyVar Generator::next(VM* vm) {
if(state == 2) { return vm->StopIteration; } if(state == 2) return vm->StopIteration;
// reset frame._sp_base // reset frame._sp_base
lf->frame._sp_base = vm->s_data._sp; lf->frame._sp_base = vm->s_data._sp;
lf->frame._locals.a = vm->s_data._sp; lf->frame._locals.a = vm->s_data._sp;
// restore the context // restore the context
for(PyVar obj: s_backup) { for(PyVar obj: s_backup)
vm->s_data.push(obj); vm->s_data.push(obj);
}
// relocate stack objects (their addresses become invalid) // relocate stack objects (their addresses become invalid)
for(PyVar* p = lf->frame.actual_sp_base(); p != vm->s_data.end(); p++) { for(PyVar* p = lf->frame.actual_sp_base(); p != vm->s_data.end(); p++) {
if(p->type == VM::tp_stack_memory) { if(p->type == VM::tp_stack_memory) {
@ -84,9 +91,8 @@ PyVar Generator::next(VM* vm) {
// backup the context // backup the context
lf = vm->callstack.popx(); lf = vm->callstack.popx();
ret = vm->s_data.popx(); ret = vm->s_data.popx();
for(PyVar obj: lf->frame.stack_view(&vm->s_data)) { for(PyVar obj: lf->frame.stack_view(&vm->s_data))
s_backup.push_back(obj); s_backup.push_back(obj);
}
vm->s_data.reset(lf->frame._sp_base); vm->s_data.reset(lf->frame._sp_base);
// TODO: should we add this snippet here? // TODO: should we add this snippet here?
// #if PK_ENABLE_PROFILER // #if PK_ENABLE_PROFILER
@ -95,7 +101,7 @@ PyVar Generator::next(VM* vm) {
// } // }
// #endif // #endif
state = 1; state = 1;
if(ret == vm->StopIteration) { state = 2; } if(ret == vm->StopIteration) state = 2;
return ret; return ret;
} else { } else {
state = 2; state = 2;
@ -104,22 +110,26 @@ PyVar Generator::next(VM* vm) {
} }
void Generator::_register(VM* vm, PyObject* mod, PyObject* type) { void Generator::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
Generator& self = _CAST(Generator&, _0); Generator& self = _CAST(Generator&, _0);
PyVar retval = self.next(vm); PyVar retval = self.next(vm);
if(retval == vm->StopIteration) { return 0; } if(retval == vm->StopIteration) return 0;
vm->s_data.push(retval); vm->s_data.push(retval);
return 1; return 1;
}); });
} }
void DictItemsIter::_register(VM* vm, PyObject* mod, PyObject* type) { void DictItemsIter::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
DictItemsIter& self = _CAST(DictItemsIter&, _0); DictItemsIter& self = _CAST(DictItemsIter&, _0);
Dict& d = PK_OBJ_GET(Dict, self.ref); Dict& d = PK_OBJ_GET(Dict, self.ref);
if(self.i == -1) { return 0; } if(self.i == -1) return 0;
vm->s_data.push(d._items[self.i].first); vm->s_data.push(d._items[self.i].first);
vm->s_data.push(d._items[self.i].second); vm->s_data.push(d._items[self.i].second);
self.i = d._items[self.i].next; self.i = d._items[self.i].next;

View File

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

View File

@ -23,7 +23,7 @@ struct JsonSerializer {
void write_array(T& arr) { void write_array(T& arr) {
ss << '['; ss << '[';
for(int i = 0; i < arr.size(); i++) { for(int i = 0; i < arr.size(); i++) {
if(i != 0) { ss << ", "; } if(i != 0) ss << ", ";
write_object(arr[i]); write_object(arr[i]);
} }
ss << ']'; ss << ']';
@ -33,7 +33,7 @@ struct JsonSerializer {
ss << '{'; ss << '{';
bool first = true; bool first = true;
dict.apply([&](PyVar k, PyVar v) { dict.apply([&](PyVar k, PyVar v) {
if(!first) { ss << ", "; } if(!first) ss << ", ";
first = false; first = false;
if(!is_type(k, VM::tp_str)) { if(!is_type(k, VM::tp_str)) {
vm->TypeError(_S("json keys must be string, got ", _type_name(vm, vm->_tp(k)))); vm->TypeError(_S("json keys must be string, got ", _type_name(vm, vm->_tp(k))));
@ -52,7 +52,7 @@ struct JsonSerializer {
ss << _CAST(i64, obj); ss << _CAST(i64, obj);
} else if(obj_t == vm->tp_float) { } else if(obj_t == vm->tp_float) {
f64 val = _CAST(f64, obj); f64 val = _CAST(f64, obj);
if(std::isinf(val) || std::isnan(val)) { vm->ValueError("cannot jsonify 'nan' or 'inf'"); } if(std::isinf(val) || std::isnan(val)) vm->ValueError("cannot jsonify 'nan' or 'inf'");
ss << val; ss << val;
} else if(obj_t == vm->tp_bool) { } else if(obj_t == vm->tp_bool) {
ss << (obj == vm->True ? "true" : "false"); ss << (obj == vm->True ? "true" : "false");
@ -80,18 +80,24 @@ VM::VM(bool enable_os) : heap(this), enable_os(enable_os) {
this->vm = this; this->vm = this;
this->__c.error = nullptr; this->__c.error = nullptr;
_ceval_on_step = nullptr; _ceval_on_step = nullptr;
_stdout = [](const char* buf, int size) { std::cout.write(buf, size); }; _stdout = [](const char* buf, int size) {
_stderr = [](const char* buf, int size) { std::cerr.write(buf, size); }; std::cout.write(buf, size);
};
_stderr = [](const char* buf, int size) {
std::cerr.write(buf, size);
};
builtins = nullptr; builtins = nullptr;
_main = nullptr; _main = nullptr;
__last_exception = nullptr; __last_exception = nullptr;
_import_handler = [](const char* name, int* out_size) -> unsigned char* { return nullptr; }; _import_handler = [](const char* name, int* out_size) -> unsigned char* {
return nullptr;
};
__init_builtin_types(); __init_builtin_types();
} }
Str VM::py_str(PyVar obj) { Str VM::py_str(PyVar obj) {
const PyTypeInfo* ti = _tp_info(obj); const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__str__) { return ti->m__str__(this, obj); } if(ti->m__str__) return ti->m__str__(this, obj);
PyVar self; PyVar self;
PyVar f = get_unbound_method(obj, __str__, &self, false); PyVar f = get_unbound_method(obj, __str__, &self, false);
if(self != PY_NULL) { if(self != PY_NULL) {
@ -104,7 +110,7 @@ Str VM::py_str(PyVar obj) {
Str VM::py_repr(PyVar obj) { Str VM::py_repr(PyVar obj) {
const PyTypeInfo* ti = _tp_info(obj); const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__repr__) { return ti->m__repr__(this, obj); } if(ti->m__repr__) return ti->m__repr__(this, obj);
PyVar retval = call_method(obj, __repr__); PyVar retval = call_method(obj, __repr__);
if(!is_type(retval, tp_str)) { throw std::runtime_error("object.__repr__ must return str"); } if(!is_type(retval, tp_str)) { throw std::runtime_error("object.__repr__ must return str"); }
return PK_OBJ_GET(Str, retval); return PK_OBJ_GET(Str, retval);
@ -117,10 +123,10 @@ Str VM::py_json(PyVar obj) {
PyVar VM::py_iter(PyVar obj) { PyVar VM::py_iter(PyVar obj) {
const PyTypeInfo* ti = _tp_info(obj); const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__iter__) { return ti->m__iter__(this, obj); } if(ti->m__iter__) return ti->m__iter__(this, obj);
PyVar self; PyVar self;
PyVar iter_f = get_unbound_method(obj, __iter__, &self, false); PyVar iter_f = get_unbound_method(obj, __iter__, &self, false);
if(self != PY_NULL) { return call_method(self, iter_f); } if(self != PY_NULL) return call_method(self, iter_f);
TypeError(_type_name(vm, _tp(obj)).escape() + " object is not iterable"); TypeError(_type_name(vm, _tp(obj)).escape() + " object is not iterable");
return nullptr; return nullptr;
} }
@ -139,9 +145,8 @@ ArgsView VM::cast_array_view(PyVar obj) {
void VM::set_main_argv(int argc, char** argv) { void VM::set_main_argv(int argc, char** argv) {
PyVar mod = vm->_modules["sys"]; PyVar mod = vm->_modules["sys"];
List argv_(argc); List argv_(argc);
for(int i = 0; i < argc; i++) { for(int i = 0; i < argc; i++)
argv_[i] = VAR(std::string_view(argv[i])); argv_[i] = VAR(std::string_view(argv[i]));
}
mod->attr().set("argv", VAR(std::move(argv_))); mod->attr().set("argv", VAR(std::move(argv_)));
} }
@ -149,9 +154,9 @@ PyVar* VM::find_name_in_mro(Type cls, StrName name) {
PyVar* val; PyVar* val;
do { do {
val = _t(cls)->attr().try_get_2(name); val = _t(cls)->attr().try_get_2(name);
if(val != nullptr) { return val; } if(val != nullptr) return val;
cls = _all_types[cls].base; cls = _all_types[cls].base;
if(!cls) { break; } if(!cls) break;
} while(true); } while(true);
return nullptr; return nullptr;
} }
@ -160,16 +165,16 @@ bool VM::isinstance(PyVar obj, Type base) { return issubclass(_tp(obj), base); }
bool VM::issubclass(Type cls, Type base) { bool VM::issubclass(Type cls, Type base) {
do { do {
if(cls == base) { return true; } if(cls == base) return true;
Type next = _all_types[cls].base; Type next = _all_types[cls].base;
if(!next) { break; } if(!next) break;
cls = next; cls = next;
} while(true); } while(true);
return false; return false;
} }
PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module) { PyVar VM::exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module) {
if(_module == nullptr) { _module = _main; } if(_module == nullptr) _module = _main;
try { try {
#if PK_DEBUG_PRECOMPILED_EXEC == 1 #if PK_DEBUG_PRECOMPILED_EXEC == 1
Str precompiled = vm->precompile(source, filename, mode); Str precompiled = vm->precompile(source, filename, mode);
@ -215,23 +220,23 @@ PyObject* VM::new_type_object(PyObject* mod, StrName name, Type base, bool subcl
} }
bool VM::py_eq(PyVar lhs, PyVar rhs) { bool VM::py_eq(PyVar lhs, PyVar rhs) {
if(is_int(lhs) && is_int(rhs)) { return lhs.as<i64>() == rhs.as<i64>(); } if(is_int(lhs) && is_int(rhs)) return lhs.as<i64>() == rhs.as<i64>();
const PyTypeInfo* ti = _tp_info(lhs); const PyTypeInfo* ti = _tp_info(lhs);
PyVar res; PyVar res;
if(ti->m__eq__) { if(ti->m__eq__) {
res = ti->m__eq__(this, lhs, rhs); res = ti->m__eq__(this, lhs, rhs);
if(!is_not_implemented(res)) { return res == vm->True; } if(!is_not_implemented(res)) return res == vm->True;
} }
res = call_method(lhs, __eq__, rhs); res = call_method(lhs, __eq__, rhs);
if(!is_not_implemented(res)) { return res == vm->True; } if(!is_not_implemented(res)) return res == vm->True;
ti = _tp_info(rhs); ti = _tp_info(rhs);
if(ti->m__eq__) { if(ti->m__eq__) {
res = ti->m__eq__(this, rhs, lhs); res = ti->m__eq__(this, rhs, lhs);
if(!is_not_implemented(res)) { return res == vm->True; } if(!is_not_implemented(res)) return res == vm->True;
} }
res = call_method(rhs, __eq__, lhs); res = call_method(rhs, __eq__, lhs);
if(!is_not_implemented(res)) { return res == vm->True; } if(!is_not_implemented(res)) return res == vm->True;
return false; return false;
} }
@ -248,7 +253,7 @@ PyVar VM::py_op(std::string_view name) {
} }
i64 VM::normalized_index(i64 index, int size) { i64 VM::normalized_index(i64 index, int size) {
if(index < 0) { index += size; } if(index < 0) index += size;
if(index < 0 || index >= size) { IndexError(std::to_string(index) + " not in [0, " + std::to_string(size) + ")"); } if(index < 0 || index >= size) { IndexError(std::to_string(index) + " not in [0, " + std::to_string(size) + ")"); }
return index; return index;
} }
@ -287,7 +292,7 @@ PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) {
return (this->*op)(a, b) ? a : b; return (this->*op)(a, b) ? a : b;
} }
if(args_tuple.size() == 0) { TypeError("expected at least 1 argument, got 0"); } if(args_tuple.size() == 0) TypeError("expected at least 1 argument, got 0");
ArgsView view(nullptr, nullptr); ArgsView view(nullptr, nullptr);
if(args_tuple.size() == 1) { if(args_tuple.size() == 1) {
@ -296,30 +301,30 @@ PyVar VM::__minmax_reduce(bool (VM::*op)(PyVar, PyVar), PyVar args, PyVar key) {
view = ArgsView(args_tuple); view = ArgsView(args_tuple);
} }
if(view.empty()) { ValueError("arg is an empty sequence"); } if(view.empty()) ValueError("arg is an empty sequence");
PyVar res = view[0]; PyVar res = view[0];
if(key == vm->None) { if(key == vm->None) {
for(int i = 1; i < view.size(); i++) { for(int i = 1; i < view.size(); i++) {
if((this->*op)(view[i], res)) { res = view[i]; } if((this->*op)(view[i], res)) res = view[i];
} }
} else { } else {
auto _lock = heap.gc_scope_lock(); auto _lock = heap.gc_scope_lock();
for(int i = 1; i < view.size(); i++) { for(int i = 1; i < view.size(); i++) {
PyVar a = call(key, view[i]); PyVar a = call(key, view[i]);
PyVar b = call(key, res); PyVar b = call(key, res);
if((this->*op)(a, b)) { res = view[i]; } if((this->*op)(a, b)) res = view[i];
} }
} }
return res; return res;
} }
PyObject* VM::py_import(Str path, bool throw_err) { PyObject* VM::py_import(Str path, bool throw_err) {
if(path.empty()) { vm->ValueError("empty module name"); } if(path.empty()) vm->ValueError("empty module name");
static auto f_join = [](const vector<std::string_view>& cpnts) { static auto f_join = [](const vector<std::string_view>& cpnts) {
SStream ss; SStream ss;
for(int i = 0; i < cpnts.size(); i++) { for(int i = 0; i < cpnts.size(); i++) {
if(i != 0) { ss << "."; } if(i != 0) ss << ".";
ss << cpnts[i]; ss << cpnts[i];
} }
return ss.str(); return ss.str();
@ -333,18 +338,16 @@ PyObject* VM::py_import(Str path, bool throw_err) {
vector<std::string_view> cpnts = curr_path.split('.'); vector<std::string_view> cpnts = curr_path.split('.');
int prefix = 0; // how many dots in the prefix int prefix = 0; // how many dots in the prefix
for(int i = 0; i < path.length(); i++) { for(int i = 0; i < path.length(); i++) {
if(path[i] == '.') { if(path[i] == '.')
prefix++; prefix++;
} else { else
break; break;
}
} }
if(prefix > cpnts.size()) { ImportError("attempted relative import beyond top-level package"); } if(prefix > cpnts.size()) ImportError("attempted relative import beyond top-level package");
path = path.substr(prefix); // remove prefix path = path.substr(prefix); // remove prefix
for(int i = (int)curr_is_init; i < prefix; i++) { for(int i = (int)curr_is_init; i < prefix; i++)
cpnts.pop_back(); cpnts.pop_back();
} if(!path.empty()) cpnts.push_back(path.sv());
if(!path.empty()) { cpnts.push_back(path.sv()); }
path = f_join(cpnts); path = f_join(cpnts);
} }
@ -353,7 +356,7 @@ PyObject* VM::py_import(Str path, bool throw_err) {
// check existing module // check existing module
StrName name(path); StrName name(path);
PyVar ext_mod = _modules.try_get(name); PyVar ext_mod = _modules.try_get(name);
if(ext_mod != nullptr) { return ext_mod.get(); } if(ext_mod != nullptr) return ext_mod.get();
vector<std::string_view> path_cpnts = path.split('.'); vector<std::string_view> path_cpnts = path.split('.');
// check circular import // check circular import
@ -373,11 +376,10 @@ PyObject* VM::py_import(Str path, bool throw_err) {
out = _import_handler(filename.c_str(), &out_size); out = _import_handler(filename.c_str(), &out_size);
} }
if(out == nullptr) { if(out == nullptr) {
if(throw_err) { if(throw_err)
ImportError(_S("module ", path.escape(), " not found")); ImportError(_S("module ", path.escape(), " not found"));
} else { else
return nullptr; return nullptr;
}
} }
assert(out_size >= 0); assert(out_size >= 0);
source = Str(std::string_view((char*)out, out_size)); source = Str(std::string_view((char*)out, out_size));
@ -398,12 +400,10 @@ PyObject* VM::py_import(Str path, bool throw_err) {
VM::~VM() { VM::~VM() {
// clear managed heap // clear managed heap
for(PyObject* obj: heap.gen) { for(PyObject* obj: heap.gen)
heap._delete(obj); heap._delete(obj);
} for(PyObject* obj: heap._no_gc)
for(PyObject* obj: heap._no_gc) {
heap._delete(obj); heap._delete(obj);
}
// clear everything // clear everything
callstack.clear(); callstack.clear();
s_data.clear(); s_data.clear();
@ -414,14 +414,14 @@ VM::~VM() {
PyVar VM::py_negate(PyVar obj) { PyVar VM::py_negate(PyVar obj) {
const PyTypeInfo* ti = _tp_info(obj); const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__neg__) { return ti->m__neg__(this, obj); } if(ti->m__neg__) return ti->m__neg__(this, obj);
return call_method(obj, __neg__); return call_method(obj, __neg__);
} }
bool VM::__py_bool_non_trivial(PyVar obj) { bool VM::__py_bool_non_trivial(PyVar obj) {
if(obj == None) { return false; } if(obj == None) return false;
if(is_int(obj)) { return _CAST(i64, obj) != 0; } if(is_int(obj)) return _CAST(i64, obj) != 0;
if(is_float(obj)) { return _CAST(f64, obj) != 0.0; } if(is_float(obj)) return _CAST(f64, obj) != 0.0;
PyVar self; PyVar self;
PyVar len_f = get_unbound_method(obj, __len__, &self, false); PyVar len_f = get_unbound_method(obj, __len__, &self, false);
if(self != PY_NULL) { if(self != PY_NULL) {
@ -432,13 +432,13 @@ bool VM::__py_bool_non_trivial(PyVar obj) {
} }
void VM::__obj_gc_mark(PyObject* obj) { void VM::__obj_gc_mark(PyObject* obj) {
if(obj->gc_marked) { return; } if(obj->gc_marked) return;
obj->gc_marked = true; obj->gc_marked = true;
const PyTypeInfo* ti = _tp_info(obj->type); const PyTypeInfo* ti = _tp_info(obj->type);
if(ti->vt._gc_mark) { ti->vt._gc_mark(obj->_value_ptr(), this); } if(ti->vt._gc_mark) ti->vt._gc_mark(obj->_value_ptr(), this);
if(obj->is_attr_valid()) { if(obj->is_attr_valid()) {
obj->attr().apply([this](StrName _, PyVar obj) { obj->attr().apply([this](StrName _, PyVar obj) {
if(obj.is_ptr) { vm->__obj_gc_mark((obj).get()); } if(obj.is_ptr) vm->__obj_gc_mark((obj).get());
}); });
} }
} }
@ -451,7 +451,7 @@ void VM::__stack_gc_mark(PyVar* begin, PyVar* end) {
if(it->type == tp_stack_memory) { if(it->type == tp_stack_memory) {
// [sm:3, _0, _1, _2, sm:-3] // [sm:3, _0, _1, _2, sm:-3]
int count = it->as<StackMemory>().count; int count = it->as<StackMemory>().count;
if(count > 0) { it += count; } if(count > 0) it += count;
} }
} }
} }
@ -481,29 +481,28 @@ List VM::py_list(PyVar it) {
void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step) { void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step) {
auto clip = [](int value, int min, int max) { auto clip = [](int value, int min, int max) {
if(value < min) { return min; } if(value < min) return min;
if(value > max) { return max; } if(value > max) return max;
return value; return value;
}; };
if(s.step == None) { if(s.step == None)
step = 1; step = 1;
} else { else
step = CAST(int, s.step); step = CAST(int, s.step);
} if(step == 0) ValueError("slice step cannot be zero");
if(step == 0) { ValueError("slice step cannot be zero"); }
if(step > 0) { if(step > 0) {
if(s.start == None) { if(s.start == None) {
start = 0; start = 0;
} else { } else {
start = CAST(int, s.start); start = CAST(int, s.start);
if(start < 0) { start += length; } if(start < 0) start += length;
start = clip(start, 0, length); start = clip(start, 0, length);
} }
if(s.stop == None) { if(s.stop == None) {
stop = length; stop = length;
} else { } else {
stop = CAST(int, s.stop); stop = CAST(int, s.stop);
if(stop < 0) { stop += length; } if(stop < 0) stop += length;
stop = clip(stop, 0, length); stop = clip(stop, 0, length);
} }
} else { } else {
@ -511,14 +510,14 @@ void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int&
start = length - 1; start = length - 1;
} else { } else {
start = CAST(int, s.start); start = CAST(int, s.start);
if(start < 0) { start += length; } if(start < 0) start += length;
start = clip(start, -1, length - 1); start = clip(start, -1, length - 1);
} }
if(s.stop == None) { if(s.stop == None) {
stop = -1; stop = -1;
} else { } else {
stop = CAST(int, s.stop); stop = CAST(int, s.stop);
if(stop < 0) { stop += length; } if(stop < 0) stop += length;
stop = clip(stop, -1, length - 1); stop = clip(stop, -1, length - 1);
} }
} }
@ -527,7 +526,7 @@ void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int&
i64 VM::py_hash(PyVar obj) { i64 VM::py_hash(PyVar obj) {
// https://docs.python.org/3.10/reference/datamodel.html#object.__hash__ // https://docs.python.org/3.10/reference/datamodel.html#object.__hash__
const PyTypeInfo* ti = _tp_info(obj); const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__hash__) { return ti->m__hash__(this, obj); } if(ti->m__hash__) return ti->m__hash__(this, obj);
PyVar self; PyVar self;
PyVar f = get_unbound_method(obj, __hash__, &self, false); PyVar f = get_unbound_method(obj, __hash__, &self, false);
@ -536,12 +535,12 @@ i64 VM::py_hash(PyVar obj) {
return CAST(i64, ret); return CAST(i64, ret);
} }
// if it is trivial `object`, return PK_BITS // if it is trivial `object`, return PK_BITS
if(ti == &_all_types[tp_object]) { return obj.hash(); } if(ti == &_all_types[tp_object]) return obj.hash();
// otherwise, we check if it has a custom __eq__ other than object.__eq__ // otherwise, we check if it has a custom __eq__ other than object.__eq__
bool has_custom_eq = false; bool has_custom_eq = false;
if(ti->m__eq__) { if(ti->m__eq__)
has_custom_eq = true; has_custom_eq = true;
} else { else {
f = get_unbound_method(obj, __eq__, &self, false); f = get_unbound_method(obj, __eq__, &self, false);
has_custom_eq = f != _t(tp_object)->attr(__eq__); has_custom_eq = f != _t(tp_object)->attr(__eq__);
} }
@ -579,7 +578,9 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local
globals_obj = new_object<DummyInstance>(VM::tp_object).get(); globals_obj = new_object<DummyInstance>(VM::tp_object).get();
globals_obj->_attr = new NameDict(); globals_obj->_attr = new NameDict();
globals_dict = &PK_OBJ_GET(Dict, globals); globals_dict = &PK_OBJ_GET(Dict, globals);
globals_dict->apply([&](PyVar k, PyVar v) { globals_obj->attr().set(CAST(Str&, k), v); }); globals_dict->apply([&](PyVar k, PyVar v) {
globals_obj->attr().set(CAST(Str&, k), v);
});
} }
} }
@ -591,7 +592,9 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local
check_compatible_type(locals, VM::tp_dict); check_compatible_type(locals, VM::tp_dict);
locals_dict = &PK_OBJ_GET(Dict, locals); locals_dict = &PK_OBJ_GET(Dict, locals);
locals_closure = std::make_shared<NameDict>(); locals_closure = std::make_shared<NameDict>();
locals_dict->apply([&](PyVar k, PyVar v) { locals_closure->set(CAST(Str&, k), v); }); locals_dict->apply([&](PyVar k, PyVar v) {
locals_closure->set(CAST(Str&, k), v);
});
PyObject* _callable = PyObject* _callable =
heap.gcnew<Function>(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure); heap.gcnew<Function>(tp_function, __dynamic_func_decl, globals_obj, nullptr, locals_closure);
retval = vm->_exec(code.get(), globals_obj, _callable, vm->s_data._sp); retval = vm->_exec(code.get(), globals_obj, _callable, vm->s_data._sp);
@ -599,12 +602,16 @@ PyVar VM::__py_exec_internal(const CodeObject_& code, PyVar globals, PyVar local
if(globals_dict) { if(globals_dict) {
globals_dict->clear(); globals_dict->clear();
globals_obj->attr().apply([&](StrName k, PyVar v) { globals_dict->set(vm, VAR(k.sv()), v); }); globals_obj->attr().apply([&](StrName k, PyVar v) {
globals_dict->set(vm, VAR(k.sv()), v);
});
} }
if(locals_dict) { if(locals_dict) {
locals_dict->clear(); locals_dict->clear();
locals_closure->apply([&](StrName k, PyVar v) { locals_dict->set(vm, VAR(k.sv()), v); }); locals_closure->apply([&](StrName k, PyVar v) {
locals_dict->set(vm, VAR(k.sv()), v);
});
} }
return retval; return retval;
} }
@ -620,7 +627,7 @@ PyVar VM::py_eval(std::string_view source, PyVar globals, PyVar locals) {
} }
PyVar VM::__format_object(PyVar obj, Str spec) { PyVar VM::__format_object(PyVar obj, Str spec) {
if(spec.empty()) { return VAR(py_str(obj)); } if(spec.empty()) return VAR(py_str(obj));
char type; char type;
switch(spec.end()[-1]) { switch(spec.end()[-1]) {
case 'f': case 'f':
@ -651,11 +658,10 @@ PyVar VM::__format_object(PyVar obj, Str spec) {
align = '<'; align = '<';
spec = spec.substr(1); spec = spec.substr(1);
} else { } else {
if(is_int(obj) || is_float(obj)) { if(is_int(obj) || is_float(obj))
align = '>'; align = '>';
} else { else
align = '<'; align = '<';
}
} }
int dot = spec.index("."); int dot = spec.index(".");
@ -674,11 +680,11 @@ PyVar VM::__format_object(PyVar obj, Str spec) {
} }
} catch(...) { ValueError("invalid format specifer"); } } catch(...) { ValueError("invalid format specifer"); }
if(type != 'f' && dot >= 0) { ValueError("precision not allowed in the format specifier"); } if(type != 'f' && dot >= 0) ValueError("precision not allowed in the format specifier");
Str ret; Str ret;
if(type == 'f') { if(type == 'f') {
f64 val = CAST(f64, obj); f64 val = CAST(f64, obj);
if(precision < 0) { precision = 6; } if(precision < 0) precision = 6;
SStream ss; SStream ss;
ss.setprecision(precision); ss.setprecision(precision);
ss << val; ss << val;
@ -694,11 +700,10 @@ PyVar VM::__format_object(PyVar obj, Str spec) {
int pad = width - ret.length(); int pad = width - ret.length();
if(align == '>' || align == '<') { if(align == '>' || align == '<') {
std::string padding(pad, pad_c); std::string padding(pad, pad_c);
if(align == '>') { if(align == '>')
ret = padding.c_str() + ret; ret = padding.c_str() + ret;
} else { else
ret = ret + padding.c_str(); ret = ret + padding.c_str();
}
} else { // ^ } else { // ^
int pad_left = pad / 2; int pad_left = pad / 2;
int pad_right = pad - pad_left; int pad_right = pad - pad_left;
@ -715,7 +720,7 @@ PyObject* VM::new_module(Str name, Str package) {
obj->attr().set(__name__, VAR(name)); obj->attr().set(__name__, VAR(name));
obj->attr().set(__package__, VAR(package)); obj->attr().set(__package__, VAR(package));
// convert to fullname // convert to fullname
if(!package.empty()) { name = package + "." + name; } if(!package.empty()) name = package + "." + name;
obj->attr().set(__path__, VAR(name)); obj->attr().set(__path__, VAR(name));
// we do not allow override in order to avoid memory leak // we do not allow override in order to avoid memory leak
@ -739,7 +744,7 @@ static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject
case OP_LOAD_CONST: case OP_LOAD_CONST:
case OP_FORMAT_STRING: case OP_FORMAT_STRING:
case OP_IMPORT_PATH: case OP_IMPORT_PATH:
if(vm != nullptr) { ss << " (" << vm->py_repr(co->consts[byte.arg]) << ")"; } if(vm != nullptr) ss << " (" << vm->py_repr(co->consts[byte.arg]) << ")";
break; break;
case OP_LOAD_NAME: case OP_LOAD_NAME:
case OP_LOAD_GLOBAL: case OP_LOAD_GLOBAL:
@ -771,7 +776,7 @@ static std::string _opcode_argstr(VM* vm, int i, Bytecode byte, const CodeObject
Str VM::disassemble(CodeObject_ co) { Str VM::disassemble(CodeObject_ co) {
auto pad = [](const Str& s, const int n) { auto pad = [](const Str& s, const int n) {
if(s.length() >= n) { return s.substr(0, n); } if(s.length() >= n) return s.substr(0, n);
return s + std::string(n - s.length(), ' '); return s + std::string(n - s.length(), ' ');
}; };
@ -785,10 +790,10 @@ Str VM::disassemble(CodeObject_ co) {
for(int i = 0; i < co->codes.size(); i++) { for(int i = 0; i < co->codes.size(); i++) {
const Bytecode& byte = co->codes[i]; const Bytecode& byte = co->codes[i];
Str line = std::to_string(co->lines[i].lineno); Str line = std::to_string(co->lines[i].lineno);
if(co->lines[i].lineno == prev_line) { if(co->lines[i].lineno == prev_line)
line = ""; line = "";
} else { else {
if(prev_line != -1) { ss << "\n"; } if(prev_line != -1) ss << "\n";
prev_line = co->lines[i].lineno; prev_line = co->lines[i].lineno;
} }
@ -800,11 +805,11 @@ Str VM::disassemble(CodeObject_ co) {
} }
ss << pad(line, 8) << pointer << pad(std::to_string(i), 3); ss << pad(line, 8) << pointer << pad(std::to_string(i), 3);
std::string bc_name(OP_NAMES[byte.op]); std::string bc_name(OP_NAMES[byte.op]);
if(co->lines[i].is_virtual) { bc_name += '*'; } if(co->lines[i].is_virtual) bc_name += '*';
ss << " " << pad(bc_name, 25) << " "; ss << " " << pad(bc_name, 25) << " ";
std::string argStr = _opcode_argstr(this, i, byte, co.get()); std::string argStr = _opcode_argstr(this, i, byte, co.get());
ss << argStr; ss << argStr;
if(i != co->codes.size() - 1) { ss << '\n'; } if(i != co->codes.size() - 1) ss << '\n';
} }
for(auto& decl: co->func_decls) { for(auto& decl: co->func_decls) {
@ -818,10 +823,10 @@ Str VM::disassemble(CodeObject_ co) {
#if PK_DEBUG_CEVAL_STEP #if PK_DEBUG_CEVAL_STEP
void VM::__log_s_data(const char* title) { void VM::__log_s_data(const char* title) {
if(_main == nullptr) { return; } if(_main == nullptr) return;
if(callstack.empty()) { return; } if(callstack.empty()) return;
SStream ss; SStream ss;
if(title) { ss << title << " | "; } if(title) ss << title << " | ";
std::map<PyVar*, int> sp_bases; std::map<PyVar*, int> sp_bases;
callstack.apply([&](Frame& f) { callstack.apply([&](Frame& f) {
assert(f._sp_base != nullptr); assert(f._sp_base != nullptr);
@ -832,10 +837,10 @@ void VM::__log_s_data(const char* title) {
ss << frame->co->name << ":" << line << " ["; ss << frame->co->name << ":" << line << " [";
for(PyVar* p = s_data.begin(); p != s_data.end(); p++) { for(PyVar* p = s_data.begin(); p != s_data.end(); p++) {
ss << std::string(sp_bases[p], '|'); ss << std::string(sp_bases[p], '|');
if(sp_bases[p] > 0) { ss << " "; } if(sp_bases[p] > 0) ss << " ";
if(*p == PY_NULL) { if(*p == PY_NULL)
ss << "NULL"; ss << "NULL";
} else { else {
switch(p->type) { switch(p->type) {
case tp_none_type: ss << "None"; break; case tp_none_type: ss << "None"; break;
case tp_int: ss << _CAST(i64, *p); break; case tp_int: ss << _CAST(i64, *p); break;
@ -849,7 +854,7 @@ void VM::__log_s_data(const char* title) {
case tp_stack_memory: { case tp_stack_memory: {
int count = p->obj_get<StackMemory>().count; int count = p->obj_get<StackMemory>().count;
ss << "M[" << count << "]"; ss << "M[" << count << "]";
if(count > 0) { p += count; } if(count > 0) p += count;
break; break;
} }
default: ss << "(" << _type_name(this, p->type) << ")"; break; default: ss << "(" << _type_name(this, p->type) << ")"; break;
@ -876,7 +881,7 @@ void VM::__init_builtin_types() {
auto validate = [](Type type, PyObject* ret) { auto validate = [](Type type, PyObject* ret) {
Type ret_t = ret->as<Type>(); Type ret_t = ret->as<Type>();
if(ret_t != type) { exit(-3); } if(ret_t != type) exit(-3);
}; };
validate(tp_int, new_type_object(nullptr, "int", tp_object, false)); validate(tp_int, new_type_object(nullptr, "int", tp_object, false));
@ -947,7 +952,7 @@ void VM::__unpack_as_list(ArgsView args, List& list) {
if(is_type(obj, tp_star_wrapper)) { if(is_type(obj, tp_star_wrapper)) {
const StarWrapper& w = _CAST(StarWrapper&, obj); const StarWrapper& w = _CAST(StarWrapper&, obj);
// maybe this check should be done in the compile time // maybe this check should be done in the compile time
if(w.level != 1) { TypeError("expected level 1 star wrapper"); } if(w.level != 1) TypeError("expected level 1 star wrapper");
PyVar _0 = py_iter(w.obj); PyVar _0 = py_iter(w.obj);
const PyTypeInfo* info = _tp_info(_0); const PyTypeInfo* info = _tp_info(_0);
PyVar _1 = _py_next(info, _0); PyVar _1 = _py_next(info, _0);
@ -967,12 +972,12 @@ void VM::__unpack_as_dict(ArgsView args, Dict& dict) {
if(is_type(obj, tp_star_wrapper)) { if(is_type(obj, tp_star_wrapper)) {
const StarWrapper& w = _CAST(StarWrapper&, obj); const StarWrapper& w = _CAST(StarWrapper&, obj);
// maybe this check should be done in the compile time // maybe this check should be done in the compile time
if(w.level != 2) { TypeError("expected level 2 star wrapper"); } if(w.level != 2) TypeError("expected level 2 star wrapper");
const Dict& other = CAST(Dict&, w.obj); const Dict& other = CAST(Dict&, w.obj);
dict.update(this, other); dict.update(this, other);
} else { } else {
const Tuple& t = CAST(Tuple&, obj); const Tuple& t = CAST(Tuple&, obj);
if(t.size() != 2) { TypeError("expected tuple of length 2"); } if(t.size() != 2) TypeError("expected tuple of length 2");
dict.set(this, t[0], t[1]); dict.set(this, t[0], t[1]);
} }
} }
@ -989,13 +994,11 @@ void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const
int i = 0; int i = 0;
// prepare args // prepare args
std::memset(buffer, 0, co->nlocals * sizeof(PyVar)); std::memset(buffer, 0, co->nlocals * sizeof(PyVar));
for(int index: decl->args) { for(int index: decl->args)
buffer[index] = args[i++]; buffer[index] = args[i++];
}
// prepare kwdefaults // prepare kwdefaults
for(auto& kv: decl->kwargs) { for(auto& kv: decl->kwargs)
buffer[kv.index] = kv.value; buffer[kv.index] = kv.value;
}
// handle *args // handle *args
if(decl->starred_arg != -1) { if(decl->starred_arg != -1) {
@ -1005,10 +1008,10 @@ void VM::__prepare_py_call(PyVar* buffer, ArgsView args, ArgsView kwargs, const
} else { } else {
// kwdefaults override // kwdefaults override
for(auto& kv: decl->kwargs) { for(auto& kv: decl->kwargs) {
if(i >= args.size()) { break; } if(i >= args.size()) break;
buffer[kv.index] = args[i++]; buffer[kv.index] = args[i++];
} }
if(i < args.size()) { TypeError(_S("too many arguments", " (", decl->code->name, ')')); } if(i < args.size()) TypeError(_S("too many arguments", " (", decl->code->name, ')'));
} }
PyVar vkwargs; PyVar vkwargs;
@ -1064,7 +1067,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
if(callable_t == tp_function) { if(callable_t == tp_function) {
/*****************_py_call*****************/ /*****************_py_call*****************/
// check stack overflow // check stack overflow
if(s_data.is_overflow()) { StackOverflowError(); } if(s_data.is_overflow()) StackOverflowError();
const Function& fn = PK_OBJ_GET(Function, callable); const Function& fn = PK_OBJ_GET(Function, callable);
const CodeObject* co = fn.decl->code.get(); const CodeObject* co = fn.decl->code.get();
@ -1074,20 +1077,18 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
__prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl); __prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
// copy buffer back to stack // copy buffer back to stack
s_data.reset(_base + co->nlocals); s_data.reset(_base + co->nlocals);
for(int j = 0; j < co->nlocals; j++) { for(int j = 0; j < co->nlocals; j++)
_base[j] = __vectorcall_buffer[j]; _base[j] = __vectorcall_buffer[j];
}
break; break;
case FuncType::SIMPLE: case FuncType::SIMPLE:
if(args.size() != fn.decl->args.size()) { if(args.size() != fn.decl->args.size())
TypeError(_S(co->name, TypeError(_S(co->name,
"() takes ", "() takes ",
fn.decl->args.size(), fn.decl->args.size(),
" positional arguments but ", " positional arguments but ",
args.size(), args.size(),
" were given")); " were given"));
} if(!kwargs.empty()) TypeError(_S(co->name, "() takes no keyword arguments"));
if(!kwargs.empty()) { TypeError(_S(co->name, "() takes no keyword arguments")); }
// [callable, <self>, args..., local_vars...] // [callable, <self>, args..., local_vars...]
// ^p0 ^p1 ^_sp // ^p0 ^p1 ^_sp
s_data.reset(_base + co->nlocals); s_data.reset(_base + co->nlocals);
@ -1095,15 +1096,14 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
std::memset(p1, 0, (char*)s_data._sp - (char*)p1); std::memset(p1, 0, (char*)s_data._sp - (char*)p1);
break; break;
case FuncType::EMPTY: case FuncType::EMPTY:
if(args.size() != fn.decl->args.size()) { if(args.size() != fn.decl->args.size())
TypeError(_S(co->name, TypeError(_S(co->name,
"() takes ", "() takes ",
fn.decl->args.size(), fn.decl->args.size(),
" positional arguments but ", " positional arguments but ",
args.size(), args.size(),
" were given")); " were given"));
} if(!kwargs.empty()) TypeError(_S(co->name, "() takes no keyword arguments"));
if(!kwargs.empty()) { TypeError(_S(co->name, "() takes no keyword arguments")); }
s_data.reset(p0); s_data.reset(p0);
return None; return None;
case FuncType::GENERATOR: case FuncType::GENERATOR:
@ -1117,7 +1117,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
// simple or normal // simple or normal
callstack.emplace(p0, co, fn._module, callable.get(), args.begin()); callstack.emplace(p0, co, fn._module, callable.get(), args.begin());
if(op_call) { return PY_OP_CALL; } if(op_call) return PY_OP_CALL;
return __run_top_frame(); return __run_top_frame();
/*****************_py_call*****************/ /*****************_py_call*****************/
} }
@ -1130,16 +1130,14 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
__prepare_py_call(__vectorcall_buffer, args, kwargs, f.decl); __prepare_py_call(__vectorcall_buffer, args, kwargs, f.decl);
// copy buffer back to stack // copy buffer back to stack
s_data.reset(_base + co_nlocals); s_data.reset(_base + co_nlocals);
for(int j = 0; j < co_nlocals; j++) { for(int j = 0; j < co_nlocals; j++)
_base[j] = __vectorcall_buffer[j]; _base[j] = __vectorcall_buffer[j];
}
ret = f.call(vm, ArgsView(s_data._sp - co_nlocals, s_data._sp)); ret = f.call(vm, ArgsView(s_data._sp - co_nlocals, s_data._sp));
} else { } else {
if(f.argc != -1) { if(f.argc != -1) {
if(KWARGC != 0) { if(KWARGC != 0)
TypeError( TypeError(
"old-style native_func does not accept keyword arguments. If you want to skip this check, specify `argc` to -1"); "old-style native_func does not accept keyword arguments. If you want to skip this check, specify `argc` to -1");
}
if(args.size() != f.argc) { vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size())); } if(args.size() != f.argc) { vm->TypeError(_S("expected ", f.argc, " arguments, got ", args.size())); }
} }
ret = f.call(this, args); ret = f.call(this, args);
@ -1160,12 +1158,10 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
PUSH(new_f); PUSH(new_f);
PUSH(PY_NULL); PUSH(PY_NULL);
PUSH(callable); // cls PUSH(callable); // cls
for(PyVar o: args) { for(PyVar o: args)
PUSH(o); PUSH(o);
} for(PyVar o: kwargs)
for(PyVar o: kwargs) {
PUSH(o); PUSH(o);
}
// if obj is not an instance of `cls`, the behavior is undefined // if obj is not an instance of `cls`, the behavior is undefined
obj = vectorcall(ARGC + 1, KWARGC); obj = vectorcall(ARGC + 1, KWARGC);
} }
@ -1203,9 +1199,9 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
void VM::delattr(PyVar _0, StrName _name) { void VM::delattr(PyVar _0, StrName _name) {
const PyTypeInfo* ti = _tp_info(_0); const PyTypeInfo* ti = _tp_info(_0);
if(ti->m__delattr__ && ti->m__delattr__(this, _0, _name)) { return; } if(ti->m__delattr__ && ti->m__delattr__(this, _0, _name)) return;
if(is_tagged(_0) || !_0->is_attr_valid()) { TypeError("cannot delete attribute"); } if(is_tagged(_0) || !_0->is_attr_valid()) TypeError("cannot delete attribute");
if(!_0->attr().del(_name)) { AttributeError(_0, _name); } if(!_0->attr().del(_name)) AttributeError(_0, _name);
} }
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance // https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
@ -1233,14 +1229,14 @@ PyVar VM::getattr(PyVar obj, StrName name, bool throw_err) {
if(obj.type == tp_type) { if(obj.type == tp_type) {
val = find_name_in_mro(PK_OBJ_GET(Type, obj), name); val = find_name_in_mro(PK_OBJ_GET(Type, obj), name);
if(val != nullptr) { if(val != nullptr) {
if(is_tagged(*val)) { return *val; } if(is_tagged(*val)) return *val;
if(val->type == tp_staticmethod) { return PK_OBJ_GET(StaticMethod, *val).func; } if(val->type == tp_staticmethod) return PK_OBJ_GET(StaticMethod, *val).func;
if(val->type == tp_classmethod) { return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, *val).func)); } if(val->type == tp_classmethod) return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, *val).func));
return *val; return *val;
} }
} else { } else {
val = obj->attr().try_get_2_likely_found(name); val = obj->attr().try_get_2_likely_found(name);
if(val != nullptr) { return *val; } if(val != nullptr) return *val;
} }
} }
if(cls_var != nullptr) { if(cls_var != nullptr) {
@ -1259,10 +1255,10 @@ PyVar VM::getattr(PyVar obj, StrName name, bool throw_err) {
const PyTypeInfo* ti = &_all_types[objtype]; const PyTypeInfo* ti = &_all_types[objtype];
if(ti->m__getattr__) { if(ti->m__getattr__) {
PyVar ret = ti->m__getattr__(this, obj, name); PyVar ret = ti->m__getattr__(this, obj, name);
if(ret) { return ret; } if(ret) return ret;
} }
if(throw_err) { AttributeError(obj, name); } if(throw_err) AttributeError(obj, name);
return nullptr; return nullptr;
} }
@ -1295,16 +1291,14 @@ PyVar VM::get_unbound_method(PyVar obj, StrName name, PyVar* self, bool throw_er
if(obj.type == tp_type) { if(obj.type == tp_type) {
val = find_name_in_mro(PK_OBJ_GET(Type, obj), name); val = find_name_in_mro(PK_OBJ_GET(Type, obj), name);
if(val != nullptr) { if(val != nullptr) {
if(is_tagged(*val)) { return *val; } if(is_tagged(*val)) return *val;
if(val->type == tp_staticmethod) { return PK_OBJ_GET(StaticMethod, *val).func; } if(val->type == tp_staticmethod) return PK_OBJ_GET(StaticMethod, *val).func;
if(val->type == tp_classmethod) { if(val->type == tp_classmethod) return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, *val).func));
return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, *val).func));
}
return *val; return *val;
} }
} else { } else {
val = obj->attr().try_get_2_likely_found(name); val = obj->attr().try_get_2_likely_found(name);
if(val != nullptr) { return *val; } if(val != nullptr) return *val;
} }
} }
} }
@ -1324,10 +1318,10 @@ PyVar VM::get_unbound_method(PyVar obj, StrName name, PyVar* self, bool throw_er
const PyTypeInfo* ti = &_all_types[objtype]; const PyTypeInfo* ti = &_all_types[objtype];
if(fallback && ti->m__getattr__) { if(fallback && ti->m__getattr__) {
PyVar ret = ti->m__getattr__(this, obj, name); PyVar ret = ti->m__getattr__(this, obj, name);
if(ret) { return ret; } if(ret) return ret;
} }
if(throw_err) { AttributeError(obj, name); } if(throw_err) AttributeError(obj, name);
return nullptr; return nullptr;
} }
@ -1362,7 +1356,7 @@ void VM::setattr(PyVar obj, StrName name, PyVar value) {
} }
// handle instance __dict__ // handle instance __dict__
if(is_tagged(obj) || !obj->is_attr_valid()) { TypeError("cannot set attribute"); } if(is_tagged(obj) || !obj->is_attr_valid()) TypeError("cannot set attribute");
obj->attr().set(name, value); obj->attr().set(name, value);
} }
@ -1373,7 +1367,7 @@ PyObject* VM::bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, a
case BindType::STATICMETHOD: nf = heap.gcnew<StaticMethod>(tp_staticmethod, nf); break; case BindType::STATICMETHOD: nf = heap.gcnew<StaticMethod>(tp_staticmethod, nf); break;
case BindType::CLASSMETHOD: nf = heap.gcnew<ClassMethod>(tp_classmethod, nf); break; case BindType::CLASSMETHOD: nf = heap.gcnew<ClassMethod>(tp_classmethod, nf); break;
} }
if(obj != nullptr) { obj->attr().set(name, nf); } if(obj != nullptr) obj->attr().set(name, nf);
return nf; return nf;
} }
@ -1397,7 +1391,7 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
case BindType::CLASSMETHOD: f_obj = heap.gcnew<ClassMethod>(tp_classmethod, f_obj); break; case BindType::CLASSMETHOD: f_obj = heap.gcnew<ClassMethod>(tp_classmethod, f_obj); break;
case BindType::DEFAULT: break; case BindType::DEFAULT: break;
} }
if(obj != nullptr) { obj->attr().set(decl->code->name, f_obj); } if(obj != nullptr) obj->attr().set(decl->code->name, f_obj);
return f_obj; return f_obj;
} }
@ -1405,10 +1399,10 @@ PyObject* VM::bind_property(PyObject* obj, const char* name, NativeFuncC fget, N
assert(is_type(obj, tp_type)); assert(is_type(obj, tp_type));
std::string_view name_sv(name); std::string_view name_sv(name);
int pos = name_sv.find(':'); int pos = name_sv.find(':');
if(pos > 0) { name_sv = name_sv.substr(0, pos); } if(pos > 0) name_sv = name_sv.substr(0, pos);
PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1); PyVar _0 = new_object<NativeFunc>(tp_native_func, fget, 1);
PyVar _1 = vm->None; PyVar _1 = vm->None;
if(fset != nullptr) { _1 = new_object<NativeFunc>(tp_native_func, fset, 2); } if(fset != nullptr) _1 = new_object<NativeFunc>(tp_native_func, fset, 2);
PyObject* prop = heap.gcnew<Property>(tp_property, _0, _1); PyObject* prop = heap.gcnew<Property>(tp_property, _0, _1);
obj->attr().set(StrName(name_sv), prop); obj->attr().set(StrName(name_sv), prop);
return prop; return prop;
@ -1459,12 +1453,10 @@ void VM::__raise_exc(bool re_raise) {
int next_ip = frame->prepare_jump_exception_handler(&s_data); int next_ip = frame->prepare_jump_exception_handler(&s_data);
int actual_ip = frame->ip(); int actual_ip = frame->ip();
if(e._ip_on_error >= 0 && e._code_on_error == (void*)frame->co) { actual_ip = e._ip_on_error; } if(e._ip_on_error >= 0 && e._code_on_error == (void*)frame->co) actual_ip = e._ip_on_error;
int current_line = frame->co->lines[actual_ip].lineno; // current line int current_line = frame->co->lines[actual_ip].lineno; // current line
auto current_f_name = frame->co->name.sv(); // current function name auto current_f_name = frame->co->name.sv(); // current function name
if(frame->_callable == nullptr) { if(frame->_callable == nullptr) current_f_name = ""; // not in a function
current_f_name = ""; // not in a function
}
e.st_push(frame->co->src, current_line, nullptr, current_f_name); e.st_push(frame->co->src, current_line, nullptr, current_f_name);
if(next_ip >= 0) { if(next_ip >= 0) {
@ -1482,7 +1474,9 @@ void VM::bind__getitem__(Type type, PyVar (*f)(VM*, PyVar, PyVar)) {
type, type,
__getitem__, __getitem__,
2, 2,
[](VM* vm, ArgsView args) { return lambda_get_userdata<decltype(f)>(args.begin())(vm, args[0], args[1]); }, [](VM* vm, ArgsView args) {
return lambda_get_userdata<decltype(f)>(args.begin())(vm, args[0], args[1]);
},
f); f);
} }
@ -1513,8 +1507,8 @@ void VM::bind__delitem__(Type type, void (*f)(VM*, PyVar, PyVar)) {
} }
PyVar VM::__pack_next_retval(unsigned n) { PyVar VM::__pack_next_retval(unsigned n) {
if(n == 0) { return StopIteration; } if(n == 0) return StopIteration;
if(n == 1) { return s_data.popx(); } if(n == 1) return s_data.popx();
PyVar retval = VAR(s_data.view(n).to_tuple()); PyVar retval = VAR(s_data.view(n).to_tuple());
s_data._sp -= n; s_data._sp -= n;
return retval; return retval;
@ -1662,7 +1656,7 @@ void Dict::_probe_0(VM* vm, PyVar key, bool& ok, int& i) const {
break; break;
} }
} else { } else {
if(_items[i].second == nullptr) { break; } if(_items[i].second == nullptr) break;
} }
// https://github.com/python/cpython/blob/3.8/Objects/dictobject.c#L166 // https://github.com/python/cpython/blob/3.8/Objects/dictobject.c#L166
i = ((5 * i) + 1) & _mask; i = ((5 * i) + 1) & _mask;
@ -1690,7 +1684,7 @@ void NextBreakpoint::_step(VM* vm) {
if(curr_callstack_size != callstack_size || curr_lineno != lineno) { vm->__breakpoint(); } if(curr_callstack_size != callstack_size || curr_lineno != lineno) { vm->__breakpoint(); }
} else { } else {
if(curr_callstack_size == callstack_size) { if(curr_callstack_size == callstack_size) {
if(curr_lineno != lineno) { vm->__breakpoint(); } if(curr_lineno != lineno) vm->__breakpoint();
} else if(curr_callstack_size < callstack_size) { } else if(curr_callstack_size < callstack_size) {
// returning // returning
vm->__breakpoint(); vm->__breakpoint();
@ -1723,12 +1717,12 @@ void VM::__breakpoint() {
while(lf != nullptr) { while(lf != nullptr) {
frames.push_back(lf); frames.push_back(lf);
lf = lf->f_back; lf = lf->f_back;
if(frames.size() >= 4) { break; } if(frames.size() >= 4) break;
} }
if(show_headers) { if(show_headers) {
for(int i = frames.size() - 1; i >= 0; i--) { for(int i = frames.size() - 1; i >= 0; i--) {
if(!show_where && i != 0) { continue; } if(!show_where && i != 0) continue;
SStream ss; SStream ss;
Frame* frame = &frames[i]->frame; Frame* frame = &frames[i]->frame;
@ -1782,11 +1776,11 @@ void VM::__breakpoint() {
show_headers = true; show_headers = true;
continue; continue;
} }
if(line == "c" || line == "continue") { break; } if(line == "c" || line == "continue") break;
if(line == "a" || line == "args") { if(line == "a" || line == "args") {
int i = 0; int i = 0;
for(PyVar obj: frame_0->_locals) { for(PyVar obj: frame_0->_locals) {
if(obj == PY_NULL) { continue; } if(obj == PY_NULL) continue;
StrName name = frame_0->co->varnames[i++]; StrName name = frame_0->co->varnames[i++];
stdout_write(_S(name.sv(), " = ", vm->py_repr(obj), '\n')); stdout_write(_S(name.sv(), " = ", vm->py_repr(obj), '\n'));
} }
@ -1797,7 +1791,7 @@ void VM::__breakpoint() {
bool is_longlist = line == "ll" || line == "longlist"; bool is_longlist = line == "ll" || line == "longlist";
if(is_list || is_longlist) { if(is_list || is_longlist) {
if(frame_0->co->src->is_precompiled) { continue; } if(frame_0->co->src->is_precompiled) continue;
int lineno = frame_0->curr_lineno(); int lineno = frame_0->curr_lineno();
int start, end; int start, end;
@ -1808,7 +1802,7 @@ void VM::__breakpoint() {
} else { } else {
start = frame_0->co->start_line; start = frame_0->co->start_line;
end = frame_0->co->end_line; end = frame_0->co->end_line;
if(start == -1 || end == -1) { continue; } if(start == -1 || end == -1) continue;
} }
SStream ss; SStream ss;
@ -1816,11 +1810,10 @@ void VM::__breakpoint() {
for(int i = start; i <= end; i++) { for(int i = start; i <= end; i++) {
int spaces = max_width - std::to_string(i).size(); int spaces = max_width - std::to_string(i).size();
ss << std::string(spaces, ' ') << std::to_string(i); ss << std::string(spaces, ' ') << std::to_string(i);
if(i == lineno) { if(i == lineno)
ss << " -> "; ss << " -> ";
} else { else
ss << " "; ss << " ";
}
ss << frame_0->co->src->get_line(i) << '\n'; ss << frame_0->co->src->get_line(i) << '\n';
} }
stdout_write(ss.str()); stdout_write(ss.str());
@ -1831,9 +1824,7 @@ void VM::__breakpoint() {
if(space != -1) { if(space != -1) {
std::string cmd = line.substr(0, space); std::string cmd = line.substr(0, space);
std::string arg = line.substr(space + 1); std::string arg = line.substr(space + 1);
if(arg.empty()) { if(arg.empty()) continue; // ignore empty command
continue; // ignore empty command
}
if(cmd == "p" || cmd == "print") { if(cmd == "p" || cmd == "print") {
CodeObject_ code = compile(arg, "<stdin>", EVAL_MODE, true); CodeObject_ code = compile(arg, "<stdin>", EVAL_MODE, true);
PyVar retval = vm->_exec(code.get(), frame_0->_module, frame_0->_callable, frame_0->_locals); PyVar retval = vm->_exec(code.get(), frame_0->_module, frame_0->_callable, frame_0->_locals);
@ -1853,31 +1844,30 @@ void VM::__breakpoint() {
void Function::_gc_mark(VM* vm) const { void Function::_gc_mark(VM* vm) const {
decl->_gc_mark(vm); decl->_gc_mark(vm);
if(_closure) { if(_closure) {
_closure->apply([=](StrName _, PyVar obj) { vm->obj_gc_mark(obj); }); _closure->apply([=](StrName _, PyVar obj) {
vm->obj_gc_mark(obj);
});
} }
} }
void NativeFunc::_gc_mark(VM* vm) const { void NativeFunc::_gc_mark(VM* vm) const {
if(decl) { decl->_gc_mark(vm); } if(decl) decl->_gc_mark(vm);
} }
void FuncDecl::_gc_mark(VM* vm) const { void FuncDecl::_gc_mark(VM* vm) const {
code->_gc_mark(vm); code->_gc_mark(vm);
for(int i = 0; i < kwargs.size(); i++) { for(int i = 0; i < kwargs.size(); i++)
vm->obj_gc_mark(kwargs[i].value); vm->obj_gc_mark(kwargs[i].value);
}
} }
void List::_gc_mark(VM* vm) const { void List::_gc_mark(VM* vm) const {
for(PyVar obj: *this) { for(PyVar obj: *this)
vm->obj_gc_mark(obj); vm->obj_gc_mark(obj);
}
} }
void Tuple::_gc_mark(VM* vm) const { void Tuple::_gc_mark(VM* vm) const {
for(PyVar obj: *this) { for(PyVar obj: *this)
vm->obj_gc_mark(obj); vm->obj_gc_mark(obj);
}
} }
void MappingProxy::_gc_mark(VM* vm) const { vm->__obj_gc_mark(obj); } void MappingProxy::_gc_mark(VM* vm) const { vm->__obj_gc_mark(obj); }
@ -1914,23 +1904,23 @@ void Frame::_gc_mark(VM* vm) const {
} }
void ManagedHeap::mark() { void ManagedHeap::mark() {
for(PyObject* obj: _no_gc) { for(PyObject* obj: _no_gc)
vm->__obj_gc_mark(obj); vm->__obj_gc_mark(obj);
} vm->callstack.apply([this](Frame& frame) {
vm->callstack.apply([this](Frame& frame) { frame._gc_mark(vm); }); frame._gc_mark(vm);
for(auto [_, co]: vm->__cached_codes) { });
for(auto [_, co]: vm->__cached_codes)
co->_gc_mark(vm); co->_gc_mark(vm);
}
vm->obj_gc_mark(vm->__last_exception); vm->obj_gc_mark(vm->__last_exception);
vm->obj_gc_mark(vm->__curr_class); vm->obj_gc_mark(vm->__curr_class);
vm->obj_gc_mark(vm->__c.error); vm->obj_gc_mark(vm->__c.error);
vm->__stack_gc_mark(vm->s_data.begin(), vm->s_data.end()); vm->__stack_gc_mark(vm->s_data.begin(), vm->s_data.end());
if(_gc_marker_ex) { _gc_marker_ex(vm); } if(_gc_marker_ex) _gc_marker_ex(vm);
} }
void ManagedHeap::_delete(PyObject* obj) { void ManagedHeap::_delete(PyObject* obj) {
const PyTypeInfo* ti = vm->_tp_info(obj->type); const PyTypeInfo* ti = vm->_tp_info(obj->type);
if(ti->vt._dtor) { ti->vt._dtor(obj->_value_ptr()); } if(ti->vt._dtor) ti->vt._dtor(obj->_value_ptr());
delete obj->_attr; // delete __dict__ if exists delete obj->_attr; // delete __dict__ if exists
PoolObject_dealloc(obj); PoolObject_dealloc(obj);
} }
@ -1943,12 +1933,10 @@ void Dict::_gc_mark(VM* vm) const {
} }
void CodeObject::_gc_mark(VM* vm) const { void CodeObject::_gc_mark(VM* vm) const {
for(PyVar v: consts) { for(PyVar v: consts)
vm->obj_gc_mark(v); vm->obj_gc_mark(v);
} for(auto& decl: func_decls)
for(auto& decl: func_decls) {
decl->_gc_mark(vm); decl->_gc_mark(vm);
}
} }
} // namespace pkpy } // namespace pkpy

View File

@ -28,7 +28,7 @@ struct Array2d {
bool is_valid(int col, int row) const { return 0 <= col && col < n_cols && 0 <= row && row < n_rows; } bool is_valid(int col, int row) const { return 0 <= col && col < n_cols && 0 <= row && row < n_rows; }
void check_valid(VM* vm, int col, int row) const { void check_valid(VM* vm, int col, int row) const {
if(is_valid(col, row)) { return; } if(is_valid(col, row)) return;
vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')')); vm->IndexError(_S('(', col, ", ", row, ')', " is not a valid index for array2d(", n_cols, ", ", n_rows, ')'));
} }
@ -49,13 +49,11 @@ struct Array2d {
if(n_cols <= 0 || n_rows <= 0) { vm->ValueError("n_cols and n_rows must be positive integers"); } if(n_cols <= 0 || n_rows <= 0) { vm->ValueError("n_cols and n_rows must be positive integers"); }
self.init(n_cols, n_rows); self.init(n_cols, n_rows);
if(vm->py_callable(args[3])) { if(vm->py_callable(args[3])) {
for(int i = 0; i < self.numel; i++) { for(int i = 0; i < self.numel; i++)
self.data[i] = vm->call(args[3]); self.data[i] = vm->call(args[3]);
}
} else { } else {
for(int i = 0; i < self.numel; i++) { for(int i = 0; i < self.numel; i++)
self.data[i] = args[3]; self.data[i] = args[3];
}
} }
return vm->None; return vm->None;
}); });
@ -96,7 +94,7 @@ struct Array2d {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
int col = CAST(int, args[1]); int col = CAST(int, args[1]);
int row = CAST(int, args[2]); int row = CAST(int, args[2]);
if(!self.is_valid(col, row)) { return args[3]; } if(!self.is_valid(col, row)) return args[3];
return self._get(col, row); return self._get(col, row);
}); });
@ -160,11 +158,9 @@ struct Array2d {
} }
if(is_basic_type) { if(is_basic_type) {
for(int j = 0; j < slice_height; j++) { for(int j = 0; j < slice_height; j++)
for(int i = 0; i < slice_width; i++) { for(int i = 0; i < slice_width; i++)
self._set(i + start_col, j + start_row, _2); self._set(i + start_col, j + start_row, _2);
}
}
return; return;
} }
@ -176,11 +172,9 @@ struct Array2d {
if(slice_width != other.n_cols || slice_height != other.n_rows) { if(slice_width != other.n_cols || slice_height != other.n_rows) {
vm->ValueError("array2d size does not match the slice size"); vm->ValueError("array2d size does not match the slice size");
} }
for(int j = 0; j < slice_height; j++) { for(int j = 0; j < slice_height; j++)
for(int i = 0; i < slice_width; i++) { for(int i = 0; i < slice_width; i++)
self._set(i + start_col, j + start_row, other._get(i, j)); self._set(i + start_col, j + start_row, other._get(i, j));
}
}
return; return;
} }
vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index"); vm->TypeError("expected `tuple[int, int]` or `tuple[slice, slice]` as index");
@ -193,9 +187,8 @@ struct Array2d {
List t(self.n_rows); List t(self.n_rows);
for(int j = 0; j < self.n_rows; j++) { for(int j = 0; j < self.n_rows; j++) {
List row(self.n_cols); List row(self.n_cols);
for(int i = 0; i < self.n_cols; i++) { for(int i = 0; i < self.n_cols; i++)
row[i] = self._get(i, j); row[i] = self._get(i, j);
}
t[j] = VAR(std::move(row)); t[j] = VAR(std::move(row));
} }
return VAR(std::move(t)); return VAR(std::move(t));
@ -277,11 +270,11 @@ struct Array2d {
vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) { vm->bind__eq__(type->as<Type>(), [](VM* vm, PyVar _0, PyVar _1) {
Array2d& self = PK_OBJ_GET(Array2d, _0); Array2d& self = PK_OBJ_GET(Array2d, _0);
if(!vm->is_user_type<Array2d>(_1)) { return vm->NotImplemented; } if(!vm->is_user_type<Array2d>(_1)) return vm->NotImplemented;
Array2d& other = PK_OBJ_GET(Array2d, _1); Array2d& other = PK_OBJ_GET(Array2d, _1);
if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) { return vm->False; } if(self.n_cols != other.n_cols || self.n_rows != other.n_rows) return vm->False;
for(int i = 0; i < self.numel; i++) { for(int i = 0; i < self.numel; i++) {
if(vm->py_ne(self.data[i], other.data[i])) { return vm->False; } if(vm->py_ne(self.data[i], other.data[i])) return vm->False;
} }
return vm->True; return vm->True;
}); });
@ -329,9 +322,8 @@ struct Array2d {
Array2d& self = PK_OBJ_GET(Array2d, args[0]); Array2d& self = PK_OBJ_GET(Array2d, args[0]);
PyVar value = args[1]; PyVar value = args[1];
int count = 0; int count = 0;
for(int i = 0; i < self.numel; i++) { for(int i = 0; i < self.numel; i++)
count += vm->py_eq(self.data[i], value); count += vm->py_eq(self.data[i], value);
}
return VAR(count); return VAR(count);
}); });
@ -354,7 +346,7 @@ struct Array2d {
} }
int width = right - left + 1; int width = right - left + 1;
int height = bottom - top + 1; int height = bottom - top + 1;
if(width <= 0 || height <= 0) { return vm->None; } if(width <= 0 || height <= 0) return vm->None;
Tuple t(4); Tuple t(4);
t[0] = VAR(left); t[0] = VAR(left);
t[1] = VAR(top); t[1] = VAR(top);
@ -365,9 +357,8 @@ struct Array2d {
} }
void _gc_mark(VM* vm) const { void _gc_mark(VM* vm) const {
for(int i = 0; i < numel; i++) { for(int i = 0; i < numel; i++)
vm->obj_gc_mark(data[i]); vm->obj_gc_mark(data[i]);
}
} }
~Array2d() { delete[] data; } ~Array2d() { delete[] data; }
@ -385,10 +376,12 @@ struct Array2dIter {
void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); } void _gc_mark(VM* vm) const { vm->obj_gc_mark(ref); }
static void _register(VM* vm, PyObject* mod, PyObject* type) { static void _register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) { return _0; }); vm->bind__iter__(type->as<Type>(), [](VM* vm, PyVar _0) {
return _0;
});
vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned { vm->bind__next__(type->as<Type>(), [](VM* vm, PyVar _0) -> unsigned {
Array2dIter& self = PK_OBJ_GET(Array2dIter, _0); Array2dIter& self = PK_OBJ_GET(Array2dIter, _0);
if(self.i == self.a->numel) { return 0; } if(self.i == self.a->numel) return 0;
std::div_t res = std::div(self.i, self.a->n_cols); std::div_t res = std::div(self.i, self.a->n_cols);
vm->s_data.emplace(VM::tp_int, res.rem); vm->s_data.emplace(VM::tp_int, res.rem);
vm->s_data.emplace(VM::tp_int, res.quot); vm->s_data.emplace(VM::tp_int, res.quot);
@ -405,8 +398,9 @@ void add_module_array2d(VM* vm) {
vm->register_user_class<Array2dIter>(mod, "_array2d_iter"); vm->register_user_class<Array2dIter>(mod, "_array2d_iter");
Type array2d_iter_t = vm->_tp_user<Array2d>(); Type array2d_iter_t = vm->_tp_user<Array2d>();
vm->bind__iter__(array2d_iter_t, vm->bind__iter__(array2d_iter_t, [](VM* vm, PyVar _0) {
[](VM* vm, PyVar _0) { return vm->new_user_object<Array2dIter>(_0, &_0.obj_get<Array2d>()); }); return vm->new_user_object<Array2dIter>(_0, &_0.obj_get<Array2d>());
});
vm->_all_types[array2d_iter_t].op__iter__ = [](VM* vm, PyVar _0) { vm->_all_types[array2d_iter_t].op__iter__ = [](VM* vm, PyVar _0) {
vm->new_stack_object<Array2dIter>(vm->_tp_user<Array2dIter>(), _0, &_0.obj_get<Array2d>()); vm->new_stack_object<Array2dIter>(vm->_tp_user<Array2dIter>(), _0, &_0.obj_get<Array2d>());
}; };

View File

@ -13,7 +13,7 @@ void add_module_csv(VM* vm) {
std::string_view line = CAST(Str&, csvfile[i]).sv(); std::string_view line = CAST(Str&, csvfile[i]).sv();
if(i == 0) { if(i == 0) {
// Skip utf8 BOM if there is any. // Skip utf8 BOM if there is any.
if(strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) { line = line.substr(3); } if(strncmp(line.data(), "\xEF\xBB\xBF", 3) == 0) line = line.substr(3);
} }
List row; List row;
int j; int j;

View File

@ -9,7 +9,9 @@ static void patch__init__(VM* vm, Type cls) {
const Tuple& args = CAST(Tuple&, _view[1]); const Tuple& args = CAST(Tuple&, _view[1]);
const Dict& kwargs_ = CAST(Dict&, _view[2]); const Dict& kwargs_ = CAST(Dict&, _view[2]);
NameDict kwargs; NameDict kwargs;
kwargs_.apply([&](PyVar k, PyVar v) { kwargs.set(CAST(Str&, k), v); }); kwargs_.apply([&](PyVar k, PyVar v) {
kwargs.set(CAST(Str&, k), v);
});
Type cls = vm->_tp(self); Type cls = vm->_tp(self);
const PyTypeInfo* cls_info = &vm->_all_types[cls]; const PyTypeInfo* cls_info = &vm->_all_types[cls];
@ -53,11 +55,10 @@ static void patch__repr__(VM* vm, Type cls) {
ss << cls_info->name << "("; ss << cls_info->name << "(";
bool first = true; bool first = true;
for(StrName field: fields) { for(StrName field: fields) {
if(first) { if(first)
first = false; first = false;
} else { else
ss << ", "; ss << ", ";
}
ss << field << "=" << vm->py_repr(obj_d[field]); ss << field << "=" << vm->py_repr(obj_d[field]);
} }
ss << ")"; ss << ")";
@ -67,13 +68,13 @@ static void patch__repr__(VM* vm, Type cls) {
static void patch__eq__(VM* vm, Type cls) { static void patch__eq__(VM* vm, Type cls) {
vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1) { vm->bind__eq__(cls, [](VM* vm, PyVar _0, PyVar _1) {
if(vm->_tp(_0) != vm->_tp(_1)) { return vm->NotImplemented; } if(vm->_tp(_0) != vm->_tp(_1)) return vm->NotImplemented;
const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)]; const PyTypeInfo* cls_info = &vm->_all_types[vm->_tp(_0)];
const auto& fields = cls_info->annotated_fields; const auto& fields = cls_info->annotated_fields;
for(StrName field: fields) { for(StrName field: fields) {
PyVar lhs = _0->attr(field); PyVar lhs = _0->attr(field);
PyVar rhs = _1->attr(field); PyVar rhs = _1->attr(field);
if(vm->py_ne(lhs, rhs)) { return vm->False; } if(vm->py_ne(lhs, rhs)) return vm->False;
} }
return vm->True; return vm->True;
}); });
@ -87,9 +88,9 @@ void add_module_dataclasses(VM* vm) {
Type cls = PK_OBJ_GET(Type, args[0]); Type cls = PK_OBJ_GET(Type, args[0]);
NameDict& cls_d = args[0]->attr(); NameDict& cls_d = args[0]->attr();
if(!cls_d.contains(__init__)) { patch__init__(vm, cls); } if(!cls_d.contains(__init__)) patch__init__(vm, cls);
if(!cls_d.contains(__repr__)) { patch__repr__(vm, cls); } if(!cls_d.contains(__repr__)) patch__repr__(vm, cls);
if(!cls_d.contains(__eq__)) { patch__eq__(vm, cls); } if(!cls_d.contains(__eq__)) patch__eq__(vm, cls);
const auto& fields = vm->_all_types[cls].annotated_fields; const auto& fields = vm->_all_types[cls].annotated_fields;
bool has_default = false; bool has_default = false;

View File

@ -23,7 +23,7 @@ static FILE* io_fopen(const char* name, const char* mode) {
#if _MSC_VER #if _MSC_VER
FILE* fp; FILE* fp;
errno_t err = fopen_s(&fp, name, mode); errno_t err = fopen_s(&fp, name, mode);
if(err != 0) { return nullptr; } if(err != 0) return nullptr;
return fp; return fp;
#else #else
return fopen(name, mode); return fopen(name, mode);
@ -40,9 +40,9 @@ static size_t io_fread(void* buffer, size_t size, size_t count, FILE* fp) {
unsigned char* _default_import_handler(const char* name, int* out_size) { unsigned char* _default_import_handler(const char* name, int* out_size) {
bool exists = std::filesystem::exists(std::filesystem::path(name)); bool exists = std::filesystem::exists(std::filesystem::path(name));
if(!exists) { return nullptr; } if(!exists) return nullptr;
FILE* fp = io_fopen(name, "rb"); FILE* fp = io_fopen(name, "rb");
if(!fp) { return nullptr; } if(!fp) return nullptr;
fseek(fp, 0, SEEK_END); fseek(fp, 0, SEEK_END);
int buffer_size = ftell(fp); int buffer_size = ftell(fp);
unsigned char* buffer = new unsigned char[buffer_size]; unsigned char* buffer = new unsigned char[buffer_size];
@ -96,7 +96,7 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind_func(type, "tell", 1, [](VM* vm, ArgsView args) { vm->bind_func(type, "tell", 1, [](VM* vm, ArgsView args) {
FileIO& io = PK_OBJ_GET(FileIO, args[0]); FileIO& io = PK_OBJ_GET(FileIO, args[0]);
long pos = ftell(io.fp); long pos = ftell(io.fp);
if(pos == -1) { vm->IOError(strerror(errno)); } if(pos == -1) vm->IOError(strerror(errno));
return VAR(pos); return VAR(pos);
}); });
@ -105,7 +105,7 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
long offset = CAST(long, args[1]); long offset = CAST(long, args[1]);
int whence = CAST(int, args[2]); int whence = CAST(int, args[2]);
int ret = fseek(io.fp, offset, whence); int ret = fseek(io.fp, offset, whence);
if(ret != 0) { vm->IOError(strerror(errno)); } if(ret != 0) vm->IOError(strerror(errno));
return vm->None; return vm->None;
}); });
@ -127,11 +127,11 @@ void FileIO::_register(VM* vm, PyObject* mod, PyObject* type) {
FileIO::FileIO(VM* vm, const Str& file, const Str& mode) { FileIO::FileIO(VM* vm, const Str& file, const Str& mode) {
this->is_text = mode.sv().find("b") == std::string::npos; this->is_text = mode.sv().find("b") == std::string::npos;
fp = io_fopen(file.c_str(), mode.c_str()); fp = io_fopen(file.c_str(), mode.c_str());
if(!fp) { vm->IOError(strerror(errno)); } if(!fp) vm->IOError(strerror(errno));
} }
void FileIO::close() { void FileIO::close() {
if(fp == nullptr) { return; } if(fp == nullptr) return;
fclose(fp); fclose(fp);
fp = nullptr; fp = nullptr;
} }
@ -172,30 +172,29 @@ void add_module_os(VM* vm) {
di = std::filesystem::directory_iterator(path); di = std::filesystem::directory_iterator(path);
} catch(std::filesystem::filesystem_error&) { vm->IOError(path.string()); } } catch(std::filesystem::filesystem_error&) { vm->IOError(path.string()); }
List ret; List ret;
for(auto& p: di) { for(auto& p: di)
ret.push_back(VAR(p.path().filename().string())); ret.push_back(VAR(p.path().filename().string()));
}
return VAR(std::move(ret)); return VAR(std::move(ret));
}); });
vm->bind_func(mod, "remove", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "remove", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
bool ok = std::filesystem::remove(path); bool ok = std::filesystem::remove(path);
if(!ok) { vm->IOError("operation failed"); } if(!ok) vm->IOError("operation failed");
return vm->None; return vm->None;
}); });
vm->bind_func(mod, "mkdir", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "mkdir", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
bool ok = std::filesystem::create_directory(path); bool ok = std::filesystem::create_directory(path);
if(!ok) { vm->IOError("operation failed"); } if(!ok) vm->IOError("operation failed");
return vm->None; return vm->None;
}); });
vm->bind_func(mod, "rmdir", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "rmdir", 1, [](VM* vm, ArgsView args) {
std::filesystem::path path(CAST(Str&, args[0]).sv()); std::filesystem::path path(CAST(Str&, args[0]).sv());
bool ok = std::filesystem::remove(path); bool ok = std::filesystem::remove(path);
if(!ok) { vm->IOError("operation failed"); } if(!ok) vm->IOError("operation failed");
return vm->None; return vm->None;
}); });

View File

@ -163,8 +163,8 @@ void Vec2::_register(VM* vm, PyObject* mod, PyObject* type) {
Vec2 __to = CAST(Vec2, args[1]); Vec2 __to = CAST(Vec2, args[1]);
float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x); float val = atan2f(__to.y, __to.x) - atan2f(__from.y, __from.x);
const float PI = 3.1415926535897932384f; const float PI = 3.1415926535897932384f;
if(val > PI) { val -= 2 * PI; } if(val > PI) val -= 2 * PI;
if(val < -PI) { val += 2 * PI; } if(val < -PI) val += 2 * PI;
return VAR(val); return VAR(val);
}, },
{}, {},
@ -284,21 +284,19 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
PY_STRUCT_LIKE(Mat3x3) PY_STRUCT_LIKE(Mat3x3)
vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args) { vm->bind_func(type, __new__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1 + 0) { return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros()); } if(args.size() == 1 + 0) return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros());
if(args.size() == 1 + 1) { if(args.size() == 1 + 1) {
const List& list = CAST(List&, args[1]); const List& list = CAST(List&, args[1]);
if(list.size() != 9) { vm->TypeError("Mat3x3.__new__ takes a list of 9 floats"); } if(list.size() != 9) vm->TypeError("Mat3x3.__new__ takes a list of 9 floats");
Mat3x3 mat; Mat3x3 mat;
for(int i = 0; i < 9; i++) { for(int i = 0; i < 9; i++)
mat.v[i] = CAST_F(list[i]); mat.v[i] = CAST_F(list[i]);
}
return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat); return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
} }
if(args.size() == 1 + 9) { if(args.size() == 1 + 9) {
Mat3x3 mat; Mat3x3 mat;
for(int i = 0; i < 9; i++) { for(int i = 0; i < 9; i++)
mat.v[i] = CAST_F(args[1 + i]); mat.v[i] = CAST_F(args[1 + i]);
}
return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat); return vm->new_object<Mat3x3>(PK_OBJ_GET(Type, args[0]), mat);
} }
vm->TypeError(_S("Mat3x3.__new__ takes 0 or 1 or 9 arguments, got ", args.size() - 1)); vm->TypeError(_S("Mat3x3.__new__ takes 0 or 1 or 9 arguments, got ", args.size() - 1));
@ -420,21 +418,21 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
vm->bind__invert__(type->as<Type>(), [](VM* vm, PyVar obj) { vm->bind__invert__(type->as<Type>(), [](VM* vm, PyVar obj) {
Mat3x3& self = _CAST(Mat3x3&, obj); Mat3x3& self = _CAST(Mat3x3&, obj);
Mat3x3 ret; Mat3x3 ret;
if(!self.inverse(ret)) { vm->ValueError("matrix is not invertible"); } if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
return vm->new_user_object<Mat3x3>(ret); return vm->new_user_object<Mat3x3>(ret);
}); });
vm->bind_func(type, "inverse", 1, [](VM* vm, ArgsView args) { vm->bind_func(type, "inverse", 1, [](VM* vm, ArgsView args) {
Mat3x3& self = _CAST(Mat3x3&, args[0]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
Mat3x3 ret; Mat3x3 ret;
if(!self.inverse(ret)) { vm->ValueError("matrix is not invertible"); } if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
return vm->new_user_object<Mat3x3>(ret); return vm->new_user_object<Mat3x3>(ret);
}); });
vm->bind_func(type, "inverse_", 1, [](VM* vm, ArgsView args) { vm->bind_func(type, "inverse_", 1, [](VM* vm, ArgsView args) {
Mat3x3& self = _CAST(Mat3x3&, args[0]); Mat3x3& self = _CAST(Mat3x3&, args[0]);
Mat3x3 ret; Mat3x3 ret;
if(!self.inverse(ret)) { vm->ValueError("matrix is not invertible"); } if(!self.inverse(ret)) vm->ValueError("matrix is not invertible");
self = ret; self = ret;
return vm->None; return vm->None;
}); });
@ -450,7 +448,9 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
type, type,
"zeros", "zeros",
0, 0,
[](VM* vm, ArgsView args) { return vm->new_user_object<Mat3x3>(Mat3x3::zeros()); }, [](VM* vm, ArgsView args) {
return vm->new_user_object<Mat3x3>(Mat3x3::zeros());
},
{}, {},
BindType::STATICMETHOD); BindType::STATICMETHOD);
@ -459,7 +459,9 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
type, type,
"ones", "ones",
0, 0,
[](VM* vm, ArgsView args) { return vm->new_user_object<Mat3x3>(Mat3x3::ones()); }, [](VM* vm, ArgsView args) {
return vm->new_user_object<Mat3x3>(Mat3x3::ones());
},
{}, {},
BindType::STATICMETHOD); BindType::STATICMETHOD);
@ -468,7 +470,9 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
type, type,
"identity", "identity",
0, 0,
[](VM* vm, ArgsView args) { return vm->new_user_object<Mat3x3>(Mat3x3::identity()); }, [](VM* vm, ArgsView args) {
return vm->new_user_object<Mat3x3>(Mat3x3::identity());
},
{}, {},
BindType::STATICMETHOD); BindType::STATICMETHOD);
@ -547,7 +551,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
const Mat3x3& self = _CAST(Mat3x3&, args[0]); const Mat3x3& self = _CAST(Mat3x3&, args[0]);
Vec2 v = CAST(Vec2, args[1]); Vec2 v = CAST(Vec2, args[1]);
Mat3x3 inv; Mat3x3 inv;
if(!self.inverse(inv)) { vm->ValueError("matrix is not invertible"); } if(!self.inverse(inv)) vm->ValueError("matrix is not invertible");
Vec2 res(inv._11 * v.x + inv._12 * v.y + inv._13, inv._21 * v.x + inv._22 * v.y + inv._23); Vec2 res(inv._11 * v.x + inv._12 * v.y + inv._13, inv._21 * v.x + inv._22 * v.y + inv._23);
return vm->new_user_object<Vec2>(res); return vm->new_user_object<Vec2>(res);
}); });
@ -563,7 +567,7 @@ void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type) {
const Mat3x3& self = _CAST(Mat3x3&, args[0]); const Mat3x3& self = _CAST(Mat3x3&, args[0]);
Vec2 v = CAST(Vec2, args[1]); Vec2 v = CAST(Vec2, args[1]);
Mat3x3 inv; Mat3x3 inv;
if(!self.inverse(inv)) { vm->ValueError("matrix is not invertible"); } if(!self.inverse(inv)) vm->ValueError("matrix is not invertible");
Vec2 res(inv._11 * v.x + inv._12 * v.y, inv._21 * v.x + inv._22 * v.y); Vec2 res(inv._11 * v.x + inv._12 * v.y, inv._21 * v.x + inv._22 * v.y);
return vm->new_user_object<Vec2>(res); return vm->new_user_object<Vec2>(res);
}); });
@ -596,46 +600,42 @@ Mat3x3 Mat3x3::identity() { return Mat3x3(1, 0, 0, 0, 1, 0, 0, 0, 1); }
Mat3x3 Mat3x3::operator+ (const Mat3x3& other) const { Mat3x3 Mat3x3::operator+ (const Mat3x3& other) const {
Mat3x3 ret; Mat3x3 ret;
for(int i = 0; i < 9; ++i) { for(int i = 0; i < 9; ++i)
ret.v[i] = v[i] + other.v[i]; ret.v[i] = v[i] + other.v[i];
}
return ret; return ret;
} }
Mat3x3 Mat3x3::operator- (const Mat3x3& other) const { Mat3x3 Mat3x3::operator- (const Mat3x3& other) const {
Mat3x3 ret; Mat3x3 ret;
for(int i = 0; i < 9; ++i) { for(int i = 0; i < 9; ++i)
ret.v[i] = v[i] - other.v[i]; ret.v[i] = v[i] - other.v[i];
}
return ret; return ret;
} }
Mat3x3 Mat3x3::operator* (float scalar) const { Mat3x3 Mat3x3::operator* (float scalar) const {
Mat3x3 ret; Mat3x3 ret;
for(int i = 0; i < 9; ++i) { for(int i = 0; i < 9; ++i)
ret.v[i] = v[i] * scalar; ret.v[i] = v[i] * scalar;
}
return ret; return ret;
} }
Mat3x3 Mat3x3::operator/ (float scalar) const { Mat3x3 Mat3x3::operator/ (float scalar) const {
Mat3x3 ret; Mat3x3 ret;
for(int i = 0; i < 9; ++i) { for(int i = 0; i < 9; ++i)
ret.v[i] = v[i] / scalar; ret.v[i] = v[i] / scalar;
}
return ret; return ret;
} }
bool Mat3x3::operator== (const Mat3x3& other) const { bool Mat3x3::operator== (const Mat3x3& other) const {
for(int i = 0; i < 9; ++i) { for(int i = 0; i < 9; ++i) {
if(!isclose(v[i], other.v[i])) { return false; } if(!isclose(v[i], other.v[i])) return false;
} }
return true; return true;
} }
bool Mat3x3::operator!= (const Mat3x3& other) const { bool Mat3x3::operator!= (const Mat3x3& other) const {
for(int i = 0; i < 9; ++i) { for(int i = 0; i < 9; ++i) {
if(!isclose(v[i], other.v[i])) { return true; } if(!isclose(v[i], other.v[i])) return true;
} }
return false; return false;
} }
@ -682,7 +682,7 @@ Mat3x3 Mat3x3::transpose() const {
bool Mat3x3::inverse(Mat3x3& out) const { bool Mat3x3::inverse(Mat3x3& out) const {
float det = determinant(); float det = determinant();
if(isclose(det, 0)) { return false; } if(isclose(det, 0)) return false;
float inv_det = 1.0f / det; float inv_det = 1.0f / det;
out._11 = (_22 * _33 - _23 * _32) * inv_det; out._11 = (_22 * _33 - _23 * _32) * inv_det;
out._12 = (_13 * _32 - _12 * _33) * inv_det; out._12 = (_13 * _32 - _12 * _33) * inv_det;
@ -704,7 +704,7 @@ Mat3x3 Mat3x3::trs(Vec2 t, float radian, Vec2 s) {
bool Mat3x3::is_affine() const { bool Mat3x3::is_affine() const {
float det = _11 * _22 - _12 * _21; float det = _11 * _22 - _12 * _21;
if(isclose(det, 0)) { return false; } if(isclose(det, 0)) return false;
return _31 == 0.0f && _32 == 0.0f && _33 == 1.0f; return _31 == 0.0f && _32 == 0.0f && _33 == 1.0f;
} }

View File

@ -62,7 +62,7 @@ void add_module_time(VM* vm) {
while(true) { while(true) {
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
f64 elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - begin).count() / 1000.0; f64 elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - begin).count() / 1000.0;
if(elapsed >= seconds) { break; } if(elapsed >= seconds) break;
} }
return vm->None; return vm->None;
}); });
@ -111,7 +111,9 @@ void add_module_json(VM* vm) {
return vm->_exec(code, vm->callstack.top()._module); return vm->_exec(code, vm->callstack.top()._module);
}); });
vm->bind_func(mod, "dumps", 1, [](VM* vm, ArgsView args) { return VAR(vm->py_json(args[0])); }); vm->bind_func(mod, "dumps", 1, [](VM* vm, ArgsView args) {
return VAR(vm->py_json(args[0]));
});
} }
// https://docs.python.org/3.5/library/math.html // https://docs.python.org/3.5/library/math.html
@ -141,8 +143,8 @@ void add_module_math(VM* vm) {
vm->bind_func(mod, "gcd", 2, [](VM* vm, ArgsView args) { vm->bind_func(mod, "gcd", 2, [](VM* vm, ArgsView args) {
i64 a = CAST(i64, args[0]); i64 a = CAST(i64, args[0]);
i64 b = CAST(i64, args[1]); i64 b = CAST(i64, args[1]);
if(a < 0) { a = -a; } if(a < 0) a = -a;
if(b < 0) { b = -b; } if(b < 0) b = -b;
while(b != 0) { while(b != 0) {
i64 t = b; i64 t = b;
b = a % b; b = a % b;
@ -195,11 +197,10 @@ void add_module_math(VM* vm) {
vm->bind_func(mod, "factorial", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "factorial", 1, [](VM* vm, ArgsView args) {
i64 n = CAST(i64, args[0]); i64 n = CAST(i64, args[0]);
if(n < 0) { vm->ValueError("factorial() not defined for negative values"); } if(n < 0) vm->ValueError("factorial() not defined for negative values");
i64 r = 1; i64 r = 1;
for(i64 i = 2; i <= n; i++) { for(i64 i = 2; i <= n; i++)
r *= i; r *= i;
}
return VAR(r); return VAR(r);
}); });
} }
@ -207,14 +208,14 @@ void add_module_math(VM* vm) {
void add_module_traceback(VM* vm) { void add_module_traceback(VM* vm) {
PyObject* mod = vm->new_module("traceback"); PyObject* mod = vm->new_module("traceback");
vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) { vm->bind_func(mod, "print_exc", 0, [](VM* vm, ArgsView args) {
if(vm->__last_exception == nullptr) { vm->ValueError("no exception"); } if(vm->__last_exception == nullptr) vm->ValueError("no exception");
Exception& e = vm->__last_exception->as<Exception>(); Exception& e = vm->__last_exception->as<Exception>();
vm->stdout_write(e.summary()); vm->stdout_write(e.summary());
return vm->None; return vm->None;
}); });
vm->bind_func(mod, "format_exc", 0, [](VM* vm, ArgsView args) { vm->bind_func(mod, "format_exc", 0, [](VM* vm, ArgsView args) {
if(vm->__last_exception == nullptr) { vm->ValueError("no exception"); } if(vm->__last_exception == nullptr) vm->ValueError("no exception");
Exception& e = vm->__last_exception->as<Exception>(); Exception& e = vm->__last_exception->as<Exception>();
return VAR(e.summary()); return VAR(e.summary());
}); });
@ -231,7 +232,7 @@ void add_module_dis(VM* vm) {
code = vm->compile(source, "<dis>", EXEC_MODE); code = vm->compile(source, "<dis>", EXEC_MODE);
} }
PyVar f = obj; PyVar f = obj;
if(is_type(f, vm->tp_bound_method)) { f = CAST(BoundMethod, obj).func; } if(is_type(f, vm->tp_bound_method)) f = CAST(BoundMethod, obj).func;
code = CAST(Function&, f).decl->code; code = CAST(Function&, f).decl->code;
vm->stdout_write(vm->disassemble(code)); vm->stdout_write(vm->disassemble(code));
return vm->None; return vm->None;
@ -254,7 +255,7 @@ void add_module_enum(VM* vm) {
for(auto [k, v]: attr.items()) { for(auto [k, v]: attr.items()) {
// wrap every attribute // wrap every attribute
std::string_view k_sv = k.sv(); std::string_view k_sv = k.sv();
if(k_sv.empty() || k_sv[0] == '_') { continue; } if(k_sv.empty() || k_sv[0] == '_') continue;
attr.set(k, vm->call(new_ti->obj, VAR(k_sv), v)); attr.set(k, vm->call(new_ti->obj, VAR(k_sv), v));
} }
}; };
@ -263,12 +264,14 @@ void add_module_enum(VM* vm) {
void add_module___builtins(VM* vm) { void add_module___builtins(VM* vm) {
PyObject* mod = vm->new_module("__builtins"); PyObject* mod = vm->new_module("__builtins");
vm->bind_func(mod, "next", 1, [](VM* vm, ArgsView args) { return vm->py_next(args[0]); }); vm->bind_func(mod, "next", 1, [](VM* vm, ArgsView args) {
return vm->py_next(args[0]);
});
vm->bind_func(mod, "_enable_instance_dict", 1, [](VM* vm, ArgsView args) { vm->bind_func(mod, "_enable_instance_dict", 1, [](VM* vm, ArgsView args) {
PyVar self = args[0]; PyVar self = args[0];
if(is_tagged(self)) { vm->TypeError("object: tagged object cannot enable instance dict"); } if(is_tagged(self)) vm->TypeError("object: tagged object cannot enable instance dict");
if(self->is_attr_valid()) { vm->RuntimeError("object: instance dict is already enabled"); } if(self->is_attr_valid()) vm->RuntimeError("object: instance dict is already enabled");
self->_attr = new NameDict(); self->_attr = new NameDict();
return vm->None; return vm->None;
}); });
@ -310,9 +313,8 @@ struct LineProfilerW {
const Tuple& args = CAST(Tuple&, view[2]); const Tuple& args = CAST(Tuple&, view[2]);
vm->s_data.push(func); vm->s_data.push(func);
vm->s_data.push(PY_NULL); vm->s_data.push(PY_NULL);
for(PyVar arg: args) { for(PyVar arg: args)
vm->s_data.push(arg); vm->s_data.push(arg);
}
_LpGuard guard(&self, vm); _LpGuard guard(&self, vm);
PyVar ret = vm->vectorcall(args.size()); PyVar ret = vm->vectorcall(args.size());
return ret; return ret;

View File

@ -69,9 +69,8 @@ struct mt19937 {
if(mti >= N) { /* generate N words at one time */ if(mti >= N) { /* generate N words at one time */
int kk; int kk;
if(mti == N + 1) { /* if init_genrand() has not been called, */ if(mti == N + 1) /* if init_genrand() has not been called, */
seed(5489UL); /* a default initial seed is used */ seed(5489UL); /* a default initial seed is used */
}
for(kk = 0; kk < N - M; kk++) { for(kk = 0; kk < N - M; kk++) {
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK); y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
@ -142,7 +141,7 @@ struct Random {
Random& self = PK_OBJ_GET(Random, args[0]); Random& self = PK_OBJ_GET(Random, args[0]);
i64 a = CAST(i64, args[1]); i64 a = CAST(i64, args[1]);
i64 b = CAST(i64, args[2]); i64 b = CAST(i64, args[2]);
if(a > b) { vm->ValueError("randint(a, b): a must be less than or equal to b"); } if(a > b) vm->ValueError("randint(a, b): a must be less than or equal to b");
return VAR(self.gen.randint(a, b)); return VAR(self.gen.randint(a, b));
}); });
@ -155,7 +154,7 @@ struct Random {
Random& self = PK_OBJ_GET(Random, args[0]); Random& self = PK_OBJ_GET(Random, args[0]);
f64 a = CAST(f64, args[1]); f64 a = CAST(f64, args[1]);
f64 b = CAST(f64, args[2]); f64 b = CAST(f64, args[2]);
if(a > b) { std::swap(a, b); } if(a > b) std::swap(a, b);
return VAR(self.gen.uniform(a, b)); return VAR(self.gen.uniform(a, b));
}); });
@ -172,7 +171,7 @@ struct Random {
vm->bind_func(type, "choice", 2, [](VM* vm, ArgsView args) { vm->bind_func(type, "choice", 2, [](VM* vm, ArgsView args) {
Random& self = PK_OBJ_GET(Random, args[0]); Random& self = PK_OBJ_GET(Random, args[0]);
ArgsView view = vm->cast_array_view(args[1]); ArgsView view = vm->cast_array_view(args[1]);
if(view.empty()) { vm->IndexError("cannot choose from an empty sequence"); } if(view.empty()) vm->IndexError("cannot choose from an empty sequence");
int index = self.gen.randint(0, view.size() - 1); int index = self.gen.randint(0, view.size() - 1);
return view[index]; return view[index];
}); });
@ -182,21 +181,20 @@ struct Random {
ArgsView view = vm->cast_array_view(args[1]); ArgsView view = vm->cast_array_view(args[1]);
PyVar* data = view.begin(); PyVar* data = view.begin();
int size = view.size(); int size = view.size();
if(size == 0) { vm->IndexError("cannot choose from an empty sequence"); } if(size == 0) vm->IndexError("cannot choose from an empty sequence");
array<f64> cum_weights(size); array<f64> cum_weights(size);
if(args[2] == vm->None) { if(args[2] == vm->None) {
for(int i = 0; i < size; i++) { for(int i = 0; i < size; i++)
cum_weights[i] = i + 1; cum_weights[i] = i + 1;
}
} else { } else {
ArgsView weights = vm->cast_array_view(args[2]); ArgsView weights = vm->cast_array_view(args[2]);
if(weights.size() != size) { vm->ValueError(_S("len(weights) != ", size)); } if(weights.size() != size) vm->ValueError(_S("len(weights) != ", size));
cum_weights[0] = CAST(f64, weights[0]); cum_weights[0] = CAST(f64, weights[0]);
for(int i = 1; i < size; i++) { for(int i = 1; i < size; i++) {
cum_weights[i] = cum_weights[i - 1] + CAST(f64, weights[i]); cum_weights[i] = cum_weights[i - 1] + CAST(f64, weights[i]);
} }
} }
if(cum_weights[size - 1] <= 0) { vm->ValueError("total of weights must be greater than zero"); } if(cum_weights[size - 1] <= 0) vm->ValueError("total of weights must be greater than zero");
int k = CAST(int, args[3]); int k = CAST(int, args[3]);
List result(k); List result(k);
for(int i = 0; i < k; i++) { for(int i = 0; i < k; i++) {

View File

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

View File

@ -3,7 +3,7 @@
namespace pkpy { namespace pkpy {
Str Exception::summary() const { Str Exception::summary() const {
SStream ss; SStream ss;
if(is_re) { ss << "Traceback (most recent call last):\n"; } if(is_re) ss << "Traceback (most recent call last):\n";
// while(!st.empty()) { // while(!st.empty()) {
// ss << st.top().snapshot() << '\n'; // ss << st.top().snapshot() << '\n';
// st.pop(); // st.pop();
@ -12,11 +12,10 @@ Str Exception::summary() const {
for(int i = container.size() - 1; i >= 0; i--) { for(int i = container.size() - 1; i >= 0; i--) {
ss << container[i].snapshot() << '\n'; ss << container[i].snapshot() << '\n';
} }
if(!msg.empty()) { if(!msg.empty())
ss << type.sv() << ": " << msg; ss << type.sv() << ": " << msg;
} else { else
ss << type.sv(); ss << type.sv();
}
return ss.str(); return ss.str();
} }

View File

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

View File

@ -15,9 +15,8 @@ Tuple::Tuple(Tuple&& other) noexcept {
_size = other._size; _size = other._size;
if(other.is_inlined()) { if(other.is_inlined()) {
_args = _inlined; _args = _inlined;
for(int i = 0; i < _size; i++) { for(int i = 0; i < _size; i++)
_args[i] = other._args[i]; _args[i] = other._args[i];
}
} else { } else {
_args = other._args; _args = other._args;
other._args = other._inlined; other._args = other._inlined;
@ -37,22 +36,20 @@ Tuple::Tuple(PyVar _0, PyVar _1, PyVar _2) : Tuple(3) {
} }
Tuple::~Tuple() { Tuple::~Tuple() {
if(!is_inlined()) { std::free(_args); } if(!is_inlined()) std::free(_args);
} }
List ArgsView::to_list() const { List ArgsView::to_list() const {
List ret(size()); List ret(size());
for(int i = 0; i < size(); i++) { for(int i = 0; i < size(); i++)
ret[i] = _begin[i]; ret[i] = _begin[i];
}
return ret; return ret;
} }
Tuple ArgsView::to_tuple() const { Tuple ArgsView::to_tuple() const {
Tuple ret(size()); Tuple ret(size());
for(int i = 0; i < size(); i++) { for(int i = 0; i < size(); i++)
ret[i] = _begin[i]; ret[i] = _begin[i];
}
return ret; return ret;
} }

View File

@ -37,11 +37,10 @@ PyVar PyArrayGetItem(VM* vm, PyVar _0, PyVar _1) {
List new_list; List new_list;
PK_SLICE_LOOP(i, start, stop, step) new_list.push_back(self[i]); PK_SLICE_LOOP(i, start, stop, step) new_list.push_back(self[i]);
if constexpr(std::is_same_v<T, List>) { if constexpr(std::is_same_v<T, List>)
return VAR(std::move(new_list)); return VAR(std::move(new_list));
} else { else
return VAR(new_list.to_tuple()); return VAR(new_list.to_tuple());
}
} }
vm->TypeError("indices must be integers or slices"); vm->TypeError("indices must be integers or slices");
} }
@ -104,7 +103,7 @@ void __init_builtins(VM* _vm) {
Frame* frame = &vm->callstack.top(); Frame* frame = &vm->callstack.top();
if(frame->_callable != nullptr) { if(frame->_callable != nullptr) {
class_arg = frame->_callable->as<Function>()._class; class_arg = frame->_callable->as<Function>()._class;
if(frame->_locals.size() > 0) { self_arg = frame->_locals[0]; } if(frame->_locals.size() > 0) self_arg = frame->_locals[0];
} }
if(class_arg == nullptr || self_arg == nullptr) { if(class_arg == nullptr || self_arg == nullptr) {
vm->TypeError("super(): unable to determine the class context, use super(class, self) instead"); vm->TypeError("super(): unable to determine the class context, use super(class, self) instead");
@ -139,7 +138,7 @@ void __init_builtins(VM* _vm) {
Tuple& types = _CAST(Tuple&, args[1]); Tuple& types = _CAST(Tuple&, args[1]);
for(PyVar type: types) { for(PyVar type: types) {
vm->check_type(type, vm->tp_type); vm->check_type(type, vm->tp_type);
if(vm->isinstance(args[0], type->as<Type>())) { return vm->True; } if(vm->isinstance(args[0], type->as<Type>())) return vm->True;
} }
return vm->False; return vm->False;
} }
@ -160,19 +159,19 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind(_vm->builtins, "round(x, ndigits=None)", [](VM* vm, ArgsView args) { _vm->bind(_vm->builtins, "round(x, ndigits=None)", [](VM* vm, ArgsView args) {
if(is_int(args[0])) { return args[0]; } if(is_int(args[0])) return args[0];
f64 x = CAST(f64, args[0]); f64 x = CAST(f64, args[0]);
f64 offset = x >= 0 ? 0.5 : -0.5; f64 offset = x >= 0 ? 0.5 : -0.5;
if(args[1] == vm->None) { return VAR((i64)(x + offset)); } if(args[1] == vm->None) return VAR((i64)(x + offset));
int ndigits = CAST(int, args[1]); int ndigits = CAST(int, args[1]);
if(ndigits < 0) { vm->ValueError("ndigits should be non-negative"); } if(ndigits < 0) vm->ValueError("ndigits should be non-negative");
// ndigits > 0 // ndigits > 0
return VAR((i64)(x * std::pow(10, ndigits) + offset) / std::pow(10, ndigits)); return VAR((i64)(x * std::pow(10, ndigits) + offset) / std::pow(10, ndigits));
}); });
_vm->bind_func(_vm->builtins, "abs", 1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "abs", 1, [](VM* vm, ArgsView args) {
if(is_int(args[0])) { return VAR(std::abs(_CAST(i64, args[0]))); } if(is_int(args[0])) return VAR(std::abs(_CAST(i64, args[0])));
if(is_float(args[0])) { return VAR(std::abs(_CAST(f64, args[0]))); } if(is_float(args[0])) return VAR(std::abs(_CAST(f64, args[0])));
vm->TypeError("bad operand type for abs()"); vm->TypeError("bad operand type for abs()");
return vm->None; return vm->None;
}); });
@ -187,11 +186,13 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(_vm->builtins, "id", 1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "id", 1, [](VM* vm, ArgsView args) {
PyVar obj = args[0]; PyVar obj = args[0];
if(is_tagged(obj)) { return vm->None; } if(is_tagged(obj)) return vm->None;
return VAR(reinterpret_cast<i64>(obj.get())); return VAR(reinterpret_cast<i64>(obj.get()));
}); });
_vm->bind_func(_vm->builtins, "callable", 1, [](VM* vm, ArgsView args) { return VAR(vm->py_callable(args[0])); }); _vm->bind_func(_vm->builtins, "callable", 1, [](VM* vm, ArgsView args) {
return VAR(vm->py_callable(args[0]));
});
_vm->bind_func(_vm->builtins, "__import__", 1, [](VM* vm, ArgsView args) -> PyVar { _vm->bind_func(_vm->builtins, "__import__", 1, [](VM* vm, ArgsView args) -> PyVar {
const Str& name = CAST(Str&, args[0]); const Str& name = CAST(Str&, args[0]);
@ -202,7 +203,7 @@ void __init_builtins(VM* _vm) {
if(is_int(args[0])) { if(is_int(args[0])) {
i64 lhs = _CAST(i64, args[0]); i64 lhs = _CAST(i64, args[0]);
i64 rhs = CAST(i64, args[1]); i64 rhs = CAST(i64, args[1]);
if(rhs == 0) { vm->ZeroDivisionError(); } if(rhs == 0) vm->ZeroDivisionError();
auto res = std::div(lhs, rhs); auto res = std::div(lhs, rhs);
return VAR(Tuple(VAR(res.quot), VAR(res.rem))); return VAR(Tuple(VAR(res.quot), VAR(res.rem)));
} else { } else {
@ -241,11 +242,13 @@ void __init_builtins(VM* _vm) {
return vm->None; return vm->None;
}); });
_vm->bind_func(_vm->builtins, "repr", 1, [](VM* vm, ArgsView args) { return VAR(vm->py_repr(args[0])); }); _vm->bind_func(_vm->builtins, "repr", 1, [](VM* vm, ArgsView args) {
return VAR(vm->py_repr(args[0]));
});
_vm->bind_func(_vm->builtins, "len", 1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "len", 1, [](VM* vm, ArgsView args) {
const PyTypeInfo* ti = vm->_tp_info(args[0]); const PyTypeInfo* ti = vm->_tp_info(args[0]);
if(ti->m__len__) { return VAR(ti->m__len__(vm, args[0])); } if(ti->m__len__) return VAR(ti->m__len__(vm, args[0]));
return vm->call_method(args[0], __len__); return vm->call_method(args[0], __len__);
}); });
@ -256,13 +259,13 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(_vm->builtins, "chr", 1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "chr", 1, [](VM* vm, ArgsView args) {
i64 i = CAST(i64, args[0]); i64 i = CAST(i64, args[0]);
if(i < 0 || i >= 128) { vm->ValueError("chr() arg not in [0, 128)"); } if(i < 0 || i >= 128) vm->ValueError("chr() arg not in [0, 128)");
return VAR(std::string(1, (char)i)); return VAR(std::string(1, (char)i));
}); });
_vm->bind_func(_vm->builtins, "ord", 1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "ord", 1, [](VM* vm, ArgsView args) {
const Str& s = CAST(Str&, args[0]); const Str& s = CAST(Str&, args[0]);
if(s.length() != 1) { vm->TypeError("ord() expected an ASCII character"); } if(s.length() != 1) vm->TypeError("ord() expected an ASCII character");
return VAR((i64)(s[0])); return VAR((i64)(s[0]));
}); });
@ -276,11 +279,11 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind_func(_vm->builtins, "getattr", -1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "getattr", -1, [](VM* vm, ArgsView args) {
if(args.size() != 2 && args.size() != 3) { vm->TypeError("getattr() takes 2 or 3 arguments"); } if(args.size() != 2 && args.size() != 3) vm->TypeError("getattr() takes 2 or 3 arguments");
StrName name = CAST(Str&, args[1]); StrName name = CAST(Str&, args[1]);
PyVar val = vm->getattr(args[0], name, false); PyVar val = vm->getattr(args[0], name, false);
if(val == nullptr) { if(val == nullptr) {
if(args.size() == 2) { vm->AttributeError(args[0], name); } if(args.size() == 2) vm->AttributeError(args[0], name);
return args[2]; return args[2];
} }
return val; return val;
@ -297,11 +300,13 @@ void __init_builtins(VM* _vm) {
return VAR(ss.str()); return VAR(ss.str());
}); });
_vm->bind_func(_vm->builtins, "iter", 1, [](VM* vm, ArgsView args) { return vm->py_iter(args[0]); }); _vm->bind_func(_vm->builtins, "iter", 1, [](VM* vm, ArgsView args) {
return vm->py_iter(args[0]);
});
_vm->bind_func(_vm->builtins, "next", 1, [](VM* vm, ArgsView args) { _vm->bind_func(_vm->builtins, "next", 1, [](VM* vm, ArgsView args) {
PyVar retval = vm->py_next(args[0]); PyVar retval = vm->py_next(args[0]);
if(retval == vm->StopIteration) { vm->_error(vm->call(vm->StopIteration)); } if(retval == vm->StopIteration) vm->_error(vm->call(vm->StopIteration));
return retval; return retval;
}); });
@ -319,7 +324,7 @@ void __init_builtins(VM* _vm) {
x >>= 1; x >>= 1;
} }
std::reverse(bits.begin(), bits.end()); std::reverse(bits.begin(), bits.end());
if(bits.empty()) { bits = "0"; } if(bits.empty()) bits = "0";
ss << bits; ss << bits;
return VAR(ss.str()); return VAR(ss.str());
}); });
@ -337,7 +342,7 @@ void __init_builtins(VM* _vm) {
List ret; List ret;
for(int i = 0; i < names.size(); i++) { for(int i = 0; i < names.size(); i++) {
// remove duplicates // remove duplicates
if(i > 0 && names[i] == names[i - 1]) { continue; } if(i > 0 && names[i] == names[i - 1]) continue;
ret.push_back(VAR(names[i].sv())); ret.push_back(VAR(names[i].sv()));
} }
return VAR(std::move(ret)); return VAR(std::move(ret));
@ -353,7 +358,9 @@ void __init_builtins(VM* _vm) {
return ss.str(); return ss.str();
}); });
_vm->bind__eq__(VM::tp_object, [](VM* vm, PyVar _0, PyVar _1) { return VAR(_0 == _1); }); _vm->bind__eq__(VM::tp_object, [](VM* vm, PyVar _0, PyVar _1) {
return VAR(_0 == _1);
});
_vm->__cached_object_new = _vm->bind_func(VM::tp_object, __new__, 1, [](VM* vm, ArgsView args) { _vm->__cached_object_new = _vm->bind_func(VM::tp_object, __new__, 1, [](VM* vm, ArgsView args) {
vm->check_type(args[0], vm->tp_type); vm->check_type(args[0], vm->tp_type);
@ -381,7 +388,7 @@ void __init_builtins(VM* _vm) {
break; break;
default: vm->TypeError("expected 1-3 arguments, got " + std::to_string(args.size())); default: vm->TypeError("expected 1-3 arguments, got " + std::to_string(args.size()));
} }
if(r.step == 0) { vm->ValueError("range() arg 3 must not be zero"); } if(r.step == 0) vm->ValueError("range() arg 3 must not be zero");
return VAR(r); return VAR(r);
}); });
@ -403,7 +410,9 @@ void __init_builtins(VM* _vm) {
}; };
// tp_nonetype // tp_nonetype
_vm->bind__repr__(_vm->_tp(_vm->None), [](VM* vm, PyVar _0) -> Str { return "None"; }); _vm->bind__repr__(_vm->_tp(_vm->None), [](VM* vm, PyVar _0) -> Str {
return "None";
});
// tp_float / tp_float // tp_float / tp_float
_vm->bind__truediv__(VM::tp_float, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__truediv__(VM::tp_float, [](VM* vm, PyVar _0, PyVar _1) {
@ -420,12 +429,12 @@ void __init_builtins(VM* _vm) {
i64 lhs = _CAST(i64, _0); i64 lhs = _CAST(i64, _0);
i64 rhs = _CAST(i64, _1); i64 rhs = _CAST(i64, _1);
if(rhs < 0) { if(rhs < 0) {
if(lhs == 0) { vm->ZeroDivisionError("0.0 cannot be raised to a negative power"); } if(lhs == 0) vm->ZeroDivisionError("0.0 cannot be raised to a negative power");
return VAR((f64)std::pow(lhs, rhs)); return VAR((f64)std::pow(lhs, rhs));
} }
i64 ret = 1; i64 ret = 1;
while(rhs) { while(rhs) {
if(rhs & 1) { ret *= lhs; } if(rhs & 1) ret *= lhs;
lhs *= lhs; lhs *= lhs;
rhs >>= 1; rhs >>= 1;
} }
@ -439,7 +448,7 @@ void __init_builtins(VM* _vm) {
_vm->bind__pow__(VM::tp_float, py_number_pow); _vm->bind__pow__(VM::tp_float, py_number_pow);
_vm->bind_func(VM::tp_int, __new__, -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_int, __new__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1 + 0) { return VAR(0); } if(args.size() == 1 + 0) return VAR(0);
// 1 arg // 1 arg
if(args.size() == 1 + 1) { if(args.size() == 1 + 1) {
switch(vm->_tp(args[1])) { switch(vm->_tp(args[1])) {
@ -451,10 +460,10 @@ void __init_builtins(VM* _vm) {
} }
} }
// 2+ args -> error // 2+ args -> error
if(args.size() > 1 + 2) { vm->TypeError("int() takes at most 2 arguments"); } if(args.size() > 1 + 2) vm->TypeError("int() takes at most 2 arguments");
// 1 or 2 args with str // 1 or 2 args with str
int base = 10; int base = 10;
if(args.size() == 1 + 2) { base = CAST(i64, args[2]); } if(args.size() == 1 + 2) base = CAST(i64, args[2]);
const Str& s = CAST(Str&, args[1]); const Str& s = CAST(Str&, args[1]);
std::string_view sv = s.sv(); std::string_view sv = s.sv();
bool negative = false; bool negative = false;
@ -466,25 +475,25 @@ void __init_builtins(VM* _vm) {
if(parse_uint(sv, &val, base) != IntParsingResult::Success) { if(parse_uint(sv, &val, base) != IntParsingResult::Success) {
vm->ValueError(_S("invalid literal for int() with base ", base, ": ", s.escape())); vm->ValueError(_S("invalid literal for int() with base ", base, ": ", s.escape()));
} }
if(negative) { val = -val; } if(negative) val = -val;
return VAR(val); return VAR(val);
}); });
_vm->bind__floordiv__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__floordiv__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) {
i64 rhs = CAST(i64, _1); i64 rhs = CAST(i64, _1);
if(rhs == 0) { vm->ZeroDivisionError(); } if(rhs == 0) vm->ZeroDivisionError();
return VAR(_CAST(i64, _0) / rhs); return VAR(_CAST(i64, _0) / rhs);
}); });
_vm->bind__mod__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__mod__(VM::tp_int, [](VM* vm, PyVar _0, PyVar _1) {
i64 rhs = CAST(i64, _1); i64 rhs = CAST(i64, _1);
if(rhs == 0) { vm->ZeroDivisionError(); } if(rhs == 0) vm->ZeroDivisionError();
return VAR(_CAST(i64, _0) % rhs); return VAR(_CAST(i64, _0) % rhs);
}); });
_vm->bind_func(VM::tp_int, "bit_length", 1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_int, "bit_length", 1, [](VM* vm, ArgsView args) {
i64 x = _CAST(i64, args[0]); i64 x = _CAST(i64, args[0]);
if(x < 0) { x = -x; } if(x < 0) x = -x;
int bits = 0; int bits = 0;
while(x) { while(x) {
x >>= 1; x >>= 1;
@ -493,13 +502,23 @@ void __init_builtins(VM* _vm) {
return VAR(bits); return VAR(bits);
}); });
_vm->bind__repr__(VM::tp_int, [](VM* vm, PyVar obj) -> Str { return std::to_string(_CAST(i64, obj)); }); _vm->bind__repr__(VM::tp_int, [](VM* vm, PyVar obj) -> Str {
_vm->bind__neg__(VM::tp_int, [](VM* vm, PyVar obj) { return VAR(-_CAST(i64, obj)); }); return std::to_string(_CAST(i64, obj));
_vm->bind__hash__(VM::tp_int, [](VM* vm, PyVar obj) { return _CAST(i64, obj); }); });
_vm->bind__invert__(VM::tp_int, [](VM* vm, PyVar obj) { return VAR(~_CAST(i64, obj)); }); _vm->bind__neg__(VM::tp_int, [](VM* vm, PyVar obj) {
return VAR(-_CAST(i64, obj));
});
_vm->bind__hash__(VM::tp_int, [](VM* vm, PyVar obj) {
return _CAST(i64, obj);
});
_vm->bind__invert__(VM::tp_int, [](VM* vm, PyVar obj) {
return VAR(~_CAST(i64, obj));
});
#define INT_BITWISE_OP(name, op) \ #define INT_BITWISE_OP(name, op) \
_vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { return VAR(_CAST(i64, lhs) op CAST(i64, rhs)); }); _vm->bind##name(VM::tp_int, [](VM* vm, PyVar lhs, PyVar rhs) { \
return VAR(_CAST(i64, lhs) op CAST(i64, rhs)); \
});
INT_BITWISE_OP(__lshift__, <<) INT_BITWISE_OP(__lshift__, <<)
INT_BITWISE_OP(__rshift__, >>) INT_BITWISE_OP(__rshift__, >>)
@ -510,8 +529,8 @@ void __init_builtins(VM* _vm) {
#undef INT_BITWISE_OP #undef INT_BITWISE_OP
_vm->bind_func(VM::tp_float, __new__, -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_float, __new__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1 + 0) { return VAR(0.0); } if(args.size() == 1 + 0) return VAR(0.0);
if(args.size() > 1 + 1) { vm->TypeError("float() takes at most 1 argument"); } if(args.size() > 1 + 1) vm->TypeError("float() takes at most 1 argument");
// 1 arg // 1 arg
switch(vm->_tp(args[1])) { switch(vm->_tp(args[1])) {
case VM::tp_int: return VAR((f64)CAST(i64, args[1])); case VM::tp_int: return VAR((f64)CAST(i64, args[1]));
@ -522,14 +541,14 @@ void __init_builtins(VM* _vm) {
} }
// str to float // str to float
const Str& s = PK_OBJ_GET(Str, args[1]); const Str& s = PK_OBJ_GET(Str, args[1]);
if(s == "inf") { return VAR(INFINITY); } if(s == "inf") return VAR(INFINITY);
if(s == "-inf") { return VAR(-INFINITY); } if(s == "-inf") return VAR(-INFINITY);
double float_out; double float_out;
char* p_end; char* p_end;
try { try {
float_out = std::strtod(s.data, &p_end); float_out = std::strtod(s.data, &p_end);
if(p_end != s.end()) { throw 1; } if(p_end != s.end()) throw 1;
} catch(...) { vm->ValueError("invalid literal for float(): " + s.escape()); } } catch(...) { vm->ValueError("invalid literal for float(): " + s.escape()); }
return VAR(float_out); return VAR(float_out);
}); });
@ -539,7 +558,9 @@ void __init_builtins(VM* _vm) {
return (i64)std::hash<f64>()(val); return (i64)std::hash<f64>()(val);
}); });
_vm->bind__neg__(VM::tp_float, [](VM* vm, PyVar _0) { return VAR(-_CAST(f64, _0)); }); _vm->bind__neg__(VM::tp_float, [](VM* vm, PyVar _0) {
return VAR(-_CAST(f64, _0));
});
_vm->bind__repr__(VM::tp_float, [](VM* vm, PyVar _0) -> Str { _vm->bind__repr__(VM::tp_float, [](VM* vm, PyVar _0) -> Str {
f64 val = _CAST(f64, _0); f64 val = _CAST(f64, _0);
@ -550,31 +571,35 @@ void __init_builtins(VM* _vm) {
// tp_str // tp_str
_vm->bind_func(VM::tp_str, __new__, -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_str, __new__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1) { return VAR(Str()); } if(args.size() == 1) return VAR(Str());
if(args.size() > 2) { vm->TypeError("str() takes at most 1 argument"); } if(args.size() > 2) vm->TypeError("str() takes at most 1 argument");
return VAR(vm->py_str(args[1])); return VAR(vm->py_str(args[1]));
}); });
_vm->bind__hash__(VM::tp_str, [](VM* vm, PyVar _0) { return (i64)_CAST(Str&, _0).hash(); }); _vm->bind__hash__(VM::tp_str, [](VM* vm, PyVar _0) {
return (i64)_CAST(Str&, _0).hash();
});
_vm->bind__add__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) { return VAR(_CAST(Str&, _0) + CAST(Str&, _1)); }); _vm->bind__add__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) {
_vm->bind__len__(VM::tp_str, [](VM* vm, PyVar _0) { return (i64)_CAST(Str&, _0).u8_length(); }); return VAR(_CAST(Str&, _0) + CAST(Str&, _1));
});
_vm->bind__len__(VM::tp_str, [](VM* vm, PyVar _0) {
return (i64)_CAST(Str&, _0).u8_length();
});
_vm->bind__mul__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__mul__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) {
const Str& self = _CAST(Str&, _0); const Str& self = _CAST(Str&, _0);
i64 n = CAST(i64, _1); i64 n = CAST(i64, _1);
SStream ss; SStream ss;
for(i64 i = 0; i < n; i++) { for(i64 i = 0; i < n; i++)
ss << self.sv(); ss << self.sv();
}
return VAR(ss.str()); return VAR(ss.str());
}); });
_vm->bind_func(VM::tp_str, "__rmul__", 2, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_str, "__rmul__", 2, [](VM* vm, ArgsView args) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
i64 n = CAST(i64, args[1]); i64 n = CAST(i64, args[1]);
SStream ss; SStream ss;
for(i64 i = 0; i < n; i++) { for(i64 i = 0; i < n; i++)
ss << self.sv(); ss << self.sv();
}
return VAR(ss.str()); return VAR(ss.str());
}); });
_vm->bind__contains__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__contains__(VM::tp_str, [](VM* vm, PyVar _0, PyVar _1) {
@ -582,8 +607,12 @@ void __init_builtins(VM* _vm) {
return VAR(self.index(CAST(Str&, _1)) != -1); return VAR(self.index(CAST(Str&, _1)) != -1);
}); });
_vm->bind_func(VM::tp_str, __str__, 1, [](VM* vm, ArgsView args) { return args[0]; }); _vm->bind_func(VM::tp_str, __str__, 1, [](VM* vm, ArgsView args) {
_vm->bind__iter__(VM::tp_str, [](VM* vm, PyVar _0) { return vm->new_user_object<StringIter>(_0); }); return args[0];
});
_vm->bind__iter__(VM::tp_str, [](VM* vm, PyVar _0) {
return vm->new_user_object<StringIter>(_0);
});
_vm->bind__repr__(VM::tp_str, [](VM* vm, PyVar _0) -> Str { _vm->bind__repr__(VM::tp_str, [](VM* vm, PyVar _0) -> Str {
const Str& self = _CAST(Str&, _0); const Str& self = _CAST(Str&, _0);
return self.escape(); return self.escape();
@ -618,7 +647,7 @@ void __init_builtins(VM* _vm) {
_vm->bind(_vm->_t(VM::tp_str), "replace(self, old, new, count=-1)", [](VM* vm, ArgsView args) { _vm->bind(_vm->_t(VM::tp_str), "replace(self, old, new, count=-1)", [](VM* vm, ArgsView args) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
const Str& old = CAST(Str&, args[1]); const Str& old = CAST(Str&, args[1]);
if(old.empty()) { vm->ValueError("empty substring"); } if(old.empty()) vm->ValueError("empty substring");
const Str& new_ = CAST(Str&, args[2]); const Str& new_ = CAST(Str&, args[2]);
int count = CAST(int, args[3]); int count = CAST(int, args[3]);
return VAR(self.replace(old, new_, count)); return VAR(self.replace(old, new_, count));
@ -627,7 +656,7 @@ void __init_builtins(VM* _vm) {
_vm->bind(_vm->_t(VM::tp_str), "split(self, sep=' ')", [](VM* vm, ArgsView args) { _vm->bind(_vm->_t(VM::tp_str), "split(self, sep=' ')", [](VM* vm, ArgsView args) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
const Str& sep = CAST(Str&, args[1]); const Str& sep = CAST(Str&, args[1]);
if(sep.empty()) { vm->ValueError("empty separator"); } if(sep.empty()) vm->ValueError("empty separator");
vector<std::string_view> parts; vector<std::string_view> parts;
if(sep.size == 1) { if(sep.size == 1) {
parts = self.split(sep[0]); parts = self.split(sep[0]);
@ -635,9 +664,8 @@ void __init_builtins(VM* _vm) {
parts = self.split(sep); parts = self.split(sep);
} }
List ret(parts.size()); List ret(parts.size());
for(int i = 0; i < parts.size(); i++) { for(int i = 0; i < parts.size(); i++)
ret[i] = VAR(Str(parts[i])); ret[i] = VAR(Str(parts[i]));
}
return VAR(std::move(ret)); return VAR(std::move(ret));
}); });
@ -645,9 +673,8 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
vector<std::string_view> parts = self.split('\n'); vector<std::string_view> parts = self.split('\n');
List ret(parts.size()); List ret(parts.size());
for(int i = 0; i < parts.size(); i++) { for(int i = 0; i < parts.size(); i++)
ret[i] = VAR(Str(parts[i])); ret[i] = VAR(Str(parts[i]));
}
return VAR(std::move(ret)); return VAR(std::move(ret));
}); });
@ -661,9 +688,9 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
const Str& value = CAST(Str&, args[1]); const Str& value = CAST(Str&, args[1]);
int start = CAST(int, args[2]); int start = CAST(int, args[2]);
if(start < 0) { vm->ValueError("argument 'start' can't be negative"); } if(start < 0) vm->ValueError("argument 'start' can't be negative");
int index = self.index(value, start); int index = self.index(value, start);
if(index < 0) { vm->ValueError("substring not found"); } if(index < 0) vm->ValueError("substring not found");
return VAR(index); return VAR(index);
}); });
@ -671,7 +698,7 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
const Str& value = CAST(Str&, args[1]); const Str& value = CAST(Str&, args[1]);
int start = CAST(int, args[2]); int start = CAST(int, args[2]);
if(start < 0) { vm->ValueError("argument 'start' can't be negative"); } if(start < 0) vm->ValueError("argument 'start' can't be negative");
return VAR(self.index(value, start)); return VAR(self.index(value, start));
}); });
@ -685,7 +712,7 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
const Str& suffix = CAST(Str&, args[1]); const Str& suffix = CAST(Str&, args[1]);
int offset = self.length() - suffix.length(); int offset = self.length() - suffix.length();
if(offset < 0) { return vm->False; } if(offset < 0) return vm->False;
bool ok = memcmp(self.data + offset, suffix.data, suffix.length()) == 0; bool ok = memcmp(self.data + offset, suffix.data, suffix.length()) == 0;
return VAR(ok); return VAR(ok);
}); });
@ -705,7 +732,7 @@ void __init_builtins(VM* _vm) {
const PyTypeInfo* info = vm->_tp_info(args[1]); const PyTypeInfo* info = vm->_tp_info(args[1]);
PyVar obj = vm->_py_next(info, it); PyVar obj = vm->_py_next(info, it);
while(obj != vm->StopIteration) { while(obj != vm->StopIteration) {
if(!ss.empty()) { ss << self; } if(!ss.empty()) ss << self;
ss << CAST(Str&, obj); ss << CAST(Str&, obj);
obj = vm->_py_next(info, it); obj = vm->_py_next(info, it);
} }
@ -757,11 +784,10 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
int width = CAST(int, args[1]); int width = CAST(int, args[1]);
int delta = width - self.u8_length(); int delta = width - self.u8_length();
if(delta <= 0) { return args[0]; } if(delta <= 0) return args[0];
SStream ss; SStream ss;
for(int i = 0; i < delta; i++) { for(int i = 0; i < delta; i++)
ss << '0'; ss << '0';
}
ss << self; ss << self;
return VAR(ss.str()); return VAR(ss.str());
}); });
@ -771,14 +797,13 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
int width = CAST(int, args[1]); int width = CAST(int, args[1]);
int delta = width - self.u8_length(); int delta = width - self.u8_length();
if(delta <= 0) { return args[0]; } if(delta <= 0) return args[0];
const Str& fillchar = CAST(Str&, args[2]); const Str& fillchar = CAST(Str&, args[2]);
if(fillchar.u8_length() != 1) { vm->TypeError("The fill character must be exactly one character long"); } if(fillchar.u8_length() != 1) vm->TypeError("The fill character must be exactly one character long");
SStream ss; SStream ss;
ss << self; ss << self;
for(int i = 0; i < delta; i++) { for(int i = 0; i < delta; i++)
ss << fillchar; ss << fillchar;
}
return VAR(ss.str()); return VAR(ss.str());
}); });
@ -787,13 +812,12 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
int width = CAST(int, args[1]); int width = CAST(int, args[1]);
int delta = width - self.u8_length(); int delta = width - self.u8_length();
if(delta <= 0) { return args[0]; } if(delta <= 0) return args[0];
const Str& fillchar = CAST(Str&, args[2]); const Str& fillchar = CAST(Str&, args[2]);
if(fillchar.u8_length() != 1) { vm->TypeError("The fill character must be exactly one character long"); } if(fillchar.u8_length() != 1) vm->TypeError("The fill character must be exactly one character long");
SStream ss; SStream ss;
for(int i = 0; i < delta; i++) { for(int i = 0; i < delta; i++)
ss << fillchar; ss << fillchar;
}
ss << self; ss << self;
return VAR(ss.str()); return VAR(ss.str());
}); });
@ -803,7 +827,9 @@ void __init_builtins(VM* _vm) {
List& self = _CAST(List&, args[0]); List& self = _CAST(List&, args[0]);
PyVar key = args[1]; PyVar key = args[1];
if(key == vm->None) { if(key == vm->None) {
std::stable_sort(self.begin(), self.end(), [vm](PyVar a, PyVar b) { return vm->py_lt(a, b); }); std::stable_sort(self.begin(), self.end(), [vm](PyVar a, PyVar b) {
return vm->py_lt(a, b);
});
} else { } else {
std::stable_sort(self.begin(), self.end(), [vm, key](PyVar a, PyVar b) { std::stable_sort(self.begin(), self.end(), [vm, key](PyVar a, PyVar b) {
return vm->py_lt(vm->call(key, a), vm->call(key, b)); return vm->py_lt(vm->call(key, a), vm->call(key, b));
@ -815,14 +841,14 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind__repr__(VM::tp_list, [](VM* vm, PyVar _0) -> Str { _vm->bind__repr__(VM::tp_list, [](VM* vm, PyVar _0) -> Str {
if(vm->_repr_recursion_set.contains(_0)) { return "[...]"; } if(vm->_repr_recursion_set.contains(_0)) return "[...]";
List& iterable = _CAST(List&, _0); List& iterable = _CAST(List&, _0);
SStream ss; SStream ss;
ss << '['; ss << '[';
vm->_repr_recursion_set.push_back(_0); vm->_repr_recursion_set.push_back(_0);
for(int i = 0; i < iterable.size(); i++) { for(int i = 0; i < iterable.size(); i++) {
ss << vm->py_repr(iterable[i]); ss << vm->py_repr(iterable[i]);
if(i != iterable.size() - 1) { ss << ", "; } if(i != iterable.size() - 1) ss << ", ";
} }
vm->_repr_recursion_set.pop_back(); vm->_repr_recursion_set.pop_back();
ss << ']'; ss << ']';
@ -839,7 +865,7 @@ void __init_builtins(VM* _vm) {
} else { } else {
for(int i = 0; i < iterable.size(); i++) { for(int i = 0; i < iterable.size(); i++) {
ss << vm->py_repr(iterable[i]); ss << vm->py_repr(iterable[i]);
if(i != iterable.size() - 1) { ss << ", "; } if(i != iterable.size() - 1) ss << ", ";
} }
} }
ss << ')'; ss << ')';
@ -847,36 +873,34 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind_func(VM::tp_list, __new__, -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_list, __new__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1 + 0) { return VAR(List()); } if(args.size() == 1 + 0) return VAR(List());
if(args.size() == 1 + 1) { return VAR(vm->py_list(args[1])); } if(args.size() == 1 + 1) return VAR(vm->py_list(args[1]));
vm->TypeError("list() takes 0 or 1 arguments"); vm->TypeError("list() takes 0 or 1 arguments");
return vm->None; return vm->None;
}); });
_vm->bind__contains__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__contains__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
List& self = _CAST(List&, _0); List& self = _CAST(List&, _0);
for(PyVar i: self) { for(PyVar i: self)
if(vm->py_eq(i, _1)) { return vm->True; } if(vm->py_eq(i, _1)) return vm->True;
}
return vm->False; return vm->False;
}); });
_vm->bind_func(VM::tp_list, "count", 2, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_list, "count", 2, [](VM* vm, ArgsView args) {
List& self = _CAST(List&, args[0]); List& self = _CAST(List&, args[0]);
int count = 0; int count = 0;
for(PyVar i: self) { for(PyVar i: self)
if(vm->py_eq(i, args[1])) { count++; } if(vm->py_eq(i, args[1])) count++;
}
return VAR(count); return VAR(count);
}); });
_vm->bind__eq__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__eq__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
List& a = _CAST(List&, _0); List& a = _CAST(List&, _0);
if(!is_type(_1, vm->tp_list)) { return vm->NotImplemented; } if(!is_type(_1, vm->tp_list)) return vm->NotImplemented;
List& b = _CAST(List&, _1); List& b = _CAST(List&, _1);
if(a.size() != b.size()) { return vm->False; } if(a.size() != b.size()) return vm->False;
for(int i = 0; i < a.size(); i++) { for(int i = 0; i < a.size(); i++) {
if(!vm->py_eq(a[i], b[i])) { return vm->False; } if(!vm->py_eq(a[i], b[i])) return vm->False;
} }
return vm->True; return vm->True;
}); });
@ -886,7 +910,7 @@ void __init_builtins(VM* _vm) {
PyVar obj = args[1]; PyVar obj = args[1];
int start = CAST(int, args[2]); int start = CAST(int, args[2]);
for(int i = start; i < self.size(); i++) { for(int i = start; i < self.size(); i++) {
if(vm->py_eq(self[i], obj)) { return VAR(i); } if(vm->py_eq(self[i], obj)) return VAR(i);
} }
vm->ValueError(vm->py_repr(obj) + " is not in list"); vm->ValueError(vm->py_repr(obj) + " is not in list");
return vm->None; return vm->None;
@ -908,7 +932,7 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(VM::tp_list, "pop", -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_list, "pop", -1, [](VM* vm, ArgsView args) {
List& self = _CAST(List&, args[0]); List& self = _CAST(List&, args[0]);
if(args.size() == 1 + 0) { if(args.size() == 1 + 0) {
if(self.empty()) { vm->IndexError("pop from empty list"); } if(self.empty()) vm->IndexError("pop from empty list");
PyVar retval = self.back(); PyVar retval = self.back();
self.pop_back(); self.pop_back();
return retval; return retval;
@ -951,33 +975,31 @@ void __init_builtins(VM* _vm) {
_vm->bind__mul__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__mul__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
const List& self = _CAST(List&, _0); const List& self = _CAST(List&, _0);
if(!is_int(_1)) { return vm->NotImplemented; } if(!is_int(_1)) return vm->NotImplemented;
int n = _CAST(int, _1); int n = _CAST(int, _1);
List result; List result;
result.reserve(self.size() * n); result.reserve(self.size() * n);
for(int i = 0; i < n; i++) { for(int i = 0; i < n; i++)
result.extend(self.begin(), self.end()); result.extend(self.begin(), self.end());
}
return VAR(std::move(result)); return VAR(std::move(result));
}); });
_vm->bind_func(VM::tp_list, "__rmul__", 2, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_list, "__rmul__", 2, [](VM* vm, ArgsView args) {
const List& self = _CAST(List&, args[0]); const List& self = _CAST(List&, args[0]);
if(!is_int(args[1])) { return vm->NotImplemented; } if(!is_int(args[1])) return vm->NotImplemented;
int n = _CAST(int, args[1]); int n = _CAST(int, args[1]);
List result; List result;
result.reserve(self.size() * n); result.reserve(self.size() * n);
for(int i = 0; i < n; i++) { for(int i = 0; i < n; i++)
result.extend(self.begin(), self.end()); result.extend(self.begin(), self.end());
}
return VAR(std::move(result)); return VAR(std::move(result));
}); });
_vm->bind_func(VM::tp_list, "insert", 3, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_list, "insert", 3, [](VM* vm, ArgsView args) {
List& self = _CAST(List&, args[0]); List& self = _CAST(List&, args[0]);
int index = CAST(int, args[1]); int index = CAST(int, args[1]);
if(index < 0) { index += self.size(); } if(index < 0) index += self.size();
if(index < 0) { index = 0; } if(index < 0) index = 0;
if(index > self.size()) { index = self.size(); } if(index > self.size()) index = self.size();
self.insert(index, args[2]); self.insert(index, args[2]);
return vm->None; return vm->None;
}); });
@ -1024,7 +1046,9 @@ void __init_builtins(VM* _vm) {
return VAR(std::move(new_list)); return VAR(std::move(new_list));
}); });
_vm->bind__len__(VM::tp_list, [](VM* vm, PyVar _0) { return (i64)_CAST(List&, _0).size(); }); _vm->bind__len__(VM::tp_list, [](VM* vm, PyVar _0) {
return (i64)_CAST(List&, _0).size();
});
_vm->bind__iter__(VM::tp_list, [](VM* vm, PyVar _0) { _vm->bind__iter__(VM::tp_list, [](VM* vm, PyVar _0) {
List& self = _CAST(List&, _0); List& self = _CAST(List&, _0);
return vm->new_user_object<ArrayIter>(_0.get(), self.begin(), self.end()); return vm->new_user_object<ArrayIter>(_0.get(), self.begin(), self.end());
@ -1049,7 +1073,7 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind_func(VM::tp_tuple, __new__, -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_tuple, __new__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1 + 0) { return VAR(Tuple(0)); } if(args.size() == 1 + 0) return VAR(Tuple(0));
if(args.size() == 1 + 1) { if(args.size() == 1 + 1) {
List list = vm->py_list(args[1]); List list = vm->py_list(args[1]);
return VAR(list.to_tuple()); return VAR(list.to_tuple());
@ -1060,28 +1084,26 @@ void __init_builtins(VM* _vm) {
_vm->bind__contains__(VM::tp_tuple, [](VM* vm, PyVar obj, PyVar item) { _vm->bind__contains__(VM::tp_tuple, [](VM* vm, PyVar obj, PyVar item) {
Tuple& self = _CAST(Tuple&, obj); Tuple& self = _CAST(Tuple&, obj);
for(PyVar i: self) { for(PyVar i: self)
if(vm->py_eq(i, item)) { return vm->True; } if(vm->py_eq(i, item)) return vm->True;
}
return vm->False; return vm->False;
}); });
_vm->bind_func(VM::tp_tuple, "count", 2, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_tuple, "count", 2, [](VM* vm, ArgsView args) {
Tuple& self = _CAST(Tuple&, args[0]); Tuple& self = _CAST(Tuple&, args[0]);
int count = 0; int count = 0;
for(PyVar i: self) { for(PyVar i: self)
if(vm->py_eq(i, args[1])) { count++; } if(vm->py_eq(i, args[1])) count++;
}
return VAR(count); return VAR(count);
}); });
_vm->bind__eq__(VM::tp_tuple, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__eq__(VM::tp_tuple, [](VM* vm, PyVar _0, PyVar _1) {
const Tuple& self = _CAST(Tuple&, _0); const Tuple& self = _CAST(Tuple&, _0);
if(!is_type(_1, vm->tp_tuple)) { return vm->NotImplemented; } if(!is_type(_1, vm->tp_tuple)) return vm->NotImplemented;
const Tuple& other = _CAST(Tuple&, _1); const Tuple& other = _CAST(Tuple&, _1);
if(self.size() != other.size()) { return vm->False; } if(self.size() != other.size()) return vm->False;
for(int i = 0; i < self.size(); i++) { for(int i = 0; i < self.size(); i++) {
if(!vm->py_eq(self[i], other[i])) { return vm->False; } if(!vm->py_eq(self[i], other[i])) return vm->False;
} }
return vm->True; return vm->True;
}); });
@ -1106,28 +1128,42 @@ void __init_builtins(VM* _vm) {
}; };
_vm->bind__getitem__(VM::tp_tuple, PyArrayGetItem<Tuple>); _vm->bind__getitem__(VM::tp_tuple, PyArrayGetItem<Tuple>);
_vm->bind__len__(VM::tp_tuple, [](VM* vm, PyVar obj) { return (i64)_CAST(Tuple&, obj).size(); }); _vm->bind__len__(VM::tp_tuple, [](VM* vm, PyVar obj) {
return (i64)_CAST(Tuple&, obj).size();
});
// tp_bool // tp_bool
_vm->bind_func(VM::tp_bool, __new__, 2, PK_LAMBDA(VAR(vm->py_bool(args[1])))); _vm->bind_func(VM::tp_bool, __new__, 2, PK_LAMBDA(VAR(vm->py_bool(args[1]))));
_vm->bind__hash__(VM::tp_bool, [](VM* vm, PyVar _0) { return (i64)_CAST(bool, _0); }); _vm->bind__hash__(VM::tp_bool, [](VM* vm, PyVar _0) {
return (i64)_CAST(bool, _0);
});
_vm->bind__repr__(VM::tp_bool, [](VM* vm, PyVar _0) -> Str { _vm->bind__repr__(VM::tp_bool, [](VM* vm, PyVar _0) -> Str {
bool val = _CAST(bool, _0); bool val = _CAST(bool, _0);
return val ? "True" : "False"; return val ? "True" : "False";
}); });
_vm->bind__and__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) { return VAR(_CAST(bool, _0) && CAST(bool, _1)); }); _vm->bind__and__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) {
_vm->bind__or__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) { return VAR(_CAST(bool, _0) || CAST(bool, _1)); }); return VAR(_CAST(bool, _0) && CAST(bool, _1));
_vm->bind__xor__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) { return VAR(_CAST(bool, _0) != CAST(bool, _1)); }); });
_vm->bind__or__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) {
return VAR(_CAST(bool, _0) || CAST(bool, _1));
});
_vm->bind__xor__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) {
return VAR(_CAST(bool, _0) != CAST(bool, _1));
});
_vm->bind__eq__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__eq__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) {
if(is_type(_1, vm->tp_bool)) { return VAR(_0 == _1); } if(is_type(_1, vm->tp_bool)) return VAR(_0 == _1);
if(is_int(_1)) { return VAR(_CAST(bool, _0) == (bool)CAST(i64, _1)); } if(is_int(_1)) return VAR(_CAST(bool, _0) == (bool)CAST(i64, _1));
return vm->NotImplemented; return vm->NotImplemented;
}); });
// tp_ellipsis / tp_NotImplementedType // tp_ellipsis / tp_NotImplementedType
_vm->bind__repr__(_vm->_tp(_vm->Ellipsis), [](VM* vm, PyVar _0) -> Str { return "..."; }); _vm->bind__repr__(_vm->_tp(_vm->Ellipsis), [](VM* vm, PyVar _0) -> Str {
_vm->bind__repr__(_vm->_tp(_vm->NotImplemented), [](VM* vm, PyVar _0) -> Str { return "NotImplemented"; }); return "...";
});
_vm->bind__repr__(_vm->_tp(_vm->NotImplemented), [](VM* vm, PyVar _0) -> Str {
return "NotImplemented";
});
// tp_bytes // tp_bytes
_vm->bind_func(VM::tp_bytes, __new__, 2, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_bytes, __new__, 2, [](VM* vm, ArgsView args) {
@ -1135,7 +1171,7 @@ void __init_builtins(VM* _vm) {
Bytes retval(list.size()); Bytes retval(list.size());
for(int i = 0; i < list.size(); i++) { for(int i = 0; i < list.size(); i++) {
i64 b = CAST(i64, list[i]); i64 b = CAST(i64, list[i]);
if(b < 0 || b > 255) { vm->ValueError("byte must be in range[0, 256)"); } if(b < 0 || b > 255) vm->ValueError("byte must be in range[0, 256)");
retval[i] = (char)b; retval[i] = (char)b;
} }
return VAR(std::move(retval)); return VAR(std::move(retval));
@ -1148,7 +1184,7 @@ void __init_builtins(VM* _vm) {
int start, stop, step; int start, stop, step;
vm->parse_int_slice(s, self.size(), start, stop, step); vm->parse_int_slice(s, self.size(), start, stop, step);
int guess_max_size = abs(stop - start) / abs(step) + 1; int guess_max_size = abs(stop - start) / abs(step) + 1;
if(guess_max_size > self.size()) { guess_max_size = self.size(); } if(guess_max_size > self.size()) guess_max_size = self.size();
unsigned char* buffer = (unsigned char*)std::malloc(guess_max_size); unsigned char* buffer = (unsigned char*)std::malloc(guess_max_size);
int j = 0; // actual size int j = 0; // actual size
PK_SLICE_LOOP(i, start, stop, step) buffer[j++] = self[i]; PK_SLICE_LOOP(i, start, stop, step) buffer[j++] = self[i];
@ -1185,7 +1221,9 @@ void __init_builtins(VM* _vm) {
ss << "'"; ss << "'";
return ss.str(); return ss.str();
}); });
_vm->bind__len__(VM::tp_bytes, [](VM* vm, PyVar _0) { return (i64)_CAST(Bytes&, _0).size(); }); _vm->bind__len__(VM::tp_bytes, [](VM* vm, PyVar _0) {
return (i64)_CAST(Bytes&, _0).size();
});
_vm->bind_func(VM::tp_bytes, "decode", 1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_bytes, "decode", 1, [](VM* vm, ArgsView args) {
const Bytes& self = _CAST(Bytes&, args[0]); const Bytes& self = _CAST(Bytes&, args[0]);
@ -1193,10 +1231,10 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind__eq__(VM::tp_bytes, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__eq__(VM::tp_bytes, [](VM* vm, PyVar _0, PyVar _1) {
if(!is_type(_1, vm->tp_bytes)) { return vm->NotImplemented; } if(!is_type(_1, vm->tp_bytes)) return vm->NotImplemented;
const Bytes& lhs = _CAST(Bytes&, _0); const Bytes& lhs = _CAST(Bytes&, _0);
const Bytes& rhs = _CAST(Bytes&, _1); const Bytes& rhs = _CAST(Bytes&, _1);
if(lhs.size() != rhs.size()) { return vm->False; } if(lhs.size() != rhs.size()) return vm->False;
return VAR(memcmp(lhs.data(), rhs.data(), lhs.size()) == 0); return VAR(memcmp(lhs.data(), rhs.data(), lhs.size()) == 0);
}); });
@ -1207,11 +1245,11 @@ void __init_builtins(VM* _vm) {
_vm->bind__eq__(VM::tp_slice, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__eq__(VM::tp_slice, [](VM* vm, PyVar _0, PyVar _1) {
const Slice& self = _CAST(Slice&, _0); const Slice& self = _CAST(Slice&, _0);
if(!is_type(_1, vm->tp_slice)) { return vm->NotImplemented; } if(!is_type(_1, vm->tp_slice)) return vm->NotImplemented;
const Slice& other = _CAST(Slice&, _1); const Slice& other = _CAST(Slice&, _1);
if(vm->py_ne(self.start, other.start)) { return vm->False; } if(vm->py_ne(self.start, other.start)) return vm->False;
if(vm->py_ne(self.stop, other.stop)) { return vm->False; } if(vm->py_ne(self.stop, other.stop)) return vm->False;
if(vm->py_ne(self.step, other.step)) { return vm->False; } if(vm->py_ne(self.step, other.step)) return vm->False;
return vm->True; return vm->True;
}); });
@ -1229,18 +1267,16 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(VM::tp_mappingproxy, "keys", 1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_mappingproxy, "keys", 1, [](VM* vm, ArgsView args) {
MappingProxy& self = _CAST(MappingProxy&, args[0]); MappingProxy& self = _CAST(MappingProxy&, args[0]);
List keys; List keys;
for(StrName name: self.attr().keys()) { for(StrName name: self.attr().keys())
keys.push_back(VAR(name.sv())); keys.push_back(VAR(name.sv()));
}
return VAR(std::move(keys)); return VAR(std::move(keys));
}); });
_vm->bind_func(VM::tp_mappingproxy, "values", 1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_mappingproxy, "values", 1, [](VM* vm, ArgsView args) {
MappingProxy& self = _CAST(MappingProxy&, args[0]); MappingProxy& self = _CAST(MappingProxy&, args[0]);
List values; List values;
for(auto [k, v]: self.attr().items()) { for(auto [k, v]: self.attr().items())
values.push_back(v); values.push_back(v);
}
return VAR(std::move(values)); return VAR(std::move(values));
}); });
@ -1254,11 +1290,13 @@ void __init_builtins(VM* _vm) {
return VAR(std::move(items)); return VAR(std::move(items));
}); });
_vm->bind__len__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) { return (i64)_CAST(MappingProxy&, _0).attr().size(); }); _vm->bind__len__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) {
return (i64)_CAST(MappingProxy&, _0).attr().size();
});
_vm->bind__eq__(VM::tp_mappingproxy, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__eq__(VM::tp_mappingproxy, [](VM* vm, PyVar _0, PyVar _1) {
const MappingProxy& a = _CAST(MappingProxy&, _0); const MappingProxy& a = _CAST(MappingProxy&, _0);
if(!is_type(_1, VM::tp_mappingproxy)) { return vm->NotImplemented; } if(!is_type(_1, VM::tp_mappingproxy)) return vm->NotImplemented;
const MappingProxy& b = _CAST(MappingProxy&, _1); const MappingProxy& b = _CAST(MappingProxy&, _1);
return VAR(a.obj == b.obj); return VAR(a.obj == b.obj);
}); });
@ -1267,7 +1305,7 @@ void __init_builtins(VM* _vm) {
MappingProxy& self = _CAST(MappingProxy&, _0); MappingProxy& self = _CAST(MappingProxy&, _0);
StrName key = CAST(Str&, _1); StrName key = CAST(Str&, _1);
PyVar ret = self.attr().try_get_likely_found(key); PyVar ret = self.attr().try_get_likely_found(key);
if(ret == nullptr) { vm->KeyError(_1); } if(ret == nullptr) vm->KeyError(_1);
return ret; return ret;
}); });
@ -1275,19 +1313,19 @@ void __init_builtins(VM* _vm) {
MappingProxy& self = _CAST(MappingProxy&, args[0]); MappingProxy& self = _CAST(MappingProxy&, args[0]);
StrName key = CAST(Str&, args[1]); StrName key = CAST(Str&, args[1]);
PyVar ret = self.attr().try_get(key); PyVar ret = self.attr().try_get(key);
if(ret == nullptr) { return args[2]; } if(ret == nullptr) return args[2];
return ret; return ret;
}); });
_vm->bind__repr__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) -> Str { _vm->bind__repr__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) -> Str {
if(vm->_repr_recursion_set.contains(_0)) { return "{...}"; } if(vm->_repr_recursion_set.contains(_0)) return "{...}";
MappingProxy& self = _CAST(MappingProxy&, _0); MappingProxy& self = _CAST(MappingProxy&, _0);
SStream ss; SStream ss;
ss << "mappingproxy({"; ss << "mappingproxy({";
bool first = true; bool first = true;
vm->_repr_recursion_set.push_back(_0); vm->_repr_recursion_set.push_back(_0);
for(auto [k, v]: self.attr().items()) { for(auto [k, v]: self.attr().items()) {
if(!first) { ss << ", "; } if(!first) ss << ", ";
first = false; first = false;
ss << k.escape() << ": "; ss << k.escape() << ": ";
ss << vm->py_repr(v); ss << vm->py_repr(v);
@ -1309,7 +1347,7 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind_func(VM::tp_dict, __init__, -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_dict, __init__, -1, [](VM* vm, ArgsView args) {
if(args.size() == 1 + 0) { return vm->None; } if(args.size() == 1 + 0) return vm->None;
if(args.size() == 1 + 1) { if(args.size() == 1 + 1) {
auto _lock = vm->heap.gc_scope_lock(); auto _lock = vm->heap.gc_scope_lock();
Dict& self = PK_OBJ_GET(Dict, args[0]); Dict& self = PK_OBJ_GET(Dict, args[0]);
@ -1335,7 +1373,9 @@ void __init_builtins(VM* _vm) {
vm->TypeError("dict() takes at most 1 argument"); vm->TypeError("dict() takes at most 1 argument");
}); });
_vm->bind__len__(VM::tp_dict, [](VM* vm, PyVar _0) { return (i64)PK_OBJ_GET(Dict, _0).size(); }); _vm->bind__len__(VM::tp_dict, [](VM* vm, PyVar _0) {
return (i64)PK_OBJ_GET(Dict, _0).size();
});
_vm->bind__getitem__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__getitem__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) {
Dict& self = PK_OBJ_GET(Dict, _0); Dict& self = PK_OBJ_GET(Dict, _0);
@ -1358,7 +1398,7 @@ void __init_builtins(VM* _vm) {
_vm->bind__delitem__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__delitem__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) {
Dict& self = _CAST(Dict&, _0); Dict& self = _CAST(Dict&, _0);
bool ok = self.del(vm, _1); bool ok = self.del(vm, _1);
if(!ok) { vm->KeyError(_1); } if(!ok) vm->KeyError(_1);
}); });
_vm->bind_func(VM::tp_dict, "pop", -1, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_dict, "pop", -1, [](VM* vm, ArgsView args) {
@ -1369,7 +1409,7 @@ void __init_builtins(VM* _vm) {
Dict& self = _CAST(Dict&, args[0]); Dict& self = _CAST(Dict&, args[0]);
PyVar value = self.try_get(vm, args[1]); PyVar value = self.try_get(vm, args[1]);
if(value == nullptr) { if(value == nullptr) {
if(args.size() == 2) { vm->KeyError(args[1]); } if(args.size() == 2) vm->KeyError(args[1]);
if(args.size() == 3) { return args[2]; } if(args.size() == 3) { return args[2]; }
} }
self.del(vm, args[1]); self.del(vm, args[1]);
@ -1390,11 +1430,11 @@ void __init_builtins(VM* _vm) {
Dict& self = _CAST(Dict&, args[0]); Dict& self = _CAST(Dict&, args[0]);
if(args.size() == 1 + 1) { if(args.size() == 1 + 1) {
PyVar ret = self.try_get(vm, args[1]); PyVar ret = self.try_get(vm, args[1]);
if(ret != nullptr) { return ret; } if(ret != nullptr) return ret;
return vm->None; return vm->None;
} else if(args.size() == 1 + 2) { } else if(args.size() == 1 + 2) {
PyVar ret = self.try_get(vm, args[1]); PyVar ret = self.try_get(vm, args[1]);
if(ret != nullptr) { return ret; } if(ret != nullptr) return ret;
return args[2]; return args[2];
} }
vm->TypeError("get() takes at most 2 arguments"); vm->TypeError("get() takes at most 2 arguments");
@ -1434,14 +1474,14 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind__repr__(VM::tp_dict, [](VM* vm, PyVar _0) -> Str { _vm->bind__repr__(VM::tp_dict, [](VM* vm, PyVar _0) -> Str {
if(vm->_repr_recursion_set.contains(_0)) { return "{...}"; } if(vm->_repr_recursion_set.contains(_0)) return "{...}";
Dict& self = _CAST(Dict&, _0); Dict& self = _CAST(Dict&, _0);
SStream ss; SStream ss;
ss << "{"; ss << "{";
bool first = true; bool first = true;
vm->_repr_recursion_set.push_back(_0); vm->_repr_recursion_set.push_back(_0);
self.apply([&](PyVar k, PyVar v) { self.apply([&](PyVar k, PyVar v) {
if(!first) { ss << ", "; } if(!first) ss << ", ";
first = false; first = false;
ss << vm->py_repr(k) << ": " << vm->py_repr(v); ss << vm->py_repr(k) << ": " << vm->py_repr(v);
}); });
@ -1452,15 +1492,15 @@ void __init_builtins(VM* _vm) {
_vm->bind__eq__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__eq__(VM::tp_dict, [](VM* vm, PyVar _0, PyVar _1) {
Dict& self = _CAST(Dict&, _0); Dict& self = _CAST(Dict&, _0);
if(!vm->isinstance(_1, vm->tp_dict)) { return vm->NotImplemented; } if(!vm->isinstance(_1, vm->tp_dict)) return vm->NotImplemented;
Dict& other = _CAST(Dict&, _1); Dict& other = _CAST(Dict&, _1);
if(self.size() != other.size()) { return vm->False; } if(self.size() != other.size()) return vm->False;
for(int i = 0; i < self._capacity; i++) { for(int i = 0; i < self._capacity; i++) {
auto item = self._items[i]; auto item = self._items[i];
if(item.first == nullptr) { continue; } if(item.first == nullptr) continue;
PyVar value = other.try_get(vm, item.first); PyVar value = other.try_get(vm, item.first);
if(value == nullptr) { return vm->False; } if(value == nullptr) return vm->False;
if(!vm->py_eq(item.second, value)) { return vm->False; } if(!vm->py_eq(item.second, value)) return vm->False;
} }
return vm->True; return vm->True;
}); });
@ -1483,14 +1523,14 @@ void __init_builtins(VM* _vm) {
_vm->bind_property(_vm->_t(VM::tp_function), "__doc__", [](VM* vm, ArgsView args) { _vm->bind_property(_vm->_t(VM::tp_function), "__doc__", [](VM* vm, ArgsView args) {
Function& func = _CAST(Function&, args[0]); Function& func = _CAST(Function&, args[0]);
if(!func.decl->docstring) { return vm->None; } if(!func.decl->docstring) return vm->None;
return VAR(func.decl->docstring); return VAR(func.decl->docstring);
}); });
_vm->bind_property(_vm->_t(VM::tp_native_func), "__doc__", [](VM* vm, ArgsView args) { _vm->bind_property(_vm->_t(VM::tp_native_func), "__doc__", [](VM* vm, ArgsView args) {
NativeFunc& func = _CAST(NativeFunc&, args[0]); NativeFunc& func = _CAST(NativeFunc&, args[0]);
if(func.decl == nullptr) { return vm->None; } if(func.decl == nullptr) return vm->None;
if(!func.decl->docstring) { return vm->None; } if(!func.decl->docstring) return vm->None;
return VAR(func.decl->docstring); return VAR(func.decl->docstring);
}); });
@ -1540,7 +1580,7 @@ void VM::__post_init_builtin_types() {
_all_types[tp_module].m__getattr__ = [](VM* vm, PyVar obj, StrName name) -> PyVar { _all_types[tp_module].m__getattr__ = [](VM* vm, PyVar obj, StrName name) -> PyVar {
const Str& path = CAST(Str&, obj->attr(__path__)); const Str& path = CAST(Str&, obj->attr(__path__));
PyObject* retval = vm->py_import(_S(path, ".", name.sv()), false); PyObject* retval = vm->py_import(_S(path, ".", name.sv()), false);
if(retval) { return retval; } if(retval) return retval;
return nullptr; return nullptr;
}; };
@ -1575,7 +1615,7 @@ void VM::__post_init_builtin_types() {
}); });
bind_property(_t(tp_type), "__module__", [](VM* vm, ArgsView args) -> PyVar { bind_property(_t(tp_type), "__module__", [](VM* vm, ArgsView args) -> PyVar {
const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])]; const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])];
if(info.mod == nullptr) { return vm->None; } if(info.mod == nullptr) return vm->None;
return info.mod; return info.mod;
}); });
bind_property(_t(tp_bound_method), "__self__", [](VM* vm, ArgsView args) { bind_property(_t(tp_bound_method), "__self__", [](VM* vm, ArgsView args) {
@ -1586,18 +1626,24 @@ void VM::__post_init_builtin_types() {
}); });
bind__eq__(tp_bound_method, [](VM* vm, PyVar lhs, PyVar rhs) { bind__eq__(tp_bound_method, [](VM* vm, PyVar lhs, PyVar rhs) {
if(!is_type(rhs, vm->tp_bound_method)) { return vm->NotImplemented; } if(!is_type(rhs, vm->tp_bound_method)) return vm->NotImplemented;
const BoundMethod& _0 = PK_OBJ_GET(BoundMethod, lhs); const BoundMethod& _0 = PK_OBJ_GET(BoundMethod, lhs);
const BoundMethod& _1 = PK_OBJ_GET(BoundMethod, rhs); const BoundMethod& _1 = PK_OBJ_GET(BoundMethod, rhs);
return VAR(_0.self == _1.self && _0.func == _1.func); return VAR(_0.self == _1.self && _0.func == _1.func);
}); });
bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args) { return CAST(Slice&, args[0]).start; }); bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args) {
bind_property(_t(tp_slice), "stop", [](VM* vm, ArgsView args) { return CAST(Slice&, args[0]).stop; }); return CAST(Slice&, args[0]).start;
bind_property(_t(tp_slice), "step", [](VM* vm, ArgsView args) { return CAST(Slice&, args[0]).step; }); });
bind_property(_t(tp_slice), "stop", [](VM* vm, ArgsView args) {
return CAST(Slice&, args[0]).stop;
});
bind_property(_t(tp_slice), "step", [](VM* vm, ArgsView args) {
return CAST(Slice&, args[0]).step;
});
bind_property(_t(tp_object), "__dict__", [](VM* vm, ArgsView args) { bind_property(_t(tp_object), "__dict__", [](VM* vm, ArgsView args) {
if(is_tagged(args[0]) || !args[0]->is_attr_valid()) { return vm->None; } if(is_tagged(args[0]) || !args[0]->is_attr_valid()) return vm->None;
return VAR(MappingProxy(args[0].get())); return VAR(MappingProxy(args[0].get()));
}); });
@ -1608,7 +1654,7 @@ void VM::__post_init_builtin_types() {
SStream ss; SStream ss;
for(int i = 0; i < _0.size(); i++) { for(int i = 0; i < _0.size(); i++) {
ss << vm->py_str(_0[i]); ss << vm->py_str(_0[i]);
if(i != _0.size() - 1) { ss << _1; } if(i != _0.size() - 1) ss << _1;
} }
ss << _2; ss << _2;
vm->stdout_write(ss.str()); vm->stdout_write(ss.str());

View File

@ -34,7 +34,7 @@ static PyVar stack_item(VM* vm, int index) {
begin = vm->__c.s_view.top().begin(); begin = vm->__c.s_view.top().begin();
} }
int size = end - begin; int size = end - begin;
if(index < 0) { index += size; } if(index < 0) index += size;
assert(index >= 0 && index < size); assert(index >= 0 && index < size);
return begin[index]; return begin[index];
} }
@ -133,7 +133,7 @@ int pkpy_stack_size(pkpy_vm* vm_handle) {
VM* vm = (VM*)vm_handle; VM* vm = (VM*)vm_handle;
PK_ASSERT_NO_ERROR() PK_ASSERT_NO_ERROR()
if(vm->callstack.empty()) { return vm->s_data.size(); } if(vm->callstack.empty()) { return vm->s_data.size(); }
if(vm->__c.s_view.empty()) { exit(127); } if(vm->__c.s_view.empty()) exit(127);
return vm->s_data._sp - vm->__c.s_view.top().begin(); return vm->s_data._sp - vm->__c.s_view.top().begin();
} }
@ -313,7 +313,7 @@ struct TempViewPopper {
TempViewPopper(VM* vm) : vm(vm), used(false) {} TempViewPopper(VM* vm) : vm(vm), used(false) {}
void restore() noexcept { void restore() noexcept {
if(used) { return; } if(used) return;
vm->__c.s_view.pop(); vm->__c.s_view.pop();
used = true; used = true;
} }
@ -339,8 +339,8 @@ static PyVar c_function_wrapper(VM* vm, ArgsView args) {
return nullptr; return nullptr;
} }
assert(retc == vm->s_data._sp - curr_sp); assert(retc == vm->s_data._sp - curr_sp);
if(retc == 0) { return vm->None; } if(retc == 0) return vm->None;
if(retc == 1) { return vm->s_data.popx(); } if(retc == 1) return vm->s_data.popx();
ArgsView ret_view(curr_sp, vm->s_data._sp); ArgsView ret_view(curr_sp, vm->s_data._sp);
return py_var(vm, ret_view.to_tuple()); return py_var(vm, ret_view.to_tuple());
} }
@ -374,7 +374,7 @@ bool pkpy_getattr(pkpy_vm* vm_handle, pkpy_CName name) {
PK_ASSERT_N_EXTRA_ELEMENTS(1) PK_ASSERT_N_EXTRA_ELEMENTS(1)
PyVar o = vm->s_data.top(); PyVar o = vm->s_data.top();
o = vm->getattr(o, StrName(name), false); o = vm->getattr(o, StrName(name), false);
if(o == nullptr) { return false; } if(o == nullptr) return false;
vm->s_data.top() = o; vm->s_data.top() = o;
return true; return true;
} }
@ -399,7 +399,7 @@ bool pkpy_getglobal(pkpy_vm* vm_handle, pkpy_CName name) {
PyVar o = vm->_main->attr().try_get(StrName(name)); PyVar o = vm->_main->attr().try_get(StrName(name));
if(o == nullptr) { if(o == nullptr) {
o = vm->builtins->attr().try_get(StrName(name)); o = vm->builtins->attr().try_get(StrName(name));
if(o == nullptr) { return false; } if(o == nullptr) return false;
} }
vm->s_data.push(o); vm->s_data.push(o);
return true; return true;
@ -433,8 +433,7 @@ bool pkpy_unpack_sequence(pkpy_vm* vm_handle, int n) {
PyVar _0 = vm->py_iter(vm->s_data.popx()); PyVar _0 = vm->py_iter(vm->s_data.popx());
for(int i=0; i<n; i++){ for(int i=0; i<n; i++){
PyVar _1 = vm->py_next(_0); PyVar _1 = vm->py_next(_0);
if(_1 == vm->StopIteration){ vm->ValueError("not enough values to unpack"); if(_1 == vm->StopIteration) vm->ValueError("not enough values to unpack");
}
vm->s_data.push(_1); vm->s_data.push(_1);
} }
if(vm->py_next(_0) != vm->StopIteration) vm->ValueError("too many values to unpack"); if(vm->py_next(_0) != vm->StopIteration) vm->ValueError("too many values to unpack");
@ -516,18 +515,17 @@ bool pkpy_check_error(pkpy_vm* vm_handle) {
bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) { bool pkpy_clear_error(pkpy_vm* vm_handle, char** message) {
VM* vm = (VM*)vm_handle; VM* vm = (VM*)vm_handle;
// no error // no error
if(vm->__c.error == nullptr) { return false; } if(vm->__c.error == nullptr) return false;
Exception& e = vm->__c.error->as<Exception>(); Exception& e = vm->__c.error->as<Exception>();
if(message != nullptr) { if(message != nullptr)
*message = strdup(e.summary().c_str()); *message = strdup(e.summary().c_str());
} else { else
std::cout << e.summary() << std::endl; std::cout << e.summary() << std::endl;
}
vm->__c.error = nullptr; vm->__c.error = nullptr;
if(vm->callstack.empty()) { if(vm->callstack.empty()) {
vm->s_data.clear(); vm->s_data.clear();
} else { } else {
if(vm->__c.s_view.empty()) { exit(127); } if(vm->__c.s_view.empty()) exit(127);
vm->s_data.reset(vm->__c.s_view.top().end()); vm->s_data.reset(vm->__c.s_view.top().end());
} }
return true; return true;

View File

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

View File

@ -20,9 +20,7 @@ std::string pkpy_platform_getline(bool* eof) {
WCHAR buf; WCHAR buf;
DWORD read; DWORD read;
while(ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') { while(ReadConsoleW(hStdin, &buf, 1, &read, NULL) && buf != L'\n') {
if(eof && buf == L'\x1A') { if(eof && buf == L'\x1A') *eof = true; // Ctrl+Z
*eof = true; // Ctrl+Z
}
wss << buf; wss << buf;
} }
std::wstring wideInput = wss.str(); std::wstring wideInput = wss.str();
@ -30,7 +28,7 @@ std::string pkpy_platform_getline(bool* eof) {
std::string output; std::string output;
output.resize(length); output.resize(length);
WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL); WideCharToMultiByte(CP_UTF8, 0, wideInput.c_str(), (int)wideInput.length(), &output[0], length, NULL, NULL);
if(!output.empty() && output.back() == '\r') { output.pop_back(); } if(!output.empty() && output.back() == '\r') output.pop_back();
return output; return output;
} }
@ -39,7 +37,7 @@ std::string pkpy_platform_getline(bool* eof) {
std::string pkpy_platform_getline(bool* eof) { std::string pkpy_platform_getline(bool* eof) {
std::string output; std::string output;
if(!std::getline(std::cin, output)) { if(!std::getline(std::cin, output)) {
if(eof) { *eof = true; } if(eof) *eof = true;
} }
return output; return output;
} }
@ -50,7 +48,7 @@ static int f_input(pkpy_vm* vm) {
if(!pkpy_is_none(vm, -1)) { if(!pkpy_is_none(vm, -1)) {
pkpy_CString prompt; pkpy_CString prompt;
bool ok = pkpy_to_string(vm, -1, &prompt); bool ok = pkpy_to_string(vm, -1, &prompt);
if(!ok) { return 0; } if(!ok) return 0;
std::cout << prompt << std::flush; std::cout << prompt << std::flush;
} }
bool eof; bool eof;
@ -77,7 +75,7 @@ int main(int argc, char** argv) {
std::cout << (need_more_lines ? "... " : ">>> "); std::cout << (need_more_lines ? "... " : ">>> ");
bool eof = false; bool eof = false;
std::string line = pkpy_platform_getline(&eof); std::string line = pkpy_platform_getline(&eof);
if(eof) { break; } if(eof) break;
need_more_lines = pkpy_repl_input(repl, line.c_str()); need_more_lines = pkpy_repl_input(repl, line.c_str());
} }
pkpy_delete_vm(vm); pkpy_delete_vm(vm);
@ -86,7 +84,7 @@ int main(int argc, char** argv) {
if(argc == 2) { if(argc == 2) {
std::string argv_1 = argv[1]; std::string argv_1 = argv[1];
if(argv_1 == "-h" || argv_1 == "--help") { goto __HELP; } if(argv_1 == "-h" || argv_1 == "--help") goto __HELP;
std::filesystem::path filepath(argv[1]); std::filesystem::path filepath(argv[1]);
filepath = std::filesystem::absolute(filepath); filepath = std::filesystem::absolute(filepath);
@ -105,7 +103,7 @@ int main(int argc, char** argv) {
pkpy_set_main_argv(vm, argc, argv); pkpy_set_main_argv(vm, argc, argv);
bool ok = pkpy_exec_2(vm, src.c_str(), filepath.filename().string().c_str(), 0, NULL); bool ok = pkpy_exec_2(vm, src.c_str(), filepath.filename().string().c_str(), 0, NULL);
if(!ok) { pkpy_clear_error(vm, NULL); } if(!ok) pkpy_clear_error(vm, NULL);
pkpy_delete_vm(vm); pkpy_delete_vm(vm);
return ok ? 0 : 1; return ok ? 0 : 1;
} }