mirror of
https://github.com/vim/vim.git
synced 2025-09-24 03:44:06 -04:00
patch 8.2.0725: Vim9: cannot call a function declared later in Vim9 script
Problem: Vim9: cannot call a function declared later in Vim9 script. Solution: Make two passes through the script file.
This commit is contained in:
@@ -164,7 +164,6 @@ static dict_T vimvardict; // Dictionary with v: variables
|
|||||||
// for VIM_VERSION_ defines
|
// for VIM_VERSION_ defines
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
static void ex_let_const(exarg_T *eap, int is_const);
|
|
||||||
static char_u *skip_var_one(char_u *arg, int include_type);
|
static char_u *skip_var_one(char_u *arg, int include_type);
|
||||||
static void list_glob_vars(int *first);
|
static void list_glob_vars(int *first);
|
||||||
static void list_buf_vars(int *first);
|
static void list_buf_vars(int *first);
|
||||||
@@ -698,11 +697,15 @@ ex_let(exarg_T *eap)
|
|||||||
void
|
void
|
||||||
ex_const(exarg_T *eap)
|
ex_const(exarg_T *eap)
|
||||||
{
|
{
|
||||||
ex_let_const(eap, TRUE);
|
ex_let_const(eap, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/*
|
||||||
ex_let_const(exarg_T *eap, int is_const)
|
* When "redefine" is TRUE the command will be executed again, redefining the
|
||||||
|
* variable is OK then.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ex_let_const(exarg_T *eap, int redefine)
|
||||||
{
|
{
|
||||||
char_u *arg = eap->arg;
|
char_u *arg = eap->arg;
|
||||||
char_u *expr = NULL;
|
char_u *expr = NULL;
|
||||||
@@ -714,11 +717,13 @@ ex_let_const(exarg_T *eap, int is_const)
|
|||||||
char_u *argend;
|
char_u *argend;
|
||||||
int first = TRUE;
|
int first = TRUE;
|
||||||
int concat;
|
int concat;
|
||||||
int flags = is_const ? LET_IS_CONST : 0;
|
int flags = eap->cmdidx == CMD_const ? LET_IS_CONST : 0;
|
||||||
|
|
||||||
// detect Vim9 assignment without ":let" or ":const"
|
// detect Vim9 assignment without ":let" or ":const"
|
||||||
if (eap->arg == eap->cmd)
|
if (eap->arg == eap->cmd)
|
||||||
flags |= LET_NO_COMMAND;
|
flags |= LET_NO_COMMAND;
|
||||||
|
if (redefine)
|
||||||
|
flags |= LET_REDEFINE;
|
||||||
|
|
||||||
argend = skip_var_list(arg, TRUE, &var_count, &semicolon);
|
argend = skip_var_list(arg, TRUE, &var_count, &semicolon);
|
||||||
if (argend == NULL)
|
if (argend == NULL)
|
||||||
@@ -2976,6 +2981,8 @@ set_var_const(
|
|||||||
|
|
||||||
if (flags & LET_IS_CONST)
|
if (flags & LET_IS_CONST)
|
||||||
di->di_tv.v_lock |= VAR_LOCKED;
|
di->di_tv.v_lock |= VAR_LOCKED;
|
||||||
|
if (flags & LET_REDEFINE)
|
||||||
|
di->di_flags |= DI_FLAGS_RELOAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -16,6 +16,7 @@ void restore_vimvar(int idx, typval_T *save_tv);
|
|||||||
list_T *heredoc_get(exarg_T *eap, char_u *cmd, int script_get);
|
list_T *heredoc_get(exarg_T *eap, char_u *cmd, int script_get);
|
||||||
void ex_let(exarg_T *eap);
|
void ex_let(exarg_T *eap);
|
||||||
void ex_const(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);
|
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);
|
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);
|
void list_hashtable_vars(hashtab_T *ht, char *prefix, int empty, int *first);
|
||||||
|
@@ -19,6 +19,8 @@ int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file);
|
|||||||
void ex_source(exarg_T *eap);
|
void ex_source(exarg_T *eap);
|
||||||
void ex_options(exarg_T *eap);
|
void ex_options(exarg_T *eap);
|
||||||
linenr_T *source_breakpoint(void *cookie);
|
linenr_T *source_breakpoint(void *cookie);
|
||||||
|
garray_T *source_get_line_ga(void *cookie);
|
||||||
|
void source_use_line_ga(void *cookie);
|
||||||
int *source_dbg_tick(void *cookie);
|
int *source_dbg_tick(void *cookie);
|
||||||
int source_level(void *cookie);
|
int source_level(void *cookie);
|
||||||
int do_source(char_u *fname, int check_other, int is_vimrc, int *ret_sid);
|
int do_source(char_u *fname, int check_other, int is_vimrc, int *ret_sid);
|
||||||
|
@@ -23,7 +23,7 @@ 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);
|
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 *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);
|
char_u *untrans_function_name(char_u *name);
|
||||||
ufunc_T *def_function(exarg_T *eap, char_u *name_arg, void *context);
|
ufunc_T *def_function(exarg_T *eap, char_u *name_arg, void *context, int compile);
|
||||||
void ex_function(exarg_T *eap);
|
void ex_function(exarg_T *eap);
|
||||||
int eval_fname_script(char_u *p);
|
int eval_fname_script(char_u *p);
|
||||||
int translated_function_exists(char_u *name, int is_global);
|
int translated_function_exists(char_u *name, int is_global);
|
||||||
|
@@ -9,6 +9,7 @@ imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
|
|||||||
char_u *to_name_const_end(char_u *arg);
|
char_u *to_name_const_end(char_u *arg);
|
||||||
int assignment_len(char_u *p, int *heredoc);
|
int assignment_len(char_u *p, int *heredoc);
|
||||||
int check_vim9_unlet(char_u *name);
|
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);
|
void compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx);
|
||||||
void delete_instr(isn_T *isn);
|
void delete_instr(isn_T *isn);
|
||||||
void delete_def_function(ufunc_T *ufunc);
|
void delete_def_function(ufunc_T *ufunc);
|
||||||
|
@@ -998,6 +998,8 @@ struct source_cookie
|
|||||||
int error; // TRUE if LF found after CR-LF
|
int error; // TRUE if LF found after CR-LF
|
||||||
#endif
|
#endif
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
|
garray_T lines_ga; // lines read in previous pass
|
||||||
|
int use_lines_ga; // next line to get from "lines_ga"
|
||||||
linenr_T breakpoint; // next line with breakpoint or zero
|
linenr_T breakpoint; // next line with breakpoint or zero
|
||||||
char_u *fname; // name of sourced file
|
char_u *fname; // name of sourced file
|
||||||
int dbg_tick; // debug_tick when breakpoint was set
|
int dbg_tick; // debug_tick when breakpoint was set
|
||||||
@@ -1016,6 +1018,24 @@ source_breakpoint(void *cookie)
|
|||||||
return &((struct source_cookie *)cookie)->breakpoint;
|
return &((struct source_cookie *)cookie)->breakpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the grow array to store script lines in.
|
||||||
|
*/
|
||||||
|
garray_T *
|
||||||
|
source_get_line_ga(void *cookie)
|
||||||
|
{
|
||||||
|
return &((struct source_cookie *)cookie)->lines_ga;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the index to start reading from the grow array with script lines.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
source_use_line_ga(void *cookie)
|
||||||
|
{
|
||||||
|
((struct source_cookie *)cookie)->use_lines_ga = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the address holding the debug tick for a source cookie.
|
* Return the address holding the debug tick for a source cookie.
|
||||||
*/
|
*/
|
||||||
@@ -1235,6 +1255,9 @@ do_source(
|
|||||||
cookie.finished = FALSE;
|
cookie.finished = FALSE;
|
||||||
|
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
|
ga_init2(&cookie.lines_ga, sizeof(char_u *), 200);
|
||||||
|
cookie.use_lines_ga = -1;
|
||||||
|
|
||||||
// Check if this script has a breakpoint.
|
// Check if this script has a breakpoint.
|
||||||
cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
|
cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0);
|
||||||
cookie.fname = fname_exp;
|
cookie.fname = fname_exp;
|
||||||
@@ -1447,6 +1470,9 @@ almosttheend:
|
|||||||
vim_free(cookie.nextline);
|
vim_free(cookie.nextline);
|
||||||
vim_free(firstline);
|
vim_free(firstline);
|
||||||
convert_setup(&cookie.conv, NULL, NULL);
|
convert_setup(&cookie.conv, NULL, NULL);
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
ga_clear_strings(&cookie.lines_ga);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (trigger_source_post)
|
if (trigger_source_post)
|
||||||
apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
|
apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
|
||||||
@@ -1702,6 +1728,31 @@ getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat)
|
|||||||
// one now.
|
// one now.
|
||||||
if (sp->finished)
|
if (sp->finished)
|
||||||
line = NULL;
|
line = NULL;
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
else if (sp->use_lines_ga >= 0)
|
||||||
|
{
|
||||||
|
// Get a line that was read in ex_vim9script().
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (sp->use_lines_ga >= sp->lines_ga.ga_len)
|
||||||
|
{
|
||||||
|
line = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line = ((char_u **)(sp->lines_ga.ga_data))[sp->use_lines_ga];
|
||||||
|
((char_u **)(sp->lines_ga.ga_data))[sp->use_lines_ga] = NULL;
|
||||||
|
++sp->use_lines_ga;
|
||||||
|
if (line != NULL)
|
||||||
|
break;
|
||||||
|
// Skip NULL lines, they are equivalent to blank lines.
|
||||||
|
++sp->sourcing_lnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SOURCING_LNUM = sp->sourcing_lnum + 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
else if (sp->nextline == NULL)
|
else if (sp->nextline == NULL)
|
||||||
line = get_one_sourceline(sp);
|
line = get_one_sourceline(sp);
|
||||||
else
|
else
|
||||||
|
@@ -1045,6 +1045,31 @@ def Test_display_func()
|
|||||||
res3)
|
res3)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_vim9script_forward_func()
|
||||||
|
let lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
def FuncOne(): string
|
||||||
|
return FuncTwo()
|
||||||
|
enddef
|
||||||
|
def FuncTwo(): string
|
||||||
|
return 'two'
|
||||||
|
enddef
|
||||||
|
let g:res_FuncOne = execute('disass FuncOne')
|
||||||
|
END
|
||||||
|
writefile(lines, 'Xdisassemble')
|
||||||
|
source Xdisassemble
|
||||||
|
|
||||||
|
" check that the first function calls the second with DCALL
|
||||||
|
assert_match('\<SNR>\d*_FuncOne.*' ..
|
||||||
|
'return FuncTwo().*' ..
|
||||||
|
'\d DCALL <SNR>\d\+_FuncTwo(argc 0).*' ..
|
||||||
|
'\d RETURN',
|
||||||
|
g:res_FuncOne)
|
||||||
|
|
||||||
|
delete('Xdisassemble')
|
||||||
|
unlet g:res_FuncOne
|
||||||
|
enddef
|
||||||
|
|
||||||
def s:ConcatStrings(): string
|
def s:ConcatStrings(): string
|
||||||
return 'one' .. 'two' .. 'three'
|
return 'one' .. 'two' .. 'three'
|
||||||
enddef
|
enddef
|
||||||
|
@@ -2378,7 +2378,7 @@ untrans_function_name(char_u *name)
|
|||||||
* Returns a pointer to the function or NULL if no function defined.
|
* Returns a pointer to the function or NULL if no function defined.
|
||||||
*/
|
*/
|
||||||
ufunc_T *
|
ufunc_T *
|
||||||
def_function(exarg_T *eap, char_u *name_arg, void *context)
|
def_function(exarg_T *eap, char_u *name_arg, void *context, int compile)
|
||||||
{
|
{
|
||||||
char_u *theline;
|
char_u *theline;
|
||||||
char_u *line_to_free = NULL;
|
char_u *line_to_free = NULL;
|
||||||
@@ -3241,6 +3241,7 @@ def_function(exarg_T *eap, char_u *name_arg, void *context)
|
|||||||
p = ret_type;
|
p = ret_type;
|
||||||
fp->uf_ret_type = parse_type(&p, &fp->uf_type_list);
|
fp->uf_ret_type = parse_type(&p, &fp->uf_type_list);
|
||||||
}
|
}
|
||||||
|
SOURCING_LNUM = lnum_save;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp->uf_lines = newlines;
|
fp->uf_lines = newlines;
|
||||||
@@ -3273,8 +3274,8 @@ def_function(exarg_T *eap, char_u *name_arg, void *context)
|
|||||||
is_export = FALSE;
|
is_export = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ":def Func()" needs to be compiled
|
// ":def Func()" may need to be compiled
|
||||||
if (eap->cmdidx == CMD_def)
|
if (eap->cmdidx == CMD_def && compile)
|
||||||
compile_def_function(fp, FALSE, context);
|
compile_def_function(fp, FALSE, context);
|
||||||
|
|
||||||
goto ret_free;
|
goto ret_free;
|
||||||
@@ -3304,7 +3305,7 @@ ret_free:
|
|||||||
void
|
void
|
||||||
ex_function(exarg_T *eap)
|
ex_function(exarg_T *eap)
|
||||||
{
|
{
|
||||||
def_function(eap, NULL, NULL);
|
(void)def_function(eap, NULL, NULL, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -746,6 +746,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
725,
|
||||||
/**/
|
/**/
|
||||||
724,
|
724,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -2133,6 +2133,7 @@ typedef enum {
|
|||||||
// Flags for assignment functions.
|
// Flags for assignment functions.
|
||||||
#define LET_IS_CONST 1 // ":const"
|
#define LET_IS_CONST 1 // ":const"
|
||||||
#define LET_NO_COMMAND 2 // "var = expr" without ":let" or ":const"
|
#define LET_NO_COMMAND 2 // "var = expr" without ":let" or ":const"
|
||||||
|
#define LET_REDEFINE 4 // variable can be redefined later
|
||||||
|
|
||||||
#include "ex_cmds.h" // Ex command defines
|
#include "ex_cmds.h" // Ex command defines
|
||||||
#include "spell.h" // spell checking stuff
|
#include "spell.h" // spell checking stuff
|
||||||
|
@@ -4441,7 +4441,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
|
|||||||
eap->cookie = cctx;
|
eap->cookie = cctx;
|
||||||
eap->skip = cctx->ctx_skip == TRUE;
|
eap->skip = cctx->ctx_skip == TRUE;
|
||||||
eap->forceit = FALSE;
|
eap->forceit = FALSE;
|
||||||
ufunc = def_function(eap, name, cctx);
|
ufunc = def_function(eap, name, cctx, TRUE);
|
||||||
|
|
||||||
if (ufunc == NULL || ufunc->uf_dfunc_idx < 0)
|
if (ufunc == NULL || ufunc->uf_dfunc_idx < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -6130,6 +6130,27 @@ theend:
|
|||||||
return (char_u *)"";
|
return (char_u *)"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a function to the list of :def functions.
|
||||||
|
* This "sets ufunc->uf_dfunc_idx" but the function isn't compiled yet.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
add_def_function(ufunc_T *ufunc)
|
||||||
|
{
|
||||||
|
dfunc_T *dfunc;
|
||||||
|
|
||||||
|
// Add the function to "def_functions".
|
||||||
|
if (ga_grow(&def_functions, 1) == FAIL)
|
||||||
|
return FAIL;
|
||||||
|
dfunc = ((dfunc_T *)def_functions.ga_data) + def_functions.ga_len;
|
||||||
|
CLEAR_POINTER(dfunc);
|
||||||
|
dfunc->df_idx = def_functions.ga_len;
|
||||||
|
ufunc->uf_dfunc_idx = dfunc->df_idx;
|
||||||
|
dfunc->df_ufunc = ufunc;
|
||||||
|
++def_functions.ga_len;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* After ex_function() has collected all the function lines: parse and compile
|
* After ex_function() has collected all the function lines: parse and compile
|
||||||
* the lines into instructions.
|
* the lines into instructions.
|
||||||
@@ -6154,30 +6175,16 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
|||||||
sctx_T save_current_sctx = current_sctx;
|
sctx_T save_current_sctx = current_sctx;
|
||||||
int emsg_before = called_emsg;
|
int emsg_before = called_emsg;
|
||||||
|
|
||||||
|
if (ufunc->uf_dfunc_idx >= 0)
|
||||||
{
|
{
|
||||||
dfunc_T *dfunc; // may be invalidated by compile_lambda()
|
// Redefining a function that was compiled before.
|
||||||
|
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||||
if (ufunc->uf_dfunc_idx >= 0)
|
+ ufunc->uf_dfunc_idx;
|
||||||
{
|
// Free old instructions.
|
||||||
// Redefining a function that was compiled before.
|
delete_def_function_contents(dfunc);
|
||||||
dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx;
|
|
||||||
|
|
||||||
// Free old instructions.
|
|
||||||
delete_def_function_contents(dfunc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Add the function to "def_functions".
|
|
||||||
if (ga_grow(&def_functions, 1) == FAIL)
|
|
||||||
return;
|
|
||||||
dfunc = ((dfunc_T *)def_functions.ga_data) + def_functions.ga_len;
|
|
||||||
CLEAR_POINTER(dfunc);
|
|
||||||
dfunc->df_idx = def_functions.ga_len;
|
|
||||||
ufunc->uf_dfunc_idx = dfunc->df_idx;
|
|
||||||
dfunc->df_ufunc = ufunc;
|
|
||||||
++def_functions.ga_len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (add_def_function(ufunc) == FAIL)
|
||||||
|
return;
|
||||||
|
|
||||||
CLEAR_FIELD(cctx);
|
CLEAR_FIELD(cctx);
|
||||||
cctx.ctx_ufunc = ufunc;
|
cctx.ctx_ufunc = ufunc;
|
||||||
|
@@ -669,6 +669,13 @@ call_def_function(
|
|||||||
ga_init2(&ectx.ec_stack, sizeof(typval_T), 500);
|
ga_init2(&ectx.ec_stack, sizeof(typval_T), 500);
|
||||||
if (ga_grow(&ectx.ec_stack, 20) == FAIL)
|
if (ga_grow(&ectx.ec_stack, 20) == FAIL)
|
||||||
return FAIL;
|
return FAIL;
|
||||||
|
{
|
||||||
|
// Check the function was compiled, it is postponed in ex_vim9script().
|
||||||
|
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
|
||||||
|
+ ufunc->uf_dfunc_idx;
|
||||||
|
if (dfunc->df_instr == NULL)
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx;
|
ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx;
|
||||||
|
|
||||||
ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10);
|
ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10);
|
||||||
|
@@ -32,7 +32,11 @@ in_vim9script(void)
|
|||||||
void
|
void
|
||||||
ex_vim9script(exarg_T *eap)
|
ex_vim9script(exarg_T *eap)
|
||||||
{
|
{
|
||||||
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||||
|
garray_T *gap;
|
||||||
|
garray_T func_ga;
|
||||||
|
int idx;
|
||||||
|
ufunc_T *ufunc;
|
||||||
|
|
||||||
if (!getline_equal(eap->getline, eap->cookie, getsourceline))
|
if (!getline_equal(eap->getline, eap->cookie, getsourceline))
|
||||||
{
|
{
|
||||||
@@ -47,12 +51,97 @@ ex_vim9script(exarg_T *eap)
|
|||||||
current_sctx.sc_version = SCRIPT_VERSION_VIM9;
|
current_sctx.sc_version = SCRIPT_VERSION_VIM9;
|
||||||
si->sn_version = SCRIPT_VERSION_VIM9;
|
si->sn_version = SCRIPT_VERSION_VIM9;
|
||||||
si->sn_had_command = TRUE;
|
si->sn_had_command = TRUE;
|
||||||
|
ga_init2(&func_ga, sizeof(ufunc_T *), 20);
|
||||||
|
|
||||||
if (STRCMP(p_cpo, CPO_VIM) != 0)
|
if (STRCMP(p_cpo, CPO_VIM) != 0)
|
||||||
{
|
{
|
||||||
si->sn_save_cpo = p_cpo;
|
si->sn_save_cpo = p_cpo;
|
||||||
p_cpo = vim_strsave((char_u *)CPO_VIM);
|
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);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile the :def functions.
|
||||||
|
for (idx = 0; idx < func_ga.ga_len; ++idx)
|
||||||
|
{
|
||||||
|
ufunc = ((ufunc_T **)(func_ga.ga_data))[idx];
|
||||||
|
compile_def_function(ufunc, FALSE, NULL);
|
||||||
|
}
|
||||||
|
ga_clear(&func_ga);
|
||||||
|
|
||||||
|
// Return to process the commands at the script level.
|
||||||
|
source_use_line_ga(eap->cookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -64,7 +153,7 @@ ex_vim9script(exarg_T *eap)
|
|||||||
* ":export {Name, ...}"
|
* ":export {Name, ...}"
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ex_export(exarg_T *eap UNUSED)
|
ex_export(exarg_T *eap)
|
||||||
{
|
{
|
||||||
if (current_sctx.sc_version != SCRIPT_VERSION_VIM9)
|
if (current_sctx.sc_version != SCRIPT_VERSION_VIM9)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user