diff --git a/src/main.cpp b/src/main.cpp index f8d55f83..c65c6f36 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,24 +70,26 @@ int main(int argc, char** argv){ if(code == nullptr) return 1; //std::cout << code->toString() << std::endl; - Timer("Running time").run([=]{ - vm->exec(code); - }); + // Timer("Running time").run([=]{ + // vm->exec(code); + // }); // for(auto& kv : _strIntern) // std::cout << kv.first << ", "; - // Timer("Running time").run([=]{ - // vm->startExec(code); - // while(pkpy_tvm_get_state(vm) != THREAD_FINISHED){ - // if(pkpy_tvm_get_state(vm) == THREAD_SUSPENDED){ - // std::string line; - // std::getline(std::cin, line); - // pkpy_tvm_write_stdin(vm, line.c_str()); - // pkpy_tvm_resume(vm); - // } - // } - // }); + Timer("Running time").run([=]{ + vm->startExec(code); + while(pkpy_tvm_get_state(vm) != THREAD_FINISHED){ + if(pkpy_tvm_get_state(vm) == THREAD_SUSPENDED){ + PyObjectDump* obj = pkpy_tvm_read_json(vm); + if(INPUT_JSONRPC_STR != obj->json) UNREACHABLE(); + pkpy_delete(obj); + std::string line; + std::getline(std::cin, line); + pkpy_tvm_resume(vm, line.c_str()); + } + } + }); return 0; } diff --git a/src/obj.h b/src/obj.h index b873aeff..de00017c 100644 --- a/src/obj.h +++ b/src/obj.h @@ -10,7 +10,7 @@ const _Int _Int_MAX_NEG = -9223372036854775807LL; const _Float _FLOAT_INF_POS = INFINITY; const _Float _FLOAT_INF_NEG = -INFINITY; -#define PK_VERSION "0.3.1" +#define PK_VERSION "0.3.2" class CodeObject; class BasePointer; diff --git a/src/pocketpy.h b/src/pocketpy.h index 36d70a7b..256b90b3 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -48,14 +48,6 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->None; }); - _vm->bindBuiltinFunc("input", [](VM* vm, const pkpy::ArgList& args) { - vm->__checkArgSize(args, 0); - ThreadedVM* tvm = dynamic_cast(vm); - if(tvm == nullptr) vm->typeError("input() can only be called in threaded mode"); - tvm->suspend(); - return vm->PyStr(tvm->readStdin()); - }); - _vm->bindBuiltinFunc("super", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 0); auto it = vm->topFrame()->f_locals.find("self"_c); @@ -776,12 +768,14 @@ extern "C" { } __EXPORT - void pkpy_tvm_write_stdin(ThreadedVM* vm, const char* line){ - vm->_stdin = _Str(line); + PyObjectDump* pkpy_tvm_read_json(ThreadedVM* vm){ + std::optional<_Str> s = vm->readSharedStr(); + if(!s.has_value()) return nullptr; + return new PyObjectDump("str", s.value()); } __EXPORT - void pkpy_tvm_resume(ThreadedVM* vm){ - vm->resume(); + void pkpy_tvm_resume(ThreadedVM* vm, const char* value){ + vm->resume(value); } } \ No newline at end of file diff --git a/src/vm.h b/src/vm.h index df0bfd5e..86b95ed8 100644 --- a/src/vm.h +++ b/src/vm.h @@ -44,7 +44,7 @@ typedef void(*PrintFn)(const VM*, const char*); class VM: public PkExportedResource{ -private: +protected: std::deque< std::unique_ptr > callstack; PyVarDict _modules; // 3rd modules PyVar __py2py_call_signal; @@ -1042,48 +1042,76 @@ enum ThreadState { THREAD_FINISHED }; +const _Str INPUT_JSONRPC_STR = "{\"method\":\"input\", \"params\":[]}"; + class ThreadedVM : public VM { std::thread* _thread = nullptr; - std::atomic state = THREAD_READY; -public: - ThreadedVM(bool use_stdio) : VM(use_stdio) {} + std::atomic _state = THREAD_READY; + std::optional<_Str> _sharedStr = {}; - _Str _stdin; + PyVar jsonRpc(const _Str& _json){ + _sharedStr = _json; + suspend(); + std::optional<_Str> ret = readSharedStr(); + if(ret.has_value()) return PyStr(ret.value()); + return None; + } +public: + ThreadedVM(bool use_stdio) : VM(use_stdio) { + bindBuiltinFunc("jsonrpc", [](VM* vm, const pkpy::ArgList& args){ + ThreadedVM *tvm = dynamic_cast(vm); + if(tvm == nullptr) UNREACHABLE(); + tvm->__checkArgSize(args, 1); + return tvm->jsonRpc(tvm->PyStr_AS_C(args[0])); + }); + + bindBuiltinFunc("input", [](VM* vm, const pkpy::ArgList& args) { + ThreadedVM *tvm = dynamic_cast(vm); + if(tvm == nullptr) UNREACHABLE(); + tvm->__checkArgSize(args, 0); + return tvm->jsonRpc(INPUT_JSONRPC_STR); + }); + } void suspend(){ if(_thread == nullptr) UNREACHABLE(); - if(state != THREAD_RUNNING) UNREACHABLE(); - state = THREAD_SUSPENDED; + if(_state != THREAD_RUNNING) UNREACHABLE(); + _state = THREAD_SUSPENDED; // 50 fps is enough - while(state == THREAD_SUSPENDED) std::this_thread::sleep_for(std::chrono::milliseconds(20)); + while(_state == THREAD_SUSPENDED) std::this_thread::sleep_for(std::chrono::milliseconds(20)); } - _Str readStdin(){ + std::optional<_Str> readSharedStr(){ if(_thread == nullptr) UNREACHABLE(); - _Str copy = _stdin; - _stdin = ""; + std::optional<_Str> copy = _sharedStr.value(); + _sharedStr = {}; return copy; } /***** For outer use *****/ ThreadState getState(){ - return state.load(); + return _state; } - void resume(){ + void resume(const char* value=nullptr){ if(_thread == nullptr) UNREACHABLE(); - if(state != THREAD_SUSPENDED) UNREACHABLE(); - state = THREAD_RUNNING; + if(_state != THREAD_SUSPENDED) UNREACHABLE(); + _state = THREAD_RUNNING; + if(value == nullptr){ + _sharedStr = {}; + }else{ + _sharedStr = value; + } } void startExec(const _Code& code){ if(_thread != nullptr) UNREACHABLE(); - if(state != THREAD_READY) UNREACHABLE(); + if(_state != THREAD_READY) UNREACHABLE(); _thread = new std::thread([this, code](){ - this->state = THREAD_RUNNING; + this->_state = THREAD_RUNNING; this->exec(code); - this->state = THREAD_FINISHED; + this->_state = THREAD_FINISHED; }); } diff --git a/tests/hidden/3.py b/tests/hidden/tvm.py similarity index 100% rename from tests/hidden/3.py rename to tests/hidden/tvm.py