changeset 19892:5feb426d2ea1 v8.2.0502

patch 8.2.0502: Vim9: some code is not tested Commit: https://github.com/vim/vim/commit/e8c4abbbd711af8fd3ed85ea69e9ac3d63a0d879 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Apr 2 21:13:25 2020 +0200 patch 8.2.0502: Vim9: some code is not tested Problem: Vim9: some code is not tested. Solution: Add more tests. Fix uncovered problems.
author Bram Moolenaar <Bram@vim.org>
date Thu, 02 Apr 2020 21:15:04 +0200
parents e1168788aa04
children 4966949f841a
files src/cmdexpand.c src/ex_cmds.c src/ex_docmd.c src/ex_eval.c src/ex_getln.c src/highlight.c src/proto/regexp.pro src/regexp.c src/search.c src/syntax.c src/tag.c src/testdir/test_vim9_disassemble.vim src/testdir/test_vim9_script.vim src/userfunc.c src/version.c src/vim9compile.c
diffstat 16 files changed, 106 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/src/cmdexpand.c
+++ b/src/cmdexpand.c
@@ -1389,7 +1389,7 @@ set_one_cmd_context(
 		if (*arg != NUL)
 		{
 		    xp->xp_context = EXPAND_NOTHING;
-		    arg = skip_regexp(arg + 1, *arg, p_magic, NULL);
+		    arg = skip_regexp(arg + 1, *arg, p_magic);
 		}
 	    }
 	    return find_nextcmd(arg);
@@ -1427,7 +1427,7 @@ set_one_cmd_context(
 	    {
 		// skip "from" part
 		++arg;
-		arg = skip_regexp(arg, delim, p_magic, NULL);
+		arg = skip_regexp(arg, delim, p_magic);
 	    }
 	    // skip "to" part
 	    while (arg[0] != NUL && arg[0] != delim)
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -451,7 +451,7 @@ ex_sort(exarg_T *eap)
 	}
 	else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL)
 	{
-	    s = skip_regexp(p + 1, *p, TRUE, NULL);
+	    s = skip_regexp(p + 1, *p, TRUE);
 	    if (*s != *p)
 	    {
 		emsg(_(e_invalpat));
@@ -3626,7 +3626,7 @@ do_sub(exarg_T *eap)
 	    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);
+	    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,7 +4801,7 @@ ex_global(exarg_T *eap)
 	if (delim)
 	    ++cmd;		// skip delimiter if there is one
 	pat = cmd;		// remember start of pattern
-	cmd = skip_regexp(cmd, delim, p_magic, &eap->arg);
+	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,7 +6441,7 @@ skip_vimgrep_pat(char_u *p, char_u **s, 
 	if (s != NULL)
 	    *s = p + 1;
 	c = *p;
-	p = skip_regexp(p + 1, c, TRUE, NULL);
+	p = skip_regexp(p + 1, c, TRUE);
 	if (*p != c)
 	    return NULL;
 
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -3663,7 +3663,7 @@ get_address(
 		}
 		if (skip)	// skip "/pat/"
 		{
-		    cmd = skip_regexp(cmd, c, (int)p_magic, NULL);
+		    cmd = skip_regexp(cmd, c, (int)p_magic);
 		    if (*cmd == c)
 			++cmd;
 		}
@@ -6123,7 +6123,7 @@ ex_open(exarg_T *eap)
     {
 	// ":open /pattern/": put cursor in column found with pattern
 	++eap->arg;
-	p = skip_regexp(eap->arg, '/', p_magic, NULL);
+	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,7 +7857,7 @@ ex_findpat(exarg_T *eap)
     {
 	whole = FALSE;
 	++eap->arg;
-	p = skip_regexp(eap->arg, '/', p_magic, NULL);
+	p = skip_regexp(eap->arg, '/', p_magic);
 	if (*p)
 	{
 	    *p++ = NUL;
--- a/src/ex_eval.c
+++ b/src/ex_eval.c
@@ -1527,7 +1527,7 @@ ex_catch(exarg_T *eap)
     else
     {
 	pat = eap->arg + 1;
-	end = skip_regexp(pat, *eap->arg, TRUE, NULL);
+	end = skip_regexp(pat, *eap->arg, TRUE);
     }
 
     if (!give_up)
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -277,7 +277,7 @@ do_incsearch_highlighting(int firstc, in
     p = skipwhite(p);
     delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++;
     *search_delim = delim;
-    end = skip_regexp(p, delim, p_magic, NULL);
+    end = skip_regexp(p, delim, p_magic);
 
     use_last_pat = end == p && *end == delim;
 
--- a/src/highlight.c
+++ b/src/highlight.c
@@ -4964,7 +4964,7 @@ ex_match(exarg_T *eap)
 	    semsg(_(e_invarg2), eap->arg);
 	    return;
 	}
-	end = skip_regexp(p + 1, *p, TRUE, NULL);
+	end = skip_regexp(p + 1, *p, TRUE);
 	if (!eap->skip)
 	{
 	    if (*end != NUL && !ends_excmd(*skipwhite(end + 1)))
--- a/src/proto/regexp.pro
+++ b/src/proto/regexp.pro
@@ -1,6 +1,7 @@
 /* regexp.c */
 int re_multiline(regprog_T *prog);
-char_u *skip_regexp(char_u *startp, int dirc, int magic, char_u **newp);
+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);
--- a/src/regexp.c
+++ b/src/regexp.c
@@ -537,16 +537,30 @@ skip_anyof(char_u *p)
  * 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)
+{
+    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)
+    char_u	**newp,
+    int		*dropped)
 {
     int		mymagic;
     char_u	*p = startp;
@@ -579,6 +593,8 @@ skip_regexp(
 		    if (*newp != NULL)
 			p = *newp + (p - startp);
 		}
+		if (dropped != NULL)
+		    ++*dropped;
 		if (*newp != NULL)
 		    STRMOVE(p, p + 1);
 		else
--- a/src/search.c
+++ b/src/search.c
@@ -1312,7 +1312,7 @@ do_search(
 	     * If there is a matching '/' or '?', toss it.
 	     */
 	    ps = strcopy;
-	    p = skip_regexp(pat, search_delim, (int)p_magic, &strcopy);
+	    p = skip_regexp_ex(pat, search_delim, (int)p_magic, &strcopy, NULL);
 	    if (strcopy != ps)
 	    {
 		// made a copy of "pat" to change "\?" to "?"
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -5598,7 +5598,7 @@ get_syn_pattern(char_u *arg, synpat_T *c
     if (arg == NULL || arg[0] == NUL || arg[1] == NUL || arg[2] == NUL)
 	return NULL;
 
-    end = skip_regexp(arg + 1, *arg, TRUE, NULL);
+    end = skip_regexp(arg + 1, *arg, TRUE);
     if (*end != *arg)			    // end delimiter not found
     {
 	semsg(_("E401: Pattern delimiter not found: %s"), arg);
@@ -5775,7 +5775,7 @@ syn_cmd_sync(exarg_T *eap, int syncing U
 		finished = TRUE;
 		break;
 	    }
-	    arg_end = skip_regexp(next_arg + 1, *next_arg, TRUE, NULL);
+	    arg_end = skip_regexp(next_arg + 1, *next_arg, TRUE);
 	    if (*arg_end != *next_arg)	    // end delimiter not found
 	    {
 		illegal = TRUE;
--- a/src/tag.c
+++ b/src/tag.c
@@ -3530,7 +3530,7 @@ jumpto_tag(
 	 */
 	str = pbuf;
 	if (pbuf[0] == '/' || pbuf[0] == '?')
-	    str = skip_regexp(pbuf + 1, pbuf[0], FALSE, NULL) + 1;
+	    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,7 +3820,7 @@ find_extra(char_u **pp)
 	    str = skipdigits(str);
 	else if (*str == '/' || *str == '?')
 	{
-	    str = skip_regexp(str + 1, *str, FALSE, NULL);
+	    str = skip_regexp(str + 1, *str, FALSE);
 	    if (*str != first_char)
 		str = NULL;
 	    else
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -809,6 +809,8 @@ def Test_disassemble_compare_const()
   let cases = [
         \ ['"xx" == "yy"', false],
         \ ['"aa" == "aa"', true],
+        \ ['has("eval") ? true : false', true],
+        \ ['has("asdf") ? true : false', false],
         \ ]
 
   let nr = 1
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -468,12 +468,20 @@ def Test_try_catch_match()
     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,6 +934,13 @@ def Test_if_elseif_else()
   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,6 +988,12 @@ def Test_if_const_expr()
   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,6 +1051,8 @@ enddef
 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,6 +1119,30 @@ def Test_for_outside_of_function()
   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,12 +1159,13 @@ def Test_while_loop()
   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:')
+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()
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -2330,7 +2330,7 @@ ex_function(exarg_T *eap)
      */
     if (*eap->arg == '/')
     {
-	p = skip_regexp(eap->arg + 1, '/', TRUE, NULL);
+	p = skip_regexp(eap->arg + 1, '/', TRUE);
 	if (!eap->skip)
 	{
 	    regmatch_T	regmatch;
--- a/src/version.c
+++ b/src/version.c
@@ -739,6 +739,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    502,
+/**/
     501,
 /**/
     500,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -4095,7 +4095,7 @@ evaluate_const_expr7(char_u **arg, cctx_
 	*arg = skipwhite(*arg);
 	if (**arg != ')')
 	    return FAIL;
-	*arg = skipwhite(*arg + 1);
+	*arg = *arg + 1;
 
 	argvars[0] = *tv;
 	argvars[1].v_type = VAR_UNKNOWN;
@@ -4269,6 +4269,7 @@ evaluate_const_expr1(char_u **arg, cctx_
 	int		val = tv2bool(tv);
 	typval_T	tv2;
 
+	// require space before and after the ?
 	if (!VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[1]))
 	    return FAIL;
 
@@ -4553,6 +4554,7 @@ compile_for(char_u *arg, cctx_T *cctx)
     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,12 +4901,13 @@ compile_catch(char_u *arg, cctx_T *cctx 
 	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(p + 1, *p, TRUE, &tofree);
+	end = skip_regexp_ex(p + 1, *p, TRUE, &tofree, &dropped);
 	if (*end != *p)
 	{
 	    semsg(_("E1067: Separator mismatch: %s"), p);
@@ -4914,10 +4917,10 @@ compile_catch(char_u *arg, cctx_T *cctx 
 	if (tofree == NULL)
 	    len = (int)(end - (p + 1));
 	else
-	    len = (int)(end - (tofree + 1));
-	pat = vim_strnsave(p + 1, len);
+	    len = (int)(end - tofree);
+	pat = vim_strnsave(tofree == NULL ? p + 1 : tofree, len);
 	vim_free(tofree);
-	p += len + 2;
+	p += len + 2 + dropped;
 	if (pat == NULL)
 	    return FAIL;
 	if (generate_PUSHS(cctx, pat) == FAIL)