move all to pkpy namespace

This commit is contained in:
blueloveTH 2023-02-27 17:07:56 +08:00
parent 29521c98d0
commit aab4ff7647
19 changed files with 626 additions and 508 deletions

View File

@ -2,6 +2,8 @@
#include "vm.h"
namespace pkpy{
PyVar VM::run_frame(Frame* frame){
while(frame->has_next_bytecode()){
const Bytecode& byte = frame->next_bytecode();
@ -15,12 +17,12 @@ PyVar VM::run_frame(Frame* frame){
case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); continue;
case OP_LOAD_FUNCTION: {
const PyVar obj = frame->co->consts[byte.arg];
pkpy::Function f = PyFunction_AS_C(obj); // copy
Function f = PyFunction_AS_C(obj); // copy
f._module = frame->_module;
frame->push(PyFunction(f));
} continue;
case OP_SETUP_CLOSURE: {
pkpy::Function& f = PyFunction_AS_C(frame->top()); // reference
Function& f = PyFunction_AS_C(frame->top()); // reference
f._closure = frame->_locals;
} continue;
case OP_LOAD_NAME_REF: {
@ -66,15 +68,15 @@ PyVar VM::run_frame(Frame* frame){
frame->_pop();
continue;
case OP_BUILD_TUPLE: {
pkpy::Args items = frame->pop_n_values_reversed(this, byte.arg);
Args items = frame->pop_n_values_reversed(this, byte.arg);
frame->push(PyTuple(std::move(items)));
} continue;
case OP_BUILD_TUPLE_REF: {
pkpy::Args items = frame->pop_n_reversed(byte.arg);
Args items = frame->pop_n_reversed(byte.arg);
frame->push(PyRef(TupleRef(std::move(items))));
} continue;
case OP_BUILD_STRING: {
pkpy::Args items = frame->pop_n_values_reversed(this, byte.arg);
Args items = frame->pop_n_values_reversed(this, byte.arg);
StrStream ss;
for(int i=0; i<items.size(); i++) ss << PyStr_AS_C(asStr(items[i]));
frame->push(PyStr(ss.str()));
@ -82,7 +84,7 @@ PyVar VM::run_frame(Frame* frame){
case OP_LOAD_EVAL_FN: frame->push(builtins->attr(m_eval)); continue;
case OP_LIST_APPEND: {
PyVar obj = frame->pop_value(this);
pkpy::List& list = PyList_AS_C(frame->top_1());
List& list = PyList_AS_C(frame->top_1());
list.push_back(std::move(obj));
} continue;
case OP_BEGIN_CLASS: {
@ -110,19 +112,19 @@ PyVar VM::run_frame(Frame* frame){
} continue;
case OP_POP_TOP: frame->_pop(); continue;
case OP_BINARY_OP: {
pkpy::Args args(2);
Args args(2);
args[1] = frame->pop_value(this);
args[0] = frame->top_value(this);
frame->top() = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args));
} continue;
case OP_BITWISE_OP: {
pkpy::Args args(2);
Args args(2);
args[1] = frame->pop_value(this);
args[0] = frame->top_value(this);
frame->top() = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args));
} continue;
case OP_INPLACE_BINARY_OP: {
pkpy::Args args(2);
Args args(2);
args[1] = frame->pop();
args[0] = frame->top_value(this);
PyVar ret = fast_call(BINARY_SPECIAL_METHODS[byte.arg], std::move(args));
@ -130,7 +132,7 @@ PyVar VM::run_frame(Frame* frame){
frame->_pop();
} continue;
case OP_INPLACE_BITWISE_OP: {
pkpy::Args args(2);
Args args(2);
args[1] = frame->pop_value(this);
args[0] = frame->top_value(this);
PyVar ret = fast_call(BITWISE_SPECIAL_METHODS[byte.arg], std::move(args));
@ -138,7 +140,7 @@ PyVar VM::run_frame(Frame* frame){
frame->_pop();
} continue;
case OP_COMPARE_OP: {
pkpy::Args args(2);
Args args(2);
args[1] = frame->pop_value(this);
args[0] = frame->top_value(this);
frame->top() = fast_call(CMP_SPECIAL_METHODS[byte.arg], std::move(args));
@ -151,7 +153,7 @@ PyVar VM::run_frame(Frame* frame){
} continue;
case OP_CONTAINS_OP: {
PyVar rhs = frame->pop_value(this);
bool ret_c = PyBool_AS_C(call(rhs, __contains__, pkpy::one_arg(frame->pop_value(this))));
bool ret_c = PyBool_AS_C(call(rhs, __contains__, one_arg(frame->pop_value(this))));
if(byte.arg == 1) ret_c = !ret_c;
frame->push(PyBool(ret_c));
} continue;
@ -192,10 +194,10 @@ PyVar VM::run_frame(Frame* frame){
frame->push(PyList(frame->pop_n_values_reversed(this, byte.arg).move_to_list()));
continue;
case OP_BUILD_MAP: {
pkpy::Args items = frame->pop_n_values_reversed(this, byte.arg*2);
Args items = frame->pop_n_values_reversed(this, byte.arg*2);
PyVar obj = call(builtins->attr("dict"));
for(int i=0; i<items.size(); i+=2){
call(obj, __setitem__, pkpy::two_args(items[i], items[i+1]));
call(obj, __setitem__, two_args(items[i], items[i+1]));
}
frame->push(obj);
} continue;
@ -203,7 +205,7 @@ PyVar VM::run_frame(Frame* frame){
PyVar list = PyList(
frame->pop_n_values_reversed(this, byte.arg).move_to_list()
);
PyVar obj = call(builtins->attr("set"), pkpy::one_arg(list));
PyVar obj = call(builtins->attr("set"), one_arg(list));
frame->push(obj);
} continue;
case OP_DUP_TOP_VALUE: frame->push(frame->top_value(this)); continue;
@ -218,8 +220,8 @@ PyVar VM::run_frame(Frame* frame){
case OP_CALL_KWARGS_UNPACK: case OP_CALL_KWARGS: {
int ARGC = byte.arg & 0xFFFF;
int KWARGC = (byte.arg >> 16) & 0xFFFF;
pkpy::Args kwargs = frame->pop_n_values_reversed(this, KWARGC*2);
pkpy::Args args = frame->pop_n_values_reversed(this, ARGC);
Args kwargs = frame->pop_n_values_reversed(this, KWARGC*2);
Args args = frame->pop_n_values_reversed(this, ARGC);
if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args);
PyVar callable = frame->pop_value(this);
PyVar ret = call(callable, std::move(args), kwargs, true);
@ -227,10 +229,10 @@ PyVar VM::run_frame(Frame* frame){
frame->push(std::move(ret));
} continue;
case OP_CALL_UNPACK: case OP_CALL: {
pkpy::Args args = frame->pop_n_values_reversed(this, byte.arg);
Args args = frame->pop_n_values_reversed(this, byte.arg);
if(byte.op == OP_CALL_UNPACK) unpack_args(args);
PyVar callable = frame->pop_value(this);
PyVar ret = call(callable, std::move(args), pkpy::no_arg(), true);
PyVar ret = call(callable, std::move(args), no_arg(), true);
if(ret == _py_op_call) return ret;
frame->push(std::move(ret));
} continue;
@ -280,7 +282,7 @@ PyVar VM::run_frame(Frame* frame){
case OP_BUILD_SLICE: {
PyVar stop = frame->pop_value(this);
PyVar start = frame->pop_value(this);
pkpy::Slice s;
Slice s;
if(start != None) { s.start = (int)PyInt_AS_C(start);}
if(stop != None) { s.stop = (int)PyInt_AS_C(stop);}
frame->push(PySlice(s));
@ -332,3 +334,5 @@ PyVar VM::run_frame(Frame* frame){
#endif
return None;
}
} // namespace pkpy

View File

@ -2,6 +2,8 @@
#include "vm.h"
namespace pkpy {
struct CType{
PY_CLASS(c, type_)
@ -13,7 +15,7 @@ struct CType{
static void _register(VM* vm, PyVar mod, PyVar type){
vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
vm->bind_method<0>(type, "__repr__", [](VM* vm, pkpy::Args& args) {
vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) {
CType& self = vm->py_cast<CType>(args[0]);
StrStream ss;
ss << "<c._type '" << self.name << "' (" << self.size*8 << " bits)>";
@ -67,61 +69,61 @@ struct Pointer{
static void _register(VM* vm, PyVar mod, PyVar type){
vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED());
vm->bind_method<0>(type, "__repr__", [](VM* vm, pkpy::Args& args) {
vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
StrStream ss;
ss << "<" << self.ctype.name << "* at " << (i64)self.ptr << ">";
return vm->PyStr(ss.str());
});
vm->bind_method<1>(type, "__add__", [](VM* vm, pkpy::Args& args) {
vm->bind_method<1>(type, "__add__", [](VM* vm, Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
return vm->new_object<Pointer>(self + vm->PyInt_AS_C(args[1]));
});
vm->bind_method<1>(type, "__sub__", [](VM* vm, pkpy::Args& args) {
vm->bind_method<1>(type, "__sub__", [](VM* vm, Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
return vm->new_object<Pointer>(self - vm->PyInt_AS_C(args[1]));
});
vm->bind_method<1>(type, "__eq__", [](VM* vm, pkpy::Args& args) {
vm->bind_method<1>(type, "__eq__", [](VM* vm, Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
Pointer& other = vm->py_cast<Pointer>(args[1]);
return vm->PyBool(self.ptr == other.ptr);
});
vm->bind_method<1>(type, "__ne__", [](VM* vm, pkpy::Args& args) {
vm->bind_method<1>(type, "__ne__", [](VM* vm, Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
Pointer& other = vm->py_cast<Pointer>(args[1]);
return vm->PyBool(self.ptr != other.ptr);
});
// https://docs.python.org/zh-cn/3/library/ctypes.html
vm->bind_method<1>(type, "__getitem__", [](VM* vm, pkpy::Args& args) {
vm->bind_method<1>(type, "__getitem__", [](VM* vm, Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
i64 index = vm->PyInt_AS_C(args[1]);
return (self+index).get(vm);
});
vm->bind_method<2>(type, "__setitem__", [](VM* vm, pkpy::Args& args) {
vm->bind_method<2>(type, "__setitem__", [](VM* vm, Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
i64 index = vm->PyInt_AS_C(args[1]);
(self+index).set(vm, args[2]);
return vm->None;
});
vm->bind_method<1>(type, "cast", [](VM* vm, pkpy::Args& args) {
vm->bind_method<1>(type, "cast", [](VM* vm, Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
CType& ctype = vm->py_cast<CType>(args[1]);
return vm->new_object<Pointer>(self.ptr, ctype);
});
vm->bind_method<0>(type, "get", [](VM* vm, pkpy::Args& args) {
vm->bind_method<0>(type, "get", [](VM* vm, Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
return self.get(vm);
});
vm->bind_method<1>(type, "set", [](VM* vm, pkpy::Args& args) {
vm->bind_method<1>(type, "set", [](VM* vm, Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
self.set(vm, args[1]);
return vm->None;
@ -235,11 +237,11 @@ struct Struct {
}
static void _register(VM* vm, PyVar mod, PyVar type){
vm->bind_static_method<-1>(type, "__new__", [](VM* vm, pkpy::Args& args) {
vm->bind_static_method<-1>(type, "__new__", [](VM* vm, Args& args) {
return vm->new_object<Struct>();
});
vm->bind_method<0>(type, "__repr__", [](VM* vm, pkpy::Args& args) {
vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) {
Struct& self = vm->py_cast<Struct>(args[0]);
StrStream ss;
ss << self.info->name << "(" << ")";
@ -259,23 +261,23 @@ void add_module_c(VM* vm){
}
vm->setattr(mod, "nullptr", vm->new_object<Pointer>(nullptr, C_TYPE_T("void_")));
vm->bind_func<1>(mod, "malloc", [](VM* vm, pkpy::Args& args) {
vm->bind_func<1>(mod, "malloc", [](VM* vm, Args& args) {
i64 size = vm->PyInt_AS_C(args[0]);
return vm->new_object<Pointer>(malloc(size), C_TYPE_T("void_"));
});
vm->bind_func<1>(mod, "free", [](VM* vm, pkpy::Args& args) {
vm->bind_func<1>(mod, "free", [](VM* vm, Args& args) {
Pointer& self = vm->py_cast<Pointer>(args[0]);
free(self.ptr);
return vm->None;
});
vm->bind_func<1>(mod, "sizeof", [](VM* vm, pkpy::Args& args) {
vm->bind_func<1>(mod, "sizeof", [](VM* vm, Args& args) {
CType& ctype = vm->py_cast<CType>(args[0]);
return vm->PyInt(ctype.size);
});
vm->bind_func<3>(mod, "memcpy", [](VM* vm, pkpy::Args& args) {
vm->bind_func<3>(mod, "memcpy", [](VM* vm, Args& args) {
Pointer& dst = vm->py_cast<Pointer>(args[0]);
Pointer& src = vm->py_cast<Pointer>(args[1]);
i64 size = vm->PyInt_AS_C(args[2]);
@ -283,7 +285,7 @@ void add_module_c(VM* vm){
return vm->None;
});
vm->bind_func<3>(mod, "memset", [](VM* vm, pkpy::Args& args) {
vm->bind_func<3>(mod, "memset", [](VM* vm, Args& args) {
Pointer& dst = vm->py_cast<Pointer>(args[0]);
i64 val = vm->PyInt_AS_C(args[1]);
i64 size = vm->PyInt_AS_C(args[2]);
@ -291,7 +293,7 @@ void add_module_c(VM* vm){
return vm->None;
});
vm->bind_func<1>(mod, "strdup", [ptr_t](VM* vm, pkpy::Args& args) {
vm->bind_func<1>(mod, "strdup", [ptr_t](VM* vm, Args& args) {
if(is_type(args[0], vm->tp_str)){
const Str& s = vm->PyStr_AS_C(args[0]);
return vm->new_object<Pointer>(strdup(s.c_str()), C_TYPE_T("char_"));
@ -304,14 +306,16 @@ void add_module_c(VM* vm){
}
});
vm->bind_func<2>(mod, "strcmp", [](VM* vm, pkpy::Args& args) {
vm->bind_func<2>(mod, "strcmp", [](VM* vm, Args& args) {
Pointer& p1 = vm->py_cast<Pointer>(args[0]);
Pointer& p2 = vm->py_cast<Pointer>(args[1]);
return vm->PyInt(strcmp(p1.cast<char*>(), p2.cast<char*>()));
});
vm->bind_func<1>(mod, "strlen", [](VM* vm, pkpy::Args& args) {
vm->bind_func<1>(mod, "strlen", [](VM* vm, Args& args) {
Pointer& p = vm->py_cast<Pointer>(args[0]);
return vm->PyInt(strlen(p.cast<char*>()));
});
}
} // namespace pkpy

View File

@ -4,6 +4,8 @@
#include "ref.h"
#include "error.h"
namespace pkpy{
enum Opcode {
#define OPCODE(name) OP_##name,
#include "opcodes.h"
@ -49,17 +51,17 @@ struct CodeBlock {
};
struct CodeObject {
pkpy::shared_ptr<SourceData> src;
shared_ptr<SourceData> src;
Str name;
bool is_generator = false;
CodeObject(pkpy::shared_ptr<SourceData> src, Str name) {
CodeObject(shared_ptr<SourceData> src, Str name) {
this->src = src;
this->name = name;
}
std::vector<Bytecode> codes;
pkpy::List consts;
List consts;
std::vector<std::pair<StrName, NameScope>> names;
std::map<StrName, int> global_names;
std::vector<CodeBlock> blocks = { CodeBlock{NO_BLOCK, -1} };
@ -111,3 +113,6 @@ struct CodeObject {
}
/************************************************/
};
} // namespace pkpy

View File

@ -26,8 +26,6 @@
#include <map>
#include <set>
#include <algorithm>
// #include <filesystem>
// namespace fs = std::filesystem;
#define PK_VERSION "0.9.1"
@ -43,6 +41,8 @@ typedef double f64;
#define S_TO_FLOAT std::stod
#endif
namespace pkpy{
struct Dummy { };
struct DummyInstance { };
struct DummyModule { };
@ -62,8 +62,8 @@ struct Type {
//#define THREAD_LOCAL thread_local
#define THREAD_LOCAL
#define CPP_LAMBDA(x) ([](VM* vm, pkpy::Args& args) { return x; })
#define CPP_NOT_IMPLEMENTED() ([](VM* vm, pkpy::Args& args) { vm->NotImplementedError(); return vm->None; })
#define CPP_LAMBDA(x) ([](VM* vm, Args& args) { return x; })
#define CPP_NOT_IMPLEMENTED() ([](VM* vm, Args& args) { vm->NotImplementedError(); return vm->None; })
#ifdef POCKETPY_H
#define UNREACHABLE() throw std::runtime_error( "L" + std::to_string(__LINE__) + " UNREACHABLE()!");
@ -79,3 +79,5 @@ const float kTypeAttrLoadFactor = 0.5;
// do extra check for debug
#define PK_EXTRA_CHECK
} // namespace pkpy

View File

@ -4,6 +4,8 @@
#include "error.h"
#include "ceval.h"
namespace pkpy{
class Compiler;
typedef void (Compiler::*GrammarFn)();
typedef void (Compiler::*CompilerAction)();
@ -32,7 +34,7 @@ public:
Compiler(VM* vm, const char* source, Str filename, CompileMode mode){
this->vm = vm;
this->parser = std::make_unique<Parser>(
pkpy::make_shared<SourceData>(source, filename, mode)
make_sp<SourceData>(source, filename, mode)
);
// http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
@ -385,13 +387,13 @@ private:
}
void exprLambda() {
pkpy::Function func;
Function func;
func.name = "<lambda>";
if(!match(TK(":"))){
_compile_f_args(func, false);
consume(TK(":"));
}
func.code = pkpy::make_shared<CodeObject>(parser->src, func.name.str());
func.code = make_sp<CodeObject>(parser->src, func.name.str());
this->codes.push(func.code);
co()->_rvalue += 1; EXPR_TUPLE(); co()->_rvalue -= 1;
emit(OP_RETURN_VALUE);
@ -1009,7 +1011,7 @@ __LISTCOMP:
emit(OP_END_CLASS);
}
void _compile_f_args(pkpy::Function& func, bool enable_type_hints){
void _compile_f_args(Function& func, bool enable_type_hints){
int state = 0; // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
do {
if(state == 3) SyntaxError("**kwargs should be the last argument");
@ -1051,7 +1053,7 @@ __LISTCOMP:
void compile_function(){
bool has_decorator = !co()->codes.empty() && co()->codes.back().op == OP_SETUP_DECORATOR;
pkpy::Function func;
Function func;
StrName obj_name;
consume(TK("@id"));
func.name = parser->prev.str();
@ -1066,7 +1068,7 @@ __LISTCOMP:
consume(TK(")"));
}
if(match(TK("->"))) consume(TK("@id")); // eat type hints
func.code = pkpy::make_shared<CodeObject>(parser->src, func.name.str());
func.code = make_sp<CodeObject>(parser->src, func.name.str());
this->codes.push(func.code);
compile_block_body();
func.code->optimize(vm);
@ -1116,7 +1118,7 @@ __LISTCOMP:
cursor = parser->curr_char;
}
if(parser->peekchar() == '\n') lineno--;
auto e = pkpy::Exception("SyntaxError", msg);
auto e = Exception("SyntaxError", msg);
e.st_push(parser->src->snapshot(lineno, cursor));
throw e;
}
@ -1130,7 +1132,7 @@ public:
if(used) UNREACHABLE();
used = true;
CodeObject_ code = pkpy::make_shared<CodeObject>(parser->src, Str("<module>"));
CodeObject_ code = make_sp<CodeObject>(parser->src, Str("<module>"));
codes.push(code);
lex_token(); lex_token();
@ -1163,3 +1165,5 @@ public:
return code;
}
};
} // namespace pkpy

View File

@ -3,6 +3,8 @@
#include "namedict.h"
#include "tuplelist.h"
namespace pkpy{
struct NeedMoreLines {
NeedMoreLines(bool is_compiling_class) : is_compiling_class(is_compiling_class) {}
bool is_compiling_class;
@ -67,7 +69,6 @@ struct SourceData {
~SourceData() { free((void*)source); }
};
namespace pkpy{
class Exception {
StrName type;
Str msg;
@ -92,4 +93,5 @@ public:
return ss.str();
}
};
}
} // namespace pkpy

View File

@ -2,6 +2,8 @@
#include "codeobject.h"
namespace pkpy{
static THREAD_LOCAL uint64_t kFrameGlobalId = 0;
struct Frame {
@ -16,8 +18,8 @@ struct Frame {
const uint64_t id;
std::vector<std::pair<int, std::vector<PyVar>>> s_try_block;
inline pkpy::NameDict& f_locals() noexcept { return _locals != nullptr ? *_locals : _module->attr(); }
inline pkpy::NameDict& f_globals() noexcept { return _module->attr(); }
inline NameDict& f_locals() noexcept { return _locals != nullptr ? *_locals : _module->attr(); }
inline NameDict& f_globals() noexcept { return _module->attr(); }
inline PyVar* f_closure_try_get(StrName name) noexcept {
if(_closure == nullptr) return nullptr;
@ -143,8 +145,8 @@ struct Frame {
}
}
pkpy::Args pop_n_values_reversed(VM* vm, int n){
pkpy::Args v(n);
Args pop_n_values_reversed(VM* vm, int n){
Args v(n);
for(int i=n-1; i>=0; i--){
v[i] = pop();
try_deref(vm, v[i]);
@ -152,9 +154,11 @@ struct Frame {
return v;
}
pkpy::Args pop_n_reversed(int n){
pkpy::Args v(n);
Args pop_n_reversed(int n){
Args v(n);
for(int i=n-1; i>=0; i--) v[i] = pop();
return v;
}
};
}; // namespace pkpy

View File

@ -2,12 +2,14 @@
#include "ceval.h"
namespace pkpy{
class RangeIter : public BaseIter {
i64 current;
pkpy::Range r;
Range r;
public:
RangeIter(VM* vm, PyVar _ref) : BaseIter(vm, _ref) {
this->r = OBJ_GET(pkpy::Range, _ref);
this->r = OBJ_GET(Range, _ref);
this->current = r.start;
}
@ -62,3 +64,5 @@ PyVar Generator::next(){
return nullptr;
}
}
} // namespace pkpy

View File

@ -1,11 +1,13 @@
#include <fstream>
#include "pocketpy.h"
using namespace pkpy;
#ifndef __EMSCRIPTEN__
int main(int argc, char** argv){
VM* vm = pkpy_new_vm(true);
vm->bind_builtin_func<0>("input", [](VM* vm, pkpy::Args& args){
vm->bind_builtin_func<0>("input", [](VM* vm, Args& args){
static std::string line;
std::getline(std::cin, line);
return vm->PyStr(line);

View File

@ -2,11 +2,12 @@
#include "common.h"
namespace pkpy{
struct PyObject;
namespace pkpy{
template<typename T>
struct SpAllocator {
template<typename T>
struct SpAllocator {
template<typename U>
inline static int* alloc(){
return (int*)malloc(sizeof(int) + sizeof(U));
@ -16,10 +17,10 @@ namespace pkpy{
((T*)(counter + 1))->~T();
free(counter);
}
};
};
template <typename T>
struct shared_ptr {
template <typename T>
struct shared_ptr {
union {
int* counter;
i64 bits;
@ -29,7 +30,7 @@ namespace pkpy{
#define _inc_counter() if(!is_tagged() && counter) ++(*counter)
#define _dec_counter() if(!is_tagged() && counter && --(*counter) == 0) SpAllocator<T>::dealloc(counter)
public:
public:
shared_ptr() : counter(nullptr) {}
shared_ptr(int* counter) : counter(counter) {}
shared_ptr(const shared_ptr& other) : counter(other.counter) {
@ -85,14 +86,14 @@ namespace pkpy{
inline bool is_tag_01() const { return (bits & 0b11) == 0b01; }
inline bool is_tag_10() const { return (bits & 0b11) == 0b10; }
inline bool is_tag_11() const { return (bits & 0b11) == 0b11; }
};
};
#undef _t
#undef _inc_counter
#undef _dec_counter
template <typename T, typename U, typename... Args>
shared_ptr<T> make_shared(Args&&... args) {
shared_ptr<T> make_sp(Args&&... args) {
static_assert(std::is_base_of_v<T, U>, "U must be derived from T");
static_assert(std::has_virtual_destructor_v<T>, "T must have virtual destructor");
static_assert(!std::is_same_v<T, PyObject> || (!std::is_same_v<U, i64> && !std::is_same_v<U, f64>));
@ -102,16 +103,15 @@ namespace pkpy{
}
template <typename T, typename... Args>
shared_ptr<T> make_shared(Args&&... args) {
shared_ptr<T> make_sp(Args&&... args) {
int* p = SpAllocator<T>::template alloc<T>(); *p = 1;
new(p+1) T(std::forward<Args>(args)...);
return shared_ptr<T>(p);
}
};
static_assert(sizeof(i64) == sizeof(int*));
static_assert(sizeof(f64) == sizeof(int*));
static_assert(sizeof(pkpy::shared_ptr<PyObject>) == sizeof(int*));
static_assert(sizeof(shared_ptr<PyObject>) == sizeof(int*));
static_assert(std::numeric_limits<float>::is_iec559);
static_assert(std::numeric_limits<double>::is_iec559);
@ -147,6 +147,8 @@ struct SmallArrayPool {
};
typedef pkpy::shared_ptr<PyObject> PyVar;
typedef shared_ptr<PyObject> PyVar;
typedef PyVar PyVarOrNull;
typedef PyVar PyVarRef;
}; // namespace pkpy

View File

@ -4,6 +4,8 @@
#include "memory.h"
#include "str.h"
namespace pkpy{
const int kNameDictNodeSize = sizeof(StrName) + sizeof(PyVar);
template<int __Bucket, int __BucketSize=32>
@ -38,19 +40,18 @@ struct DictArrayPool {
}
};
namespace pkpy{
const std::vector<uint16_t> kHashSeeds = {9629, 43049, 13267, 59509, 39251, 1249, 35803, 54469, 27689, 9719, 34897, 18973, 30661, 19913, 27919, 32143, 3467, 28019, 1051, 39419, 1361, 28547, 48197, 2609, 24317, 22861, 41467, 17623, 52837, 59053, 33589, 32117};
static DictArrayPool<32> _dict_pool;
const std::vector<uint16_t> kHashSeeds = {9629, 43049, 13267, 59509, 39251, 1249, 35803, 54469, 27689, 9719, 34897, 18973, 30661, 19913, 27919, 32143, 3467, 28019, 1051, 39419, 1361, 28547, 48197, 2609, 24317, 22861, 41467, 17623, 52837, 59053, 33589, 32117};
static DictArrayPool<32> _dict_pool;
uint16_t find_next_capacity(uint16_t n){
uint16_t find_next_capacity(uint16_t n){
uint16_t x = 2;
while(x < n) x <<= 1;
return x;
}
}
#define _hash(key, mask, hash_seed) ( ( (key).index * (hash_seed) >> 8 ) & (mask) )
uint16_t find_perfect_hash_seed(uint16_t capacity, const std::vector<StrName>& keys){
uint16_t find_perfect_hash_seed(uint16_t capacity, const std::vector<StrName>& keys){
if(keys.empty()) return kHashSeeds[0];
std::set<uint16_t> indices;
std::pair<uint16_t, float> best_score = {kHashSeeds[0], 0.0f};
@ -64,9 +65,9 @@ namespace pkpy{
if(score > best_score.second) best_score = {kHashSeeds[i], score};
}
return best_score.first;
}
}
struct NameDict {
struct NameDict {
uint16_t _capacity;
uint16_t _size;
float _load_factor;
@ -115,12 +116,12 @@ namespace pkpy{
uint16_t size() const { return _size; }
#define HASH_PROBE(key, ok, i) \
ok = false; \
i = _hash(key, _mask, _hash_seed); \
while(!_keys[i].empty()) { \
ok = false; \
i = _hash(key, _mask, _hash_seed); \
while(!_keys[i].empty()) { \
if(_keys[i] == (key)) { ok = true; break; } \
i = (i + 1) & _mask; \
}
}
const PyVar& operator[](StrName key) const {
bool ok; uint16_t i;
@ -231,6 +232,6 @@ namespace pkpy{
}
#undef HASH_PROBE
#undef _hash
};
};
} // namespace pkpy

View File

@ -3,23 +3,24 @@
#include "namedict.h"
#include "tuplelist.h"
namespace pkpy {
struct CodeObject;
struct Frame;
struct BaseRef;
class VM;
typedef std::function<PyVar(VM*, pkpy::Args&)> NativeFuncRaw;
typedef pkpy::shared_ptr<CodeObject> CodeObject_;
typedef pkpy::shared_ptr<pkpy::NameDict> NameDict_;
typedef std::function<PyVar(VM*, Args&)> NativeFuncRaw;
typedef shared_ptr<CodeObject> CodeObject_;
typedef shared_ptr<NameDict> NameDict_;
namespace pkpy{
struct NativeFunc {
NativeFuncRaw f;
int argc; // DONOT include self
bool method;
NativeFunc(NativeFuncRaw f, int argc, bool method) : f(f), argc(argc), method(method) {}
inline PyVar operator()(VM* vm, pkpy::Args& args) const;
inline PyVar operator()(VM* vm, Args& args) const;
};
struct Function {
@ -27,7 +28,7 @@ struct Function {
CodeObject_ code;
std::vector<StrName> args;
StrName starred_arg; // empty if no *arg
pkpy::NameDict kwargs; // empty if no k=v
NameDict kwargs; // empty if no k=v
std::vector<StrName> kwargs_order;
// runtime settings
@ -71,7 +72,6 @@ struct Slice {
if(stop < start) stop = start;
}
};
}
class BaseIter {
protected:
@ -86,10 +86,10 @@ public:
struct PyObject {
Type type;
pkpy::NameDict* _attr;
NameDict* _attr;
inline bool is_attr_valid() const noexcept { return _attr != nullptr; }
inline pkpy::NameDict& attr() noexcept { return *_attr; }
inline NameDict& attr() noexcept { return *_attr; }
inline const PyVar& attr(StrName name) const noexcept { return _attr->get(name); }
virtual void* value() = 0;
@ -106,11 +106,11 @@ struct Py_ : PyObject {
inline void _init() noexcept {
if constexpr (std::is_same_v<T, Type> || std::is_same_v<T, DummyModule>) {
_attr = new pkpy::NameDict(16, kTypeAttrLoadFactor);
_attr = new NameDict(16, kTypeAttrLoadFactor);
}else if constexpr(std::is_same_v<T, DummyInstance>){
_attr = new pkpy::NameDict(4, kInstAttrLoadFactor);
}else if constexpr(std::is_same_v<T, pkpy::Function> || std::is_same_v<T, pkpy::NativeFunc>){
_attr = new pkpy::NameDict(4, kInstAttrLoadFactor);
_attr = new NameDict(4, kInstAttrLoadFactor);
}else if constexpr(std::is_same_v<T, Function> || std::is_same_v<T, NativeFunc>){
_attr = new NameDict(4, kInstAttrLoadFactor);
}else{
_attr = nullptr;
}
@ -163,3 +163,23 @@ union __8B {
__8B(i64 val) : _int(val) {}
__8B(f64 val) : _float(val) {}
};
// Create a new object with the native type `T` and return a PyVar
template<typename T>
PyVar object(VM* vm, T&) { UNREACHABLE(); }
template<typename T>
PyVar object(VM* vm, T&&) { UNREACHABLE(); }
template<typename T>
PyVar object(VM* vm, T) { UNREACHABLE(); }
// Cast a PyVar to a native type `T` by reference
template<typename T>
T& cast(VM* vm, const PyVar& var) { UNREACHABLE(); }
template<typename T>
T cast(VM* vm, const PyVar& var) { UNREACHABLE(); }
template<typename T>
T& _cast(VM* vm, const PyVar& var) { UNREACHABLE(); }
template<typename T>
T _cast(VM* vm, const PyVar& var) { UNREACHABLE(); }
} // namespace pkpy

View File

@ -2,6 +2,8 @@
#include "obj.h"
namespace pkpy{
typedef uint8_t TokenIndex;
constexpr const char* kTokens[] = {
@ -90,7 +92,7 @@ enum Precedence {
// The context of the parsing phase for the compiler.
struct Parser {
pkpy::shared_ptr<SourceData> src;
shared_ptr<SourceData> src;
const char* token_start;
const char* curr_char;
@ -285,7 +287,7 @@ struct Parser {
else set_next_token(one);
}
Parser(pkpy::shared_ptr<SourceData> src) {
Parser(shared_ptr<SourceData> src) {
this->src = src;
this->token_start = src->source;
this->curr_char = src->source;
@ -293,3 +295,5 @@ struct Parser {
this->indents.push(0);
}
};
} // namespace pkpy

View File

@ -4,12 +4,15 @@
#include "compiler.h"
#include "repl.h"
#include "iter.h"
#include "cffi.h"
namespace pkpy {
CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) {
Compiler compiler(this, source.c_str(), filename, mode);
try{
return compiler.compile();
}catch(pkpy::Exception& e){
}catch(Exception& e){
// std::cout << e.summary() << std::endl;
_error(e);
return nullptr;
@ -17,7 +20,7 @@ CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) {
}
#define BIND_NUM_ARITH_OPT(name, op) \
_vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, pkpy::Args& args){ \
_vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, Args& args){ \
if(is_both_int(args[0], args[1])){ \
return vm->PyInt(vm->_PyInt_AS_C(args[0]) op vm->_PyInt_AS_C(args[1])); \
}else{ \
@ -26,7 +29,7 @@ CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) {
});
#define BIND_NUM_LOGICAL_OPT(name, op, is_eq) \
_vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, pkpy::Args& args){ \
_vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, Args& args){ \
if(!is_both_int_or_float(args[0], args[1])){ \
if constexpr(is_eq) return vm->PyBool(args[0] op args[1]); \
vm->TypeError("unsupported operand type(s) for " #op ); \
@ -52,40 +55,40 @@ void init_builtins(VM* _vm) {
#undef BIND_NUM_ARITH_OPT
#undef BIND_NUM_LOGICAL_OPT
_vm->bind_builtin_func<1>("__sys_stdout_write", [](VM* vm, pkpy::Args& args) {
_vm->bind_builtin_func<1>("__sys_stdout_write", [](VM* vm, Args& args) {
(*vm->_stdout) << vm->PyStr_AS_C(args[0]);
return vm->None;
});
// _vm->bind_builtin_func<1>("test", [](VM* vm, pkpy::Args& args) {
// _vm->bind_builtin_func<1>("test", [](VM* vm, Args& args) {
// args[0]->attr().print_stats();
// return vm->None;
// });
_vm->bind_builtin_func<0>("super", [](VM* vm, pkpy::Args& args) {
_vm->bind_builtin_func<0>("super", [](VM* vm, Args& args) {
const PyVar* self = vm->top_frame()->f_locals().try_get(m_self);
if(self == nullptr) vm->TypeError("super() can only be called in a class");
return vm->new_object(vm->tp_super, *self);
});
_vm->bind_builtin_func<1>("id", [](VM* vm, pkpy::Args& args) {
_vm->bind_builtin_func<1>("id", [](VM* vm, Args& args) {
const PyVar& obj = args[0];
if(obj.is_tagged()) return vm->PyInt((i64)0);
return vm->PyInt(obj.bits);
});
_vm->bind_builtin_func<1>("eval", [](VM* vm, pkpy::Args& args) {
_vm->bind_builtin_func<1>("eval", [](VM* vm, Args& args) {
CodeObject_ code = vm->compile(vm->PyStr_AS_C(args[0]), "<eval>", EVAL_MODE);
return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
});
_vm->bind_builtin_func<1>("exec", [](VM* vm, pkpy::Args& args) {
_vm->bind_builtin_func<1>("exec", [](VM* vm, Args& args) {
CodeObject_ code = vm->compile(vm->PyStr_AS_C(args[0]), "<exec>", EXEC_MODE);
vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
return vm->None;
});
_vm->bind_builtin_func<-1>("exit", [](VM* vm, pkpy::Args& args) {
_vm->bind_builtin_func<-1>("exit", [](VM* vm, Args& args) {
if(args.size() == 0) std::exit(0);
else if(args.size() == 1) std::exit((int)vm->PyInt_AS_C(args[0]));
else vm->TypeError("exit() takes at most 1 argument");
@ -93,61 +96,61 @@ void init_builtins(VM* _vm) {
});
_vm->bind_builtin_func<1>("repr", CPP_LAMBDA(vm->asRepr(args[0])));
_vm->bind_builtin_func<1>("len", CPP_LAMBDA(vm->call(args[0], __len__, pkpy::no_arg())));
_vm->bind_builtin_func<1>("len", CPP_LAMBDA(vm->call(args[0], __len__, no_arg())));
_vm->bind_builtin_func<1>("hash", [](VM* vm, pkpy::Args& args){
_vm->bind_builtin_func<1>("hash", [](VM* vm, Args& args){
i64 value = vm->hash(args[0]);
if(((value << 2) >> 2) != value) value >>= 2;
return vm->PyInt(value);
});
_vm->bind_builtin_func<1>("chr", [](VM* vm, pkpy::Args& args) {
_vm->bind_builtin_func<1>("chr", [](VM* vm, Args& args) {
i64 i = vm->PyInt_AS_C(args[0]);
if (i < 0 || i > 128) vm->ValueError("chr() arg not in range(128)");
return vm->PyStr(std::string(1, (char)i));
});
_vm->bind_builtin_func<1>("ord", [](VM* vm, pkpy::Args& args) {
_vm->bind_builtin_func<1>("ord", [](VM* vm, Args& args) {
Str s = vm->PyStr_AS_C(args[0]);
if (s.size() != 1) vm->TypeError("ord() expected an ASCII character");
return vm->PyInt((i64)(s.c_str()[0]));
});
_vm->bind_builtin_func<2>("hasattr", [](VM* vm, pkpy::Args& args) {
_vm->bind_builtin_func<2>("hasattr", [](VM* vm, Args& args) {
return vm->PyBool(vm->getattr(args[0], vm->PyStr_AS_C(args[1]), false) != nullptr);
});
_vm->bind_builtin_func<3>("setattr", [](VM* vm, pkpy::Args& args) {
_vm->bind_builtin_func<3>("setattr", [](VM* vm, Args& args) {
vm->setattr(args[0], vm->PyStr_AS_C(args[1]), args[2]);
return vm->None;
});
_vm->bind_builtin_func<2>("getattr", [](VM* vm, pkpy::Args& args) {
_vm->bind_builtin_func<2>("getattr", [](VM* vm, Args& args) {
Str name = vm->PyStr_AS_C(args[1]);
return vm->getattr(args[0], name);
});
_vm->bind_builtin_func<1>("hex", [](VM* vm, pkpy::Args& args) {
_vm->bind_builtin_func<1>("hex", [](VM* vm, Args& args) {
std::stringstream ss;
ss << std::hex << vm->PyInt_AS_C(args[0]);
return vm->PyStr("0x" + ss.str());
});
_vm->bind_builtin_func<1>("dir", [](VM* vm, pkpy::Args& args) {
_vm->bind_builtin_func<1>("dir", [](VM* vm, Args& args) {
std::set<StrName> names;
if(args[0]->is_attr_valid()){
std::vector<StrName> keys = args[0]->attr().keys();
names.insert(keys.begin(), keys.end());
}
const pkpy::NameDict& t_attr = vm->_t(args[0])->attr();
const NameDict& t_attr = vm->_t(args[0])->attr();
std::vector<StrName> keys = t_attr.keys();
names.insert(keys.begin(), keys.end());
pkpy::List ret;
List ret;
for (StrName name : names) ret.push_back(vm->PyStr(name.str()));
return vm->PyList(std::move(ret));
});
_vm->bind_method<0>("object", "__repr__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<0>("object", "__repr__", [](VM* vm, Args& args) {
PyVar self = args[0];
std::uintptr_t addr = self.is_tagged() ? 0 : (uintptr_t)self.get();
StrStream ss;
@ -161,8 +164,8 @@ void init_builtins(VM* _vm) {
_vm->bind_static_method<1>("type", "__new__", CPP_LAMBDA(vm->_t(args[0])));
_vm->bind_static_method<-1>("range", "__new__", [](VM* vm, pkpy::Args& args) {
pkpy::Range r;
_vm->bind_static_method<-1>("range", "__new__", [](VM* vm, Args& args) {
Range r;
switch (args.size()) {
case 1: r.stop = vm->PyInt_AS_C(args[0]); break;
case 2: r.start = vm->PyInt_AS_C(args[0]); r.stop = vm->PyInt_AS_C(args[1]); break;
@ -179,13 +182,13 @@ void init_builtins(VM* _vm) {
_vm->bind_method<0>("NoneType", "__repr__", CPP_LAMBDA(vm->PyStr("None")));
_vm->bind_method<0>("NoneType", "__json__", CPP_LAMBDA(vm->PyStr("null")));
_vm->_bind_methods<1>({"int", "float"}, "__truediv__", [](VM* vm, pkpy::Args& args) {
_vm->_bind_methods<1>({"int", "float"}, "__truediv__", [](VM* vm, Args& args) {
f64 rhs = vm->num_to_float(args[1]);
if (rhs == 0) vm->ZeroDivisionError();
return vm->PyFloat(vm->num_to_float(args[0]) / rhs);
});
_vm->_bind_methods<1>({"int", "float"}, "__pow__", [](VM* vm, pkpy::Args& args) {
_vm->_bind_methods<1>({"int", "float"}, "__pow__", [](VM* vm, Args& args) {
if(is_both_int(args[0], args[1])){
i64 lhs = vm->_PyInt_AS_C(args[0]);
i64 rhs = vm->_PyInt_AS_C(args[1]);
@ -205,7 +208,7 @@ void init_builtins(VM* _vm) {
});
/************ PyInt ************/
_vm->bind_static_method<1>("int", "__new__", [](VM* vm, pkpy::Args& args) {
_vm->bind_static_method<1>("int", "__new__", [](VM* vm, Args& args) {
if (is_type(args[0], vm->tp_int)) return args[0];
if (is_type(args[0], vm->tp_float)) return vm->PyInt((i64)vm->PyFloat_AS_C(args[0]));
if (is_type(args[0], vm->tp_bool)) return vm->PyInt(vm->_PyBool_AS_C(args[0]) ? 1 : 0);
@ -224,13 +227,13 @@ void init_builtins(VM* _vm) {
return vm->None;
});
_vm->bind_method<1>("int", "__floordiv__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<1>("int", "__floordiv__", [](VM* vm, Args& args) {
i64 rhs = vm->PyInt_AS_C(args[1]);
if(rhs == 0) vm->ZeroDivisionError();
return vm->PyInt(vm->PyInt_AS_C(args[0]) / rhs);
});
_vm->bind_method<1>("int", "__mod__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<1>("int", "__mod__", [](VM* vm, Args& args) {
i64 rhs = vm->PyInt_AS_C(args[1]);
if(rhs == 0) vm->ZeroDivisionError();
return vm->PyInt(vm->PyInt_AS_C(args[0]) % rhs);
@ -251,10 +254,10 @@ void init_builtins(VM* _vm) {
#undef INT_BITWISE_OP
/************ PyFloat ************/
_vm->bind_static_method<1>("float", "__new__", [](VM* vm, pkpy::Args& args) {
_vm->bind_static_method<1>("float", "__new__", [](VM* vm, Args& args) {
if (is_type(args[0], vm->tp_int)) return vm->PyFloat((f64)vm->PyInt_AS_C(args[0]));
if (is_type(args[0], vm->tp_float)) return args[0];
if (is_type(args[0], vm->tp_bool)) return vm->PyFloat(vm->PyBool_AS_C(args[0]) ? 1.0 : 0.0);
if (is_type(args[0], vm->tp_bool)) return vm->PyFloat(vm->_PyBool_AS_C(args[0]) ? 1.0 : 0.0);
if (is_type(args[0], vm->tp_str)) {
const Str& s = vm->PyStr_AS_C(args[0]);
if(s == "inf") return vm->PyFloat(INFINITY);
@ -270,7 +273,7 @@ void init_builtins(VM* _vm) {
return vm->None;
});
_vm->bind_method<0>("float", "__repr__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<0>("float", "__repr__", [](VM* vm, Args& args) {
f64 val = vm->PyFloat_AS_C(args[0]);
if(std::isinf(val) || std::isnan(val)) return vm->PyStr(std::to_string(val));
StrStream ss;
@ -280,7 +283,7 @@ void init_builtins(VM* _vm) {
return vm->PyStr(s);
});
_vm->bind_method<0>("float", "__json__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<0>("float", "__json__", [](VM* vm, Args& args) {
f64 val = vm->PyFloat_AS_C(args[0]);
if(std::isinf(val) || std::isnan(val)) vm->ValueError("cannot jsonify 'nan' or 'inf'");
return vm->PyStr(std::to_string(val));
@ -289,18 +292,18 @@ void init_builtins(VM* _vm) {
/************ PyString ************/
_vm->bind_static_method<1>("str", "__new__", CPP_LAMBDA(vm->asStr(args[0])));
_vm->bind_method<1>("str", "__add__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<1>("str", "__add__", [](VM* vm, Args& args) {
const Str& lhs = vm->PyStr_AS_C(args[0]);
const Str& rhs = vm->PyStr_AS_C(args[1]);
return vm->PyStr(lhs + rhs);
});
_vm->bind_method<0>("str", "__len__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<0>("str", "__len__", [](VM* vm, Args& args) {
const Str& self = vm->PyStr_AS_C(args[0]);
return vm->PyInt(self.u8_length());
});
_vm->bind_method<1>("str", "__contains__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<1>("str", "__contains__", [](VM* vm, Args& args) {
const Str& self = vm->PyStr_AS_C(args[0]);
const Str& other = vm->PyStr_AS_C(args[1]);
return vm->PyBool(self.find(other) != Str::npos);
@ -309,33 +312,33 @@ void init_builtins(VM* _vm) {
_vm->bind_method<0>("str", "__str__", CPP_LAMBDA(args[0]));
_vm->bind_method<0>("str", "__iter__", CPP_LAMBDA(vm->PyIter(StringIter(vm, args[0]))));
_vm->bind_method<0>("str", "__repr__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<0>("str", "__repr__", [](VM* vm, Args& args) {
const Str& _self = vm->PyStr_AS_C(args[0]);
return vm->PyStr(_self.escape(true));
});
_vm->bind_method<0>("str", "__json__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<0>("str", "__json__", [](VM* vm, Args& args) {
const Str& _self = vm->PyStr_AS_C(args[0]);
return vm->PyStr(_self.escape(false));
});
_vm->bind_method<1>("str", "__eq__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<1>("str", "__eq__", [](VM* vm, Args& args) {
if(is_type(args[0], vm->tp_str) && is_type(args[1], vm->tp_str))
return vm->PyBool(vm->PyStr_AS_C(args[0]) == vm->PyStr_AS_C(args[1]));
return vm->PyBool(args[0] == args[1]);
});
_vm->bind_method<1>("str", "__ne__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<1>("str", "__ne__", [](VM* vm, Args& args) {
if(is_type(args[0], vm->tp_str) && is_type(args[1], vm->tp_str))
return vm->PyBool(vm->PyStr_AS_C(args[0]) != vm->PyStr_AS_C(args[1]));
return vm->PyBool(args[0] != args[1]);
});
_vm->bind_method<1>("str", "__getitem__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<1>("str", "__getitem__", [](VM* vm, Args& args) {
const Str& self (vm->PyStr_AS_C(args[0]));
if(is_type(args[1], vm->tp_slice)){
pkpy::Slice s = vm->PySlice_AS_C(args[1]);
Slice s = vm->PySlice_AS_C(args[1]);
s.normalize(self.u8_length());
return vm->PyStr(self.u8_substr(s.start, s.stop));
}
@ -345,19 +348,19 @@ void init_builtins(VM* _vm) {
return vm->PyStr(self.u8_getitem(index));
});
_vm->bind_method<1>("str", "__gt__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<1>("str", "__gt__", [](VM* vm, Args& args) {
const Str& self (vm->PyStr_AS_C(args[0]));
const Str& obj (vm->PyStr_AS_C(args[1]));
return vm->PyBool(self > obj);
});
_vm->bind_method<1>("str", "__lt__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<1>("str", "__lt__", [](VM* vm, Args& args) {
const Str& self (vm->PyStr_AS_C(args[0]));
const Str& obj (vm->PyStr_AS_C(args[1]));
return vm->PyBool(self < obj);
});
_vm->bind_method<2>("str", "replace", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<2>("str", "replace", [](VM* vm, Args& args) {
const Str& _self = vm->PyStr_AS_C(args[0]);
const Str& _old = vm->PyStr_AS_C(args[1]);
const Str& _new = vm->PyStr_AS_C(args[2]);
@ -371,23 +374,23 @@ void init_builtins(VM* _vm) {
return vm->PyStr(_copy);
});
_vm->bind_method<1>("str", "startswith", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<1>("str", "startswith", [](VM* vm, Args& args) {
const Str& _self = vm->PyStr_AS_C(args[0]);
const Str& _prefix = vm->PyStr_AS_C(args[1]);
return vm->PyBool(_self.find(_prefix) == 0);
});
_vm->bind_method<1>("str", "endswith", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<1>("str", "endswith", [](VM* vm, Args& args) {
const Str& _self = vm->PyStr_AS_C(args[0]);
const Str& _suffix = vm->PyStr_AS_C(args[1]);
return vm->PyBool(_self.rfind(_suffix) == _self.length() - _suffix.length());
});
_vm->bind_method<1>("str", "join", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<1>("str", "join", [](VM* vm, Args& args) {
const Str& self = vm->PyStr_AS_C(args[0]);
StrStream ss;
PyVar obj = vm->asList(args[1]);
const pkpy::List& list = vm->PyList_AS_C(obj);
const List& list = vm->PyList_AS_C(obj);
for (int i = 0; i < list.size(); ++i) {
if (i > 0) ss << self;
ss << vm->PyStr_AS_C(list[i]);
@ -396,29 +399,29 @@ void init_builtins(VM* _vm) {
});
/************ PyList ************/
_vm->bind_method<1>("list", "append", [](VM* vm, pkpy::Args& args) {
pkpy::List& self = vm->PyList_AS_C(args[0]);
_vm->bind_method<1>("list", "append", [](VM* vm, Args& args) {
List& self = vm->PyList_AS_C(args[0]);
self.push_back(args[1]);
return vm->None;
});
_vm->bind_method<0>("list", "reverse", [](VM* vm, pkpy::Args& args) {
pkpy::List& self = vm->PyList_AS_C(args[0]);
_vm->bind_method<0>("list", "reverse", [](VM* vm, Args& args) {
List& self = vm->PyList_AS_C(args[0]);
std::reverse(self.begin(), self.end());
return vm->None;
});
_vm->bind_method<1>("list", "__mul__", [](VM* vm, pkpy::Args& args) {
const pkpy::List& self = vm->PyList_AS_C(args[0]);
_vm->bind_method<1>("list", "__mul__", [](VM* vm, Args& args) {
const List& self = vm->PyList_AS_C(args[0]);
int n = (int)vm->PyInt_AS_C(args[1]);
pkpy::List result;
List result;
result.reserve(self.size() * n);
for(int i = 0; i < n; i++) result.insert(result.end(), self.begin(), self.end());
return vm->PyList(std::move(result));
});
_vm->bind_method<2>("list", "insert", [](VM* vm, pkpy::Args& args) {
pkpy::List& _self = vm->PyList_AS_C(args[0]);
_vm->bind_method<2>("list", "insert", [](VM* vm, Args& args) {
List& _self = vm->PyList_AS_C(args[0]);
int index = (int)vm->PyInt_AS_C(args[1]);
if(index < 0) index += _self.size();
if(index < 0) index = 0;
@ -427,37 +430,37 @@ void init_builtins(VM* _vm) {
return vm->None;
});
_vm->bind_method<0>("list", "clear", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<0>("list", "clear", [](VM* vm, Args& args) {
vm->PyList_AS_C(args[0]).clear();
return vm->None;
});
_vm->bind_method<0>("list", "copy", CPP_LAMBDA(vm->PyList(vm->PyList_AS_C(args[0]))));
_vm->bind_method<1>("list", "__add__", [](VM* vm, pkpy::Args& args) {
const pkpy::List& self = vm->PyList_AS_C(args[0]);
const pkpy::List& obj = vm->PyList_AS_C(args[1]);
pkpy::List new_list = self;
_vm->bind_method<1>("list", "__add__", [](VM* vm, Args& args) {
const List& self = vm->PyList_AS_C(args[0]);
const List& obj = vm->PyList_AS_C(args[1]);
List new_list = self;
new_list.insert(new_list.end(), obj.begin(), obj.end());
return vm->PyList(new_list);
});
_vm->bind_method<0>("list", "__len__", [](VM* vm, pkpy::Args& args) {
const pkpy::List& self = vm->PyList_AS_C(args[0]);
_vm->bind_method<0>("list", "__len__", [](VM* vm, Args& args) {
const List& self = vm->PyList_AS_C(args[0]);
return vm->PyInt(self.size());
});
_vm->bind_method<0>("list", "__iter__", [](VM* vm, pkpy::Args& args) {
return vm->PyIter(ArrayIter<pkpy::List>(vm, args[0]));
_vm->bind_method<0>("list", "__iter__", [](VM* vm, Args& args) {
return vm->PyIter(ArrayIter<List>(vm, args[0]));
});
_vm->bind_method<1>("list", "__getitem__", [](VM* vm, pkpy::Args& args) {
const pkpy::List& self = vm->PyList_AS_C(args[0]);
_vm->bind_method<1>("list", "__getitem__", [](VM* vm, Args& args) {
const List& self = vm->PyList_AS_C(args[0]);
if(is_type(args[1], vm->tp_slice)){
pkpy::Slice s = vm->PySlice_AS_C(args[1]);
Slice s = vm->PySlice_AS_C(args[1]);
s.normalize(self.size());
pkpy::List new_list;
List new_list;
for(size_t i = s.start; i < s.stop; i++) new_list.push_back(self[i]);
return vm->PyList(std::move(new_list));
}
@ -467,16 +470,16 @@ void init_builtins(VM* _vm) {
return self[index];
});
_vm->bind_method<2>("list", "__setitem__", [](VM* vm, pkpy::Args& args) {
pkpy::List& self = vm->PyList_AS_C(args[0]);
_vm->bind_method<2>("list", "__setitem__", [](VM* vm, Args& args) {
List& self = vm->PyList_AS_C(args[0]);
int index = (int)vm->PyInt_AS_C(args[1]);
index = vm->normalized_index(index, self.size());
self[index] = args[2];
return vm->None;
});
_vm->bind_method<1>("list", "__delitem__", [](VM* vm, pkpy::Args& args) {
pkpy::List& self = vm->PyList_AS_C(args[0]);
_vm->bind_method<1>("list", "__delitem__", [](VM* vm, Args& args) {
List& self = vm->PyList_AS_C(args[0]);
int index = (int)vm->PyInt_AS_C(args[1]);
index = vm->normalized_index(index, self.size());
self.erase(self.begin() + index);
@ -484,22 +487,22 @@ void init_builtins(VM* _vm) {
});
/************ PyTuple ************/
_vm->bind_static_method<1>("tuple", "__new__", [](VM* vm, pkpy::Args& args) {
pkpy::List list = vm->PyList_AS_C(vm->asList(args[0]));
_vm->bind_static_method<1>("tuple", "__new__", [](VM* vm, Args& args) {
List list = vm->PyList_AS_C(vm->asList(args[0]));
return vm->PyTuple(std::move(list));
});
_vm->bind_method<0>("tuple", "__iter__", [](VM* vm, pkpy::Args& args) {
return vm->PyIter(ArrayIter<pkpy::Args>(vm, args[0]));
_vm->bind_method<0>("tuple", "__iter__", [](VM* vm, Args& args) {
return vm->PyIter(ArrayIter<Args>(vm, args[0]));
});
_vm->bind_method<1>("tuple", "__getitem__", [](VM* vm, pkpy::Args& args) {
const pkpy::Tuple& self = vm->PyTuple_AS_C(args[0]);
_vm->bind_method<1>("tuple", "__getitem__", [](VM* vm, Args& args) {
const Tuple& self = vm->PyTuple_AS_C(args[0]);
if(is_type(args[1], vm->tp_slice)){
pkpy::Slice s = vm->PySlice_AS_C(args[1]);
Slice s = vm->PySlice_AS_C(args[1]);
s.normalize(self.size());
pkpy::List new_list;
List new_list;
for(size_t i = s.start; i < s.stop; i++) new_list.push_back(self[i]);
return vm->PyTuple(std::move(new_list));
}
@ -509,25 +512,25 @@ void init_builtins(VM* _vm) {
return self[index];
});
_vm->bind_method<0>("tuple", "__len__", [](VM* vm, pkpy::Args& args) {
const pkpy::Tuple& self = vm->PyTuple_AS_C(args[0]);
_vm->bind_method<0>("tuple", "__len__", [](VM* vm, Args& args) {
const Tuple& self = vm->PyTuple_AS_C(args[0]);
return vm->PyInt(self.size());
});
/************ PyBool ************/
_vm->bind_static_method<1>("bool", "__new__", CPP_LAMBDA(vm->asBool(args[0])));
_vm->bind_method<0>("bool", "__repr__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<0>("bool", "__repr__", [](VM* vm, Args& args) {
bool val = vm->PyBool_AS_C(args[0]);
return vm->PyStr(val ? "True" : "False");
});
_vm->bind_method<0>("bool", "__json__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<0>("bool", "__json__", [](VM* vm, Args& args) {
bool val = vm->PyBool_AS_C(args[0]);
return vm->PyStr(val ? "true" : "false");
});
_vm->bind_method<1>("bool", "__xor__", [](VM* vm, pkpy::Args& args) {
_vm->bind_method<1>("bool", "__xor__", [](VM* vm, Args& args) {
bool self = vm->PyBool_AS_C(args[0]);
bool other = vm->PyBool_AS_C(args[1]);
return vm->PyBool(self ^ other);
@ -552,7 +555,7 @@ void init_builtins(VM* _vm) {
void add_module_time(VM* vm){
PyVar mod = vm->new_module("time");
vm->bind_func<0>(mod, "time", [](VM* vm, pkpy::Args& args) {
vm->bind_func<0>(mod, "time", [](VM* vm, Args& args) {
auto now = std::chrono::high_resolution_clock::now();
return vm->PyFloat(std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count() / 1000000.0);
});
@ -565,7 +568,7 @@ void add_module_sys(VM* vm){
vm->bind_func<1>(mod, "getrefcount", CPP_LAMBDA(vm->PyInt(args[0].use_count())));
vm->bind_func<0>(mod, "getrecursionlimit", CPP_LAMBDA(vm->PyInt(vm->recursionlimit)));
vm->bind_func<1>(mod, "setrecursionlimit", [](VM* vm, pkpy::Args& args) {
vm->bind_func<1>(mod, "setrecursionlimit", [](VM* vm, Args& args) {
vm->recursionlimit = (int)vm->PyInt_AS_C(args[0]);
return vm->None;
});
@ -573,7 +576,7 @@ void add_module_sys(VM* vm){
void add_module_json(VM* vm){
PyVar mod = vm->new_module("json");
vm->bind_func<1>(mod, "loads", [](VM* vm, pkpy::Args& args) {
vm->bind_func<1>(mod, "loads", [](VM* vm, Args& args) {
const Str& expr = vm->PyStr_AS_C(args[0]);
CodeObject_ code = vm->compile(expr, "<json>", JSON_MODE);
return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals);
@ -603,7 +606,7 @@ void add_module_math(VM* vm){
void add_module_dis(VM* vm){
PyVar mod = vm->new_module("dis");
vm->bind_func<1>(mod, "dis", [](VM* vm, pkpy::Args& args) {
vm->bind_func<1>(mod, "dis", [](VM* vm, Args& args) {
PyVar f = args[0];
if(is_type(f, vm->tp_bound_method)) f = vm->PyBoundMethod_AS_C(args[0]).method;
CodeObject_ code = vm->PyFunction_AS_C(f).code;
@ -632,32 +635,32 @@ struct FileIO {
}
static void _register(VM* vm, PyVar mod, PyVar type){
vm->bind_static_method<2>(type, "__new__", [](VM* vm, pkpy::Args& args){
vm->bind_static_method<2>(type, "__new__", [](VM* vm, Args& args){
return vm->new_object<FileIO>(
vm, vm->PyStr_AS_C(args[0]), vm->PyStr_AS_C(args[1])
);
});
vm->bind_method<0>(type, "read", [](VM* vm, pkpy::Args& args){
vm->bind_method<0>(type, "read", [](VM* vm, Args& args){
FileIO& io = vm->py_cast<FileIO>(args[0]);
std::string buffer;
io._fs >> buffer;
return vm->PyStr(buffer);
});
vm->bind_method<1>(type, "write", [](VM* vm, pkpy::Args& args){
vm->bind_method<1>(type, "write", [](VM* vm, Args& args){
FileIO& io = vm->py_cast<FileIO>(args[0]);
io._fs << vm->PyStr_AS_C(args[1]);
return vm->None;
});
vm->bind_method<0>(type, "close", [](VM* vm, pkpy::Args& args){
vm->bind_method<0>(type, "close", [](VM* vm, Args& args){
FileIO& io = vm->py_cast<FileIO>(args[0]);
io._fs.close();
return vm->None;
});
vm->bind_method<0>(type, "__exit__", [](VM* vm, pkpy::Args& args){
vm->bind_method<0>(type, "__exit__", [](VM* vm, Args& args){
FileIO& io = vm->py_cast<FileIO>(args[0]);
io._fs.close();
return vm->None;
@ -669,7 +672,7 @@ struct FileIO {
void add_module_io(VM* vm){
PyVar mod = vm->new_module("io");
PyVar type = vm->register_class<FileIO>(mod);
vm->bind_builtin_func<2>("open", [type](VM* vm, const pkpy::Args& args){
vm->bind_builtin_func<2>("open", [type](VM* vm, const Args& args){
return vm->call(type, args);
});
}
@ -689,12 +692,12 @@ struct ReMatch {
vm->bind_method<0>(type, "start", CPP_LAMBDA(vm->PyInt(vm->py_cast<ReMatch>(args[0]).start)));
vm->bind_method<0>(type, "end", CPP_LAMBDA(vm->PyInt(vm->py_cast<ReMatch>(args[0]).end)));
vm->bind_method<0>(type, "span", [](VM* vm, pkpy::Args& args) {
vm->bind_method<0>(type, "span", [](VM* vm, Args& args) {
auto& self = vm->py_cast<ReMatch>(args[0]);
return vm->PyTuple({ vm->PyInt(self.start), vm->PyInt(self.end) });
});
vm->bind_method<1>(type, "group", [](VM* vm, pkpy::Args& args) {
vm->bind_method<1>(type, "group", [](VM* vm, Args& args) {
auto& self = vm->py_cast<ReMatch>(args[0]);
int index = (int)vm->PyInt_AS_C(args[1]);
index = vm->normalized_index(index, self.m.size());
@ -719,19 +722,19 @@ void add_module_re(VM* vm){
PyVar mod = vm->new_module("re");
vm->register_class<ReMatch>(mod);
vm->bind_func<2>(mod, "match", [](VM* vm, pkpy::Args& args) {
vm->bind_func<2>(mod, "match", [](VM* vm, Args& args) {
const Str& pattern = vm->PyStr_AS_C(args[0]);
const Str& string = vm->PyStr_AS_C(args[1]);
return _regex_search(pattern, string, true, vm);
});
vm->bind_func<2>(mod, "search", [](VM* vm, pkpy::Args& args) {
vm->bind_func<2>(mod, "search", [](VM* vm, Args& args) {
const Str& pattern = vm->PyStr_AS_C(args[0]);
const Str& string = vm->PyStr_AS_C(args[1]);
return _regex_search(pattern, string, false, vm);
});
vm->bind_func<3>(mod, "sub", [](VM* vm, pkpy::Args& args) {
vm->bind_func<3>(mod, "sub", [](VM* vm, Args& args) {
const Str& pattern = vm->PyStr_AS_C(args[0]);
const Str& repl = vm->PyStr_AS_C(args[1]);
const Str& string = vm->PyStr_AS_C(args[2]);
@ -739,13 +742,13 @@ void add_module_re(VM* vm){
return vm->PyStr(std::regex_replace(string, re, repl));
});
vm->bind_func<2>(mod, "split", [](VM* vm, pkpy::Args& args) {
vm->bind_func<2>(mod, "split", [](VM* vm, Args& args) {
const Str& pattern = vm->PyStr_AS_C(args[0]);
const Str& string = vm->PyStr_AS_C(args[1]);
std::regex re(pattern);
std::sregex_token_iterator it(string.begin(), string.end(), re, -1);
std::sregex_token_iterator end;
pkpy::List vec;
List vec;
for(; it != end; ++it){
vec.push_back(vm->PyStr(it->str()));
}
@ -756,20 +759,20 @@ void add_module_re(VM* vm){
void add_module_random(VM* vm){
PyVar mod = vm->new_module("random");
std::srand(std::time(0));
vm->bind_func<1>(mod, "seed", [](VM* vm, pkpy::Args& args) {
vm->bind_func<1>(mod, "seed", [](VM* vm, Args& args) {
std::srand((unsigned int)vm->PyInt_AS_C(args[0]));
return vm->None;
});
vm->bind_func<0>(mod, "random", CPP_LAMBDA(vm->PyFloat(std::rand() / (f64)RAND_MAX)));
vm->bind_func<2>(mod, "randint", [](VM* vm, pkpy::Args& args) {
vm->bind_func<2>(mod, "randint", [](VM* vm, Args& args) {
i64 a = vm->PyInt_AS_C(args[0]);
i64 b = vm->PyInt_AS_C(args[1]);
if(a > b) std::swap(a, b);
return vm->PyInt(a + std::rand() % (b - a + 1));
});
vm->bind_func<2>(mod, "uniform", [](VM* vm, pkpy::Args& args) {
vm->bind_func<2>(mod, "uniform", [](VM* vm, Args& args) {
f64 a = vm->PyFloat_AS_C(args[0]);
f64 b = vm->PyFloat_AS_C(args[1]);
if(a > b) std::swap(a, b);
@ -786,8 +789,6 @@ void add_module_functools(VM* vm){
vm->_exec(code, mod);
}
#include "cffi.h"
void VM::post_init(){
init_builtins(this);
add_module_sys(this);
@ -806,17 +807,15 @@ void VM::post_init(){
this->_exec(code, this->builtins);
}
class _PkExported{
class PkExportedBase{
public:
virtual ~_PkExported() = default;
virtual ~PkExportedBase() = default;
virtual void* get() = 0;
};
static std::vector<_PkExported*> _pk_lookup_table;
static std::vector<PkExportedBase*> _pk_lookup_table;
template<typename T>
class PkExported : public _PkExported{
class PkExported : public PkExportedBase{
T* _ptr;
public:
template<typename... Args>
@ -832,7 +831,6 @@ public:
#define PKPY_ALLOCATE(T, ...) *(new PkExported<T>(__VA_ARGS__))
extern "C" {
__EXPORT
/// Delete a pointer allocated by `pkpy_xxx_xxx`.
@ -947,12 +945,12 @@ extern "C" {
__EXPORT
/// Setup the callback functions.
void pkpy_setup_callbacks(f_int_t f_int, f_float_t f_float, f_bool_t f_bool, f_str_t f_str, f_None_t f_None){
::f_int = f_int;
::f_float = f_float;
::f_bool = f_bool;
::f_str = f_str;
::f_None = f_None;
void pkpy_setup_callbacks(f_int_t _f_int, f_float_t _f_float, f_bool_t _f_bool, f_str_t _f_str, f_None_t _f_None){
f_int = _f_int;
f_float = _f_float;
f_bool = _f_bool;
f_str = _f_str;
f_None = _f_None;
}
__EXPORT
@ -964,7 +962,7 @@ extern "C" {
for(int i=0; name[i]; i++) if(name[i] == ' ') return nullptr;
std::string f_header = std::string(mod) + '.' + name + '#' + std::to_string(kGlobalBindId++);
PyVar obj = vm->_modules.contains(mod) ? vm->_modules[mod] : vm->new_module(mod);
vm->bind_func<-1>(obj, name, [ret_code, f_header](VM* vm, const pkpy::Args& args){
vm->bind_func<-1>(obj, name, [ret_code, f_header](VM* vm, const Args& args){
StrStream ss;
ss << f_header;
for(int i=0; i<args.size(); i++){
@ -991,3 +989,5 @@ extern "C" {
return strdup(f_header.c_str());
}
}
} // namespace pkpy

View File

@ -2,6 +2,8 @@
#include "obj.h"
namespace pkpy {
struct BaseRef {
virtual PyVar get(VM*, Frame*) const = 0;
virtual void set(VM*, Frame*, PyVar) const = 0;
@ -48,10 +50,13 @@ struct IndexRef : BaseRef {
};
struct TupleRef : BaseRef {
pkpy::Tuple objs;
TupleRef(pkpy::Tuple&& objs) : objs(std::move(objs)) {}
Tuple objs;
TupleRef(Tuple&& objs) : objs(std::move(objs)) {}
PyVar get(VM* vm, Frame* frame) const;
void set(VM* vm, Frame* frame, PyVar val) const;
void del(VM* vm, Frame* frame) const;
};
} // namespace pkpy

View File

@ -3,6 +3,8 @@
#include "compiler.h"
#include "ceval.h"
namespace pkpy{
class REPL {
protected:
int need_more_lines = 0;
@ -46,3 +48,5 @@ public:
return false;
}
};
} // namespace pkpy

View File

@ -2,6 +2,8 @@
#include "common.h"
namespace pkpy {
typedef std::stringstream StrStream;
class Str : public std::string {
@ -213,3 +215,5 @@ const StrName BITWISE_SPECIAL_METHODS[] = {
StrName::get("__lshift__"), StrName::get("__rshift__"),
StrName::get("__and__"), StrName::get("__or__"), StrName::get("__xor__")
};
} // namespace pkpy

View File

@ -39,7 +39,7 @@ namespace pkpy {
other._size = 0;
}
Args(pkpy::List&& other) noexcept {
Args(List&& other) noexcept {
_alloc(other.size());
memcpy((void*)_args, (void*)other.data(), sizeof(PyVar)*_size);
memset((void*)other.data(), 0, sizeof(PyVar)*_size);
@ -60,8 +60,8 @@ namespace pkpy {
inline int size() const { return _size; }
pkpy::List move_to_list() noexcept {
pkpy::List ret(_size);
List move_to_list() noexcept {
List ret(_size);
memcpy((void*)ret.data(), (void*)_args, sizeof(PyVar)*_size);
memset((void*)_args, 0, sizeof(PyVar)*_size);
return ret;

153
src/vm.h
View File

@ -3,6 +3,8 @@
#include "frame.h"
#include "error.h"
namespace pkpy{
#define DEF_NATIVE(type, ctype, ptype) \
inline ctype& Py##type##_AS_C(const PyVar& obj) { \
check_type(obj, ptype); \
@ -31,8 +33,8 @@ public:
PyVar run_frame(Frame* frame);
pkpy::NameDict _types;
pkpy::NameDict _modules; // loaded modules
NameDict _types;
NameDict _modules; // loaded modules
std::map<StrName, Str> _lazy_modules; // lazy loaded modules
PyVar None, True, False, Ellipsis;
@ -100,10 +102,10 @@ public:
PyVar asList(const PyVar& iterable){
if(is_type(iterable, tp_list)) return iterable;
return call(_t(tp_list), pkpy::one_arg(iterable));
return call(_t(tp_list), one_arg(iterable));
}
PyVar fast_call(StrName name, pkpy::Args&& args){
PyVar fast_call(StrName name, Args&& args){
PyObject* cls = _t(args[0]).get();
while(cls != None.get()) {
PyVar* val = cls->attr().try_get(name);
@ -115,26 +117,26 @@ public:
}
inline PyVar call(const PyVar& _callable){
return call(_callable, pkpy::no_arg(), pkpy::no_arg(), false);
return call(_callable, no_arg(), no_arg(), false);
}
template<typename ArgT>
inline std::enable_if_t<std::is_same_v<RAW(ArgT), pkpy::Args>, PyVar>
inline std::enable_if_t<std::is_same_v<RAW(ArgT), Args>, PyVar>
call(const PyVar& _callable, ArgT&& args){
return call(_callable, std::forward<ArgT>(args), pkpy::no_arg(), false);
return call(_callable, std::forward<ArgT>(args), no_arg(), false);
}
template<typename ArgT>
inline std::enable_if_t<std::is_same_v<RAW(ArgT), pkpy::Args>, PyVar>
inline std::enable_if_t<std::is_same_v<RAW(ArgT), Args>, PyVar>
call(const PyVar& obj, const StrName name, ArgT&& args){
return call(getattr(obj, name), std::forward<ArgT>(args), pkpy::no_arg(), false);
return call(getattr(obj, name), std::forward<ArgT>(args), no_arg(), false);
}
inline PyVar call(const PyVar& obj, StrName name){
return call(getattr(obj, name), pkpy::no_arg(), pkpy::no_arg(), false);
return call(getattr(obj, name), no_arg(), no_arg(), false);
}
PyVar call(const PyVar& _callable, pkpy::Args args, const pkpy::Args& kwargs, bool opCall){
PyVar call(const PyVar& _callable, Args args, const Args& kwargs, bool opCall){
if(is_type(_callable, tp_type)){
PyVar* new_f = _callable->attr().try_get(__new__);
PyVar obj;
@ -156,12 +158,12 @@ public:
}
if(is_type(*callable, tp_native_function)){
const auto& f = OBJ_GET(pkpy::NativeFunc, *callable);
const auto& f = OBJ_GET(NativeFunc, *callable);
if(kwargs.size() != 0) TypeError("native_function does not accept keyword arguments");
return f(this, args);
} else if(is_type(*callable, tp_function)){
const pkpy::Function& fn = PyFunction_AS_C(*callable);
NameDict_ locals = pkpy::make_shared<pkpy::NameDict>(
const Function& fn = PyFunction_AS_C(*callable);
NameDict_ locals = make_sp<NameDict>(
fn.code->perfect_locals_capacity,
kLocalsLoadFactor,
fn.code->perfect_hash_seed
@ -179,7 +181,7 @@ public:
locals->update(fn.kwargs);
if(!fn.starred_arg.empty()){
pkpy::List vargs; // handle *args
List vargs; // handle *args
while(i < args.size()) vargs.push_back(std::move(args[i++]));
locals->set(fn.starred_arg, PyTuple(std::move(vargs)));
}else{
@ -217,7 +219,7 @@ public:
try {
CodeObject_ code = compile(source, filename, mode);
return _exec(code, _module);
}catch (const pkpy::Exception& e){
}catch (const Exception& e){
*_stderr << e.summary() << '\n';
}catch (const std::exception& e) {
*_stderr << "An std::exception occurred! It could be a bug.\n";
@ -269,7 +271,7 @@ public:
continue;
}catch(UnhandledException& e){
PyVar obj = frame->pop();
pkpy::Exception& _e = PyException_AS_C(obj);
Exception& _e = PyException_AS_C(obj);
_e.st_push(frame->snapshot());
callstack.pop();
if(callstack.empty()) throw _e;
@ -285,7 +287,7 @@ public:
PyVar new_type_object(PyVar mod, StrName name, PyVar base){
if(!is_type(base, tp_type)) UNREACHABLE();
PyVar obj = pkpy::make_shared<PyObject, Py_<Type>>(tp_type, _all_types.size());
PyVar obj = make_sp<PyObject, Py_<Type>>(tp_type, _all_types.size());
setattr(obj, __base__, base);
Str fullName = name.str();
if(mod != builtins) fullName = OBJ_NAME(mod) + "." + name.str();
@ -296,7 +298,7 @@ public:
}
Type _new_type_object(StrName name, Type base=0) {
PyVar obj = pkpy::make_shared<PyObject, Py_<Type>>(tp_type, _all_types.size());
PyVar obj = make_sp<PyObject, Py_<Type>>(tp_type, _all_types.size());
setattr(obj, __base__, _t(base));
_types.set(name, obj);
_all_types.push_back(obj);
@ -306,21 +308,21 @@ public:
template<typename T>
inline PyVar new_object(const PyVar& type, const T& _value) {
if(!is_type(type, tp_type)) UNREACHABLE();
return pkpy::make_shared<PyObject, Py_<RAW(T)>>(OBJ_GET(Type, type), _value);
return make_sp<PyObject, Py_<RAW(T)>>(OBJ_GET(Type, type), _value);
}
template<typename T>
inline PyVar new_object(const PyVar& type, T&& _value) {
if(!is_type(type, tp_type)) UNREACHABLE();
return pkpy::make_shared<PyObject, Py_<RAW(T)>>(OBJ_GET(Type, type), std::move(_value));
return make_sp<PyObject, Py_<RAW(T)>>(OBJ_GET(Type, type), std::move(_value));
}
template<typename T>
inline PyVar new_object(Type type, const T& _value) {
return pkpy::make_shared<PyObject, Py_<RAW(T)>>(type, _value);
return make_sp<PyObject, Py_<RAW(T)>>(type, _value);
}
template<typename T>
inline PyVar new_object(Type type, T&& _value) {
return pkpy::make_shared<PyObject, Py_<RAW(T)>>(type, std::move(_value));
return make_sp<PyObject, Py_<RAW(T)>>(type, std::move(_value));
}
template<typename T, typename... Args>
@ -365,7 +367,7 @@ public:
if(val != nullptr){
PyVarOrNull descriptor = getattr(*val, __get__, false);
if(descriptor != nullptr){
return call(descriptor, pkpy::one_arg(obj));
return call(descriptor, one_arg(obj));
}
if(is_type(*val, tp_function) || is_type(*val, tp_native_function)){
return PyBoundMethod({obj, *val});
@ -391,12 +393,12 @@ public:
template<int ARGC>
void bind_method(PyVar obj, Str funcName, NativeFuncRaw fn) {
check_type(obj, tp_type);
setattr(obj, funcName, PyNativeFunc(pkpy::NativeFunc(fn, ARGC, true)));
setattr(obj, funcName, PyNativeFunc(NativeFunc(fn, ARGC, true)));
}
template<int ARGC>
void bind_func(PyVar obj, Str funcName, NativeFuncRaw fn) {
setattr(obj, funcName, PyNativeFunc(pkpy::NativeFunc(fn, ARGC, false)));
setattr(obj, funcName, PyNativeFunc(NativeFunc(fn, ARGC, false)));
}
template<int ARGC>
@ -504,7 +506,7 @@ public:
StrStream names;
names << "co_names: ";
pkpy::List list;
List list;
for(int i=0; i<co->names.size(); i++){
list.push_back(PyStr(co->names[i].first.str()));
}
@ -602,15 +604,15 @@ public:
return __8B(bits)._float;
}
DEF_NATIVE(List, pkpy::List, tp_list)
DEF_NATIVE(Tuple, pkpy::Tuple, tp_tuple)
DEF_NATIVE(Function, pkpy::Function, tp_function)
DEF_NATIVE(NativeFunc, pkpy::NativeFunc, tp_native_function)
DEF_NATIVE(BoundMethod, pkpy::BoundMethod, tp_bound_method)
DEF_NATIVE(Range, pkpy::Range, tp_range)
DEF_NATIVE(Slice, pkpy::Slice, tp_slice)
DEF_NATIVE(Exception, pkpy::Exception, tp_exception)
DEF_NATIVE(StarWrapper, pkpy::StarWrapper, tp_star_wrapper)
DEF_NATIVE(List, List, tp_list)
DEF_NATIVE(Tuple, Tuple, tp_tuple)
DEF_NATIVE(Function, Function, tp_function)
DEF_NATIVE(NativeFunc, NativeFunc, tp_native_function)
DEF_NATIVE(BoundMethod, BoundMethod, tp_bound_method)
DEF_NATIVE(Range, Range, tp_range)
DEF_NATIVE(Slice, Slice, tp_slice)
DEF_NATIVE(Exception, Exception, tp_exception)
DEF_NATIVE(StarWrapper, StarWrapper, tp_star_wrapper)
// there is only one True/False, so no need to copy them!
inline bool PyBool_AS_C(const PyVar& obj){
@ -621,8 +623,8 @@ public:
inline const PyVar& PyBool(bool value){return value ? True : False;}
void init_builtin_types(){
PyVar _tp_object = pkpy::make_shared<PyObject, Py_<Type>>(1, 0);
PyVar _tp_type = pkpy::make_shared<PyObject, Py_<Type>>(1, 1);
PyVar _tp_object = make_sp<PyObject, Py_<Type>>(1, 0);
PyVar _tp_type = make_sp<PyObject, Py_<Type>>(1, 1);
_all_types.push_back(_tp_object);
_all_types.push_back(_tp_type);
tp_object = 0; tp_type = 1;
@ -684,7 +686,7 @@ public:
if (is_int(obj)) return PyInt_AS_C(obj);
if (is_type(obj, tp_tuple)) {
i64 x = 1000003;
const pkpy::Tuple& items = PyTuple_AS_C(obj);
const Tuple& items = PyTuple_AS_C(obj);
for (int i=0; i<items.size(); i++) {
i64 y = hash(items[i]);
x = x ^ (y + 0x9e3779b9 + (x << 6) + (x >> 2)); // recommended by Github Copilot
@ -702,12 +704,11 @@ public:
}
/***** Error Reporter *****/
private:
void _error(StrName name, const Str& msg){
_error(pkpy::Exception(name, msg));
_error(Exception(name, msg));
}
void _error(pkpy::Exception e){
void _error(Exception e){
if(callstack.empty()){
e.is_re = false;
throw e;
@ -767,14 +768,14 @@ public:
return OBJ_GET(T, obj);
}
void unpack_args(pkpy::Args& args){
pkpy::List unpacked;
void unpack_args(Args& args){
List unpacked;
for(int i=0; i<args.size(); i++){
if(is_type(args[i], tp_star_wrapper)){
auto& star = PyStarWrapper_AS_C(args[i]);
if(!star.rvalue) UNREACHABLE();
PyVar list = asList(star.obj);
pkpy::List& list_c = PyList_AS_C(list);
List& list_c = PyList_AS_C(list);
unpacked.insert(unpacked.end(), list_c.begin(), list_c.end());
}else{
unpacked.push_back(args[i]);
@ -859,21 +860,21 @@ void AttrRef::del(VM* vm, Frame* frame) const{
}
PyVar IndexRef::get(VM* vm, Frame* frame) const{
return vm->fast_call(__getitem__, pkpy::two_args(obj, index));
return vm->fast_call(__getitem__, two_args(obj, index));
}
void IndexRef::set(VM* vm, Frame* frame, PyVar val) const{
pkpy::Args args(3);
Args args(3);
args[0] = obj; args[1] = index; args[2] = std::move(val);
vm->fast_call(__setitem__, std::move(args));
}
void IndexRef::del(VM* vm, Frame* frame) const{
vm->fast_call(__delitem__, pkpy::two_args(obj, index));
vm->fast_call(__delitem__, two_args(obj, index));
}
PyVar TupleRef::get(VM* vm, Frame* frame) const{
pkpy::Tuple args(objs.size());
Tuple args(objs.size());
for (int i = 0; i < objs.size(); i++) {
args[i] = vm->PyRef_AS_C(objs[i])->get(vm, frame);
}
@ -890,7 +891,7 @@ void TupleRef::set(VM* vm, Frame* frame, PyVar val) const{
if(star.rvalue) vm->ValueError("can't use starred expression here");
if(i != objs.size()-1) vm->ValueError("* can only be used at the end");
auto ref = vm->PyRef_AS_C(star.obj);
pkpy::List list;
List list;
while((x = iter->next()) != nullptr) list.push_back(x);
ref->set(vm, frame, vm->PyList(std::move(list)));
return;
@ -913,7 +914,7 @@ inline void Frame::try_deref(VM* vm, PyVar& v){
if(is_type(v, vm->tp_ref)) v = vm->PyRef_AS_C(v)->get(vm, this);
}
PyVar pkpy::NativeFunc::operator()(VM* vm, pkpy::Args& args) const{
PyVar NativeFunc::operator()(VM* vm, Args& args) const{
int args_size = args.size() - (int)method; // remove self
if(argc != -1 && args_size != argc) {
vm->TypeError("expected " + std::to_string(argc) + " arguments, but got " + std::to_string(args_size));
@ -925,8 +926,8 @@ void CodeObject::optimize(VM* vm){
std::vector<StrName> keys;
for(auto& p: names) if(p.second == NAME_LOCAL) keys.push_back(p.first);
uint32_t base_n = (uint32_t)(keys.size() / kLocalsLoadFactor + 0.5);
perfect_locals_capacity = pkpy::find_next_capacity(base_n);
perfect_hash_seed = pkpy::find_perfect_hash_seed(perfect_locals_capacity, keys);
perfect_locals_capacity = find_next_capacity(base_n);
perfect_hash_seed = find_perfect_hash_seed(perfect_locals_capacity, keys);
for(int i=1; i<codes.size(); i++){
if(codes[i].op == OP_UNARY_NEGATIVE && codes[i-1].op == OP_LOAD_CONST){
@ -953,3 +954,49 @@ void CodeObject::optimize(VM* vm){
}
}
}
template<> PyVar object<i64>(VM* vm, i64 val){
if(((val << 2) >> 2) != val){
vm->_error("OverflowError", std::to_string(val) + " is out of range");
}
val = (val << 2) | 0b01;
return PyVar(reinterpret_cast<int*>(val));
}
template<> i64 cast<i64>(VM* vm, const PyVar& obj){
vm->check_type(obj, vm->tp_int);
return obj.bits >> 2;
}
template<> i64 _cast<i64>(VM* vm, const PyVar& obj){
return obj.bits >> 2;
}
template<> PyVar object<f64>(VM* vm, f64 val){
i64 bits = __8B(val)._int;
bits = (bits >> 2) << 2;
bits |= 0b10;
return PyVar(reinterpret_cast<int*>(bits));
}
template<> f64 cast<f64>(VM* vm, const PyVar& obj){
vm->check_type(obj, vm->tp_float);
i64 bits = obj.bits;
bits = (bits >> 2) << 2;
return __8B(bits)._float;
}
template<> f64 _cast<f64>(VM* vm, const PyVar& obj){
i64 bits = obj.bits;
bits = (bits >> 2) << 2;
return __8B(bits)._float;
}
template<> PyVar object<bool>(VM* vm, bool val){
return val ? vm->True : vm->False;
}
template<> bool cast<bool>(VM* vm, const PyVar& obj){
vm->check_type(obj, vm->tp_bool);
return obj == vm->True;
}
template<> bool _cast<bool>(VM* vm, const PyVar& obj){
return obj == vm->True;
}
} // namespace pkpy