Explorar o código

feat: 调用C函数允许返回值

link #9
SongZihuan %!s(int64=4) %!d(string=hai) anos
pai
achega
3617668f25

+ 1 - 1
VirtulMathCore/include/mem.h

@@ -22,7 +22,7 @@ wchar_t *memStrToWcs(char *str, bool free_old);
 
 #define memFree(p) ((p)=((p) != NULL ? (free((p)), NULL) : NULL))
 #define eqString(str1, str2) (!strcmp((str1), (str2)))
-#define eqWide(wid1, wid2) (!wcscmp((wid1), (wid2)))
+#define eqWide(wid1, wid2) (!wcscmp((wchar_t *)(wid1), (wchar_t *)(wid2)))
 #define memString(size) (char *)memCalloc((size) + 1, sizeof(char))
 #define memWide(size) (wchar_t *)memCalloc((size) + 1, sizeof(wchar_t))
 #define memStrlen(p) (((p) == NULL) ? 0 :strlen((p)))

+ 3 - 0
VirtulMathCore/include/parameter.h

@@ -60,6 +60,8 @@ struct ArgumentFFI {
         af_int,
         af_double,
         af_str,
+        af_char,
+        af_void,
     } *type;  // 数据类型 (决定如何释放arg_v)
     unsigned int size;  // 数组长度
 };
@@ -122,4 +124,5 @@ void freeArgumentFFI(ArgumentFFI *af);
 
 unsigned int checkArgument(Argument *arg, enum ArgumentType type);
 bool setArgumentToFFI(ArgumentFFI *af, Argument *arg);
+ffi_type *getFFIType(wchar_t *str, enum ArgumentFFIType *aft);
 #endif //VIRTUALMATH_PARAMETER_H

+ 41 - 1
VirtulMathCore/src/parameter.c

@@ -883,6 +883,11 @@ void freeArgumentFFI(ArgumentFFI *af) {
             case af_int:
                 memFree(af->arg_v[i]);
                 break;
+            case af_str:
+                if (af->arg_v[i] != NULL)
+                    memFree(*(char **)af->arg_v[i]);
+                memFree(af->arg_v[i]);
+                break;
             default:
                 break;
         }
@@ -913,6 +918,20 @@ bool setArgumentToFFI(ArgumentFFI *af, Argument *arg) {
                     af->arg_v[i] = (int *)memCalloc(1, sizeof(int));  // af->arg_v是ffi_type **arg_v, 即 *arg_v[]
                     *(int *)(af->arg_v[i]) = (int)arg->data.value->value->data.int_.num;
                     break;
+                case V_dou:
+                    af->arg[i] = &ffi_type_double;  // af->arg是ffi_type **arg, 即*arg[]
+                    af->type[i] = af_double;
+
+                    af->arg_v[i] = (double *)memCalloc(1, sizeof(double));  // af->arg_v是ffi_type **arg_v, 即 *arg_v[]
+                    *(double *)(af->arg_v[i]) = (double)arg->data.value->value->data.dou.num;
+                    break;
+                case V_str:
+                    af->arg[i] = &ffi_type_pointer;  // af->arg是ffi_type **arg, 即*arg[]
+                    af->type[i] = af_str;
+
+                    af->arg_v[i] = (char **)memCalloc(1, sizeof(char **));  // af->arg_v是ffi_type **arg_v, 即 *arg_v[]
+                    *(char **)(af->arg_v[i]) = (char *)memWcsToStr(arg->data.value->value->data.str.str, false);
+                    break;
                 default:
                     return false;
             }
@@ -920,4 +939,25 @@ bool setArgumentToFFI(ArgumentFFI *af, Argument *arg) {
             return false;
     }
     return arg == NULL ? true : false;
-}
+}
+
+ffi_type *getFFIType(wchar_t *str, enum ArgumentFFIType *aft) {
+    ffi_type *return_ = NULL;
+    if (eqWide(str, L"int")) {
+        return_ = &ffi_type_sint;
+        *aft = af_int;
+    } else if (eqWide(str, L"dou")) {
+        return_ = &ffi_type_double;
+        *aft = af_double;
+    } else if (eqWide(str, L"str")) {
+        return_ = &ffi_type_pointer;
+        *aft = af_str;
+    } else if (eqWide(str, L"void")) {
+        return_ = &ffi_type_void;
+        *aft = af_void;
+    } else if (eqWide(str, L"char")) {
+        return_ = &ffi_type_schar;
+        *aft = af_char;
+    }
+    return return_;
+}

+ 70 - 6
VirtulMathCore/src/runcall.c

@@ -260,8 +260,10 @@ static ResultType callCFunction(LinkValue *function_value, Argument *arg, long i
 
 static ResultType callFFunction(LinkValue *function_value, Argument *arg, long int line, char *file, int pt_sep, FUNC_NT){
     ffi_cif cif;
+    ffi_type *re;
     unsigned int size;
     ArgumentFFI af;
+    enum ArgumentFFIType aft = af_void;
     setResultCore(result);
     setArgumentFFICore(&af);
     if (pt_sep != 0 || (size = checkArgument(arg, value_arg)) == -1) {
@@ -269,18 +271,80 @@ static ResultType callFFunction(LinkValue *function_value, Argument *arg, long i
         return R_error;
     }
 
+    {
+        LinkValue *re_var = findAttributes(L"rearg", false, line, file, true, CFUNC_NT(var_list, result, function_value));
+        if (!CHECK_RESULT(result))
+            return result->type;
+        freeResult(result);
+        if (re_var != NULL) {
+            if (re_var->value->type != V_str) {
+                setResultError(E_TypeException, ONLY_ACC(rearg, str), line, file, true, CNEXT_NT);
+                return R_error;
+            }
+            re = getFFIType(re_var->value->data.str.str, &aft);
+            if (re == NULL) {
+                setResultError(E_ArgumentException, L"no-support argument type for C function", line, file, true, CNEXT_NT);
+                return R_error;
+            }
+        } else
+            re = &ffi_type_void;
+    }
+
     setArgumentFFI(&af, size);
     if (!setArgumentToFFI(&af, arg)) {
         setResultError(E_ArgumentException, L"parameter exception when calling C function", line, file, true, CNEXT_NT);
         goto return_;
     }
 
-    gc_addTmpLink(&function_value->gc_status);
-    ffi_prep_cif(&cif, FFI_DEFAULT_ABI, af.size, &ffi_type_void, af.arg);
-    ffi_call(&cif, function_value->value->data.function.ffunc,  NULL, af.arg_v);
-    gc_freeTmpLink(&function_value->gc_status);
-
-    setResult(result, inter);
+    ffi_prep_cif(&cif, FFI_DEFAULT_ABI, af.size, re, af.arg);
+    {
+        void *re_v = NULL;  // 存放返回值的函數
+        switch (aft) {
+            case af_int:
+                re_v = memCalloc(1, sizeof(int));
+                break;
+            case af_double:
+                re_v = memCalloc(1, sizeof(double));
+                break;
+            case af_str:
+                re_v = memCalloc(1, sizeof(char *));
+                break;
+            case af_char:
+                re_v = memCalloc(1, sizeof(char));
+                break;
+            case af_void:
+                break;
+            default:
+                setResultError(E_ArgumentException, L"no-support return type for C function", line, file, true, CNEXT_NT);
+                goto return_;
+        }
+        ffi_call(&cif, function_value->value->data.function.ffunc,  re_v, af.arg_v);
+        switch (aft) {  // 应用返回值函数
+            case af_int:
+                makeIntValue(*(int *)re_v, line, file, CNEXT_NT);
+                break;
+            case af_double:
+                makeDouValue(*(double *)re_v, line, file, CNEXT_NT);
+                break;
+            case af_str: {
+                wchar_t *tmp = memStrToWcs(re_v, false);
+                makeStringValue(tmp, line, file, CNEXT_NT);
+                memFree(tmp);
+                break;
+            }
+            case af_char: {
+                wchar_t tmp[] = {(wchar_t)(*(char *)re_v), (wchar_t)NUL};
+                makeStringValue(tmp, line, file, CNEXT_NT);
+                break;
+            }
+            case af_void:
+                setResult(result, inter);
+                break;
+            default:
+                break;
+        }
+        memFree(re_v);
+    }
 
     return_:
     freeArgumentFFI(&af);