Patch 8.2.0502
Problem:    Vim9: some code is not tested.
Solution:   Add more tests.  Fix uncovered problems.
Files:      src/vim9compile.c, src/regexp.c, src/proto/regexp.pro,
            src/cmdexpand.c, src/ex_cmds.c, src/ex_docmd.c, src/ex_eval.c,
            src/ex_getln.c, src/highlight.c, src/search.c, src/syntax.c,
            src/tag.c, src/userfunc.c, src/testdir/test_vim9_script.vim,
            src/testdir/test_vim9_disassemble.vim


*** ../vim-8.2.0501/src/vim9compile.c   2020-04-02 16:00:01.120265119 +0200
--- src/vim9compile.c   2020-04-02 21:10:02.009028579 +0200
***************
*** 4095,4101 ****
        *arg = skipwhite(*arg);
        if (**arg != ')')
            return FAIL;
!       *arg = skipwhite(*arg + 1);
  
        argvars[0] = *tv;
        argvars[1].v_type = VAR_UNKNOWN;
--- 4095,4101 ----
        *arg = skipwhite(*arg);
        if (**arg != ')')
            return FAIL;
!       *arg = *arg + 1;
  
        argvars[0] = *tv;
        argvars[1].v_type = VAR_UNKNOWN;
***************
*** 4269,4274 ****
--- 4269,4275 ----
        int             val = tv2bool(tv);
        typval_T        tv2;
  
+       // require space before and after the ?
        if (!VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[1]))
            return FAIL;
  
***************
*** 4553,4558 ****
--- 4554,4560 ----
      loop_idx = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number);
      if (loop_idx < 0)
      {
+       // only happens when out of memory
        drop_scope(cctx);
        return NULL;
      }
***************
*** 4899,4910 ****
        char_u *end;
        char_u *pat;
        char_u *tofree = NULL;
        int     len;
  
        // Push v:exception, push {expr} and MATCH
        generate_instr_type(cctx, ISN_PUSHEXC, &t_string);
  
!       end = skip_regexp(p + 1, *p, TRUE, &tofree);
        if (*end != *p)
        {
            semsg(_("E1067: Separator mismatch: %s"), p);
--- 4901,4913 ----
        char_u *end;
        char_u *pat;
        char_u *tofree = NULL;
+       int     dropped = 0;
        int     len;
  
        // Push v:exception, push {expr} and MATCH
        generate_instr_type(cctx, ISN_PUSHEXC, &t_string);
  
!       end = skip_regexp_ex(p + 1, *p, TRUE, &tofree, &dropped);
        if (*end != *p)
        {
            semsg(_("E1067: Separator mismatch: %s"), p);
***************
*** 4914,4923 ****
        if (tofree == NULL)
            len = (int)(end - (p + 1));
        else
!           len = (int)(end - (tofree + 1));
!       pat = vim_strnsave(p + 1, len);
        vim_free(tofree);
!       p += len + 2;
        if (pat == NULL)
            return FAIL;
        if (generate_PUSHS(cctx, pat) == FAIL)
--- 4917,4926 ----
        if (tofree == NULL)
            len = (int)(end - (p + 1));
        else
!           len = (int)(end - tofree);
!       pat = vim_strnsave(tofree == NULL ? p + 1 : tofree, len);
        vim_free(tofree);
!       p += len + 2 + dropped;
        if (pat == NULL)
            return FAIL;
        if (generate_PUSHS(cctx, pat) == FAIL)
*** ../vim-8.2.0501/src/regexp.c        2020-02-15 23:06:40.826770264 +0100
--- src/regexp.c        2020-04-02 21:09:53.369056994 +0200
***************
*** 537,552 ****
   * Stop at end of "startp" or where "dirc" is found ('/', '?', etc).
   * Take care of characters with a backslash in front of it.
   * Skip strings inside [ and ].
   * When "newp" is not NULL and "dirc" is '?', make an allocated copy of the
   * expression and change "\?" to "?".  If "*newp" is not NULL the expression
   * is changed in-place.
   */
      char_u *
! skip_regexp(
      char_u    *startp,
      int               dirc,
      int               magic,
!     char_u    **newp)
  {
      int               mymagic;
      char_u    *p = startp;
--- 537,566 ----
   * Stop at end of "startp" or where "dirc" is found ('/', '?', etc).
   * Take care of characters with a backslash in front of it.
   * Skip strings inside [ and ].
+  */
+     char_u *
+ skip_regexp(
+     char_u    *startp,
+     int               dirc,
+     int               magic)
+ {
+     return skip_regexp_ex(startp, dirc, magic, NULL, NULL);
+ }
+ 
+ /*
+  * skip_regexp() with extra arguments:
   * When "newp" is not NULL and "dirc" is '?', make an allocated copy of the
   * expression and change "\?" to "?".  If "*newp" is not NULL the expression
   * is changed in-place.
+  * If a "\?" is changed to "?" then "dropped" is incremented, unless NULL.
   */
      char_u *
! skip_regexp_ex(
      char_u    *startp,
      int               dirc,
      int               magic,
!     char_u    **newp,
!     int               *dropped)
  {
      int               mymagic;
      char_u    *p = startp;
***************
*** 579,584 ****
--- 593,600 ----
                    if (*newp != NULL)
                        p = *newp + (p - startp);
                }
+               if (dropped != NULL)
+                   ++*dropped;
                if (*newp != NULL)
                    STRMOVE(p, p + 1);
                else
*** ../vim-8.2.0501/src/proto/regexp.pro        2020-02-12 22:15:14.856205206 
+0100
--- src/proto/regexp.pro        2020-04-02 21:06:37.613688311 +0200
***************
*** 1,6 ****
  /* regexp.c */
  int re_multiline(regprog_T *prog);
! char_u *skip_regexp(char_u *startp, int dirc, int magic, char_u **newp);
  reg_extmatch_T *ref_extmatch(reg_extmatch_T *em);
  void unref_extmatch(reg_extmatch_T *em);
  char_u *regtilde(char_u *source, int magic);
--- 1,7 ----
  /* regexp.c */
  int re_multiline(regprog_T *prog);
! char_u *skip_regexp(char_u *startp, int dirc, int magic);
! char_u *skip_regexp_ex(char_u *startp, int dirc, int magic, char_u **newp, 
int *dropped);
  reg_extmatch_T *ref_extmatch(reg_extmatch_T *em);
  void unref_extmatch(reg_extmatch_T *em);
  char_u *regtilde(char_u *source, int magic);
*** ../vim-8.2.0501/src/cmdexpand.c     2020-04-02 18:50:42.415773144 +0200
--- src/cmdexpand.c     2020-04-02 21:07:00.233616784 +0200
***************
*** 1389,1395 ****
                if (*arg != NUL)
                {
                    xp->xp_context = EXPAND_NOTHING;
!                   arg = skip_regexp(arg + 1, *arg, p_magic, NULL);
                }
            }
            return find_nextcmd(arg);
--- 1389,1395 ----
                if (*arg != NUL)
                {
                    xp->xp_context = EXPAND_NOTHING;
!                   arg = skip_regexp(arg + 1, *arg, p_magic);
                }
            }
            return find_nextcmd(arg);
***************
*** 1427,1433 ****
            {
                // skip "from" part
                ++arg;
!               arg = skip_regexp(arg, delim, p_magic, NULL);
            }
            // skip "to" part
            while (arg[0] != NUL && arg[0] != delim)
--- 1427,1433 ----
            {
                // skip "from" part
                ++arg;
!               arg = skip_regexp(arg, delim, p_magic);
            }
            // skip "to" part
            while (arg[0] != NUL && arg[0] != delim)
*** ../vim-8.2.0501/src/ex_cmds.c       2020-03-19 12:38:16.557889484 +0100
--- src/ex_cmds.c       2020-04-02 21:07:27.865528855 +0200
***************
*** 451,457 ****
        }
        else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL)
        {
!           s = skip_regexp(p + 1, *p, TRUE, NULL);
            if (*s != *p)
            {
                emsg(_(e_invalpat));
--- 451,457 ----
        }
        else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL)
        {
!           s = skip_regexp(p + 1, *p, TRUE);
            if (*s != *p)
            {
                emsg(_(e_invalpat));
***************
*** 3626,3632 ****
            which_pat = RE_LAST;            // use last used regexp
            delimiter = *cmd++;             // remember delimiter character
            pat = cmd;                      // remember start of search pat
!           cmd = skip_regexp(cmd, delimiter, p_magic, &eap->arg);
            if (cmd[0] == delimiter)        // end delimiter found
                *cmd++ = NUL;               // replace it with a NUL
        }
--- 3626,3632 ----
            which_pat = RE_LAST;            // use last used regexp
            delimiter = *cmd++;             // remember delimiter character
            pat = cmd;                      // remember start of search pat
!           cmd = skip_regexp_ex(cmd, delimiter, p_magic, &eap->arg, NULL);
            if (cmd[0] == delimiter)        // end delimiter found
                *cmd++ = NUL;               // replace it with a NUL
        }
***************
*** 4801,4807 ****
        if (delim)
            ++cmd;              // skip delimiter if there is one
        pat = cmd;              // remember start of pattern
!       cmd = skip_regexp(cmd, delim, p_magic, &eap->arg);
        if (cmd[0] == delim)                // end delimiter found
            *cmd++ = NUL;                   // replace it with a NUL
      }
--- 4801,4807 ----
        if (delim)
            ++cmd;              // skip delimiter if there is one
        pat = cmd;              // remember start of pattern
!       cmd = skip_regexp_ex(cmd, delim, p_magic, &eap->arg, NULL);
        if (cmd[0] == delim)                // end delimiter found
            *cmd++ = NUL;                   // replace it with a NUL
      }
***************
*** 6441,6447 ****
        if (s != NULL)
            *s = p + 1;
        c = *p;
!       p = skip_regexp(p + 1, c, TRUE, NULL);
        if (*p != c)
            return NULL;
  
--- 6441,6447 ----
        if (s != NULL)
            *s = p + 1;
        c = *p;
!       p = skip_regexp(p + 1, c, TRUE);
        if (*p != c)
            return NULL;
  
*** ../vim-8.2.0501/src/ex_docmd.c      2020-03-18 15:23:10.979695103 +0100
--- src/ex_docmd.c      2020-04-02 21:07:50.173457454 +0200
***************
*** 3663,3669 ****
                }
                if (skip)       // skip "/pat/"
                {
!                   cmd = skip_regexp(cmd, c, (int)p_magic, NULL);
                    if (*cmd == c)
                        ++cmd;
                }
--- 3663,3669 ----
                }
                if (skip)       // skip "/pat/"
                {
!                   cmd = skip_regexp(cmd, c, (int)p_magic);
                    if (*cmd == c)
                        ++cmd;
                }
***************
*** 6123,6129 ****
      {
        // ":open /pattern/": put cursor in column found with pattern
        ++eap->arg;
!       p = skip_regexp(eap->arg, '/', p_magic, NULL);
        *p = NUL;
        regmatch.regprog = vim_regcomp(eap->arg, p_magic ? RE_MAGIC : 0);
        if (regmatch.regprog != NULL)
--- 6123,6129 ----
      {
        // ":open /pattern/": put cursor in column found with pattern
        ++eap->arg;
!       p = skip_regexp(eap->arg, '/', p_magic);
        *p = NUL;
        regmatch.regprog = vim_regcomp(eap->arg, p_magic ? RE_MAGIC : 0);
        if (regmatch.regprog != NULL)
***************
*** 7857,7863 ****
      {
        whole = FALSE;
        ++eap->arg;
!       p = skip_regexp(eap->arg, '/', p_magic, NULL);
        if (*p)
        {
            *p++ = NUL;
--- 7857,7863 ----
      {
        whole = FALSE;
        ++eap->arg;
!       p = skip_regexp(eap->arg, '/', p_magic);
        if (*p)
        {
            *p++ = NUL;
*** ../vim-8.2.0501/src/ex_eval.c       2020-01-26 15:52:33.019833259 +0100
--- src/ex_eval.c       2020-04-02 21:07:58.309431320 +0200
***************
*** 1527,1533 ****
      else
      {
        pat = eap->arg + 1;
!       end = skip_regexp(pat, *eap->arg, TRUE, NULL);
      }
  
      if (!give_up)
--- 1527,1533 ----
      else
      {
        pat = eap->arg + 1;
!       end = skip_regexp(pat, *eap->arg, TRUE);
      }
  
      if (!give_up)
*** ../vim-8.2.0501/src/ex_getln.c      2020-03-19 18:46:53.956641477 +0100
--- src/ex_getln.c      2020-04-02 21:08:03.381414988 +0200
***************
*** 277,283 ****
      p = skipwhite(p);
      delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++;
      *search_delim = delim;
!     end = skip_regexp(p, delim, p_magic, NULL);
  
      use_last_pat = end == p && *end == delim;
  
--- 277,283 ----
      p = skipwhite(p);
      delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++;
      *search_delim = delim;
!     end = skip_regexp(p, delim, p_magic);
  
      use_last_pat = end == p && *end == delim;
  
*** ../vim-8.2.0501/src/highlight.c     2020-03-23 21:45:25.719928947 +0100
--- src/highlight.c     2020-04-02 21:08:09.413395558 +0200
***************
*** 4964,4970 ****
            semsg(_(e_invarg2), eap->arg);
            return;
        }
!       end = skip_regexp(p + 1, *p, TRUE, NULL);
        if (!eap->skip)
        {
            if (*end != NUL && !ends_excmd(*skipwhite(end + 1)))
--- 4964,4970 ----
            semsg(_(e_invarg2), eap->arg);
            return;
        }
!       end = skip_regexp(p + 1, *p, TRUE);
        if (!eap->skip)
        {
            if (*end != NUL && !ends_excmd(*skipwhite(end + 1)))
*** ../vim-8.2.0501/src/search.c        2020-02-21 21:30:33.871979710 +0100
--- src/search.c        2020-04-02 21:08:19.045364490 +0200
***************
*** 1312,1318 ****
             * If there is a matching '/' or '?', toss it.
             */
            ps = strcopy;
!           p = skip_regexp(pat, search_delim, (int)p_magic, &strcopy);
            if (strcopy != ps)
            {
                // made a copy of "pat" to change "\?" to "?"
--- 1312,1318 ----
             * If there is a matching '/' or '?', toss it.
             */
            ps = strcopy;
!           p = skip_regexp_ex(pat, search_delim, (int)p_magic, &strcopy, NULL);
            if (strcopy != ps)
            {
                // made a copy of "pat" to change "\?" to "?"
*** ../vim-8.2.0501/src/syntax.c        2020-01-26 15:52:33.023833239 +0100
--- src/syntax.c        2020-04-02 21:08:35.761310404 +0200
***************
*** 5598,5604 ****
      if (arg == NULL || arg[0] == NUL || arg[1] == NUL || arg[2] == NUL)
        return NULL;
  
!     end = skip_regexp(arg + 1, *arg, TRUE, NULL);
      if (*end != *arg)                     // end delimiter not found
      {
        semsg(_("E401: Pattern delimiter not found: %s"), arg);
--- 5598,5604 ----
      if (arg == NULL || arg[0] == NUL || arg[1] == NUL || arg[2] == NUL)
        return NULL;
  
!     end = skip_regexp(arg + 1, *arg, TRUE);
      if (*end != *arg)                     // end delimiter not found
      {
        semsg(_("E401: Pattern delimiter not found: %s"), arg);
***************
*** 5775,5781 ****
                finished = TRUE;
                break;
            }
!           arg_end = skip_regexp(next_arg + 1, *next_arg, TRUE, NULL);
            if (*arg_end != *next_arg)      // end delimiter not found
            {
                illegal = TRUE;
--- 5775,5781 ----
                finished = TRUE;
                break;
            }
!           arg_end = skip_regexp(next_arg + 1, *next_arg, TRUE);
            if (*arg_end != *next_arg)      // end delimiter not found
            {
                illegal = TRUE;
*** ../vim-8.2.0501/src/tag.c   2020-04-02 18:50:42.427773097 +0200
--- src/tag.c   2020-04-02 21:08:46.469275665 +0200
***************
*** 3530,3536 ****
         */
        str = pbuf;
        if (pbuf[0] == '/' || pbuf[0] == '?')
!           str = skip_regexp(pbuf + 1, pbuf[0], FALSE, NULL) + 1;
        if (str > pbuf_end - 1) // search command with nothing following
        {
            save_p_ws = p_ws;
--- 3530,3536 ----
         */
        str = pbuf;
        if (pbuf[0] == '/' || pbuf[0] == '?')
!           str = skip_regexp(pbuf + 1, pbuf[0], FALSE) + 1;
        if (str > pbuf_end - 1) // search command with nothing following
        {
            save_p_ws = p_ws;
***************
*** 3820,3826 ****
            str = skipdigits(str);
        else if (*str == '/' || *str == '?')
        {
!           str = skip_regexp(str + 1, *str, FALSE, NULL);
            if (*str != first_char)
                str = NULL;
            else
--- 3820,3826 ----
            str = skipdigits(str);
        else if (*str == '/' || *str == '?')
        {
!           str = skip_regexp(str + 1, *str, FALSE);
            if (*str != first_char)
                str = NULL;
            else
*** ../vim-8.2.0501/src/userfunc.c      2020-04-02 18:50:42.431773081 +0200
--- src/userfunc.c      2020-04-02 21:08:52.053257500 +0200
***************
*** 2330,2336 ****
       */
      if (*eap->arg == '/')
      {
!       p = skip_regexp(eap->arg + 1, '/', TRUE, NULL);
        if (!eap->skip)
        {
            regmatch_T  regmatch;
--- 2330,2336 ----
       */
      if (*eap->arg == '/')
      {
!       p = skip_regexp(eap->arg + 1, '/', TRUE);
        if (!eap->skip)
        {
            regmatch_T  regmatch;
*** ../vim-8.2.0501/src/testdir/test_vim9_script.vim    2020-04-02 
19:12:05.018697677 +0200
--- src/testdir/test_vim9_script.vim    2020-04-02 20:47:49.081163462 +0200
***************
*** 468,479 ****
--- 468,487 ----
      seq ..= 'b'
    catch /asdf/
      seq ..= 'x'
+   catch ?a\?sdf?
+     seq ..= 'y'
    finally
      seq ..= 'c'
    endtry
    assert_equal('abc', seq)
  enddef
  
+ def Test_try_catch_fails()
+   call CheckDefFailure(['catch'], 'E603:')
+   call CheckDefFailure(['try', 'echo 0', 'catch','catch'], 'E1033:')
+   call CheckDefFailure(['try', 'echo 0', 'catch /pat'], 'E1067:')
+ enddef
+ 
  let s:export_script_lines =<< trim END
    vim9script
    let name: string = 'bob'
***************
*** 926,931 ****
--- 934,946 ----
    assert_equal('three', IfElse(3))
  enddef
  
+ def Test_if_elseif_else_fails()
+   call CheckDefFailure(['elseif true'], 'E582:')
+   call CheckDefFailure(['else'], 'E581:')
+   call CheckDefFailure(['endif'], 'E580:')
+   call CheckDefFailure(['if true', 'elseif xxx'], 'E1001:')
+ enddef
+ 
  let g:bool_true = v:true
  let g:bool_false = v:false
  
***************
*** 973,978 ****
--- 988,999 ----
    assert_equal(false, res)
  
    res = false
+   if has('xyz') ? true : false
+     res = true
+   endif
+   assert_equal(false, res)
+ 
+   res = false
    if true && true
      res = true
    endif
***************
*** 1030,1035 ****
--- 1051,1058 ----
  def Test_if_const_expr_fails()
    call CheckDefFailure(['if "aaa" == "bbb'], 'E114:')
    call CheckDefFailure(["if 'aaa' == 'bbb"], 'E115:')
+   call CheckDefFailure(["if has('aaa'"], 'E110:')
+   call CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
  enddef
  
  def Test_delfunc()
***************
*** 1096,1101 ****
--- 1119,1148 ----
    delete('Xvim9for.vim')
  enddef
  
+ def Test_for_loop()
+   let result = ''
+   for cnt in range(7)
+     if cnt == 4
+       break
+     endif
+     if cnt == 2
+       continue
+     endif
+     result ..= cnt .. '_'
+   endfor
+   assert_equal('0_1_3_', result)
+ enddef
+ 
+ def Test_for_loop_fails()
+   call CheckDefFailure(['for # in range(5)'], 'E690:')
+   call CheckDefFailure(['for i In range(5)'], 'E690:')
+   call CheckDefFailure(['let x = 5', 'for x in range(5)'], 'E1023:')
+   call CheckScriptFailure(['def Func(arg)', 'for arg in range(5)', 'enddef'], 
'E1006:')
+   call CheckDefFailure(['for i in "text"'], 'E1024:')
+   call CheckDefFailure(['for i in xxx'], 'E1001:')
+   call CheckDefFailure(['endfor'], 'E588:')
+ enddef
+ 
  def Test_while_loop()
    let result = ''
    let cnt = 0
***************
*** 1112,1123 ****
    assert_equal('1_3_', result)
  enddef
  
! def Test_for_loop_fails()
!   call CheckDefFailure(['for # in range(5)'], 'E690:')
!   call CheckDefFailure(['for i In range(5)'], 'E690:')
!   call CheckDefFailure(['let x = 5', 'for x in range(5)'], 'E1023:')
!   call CheckScriptFailure(['def Func(arg)', 'for arg in range(5)', 'enddef'], 
'E1006:')
!   call CheckDefFailure(['for i in "text"'], 'E1024:')
  enddef
  
  def Test_interrupt_loop()
--- 1159,1171 ----
    assert_equal('1_3_', result)
  enddef
  
! def Test_while_loop_fails()
!   call CheckDefFailure(['while xxx'], 'E1001:')
!   call CheckDefFailure(['endwhile'], 'E588:')
!   call CheckDefFailure(['continue'], 'E586:')
!   call CheckDefFailure(['if true', 'continue'], 'E586:')
!   call CheckDefFailure(['break'], 'E587:')
!   call CheckDefFailure(['if true', 'break'], 'E587:')
  enddef
  
  def Test_interrupt_loop()
*** ../vim-8.2.0501/src/testdir/test_vim9_disassemble.vim       2020-04-02 
13:49:23.744286754 +0200
--- src/testdir/test_vim9_disassemble.vim       2020-04-02 20:21:04.987979692 
+0200
***************
*** 809,814 ****
--- 809,816 ----
    let cases = [
          \ ['"xx" == "yy"', false],
          \ ['"aa" == "aa"', true],
+         \ ['has("eval") ? true : false', true],
+         \ ['has("asdf") ? true : false', false],
          \ ]
  
    let nr = 1
*** ../vim-8.2.0501/src/version.c       2020-04-02 19:12:05.018697677 +0200
--- src/version.c       2020-04-02 19:51:40.073804579 +0200
***************
*** 740,741 ****
--- 740,743 ----
  {   /* Add new patch number below this line */
+ /**/
+     502,
  /**/

-- 
Shaw's Principle: Build a system that even a fool can use, and
only a fool will want to use it.

 /// 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/202004021913.032JDrrw005654%40masaka.moolenaar.net.

Raspunde prin e-mail lui