mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-21 20:10:17 +00:00
move all to pkpy
namespace
This commit is contained in:
parent
29521c98d0
commit
aab4ff7647
44
src/ceval.h
44
src/ceval.h
@ -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
|
46
src/cffi.h
46
src/cffi.h
@ -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
|
@ -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
|
10
src/common.h
10
src/common.h
@ -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
|
@ -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
|
@ -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
|
16
src/frame.h
16
src/frame.h
@ -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
|
@ -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
|
@ -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);
|
||||
|
28
src/memory.h
28
src/memory.h
@ -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
|
||||
|
@ -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
|
46
src/obj.h
46
src/obj.h
@ -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
|
@ -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
|
248
src/pocketpy.h
248
src/pocketpy.h
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
153
src/vm.h
@ -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
|
Loading…
x
Reference in New Issue
Block a user