ソースを参照

feat: C函数允许使用可变参数, 函数添加set方法

可变参数带有类型提升功能
可变参数调用ffi的ffi_call_cif_var函数

函数添加set方法设置可变参数
set方法返回函数本身

link #9
SongZihuan 4 年 前
コミット
d3a3f9e387

+ 3 - 1
VirtulMathCore/include/parameter.h

@@ -78,6 +78,7 @@ struct ArgumentFFI {
         af_pointer,
     } *type;  // 数据类型 (决定如何释放arg_v)
     unsigned int size;  // 数组长度
+    unsigned int b_va;  // 非可变参数的个数
 };
 
 typedef struct Parameter Parameter;
@@ -137,7 +138,8 @@ void setArgumentFFI(ArgumentFFI *af, unsigned int size);
 void freeArgumentFFI(ArgumentFFI *af);
 
 unsigned int checkArgument(Argument *arg, enum ArgumentType type);
-bool listToArgumentFFI(ArgumentFFI *af, LinkValue **list, vint size);
+bool listToArgumentFFI(ArgumentFFI *af, LinkValue **list, vint size, LinkValue **valist, vint vasize);
 bool setArgumentToFFI(ArgumentFFI *af, Argument *arg);
 ffi_type *getFFIType(wchar_t *str, enum ArgumentFFIType *aft);
+ffi_type *getFFITypeUp(wchar_t *str, enum ArgumentFFIType *aft);
 #endif //VIRTUALMATH_PARAMETER_H

+ 38 - 3
VirtulMathCore/ofunc/src/function.c

@@ -47,8 +47,7 @@ ResultType function_init(O_FUNC){
         return result->type;
     freeResult(result);
     if ((func = ap[0].value)->value->type != V_func) {
-        setResultError(E_TypeException, INSTANCE_ERROR(func), LINEFILE, true,
-                       CNEXT_NT);
+        setResultError(E_TypeException, INSTANCE_ERROR(func), LINEFILE, true, CNEXT_NT);
         return R_error;
     }
 
@@ -63,9 +62,45 @@ ResultType function_init(O_FUNC){
     return result->type;
 }
 
+ResultType function_set(O_FUNC){  // 针对FFI设置vaargs
+    ArgumentParser ap[] = {{.type=only_value, .must=1, .long_arg=false},
+                           {.type=only_value, .must=0, .long_arg=true},
+                           {.must=-1}};
+    LinkValue *func;
+    setResultCore(result);
+    parserArgumentUnion(ap, arg, CNEXT_NT);
+    if (!CHECK_RESULT(result))
+        return result->type;
+    freeResult(result);
+    if ((func = ap[0].value)->value->type != V_func || (func = ap[0].value)->value->data.function.type != f_func) {
+        setResultError(E_TypeException, INSTANCE_ERROR(func), LINEFILE, true, CNEXT_NT);
+        return R_error;
+    }
+
+    if (ap[1].arg != NULL) {
+        LinkValue *list;
+        makeListValue(ap[1].arg, LINEFILE, L_tuple, CNEXT_NT);
+        if (!CHECK_RESULT(result))
+            return result->type;
+        list = result->value;
+        result->value = NULL;
+        freeResult(result);
+
+        addAttributes(L"vaargs", false, list, LINEFILE, true, CFUNC_NT(var_list, result, func));
+        gc_freeTmpLink(&list->gc_status);
+    }
+    else
+        findFromVarList(L"vaargs", 0, del_var, CFUNC_CORE(var_list));
+
+    if (CHECK_RESULT(result))
+        setResultOperation(result, func);
+    return result->type;
+}
+
 void registeredFunction(R_FUNC){
     LinkValue *object = inter->data.function;
-    NameFunc tmp[] = {{NULL, NULL}};
+    NameFunc tmp[] = {{L"set", function_set, object_free_},
+                      {NULL, NULL}};
     gc_addTmpLink(&object->gc_status);
     addBaseClassVar(L"func", object, belong, inter);
     iterBaseClassFunc(tmp, object, CFUNC_CORE(inter->var_list));

+ 57 - 5
VirtulMathCore/src/parameter.c

@@ -864,6 +864,7 @@ void setArgumentFFICore(ArgumentFFI *af) {
     af->arg = NULL;
     af->arg_v = NULL;
     af->size = 0;
+    af->b_va = 0;
 }
 
 void setArgumentFFI(ArgumentFFI *af, unsigned int size) {
@@ -871,6 +872,7 @@ void setArgumentFFI(ArgumentFFI *af, unsigned int size) {
     af->arg = memCalloc((size_t)size, sizeof(ffi_type *));
     af->arg_v = memCalloc((size_t)size, sizeof(void *));
     af->size = size;
+    af->b_va = size;
     memset(af->type, 0, (size_t)size);
     memset(af->arg, 0, (size_t)size);
     memset(af->arg_v, 0, (size_t)size);
@@ -907,10 +909,12 @@ unsigned int checkArgument(Argument *arg, enum ArgumentType type) {
     return count;
 }
 
-bool listToArgumentFFI(ArgumentFFI *af, LinkValue **list, vint size) {
-    if (size > af->size)
+bool listToArgumentFFI(ArgumentFFI *af, LinkValue **list, vint size, LinkValue **valist, vint vasize) {
+    int i=0;
+    if ((size + vasize) != af->size)
         return false;
-    for (int i=0; i < size; i ++) {
+
+    for (PASS; i < size; i++) {
         LinkValue *str = list[i];
         if (str->value->type != V_str)
             return false;
@@ -918,6 +922,15 @@ bool listToArgumentFFI(ArgumentFFI *af, LinkValue **list, vint size) {
         if (af->arg[i] == NULL || af->type[i] == af_void)
             return false;
     }
+
+    for (PASS; i < af->size; i++) {  // 处理可变参数
+        LinkValue *str = valist[i - size];
+        if (str->value->type != V_str)
+            return false;
+        af->arg[i] = getFFITypeUp(str->value->data.str.str, af->type + i);
+        if (af->arg[i] == NULL || af->type[i] == af_void)
+            return false;
+    }
     return true;
 }
 
@@ -1051,7 +1064,7 @@ bool setArgumentToFFI(ArgumentFFI *af, Argument *arg) {
     return arg == NULL;  // 若arg还没迭代完, 则证明有问题
 }
 
-ffi_type *getFFIType(wchar_t *str, enum ArgumentFFIType *aft) {\
+ffi_type *getFFIType(wchar_t *str, enum ArgumentFFIType *aft) {
     ffi_type *return_ = NULL;
     if (eqWide(str, L"int")) {
         return_ = &ffi_type_sint32;
@@ -1087,7 +1100,10 @@ ffi_type *getFFIType(wchar_t *str, enum ArgumentFFIType *aft) {\
         return_ = &ffi_type_pointer;
         *aft = af_wstr;
     } else if (eqWide(str, L"char")) {
-        return_ = &ffi_type_schar;
+        return_ = &ffi_type_sint8;
+        *aft = af_char;
+    } else if (eqWide(str, L"uchar")) {
+        return_ = &ffi_type_uint8;
         *aft = af_char;
     } else if (eqWide(str, L"void")) {
         return_ = &ffi_type_void;
@@ -1098,3 +1114,39 @@ ffi_type *getFFIType(wchar_t *str, enum ArgumentFFIType *aft) {\
     }
     return return_;
 }
+
+ffi_type *getFFITypeUp(wchar_t *str, enum ArgumentFFIType *aft) {
+    ffi_type *return_ = NULL;
+    if (eqWide(str, L"int") || eqWide(str, L"sint") || eqWide(str, L"char")) {
+        return_ = &ffi_type_sint32;
+        *aft = af_int;
+    } else if (eqWide(str, L"uint") || eqWide(str, L"usint") || eqWide(str, L"uchar")) {
+        return_ = &ffi_type_uint32;
+        *aft = af_uint;
+    } else if (eqWide(str, L"lint")) {
+        return_ = &ffi_type_sint64;
+        *aft = af_lint;
+    } else if (eqWide(str, L"ulint")) {
+        return_ = &ffi_type_uint64;
+        *aft = af_ulint;
+    } else if (eqWide(str, L"float") || eqWide(str, L"double")) {
+        return_ = &ffi_type_double;
+        *aft = af_double;
+    } else if (eqWide(str, L"ldouble")) {
+        return_ = &ffi_type_longdouble;
+        *aft = af_ldouble;
+    } else if (eqWide(str, L"str")) {
+        return_ = &ffi_type_pointer;
+        *aft = af_str;
+    } else if (eqWide(str, L"wstr")) {
+        return_ = &ffi_type_pointer;
+        *aft = af_wstr;
+    } else if (eqWide(str, L"void")) {
+        return_ = &ffi_type_void;
+        *aft = af_void;
+    } else if (eqWide(str, L"pointer")) {
+        return_ = &ffi_type_pointer;
+        *aft = af_pointer;
+    }
+    return return_;
+}

+ 19 - 4
VirtulMathCore/src/runcall.c

@@ -381,6 +381,7 @@ static ffi_type *getRearg(LinkValue *function_value, enum ArgumentFFIType *aft,
 
 static ResultType getFuncargs(LinkValue *function_value, ArgumentFFI *af, fline line, char *file, FUNC_NT) {
     LinkValue *arg_var = NULL;
+    LinkValue *vaarg_var = NULL;
     setResultCore(result);
 
     arg_var = findAttributes(L"funcargs", false, line, file, true, CFUNC_NT(var_list, result, function_value));
@@ -388,12 +389,22 @@ static ResultType getFuncargs(LinkValue *function_value, ArgumentFFI *af, fline
         return result->type;
     freeResult(result);
 
+    vaarg_var = findAttributes(L"vaargs", 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);
+        LinkValue **valist = vaarg_var != NULL ? vaarg_var->value->data.list.list : NULL;
+        vint vasize = vaarg_var != NULL ? vaarg_var->value->data.list.size : 0;
+        af->b_va = arg_var->value->data.list.size;
+
+        if (arg_var->value->type != V_list || vaarg_var != NULL && vaarg_var->value->type != V_list) {
+            setResultError(E_TypeException, ONLY_ACC(funcargs / vaarg_var, list), line, file, true, CNEXT_NT);
             return R_error;
         }
-        if (!listToArgumentFFI(af, arg_var->value->data.list.list, arg_var->value->data.list.size)) {
+
+        if (!listToArgumentFFI(af, arg_var->value->data.list.list, arg_var->value->data.list.size, valist, vasize)) {
             setResultError(E_ArgumentException, (wchar_t *) L"no-support argument type for C function", line, file, true, CNEXT_NT);
             return R_error;
         }
@@ -430,7 +441,11 @@ static ResultType callFFunction(LinkValue *function_value, Argument *arg, long i
         goto return_;
     }
 
-    ffi_prep_cif(&cif, FFI_DEFAULT_ABI, af.size, re, af.arg);
+    if (af.size == af.b_va)
+        ffi_prep_cif(&cif, FFI_DEFAULT_ABI, af.size, re, af.arg);
+    else
+        ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, af.b_va, af.size, re, af.arg);
+
     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);

+ 0 - 1
VirtulMathCore/src/runoperation.c

@@ -469,7 +469,6 @@ ResultType getVar(FUNC, VarInfo var_info) {
             LinkValue *_attr_;
             setResultCore(&tmp);
             addAttributes(L"val", false, val, st->line, st->code_file, true, CFUNC_NT(var_list, &tmp, result->value));
-            printf("val = %ls\n", val->value->data.str.str);
             if (!RUN_TYPE(tmp.type)) {
                 freeResult(result);
                 *result = tmp;