ソースを参照

feat: 添加对中缀调用的支持

SongZihuan 3 年 前
コミット
c135cc5ff4
4 ファイル変更157 行追加19 行削除
  1. 2 1
      include/obj_api.h
  2. 44 10
      src/core/env.c
  3. 16 8
      src/core/run.c
  4. 95 0
      src/main.c

+ 2 - 1
include/obj_api.h

@@ -42,8 +42,9 @@ typedef void obj_funcFreeMask(void *mark);  // 释放mask的函数
 /* Object 字面量设定 */
 typedef void obj_literalSetting(char *str, void *data, af_Object *obj, af_Environment *env);
 
-/* Object 变量专项 */
+/* Object 函数管理 */
 typedef bool obj_isObjFunc(af_Object *obj);  // 是否对象函数
+typedef bool obj_isInfixFunc(af_Object *obj);  // 是否中缀函数
 
 /* Object gc管理 */
 typedef af_GcList *obj_getGcList(char *id, void *data);  // 是否对象函数

+ 44 - 10
src/core/env.c

@@ -540,6 +540,20 @@ bool pushExecutionActivity(af_Code *bt, bool return_first, af_Environment *env)
     return true;
 }
 
+static bool isInfixFunc(af_Code *code, af_Environment *env) {
+    if (code == NULL || code->type != variable || code->prefix == env->core->prefix[V_QUOTE])
+        return false;
+
+    af_Var *var = findVarFromVarList(code->variable.name, env->activity->belong, env->activity->var_list);
+    if (var == NULL)
+        return false;
+
+    obj_isInfixFunc *func = findAPI("obj_isInfixFunc", var->vn->obj->data->api);
+    if (func == NULL)
+        return false;
+    return func(var->vn->obj);
+}
+
 bool pushFuncActivity(af_Code *bt, af_Environment *env) {
     af_Code *next;
     af_Code *func;
@@ -551,17 +565,37 @@ bool pushFuncActivity(af_Code *bt, af_Environment *env) {
         return false;
     }
 
-    if (bt->block.type == curly) {  // 大括号
-        if (bt->block.elements == 0) {
-            pushMessageDown(makeMessage("ERROR-STR", 0), env);
-            return false;
-        } else
+    switch (bt->block.type) {
+        case curly:
+            if (bt->block.elements == 0) {
+                pushMessageDown(makeMessage("ERROR-STR", 0), env);
+                return false;
+            }
             func = bt->next;
-    } else if (bt->block.type == brackets) {  // 暂时不考虑中括号
-        pushMessageDown(makeMessage("ERROR-STR", 0), env);
-        return false;
-    } else
-        func = NULL;  // 小括号则不在需要匹配
+            break;
+        case brackets: {
+            af_Code *code = bt->next;
+            func = NULL;
+            for (int i = 0; i < bt->block.elements; i++) {
+                if (isInfixFunc(code, env)) {
+                    func = code;
+                    break;
+                }
+                if (!getCodeBlockNext(bt, &code))
+                    break;
+            }
+            if (func == NULL) {
+                pushMessageDown(makeMessage("ERROR-STR", 0), env);
+                return false;
+            }
+            break;
+        }
+        case parentheses:
+            func = NULL;  // 小括号则不在需要匹配
+            break;
+        default:
+            break;
+    }
 
     env->activity->bt_next = next;
 

+ 16 - 8
src/core/run.c

@@ -130,16 +130,24 @@ static bool codeVariable(af_Code *code, af_Environment *env) {
     }
 
     af_Object *obj = var->vn->obj;
-    obj_isObjFunc *func;
-    if (code->prefix == env->core->prefix[V_QUOTE] ||
-        (func = findAPI("obj_isObjFunc", obj->data->api)) == NULL || !func(obj)) {  // 非对象函数 或 引用调用
-        pushMessageDown(makeNORMALMessage(obj), env);
-        env->activity->bt_next = env->activity->bt_next->next;
-        printf("Get Variable %s : %p\n", code->variable.name, obj);
-        return false;
+    obj_isObjFunc *is_obj;
+    obj_isInfixFunc *is_infix;
+
+    if (code->prefix != env->core->prefix[V_QUOTE]) {
+        if ((is_obj = findAPI("obj_isObjFunc", obj->data->api)) != NULL && is_obj(obj))
+            return pushVariableActivity(code, var->vn->obj, env);  // 对象函数
+        else if (env->activity->status != act_func && // 在act_func模式时关闭保护
+                 (is_infix = findAPI("obj_isInfixFunc", obj->data->api)) != NULL && is_infix(obj)) {
+            pushMessageDown(makeMessage("ERROR-STR", 0), env);
+            printf("Infix protect : %s\n", code->variable.name);
+            return false;
+        }
     }
 
-    return pushVariableActivity(code, var->vn->obj, env);
+    pushMessageDown(makeNORMALMessage(obj), env);
+    env->activity->bt_next = env->activity->bt_next->next;
+    printf("Get Variable %s : %p\n", code->variable.name, obj);
+    return false;
 }
 
 /*

+ 95 - 0
src/main.c

@@ -365,6 +365,10 @@ bool objFunc(af_Object *obj) {
     return true;
 }
 
+bool infixFunc(af_Object *obj) {
+    return true;
+}
+
 int main() {
     aFunInit();
     printf("Hello World\n");
@@ -741,6 +745,56 @@ int main() {
         printf("func7(%p)\n", obj);
     }
 
+    {
+        af_ObjectAPI *api = makeObjectAPI();
+        af_Object *obj;
+        DLC_SYMBOL(objectAPIFunc) get_alc = MAKE_SYMBOL(getAcl, objectAPIFunc);
+        DLC_SYMBOL(objectAPIFunc) get_vsl = MAKE_SYMBOL(getVsl, objectAPIFunc);
+        DLC_SYMBOL(objectAPIFunc) get_al = MAKE_SYMBOL(getAl, objectAPIFunc);
+        DLC_SYMBOL(objectAPIFunc) get_info = MAKE_SYMBOL(getInfo, objectAPIFunc);
+        DLC_SYMBOL(objectAPIFunc) free_mark = MAKE_SYMBOL(freeMark, objectAPIFunc);
+        DLC_SYMBOL(objectAPIFunc) get_gl = MAKE_SYMBOL(getGcList, objectAPIFunc);
+        DLC_SYMBOL(objectAPIFunc) getSize_2 = MAKE_SYMBOL(getSize2, objectAPIFunc);
+        DLC_SYMBOL(objectAPIFunc) initData_2 = MAKE_SYMBOL(initData2, objectAPIFunc);
+        DLC_SYMBOL(objectAPIFunc) freeData_2 = MAKE_SYMBOL(freeData2, objectAPIFunc);
+        DLC_SYMBOL(objectAPIFunc) infix_func = MAKE_SYMBOL(infixFunc, objectAPIFunc);
+        if (addAPI(getSize_2, "obj_getDataSize", api) != 1)
+            return 2;
+        if (addAPI(initData_2, "obj_initData", api) != 1)
+            return 2;
+        if (addAPI(freeData_2, "obj_destructData", api) != 1)
+            return 2;
+        if (addAPI(get_alc, "obj_funcGetArgCodeList", api) != 1)
+            return 2;
+        if (addAPI(get_vsl, "obj_funcGetVarList", api) != 1)
+            return 2;
+        if (addAPI(get_al, "obj_funcGetArgList", api) != 1)
+            return 2;
+        if (addAPI(get_info, "obj_funcGetInfo", api) != 1)
+            return 2;
+        if (addAPI(free_mark, "obj_funcFreeMask", api) != 1)
+            return 2;
+        if (addAPI(get_gl, "obj_getGcList", api) != 1)
+            return 2;
+        if (addAPI(infix_func, "obj_isInfixFunc", api) != 1)
+            return 2;
+
+        addVarToProtectVarSpace(makeVar("func8", 3, 3, 3,
+                                        (obj = makeObject("func", true, api, true, NULL, NULL, env)), env),
+                                env);
+        FREE_SYMBOL(get_alc);
+        FREE_SYMBOL(get_vsl);
+        FREE_SYMBOL(get_al);
+        FREE_SYMBOL(get_info);
+        FREE_SYMBOL(free_mark);
+        FREE_SYMBOL(get_gl);
+        FREE_SYMBOL(getSize_2);
+        FREE_SYMBOL(initData_2);
+        FREE_SYMBOL(freeData_2);
+        FREE_SYMBOL(infix_func);
+        printf("func8(%p)\n", obj);
+    }
+
     printf("\n");
 
     {
@@ -1009,6 +1063,47 @@ int main() {
         printf("\n");
     }
 
+    {  // 中缀调用测试
+        printf("TAG S:\n");
+
+        af_Code *bt2 = makeVariableCode("func8", 0, 1, NULL);
+        af_Code *bt1 = makeBlockCode(brackets, bt2, 0, 1, NULL, NULL);
+        af_Code *bt3 = makeVariableCode("global", 0, 1, NULL);
+
+        connectCode(&bt1, bt3);
+
+        iterCode(bt1, env);
+        freeAllCode(bt1);
+        printf("\n");
+    }
+
+    {  // 中缀调用测试
+        printf("TAG T: ERROR\n");
+
+        af_Code *bt2 = makeVariableCode("func", 0, 1, NULL);
+        af_Code *bt1 = makeBlockCode(brackets, bt2, 0, 1, NULL, NULL);
+        af_Code *bt3 = makeVariableCode("global", 0, 1, NULL);
+
+        connectCode(&bt1, bt3);
+
+        iterCode(bt1, env);
+        freeAllCode(bt1);
+        printf("\n");
+    }
+
+    {  // 中缀保护测试
+        printf("TAG U: ERROR\n");
+
+        af_Code *bt2 = makeVariableCode("func8", 0, 1, NULL);
+        af_Code *bt1 = makeVariableCode("global", 0, 1, NULL);
+
+        connectCode(&bt1, bt2);
+
+        iterCode(bt1, env);
+        freeAllCode(bt1);
+        printf("\n");
+    }
+
     printf("freeEnvironment:\n");
     freeEnvironment(env);
     return 0;