Compare commits

..

5 Commits

Author SHA1 Message Date
Bram Moolenaar
acbae18df5 patch 8.2.2139: Vim9: unreachable code in assignment
Problem:    Vim9: unreachable code in assignment.
Solution:   Don't check "new_local" when "has_index" is set.  Add test for
            wrong type of list index.
2020-12-13 18:44:43 +01:00
Bram Moolenaar
b5b9480ee9 patch 8.2.2138: Vim9: "exit_cb" causes Vim to exit
Problem:    Vim9: "exit_cb" causes Vim to exit.
Solution:   Require white space after a command in Vim9 script. (closes #7467)
            Also fix that Vim9 style heredoc was not always recognized.
2020-12-13 17:50:20 +01:00
Bram Moolenaar
e498429087 patch 8.2.2137: Vim9: :echo and :execute give error for empty argument
Problem:    Vim9: :echo and :execute give error for empty argument.
Solution:   Ignore an empty argument. (closes #7468)
2020-12-13 14:19:25 +01:00
Bram Moolenaar
c530852315 patch 8.2.2136: Vim9: Using uninitialized variable
Problem:    Vim9: Using uninitialized variable.
Solution:   Initialize "len" to zero.  Clean up fnamemodify().
2020-12-13 12:25:35 +01:00
Bram Moolenaar
93f82cbee5 patch 8.2.2135: Vim9: #{ still seen as start of dict in some places
Problem:    Vim9: #{ still seen as start of dict in some places.
Solution:   Remove check for { after #. (closes #7456)
2020-12-12 21:25:56 +01:00
11 changed files with 147 additions and 53 deletions

View File

@@ -61,7 +61,7 @@ EXTERN char e_argument_nr_type_mismatch_expected_str_but_got_str[]
INIT(= N_("E1013: Argument %d: type mismatch, expected %s but got %s"));
EXTERN char e_invalid_key_str[]
INIT(= N_("E1014: Invalid key: %s"));
EXTERN char e_name_expected[]
EXTERN char e_name_expected_str[]
INIT(= N_("E1015: Name expected: %s"));
EXTERN char e_cannot_declare_a_scope_variable[]
INIT(= N_("E1016: Cannot declare a %s variable: %s"));
@@ -315,3 +315,9 @@ EXTERN char e_indexable_type_required[]
INIT(= N_("E1141: Indexable type required"));
EXTERN char e_non_empty_string_required[]
INIT(= N_("E1142: Non-empty string required"));
EXTERN char e_empty_expression_str[]
INIT(= N_("E1143: Empty expression: \"%s\""));
EXTERN char e_command_not_followed_by_white_space_str[]
INIT(= N_("E1144: Command is not followed by white space: %s"));
EXTERN char e_missing_heredoc_end_marker_str[]
INIT(= N_("E1145: Missing heredoc end marker: %s"));

View File

@@ -55,6 +55,7 @@
#define EX_LOCK_OK 0x1000000 // command can be executed when textlock is
// set; when missing disallows editing another
// buffer when curbuf_lock is set
#define EX_NONWHITE_OK 0x2000000 // command can be followed by non-white
#define EX_FILES (EX_XFILE | EX_EXTRA) // multiple extra files allowed
#define EX_FILE1 (EX_FILES | EX_NOSPC) // 1 file, defaults to current file
@@ -632,7 +633,7 @@ EXCMD(CMD_function, "function", ex_function,
EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
ADDR_NONE),
EXCMD(CMD_global, "global", ex_global,
EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_EXTRA|EX_DFLALL|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_EXTRA|EX_DFLALL|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
ADDR_LINES),
EXCMD(CMD_goto, "goto", ex_goto,
EX_RANGE|EX_COUNT|EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
@@ -1277,7 +1278,7 @@ EXCMD(CMD_rviminfo, "rviminfo", ex_viminfo,
EX_BANG|EX_FILE1|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
ADDR_NONE),
EXCMD(CMD_substitute, "substitute", ex_substitute,
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK,
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
ADDR_LINES),
EXCMD(CMD_sNext, "sNext", ex_previous,
EX_EXTRA|EX_RANGE|EX_COUNT|EX_BANG|EX_CMDARG|EX_ARGOPT|EX_TRLBAR,
@@ -1652,7 +1653,7 @@ EXCMD(CMD_update, "update", ex_update,
EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_FILE1|EX_ARGOPT|EX_DFLALL|EX_TRLBAR,
ADDR_LINES),
EXCMD(CMD_vglobal, "vglobal", ex_global,
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_DFLALL|EX_CMDWIN|EX_LOCK_OK,
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_DFLALL|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
ADDR_LINES),
EXCMD(CMD_var, "var", ex_var,
EX_EXTRA|EX_NOTRLCOM|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
@@ -1792,16 +1793,16 @@ EXCMD(CMD_z, "z", ex_z,
// commands that don't start with a letter
EXCMD(CMD_bang, "!", ex_bang,
EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_FILES|EX_CMDWIN|EX_LOCK_OK,
EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_FILES|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
ADDR_LINES),
EXCMD(CMD_pound, "#", ex_print,
EX_RANGE|EX_WHOLEFOLD|EX_COUNT|EX_FLAGS|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
ADDR_LINES),
EXCMD(CMD_and, "&", ex_substitute,
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY|EX_NONWHITE_OK,
ADDR_LINES),
EXCMD(CMD_star, "*", ex_at,
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
ADDR_LINES),
EXCMD(CMD_lshift, "<", ex_operators,
EX_RANGE|EX_WHOLEFOLD|EX_COUNT|EX_FLAGS|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
@@ -1813,7 +1814,7 @@ EXCMD(CMD_rshift, ">", ex_operators,
EX_RANGE|EX_WHOLEFOLD|EX_COUNT|EX_FLAGS|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
ADDR_LINES),
EXCMD(CMD_at, "@", ex_at,
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
ADDR_LINES),
EXCMD(CMD_block, "{{{{{{{{", ex_block, // not found normally
0,
@@ -1822,7 +1823,7 @@ EXCMD(CMD_endblock, "}", ex_endblock,
EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
ADDR_NONE),
EXCMD(CMD_tilde, "~", ex_substitute,
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY|EX_NONWHITE_OK,
ADDR_LINES),
// commands that start with an uppercase letter

View File

@@ -1683,7 +1683,7 @@ comment_start(char_u *p, int starts_with_colon UNUSED)
{
#ifdef FEAT_EVAL
if (in_vim9script())
return p[0] == '#' && p[1] != '{' && !starts_with_colon;
return p[0] == '#' && !starts_with_colon;
#endif
return *p == '"';
}
@@ -3528,6 +3528,14 @@ find_ex_command(
if (eap->cmdidx == CMD_final && p - eap->cmd == 4)
eap->cmdidx = CMD_finally;
if (eap->cmdidx != CMD_SIZE && in_vim9script()
&& !IS_WHITE_OR_NUL(*p) && !ends_excmd(*p) && *p != '!'
&& (cmdnames[eap->cmdidx].cmd_argt & EX_NONWHITE_OK) == 0)
{
semsg(_(e_command_not_followed_by_white_space_str), eap->cmd);
eap->cmdidx = CMD_SIZE;
}
return p;
}
@@ -4780,7 +4788,6 @@ separate_nextcmd(exarg_T *eap)
|| (*p == '#'
&& in_vim9script()
&& !(eap->argt & EX_NOTRLCOM)
&& p[1] != '{'
&& p > eap->cmd && VIM_ISWHITE(p[-1]))
#endif
|| *p == '|' || *p == '\n')
@@ -5115,7 +5122,7 @@ ex_blast(exarg_T *eap)
/*
* Check if "c" ends an Ex command.
* In Vim9 script does not check for white space before # or #{.
* In Vim9 script does not check for white space before #.
*/
int
ends_excmd(int c)

View File

@@ -1019,7 +1019,7 @@ f_fnamemodify(typval_T *argvars, typval_T *rettv)
char_u *fname;
char_u *mods;
int usedlen = 0;
int len;
int len = 0;
char_u *fbuf = NULL;
char_u buf[NUMBUFLEN];
@@ -1028,12 +1028,13 @@ f_fnamemodify(typval_T *argvars, typval_T *rettv)
return;
fname = tv_get_string_chk(&argvars[0]);
mods = tv_get_string_buf_chk(&argvars[1], buf);
if (fname == NULL)
if (mods == NULL || fname == NULL)
fname = NULL;
else if (mods != NULL && *mods != NUL)
else
{
len = (int)STRLEN(fname);
(void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
if (mods != NULL && *mods != NUL)
(void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
}
rettv->v_type = VAR_STRING;

View File

@@ -338,7 +338,7 @@ func Test_let_heredoc_fails()
endfunc
END
call writefile(text, 'XheredocFail')
call assert_fails('source XheredocFail', 'E126:')
call assert_fails('source XheredocFail', 'E1145:')
call delete('XheredocFail')
let text =<< trim CodeEnd
@@ -347,7 +347,7 @@ func Test_let_heredoc_fails()
endfunc
CodeEnd
call writefile(text, 'XheredocWrong')
call assert_fails('source XheredocWrong', 'E126:')
call assert_fails('source XheredocWrong', 'E1145:')
call delete('XheredocWrong')
let text =<< trim TEXTend

View File

@@ -326,6 +326,18 @@ def Test_assign_index()
END
CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got dict<unknown>', 3)
lines =<< trim END
var lines: list<string>
lines['a'] = 'asdf'
END
CheckDefFailure(lines, 'E39:', 2)
lines =<< trim END
var lines: string
lines[9] = 'asdf'
END
CheckDefFailure(lines, 'E1141:', 2)
# list of dict
var ld: list<dict<number>>
ld[0] = {}
@@ -982,6 +994,17 @@ def Test_heredoc()
var&lines =<< trim END
x
x
enddef
defcompile
[END]
CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END')
delfunc! g:Func
lines =<< trim [END]
def Func()
var lines =<< trim END
x
x
x
x
x
@@ -991,7 +1014,7 @@ def Test_heredoc()
enddef
call Func()
[END]
CheckScriptFailure(lines, 'E990:')
CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END')
delfunc! g:Func
enddef

View File

@@ -15,6 +15,7 @@ let t:tabpagevar = 't'
def s:ScriptFuncLoad(arg: string)
var local = 1
buffers
echo
echo arg
echo local
echo &lines
@@ -43,14 +44,27 @@ def Test_disassemble_load()
var res = execute('disass s:ScriptFuncLoad')
assert_match('<SNR>\d*_ScriptFuncLoad.*' ..
'buffers.*' ..
' EXEC \+buffers.*' ..
' LOAD arg\[-1\].*' ..
' LOAD $0.*' ..
' LOADOPT &lines.*' ..
' LOADV v:version.*' ..
' LOADS s:scriptvar from .*test_vim9_disassemble.vim.*' ..
' LOADG g:globalvar.*' ..
'buffers\_s*' ..
'\d\+ EXEC \+buffers\_s*' ..
'echo\_s*' ..
'echo arg\_s*' ..
'\d\+ LOAD arg\[-1\]\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo local\_s*' ..
'\d\+ LOAD $0\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo &lines\_s*' ..
'\d\+ LOADOPT &lines\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo v:version\_s*' ..
'\d\+ LOADV v:version\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo s:scriptvar\_s*' ..
'\d\+ LOADS s:scriptvar from .*test_vim9_disassemble.vim\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo g:globalvar\_s*' ..
'\d\+ LOADG g:globalvar\_s*' ..
'\d\+ ECHO 1\_s*' ..
'echo get(g:, "global")\_s*' ..
'\d\+ LOAD g:\_s*' ..
'\d\+ PUSHS "global"\_s*' ..

View File

@@ -620,7 +620,7 @@ def Test_try_catch_fails()
CheckDefFailure(['if 1', 'endtry'], 'E171:')
CheckDefFailure(['try', 'echo 1', 'endtry'], 'E1032:')
CheckDefFailure(['throw'], 'E1015:')
CheckDefFailure(['throw'], 'E1143:')
CheckDefFailure(['throw xxx'], 'E1001:')
enddef
@@ -1719,6 +1719,10 @@ def Test_nested_if()
enddef
def Test_execute_cmd()
# missing argument is ignored
execute
execute # comment
new
setline(1, 'default')
execute 'setline(1, "execute-string")'
@@ -2069,7 +2073,21 @@ def Test_vim9_comment()
CheckScriptSuccess([
'vim9script',
'# something',
'#something',
'#{something',
])
split Xfile
CheckScriptSuccess([
'vim9script',
'edit #something',
])
CheckScriptSuccess([
'vim9script',
'edit #{something',
])
close
CheckScriptFailure([
'vim9script',
':# something',
@@ -2123,9 +2141,6 @@ def Test_vim9_comment()
'vim9script',
'exe "echo"# something',
], 'E121:')
CheckDefFailure([
'exe # comment',
], 'E1015:')
CheckScriptFailure([
'vim9script',
'exe# something',
@@ -2150,7 +2165,7 @@ def Test_vim9_comment()
' throw#comment',
'catch',
'endtry',
], 'E1015:')
], 'E1143:')
CheckDefFailure([
'try',
' throw "yes"#comment',
@@ -3043,7 +3058,7 @@ def Test_put_with_linebreak()
new
var lines =<< trim END
vim9script
pu=split('abc', '\zs')
pu =split('abc', '\zs')
->join()
END
CheckScriptSuccess(lines)
@@ -3064,6 +3079,13 @@ def Test_invoke_normal_in_visual_mode()
xunmap <F3>
enddef
def Test_white_space_after_command()
var lines =<< trim END
exit_cb: Func})
END
CheckDefAndScriptFailure(lines, 'E1144:', 1)
enddef
" Keep this last, it messes up highlighting.
def Test_substitute_cmd()
new

View File

@@ -3185,7 +3185,9 @@ define_function(exarg_T *eap, char_u *name_arg)
lines_left = Rows - 1;
if (theline == NULL)
{
if (eap->cmdidx == CMD_def)
if (skip_until != NULL)
semsg(_(e_missing_heredoc_end_marker_str), skip_until);
else if (eap->cmdidx == CMD_def)
emsg(_(e_missing_enddef));
else
emsg(_("E126: Missing :endfunction"));
@@ -3352,18 +3354,24 @@ define_function(exarg_T *eap, char_u *name_arg)
// Check for ":cmd v =<< [trim] EOF"
// and ":cmd [a, b] =<< [trim] EOF"
// and "lines =<< [trim] EOF" for Vim9
// Where "cmd" can be "let", "var", "final" or "const".
arg = skipwhite(skiptowhite(p));
if (*arg == '[')
arg = vim_strchr(arg, ']');
if (arg != NULL)
{
arg = skipwhite(skiptowhite(arg));
if (arg[0] == '=' && arg[1] == '<' && arg[2] =='<'
int found = (eap->cmdidx == CMD_def && arg[0] == '='
&& arg[1] == '<' && arg[2] =='<');
if (!found)
// skip over the argument after "cmd"
arg = skipwhite(skiptowhite(arg));
if (found || (arg[0] == '=' && arg[1] == '<' && arg[2] =='<'
&& (checkforcmd(&p, "let", 2)
|| checkforcmd(&p, "var", 3)
|| checkforcmd(&p, "final", 5)
|| checkforcmd(&p, "const", 5)))
|| checkforcmd(&p, "const", 5))))
{
p = skipwhite(arg + 3);
if (STRNCMP(p, "trim", 4) == 0)

View File

@@ -750,6 +750,16 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2139,
/**/
2138,
/**/
2137,
/**/
2136,
/**/
2135,
/**/
2134,
/**/

View File

@@ -3975,7 +3975,10 @@ compile_expr7(
if (!eval_isnamec1(**arg))
{
semsg(_(e_name_expected), *arg);
if (ends_excmd(*skipwhite(*arg)))
semsg(_(e_empty_expression_str), *arg);
else
semsg(_(e_name_expected_str), *arg);
return FAIL;
}
@@ -5853,8 +5856,6 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
int r;
// Compile the "idx" in "var[idx]" or "key" in "var.key".
if (new_local)
--cctx->ctx_locals.ga_len;
p = var_start + varlen;
if (*p == '[')
{
@@ -5874,8 +5875,6 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
r = generate_PUSHS(cctx, key);
}
if (new_local)
++cctx->ctx_locals.ga_len;
if (r == FAIL)
goto theend;
@@ -7101,28 +7100,31 @@ compile_throw(char_u *arg, cctx_T *cctx UNUSED)
compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx)
{
char_u *p = arg;
char_u *prev;
char_u *prev = arg;
int count = 0;
for (;;)
{
if (ends_excmd2(prev, p))
break;
if (compile_expr0(&p, cctx) == FAIL)
return NULL;
++count;
prev = p;
p = skipwhite(p);
if (ends_excmd2(prev, p))
break;
}
if (cmdidx == CMD_echo || cmdidx == CMD_echon)
generate_ECHO(cctx, cmdidx == CMD_echo, count);
else if (cmdidx == CMD_execute)
generate_MULT_EXPR(cctx, ISN_EXECUTE, count);
else if (cmdidx == CMD_echomsg)
generate_MULT_EXPR(cctx, ISN_ECHOMSG, count);
else
generate_MULT_EXPR(cctx, ISN_ECHOERR, count);
if (count > 0)
{
if (cmdidx == CMD_echo || cmdidx == CMD_echon)
generate_ECHO(cctx, cmdidx == CMD_echo, count);
else if (cmdidx == CMD_execute)
generate_MULT_EXPR(cctx, ISN_EXECUTE, count);
else if (cmdidx == CMD_echomsg)
generate_MULT_EXPR(cctx, ISN_ECHOMSG, count);
else
generate_MULT_EXPR(cctx, ISN_ECHOERR, count);
}
return p;
}