Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d905c2b96 | ||
|
|
5deeb3f1f9 | ||
|
|
d7ffc0ba8c | ||
|
|
8d4ed11da6 | ||
|
|
cde0ff39da | ||
|
|
d77a8525d5 | ||
|
|
5259275347 | ||
|
|
d1e9dc2723 | ||
|
|
01603a9970 | ||
|
|
3cca299520 | ||
|
|
585fea7b98 |
@@ -1,4 +1,4 @@
|
||||
*vim9.txt* For Vim version 8.2. Last change: 2020 Mar 01
|
||||
*vim9.txt* For Vim version 8.2. Last change: 2020 Apr 03
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -249,8 +249,8 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
|
||||
the function follows in the next lines, until the
|
||||
matching `:enddef`.
|
||||
|
||||
When {return-type} is omitted the function is not
|
||||
expected to return anything.
|
||||
When {return-type} is omitted or is "void" the
|
||||
function is not expected to return anything.
|
||||
|
||||
{arguments} is a sequence of zero or more argument
|
||||
declarations. There are three forms:
|
||||
@@ -296,29 +296,40 @@ The following builtin types are supported:
|
||||
float
|
||||
string
|
||||
blob
|
||||
list<type>
|
||||
dict<type>
|
||||
(a: type, b: type): type
|
||||
list<{type}>
|
||||
dict<{type}>
|
||||
job
|
||||
channel
|
||||
func
|
||||
partial
|
||||
func({type}, ...)
|
||||
func({type}, ...): {type}
|
||||
|
||||
Not supported yet:
|
||||
tuple<a: type, b: type, ...>
|
||||
tuple<a: {type}, b: {type}, ...>
|
||||
|
||||
These types can be used in declarations, but no variable will have this type:
|
||||
type|type
|
||||
These types can be used in declarations, but no value will have this type:
|
||||
{type}|{type}
|
||||
void
|
||||
any
|
||||
|
||||
There is no array type, use list<type> instead. For a list constant an
|
||||
There is no array type, use list<{type}> instead. For a list constant an
|
||||
efficient implementation is used that avoids allocating lot of small pieces of
|
||||
memory.
|
||||
|
||||
A function defined with `:def` must declare the return type. If there is no
|
||||
type then the function doesn't return anything. "void" is used in type
|
||||
declarations.
|
||||
A partial and function can be declared in more or less specific ways:
|
||||
func any kind of function reference, no type
|
||||
checking
|
||||
func: {type} any number and type of arguments with specific
|
||||
return type
|
||||
func({type} ...) function with argument types, does not return
|
||||
a value
|
||||
func({type} ...): {type} function with argument types and return type
|
||||
|
||||
If the return type is "void" the function does not return a value.
|
||||
|
||||
The reference can also be a |Partial|, in which case it stores extra arguments
|
||||
and/or a dictionary, which are not visible to the caller. Since they are
|
||||
called in the same way the declaration is the same.
|
||||
|
||||
Custom types can be defined with `:type`: >
|
||||
:type MyList list<string>
|
||||
|
||||
@@ -110,6 +110,8 @@ find_word_under_cursor(
|
||||
lbuf = vim_strnsave(lbuf, len);
|
||||
}
|
||||
}
|
||||
else
|
||||
scol = col;
|
||||
|
||||
if (winp != NULL)
|
||||
*winp = wp;
|
||||
|
||||
@@ -336,11 +336,6 @@ ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED)
|
||||
return &t_func_any;
|
||||
}
|
||||
static type_T *
|
||||
ret_partial_any(int argcount UNUSED, type_T **argtypes UNUSED)
|
||||
{
|
||||
return &t_partial_any;
|
||||
}
|
||||
static type_T *
|
||||
ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
|
||||
{
|
||||
return &t_channel;
|
||||
@@ -564,7 +559,7 @@ static funcentry_T global_functions[] =
|
||||
{"foldtext", 0, 0, 0, ret_string, f_foldtext},
|
||||
{"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
|
||||
{"foreground", 0, 0, 0, ret_void, f_foreground},
|
||||
{"funcref", 1, 3, FEARG_1, ret_partial_any, f_funcref},
|
||||
{"funcref", 1, 3, FEARG_1, ret_func_any, f_funcref},
|
||||
{"function", 1, 3, FEARG_1, ret_f_function, f_function},
|
||||
{"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
|
||||
{"get", 2, 3, FEARG_1, ret_any, f_get},
|
||||
@@ -961,7 +956,7 @@ static funcentry_T global_functions[] =
|
||||
{"test_null_function", 0, 0, 0, ret_func_any, f_test_null_function},
|
||||
{"test_null_job", 0, 0, 0, ret_job, JOB_FUNC(f_test_null_job)},
|
||||
{"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
|
||||
{"test_null_partial", 0, 0, 0, ret_partial_any, f_test_null_partial},
|
||||
{"test_null_partial", 0, 0, 0, ret_func_any, f_test_null_partial},
|
||||
{"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
|
||||
{"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
|
||||
{"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
|
||||
@@ -2902,7 +2897,7 @@ ret_f_function(int argcount, type_T **argtypes UNUSED)
|
||||
{
|
||||
if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
|
||||
return &t_func_any;
|
||||
return &t_partial_void;
|
||||
return &t_func_void;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -2382,6 +2382,7 @@ find_var(char_u *name, hashtab_T **htp, int no_autoload)
|
||||
|
||||
/*
|
||||
* Find variable "varname" in hashtab "ht" with name "htname".
|
||||
* When "varname" is empty returns curwin/curtab/etc vars dictionary.
|
||||
* Returns NULL if not found.
|
||||
*/
|
||||
dictitem_T *
|
||||
@@ -3503,8 +3504,12 @@ f_getbufvar(typval_T *argvars, typval_T *rettv)
|
||||
else
|
||||
{
|
||||
// Look up the variable.
|
||||
// Let getbufvar({nr}, "") return the "b:" dictionary.
|
||||
v = find_var_in_ht(&buf->b_vars->dv_hashtab, 'b', varname, FALSE);
|
||||
if (*varname == NUL)
|
||||
// Let getbufvar({nr}, "") return the "b:" dictionary.
|
||||
v = &buf->b_bufvar;
|
||||
else
|
||||
v = find_var_in_ht(&buf->b_vars->dv_hashtab, 'b',
|
||||
varname, FALSE);
|
||||
if (v != NULL)
|
||||
{
|
||||
copy_tv(&v->di_tv, rettv);
|
||||
|
||||
@@ -379,36 +379,39 @@ EXTERN sctx_T current_sctx INIT4(0, 0, 0, 0);
|
||||
|
||||
|
||||
// Commonly used types.
|
||||
EXTERN type_T t_any INIT4(VAR_UNKNOWN, 0, NULL, NULL);
|
||||
EXTERN type_T t_void INIT4(VAR_VOID, 0, NULL, NULL);
|
||||
EXTERN type_T t_bool INIT4(VAR_BOOL, 0, NULL, NULL);
|
||||
EXTERN type_T t_special INIT4(VAR_SPECIAL, 0, NULL, NULL);
|
||||
EXTERN type_T t_number INIT4(VAR_NUMBER, 0, NULL, NULL);
|
||||
EXTERN type_T t_float INIT4(VAR_FLOAT, 0, NULL, NULL);
|
||||
EXTERN type_T t_string INIT4(VAR_STRING, 0, NULL, NULL);
|
||||
EXTERN type_T t_blob INIT4(VAR_BLOB, 0, NULL, NULL);
|
||||
EXTERN type_T t_job INIT4(VAR_JOB, 0, NULL, NULL);
|
||||
EXTERN type_T t_channel INIT4(VAR_CHANNEL, 0, NULL, NULL);
|
||||
EXTERN type_T t_any INIT6(VAR_UNKNOWN, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_void INIT6(VAR_VOID, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_bool INIT6(VAR_BOOL, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_special INIT6(VAR_SPECIAL, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_number INIT6(VAR_NUMBER, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_float INIT6(VAR_FLOAT, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_string INIT6(VAR_STRING, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_blob INIT6(VAR_BLOB, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_job INIT6(VAR_JOB, 0, 0, 0, NULL, NULL);
|
||||
EXTERN type_T t_channel INIT6(VAR_CHANNEL, 0, 0, 0, NULL, NULL);
|
||||
|
||||
EXTERN type_T t_func_void INIT4(VAR_FUNC, -1, &t_void, NULL);
|
||||
EXTERN type_T t_func_any INIT4(VAR_FUNC, -1, &t_any, NULL);
|
||||
EXTERN type_T t_func_void INIT6(VAR_FUNC, -1, 0, 0, &t_void, NULL);
|
||||
EXTERN type_T t_func_any INIT6(VAR_FUNC, -1, 0, 0, &t_any, NULL);
|
||||
EXTERN type_T t_func_number INIT6(VAR_FUNC, -1, 0, 0, &t_number, NULL);
|
||||
EXTERN type_T t_func_string INIT6(VAR_FUNC, -1, 0, 0, &t_string, NULL);
|
||||
EXTERN type_T t_func_0_void INIT6(VAR_FUNC, 0, 0, 0, &t_void, NULL);
|
||||
EXTERN type_T t_func_0_any INIT6(VAR_FUNC, 0, 0, 0, &t_any, NULL);
|
||||
EXTERN type_T t_func_0_number INIT6(VAR_FUNC, 0, 0, 0, &t_number, NULL);
|
||||
EXTERN type_T t_func_0_string INIT6(VAR_FUNC, 0, 0, 0, &t_string, NULL);
|
||||
|
||||
EXTERN type_T t_partial_void INIT4(VAR_PARTIAL, -1, &t_void, NULL);
|
||||
EXTERN type_T t_partial_any INIT4(VAR_PARTIAL, -1, &t_any, NULL);
|
||||
EXTERN type_T t_list_any INIT6(VAR_LIST, 0, 0, 0, &t_any, NULL);
|
||||
EXTERN type_T t_dict_any INIT6(VAR_DICT, 0, 0, 0, &t_any, NULL);
|
||||
EXTERN type_T t_list_empty INIT6(VAR_LIST, 0, 0, 0, &t_void, NULL);
|
||||
EXTERN type_T t_dict_empty INIT6(VAR_DICT, 0, 0, 0, &t_void, NULL);
|
||||
|
||||
EXTERN type_T t_list_any INIT4(VAR_LIST, 0, &t_any, NULL);
|
||||
EXTERN type_T t_dict_any INIT4(VAR_DICT, 0, &t_any, NULL);
|
||||
EXTERN type_T t_list_empty INIT4(VAR_LIST, 0, &t_void, NULL);
|
||||
EXTERN type_T t_dict_empty INIT4(VAR_DICT, 0, &t_void, NULL);
|
||||
EXTERN type_T t_list_bool INIT6(VAR_LIST, 0, 0, 0, &t_bool, NULL);
|
||||
EXTERN type_T t_list_number INIT6(VAR_LIST, 0, 0, 0, &t_number, NULL);
|
||||
EXTERN type_T t_list_string INIT6(VAR_LIST, 0, 0, 0, &t_string, NULL);
|
||||
EXTERN type_T t_list_dict_any INIT6(VAR_LIST, 0, 0, 0, &t_dict_any, NULL);
|
||||
|
||||
EXTERN type_T t_list_bool INIT4(VAR_LIST, 0, &t_bool, NULL);
|
||||
EXTERN type_T t_list_number INIT4(VAR_LIST, 0, &t_number, NULL);
|
||||
EXTERN type_T t_list_string INIT4(VAR_LIST, 0, &t_string, NULL);
|
||||
EXTERN type_T t_list_dict_any INIT4(VAR_LIST, 0, &t_dict_any, NULL);
|
||||
|
||||
EXTERN type_T t_dict_bool INIT4(VAR_DICT, 0, &t_bool, NULL);
|
||||
EXTERN type_T t_dict_number INIT4(VAR_DICT, 0, &t_number, NULL);
|
||||
EXTERN type_T t_dict_string INIT4(VAR_DICT, 0, &t_string, NULL);
|
||||
EXTERN type_T t_dict_bool INIT6(VAR_DICT, 0, 0, 0, &t_bool, NULL);
|
||||
EXTERN type_T t_dict_number INIT6(VAR_DICT, 0, 0, 0, &t_number, NULL);
|
||||
EXTERN type_T t_dict_string INIT6(VAR_DICT, 0, 0, 0, &t_string, NULL);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1966,7 +1966,7 @@ parse_command_name(mparm_T *parmp)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Checking for "ex" here may catch some weir names, such as "vimex" or
|
||||
// Checking for "ex" here may catch some weird names, such as "vimex" or
|
||||
// "viewex", we assume the user knows that.
|
||||
if (STRNICMP(initstr, "ex", 2) == 0)
|
||||
{
|
||||
|
||||
@@ -798,16 +798,16 @@ apply_general_options(win_T *wp, dict_T *dict)
|
||||
if (*str != NUL)
|
||||
wp->w_border_char[i] = mb_ptr2char(str);
|
||||
}
|
||||
}
|
||||
if (list->lv_len == 1)
|
||||
for (i = 1; i < 8; ++i)
|
||||
wp->w_border_char[i] = wp->w_border_char[0];
|
||||
if (list->lv_len == 2)
|
||||
{
|
||||
for (i = 4; i < 8; ++i)
|
||||
wp->w_border_char[i] = wp->w_border_char[1];
|
||||
for (i = 1; i < 4; ++i)
|
||||
wp->w_border_char[i] = wp->w_border_char[0];
|
||||
if (list->lv_len == 1)
|
||||
for (i = 1; i < 8; ++i)
|
||||
wp->w_border_char[i] = wp->w_border_char[0];
|
||||
if (list->lv_len == 2)
|
||||
{
|
||||
for (i = 4; i < 8; ++i)
|
||||
wp->w_border_char[i] = wp->w_border_char[1];
|
||||
for (i = 1; i < 4; ++i)
|
||||
wp->w_border_char[i] = wp->w_border_char[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1341,11 +1341,16 @@ typedef enum
|
||||
typedef struct type_S type_T;
|
||||
struct type_S {
|
||||
vartype_T tt_type;
|
||||
short tt_argcount; // for func, partial, -1 for unknown
|
||||
char tt_argcount; // for func, -1 for unknown
|
||||
char tt_min_argcount; // number of non-optional arguments
|
||||
char tt_flags; // TTFLAG_ values
|
||||
type_T *tt_member; // for list, dict, func return type
|
||||
type_T *tt_args; // func arguments
|
||||
type_T **tt_args; // func argument types, allocated
|
||||
};
|
||||
|
||||
#define TTFLAG_VARARGS 1 // func args ends with "..."
|
||||
#define TTFLAG_OPTARG 2 // func arg type with "?"
|
||||
|
||||
/*
|
||||
* Structure to hold an internal variable without a name.
|
||||
*/
|
||||
@@ -1516,7 +1521,7 @@ typedef struct
|
||||
int uf_calls; // nr of active calls
|
||||
int uf_cleared; // func_clear() was already called
|
||||
int uf_dfunc_idx; // >= 0 for :def function only
|
||||
garray_T uf_args; // arguments
|
||||
garray_T uf_args; // arguments, including optional arguments
|
||||
garray_T uf_def_args; // default argument expressions
|
||||
|
||||
// for :def (for :function uf_ret_type is NULL)
|
||||
@@ -1527,6 +1532,7 @@ typedef struct
|
||||
// uf_def_args; length: uf_def_args.ga_len + 1
|
||||
char_u *uf_va_name; // name from "...name" or NULL
|
||||
type_T *uf_va_type; // type from "...name: type" or NULL
|
||||
type_T *uf_func_type; // type of the function, &t_func_any if unknown
|
||||
|
||||
garray_T uf_lines; // function lines
|
||||
# ifdef FEAT_PROFILE
|
||||
|
||||
@@ -274,6 +274,7 @@ NEW_TESTS = \
|
||||
test_vartabs \
|
||||
test_vim9_disassemble \
|
||||
test_vim9_expr \
|
||||
test_vim9_func \
|
||||
test_vim9_script \
|
||||
test_viminfo \
|
||||
test_vimscript \
|
||||
@@ -483,6 +484,7 @@ NEW_TESTS_RES = \
|
||||
test_vartabs.res \
|
||||
test_vim9_disassemble.res \
|
||||
test_vim9_expr.res \
|
||||
test_vim9_func.res \
|
||||
test_vim9_script.res \
|
||||
test_viminfo.res \
|
||||
test_vimscript.res \
|
||||
|
||||
@@ -133,3 +133,13 @@ func CheckNotRoot()
|
||||
throw 'Skipped: cannot run test as root'
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" Command to check that the current language is English
|
||||
command CheckEnglish call CheckEnglish()
|
||||
func CheckEnglish()
|
||||
if v:lang != "C" && v:lang !~ '^[Ee]n'
|
||||
throw 'Skipped: only works in English language environment'
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -337,3 +337,5 @@ func IsRoot()
|
||||
endif
|
||||
return v:false
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -82,6 +82,8 @@ func RunVimInTerminal(arguments, options)
|
||||
let cols = term_getsize(buf)[1]
|
||||
endif
|
||||
|
||||
call term_wait(buf)
|
||||
|
||||
" Wait for "All" or "Top" of the ruler to be shown in the last line or in
|
||||
" the status line of the last window. This can be quite slow (e.g. when
|
||||
" using valgrind).
|
||||
@@ -113,3 +115,5 @@ func StopVimInTerminal(buf)
|
||||
call WaitForAssert({-> assert_equal("finished", term_getstatus(a:buf))})
|
||||
only!
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -6,11 +6,7 @@ CheckFeature clientserver
|
||||
|
||||
source shared.vim
|
||||
|
||||
func Test_client_server()
|
||||
let cmd = GetVimCommand()
|
||||
if cmd == ''
|
||||
return
|
||||
endif
|
||||
func Check_X11_Connection()
|
||||
if has('x11')
|
||||
if empty($DISPLAY)
|
||||
throw 'Skipped: $DISPLAY is not set'
|
||||
@@ -19,11 +15,19 @@ func Test_client_server()
|
||||
call remote_send('xxx', '')
|
||||
catch
|
||||
if v:exception =~ 'E240:'
|
||||
throw 'Skipped: no connection to the X server'
|
||||
throw 'Skipped: no connection to the X server'
|
||||
endif
|
||||
" ignore other errors
|
||||
endtry
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func Test_client_server()
|
||||
let cmd = GetVimCommand()
|
||||
if cmd == ''
|
||||
return
|
||||
endif
|
||||
call Check_X11_Connection()
|
||||
|
||||
let name = 'XVIMTEST'
|
||||
let cmd .= ' --servername ' . name
|
||||
@@ -72,6 +76,10 @@ func Test_client_server()
|
||||
endif
|
||||
let g:testvar = 'myself'
|
||||
call assert_equal('myself', remote_expr(v:servername, 'testvar'))
|
||||
call remote_send(v:servername, ":let g:testvar2 = 75\<CR>")
|
||||
call feedkeys('', 'x')
|
||||
call assert_equal(75, g:testvar2)
|
||||
call assert_fails('let v = remote_expr(v:servername, "/2")', 'E449:')
|
||||
|
||||
call remote_send(name, ":call server2client(expand('<client>'), 'got it')\<CR>", 'g:myserverid')
|
||||
call assert_equal('got it', g:myserverid->remote_read(2))
|
||||
@@ -92,6 +100,55 @@ func Test_client_server()
|
||||
call assert_equal('another', g:peek_result)
|
||||
call assert_equal('another', remote_read(g:myserverid, 2))
|
||||
|
||||
if !has('gui_running')
|
||||
" In GUI vim, the following tests display a dialog box
|
||||
|
||||
let cmd = GetVimProg() .. ' --servername ' .. name
|
||||
|
||||
" Run a separate instance to send a command to the server
|
||||
call remote_expr(name, 'execute("only")')
|
||||
call system(cmd .. ' --remote-send ":new Xfile<CR>"')
|
||||
call assert_equal('2', remote_expr(name, 'winnr("$")'))
|
||||
call assert_equal('Xfile', remote_expr(name, 'winbufnr(1)->bufname()'))
|
||||
call remote_expr(name, 'execute("only")')
|
||||
|
||||
" Invoke a remote-expr. On MS-Windows, the returned value has a carriage
|
||||
" return.
|
||||
let l = system(cmd .. ' --remote-expr "2 + 2"')
|
||||
call assert_equal(['4'], split(l, "\n"))
|
||||
|
||||
" Edit multiple files using --remote
|
||||
call system(cmd .. ' --remote Xfile1 Xfile2 Xfile3')
|
||||
call assert_equal("Xfile1\nXfile2\nXfile3\n", remote_expr(name, 'argv()'))
|
||||
eval name->remote_send(":%bw!\<CR>")
|
||||
|
||||
" Edit files in separate tab pages
|
||||
call system(cmd .. ' --remote-tab Xfile1 Xfile2 Xfile3')
|
||||
call assert_equal('3', remote_expr(name, 'tabpagenr("$")'))
|
||||
call assert_equal('Xfile2', remote_expr(name, 'bufname(tabpagebuflist(2)[0])'))
|
||||
eval name->remote_send(":%bw!\<CR>")
|
||||
|
||||
" Edit a file using --remote-wait
|
||||
eval name->remote_send(":source $VIMRUNTIME/plugin/rrhelper.vim\<CR>")
|
||||
call system(cmd .. ' --remote-wait +enew Xfile1')
|
||||
call assert_equal("Xfile1", remote_expr(name, 'bufname("#")'))
|
||||
eval name->remote_send(":%bw!\<CR>")
|
||||
|
||||
" Edit files using --remote-tab-wait
|
||||
call system(cmd .. ' --remote-tabwait +tabonly\|enew Xfile1 Xfile2')
|
||||
call assert_equal('1', remote_expr(name, 'tabpagenr("$")'))
|
||||
eval name->remote_send(":%bw!\<CR>")
|
||||
|
||||
" Error cases
|
||||
if v:lang == "C" || v:lang =~ '^[Ee]n'
|
||||
let l = split(system(cmd .. ' --remote +pwd'), "\n")
|
||||
call assert_equal("Argument missing after: \"+pwd\"", l[1])
|
||||
endif
|
||||
let l = system(cmd .. ' --remote-expr "abcd"')
|
||||
call assert_match('^E449: ', l)
|
||||
endif
|
||||
|
||||
eval name->remote_send(":%bw!\<CR>")
|
||||
eval name->remote_send(":qa!\<CR>")
|
||||
try
|
||||
call WaitForAssert({-> assert_equal("dead", job_status(job))})
|
||||
@@ -102,8 +159,8 @@ func Test_client_server()
|
||||
endif
|
||||
endtry
|
||||
|
||||
call assert_fails("let x=remote_peek([])", 'E730:')
|
||||
call assert_fails("let x=remote_read('vim10')", 'E277:')
|
||||
call assert_fails("let x = remote_peek([])", 'E730:')
|
||||
call assert_fails("let x = remote_read('vim10')", 'E277:')
|
||||
endfunc
|
||||
|
||||
" Uncomment this line to get a debugging log
|
||||
|
||||
@@ -23,7 +23,7 @@ endfunc
|
||||
|
||||
func Test_cscopeWithCscopeConnections()
|
||||
call CscopeSetupOrClean(1)
|
||||
" Test 0: E568: duplicate cscope database not added
|
||||
" Test: E568: duplicate cscope database not added
|
||||
try
|
||||
set nocscopeverbose
|
||||
cscope add Xcscope.out
|
||||
@@ -34,44 +34,49 @@ func Test_cscopeWithCscopeConnections()
|
||||
call assert_fails('cscope add', 'E560')
|
||||
call assert_fails('cscope add Xcscope.out', 'E568')
|
||||
call assert_fails('cscope add doesnotexist.out', 'E563')
|
||||
if has('unix')
|
||||
call assert_fails('cscope add /dev/null', 'E564:')
|
||||
endif
|
||||
|
||||
" Test 1: Find this C-Symbol
|
||||
" Test: Find this C-Symbol
|
||||
for cmd in ['cs find s main', 'cs find 0 main']
|
||||
let a = execute(cmd)
|
||||
" Test 1.1 test where it moves the cursor
|
||||
" Test where it moves the cursor
|
||||
call assert_equal('main(void)', getline('.'))
|
||||
" Test 1.2 test the output of the :cs command
|
||||
" Test the output of the :cs command
|
||||
call assert_match('\n(1 of 1): <<main>> main(void )', a)
|
||||
endfor
|
||||
|
||||
" Test 2: Find this definition
|
||||
for cmd in ['cs find g test_mf_hash', 'cs find 1 test_mf_hash']
|
||||
" Test: Find this definition
|
||||
for cmd in ['cs find g test_mf_hash',
|
||||
\ 'cs find 1 test_mf_hash',
|
||||
\ 'cs find 1 test_mf_hash'] " leading space ignored.
|
||||
exe cmd
|
||||
call assert_equal(['', '/*', ' * Test mf_hash_*() functions.', ' */', ' static void', 'test_mf_hash(void)', '{'], getline(line('.')-5, line('.')+1))
|
||||
endfor
|
||||
|
||||
" Test 3: Find functions called by this function
|
||||
" Test: Find functions called by this function
|
||||
for cmd in ['cs find d test_mf_hash', 'cs find 2 test_mf_hash']
|
||||
let a = execute(cmd)
|
||||
call assert_match('\n(1 of 42): <<mf_hash_init>> mf_hash_init(&ht);', a)
|
||||
call assert_equal(' mf_hash_init(&ht);', getline('.'))
|
||||
endfor
|
||||
|
||||
" Test 4: Find functions calling this function
|
||||
" Test: Find functions calling this function
|
||||
for cmd in ['cs find c test_mf_hash', 'cs find 3 test_mf_hash']
|
||||
let a = execute(cmd)
|
||||
call assert_match('\n(1 of 1): <<main>> test_mf_hash();', a)
|
||||
call assert_equal(' test_mf_hash();', getline('.'))
|
||||
endfor
|
||||
|
||||
" Test 5: Find this text string
|
||||
" Test: Find this text string
|
||||
for cmd in ['cs find t Bram', 'cs find 4 Bram']
|
||||
let a = execute(cmd)
|
||||
call assert_match('(1 of 1): <<<unknown>>> \* VIM - Vi IMproved^Iby Bram Moolenaar', a)
|
||||
call assert_equal(' * VIM - Vi IMproved by Bram Moolenaar', getline('.'))
|
||||
endfor
|
||||
|
||||
" Test 6: Find this egrep pattern
|
||||
" Test: Find this egrep pattern
|
||||
" test all matches returned by cscope
|
||||
for cmd in ['cs find e ^\#includ.', 'cs find 6 ^\#includ.']
|
||||
let a = execute(cmd)
|
||||
@@ -84,7 +89,7 @@ func Test_cscopeWithCscopeConnections()
|
||||
call assert_fails('cnext', 'E553:')
|
||||
endfor
|
||||
|
||||
" Test 7: Find the same egrep pattern using lcscope this time.
|
||||
" Test: Find the same egrep pattern using lcscope this time.
|
||||
let a = execute('lcs find e ^\#includ.')
|
||||
call assert_match('\n(1 of 3): <<<unknown>>> #include <assert.h>', a)
|
||||
call assert_equal('#include <assert.h>', getline('.'))
|
||||
@@ -94,7 +99,7 @@ func Test_cscopeWithCscopeConnections()
|
||||
call assert_equal('#include "memfile.c"', getline('.'))
|
||||
call assert_fails('lnext', 'E553:')
|
||||
|
||||
" Test 8: Find this file
|
||||
" Test: Find this file
|
||||
for cmd in ['cs find f Xmemfile_test.c', 'cs find 7 Xmemfile_test.c']
|
||||
enew
|
||||
let a = execute(cmd)
|
||||
@@ -102,7 +107,7 @@ func Test_cscopeWithCscopeConnections()
|
||||
call assert_equal('Xmemfile_test.c', @%)
|
||||
endfor
|
||||
|
||||
" Test 9: Find files #including this file
|
||||
" Test: Find files #including this file
|
||||
for cmd in ['cs find i assert.h', 'cs find 8 assert.h']
|
||||
enew
|
||||
let a = execute(cmd)
|
||||
@@ -113,11 +118,11 @@ func Test_cscopeWithCscopeConnections()
|
||||
call assert_equal('#include <assert.h>', getline('.'))
|
||||
endfor
|
||||
|
||||
" Test 10: Invalid find command
|
||||
" Test: Invalid find command
|
||||
call assert_fails('cs find x', 'E560:')
|
||||
|
||||
if has('float')
|
||||
" Test 11: Find places where this symbol is assigned a value
|
||||
" Test: Find places where this symbol is assigned a value
|
||||
" this needs a cscope >= 15.8
|
||||
" unfortunately, Travis has cscope version 15.7
|
||||
let cscope_version = systemlist('cscope --version')[0]
|
||||
@@ -137,17 +142,17 @@ func Test_cscopeWithCscopeConnections()
|
||||
endif
|
||||
endif
|
||||
|
||||
" Test 12: leading whitespace is not removed for cscope find text
|
||||
" Test: leading whitespace is not removed for cscope find text
|
||||
let a = execute('cscope find t test_mf_hash')
|
||||
call assert_equal(['', '(1 of 1): <<<unknown>>> test_mf_hash();'], split(a, '\n', 1))
|
||||
call assert_equal(' test_mf_hash();', getline('.'))
|
||||
|
||||
" Test 13: test with scscope
|
||||
" Test: test with scscope
|
||||
let a = execute('scs find t Bram')
|
||||
call assert_match('(1 of 1): <<<unknown>>> \* VIM - Vi IMproved^Iby Bram Moolenaar', a)
|
||||
call assert_equal(' * VIM - Vi IMproved by Bram Moolenaar', getline('.'))
|
||||
|
||||
" Test 14: cscope help
|
||||
" Test: cscope help
|
||||
for cmd in ['cs', 'cs help', 'cs xxx']
|
||||
let a = execute(cmd)
|
||||
call assert_match('^cscope commands:\n', a)
|
||||
@@ -161,16 +166,16 @@ func Test_cscopeWithCscopeConnections()
|
||||
let a = execute('scscope help')
|
||||
call assert_match('This cscope command does not support splitting the window\.', a)
|
||||
|
||||
" Test 15: reset connections
|
||||
" Test: reset connections
|
||||
let a = execute('cscope reset')
|
||||
call assert_match('\nAdded cscope database.*Xcscope.out (#0)', a)
|
||||
call assert_match('\nAll cscope databases reset', a)
|
||||
|
||||
" Test 16: cscope show
|
||||
" Test: cscope show
|
||||
let a = execute('cscope show')
|
||||
call assert_match('\n 0 \d\+.*Xcscope.out\s*<none>', a)
|
||||
|
||||
" Test 17: cstag and 'csto' option
|
||||
" Test: cstag and 'csto' option
|
||||
set csto=0
|
||||
let a = execute('cstag TEST_COUNT')
|
||||
call assert_match('(1 of 1): <<TEST_COUNT>> #define TEST_COUNT 50000', a)
|
||||
@@ -182,7 +187,7 @@ func Test_cscopeWithCscopeConnections()
|
||||
call assert_fails('cstag xxx', 'E257:')
|
||||
call assert_fails('cstag', 'E562:')
|
||||
|
||||
" Test 18: 'cst' option
|
||||
" Test: 'cst' option
|
||||
set nocst
|
||||
call assert_fails('tag TEST_COUNT', 'E426:')
|
||||
set cst
|
||||
@@ -192,12 +197,24 @@ func Test_cscopeWithCscopeConnections()
|
||||
let a = execute('tags')
|
||||
call assert_match('1 1 TEST_COUNT\s\+\d\+\s\+#define index_to_key', a)
|
||||
|
||||
" Test 19: this should trigger call to cs_print_tags()
|
||||
" Test: 'cscoperelative'
|
||||
call mkdir('Xcscoperelative')
|
||||
cd Xcscoperelative
|
||||
let a = execute('cs find g test_mf_hash')
|
||||
call assert_notequal('test_mf_hash(void)', getline('.'))
|
||||
set cscoperelative
|
||||
let a = execute('cs find g test_mf_hash')
|
||||
call assert_equal('test_mf_hash(void)', getline('.'))
|
||||
set nocscoperelative
|
||||
cd ..
|
||||
call delete('Xcscoperelative', 'd')
|
||||
|
||||
" Test: this should trigger call to cs_print_tags()
|
||||
" Unclear how to check result though, we just exercise the code.
|
||||
set cst cscopequickfix=s0
|
||||
call feedkeys(":cs find s main\<CR>", 't')
|
||||
|
||||
" Test 20: cscope kill
|
||||
" Test: cscope kill
|
||||
call assert_fails('cscope kill 2', 'E261:')
|
||||
call assert_fails('cscope kill xxx', 'E261:')
|
||||
|
||||
@@ -214,20 +231,20 @@ func Test_cscopeWithCscopeConnections()
|
||||
let a = execute('cscope kill -1')
|
||||
call assert_equal('', a)
|
||||
|
||||
" Test 21: 'csprg' option
|
||||
" Test: 'csprg' option
|
||||
call assert_equal('cscope', &csprg)
|
||||
set csprg=doesnotexist
|
||||
call assert_fails('cscope add Xcscope2.out', 'E609:')
|
||||
set csprg=cscope
|
||||
|
||||
" Test 22: multiple cscope connections
|
||||
" Test: multiple cscope connections
|
||||
cscope add Xcscope.out
|
||||
cscope add Xcscope2.out . -C
|
||||
let a = execute('cscope show')
|
||||
call assert_match('\n 0 \d\+.*Xcscope.out\s*<none>', a)
|
||||
call assert_match('\n 1 \d\+.*Xcscope2.out\s*\.', a)
|
||||
|
||||
" Test 23: test Ex command line completion
|
||||
" Test: test Ex command line completion
|
||||
call feedkeys(":cs \<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"cs add find help kill reset show', @:)
|
||||
|
||||
@@ -243,19 +260,26 @@ func Test_cscopeWithCscopeConnections()
|
||||
call feedkeys(":cs add Xcscope\<C-A>\<C-B>\"\<CR>", 'tx')
|
||||
call assert_equal('"cs add Xcscope.out Xcscope2.out', @:)
|
||||
|
||||
" Test 24: cscope_connection()
|
||||
" Test: cscope_connection()
|
||||
call assert_equal(cscope_connection(), 1)
|
||||
call assert_equal(cscope_connection(0, 'out'), 1)
|
||||
call assert_equal(cscope_connection(0, 'xxx'), 1)
|
||||
|
||||
call assert_equal(cscope_connection(1, 'out'), 1)
|
||||
call assert_equal(cscope_connection(1, 'xxx'), 0)
|
||||
|
||||
call assert_equal(cscope_connection(2, 'out'), 0)
|
||||
call assert_equal(cscope_connection(2, getcwd() .. '/Xcscope.out', 1), 1)
|
||||
|
||||
call assert_equal(cscope_connection(3, 'xxx', '..'), 0)
|
||||
call assert_equal(cscope_connection(3, 'out', 'xxx'), 0)
|
||||
call assert_equal(cscope_connection(3, 'out', '.'), 1)
|
||||
|
||||
call assert_equal(cscope_connection(4, 'out', '.'), 0)
|
||||
|
||||
" CleanUp
|
||||
call assert_equal(cscope_connection(5, 'out'), 0)
|
||||
call assert_equal(cscope_connection(-1, 'out'), 0)
|
||||
|
||||
call CscopeSetupOrClean(0)
|
||||
endfunc
|
||||
|
||||
|
||||
@@ -146,9 +146,7 @@ endfunc
|
||||
" In Ex-mode, backslashes at the end of a command should be halved.
|
||||
func Test_Ex_echo_backslash()
|
||||
" This test works only when the language is English
|
||||
if v:lang != "C" && v:lang !~ '^[Ee]n'
|
||||
return
|
||||
endif
|
||||
CheckEnglish
|
||||
let bsl = '\\\\'
|
||||
let bsl2 = '\\\'
|
||||
call assert_fails('call feedkeys("Qecho " .. bsl .. "\nvisual\n", "xt")',
|
||||
|
||||
@@ -84,6 +84,15 @@ func Test_expandcmd()
|
||||
let $FOO="blue\tsky"
|
||||
call setline(1, "$FOO")
|
||||
call assert_equal("grep pat blue\tsky", expandcmd('grep pat <cfile>'))
|
||||
|
||||
" Test for expression expansion `=
|
||||
let $FOO= "blue"
|
||||
call assert_equal("blue sky", expandcmd("`=$FOO .. ' sky'`"))
|
||||
|
||||
" Test for env variable with spaces
|
||||
let $FOO= "foo bar baz"
|
||||
call assert_equal("e foo bar baz", expandcmd("e $FOO"))
|
||||
|
||||
unlet $FOO
|
||||
close!
|
||||
endfunc
|
||||
|
||||
@@ -659,6 +659,7 @@ func Save_mode()
|
||||
return ''
|
||||
endfunc
|
||||
|
||||
" Test for the mode() function
|
||||
func Test_mode()
|
||||
new
|
||||
call append(0, ["Blue Ball Black", "Brown Band Bowl", ""])
|
||||
@@ -782,6 +783,8 @@ func Test_mode()
|
||||
call assert_equal('c-c', g:current_modes)
|
||||
call feedkeys("gQecho \<C-R>=Save_mode()\<CR>\<CR>vi\<CR>", 'xt')
|
||||
call assert_equal('c-cv', g:current_modes)
|
||||
call feedkeys("Qcall Save_mode()\<CR>vi\<CR>", 'xt')
|
||||
call assert_equal('c-ce', g:current_modes)
|
||||
" How to test Ex mode?
|
||||
|
||||
bwipe!
|
||||
@@ -841,6 +844,16 @@ func Test_getbufvar()
|
||||
call assert_equal('iso-8859-2', getbufvar(bufnr('%'), '&fenc'))
|
||||
close
|
||||
|
||||
" Get the b: dict.
|
||||
let b:testvar = 'one'
|
||||
new
|
||||
let b:testvar = 'two'
|
||||
let thebuf = bufnr()
|
||||
wincmd w
|
||||
call assert_equal('two', getbufvar(thebuf, 'testvar'))
|
||||
call assert_equal('two', getbufvar(thebuf, '').testvar)
|
||||
bwipe!
|
||||
|
||||
set fileformats&
|
||||
endfunc
|
||||
|
||||
@@ -1274,6 +1287,19 @@ func Test_inputlist()
|
||||
call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>3\<cr>", 'tx')
|
||||
call assert_equal(3, c)
|
||||
|
||||
" Use backspace to delete characters in the prompt
|
||||
call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>1\<BS>3\<BS>2\<cr>", 'tx')
|
||||
call assert_equal(2, c)
|
||||
|
||||
" Use mouse to make a selection
|
||||
call test_setmouse(&lines - 3, 2)
|
||||
call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>\<LeftMouse>", 'tx')
|
||||
call assert_equal(1, c)
|
||||
" Mouse click outside of the list
|
||||
call test_setmouse(&lines - 6, 2)
|
||||
call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>\<LeftMouse>", 'tx')
|
||||
call assert_equal(-2, c)
|
||||
|
||||
call assert_fails('call inputlist("")', 'E686:')
|
||||
endfunc
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
" Test for options
|
||||
|
||||
source check.vim
|
||||
source view_util.vim
|
||||
|
||||
func Test_whichwrap()
|
||||
set whichwrap=b,s
|
||||
@@ -707,4 +708,12 @@ func Test_rightleftcmd()
|
||||
set rightleft&
|
||||
endfunc
|
||||
|
||||
" Test for the "debug" option
|
||||
func Test_debug_option()
|
||||
set debug=beep
|
||||
exe "normal \<C-c>"
|
||||
call assert_equal('Beep!', Screenline(&lines))
|
||||
set debug&
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
source shared.vim
|
||||
source screendump.vim
|
||||
source term_util.vim
|
||||
source check.vim
|
||||
|
||||
" Check that loading startup.vim works.
|
||||
@@ -10,6 +11,9 @@ func Test_startup_script()
|
||||
source $VIMRUNTIME/defaults.vim
|
||||
|
||||
call assert_equal(0, &compatible)
|
||||
" Restore some options, so that the following tests doesn't break
|
||||
set nomore
|
||||
set noshowmode
|
||||
endfunc
|
||||
|
||||
" Verify the order in which plugins are loaded:
|
||||
@@ -322,6 +326,10 @@ func Test_q_arg()
|
||||
\ lines)
|
||||
endif
|
||||
|
||||
" Test with a non-existing error file (exits with value 3)
|
||||
let out = system(GetVimCommand() .. ' -q xyz.err')
|
||||
call assert_equal(3, v:shell_error)
|
||||
|
||||
call delete('Xtestout')
|
||||
call delete('Xerrors')
|
||||
endfunc
|
||||
@@ -687,3 +695,268 @@ func Test_v_argv()
|
||||
call assert_true(idx > 2)
|
||||
call assert_equal(['arg1', '--cmd', 'echo v:argv', '--cmd', 'q'']'], list[idx:])
|
||||
endfunc
|
||||
|
||||
" Test for the "-r" recovery mode option
|
||||
func Test_r_arg()
|
||||
" Can't catch the output of gvim.
|
||||
CheckNotGui
|
||||
CheckUnix
|
||||
CheckEnglish
|
||||
let cmd = GetVimCommand()
|
||||
" There can be swap files anywhere, only check for the headers.
|
||||
let expected =<< trim END
|
||||
Swap files found:.*
|
||||
In current directory:.*
|
||||
In directory \~/tmp:.*
|
||||
In directory /var/tmp:.*
|
||||
In directory /tmp:.*
|
||||
END
|
||||
call assert_match(join(expected, ""), system(cmd .. " -r")->substitute("[\r\n]\\+", '', ''))
|
||||
endfunc
|
||||
|
||||
" Test for the '-t' option to jump to a tag
|
||||
func Test_t_arg()
|
||||
let before =<< trim [CODE]
|
||||
set tags=Xtags
|
||||
[CODE]
|
||||
let after =<< trim [CODE]
|
||||
let s = bufname('') .. ':L' .. line('.') .. 'C' .. col('.')
|
||||
call writefile([s], "Xtestout")
|
||||
qall
|
||||
[CODE]
|
||||
|
||||
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
|
||||
\ "first\tXfile1\t/^ \\zsfirst$/",
|
||||
\ "second\tXfile1\t/^ \\zssecond$/",
|
||||
\ "third\tXfile1\t/^ \\zsthird$/"],
|
||||
\ 'Xtags')
|
||||
call writefile([' first', ' second', ' third'], 'Xfile1')
|
||||
|
||||
if RunVim(before, after, '-t second')
|
||||
call assert_equal(['Xfile1:L2C5'], readfile('Xtestout'))
|
||||
call delete('Xtestout')
|
||||
endif
|
||||
|
||||
call delete('Xtags')
|
||||
call delete('Xfile1')
|
||||
endfunc
|
||||
|
||||
" Test for entering the insert mode on startup
|
||||
func Test_start_insertmode()
|
||||
let before =<< trim [CODE]
|
||||
set insertmode
|
||||
[CODE]
|
||||
let after =<< trim [CODE]
|
||||
call writefile(['insertmode=' .. &insertmode], 'Xtestout')
|
||||
qall
|
||||
[CODE]
|
||||
if RunVim(before, after, '')
|
||||
call assert_equal(['insertmode=1'], readfile('Xtestout'))
|
||||
call delete('Xtestout')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" Test for enabling the binary mode on startup
|
||||
func Test_b_arg()
|
||||
let after =<< trim [CODE]
|
||||
call writefile(['binary=' .. &binary], 'Xtestout')
|
||||
qall
|
||||
[CODE]
|
||||
if RunVim([], after, '-b')
|
||||
call assert_equal(['binary=1'], readfile('Xtestout'))
|
||||
call delete('Xtestout')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" Test for enabling the lisp mode on startup
|
||||
func Test_l_arg()
|
||||
let after =<< trim [CODE]
|
||||
let s = 'lisp=' .. &lisp .. ', showmatch=' .. &showmatch
|
||||
call writefile([s], 'Xtestout')
|
||||
qall
|
||||
[CODE]
|
||||
if RunVim([], after, '-l')
|
||||
call assert_equal(['lisp=1, showmatch=1'], readfile('Xtestout'))
|
||||
call delete('Xtestout')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" Test for specifying a non-existing vimrc file using "-u"
|
||||
func Test_missing_vimrc()
|
||||
if !CanRunVimInTerminal()
|
||||
throw 'Skipped: cannot run vim in terminal'
|
||||
endif
|
||||
let after =<< trim [CODE]
|
||||
call assert_match('^E282:', v:errmsg)
|
||||
call writefile(v:errors, 'Xtestout')
|
||||
[CODE]
|
||||
call writefile(after, 'Xafter')
|
||||
|
||||
let cmd = GetVimCommandCleanTerm() . ' -u Xvimrc_missing -S Xafter'
|
||||
let buf = term_start(cmd, {'term_rows' : 10})
|
||||
call WaitForAssert({-> assert_equal("running", term_getstatus(buf))})
|
||||
call term_wait(buf)
|
||||
call term_sendkeys(buf, "\n:")
|
||||
call term_wait(buf)
|
||||
call WaitForAssert({-> assert_match(':', term_getline(buf, 10))})
|
||||
call StopVimInTerminal(buf)
|
||||
call assert_equal([], readfile('Xtestout'))
|
||||
call delete('Xafter')
|
||||
call delete('Xtestout')
|
||||
endfunc
|
||||
|
||||
" Test for using the $VIMINIT environment variable
|
||||
func Test_VIMINIT()
|
||||
let after =<< trim [CODE]
|
||||
call assert_equal(1, exists('viminit_found'))
|
||||
call assert_equal('yes', viminit_found)
|
||||
call writefile(v:errors, 'Xtestout')
|
||||
qall
|
||||
[CODE]
|
||||
call writefile(after, 'Xafter')
|
||||
let cmd = GetVimProg() . ' --not-a-term -S Xafter --cmd "set enc=utf8"'
|
||||
call setenv('VIMINIT', 'let viminit_found="yes"')
|
||||
exe "silent !" . cmd
|
||||
call assert_equal([], readfile('Xtestout'))
|
||||
call delete('Xtestout')
|
||||
call delete('Xafter')
|
||||
endfunc
|
||||
|
||||
" Test for using the $EXINIT environment variable
|
||||
func Test_EXINIT()
|
||||
let after =<< trim [CODE]
|
||||
call assert_equal(1, exists('exinit_found'))
|
||||
call assert_equal('yes', exinit_found)
|
||||
call writefile(v:errors, 'Xtestout')
|
||||
qall
|
||||
[CODE]
|
||||
call writefile(after, 'Xafter')
|
||||
let cmd = GetVimProg() . ' --not-a-term -S Xafter --cmd "set enc=utf8"'
|
||||
call setenv('EXINIT', 'let exinit_found="yes"')
|
||||
exe "silent !" . cmd
|
||||
call assert_equal([], readfile('Xtestout'))
|
||||
call delete('Xtestout')
|
||||
call delete('Xafter')
|
||||
endfunc
|
||||
|
||||
" Test for using the 'exrc' option
|
||||
func Test_exrc()
|
||||
let after =<< trim [CODE]
|
||||
call assert_equal(1, &exrc)
|
||||
call assert_equal(1, &secure)
|
||||
call assert_equal(37, exrc_found)
|
||||
call writefile(v:errors, 'Xtestout')
|
||||
qall
|
||||
[CODE]
|
||||
call mkdir('Xdir')
|
||||
call writefile(['let exrc_found=37'], 'Xdir/.exrc')
|
||||
call writefile(after, 'Xdir/Xafter')
|
||||
let cmd = GetVimProg() . ' --not-a-term -S Xafter --cmd "cd Xdir" --cmd "set enc=utf8 exrc secure"'
|
||||
exe "silent !" . cmd
|
||||
call assert_equal([], readfile('Xdir/Xtestout'))
|
||||
call delete('Xdir', 'rf')
|
||||
endfunc
|
||||
|
||||
" Test for starting Vim with a non-terminal as input/output
|
||||
func Test_io_not_a_terminal()
|
||||
" Can't catch the output of gvim.
|
||||
CheckNotGui
|
||||
CheckUnix
|
||||
CheckEnglish
|
||||
let l = systemlist(GetVimProg() .. ' --ttyfail')
|
||||
call assert_equal(['Vim: Warning: Output is not to a terminal',
|
||||
\ 'Vim: Warning: Input is not from a terminal'], l)
|
||||
endfunc
|
||||
|
||||
" Test for the "-w scriptout" argument
|
||||
func Test_w_arg()
|
||||
" Can't catch the output of gvim.
|
||||
CheckNotGui
|
||||
call writefile(["iVim Editor\<Esc>:q!\<CR>"], 'Xscriptin', 'b')
|
||||
if RunVim([], [], '-s Xscriptin -w Xscriptout')
|
||||
call assert_equal(["iVim Editor\e:q!\r"], readfile('Xscriptout'))
|
||||
call delete('Xscriptout')
|
||||
endif
|
||||
call delete('Xscriptin')
|
||||
|
||||
" Test for failing to open the script output file. This test works only when
|
||||
" the language is English.
|
||||
if v:lang == "C" || v:lang =~ '^[Ee]n'
|
||||
call mkdir("Xdir")
|
||||
let m = system(GetVimCommand() .. " -w Xdir")
|
||||
call assert_equal("Cannot open for script output: \"Xdir\"\n", m)
|
||||
call delete("Xdir", 'rf')
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" Test for the "-s scriptin" argument
|
||||
func Test_s_arg()
|
||||
" Can't catch the output of gvim.
|
||||
CheckNotGui
|
||||
CheckEnglish
|
||||
" Test for failing to open the script input file.
|
||||
let m = system(GetVimCommand() .. " -s abcxyz")
|
||||
call assert_equal("Cannot open for reading: \"abcxyz\"\n", m)
|
||||
|
||||
call writefile([], 'Xinput')
|
||||
let m = system(GetVimCommand() .. " -s Xinput -s Xinput")
|
||||
call assert_equal("Attempt to open script file again: \"-s Xinput\"\n", m)
|
||||
call delete('Xinput')
|
||||
endfunc
|
||||
|
||||
" Test for the "-n" (no swap file) argument
|
||||
func Test_n_arg()
|
||||
let after =<< trim [CODE]
|
||||
call assert_equal(0, &updatecount)
|
||||
call writefile(v:errors, 'Xtestout')
|
||||
qall
|
||||
[CODE]
|
||||
if RunVim([], after, '-n')
|
||||
call assert_equal([], readfile('Xtestout'))
|
||||
call delete('Xtestout')
|
||||
endif
|
||||
call delete('Xafter')
|
||||
endfunc
|
||||
|
||||
" Test for the "-h" (help) argument
|
||||
func Test_h_arg()
|
||||
" Can't catch the output of gvim.
|
||||
CheckNotGui
|
||||
let l = systemlist(GetVimProg() .. ' -h')
|
||||
call assert_match('^VIM - Vi IMproved', l[0])
|
||||
let l = systemlist(GetVimProg() .. ' -?')
|
||||
call assert_match('^VIM - Vi IMproved', l[0])
|
||||
endfunc
|
||||
|
||||
" Test for the "-F" (farsi) argument
|
||||
func Test_F_arg()
|
||||
" Can't catch the output of gvim.
|
||||
CheckNotGui
|
||||
let l = systemlist(GetVimProg() .. ' -F')
|
||||
call assert_match('^E27:', l[0])
|
||||
endfunc
|
||||
|
||||
" Test for the "-E" (improved Ex mode) argument
|
||||
func Test_E_arg()
|
||||
let after =<< trim [CODE]
|
||||
call assert_equal('cv', mode(1))
|
||||
call writefile(v:errors, 'Xtestout')
|
||||
qall
|
||||
[CODE]
|
||||
if RunVim([], after, '-E')
|
||||
call assert_equal([], readfile('Xtestout'))
|
||||
call delete('Xtestout')
|
||||
endif
|
||||
call delete('Xafter')
|
||||
endfunc
|
||||
|
||||
" Test for too many edit argument errors
|
||||
func Test_too_many_edit_args()
|
||||
" Can't catch the output of gvim.
|
||||
CheckNotGui
|
||||
CheckEnglish
|
||||
let l = systemlist(GetVimProg() .. ' - -')
|
||||
call assert_match('^Too many edit arguments: "-"', l[1])
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -36,16 +36,6 @@ func Test_terminal_basic()
|
||||
au TerminalOpen * let b:done = 'yes'
|
||||
let buf = Run_shell_in_terminal({})
|
||||
|
||||
if has("unix")
|
||||
call assert_match('^/dev/', job_info(g:job).tty_out)
|
||||
call assert_match('^/dev/', term_gettty(''))
|
||||
else
|
||||
" ConPTY works on anonymous pipe.
|
||||
if !has('conpty')
|
||||
call assert_match('^\\\\.\\pipe\\', job_info(g:job).tty_out)
|
||||
call assert_match('^\\\\.\\pipe\\', ''->term_gettty())
|
||||
endif
|
||||
endif
|
||||
call assert_equal('t', mode())
|
||||
call assert_equal('yes', b:done)
|
||||
call assert_match('%aR[^\n]*running]', execute('ls'))
|
||||
@@ -2186,6 +2176,49 @@ func Test_term_gettitle()
|
||||
exe term . 'bwipe!'
|
||||
endfunc
|
||||
|
||||
func Test_term_gettty()
|
||||
let buf = Run_shell_in_terminal({})
|
||||
let gettty = term_gettty(buf)
|
||||
|
||||
if has('unix') && executable('tty')
|
||||
" Find tty using the tty shell command.
|
||||
call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))})
|
||||
call term_sendkeys(buf, "tty\r")
|
||||
call WaitForAssert({-> assert_notequal('', term_getline(buf, 3))})
|
||||
let tty = term_getline(buf, 2)
|
||||
call assert_equal(tty, gettty)
|
||||
endif
|
||||
|
||||
let gettty0 = term_gettty(buf, 0)
|
||||
let gettty1 = term_gettty(buf, 1)
|
||||
|
||||
call assert_equal(gettty, gettty0)
|
||||
call assert_equal(job_info(g:job).tty_out, gettty0)
|
||||
call assert_equal(job_info(g:job).tty_in, gettty1)
|
||||
|
||||
if has('unix')
|
||||
" For unix, term_gettty(..., 0) and term_gettty(..., 1)
|
||||
" are identical according to :help term_gettty()
|
||||
call assert_equal(gettty0, gettty1)
|
||||
call assert_match('^/dev/', gettty)
|
||||
else
|
||||
" ConPTY works on anonymous pipe.
|
||||
if !has('conpty')
|
||||
call assert_match('^\\\\.\\pipe\\', gettty0)
|
||||
call assert_match('^\\\\.\\pipe\\', gettty1)
|
||||
endif
|
||||
endif
|
||||
|
||||
call assert_fails('call term_gettty(buf, 2)', 'E475:')
|
||||
call assert_fails('call term_gettty(buf, -1)', 'E475:')
|
||||
|
||||
call assert_equal('', term_gettty(buf + 1))
|
||||
|
||||
call StopShellInTerminal(buf)
|
||||
call term_wait(buf)
|
||||
exe buf . 'bwipe'
|
||||
endfunc
|
||||
|
||||
" When drawing the statusline the cursor position may not have been updated
|
||||
" yet.
|
||||
" 1. create a terminal, make it show 2 lines
|
||||
|
||||
@@ -1026,6 +1026,41 @@ func Test_comment_nested()
|
||||
%bw!
|
||||
endfunc
|
||||
|
||||
" Test for a space character in 'comments' setting
|
||||
func Test_comment_space()
|
||||
new
|
||||
setlocal comments=b:\ > fo+=ro
|
||||
exe "normal i> B\nD\<C-C>ggOA\<C-C>joC"
|
||||
exe "normal Go > F\nH\<C-C>kOE\<C-C>joG"
|
||||
let expected =<< trim END
|
||||
A
|
||||
> B
|
||||
C
|
||||
D
|
||||
> E
|
||||
> F
|
||||
> G
|
||||
> H
|
||||
END
|
||||
call assert_equal(expected, getline(1, '$'))
|
||||
%bw!
|
||||
endfunc
|
||||
|
||||
" Test for the 'O' flag in 'comments'
|
||||
func Test_comment_O()
|
||||
new
|
||||
setlocal comments=Ob:* fo+=ro
|
||||
exe "normal i* B\nD\<C-C>kOA\<C-C>joC"
|
||||
let expected =<< trim END
|
||||
A
|
||||
* B
|
||||
* C
|
||||
* D
|
||||
END
|
||||
call assert_equal(expected, getline(1, '$'))
|
||||
%bw!
|
||||
endfunc
|
||||
|
||||
" Test for 'a' and 'w' flags in 'formatoptions'
|
||||
func Test_fo_a_w()
|
||||
new
|
||||
@@ -1035,4 +1070,23 @@ func Test_fo_a_w()
|
||||
%bw!
|
||||
endfunc
|
||||
|
||||
" Test for 'j' flag in 'formatoptions'
|
||||
func Test_fo_j()
|
||||
new
|
||||
setlocal fo+=j comments=://
|
||||
call setline(1, ['i++; // comment1', ' // comment2'])
|
||||
normal J
|
||||
call assert_equal('i++; // comment1 comment2', getline(1))
|
||||
setlocal fo-=j
|
||||
call setline(1, ['i++; // comment1', ' // comment2'])
|
||||
normal J
|
||||
call assert_equal('i++; // comment1 // comment2', getline(1))
|
||||
" Test with nested comments
|
||||
setlocal fo+=j comments=n:>,n:)
|
||||
call setline(1, ['i++; > ) > ) comment1', ' > ) comment2'])
|
||||
normal J
|
||||
call assert_equal('i++; > ) > ) comment1 comment2', getline(1))
|
||||
%bw!
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -2012,9 +2012,7 @@ endfunc
|
||||
" Test for verbose messages with :try :catch, and :finally {{{1
|
||||
func Test_try_catch_verbose()
|
||||
" This test works only when the language is English
|
||||
if v:lang != "C" && v:lang !~ '^[Ee]n'
|
||||
return
|
||||
endif
|
||||
CheckEnglish
|
||||
|
||||
set verbose=14
|
||||
|
||||
|
||||
@@ -87,8 +87,10 @@ enddef
|
||||
def Test_disassemble_store()
|
||||
let res = execute('disass s:ScriptFuncStore')
|
||||
assert_match('<SNR>\d*_ScriptFuncStore.*'
|
||||
\ .. 'let localnr = 1.*'
|
||||
\ .. 'localnr = 2.*'
|
||||
\ .. ' STORE 2 in $0.*'
|
||||
\ .. 'let localstr = ''abc''.*'
|
||||
\ .. 'localstr = ''xyz''.*'
|
||||
\ .. ' STORE $1.*'
|
||||
\ .. 'v:char = ''abc''.*'
|
||||
@@ -360,31 +362,27 @@ def Test_disassemble_const_expr()
|
||||
enddef
|
||||
|
||||
def WithFunc()
|
||||
let funky1: func
|
||||
let funky2: func = function("len")
|
||||
let party1: partial
|
||||
let party2: partial = funcref("UserFunc")
|
||||
let Funky1: func
|
||||
let Funky2: func = function("len")
|
||||
let Party2: func = funcref("UserFunc")
|
||||
enddef
|
||||
|
||||
def Test_disassemble_function()
|
||||
let instr = execute('disassemble WithFunc')
|
||||
assert_match('WithFunc.*'
|
||||
\ .. 'let funky1: func.*'
|
||||
\ .. 'let Funky1: func.*'
|
||||
\ .. '0 PUSHFUNC "\[none]".*'
|
||||
\ .. '1 STORE $0.*'
|
||||
\ .. 'let funky2: func = function("len").*'
|
||||
\ .. 'let Funky2: func = function("len").*'
|
||||
\ .. '2 PUSHS "len".*'
|
||||
\ .. '3 BCALL function(argc 1).*'
|
||||
\ .. '4 STORE $1.*'
|
||||
\ .. 'let party1: partial.*'
|
||||
\ .. '5 PUSHPARTIAL "\[none]".*'
|
||||
\ .. '6 STORE $2.*'
|
||||
\ .. 'let party2: partial = funcref("UserFunc").*'
|
||||
\ .. '7 PUSHS "UserFunc".*'
|
||||
\ .. '8 BCALL funcref(argc 1).*'
|
||||
\ .. '9 STORE $3.*'
|
||||
\ .. '10 PUSHNR 0.*'
|
||||
\ .. '11 RETURN.*'
|
||||
\ .. 'let Party2: func = funcref("UserFunc").*'
|
||||
\ .. '\d PUSHS "UserFunc".*'
|
||||
\ .. '\d BCALL funcref(argc 1).*'
|
||||
\ .. '\d STORE $2.*'
|
||||
\ .. '\d PUSHNR 0.*'
|
||||
\ .. '\d RETURN.*'
|
||||
\, instr)
|
||||
enddef
|
||||
|
||||
@@ -753,10 +751,10 @@ def Test_disassemble_compare()
|
||||
\ ['#{a:1} is #{x:2}', 'COMPAREDICT is'],
|
||||
\ ['#{a:1} isnot #{x:2}', 'COMPAREDICT isnot'],
|
||||
\
|
||||
\ ['{->33} == {->44}', 'COMPAREPARTIAL =='],
|
||||
\ ['{->33} != {->44}', 'COMPAREPARTIAL !='],
|
||||
\ ['{->33} is {->44}', 'COMPAREPARTIAL is'],
|
||||
\ ['{->33} isnot {->44}', 'COMPAREPARTIAL isnot'],
|
||||
\ ['{->33} == {->44}', 'COMPAREFUNC =='],
|
||||
\ ['{->33} != {->44}', 'COMPAREFUNC !='],
|
||||
\ ['{->33} is {->44}', 'COMPAREFUNC is'],
|
||||
\ ['{->33} isnot {->44}', 'COMPAREFUNC isnot'],
|
||||
\
|
||||
\ ['77 == g:xx', 'COMPAREANY =='],
|
||||
\ ['77 != g:xx', 'COMPAREANY !='],
|
||||
|
||||
@@ -460,8 +460,8 @@ func Test_expr4_fails()
|
||||
|
||||
call CheckDefFailureMult(['let j: job', 'let chan: channel', 'let r = j == chan'], 'Cannot compare job with channel')
|
||||
call CheckDefFailureMult(['let j: job', 'let x: list<any>', 'let r = j == x'], 'Cannot compare job with list')
|
||||
call CheckDefFailureMult(['let j: job', 'let x: func', 'let r = j == x'], 'Cannot compare job with func')
|
||||
call CheckDefFailureMult(['let j: job', 'let x: partial', 'let r = j == x'], 'Cannot compare job with partial')
|
||||
call CheckDefFailureMult(['let j: job', 'let Xx: func', 'let r = j == Xx'], 'Cannot compare job with func')
|
||||
call CheckDefFailureMult(['let j: job', 'let Xx: func', 'let r = j == Xx'], 'Cannot compare job with func')
|
||||
endfunc
|
||||
|
||||
" test addition, subtraction, concatenation
|
||||
|
||||
400
src/testdir/test_vim9_func.vim
Normal file
400
src/testdir/test_vim9_func.vim
Normal file
@@ -0,0 +1,400 @@
|
||||
" Test various aspects of the Vim9 script language.
|
||||
|
||||
source check.vim
|
||||
source view_util.vim
|
||||
|
||||
" Check that "lines" inside ":def" results in an "error" message.
|
||||
func CheckDefFailure(lines, error)
|
||||
call writefile(['def Func()'] + a:lines + ['enddef'], 'Xdef')
|
||||
call assert_fails('so Xdef', a:error, a:lines)
|
||||
call delete('Xdef')
|
||||
endfunc
|
||||
|
||||
func CheckScriptFailure(lines, error)
|
||||
call writefile(a:lines, 'Xdef')
|
||||
call assert_fails('so Xdef', a:error, a:lines)
|
||||
call delete('Xdef')
|
||||
endfunc
|
||||
|
||||
func Test_def_basic()
|
||||
def SomeFunc(): string
|
||||
return 'yes'
|
||||
enddef
|
||||
call assert_equal('yes', SomeFunc())
|
||||
endfunc
|
||||
|
||||
def ReturnString(): string
|
||||
return 'string'
|
||||
enddef
|
||||
|
||||
def ReturnNumber(): number
|
||||
return 123
|
||||
enddef
|
||||
|
||||
let g:notNumber = 'string'
|
||||
|
||||
def ReturnGlobal(): number
|
||||
return g:notNumber
|
||||
enddef
|
||||
|
||||
def Test_return_something()
|
||||
assert_equal('string', ReturnString())
|
||||
assert_equal(123, ReturnNumber())
|
||||
assert_fails('call ReturnGlobal()', 'E1029: Expected number but got string')
|
||||
enddef
|
||||
|
||||
let s:nothing = 0
|
||||
def ReturnNothing()
|
||||
s:nothing = 1
|
||||
if true
|
||||
return
|
||||
endif
|
||||
s:nothing = 2
|
||||
enddef
|
||||
|
||||
def Test_return_nothing()
|
||||
ReturnNothing()
|
||||
assert_equal(1, s:nothing)
|
||||
enddef
|
||||
|
||||
func Increment()
|
||||
let g:counter += 1
|
||||
endfunc
|
||||
|
||||
def Test_call_ufunc_count()
|
||||
g:counter = 1
|
||||
Increment()
|
||||
Increment()
|
||||
Increment()
|
||||
" works with and without :call
|
||||
assert_equal(4, g:counter)
|
||||
call assert_equal(4, g:counter)
|
||||
unlet g:counter
|
||||
enddef
|
||||
|
||||
def MyVarargs(arg: string, ...rest: list<string>): string
|
||||
let res = arg
|
||||
for s in rest
|
||||
res ..= ',' .. s
|
||||
endfor
|
||||
return res
|
||||
enddef
|
||||
|
||||
def Test_call_varargs()
|
||||
assert_equal('one', MyVarargs('one'))
|
||||
assert_equal('one,two', MyVarargs('one', 'two'))
|
||||
assert_equal('one,two,three', MyVarargs('one', 'two', 'three'))
|
||||
enddef
|
||||
|
||||
def MyDefaultArgs(name = 'string'): string
|
||||
return name
|
||||
enddef
|
||||
|
||||
def Test_call_default_args()
|
||||
assert_equal('string', MyDefaultArgs())
|
||||
assert_equal('one', MyDefaultArgs('one'))
|
||||
assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
|
||||
|
||||
call CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef'], 'E1001:')
|
||||
enddef
|
||||
|
||||
func Test_call_default_args_from_func()
|
||||
call assert_equal('string', MyDefaultArgs())
|
||||
call assert_equal('one', MyDefaultArgs('one'))
|
||||
call assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
|
||||
endfunc
|
||||
|
||||
func TakesOneArg(arg)
|
||||
echo a:arg
|
||||
endfunc
|
||||
|
||||
def Test_call_wrong_args()
|
||||
call CheckDefFailure(['TakesOneArg()'], 'E119:')
|
||||
call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:')
|
||||
call CheckDefFailure(['bufnr(xxx)'], 'E1001:')
|
||||
enddef
|
||||
|
||||
" Default arg and varargs
|
||||
def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
|
||||
let res = one .. ',' .. two
|
||||
for s in rest
|
||||
res ..= ',' .. s
|
||||
endfor
|
||||
return res
|
||||
enddef
|
||||
|
||||
def Test_call_def_varargs()
|
||||
call assert_fails('call MyDefVarargs()', 'E119:')
|
||||
assert_equal('one,foo', MyDefVarargs('one'))
|
||||
assert_equal('one,two', MyDefVarargs('one', 'two'))
|
||||
assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three'))
|
||||
enddef
|
||||
|
||||
def Test_using_var_as_arg()
|
||||
call writefile(['def Func(x: number)', 'let x = 234', 'enddef'], 'Xdef')
|
||||
call assert_fails('so Xdef', 'E1006:')
|
||||
call delete('Xdef')
|
||||
enddef
|
||||
|
||||
def Test_call_func_defined_later()
|
||||
call assert_equal('one', DefinedLater('one'))
|
||||
call assert_fails('call NotDefined("one")', 'E117:')
|
||||
enddef
|
||||
|
||||
func DefinedLater(arg)
|
||||
return a:arg
|
||||
endfunc
|
||||
|
||||
def FuncWithForwardCall()
|
||||
return DefinedEvenLater("yes")
|
||||
enddef
|
||||
|
||||
def DefinedEvenLater(arg: string): string
|
||||
return arg
|
||||
enddef
|
||||
|
||||
def Test_error_in_nested_function()
|
||||
" Error in called function requires unwinding the call stack.
|
||||
assert_fails('call FuncWithForwardCall()', 'E1029')
|
||||
enddef
|
||||
|
||||
def Test_return_type_wrong()
|
||||
CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 'expected number but got string')
|
||||
CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected string but got number')
|
||||
CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef'], 'expected void but got string')
|
||||
CheckScriptFailure(['def Func()', 'return "a"', 'enddef'], 'expected void but got string')
|
||||
|
||||
CheckScriptFailure(['def Func(): number', 'return', 'enddef'], 'E1003:')
|
||||
|
||||
CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:')
|
||||
CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
|
||||
enddef
|
||||
|
||||
def Test_arg_type_wrong()
|
||||
CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>')
|
||||
enddef
|
||||
|
||||
def Test_vim9script_call()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
let var = ''
|
||||
def MyFunc(arg: string)
|
||||
var = arg
|
||||
enddef
|
||||
MyFunc('foobar')
|
||||
assert_equal('foobar', var)
|
||||
|
||||
let str = 'barfoo'
|
||||
str->MyFunc()
|
||||
assert_equal('barfoo', var)
|
||||
|
||||
let g:value = 'value'
|
||||
g:value->MyFunc()
|
||||
assert_equal('value', var)
|
||||
|
||||
let listvar = []
|
||||
def ListFunc(arg: list<number>)
|
||||
listvar = arg
|
||||
enddef
|
||||
[1, 2, 3]->ListFunc()
|
||||
assert_equal([1, 2, 3], listvar)
|
||||
|
||||
let dictvar = {}
|
||||
def DictFunc(arg: dict<number>)
|
||||
dictvar = arg
|
||||
enddef
|
||||
{'a': 1, 'b': 2}->DictFunc()
|
||||
assert_equal(#{a: 1, b: 2}, dictvar)
|
||||
def CompiledDict()
|
||||
{'a': 3, 'b': 4}->DictFunc()
|
||||
enddef
|
||||
CompiledDict()
|
||||
assert_equal(#{a: 3, b: 4}, dictvar)
|
||||
|
||||
#{a: 3, b: 4}->DictFunc()
|
||||
assert_equal(#{a: 3, b: 4}, dictvar)
|
||||
|
||||
('text')->MyFunc()
|
||||
assert_equal('text', var)
|
||||
("some")->MyFunc()
|
||||
assert_equal('some', var)
|
||||
END
|
||||
writefile(lines, 'Xcall.vim')
|
||||
source Xcall.vim
|
||||
delete('Xcall.vim')
|
||||
enddef
|
||||
|
||||
def Test_vim9script_call_fail_decl()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
let var = ''
|
||||
def MyFunc(arg: string)
|
||||
let var = 123
|
||||
enddef
|
||||
END
|
||||
writefile(lines, 'Xcall_decl.vim')
|
||||
assert_fails('source Xcall_decl.vim', 'E1054:')
|
||||
delete('Xcall_decl.vim')
|
||||
enddef
|
||||
|
||||
def Test_vim9script_call_fail_const()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
const var = ''
|
||||
def MyFunc(arg: string)
|
||||
var = 'asdf'
|
||||
enddef
|
||||
END
|
||||
writefile(lines, 'Xcall_const.vim')
|
||||
assert_fails('source Xcall_const.vim', 'E46:')
|
||||
delete('Xcall_const.vim')
|
||||
enddef
|
||||
|
||||
" Test that inside :function a Python function can be defined, :def is not
|
||||
" recognized.
|
||||
func Test_function_python()
|
||||
CheckFeature python3
|
||||
let py = 'python3'
|
||||
execute py "<< EOF"
|
||||
def do_something():
|
||||
return 1
|
||||
EOF
|
||||
endfunc
|
||||
|
||||
def Test_delfunc()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
def GoneSoon()
|
||||
echo 'hello'
|
||||
enddef
|
||||
|
||||
def CallGoneSoon()
|
||||
GoneSoon()
|
||||
enddef
|
||||
|
||||
delfunc GoneSoon
|
||||
CallGoneSoon()
|
||||
END
|
||||
writefile(lines, 'XToDelFunc')
|
||||
assert_fails('so XToDelFunc', 'E933')
|
||||
assert_fails('so XToDelFunc', 'E933')
|
||||
|
||||
delete('XToDelFunc')
|
||||
enddef
|
||||
|
||||
def Test_redef_failure()
|
||||
call writefile(['def Func0(): string', 'return "Func0"', 'enddef'], 'Xdef')
|
||||
so Xdef
|
||||
call writefile(['def Func1(): string', 'return "Func1"', 'enddef'], 'Xdef')
|
||||
so Xdef
|
||||
call writefile(['def! Func0(): string', 'enddef'], 'Xdef')
|
||||
call assert_fails('so Xdef', 'E1027:')
|
||||
call writefile(['def Func2(): string', 'return "Func2"', 'enddef'], 'Xdef')
|
||||
so Xdef
|
||||
call delete('Xdef')
|
||||
|
||||
call assert_equal(0, Func0())
|
||||
call assert_equal('Func1', Func1())
|
||||
call assert_equal('Func2', Func2())
|
||||
|
||||
delfunc! Func0
|
||||
delfunc! Func1
|
||||
delfunc! Func2
|
||||
enddef
|
||||
|
||||
" Test for internal functions returning different types
|
||||
func Test_InternalFuncRetType()
|
||||
let lines =<< trim END
|
||||
def RetFloat(): float
|
||||
return ceil(1.456)
|
||||
enddef
|
||||
|
||||
def RetListAny(): list<any>
|
||||
return items({'k' : 'v'})
|
||||
enddef
|
||||
|
||||
def RetListString(): list<string>
|
||||
return split('a:b:c', ':')
|
||||
enddef
|
||||
|
||||
def RetListDictAny(): list<dict<any>>
|
||||
return getbufinfo()
|
||||
enddef
|
||||
|
||||
def RetDictNumber(): dict<number>
|
||||
return wordcount()
|
||||
enddef
|
||||
|
||||
def RetDictString(): dict<string>
|
||||
return environ()
|
||||
enddef
|
||||
END
|
||||
call writefile(lines, 'Xscript')
|
||||
source Xscript
|
||||
|
||||
call assert_equal(2.0, RetFloat())
|
||||
call assert_equal([['k', 'v']], RetListAny())
|
||||
call assert_equal(['a', 'b', 'c'], RetListString())
|
||||
call assert_notequal([], RetListDictAny())
|
||||
call assert_notequal({}, RetDictNumber())
|
||||
call assert_notequal({}, RetDictString())
|
||||
call delete('Xscript')
|
||||
endfunc
|
||||
|
||||
" Test for passing too many or too few arguments to internal functions
|
||||
func Test_internalfunc_arg_error()
|
||||
let l =<< trim END
|
||||
def! FArgErr(): float
|
||||
return ceil(1.1, 2)
|
||||
enddef
|
||||
END
|
||||
call writefile(l, 'Xinvalidarg')
|
||||
call assert_fails('so Xinvalidarg', 'E118:')
|
||||
let l =<< trim END
|
||||
def! FArgErr(): float
|
||||
return ceil()
|
||||
enddef
|
||||
END
|
||||
call writefile(l, 'Xinvalidarg')
|
||||
call assert_fails('so Xinvalidarg', 'E119:')
|
||||
call delete('Xinvalidarg')
|
||||
endfunc
|
||||
|
||||
let s:funcResult = 0
|
||||
|
||||
def FuncNoArgNoRet()
|
||||
funcResult = 11
|
||||
enddef
|
||||
|
||||
def FuncNoArgRetNumber(): number
|
||||
funcResult = 22
|
||||
return 1234
|
||||
enddef
|
||||
|
||||
def FuncOneArgNoRet(arg: number)
|
||||
funcResult = arg
|
||||
enddef
|
||||
|
||||
def FuncOneArgRetNumber(arg: number): number
|
||||
funcResult = arg
|
||||
return arg
|
||||
enddef
|
||||
|
||||
def Test_func_type()
|
||||
let Ref1: func()
|
||||
funcResult = 0
|
||||
Ref1 = FuncNoArgNoRet
|
||||
Ref1()
|
||||
assert_equal(11, funcResult)
|
||||
enddef
|
||||
|
||||
def Test_func_type_fails()
|
||||
CheckDefFailure(['let ref1: func()'], 'E704:')
|
||||
|
||||
CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
|
||||
CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1013: type mismatch, expected func() but got func(number)')
|
||||
CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1013: type mismatch, expected func() but got func(number): number')
|
||||
enddef
|
||||
|
||||
|
||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||
@@ -21,13 +21,6 @@ def Test_syntax()
|
||||
let other: list<string> = ['asdf']
|
||||
enddef
|
||||
|
||||
func Test_def_basic()
|
||||
def SomeFunc(): string
|
||||
return 'yes'
|
||||
enddef
|
||||
call assert_equal('yes', SomeFunc())
|
||||
endfunc
|
||||
|
||||
let s:appendToMe = 'xxx'
|
||||
let s:addToMe = 111
|
||||
let g:existing = 'yes'
|
||||
@@ -66,10 +59,9 @@ def Test_assignment()
|
||||
if has('float')
|
||||
let float1: float = 3.4
|
||||
endif
|
||||
let funky1: func
|
||||
let funky2: func = function('len')
|
||||
let party1: partial
|
||||
let party2: partial = funcref('Test_syntax')
|
||||
let Funky1: func
|
||||
let Funky2: func = function('len')
|
||||
let Party2: func = funcref('Test_syntax')
|
||||
|
||||
" type becomes list<any>
|
||||
let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c']
|
||||
@@ -112,6 +104,8 @@ def Test_assignment()
|
||||
call CheckDefFailure(['¬ex += 3'], 'E113:')
|
||||
call CheckDefFailure(['&ts ..= "xxx"'], 'E1019:')
|
||||
call CheckDefFailure(['&path += 3'], 'E1013:')
|
||||
" test freeing ISN_STOREOPT
|
||||
call CheckDefFailure(['&ts = 3', 'let asdf'], 'E1022:')
|
||||
&ts = 8
|
||||
|
||||
g:inc_counter += 1
|
||||
@@ -133,6 +127,9 @@ def Test_assignment()
|
||||
assert_equal('noneagain', v:errmsg)
|
||||
call CheckDefFailure(['v:errmsg += "more"'], 'E1013:')
|
||||
call CheckDefFailure(['v:errmsg += 123'], 'E1013:')
|
||||
enddef
|
||||
|
||||
def Test_assignment_default()
|
||||
|
||||
" Test default values.
|
||||
let thebool: bool
|
||||
@@ -152,11 +149,8 @@ def Test_assignment()
|
||||
let theblob: blob
|
||||
assert_equal(0z, theblob)
|
||||
|
||||
let thefunc: func
|
||||
assert_equal(test_null_function(), thefunc)
|
||||
|
||||
let thepartial: partial
|
||||
assert_equal(test_null_partial(), thepartial)
|
||||
let Thefunc: func
|
||||
assert_equal(test_null_function(), Thefunc)
|
||||
|
||||
let thelist: list<any>
|
||||
assert_equal([], thelist)
|
||||
@@ -171,6 +165,9 @@ def Test_assignment()
|
||||
let thechannel: channel
|
||||
assert_equal(test_null_channel(), thechannel)
|
||||
endif
|
||||
|
||||
let nr = 1234 | nr = 5678
|
||||
assert_equal(5678, nr)
|
||||
enddef
|
||||
|
||||
func Test_assignment_failure()
|
||||
@@ -208,7 +205,7 @@ func Test_assignment_failure()
|
||||
call CheckDefFailure(['let var = feedkeys("0")'], 'E1031:')
|
||||
call CheckDefFailure(['let var: number = feedkeys("0")'], 'expected number but got void')
|
||||
|
||||
call CheckDefFailure(['let var: dict <number>'], 'E1007:')
|
||||
call CheckDefFailure(['let var: dict <number>'], 'E1068:')
|
||||
call CheckDefFailure(['let var: dict<number'], 'E1009:')
|
||||
endfunc
|
||||
|
||||
@@ -253,156 +250,15 @@ enddef
|
||||
|
||||
func Test_block_failure()
|
||||
call CheckDefFailure(['{', 'let inner = 1', '}', 'echo inner'], 'E1001:')
|
||||
call CheckDefFailure(['}'], 'E1025:')
|
||||
call CheckDefFailure(['{', 'echo 1'], 'E1026:')
|
||||
endfunc
|
||||
|
||||
def ReturnString(): string
|
||||
return 'string'
|
||||
def Test_cmd_modifier()
|
||||
tab echo '0'
|
||||
call CheckDefFailure(['5tab echo 3'], 'E16:')
|
||||
enddef
|
||||
|
||||
def ReturnNumber(): number
|
||||
return 123
|
||||
enddef
|
||||
|
||||
let g:notNumber = 'string'
|
||||
|
||||
def ReturnGlobal(): number
|
||||
return g:notNumber
|
||||
enddef
|
||||
|
||||
def Test_return_something()
|
||||
assert_equal('string', ReturnString())
|
||||
assert_equal(123, ReturnNumber())
|
||||
assert_fails('call ReturnGlobal()', 'E1029: Expected number but got string')
|
||||
enddef
|
||||
|
||||
let s:nothing = 0
|
||||
def ReturnNothing()
|
||||
s:nothing = 1
|
||||
if true
|
||||
return
|
||||
endif
|
||||
s:nothing = 2
|
||||
enddef
|
||||
|
||||
def Test_return_nothing()
|
||||
ReturnNothing()
|
||||
assert_equal(1, s:nothing)
|
||||
enddef
|
||||
|
||||
func Increment()
|
||||
let g:counter += 1
|
||||
endfunc
|
||||
|
||||
def Test_call_ufunc_count()
|
||||
g:counter = 1
|
||||
Increment()
|
||||
Increment()
|
||||
Increment()
|
||||
" works with and without :call
|
||||
assert_equal(4, g:counter)
|
||||
call assert_equal(4, g:counter)
|
||||
unlet g:counter
|
||||
enddef
|
||||
|
||||
def MyVarargs(arg: string, ...rest: list<string>): string
|
||||
let res = arg
|
||||
for s in rest
|
||||
res ..= ',' .. s
|
||||
endfor
|
||||
return res
|
||||
enddef
|
||||
|
||||
def Test_call_varargs()
|
||||
assert_equal('one', MyVarargs('one'))
|
||||
assert_equal('one,two', MyVarargs('one', 'two'))
|
||||
assert_equal('one,two,three', MyVarargs('one', 'two', 'three'))
|
||||
enddef
|
||||
|
||||
def MyDefaultArgs(name = 'string'): string
|
||||
return name
|
||||
enddef
|
||||
|
||||
def Test_call_default_args()
|
||||
assert_equal('string', MyDefaultArgs())
|
||||
assert_equal('one', MyDefaultArgs('one'))
|
||||
assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
|
||||
enddef
|
||||
|
||||
func Test_call_default_args_from_func()
|
||||
call assert_equal('string', MyDefaultArgs())
|
||||
call assert_equal('one', MyDefaultArgs('one'))
|
||||
call assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
|
||||
endfunc
|
||||
|
||||
func TakesOneArg(arg)
|
||||
echo a:arg
|
||||
endfunc
|
||||
|
||||
def Test_call_wrong_args()
|
||||
call CheckDefFailure(['TakesOneArg()'], 'E119:')
|
||||
call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:')
|
||||
call CheckDefFailure(['bufnr(xxx)'], 'E1001:')
|
||||
enddef
|
||||
|
||||
" Default arg and varargs
|
||||
def MyDefVarargs(one: string, two = 'foo', ...rest: list<string>): string
|
||||
let res = one .. ',' .. two
|
||||
for s in rest
|
||||
res ..= ',' .. s
|
||||
endfor
|
||||
return res
|
||||
enddef
|
||||
|
||||
def Test_call_def_varargs()
|
||||
call assert_fails('call MyDefVarargs()', 'E119:')
|
||||
assert_equal('one,foo', MyDefVarargs('one'))
|
||||
assert_equal('one,two', MyDefVarargs('one', 'two'))
|
||||
assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three'))
|
||||
enddef
|
||||
|
||||
def Test_using_var_as_arg()
|
||||
call writefile(['def Func(x: number)', 'let x = 234', 'enddef'], 'Xdef')
|
||||
call assert_fails('so Xdef', 'E1006:')
|
||||
call delete('Xdef')
|
||||
enddef
|
||||
|
||||
def Test_call_func_defined_later()
|
||||
call assert_equal('one', DefinedLater('one'))
|
||||
call assert_fails('call NotDefined("one")', 'E117:')
|
||||
enddef
|
||||
|
||||
func DefinedLater(arg)
|
||||
return a:arg
|
||||
endfunc
|
||||
|
||||
def FuncWithForwardCall()
|
||||
return DefinedEvenLater("yes")
|
||||
enddef
|
||||
|
||||
def DefinedEvenLater(arg: string): string
|
||||
return arg
|
||||
enddef
|
||||
|
||||
def Test_error_in_nested_function()
|
||||
" Error in called function requires unwinding the call stack.
|
||||
assert_fails('call FuncWithForwardCall()', 'E1029')
|
||||
enddef
|
||||
|
||||
def Test_return_type_wrong()
|
||||
CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 'expected number but got string')
|
||||
CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected string but got number')
|
||||
CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef'], 'expected void but got string')
|
||||
CheckScriptFailure(['def Func()', 'return "a"', 'enddef'], 'expected void but got string')
|
||||
|
||||
CheckScriptFailure(['def Func(): number', 'return', 'enddef'], 'E1003:')
|
||||
|
||||
CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:')
|
||||
CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
|
||||
enddef
|
||||
|
||||
def Test_arg_type_wrong()
|
||||
CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing <type>')
|
||||
enddef
|
||||
|
||||
def Test_try_catch()
|
||||
let l = []
|
||||
@@ -480,6 +336,16 @@ 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:')
|
||||
call CheckDefFailure(['finally'], 'E606:')
|
||||
call CheckDefFailure(['try', 'echo 0', 'finally', 'echo 1', 'finally'], 'E607:')
|
||||
call CheckDefFailure(['endtry'], 'E602:')
|
||||
call CheckDefFailure(['while 1', 'endtry'], 'E170:')
|
||||
call CheckDefFailure(['for i in range(5)', 'endtry'], 'E170:')
|
||||
call CheckDefFailure(['if 2', 'endtry'], 'E171:')
|
||||
call CheckDefFailure(['try', 'echo 1', 'endtry'], 'E1032:')
|
||||
|
||||
call CheckDefFailure(['throw'], 'E471:')
|
||||
call CheckDefFailure(['throw xxx'], 'E1001:')
|
||||
enddef
|
||||
|
||||
let s:export_script_lines =<< trim END
|
||||
@@ -711,82 +577,6 @@ def Test_vim9script_fails()
|
||||
assert_fails('export something', 'E1042')
|
||||
enddef
|
||||
|
||||
def Test_vim9script_call()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
let var = ''
|
||||
def MyFunc(arg: string)
|
||||
var = arg
|
||||
enddef
|
||||
MyFunc('foobar')
|
||||
assert_equal('foobar', var)
|
||||
|
||||
let str = 'barfoo'
|
||||
str->MyFunc()
|
||||
assert_equal('barfoo', var)
|
||||
|
||||
let g:value = 'value'
|
||||
g:value->MyFunc()
|
||||
assert_equal('value', var)
|
||||
|
||||
let listvar = []
|
||||
def ListFunc(arg: list<number>)
|
||||
listvar = arg
|
||||
enddef
|
||||
[1, 2, 3]->ListFunc()
|
||||
assert_equal([1, 2, 3], listvar)
|
||||
|
||||
let dictvar = {}
|
||||
def DictFunc(arg: dict<number>)
|
||||
dictvar = arg
|
||||
enddef
|
||||
{'a': 1, 'b': 2}->DictFunc()
|
||||
assert_equal(#{a: 1, b: 2}, dictvar)
|
||||
def CompiledDict()
|
||||
{'a': 3, 'b': 4}->DictFunc()
|
||||
enddef
|
||||
CompiledDict()
|
||||
assert_equal(#{a: 3, b: 4}, dictvar)
|
||||
|
||||
#{a: 3, b: 4}->DictFunc()
|
||||
assert_equal(#{a: 3, b: 4}, dictvar)
|
||||
|
||||
('text')->MyFunc()
|
||||
assert_equal('text', var)
|
||||
("some")->MyFunc()
|
||||
assert_equal('some', var)
|
||||
END
|
||||
writefile(lines, 'Xcall.vim')
|
||||
source Xcall.vim
|
||||
delete('Xcall.vim')
|
||||
enddef
|
||||
|
||||
def Test_vim9script_call_fail_decl()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
let var = ''
|
||||
def MyFunc(arg: string)
|
||||
let var = 123
|
||||
enddef
|
||||
END
|
||||
writefile(lines, 'Xcall_decl.vim')
|
||||
assert_fails('source Xcall_decl.vim', 'E1054:')
|
||||
delete('Xcall_decl.vim')
|
||||
enddef
|
||||
|
||||
def Test_vim9script_call_fail_const()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
const var = ''
|
||||
def MyFunc(arg: string)
|
||||
var = 'asdf'
|
||||
enddef
|
||||
END
|
||||
writefile(lines, 'Xcall_const.vim')
|
||||
assert_fails('source Xcall_const.vim', 'E46:')
|
||||
delete('Xcall_const.vim')
|
||||
enddef
|
||||
|
||||
def Test_vim9script_reload()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
@@ -905,17 +695,6 @@ def Test_fixed_size_list()
|
||||
assert_equal([2, 99, 3, 4, 5], l)
|
||||
enddef
|
||||
|
||||
" Test that inside :function a Python function can be defined, :def is not
|
||||
" recognized.
|
||||
func Test_function_python()
|
||||
CheckFeature python3
|
||||
let py = 'python3'
|
||||
execute py "<< EOF"
|
||||
def do_something():
|
||||
return 1
|
||||
EOF
|
||||
endfunc
|
||||
|
||||
def IfElse(what: number): string
|
||||
let res = ''
|
||||
if what == 1
|
||||
@@ -939,6 +718,7 @@ def Test_if_elseif_else_fails()
|
||||
call CheckDefFailure(['else'], 'E581:')
|
||||
call CheckDefFailure(['endif'], 'E580:')
|
||||
call CheckDefFailure(['if true', 'elseif xxx'], 'E1001:')
|
||||
call CheckDefFailure(['if true', 'echo 1'], 'E171:')
|
||||
enddef
|
||||
|
||||
let g:bool_true = v:true
|
||||
@@ -951,6 +731,16 @@ def Test_if_const_expr()
|
||||
endif
|
||||
assert_equal(true, res)
|
||||
|
||||
g:glob = 2
|
||||
if false
|
||||
execute('let g:glob = 3')
|
||||
endif
|
||||
assert_equal(2, g:glob)
|
||||
if true
|
||||
execute('let g:glob = 3')
|
||||
endif
|
||||
assert_equal(3, g:glob)
|
||||
|
||||
res = false
|
||||
if g:bool_true ? true : false
|
||||
res = true
|
||||
@@ -1055,27 +845,6 @@ def Test_if_const_expr_fails()
|
||||
call CheckDefFailure(["if has('aaa') ? true false"], 'E109:')
|
||||
enddef
|
||||
|
||||
def Test_delfunc()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
def GoneSoon()
|
||||
echo 'hello'
|
||||
enddef
|
||||
|
||||
def CallGoneSoon()
|
||||
GoneSoon()
|
||||
enddef
|
||||
|
||||
delfunc GoneSoon
|
||||
CallGoneSoon()
|
||||
END
|
||||
writefile(lines, 'XToDelFunc')
|
||||
assert_fails('so XToDelFunc', 'E933')
|
||||
assert_fails('so XToDelFunc', 'E933')
|
||||
|
||||
delete('XToDelFunc')
|
||||
enddef
|
||||
|
||||
def Test_execute_cmd()
|
||||
new
|
||||
setline(1, 'default')
|
||||
@@ -1092,10 +861,13 @@ def Test_execute_cmd()
|
||||
execute cmd_first .. cmd_last
|
||||
assert_equal('execute-var-var', getline(1))
|
||||
bwipe!
|
||||
|
||||
call CheckDefFailure(['execute xxx'], 'E1001:')
|
||||
enddef
|
||||
|
||||
def Test_echo_cmd()
|
||||
echo 'something'
|
||||
echo 'some'
|
||||
echon 'thing'
|
||||
assert_match('^something$', Screenline(&lines))
|
||||
|
||||
let str1 = 'some'
|
||||
@@ -1141,6 +913,7 @@ def Test_for_loop_fails()
|
||||
call CheckDefFailure(['for i in "text"'], 'E1024:')
|
||||
call CheckDefFailure(['for i in xxx'], 'E1001:')
|
||||
call CheckDefFailure(['endfor'], 'E588:')
|
||||
call CheckDefFailure(['for i in range(3)', 'echo 3'], 'E170:')
|
||||
enddef
|
||||
|
||||
def Test_while_loop()
|
||||
@@ -1166,6 +939,7 @@ def Test_while_loop_fails()
|
||||
call CheckDefFailure(['if true', 'continue'], 'E586:')
|
||||
call CheckDefFailure(['break'], 'E587:')
|
||||
call CheckDefFailure(['if true', 'break'], 'E587:')
|
||||
call CheckDefFailure(['while 1', 'echo 3'], 'E170:')
|
||||
enddef
|
||||
|
||||
def Test_interrupt_loop()
|
||||
@@ -1185,6 +959,8 @@ def Test_interrupt_loop()
|
||||
assert_true(caught, 'should have caught an exception')
|
||||
enddef
|
||||
|
||||
|
||||
" Keep this last, it messes up highlighting.
|
||||
def Test_substitute_cmd()
|
||||
new
|
||||
setline(1, 'something')
|
||||
@@ -1207,82 +983,4 @@ def Test_substitute_cmd()
|
||||
delete('Xvim9lines')
|
||||
enddef
|
||||
|
||||
def Test_redef_failure()
|
||||
call writefile(['def Func0(): string', 'return "Func0"', 'enddef'], 'Xdef')
|
||||
so Xdef
|
||||
call writefile(['def Func1(): string', 'return "Func1"', 'enddef'], 'Xdef')
|
||||
so Xdef
|
||||
call writefile(['def! Func0(): string', 'enddef'], 'Xdef')
|
||||
call assert_fails('so Xdef', 'E1027:')
|
||||
call writefile(['def Func2(): string', 'return "Func2"', 'enddef'], 'Xdef')
|
||||
so Xdef
|
||||
call delete('Xdef')
|
||||
|
||||
call assert_equal(0, Func0())
|
||||
call assert_equal('Func1', Func1())
|
||||
call assert_equal('Func2', Func2())
|
||||
|
||||
delfunc! Func0
|
||||
delfunc! Func1
|
||||
delfunc! Func2
|
||||
enddef
|
||||
|
||||
" Test for internal functions returning different types
|
||||
func Test_InternalFuncRetType()
|
||||
let lines =<< trim END
|
||||
def RetFloat(): float
|
||||
return ceil(1.456)
|
||||
enddef
|
||||
|
||||
def RetListAny(): list<any>
|
||||
return items({'k' : 'v'})
|
||||
enddef
|
||||
|
||||
def RetListString(): list<string>
|
||||
return split('a:b:c', ':')
|
||||
enddef
|
||||
|
||||
def RetListDictAny(): list<dict<any>>
|
||||
return getbufinfo()
|
||||
enddef
|
||||
|
||||
def RetDictNumber(): dict<number>
|
||||
return wordcount()
|
||||
enddef
|
||||
|
||||
def RetDictString(): dict<string>
|
||||
return environ()
|
||||
enddef
|
||||
END
|
||||
call writefile(lines, 'Xscript')
|
||||
source Xscript
|
||||
|
||||
call assert_equal(2.0, RetFloat())
|
||||
call assert_equal([['k', 'v']], RetListAny())
|
||||
call assert_equal(['a', 'b', 'c'], RetListString())
|
||||
call assert_notequal([], RetListDictAny())
|
||||
call assert_notequal({}, RetDictNumber())
|
||||
call assert_notequal({}, RetDictString())
|
||||
call delete('Xscript')
|
||||
endfunc
|
||||
|
||||
" Test for passing too many or too few arguments to internal functions
|
||||
func Test_internalfunc_arg_error()
|
||||
let l =<< trim END
|
||||
def! FArgErr(): float
|
||||
return ceil(1.1, 2)
|
||||
enddef
|
||||
END
|
||||
call writefile(l, 'Xinvalidarg')
|
||||
call assert_fails('so Xinvalidarg', 'E118:')
|
||||
let l =<< trim END
|
||||
def! FArgErr(): float
|
||||
return ceil()
|
||||
enddef
|
||||
END
|
||||
call writefile(l, 'Xinvalidarg')
|
||||
call assert_fails('so Xinvalidarg', 'E119:')
|
||||
call delete('Xinvalidarg')
|
||||
endfunc
|
||||
|
||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||
|
||||
@@ -760,6 +760,11 @@ func Test_viminfo_perm()
|
||||
call setfperm('Xviminfo', '--x------')
|
||||
call assert_fails('rviminfo Xviminfo', 'E195:')
|
||||
call delete('Xviminfo')
|
||||
|
||||
" Try to write the viminfo to a directory
|
||||
call mkdir('Xdir')
|
||||
call assert_fails('wviminfo Xdir', 'E886:')
|
||||
call delete('Xdir', 'rf')
|
||||
endfunc
|
||||
|
||||
" Test for writing to an existing viminfo file merges the file marks
|
||||
|
||||
@@ -951,6 +951,9 @@ func_clear_items(ufunc_T *fp)
|
||||
VIM_CLEAR(fp->uf_arg_types);
|
||||
VIM_CLEAR(fp->uf_def_arg_idx);
|
||||
VIM_CLEAR(fp->uf_va_name);
|
||||
while (fp->uf_type_list.ga_len > 0)
|
||||
vim_free(((type_T **)fp->uf_type_list.ga_data)
|
||||
[--fp->uf_type_list.ga_len]);
|
||||
ga_clear(&fp->uf_type_list);
|
||||
#ifdef FEAT_PROFILE
|
||||
VIM_CLEAR(fp->uf_tml_count);
|
||||
@@ -1321,7 +1324,7 @@ call_user_func(
|
||||
// A Lambda always has the command "return {expr}". It is much faster
|
||||
// to evaluate {expr} directly.
|
||||
++ex_nesting_level;
|
||||
eval1(&p, rettv, TRUE);
|
||||
(void)eval1(&p, rettv, TRUE);
|
||||
--ex_nesting_level;
|
||||
}
|
||||
else
|
||||
@@ -3013,6 +3016,7 @@ ex_function(exarg_T *eap)
|
||||
fp->uf_args = newargs;
|
||||
fp->uf_def_args = default_args;
|
||||
fp->uf_ret_type = &t_any;
|
||||
fp->uf_func_type = &t_func_any;
|
||||
|
||||
if (eap->cmdidx == CMD_def)
|
||||
{
|
||||
@@ -3022,7 +3026,7 @@ ex_function(exarg_T *eap)
|
||||
SOURCING_LNUM = sourcing_lnum_top;
|
||||
|
||||
// parse the argument types
|
||||
ga_init2(&fp->uf_type_list, sizeof(type_T), 5);
|
||||
ga_init2(&fp->uf_type_list, sizeof(type_T *), 10);
|
||||
|
||||
if (argtypes.ga_len > 0)
|
||||
{
|
||||
|
||||
@@ -738,6 +738,28 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
513,
|
||||
/**/
|
||||
512,
|
||||
/**/
|
||||
511,
|
||||
/**/
|
||||
510,
|
||||
/**/
|
||||
509,
|
||||
/**/
|
||||
508,
|
||||
/**/
|
||||
507,
|
||||
/**/
|
||||
506,
|
||||
/**/
|
||||
505,
|
||||
/**/
|
||||
504,
|
||||
/**/
|
||||
503,
|
||||
/**/
|
||||
502,
|
||||
/**/
|
||||
|
||||
@@ -1751,6 +1751,7 @@ void *vim_memset(void *, int, size_t);
|
||||
# define INIT3(a, b, c)
|
||||
# define INIT4(a, b, c, d)
|
||||
# define INIT5(a, b, c, d, e)
|
||||
# define INIT6(a, b, c, d, e, f)
|
||||
#else
|
||||
# ifndef INIT
|
||||
# define INIT(x) x
|
||||
@@ -1758,6 +1759,7 @@ void *vim_memset(void *, int, size_t);
|
||||
# define INIT3(a, b, c) = {a, b, c}
|
||||
# define INIT4(a, b, c, d) = {a, b, c, d}
|
||||
# define INIT5(a, b, c, d, e) = {a, b, c, d, e}
|
||||
# define INIT6(a, b, c, d, e, f) = {a, b, c, d, e, f}
|
||||
# define DO_INIT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -29,8 +29,8 @@ typedef enum {
|
||||
ISN_STORE, // pop into local variable isn_arg.number
|
||||
ISN_STOREV, // pop into v: variable isn_arg.number
|
||||
ISN_STOREG, // pop into global variable isn_arg.string
|
||||
ISN_STORES, // pop into scirpt variable isn_arg.loadstore
|
||||
ISN_STORESCRIPT, // pop into scirpt variable isn_arg.script
|
||||
ISN_STORES, // pop into script variable isn_arg.loadstore
|
||||
ISN_STORESCRIPT, // pop into script variable isn_arg.script
|
||||
ISN_STOREOPT, // pop into option isn_arg.string
|
||||
ISN_STOREENV, // pop into environment variable isn_arg.string
|
||||
ISN_STOREREG, // pop into register isn_arg.number
|
||||
@@ -191,7 +191,7 @@ typedef struct {
|
||||
|
||||
// arguments to ISN_LOADS and ISN_STORES
|
||||
typedef struct {
|
||||
char_u *ls_name; // variable name
|
||||
char_u *ls_name; // variable name (with s: for ISN_STORES)
|
||||
int ls_sid; // script ID
|
||||
} loadstore_T;
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ struct cctx_S {
|
||||
scope_T *ctx_scope; // current scope, NULL at toplevel
|
||||
|
||||
garray_T ctx_type_stack; // type of each item on the stack
|
||||
garray_T *ctx_type_list; // space for adding types
|
||||
garray_T *ctx_type_list; // list of pointers to allocated types
|
||||
};
|
||||
|
||||
static char e_var_notfound[] = N_("E1001: variable not found: %s");
|
||||
@@ -223,8 +223,28 @@ check_defined(char_u *p, int len, cctx_T *cctx)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate memory for a type_T and add the pointer to type_gap, so that it can
|
||||
* be freed later.
|
||||
*/
|
||||
static type_T *
|
||||
get_list_type(type_T *member_type, garray_T *type_list)
|
||||
alloc_type(garray_T *type_gap)
|
||||
{
|
||||
type_T *type;
|
||||
|
||||
if (ga_grow(type_gap, 1) == FAIL)
|
||||
return NULL;
|
||||
type = ALLOC_CLEAR_ONE(type_T);
|
||||
if (type != NULL)
|
||||
{
|
||||
((type_T **)type_gap->ga_data)[type_gap->ga_len] = type;
|
||||
++type_gap->ga_len;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
static type_T *
|
||||
get_list_type(type_T *member_type, garray_T *type_gap)
|
||||
{
|
||||
type_T *type;
|
||||
|
||||
@@ -241,17 +261,18 @@ get_list_type(type_T *member_type, garray_T *type_list)
|
||||
return &t_list_string;
|
||||
|
||||
// Not a common type, create a new entry.
|
||||
if (ga_grow(type_list, 1) == FAIL)
|
||||
type = alloc_type(type_gap);
|
||||
if (type == NULL)
|
||||
return &t_any;
|
||||
type = ((type_T *)type_list->ga_data) + type_list->ga_len;
|
||||
++type_list->ga_len;
|
||||
type->tt_type = VAR_LIST;
|
||||
type->tt_member = member_type;
|
||||
type->tt_argcount = 0;
|
||||
type->tt_args = NULL;
|
||||
return type;
|
||||
}
|
||||
|
||||
static type_T *
|
||||
get_dict_type(type_T *member_type, garray_T *type_list)
|
||||
get_dict_type(type_T *member_type, garray_T *type_gap)
|
||||
{
|
||||
type_T *type;
|
||||
|
||||
@@ -268,15 +289,93 @@ get_dict_type(type_T *member_type, garray_T *type_list)
|
||||
return &t_dict_string;
|
||||
|
||||
// Not a common type, create a new entry.
|
||||
if (ga_grow(type_list, 1) == FAIL)
|
||||
type = alloc_type(type_gap);
|
||||
if (type == NULL)
|
||||
return &t_any;
|
||||
type = ((type_T *)type_list->ga_data) + type_list->ga_len;
|
||||
++type_list->ga_len;
|
||||
type->tt_type = VAR_DICT;
|
||||
type->tt_member = member_type;
|
||||
type->tt_argcount = 0;
|
||||
type->tt_args = NULL;
|
||||
return type;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a function type, based on the return type "ret_type".
|
||||
* If "argcount" is -1 or 0 a predefined type can be used.
|
||||
* If "argcount" > 0 always create a new type, so that arguments can be added.
|
||||
*/
|
||||
static type_T *
|
||||
get_func_type(type_T *ret_type, int argcount, garray_T *type_gap)
|
||||
{
|
||||
type_T *type;
|
||||
|
||||
// recognize commonly used types
|
||||
if (argcount <= 0)
|
||||
{
|
||||
if (ret_type == &t_void)
|
||||
{
|
||||
if (argcount == 0)
|
||||
return &t_func_0_void;
|
||||
else
|
||||
return &t_func_void;
|
||||
}
|
||||
if (ret_type == &t_any)
|
||||
{
|
||||
if (argcount == 0)
|
||||
return &t_func_0_any;
|
||||
else
|
||||
return &t_func_any;
|
||||
}
|
||||
if (ret_type == &t_number)
|
||||
{
|
||||
if (argcount == 0)
|
||||
return &t_func_0_number;
|
||||
else
|
||||
return &t_func_number;
|
||||
}
|
||||
if (ret_type == &t_string)
|
||||
{
|
||||
if (argcount == 0)
|
||||
return &t_func_0_string;
|
||||
else
|
||||
return &t_func_string;
|
||||
}
|
||||
}
|
||||
|
||||
// Not a common type or has arguments, create a new entry.
|
||||
type = alloc_type(type_gap);
|
||||
if (type == NULL)
|
||||
return &t_any;
|
||||
type->tt_type = VAR_FUNC;
|
||||
type->tt_member = ret_type;
|
||||
type->tt_args = NULL;
|
||||
return type;
|
||||
}
|
||||
|
||||
/*
|
||||
* For a function type, reserve space for "argcount" argument types (including
|
||||
* vararg).
|
||||
*/
|
||||
static int
|
||||
func_type_add_arg_types(
|
||||
type_T *functype,
|
||||
int argcount,
|
||||
int min_argcount,
|
||||
garray_T *type_gap)
|
||||
{
|
||||
if (ga_grow(type_gap, 1) == FAIL)
|
||||
return FAIL;
|
||||
functype->tt_args = ALLOC_CLEAR_MULT(type_T *, argcount);
|
||||
if (functype->tt_args == NULL)
|
||||
return FAIL;
|
||||
((type_T **)type_gap->ga_data)[type_gap->ga_len] = (void *)functype->tt_args;
|
||||
++type_gap->ga_len;
|
||||
|
||||
functype->tt_argcount = argcount;
|
||||
functype->tt_min_argcount = min_argcount;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the type_T for a typval. Only for primitive types.
|
||||
*/
|
||||
@@ -752,12 +851,12 @@ generate_PUSHBLOB(cctx_T *cctx, blob_T *blob)
|
||||
* Consumes "name".
|
||||
*/
|
||||
static int
|
||||
generate_PUSHFUNC(cctx_T *cctx, char_u *name)
|
||||
generate_PUSHFUNC(cctx_T *cctx, char_u *name, type_T *type)
|
||||
{
|
||||
isn_T *isn;
|
||||
|
||||
RETURN_OK_IF_SKIP(cctx);
|
||||
if ((isn = generate_instr_type(cctx, ISN_PUSHFUNC, &t_func_void)) == NULL)
|
||||
if ((isn = generate_instr_type(cctx, ISN_PUSHFUNC, type)) == NULL)
|
||||
return FAIL;
|
||||
isn->isn_arg.string = name;
|
||||
|
||||
@@ -774,8 +873,7 @@ generate_PUSHPARTIAL(cctx_T *cctx, partial_T *part)
|
||||
isn_T *isn;
|
||||
|
||||
RETURN_OK_IF_SKIP(cctx);
|
||||
if ((isn = generate_instr_type(cctx, ISN_PUSHPARTIAL,
|
||||
&t_partial_any)) == NULL)
|
||||
if ((isn = generate_instr_type(cctx, ISN_PUSHPARTIAL, &t_func_any)) == NULL)
|
||||
return FAIL;
|
||||
isn->isn_arg.partial = part;
|
||||
|
||||
@@ -942,7 +1040,6 @@ generate_NEWLIST(cctx_T *cctx, int count)
|
||||
{
|
||||
isn_T *isn;
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
garray_T *type_list = cctx->ctx_type_list;
|
||||
type_T *type;
|
||||
type_T *member;
|
||||
|
||||
@@ -954,13 +1051,13 @@ generate_NEWLIST(cctx_T *cctx, int count)
|
||||
// drop the value types
|
||||
stack->ga_len -= count;
|
||||
|
||||
// Use the first value type for the list member type. Use "void" for an
|
||||
// Use the first value type for the list member type. Use "any" for an
|
||||
// empty list.
|
||||
if (count > 0)
|
||||
member = ((type_T **)stack->ga_data)[stack->ga_len];
|
||||
else
|
||||
member = &t_void;
|
||||
type = get_list_type(member, type_list);
|
||||
type = get_list_type(member, cctx->ctx_type_list);
|
||||
|
||||
// add the list type to the type stack
|
||||
if (ga_grow(stack, 1) == FAIL)
|
||||
@@ -979,7 +1076,6 @@ generate_NEWDICT(cctx_T *cctx, int count)
|
||||
{
|
||||
isn_T *isn;
|
||||
garray_T *stack = &cctx->ctx_type_stack;
|
||||
garray_T *type_list = cctx->ctx_type_list;
|
||||
type_T *type;
|
||||
type_T *member;
|
||||
|
||||
@@ -997,7 +1093,7 @@ generate_NEWDICT(cctx_T *cctx, int count)
|
||||
member = ((type_T **)stack->ga_data)[stack->ga_len + 1];
|
||||
else
|
||||
member = &t_void;
|
||||
type = get_dict_type(member, type_list);
|
||||
type = get_dict_type(member, cctx->ctx_type_list);
|
||||
|
||||
// add the dict type to the type stack
|
||||
if (ga_grow(stack, 1) == FAIL)
|
||||
@@ -1024,7 +1120,7 @@ generate_FUNCREF(cctx_T *cctx, int dfunc_idx)
|
||||
|
||||
if (ga_grow(stack, 1) == FAIL)
|
||||
return FAIL;
|
||||
((type_T **)stack->ga_data)[stack->ga_len] = &t_partial_any;
|
||||
((type_T **)stack->ga_data)[stack->ga_len] = &t_func_any;
|
||||
// TODO: argument and return types
|
||||
++stack->ga_len;
|
||||
|
||||
@@ -1298,6 +1394,8 @@ generate_EXEC(cctx_T *cctx, char_u *line)
|
||||
|
||||
static char e_white_both[] =
|
||||
N_("E1004: white space required before and after '%s'");
|
||||
static char e_white_after[] = N_("E1069: white space required after '%s'");
|
||||
static char e_no_white_before[] = N_("E1068: No white space allowed before '%s'");
|
||||
|
||||
/*
|
||||
* Reserve space for a local variable.
|
||||
@@ -1385,11 +1483,11 @@ skip_type(char_u *start)
|
||||
|
||||
/*
|
||||
* Parse the member type: "<type>" and return "type" with the member set.
|
||||
* Use "type_list" if a new type needs to be added.
|
||||
* Use "type_gap" if a new type needs to be added.
|
||||
* Returns NULL in case of failure.
|
||||
*/
|
||||
static type_T *
|
||||
parse_type_member(char_u **arg, type_T *type, garray_T *type_list)
|
||||
parse_type_member(char_u **arg, type_T *type, garray_T *type_gap)
|
||||
{
|
||||
type_T *member_type;
|
||||
int prev_called_emsg = called_emsg;
|
||||
@@ -1397,14 +1495,14 @@ parse_type_member(char_u **arg, type_T *type, garray_T *type_list)
|
||||
if (**arg != '<')
|
||||
{
|
||||
if (*skipwhite(*arg) == '<')
|
||||
emsg(_("E1007: No white space allowed before <"));
|
||||
semsg(_(e_no_white_before), "<");
|
||||
else
|
||||
emsg(_("E1008: Missing <type>"));
|
||||
return type;
|
||||
}
|
||||
*arg = skipwhite(*arg + 1);
|
||||
|
||||
member_type = parse_type(arg, type_list);
|
||||
member_type = parse_type(arg, type_gap);
|
||||
|
||||
*arg = skipwhite(*arg);
|
||||
if (**arg != '>' && called_emsg == prev_called_emsg)
|
||||
@@ -1415,8 +1513,8 @@ parse_type_member(char_u **arg, type_T *type, garray_T *type_list)
|
||||
++*arg;
|
||||
|
||||
if (type->tt_type == VAR_LIST)
|
||||
return get_list_type(member_type, type_list);
|
||||
return get_dict_type(member_type, type_list);
|
||||
return get_list_type(member_type, type_gap);
|
||||
return get_dict_type(member_type, type_gap);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1424,7 +1522,7 @@ parse_type_member(char_u **arg, type_T *type, garray_T *type_list)
|
||||
* Return &t_any for failure.
|
||||
*/
|
||||
type_T *
|
||||
parse_type(char_u **arg, garray_T *type_list)
|
||||
parse_type(char_u **arg, garray_T *type_gap)
|
||||
{
|
||||
char_u *p = *arg;
|
||||
size_t len;
|
||||
@@ -1466,7 +1564,7 @@ parse_type(char_u **arg, garray_T *type_list)
|
||||
if (len == 4 && STRNCMP(*arg, "dict", len) == 0)
|
||||
{
|
||||
*arg += len;
|
||||
return parse_type_member(arg, &t_dict_any, type_list);
|
||||
return parse_type_member(arg, &t_dict_any, type_gap);
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
@@ -1476,15 +1574,101 @@ parse_type(char_u **arg, garray_T *type_list)
|
||||
*arg += len;
|
||||
return &t_float;
|
||||
#else
|
||||
emsg(_("E1055: This Vim is not compiled with float support"));
|
||||
emsg(_("E1076: This Vim is not compiled with float support"));
|
||||
return &t_any;
|
||||
#endif
|
||||
}
|
||||
if (len == 4 && STRNCMP(*arg, "func", len) == 0)
|
||||
{
|
||||
type_T *type;
|
||||
type_T *ret_type = &t_any;
|
||||
int argcount = -1;
|
||||
int flags = 0;
|
||||
int first_optional = -1;
|
||||
type_T *arg_type[MAX_FUNC_ARGS + 1];
|
||||
|
||||
// func({type}, ...): {type}
|
||||
*arg += len;
|
||||
// TODO: arguments and return type
|
||||
return &t_func_any;
|
||||
if (**arg == '(')
|
||||
{
|
||||
// "func" may or may not return a value, "func()" does
|
||||
// not return a value.
|
||||
ret_type = &t_void;
|
||||
|
||||
p = ++*arg;
|
||||
argcount = 0;
|
||||
while (*p != NUL && *p != ')')
|
||||
{
|
||||
if (STRNCMP(p, "...", 3) == 0)
|
||||
{
|
||||
flags |= TTFLAG_VARARGS;
|
||||
break;
|
||||
}
|
||||
arg_type[argcount++] = parse_type(&p, type_gap);
|
||||
|
||||
if (*p == '?')
|
||||
{
|
||||
if (first_optional == -1)
|
||||
first_optional = argcount;
|
||||
++p;
|
||||
}
|
||||
else if (first_optional != -1)
|
||||
{
|
||||
emsg(_("E1007: mandatory argument after optional argument"));
|
||||
return &t_any;
|
||||
}
|
||||
|
||||
if (*p != ',' && *skipwhite(p) == ',')
|
||||
{
|
||||
semsg(_(e_no_white_before), ",");
|
||||
return &t_any;
|
||||
}
|
||||
if (*p == ',')
|
||||
{
|
||||
++p;
|
||||
if (!VIM_ISWHITE(*p))
|
||||
semsg(_(e_white_after), ",");
|
||||
}
|
||||
p = skipwhite(p);
|
||||
if (argcount == MAX_FUNC_ARGS)
|
||||
{
|
||||
emsg(_("E740: Too many argument types"));
|
||||
return &t_any;
|
||||
}
|
||||
}
|
||||
|
||||
p = skipwhite(p);
|
||||
if (*p != ')')
|
||||
{
|
||||
emsg(_(e_missing_close));
|
||||
return &t_any;
|
||||
}
|
||||
*arg = p + 1;
|
||||
}
|
||||
if (**arg == ':')
|
||||
{
|
||||
// parse return type
|
||||
++*arg;
|
||||
if (!VIM_ISWHITE(*p))
|
||||
semsg(_(e_white_after), ":");
|
||||
*arg = skipwhite(*arg);
|
||||
ret_type = parse_type(arg, type_gap);
|
||||
}
|
||||
type = get_func_type(ret_type,
|
||||
flags == 0 && first_optional == -1 ? argcount : 99,
|
||||
type_gap);
|
||||
if (flags != 0)
|
||||
type->tt_flags = flags;
|
||||
if (argcount > 0)
|
||||
{
|
||||
if (func_type_add_arg_types(type, argcount,
|
||||
first_optional == -1 ? argcount : first_optional,
|
||||
type_gap) == FAIL)
|
||||
return &t_any;
|
||||
mch_memmove(type->tt_args, arg_type,
|
||||
sizeof(type_T *) * argcount);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
break;
|
||||
case 'j':
|
||||
@@ -1498,7 +1682,7 @@ parse_type(char_u **arg, garray_T *type_list)
|
||||
if (len == 4 && STRNCMP(*arg, "list", len) == 0)
|
||||
{
|
||||
*arg += len;
|
||||
return parse_type_member(arg, &t_list_any, type_list);
|
||||
return parse_type_member(arg, &t_list_any, type_gap);
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
@@ -1508,14 +1692,6 @@ parse_type(char_u **arg, garray_T *type_list)
|
||||
return &t_number;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
if (len == 7 && STRNCMP(*arg, "partial", len) == 0)
|
||||
{
|
||||
*arg += len;
|
||||
// TODO: arguments and return type
|
||||
return &t_partial_any;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (len == 6 && STRNCMP(*arg, "string", len) == 0)
|
||||
{
|
||||
@@ -1574,7 +1750,7 @@ equal_type(type_T *type1, type_T *type2)
|
||||
* "type2" and "dest" may be the same.
|
||||
*/
|
||||
static void
|
||||
common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_list)
|
||||
common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_gap)
|
||||
{
|
||||
if (equal_type(type1, type2))
|
||||
{
|
||||
@@ -1588,11 +1764,11 @@ common_type(type_T *type1, type_T *type2, type_T **dest, garray_T *type_list)
|
||||
{
|
||||
type_T *common;
|
||||
|
||||
common_type(type1->tt_member, type2->tt_member, &common, type_list);
|
||||
common_type(type1->tt_member, type2->tt_member, &common, type_gap);
|
||||
if (type1->tt_type == VAR_LIST)
|
||||
*dest = get_list_type(common, type_list);
|
||||
*dest = get_list_type(common, type_gap);
|
||||
else
|
||||
*dest = get_dict_type(common, type_list);
|
||||
*dest = get_dict_type(common, type_gap);
|
||||
return;
|
||||
}
|
||||
// TODO: VAR_FUNC and VAR_PARTIAL
|
||||
@@ -1650,7 +1826,62 @@ type_name(type_T *type, char **tofree)
|
||||
return *tofree;
|
||||
}
|
||||
}
|
||||
// TODO: function and partial argument types
|
||||
if (type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL)
|
||||
{
|
||||
garray_T ga;
|
||||
int i;
|
||||
|
||||
ga_init2(&ga, 1, 100);
|
||||
if (ga_grow(&ga, 20) == FAIL)
|
||||
return "[unknown]";
|
||||
*tofree = ga.ga_data;
|
||||
STRCPY(ga.ga_data, "func(");
|
||||
ga.ga_len += 5;
|
||||
|
||||
for (i = 0; i < type->tt_argcount; ++i)
|
||||
{
|
||||
char *arg_free;
|
||||
char *arg_type = type_name(type->tt_args[i], &arg_free);
|
||||
int len;
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
STRCPY(ga.ga_data + ga.ga_len, ", ");
|
||||
ga.ga_len += 2;
|
||||
}
|
||||
len = (int)STRLEN(arg_type);
|
||||
if (ga_grow(&ga, len + 6) == FAIL)
|
||||
{
|
||||
vim_free(arg_free);
|
||||
return "[unknown]";
|
||||
}
|
||||
*tofree = ga.ga_data;
|
||||
STRCPY(ga.ga_data + ga.ga_len, arg_type);
|
||||
ga.ga_len += len;
|
||||
vim_free(arg_free);
|
||||
}
|
||||
|
||||
if (type->tt_member == &t_void)
|
||||
STRCPY(ga.ga_data + ga.ga_len, ")");
|
||||
else
|
||||
{
|
||||
char *ret_free;
|
||||
char *ret_name = type_name(type->tt_member, &ret_free);
|
||||
int len;
|
||||
|
||||
len = (int)STRLEN(ret_name) + 4;
|
||||
if (ga_grow(&ga, len) == FAIL)
|
||||
{
|
||||
vim_free(ret_free);
|
||||
return "[unknown]";
|
||||
}
|
||||
*tofree = ga.ga_data;
|
||||
STRCPY(ga.ga_data + ga.ga_len, "): ");
|
||||
STRCPY(ga.ga_data + ga.ga_len + 3, ret_name);
|
||||
vim_free(ret_free);
|
||||
}
|
||||
return ga.ga_data;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
@@ -1743,7 +1974,9 @@ free_imported(cctx_T *cctx)
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate an instruction to load script-local variable "name".
|
||||
* Generate an instruction to load script-local variable "name", without the
|
||||
* leading "s:".
|
||||
* Also finds imported variables.
|
||||
*/
|
||||
static int
|
||||
compile_load_scriptvar(
|
||||
@@ -1808,7 +2041,7 @@ compile_load_scriptvar(
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: check this is a variable, not a function
|
||||
// TODO: check this is a variable, not a function?
|
||||
generate_VIM9SCRIPT(cctx, ISN_LOADSCRIPT,
|
||||
import->imp_sid,
|
||||
import->imp_var_vals_idx,
|
||||
@@ -1822,6 +2055,17 @@ compile_load_scriptvar(
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
static int
|
||||
generate_funcref(cctx_T *cctx, char_u *name)
|
||||
{
|
||||
ufunc_T *ufunc = find_func(name, cctx);
|
||||
|
||||
if (ufunc == NULL)
|
||||
return FAIL;
|
||||
|
||||
return generate_PUSHFUNC(cctx, vim_strsave(name), ufunc->uf_func_type);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compile a variable name into a load instruction.
|
||||
* "end" points to just after the name.
|
||||
@@ -1926,10 +2170,21 @@ compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error)
|
||||
|| (len == 5 && STRNCMP("false", *arg, 5) == 0))
|
||||
res = generate_PUSHBOOL(cctx, **arg == 't'
|
||||
? VVAL_TRUE : VVAL_FALSE);
|
||||
else if (SCRIPT_ITEM(current_sctx.sc_sid)->sn_version
|
||||
== SCRIPT_VERSION_VIM9)
|
||||
// in Vim9 script "var" can be script-local.
|
||||
res = compile_load_scriptvar(cctx, name, *arg, &end, error);
|
||||
else
|
||||
{
|
||||
// "var" can be script-local even without using "s:" if it
|
||||
// already exists.
|
||||
if (SCRIPT_ITEM(current_sctx.sc_sid)->sn_version
|
||||
== SCRIPT_VERSION_VIM9
|
||||
|| lookup_script(*arg, len) == OK)
|
||||
res = compile_load_scriptvar(cctx, name, *arg, &end,
|
||||
FALSE);
|
||||
|
||||
// When the name starts with an uppercase letter or "x:" it
|
||||
// can be a user defined function.
|
||||
if (res == FAIL && (ASCII_ISUPPER(*name) || name[1] == ':'))
|
||||
res = generate_funcref(cctx, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gen_load)
|
||||
@@ -1962,14 +2217,14 @@ compile_arguments(char_u **arg, cctx_T *cctx, int *argcount)
|
||||
|
||||
if (*p != ',' && *skipwhite(p) == ',')
|
||||
{
|
||||
emsg(_("E1068: No white space allowed before ,"));
|
||||
semsg(_(e_no_white_before), ",");
|
||||
p = skipwhite(p);
|
||||
}
|
||||
if (*p == ',')
|
||||
{
|
||||
++p;
|
||||
if (!VIM_ISWHITE(*p))
|
||||
emsg(_("E1069: white space required after ,"));
|
||||
semsg(_(e_white_after), ",");
|
||||
}
|
||||
p = skipwhite(p);
|
||||
}
|
||||
@@ -2024,11 +2279,10 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init)
|
||||
// builtin function
|
||||
idx = find_internal_func(name);
|
||||
if (idx >= 0)
|
||||
{
|
||||
res = generate_BCALL(cctx, idx, argcount);
|
||||
goto theend;
|
||||
}
|
||||
semsg(_(e_unknownfunc), namebuf);
|
||||
else
|
||||
semsg(_(e_unknownfunc), namebuf);
|
||||
goto theend;
|
||||
}
|
||||
|
||||
// If we can find the function by name generate the right call.
|
||||
@@ -2139,6 +2393,8 @@ type_mismatch(type_T *expected, type_T *actual)
|
||||
static int
|
||||
check_type(type_T *expected, type_T *actual, int give_msg)
|
||||
{
|
||||
int ret = OK;
|
||||
|
||||
if (expected->tt_type != VAR_UNKNOWN)
|
||||
{
|
||||
if (expected->tt_type != actual->tt_type)
|
||||
@@ -2149,17 +2405,21 @@ check_type(type_T *expected, type_T *actual, int give_msg)
|
||||
}
|
||||
if (expected->tt_type == VAR_DICT || expected->tt_type == VAR_LIST)
|
||||
{
|
||||
int ret;
|
||||
|
||||
// void is used for an empty list or dict
|
||||
if (actual->tt_member == &t_void)
|
||||
ret = OK;
|
||||
else
|
||||
if (actual->tt_member != &t_void)
|
||||
ret = check_type(expected->tt_member, actual->tt_member, FALSE);
|
||||
if (ret == FAIL && give_msg)
|
||||
type_mismatch(expected, actual);
|
||||
return ret;
|
||||
}
|
||||
else if (expected->tt_type == VAR_FUNC)
|
||||
{
|
||||
if (expected->tt_member != &t_any)
|
||||
ret = check_type(expected->tt_member, actual->tt_member, FALSE);
|
||||
if (ret == OK && expected->tt_argcount != -1
|
||||
&& (actual->tt_argcount < expected->tt_min_argcount
|
||||
|| actual->tt_argcount > expected->tt_argcount))
|
||||
ret = FAIL;
|
||||
}
|
||||
if (ret == FAIL && give_msg)
|
||||
type_mismatch(expected, actual);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
@@ -2232,6 +2492,7 @@ compile_lambda(char_u **arg, cctx_T *cctx)
|
||||
ufunc = rettv.vval.v_partial->pt_func;
|
||||
++ufunc->uf_refcount;
|
||||
clear_tv(&rettv);
|
||||
ga_init2(&ufunc->uf_type_list, sizeof(type_T *), 10);
|
||||
|
||||
// The function will have one line: "return {expr}".
|
||||
// Compile it into instructions.
|
||||
@@ -2276,6 +2537,7 @@ compile_lambda_call(char_u **arg, cctx_T *cctx)
|
||||
ufunc = rettv.vval.v_partial->pt_func;
|
||||
++ufunc->uf_refcount;
|
||||
clear_tv(&rettv);
|
||||
ga_init2(&ufunc->uf_type_list, sizeof(type_T *), 10);
|
||||
|
||||
// The function will have one line: "return {expr}".
|
||||
// Compile it into instructions.
|
||||
@@ -3554,7 +3816,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
type = &t_string;
|
||||
if (is_decl)
|
||||
{
|
||||
semsg(_("E1065: Cannot declare an environment variable: %s"), name);
|
||||
semsg(_("E1065: Cannot declare an environment variable: %s"),
|
||||
name);
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
@@ -3636,7 +3899,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
if (is_decl)
|
||||
{
|
||||
semsg(_("E1054: Variable already declared in the script: %s"),
|
||||
name);
|
||||
name);
|
||||
goto theend;
|
||||
}
|
||||
}
|
||||
@@ -3678,17 +3941,20 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
goto theend;
|
||||
}
|
||||
|
||||
// +=, /=, etc. require an existing variable
|
||||
if (idx < 0 && dest == dest_local && cctx->ctx_skip != TRUE)
|
||||
{
|
||||
if (oplen > 1 && !heredoc)
|
||||
{
|
||||
// +=, /=, etc. require an existing variable
|
||||
semsg(_("E1020: cannot use an operator on a new variable: %s"),
|
||||
name);
|
||||
goto theend;
|
||||
}
|
||||
|
||||
// new local variable
|
||||
if ((type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL)
|
||||
&& var_check_func_name(name, TRUE))
|
||||
goto theend;
|
||||
idx = reserve_local(cctx, arg, varlen, cmdidx == CMD_const, type);
|
||||
if (idx < 0)
|
||||
goto theend;
|
||||
@@ -3772,7 +4038,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
if (idx >= 0 && (is_decl || !has_type))
|
||||
{
|
||||
lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx;
|
||||
if (!has_type)
|
||||
if (new_local && !has_type)
|
||||
{
|
||||
if (stacktype->tt_type == VAR_VOID)
|
||||
{
|
||||
@@ -3780,11 +4046,19 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
goto theend;
|
||||
}
|
||||
else
|
||||
lvar->lv_type = stacktype;
|
||||
{
|
||||
// An empty list or dict has a &t_void member, for a
|
||||
// variable that implies &t_any.
|
||||
if (stacktype == &t_list_empty)
|
||||
lvar->lv_type = &t_list_any;
|
||||
else if (stacktype == &t_dict_empty)
|
||||
lvar->lv_type = &t_dict_any;
|
||||
else
|
||||
lvar->lv_type = stacktype;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (check_type(lvar->lv_type, stacktype, TRUE) == FAIL)
|
||||
goto theend;
|
||||
else if (check_type(lvar->lv_type, stacktype, TRUE) == FAIL)
|
||||
goto theend;
|
||||
}
|
||||
else if (*p != '=' && check_type(type, stacktype, TRUE) == FAIL)
|
||||
goto theend;
|
||||
@@ -3821,7 +4095,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
generate_PUSHBLOB(cctx, NULL);
|
||||
break;
|
||||
case VAR_FUNC:
|
||||
generate_PUSHFUNC(cctx, NULL);
|
||||
generate_PUSHFUNC(cctx, NULL, &t_func_void);
|
||||
break;
|
||||
case VAR_PARTIAL:
|
||||
generate_PUSHPARTIAL(cctx, NULL);
|
||||
@@ -3914,7 +4188,24 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
|
||||
idx = get_script_item_idx(sid, rawname, TRUE);
|
||||
// TODO: specific type
|
||||
if (idx < 0)
|
||||
generate_OLDSCRIPT(cctx, ISN_STORES, name, sid, &t_any);
|
||||
{
|
||||
char_u *name_s = name;
|
||||
|
||||
// Include s: in the name for store_var()
|
||||
if (name[1] != ':')
|
||||
{
|
||||
int len = (int)STRLEN(name) + 3;
|
||||
|
||||
name_s = alloc(len);
|
||||
if (name_s == NULL)
|
||||
name_s = name;
|
||||
else
|
||||
vim_snprintf((char *)name_s, len, "s:%s", name);
|
||||
}
|
||||
generate_OLDSCRIPT(cctx, ISN_STORES, name_s, sid, &t_any);
|
||||
if (name_s != name)
|
||||
vim_free(name_s);
|
||||
}
|
||||
else
|
||||
generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT,
|
||||
sid, idx, &t_any);
|
||||
@@ -3995,6 +4286,18 @@ compile_fill_jump_to_end(endlabel_T **el, cctx_T *cctx)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
compile_free_jump_to_end(endlabel_T **el)
|
||||
{
|
||||
while (*el != NULL)
|
||||
{
|
||||
endlabel_T *cur = (*el);
|
||||
|
||||
*el = cur->el_next;
|
||||
vim_free(cur);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new scope and set up the generic items.
|
||||
*/
|
||||
@@ -4026,6 +4329,20 @@ drop_scope(cctx_T *cctx)
|
||||
return;
|
||||
}
|
||||
cctx->ctx_scope = scope->se_outer;
|
||||
switch (scope->se_type)
|
||||
{
|
||||
case IF_SCOPE:
|
||||
compile_free_jump_to_end(&scope->se_u.se_if.is_end_label); break;
|
||||
case FOR_SCOPE:
|
||||
compile_free_jump_to_end(&scope->se_u.se_for.fs_end_label); break;
|
||||
case WHILE_SCOPE:
|
||||
compile_free_jump_to_end(&scope->se_u.se_while.ws_end_label); break;
|
||||
case TRY_SCOPE:
|
||||
compile_free_jump_to_end(&scope->se_u.se_try.ts_end_label); break;
|
||||
case NO_SCOPE:
|
||||
case BLOCK_SCOPE:
|
||||
break;
|
||||
}
|
||||
vim_free(scope);
|
||||
}
|
||||
|
||||
@@ -4972,6 +5289,7 @@ compile_finally(char_u *arg, cctx_T *cctx)
|
||||
// Fill in the "end" label in jumps at the end of the blocks.
|
||||
compile_fill_jump_to_end(&scope->se_u.se_try.ts_end_label, cctx);
|
||||
|
||||
isn->isn_arg.try.try_finally = instr->ga_len;
|
||||
if (scope->se_u.se_try.ts_catch_label != 0)
|
||||
{
|
||||
// Previous catch without match jumps here
|
||||
@@ -4979,7 +5297,6 @@ compile_finally(char_u *arg, cctx_T *cctx)
|
||||
isn->isn_arg.jump.jump_where = instr->ga_len;
|
||||
}
|
||||
|
||||
isn->isn_arg.try.try_finally = instr->ga_len;
|
||||
// TODO: set index in ts_finally_label jumps
|
||||
|
||||
return arg;
|
||||
@@ -5206,13 +5523,17 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
|
||||
{
|
||||
int is_ex_command;
|
||||
|
||||
// Bail out on the first error to avoid a flood of errors and report
|
||||
// the right line number when inside try/catch.
|
||||
if (emsg_before != called_emsg)
|
||||
goto erret;
|
||||
|
||||
if (line != NULL && *line == '|')
|
||||
// the line continues after a '|'
|
||||
++line;
|
||||
else if (line != NULL && *line != NUL)
|
||||
{
|
||||
if (emsg_before == called_emsg)
|
||||
semsg(_("E488: Trailing characters: %s"), line);
|
||||
semsg(_("E488: Trailing characters: %s"), line);
|
||||
goto erret;
|
||||
}
|
||||
else
|
||||
@@ -5350,13 +5671,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
|
||||
line = p;
|
||||
continue;
|
||||
}
|
||||
if (ea.cmdidx == CMD_let)
|
||||
{
|
||||
line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
|
||||
if (line == NULL)
|
||||
goto erret;
|
||||
continue;
|
||||
}
|
||||
// CMD_let cannot happen, compile_assignment() above is used
|
||||
iemsg("Command from find_ex_command() not handled");
|
||||
goto erret;
|
||||
}
|
||||
@@ -5464,6 +5779,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
|
||||
}
|
||||
if (line == NULL)
|
||||
goto erret;
|
||||
line = skipwhite(line);
|
||||
|
||||
if (cctx.ctx_type_stack.ga_len < 0)
|
||||
{
|
||||
@@ -5507,6 +5823,43 @@ compile_def_function(ufunc_T *ufunc, int set_return_type)
|
||||
dfunc->df_varcount = cctx.ctx_max_local;
|
||||
}
|
||||
|
||||
{
|
||||
int varargs = ufunc->uf_va_name != NULL;
|
||||
int argcount = ufunc->uf_args.ga_len - (varargs ? 1 : 0);
|
||||
|
||||
// Create a type for the function, with the return type and any
|
||||
// argument types.
|
||||
// A vararg is included in uf_args.ga_len but not in uf_arg_types.
|
||||
// The type is included in "tt_args".
|
||||
ufunc->uf_func_type = get_func_type(ufunc->uf_ret_type,
|
||||
ufunc->uf_args.ga_len, &ufunc->uf_type_list);
|
||||
if (ufunc->uf_args.ga_len > 0)
|
||||
{
|
||||
if (func_type_add_arg_types(ufunc->uf_func_type,
|
||||
ufunc->uf_args.ga_len,
|
||||
argcount - ufunc->uf_def_args.ga_len,
|
||||
&ufunc->uf_type_list) == FAIL)
|
||||
{
|
||||
ret = FAIL;
|
||||
goto erret;
|
||||
}
|
||||
if (ufunc->uf_arg_types == NULL)
|
||||
{
|
||||
int i;
|
||||
|
||||
// lambda does not have argument types.
|
||||
for (i = 0; i < argcount; ++i)
|
||||
ufunc->uf_func_type->tt_args[i] = &t_any;
|
||||
}
|
||||
else
|
||||
mch_memmove(ufunc->uf_func_type->tt_args,
|
||||
ufunc->uf_arg_types, sizeof(type_T *) * argcount);
|
||||
if (varargs)
|
||||
ufunc->uf_func_type->tt_args[argcount] =
|
||||
ufunc->uf_va_type == NULL ? &t_any : ufunc->uf_va_type;
|
||||
}
|
||||
}
|
||||
|
||||
ret = OK;
|
||||
|
||||
erret:
|
||||
@@ -5524,6 +5877,9 @@ erret:
|
||||
if (!dfunc->df_deleted)
|
||||
--def_functions.ga_len;
|
||||
|
||||
while (cctx.ctx_scope != NULL)
|
||||
drop_scope(&cctx);
|
||||
|
||||
// Don't execute this function body.
|
||||
ga_clear_strings(&ufunc->uf_lines);
|
||||
|
||||
|
||||
@@ -377,7 +377,7 @@ store_var(char_u *name, typval_T *tv)
|
||||
funccal_entry_T entry;
|
||||
|
||||
save_funccal(&entry);
|
||||
set_var_const(name, NULL, tv, FALSE, 0);
|
||||
set_var_const(name, NULL, tv, FALSE, LET_NO_COMMAND);
|
||||
restore_funccal();
|
||||
}
|
||||
|
||||
@@ -739,7 +739,7 @@ call_def_function(
|
||||
|
||||
--ectx.ec_stack.ga_len;
|
||||
if (di == NULL)
|
||||
store_var(iptr->isn_arg.string, STACK_TV_BOT(0));
|
||||
store_var(name, STACK_TV_BOT(0));
|
||||
else
|
||||
{
|
||||
clear_tv(&di->di_tv);
|
||||
@@ -1828,7 +1828,7 @@ ex_disassemble(exarg_T *eap)
|
||||
iptr->isn_arg.loadstore.ls_sid);
|
||||
|
||||
smsg("%4d LOADS s:%s from %s", current,
|
||||
iptr->isn_arg.string, si->sn_name);
|
||||
iptr->isn_arg.loadstore.ls_name, si->sn_name);
|
||||
}
|
||||
break;
|
||||
case ISN_LOADG:
|
||||
@@ -1865,7 +1865,7 @@ ex_disassemble(exarg_T *eap)
|
||||
iptr->isn_arg.loadstore.ls_sid);
|
||||
|
||||
smsg("%4d STORES %s in %s", current,
|
||||
iptr->isn_arg.string, si->sn_name);
|
||||
iptr->isn_arg.loadstore.ls_name, si->sn_name);
|
||||
}
|
||||
break;
|
||||
case ISN_STORESCRIPT:
|
||||
|
||||
Reference in New Issue
Block a user