From bc17e61463d7c809c05e9e36c8b79cdd05bc6c4f Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 20 Nov 2022 22:34:38 +0800 Subject: [PATCH] 0.3.0 --- src/compiler.h | 3 ++- src/obj.h | 11 ++--------- src/opcodes.h | 1 + src/pocketpy.h | 17 ----------------- src/pointer.h | 10 ++++++++++ src/vm.h | 31 +++++++++++++++++++++++++++++-- tests/pointer.py | 19 +++++++++++++++++++ 7 files changed, 63 insertions(+), 29 deletions(-) create mode 100644 tests/pointer.py diff --git a/src/compiler.h b/src/compiler.h index 55753ecf..2332fa88 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -60,7 +60,7 @@ public: rules[TK("%")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; rules[TK("+")] = { nullptr, METHOD(exprBinaryOp), PREC_TERM }; rules[TK("-")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_TERM }; - rules[TK("*")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; + rules[TK("*")] = { METHOD(exprUnaryOp), METHOD(exprBinaryOp), PREC_FACTOR }; rules[TK("/")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; rules[TK("//")] = { nullptr, METHOD(exprBinaryOp), PREC_FACTOR }; rules[TK("**")] = { nullptr, METHOD(exprBinaryOp), PREC_EXPONENT }; @@ -450,6 +450,7 @@ public: case TK("-"): emitCode(OP_UNARY_NEGATIVE); break; case TK("not"): emitCode(OP_UNARY_NOT); break; case TK("&"): emitCode(OP_UNARY_REF); break; + case TK("*"): emitCode(OP_UNARY_DEREF); break; default: UNREACHABLE(); } } diff --git a/src/obj.h b/src/obj.h index 67dcd26a..e5b24de3 100644 --- a/src/obj.h +++ b/src/obj.h @@ -10,11 +10,10 @@ const _Int _Int_MAX_NEG = -9223372036854775807LL; const _Float _FLOAT_INF_POS = INFINITY; const _Float _FLOAT_INF_NEG = -INFINITY; -#define PK_VERSION "0.2.9" +#define PK_VERSION "0.3.0" class CodeObject; class BasePointer; -class Pointer; class VM; class Frame; class PkExportedResource {}; @@ -23,12 +22,6 @@ typedef std::shared_ptr _Pointer; typedef PyVar (*_CppFunc)(VM*, const pkpy::ArgList&); typedef std::shared_ptr _Code; -struct Pointer { - Frame* frame; // the frame that created this pointer - _Pointer ptr; // the internal pointer - Pointer(Frame* frame, _Pointer ptr) : frame(frame), ptr(ptr) {} -}; - struct Function { _Str name; _Code code; @@ -80,7 +73,7 @@ public: }; typedef std::shared_ptr _Func; -typedef std::variant<_Int,_Float,bool,_Str,PyVarList,_CppFunc,_Func,std::shared_ptr<_Iterator>,_BoundedMethod,_Range,_Slice,_Pointer,Pointer> _Value; +typedef std::variant<_Int,_Float,bool,_Str,PyVarList,_CppFunc,_Func,std::shared_ptr<_Iterator>,_BoundedMethod,_Range,_Slice,_Pointer> _Value; const int _SIZEOF_VALUE = sizeof(_Value); diff --git a/src/opcodes.h b/src/opcodes.h index 281e6f47..815e1587 100644 --- a/src/opcodes.h +++ b/src/opcodes.h @@ -60,5 +60,6 @@ OPCODE(BUILD_STRING) // arg is the expr count, build a string from the to OPCODE(GOTO) OPCODE(UNARY_REF) // for & +OPCODE(UNARY_DEREF) // for * #endif \ No newline at end of file diff --git a/src/pocketpy.h b/src/pocketpy.h index 5b86c329..17f0042d 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -56,23 +56,6 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->PyStr(tvm->readStdin()); }); - _vm->bindMethod("pointer", "set", [](VM* vm, const pkpy::ArgList& args) { - vm->__checkArgSize(args, 2, true); - Pointer& p = std::get(args[0]->_native); - // this check is unsafe, but it's the best we can do - if(!vm->__isFrameValid(p.frame)) vm->nullPointerError(); - p.ptr->set(vm, p.frame, args[1]); - return vm->None; - }); - - _vm->bindMethod("pointer", "get", [](VM* vm, const pkpy::ArgList& args) { - vm->__checkArgSize(args, 1, true); - Pointer& p = std::get(args[0]->_native); - // this check is unsafe, but it's the best we can do - if(!vm->__isFrameValid(p.frame)) vm->nullPointerError(); - return p.ptr->get(vm, p.frame); - }); - _vm->bindBuiltinFunc("eval", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1); const _Str& expr = vm->PyStr_AS_C(args[0]); diff --git a/src/pointer.h b/src/pointer.h index d2004d87..74b3d82a 100644 --- a/src/pointer.h +++ b/src/pointer.h @@ -55,6 +55,16 @@ struct CompoundPointer : BasePointer { CompoundPointer(std::vector<_Pointer> pointers) : pointers(pointers) {} CompoundPointer(std::vector<_Pointer>&& pointers) : pointers(pointers) {} + PyVar get(VM* vm, Frame* frame) const; + void set(VM* vm, Frame* frame, PyVar val) const; + void del(VM* vm, Frame* frame) const; +}; + +struct UserPointer : BasePointer { + const _Pointer p; + Frame* frame; + UserPointer(_Pointer p, Frame* frame) : p(p), frame(frame) {} + PyVar get(VM* vm, Frame* frame) const; void set(VM* vm, Frame* frame, PyVar val) const; void del(VM* vm, Frame* frame) const; diff --git a/src/vm.h b/src/vm.h index 829cc60b..ad77086d 100644 --- a/src/vm.h +++ b/src/vm.h @@ -209,8 +209,17 @@ private: } break; case OP_UNARY_REF: { - _Pointer p = PyPointer_AS_C(frame->__pop()); - frame->push(newObject(_tp_user_pointer, Pointer(frame, p))); + // _pointer to pointer + const _Pointer& p = PyPointer_AS_C(frame->__pop()); + _Pointer up = std::make_shared(p, frame); + frame->push(newObject(_tp_user_pointer, std::move(up))); + } break; + case OP_UNARY_DEREF: + { + // pointer to _pointer + PyVar obj = frame->popValue(this); + __checkType(obj, _tp_user_pointer); + frame->push(PyPointer(std::get<_Pointer>(obj->_native))); } break; case OP_POP_JUMP_IF_FALSE: if(!PyBool_AS_C(asBool(frame->popValue(this)))) frame->jump(byte.arg); @@ -941,6 +950,24 @@ void CompoundPointer::del(VM* vm, Frame* frame) const{ for (auto& ptr : pointers) ptr->del(vm, frame); } +PyVar UserPointer::get(VM* vm, Frame* frame) const{ + frame = this->frame; + // this check is unsafe, but it's the best we can do + if(!vm->__isFrameValid(frame)) vm->nullPointerError(); + return p->get(vm, frame); +} + +void UserPointer::set(VM* vm, Frame* frame, PyVar val) const{ + frame = this->frame; + // this check is unsafe, but it's the best we can do + if(!vm->__isFrameValid(frame)) vm->nullPointerError(); + p->set(vm, frame, val); +} + +void UserPointer::del(VM* vm, Frame* frame) const{ + vm->typeError("delete is unsupported"); +} + /***** Frame's Impl *****/ inline PyVar Frame::__deref_pointer(VM* vm, PyVar v){ if(v->isType(vm->_tp_pointer)) return vm->PyPointer_AS_C(v)->get(vm, this); diff --git a/tests/pointer.py b/tests/pointer.py new file mode 100644 index 00000000..db45627f --- /dev/null +++ b/tests/pointer.py @@ -0,0 +1,19 @@ +a = 1 +assert a == 1 +assert *&a == 1 +b = &a +*b = 2 +assert a == 2 + +def swap(a,b): + t = *a + *a = *b + *b = t + +def f(): + a,b = 5,6 + swap(&a,&b) + assert a == 6 + assert b == 5 + +f() \ No newline at end of file