浏览代码

feat: 允许设定C函数参数的类型

link #9
SongZihuan 4 年之前
父节点
当前提交
9809010c05
共有 4 个文件被更改,包括 168 次插入79 次删除
  1. 1 0
      VirtulMathCore/include/parameter.h
  2. 10 10
      VirtulMathCore/include/value.h
  3. 46 2
      VirtulMathCore/src/parameter.c
  4. 111 67
      VirtulMathCore/src/runcall.c

+ 1 - 0
VirtulMathCore/include/parameter.h

@@ -123,6 +123,7 @@ void setArgumentFFI(ArgumentFFI *af, unsigned int size);
 void freeArgumentFFI(ArgumentFFI *af);
 void freeArgumentFFI(ArgumentFFI *af);
 
 
 unsigned int checkArgument(Argument *arg, enum ArgumentType type);
 unsigned int checkArgument(Argument *arg, enum ArgumentType type);
+bool listToArgumentFFI(ArgumentFFI *af, LinkValue **list, vint size);
 bool setArgumentToFFI(ArgumentFFI *af, Argument *arg);
 bool setArgumentToFFI(ArgumentFFI *af, Argument *arg);
 ffi_type *getFFIType(wchar_t *str, enum ArgumentFFIType *aft);
 ffi_type *getFFIType(wchar_t *str, enum ArgumentFFIType *aft);
 #endif //VIRTUALMATH_PARAMETER_H
 #endif //VIRTUALMATH_PARAMETER_H

+ 10 - 10
VirtulMathCore/include/value.h

@@ -3,16 +3,16 @@
 #include "__macro.h"
 #include "__macro.h"
 
 
 // 标准错误信息定义
 // 标准错误信息定义
-#define INSTANCE_ERROR(class) L"Instance error when calling func, call non-" L###class L" " L###class L" method"
-#define VALUE_ERROR(value, acc) L###value L" value is not a " L###acc L" (may be modified by an external program)"
-#define ONLY_ACC(var, value) L###var L" only accepts " L###value
-#define ERROR_INIT(class) L###class L" get wrong initialization parameters"
-#define MANY_ARG L"Too many parameters"
-#define FEW_ARG L"Too few parameters"
-#define CUL_ERROR(opt) L###opt L" operation gets incorrect value"
-#define OBJ_NOTSUPPORT(opt) L"Object does not support " L###opt L" operation"
-#define RETURN_ERROR(func, type) L###func L" func should return " L###type L" type data"
-#define KEY_INTERRUPT L"KeyInterrupt"
+#define INSTANCE_ERROR(class)  (wchar_t *) L"Instance error when calling func, call non-" L###class L" " L###class L" method"
+#define VALUE_ERROR(value, acc) (wchar_t *) L###value L" value is not a " L###acc L" (may be modified by an external program)"
+#define ONLY_ACC(var, value) (wchar_t *) L###var L" only accepts " L###value
+#define ERROR_INIT(class) (wchar_t *) L###class L" get wrong initialization parameters"
+#define MANY_ARG (wchar_t *) L"Too many parameters"
+#define FEW_ARG (wchar_t *) L"Too few parameters"
+#define CUL_ERROR(opt) (wchar_t *) L###opt L" operation gets incorrect value"
+#define OBJ_NOTSUPPORT(opt) (wchar_t *) L"Object does not support " L###opt L" operation"
+#define RETURN_ERROR(func, type) (wchar_t *) L###func L" func should return " L###type L" type data"
+#define KEY_INTERRUPT (wchar_t *) L"KeyInterrupt"
 
 
 typedef struct Argument Argument;
 typedef struct Argument Argument;
 typedef struct Inter Inter;
 typedef struct Inter Inter;

+ 46 - 2
VirtulMathCore/src/parameter.c

@@ -907,6 +907,20 @@ unsigned int checkArgument(Argument *arg, enum ArgumentType type) {
     return count;
     return count;
 }
 }
 
 
+bool listToArgumentFFI(ArgumentFFI *af, LinkValue **list, vint size) {
+    if (size > af->size)
+        return false;
+    for (int i=0; i < size; i ++) {
+        LinkValue *str = list[i];
+        if (str->value->type != V_str)
+            return false;
+        af->arg[i] = getFFIType(str->value->data.str.str, af->type + i);
+        if (af->arg[i] == NULL || af->type[i] == af_void)
+            return false;
+    }
+    return true;
+}
+
 bool setArgumentToFFI(ArgumentFFI *af, Argument *arg) {
 bool setArgumentToFFI(ArgumentFFI *af, Argument *arg) {
     for (unsigned int i=0; arg != NULL && i < af->size; arg = arg->next, i++) {
     for (unsigned int i=0; arg != NULL && i < af->size; arg = arg->next, i++) {
         if (af->arg[i] == NULL) {
         if (af->arg[i] == NULL) {
@@ -935,8 +949,38 @@ bool setArgumentToFFI(ArgumentFFI *af, Argument *arg) {
                 default:
                 default:
                     return false;
                     return false;
             }
             }
-        } else
-            return false;
+        } else {
+            switch (af->type[i]) {
+                case af_int:
+                    af->arg_v[i] = (int *)memCalloc(1, sizeof(int));  // af->arg_v是ffi_type **arg_v, 即 *arg_v[]
+                    switch (arg->data.value->value->type) {
+                       case V_int:
+                           *(int *)(af->arg_v[i]) = (int)arg->data.value->value->data.int_.num;
+                           break;
+                       case V_dou:
+                           *(int *)(af->arg_v[i]) = (int)arg->data.value->value->data.dou.num;
+                           break;
+                       default:
+                           return false;
+                   }
+                   break;
+                case af_double:
+                    af->arg_v[i] = (double *)memCalloc(1, sizeof(double));  // af->arg_v是ffi_type **arg_v, 即 *arg_v[]
+                    switch (arg->data.value->value->type) {
+                        case V_int:
+                            *(double *)(af->arg_v[i]) = (double)arg->data.value->value->data.int_.num;
+                            break;
+                        case V_dou:
+                            *(double *)(af->arg_v[i]) = (double)arg->data.value->value->data.dou.num;
+                            break;
+                        default:
+                            return false;
+                    }
+                    break;
+                default:
+                    return false;
+            }
+        }
     }
     }
     return arg == NULL ? true : false;
     return arg == NULL ? true : false;
 }
 }

+ 111 - 67
VirtulMathCore/src/runcall.c

@@ -258,93 +258,137 @@ static ResultType callCFunction(LinkValue *function_value, Argument *arg, long i
     return result->type;
     return result->type;
 }
 }
 
 
+static bool makeFFIReturn(enum ArgumentFFIType af, void **re_v) {
+    switch (af) {
+        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:
+            *re_v = NULL;
+            break;
+        default:
+            return false;
+    }
+    return true;
+}
+
+static bool FFIReturnValue(enum ArgumentFFIType aft, void *re_v, fline line, char *file, FUNC_NT) {
+    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:
+            setResultError(E_ArgumentException, (wchar_t *) L"no-support return type for C function", line, file, true, CNEXT_NT);
+            return false;
+    }
+    return true;
+}
+
+static ffi_type *getRearg(LinkValue *function_value, enum ArgumentFFIType *aft, fline line, char *file, FUNC_NT) {
+    ffi_type *re;
+    LinkValue *re_var = findAttributes(L"rearg", false, line, file, true, CFUNC_NT(var_list, result, function_value));
+    if (!CHECK_RESULT(result))
+        return NULL;
+    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 NULL;
+        }
+        re = getFFIType(re_var->value->data.str.str, aft);
+        if (re == NULL) {
+            setResultError(E_ArgumentException, (wchar_t *) L"no-support argument type for C function", line, file, true, CNEXT_NT);
+            return NULL;
+        }
+    } else
+        re = &ffi_type_void;
+    return re;
+}
+
+static ResultType getFuncargs(LinkValue *function_value, ArgumentFFI *af, fline line, char *file, FUNC_NT) {
+    LinkValue *arg_var = NULL;
+    setResultCore(result);
+
+    arg_var = findAttributes(L"funcargs", false, line, file, true, CFUNC_NT(var_list, result, function_value));
+    if (!CHECK_RESULT(result))
+        return result->type;
+    freeResult(result);
+
+    if (arg_var != NULL) {
+        if (arg_var->value->type != V_list) {
+            setResultError(E_TypeException, ONLY_ACC(funcargs, list), line, file, true, CNEXT_NT);
+            return R_error;
+        }
+        if (!listToArgumentFFI(af, arg_var->value->data.list.list, arg_var->value->data.list.size)) {
+            setResultError(E_ArgumentException, (wchar_t *) L"no-support argument type for C function", line, file, true, CNEXT_NT);
+            return R_error;
+        }
+    }
+    return result->type;
+}
+
 static ResultType callFFunction(LinkValue *function_value, Argument *arg, long int line, char *file, int pt_sep, FUNC_NT){
 static ResultType callFFunction(LinkValue *function_value, Argument *arg, long int line, char *file, int pt_sep, FUNC_NT){
     ffi_cif cif;
     ffi_cif cif;
     ffi_type *re;
     ffi_type *re;
     unsigned int size;
     unsigned int size;
     ArgumentFFI af;
     ArgumentFFI af;
     enum ArgumentFFIType aft = af_void;
     enum ArgumentFFIType aft = af_void;
+    void *re_v = NULL;  // 存放返回值的函數
+
     setResultCore(result);
     setResultCore(result);
     setArgumentFFICore(&af);
     setArgumentFFICore(&af);
     if (pt_sep != 0 || (size = checkArgument(arg, value_arg)) == -1) {
     if (pt_sep != 0 || (size = checkArgument(arg, value_arg)) == -1) {
-        setResultError(E_ArgumentException, L"does not support key-value arguments", line, file, true, CNEXT_NT);
+        setResultError(E_ArgumentException, (wchar_t *) L"does not support key-value arguments", line, file, true, CNEXT_NT);
         return R_error;
         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;
-    }
+    re = getRearg(function_value, &aft, line, file, CNEXT_NT);
+    if (!CHECK_RESULT(result))
+        return result->type;
 
 
     setArgumentFFI(&af, size);
     setArgumentFFI(&af, size);
+    getFuncargs(function_value, &af, line, file, CNEXT_NT);
+    if (!CHECK_RESULT(result))
+        goto return_;
+
     if (!setArgumentToFFI(&af, arg)) {
     if (!setArgumentToFFI(&af, arg)) {
-        setResultError(E_ArgumentException, L"parameter exception when calling C function", line, file, true, CNEXT_NT);
+        setResultError(E_ArgumentException, (wchar_t *) L"parameter exception when calling C function", line, file, true, CNEXT_NT);
         goto return_;
         goto return_;
     }
     }
 
 
     ffi_prep_cif(&cif, FFI_DEFAULT_ABI, af.size, re, af.arg);
     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;
-        }
+    if (makeFFIReturn(aft, &re_v)) {
+        ffi_call(&cif, function_value->value->data.function.ffunc, re_v, af.arg_v);
+        FFIReturnValue(aft, re_v, line, file, CNEXT_NT);
         memFree(re_v);
         memFree(re_v);
-    }
+    } else
+        setResultError(E_ArgumentException, (wchar_t *) L"no-support return type for C function", line, file, true, CNEXT_NT);
 
 
     return_:
     return_:
     freeArgumentFFI(&af);
     freeArgumentFFI(&af);