patch 9.1.0450: evalc. code too complex

Commit: 
https://github.com/vim/vim/commit/51c45e89b50a4841147b9fbd7c6095ab79a10c71
Author: Yegappan Lakshmanan <yegap...@yahoo.com>
Date:   Thu May 30 07:50:08 2024 +0200

    patch 9.1.0450: evalc. code too complex
    
    Problem:  eval.c code too complex
    Solution: refactor eval6() and eval9() functions into several smaller
              functions (Yegappan Lakshmanan)
    
    closes: #14875
    
    Signed-off-by: Yegappan Lakshmanan <yegap...@yahoo.com>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/dict.c b/src/dict.c
index c78995d80..bf45b0b92 100644
--- a/src/dict.c
+++ b/src/dict.c
@@ -1091,6 +1091,33 @@ failret:
     return OK;
 }
 
+/*
+ * Evaluate a literal dictionary: #{key: val, key: val}
+ * "*arg" points to the "#".
+ * On return, "*arg" points to the character after the Dict.
+ * Return OK or FAIL.  Returns NOTDONE for {expr}.
+ */
+    int
+eval_lit_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
+{
+    int                vim9script = in_vim9script();
+    int                ret = OK;
+
+    if (vim9script)
+    {
+       ret = vim9_bad_comment(*arg) ? FAIL : NOTDONE;
+    }
+    else if ((*arg)[1] == '{')
+    {
+       ++*arg;
+       ret = eval_dict(arg, rettv, evalarg, TRUE);
+    }
+    else
+       ret = NOTDONE;
+
+    return ret;
+}
+
 /*
  * Go over all entries in "d2" and add them to "d1".
  * When "action" is "error" then a duplicate key is an error.
diff --git a/src/eval.c b/src/eval.c
index b08f29657..4a039792c 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1299,8 +1299,8 @@ typedef enum {
  */
     static int
 get_lval_dict_item(
-    char_u     *name,
     lval_T     *lp,
+    char_u     *name,
     char_u     *key,
     int                len,
     char_u     **key_end,
@@ -1513,24 +1513,107 @@ get_lval_list(
 }
 
 /*
- * Get a Class or Object lval variable that can be assigned a value to:
- * "name", "name.key", "name.key[expr]" etc.
+ * Get a class or object lval method in class "cl".  The 'key' argument points
+ * to the method name and 'key_end' points to the character after 'key'.
+ * 'v_type' is VAR_CLASS or VAR_OBJECT.
+ *
+ * The method index, method function pointer and method type are returned in
+ * "lp".
+ */
+    static void
+get_lval_oc_method(
+    lval_T     *lp,
+    class_T    *cl,
+    char_u     *key,
+    char_u     *key_end,
+    vartype_T  v_type)
+{
+    // Look for a method with this name.
+    // round 1: class functions (skipped for an object)
+    // round 2: object methods
+    for (int round = v_type == VAR_OBJECT ? 2 : 1; round <= 2; ++round)
+    {
+       int     m_idx;
+       ufunc_T *fp;
+
+       fp = method_lookup(cl, round == 1 ? VAR_CLASS : VAR_OBJECT,
+                                               key, key_end - key, &m_idx);
+       lp->ll_oi = m_idx;
+       if (fp != NULL)
+       {
+           lp->ll_ufunc = fp;
+           lp->ll_valtype = fp->uf_func_type;
+           break;
+       }
+    }
+}
+
+/*
+ * Get a class or object lval variable in class "cl".  The "key" argument
+ * points to the variable name and "key_end" points to the character after
+ * "key".  "v_type" is VAR_CLASS or VAR_OBJECT.  "cl_exec" is the class that is
+ * executing, or NULL.
+ *
+ * The variable index, typval and type are returned in "lp".  Returns FAIL if
+ * the variable is not writable.  Otherwise returns OK.
+ */
+    static int
+get_lval_oc_variable(
+    lval_T     *lp,
+    class_T    *cl,
+    char_u     *key,
+    char_u     *key_end,
+    vartype_T  v_type,
+    class_T    *cl_exec,
+    int                flags)
+{
+    int                m_idx;
+    ocmember_T *om;
+
+    om = member_lookup(cl, v_type, key, key_end - key, &m_idx);
+    lp->ll_oi = m_idx;
+    if (om == NULL)
+       return OK;
+
+    // Check variable is accessible
+    if (get_lval_check_access(cl_exec, cl, om, key_end, flags) == FAIL)
+       return FAIL;
+
+    // When lhs is used to modify the variable, check it is not a read-only
+    // variable.
+    if ((flags & GLV_READ_ONLY) == 0 && (*key_end != '.' && *key_end != '[')
+           && oc_var_check_ro(cl, om))
+       return FAIL;
+
+    lp->ll_valtype = om->ocm_type;
+
+    if (v_type == VAR_OBJECT)
+       lp->ll_tv = ((typval_T *)(lp->ll_tv->vval.v_object + 1)) + m_idx;
+    else
+       lp->ll_tv = &cl->class_members_tv[m_idx];
+
+    return OK;
+}
+
+/*
+ * Get a Class or Object lval variable or method that can be assigned a value
+ * to: "name", "name.key", "name.key[expr]" etc.
  *
- * 'cl_exec' is the class that is executing, or NULL. 'v_type' is VAR_CLASS or
- * VAR_OBJECT.  'key' points to the member variable name and 'key_end' points
- * to the character after 'key'.  If 'quiet' is TRUE, then error messages
- * are not displayed for invalid indexes.
+ * The 'key' argument points to the member name and 'key_end' points to the
+ * character after 'key'.  'v_type' is VAR_CLASS or VAR_OBJECT.  'cl_exec' is
+ * the class that is executing, or NULL.  If 'quiet' is TRUE, then error
+ * messages are not displayed for invalid indexes.
  *
  * The Class or Object is returned in 'lp'.  Returns OK on success and FAIL on
  * failure.
  */
     static int
 get_lval_class_or_obj(
-    class_T    *cl_exec,
-    vartype_T  v_type,
     lval_T     *lp,
     char_u     *key,
     char_u     *key_end,
+    vartype_T  v_type,
+    class_T    *cl_exec,
     int                flags,
     int                quiet)
 {
@@ -1556,69 +1639,27 @@ get_lval_class_or_obj(
     }
     lp->ll_class = cl;
 
-    // TODO: what if class is NULL?
-    if (cl != NULL)
-    {
-       lp->ll_valtype = NULL;
-
-       if (flags & GLV_PREFER_FUNC)
-       {
-           // First look for a function with this name.
-           // round 1: class functions (skipped for an object)
-           // round 2: object methods
-           for (int round = v_type == VAR_OBJECT ? 2 : 1;
-                   round <= 2; ++round)
-           {
-               int     m_idx;
-               ufunc_T *fp;
-
-               fp = method_lookup(cl,
-                       round == 1 ? VAR_CLASS : VAR_OBJECT,
-                       key, key_end - key, &m_idx);
-               lp->ll_oi = m_idx;
-               if (fp != NULL)
-               {
-                   lp->ll_ufunc = fp;
-                   lp->ll_valtype = fp->uf_func_type;
-                   break;
-               }
-           }
-       }
-
-       if (lp->ll_valtype == NULL)
-       {
-           int         m_idx;
-           ocmember_T  *om
-               = member_lookup(cl, v_type, key, key_end - key, &m_idx);
-           lp->ll_oi = m_idx;
-           if (om != NULL)
-           {
-               if (get_lval_check_access(cl_exec, cl, om,
-                           key_end, flags) == FAIL)
-                   return FAIL;
-
-               // When lhs is used to modify the variable, check it is
-               // not a read-only variable.
-               if ((flags & GLV_READ_ONLY) == 0
-                       && (*key_end != '.' && *key_end != '[')
-                       && oc_var_check_ro(cl, om))
-                   return FAIL;
+    if (cl == NULL)
+       // TODO: what if class is NULL?
+       return OK;
 
-               lp->ll_valtype = om->ocm_type;
+    lp->ll_valtype = NULL;
 
-               if (v_type == VAR_OBJECT)
-                   lp->ll_tv = ((typval_T *)(
-                               lp->ll_tv->vval.v_object + 1)) + m_idx;
-               else
-                   lp->ll_tv = &cl->class_members_tv[m_idx];
-           }
-       }
+    if (flags & GLV_PREFER_FUNC)
+       get_lval_oc_method(lp, cl, key, key_end, v_type);
 
-       if (lp->ll_valtype == NULL)
-       {
-           member_not_found_msg(cl, v_type, key, key_end - key);
+    // Look for object/class member variable
+    if (lp->ll_valtype == NULL)
+    {
+       if (get_lval_oc_variable(lp, cl, key, key_end, v_type, cl_exec, flags)
+                                                               == FAIL)
            return FAIL;
-       }
+    }
+
+    if (lp->ll_valtype == NULL)
+    {
+       member_not_found_msg(cl, v_type, key, key_end - key);
+       return FAIL;
     }
 
     return OK;
@@ -1861,7 +1902,7 @@ get_lval_subscript(
        {
            glv_status_T glv_status;
 
-           glv_status = get_lval_dict_item(name, lp, key, len, &p, &var1,
+           glv_status = get_lval_dict_item(lp, name, key, len, &p, &var1,
                                                        flags, unlet, rettv);
            if (glv_status == GLV_FAIL)
                goto done;
@@ -1882,8 +1923,8 @@ get_lval_subscript(
        }
        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)
+           if (get_lval_class_or_obj(lp, key, p, v_type, cl_exec, flags,
+                                                       quiet) == FAIL)
                goto done;
        }
 
@@ -4014,6 +4055,120 @@ eval5(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
     return OK;
 }
 
+/*
+ * Concatenate strings "tv1" and "tv2" and store the result in "tv1".
+ */
+    static int
+eval_concat_str(typval_T *tv1, typval_T *tv2)
+{
+    char_u     buf1[NUMBUFLEN], buf2[NUMBUFLEN];
+    char_u     *s1 = tv_get_string_buf(tv1, buf1);
+    char_u     *s2 = NULL;
+    char_u     *p;
+    int                vim9script = in_vim9script();
+
+    if (vim9script && (tv2->v_type == VAR_VOID
+               || tv2->v_type == VAR_CHANNEL
+               || tv2->v_type == VAR_JOB))
+       semsg(_(e_using_invalid_value_as_string_str),
+               vartype_name(tv2->v_type));
+    else if (vim9script && tv2->v_type == VAR_FLOAT)
+    {
+       vim_snprintf((char *)buf2, NUMBUFLEN, "%g",
+               tv2->vval.v_float);
+       s2 = buf2;
+    }
+    else
+       s2 = tv_get_string_buf_chk(tv2, buf2);
+    if (s2 == NULL)            // type error ?
+    {
+       clear_tv(tv1);
+       clear_tv(tv2);
+       return FAIL;
+    }
+
+    p = concat_str(s1, s2);
+    clear_tv(tv1);
+    tv1->v_type = VAR_STRING;
+    tv1->vval.v_string = p;
+
+    return OK;
+}
+
+/*
+ * Add or subtract numbers "tv1" and "tv2" and store the result in "tv1".
+ * The numbers can be whole numbers or floats.
+ */
+    static int
+eval_addsub_num(typval_T *tv1, typval_T *tv2, int op)
+{
+    int                error = FALSE;
+    varnumber_T        n1, n2;
+    float_T    f1 = 0, f2 = 0;
+
+    if (tv1->v_type == VAR_FLOAT)
+    {
+       f1 = tv1->vval.v_float;
+       n1 = 0;
+    }
+    else
+    {
+       n1 = tv_get_number_chk(tv1, &error);
+       if (error)
+       {
+           // This can only happen for "list + non-list" or
+           // "blob + non-blob".  For "non-list + ..." or
+           // "something - ...", we returned before evaluating the
+           // 2nd operand.
+           clear_tv(tv1);
+           clear_tv(tv2);
+           return FAIL;
+       }
+       if (tv2->v_type == VAR_FLOAT)
+           f1 = n1;
+    }
+    if (tv2->v_type == VAR_FLOAT)
+    {
+       f2 = tv2->vval.v_float;
+       n2 = 0;
+    }
+    else
+    {
+       n2 = tv_get_number_chk(tv2, &error);
+       if (error)
+       {
+           clear_tv(tv1);
+           clear_tv(tv2);
+           return FAIL;
+       }
+       if (tv1->v_type == VAR_FLOAT)
+           f2 = n2;
+    }
+    clear_tv(tv1);
+
+    // If there is a float on either side the result is a float.
+    if (tv1->v_type == VAR_FLOAT || tv2->v_type == VAR_FLOAT)
+    {
+       if (op == '+')
+           f1 = f1 + f2;
+       else
+           f1 = f1 - f2;
+       tv1->v_type = VAR_FLOAT;
+       tv1->vval.v_float = f1;
+    }
+    else
+    {
+       if (op == '+')
+           n1 = n1 + n2;
+       else
+           n1 = n1 - n2;
+       tv1->v_type = VAR_NUMBER;
+       tv1->vval.v_number = n1;
+    }
+
+    return OK;
+}
+
 /*
  * Handle fifth level expression:
  *     +       number addition, concatenation of list or blob
@@ -4121,33 +4276,8 @@ eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
             */
            if (op == '.')
            {
-               char_u  buf1[NUMBUFLEN], buf2[NUMBUFLEN];
-               char_u  *s1 = tv_get_string_buf(rettv, buf1);
-               char_u  *s2 = NULL;
-
-               if (vim9script && (var2.v_type == VAR_VOID
-                       || var2.v_type == VAR_CHANNEL
-                       || var2.v_type == VAR_JOB))
-                   semsg(_(e_using_invalid_value_as_string_str),
-                                                  vartype_name(var2.v_type));
-               else if (vim9script && var2.v_type == VAR_FLOAT)
-               {
-                   vim_snprintf((char *)buf2, NUMBUFLEN, "%g",
-                                                           var2.vval.v_float);
-                   s2 = buf2;
-               }
-               else
-                   s2 = tv_get_string_buf_chk(&var2, buf2);
-               if (s2 == NULL)         // type error ?
-               {
-                   clear_tv(rettv);
-                   clear_tv(&var2);
+               if (eval_concat_str(rettv, &var2) == FAIL)
                    return FAIL;
-               }
-               p = concat_str(s1, s2);
-               clear_tv(rettv);
-               rettv->v_type = VAR_STRING;
-               rettv->vval.v_string = p;
            }
            else if (op == '+' && rettv->v_type == VAR_BLOB
                                                   && var2.v_type == VAR_BLOB)
@@ -4160,69 +4290,8 @@ eval6(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
            }
            else
            {
-               int             error = FALSE;
-               varnumber_T     n1, n2;
-               float_T         f1 = 0, f2 = 0;
-
-               if (rettv->v_type == VAR_FLOAT)
-               {
-                   f1 = rettv->vval.v_float;
-                   n1 = 0;
-               }
-               else
-               {
-                   n1 = tv_get_number_chk(rettv, &error);
-                   if (error)
-                   {
-                       // This can only happen for "list + non-list" or
-                       // "blob + non-blob".  For "non-list + ..." or
-                       // "something - ...", we returned before evaluating the
-                       // 2nd operand.
-                       clear_tv(rettv);
-                       clear_tv(&var2);
-                       return FAIL;
-                   }
-                   if (var2.v_type == VAR_FLOAT)
-                       f1 = n1;
-               }
-               if (var2.v_type == VAR_FLOAT)
-               {
-                   f2 = var2.vval.v_float;
-                   n2 = 0;
-               }
-               else
-               {
-                   n2 = tv_get_number_chk(&var2, &error);
-                   if (error)
-                   {
-                       clear_tv(rettv);
-                       clear_tv(&var2);
-                       return FAIL;
-                   }
-                   if (rettv->v_type == VAR_FLOAT)
-                       f2 = n2;
-               }
-               clear_tv(rettv);
-
-               // If there is a float on either side the result is a float.
-               if (rettv->v_type == VAR_FLOAT || var2.v_type == VAR_FLOAT)
-               {
-                   if (op == '+')
-                       f1 = f1 + f2;
-                   else
-                       f1 = f1 - f2;
-                   rettv->v_type = VAR_FLOAT;
-                   rettv->vval.v_float = f1;
-               }
-               else
-               {
-                   if (op == '+')
-                       n1 = n1 + n2;
-                   else
-                       n1 = n1 - n2;
-                   rettv->v_type = VAR_NUMBER;
-                   rettv->vval.v_number = n1;
-               }
+               if (eval_addsub_num(rettv, &var2, op) == FAIL)
+                   return FAIL;
            }
            clear_tv(&var2);
        }
@@ -4623,6 +4692,158 @@ handle_predefined(char_u *s, int len, typval_T *rettv)
     return FAIL;
 }
 
+/*
+ * Handle register contents: @r.
+ */
+    static void
+eval9_reg_contents(
+    char_u     **arg,
+    typval_T   *rettv,
+    int                evaluate)
+{
+    int                vim9script = in_vim9script();
+
+    ++*arg;    // skip '@'
+    if (evaluate)
+    {
+       if (vim9script && IS_WHITE_OR_NUL(**arg))
+           semsg(_(e_syntax_error_at_str), *arg);
+       else if (vim9script && !valid_yank_reg(**arg, FALSE))
+           emsg_invreg(**arg);
+       else
+       {
+           rettv->v_type = VAR_STRING;
+           rettv->vval.v_string = get_reg_contents(**arg,
+                   GREG_EXPR_SRC);
+       }
+    }
+    if (**arg != NUL)
+       ++*arg;
+}
+
+/*
+ * Handle a nested expression: (expression) or lambda: (arg) => expr
+ */
+    static int
+eval9_nested_expr(
+    char_u     **arg,
+    typval_T   *rettv,
+    evalarg_T  *evalarg,
+    int                evaluate)
+{
+    int                ret = NOTDONE;
+    int                vim9script = in_vim9script();
+
+    if (vim9script)
+    {
+       ret = get_lambda_tv(arg, rettv, TRUE, evalarg);
+       if (ret == OK && evaluate)
+       {
+           ufunc_T *ufunc = rettv->vval.v_partial->pt_func;
+
+           // Compile it here to get the return type.  The return
+           // type is optional, when it's missing use t_unknown.
+           // This is recognized in compile_return().
+           if (ufunc->uf_ret_type->tt_type == VAR_VOID)
+               ufunc->uf_ret_type = &t_unknown;
+           if (compile_def_function(ufunc, FALSE,
+                               get_compile_type(ufunc), NULL) == FAIL)
+           {
+               clear_tv(rettv);
+               ret = FAIL;
+           }
+       }
+    }
+    if (ret == NOTDONE)
+    {
+       *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
+       ret = eval1(arg, rettv, evalarg);       // recursive!
+
+       *arg = skipwhite_and_linebreak(*arg, evalarg);
+       if (**arg == ')')
+           ++*arg;
+       else if (ret == OK)
+       {
+           emsg(_(e_missing_closing_paren));
+           clear_tv(rettv);
+           ret = FAIL;
+       }
+    }
+
+    return ret;
+}
+
+/*
+* Handle be a variable or function name.
+* Can also be a curly-braces kind of name: {expr}.
+*/
+    static int
+eval9_var_func_name(
+    char_u     **arg,
+    typval_T   *rettv,
+    evalarg_T  *evalarg,
+    int                evaluate,
+    char_u     **name_start)
+{
+    char_u     *s;
+    int                len;
+    char_u     *alias;
+    int                ret = OK;
+    int                vim9script = in_vim9script();
+
+    s = *arg;
+    len = get_name_len(arg, &alias, evaluate, TRUE);
+    if (alias != NULL)
+       s = alias;
+
+    if (len <= 0)
+       ret = FAIL;
+    else
+    {
+       int     flags = evalarg == NULL ? 0 : evalarg->eval_flags;
+
+       if (evaluate && vim9script && len == 1 && *s == '_')
+       {
+           emsg(_(e_cannot_use_underscore_here));
+           ret = FAIL;
+       }
+       else if (evaluate && vim9script && len > 2
+                                               && s[0] == 's' && s[1] == ':')
+       {
+           semsg(_(e_cannot_use_s_colon_in_vim9_script_str), s);
+           ret = FAIL;
+       }
+       else if ((vim9script ? **arg : *skipwhite(*arg)) == '(')
+       {
+           // "name(..."  recursive!
+           *arg = skipwhite(*arg);
+           ret = eval_func(arg, evalarg, s, len, rettv, flags, NULL);
+       }
+       else if (evaluate)
+       {
+           // get the value of "true", "false", etc. or a variable
+           ret = FAIL;
+           if (vim9script)
+               ret = handle_predefined(s, len, rettv);
+           if (ret == FAIL)
+           {
+               *name_start = s;
+               ret = eval_variable(s, len, 0, rettv, NULL,
+                                       EVAL_VAR_VERBOSE + EVAL_VAR_IMPORT);
+           }
+       }
+       else
+       {
+           // skip the name
+           check_vars(s, len);
+           ret = OK;
+       }
+    }
+    vim_free(alias);
+
+    return ret;
+}
+
 /*
  * Handle sixth level expression:
  *  number             number constant
@@ -4662,12 +4883,9 @@ eval9(
 {
     int                evaluate = evalarg != NULL
                                      && (evalarg->eval_flags & EVAL_EVALUATE);
-    int                len;
-    char_u     *s;
     char_u     *name_start = NULL;
     char_u     *start_leader, *end_leader;
     int                ret = OK;
-    char_u     *alias;
     static int recurse = 0;
     int                vim9script = in_vim9script();
 
@@ -4750,19 +4968,9 @@ eval9(
                break;
 
     /*
-     * Dictionary: #{key: val, key: val}
+     * Literal Dictionary: #{key: val, key: val}
      */
-    case '#':  if (vim9script)
-               {
-                   ret = vim9_bad_comment(*arg) ? FAIL : NOTDONE;
-               }
-               else if ((*arg)[1] == '{')
-               {
-                   ++*arg;
-                   ret = eval_dict(arg, rettv, evalarg, TRUE);
-               }
-               else
-                   ret = NOTDONE;
+    case '#':  ret = eval_lit_dict(arg, rettv, evalarg);
                break;
 
     /*
@@ -4796,64 +5004,14 @@ eval9(
     /*
      * Register contents: @r.
      */
-    case '@':  ++*arg;
-               if (evaluate)
-               {
-                   if (vim9script && IS_WHITE_OR_NUL(**arg))
-                       semsg(_(e_syntax_error_at_str), *arg);
-                   else if (vim9script && !valid_yank_reg(**arg, FALSE))
-                       emsg_invreg(**arg);
-                   else
-                   {
-                       rettv->v_type = VAR_STRING;
-                       rettv->vval.v_string = get_reg_contents(**arg,
-                                                               GREG_EXPR_SRC);
-                   }
-               }
-               if (**arg != NUL)
-                   ++*arg;
+    case '@':  eval9_reg_contents(arg, rettv, evaluate);
                break;
 
     /*
      * nested expression: (expression).
      * or lambda: (arg) => expr
      */
-    case '(':  ret = NOTDONE;
-               if (vim9script)
-               {
-                   ret = get_lambda_tv(arg, rettv, TRUE, evalarg);
-                   if (ret == OK && evaluate)
-                   {
-                       ufunc_T *ufunc = rettv->vval.v_partial->pt_func;
-
-                       // Compile it here to get the return type.  The return
-                       // type is optional, when it's missing use t_unknown.
-                       // This is recognized in compile_return().
-                       if (ufunc->uf_ret_type->tt_type == VAR_VOID)
-                           ufunc->uf_ret_type = &t_unknown;
-                       if (compile_def_function(ufunc, FALSE,
-                                       get_compile_type(ufunc), NULL) == FAIL)
-                       {
-                           clear_tv(rettv);
-                           ret = FAIL;
-                       }
-                   }
-               }
-               if (ret == NOTDONE)
-               {
-                   *arg = skipwhite_and_linebreak(*arg + 1, evalarg);
-                   ret = eval1(arg, rettv, evalarg);   // recursive!
-
-                   *arg = skipwhite_and_linebreak(*arg, evalarg);
-                   if (**arg == ')')
-                       ++*arg;
-                   else if (ret == OK)
-                   {
-                       emsg(_(e_missing_closing_paren));
-                       clear_tv(rettv);
-                       ret = FAIL;
-                   }
-               }
+    case '(':  ret = eval9_nested_expr(arg, rettv, evalarg, evaluate);
                break;
 
     default:   ret = NOTDONE;
@@ -4866,55 +5024,7 @@ eval9(
         * Must be a variable or function name.
         * Can also be a curly-braces kind of name: {expr}.
         */
-       s = *arg;
-       len = get_name_len(arg, &alias, evaluate, TRUE);
-       if (alias != NULL)
-           s = alias;
-
-       if (len <= 0)
-           ret = FAIL;
-       else
-       {
-           int     flags = evalarg == NULL ? 0 : evalarg->eval_flags;
-
-           if (evaluate && vim9script && len == 1 && *s == '_')
-           {
-               emsg(_(e_cannot_use_underscore_here));
-               ret = FAIL;
-           }
-           else if (evaluate && vim9script && len > 2
-                                                && s[0] == 's' && s[1] == ':')
-           {
-               semsg(_(e_cannot_use_s_colon_in_vim9_script_str), s);
-               ret = FAIL;
-           }
-           else if ((vim9script ? **arg : *skipwhite(*arg)) == '(')
-           {
-               // "name(..."  recursive!
-               *arg = skipwhite(*arg);
-               ret = eval_func(arg, evalarg, s, len, rettv, flags, NULL);
-           }
-           else if (evaluate)
-           {
-               // get the value of "true", "false", etc. or a variable
-               ret = FAIL;
-               if (vim9script)
-                   ret = handle_predefined(s, len, rettv);
-               if (ret == FAIL)
-               {
-                   name_start = s;
-                   ret = eval_variable(s, len, 0, rettv, NULL,
-                                          EVAL_VAR_VERBOSE + EVAL_VAR_IMPORT);
-               }
-           }
-           else
-           {
-               // skip the name
-               check_vars(s, len);
-               ret = OK;
-           }
-       }
-       vim_free(alias);
+       ret = eval9_var_func_name(arg, rettv, evalarg, evaluate, &name_start);
     }
 
     // Handle following '[', '(' and '.' for expr[expr], expr.name,
@@ -5761,32 +5871,27 @@ func_tv2string(typval_T *tv, char_u **tofree, int 
echo_style)
 
     if (echo_style)
     {
+       *tofree = NULL;
+
        if (tv->vval.v_string == NULL)
-       {
            r = (char_u *)"function()";
-           *tofree = NULL;
-       }
        else
        {
            r = make_ufunc_name_readable(tv->vval.v_string, buf,
                                                        MAX_FUNC_NAME_LEN);
            if (r == buf)
-           {
-               r = vim_strsave(buf);
-               *tofree = r;
-           }
-           else
-               *tofree = NULL;
+               r = *tofree = vim_strsave(buf);
        }
     }
     else
     {
-       if (tv->vval.v_string == NULL)
-           *tofree = string_quote(NULL, TRUE);
-       else
-           *tofree = string_quote(make_ufunc_name_readable(tv->vval.v_string,
-                                               buf, MAX_FUNC_NAME_LEN), TRUE);
-       r = *tofree;
+       char_u *s = NULL;
+
+       if (tv->vval.v_string != NULL)
+           s = make_ufunc_name_readable(tv->vval.v_string, buf,
+                                                       MAX_FUNC_NAME_LEN);
+
+       r = *tofree = string_quote(s, TRUE);
     }
 
     return r;
diff --git a/src/proto/dict.pro b/src/proto/dict.pro
index fdccca573..346e1d541 100644
--- a/src/proto/dict.pro
+++ b/src/proto/dict.pro
@@ -37,6 +37,7 @@ varnumber_T dict_get_bool(dict_T *d, char *key, int def);
 char_u *dict2string(typval_T *tv, int copyID, int restore_copyID);
 char_u *get_literal_key(char_u **arg);
 int eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal);
+int eval_lit_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg);
 void dict_extend(dict_T *d1, dict_T *d2, char_u *action, char *func_name);
 dictitem_T *dict_lookup(hashitem_T *hi);
 int dict_equal(dict_T *d1, dict_T *d2, int ic, int recursive);
diff --git a/src/version.c b/src/version.c
index 6871bf978..bedc35bf2 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 */
+/**/
+    450,
 /**/
     449,
 /**/

-- 
-- 
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/E1sCYpb-00GBLN-Id%40256bit.org.

Raspunde prin e-mail lui