From c8f8739dc7d1ea4548ec1f908f2c3e9c3535342e Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sat, 3 Dec 2022 05:17:44 +0800 Subject: [PATCH] up --- src/main.cpp | 2 +- src/pocketpy.h | 88 +++++++++++++++++++++++++++++++++++++++++--------- src/vm.h | 2 +- 3 files changed, 75 insertions(+), 17 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8dfa4fdf..142b2ff9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -42,7 +42,7 @@ extern "C" { void _tvm_dispatch(ThreadedVM* vm){ while(pkpy_tvm_get_state(vm) != THREAD_FINISHED){ if(pkpy_tvm_get_state(vm) == THREAD_SUSPENDED){ - PyObjectDump* obj = pkpy_tvm_read_json(vm); + PyObjectDump* obj = pkpy_tvm_read_jsonrpc_request(vm); bool is_input_call = INPUT_JSONRPC_STR == obj->json; if(is_input_call){ std::string line; diff --git a/src/pocketpy.h b/src/pocketpy.h index ce8627bd..b8626cb5 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -687,6 +687,12 @@ extern "C" { }; __EXPORT + /// Delete a pointer allocated by `pkpy_xxx_xxx`. + /// It can be `VM*`, `REPL*` or `PyXXXDump*`, etc. + /// + /// !!! + /// If the pointer not allocated by `pkpy_xxx_xxx`, nothing will happen. + /// !!! void pkpy_delete(void* p){ for(int i = 0; i < _pkLookupTable.size(); i++){ if(_pkLookupTable[i]->get() == p){ @@ -697,22 +703,21 @@ extern "C" { } __EXPORT - bool pkpy_exec(VM* vm, const char* source){ + /// Run a given source on a virtual machine. + /// + /// Return `true` if there is no error. + bool pkpy_vm_exec(VM* vm, const char* source){ _Code code = compile(vm, source, "main.py"); if(code == nullptr) return false; return vm->exec(code) != nullptr; } __EXPORT - bool pkpy_exec_async(VM* vm, const char* source){ - _Code code = compile(vm, source, "main.py"); - if(code == nullptr) return false; - vm->execAsync(code); - return true; - } - - __EXPORT - PyObjectDump* pkpy_get_global(VM* vm, const char* name){ + /// Get a global variable of a virtual machine. + /// Return a `PyObjectDump*` representing the variable. + /// You need to call `pkpy_delete` to free the returned `PyObjectDump*` later. + /// If the variable is not found, return `nullptr`. + PyObjectDump* pkpy_vm_get_global(VM* vm, const char* name){ auto it = vm->_main->attribs.find(name); if(it == vm->_main->attribs.end()) return nullptr; return pkpy_allocate(PyObjectDump, @@ -722,7 +727,12 @@ extern "C" { } __EXPORT - PyObjectDump* pkpy_eval(VM* vm, const char* source){ + /// Evaluate an expression. + /// + /// Return a `PyObjectDump*` representing the result. + /// You need to call `pkpy_delete` to free the returned `PyObjectDump*` later. + /// If there is any error, return `nullptr`. + PyObjectDump* pkpy_vm_eval(VM* vm, const char* source){ _Code code = compile(vm, source, "", EVAL_MODE); if(code == nullptr) return nullptr; PyVarOrNull ret = vm->exec(code); @@ -734,17 +744,26 @@ extern "C" { } __EXPORT + /// Create a REPL, using the given virtual machine as the backend. REPL* pkpy_new_repl(VM* vm){ return pkpy_allocate(REPL, vm); } __EXPORT + /// Input a source line to an interactive console. + /// + /// Return `0` if need more lines, + /// `1` if execution happened, + /// `2` if execution skipped (compile error or empty input). int pkpy_repl_input(REPL* r, const char* line){ return r->input(line); } __EXPORT - bool pkpy_add_module(VM* vm, const char* name, const char* source){ + /// Add a source module into a virtual machine. + /// + /// Return `true` if there is no complie error. + bool pkpy_vm_add_module(VM* vm, const char* name, const char* source){ // compile the module but don't execute it _Code code = compile(vm, source, name + _Str(".py")); if(code == nullptr) return false; @@ -760,10 +779,11 @@ extern "C" { __addModuleSys(vm); __addModuleTime(vm); - pkpy_add_module(vm, "random", __RANDOM_CODE); + pkpy_vm_add_module(vm, "random", __RANDOM_CODE); } __EXPORT + /// Create a virtual machine. VM* pkpy_new_vm(bool use_stdio){ VM* vm = pkpy_allocate(VM, use_stdio); __vm_init(vm); @@ -771,6 +791,7 @@ extern "C" { } __EXPORT + /// Create a virtual machine that supports asynchronous execution. ThreadedVM* pkpy_new_tvm(bool use_stdio){ ThreadedVM* vm = pkpy_allocate(ThreadedVM, use_stdio); __vm_init(vm); @@ -778,6 +799,12 @@ extern "C" { } __EXPORT + /// Read the standard output and standard error as string of a virtual machine. + /// The `vm->use_stdio` should be `false`. + /// After this operation, both stream will be cleared. + /// + /// Return a `PyOutputDump*` representing the result. + /// You need to call `pkpy_delete` to free the returned `PyOutputDump*` later. PyOutputDump* pkpy_vm_read_output(VM* vm){ if(vm->use_stdio) return nullptr; _StrStream* s_out = dynamic_cast<_StrStream*>(vm->_stdout); @@ -790,29 +817,60 @@ extern "C" { } __EXPORT + /// Get the current state of a threaded virtual machine. + /// + /// Return `0` for `THREAD_READY`, + /// `1` for `THREAD_RUNNING`, + /// `2` for `THREAD_SUSPENDED`, + /// `3` for `THREAD_FINISHED`. int pkpy_tvm_get_state(ThreadedVM* vm){ return vm->getState(); } __EXPORT + /// Set the state of a threaded virtual machine to `THREAD_READY`. + /// The current state should be `THREAD_FINISHED`. void pkpy_tvm_reset_state(ThreadedVM* vm){ vm->resetState(); } __EXPORT - PyObjectDump* pkpy_tvm_read_json(ThreadedVM* vm){ + /// Read the current JSONRPC request from shared string buffer. + /// + /// Return a `PyObjectDump*` representing the string. + /// You need to call `pkpy_delete` to free the returned `PyObjectDump*` later. + /// If the buffer is empty, return `nullptr`. + PyObjectDump* pkpy_tvm_read_jsonrpc_request(ThreadedVM* vm){ std::optional<_Str> s = vm->readSharedStr(); if(!s.has_value()) return nullptr; return pkpy_allocate(PyObjectDump, "str"_c, s.value()); } __EXPORT + /// Resume a suspended threaded virtual machine + /// and put the given string into the shared string buffer. + /// It is usually used for JSONRPC. void pkpy_tvm_resume(ThreadedVM* vm, const char* value){ vm->resume(value); } __EXPORT - void pkpy_vm_keyboard_interrupt(VM* vm){ + /// Emit a KeyboardInterrupt signal in order to stop a running threaded virtual machine. + void pkpy_tvm_keyboard_interrupt(VM* vm){ + // although this is a method of VM, it's only used in ThreadedVM vm->keyboardInterrupt(); } + + __EXPORT + /// Run a given source on a threaded virtual machine. + /// The excution will be started in a new thread. + /// + /// Return `true` if there is no compile error. + bool pkpy_tvm_exec_async(VM* vm, const char* source){ + // although this is a method of VM, it's only used in ThreadedVM + _Code code = compile(vm, source, "main.py"); + if(code == nullptr) return false; + vm->execAsync(code); + return true; + } } \ No newline at end of file diff --git a/src/vm.h b/src/vm.h index 98ee9120..75d0e0a6 100644 --- a/src/vm.h +++ b/src/vm.h @@ -1179,7 +1179,7 @@ public: } void resetState(){ - if(this->_state != THREAD_FINISHED) UNREACHABLE(); + if(this->_state != THREAD_FINISHED) return; this->_state = THREAD_READY; }