To: vim_dev@googlegroups.com Subject: Patch 8.2.0502 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 -- Bram@Moolenaar.net -- 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 ///