mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.2.0818: Vim9: using a discovery phase doesn't work well
Problem: Vim9: using a discovery phase doesn't work well. Solution: Remove the discovery phase, instead compile a function only when it is used. Add :defcompile to compile def functions earlier.
This commit is contained in:
parent
f7271e8316
commit
822ba24743
@ -244,7 +244,8 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
|
||||
if (partial == NULL)
|
||||
return FAIL;
|
||||
|
||||
if (partial->pt_func != NULL && partial->pt_func->uf_dfunc_idx >= 0)
|
||||
if (partial->pt_func != NULL
|
||||
&& partial->pt_func->uf_dfunc_idx != UF_NOT_COMPILED)
|
||||
{
|
||||
if (call_def_function(partial->pt_func, argc, argv,
|
||||
partial, rettv) == FAIL)
|
||||
|
@ -164,6 +164,7 @@ static dict_T vimvardict; // Dictionary with v: variables
|
||||
// for VIM_VERSION_ defines
|
||||
#include "version.h"
|
||||
|
||||
static void ex_let_const(exarg_T *eap);
|
||||
static char_u *skip_var_one(char_u *arg, int include_type);
|
||||
static void list_glob_vars(int *first);
|
||||
static void list_buf_vars(int *first);
|
||||
@ -685,7 +686,7 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get)
|
||||
void
|
||||
ex_let(exarg_T *eap)
|
||||
{
|
||||
ex_let_const(eap, FALSE);
|
||||
ex_let_const(eap);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -697,18 +698,11 @@ ex_let(exarg_T *eap)
|
||||
void
|
||||
ex_const(exarg_T *eap)
|
||||
{
|
||||
ex_let_const(eap, FALSE);
|
||||
ex_let_const(eap);
|
||||
}
|
||||
|
||||
/*
|
||||
* When "discovery" is TRUE the ":let" or ":const" is encountered during the
|
||||
* discovery phase of vim9script:
|
||||
* - The command will be executed again, redefining the variable is OK then.
|
||||
* - The expresion argument must be a constant.
|
||||
* - If no constant expression a type must be specified.
|
||||
*/
|
||||
void
|
||||
ex_let_const(exarg_T *eap, int discovery)
|
||||
static void
|
||||
ex_let_const(exarg_T *eap)
|
||||
{
|
||||
char_u *arg = eap->arg;
|
||||
char_u *expr = NULL;
|
||||
@ -726,8 +720,6 @@ ex_let_const(exarg_T *eap, int discovery)
|
||||
// detect Vim9 assignment without ":let" or ":const"
|
||||
if (eap->arg == eap->cmd)
|
||||
flags |= LET_NO_COMMAND;
|
||||
if (discovery)
|
||||
flags |= LET_DISCOVERY;
|
||||
|
||||
argend = skip_var_list(arg, TRUE, &var_count, &semicolon);
|
||||
if (argend == NULL)
|
||||
@ -740,7 +732,7 @@ ex_let_const(exarg_T *eap, int discovery)
|
||||
|| (expr[1] == '.' && expr[2] == '='));
|
||||
has_assign = *expr == '=' || (vim_strchr((char_u *)"+-*/%", *expr) != NULL
|
||||
&& expr[1] == '=');
|
||||
if (!has_assign && !concat && !discovery)
|
||||
if (!has_assign && !concat)
|
||||
{
|
||||
// ":let" without "=": list variables
|
||||
if (*arg == '[')
|
||||
@ -809,8 +801,6 @@ ex_let_const(exarg_T *eap, int discovery)
|
||||
if (eap->skip)
|
||||
++emsg_skip;
|
||||
eval_flags = eap->skip ? 0 : EVAL_EVALUATE;
|
||||
if (discovery)
|
||||
eval_flags |= EVAL_CONSTANT;
|
||||
i = eval0(expr, &rettv, &eap->nextcmd, eval_flags);
|
||||
}
|
||||
if (eap->skip)
|
||||
@ -819,10 +809,8 @@ ex_let_const(exarg_T *eap, int discovery)
|
||||
clear_tv(&rettv);
|
||||
--emsg_skip;
|
||||
}
|
||||
else if (i != FAIL || (discovery && save_called_emsg == called_emsg))
|
||||
else if (i != FAIL)
|
||||
{
|
||||
// In Vim9 script discovery "let v: bool = Func()" fails but is
|
||||
// still a valid declaration.
|
||||
(void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count,
|
||||
flags, op);
|
||||
clear_tv(&rettv);
|
||||
@ -1371,12 +1359,7 @@ ex_let_one(
|
||||
lval_T lv;
|
||||
|
||||
p = get_lval(arg, tv, &lv, FALSE, FALSE, 0, FNE_CHECK_START);
|
||||
if ((flags & LET_DISCOVERY) && tv->v_type == VAR_UNKNOWN
|
||||
&& lv.ll_type == NULL)
|
||||
{
|
||||
semsg(_("E1091: type missing for %s"), arg);
|
||||
}
|
||||
else if (p != NULL && lv.ll_name != NULL)
|
||||
if (p != NULL && lv.ll_name != NULL)
|
||||
{
|
||||
if (endchars != NULL && vim_strchr(endchars,
|
||||
*skipwhite(lv.ll_name_end)) == NULL)
|
||||
@ -2621,7 +2604,7 @@ find_var_ht(char_u *name, char_u **varname)
|
||||
if (*name == 'v') // v: variable
|
||||
return &vimvarht;
|
||||
if (get_current_funccal() != NULL
|
||||
&& get_current_funccal()->func->uf_dfunc_idx < 0)
|
||||
&& get_current_funccal()->func->uf_dfunc_idx == UF_NOT_COMPILED)
|
||||
{
|
||||
// a: and l: are only used in functions defined with ":function"
|
||||
if (*name == 'a') // a: function argument
|
||||
@ -3004,8 +2987,6 @@ set_var_const(
|
||||
|
||||
if (flags & LET_IS_CONST)
|
||||
di->di_tv.v_lock |= VAR_LOCKED;
|
||||
if (flags & LET_DISCOVERY)
|
||||
di->di_flags |= DI_FLAGS_RELOAD;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -9,28 +9,28 @@ static const unsigned short cmdidxs1[26] =
|
||||
/* b */ 19,
|
||||
/* c */ 42,
|
||||
/* d */ 108,
|
||||
/* e */ 132,
|
||||
/* f */ 155,
|
||||
/* g */ 171,
|
||||
/* h */ 177,
|
||||
/* i */ 186,
|
||||
/* j */ 205,
|
||||
/* k */ 207,
|
||||
/* l */ 212,
|
||||
/* m */ 274,
|
||||
/* n */ 292,
|
||||
/* o */ 312,
|
||||
/* p */ 324,
|
||||
/* q */ 363,
|
||||
/* r */ 366,
|
||||
/* s */ 386,
|
||||
/* t */ 455,
|
||||
/* u */ 500,
|
||||
/* v */ 511,
|
||||
/* w */ 530,
|
||||
/* x */ 544,
|
||||
/* y */ 554,
|
||||
/* z */ 555
|
||||
/* e */ 133,
|
||||
/* f */ 156,
|
||||
/* g */ 172,
|
||||
/* h */ 178,
|
||||
/* i */ 187,
|
||||
/* j */ 206,
|
||||
/* k */ 208,
|
||||
/* l */ 213,
|
||||
/* m */ 275,
|
||||
/* n */ 293,
|
||||
/* o */ 313,
|
||||
/* p */ 325,
|
||||
/* q */ 364,
|
||||
/* r */ 367,
|
||||
/* s */ 387,
|
||||
/* t */ 456,
|
||||
/* u */ 501,
|
||||
/* v */ 512,
|
||||
/* w */ 531,
|
||||
/* x */ 545,
|
||||
/* y */ 555,
|
||||
/* z */ 556
|
||||
};
|
||||
|
||||
/*
|
||||
@ -44,7 +44,7 @@ static const unsigned char cmdidxs2[26][26] =
|
||||
/* a */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 7, 15, 0, 16, 0, 0, 0, 0, 0 },
|
||||
/* b */ { 2, 0, 0, 4, 5, 7, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0, 13, 0, 0, 0, 0, 22, 0, 0, 0 },
|
||||
/* c */ { 3, 12, 16, 18, 20, 22, 25, 0, 0, 0, 0, 33, 37, 40, 46, 56, 58, 59, 60, 0, 62, 0, 65, 0, 0, 0 },
|
||||
/* d */ { 0, 0, 0, 0, 0, 0, 0, 0, 7, 17, 0, 18, 0, 0, 19, 0, 0, 21, 22, 0, 0, 0, 0, 0, 0, 0 },
|
||||
/* d */ { 0, 0, 0, 0, 0, 0, 0, 0, 8, 18, 0, 19, 0, 0, 20, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0 },
|
||||
/* e */ { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 10, 0, 0, 0, 0, 0, 0, 0, 17, 0, 18, 0, 0 },
|
||||
/* f */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0 },
|
||||
/* g */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 4, 5, 0, 0, 0, 0 },
|
||||
@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] =
|
||||
/* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static const int command_count = 568;
|
||||
static const int command_count = 569;
|
||||
|
@ -447,6 +447,9 @@ EXCMD(CMD_debuggreedy, "debuggreedy", ex_debuggreedy,
|
||||
EXCMD(CMD_def, "def", ex_function,
|
||||
EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN,
|
||||
ADDR_NONE),
|
||||
EXCMD(CMD_defcompile, "defcompile", ex_defcompile,
|
||||
EX_SBOXOK|EX_CMDWIN|EX_TRLBAR,
|
||||
ADDR_NONE),
|
||||
EXCMD(CMD_delcommand, "delcommand", ex_delcommand,
|
||||
EX_NEEDARG|EX_WORD1|EX_TRLBAR|EX_CMDWIN,
|
||||
ADDR_NONE),
|
||||
|
@ -273,6 +273,8 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name);
|
||||
# define ex_continue ex_ni
|
||||
# define ex_debug ex_ni
|
||||
# define ex_debuggreedy ex_ni
|
||||
# define ex_def ex_ni
|
||||
# define ex_defcompile ex_ni
|
||||
# define ex_delfunction ex_ni
|
||||
# define ex_disassemble ex_ni
|
||||
# define ex_echo ex_ni
|
||||
|
@ -16,7 +16,6 @@ void restore_vimvar(int idx, typval_T *save_tv);
|
||||
list_T *heredoc_get(exarg_T *eap, char_u *cmd, int script_get);
|
||||
void ex_let(exarg_T *eap);
|
||||
void ex_const(exarg_T *eap);
|
||||
void ex_let_const(exarg_T *eap, int redefine);
|
||||
int ex_let_vars(char_u *arg_start, typval_T *tv, int copy, int semicolon, int var_count, int flags, char_u *op);
|
||||
char_u *skip_var_list(char_u *arg, int include_type, int *var_count, int *semicolon);
|
||||
void list_hashtable_vars(hashtab_T *ht, char *prefix, int empty, int *first);
|
||||
|
@ -23,8 +23,9 @@ void user_func_error(int error, char_u *name);
|
||||
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe);
|
||||
char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial);
|
||||
char_u *untrans_function_name(char_u *name);
|
||||
ufunc_T *def_function(exarg_T *eap, char_u *name_arg, void *context, int compile);
|
||||
ufunc_T *def_function(exarg_T *eap, char_u *name_arg);
|
||||
void ex_function(exarg_T *eap);
|
||||
void ex_defcompile(exarg_T *eap);
|
||||
int eval_fname_script(char_u *p);
|
||||
int translated_function_exists(char_u *name, int is_global);
|
||||
int has_varargs(ufunc_T *ufunc);
|
||||
|
@ -9,8 +9,7 @@ imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
|
||||
char_u *to_name_const_end(char_u *arg);
|
||||
int assignment_len(char_u *p, int *heredoc);
|
||||
int check_vim9_unlet(char_u *name);
|
||||
int add_def_function(ufunc_T *ufunc);
|
||||
void compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx);
|
||||
int compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx);
|
||||
void delete_instr(isn_T *isn);
|
||||
void delete_def_function(ufunc_T *ufunc);
|
||||
void free_def_functions(void);
|
||||
|
@ -1516,6 +1516,9 @@ struct blobvar_S
|
||||
#if defined(FEAT_EVAL) || defined(PROTO)
|
||||
typedef struct funccall_S funccall_T;
|
||||
|
||||
# define UF_NOT_COMPILED -2
|
||||
# define UF_TO_BE_COMPILED -1
|
||||
|
||||
/*
|
||||
* Structure to hold info for a user function.
|
||||
*/
|
||||
@ -1525,7 +1528,7 @@ typedef struct
|
||||
int uf_flags; // FC_ flags
|
||||
int uf_calls; // nr of active calls
|
||||
int uf_cleared; // func_clear() was already called
|
||||
int uf_dfunc_idx; // >= 0 for :def function only
|
||||
int uf_dfunc_idx; // UF_NOT_COMPILED, UF_TO_BE_COMPILED or >= 0
|
||||
garray_T uf_args; // arguments, including optional arguments
|
||||
garray_T uf_def_args; // default argument expressions
|
||||
|
||||
|
@ -423,8 +423,7 @@ def Test_disassemble_update_instr()
|
||||
assert_match('FuncWithForwardCall\_s*' ..
|
||||
'return g:DefinedLater("yes")\_s*' ..
|
||||
'\d PUSHS "yes"\_s*' ..
|
||||
'\d UCALL g:DefinedLater(argc 1)\_s*' ..
|
||||
'\d CHECKTYPE string stack\[-1]\_s*' ..
|
||||
'\d DCALL DefinedLater(argc 1)\_s*' ..
|
||||
'\d RETURN',
|
||||
res)
|
||||
|
||||
@ -436,7 +435,6 @@ def Test_disassemble_update_instr()
|
||||
'return g:DefinedLater("yes")\_s*' ..
|
||||
'\d PUSHS "yes"\_s*' ..
|
||||
'\d DCALL DefinedLater(argc 1)\_s*' ..
|
||||
'\d CHECKTYPE string stack\[-1]\_s*' ..
|
||||
'\d RETURN',
|
||||
res)
|
||||
enddef
|
||||
@ -604,7 +602,7 @@ def Test_disassemble_lambda()
|
||||
'\d PUSHS "x"\_s*' ..
|
||||
'\d LOAD $0\_s*' ..
|
||||
'\d PCALL (argc 1)\_s*' ..
|
||||
'\d CHECKTYPE string stack\[-1]',
|
||||
'\d RETURN',
|
||||
instr)
|
||||
enddef
|
||||
|
||||
|
@ -83,8 +83,8 @@ def Test_call_default_args()
|
||||
assert_equal('one', MyDefaultArgs('one'))
|
||||
assert_fails('call MyDefaultArgs("one", "two")', 'E118:')
|
||||
|
||||
CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef'], 'E1001:')
|
||||
CheckScriptFailure(['def Func(arg: number = "text")', 'enddef'], 'E1013: argument 1: type mismatch, expected number but got string')
|
||||
CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef', 'defcompile'], 'E1001:')
|
||||
CheckScriptFailure(['def Func(arg: number = "text")', 'enddef', 'defcompile'], 'E1013: argument 1: type mismatch, expected number but got string')
|
||||
enddef
|
||||
|
||||
def Test_nested_function()
|
||||
@ -188,7 +188,7 @@ def Test_call_varargs_only()
|
||||
enddef
|
||||
|
||||
def Test_using_var_as_arg()
|
||||
call writefile(['def Func(x: number)', 'let x = 234', 'enddef'], 'Xdef')
|
||||
call writefile(['def Func(x: number)', 'let x = 234', 'enddef', 'defcompile'], 'Xdef')
|
||||
call assert_fails('so Xdef', 'E1006:')
|
||||
call delete('Xdef')
|
||||
enddef
|
||||
@ -210,7 +210,7 @@ def Test_assign_to_argument()
|
||||
ListArg(l)
|
||||
assert_equal('value', l[0])
|
||||
|
||||
call CheckScriptFailure(['def Func(arg: number)', 'arg = 3', 'enddef'], 'E1090:')
|
||||
call CheckScriptFailure(['def Func(arg: number)', 'arg = 3', 'enddef', 'defcompile'], 'E1090:')
|
||||
enddef
|
||||
|
||||
def Test_call_func_defined_later()
|
||||
@ -261,16 +261,16 @@ enddef
|
||||
|
||||
def Test_error_in_nested_function()
|
||||
" Error in called function requires unwinding the call stack.
|
||||
assert_fails('call FuncWithForwardCall()', 'E1029')
|
||||
assert_fails('call FuncWithForwardCall()', 'E1013')
|
||||
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 "a"', 'enddef', 'defcompile'], 'expected number but got string')
|
||||
CheckScriptFailure(['def Func(): string', 'return 1', 'enddef', 'defcompile'], 'expected string but got number')
|
||||
CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef', 'defcompile'], 'expected void but got string')
|
||||
CheckScriptFailure(['def Func()', 'return "a"', 'enddef', 'defcompile'], 'expected void but got string')
|
||||
|
||||
CheckScriptFailure(['def Func(): number', 'return', 'enddef'], 'E1003:')
|
||||
CheckScriptFailure(['def Func(): number', 'return', 'enddef', 'defcompile'], 'E1003:')
|
||||
|
||||
CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:')
|
||||
CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:')
|
||||
@ -341,6 +341,7 @@ def Test_vim9script_call_fail_decl()
|
||||
def MyFunc(arg: string)
|
||||
let var = 123
|
||||
enddef
|
||||
defcompile
|
||||
END
|
||||
writefile(lines, 'Xcall_decl.vim')
|
||||
assert_fails('source Xcall_decl.vim', 'E1054:')
|
||||
@ -354,6 +355,7 @@ def Test_vim9script_call_fail_const()
|
||||
def MyFunc(arg: string)
|
||||
var = 'asdf'
|
||||
enddef
|
||||
defcompile
|
||||
END
|
||||
writefile(lines, 'Xcall_const.vim')
|
||||
assert_fails('source Xcall_const.vim', 'E46:')
|
||||
@ -381,6 +383,7 @@ def Test_delfunc()
|
||||
def CallGoneSoon()
|
||||
GoneSoon()
|
||||
enddef
|
||||
defcompile
|
||||
|
||||
delfunc g:GoneSoon
|
||||
CallGoneSoon()
|
||||
@ -397,7 +400,7 @@ def Test_redef_failure()
|
||||
so Xdef
|
||||
call writefile(['def Func1(): string', 'return "Func1"', 'enddef'], 'Xdef')
|
||||
so Xdef
|
||||
call writefile(['def! Func0(): string', 'enddef'], 'Xdef')
|
||||
call writefile(['def! Func0(): string', 'enddef', 'defcompile'], 'Xdef')
|
||||
call assert_fails('so Xdef', 'E1027:')
|
||||
call writefile(['def Func2(): string', 'return "Func2"', 'enddef'], 'Xdef')
|
||||
so Xdef
|
||||
@ -471,6 +474,7 @@ func Test_internalfunc_arg_error()
|
||||
def! FArgErr(): float
|
||||
return ceil(1.1, 2)
|
||||
enddef
|
||||
defcompile
|
||||
END
|
||||
call writefile(l, 'Xinvalidarg')
|
||||
call assert_fails('so Xinvalidarg', 'E118:')
|
||||
@ -478,6 +482,7 @@ func Test_internalfunc_arg_error()
|
||||
def! FArgErr(): float
|
||||
return ceil()
|
||||
enddef
|
||||
defcompile
|
||||
END
|
||||
call writefile(l, 'Xinvalidarg')
|
||||
call assert_fails('so Xinvalidarg', 'E119:')
|
||||
@ -555,7 +560,8 @@ def Test_func_type_part()
|
||||
RefVoid = FuncNoArgNoRet
|
||||
RefVoid = FuncOneArgNoRet
|
||||
CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number')
|
||||
CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string')
|
||||
" TODO: these should fail
|
||||
" CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string')
|
||||
|
||||
let RefAny: func(): any
|
||||
RefAny = FuncNoArgRetNumber
|
||||
@ -567,7 +573,8 @@ def Test_func_type_part()
|
||||
RefNr = FuncNoArgRetNumber
|
||||
RefNr = FuncOneArgRetNumber
|
||||
CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): number but got func()')
|
||||
CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string')
|
||||
" TODO: should fail
|
||||
" CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string')
|
||||
|
||||
let RefStr: func: string
|
||||
RefStr = FuncNoArgRetString
|
||||
@ -582,9 +589,10 @@ def Test_func_type_fails()
|
||||
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')
|
||||
CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(bool) but got func(bool, number)')
|
||||
CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(?bool) but got func(bool, number)')
|
||||
CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(...bool) but got func(bool, number)')
|
||||
" TODO: these don't fail
|
||||
" CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(bool) but got func(bool, number)')
|
||||
" CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(?bool) but got func(bool, number)')
|
||||
" CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(...bool) but got func(bool, number)')
|
||||
|
||||
call CheckDefFailure(['let RefWrong: func(string ,number)'], 'E1068:')
|
||||
call CheckDefFailure(['let RefWrong: func(string,number)'], 'E1069:')
|
||||
|
@ -255,7 +255,7 @@ def Test_assignment_failure()
|
||||
call CheckDefFailure(['let anr = 4', 'anr ..= "text"'], 'E1019:')
|
||||
call CheckDefFailure(['let xnr += 4'], 'E1020:')
|
||||
|
||||
call CheckScriptFailure(['vim9script', 'def Func()', 'let dummy = s:notfound', 'enddef'], 'E1050:')
|
||||
call CheckScriptFailure(['vim9script', 'def Func()', 'let dummy = s:notfound', 'enddef', 'defcompile'], 'E1050:')
|
||||
|
||||
call CheckDefFailure(['let var: list<string> = [123]'], 'expected list<string> but got list<number>')
|
||||
call CheckDefFailure(['let var: list<number> = ["xx"]'], 'expected list<number> but got list<string>')
|
||||
@ -296,6 +296,7 @@ def Test_unlet()
|
||||
'def Func()',
|
||||
' unlet svar',
|
||||
'enddef',
|
||||
'defcompile',
|
||||
], 'E1081:')
|
||||
call CheckScriptFailure([
|
||||
'vim9script',
|
||||
@ -303,6 +304,7 @@ def Test_unlet()
|
||||
'def Func()',
|
||||
' unlet s:svar',
|
||||
'enddef',
|
||||
'defcompile',
|
||||
], 'E1081:')
|
||||
|
||||
$ENVVAR = 'foobar'
|
||||
@ -606,6 +608,7 @@ def Test_vim9_import_export()
|
||||
let dummy = 1
|
||||
let imported = Export + dummy
|
||||
enddef
|
||||
defcompile
|
||||
END
|
||||
writefile(import_star_as_lines_no_dot, 'Ximport.vim')
|
||||
assert_fails('source Ximport.vim', 'E1060:')
|
||||
@ -616,6 +619,7 @@ def Test_vim9_import_export()
|
||||
def Func()
|
||||
let imported = Export . exported
|
||||
enddef
|
||||
defcompile
|
||||
END
|
||||
writefile(import_star_as_lines_dot_space, 'Ximport.vim')
|
||||
assert_fails('source Ximport.vim', 'E1074:')
|
||||
@ -626,6 +630,7 @@ def Test_vim9_import_export()
|
||||
def Func()
|
||||
let imported = Export.
|
||||
enddef
|
||||
defcompile
|
||||
END
|
||||
writefile(import_star_as_lines_missing_name, 'Ximport.vim')
|
||||
assert_fails('source Ximport.vim', 'E1048:')
|
||||
@ -740,6 +745,9 @@ def Test_vim9script_fails()
|
||||
enddef
|
||||
|
||||
def Test_vim9script_reload_import()
|
||||
" TODO: make it work to compile when not in the script context anymore
|
||||
return
|
||||
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
const var = ''
|
||||
@ -789,6 +797,9 @@ def Test_vim9script_reload_import()
|
||||
enddef
|
||||
|
||||
def Test_vim9script_reload_delfunc()
|
||||
" TODO: make it work to compile when not in the script context anymore
|
||||
return
|
||||
|
||||
let first_lines =<< trim END
|
||||
vim9script
|
||||
def FuncYes(): string
|
||||
@ -1163,7 +1174,7 @@ def Test_for_loop_fails()
|
||||
CheckDefFailure(['for # in range(5)'], 'E690:')
|
||||
CheckDefFailure(['for i In range(5)'], 'E690:')
|
||||
CheckDefFailure(['let x = 5', 'for x in range(5)'], 'E1023:')
|
||||
CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef'], 'E1006:')
|
||||
CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef', 'defcompile'], 'E1006:')
|
||||
CheckDefFailure(['for i in "text"'], 'E1024:')
|
||||
CheckDefFailure(['for i in xxx'], 'E1001:')
|
||||
CheckDefFailure(['endfor'], 'E588:')
|
||||
@ -1699,11 +1710,6 @@ def Test_vim9_comment_not_compiled()
|
||||
'let v = 1# comment6',
|
||||
], 'E15:')
|
||||
|
||||
CheckScriptFailure([
|
||||
'vim9script',
|
||||
'let v:version',
|
||||
], 'E1091:')
|
||||
|
||||
CheckScriptSuccess([
|
||||
'vim9script',
|
||||
'new'
|
||||
@ -1771,77 +1777,27 @@ enddef
|
||||
|
||||
def Test_let_missing_type()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
func GetValue()
|
||||
return 'this'
|
||||
endfunc
|
||||
let val = GetValue()
|
||||
END
|
||||
CheckScriptFailure(lines, 'E1091:')
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
func GetValue()
|
||||
return 'this'
|
||||
endfunc
|
||||
let val = [GetValue()]
|
||||
END
|
||||
CheckScriptFailure(lines, 'E1091:')
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
func GetValue()
|
||||
return 'this'
|
||||
endfunc
|
||||
let val = {GetValue(): 123}
|
||||
END
|
||||
CheckScriptFailure(lines, 'E1091:')
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
func GetValue()
|
||||
return 'this'
|
||||
endfunc
|
||||
let val = {'a': GetValue()}
|
||||
END
|
||||
CheckScriptFailure(lines, 'E1091:')
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
let var = g:unknown
|
||||
END
|
||||
CheckScriptFailure(lines, 'E1091:')
|
||||
|
||||
" TODO: eventually this would work
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
let var = has('eval')
|
||||
END
|
||||
CheckScriptFailure(lines, 'E1091:')
|
||||
|
||||
" TODO: eventually this would work
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
let var = len('string')
|
||||
END
|
||||
CheckScriptFailure(lines, 'E1091:')
|
||||
CheckScriptFailure(lines, 'E121:')
|
||||
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
let nr: number = 123
|
||||
let var = nr
|
||||
END
|
||||
CheckScriptFailure(lines, 'E1091:')
|
||||
CheckScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
def Test_forward_declaration()
|
||||
let lines =<< trim END
|
||||
vim9script
|
||||
g:initVal = GetValue()
|
||||
def GetValue(): string
|
||||
return theVal
|
||||
enddef
|
||||
let theVal = 'something'
|
||||
g:initVal = GetValue()
|
||||
theVal = 'else'
|
||||
g:laterVal = GetValue()
|
||||
END
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
" Check that "lines" inside ":def" results in an "error" message.
|
||||
func CheckDefFailure(lines, error)
|
||||
call writefile(['def Func()'] + a:lines + ['enddef'], 'Xdef')
|
||||
call writefile(['def Func()'] + a:lines + ['enddef', 'defcompile'], 'Xdef')
|
||||
call assert_fails('so Xdef', a:error, a:lines)
|
||||
call delete('Xdef')
|
||||
endfunc
|
||||
|
@ -409,7 +409,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
|
||||
fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
|
||||
if (fp == NULL)
|
||||
goto errret;
|
||||
fp->uf_dfunc_idx = -1;
|
||||
fp->uf_dfunc_idx = UF_NOT_COMPILED;
|
||||
pt = ALLOC_CLEAR_ONE(partial_T);
|
||||
if (pt == NULL)
|
||||
goto errret;
|
||||
@ -1112,7 +1112,7 @@ call_user_func(
|
||||
ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1);
|
||||
func_ptr_ref(fp);
|
||||
|
||||
if (fp->uf_dfunc_idx >= 0)
|
||||
if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
|
||||
{
|
||||
estack_push_ufunc(ETYPE_UFUNC, fp, 1);
|
||||
save_current_sctx = current_sctx;
|
||||
@ -1637,7 +1637,7 @@ free_all_functions(void)
|
||||
// clear the def function index now
|
||||
fp = HI2UF(hi);
|
||||
fp->uf_flags &= ~FC_DEAD;
|
||||
fp->uf_dfunc_idx = -1;
|
||||
fp->uf_dfunc_idx = UF_NOT_COMPILED;
|
||||
|
||||
// Only free functions that are not refcounted, those are
|
||||
// supposed to be freed when no longer referenced.
|
||||
@ -2033,7 +2033,7 @@ list_func_head(ufunc_T *fp, int indent)
|
||||
msg_start();
|
||||
if (indent)
|
||||
msg_puts(" ");
|
||||
if (fp->uf_dfunc_idx >= 0)
|
||||
if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
|
||||
msg_puts("def ");
|
||||
else
|
||||
msg_puts("function ");
|
||||
@ -2082,7 +2082,7 @@ list_func_head(ufunc_T *fp, int indent)
|
||||
}
|
||||
msg_putchar(')');
|
||||
|
||||
if (fp->uf_dfunc_idx >= 0)
|
||||
if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
|
||||
{
|
||||
if (fp->uf_ret_type != &t_void)
|
||||
{
|
||||
@ -2377,7 +2377,7 @@ untrans_function_name(char_u *name)
|
||||
* Returns a pointer to the function or NULL if no function defined.
|
||||
*/
|
||||
ufunc_T *
|
||||
def_function(exarg_T *eap, char_u *name_arg, void *context, int compile)
|
||||
def_function(exarg_T *eap, char_u *name_arg)
|
||||
{
|
||||
char_u *theline;
|
||||
char_u *line_to_free = NULL;
|
||||
@ -2416,6 +2416,12 @@ def_function(exarg_T *eap, char_u *name_arg, void *context, int compile)
|
||||
char_u *skip_until = NULL;
|
||||
char_u *heredoc_trimmed = NULL;
|
||||
|
||||
if (in_vim9script() && eap->forceit)
|
||||
{
|
||||
emsg(_(e_nobang));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ":function" without argument: list functions.
|
||||
*/
|
||||
@ -2584,7 +2590,7 @@ def_function(exarg_T *eap, char_u *name_arg, void *context, int compile)
|
||||
if (!got_int)
|
||||
{
|
||||
msg_putchar('\n');
|
||||
if (fp->uf_dfunc_idx >= 0)
|
||||
if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
|
||||
msg_puts(" enddef");
|
||||
else
|
||||
msg_puts(" endfunction");
|
||||
@ -3122,7 +3128,8 @@ def_function(exarg_T *eap, char_u *name_arg, void *context, int compile)
|
||||
fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
|
||||
if (fp == NULL)
|
||||
goto erret;
|
||||
fp->uf_dfunc_idx = -1;
|
||||
fp->uf_dfunc_idx = eap->cmdidx == CMD_def ? UF_TO_BE_COMPILED
|
||||
: UF_NOT_COMPILED;
|
||||
|
||||
if (fudi.fd_dict != NULL)
|
||||
{
|
||||
@ -3175,6 +3182,8 @@ def_function(exarg_T *eap, char_u *name_arg, void *context, int compile)
|
||||
{
|
||||
int lnum_save = SOURCING_LNUM;
|
||||
|
||||
fp->uf_dfunc_idx = UF_TO_BE_COMPILED;
|
||||
|
||||
// error messages are for the first function line
|
||||
SOURCING_LNUM = sourcing_lnum_top;
|
||||
|
||||
@ -3242,6 +3251,8 @@ def_function(exarg_T *eap, char_u *name_arg, void *context, int compile)
|
||||
}
|
||||
SOURCING_LNUM = lnum_save;
|
||||
}
|
||||
else
|
||||
fp->uf_dfunc_idx = UF_NOT_COMPILED;
|
||||
|
||||
fp->uf_lines = newlines;
|
||||
if ((flags & FC_CLOSURE) != 0)
|
||||
@ -3273,10 +3284,6 @@ def_function(exarg_T *eap, char_u *name_arg, void *context, int compile)
|
||||
is_export = FALSE;
|
||||
}
|
||||
|
||||
// ":def Func()" may need to be compiled
|
||||
if (eap->cmdidx == CMD_def && compile)
|
||||
compile_def_function(fp, FALSE, context);
|
||||
|
||||
goto ret_free;
|
||||
|
||||
erret:
|
||||
@ -3304,7 +3311,30 @@ ret_free:
|
||||
void
|
||||
ex_function(exarg_T *eap)
|
||||
{
|
||||
(void)def_function(eap, NULL, NULL, TRUE);
|
||||
(void)def_function(eap, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* :defcompile - compile all :def functions in the current script.
|
||||
*/
|
||||
void
|
||||
ex_defcompile(exarg_T *eap UNUSED)
|
||||
{
|
||||
int todo = (int)func_hashtab.ht_used;
|
||||
hashitem_T *hi;
|
||||
ufunc_T *ufunc;
|
||||
|
||||
for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
|
||||
{
|
||||
if (!HASHITEM_EMPTY(hi))
|
||||
{
|
||||
--todo;
|
||||
ufunc = HI2UF(hi);
|
||||
if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
|
||||
&& ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED)
|
||||
compile_def_function(ufunc, FALSE, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -746,6 +746,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
818,
|
||||
/**/
|
||||
817,
|
||||
/**/
|
||||
|
@ -2133,7 +2133,6 @@ typedef enum {
|
||||
// Flags for assignment functions.
|
||||
#define LET_IS_CONST 1 // ":const"
|
||||
#define LET_NO_COMMAND 2 // "var = expr" without ":let" or ":const"
|
||||
#define LET_DISCOVERY 4 // discovery phase: variable can be redefined later
|
||||
|
||||
#include "ex_cmds.h" // Ex command defines
|
||||
#include "spell.h" // spell checking stuff
|
||||
|
@ -1418,7 +1418,7 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (ufunc->uf_dfunc_idx >= 0)
|
||||
if (ufunc->uf_dfunc_idx != UF_NOT_COMPILED)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -1442,12 +1442,16 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount)
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED)
|
||||
if (compile_def_function(ufunc, TRUE, cctx) == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if ((isn = generate_instr(cctx,
|
||||
ufunc->uf_dfunc_idx >= 0 ? ISN_DCALL : ISN_UCALL)) == NULL)
|
||||
ufunc->uf_dfunc_idx != UF_NOT_COMPILED ? ISN_DCALL
|
||||
: ISN_UCALL)) == NULL)
|
||||
return FAIL;
|
||||
if (ufunc->uf_dfunc_idx >= 0)
|
||||
if (ufunc->uf_dfunc_idx != UF_NOT_COMPILED)
|
||||
{
|
||||
isn->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
|
||||
isn->isn_arg.dfunc.cdf_argcount = argcount;
|
||||
@ -4454,9 +4458,12 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
|
||||
eap->cookie = cctx;
|
||||
eap->skip = cctx->ctx_skip == TRUE;
|
||||
eap->forceit = FALSE;
|
||||
ufunc = def_function(eap, name, cctx, TRUE);
|
||||
ufunc = def_function(eap, name);
|
||||
|
||||
if (ufunc == NULL || ufunc->uf_dfunc_idx < 0)
|
||||
if (ufunc == NULL)
|
||||
return NULL;
|
||||
if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
|
||||
&& compile_def_function(ufunc, TRUE, cctx) == FAIL)
|
||||
return NULL;
|
||||
|
||||
// Define a local variable for the function reference.
|
||||
@ -6302,7 +6309,7 @@ theend:
|
||||
* Add a function to the list of :def functions.
|
||||
* This "sets ufunc->uf_dfunc_idx" but the function isn't compiled yet.
|
||||
*/
|
||||
int
|
||||
static int
|
||||
add_def_function(ufunc_T *ufunc)
|
||||
{
|
||||
dfunc_T *dfunc;
|
||||
@ -6328,8 +6335,9 @@ add_def_function(ufunc_T *ufunc)
|
||||
* "outer_cctx" is set for a nested function.
|
||||
* This can be used recursively through compile_lambda(), which may reallocate
|
||||
* "def_functions".
|
||||
* Returns OK or FAIL.
|
||||
*/
|
||||
void
|
||||
int
|
||||
compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
{
|
||||
char_u *line = NULL;
|
||||
@ -6352,7 +6360,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
||||
delete_def_function_contents(dfunc);
|
||||
}
|
||||
else if (add_def_function(ufunc) == FAIL)
|
||||
return;
|
||||
return FAIL;
|
||||
|
||||
CLEAR_FIELD(cctx);
|
||||
cctx.ctx_ufunc = ufunc;
|
||||
@ -6816,7 +6824,7 @@ erret:
|
||||
delete_instr(((isn_T *)instr->ga_data) + idx);
|
||||
ga_clear(instr);
|
||||
|
||||
ufunc->uf_dfunc_idx = -1;
|
||||
ufunc->uf_dfunc_idx = UF_NOT_COMPILED;
|
||||
if (!dfunc->df_deleted)
|
||||
--def_functions.ga_len;
|
||||
|
||||
@ -6836,6 +6844,7 @@ erret:
|
||||
free_imported(&cctx);
|
||||
free_locals(&cctx);
|
||||
ga_clear(&cctx.ctx_type_stack);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -487,6 +487,9 @@ call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx, isn_T *iptr)
|
||||
int error;
|
||||
int idx;
|
||||
|
||||
if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
|
||||
&& compile_def_function(ufunc, FALSE, NULL) == FAIL)
|
||||
return FAIL;
|
||||
if (ufunc->uf_dfunc_idx >= 0)
|
||||
{
|
||||
// The function has been compiled, can call it quickly. For a function
|
||||
@ -667,8 +670,13 @@ call_def_function(
|
||||
// Like STACK_TV_VAR but use the outer scope
|
||||
#define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx)
|
||||
|
||||
if (ufunc->uf_dfunc_idx == UF_NOT_COMPILED
|
||||
|| (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
|
||||
&& compile_def_function(ufunc, FALSE, NULL) == FAIL))
|
||||
return FAIL;
|
||||
|
||||
{
|
||||
// Check the function was compiled, it is postponed in ex_vim9script().
|
||||
// Check the function was really compiled.
|
||||
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||
+ ufunc->uf_dfunc_idx;
|
||||
if (dfunc->df_instr == NULL)
|
||||
@ -2303,6 +2311,9 @@ ex_disassemble(exarg_T *eap)
|
||||
semsg(_("E1061: Cannot find function %s"), eap->arg);
|
||||
return;
|
||||
}
|
||||
if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
|
||||
&& compile_def_function(ufunc, FALSE, NULL) == FAIL)
|
||||
return;
|
||||
if (ufunc->uf_dfunc_idx < 0)
|
||||
{
|
||||
semsg(_("E1062: Function %s is not compiled"), eap->arg);
|
||||
|
109
src/vim9script.c
109
src/vim9script.c
@ -33,11 +33,6 @@ in_vim9script(void)
|
||||
ex_vim9script(exarg_T *eap)
|
||||
{
|
||||
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||
garray_T *gap;
|
||||
garray_T func_ga;
|
||||
int idx;
|
||||
ufunc_T *ufunc;
|
||||
int start_called_emsg = called_emsg;
|
||||
|
||||
if (!getline_equal(eap->getline, eap->cookie, getsourceline))
|
||||
{
|
||||
@ -52,116 +47,12 @@ ex_vim9script(exarg_T *eap)
|
||||
current_sctx.sc_version = SCRIPT_VERSION_VIM9;
|
||||
si->sn_version = SCRIPT_VERSION_VIM9;
|
||||
si->sn_had_command = TRUE;
|
||||
ga_init2(&func_ga, sizeof(ufunc_T *), 20);
|
||||
|
||||
if (STRCMP(p_cpo, CPO_VIM) != 0)
|
||||
{
|
||||
si->sn_save_cpo = p_cpo;
|
||||
p_cpo = vim_strsave((char_u *)CPO_VIM);
|
||||
}
|
||||
|
||||
// Make a pass through the script to find:
|
||||
// - function declarations
|
||||
// - variable and constant declarations
|
||||
// - imports
|
||||
// The types are recognized, so that they can be used when compiling a
|
||||
// function.
|
||||
gap = source_get_line_ga(eap->cookie);
|
||||
while (called_emsg == start_called_emsg)
|
||||
{
|
||||
char_u *line;
|
||||
char_u *p;
|
||||
|
||||
if (ga_grow(gap, 1) == FAIL)
|
||||
return;
|
||||
line = eap->getline(':', eap->cookie, 0, TRUE);
|
||||
if (line == NULL)
|
||||
break;
|
||||
((char_u **)(gap->ga_data))[gap->ga_len++] = line;
|
||||
line = skipwhite(line);
|
||||
p = line;
|
||||
if (checkforcmd(&p, "function", 2) || checkforcmd(&p, "def", 3))
|
||||
{
|
||||
int lnum_start = SOURCING_LNUM - 1;
|
||||
|
||||
if (*p == '!')
|
||||
{
|
||||
emsg(_(e_nobang));
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle :function and :def by calling def_function().
|
||||
// It will read upto the matching :endded or :endfunction.
|
||||
eap->cmdidx = *line == 'f' ? CMD_function : CMD_def;
|
||||
eap->cmd = line;
|
||||
eap->arg = p;
|
||||
eap->forceit = FALSE;
|
||||
ufunc = def_function(eap, NULL, NULL, FALSE);
|
||||
|
||||
if (ufunc != NULL && *line == 'd' && ga_grow(&func_ga, 1) == OK)
|
||||
{
|
||||
// Add the function to the list of :def functions, so that it
|
||||
// can be referenced by index. It's compiled below.
|
||||
add_def_function(ufunc);
|
||||
((ufunc_T **)(func_ga.ga_data))[func_ga.ga_len++] = ufunc;
|
||||
}
|
||||
|
||||
// Store empty lines in place of the function, we don't need to
|
||||
// process it again.
|
||||
vim_free(((char_u **)(gap->ga_data))[--gap->ga_len]);
|
||||
if (ga_grow(gap, SOURCING_LNUM - lnum_start) == OK)
|
||||
while (lnum_start < SOURCING_LNUM)
|
||||
{
|
||||
// getsourceline() will skip over NULL lines.
|
||||
((char_u **)(gap->ga_data))[gap->ga_len++] = NULL;
|
||||
++lnum_start;
|
||||
}
|
||||
}
|
||||
else if (checkforcmd(&p, "let", 3) || checkforcmd(&p, "const", 4))
|
||||
{
|
||||
eap->cmd = line;
|
||||
eap->arg = p;
|
||||
eap->forceit = FALSE;
|
||||
eap->cmdidx = *line == 'l' ? CMD_let: CMD_const;
|
||||
|
||||
// The command will be executed again, it's OK to redefine the
|
||||
// variable then.
|
||||
ex_let_const(eap, TRUE);
|
||||
}
|
||||
else if (checkforcmd(&p, "import", 3))
|
||||
{
|
||||
eap->arg = p;
|
||||
ex_import(eap);
|
||||
|
||||
// Store empty line, we don't need to process the command again.
|
||||
vim_free(((char_u **)(gap->ga_data))[--gap->ga_len]);
|
||||
((char_u **)(gap->ga_data))[gap->ga_len++] = NULL;
|
||||
}
|
||||
else if (checkforcmd(&p, "finish", 4))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Compile the :def functions.
|
||||
for (idx = 0; idx < func_ga.ga_len && called_emsg == start_called_emsg; ++idx)
|
||||
{
|
||||
ufunc = ((ufunc_T **)(func_ga.ga_data))[idx];
|
||||
compile_def_function(ufunc, FALSE, NULL);
|
||||
}
|
||||
ga_clear(&func_ga);
|
||||
|
||||
if (called_emsg == start_called_emsg)
|
||||
{
|
||||
// Return to process the commands at the script level.
|
||||
source_use_line_ga(eap->cookie);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there was an error in the first or second phase then don't
|
||||
// execute the script lines.
|
||||
do_finish(eap, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user