patch 9.1.0440: function get_lval() is too long

Commit: 
https://github.com/vim/vim/commit/44cadaa18c1816f7a576f1870790ee01a23c1071
Author: Yegappan Lakshmanan <yegap...@yahoo.com>
Date:   Fri May 24 07:44:10 2024 +0200

    patch 9.1.0440: function get_lval() is too long
    
    Problem:  function get_lval() is too long
    Solution: factor out the get_lval_subscript() function
              (Yegappan Lakshmanan)
    
    closes: #14839
    
    Signed-off-by: Yegappan Lakshmanan <yegap...@yahoo.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/eval.c b/src/eval.c
index dc68c65c5..23237c2c7 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1650,6 +1650,238 @@ get_lval_class_or_obj(
     return OK;
 }
 
+/*
+ * Get the lval of a list/dict/blob/object/class subitem starting at "p". Loop
+ * until no more [idx] or .key is following.
+ *
+ * Returns a pointer to the character after the subscript on success or NULL on
+ * failure.
+ */
+    static char_u *
+get_lval_subscript(
+    lval_T     *lp,
+    char_u     *p,
+    char_u     *name,
+    typval_T   *rettv,
+    hashtab_T  *ht,
+    dictitem_T *v,
+    int                unlet,
+    int                flags,      // GLV_ values
+    class_T    *cl_exec)
+{
+    int                vim9script = in_vim9script();
+    int                quiet = flags & GLV_QUIET;
+    char_u     *key = NULL;
+    int                len;
+    typval_T   var1;
+    typval_T   var2;
+    int                empty1 = FALSE;
+
+    /*
+     * Loop until no more [idx] or .key is following.
+     */
+    var1.v_type = VAR_UNKNOWN;
+    var2.v_type = VAR_UNKNOWN;
+
+    while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.'))
+    {
+       vartype_T v_type = lp->ll_tv->v_type;
+
+       if (*p == '.' && v_type != VAR_DICT
+               && v_type != VAR_OBJECT
+               && v_type != VAR_CLASS)
+       {
+           if (!quiet)
+               semsg(_(e_dot_not_allowed_after_str_str),
+                       vartype_name(v_type), name);
+           return NULL;
+       }
+       if (v_type != VAR_LIST
+               && v_type != VAR_DICT
+               && v_type != VAR_BLOB
+               && v_type != VAR_OBJECT
+               && v_type != VAR_CLASS)
+       {
+           if (!quiet)
+               semsg(_(e_index_not_allowed_after_str_str),
+                       vartype_name(v_type), name);
+           return NULL;
+       }
+
+       // A NULL list/blob works like an empty list/blob, allocate one now.
+       int r = OK;
+       if (v_type == VAR_LIST && lp->ll_tv->vval.v_list == NULL)
+           r = rettv_list_alloc(lp->ll_tv);
+       else if (v_type == VAR_BLOB && lp->ll_tv->vval.v_blob == NULL)
+           r = rettv_blob_alloc(lp->ll_tv);
+       if (r == FAIL)
+           return NULL;
+
+       if (lp->ll_range)
+       {
+           if (!quiet)
+               emsg(_(e_slice_must_come_last));
+           return NULL;
+       }
+#ifdef LOG_LOCKVAR
+       ch_log(NULL, "LKVAR: get_lval() loop: p: %s, type: %s", p,
+               vartype_name(v_type));
+#endif
+
+       if (vim9script && lp->ll_valtype == NULL
+               && v != NULL
+               && lp->ll_tv == &v->di_tv
+               && ht != NULL && ht == get_script_local_ht())
+       {
+           svar_T  *sv = find_typval_in_script(lp->ll_tv, 0, TRUE);
+
+           // Vim9 script local variable: get the type
+           if (sv != NULL)
+           {
+               lp->ll_valtype = sv->sv_type;
+#ifdef LOG_LOCKVAR
+               ch_log(NULL, "LKVAR:    ... loop: vim9 assign type: %s",
+                       vartype_name(lp->ll_valtype->tt_type));
+#endif
+           }
+       }
+
+       len = -1;
+       if (*p == '.')
+       {
+           key = p + 1;
+
+           for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len)
+               ;
+           if (len == 0)
+           {
+               if (!quiet)
+                   emsg(_(e_cannot_use_empty_key_for_dictionary));
+               return NULL;
+           }
+           p = key + len;
+       }
+       else
+       {
+           // Get the index [expr] or the first index [expr: ].
+           p = skipwhite(p + 1);
+           if (*p == ':')
+               empty1 = TRUE;
+           else
+           {
+               empty1 = FALSE;
+               if (eval1(&p, &var1, &EVALARG_EVALUATE) == FAIL)  // recursive!
+                   return NULL;
+               if (tv_get_string_chk(&var1) == NULL)
+               {
+                   // not a number or string
+                   clear_tv(&var1);
+                   return NULL;
+               }
+               p = skipwhite(p);
+           }
+
+           // Optionally get the second index [ :expr].
+           if (*p == ':')
+           {
+               if (v_type == VAR_DICT)
+               {
+                   if (!quiet)
+                       emsg(_(e_cannot_slice_dictionary));
+                   clear_tv(&var1);
+                   return NULL;
+               }
+               if (rettv != NULL
+                       && !(rettv->v_type == VAR_LIST
+                           && rettv->vval.v_list != NULL)
+                       && !(rettv->v_type == VAR_BLOB
+                           && rettv->vval.v_blob != NULL))
+               {
+                   if (!quiet)
+                       emsg(_(e_slice_requires_list_or_blob_value));
+                   clear_tv(&var1);
+                   return NULL;
+               }
+               p = skipwhite(p + 1);
+               if (*p == ']')
+                   lp->ll_empty2 = TRUE;
+               else
+               {
+                   lp->ll_empty2 = FALSE;
+                   // recursive!
+                   if (eval1(&p, &var2, &EVALARG_EVALUATE) == FAIL)
+                   {
+                       clear_tv(&var1);
+                       return NULL;
+                   }
+                   if (tv_get_string_chk(&var2) == NULL)
+                   {
+                       // not a number or string
+                       clear_tv(&var1);
+                       clear_tv(&var2);
+                       return NULL;
+                   }
+               }
+               lp->ll_range = TRUE;
+           }
+           else
+               lp->ll_range = FALSE;
+
+           if (*p != ']')
+           {
+               if (!quiet)
+                   emsg(_(e_missing_closing_square_brace));
+               clear_tv(&var1);
+               clear_tv(&var2);
+               return NULL;
+           }
+
+           // Skip to past ']'.
+           ++p;
+       }
+#ifdef LOG_LOCKVAR
+       if (len == -1)
+           ch_log(NULL, "LKVAR:    ... loop: p: %s, '[' key: %s", p,
+                   empty1 ? ":" : (char*)tv_get_string(&var1));
+       else
+           ch_log(NULL, "LKVAR:    ... loop: p: %s, '.' key: %s", p, key);
+#endif
+
+       if (v_type == VAR_DICT)
+       {
+           glv_status_T glv_status;
+
+           glv_status = get_lval_dict_item(name, lp, key, len, &p, &var1,
+                                                       flags, unlet, rettv);
+           if (glv_status == GLV_FAIL)
+               return NULL;
+           if (glv_status == GLV_STOP)
+               break;
+       }
+       else if (v_type == VAR_BLOB)
+       {
+           if (get_lval_blob(lp, &var1, &var2, empty1, quiet) == FAIL)
+               return NULL;
+
+           break;
+       }
+       else if (v_type == VAR_LIST)
+       {
+           if (get_lval_list(lp, &var1, &var2, empty1, flags, quiet) == FAIL)
+               return NULL;
+       }
+       else  // v_type == VAR_CLASS || v_type == VAR_OBJECT
+       {
+           if (get_lval_class_or_obj(cl_exec, v_type, lp, key, p, flags,
+                       quiet) == FAIL)
+               return NULL;
+       }
+    }
+
+    clear_tv(&var1);
+    return p;
+}
+
 /*
  * Get an lval: variable, Dict item or List item that can be assigned a value
  * to: "name", "na{me}", "name[expr]", "name[expr:expr]", "name[expr][expr]",
@@ -1683,11 +1915,6 @@ get_lval(
     char_u     *expr_start, *expr_end;
     int                cc;
     dictitem_T *v = NULL;
-    typval_T   var1;
-    typval_T   var2;
-    int                empty1 = FALSE;
-    char_u     *key = NULL;
-    int                len;
     hashtab_T  *ht = NULL;
     int                quiet = flags & GLV_QUIET;
     int                writing = 0;
@@ -1864,204 +2091,10 @@ get_lval(
        return NULL;
     }
 
-    /*
-     * Loop until no more [idx] or .key is following.
-     */
-    var1.v_type = VAR_UNKNOWN;
-    var2.v_type = VAR_UNKNOWN;
-    while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.'))
-    {
-       vartype_T v_type = lp->ll_tv->v_type;
-
-       if (*p == '.' && v_type != VAR_DICT
-                     && v_type != VAR_OBJECT
-                     && v_type != VAR_CLASS)
-       {
-           if (!quiet)
-               semsg(_(e_dot_not_allowed_after_str_str),
-                                               vartype_name(v_type), name);
-           return NULL;
-       }
-       if (v_type != VAR_LIST
-               && v_type != VAR_DICT
-               && v_type != VAR_BLOB
-               && v_type != VAR_OBJECT
-               && v_type != VAR_CLASS)
-       {
-           if (!quiet)
-               semsg(_(e_index_not_allowed_after_str_str),
-                                               vartype_name(v_type), name);
-           return NULL;
-       }
-
-       // A NULL list/blob works like an empty list/blob, allocate one now.
-       int r = OK;
-       if (v_type == VAR_LIST && lp->ll_tv->vval.v_list == NULL)
-           r = rettv_list_alloc(lp->ll_tv);
-       else if (v_type == VAR_BLOB && lp->ll_tv->vval.v_blob == NULL)
-           r = rettv_blob_alloc(lp->ll_tv);
-       if (r == FAIL)
-           return NULL;
-
-       if (lp->ll_range)
-       {
-           if (!quiet)
-               emsg(_(e_slice_must_come_last));
-           return NULL;
-       }
-#ifdef LOG_LOCKVAR
-       ch_log(NULL, "LKVAR: get_lval() loop: p: %s, type: %s", p,
-                                                       vartype_name(v_type));
-#endif
-
-       if (vim9script && lp->ll_valtype == NULL
-               && v != NULL
-               && lp->ll_tv == &v->di_tv
-               && ht != NULL && ht == get_script_local_ht())
-       {
-           svar_T  *sv = find_typval_in_script(lp->ll_tv, 0, TRUE);
-
-           // Vim9 script local variable: get the type
-           if (sv != NULL)
-           {
-               lp->ll_valtype = sv->sv_type;
-#ifdef LOG_LOCKVAR
-               ch_log(NULL, "LKVAR:    ... loop: vim9 assign type: %s",
-                                       vartype_name(lp->ll_valtype->tt_type));
-#endif
-           }
-       }
-
-       len = -1;
-       if (*p == '.')
-       {
-           key = p + 1;
-           for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len)
-               ;
-           if (len == 0)
-           {
-               if (!quiet)
-                   emsg(_(e_cannot_use_empty_key_for_dictionary));
-               return NULL;
-           }
-           p = key + len;
-       }
-       else
-       {
-           // Get the index [expr] or the first index [expr: ].
-           p = skipwhite(p + 1);
-           if (*p == ':')
-               empty1 = TRUE;
-           else
-           {
-               empty1 = FALSE;
-               if (eval1(&p, &var1, &EVALARG_EVALUATE) == FAIL)  // recursive!
-                   return NULL;
-               if (tv_get_string_chk(&var1) == NULL)
-               {
-                   // not a number or string
-                   clear_tv(&var1);
-                   return NULL;
-               }
-               p = skipwhite(p);
-           }
-
-           // Optionally get the second index [ :expr].
-           if (*p == ':')
-           {
-               if (v_type == VAR_DICT)
-               {
-                   if (!quiet)
-                       emsg(_(e_cannot_slice_dictionary));
-                   clear_tv(&var1);
-                   return NULL;
-               }
-               if (rettv != NULL
-                       && !(rettv->v_type == VAR_LIST
-                                                && rettv->vval.v_list != NULL)
-                       && !(rettv->v_type == VAR_BLOB
-                                               && rettv->vval.v_blob != NULL))
-               {
-                   if (!quiet)
-                       emsg(_(e_slice_requires_list_or_blob_value));
-                   clear_tv(&var1);
-                   return NULL;
-               }
-               p = skipwhite(p + 1);
-               if (*p == ']')
-                   lp->ll_empty2 = TRUE;
-               else
-               {
-                   lp->ll_empty2 = FALSE;
-                   // recursive!
-                   if (eval1(&p, &var2, &EVALARG_EVALUATE) == FAIL)
-                   {
-                       clear_tv(&var1);
-                       return NULL;
-                   }
-                   if (tv_get_string_chk(&var2) == NULL)
-                   {
-                       // not a number or string
-                       clear_tv(&var1);
-                       clear_tv(&var2);
-                       return NULL;
-                   }
-               }
-               lp->ll_range = TRUE;
-           }
-           else
-               lp->ll_range = FALSE;
-
-           if (*p != ']')
-           {
-               if (!quiet)
-                   emsg(_(e_missing_closing_square_brace));
-               clear_tv(&var1);
-               clear_tv(&var2);
-               return NULL;
-           }
-
-           // Skip to past ']'.
-           ++p;
-       }
-#ifdef LOG_LOCKVAR
-       if (len == -1)
-           ch_log(NULL, "LKVAR:    ... loop: p: %s, '[' key: %s", p,
-                               empty1 ? ":" : (char*)tv_get_string(&var1));
-       else
-           ch_log(NULL, "LKVAR:    ... loop: p: %s, '.' key: %s", p, key);
-#endif
-
-       if (v_type == VAR_DICT)
-       {
-           glv_status_T glv_status;
-
-           glv_status = get_lval_dict_item(name, lp, key, len, &p, &var1,
-                                                       flags, unlet, rettv);
-           if (glv_status == GLV_FAIL)
-               return NULL;
-           if (glv_status == GLV_STOP)
-               break;
-       }
-       else if (v_type == VAR_BLOB)
-       {
-           if (get_lval_blob(lp, &var1, &var2, empty1, quiet) == FAIL)
-               return NULL;
-
-           break;
-       }
-       else if (v_type == VAR_LIST)
-       {
-           if (get_lval_list(lp, &var1, &var2, empty1, flags, quiet) == FAIL)
-               return NULL;
-       }
-       else  // v_type == VAR_CLASS || v_type == VAR_OBJECT
-       {
-           if (get_lval_class_or_obj(cl_exec, v_type, lp, key, p, flags,
-                                                       quiet) == FAIL)
-               return FAIL;
-       }
-    }
+    // If the next character is a "." or a "[", then process the subitem.
+    p = get_lval_subscript(lp, p, name, rettv, ht, v, unlet, flags, cl_exec);
+    if (p == NULL)
+       return NULL;
 
     if (vim9script && lp->ll_valtype != NULL && rettv != NULL)
     {
@@ -2073,8 +2106,6 @@ get_lval(
            return NULL;
     }
 
-
-    clear_tv(&var1);
     lp->ll_name_end = p;
     return p;
 }
diff --git a/src/version.c b/src/version.c
index f6a7db8ae..f05081a11 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    440,
 /**/
     439,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1sANz8-003oa0-P7%40256bit.org.

Raspunde prin e-mail lui