Преглед изворни кода

feat: 错误回溯信息显示`note`

SongZihuan пре 3 година
родитељ
комит
c7b7886102
2 измењених фајлова са 107 додато и 9 уклоњено
  1. 18 2
      src/core/__env.h
  2. 89 7
      src/core/env.c

+ 18 - 2
src/core/__env.h

@@ -107,11 +107,12 @@ struct af_Activity {  // 活动记录器
             struct af_Code *bt_start;  // 代码的起始位置 (block的第一个元素)
             struct af_Code *bt_next;  // 指示代码下一步要运行的位置 [总是超前当前执行的code]
 
+            /* 返回值 */
             bool return_first;  // 顺序执行, 获取第一个返回结果
             struct af_Object *return_obj;  // 调用者向被调用者传递信息
             size_t process_msg_first;  // 优先处理msg而不是code
 
-            /* 函数调用专项 */
+            /* 函数调用: 常规 */
             enum af_BlockType call_type;  // 函数调用类型
             struct af_Object *parentheses_call;  // 类前缀调用
             struct af_ArgCodeList *acl_start;
@@ -119,12 +120,27 @@ struct af_Activity {  // 活动记录器
             struct af_FuncInfo *fi;
             struct af_FuncBody *body_next;  // 下一个需要执行的body [总是超前当前执行的body]
             void *mark;  // 标记 [完全由API管理, 不随activity释放]
+
+            /* 函数调用: 宏函数*/
+            bool is_macro_call;  // 宏函数隐式调用
             struct af_VarSpaceListNode *macro_vsl;  // 宏函数执行的vsl
             ActivityCount macro_vs_count;
 
-            /* 字面量专项 */
+            /* 函数调用: 析构函数 */
+            bool is_gc_call;
+
+            /* 字面量 */
             bool is_literal;  // 处于字面量运算 意味着函数调用结束后会调用指定API
             struct af_LiteralDataList *ld;
+
+            /* 变量 */
+            bool is_obj_func;  // 对象函数的调用
+
+            /* 顺序执行 */
+            bool is_execution;
+
+            /* 尾调用优化 */
+            bool optimization;
         };
     };
 };

+ 89 - 7
src/core/env.c

@@ -48,6 +48,14 @@ static af_ErrorBacktracking *makeErrorBacktracking(FileLine line, FilePath file,
 static af_ErrorBacktracking *freeErrorBacktracking(af_ErrorBacktracking *ebt);
 static void freeAllErrorBacktracking(af_ErrorBacktracking *ebt);
 
+/* af_ErrorBacktracking 相关函数 */
+static char *getActivityInfoToBacktracking(af_Activity *activity);
+static void fprintfNote(FILE *file, char *note);
+
+/* 内置顶层消息处理器 */
+static void mp_NORMAL(af_Message *msg, bool is_gc, af_Environment *env);
+static void mp_ERROR(af_Message *msg, bool is_gc, af_Environment *env);
+
 static af_Core *makeCore(enum GcRunTime grt) {
     af_Core *core = calloc(sizeof(af_Core), 1);
     core->status = core_creat;
@@ -395,15 +403,21 @@ void connectMessage(af_Message **base, af_Message *msg) {
 
 af_Message *makeNORMALMessage(af_Object *obj) {
     af_Message *msg = makeMessage("NORMAL", sizeof(af_Object *));
-    *(af_Object **)msg->msg = obj;  // env->activity->return_obj本来就有一个gc_Reference
+    *(af_Object **)msg->msg = obj;
     gc_addReference(obj);
     return msg;
 }
 
 af_Message *makeERRORMessage(char *type, char *error, af_Environment *env) {
-    af_ErrorInfo *ei = makeErrorInfo(type, error, NULL, env->activity->line, env->activity->file);
-    for (af_Activity *activity = env->activity->prev; activity != NULL; activity = activity->prev)
-        pushErrorBacktracking(activity->line, activity->file, NULL, ei);
+    char *info = getActivityInfoToBacktracking(env->activity);
+    af_ErrorInfo *ei = makeErrorInfo(type, error, info, env->activity->line, env->activity->file);
+    free(info);
+
+    for (af_Activity *activity = env->activity->prev; activity != NULL; activity = activity->prev) {
+        info = getActivityInfoToBacktracking(activity);
+        pushErrorBacktracking(activity->line, activity->file, info, ei);
+        free(info);
+    }
 
     af_Message *msg = makeMessage("ERROR", sizeof(af_ErrorInfo *));
     *(af_ErrorInfo **)msg->msg = ei;
@@ -477,7 +491,7 @@ char *findEnvVar(char *name, af_Environment *env) {
     return NULL;
 }
 
-void mp_NORMAL(af_Message *msg, bool is_gc, af_Environment *env) {
+static void mp_NORMAL(af_Message *msg, bool is_gc, af_Environment *env) {
     if (msg->msg == NULL || *(af_Object **)msg->msg == NULL) {
         fprintf(stderr, "msg: %p error\n", msg->msg);
         return;
@@ -487,7 +501,7 @@ void mp_NORMAL(af_Message *msg, bool is_gc, af_Environment *env) {
         printf("NORMAL Point: %p\n", *(af_Object **)msg->msg);
 }
 
-void mp_ERROR(af_Message *msg, bool is_gc, af_Environment *env) {
+static void mp_ERROR(af_Message *msg, bool is_gc, af_Environment *env) {
     if (msg->msg == NULL || *(af_ErrorInfo **)msg->msg == NULL) {
         printf("msg: %p error\n", msg->msg);
         return;
@@ -606,6 +620,7 @@ static void newActivity(af_Code *bt, const af_Code *next, bool return_first, af_
     if (next == NULL && env->activity->body_next == NULL && env->activity->type == act_func) {
         printf("Tail tone recursive optimization\n");
         clearActivity(env->activity);
+        env->activity->optimization = true;
         setActivityBtTop(bt, env->activity);
         if (!env->activity->return_first)  // 若原本就有设置 return_first 则没有在设置的必要了, 因为该执行不会被返回
             env->activity->return_first = return_first;
@@ -636,6 +651,7 @@ bool pushExecutionActivity(af_Code *bt, bool return_first, af_Environment *env)
     setActivityBtStart(bt->next, env->activity);
 
     env->activity->status = act_func_normal;
+    env->activity->is_execution = true;
     return true;
 }
 
@@ -726,6 +742,7 @@ bool pushVariableActivity(af_Code *bt, af_Object *func, af_Environment *env) {
     setActivityBtNext(bt->next, env->activity);
 
     newActivity(bt, bt->next, false, env);
+    env->activity->is_obj_func = true;
     return setFuncActivityToArg(func, env);
 }
 
@@ -743,6 +760,7 @@ bool pushMacroFuncActivity(af_Object *func, af_Environment *env) {
     env->activity->var_list = env->activity->macro_vsl;
     env->activity->new_vs_count = env->activity->macro_vs_count;
     env->activity->macro_vs_count = 0;
+    env->activity->is_macro_call = true;
 
     clearActivity(env->activity);  /* 隐式调用不设置 bt_top */
     return setFuncActivityToArg(func, env);
@@ -774,6 +792,7 @@ bool pushDestructActivity(gc_DestructList *dl, af_Environment *env) {
                                              env->activity->var_list, env->activity->belong, NULL);
     activity->prev = env->activity;
     env->activity = activity;
+    env->activity->is_gc_call = true;
     return setFuncActivityToArg(dl->func, env);
 }
 
@@ -1086,12 +1105,26 @@ void freeErrorInfo(af_ErrorInfo *ei) {
     free(ei);
 }
 
+static void fprintfNote(FILE *file, char *note) {
+    char *ent = NULL;
+    while(true) {
+        ent = strchr(note, '\n');
+        if (ent != NULL)
+            *ent = NUL;
+        fprintf(file, "   #note: %s\n", note);
+        if (ent == NULL)  // 意味着是最后一部分`note`
+            break;
+        *ent = '\n';
+        note = ent + 1;
+    }
+}
+
 void fprintfErrorInfo(FILE *file, af_ErrorInfo *ei) {
     fprintf(file, "Error Traceback (most recent call last):\n");
     for (af_ErrorBacktracking *ebt = ei->track; ebt != NULL; ebt = ebt->next) {
         fprintf(file, "  File \"%s\", line %d\n", ebt->file, ebt->line);
         if (ebt->note != NULL)
-            fprintf(file, "   #note: %s", ebt->note);
+            fprintfNote(file, ebt->note);
     }
     fprintf(file, "%s: \"%s\"\n", ei->error_type, ei->error);
     fflush(file);
@@ -1128,3 +1161,52 @@ void pushErrorBacktracking(FileLine line, FilePath file, char *note, af_ErrorInf
     ebt->next = ei->track;
     ei->track = ebt;
 }
+
+static char *getActivityInfoToBacktracking(af_Activity *activity) {
+    char *info = NULL;
+    if (activity->type == act_gc) {
+        info = strJoin(info, "gc-activity;", true, false);
+        return info;
+    }
+
+    if (activity->is_execution)
+        info = strJoin(info, "execution-activity;", true, false);
+    else if (activity->is_gc_call)
+        info = strJoin(info, "gc-destruct-function-call-activity;", true, false);
+    else if (activity->prev == NULL)
+        info = strJoin(info, "top-activity;", true, false);
+    else
+        info = strJoin(info, "function-call-activity;", true, false);
+
+    switch (activity->status) {
+        case act_func_get:
+            info = strJoin(info, "\nfunc-get;", true, false);
+            break;
+        case act_func_arg:
+            info = strJoin(info, "\nfunc-arg;", true, false);
+            if (activity->run_in_func)
+                info = strJoin(info, " run-in-function-var-space;", true, false);
+            break;
+        case act_func_normal:
+            info = strJoin(info, "\nrun-code;", true, false);
+            if (activity->return_first)
+                info = strJoin(info, " return-first-result;", true, false);
+            break;
+        default:
+            break;
+    }
+
+    if (activity->is_macro_call)
+        info = strJoin(info, "\nmacro-call;", true, false);
+
+    if (activity->is_literal)
+        info = strJoin(info, "\nliteral-call;", true, false);
+
+    if (activity->is_obj_func)
+        info = strJoin(info, "\nobject-function-call;", true, false);
+
+    if (activity->optimization)
+        info = strJoin(info, "\ntail-call-Optimization;", true, false);
+
+    return info;
+}