blueloveTH пре 3 година
родитељ
комит
ad2a15a76c
7 измењених фајлова са 82 додато и 59 уклоњено
  1. 2 1
      src/__stl__.h
  2. 2 3
      src/compiler.h
  3. 6 24
      src/main.cpp
  4. 1 1
      src/obj.h
  5. 39 12
      src/pocketpy.h
  6. 4 4
      src/repl.h
  7. 28 14
      src/vm.h

+ 2 - 1
src/__stl__.h

@@ -18,4 +18,5 @@
 #include <iomanip>
 
 #include <thread>
-#include <atomic>
+#include <atomic>
+#include <iostream>

+ 2 - 3
src/compiler.h

@@ -941,12 +941,11 @@ _Code compile(VM* vm, const char* source, _Str filename, CompileMode mode=EXEC_M
         return compiler.__fillCode();
     }catch(std::exception& e){
         if(const _Error* _ = dynamic_cast<const _Error*>(&e)){
-            vm->_stderr(vm, e.what());
+            (*vm->_stderr) << e.what() << '\n';
         }else{
             auto ce = CompileError("UnexpectedError", e.what(), compiler.getLineSnapshot());
-            vm->_stderr(vm, ce.what());
+            (*vm->_stderr) << ce.what() << '\n';
         }
-        vm->_stderr(vm, "\n");
         return nullptr;
     }
 }

+ 6 - 24
src/main.cpp

@@ -1,4 +1,3 @@
-#include <iostream>
 #include <fstream>
 
 #include "pocketpy.h"
@@ -19,25 +18,6 @@ struct Timer{
     }
 };
 
-ThreadedVM* new_tvm_with_callbacks(){
-    ThreadedVM* vm = pkpy_new_tvm([](const VM* vm, const char* str) { 
-        std::cout << str; std::cout.flush();
-    }, [](const VM* vm, const char* str) { 
-        std::cerr << str; std::cerr.flush();
-    });
-    return vm;
-}
-
-VM* new_vm_with_callbacks(){
-    VM* vm = pkpy_new_vm([](const VM* vm, const char* str) { 
-        std::cout << str; std::cout.flush();
-    }, [](const VM* vm, const char* str) { 
-        std::cerr << str; std::cerr.flush();
-    });
-    return vm;
-}
-
-
 #if defined(__EMSCRIPTEN__) || defined(__wasm__) || defined(__wasm32__) || defined(__wasm64__)
 
 // these code is for demo use, feel free to modify it
@@ -47,7 +27,9 @@ REPL* _repl;
 extern "C" {
     __EXPORT
     void repl_start(){
-        _repl = pkpy_new_repl(new_vm_with_callbacks(), false);
+        VM* vm = pkpy_new_vm(true);
+        useStandardBuffer(vm);
+        _repl = pkpy_new_repl(vm, false);
     }
 
     __EXPORT
@@ -58,10 +40,10 @@ extern "C" {
 
 #else
 
-
 int main(int argc, char** argv){
     if(argc == 1){
-        REPL repl(new_vm_with_callbacks());
+        VM* vm = pkpy_new_vm(true);
+        REPL repl(vm);
         while(true){
             std::string line;
             std::getline(std::cin, line);
@@ -81,7 +63,7 @@ int main(int argc, char** argv){
         }
         std::string src((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
 
-        ThreadedVM* vm = new_tvm_with_callbacks();
+        ThreadedVM* vm = pkpy_new_tvm(true);
         _Code code;
         Timer("Compile time").run([&]{
             code = compile(vm, src.c_str(), filename);

+ 1 - 1
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.2.3"
+#define PK_VERSION "0.2.4"
 
 class CodeObject;
 class BasePointer;

+ 39 - 12
src/pocketpy.h

@@ -42,8 +42,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
     _vm->bindBuiltinFunc("print", [](VM* vm, PyVarList args) {
         _StrStream ss;
         for (auto& arg : args) ss << vm->PyStr_AS_C(vm->asStr(arg)) << " ";
-        vm->_stdout(vm, ss.str().c_str());
-        vm->_stdout(vm, "\n");
+        (*vm->_stdout) << ss.str() << '\n';
         return vm->None;
     });
 
@@ -593,6 +592,22 @@ extern "C" {
         }
     };
 
+    __EXPORT
+    struct PyOutputDump: public PkExportedResource{
+        const char* stdout;
+        const char* stderr;
+
+        PyOutputDump(const char* _stdout, const char* _stderr){
+            stdout = strdup(_stdout);
+            stderr = strdup(_stderr);
+        }
+
+        ~PyOutputDump(){
+            delete[] stdout;
+            delete[] stderr;
+        }
+    };
+
     __EXPORT
     void pkpy_delete(PkExportedResource* p){
         delete p;
@@ -665,11 +680,8 @@ extern "C" {
         return vm->exec(code, _m) != nullptr;
     }
 
-    void __vm_init(VM* vm, PrintFn _stdout, PrintFn _stderr){
+    void __vm_init(VM* vm){
         __initializeBuiltinFunctions(vm);
-        vm->_stdout = _stdout;
-        vm->_stderr = _stderr;
-
         _Code code = compile(vm, __BUILTINS_CODE, "<builtins>");
         if(code == nullptr) exit(1);
         vm->_exec(code, vm->builtins);
@@ -680,19 +692,34 @@ extern "C" {
     }
 
     __EXPORT
-    VM* pkpy_new_vm(PrintFn _stdout, PrintFn _stderr){
-        VM* vm = new VM();
-        __vm_init(vm, _stdout, _stderr);
+    VM* pkpy_new_vm(bool use_stdio){
+        VM* vm = new VM(use_stdio);
+        __vm_init(vm);
         return vm;
     }
 
     __EXPORT
-    ThreadedVM* pkpy_new_tvm(PrintFn _stdout, PrintFn _stderr){
-        ThreadedVM* vm = new ThreadedVM();
-        __vm_init(vm, _stdout, _stderr);
+    ThreadedVM* pkpy_new_tvm(bool use_stdio){
+        ThreadedVM* vm = new ThreadedVM(use_stdio);
+        __vm_init(vm);
         return vm;
     }
 
+    __EXPORT
+    PyOutputDump* pkpy_vm_read_output(VM* vm){
+        if(vm->use_stdio) UNREACHABLE();
+        _StrStream* s_out = dynamic_cast<_StrStream*>(vm->_stdout);
+        _StrStream* s_err = dynamic_cast<_StrStream*>(vm->_stderr);
+        if(s_out == nullptr || s_err == nullptr) UNREACHABLE();
+        PyOutputDump* dump = new PyOutputDump(
+            s_out->str().c_str(),
+            s_out->str().c_str()
+        );
+        s_out->str("");
+        s_err->str("");
+        return dump;
+    }
+
     __EXPORT
     int pkpy_tvm_get_state(ThreadedVM* vm){
         return vm->getState();

+ 4 - 4
src/repl.h

@@ -21,15 +21,15 @@ class REPL: public PkExportedResource {
     void _loop_start(){
         mode = SINGLE_MODE;
         if(use_prompt){
-            vm->_stdout(vm, need_more_lines ? "... " : ">>> ");
+            (*vm->_stdout) << (need_more_lines ? "... " : ">>> ");
         }
     }
 
 public:
     REPL(VM* vm, bool use_prompt=true) : vm(vm), use_prompt(use_prompt) {
-        vm->_stdout(vm, "pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ")\n");
-        vm->_stdout(vm, "https://github.com/blueloveTH/pocketpy" "\n");
-        vm->_stdout(vm, "Type \"exit()\" to exit." "\n");
+        (*vm->_stdout) << ("pocketpy " PK_VERSION " (" __DATE__ ", " __TIME__ ")\n");
+        (*vm->_stdout) << ("https://github.com/blueloveTH/pocketpy" "\n");
+        (*vm->_stdout) << ("Type \"exit()\" to exit." "\n");
         _loop_start();
     }
 

+ 28 - 14
src/vm.h

@@ -48,7 +48,6 @@ class VM: public PkExportedResource{
 private:
     std::stack< std::unique_ptr<Frame> > callstack;
     PyVarDict _modules;       // 3rd modules
-
     PyVar __py2py_call_signal;
 
     PyVar runFrame(Frame* frame){
@@ -155,8 +154,7 @@ private:
                 {
                     const PyVar& expr = frame->topValue(this);
                     if(expr == None) break;
-                    _stdout(this, PyStr_AS_C(asRepr(expr)).c_str());
-                    _stdout(this, "\n");
+                    *_stdout << PyStr_AS_C(asRepr(expr)) << '\n';
                 } break;
             case OP_POP_TOP: frame->popValue(this); break;
             case OP_BINARY_OP:
@@ -328,15 +326,26 @@ public:
     PyVarDict _types;
     PyVar None, True, False;
 
-    PrintFn _stdout = [](const VM* vm, auto s){};
-    PrintFn _stderr = [](const VM* vm, auto s){};
+    bool use_stdio;
+    std::ostream* _stdout;
+    std::ostream* _stderr;
     
     PyVar builtins;         // builtins module
     PyVar _main;            // __main__ module
 
     int maxRecursionDepth = 1000;
 
-    VM(){
+    VM(bool use_stdio){
+        this->use_stdio = use_stdio;
+        if(use_stdio){
+            std::cout.setf(std::ios::unitbuf);
+            std::cerr.setf(std::ios::unitbuf);
+            this->_stdout = &std::cout;
+            this->_stderr = &std::cerr;
+        }else{
+            this->_stdout = new _StrStream();
+            this->_stderr = new _StrStream();
+        }
         initializeBuiltinClasses();
     }
 
@@ -462,12 +471,11 @@ public:
             return _exec(code, _module);
         } catch (const std::exception& e) {
             if(const _Error* _ = dynamic_cast<const _Error*>(&e)){
-                _stderr(this, e.what());
+                *_stderr << e.what() << '\n';
             }else{
                 auto re = RuntimeError("UnexpectedError", e.what(), _cleanErrorAndGetSnapshots());
-                _stderr(this, re.what());
+                *_stderr << re.what() << '\n';
             }
-            _stderr(this, "\n");
             return nullptr;
         }
     }
@@ -785,7 +793,12 @@ public:
         if (!val) _error("AssertionError", msg);
     }
 
-    virtual ~VM() = default;
+    virtual ~VM() {
+        if(!use_stdio){
+            delete _stdout;
+            delete _stderr;
+        }
+    }
 };
 
 /***** Pointers' Impl *****/
@@ -916,10 +929,11 @@ enum ThreadState {
 class ThreadedVM : public VM {
     std::thread* _thread;
     std::atomic<ThreadState> state = THREAD_READY;
-
 public:
+    ThreadedVM(bool use_stdio) : VM(use_stdio) {}
+
     _Str _stdin;
-    
+
     void suspend(){
         if(_thread == nullptr) UNREACHABLE();
         if(state != THREAD_RUNNING) UNREACHABLE();
@@ -938,8 +952,7 @@ public:
     /***** For outer use *****/
 
     ThreadState getState(){
-        if(_thread == nullptr) UNREACHABLE();
-        return state;
+        return state.load();
     }
 
     void resume(){
@@ -950,6 +963,7 @@ public:
 
     void startExec(const _Code& code){
         if(_thread != nullptr) UNREACHABLE();
+        if(state != THREAD_READY) UNREACHABLE();
         _thread = new std::thread([this, code](){
             this->state = THREAD_RUNNING;
             this->exec(code);