From eb58389945d9626b5d13f45d5c3643c269548f8b Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Fri, 30 Dec 2022 19:15:51 +0800 Subject: [PATCH] re --- .github/workflows/main.yml | 4 --- build_wasm.sh | 2 +- src/__stl__.h | 9 ++++-- src/compiler.h | 16 +---------- src/main.cpp | 16 ++--------- src/pocketpy.h | 56 ++++++++++++++++---------------------- src/repl.h | 4 +-- src/vm.h | 55 +++++++++++++++++++++++++------------ 8 files changed, 75 insertions(+), 87 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 329f0bcf..67e5916a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,10 +26,6 @@ jobs: - name: Compiling run: | mkdir -p output/web/lib - mkdir -p output/web/lib_pthread - bash build_wasm.sh - mv web/lib/* output/web/lib_pthread - export PTHREAD_FLAG=" " bash build_wasm.sh cp web/lib/* output/web/lib - uses: crazy-max/ghaction-github-pages@v3 diff --git a/build_wasm.sh b/build_wasm.sh index 4975bdd2..9d5e1026 100644 --- a/build_wasm.sh +++ b/build_wasm.sh @@ -1,3 +1,3 @@ rm -rf web/lib/ mkdir -p web/lib/ -em++ src/main.cpp ${PTHREAD_FLAG:--pthread -sPTHREAD_POOL_SIZE=2} -fno-rtti -fexceptions -O3 -sEXPORTED_FUNCTIONS=_pkpy_delete,_pkpy_new_repl,_pkpy_repl_input,_pkpy_new_tvm,_pkpy_tvm_exec_async,_pkpy_tvm_get_state,_pkpy_tvm_read_jsonrpc_request,_pkpy_tvm_reset_state,_pkpy_tvm_terminate,_pkpy_tvm_write_jsonrpc_response,_pkpy_new_vm,_pkpy_vm_add_module,_pkpy_vm_eval,_pkpy_vm_exec,_pkpy_vm_get_global,_pkpy_vm_read_output -sEXPORTED_RUNTIME_METHODS=ccall -o web/lib/pocketpy.js \ No newline at end of file +em++ src/main.cpp -fno-rtti -fexceptions -O3 -sEXPORTED_FUNCTIONS=_pkpy_delete,_pkpy_new_repl,_pkpy_repl_input,_pkpy_new_tvm,_pkpy_tvm_exec_async,_pkpy_tvm_get_state,_pkpy_tvm_read_jsonrpc_request,_pkpy_tvm_reset_state,_pkpy_tvm_terminate,_pkpy_tvm_write_jsonrpc_response,_pkpy_new_vm,_pkpy_vm_add_module,_pkpy_vm_eval,_pkpy_vm_exec,_pkpy_vm_get_global,_pkpy_vm_read_output -sASYNCIFY -sEXPORTED_RUNTIME_METHODS=ccall -sASYNCIFY_IMPORTS=pkpy_tvm_exec_async -o web/lib/pocketpy.js \ No newline at end of file diff --git a/src/__stl__.h b/src/__stl__.h index d9728d1c..a513f1f1 100644 --- a/src/__stl__.h +++ b/src/__stl__.h @@ -20,7 +20,6 @@ #include #include -#include #include #include @@ -30,7 +29,13 @@ #define UNREACHABLE() throw std::runtime_error( __FILE__ + std::string(":") + std::to_string(__LINE__) + " UNREACHABLE()!"); #endif -#define PK_VERSION "0.5.2" +#ifdef __EMSCRIPTEN__ +#include +#else +#include +#endif + +#define PK_VERSION "0.6.0" //#define PKPY_NO_TYPE_CHECK //#define PKPY_NO_INDEX_CHECK \ No newline at end of file diff --git a/src/compiler.h b/src/compiler.h index ba957065..42286cae 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -1062,18 +1062,4 @@ __LISTCOMP: void syntaxError(_Str msg){ throw CompileError("SyntaxError", msg, getLineSnapshot()); } void indentationError(_Str msg){ throw CompileError("IndentationError", msg, getLineSnapshot()); } void unexpectedError(_Str msg){ throw CompileError("UnexpectedError", msg, getLineSnapshot()); } -}; - -_Code compile(VM* vm, const char* source, _Str filename, CompileMode mode=EXEC_MODE, bool noThrow=true) { - Compiler compiler(vm, source, filename, mode); - if(!noThrow) return compiler.__fillCode(); - try{ - return compiler.__fillCode(); - }catch(_Error& e){ - (*vm->_stderr) << e.what() << '\n'; - }catch(std::exception& e){ - auto ce = CompileError("UnexpectedError", e.what(), compiler.getLineSnapshot()); - (*vm->_stderr) << ce.what() << '\n'; - } - return nullptr; -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index e3f9c0fc..00ede797 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,7 +4,7 @@ #include "pocketpy.h" //#define PK_DEBUG_TIME -//#define PK_DEBUG_THREADED +#define PK_DEBUG_THREADED struct Timer{ const char* title; @@ -83,25 +83,15 @@ int main(int argc, char** argv){ std::string src((std::istreambuf_iterator(file)), std::istreambuf_iterator()); ThreadedVM* vm = pkpy_new_tvm(true); - _Code code = nullptr; - Timer("Compile time").run([&]{ - code = compile(vm, src.c_str(), filename); - }); - if(code == nullptr) return 1; - //std::cout << code->toString() << std::endl; - - // for(auto& kv : _strIntern) - // std::cout << kv.first << ", "; - #ifdef PK_DEBUG_THREADED Timer("Running time").run([=]{ - vm->execAsync(code); + vm->execAsync(src.c_str(), filename, EXEC_MODE); _tvm_dispatch(vm); }); #else Timer("Running time").run([=]{ - vm->exec(code); + vm->exec(src.c_str(), filename, EXEC_MODE); }); #endif diff --git a/src/pocketpy.h b/src/pocketpy.h index e0d5594c..55589aa7 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -4,6 +4,17 @@ #include "compiler.h" #include "repl.h" +_Code VM::compile(const char* source, _Str filename, CompileMode mode) { + Compiler compiler(this, source, filename, mode); + try{ + return compiler.__fillCode(); + }catch(_Error& e){ + throw e; + }catch(std::exception& e){ + throw CompileError("UnexpectedError", e.what(), compiler.getLineSnapshot()); + } +} + #define BIND_NUM_ARITH_OPT(name, op) \ _vm->bindMethodMulti({"int","float"}, #name, [](VM* vm, const pkpy::ArgList& args){ \ if(!vm->isIntOrFloat(args[0], args[1])) \ @@ -55,7 +66,7 @@ void __initializeBuiltinFunctions(VM* _vm) { _vm->bindBuiltinFunc("eval", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1); const _Str& expr = vm->PyStr_AS_C(args[0]); - _Code code = compile(vm, expr.c_str(), "", EVAL_MODE, false); + _Code code = vm->compile(expr.c_str(), "", EVAL_MODE); return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->copy_f_locals()); }); @@ -589,8 +600,7 @@ void __initializeBuiltinFunctions(VM* _vm) { #define __EXPORT __declspec(dllexport) #elif __APPLE__ #define __EXPORT __attribute__((visibility("default"))) __attribute__((used)) -#elif defined(__EMSCRIPTEN__) || defined(__wasm__) || defined(__wasm32__) || defined(__wasm64__) -#include +#elif __EMSCRIPTEN__ #define __EXPORT EMSCRIPTEN_KEEPALIVE #define __NO_MAIN #else @@ -642,7 +652,7 @@ void __addModuleJson(VM* vm){ vm->bindFunc(mod, "loads", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1); const _Str& expr = vm->PyStr_AS_C(args[0]); - _Code code = compile(vm, expr.c_str(), "", JSON_MODE, false); + _Code code = vm->compile(expr.c_str(), "", JSON_MODE); return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->copy_f_locals()); }); @@ -846,13 +856,8 @@ extern "C" { __EXPORT /// Run a given source on a virtual machine. - /// - /// Return `true` if there is no compile error. - bool pkpy_vm_exec(VM* vm, const char* source){ - _Code code = compile(vm, source, "main.py"); - if(code == nullptr) return false; - vm->exec(code); - return true; + void pkpy_vm_exec(VM* vm, const char* source){ + vm->exec(source, "main.py", EXEC_MODE); } __EXPORT @@ -877,9 +882,7 @@ extern "C" { /// Return a json representing the result. /// If there is any error, return `nullptr`. char* 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); + PyVarOrNull ret = vm->exec(source, "", EVAL_MODE); if(ret == nullptr) return nullptr; try{ _Str _json = vm->PyStr_AS_C(vm->asJson(ret)); @@ -907,14 +910,8 @@ extern "C" { __EXPORT /// 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; - vm->addLazyModule(name, code); - return true; + void pkpy_vm_add_module(VM* vm, const char* name, const char* source){ + vm->addLazyModule(name, source); } void __vm_init(VM* vm){ @@ -925,9 +922,10 @@ extern "C" { __addModuleMath(vm); __addModuleRe(vm); - _Code code = compile(vm, __BUILTINS_CODE, ""); - if(code == nullptr) exit(1); + // add builtins | no exception handler | must succeed + _Code code = vm->compile(__BUILTINS_CODE, "", EXEC_MODE); vm->_exec(code, vm->builtins, {}); + pkpy_vm_add_module(vm, "random", __RANDOM_CODE); pkpy_vm_add_module(vm, "os", __OS_CODE); } @@ -1009,13 +1007,7 @@ extern "C" { __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; + void pkpy_tvm_exec_async(VM* vm, const char* source){ + vm->execAsync(source, "main.py", EXEC_MODE); } } \ No newline at end of file diff --git a/src/repl.h b/src/repl.h index 8e15f5e5..1f33ab5d 100644 --- a/src/repl.h +++ b/src/repl.h @@ -54,9 +54,7 @@ __NOT_ENOUGH_LINES: } try{ - _Code code = compile(vm, line.c_str(), "", SINGLE_MODE); - if(code == nullptr) return EXEC_SKIPPED; - vm->execAsync(code); + vm->execAsync(line.c_str(), "", SINGLE_MODE); return EXEC_DONE; }catch(NeedMoreLines& ne){ buffer += line; diff --git a/src/vm.h b/src/vm.h index 82648d59..53d82d25 100644 --- a/src/vm.h +++ b/src/vm.h @@ -26,7 +26,7 @@ class VM { protected: std::deque< pkpy::unique_ptr > callstack; PyVarDict _modules; // loaded modules - std::map<_Str, _Code> _lazyModules; // lazy loaded modules + std::map<_Str, _Str> _lazyModules; // lazy loaded modules PyVar __py2py_call_signal; void _checkStopFlag(){ @@ -313,7 +313,8 @@ protected: if(it2 == _lazyModules.end()){ _error("ImportError", "module '" + name + "' not found"); }else{ - _Code code = it2->second; + const _Str& source = it2->second; + _Code code = compile(source.c_str(), name, EXEC_MODE); PyVar _m = newModule(name); _exec(code, _m, {}); frame->push(_m); @@ -377,9 +378,14 @@ public: void sleepForSecs(_Float sec){ _Int ms = (_Int)(sec * 1000); - for(_Int i=0; iid` to 0 - virtual PyVarOrNull exec(const _Code& code, PyVar _module=nullptr){ + virtual PyVarOrNull exec(const char* source, _Str filename, CompileMode mode, PyVar _module=nullptr){ if(_module == nullptr) _module = _main; try { + _Code code = compile(source, filename, mode); return _exec(code, _module, {}); }catch (const _Error& e){ *_stderr << e.what() << '\n'; @@ -559,8 +566,8 @@ public: return nullptr; } - virtual void execAsync(const _Code& code) { - exec(code); + virtual void execAsync(const char* source, _Str filename, CompileMode mode) { + exec(source, filename, mode); } Frame* __pushNewFrame(const _Code& code, PyVar _module, PyVarDict&& locals){ @@ -629,8 +636,8 @@ public: return obj; } - void addLazyModule(_Str name, _Code code){ - _lazyModules[name] = code; + void addLazyModule(_Str name, const char* source){ + _lazyModules[name] = source; } PyVarOrNull getAttr(const PyVar& obj, const _Str& name, bool throw_err=true) { @@ -949,6 +956,8 @@ public: delete _stderr; } } + + _Code compile(const char* source, _Str filename, CompileMode mode); }; /***** Pointers' Impl *****/ @@ -1077,10 +1086,11 @@ enum ThreadState { }; class ThreadedVM : public VM { - std::thread* _thread = nullptr; std::atomic _state = THREAD_READY; _Str _sharedStr = ""; - + +#ifndef __EMSCRIPTEN__ + std::thread* _thread = nullptr; void __deleteThread(){ if(_thread != nullptr){ terminate(); @@ -1089,6 +1099,10 @@ class ThreadedVM : public VM { _thread = nullptr; } } +#else + void __deleteThread(){} +#endif + public: ThreadedVM(bool use_stdio) : VM(use_stdio) { bindBuiltinFunc("__string_channel_call", [](VM* vm, const pkpy::ArgList& args){ @@ -1133,21 +1147,28 @@ public: _state = THREAD_RUNNING; } - void execAsync(const _Code& code) override { + void execAsync(const char* source, _Str filename, CompileMode mode) override { if(_state != THREAD_READY) UNREACHABLE(); + +#ifdef __EMSCRIPTEN__ + this->_state = THREAD_RUNNING; + VM::exec(source, filename, mode); + this->_state = THREAD_FINISHED; +#else __deleteThread(); - _thread = new std::thread([this, code](){ + _thread = new std::thread([=](){ this->_state = THREAD_RUNNING; - VM::exec(code); + VM::exec(source, filename, mode); this->_state = THREAD_FINISHED; }); +#endif } - PyVarOrNull exec(const _Code& code, PyVar _module = nullptr) override { - if(_state == THREAD_READY) return VM::exec(code, _module); + PyVarOrNull exec(const char* source, _Str filename, CompileMode mode, PyVar _module=nullptr) override { + if(_state == THREAD_READY) return VM::exec(source, filename, mode, _module); auto callstackBackup = std::move(callstack); callstack.clear(); - PyVarOrNull ret = VM::exec(code, _module); + PyVarOrNull ret = VM::exec(source, filename, mode, _module); callstack = std::move(callstackBackup); return ret; }