浏览代码

refactor & feat: 错误回溯

SongZihuan 3 年之前
父节点
当前提交
a74290c51b
共有 8 个文件被更改,包括 124 次插入33 次删除
  1. 5 2
      include/core/activation.hpp
  2. 1 1
      include/core/code.hpp
  3. 1 0
      include/core/core.hpp
  4. 19 1
      include/core/msg.hpp
  5. 50 15
      src/core/activation.cpp
  6. 12 10
      src/core/inter.cpp
  7. 28 4
      src/core/msg.cpp
  8. 8 0
      test/src/run-code.cpp

+ 5 - 2
include/core/activation.hpp

@@ -15,11 +15,11 @@ namespace aFuncore {
 
         UpMessage *up;
         DownMessage *down;
-    public:
-        Inter *const inter;
 
         StringFilePath path;
         FileLine line;
+    public:
+        Inter *const inter;
 
         explicit Activation(Inter *inter_);
         virtual ~Activation();
@@ -32,6 +32,9 @@ namespace aFuncore {
         [[nodiscard]] Activation *toPrev() const {return prev;}
         [[nodiscard]] UpMessage *getUpStream() const {return up;}
         [[nodiscard]] DownMessage *getDownStream() const {return down;}
+
+        [[nodiscard]] FileLine getFileLine() {return line;}
+        [[nodiscard]] StringFilePath &getFilePath() {return path;}
     };
 
     class ExeActivation : public Activation {

+ 1 - 1
include/core/code.hpp

@@ -54,7 +54,7 @@ namespace aFuncore {
         [[nodiscard]] Code *toFather() const {return father;}
 
         [[nodiscard]] aFuntool::FileLine getFileLine() const {return line;}
-        [[nodiscard]] aFuntool::StringFilePath getFilePath() const {return file;}
+        [[nodiscard]] aFuntool::FilePath getFilePath() const {return file;}
     };
 }
 

+ 1 - 0
include/core/core.hpp

@@ -46,6 +46,7 @@ namespace aFuncore {
 
     class Message;
     class NormalMessage;
+    class ErrorMessage;
 
     class MessageStream;
     class UpMessage;

+ 19 - 1
include/core/msg.hpp

@@ -3,6 +3,7 @@
 #include "tool.hpp"
 #include "aFunCoreExport.h"
 #include "core.hpp"
+#include "list"
 
 namespace aFuncore {
     class Message {
@@ -26,12 +27,29 @@ namespace aFuncore {
     class NormalMessage : public TopMessage {
         Object *obj;
     public:
-        AFUN_CORE_EXPORT explicit NormalMessage(Object *obj);
+        AFUN_CORE_EXPORT explicit NormalMessage(Object *obj_) : TopMessage("NORMAL"), obj {obj_} {}
         AFUN_CORE_EXPORT ~NormalMessage() override;
         void topProgress() override;
         Object *getObject() {return obj;}
     };
 
+    class ErrorMessage : public TopMessage {
+        Inter *inter;
+
+        std::string error_type;
+        std::string error_info;
+        struct TrackBack{
+            StringFilePath path;
+            FileLine line;
+        };
+        std::list<TrackBack> trackback;
+    public:
+        AFUN_CORE_EXPORT explicit ErrorMessage(const std::string &error_type_, const std::string &error_info_, Activation *activation);
+        void topProgress() override;
+        std::string getErrorType() {return error_type;}
+        std::string getErrorInfo() {return error_info;}
+    };
+
     class MessageStream {
     protected:
         Message *stream;

+ 50 - 15
src/core/activation.cpp

@@ -23,6 +23,10 @@ Activation::Activation(Inter *inter_) : inter{inter_}, line{0} {
     varlist = old_varlist;
     down = new DownMessage();
     up = new UpMessage(prev ? prev->up : nullptr);
+    if (prev != nullptr) {
+        line = prev->line;
+        path = prev->path;
+    }
     inter->pushActivation(this);
 }
 
@@ -62,17 +66,19 @@ void Activation::runCode(Code *code){
                 auto literaler = dynamic_cast<Literaler *>(obj);
                 if (literaler != nullptr)
                     literaler->getObject(code->getElement(), code->getPrefix());
+                else
+                    down->pushMessage(new ErrorMessage("TypeError", "Error type of literal.", this));
             } else {
                 if (varlist != nullptr)
                     obj = varlist->findObject(code->getElement());
-                trackLog(aFunCoreLogger, "Find Var %s -> %p", code->getElement(), obj);
                 if (obj != nullptr) {
                     auto cbv = dynamic_cast<CallBackVar *>(obj);
                     if (cbv != nullptr && cbv->isCallBack())
                         cbv->callBack();
                     else
                         down->pushMessage(new NormalMessage(obj));
-                }
+                } else
+                    down->pushMessage(new ErrorMessage("NameError", std::string("Variable ") + code->getElement() + " not fount.", this));
             }
         } else switch (code->getBlockType()) {
             case block_p:  // 顺序执行
@@ -104,6 +110,9 @@ ActivationStatus ExeActivation::getCode(Code *&code){
     }
 
     first = false;
+    line = code->getFileLine();
+    if (code->getFilePath() != nullptr)
+        path = code->getFilePath();
     next = code->toNext();
     return as_run;
 }
@@ -132,10 +141,18 @@ ActivationStatus FuncActivation::getCode(Code *&code){
         return as_end;
 
     if (status == func_first) {
-        status = func_get_func;
         switch (call->getBlockType()) {
             case block_c:
+                status = func_get_func;
                 code = call->getSon();
+                if (code == nullptr) {
+                    line = 0;
+                    down->pushMessage(new ErrorMessage("SyntaxError", "Callback without code.", this));
+                    return as_end;
+                }
+                line = code->getFileLine();
+                if (code->getFilePath() != nullptr)
+                    path = code->getFilePath();
                 return as_run;
             case block_b: {
                 std::string prefix;
@@ -154,10 +171,17 @@ ActivationStatus FuncActivation::getCode(Code *&code){
                     status = func_get_func;
                     break;  /* 跳转到: 执行变量获取前的准备 */
                 }
+                if (status != func_get_func) {
+                    line = 0;
+                    down->pushMessage(new ErrorMessage("SyntaxError", "Callback without code.", this));
+                    return as_end;
+                }
                 break;
             }
             default:
                 errorLog(aFunCoreLogger, "Error FuncActivation block type");
+                line = 0;
+                down->pushMessage(new ErrorMessage("RuntimeError", "Error FuncActivation block type.", this));
                 return as_end;
         }
     }
@@ -171,8 +195,10 @@ ActivationStatus FuncActivation::getCode(Code *&code){
                 down->popMessage("NORMAL");
             func = dynamic_cast<Function *>(msg->getObject());
             delete msg;
-            if (func == nullptr)
+            if (func == nullptr) {
+                down->pushMessage(new ErrorMessage("TypeError", "Callback without function.", this));
                 return as_end;
+            }
         }
 
         /* Label: 执行变量获取前的准备 */
@@ -181,27 +207,36 @@ ActivationStatus FuncActivation::getCode(Code *&code){
         acl = call_func->getArgCodeList();
         acl_begin = acl->begin();
         acl_end = acl->end();
-        if (acl_begin != acl_end) {
+        if (acl_begin != acl_end) {  // 如果有参数需要计算
             code = acl_begin->code;
+            line = code->getFileLine();
+            if (code->getFilePath() != nullptr)
+                path = code->getFilePath();
             return as_run;
         }
     }
 
-    auto *msg = down->getMessage<NormalMessage>("NORMAL");
-    if (msg == nullptr)
-        return as_end;
-    down->popMessage("NORMAL");
+    if (acl_begin != acl_end) {  // 获取参数计算结果
+        auto *msg = down->getMessage<NormalMessage>("NORMAL");
+        if (msg == nullptr)
+            return as_end;
+        down->popMessage("NORMAL");
 
-    acl_begin->ret = msg->getObject();
-    delete msg;
+        acl_begin->ret = msg->getObject();
+        delete msg;
 
-    acl_begin++;
-    if (acl_begin != acl_end) {
-        code = acl_begin->code;
-        return as_run;
+        acl_begin++;
+        if (acl_begin != acl_end) {
+            code = acl_begin->code;
+            line = code->getFileLine();
+            if (code->getFilePath() != nullptr)
+                path = code->getFilePath();
+            return as_run;
+        }
     }
 
     on_tail = true;
+    line = 0;
     return as_end_run;
 }
 

+ 12 - 10
src/core/inter.cpp

@@ -3,6 +3,7 @@
 #include "init.hpp"
 #include "env-var.hpp"
 #include "var.hpp"
+#include "msg.hpp"
 #include "__gc.hpp"
 
 using namespace aFuncore;
@@ -86,15 +87,6 @@ void Inter::enable(){
  */
 bool Inter::runCode(){
     while (activation != nullptr) {
-        if (isExit()) {
-            while (activation != nullptr) {
-                Activation *prev = activation->toPrev();
-                delete activation;
-                activation = prev;
-            }
-            return false;
-        }
-
         Code *code = nullptr;
         ActivationStatus as = activation->getCode(code);
         switch (as) {
@@ -112,8 +104,18 @@ bool Inter::runCode(){
                 break;
             default:
                 errorLog(aFunCoreLogger, "Error activation status.");
+                activation->getDownStream()->pushMessage(new ErrorMessage("RuntimeError", "Error activation status.", activation));
                 break;
         }
+
+        if (isExit()) {
+            while (activation != nullptr) {
+                Activation *prev = activation->toPrev();
+                delete activation;
+                activation = prev;
+            }
+            return false;
+        }
     }
     return true;
 }
@@ -187,7 +189,7 @@ bool Inter::checkLiteral(const std::string &element, std::string &literaler, boo
 
 bool Inter::pushLiteral(const std::string &pattern, const std::string &literaler, bool in_protect){
     try {
-        Regex *rg =  new Regex(pattern);
+        auto rg =  new Regex(pattern);
         literal->push_front({rg, pattern, literaler, in_protect});
     } catch (RegexException &e) {
         return false;

+ 28 - 4
src/core/msg.cpp

@@ -1,11 +1,11 @@
 #include "msg.hpp"
+#include "activation.hpp"
+#include "inter.hpp"
+#include "env-var.hpp"
+
 using namespace aFuncore;
 using namespace aFuntool;
 
-NormalMessage::NormalMessage(Object *obj) : TopMessage("NORMAL") {
-    this->obj = obj;
-}
-
 NormalMessage::~NormalMessage(){
     this->obj = nullptr;
 }
@@ -14,6 +14,30 @@ void NormalMessage::topProgress(){
     printf_stdout(0, "NORMAL: %p\n", obj);
 }
 
+ErrorMessage::ErrorMessage(const std::string &error_type_, const std::string &error_info_, Activation *activation)
+        : TopMessage("ERROR"), error_type{error_type_}, error_info{error_info_}, inter{activation->inter} {
+    for (NULL; activation != nullptr; activation = activation->toPrev()) {
+        if (activation->getFileLine() != 0)
+            trackback.push_front({activation->getFilePath(), activation->getFileLine()});
+    }
+}
+
+void ErrorMessage::topProgress(){
+    int32_t error_std = 0;
+    inter->getEnvVarSpace()->findNumber("sys:error_std", error_std);
+    if (error_std == 0) {
+        printf_stderr(0, "Error TrackBack\n");
+        for (auto begin = trackback.rbegin(), end = trackback.rend(); begin != end; begin++)
+            printf_stderr(0, "  File \"%s\", line %d\n", begin->path.c_str(), begin->line);
+        printf_stderr(0, "%s: %s\n", error_type.c_str(), error_info.c_str());
+    } else {
+        printf_stdout(0, "Error TrackBack\n");
+        for (auto begin = trackback.rbegin(), end = trackback.rend(); begin != end; begin++)
+            printf_stdout(0, "  File \"%s\", line %d\n", begin->path.c_str(), begin->line);
+        printf_stdout(0, "%s: %s\n", error_type.c_str(), error_info.c_str());
+    }
+}
+
 MessageStream::MessageStream(){
     stream = nullptr;
 }

+ 8 - 0
test/src/run-code.cpp

@@ -155,6 +155,14 @@ int main() {
         fputs_stdout("\n");
     }
 
+    {
+        auto code = (new Code(0, "run-code.aun"));
+        code->connect(new Code("test-not-var", 1));
+        inter->runCode(code);
+        code->destructAll();
+        fputs_stdout("\n");
+    }
+
     delete inter;
     return 0;
 }