blueloveTH пре 3 година
родитељ
комит
661b2033f9
5 измењених фајлова са 198 додато и 193 уклоњено
  1. 7 2
      src/compiler.h
  2. 11 2
      src/error.h
  3. 36 53
      src/main.cpp
  4. 14 9
      src/pocketpy.h
  5. 130 127
      src/vm.h

+ 7 - 2
src/compiler.h

@@ -887,6 +887,11 @@ __LITERAL_EXIT:
 };
 
 _Code compile(VM* vm, const char* source, _Str filename, CompileMode mode=EXEC_MODE) {
-    Compiler compiler(vm, source, filename, mode);
-    return compiler.__fillCode();
+    try{
+        Compiler compiler(vm, source, filename, mode);
+        return compiler.__fillCode();
+    }catch(std::exception& e){
+        REDIRECT_ERROR()
+        return nullptr;
+    }
 }

+ 11 - 2
src/error.h

@@ -6,7 +6,7 @@
 
 #include "str.h"
 
-class NeedMoreLines : public std::exception {
+class NeedMoreLines {
 public:
     NeedMoreLines(bool isClassDef) : isClassDef(isClassDef) {}
     bool isClassDef;
@@ -92,4 +92,13 @@ class UnexpectedError : public _Error {
 public:
     UnexpectedError(_Str msg)
         : _Error("UnexpectedError", msg, "") {}
-};
+};
+
+#define REDIRECT_ERROR()                                            \
+    if(const _Error* _ = dynamic_cast<const _Error*>(&e)){          \
+        vm->_stderr(e.what());                                      \
+    }else{                                                          \
+        vm->_stderr(UnexpectedError(e.what()).what());              \
+    }                                                               \
+    vm->_stderr("\n");
+

+ 36 - 53
src/main.cpp

@@ -7,22 +7,15 @@
 //#define PK_DEBUG
 //#define PK_DEBUG_TIME
 
-class Timer{
-private:
-    std::chrono::time_point<std::chrono::high_resolution_clock> start;
-    std::string title;
-public:
-    Timer(const std::string& title){
-#ifdef PK_DEBUG_TIME
-        start = std::chrono::high_resolution_clock::now();
-        this->title = title;
-#endif
-    }
-
-    void stop(){
-#ifdef PK_DEBUG_TIME
+struct Timer{
+    const char* title;
+    Timer(const char* title) : title(title) {}
+    void run(std::function<void()> f){
+        auto start = std::chrono::high_resolution_clock::now();
+        f();
         auto end = std::chrono::high_resolution_clock::now();
         double elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() / 1000000.0;
+#ifdef PK_DEBUG_TIME
         std::cout << title << ": " << elapsed << " s" << std::endl;
 #endif
     }
@@ -32,6 +25,9 @@ VM* newVM(){
     VM* vm = createVM([](const char* str) { 
         std::cout << str;
         std::cout.flush();
+    }, [](const char* str) { 
+        std::cerr << str;
+        std::cerr.flush();
     });
     return vm;
 }
@@ -40,12 +36,10 @@ void REPL(){
     std::cout << "pocketpy 0.1.0" << std::endl;
     std::cout << "https://github.com/blueloveTH/pocketpy" << std::endl;
 #ifdef PK_DEBUG
-    std::cout << "[ DEBUG MODE ENABLED ]" << std::endl;
+    std::cout << "[DEBUG MODE ENABLED]" << std::endl;
 #endif
 
-
     int need_more_lines = 0;
-
     std::string buffer;
     VM* vm = newVM();
 
@@ -75,24 +69,14 @@ __NOT_ENOUGH_LINES:
             if(line == "exit()") break;
             if(line.empty()) continue;
         }
+
         try{
             _Code code = compile(vm, line.c_str(), "<stdin>", mode);
-            vm->exec(code);
-#ifdef PK_DEBUG
-        }catch(NeedMoreLines& e){
-#else
-        }catch(std::exception& e){
-#endif
-            NeedMoreLines* ne = dynamic_cast<NeedMoreLines*>(&e);
-            if(ne){
-                buffer += line;
-                buffer += '\n';
-                need_more_lines = ne->isClassDef ? 3 : 2;
-            }else{
-                vm->_stdout(e.what());
-                vm->_stdout("\n");
-                vm->cleanError();
-            }
+            if(code != nullptr) vm->exec(code);
+        }catch(NeedMoreLines& ne){
+            buffer += line;
+            buffer += '\n';
+            need_more_lines = ne.isClassDef ? 3 : 2;
         }
     }
 }
@@ -101,9 +85,6 @@ int main(int argc, char** argv){
     if(argc == 1){
         REPL();
         return 0;
-
-        // argc = 2;
-        // argv = new char*[2]{argv[0], (char*)"../tests/singletype/basic.py"};
     }
     
     if(argc == 2){
@@ -112,24 +93,26 @@ int main(int argc, char** argv){
             std::cout << "Usage: pocketpy [filename]" << std::endl;
             return 0;
         }
-#ifndef PK_DEBUG
-        try{
-#endif
-            std::ifstream file(filename);
-            std::string src((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
-            VM* vm = newVM();
-            Timer timer("Compile time");
-            _Code code = compile(vm, src.c_str(), filename);
-            timer.stop();
-            //std::cout << code->toString() << std::endl;
-            Timer timer2("Running time");
-            vm->exec(code);
-            timer2.stop();
-#ifndef PK_DEBUG
-        }catch(std::exception& e){
-            std::cout << e.what() << std::endl;
+
+        std::ifstream file(filename);
+        if(!file.is_open()){
+            std::cerr << "File not found: " << filename << std::endl;
+            return 1;
         }
-#endif
+        std::string src((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
+
+        VM* vm = newVM();
+        _Code code;
+        Timer("Compile time").run([&]{
+            code = compile(vm, src.c_str(), filename);
+        });
+        if(code == nullptr) return 1;
+
+        //std::cout << code->toString() << std::endl;
+
+        Timer("Running time").run([=]{
+            vm->exec(code);
+        });
         return 0;
     }
 }

+ 14 - 9
src/pocketpy.h

@@ -414,13 +414,24 @@ void __runCodeBuiltins(VM* vm, const char* src){
 #define __EXPORT
 #endif
 
+#include <ctime>
+void __addModuleTime(VM* vm){
+    PyVar mod = vm->newModule("time");
+    vm->bindFunc(mod, "time", [](VM* vm, PyVarList args) {
+        return vm->PyInt((int)std::time(nullptr));
+    });
+}
+
+
 extern "C" {
     __EXPORT
-    VM* createVM(PrintFn _stdout){
+    VM* createVM(PrintFn _stdout, PrintFn _stderr){
         VM* vm = new VM();
         __initializeBuiltinFunctions(vm);
         __runCodeBuiltins(vm, __BUILTINS_CODE);
+        __addModuleTime(vm);
         vm->_stdout = _stdout;
+        vm->_stderr = _stderr;
         return vm;
     }
 
@@ -431,14 +442,8 @@ extern "C" {
 
     __EXPORT
     void exec(VM* vm, const char* source){
-        try{
-            _Code code = compile(vm, source, "main.py");
-            vm->exec(code);
-        }catch(std::exception& e){
-            vm->_stdout(e.what());
-            vm->_stdout("\n");
-            vm->cleanError();
-        }
+        _Code code = compile(vm, source, "main.py");
+        if(code != nullptr) vm->exec(code);
     }
 
     __EXPORT

+ 130 - 127
src/vm.h

@@ -27,123 +27,8 @@ class VM{
 private:
     std::stack< std::shared_ptr<Frame> > callstack;
     std::vector<PyObject*> numPool;
-public:
-    PyVarDict _types;         // builtin types
-    PyVar None, True, False;
-
-    PrintFn _stdout = [](auto s){};
-    PrintFn _stderr = [](auto s){};
-    
-    PyVar builtins;         // builtins module
-    PyVar _main;            // __main__ module
     PyVarDict _modules;       // 3rd modules
 
-    VM(){
-        initializeBuiltinClasses();
-    }
-
-    PyVar asStr(const PyVar& obj){
-        PyVarOrNull str_fn = getAttr(obj, __str__, false);
-        if(str_fn != nullptr) return call(str_fn, {});
-        return asRepr(obj);
-    }
-
-    PyVar asRepr(const PyVar& obj){
-        if(obj->isType(_tp_type)) return PyStr("<class '" + obj->getName() + "'>");
-        return call(obj, __repr__, {});
-    }
-
-    PyVar asBool(const PyVar& obj){
-        if(obj == None) return False;
-        PyVar tp = obj->attribs[__class__];
-        if(tp == _tp_bool) return obj;
-        if(tp == _tp_int) return PyBool(PyInt_AS_C(obj) != 0);
-        if(tp == _tp_float) return PyBool(PyFloat_AS_C(obj) != 0.0f);
-        PyVarOrNull len_fn = getAttr(obj, "__len__", false);
-        if(len_fn != nullptr){
-            PyVar ret = call(len_fn, {});
-            return PyBool(PyInt_AS_C(ret) > 0);
-        }
-        return True;
-    }
-
-    PyVar fastCall(const PyVar& obj, const _Str& name, PyVarList args){
-        PyVar cls = obj->attribs[__class__];
-        while(cls != None) {
-            auto it = cls->attribs.find(name);
-            if(it != cls->attribs.end()){
-                return call(it->second, args);
-            }
-            cls = cls->attribs[__base__];
-        }
-        attributeError(obj, name);
-        return nullptr;
-    }
-
-    PyVar call(PyVar callable, PyVarList args){
-        if(callable->isType(_tp_type)){
-            auto it = callable->attribs.find(__new__);
-            PyVar obj;
-            if(it != callable->attribs.end()){
-                obj = call(it->second, args);
-            }else{
-                obj = newObject(callable, -1);
-            }
-            if(obj->isType(callable)){
-                PyVarOrNull init_fn = getAttr(obj, __init__, false);
-                if (init_fn != nullptr) call(init_fn, args);
-            }
-            return obj;
-        }
-
-        if(callable->isType(_tp_bounded_method)){
-            auto& bm = PyBoundedMethod_AS_C(callable);
-            args.insert(args.begin(), bm.obj);
-            callable = bm.method;
-        }
-        
-        if(callable->isType(_tp_native_function)){
-            auto f = std::get<_CppFunc>(callable->_native);
-            return f(this, args);
-        } else if(callable->isType(_tp_function)){
-            _Func fn = PyFunction_AS_C(callable);
-            PyVarDict locals;
-            int i = 0;
-            for(const auto& name : fn.args){
-                if(i < args.size()) {
-                    locals[name] = args[i++];
-                }else{
-                    typeError("missing positional argument '" + name + "'");
-                }
-            }
-            // handle *args
-            if(!fn.starredArg.empty()){
-                PyVarList vargs;
-                while(i < args.size()) vargs.push_back(args[i++]);
-                locals[fn.starredArg] = PyTuple(vargs);
-            }
-            // handle keyword arguments
-            for(const auto& [name, value] : fn.kwArgs){
-                if(i < args.size()) {
-                    locals[name] = args[i++];
-                }else{
-                    locals[name] = value;
-                }
-            }
-
-            if(i < args.size()) typeError("too many arguments");
-
-            // TODO: handle **kwargs
-            return exec(fn.code, locals);
-        }
-        typeError("'" + callable->getTypeName() + "' object is not callable");
-        return None;
-    }
-
-    inline PyVar call(const PyVar& obj, const _Str& func, PyVarList args){
-        return call(getAttr(obj, func), args);
-    }
-    
     PyVar runFrame(std::shared_ptr<Frame> frame){
         callstack.push(frame);
         while(!frame->isEnd()){
@@ -380,11 +265,8 @@ public:
                 {
                     const _Str& name = frame->code->co_names[byte.arg]->name;
                     auto it = _modules.find(name);
-                    if(it == _modules.end()){
-                        _error("ImportError", "module '" + name + "' not found");
-                    }else{
-                        frame->push(it->second);
-                    }
+                    if(it == _modules.end()) _error("ImportError", "module '" + name + "' not found");
+                    else frame->push(it->second); 
                 } break;
             default:
                 systemError(_Str("opcode ") + OP_NAMES[byte.op] + " is not implemented");
@@ -404,14 +286,139 @@ public:
         return None;
     }
 
+public:
+    PyVarDict _types;         // builtin types
+    PyVar None, True, False;
+
+    PrintFn _stdout = [](auto s){};
+    PrintFn _stderr = [](auto s){};
+    
+    PyVar builtins;         // builtins module
+    PyVar _main;            // __main__ module
+
+    VM(){
+        initializeBuiltinClasses();
+    }
+
+    PyVar asStr(const PyVar& obj){
+        PyVarOrNull str_fn = getAttr(obj, __str__, false);
+        if(str_fn != nullptr) return call(str_fn, {});
+        return asRepr(obj);
+    }
+
+    PyVar asRepr(const PyVar& obj){
+        if(obj->isType(_tp_type)) return PyStr("<class '" + obj->getName() + "'>");
+        return call(obj, __repr__, {});
+    }
+
+    PyVar asBool(const PyVar& obj){
+        if(obj == None) return False;
+        PyVar tp = obj->attribs[__class__];
+        if(tp == _tp_bool) return obj;
+        if(tp == _tp_int) return PyBool(PyInt_AS_C(obj) != 0);
+        if(tp == _tp_float) return PyBool(PyFloat_AS_C(obj) != 0.0f);
+        PyVarOrNull len_fn = getAttr(obj, "__len__", false);
+        if(len_fn != nullptr){
+            PyVar ret = call(len_fn, {});
+            return PyBool(PyInt_AS_C(ret) > 0);
+        }
+        return True;
+    }
+
+    PyVar fastCall(const PyVar& obj, const _Str& name, PyVarList args){
+        PyVar cls = obj->attribs[__class__];
+        while(cls != None) {
+            auto it = cls->attribs.find(name);
+            if(it != cls->attribs.end()){
+                return call(it->second, args);
+            }
+            cls = cls->attribs[__base__];
+        }
+        attributeError(obj, name);
+        return nullptr;
+    }
+
+    PyVar call(PyVar callable, PyVarList args){
+        if(callable->isType(_tp_type)){
+            auto it = callable->attribs.find(__new__);
+            PyVar obj;
+            if(it != callable->attribs.end()){
+                obj = call(it->second, args);
+            }else{
+                obj = newObject(callable, -1);
+            }
+            if(obj->isType(callable)){
+                PyVarOrNull init_fn = getAttr(obj, __init__, false);
+                if (init_fn != nullptr) call(init_fn, args);
+            }
+            return obj;
+        }
+
+        if(callable->isType(_tp_bounded_method)){
+            auto& bm = PyBoundedMethod_AS_C(callable);
+            args.insert(args.begin(), bm.obj);
+            callable = bm.method;
+        }
+        
+        if(callable->isType(_tp_native_function)){
+            auto f = std::get<_CppFunc>(callable->_native);
+            return f(this, args);
+        } else if(callable->isType(_tp_function)){
+            _Func fn = PyFunction_AS_C(callable);
+            PyVarDict locals;
+            int i = 0;
+            for(const auto& name : fn.args){
+                if(i < args.size()) {
+                    locals[name] = args[i++];
+                }else{
+                    typeError("missing positional argument '" + name + "'");
+                }
+            }
+            // handle *args
+            if(!fn.starredArg.empty()){
+                PyVarList vargs;
+                while(i < args.size()) vargs.push_back(args[i++]);
+                locals[fn.starredArg] = PyTuple(vargs);
+            }
+            // handle keyword arguments
+            for(const auto& [name, value] : fn.kwArgs){
+                if(i < args.size()) {
+                    locals[name] = args[i++];
+                }else{
+                    locals[name] = value;
+                }
+            }
+
+            if(i < args.size()) typeError("too many arguments");
+
+            // TODO: handle **kwargs
+            return exec(fn.code, locals);
+        }
+        typeError("'" + callable->getTypeName() + "' object is not callable");
+        return None;
+    }
+
+    inline PyVar call(const PyVar& obj, const _Str& func, PyVarList args){
+        return call(getAttr(obj, func), args);
+    }
+    
     PyVar exec(const _Code& code, const PyVarDict& locals={}, PyVar _module=nullptr){
+        if(code == nullptr) UNREACHABLE();
         if(_module == nullptr) _module = _main;
         auto frame = std::make_shared<Frame>(
             code.get(),
             locals,
             &_module->attribs
         );
-        return runFrame(frame);
+
+        try {
+            return runFrame(frame);
+        } catch (const std::exception& e) {
+            while(!callstack.empty()) callstack.pop();
+            VM* vm = this;
+            REDIRECT_ERROR()
+            return None;
+        }
     }
 
     PyVar newUserClassType(_Str name, PyVar base){
@@ -456,8 +463,9 @@ public:
     }
 
     PyVar newModule(_Str name) {
-        PyVar obj = newObject(_tp_module, 0);
+        PyVar obj = newObject(_tp_module, -2);
         setAttr(obj, "__name__", PyStr(name));
+        _modules[name] = obj;
         return obj;
     }
 
@@ -628,7 +636,6 @@ public:
     void registerCompiledModule(_Str name, _Code code){
         PyVar _m = newModule(name);
         exec(code, {}, _m);
-        _modules[name] = _m;
     }
 
     /***** Error Reporter *****/
@@ -644,10 +651,6 @@ private:
     }
 
 public:
-    void cleanError(){
-        while(!callstack.empty()) callstack.pop();
-    }
-
     void typeError(const _Str& msg){
         typeError(msg);
     }