This commit is contained in:
blueloveTH 2022-12-08 19:44:50 +08:00
parent 16f46dec82
commit c0180efe84
3 changed files with 335 additions and 197 deletions

View File

@ -273,7 +273,7 @@ private:
pkpy::shared_ptr<_StrMemory> _s;
bool interned = false;
public:
_Str(const _StrLiteral& s){
_Str(_StrLiteral s){
construct(s);
intern();
}
@ -296,7 +296,7 @@ public:
this->_s = pkpy::make_shared<_StrMemory>(std::move(s));
}
void construct(const std::string_view& sv){
void construct(std::string_view sv){
auto it = _strIntern.find(sv);
if(it != _strIntern.end()){
this->_s = it->second;
@ -2326,7 +2326,7 @@ public:
}
#endif
PyVarDict() : emhash8::HashMap<_Str, PyVar>(5) {}
using emhash8::HashMap<_Str, PyVar>::HashMap;
};
@ -2396,13 +2396,6 @@ namespace pkpy {
other.clear();
}
// deprecated, this is very slow, do not use it!!!
ArgList(std::initializer_list<PyVar> args){
__tryAlloc(args.size());
uint8_t i = 0;
for(auto& arg: args) this->_args[i++] = arg;
}
PyVar& operator[](uint8_t i){
__checkIndex(i);
return _args[i];
@ -2429,7 +2422,7 @@ namespace pkpy {
return *this;
}
uint8_t size() const {
inline uint8_t size() const {
return _size;
}
@ -2454,6 +2447,37 @@ namespace pkpy {
__tryRelease();
}
};
const ArgList& noArg(){
static ArgList ret(0);
return ret;
}
ArgList oneArg(PyVar&& a) {
ArgList ret(1);
ret[0] = std::move(a);
return ret;
}
ArgList oneArg(const PyVar& a) {
ArgList ret(1);
ret[0] = a;
return ret;
}
ArgList twoArgs(PyVar&& a, PyVar&& b) {
ArgList ret(2);
ret[0] = std::move(a);
ret[1] = std::move(b);
return ret;
}
ArgList twoArgs(const PyVar& a, const PyVar& b) {
ArgList ret(2);
ret[0] = a;
ret[1] = b;
return ret;
}
}
@ -2461,6 +2485,11 @@ const char* __BUILTINS_CODE = R"(
def len(x):
return x.__len__()
def print(*args, sep=' ', end='\n'):
s = sep.join([str(i) for i in args])
__sys_stdout_write(s + end)
str.__mul__ = lambda self, n: ''.join([self for _ in range(n)])
def __str4split(self, sep):
@ -2866,7 +2895,9 @@ struct SourceMetadata {
_Str getLine(int lineno) const {
if(lineno == -1) return "<?>";
const char* _start = lineStarts.at(lineno-1);
lineno -= 1;
if(lineno < 0) lineno = 0;
const char* _start = lineStarts.at(lineno);
const char* i = _start;
while(*i != '\n' && *i != '\0') i++;
return _Str(_start, i-_start);
@ -3726,11 +3757,15 @@ public:
uint64_t id;
inline PyVarDict copy_f_locals(){
return f_locals;
}
inline PyVarDict& f_globals(){
return _module->attribs;
}
Frame(const CodeObject* code, PyVar _module, const PyVarDict& locals)
Frame(const CodeObject* code, PyVar _module, PyVarDict&& locals)
: code(code), _module(_module), f_locals(locals) {
static uint64_t frame_id = 1;
@ -3906,7 +3941,7 @@ protected:
} break;
case OP_BUILD_INDEX_PTR: {
PyVar index = frame->popValue(this);
PyVar obj = frame->popValue(this);
VarRef obj = frame->popValue(this);
frame->push(PyPointer(IndexPointer(obj, index)));
} break;
case OP_STORE_PTR: {
@ -4011,8 +4046,7 @@ protected:
case OP_CONTAINS_OP:
{
PyVar rhs = frame->popValue(this);
PyVar lhs = frame->popValue(this);
bool ret_c = PyBool_AS_C(call(rhs, __contains__, {std::move(lhs)}));
bool ret_c = PyBool_AS_C(call(rhs, __contains__, pkpy::oneArg(frame->popValue(this))));
if(byte.arg == 1) ret_c = !ret_c;
frame->push(PyBool(ret_c));
} break;
@ -4070,18 +4104,22 @@ protected:
case OP_BUILD_MAP:
{
pkpy::ArgList items = frame->popNValuesReversed(this, byte.arg*2);
PyVar obj = call(builtins->attribs["dict"], {});
PyVar obj = call(builtins->attribs["dict"]);
for(int i=0; i<items.size(); i+=2){
call(obj, __setitem__, {items[i], items[i+1]});
call(obj, __setitem__, pkpy::twoArgs(items[i], items[i+1]));
}
frame->push(obj);
} break;
case OP_DUP_TOP: frame->push(frame->topValue(this)); break;
case OP_CALL:
{
pkpy::ArgList args = frame->popNValuesReversed(this, byte.arg);
int ARGC = byte.arg & 0xFFFF;
int KWARGC = (byte.arg >> 16) & 0xFFFF;
pkpy::ArgList kwargs(0);
if(KWARGC > 0) kwargs = frame->popNValuesReversed(this, KWARGC*2);
pkpy::ArgList args = frame->popNValuesReversed(this, ARGC);
PyVar callable = frame->popValue(this);
PyVar ret = call(std::move(callable), std::move(args), true);
PyVar ret = call(callable, std::move(args), kwargs, true);
if(ret == __py2py_call_signal) return ret;
frame->push(std::move(ret));
} break;
@ -4101,7 +4139,7 @@ protected:
PyVar obj = frame->popValue(this);
PyVarOrNull iter_fn = getAttr(obj, __iter__, false);
if(iter_fn != nullptr){
PyVar tmp = call(iter_fn, {obj});
PyVar tmp = call(iter_fn, pkpy::oneArg(obj));
VarRef var = frame->__pop();
__checkType(var, _tp_pointer);
PyIter_AS_C(tmp)->var = var;
@ -4162,18 +4200,8 @@ protected:
frame->push(it->second);
}
} break;
case OP_WITH_ENTER:
{
PyVar obj = frame->popValue(this);
PyVar enter_fn = getAttr(obj, "__enter__"_c);
call(enter_fn, {});
} break;
case OP_WITH_EXIT:
{
PyVar obj = frame->popValue(this);
PyVar exit_fn = getAttr(obj, "__exit__"_c);
call(exit_fn, {});
} break;
case OP_WITH_ENTER: call(frame->popValue(this), "__enter__"_c); break;
case OP_WITH_EXIT: call(frame->popValue(this), "__exit__"_c); break;
default:
systemError(_Str("opcode ") + OP_NAMES[byte.op] + " is not implemented");
break;
@ -4233,7 +4261,7 @@ public:
PyVar asStr(const PyVar& obj){
PyVarOrNull str_fn = getAttr(obj, __str__, false);
if(str_fn != nullptr) return call(str_fn, {});
if(str_fn != nullptr) return call(str_fn);
return asRepr(obj);
}
@ -4253,11 +4281,11 @@ public:
PyVar asRepr(const PyVar& obj){
if(obj->isType(_tp_type)) return PyStr("<class '" + UNION_GET(_Str, obj->attribs[__name__]) + "'>");
return call(obj, __repr__, {});
return call(obj, __repr__);
}
PyVar asJson(const PyVar& obj){
return call(obj, __json__, {});
return call(obj, __json__);
}
const PyVar& asBool(const PyVar& obj){
@ -4267,7 +4295,7 @@ public:
if(obj->_type == _tp_float) return PyBool(PyFloat_AS_C(obj) != 0.0);
PyVarOrNull len_fn = getAttr(obj, __len__, false);
if(len_fn != nullptr){
PyVar ret = call(std::move(len_fn), {});
PyVar ret = call(len_fn);
return PyBool(PyInt_AS_C(ret) > 0);
}
return True;
@ -4278,25 +4306,39 @@ public:
PyObject* cls = obj->_type.get();
while(cls != None.get()) {
auto it = cls->attribs.find(name);
if(it != cls->attribs.end()){
return call(it->second, args);
}
if(it != cls->attribs.end()) return call(it->second, std::move(args));
cls = cls->attribs[__base__].get();
}
attributeError(obj, name);
return nullptr;
}
PyVar call(const PyVar& _callable, pkpy::ArgList args, bool opCall=false){
inline PyVar call(const PyVar& _callable){
return call(_callable, pkpy::noArg(), pkpy::noArg(), false);
}
inline PyVar call(const PyVar& _callable, pkpy::ArgList args){
return call(_callable, args, pkpy::noArg(), false);
}
inline PyVar call(const PyVar& obj, const _Str& func, pkpy::ArgList args){
return call(getAttr(obj, func), args, pkpy::noArg(), false);
}
inline PyVar call(const PyVar& obj, const _Str& func){
return call(getAttr(obj, func), pkpy::noArg(), pkpy::noArg(), false);
}
PyVar call(const PyVar& _callable, pkpy::ArgList args, const pkpy::ArgList& kwargs, bool opCall){
if(_callable->isType(_tp_type)){
auto it = _callable->attribs.find(__new__);
PyVar obj;
if(it != _callable->attribs.end()){
obj = call(it->second, args);
obj = call(it->second, args, kwargs, false);
}else{
obj = newObject(_callable, (_Int)-1);
PyVarOrNull init_fn = getAttr(obj, __init__, false);
if (init_fn != nullptr) call(init_fn, args);
if (init_fn != nullptr) call(init_fn, args, kwargs, false);
}
return obj;
}
@ -4314,54 +4356,67 @@ public:
if((*callable)->isType(_tp_native_function)){
const auto& f = UNION_GET(_CppFunc, *callable);
// _CppFunc do not support kwargs
return f(this, args);
} else if((*callable)->isType(_tp_function)){
const _Func& fn = PyFunction_AS_C((*callable));
PyVarDict locals;
int i = 0;
for(const auto& name : fn->args){
if(i < args.size()) {
locals[name] = args[i++];
}else{
typeError("missing positional argument '" + name + "'");
}
}
// handle *args
if(!fn->starredArg.empty()){
PyVarList vargs;
while(i < args.size()) vargs.push_back(args[i++]);
locals[fn->starredArg] = PyTuple(vargs);
}
// handle keyword arguments
for(const _Str& name : fn->kwArgsOrder){
if(i < args.size()) {
locals[name] = args[i++];
}else{
locals[name] = fn->kwArgs[name];
if(i < args.size()){
locals.emplace(name, args[i++]);
continue;
}
typeError("missing positional argument '" + name + "'");
}
if(i < args.size()) typeError("too many arguments");
locals.insert(fn->kwArgs.begin(), fn->kwArgs.end());
std::vector<_Str> positional_overrided_keys;
if(!fn->starredArg.empty()){
// handle *args
PyVarList vargs;
while(i < args.size()) vargs.push_back(args[i++]);
locals.emplace(fn->starredArg, PyTuple(std::move(vargs)));
}else{
for(const auto& key : fn->kwArgsOrder){
if(i < args.size()){
locals[key] = args[i++];
positional_overrided_keys.push_back(key);
}else{
break;
}
}
if(i < args.size()) typeError("too many arguments");
}
for(int i=0; i<kwargs.size(); i+=2){
const _Str& key = PyStr_AS_C(kwargs[i]);
if(fn->kwArgs.find(key) == fn->kwArgs.end()){
typeError(key.__escape(true) + " is an invalid keyword argument for " + fn->name + "()");
}
const PyVar& val = kwargs[i+1];
if(!positional_overrided_keys.empty()){
auto it = std::find(positional_overrided_keys.begin(), positional_overrided_keys.end(), key);
if(it != positional_overrided_keys.end()){
typeError("multiple values for argument '" + key + "'");
}
}
locals[key] = val;
}
auto it_m = (*callable)->attribs.find(__module__);
PyVar _module = it_m != (*callable)->attribs.end() ? it_m->second : topFrame()->_module;
if(opCall){
__pushNewFrame(fn->code, _module, locals);
__pushNewFrame(fn->code, _module, std::move(locals));
return __py2py_call_signal;
}
return _exec(fn->code, _module, locals);
return _exec(fn->code, _module, std::move(locals));
}
typeError("'" + UNION_TP_NAME(*callable) + "' object is not callable");
return None;
}
inline PyVar call(const PyVar& obj, const _Str& func, const pkpy::ArgList& args){
return call(getAttr(obj, func), args);
}
inline PyVar call(const PyVar& obj, const _Str& func, pkpy::ArgList&& args){
return call(getAttr(obj, func), args);
}
// repl mode is only for setting `frame->id` to 0
virtual PyVarOrNull exec(const _Code& code, PyVar _module=nullptr){
@ -4381,18 +4436,18 @@ public:
exec(code);
}
Frame* __pushNewFrame(const _Code& code, PyVar _module, const PyVarDict& locals){
Frame* __pushNewFrame(const _Code& code, PyVar _module, PyVarDict&& locals){
if(code == nullptr) UNREACHABLE();
if(callstack.size() > maxRecursionDepth){
throw RuntimeError("RecursionError", "maximum recursion depth exceeded", _cleanErrorAndGetSnapshots());
}
Frame* frame = new Frame(code.get(), _module, locals);
Frame* frame = new Frame(code.get(), _module, std::move(locals));
callstack.emplace_back(pkpy::unique_ptr<Frame>(frame));
return frame;
}
PyVar _exec(const _Code& code, PyVar _module, const PyVarDict& locals){
Frame* frame = __pushNewFrame(code, _module, locals);
PyVar _exec(const _Code& code, PyVar _module, PyVarDict&& locals){
Frame* frame = __pushNewFrame(code, _module, std::move(locals));
if(code->mode() == SINGLE_MODE) frame->id = 0;
Frame* frameBase = frame;
PyVar ret = nullptr;
@ -4539,10 +4594,10 @@ public:
bool isInstance(PyVar obj, PyVar type){
__checkType(type, _tp_type);
PyVar t = obj->_type;
while (t != None){
if (t == type) return true;
t = t->attribs[__base__];
PyObject* t = obj->_type.get();
while (t != None.get()){
if (t == type.get()) return true;
t = t->attribs[__base__].get();
}
return false;
}
@ -4837,15 +4892,15 @@ void AttrPointer::del(VM* vm, Frame* frame) const{
}
PyVar IndexPointer::get(VM* vm, Frame* frame) const{
return vm->call(obj, __getitem__, {index});
return vm->call(obj, __getitem__, pkpy::oneArg(index));
}
void IndexPointer::set(VM* vm, Frame* frame, PyVar val) const{
vm->call(obj, __setitem__, {index, val});
vm->call(obj, __setitem__, pkpy::twoArgs(index, val));
}
void IndexPointer::del(VM* vm, Frame* frame) const{
vm->call(obj, __delitem__, {index});
vm->call(obj, __delitem__, pkpy::oneArg(index));
}
PyVar CompoundPointer::get(VM* vm, Frame* frame) const{
@ -5271,10 +5326,16 @@ public:
parser->setNextToken(TK("@eof"));
}
_TokenType peek() {
inline _TokenType peek() {
return parser->current.type;
}
// not sure this will work
_TokenType peekNext() {
if(parser->nexts.empty()) return TK("@eof");
return parser->nexts.front().type;
}
bool match(_TokenType expected) {
if (peek() != expected) return false;
lexToken();
@ -5540,15 +5601,26 @@ __LISTCOMP:
void exprCall() {
int ARGC = 0;
int KWARGC = 0;
do {
matchNewLines(mode()==SINGLE_MODE);
if (peek() == TK(")")) break;
EXPR();
ARGC++;
if(peek() == TK("@id") && peekNext() == TK("=")) {
consume(TK("@id"));
const _Str& key = parser->previous.str();
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(key)));
consume(TK("="));
EXPR();
KWARGC++;
} else{
if(KWARGC > 0) syntaxError("positional argument follows keyword argument");
EXPR();
ARGC++;
}
matchNewLines(mode()==SINGLE_MODE);
} while (match(TK(",")));
consume(TK(")"));
emitCode(OP_CALL, ARGC);
emitCode(OP_CALL, (KWARGC << 16) | ARGC);
}
void exprName() {
@ -6132,12 +6204,9 @@ void __initializeBuiltinFunctions(VM* _vm) {
#undef BIND_NUM_ARITH_OPT
#undef BIND_NUM_LOGICAL_OPT
_vm->bindBuiltinFunc("print", [](VM* vm, const pkpy::ArgList& args) {
_StrStream ss;
for(int i=0; i<args.size(); i++){
ss << vm->PyStr_AS_C(vm->asStr(args[i])) << " ";
}
(*vm->_stdout) << ss.str() << '\n';
_vm->bindBuiltinFunc("__sys_stdout_write", [](VM* vm, const pkpy::ArgList& args) {
vm->__checkArgSize(args, 1);
(*vm->_stdout) << vm->PyStr_AS_C(args[0]);
return vm->None;
});
@ -6152,7 +6221,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
vm->__checkArgSize(args, 1);
const _Str& expr = vm->PyStr_AS_C(args[0]);
_Code code = compile(vm, expr.c_str(), "<eval>", EVAL_MODE, false);
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->f_locals);
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->copy_f_locals());
});
_vm->bindBuiltinFunc("isinstance", [](VM* vm, const pkpy::ArgList& args) {
@ -6187,9 +6256,9 @@ void __initializeBuiltinFunctions(VM* _vm) {
_vm->bindBuiltinFunc("globals", [](VM* vm, const pkpy::ArgList& args) {
vm->__checkArgSize(args, 0);
const auto& d = vm->topFrame()->f_globals();
PyVar obj = vm->call(vm->builtins->attribs["dict"], {});
PyVar obj = vm->call(vm->builtins->attribs["dict"]);
for (const auto& [k, v] : d) {
vm->call(obj, __setitem__, {vm->PyStr(k), v});
vm->call(obj, __setitem__, pkpy::twoArgs(vm->PyStr(k), v));
}
return obj;
});
@ -6197,9 +6266,9 @@ void __initializeBuiltinFunctions(VM* _vm) {
_vm->bindBuiltinFunc("locals", [](VM* vm, const pkpy::ArgList& args) {
vm->__checkArgSize(args, 0);
const auto& d = vm->topFrame()->f_locals;
PyVar obj = vm->call(vm->builtins->attribs["dict"], {});
PyVar obj = vm->call(vm->builtins->attribs["dict"]);
for (const auto& [k, v] : d) {
vm->call(obj, __setitem__, {vm->PyStr(k), v});
vm->call(obj, __setitem__, pkpy::twoArgs(vm->PyStr(k), v));
}
return obj;
});
@ -6736,7 +6805,7 @@ void __addModuleJson(VM* vm){
vm->__checkArgSize(args, 1);
const _Str& expr = vm->PyStr_AS_C(args[0]);
_Code code = compile(vm, expr.c_str(), "<json>", JSON_MODE, false);
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->f_locals);
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->copy_f_locals());
});
vm->bindFunc(mod, "dumps", [](VM* vm, const pkpy::ArgList& args) {

@ -1 +1 @@
Subproject commit 711b948542a1fa76abb1d5786ab5dbd28e5c1b88
Subproject commit 6a2bba868bc7d65869e8c754972b6d183516e94b

View File

@ -273,7 +273,7 @@ private:
pkpy::shared_ptr<_StrMemory> _s;
bool interned = false;
public:
_Str(const _StrLiteral& s){
_Str(_StrLiteral s){
construct(s);
intern();
}
@ -296,7 +296,7 @@ public:
this->_s = pkpy::make_shared<_StrMemory>(std::move(s));
}
void construct(const std::string_view& sv){
void construct(std::string_view sv){
auto it = _strIntern.find(sv);
if(it != _strIntern.end()){
this->_s = it->second;
@ -2326,7 +2326,7 @@ public:
}
#endif
PyVarDict() : emhash8::HashMap<_Str, PyVar>(5) {}
using emhash8::HashMap<_Str, PyVar>::HashMap;
};
@ -2396,13 +2396,6 @@ namespace pkpy {
other.clear();
}
// deprecated, this is very slow, do not use it!!!
ArgList(std::initializer_list<PyVar> args){
__tryAlloc(args.size());
uint8_t i = 0;
for(auto& arg: args) this->_args[i++] = arg;
}
PyVar& operator[](uint8_t i){
__checkIndex(i);
return _args[i];
@ -2429,7 +2422,7 @@ namespace pkpy {
return *this;
}
uint8_t size() const {
inline uint8_t size() const {
return _size;
}
@ -2454,6 +2447,37 @@ namespace pkpy {
__tryRelease();
}
};
const ArgList& noArg(){
static ArgList ret(0);
return ret;
}
ArgList oneArg(PyVar&& a) {
ArgList ret(1);
ret[0] = std::move(a);
return ret;
}
ArgList oneArg(const PyVar& a) {
ArgList ret(1);
ret[0] = a;
return ret;
}
ArgList twoArgs(PyVar&& a, PyVar&& b) {
ArgList ret(2);
ret[0] = std::move(a);
ret[1] = std::move(b);
return ret;
}
ArgList twoArgs(const PyVar& a, const PyVar& b) {
ArgList ret(2);
ret[0] = a;
ret[1] = b;
return ret;
}
}
@ -2461,6 +2485,11 @@ const char* __BUILTINS_CODE = R"(
def len(x):
return x.__len__()
def print(*args, sep=' ', end='\n'):
s = sep.join([str(i) for i in args])
__sys_stdout_write(s + end)
str.__mul__ = lambda self, n: ''.join([self for _ in range(n)])
def __str4split(self, sep):
@ -2866,7 +2895,9 @@ struct SourceMetadata {
_Str getLine(int lineno) const {
if(lineno == -1) return "<?>";
const char* _start = lineStarts.at(lineno-1);
lineno -= 1;
if(lineno < 0) lineno = 0;
const char* _start = lineStarts.at(lineno);
const char* i = _start;
while(*i != '\n' && *i != '\0') i++;
return _Str(_start, i-_start);
@ -3726,11 +3757,15 @@ public:
uint64_t id;
inline PyVarDict copy_f_locals(){
return f_locals;
}
inline PyVarDict& f_globals(){
return _module->attribs;
}
Frame(const CodeObject* code, PyVar _module, const PyVarDict& locals)
Frame(const CodeObject* code, PyVar _module, PyVarDict&& locals)
: code(code), _module(_module), f_locals(locals) {
static uint64_t frame_id = 1;
@ -3906,7 +3941,7 @@ protected:
} break;
case OP_BUILD_INDEX_PTR: {
PyVar index = frame->popValue(this);
PyVar obj = frame->popValue(this);
VarRef obj = frame->popValue(this);
frame->push(PyPointer(IndexPointer(obj, index)));
} break;
case OP_STORE_PTR: {
@ -4011,8 +4046,7 @@ protected:
case OP_CONTAINS_OP:
{
PyVar rhs = frame->popValue(this);
PyVar lhs = frame->popValue(this);
bool ret_c = PyBool_AS_C(call(rhs, __contains__, {std::move(lhs)}));
bool ret_c = PyBool_AS_C(call(rhs, __contains__, pkpy::oneArg(frame->popValue(this))));
if(byte.arg == 1) ret_c = !ret_c;
frame->push(PyBool(ret_c));
} break;
@ -4070,18 +4104,22 @@ protected:
case OP_BUILD_MAP:
{
pkpy::ArgList items = frame->popNValuesReversed(this, byte.arg*2);
PyVar obj = call(builtins->attribs["dict"], {});
PyVar obj = call(builtins->attribs["dict"]);
for(int i=0; i<items.size(); i+=2){
call(obj, __setitem__, {items[i], items[i+1]});
call(obj, __setitem__, pkpy::twoArgs(items[i], items[i+1]));
}
frame->push(obj);
} break;
case OP_DUP_TOP: frame->push(frame->topValue(this)); break;
case OP_CALL:
{
pkpy::ArgList args = frame->popNValuesReversed(this, byte.arg);
int ARGC = byte.arg & 0xFFFF;
int KWARGC = (byte.arg >> 16) & 0xFFFF;
pkpy::ArgList kwargs(0);
if(KWARGC > 0) kwargs = frame->popNValuesReversed(this, KWARGC*2);
pkpy::ArgList args = frame->popNValuesReversed(this, ARGC);
PyVar callable = frame->popValue(this);
PyVar ret = call(std::move(callable), std::move(args), true);
PyVar ret = call(callable, std::move(args), kwargs, true);
if(ret == __py2py_call_signal) return ret;
frame->push(std::move(ret));
} break;
@ -4101,7 +4139,7 @@ protected:
PyVar obj = frame->popValue(this);
PyVarOrNull iter_fn = getAttr(obj, __iter__, false);
if(iter_fn != nullptr){
PyVar tmp = call(iter_fn, {obj});
PyVar tmp = call(iter_fn, pkpy::oneArg(obj));
VarRef var = frame->__pop();
__checkType(var, _tp_pointer);
PyIter_AS_C(tmp)->var = var;
@ -4162,18 +4200,8 @@ protected:
frame->push(it->second);
}
} break;
case OP_WITH_ENTER:
{
PyVar obj = frame->popValue(this);
PyVar enter_fn = getAttr(obj, "__enter__"_c);
call(enter_fn, {});
} break;
case OP_WITH_EXIT:
{
PyVar obj = frame->popValue(this);
PyVar exit_fn = getAttr(obj, "__exit__"_c);
call(exit_fn, {});
} break;
case OP_WITH_ENTER: call(frame->popValue(this), "__enter__"_c); break;
case OP_WITH_EXIT: call(frame->popValue(this), "__exit__"_c); break;
default:
systemError(_Str("opcode ") + OP_NAMES[byte.op] + " is not implemented");
break;
@ -4233,7 +4261,7 @@ public:
PyVar asStr(const PyVar& obj){
PyVarOrNull str_fn = getAttr(obj, __str__, false);
if(str_fn != nullptr) return call(str_fn, {});
if(str_fn != nullptr) return call(str_fn);
return asRepr(obj);
}
@ -4253,11 +4281,11 @@ public:
PyVar asRepr(const PyVar& obj){
if(obj->isType(_tp_type)) return PyStr("<class '" + UNION_GET(_Str, obj->attribs[__name__]) + "'>");
return call(obj, __repr__, {});
return call(obj, __repr__);
}
PyVar asJson(const PyVar& obj){
return call(obj, __json__, {});
return call(obj, __json__);
}
const PyVar& asBool(const PyVar& obj){
@ -4267,7 +4295,7 @@ public:
if(obj->_type == _tp_float) return PyBool(PyFloat_AS_C(obj) != 0.0);
PyVarOrNull len_fn = getAttr(obj, __len__, false);
if(len_fn != nullptr){
PyVar ret = call(std::move(len_fn), {});
PyVar ret = call(len_fn);
return PyBool(PyInt_AS_C(ret) > 0);
}
return True;
@ -4278,25 +4306,39 @@ public:
PyObject* cls = obj->_type.get();
while(cls != None.get()) {
auto it = cls->attribs.find(name);
if(it != cls->attribs.end()){
return call(it->second, args);
}
if(it != cls->attribs.end()) return call(it->second, std::move(args));
cls = cls->attribs[__base__].get();
}
attributeError(obj, name);
return nullptr;
}
PyVar call(const PyVar& _callable, pkpy::ArgList args, bool opCall=false){
inline PyVar call(const PyVar& _callable){
return call(_callable, pkpy::noArg(), pkpy::noArg(), false);
}
inline PyVar call(const PyVar& _callable, pkpy::ArgList args){
return call(_callable, args, pkpy::noArg(), false);
}
inline PyVar call(const PyVar& obj, const _Str& func, pkpy::ArgList args){
return call(getAttr(obj, func), args, pkpy::noArg(), false);
}
inline PyVar call(const PyVar& obj, const _Str& func){
return call(getAttr(obj, func), pkpy::noArg(), pkpy::noArg(), false);
}
PyVar call(const PyVar& _callable, pkpy::ArgList args, const pkpy::ArgList& kwargs, bool opCall){
if(_callable->isType(_tp_type)){
auto it = _callable->attribs.find(__new__);
PyVar obj;
if(it != _callable->attribs.end()){
obj = call(it->second, args);
obj = call(it->second, args, kwargs, false);
}else{
obj = newObject(_callable, (_Int)-1);
PyVarOrNull init_fn = getAttr(obj, __init__, false);
if (init_fn != nullptr) call(init_fn, args);
if (init_fn != nullptr) call(init_fn, args, kwargs, false);
}
return obj;
}
@ -4314,54 +4356,67 @@ public:
if((*callable)->isType(_tp_native_function)){
const auto& f = UNION_GET(_CppFunc, *callable);
// _CppFunc do not support kwargs
return f(this, args);
} else if((*callable)->isType(_tp_function)){
const _Func& fn = PyFunction_AS_C((*callable));
PyVarDict locals;
int i = 0;
for(const auto& name : fn->args){
if(i < args.size()) {
locals[name] = args[i++];
}else{
typeError("missing positional argument '" + name + "'");
}
}
// handle *args
if(!fn->starredArg.empty()){
PyVarList vargs;
while(i < args.size()) vargs.push_back(args[i++]);
locals[fn->starredArg] = PyTuple(vargs);
}
// handle keyword arguments
for(const _Str& name : fn->kwArgsOrder){
if(i < args.size()) {
locals[name] = args[i++];
}else{
locals[name] = fn->kwArgs[name];
if(i < args.size()){
locals.emplace(name, args[i++]);
continue;
}
typeError("missing positional argument '" + name + "'");
}
if(i < args.size()) typeError("too many arguments");
locals.insert(fn->kwArgs.begin(), fn->kwArgs.end());
std::vector<_Str> positional_overrided_keys;
if(!fn->starredArg.empty()){
// handle *args
PyVarList vargs;
while(i < args.size()) vargs.push_back(args[i++]);
locals.emplace(fn->starredArg, PyTuple(std::move(vargs)));
}else{
for(const auto& key : fn->kwArgsOrder){
if(i < args.size()){
locals[key] = args[i++];
positional_overrided_keys.push_back(key);
}else{
break;
}
}
if(i < args.size()) typeError("too many arguments");
}
for(int i=0; i<kwargs.size(); i+=2){
const _Str& key = PyStr_AS_C(kwargs[i]);
if(fn->kwArgs.find(key) == fn->kwArgs.end()){
typeError(key.__escape(true) + " is an invalid keyword argument for " + fn->name + "()");
}
const PyVar& val = kwargs[i+1];
if(!positional_overrided_keys.empty()){
auto it = std::find(positional_overrided_keys.begin(), positional_overrided_keys.end(), key);
if(it != positional_overrided_keys.end()){
typeError("multiple values for argument '" + key + "'");
}
}
locals[key] = val;
}
auto it_m = (*callable)->attribs.find(__module__);
PyVar _module = it_m != (*callable)->attribs.end() ? it_m->second : topFrame()->_module;
if(opCall){
__pushNewFrame(fn->code, _module, locals);
__pushNewFrame(fn->code, _module, std::move(locals));
return __py2py_call_signal;
}
return _exec(fn->code, _module, locals);
return _exec(fn->code, _module, std::move(locals));
}
typeError("'" + UNION_TP_NAME(*callable) + "' object is not callable");
return None;
}
inline PyVar call(const PyVar& obj, const _Str& func, const pkpy::ArgList& args){
return call(getAttr(obj, func), args);
}
inline PyVar call(const PyVar& obj, const _Str& func, pkpy::ArgList&& args){
return call(getAttr(obj, func), args);
}
// repl mode is only for setting `frame->id` to 0
virtual PyVarOrNull exec(const _Code& code, PyVar _module=nullptr){
@ -4381,18 +4436,18 @@ public:
exec(code);
}
Frame* __pushNewFrame(const _Code& code, PyVar _module, const PyVarDict& locals){
Frame* __pushNewFrame(const _Code& code, PyVar _module, PyVarDict&& locals){
if(code == nullptr) UNREACHABLE();
if(callstack.size() > maxRecursionDepth){
throw RuntimeError("RecursionError", "maximum recursion depth exceeded", _cleanErrorAndGetSnapshots());
}
Frame* frame = new Frame(code.get(), _module, locals);
Frame* frame = new Frame(code.get(), _module, std::move(locals));
callstack.emplace_back(pkpy::unique_ptr<Frame>(frame));
return frame;
}
PyVar _exec(const _Code& code, PyVar _module, const PyVarDict& locals){
Frame* frame = __pushNewFrame(code, _module, locals);
PyVar _exec(const _Code& code, PyVar _module, PyVarDict&& locals){
Frame* frame = __pushNewFrame(code, _module, std::move(locals));
if(code->mode() == SINGLE_MODE) frame->id = 0;
Frame* frameBase = frame;
PyVar ret = nullptr;
@ -4539,10 +4594,10 @@ public:
bool isInstance(PyVar obj, PyVar type){
__checkType(type, _tp_type);
PyVar t = obj->_type;
while (t != None){
if (t == type) return true;
t = t->attribs[__base__];
PyObject* t = obj->_type.get();
while (t != None.get()){
if (t == type.get()) return true;
t = t->attribs[__base__].get();
}
return false;
}
@ -4837,15 +4892,15 @@ void AttrPointer::del(VM* vm, Frame* frame) const{
}
PyVar IndexPointer::get(VM* vm, Frame* frame) const{
return vm->call(obj, __getitem__, {index});
return vm->call(obj, __getitem__, pkpy::oneArg(index));
}
void IndexPointer::set(VM* vm, Frame* frame, PyVar val) const{
vm->call(obj, __setitem__, {index, val});
vm->call(obj, __setitem__, pkpy::twoArgs(index, val));
}
void IndexPointer::del(VM* vm, Frame* frame) const{
vm->call(obj, __delitem__, {index});
vm->call(obj, __delitem__, pkpy::oneArg(index));
}
PyVar CompoundPointer::get(VM* vm, Frame* frame) const{
@ -5271,10 +5326,16 @@ public:
parser->setNextToken(TK("@eof"));
}
_TokenType peek() {
inline _TokenType peek() {
return parser->current.type;
}
// not sure this will work
_TokenType peekNext() {
if(parser->nexts.empty()) return TK("@eof");
return parser->nexts.front().type;
}
bool match(_TokenType expected) {
if (peek() != expected) return false;
lexToken();
@ -5540,15 +5601,26 @@ __LISTCOMP:
void exprCall() {
int ARGC = 0;
int KWARGC = 0;
do {
matchNewLines(mode()==SINGLE_MODE);
if (peek() == TK(")")) break;
EXPR();
ARGC++;
if(peek() == TK("@id") && peekNext() == TK("=")) {
consume(TK("@id"));
const _Str& key = parser->previous.str();
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(key)));
consume(TK("="));
EXPR();
KWARGC++;
} else{
if(KWARGC > 0) syntaxError("positional argument follows keyword argument");
EXPR();
ARGC++;
}
matchNewLines(mode()==SINGLE_MODE);
} while (match(TK(",")));
consume(TK(")"));
emitCode(OP_CALL, ARGC);
emitCode(OP_CALL, (KWARGC << 16) | ARGC);
}
void exprName() {
@ -6132,12 +6204,9 @@ void __initializeBuiltinFunctions(VM* _vm) {
#undef BIND_NUM_ARITH_OPT
#undef BIND_NUM_LOGICAL_OPT
_vm->bindBuiltinFunc("print", [](VM* vm, const pkpy::ArgList& args) {
_StrStream ss;
for(int i=0; i<args.size(); i++){
ss << vm->PyStr_AS_C(vm->asStr(args[i])) << " ";
}
(*vm->_stdout) << ss.str() << '\n';
_vm->bindBuiltinFunc("__sys_stdout_write", [](VM* vm, const pkpy::ArgList& args) {
vm->__checkArgSize(args, 1);
(*vm->_stdout) << vm->PyStr_AS_C(args[0]);
return vm->None;
});
@ -6152,7 +6221,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
vm->__checkArgSize(args, 1);
const _Str& expr = vm->PyStr_AS_C(args[0]);
_Code code = compile(vm, expr.c_str(), "<eval>", EVAL_MODE, false);
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->f_locals);
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->copy_f_locals());
});
_vm->bindBuiltinFunc("isinstance", [](VM* vm, const pkpy::ArgList& args) {
@ -6187,9 +6256,9 @@ void __initializeBuiltinFunctions(VM* _vm) {
_vm->bindBuiltinFunc("globals", [](VM* vm, const pkpy::ArgList& args) {
vm->__checkArgSize(args, 0);
const auto& d = vm->topFrame()->f_globals();
PyVar obj = vm->call(vm->builtins->attribs["dict"], {});
PyVar obj = vm->call(vm->builtins->attribs["dict"]);
for (const auto& [k, v] : d) {
vm->call(obj, __setitem__, {vm->PyStr(k), v});
vm->call(obj, __setitem__, pkpy::twoArgs(vm->PyStr(k), v));
}
return obj;
});
@ -6197,9 +6266,9 @@ void __initializeBuiltinFunctions(VM* _vm) {
_vm->bindBuiltinFunc("locals", [](VM* vm, const pkpy::ArgList& args) {
vm->__checkArgSize(args, 0);
const auto& d = vm->topFrame()->f_locals;
PyVar obj = vm->call(vm->builtins->attribs["dict"], {});
PyVar obj = vm->call(vm->builtins->attribs["dict"]);
for (const auto& [k, v] : d) {
vm->call(obj, __setitem__, {vm->PyStr(k), v});
vm->call(obj, __setitem__, pkpy::twoArgs(vm->PyStr(k), v));
}
return obj;
});
@ -6736,7 +6805,7 @@ void __addModuleJson(VM* vm){
vm->__checkArgSize(args, 1);
const _Str& expr = vm->PyStr_AS_C(args[0]);
_Code code = compile(vm, expr.c_str(), "<json>", JSON_MODE, false);
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->f_locals);
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->copy_f_locals());
});
vm->bindFunc(mod, "dumps", [](VM* vm, const pkpy::ArgList& args) {