mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-21 03:50:16 +00:00
up
This commit is contained in:
parent
c694e1e67d
commit
5d6d109164
21
src/ceval.h
21
src/ceval.h
@ -48,6 +48,7 @@ __NEXT_STEP:;
|
||||
PyObject* obj = VAR(Function({decl, frame->_module, frame->_locals}));
|
||||
frame->push(obj);
|
||||
} DISPATCH();
|
||||
case OP_LOAD_NULL: frame->push(_py_null); DISPATCH();
|
||||
/*****************************************/
|
||||
case OP_LOAD_NAME: {
|
||||
StrName name = frame->co->names[byte.arg];
|
||||
@ -67,6 +68,13 @@ __NEXT_STEP:;
|
||||
StrName name = frame->co->names[byte.arg];
|
||||
frame->top() = getattr(a, name);
|
||||
} DISPATCH();
|
||||
case OP_LOAD_METHOD: {
|
||||
PyObject* a = frame->top();
|
||||
StrName name = frame->co->names[byte.arg];
|
||||
PyObject* self;
|
||||
frame->top() = get_unbound_method(a, name, &self);
|
||||
frame->push(self);
|
||||
} DISPATCH();
|
||||
case OP_LOAD_SUBSCR: {
|
||||
Args args(2);
|
||||
args[1] = frame->popx(); // b
|
||||
@ -222,7 +230,13 @@ __NEXT_STEP:;
|
||||
/*****************************************/
|
||||
// TODO: examine this later
|
||||
case OP_CALL: case OP_CALL_UNPACK: {
|
||||
Args args = frame->popx_n_reversed(byte.arg);
|
||||
int ARGC = byte.arg;
|
||||
|
||||
bool method_call = frame->top_n(ARGC) != _py_null;
|
||||
if(method_call) ARGC++; // add self into args
|
||||
Args args = frame->popx_n_reversed(ARGC);
|
||||
if(!method_call) frame->pop();
|
||||
|
||||
if(byte.op == OP_CALL_UNPACK) unpack_args(args);
|
||||
PyObject* callable = frame->popx();
|
||||
PyObject* ret = call(callable, std::move(args), no_arg(), true);
|
||||
@ -233,7 +247,12 @@ __NEXT_STEP:;
|
||||
int ARGC = byte.arg & 0xFFFF;
|
||||
int KWARGC = (byte.arg >> 16) & 0xFFFF;
|
||||
Args kwargs = frame->popx_n_reversed(KWARGC*2);
|
||||
|
||||
bool method_call = frame->top_n(ARGC) != _py_null;
|
||||
if(method_call) ARGC++; // add self into args
|
||||
Args args = frame->popx_n_reversed(ARGC);
|
||||
if(!method_call) frame->pop();
|
||||
|
||||
if(byte.op == OP_CALL_KWARGS_UNPACK) unpack_args(args);
|
||||
PyObject* callable = frame->popx();
|
||||
PyObject* ret = call(callable, std::move(args), kwargs, true);
|
||||
|
@ -33,12 +33,12 @@
|
||||
// debug macros
|
||||
#define DEBUG_NO_BUILTIN_MODULES 0
|
||||
#define DEBUG_EXTRA_CHECK 0
|
||||
#define DEBUG_DIS_EXEC 1
|
||||
#define DEBUG_DIS_EXEC 0
|
||||
#define DEBUG_DIS_EXEC_MIN 1
|
||||
#define DEBUG_CEVAL_STEP 0
|
||||
#define DEBUG_FULL_EXCEPTION 0
|
||||
#define DEBUG_NO_AUTO_GC 1
|
||||
#define DEBUG_GC_STATS 0
|
||||
#define DEBUG_GC_STATS 1
|
||||
|
||||
#if (defined(__ANDROID__) && __ANDROID_API__ <= 22) || defined(__EMSCRIPTEN__)
|
||||
#define PK_ENABLE_FILEIO 0
|
||||
|
@ -884,6 +884,8 @@ __SUBSCR_END:
|
||||
for(auto it=decorators.rbegin(); it!=decorators.rend(); ++it){
|
||||
(*it)->emit(ctx());
|
||||
ctx()->emit(OP_ROT_TWO, BC_NOARG, (*it)->line);
|
||||
ctx()->emit(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE);
|
||||
ctx()->emit(OP_ROT_TWO, BC_NOARG, BC_KEEPLINE);
|
||||
ctx()->emit(OP_CALL, 1, (*it)->line);
|
||||
}
|
||||
if(!ctx()->is_compiling_class){
|
||||
|
56
src/expr.h
56
src/expr.h
@ -17,10 +17,10 @@ struct Expr{
|
||||
virtual void emit(CodeEmitContext* ctx) = 0;
|
||||
virtual Str str() const = 0;
|
||||
|
||||
virtual std::vector<const Expr*> children() const { return {}; }
|
||||
virtual bool is_starred() const { return false; }
|
||||
virtual bool is_literal() const { return false; }
|
||||
virtual bool is_json_object() const { return false; }
|
||||
virtual bool is_attrib() const { return false; }
|
||||
|
||||
// for OP_DELETE_XXX
|
||||
virtual bool emit_del(CodeEmitContext* ctx) { return false; }
|
||||
@ -163,8 +163,6 @@ struct StarredExpr: Expr{
|
||||
StarredExpr(Expr_&& child): child(std::move(child)) {}
|
||||
Str str() const override { return "*"; }
|
||||
|
||||
std::vector<const Expr*> children() const override { return {child.get()}; }
|
||||
|
||||
bool is_starred() const override { return true; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
@ -184,8 +182,6 @@ struct NotExpr: Expr{
|
||||
NotExpr(Expr_&& child): child(std::move(child)) {}
|
||||
Str str() const override { return "not"; }
|
||||
|
||||
std::vector<const Expr*> children() const override { return {child.get()}; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
child->emit(ctx);
|
||||
ctx->emit(OP_UNARY_NOT, BC_NOARG, line);
|
||||
@ -198,8 +194,6 @@ struct AndExpr: Expr{
|
||||
Expr_ rhs;
|
||||
Str str() const override { return "and"; }
|
||||
|
||||
std::vector<const Expr*> children() const override { return {lhs.get(), rhs.get()}; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
lhs->emit(ctx);
|
||||
int patch = ctx->emit(OP_JUMP_IF_FALSE_OR_POP, BC_NOARG, line);
|
||||
@ -214,8 +208,6 @@ struct OrExpr: Expr{
|
||||
Expr_ rhs;
|
||||
Str str() const override { return "or"; }
|
||||
|
||||
std::vector<const Expr*> children() const override { return {lhs.get(), rhs.get()}; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
lhs->emit(ctx);
|
||||
int patch = ctx->emit(OP_JUMP_IF_TRUE_OR_POP, BC_NOARG, line);
|
||||
@ -295,8 +287,6 @@ struct NegatedExpr: Expr{
|
||||
NegatedExpr(Expr_&& child): child(std::move(child)) {}
|
||||
Str str() const override { return "-"; }
|
||||
|
||||
std::vector<const Expr*> children() const override { return {child.get()}; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
VM* vm = ctx->vm;
|
||||
// if child is a int of float, do constant folding
|
||||
@ -330,11 +320,6 @@ struct SliceExpr: Expr{
|
||||
Expr_ step;
|
||||
Str str() const override { return "slice()"; }
|
||||
|
||||
std::vector<const Expr*> children() const override {
|
||||
// may contain nullptr
|
||||
return {start.get(), stop.get(), step.get()};
|
||||
}
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
if(start){
|
||||
start->emit(ctx);
|
||||
@ -362,7 +347,6 @@ struct DictItemExpr: Expr{
|
||||
Expr_ key;
|
||||
Expr_ value;
|
||||
Str str() const override { return "k:v"; }
|
||||
std::vector<const Expr*> children() const override { return {key.get(), value.get()}; }
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
value->emit(ctx);
|
||||
@ -376,12 +360,6 @@ struct SequenceExpr: Expr{
|
||||
SequenceExpr(std::vector<Expr_>&& items): items(std::move(items)) {}
|
||||
virtual Opcode opcode() const = 0;
|
||||
|
||||
std::vector<const Expr*> children() const override {
|
||||
std::vector<const Expr*> ret;
|
||||
for(auto& item: items) ret.push_back(item.get());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
for(auto& item: items) item->emit(ctx);
|
||||
ctx->emit(opcode(), items.size(), line);
|
||||
@ -543,6 +521,7 @@ struct FStringExpr: Expr{
|
||||
size++;
|
||||
}
|
||||
ctx->emit(OP_LOAD_BUILTIN_EVAL, BC_NOARG, line);
|
||||
ctx->emit(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE);
|
||||
ctx->emit(OP_LOAD_CONST, ctx->add_const(VAR(m[1].str())), line);
|
||||
ctx->emit(OP_CALL, 1, line);
|
||||
size++;
|
||||
@ -609,6 +588,14 @@ struct AttribExpr: Expr{
|
||||
ctx->emit(OP_STORE_ATTR, index, line);
|
||||
return true;
|
||||
}
|
||||
|
||||
void emit_method(CodeEmitContext* ctx) {
|
||||
a->emit(ctx);
|
||||
int index = ctx->add_name(b);
|
||||
ctx->emit(OP_LOAD_METHOD, index, line);
|
||||
}
|
||||
|
||||
bool is_attrib() const override { return true; }
|
||||
};
|
||||
|
||||
// PASS
|
||||
@ -618,13 +605,6 @@ struct CallExpr: Expr{
|
||||
std::vector<std::pair<Str, Expr_>> kwargs;
|
||||
Str str() const override { return "call(...)"; }
|
||||
|
||||
std::vector<const Expr*> children() const override {
|
||||
std::vector<const Expr*> ret;
|
||||
for(auto& item: args) ret.push_back(item.get());
|
||||
// ...ignore kwargs for simplicity
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool need_unpack() const {
|
||||
for(auto& item: args) if(item->is_starred()) return true;
|
||||
return false;
|
||||
@ -634,7 +614,13 @@ struct CallExpr: Expr{
|
||||
VM* vm = ctx->vm;
|
||||
// TODO: if callable is a AttrExpr, we should try to use `fast_call`
|
||||
// instead of use `boundmethod` proxy
|
||||
callable->emit(ctx);
|
||||
if(callable->is_attrib()){
|
||||
auto p = static_cast<AttribExpr*>(callable.get());
|
||||
p->emit_method(ctx);
|
||||
}else{
|
||||
callable->emit(ctx);
|
||||
ctx->emit(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE);
|
||||
}
|
||||
// emit args
|
||||
for(auto& item: args) item->emit(ctx);
|
||||
// emit kwargs
|
||||
@ -659,10 +645,6 @@ struct BinaryExpr: Expr{
|
||||
Expr_ rhs;
|
||||
Str str() const override { return TK_STR(op); }
|
||||
|
||||
std::vector<const Expr*> children() const override {
|
||||
return {lhs.get(), rhs.get()};
|
||||
}
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
lhs->emit(ctx);
|
||||
rhs->emit(ctx);
|
||||
@ -706,10 +688,6 @@ struct TernaryExpr: Expr{
|
||||
return "cond ? t : f";
|
||||
}
|
||||
|
||||
std::vector<const Expr*> children() const override {
|
||||
return {cond.get(), true_expr.get(), false_expr.get()};
|
||||
}
|
||||
|
||||
void emit(CodeEmitContext* ctx) override {
|
||||
cond->emit(ctx);
|
||||
int patch = ctx->emit(OP_POP_JUMP_IF_FALSE, BC_NOARG, cond->line);
|
||||
|
@ -15,9 +15,11 @@ OPCODE(LOAD_FALSE)
|
||||
OPCODE(LOAD_ELLIPSIS)
|
||||
OPCODE(LOAD_BUILTIN_EVAL)
|
||||
OPCODE(LOAD_FUNCTION)
|
||||
OPCODE(LOAD_NULL)
|
||||
/**************************/
|
||||
OPCODE(LOAD_NAME)
|
||||
OPCODE(LOAD_ATTR)
|
||||
OPCODE(LOAD_METHOD)
|
||||
OPCODE(LOAD_SUBSCR)
|
||||
|
||||
OPCODE(STORE_LOCAL)
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "ceval.h"
|
||||
#include "compiler.h"
|
||||
#include "obj.h"
|
||||
#include "repl.h"
|
||||
#include "iter.h"
|
||||
#include "cffi.h"
|
||||
@ -68,7 +69,9 @@ inline void init_builtins(VM* _vm) {
|
||||
vm->check_type(args[0], vm->tp_type);
|
||||
Type type = OBJ_GET(Type, args[0]);
|
||||
if(!vm->isinstance(args[1], type)){
|
||||
vm->TypeError("super(type, obj): obj must be an instance or subtype of type");
|
||||
Str _0 = obj_type_name(vm, OBJ_GET(Type, vm->_t(args[1])));
|
||||
Str _1 = obj_type_name(vm, type);
|
||||
vm->TypeError("super(): " + _0.escape(true) + " is not an instance of " + _1.escape(true));
|
||||
}
|
||||
Type base = vm->_all_types[type].base;
|
||||
return vm->heap.gcnew(vm->tp_super, Super(args[1], base));
|
||||
|
47
src/vm.h
47
src/vm.h
@ -60,6 +60,7 @@ public:
|
||||
|
||||
PyObject* _py_op_call;
|
||||
PyObject* _py_op_yield;
|
||||
PyObject* _py_null;
|
||||
PyObject* None;
|
||||
PyObject* True;
|
||||
PyObject* False;
|
||||
@ -337,6 +338,7 @@ public:
|
||||
PyObject* call(PyObject* callable, Args args, const Args& kwargs, bool opCall);
|
||||
void unpack_args(Args& args);
|
||||
PyObject* getattr(PyObject* obj, StrName name, bool throw_err=true, bool class_only=false);
|
||||
PyObject* get_unbound_method(PyObject* obj, StrName name, PyObject** self);
|
||||
template<typename T>
|
||||
void setattr(PyObject* obj, StrName name, T&& value);
|
||||
template<int ARGC>
|
||||
@ -594,7 +596,7 @@ inline Str VM::disassemble(CodeObject_ co){
|
||||
argStr += " (" + CAST(Str, asRepr(co->consts[byte.arg])) + ")";
|
||||
break;
|
||||
case OP_LOAD_NAME: case OP_STORE_LOCAL: case OP_STORE_GLOBAL:
|
||||
case OP_LOAD_ATTR: case OP_STORE_ATTR: case OP_DELETE_ATTR:
|
||||
case OP_LOAD_ATTR: case OP_LOAD_METHOD: case OP_STORE_ATTR: case OP_DELETE_ATTR:
|
||||
case OP_IMPORT_NAME: case OP_BEGIN_CLASS:
|
||||
case OP_DELETE_LOCAL: case OP_DELETE_GLOBAL:
|
||||
argStr += " (" + co->names[byte.arg].str().escape(true) + ")";
|
||||
@ -663,6 +665,7 @@ inline void VM::init_builtin_types(){
|
||||
this->Ellipsis = heap._new<Dummy>(_new_type_object("ellipsis"), {});
|
||||
this->True = heap._new<Dummy>(tp_bool, {});
|
||||
this->False = heap._new<Dummy>(tp_bool, {});
|
||||
this->_py_null = heap._new<Dummy>(_new_type_object("_py_null"), {});
|
||||
this->_py_op_call = heap._new<Dummy>(_new_type_object("_py_op_call"), {});
|
||||
this->_py_op_yield = heap._new<Dummy>(_new_type_object("_py_op_yield"), {});
|
||||
|
||||
@ -682,7 +685,6 @@ inline void VM::init_builtin_types(){
|
||||
|
||||
post_init();
|
||||
for(int i=0; i<_all_types.size(); i++){
|
||||
// std::cout << i << ": " << _all_types[i].name << std::endl;
|
||||
_all_types[i].obj->attr()._try_perfect_rehash();
|
||||
}
|
||||
for(auto [k, v]: _modules.items()) v->attr()._try_perfect_rehash();
|
||||
@ -786,6 +788,7 @@ inline void VM::unpack_args(Args& args){
|
||||
|
||||
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
|
||||
inline PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err, bool class_only){
|
||||
// TODO: class_only impl may not be correct
|
||||
PyObject* objtype = _t(obj);
|
||||
// handle super() proxy
|
||||
if(is_type(obj, tp_super)){
|
||||
@ -815,6 +818,39 @@ inline PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err, bool c
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// used by OP_LOAD_METHOD
|
||||
// try to load a unbound method (fallback to `getattr` if not found)
|
||||
inline PyObject* VM::get_unbound_method(PyObject* obj, StrName name, PyObject** self){
|
||||
*self = _py_null;
|
||||
// TODO: class_only impl may not be correct
|
||||
PyObject* objtype = _t(obj);
|
||||
// handle super() proxy
|
||||
if(is_type(obj, tp_super)){
|
||||
const Super& super = OBJ_GET(Super, obj);
|
||||
obj = super.first;
|
||||
objtype = _t(super.second);
|
||||
}
|
||||
PyObject* cls_var = find_name_in_mro(objtype, name);
|
||||
if(cls_var != nullptr){
|
||||
// handle descriptor
|
||||
PyObject* descr_get = _t(cls_var)->attr().try_get(__get__);
|
||||
if(descr_get != nullptr) return call(descr_get, Args{cls_var, obj});
|
||||
}
|
||||
// handle instance __dict__
|
||||
if(!is_tagged(obj) && obj->is_attr_valid()){
|
||||
PyObject* val = obj->attr().try_get(name);
|
||||
if(val != nullptr) return val;
|
||||
}
|
||||
if(cls_var != nullptr){
|
||||
if(is_type(cls_var, tp_function) || is_type(cls_var, tp_native_function)){
|
||||
*self = obj;
|
||||
}
|
||||
return cls_var;
|
||||
}
|
||||
AttributeError(obj, name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void VM::setattr(PyObject* obj, StrName name, T&& value){
|
||||
static_assert(std::is_same_v<std::decay_t<T>, PyObject*>);
|
||||
@ -894,7 +930,12 @@ inline PyObject* VM::_exec(){
|
||||
Exception& _e = CAST(Exception&, obj);
|
||||
_e.st_push(frame->snapshot());
|
||||
callstack.pop();
|
||||
if(callstack.empty()) throw _e;
|
||||
if(callstack.empty()){
|
||||
#if DEBUG_FULL_EXCEPTION
|
||||
std::cerr << _e.summary() << std::endl;
|
||||
#endif
|
||||
throw _e;
|
||||
}
|
||||
frame = callstack.top().get();
|
||||
frame->push(obj);
|
||||
if(frame->id < base_id) throw ToBeRaisedException();
|
||||
|
Loading…
x
Reference in New Issue
Block a user