Patch 8.2.0350
Problem:    Vim9: expression tests don't use recognized constants.
Solution:   Recognize "true" and "false" as constants.  Make skipping work for
            assignment and expression evaluation.
Files:      src/vim9compile.c


*** ../vim-8.2.0349/src/vim9compile.c   2020-03-02 22:53:28.460549750 +0100
--- src/vim9compile.c   2020-03-03 21:51:38.377388231 +0100
***************
*** 260,265 ****
--- 260,268 ----
  /////////////////////////////////////////////////////////////////////
  // Following generate_ functions expect the caller to call ga_grow().
  
+ #define RETURN_NULL_IF_SKIP(cctx) if (cctx->ctx_skip == TRUE) return NULL
+ #define RETURN_OK_IF_SKIP(cctx) if (cctx->ctx_skip == TRUE) return OK
+ 
  /*
   * Generate an instruction without arguments.
   * Returns a pointer to the new instruction, NULL if failed.
***************
*** 270,275 ****
--- 273,279 ----
      garray_T  *instr = &cctx->ctx_instr;
      isn_T     *isn;
  
+     RETURN_NULL_IF_SKIP(cctx);
      if (ga_grow(instr, 1) == FAIL)
        return NULL;
      isn = ((isn_T *)instr->ga_data) + instr->ga_len;
***************
*** 290,295 ****
--- 294,300 ----
  {
      garray_T  *stack = &cctx->ctx_type_stack;
  
+     RETURN_NULL_IF_SKIP(cctx);
      stack->ga_len -= drop;
      return generate_instr(cctx, isn_type);
  }
***************
*** 364,369 ****
--- 369,376 ----
      vartype_T vartype;
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
+ 
      // Get the known type of the two items on the stack.  If they are matching
      // use a type-specific instruction. Otherwise fall back to runtime type
      // checking.
***************
*** 461,466 ****
--- 468,475 ----
      vartype_T type1;
      vartype_T type2;
  
+     RETURN_OK_IF_SKIP(cctx);
+ 
      // Get the known type of the two items on the stack.  If they are matching
      // use a type-specific instruction. Otherwise fall back to runtime type
      // checking.
***************
*** 536,541 ****
--- 545,551 ----
      isn_T     *isn;
      garray_T  *stack = &cctx->ctx_type_stack;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_2BOOL)) == NULL)
        return FAIL;
      isn->isn_arg.number = invert;
***************
*** 552,557 ****
--- 562,568 ----
      isn_T     *isn;
      garray_T  *stack = &cctx->ctx_type_stack;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_CHECKTYPE)) == NULL)
        return FAIL;
      isn->isn_arg.type.ct_type = vartype->tt_type;  // TODO: whole type
***************
*** 571,576 ****
--- 582,588 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_type(cctx, ISN_PUSHNR, &t_number)) == NULL)
        return FAIL;
      isn->isn_arg.number = number;
***************
*** 586,591 ****
--- 598,604 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_type(cctx, ISN_PUSHBOOL, &t_bool)) == NULL)
        return FAIL;
      isn->isn_arg.number = number;
***************
*** 601,606 ****
--- 614,620 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_type(cctx, ISN_PUSHSPEC, &t_special)) == NULL)
        return FAIL;
      isn->isn_arg.number = number;
***************
*** 617,622 ****
--- 631,637 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_type(cctx, ISN_PUSHF, &t_float)) == NULL)
        return FAIL;
      isn->isn_arg.fnumber = fnumber;
***************
*** 634,639 ****
--- 649,655 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_type(cctx, ISN_PUSHS, &t_string)) == NULL)
        return FAIL;
      isn->isn_arg.string = str;
***************
*** 650,655 ****
--- 666,672 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_type(cctx, ISN_PUSHCHANNEL, &t_channel)) == 
NULL)
        return FAIL;
      isn->isn_arg.channel = channel;
***************
*** 666,671 ****
--- 683,689 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_type(cctx, ISN_PUSHJOB, &t_channel)) == NULL)
        return FAIL;
      isn->isn_arg.job = job;
***************
*** 682,687 ****
--- 700,706 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_type(cctx, ISN_PUSHBLOB, &t_blob)) == NULL)
        return FAIL;
      isn->isn_arg.blob = blob;
***************
*** 698,703 ****
--- 717,723 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_type(cctx, ISN_PUSHFUNC, &t_func_void)) == NULL)
        return FAIL;
      isn->isn_arg.string = name;
***************
*** 714,719 ****
--- 734,740 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_type(cctx, ISN_PUSHPARTIAL,
                                                      &t_partial_any)) == NULL)
        return FAIL;
***************
*** 730,735 ****
--- 751,757 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_drop(cctx, isn_type, 1)) == NULL)
        return FAIL;
      if (name != NULL)
***************
*** 748,753 ****
--- 770,776 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_STORENR)) == NULL)
        return FAIL;
      isn->isn_arg.storenr.str_idx = idx;
***************
*** 764,769 ****
--- 787,793 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_STOREOPT)) == NULL)
        return FAIL;
      isn->isn_arg.storeopt.so_name = vim_strsave(name);
***************
*** 785,790 ****
--- 809,815 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_type(cctx, isn_type, type)) == NULL)
        return FAIL;
      if (name != NULL)
***************
*** 807,812 ****
--- 832,838 ----
      // load v:var
      int vidx = find_vim_var(name);
  
+     RETURN_OK_IF_SKIP(cctx);
      if (vidx < 0)
      {
        if (error)
***************
*** 831,836 ****
--- 857,863 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if (isn_type == ISN_LOADS)
        isn = generate_instr_type(cctx, isn_type, type);
      else
***************
*** 856,861 ****
--- 883,889 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if (isn_type == ISN_LOADSCRIPT)
        isn = generate_instr_type(cctx, isn_type, type);
      else
***************
*** 879,884 ****
--- 907,913 ----
      type_T    *type;
      type_T    *member;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_NEWLIST)) == NULL)
        return FAIL;
      isn->isn_arg.number = count;
***************
*** 915,920 ****
--- 944,950 ----
      type_T    *type;
      type_T    *member;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_NEWDICT)) == NULL)
        return FAIL;
      isn->isn_arg.number = count;
***************
*** 948,953 ****
--- 978,984 ----
      isn_T     *isn;
      garray_T  *stack = &cctx->ctx_type_stack;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL)
        return FAIL;
      isn->isn_arg.number = dfunc_idx;
***************
*** 970,975 ****
--- 1001,1007 ----
      isn_T     *isn;
      garray_T  *stack = &cctx->ctx_type_stack;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_JUMP)) == NULL)
        return FAIL;
      isn->isn_arg.jump.jump_when = when;
***************
*** 987,992 ****
--- 1019,1025 ----
      isn_T     *isn;
      garray_T  *stack = &cctx->ctx_type_stack;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_FOR)) == NULL)
        return FAIL;
      isn->isn_arg.forloop.for_idx = loop_idx;
***************
*** 1012,1017 ****
--- 1045,1051 ----
      type_T    *argtypes[MAX_FUNC_ARGS];
      int               i;
  
+     RETURN_OK_IF_SKIP(cctx);
      if (check_internal_func(func_idx, argcount) == FAIL)
        return FAIL;
  
***************
*** 1045,1050 ****
--- 1079,1085 ----
      int               regular_args = ufunc->uf_args.ga_len;
      int               argcount = pushed_argcount;
  
+     RETURN_OK_IF_SKIP(cctx);
      if (argcount > regular_args && !has_varargs(ufunc))
      {
        semsg(_(e_toomanyarg), ufunc->uf_name);
***************
*** 1105,1110 ****
--- 1140,1146 ----
      isn_T     *isn;
      garray_T  *stack = &cctx->ctx_type_stack;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_UCALL)) == NULL)
        return FAIL;
      isn->isn_arg.ufunc.cuf_name = vim_strsave(name);
***************
*** 1129,1134 ****
--- 1165,1171 ----
      isn_T     *isn;
      garray_T  *stack = &cctx->ctx_type_stack;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_PCALL)) == NULL)
        return FAIL;
      isn->isn_arg.pfunc.cpf_top = at_top;
***************
*** 1152,1157 ****
--- 1189,1195 ----
      garray_T  *stack = &cctx->ctx_type_stack;
      type_T    *type;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_MEMBER)) == NULL)
        return FAIL;
      isn->isn_arg.string = vim_strnsave(name, (int)len);
***************
*** 1178,1183 ****
--- 1216,1222 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr_drop(cctx, ISN_ECHO, count)) == NULL)
        return FAIL;
      isn->isn_arg.echo.echo_with_white = with_white;
***************
*** 1206,1211 ****
--- 1245,1251 ----
  {
      isn_T     *isn;
  
+     RETURN_OK_IF_SKIP(cctx);
      if ((isn = generate_instr(cctx, ISN_EXEC)) == NULL)
        return FAIL;
      isn->isn_arg.string = vim_strsave(line);
***************
*** 2878,2914 ****
      return OK;
  }
  
! /*
!  * expr5a == expr5b
!  * expr5a =~ expr5b
!  * expr5a != expr5b
!  * expr5a !~ expr5b
!  * expr5a > expr5b
!  * expr5a >= expr5b
!  * expr5a < expr5b
!  * expr5a <= expr5b
!  * expr5a is expr5b
!  * expr5a isnot expr5b
!  *
!  * Produces instructions:
!  *    EVAL expr5a             Push result of "expr5a"
!  *    EVAL expr5b             Push result of "expr5b"
!  *    COMPARE                 one of the compare instructions
!  */
!     static int
! compile_expr4(char_u **arg, cctx_T *cctx)
  {
      exptype_T type = EXPR_UNKNOWN;
-     char_u    *p;
-     int               len = 2;
      int               i;
-     int               type_is = FALSE;
- 
-     // get the first variable
-     if (compile_expr5(arg, cctx) == FAIL)
-       return FAIL;
  
-     p = skipwhite(*arg);
      switch (p[0])
      {
        case '=':   if (p[1] == '=')
--- 2918,2929 ----
      return OK;
  }
  
!     static exptype_T
! get_compare_type(char_u *p, int *len, int *type_is)
  {
      exptype_T type = EXPR_UNKNOWN;
      int               i;
  
      switch (p[0])
      {
        case '=':   if (p[1] == '=')
***************
*** 2924,2930 ****
        case '>':   if (p[1] != '=')
                    {
                        type = EXPR_GREATER;
!                       len = 1;
                    }
                    else
                        type = EXPR_GEQUAL;
--- 2939,2945 ----
        case '>':   if (p[1] != '=')
                    {
                        type = EXPR_GREATER;
!                       *len = 1;
                    }
                    else
                        type = EXPR_GEQUAL;
***************
*** 2932,2938 ****
        case '<':   if (p[1] != '=')
                    {
                        type = EXPR_SMALLER;
!                       len = 1;
                    }
                    else
                        type = EXPR_SEQUAL;
--- 2947,2953 ----
        case '<':   if (p[1] != '=')
                    {
                        type = EXPR_SMALLER;
!                       *len = 1;
                    }
                    else
                        type = EXPR_SEQUAL;
***************
*** 2941,2956 ****
                    {
                        // "is" and "isnot"; but not a prefix of a name
                        if (p[2] == 'n' && p[3] == 'o' && p[4] == 't')
!                           len = 5;
!                       i = p[len];
                        if (!isalnum(i) && i != '_')
                        {
!                           type = len == 2 ? EXPR_IS : EXPR_ISNOT;
!                           type_is = TRUE;
                        }
                    }
                    break;
      }
  
      /*
       * If there is a comparative operator, use it.
--- 2956,3005 ----
                    {
                        // "is" and "isnot"; but not a prefix of a name
                        if (p[2] == 'n' && p[3] == 'o' && p[4] == 't')
!                           *len = 5;
!                       i = p[*len];
                        if (!isalnum(i) && i != '_')
                        {
!                           type = *len == 2 ? EXPR_IS : EXPR_ISNOT;
!                           *type_is = TRUE;
                        }
                    }
                    break;
      }
+     return type;
+ }
+ 
+ /*
+  * expr5a == expr5b
+  * expr5a =~ expr5b
+  * expr5a != expr5b
+  * expr5a !~ expr5b
+  * expr5a > expr5b
+  * expr5a >= expr5b
+  * expr5a < expr5b
+  * expr5a <= expr5b
+  * expr5a is expr5b
+  * expr5a isnot expr5b
+  *
+  * Produces instructions:
+  *    EVAL expr5a             Push result of "expr5a"
+  *    EVAL expr5b             Push result of "expr5b"
+  *    COMPARE                 one of the compare instructions
+  */
+     static int
+ compile_expr4(char_u **arg, cctx_T *cctx)
+ {
+     exptype_T type = EXPR_UNKNOWN;
+     char_u    *p;
+     int               len = 2;
+     int               type_is = FALSE;
+ 
+     // get the first variable
+     if (compile_expr5(arg, cctx) == FAIL)
+       return FAIL;
+ 
+     p = skipwhite(*arg);
+     type = get_compare_type(p, &len, &type_is);
  
      /*
       * If there is a comparative operator, use it.
***************
*** 3324,3451 ****
      if (name == NULL)
        return NULL;
  
!     if (*arg == '&')
      {
!       int         cc;
!       long        numval;
!       char_u      *stringval = NULL;
! 
!       dest = dest_option;
!       if (cmdidx == CMD_const)
!       {
!           emsg(_(e_const_option));
!           return NULL;
!       }
!       if (is_decl)
!       {
!           semsg(_("E1052: Cannot declare an option: %s"), arg);
!           goto theend;
!       }
!       p = arg;
!       p = find_option_end(&p, &opt_flags);
!       if (p == NULL)
        {
!           emsg(_(e_letunexp));
!           return NULL;
!       }
!       cc = *p;
!       *p = NUL;
!       opt_type = get_option_value(arg + 1, &numval, &stringval, opt_flags);
!       *p = cc;
!       if (opt_type == -3)
!       {
!           semsg(_(e_unknown_option), *arg);
!           return NULL;
!       }
!       if (opt_type == -2 || opt_type == 0)
!           type = &t_string;
!       else
!           type = &t_number;   // both number and boolean option
!     }
!     else if (*arg == '$')
!     {
!       dest = dest_env;
!       if (is_decl)
!       {
!           semsg(_("E1065: Cannot declare an environment variable: %s"), name);
!           goto theend;
!       }
!     }
!     else if (*arg == '@')
!     {
!       if (!valid_yank_reg(arg[1], TRUE))
!       {
!           emsg_invreg(arg[1]);
!           return FAIL;
        }
!       dest = dest_reg;
!       if (is_decl)
        {
!           semsg(_("E1066: Cannot declare a register: %s"), name);
!           goto theend;
        }
!     }
!     else if (STRNCMP(arg, "g:", 2) == 0)
!     {
!       dest = dest_global;
!       if (is_decl)
        {
!           semsg(_("E1016: Cannot declare a global variable: %s"), name);
!           goto theend;
        }
!     }
!     else if (STRNCMP(arg, "v:", 2) == 0)
!     {
!       vimvaridx = find_vim_var(name + 2);
!       if (vimvaridx < 0)
        {
!           semsg(_(e_var_notfound), arg);
!           goto theend;
        }
!       dest = dest_vimvar;
!       if (is_decl)
        {
!           semsg(_("E1064: Cannot declare a v: variable: %s"), name);
!           goto theend;
!       }
!     }
!     else
!     {
!       for (idx = 0; reserved[idx] != NULL; ++idx)
!           if (STRCMP(reserved[idx], name) == 0)
            {
!               semsg(_("E1034: Cannot use reserved name %s"), name);
                goto theend;
            }
! 
!       idx = lookup_local(arg, varlen, cctx);
!       if (idx >= 0)
!       {
            if (is_decl)
            {
!               semsg(_("E1017: Variable already declared: %s"), name);
                goto theend;
            }
!           else
            {
!               lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
!               if (lvar->lv_const)
                {
!                   semsg(_("E1018: Cannot assign to a constant: %s"), name);
                    goto theend;
                }
            }
!       }
!       else if (STRNCMP(arg, "s:", 2) == 0
!               || lookup_script(arg, varlen) == OK
!               || find_imported(arg, varlen, cctx) != NULL)
!       {
!           dest = dest_script;
!           if (is_decl)
            {
!               semsg(_("E1054: Variable already declared in the script: %s"),
!                                                                        name);
!               goto theend;
            }
        }
      }
--- 3373,3503 ----
      if (name == NULL)
        return NULL;
  
!     if (cctx->ctx_skip != TRUE)
      {
!       if (*arg == '&')
        {
!           int     cc;
!           long            numval;
!           char_u          *stringval = NULL;
! 
!           dest = dest_option;
!           if (cmdidx == CMD_const)
!           {
!               emsg(_(e_const_option));
!               return NULL;
!           }
!           if (is_decl)
!           {
!               semsg(_("E1052: Cannot declare an option: %s"), arg);
!               goto theend;
!           }
!           p = arg;
!           p = find_option_end(&p, &opt_flags);
!           if (p == NULL)
!           {
!               emsg(_(e_letunexp));
!               return NULL;
!           }
!           cc = *p;
!           *p = NUL;
!           opt_type = get_option_value(arg + 1, &numval, &stringval, 
opt_flags);
!           *p = cc;
!           if (opt_type == -3)
!           {
!               semsg(_(e_unknown_option), *arg);
!               return NULL;
!           }
!           if (opt_type == -2 || opt_type == 0)
!               type = &t_string;
!           else
!               type = &t_number;       // both number and boolean option
        }
!       else if (*arg == '$')
        {
!           dest = dest_env;
!           if (is_decl)
!           {
!               semsg(_("E1065: Cannot declare an environment variable: %s"), 
name);
!               goto theend;
!           }
        }
!       else if (*arg == '@')
        {
!           if (!valid_yank_reg(arg[1], TRUE))
!           {
!               emsg_invreg(arg[1]);
!               return FAIL;
!           }
!           dest = dest_reg;
!           if (is_decl)
!           {
!               semsg(_("E1066: Cannot declare a register: %s"), name);
!               goto theend;
!           }
        }
!       else if (STRNCMP(arg, "g:", 2) == 0)
        {
!           dest = dest_global;
!           if (is_decl)
!           {
!               semsg(_("E1016: Cannot declare a global variable: %s"), name);
!               goto theend;
!           }
        }
!       else if (STRNCMP(arg, "v:", 2) == 0)
        {
!           vimvaridx = find_vim_var(name + 2);
!           if (vimvaridx < 0)
            {
!               semsg(_(e_var_notfound), arg);
                goto theend;
            }
!           dest = dest_vimvar;
            if (is_decl)
            {
!               semsg(_("E1064: Cannot declare a v: variable: %s"), name);
                goto theend;
            }
!       }
!       else
!       {
!           for (idx = 0; reserved[idx] != NULL; ++idx)
!               if (STRCMP(reserved[idx], name) == 0)
!               {
!                   semsg(_("E1034: Cannot use reserved name %s"), name);
!                   goto theend;
!               }
! 
!           idx = lookup_local(arg, varlen, cctx);
!           if (idx >= 0)
            {
!               if (is_decl)
                {
!                   semsg(_("E1017: Variable already declared: %s"), name);
                    goto theend;
                }
+               else
+               {
+                   lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
+                   if (lvar->lv_const)
+                   {
+                       semsg(_("E1018: Cannot assign to a constant: %s"), 
name);
+                       goto theend;
+                   }
+               }
            }
!           else if (STRNCMP(arg, "s:", 2) == 0
!                   || lookup_script(arg, varlen) == OK
!                   || find_imported(arg, varlen, cctx) != NULL)
            {
!               dest = dest_script;
!               if (is_decl)
!               {
!                   semsg(_("E1054: Variable already declared in the script: 
%s"),
!                                                                            
name);
!                   goto theend;
!               }
            }
        }
      }
***************
*** 3493,3499 ****
      }
  
      // +=, /=, etc. require an existing variable
!     if (idx < 0 && dest == dest_local)
      {
        if (oplen > 1 && !heredoc)
        {
--- 3545,3551 ----
      }
  
      // +=, /=, etc. require an existing variable
!     if (idx < 0 && dest == dest_local && cctx->ctx_skip != TRUE)
      {
        if (oplen > 1 && !heredoc)
        {
***************
*** 3840,3847 ****
      end_leader = *arg;
  
      /*
!      * Recognize only has() for now.
       */
      if (STRNCMP("has(", *arg, 4) != 0)
        return FAIL;
      *arg = skipwhite(*arg + 4);
--- 3892,3914 ----
      end_leader = *arg;
  
      /*
!      * Recognize only a few types of constants for now.
       */
+     if (STRNCMP("true", *arg, 4) == 0 && !ASCII_ISALNUM((*arg)[4]))
+     {
+       tv->v_type = VAR_SPECIAL;
+       tv->vval.v_number = VVAL_TRUE;
+       *arg += 4;
+       return OK;
+     }
+     if (STRNCMP("false", *arg, 5) == 0 && !ASCII_ISALNUM((*arg)[5]))
+     {
+       tv->v_type = VAR_SPECIAL;
+       tv->vval.v_number = VVAL_FALSE;
+       *arg += 5;
+       return OK;
+     }
+ 
      if (STRNCMP("has(", *arg, 4) != 0)
        return FAIL;
      *arg = skipwhite(*arg + 4);
***************
*** 3881,3886 ****
--- 3948,3980 ----
      return OK;
  }
  
+     static int
+ evaluate_const_expr4(char_u **arg, cctx_T *cctx UNUSED, typval_T *tv)
+ {
+     exptype_T type = EXPR_UNKNOWN;
+     char_u    *p;
+     int               len = 2;
+     int               type_is = FALSE;
+ 
+     // get the first variable
+     if (evaluate_const_expr7(arg, cctx, tv) == FAIL)
+       return FAIL;
+ 
+     p = skipwhite(*arg);
+     type = get_compare_type(p, &len, &type_is);
+ 
+     /*
+      * If there is a comparative operator, use it.
+      */
+     if (type != EXPR_UNKNOWN)
+     {
+       // TODO
+       return FAIL;
+     }
+ 
+     return OK;
+ }
+ 
  static int evaluate_const_expr3(char_u **arg, cctx_T *cctx, typval_T *tv);
  
  /*
***************
*** 3911,3917 ****
            tv2.v_type = VAR_UNKNOWN;
            tv2.v_lock = 0;
            if ((opchar == '|' ? evaluate_const_expr3(arg, cctx, &tv2)
!                              : evaluate_const_expr7(arg, cctx, &tv2)) == FAIL)
            {
                clear_tv(&tv2);
                return FAIL;
--- 4005,4011 ----
            tv2.v_type = VAR_UNKNOWN;
            tv2.v_lock = 0;
            if ((opchar == '|' ? evaluate_const_expr3(arg, cctx, &tv2)
!                              : evaluate_const_expr4(arg, cctx, &tv2)) == FAIL)
            {
                clear_tv(&tv2);
                return FAIL;
***************
*** 3940,3946 ****
  evaluate_const_expr3(char_u **arg, cctx_T *cctx, typval_T *tv)
  {
      // evaluate the first expression
!     if (evaluate_const_expr7(arg, cctx, tv) == FAIL)
        return FAIL;
  
      // || and && work almost the same
--- 4034,4040 ----
  evaluate_const_expr3(char_u **arg, cctx_T *cctx, typval_T *tv)
  {
      // evaluate the first expression
!     if (evaluate_const_expr4(arg, cctx, tv) == FAIL)
        return FAIL;
  
      // || and && work almost the same
*** ../vim-8.2.0349/src/version.c       2020-03-03 19:02:09.185924967 +0100
--- src/version.c       2020-03-03 20:58:52.605719249 +0100
***************
*** 740,741 ****
--- 740,743 ----
  {   /* Add new patch number below this line */
+ /**/
+     350,
  /**/

-- 
Apathy Error: Don't bother striking any key.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202003032053.023Krv5R013680%40masaka.moolenaar.net.

Raspunde prin e-mail lui