mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
support execdyn
This commit is contained in:
parent
41a938386a
commit
46fb524a01
@ -36,17 +36,19 @@ typedef struct Frame {
|
|||||||
const Bytecode* ip;
|
const Bytecode* ip;
|
||||||
const CodeObject* co;
|
const CodeObject* co;
|
||||||
py_GlobalRef module;
|
py_GlobalRef module;
|
||||||
bool has_function; // is p0 a function?
|
|
||||||
py_StackRef p0; // unwinding base
|
py_StackRef p0; // unwinding base
|
||||||
py_StackRef locals; // locals base
|
py_StackRef locals; // locals base
|
||||||
|
bool has_function; // is p0 a function?
|
||||||
|
bool is_dynamic; // is dynamic frame?
|
||||||
UnwindTarget* uw_list;
|
UnwindTarget* uw_list;
|
||||||
} Frame;
|
} Frame;
|
||||||
|
|
||||||
Frame* Frame__new(const CodeObject* co,
|
Frame* Frame__new(const CodeObject* co,
|
||||||
py_GlobalRef module,
|
py_GlobalRef module,
|
||||||
bool has_function,
|
|
||||||
py_StackRef p0,
|
py_StackRef p0,
|
||||||
py_StackRef locals);
|
py_StackRef locals,
|
||||||
|
bool has_function,
|
||||||
|
bool is_dynamic);
|
||||||
void Frame__delete(Frame* self);
|
void Frame__delete(Frame* self);
|
||||||
|
|
||||||
int Frame__ip(const Frame* self);
|
int Frame__ip(const Frame* self);
|
||||||
|
@ -125,5 +125,11 @@ py_Type pk_property__register();
|
|||||||
py_Type pk_staticmethod__register();
|
py_Type pk_staticmethod__register();
|
||||||
py_Type pk_classmethod__register();
|
py_Type pk_classmethod__register();
|
||||||
py_Type pk_generator__register();
|
py_Type pk_generator__register();
|
||||||
|
py_Type pk_namedict__register();
|
||||||
|
py_Type pk_locals__register();
|
||||||
|
|
||||||
py_TValue pk_builtins__register();
|
py_TValue pk_builtins__register();
|
||||||
|
|
||||||
|
/* mappingproxy */
|
||||||
|
void pk_mappingproxy__namedict(py_Ref out, py_Ref object);
|
||||||
|
void pk_mappingproxy__locals(py_Ref out, Frame* frame);
|
@ -79,7 +79,7 @@ bool py_exec(const char* source,
|
|||||||
/// Assume `globals()` and `locals()` are pushed to the stack.
|
/// Assume `globals()` and `locals()` are pushed to the stack.
|
||||||
/// After the execution, the result will be set to `py_retval()`.
|
/// After the execution, the result will be set to `py_retval()`.
|
||||||
/// The stack size will be reduced by 2.
|
/// The stack size will be reduced by 2.
|
||||||
bool py_execdynamic(const char* source,
|
bool py_execdyn(const char* source,
|
||||||
const char* filename,
|
const char* filename,
|
||||||
enum py_CompileMode mode,
|
enum py_CompileMode mode,
|
||||||
py_Ref module) PY_RAISE;
|
py_Ref module) PY_RAISE;
|
||||||
@ -526,7 +526,8 @@ enum py_PredefinedTypes {
|
|||||||
tp_BaseException, // 2 slots (arg + inner exc)
|
tp_BaseException, // 2 slots (arg + inner exc)
|
||||||
tp_Exception,
|
tp_Exception,
|
||||||
tp_bytes,
|
tp_bytes,
|
||||||
tp_mappingproxy,
|
tp_namedict,
|
||||||
|
tp_locals,
|
||||||
tp_dict,
|
tp_dict,
|
||||||
tp_dict_items, // 1 slot
|
tp_dict_items, // 1 slot
|
||||||
tp_property, // 2 slots (getter + setter)
|
tp_property, // 2 slots (getter + setter)
|
||||||
|
@ -159,7 +159,10 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
}
|
}
|
||||||
case OP_LOAD_NAME: {
|
case OP_LOAD_NAME: {
|
||||||
py_Name name = byte.arg;
|
py_Name name = byte.arg;
|
||||||
py_Ref tmp = Frame__f_locals_try_get(frame, name);
|
py_TValue* tmp;
|
||||||
|
if(!frame->is_dynamic) {
|
||||||
|
// locals
|
||||||
|
tmp = Frame__f_locals_try_get(frame, name);
|
||||||
if(tmp != NULL) {
|
if(tmp != NULL) {
|
||||||
if(py_isnil(tmp)) {
|
if(py_isnil(tmp)) {
|
||||||
UnboundLocalError(name);
|
UnboundLocalError(name);
|
||||||
@ -168,19 +171,53 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
PUSH(tmp);
|
PUSH(tmp);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
// closure
|
||||||
tmp = Frame__f_closure_try_get(frame, name);
|
tmp = Frame__f_closure_try_get(frame, name);
|
||||||
if(tmp != NULL) {
|
if(tmp != NULL) {
|
||||||
PUSH(tmp);
|
PUSH(tmp);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
// globals
|
||||||
tmp = py_getdict(frame->module, name);
|
tmp = py_getdict(frame->module, name);
|
||||||
if(tmp != NULL) {
|
if(tmp != NULL) {
|
||||||
PUSH(tmp);
|
PUSH(tmp);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
py_newstr(SP()++, py_name2str(name));
|
||||||
|
// locals
|
||||||
|
if(py_getitem(&frame->p0[1], TOP())) {
|
||||||
|
py_assign(TOP(), py_retval());
|
||||||
|
DISPATCH();
|
||||||
|
} else {
|
||||||
|
if(py_matchexc(tp_KeyError)) {
|
||||||
|
py_clearexc(NULL);
|
||||||
|
} else {
|
||||||
|
goto __ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// closure
|
||||||
|
tmp = Frame__f_closure_try_get(frame, name);
|
||||||
|
if(tmp != NULL) {
|
||||||
|
py_assign(TOP(), tmp);
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
// globals
|
||||||
|
if(py_getitem(&frame->p0[0], TOP())) {
|
||||||
|
py_assign(TOP(), py_retval());
|
||||||
|
DISPATCH();
|
||||||
|
} else {
|
||||||
|
if(py_matchexc(tp_KeyError)) {
|
||||||
|
py_clearexc(NULL);
|
||||||
|
} else {
|
||||||
|
goto __ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// builtins
|
||||||
tmp = py_getdict(&self->builtins, name);
|
tmp = py_getdict(&self->builtins, name);
|
||||||
if(tmp != NULL) {
|
if(tmp != NULL) {
|
||||||
PUSH(tmp);
|
py_assign(TOP(), tmp);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
NameError(name);
|
NameError(name);
|
||||||
@ -284,19 +321,35 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
}
|
}
|
||||||
case OP_STORE_FAST: frame->locals[byte.arg] = POPX(); DISPATCH();
|
case OP_STORE_FAST: frame->locals[byte.arg] = POPX(); DISPATCH();
|
||||||
case OP_STORE_NAME: {
|
case OP_STORE_NAME: {
|
||||||
|
assert(frame->is_dynamic);
|
||||||
py_Name name = byte.arg;
|
py_Name name = byte.arg;
|
||||||
if(frame->has_function) {
|
py_newstr(SP()++, py_name2str(name));
|
||||||
py_Ref slot = Frame__f_locals_try_get(frame, name);
|
// [value, name]
|
||||||
if(slot != NULL) {
|
if(!py_isnone(&frame->p0[1])){
|
||||||
*slot = *TOP(); // store in locals if possible
|
// locals
|
||||||
|
if(py_setitem(&frame->p0[1], TOP(), SECOND())) {
|
||||||
|
STACK_SHRINK(2);
|
||||||
|
DISPATCH();
|
||||||
} else {
|
} else {
|
||||||
|
if(py_matchexc(tp_KeyError)) {
|
||||||
|
py_clearexc(NULL);
|
||||||
NameError(name);
|
NameError(name);
|
||||||
|
}
|
||||||
goto __ERROR;
|
goto __ERROR;
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
// globals
|
||||||
|
if(py_setitem(&frame->p0[0], TOP(), SECOND())) {
|
||||||
|
STACK_SHRINK(2);
|
||||||
|
DISPATCH();
|
||||||
} else {
|
} else {
|
||||||
py_setdict(frame->module, name, TOP());
|
if(py_matchexc(tp_KeyError)) {
|
||||||
|
py_clearexc(NULL);
|
||||||
|
NameError(name);
|
||||||
|
}
|
||||||
|
goto __ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
POP();
|
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_STORE_GLOBAL: {
|
case OP_STORE_GLOBAL: {
|
||||||
@ -339,19 +392,31 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_DELETE_NAME: {
|
case OP_DELETE_NAME: {
|
||||||
|
assert(frame->is_dynamic);
|
||||||
py_Name name = byte.arg;
|
py_Name name = byte.arg;
|
||||||
if(frame->has_function) {
|
py_newstr(SP()++, py_name2str(name));
|
||||||
py_TValue* slot = Frame__f_locals_try_get(frame, name);
|
if(!py_isnone(&frame->p0[1])){
|
||||||
if(slot) {
|
// locals
|
||||||
py_newnil(slot);
|
if(py_delitem(&frame->p0[1], TOP())) {
|
||||||
|
POP();
|
||||||
|
DISPATCH();
|
||||||
} else {
|
} else {
|
||||||
|
if(py_matchexc(tp_KeyError)) {
|
||||||
|
py_clearexc(NULL);
|
||||||
NameError(name);
|
NameError(name);
|
||||||
|
}
|
||||||
goto __ERROR;
|
goto __ERROR;
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
// globals
|
||||||
|
if(py_delitem(&frame->p0[0], TOP())) {
|
||||||
|
POP();
|
||||||
|
DISPATCH();
|
||||||
} else {
|
} else {
|
||||||
bool ok = py_deldict(frame->module, name);
|
if(py_matchexc(tp_KeyError)) {
|
||||||
if(!ok) {
|
py_clearexc(NULL);
|
||||||
NameError(name);
|
NameError(name);
|
||||||
|
}
|
||||||
goto __ERROR;
|
goto __ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -889,8 +954,9 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
case OP_WITH_ENTER: {
|
case OP_WITH_ENTER: {
|
||||||
// [expr]
|
// [expr]
|
||||||
py_push(TOP());
|
py_push(TOP());
|
||||||
if(!py_pushmethod(__enter__)){
|
if(!py_pushmethod(__enter__)) {
|
||||||
TypeError("'%t' object does not support the context manager protocol", TOP()->type);
|
TypeError("'%t' object does not support the context manager protocol",
|
||||||
|
TOP()->type);
|
||||||
goto __ERROR;
|
goto __ERROR;
|
||||||
}
|
}
|
||||||
if(!py_vectorcall(0, 0)) goto __ERROR;
|
if(!py_vectorcall(0, 0)) goto __ERROR;
|
||||||
@ -900,8 +966,9 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
case OP_WITH_EXIT: {
|
case OP_WITH_EXIT: {
|
||||||
// [expr]
|
// [expr]
|
||||||
py_push(TOP());
|
py_push(TOP());
|
||||||
if(!py_pushmethod(__exit__)){
|
if(!py_pushmethod(__exit__)) {
|
||||||
TypeError("'%t' object does not support the context manager protocol", TOP()->type);
|
TypeError("'%t' object does not support the context manager protocol",
|
||||||
|
TOP()->type);
|
||||||
goto __ERROR;
|
goto __ERROR;
|
||||||
}
|
}
|
||||||
if(!py_vectorcall(0, 0)) goto __ERROR;
|
if(!py_vectorcall(0, 0)) goto __ERROR;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "pocketpy/objects/codeobject.h"
|
#include "pocketpy/objects/codeobject.h"
|
||||||
#include "pocketpy/objects/object.h"
|
#include "pocketpy/objects/object.h"
|
||||||
#include "pocketpy/pocketpy.h"
|
#include "pocketpy/pocketpy.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
void ValueStack__ctor(ValueStack* self) {
|
void ValueStack__ctor(ValueStack* self) {
|
||||||
self->sp = self->begin;
|
self->sp = self->begin;
|
||||||
@ -37,18 +38,20 @@ void UnwindTarget__delete(UnwindTarget* self) { free(self); }
|
|||||||
|
|
||||||
Frame* Frame__new(const CodeObject* co,
|
Frame* Frame__new(const CodeObject* co,
|
||||||
py_GlobalRef module,
|
py_GlobalRef module,
|
||||||
bool has_function,
|
|
||||||
py_StackRef p0,
|
py_StackRef p0,
|
||||||
py_StackRef locals) {
|
py_StackRef locals,
|
||||||
|
bool has_function,
|
||||||
|
bool is_dynamic) {
|
||||||
static_assert(sizeof(Frame) <= kPoolFrameBlockSize, "!(sizeof(Frame) <= kPoolFrameBlockSize)");
|
static_assert(sizeof(Frame) <= kPoolFrameBlockSize, "!(sizeof(Frame) <= kPoolFrameBlockSize)");
|
||||||
Frame* self = PoolFrame_alloc();
|
Frame* self = PoolFrame_alloc();
|
||||||
self->f_back = NULL;
|
self->f_back = NULL;
|
||||||
self->ip = (Bytecode*)co->codes.data - 1;
|
self->ip = (Bytecode*)co->codes.data - 1;
|
||||||
self->co = co;
|
self->co = co;
|
||||||
self->module = module;
|
self->module = module;
|
||||||
self->has_function = has_function;
|
|
||||||
self->p0 = p0;
|
self->p0 = p0;
|
||||||
self->locals = locals;
|
self->locals = locals;
|
||||||
|
self->has_function = has_function;
|
||||||
|
self->is_dynamic = is_dynamic;
|
||||||
self->uw_list = NULL;
|
self->uw_list = NULL;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -150,5 +153,6 @@ int Frame__iblock(const Frame* self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
py_TValue* Frame__f_locals_try_get(Frame* self, py_Name name) {
|
py_TValue* Frame__f_locals_try_get(Frame* self, py_Name name) {
|
||||||
|
assert(!self->is_dynamic);
|
||||||
return FastLocals__try_get_by_name(self->locals, self->co, name);
|
return FastLocals__try_get_by_name(self->locals, self->co, name);
|
||||||
}
|
}
|
@ -7,6 +7,7 @@
|
|||||||
#include "pocketpy/objects/base.h"
|
#include "pocketpy/objects/base.h"
|
||||||
#include "pocketpy/common/_generated.h"
|
#include "pocketpy/common/_generated.h"
|
||||||
#include "pocketpy/pocketpy.h"
|
#include "pocketpy/pocketpy.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
static char* pk_default_import_file(const char* path) {
|
static char* pk_default_import_file(const char* path) {
|
||||||
#if PK_ENABLE_OS
|
#if PK_ENABLE_OS
|
||||||
@ -112,7 +113,8 @@ void VM__ctor(VM* self) {
|
|||||||
validate(tp_BaseException, pk_BaseException__register());
|
validate(tp_BaseException, pk_BaseException__register());
|
||||||
validate(tp_Exception, pk_Exception__register());
|
validate(tp_Exception, pk_Exception__register());
|
||||||
validate(tp_bytes, pk_bytes__register());
|
validate(tp_bytes, pk_bytes__register());
|
||||||
validate(tp_mappingproxy, pk_newtype("mappingproxy", tp_object, NULL, NULL, false, true));
|
validate(tp_namedict, pk_namedict__register());
|
||||||
|
validate(tp_locals, pk_locals__register());
|
||||||
|
|
||||||
validate(tp_dict, pk_dict__register());
|
validate(tp_dict, pk_dict__register());
|
||||||
validate(tp_dict_items, pk_dict_items__register());
|
validate(tp_dict_items, pk_dict_items__register());
|
||||||
@ -427,10 +429,10 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
|
|||||||
memcpy(argv, self->__vectorcall_buffer, co->nlocals * sizeof(py_TValue));
|
memcpy(argv, self->__vectorcall_buffer, co->nlocals * sizeof(py_TValue));
|
||||||
// submit the call
|
// submit the call
|
||||||
if(!fn->cfunc) {
|
if(!fn->cfunc) {
|
||||||
VM__push_frame(self, Frame__new(co, &fn->module, true, p0, argv));
|
VM__push_frame(self, Frame__new(co, &fn->module, p0, argv, true, false));
|
||||||
return opcall ? RES_CALL : VM__run_top_frame(self);
|
return opcall ? RES_CALL : VM__run_top_frame(self);
|
||||||
} else {
|
} else {
|
||||||
bool ok = fn->cfunc(co->nlocals, argv);
|
bool ok = py_callcfunc(fn->cfunc, co->nlocals, argv);
|
||||||
self->stack.sp = p0;
|
self->stack.sp = p0;
|
||||||
return ok ? RES_RETURN : RES_ERROR;
|
return ok ? RES_RETURN : RES_ERROR;
|
||||||
}
|
}
|
||||||
@ -451,22 +453,16 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
|
|||||||
// initialize local variables to py_NIL
|
// initialize local variables to py_NIL
|
||||||
memset(p1, 0, (char*)self->stack.sp - (char*)p1);
|
memset(p1, 0, (char*)self->stack.sp - (char*)p1);
|
||||||
// submit the call
|
// submit the call
|
||||||
VM__push_frame(self, Frame__new(co, &fn->module, true, p0, argv));
|
VM__push_frame(self, Frame__new(co, &fn->module, p0, argv, true, false));
|
||||||
return opcall ? RES_CALL : VM__run_top_frame(self);
|
return opcall ? RES_CALL : VM__run_top_frame(self);
|
||||||
case FuncType_GENERATOR: {
|
case FuncType_GENERATOR: {
|
||||||
bool ok = prepare_py_call(self->__vectorcall_buffer, argv, p1, kwargc, fn->decl);
|
bool ok = prepare_py_call(self->__vectorcall_buffer, argv, p1, kwargc, fn->decl);
|
||||||
if(!ok) return RES_ERROR;
|
if(!ok) return RES_ERROR;
|
||||||
Frame* frame = Frame__new(co, &fn->module, false, p0, argv);
|
Frame* frame = Frame__new(co, &fn->module, p0, argv, false, false);
|
||||||
pk_newgenerator(py_retval(), frame, self->__vectorcall_buffer, co->nlocals);
|
pk_newgenerator(py_retval(), frame, self->__vectorcall_buffer, co->nlocals);
|
||||||
self->stack.sp = p0;
|
self->stack.sp = p0;
|
||||||
return RES_RETURN;
|
return RES_RETURN;
|
||||||
}
|
}
|
||||||
// prepare_py_call(__vectorcall_buffer, args, kwargs, fn.decl);
|
|
||||||
// s_data.reset(p0);
|
|
||||||
// callstack.emplace(nullptr, co, fn._module, callable.get(), nullptr);
|
|
||||||
// return __py_generator(
|
|
||||||
// callstack.popx(),
|
|
||||||
// ArgsView(__vectorcall_buffer, __vectorcall_buffer + co->nlocals));
|
|
||||||
default: c11__unreachedable();
|
default: c11__unreachedable();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "pocketpy/objects/object.h"
|
#include "pocketpy/objects/object.h"
|
||||||
#include "pocketpy/interpreter/vm.h"
|
#include "pocketpy/interpreter/vm.h"
|
||||||
#include "pocketpy/compiler/compiler.h"
|
#include "pocketpy/compiler/compiler.h"
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
VM* pk_current_vm;
|
VM* pk_current_vm;
|
||||||
@ -103,7 +104,7 @@ static bool _py_exec(const char* source,
|
|||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame* frame = Frame__new(&co, module, false, sp, sp);
|
Frame* frame = Frame__new(&co, module, sp, sp, false, is_dynamic);
|
||||||
VM__push_frame(vm, frame);
|
VM__push_frame(vm, frame);
|
||||||
FrameResult res = VM__run_top_frame(vm);
|
FrameResult res = VM__run_top_frame(vm);
|
||||||
CodeObject__dtor(&co);
|
CodeObject__dtor(&co);
|
||||||
@ -117,10 +118,7 @@ bool py_exec(const char* source, const char* filename, enum py_CompileMode mode,
|
|||||||
return _py_exec(source, filename, mode, module, false);
|
return _py_exec(source, filename, mode, module, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool py_execdynamic(const char* source,
|
bool py_execdyn(const char* source, const char* filename, enum py_CompileMode mode, py_Ref module) {
|
||||||
const char* filename,
|
|
||||||
enum py_CompileMode mode,
|
|
||||||
py_Ref module) {
|
|
||||||
return _py_exec(source, filename, mode, module, true);
|
return _py_exec(source, filename, mode, module, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,11 +126,14 @@ bool py_call(py_Ref f, int argc, py_Ref argv) {
|
|||||||
if(f->type == tp_nativefunc) {
|
if(f->type == tp_nativefunc) {
|
||||||
return py_callcfunc(f->_cfunc, argc, argv);
|
return py_callcfunc(f->_cfunc, argc, argv);
|
||||||
} else {
|
} else {
|
||||||
|
py_StackRef p0 = py_peek(0);
|
||||||
py_push(f);
|
py_push(f);
|
||||||
py_pushnil();
|
py_pushnil();
|
||||||
for(int i = 0; i < argc; i++)
|
for(int i = 0; i < argc; i++)
|
||||||
py_push(py_offset(argv, i));
|
py_push(py_offset(argv, i));
|
||||||
return py_vectorcall(argc, 0);
|
bool ok = py_vectorcall(argc, 0);
|
||||||
|
pk_current_vm->stack.sp = p0;
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,8 +151,7 @@ bool py_callcfunc(py_CFunction f, int argc, py_Ref argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool py_vectorcall(uint16_t argc, uint16_t kwargc) {
|
bool py_vectorcall(uint16_t argc, uint16_t kwargc) {
|
||||||
VM* vm = pk_current_vm;
|
return VM__vectorcall(pk_current_vm, argc, kwargc, false) != RES_ERROR;
|
||||||
return VM__vectorcall(vm, argc, kwargc, false) != RES_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
py_Ref py_retval() { return &pk_current_vm->last_retval; }
|
py_Ref py_retval() { return &pk_current_vm->last_retval; }
|
||||||
|
@ -252,20 +252,6 @@ static bool builtins_print(int argc, py_Ref argv) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool builtins_exec(int argc, py_Ref argv) {
|
|
||||||
PY_CHECK_ARGC(1);
|
|
||||||
PY_CHECK_ARG_TYPE(0, tp_str);
|
|
||||||
Frame* frame = pk_current_vm->top_frame;
|
|
||||||
return py_exec(py_tostr(argv), "<exec>", EXEC_MODE, frame->module);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool builtins_eval(int argc, py_Ref argv) {
|
|
||||||
PY_CHECK_ARGC(1);
|
|
||||||
PY_CHECK_ARG_TYPE(0, tp_str);
|
|
||||||
Frame* frame = pk_current_vm->top_frame;
|
|
||||||
return py_exec(py_tostr(argv), "<eval>", EVAL_MODE, frame->module);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool builtins_isinstance(int argc, py_Ref argv) {
|
static bool builtins_isinstance(int argc, py_Ref argv) {
|
||||||
PY_CHECK_ARGC(2);
|
PY_CHECK_ARGC(2);
|
||||||
if(py_istuple(py_arg(1))) {
|
if(py_istuple(py_arg(1))) {
|
||||||
@ -301,10 +287,9 @@ static bool builtins_getattr(int argc, py_Ref argv) {
|
|||||||
if(argc == 2) {
|
if(argc == 2) {
|
||||||
return py_getattr(py_arg(0), name);
|
return py_getattr(py_arg(0), name);
|
||||||
} else if(argc == 3) {
|
} else if(argc == 3) {
|
||||||
py_StackRef p0 = py_peek(0);
|
|
||||||
bool ok = py_getattr(py_arg(0), name);
|
bool ok = py_getattr(py_arg(0), name);
|
||||||
if(!ok && py_matchexc(tp_AttributeError)) {
|
if(!ok && py_matchexc(tp_AttributeError)) {
|
||||||
py_clearexc(p0);
|
py_clearexc(NULL);
|
||||||
py_assign(py_retval(), py_arg(2));
|
py_assign(py_retval(), py_arg(2));
|
||||||
return true; // default value
|
return true; // default value
|
||||||
}
|
}
|
||||||
@ -327,14 +312,13 @@ static bool builtins_hasattr(int argc, py_Ref argv) {
|
|||||||
PY_CHECK_ARGC(2);
|
PY_CHECK_ARGC(2);
|
||||||
PY_CHECK_ARG_TYPE(1, tp_str);
|
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||||
py_Name name = py_namev(py_tosv(py_arg(1)));
|
py_Name name = py_namev(py_tosv(py_arg(1)));
|
||||||
py_StackRef p0 = py_peek(0);
|
|
||||||
bool ok = py_getattr(py_arg(0), name);
|
bool ok = py_getattr(py_arg(0), name);
|
||||||
if(ok) {
|
if(ok) {
|
||||||
py_newbool(py_retval(), true);
|
py_newbool(py_retval(), true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(py_matchexc(tp_AttributeError)) {
|
if(py_matchexc(tp_AttributeError)) {
|
||||||
py_clearexc(p0);
|
py_clearexc(NULL);
|
||||||
py_newbool(py_retval(), false);
|
py_newbool(py_retval(), false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -369,6 +353,64 @@ static bool builtins_ord(int argc, py_Ref argv) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool builtins_globals(int argc, py_Ref argv) {
|
||||||
|
Frame* frame = pk_current_vm->top_frame;
|
||||||
|
if(frame->is_dynamic){
|
||||||
|
py_assign(py_retval(), &frame->p0[0]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
pk_mappingproxy__namedict(py_retval(), frame->module);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool builtins_locals(int argc, py_Ref argv){
|
||||||
|
Frame* frame = pk_current_vm->top_frame;
|
||||||
|
if(frame->is_dynamic){
|
||||||
|
py_assign(py_retval(), &frame->p0[1]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(!frame->has_function) return builtins_globals(argc, argv);
|
||||||
|
pk_mappingproxy__locals(py_retval(), frame);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _builtins_execdyn(const char* title, int argc, py_Ref argv, enum py_CompileMode mode) {
|
||||||
|
PY_CHECK_ARG_TYPE(0, tp_str);
|
||||||
|
Frame* frame = pk_current_vm->top_frame;
|
||||||
|
switch(argc){
|
||||||
|
case 1: {
|
||||||
|
// system globals + system locals
|
||||||
|
if(!builtins_globals(0, NULL)) return false;
|
||||||
|
py_push(py_retval());
|
||||||
|
if(!builtins_locals(0, NULL)) return false;
|
||||||
|
py_push(py_retval());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
// user globals + user globals
|
||||||
|
py_push(py_arg(1));
|
||||||
|
py_push(py_arg(1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
// user globals + user locals
|
||||||
|
py_push(py_arg(1));
|
||||||
|
py_push(py_arg(2));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: return TypeError("%s() takes at most 3 arguments", title);
|
||||||
|
}
|
||||||
|
return py_execdyn(py_tostr(argv), "<string>", mode, frame->module);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool builtins_exec(int argc, py_Ref argv){
|
||||||
|
return _builtins_execdyn("exec", argc, argv, EXEC_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool builtins_eval(int argc, py_Ref argv) {
|
||||||
|
return _builtins_execdyn("eval", argc, argv, EVAL_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
static bool NoneType__repr__(int argc, py_Ref argv) {
|
static bool NoneType__repr__(int argc, py_Ref argv) {
|
||||||
py_newstr(py_retval(), "None");
|
py_newstr(py_retval(), "None");
|
||||||
return true;
|
return true;
|
||||||
@ -396,9 +438,6 @@ py_TValue pk_builtins__register() {
|
|||||||
py_bindfunc(builtins, "abs", builtins_abs);
|
py_bindfunc(builtins, "abs", builtins_abs);
|
||||||
py_bindfunc(builtins, "divmod", builtins_divmod);
|
py_bindfunc(builtins, "divmod", builtins_divmod);
|
||||||
|
|
||||||
py_bindfunc(builtins, "exec", builtins_exec);
|
|
||||||
py_bindfunc(builtins, "eval", builtins_eval);
|
|
||||||
|
|
||||||
py_bind(builtins, "print(*args, sep=' ', end='\\n')", builtins_print);
|
py_bind(builtins, "print(*args, sep=' ', end='\\n')", builtins_print);
|
||||||
|
|
||||||
py_bindfunc(builtins, "isinstance", builtins_isinstance);
|
py_bindfunc(builtins, "isinstance", builtins_isinstance);
|
||||||
@ -412,6 +451,11 @@ py_TValue pk_builtins__register() {
|
|||||||
py_bindfunc(builtins, "chr", builtins_chr);
|
py_bindfunc(builtins, "chr", builtins_chr);
|
||||||
py_bindfunc(builtins, "ord", builtins_ord);
|
py_bindfunc(builtins, "ord", builtins_ord);
|
||||||
|
|
||||||
|
py_bindfunc(builtins, "globals", builtins_globals);
|
||||||
|
py_bindfunc(builtins, "locals", builtins_locals);
|
||||||
|
py_bindfunc(builtins, "exec", builtins_exec);
|
||||||
|
py_bindfunc(builtins, "eval", builtins_eval);
|
||||||
|
|
||||||
// some patches
|
// some patches
|
||||||
py_bindmagic(tp_NoneType, __repr__, NoneType__repr__);
|
py_bindmagic(tp_NoneType, __repr__, NoneType__repr__);
|
||||||
py_bindmagic(tp_ellipsis, __repr__, ellipsis__repr__);
|
py_bindmagic(tp_ellipsis, __repr__, ellipsis__repr__);
|
||||||
|
123
src/public/py_mappingproxy.c
Normal file
123
src/public/py_mappingproxy.c
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
#include "pocketpy/pocketpy.h"
|
||||||
|
|
||||||
|
#include "pocketpy/common/utils.h"
|
||||||
|
#include "pocketpy/objects/object.h"
|
||||||
|
#include "pocketpy/interpreter/vm.h"
|
||||||
|
#include "pocketpy/common/sstream.h"
|
||||||
|
|
||||||
|
|
||||||
|
void pk_mappingproxy__namedict(py_Ref out, py_Ref object){
|
||||||
|
py_newobject(py_retval(), tp_namedict, 1, 0);
|
||||||
|
assert(object->is_ptr && object->_obj->slots == -1);
|
||||||
|
py_setslot(py_retval(), 0, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool namedict__getitem__(int argc, py_Ref argv){
|
||||||
|
PY_CHECK_ARGC(2);
|
||||||
|
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||||
|
py_Name name = py_namev(py_tosv(py_arg(1)));
|
||||||
|
py_Ref res = py_getdict(py_getslot(argv, 0), name);
|
||||||
|
if(!res) return KeyError(py_arg(1));
|
||||||
|
py_assign(py_retval(), res);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool namedict__setitem__(int argc, py_Ref argv){
|
||||||
|
PY_CHECK_ARGC(3);
|
||||||
|
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||||
|
py_Name name = py_namev(py_tosv(py_arg(1)));
|
||||||
|
py_setdict(py_getslot(argv, 0), name, py_arg(2));
|
||||||
|
py_newnone(py_retval());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool namedict__delitem__(int argc, py_Ref argv){
|
||||||
|
PY_CHECK_ARGC(2);
|
||||||
|
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||||
|
py_Name name = py_namev(py_tosv(py_arg(1)));
|
||||||
|
if(!py_deldict(py_getslot(argv, 0), name)) return KeyError(py_arg(1));
|
||||||
|
py_newnone(py_retval());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool namedict__contains__(int argc, py_Ref argv){
|
||||||
|
PY_CHECK_ARGC(2);
|
||||||
|
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||||
|
py_Name name = py_namev(py_tosv(py_arg(1)));
|
||||||
|
py_Ref res = py_getdict(py_getslot(argv, 0), name);
|
||||||
|
py_newbool(py_retval(), res != NULL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
py_Type pk_namedict__register() {
|
||||||
|
py_Type type = pk_newtype("namedict", tp_object, NULL, NULL, false, true);
|
||||||
|
|
||||||
|
py_bindmagic(type, __getitem__, namedict__getitem__);
|
||||||
|
py_bindmagic(type, __setitem__, namedict__setitem__);
|
||||||
|
py_bindmagic(type, __delitem__, namedict__delitem__);
|
||||||
|
py_bindmagic(type, __contains__, namedict__contains__);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////
|
||||||
|
|
||||||
|
void pk_mappingproxy__locals(py_Ref out, Frame* frame){
|
||||||
|
assert(frame->has_function && !frame->is_dynamic);
|
||||||
|
Frame** ud = py_newobject(py_retval(), tp_locals, 0, sizeof(Frame*));
|
||||||
|
*ud = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool locals__getitem__(int argc, py_Ref argv){
|
||||||
|
PY_CHECK_ARGC(2);
|
||||||
|
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||||
|
Frame** ud = py_touserdata(argv);
|
||||||
|
py_Name name = py_namev(py_tosv(py_arg(1)));
|
||||||
|
py_Ref slot = Frame__f_locals_try_get(*ud, name);
|
||||||
|
if(!slot || py_isnil(slot)) return KeyError(py_arg(1));
|
||||||
|
py_assign(py_retval(), slot);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool locals__setitem__(int argc, py_Ref argv){
|
||||||
|
PY_CHECK_ARGC(3);
|
||||||
|
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||||
|
Frame** ud = py_touserdata(argv);
|
||||||
|
py_Name name = py_namev(py_tosv(py_arg(1)));
|
||||||
|
py_Ref slot = Frame__f_locals_try_get(*ud, name);
|
||||||
|
if(!slot) return KeyError(py_arg(1));
|
||||||
|
py_assign(slot, py_arg(2));
|
||||||
|
py_newnone(py_retval());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool locals__delitem__(int argc, py_Ref argv){
|
||||||
|
PY_CHECK_ARGC(2);
|
||||||
|
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||||
|
Frame** ud = py_touserdata(argv);
|
||||||
|
py_Name name = py_namev(py_tosv(py_arg(1)));
|
||||||
|
py_Ref res = Frame__f_locals_try_get(*ud, name);
|
||||||
|
if(!res || py_isnil(res)) return KeyError(py_arg(1));
|
||||||
|
py_newnil(res);
|
||||||
|
py_newnone(py_retval());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool locals__contains__(int argc, py_Ref argv){
|
||||||
|
PY_CHECK_ARGC(2);
|
||||||
|
PY_CHECK_ARG_TYPE(1, tp_str);
|
||||||
|
Frame** ud = py_touserdata(argv);
|
||||||
|
py_Name name = py_namev(py_tosv(py_arg(1)));
|
||||||
|
py_Ref slot = Frame__f_locals_try_get(*ud, name);
|
||||||
|
py_newbool(py_retval(), slot && !py_isnil(slot));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
py_Type pk_locals__register() {
|
||||||
|
py_Type type = pk_newtype("locals", tp_locals, NULL, NULL, false, true);
|
||||||
|
|
||||||
|
py_bindmagic(type, __getitem__, locals__getitem__);
|
||||||
|
py_bindmagic(type, __setitem__, locals__setitem__);
|
||||||
|
py_bindmagic(type, __delitem__, locals__delitem__);
|
||||||
|
py_bindmagic(type, __contains__, locals__contains__);
|
||||||
|
return type;
|
||||||
|
}
|
@ -44,6 +44,16 @@ static bool object__repr__(int argc, py_Ref argv) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool object__dict__getter(int argc, py_Ref argv) {
|
||||||
|
PY_CHECK_ARGC(1);
|
||||||
|
if(argv->is_ptr && argv->_obj->slots == -1){
|
||||||
|
pk_mappingproxy__namedict(py_retval(), argv);
|
||||||
|
}else{
|
||||||
|
py_newnone(py_retval());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool type__repr__(int argc, py_Ref argv) {
|
static bool type__repr__(int argc, py_Ref argv) {
|
||||||
PY_CHECK_ARGC(1);
|
PY_CHECK_ARGC(1);
|
||||||
c11_sbuf buf;
|
c11_sbuf buf;
|
||||||
@ -88,6 +98,7 @@ void pk_object__register() {
|
|||||||
py_bindmagic(tp_object, __eq__, object__eq__);
|
py_bindmagic(tp_object, __eq__, object__eq__);
|
||||||
py_bindmagic(tp_object, __ne__, object__ne__);
|
py_bindmagic(tp_object, __ne__, object__ne__);
|
||||||
py_bindmagic(tp_object, __repr__, object__repr__);
|
py_bindmagic(tp_object, __repr__, object__repr__);
|
||||||
|
py_bindproperty(tp_object, "__dict__", object__dict__getter, NULL);
|
||||||
|
|
||||||
py_bindmagic(tp_type, __repr__, type__repr__);
|
py_bindmagic(tp_type, __repr__, type__repr__);
|
||||||
py_bindmagic(tp_type, __new__, type__new__);
|
py_bindmagic(tp_type, __new__, type__new__);
|
||||||
|
@ -75,10 +75,9 @@ int py_next(py_Ref val) {
|
|||||||
TypeError("'%t' object is not an iterator", val->type);
|
TypeError("'%t' object is not an iterator", val->type);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
py_StackRef p0 = py_peek(0);
|
|
||||||
if(py_call(tmp, 1, val)) return true;
|
if(py_call(tmp, 1, val)) return true;
|
||||||
if(vm->curr_exception.type == tp_StopIteration) {
|
if(vm->curr_exception.type == tp_StopIteration) {
|
||||||
py_clearexc(p0);
|
py_clearexc(NULL);
|
||||||
vm->is_stopiteration = true;
|
vm->is_stopiteration = true;
|
||||||
}
|
}
|
||||||
int retval = vm->is_stopiteration ? 0 : -1;
|
int retval = vm->is_stopiteration ? 0 : -1;
|
||||||
|
@ -327,8 +327,8 @@ assert s.step == 3
|
|||||||
# test slice.__repr__
|
# test slice.__repr__
|
||||||
assert type(repr(slice(1,1,1))) is str
|
assert type(repr(slice(1,1,1))) is str
|
||||||
|
|
||||||
# /************ mappingproxy ************/
|
# /************ namedict ************/
|
||||||
# test mappingproxy.keys:
|
# test namedict.keys:
|
||||||
class A():
|
class A():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.a = 10
|
self.a = 10
|
||||||
@ -336,12 +336,12 @@ class A():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
my_mappingproxy = A().__dict__
|
my_namedict = A().__dict__
|
||||||
assert type(my_mappingproxy.keys()) is list
|
assert type(my_namedict.keys()) is list
|
||||||
|
|
||||||
|
|
||||||
# 未完全测试准确性-----------------------------------------------
|
# 未完全测试准确性-----------------------------------------------
|
||||||
# test mappingproxy.values:
|
# test namedict.values:
|
||||||
class A():
|
class A():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.a = 10
|
self.a = 10
|
||||||
@ -349,8 +349,8 @@ class A():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
my_mappingproxy = A().__dict__
|
my_namedict = A().__dict__
|
||||||
assert type(my_mappingproxy.values()) is list
|
assert type(my_namedict.values()) is list
|
||||||
|
|
||||||
|
|
||||||
class A():
|
class A():
|
||||||
@ -360,8 +360,8 @@ class A():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
my_mappingproxy = A().__dict__
|
my_namedict = A().__dict__
|
||||||
assert type(len(my_mappingproxy)) is int
|
assert type(len(my_namedict)) is int
|
||||||
|
|
||||||
|
|
||||||
class A():
|
class A():
|
||||||
@ -371,11 +371,11 @@ class A():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
my_mappingproxy = A().__dict__
|
my_namedict = A().__dict__
|
||||||
|
|
||||||
try:
|
try:
|
||||||
hash(my_mappingproxy)
|
hash(my_namedict)
|
||||||
print('未能拦截错误, 在测试 mappingproxy.__hash__')
|
print('未能拦截错误, 在测试 namedict.__hash__')
|
||||||
exit(1)
|
exit(1)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
@ -393,7 +393,7 @@ except TypeError:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# 未完全测试准确性-----------------------------------------------
|
# 未完全测试准确性-----------------------------------------------
|
||||||
# test mappingproxy.__repr__:
|
# test namedict.__repr__:
|
||||||
class A():
|
class A():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.a = 10
|
self.a = 10
|
||||||
@ -401,8 +401,8 @@ class A():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
my_mappingproxy = A().__dict__
|
my_namedict = A().__dict__
|
||||||
assert type(repr(my_mappingproxy)) is str
|
assert type(repr(my_namedict)) is str
|
||||||
|
|
||||||
|
|
||||||
# /************ dict ************/
|
# /************ dict ************/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user