blueloveTH 3 years ago
parent
commit
c8f8739dc7
3 changed files with 75 additions and 17 deletions
  1. 1 1
      src/main.cpp
  2. 73 15
      src/pocketpy.h
  3. 1 1
      src/vm.h

+ 1 - 1
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;

+ 73 - 15
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>", 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;
+    }
 }

+ 1 - 1
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;
     }