diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-05-09 22:50:08 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-05-09 22:50:08 +0200 |
commit | 09689a02840be40fa7bb10b1921fb5bc5b2908f1 (patch) | |
tree | 4aced60f6702ce56232c9ee70bf977234e054c39 /src/vim9script.c | |
parent | 396f3138ca83ce844679143861f544070683d479 (diff) | |
download | vim-git-09689a02840be40fa7bb10b1921fb5bc5b2908f1.tar.gz |
patch 8.2.0725: Vim9: cannot call a function declared later in Vim9 scriptv8.2.0725
Problem: Vim9: cannot call a function declared later in Vim9 script.
Solution: Make two passes through the script file.
Diffstat (limited to 'src/vim9script.c')
-rw-r--r-- | src/vim9script.c | 93 |
1 files changed, 91 insertions, 2 deletions
diff --git a/src/vim9script.c b/src/vim9script.c index afd6a4af9..8bc1962bf 100644 --- a/src/vim9script.c +++ b/src/vim9script.c @@ -32,7 +32,11 @@ in_vim9script(void) void 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)) { @@ -47,12 +51,97 @@ 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); + 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, ...}" */ void -ex_export(exarg_T *eap UNUSED) +ex_export(exarg_T *eap) { if (current_sctx.sc_version != SCRIPT_VERSION_VIM9) { |