Bläddra i källkod

feat: 函数参数支持双星号表达式

字典支持使用双星号表达式
函数形参支持双星号表达式结尾
函数实参支持双星号表达式
SongZihuan 4 år sedan
förälder
incheckning
720a3aa25f
10 ändrade filer med 161 tillägg och 43 borttagningar
  1. 15 2
      include/parameter.h
  2. 1 1
      include/value.h
  3. 1 0
      include/var.h
  4. 0 1
      main.c
  5. 24 5
      parser/grammar.c
  6. 1 1
      src/__run.c
  7. 2 2
      src/operation.c
  8. 106 21
      src/parameter.c
  9. 2 2
      src/run.c
  10. 9 8
      src/value.c

+ 15 - 2
include/parameter.h

@@ -7,6 +7,7 @@ struct Parameter{
         value_par,
         name_par,
         args_par,
+        kwargs_par,
     } type;
     struct ParameterData{
         struct Statement *value;
@@ -20,9 +21,14 @@ struct Argument{
         value_arg,
         name_arg,
     } type;
+    enum ArgumentNameType{
+        name_st,
+        name_char,
+    } name_type;
     struct ArgumentData{
         struct LinkValue *value;
         struct Statement *name;  // 仅在name-value模式生效
+        char *name_;
     } data;
     struct Argument *next;
 };
@@ -33,21 +39,27 @@ typedef struct Argument Argument;
 Argument *makeArgument();
 Argument *makeOnlyValueArgument(LinkValue *value);
 Argument *makeNameValueArgument(LinkValue *value, struct Statement *name);
+Argument *makeCharNameArgument(LinkValue *value, char *name);
 Argument *connectArgument(Argument *new, Argument *base);
 Argument *connectOnlyValueArgument(LinkValue *value, Argument *base);
 Argument *connectNameValueArgument(LinkValue *value, struct Statement *name, Argument *base);
-void freeArgument(Argument *pt, bool free_st);
+Argument *connectCharNameArgument(LinkValue *value, char *name, Argument *base);
+void freeArgument(Argument *at, bool free_st);
 
 Parameter *makeParameter();
 Parameter *copyParameter(Parameter *base);
 Parameter *makeOnlyValueParameter(struct Statement *st);
 Parameter *makeNameValueParameter(struct Statement *value, struct Statement *name);
 Parameter *makeOnlyArgsParameter(struct Statement *st);
+Parameter *makeNameArgsParameter(struct Statement *st);
 Parameter *connectParameter(Parameter *new, Parameter *base);
 Parameter *connectOnlyValueParameter(struct Statement *st, Parameter *base);
 Parameter *connectNameValueParameter(struct Statement *value, struct Statement *name, Parameter *base);
 Parameter *connectOnlyArgsParameter(struct Statement *st, Parameter *base);
+Parameter *connectNameArgsParameter(struct Statement *st, Parameter *base);
 void freeParameter(Parameter *pt, bool free_st);
+Argument *listToArgument(LinkValue *list_value, INTER_FUNCTIONSIG_CORE);
+Argument *dictToArgument(LinkValue *dict_value, INTER_FUNCTIONSIG_CORE);
 
 Result setParameterCore(Argument *call, Parameter *function_base, VarList *function_var, INTER_FUNCTIONSIG_CORE);
 Result setParameter(Parameter *call, Parameter *function, VarList *function_var, INTER_FUNCTIONSIG_CORE);
@@ -56,6 +68,7 @@ Argument *getArgument(Parameter *call, Result *result, INTER_FUNCTIONSIG_CORE);
 
 Result defaultParameter(Parameter **function_ad, Inter *inter, VarList *var_list, int *num);
 Result argumentToVar(Argument **call_ad, struct Inter *inter, struct VarList *var_list, NUMBER_TYPE *num);
-Result parameterFromVar(Parameter **function_ad, VarList *function_var, INTER_FUNCTIONSIG_CORE, NUMBER_TYPE *num);
+Result parameterFromVar(Parameter **function_ad, VarList *function_var, struct Inter *inter, struct VarList *var_list,
+                        NUMBER_TYPE *num, NUMBER_TYPE max, bool *status);
 Result argumentToParameter(Argument **call_ad, Parameter **function_ad, VarList *function_var, INTER_FUNCTIONSIG_CORE);
 #endif //VIRTUALMATH_PARAMETER_H

+ 1 - 1
include/value.h

@@ -76,7 +76,7 @@ Value *makeNumberValue(long num, Inter *inter);
 Value *makeStringValue(char *str, Inter *inter);
 Value *makeFunctionValue(struct Statement *st, struct Parameter *pt, struct VarList *var_list, Inter *inter);
 Value *makeListValue(struct Argument **arg_ad, Inter *inter, enum ListType type);
-Value *makeDictValue(struct Argument **arg_ad, Inter *inter);
+Value *makeDictValue(struct Argument **arg_ad, bool new_hash, Inter *inter);
 
 void setResult(Result *ru, bool link, Inter *inter);
 void setResultError(Result *ru, Inter *inter);

+ 1 - 0
include/var.h

@@ -3,6 +3,7 @@
 
 #define MAX_SIZE (1024)
 #define VARSTR_PREFIX "str_"
+#define VARNUM_PREFIX "num_"
 #define VARDEFAULT_PREFIX "default_var"
 
 struct Var{

+ 0 - 1
main.c

@@ -119,7 +119,6 @@ void freeArgs(){
 
 /**
  *  TODO-szh 函数形式参数复制
- *  TODO-szh 字典
  *  TODO-szh 运行错误的内存释放检查
  *  TODO-szh syntax错误的内存释放检查
  */

+ 24 - 5
parser/grammar.c

@@ -447,6 +447,7 @@ bool parserParameter(ParserMessage *pm, Inter *inter, Parameter **pt, bool is_fo
         s_1,  // only_value模式
         s_2,  // name_value模式
         s_3,  // only_args模式
+        s_4,  // name_args模式
     } status;
 
     if (is_dict)
@@ -458,6 +459,9 @@ bool parserParameter(ParserMessage *pm, Inter *inter, Parameter **pt, bool is_fo
         tmp = NULL;
         if (!is_dict && status != s_2 && checkToken_(pm, MATHER_MUL))  // is_formal关闭对*args的支持
             status = s_3;
+        else if (!is_list && checkToken_(pm, MATHER_POW))  // is_formal关闭对*args的支持
+            status = s_4;
+
         parserPolynomial(CALLPASERSSIGNATURE);
         if (!call_success(pm))
             goto error_;
@@ -491,6 +495,11 @@ bool parserParameter(ParserMessage *pm, Inter *inter, Parameter **pt, bool is_fo
             if (!checkToken_(pm, sep))
                 last_pt = true;
         }
+        else if (status == s_4){
+            pt_type = kwargs_par;
+            if (!checkToken_(pm, sep))
+                last_pt = true;
+        }
 
         if (pt_type == value_par)
             new_pt = connectOnlyValueParameter(tmp->data.st, new_pt);
@@ -509,6 +518,13 @@ bool parserParameter(ParserMessage *pm, Inter *inter, Parameter **pt, bool is_fo
             else
                 status = s_1;
         }
+        else if (pt_type == kwargs_par){
+            new_pt = connectNameArgsParameter(tmp->data.st, new_pt);
+            if (is_formal)
+                last_pt = true; // 是否规定**kwargs只出现一次
+            else
+                status = s_2;
+        }
         freeToken(tmp, true, false);
     }
     *pt = new_pt;
@@ -653,15 +669,19 @@ void parserTuple(PASERSSIGNATURE){
     Parameter *pt = NULL;
     Statement *st = NULL;
     Token *tmp = NULL;
+    if (readBackToken(pm) == MATHER_MUL)
+        goto parserPt;
+
     if (!callChildToken(CALLPASERSSIGNATURE, parserPolynomial, POLYNOMIAL, &tmp, NULL, syntax_error))
         goto return_;
-    if (!checkToken_(pm, MATHER_COMMA)){
+    if (readBackToken(pm) != MATHER_COMMA){
         tmp->token_type = TUPLE;
         addToken_(pm ,tmp);
         goto return_;
     }
-    addLexToken(pm, MATHER_COMMA);
     addToken_(pm ,tmp);
+
+    parserPt:
     if (!parserParameter(CALLPASERSSIGNATURE, &pt, false, true, false, MATHER_COMMA, MATHER_ASSIGNMENT)) {
         syntaxError(pm, syntax_error, 1, "Don't get tuple element");
         goto return_;
@@ -746,19 +766,18 @@ void parserCallBack(PASERSSIGNATURE){
 
 int getOperation(PASERSSIGNATURE, int right_type, Statement **st, char *name){
     *st = NULL;
-    if (readBackToken(pm) == right_type)  // TODO-szh checkToken_
+    if (checkToken_(pm, right_type))
         goto return_;
 
     if (!callChildStatement(CALLPASERSSIGNATURE, parserOperation, OPERATION, st, NULL))
         return 0;
 
-    if (readBackToken(pm) != right_type){  // TODO-szh checkToken_
+    if (!checkToken_(pm, right_type)){
         freeStatement(*st);
         return -1;
     }
 
     return_:
-    delToken(pm);
     return 1;
 }
 /**

+ 1 - 1
src/__run.c

@@ -66,7 +66,7 @@ char *setStrVarName(char *old, bool free_old){
 char *setNumVarName(NUMBER_TYPE num){
     char name[50];
     snprintf(name, 50, "%"NUMBER_FORMAT, num);
-    return memStrcpy(name, 0, false, false);
+    return memStrcat(VARNUM_PREFIX, name);
 }
 
 char *getNameFromValue(Value *value){

+ 2 - 2
src/operation.c

@@ -158,7 +158,7 @@ Result assCore(Statement *name, LinkValue *value, INTER_FUNCTIONSIG_CORE){
             return tmp_result;
         }
         tmp_result = setParameterCore(call, name->u.base_list.list, var_list, CALL_INTER_FUNCTIONSIG_CORE(var_list));
-        if (run_continue(tmp_result))
+        if (!run_continue(tmp_result))
             result = tmp_result;
         else{
             Argument *tmp = call;
@@ -237,7 +237,7 @@ Result getDict(INTER_FUNCTIONSIG) {
         return result;
     }
 
-    Value *value = makeDictValue(&at, inter);
+    Value *value = makeDictValue(&at, true, inter);
     setResultOperation(&result ,inter);
     result.value->value = value;
     freeArgument(at_tmp, false);

+ 106 - 21
src/parameter.c

@@ -11,6 +11,8 @@ Argument *makeArgument(){
     tmp->type = value_arg;
     tmp->data.value = NULL;
     tmp->data.name = NULL;
+    tmp->data.name_ = NULL;
+    tmp->name_type = name_st;
     tmp->next = NULL;
     return tmp;
 }
@@ -29,6 +31,15 @@ Argument *makeNameValueArgument(LinkValue *value, Statement *name){
     return tmp;
 }
 
+Argument *makeCharNameArgument(LinkValue *value, char *name){
+    Argument *tmp = makeArgument();
+    tmp->type = name_arg;
+    tmp->name_type = name_char;
+    tmp->data.value = value;
+    tmp->data.name_ = memStrcpy(name, 0, false, false);
+    return tmp;
+}
+
 Argument *connectArgument(Argument *new, Argument *base){
     if (base == NULL)
         return new;
@@ -49,13 +60,19 @@ Argument *connectNameValueArgument(LinkValue *value, Statement *name, Argument *
     return connectArgument(new, base);
 }
 
-void freeArgument(Argument *pt, bool free_st) {
-    while (pt != NULL){
+Argument *connectCharNameArgument(LinkValue *value, char *name, Argument *base){
+    Argument *new = makeCharNameArgument(value, name);
+    return connectArgument(new, base);
+}
+
+void freeArgument(Argument *at, bool free_st) {
+    while (at != NULL){
         if (free_st)
-            freeStatement(pt->data.name);
-        Argument *tmp = pt->next;
-        memFree(pt);
-        pt = tmp;
+            freeStatement(at->data.name);
+        memFree(at->data.name_);
+        Argument *tmp = at->next;
+        memFree(at);
+        at = tmp;
     }
 }
 
@@ -105,6 +122,13 @@ Parameter *makeOnlyArgsParameter(Statement *st){
     return tmp;
 }
 
+Parameter *makeNameArgsParameter(Statement *st){
+    Parameter *tmp = makeParameter();
+    tmp->type = kwargs_par;
+    tmp->data.value = st;
+    return tmp;
+}
+
 Parameter *connectParameter(Parameter *new, Parameter *base){
     if (base == NULL)
         return new;
@@ -130,6 +154,11 @@ Parameter *connectOnlyArgsParameter(Statement *st, Parameter *base){
     return connectParameter(new, base);
 }
 
+Parameter *connectNameArgsParameter(Statement *st, Parameter *base){
+    Parameter *new = makeNameArgsParameter(st);
+    return connectParameter(new, base);
+}
+
 void freeParameter(Parameter *pt, bool free_st) {
     while (pt != NULL){
         if (free_st) {
@@ -150,6 +179,18 @@ Argument *listToArgument(LinkValue *list_value, INTER_FUNCTIONSIG_CORE){
     return at;
 }
 
+Argument *dictToArgument(LinkValue *dict_value, INTER_FUNCTIONSIG_CORE){
+    Argument *at = NULL;
+    for (int i = 0; i < MAX_SIZE; i++) {
+        Var *tmp = dict_value->value->data.dict.dict->hashtable[i];
+        while (tmp != NULL) {
+            at = connectCharNameArgument(tmp->value, tmp->name, at);
+            tmp = tmp->next;
+        }
+    }
+    return at;
+}
+
 /**
  * 设置形式参数的默认值
  * 仅支持name_value
@@ -162,6 +203,7 @@ Argument *listToArgument(LinkValue *list_value, INTER_FUNCTIONSIG_CORE){
 Result defaultParameter(Parameter **function_ad, Inter *inter, VarList *var_list, int *num) {
     Parameter *function = *function_ad;
     Result result;
+    *num = 0;
     while (function != NULL && function->type == name_par){
         Result tmp, tmp_ass;
         if(operationSafeInterStatement(&tmp, CALL_INTER_FUNCTIONSIG(function->data.value, var_list))) {
@@ -194,13 +236,20 @@ Result defaultParameter(Parameter **function_ad, Inter *inter, VarList *var_list
 Result argumentToVar(Argument **call_ad, struct Inter *inter, struct VarList *var_list, NUMBER_TYPE *num) {
     Argument *call = *call_ad;
     Result result;
+    *num = 0;
     while (call != NULL && call->type == name_arg){
         Result tmp_ass;
+        if (call->name_type == name_char){
+            addFromVarList(call->data.name_, var_list, 0, call->data.value);
+            goto next;
+        }
         tmp_ass = assCore(call->data.name, call->data.value, CALL_INTER_FUNCTIONSIG_CORE(var_list));
         if (!run_continue(tmp_ass)) {
             *call_ad = call;
             return tmp_ass;
         }
+
+        next:
         (*num)++;
         call = call->next;
     }
@@ -219,19 +268,30 @@ Result argumentToVar(Argument **call_ad, struct Inter *inter, struct VarList *va
  * @param num
  * @return
  */
-Result parameterFromVar(Parameter **function_ad, VarList *function_var, INTER_FUNCTIONSIG_CORE, NUMBER_TYPE *num){
+Result parameterFromVar(Parameter **function_ad, VarList *function_var, struct Inter *inter, struct VarList *var_list,
+                        NUMBER_TYPE *num, NUMBER_TYPE max, bool *status) {
     Parameter *function = *function_ad;
     Result result;
     setResultOperation(&result, inter);
     bool get;
+    *num = 0;
+    *status = false;
     while (function != NULL){
         Result tmp;
-        Statement *name = function->type == value_par ? function->data.value : function->data.name;
+        Statement *name = function->type == name_par ? function->data.name : function->data.value;
         char *str_name = NULL;
         int int_times;
         LinkValue *value = NULL;
         get = true;
 
+        if (function->type == kwargs_par){
+            value = makeLinkValue(makeDictValue(NULL, false, inter), NULL, inter);
+            value->value->data.dict.dict = var_list->hashtable;
+            value->value->data.dict.size = max - *num;
+            *status = true;
+            goto not_return;
+        }
+
         tmp = getBaseVarInfo(&str_name, &int_times, CALL_INTER_FUNCTIONSIG(name, var_list));
         if (!run_continue(tmp)) {
             memFree(str_name);
@@ -250,8 +310,8 @@ Result parameterFromVar(Parameter **function_ad, VarList *function_var, INTER_FU
             *function_ad = function;
             return tmp;
         }
-        not_return:
 
+        not_return:
         tmp = assCore(name, value, CALL_INTER_FUNCTIONSIG_CORE(function_var));
         if (!run_continue(tmp)) {
             *function_ad = function;
@@ -324,6 +384,10 @@ Result iterParameter(Parameter *call, Argument **base_ad, INTER_FUNCTIONSIG_CORE
             Argument *tmp_at = listToArgument(tmp.value, CALL_INTER_FUNCTIONSIG_CORE(var_list));
             base = connectArgument(tmp_at, base);
         }
+        else if (call->type == kwargs_par){
+            Argument *tmp_at = dictToArgument(tmp.value, CALL_INTER_FUNCTIONSIG_CORE(var_list));
+            base = connectArgument(tmp_at, base);
+        }
         call = call->next;
     }
     setResult(&result, true, inter);
@@ -341,11 +405,11 @@ Argument *getArgument(Parameter *call, Result *result, INTER_FUNCTIONSIG_CORE){
  * 参数表:
  |实参 \ 形参| name | value | arg | kwarg | null |
  ----------------------------------------
- |name     | p_3  |  p_3  | p_4 |  p_5! | error |
+ |name     | p_3  |  p_3  | p_4 |  p_3! | error |
  |value    | p_1  |  p_1  | p_4 | error | error |
  |null     | p_2  | error | p_4 |  p_5  | okay  |
  ----------------------------------------
- * 注解: @p_1 match_status; @p_2 default_status; @p_3 self_ass; @p_4 mul_par; @p_5 pow_par
+ * 注解: @p_1 match_status; @p_2 default_status; @p_3 self_ass; @p_4 mul_par; @p_5 pow_par; @p_3! 通过p_3处理**kwargs
  * @param call
  * @param function
  * @param function_var
@@ -374,17 +438,21 @@ Result setParameterCore(Argument *call, Parameter *function_base, VarList *funct
         default_status = 2,
         self_ass = 3,
         mul_par = 4,
+        space_kwargs = 5,
         error = -1,
-        finished = 0
+        finished = 0,
     } status = match_status;
     while (true){
         if (call == NULL && function == NULL)
             status = finished;
-        else if ((call != NULL && function == NULL) || (call == NULL && function != NULL && function->type == value_par))
+        else if ((call != NULL && (function == NULL || call->type == value_par && function->type == kwargs_par)) ||
+                 (call == NULL && function != NULL && function->type == value_par))
             status = error;
         else if (call == NULL && function->type == name_par)  // 根据前面的条件, 已经决定function不会为NULL
             status = default_status;
-        else if (function->type == args_par)
+        else if (call == NULL && function->type == kwargs_par)
+            status = space_kwargs;
+        else if (function->type == args_par)  // 根据前面的条件, 已经决定call不会为NULL
             status = mul_par;
         else if (call->type == value_arg)
             status = match_status;
@@ -406,26 +474,43 @@ Result setParameterCore(Argument *call, Parameter *function_base, VarList *funct
             case self_ass: {
                 VarList *tmp = makeVarList(inter);
                 NUMBER_TYPE set_num = 0, get_num = 0;
+                bool dict_status = false;
                 result = argumentToVar(&call, CALL_INTER_FUNCTIONSIG_CORE(tmp), &set_num);
                 returnResult(result);
-                result = parameterFromVar(&function, function_var, CALL_INTER_FUNCTIONSIG_CORE(tmp), &get_num);
-                returnResult(result);
+                if (!run_continue(result)) {
+                    freeVarList(tmp, true);
+                    goto return_;
+                }
+                result = parameterFromVar(&function, function_var, CALL_INTER_FUNCTIONSIG_CORE(tmp), &get_num, set_num,
+                                          &dict_status);
+                if (!run_continue(result)) {
+                    freeVarList(tmp, true);
+                    goto return_;
+                }
                 freeVarList(tmp, true);
 
-                if (set_num > get_num)
-                    status = error;
+                if (!dict_status && set_num > get_num) {
+                    goto error_;
+                }
                 break;
             }
             case mul_par: {
-                Value *value = makeListValue(&call, inter, value_tuple);
-                LinkValue *tmp = makeLinkValue(value, NULL, inter);
+                LinkValue *tmp = makeLinkValue(makeListValue(&call, inter, value_tuple), NULL, inter);
+                result = assCore(function->data.value, tmp, CALL_INTER_FUNCTIONSIG_CORE(function_var));
+                returnResult(result);
+                function = function->next;
+                break;
+            }
+            case space_kwargs:{
+                LinkValue *tmp = makeLinkValue(makeDictValue(NULL, true, inter), NULL, inter);
                 result = assCore(function->data.value, tmp, CALL_INTER_FUNCTIONSIG_CORE(function_var));
                 returnResult(result);
                 function = function->next;
                 break;
             }
             case error:
-                writeLog(inter->debug, ERROR, "setParameter error", NULL);
+            error_:
+                writeLog(inter->debug, ERROR, "setParameter error\n", NULL);
                 setResultError(&result, inter);
                 goto return_;
             default:

+ 2 - 2
src/run.c

@@ -98,7 +98,7 @@ Result iterStatement(INTER_FUNCTIONSIG) {
     }
 
     if (result.type == not_return)
-        setResult(&result, true, inter);
+        setResultOperation(&result, inter);
     return result;
 }
 
@@ -126,7 +126,7 @@ Result globalIterStatement(Inter *inter) {
     }
 
     if (result.type != error_return && result.type != function_return)
-        setResult(&result, true, inter);
+        setResultOperation(&result, inter);
     return result;
 }
 

+ 9 - 8
src/value.c

@@ -65,15 +65,19 @@ Value *makeListValue(Argument **arg_ad, Inter *inter, enum ListType type) {
     return tmp;
 }
 
-Value *makeDictValue(Argument **arg_ad, Inter *inter){
+Value *makeDictValue(Argument **arg_ad, bool new_hash, Inter *inter) {
     Value *tmp;
-    VarList *hash = makeVarList(inter);
     tmp = makeValue(inter);
     tmp->data.dict.size = 0;
     tmp->type = dict;
-    tmp->data.dict.dict = hash->hashtable;
-    argumentToVar(arg_ad, inter, hash, &tmp->data.dict.size);
-    freeVarList(hash, true);
+    if (new_hash) {
+        VarList *hash = makeVarList(inter);
+        tmp->data.dict.dict = hash->hashtable;
+        argumentToVar(arg_ad, inter, hash, &tmp->data.dict.size);
+        freeVarList(hash, true);
+    }
+    else
+        tmp->data.dict.dict = NULL;
     return tmp;
 }
 
@@ -101,9 +105,6 @@ void freeValue(Value *value, Inter *inter){
         case list:
             memFree(value->data.list.list);
             break;
-        case dict:
-            freeHashTable(value->data.dict.dict, inter, true);
-            break;
         default:
             break;
     }