This commit is contained in:
blueloveTH 2022-12-03 05:17:44 +08:00
parent 93d16a66e0
commit c8f8739dc7
3 changed files with 75 additions and 17 deletions

View File

@ -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;

View File

@ -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>", 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;
}
}

View File

@ -1179,7 +1179,7 @@ public:
}
void resetState(){
if(this->_state != THREAD_FINISHED) UNREACHABLE();
if(this->_state != THREAD_FINISHED) return;
this->_state = THREAD_READY;
}