Mercurial > vim
comparison src/vim9script.c @ 20339:7587d892c00c v8.2.0725
patch 8.2.0725: Vim9: cannot call a function declared later in Vim9 script
Commit: https://github.com/vim/vim/commit/09689a02840be40fa7bb10b1921fb5bc5b2908f1
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat May 9 22:50:08 2020 +0200
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.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 09 May 2020 23:00:04 +0200 |
parents | 63cc54100ae4 |
children | 680296770464 |
comparison
equal
deleted
inserted
replaced
20338:ff4ae3f09307 | 20339:7587d892c00c |
---|---|
30 * ":vim9script". | 30 * ":vim9script". |
31 */ | 31 */ |
32 void | 32 void |
33 ex_vim9script(exarg_T *eap) | 33 ex_vim9script(exarg_T *eap) |
34 { | 34 { |
35 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); | 35 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); |
36 garray_T *gap; | |
37 garray_T func_ga; | |
38 int idx; | |
39 ufunc_T *ufunc; | |
36 | 40 |
37 if (!getline_equal(eap->getline, eap->cookie, getsourceline)) | 41 if (!getline_equal(eap->getline, eap->cookie, getsourceline)) |
38 { | 42 { |
39 emsg(_("E1038: vim9script can only be used in a script")); | 43 emsg(_("E1038: vim9script can only be used in a script")); |
40 return; | 44 return; |
45 return; | 49 return; |
46 } | 50 } |
47 current_sctx.sc_version = SCRIPT_VERSION_VIM9; | 51 current_sctx.sc_version = SCRIPT_VERSION_VIM9; |
48 si->sn_version = SCRIPT_VERSION_VIM9; | 52 si->sn_version = SCRIPT_VERSION_VIM9; |
49 si->sn_had_command = TRUE; | 53 si->sn_had_command = TRUE; |
54 ga_init2(&func_ga, sizeof(ufunc_T *), 20); | |
50 | 55 |
51 if (STRCMP(p_cpo, CPO_VIM) != 0) | 56 if (STRCMP(p_cpo, CPO_VIM) != 0) |
52 { | 57 { |
53 si->sn_save_cpo = p_cpo; | 58 si->sn_save_cpo = p_cpo; |
54 p_cpo = vim_strsave((char_u *)CPO_VIM); | 59 p_cpo = vim_strsave((char_u *)CPO_VIM); |
55 } | 60 } |
61 | |
62 // Make a pass through the script to find: | |
63 // - function declarations | |
64 // - variable and constant declarations | |
65 // - imports | |
66 // The types are recognized, so that they can be used when compiling a | |
67 // function. | |
68 gap = source_get_line_ga(eap->cookie); | |
69 for (;;) | |
70 { | |
71 char_u *line; | |
72 char_u *p; | |
73 | |
74 if (ga_grow(gap, 1) == FAIL) | |
75 return; | |
76 line = eap->getline(':', eap->cookie, 0, TRUE); | |
77 if (line == NULL) | |
78 break; | |
79 ((char_u **)(gap->ga_data))[gap->ga_len++] = line; | |
80 line = skipwhite(line); | |
81 p = line; | |
82 if (checkforcmd(&p, "function", 2) || checkforcmd(&p, "def", 3)) | |
83 { | |
84 int lnum_start = SOURCING_LNUM - 1; | |
85 | |
86 // Handle :function and :def by calling def_function(). | |
87 // It will read upto the matching :endded or :endfunction. | |
88 eap->cmdidx = *line == 'f' ? CMD_function : CMD_def; | |
89 eap->cmd = line; | |
90 eap->arg = p; | |
91 eap->forceit = FALSE; | |
92 ufunc = def_function(eap, NULL, NULL, FALSE); | |
93 | |
94 if (ufunc != NULL && *line == 'd' && ga_grow(&func_ga, 1) == OK) | |
95 { | |
96 // Add the function to the list of :def functions, so that it | |
97 // can be referenced by index. It's compiled below. | |
98 add_def_function(ufunc); | |
99 ((ufunc_T **)(func_ga.ga_data))[func_ga.ga_len++] = ufunc; | |
100 } | |
101 | |
102 // Store empty lines in place of the function, we don't need to | |
103 // process it again. | |
104 vim_free(((char_u **)(gap->ga_data))[--gap->ga_len]); | |
105 if (ga_grow(gap, SOURCING_LNUM - lnum_start) == OK) | |
106 while (lnum_start < SOURCING_LNUM) | |
107 { | |
108 // getsourceline() will skip over NULL lines. | |
109 ((char_u **)(gap->ga_data))[gap->ga_len++] = NULL; | |
110 ++lnum_start; | |
111 } | |
112 } | |
113 else if (checkforcmd(&p, "let", 3) || checkforcmd(&p, "const", 4)) | |
114 { | |
115 eap->cmd = line; | |
116 eap->arg = p; | |
117 eap->forceit = FALSE; | |
118 eap->cmdidx = *line == 'l' ? CMD_let: CMD_const; | |
119 | |
120 // The command will be executed again, it's OK to redefine the | |
121 // variable then. | |
122 ex_let_const(eap, TRUE); | |
123 } | |
124 else if (checkforcmd(&p, "import", 3)) | |
125 { | |
126 eap->arg = p; | |
127 ex_import(eap); | |
128 | |
129 // Store empty line, we don't need to process the command again. | |
130 vim_free(((char_u **)(gap->ga_data))[--gap->ga_len]); | |
131 ((char_u **)(gap->ga_data))[gap->ga_len++] = NULL; | |
132 } | |
133 } | |
134 | |
135 // Compile the :def functions. | |
136 for (idx = 0; idx < func_ga.ga_len; ++idx) | |
137 { | |
138 ufunc = ((ufunc_T **)(func_ga.ga_data))[idx]; | |
139 compile_def_function(ufunc, FALSE, NULL); | |
140 } | |
141 ga_clear(&func_ga); | |
142 | |
143 // Return to process the commands at the script level. | |
144 source_use_line_ga(eap->cookie); | |
56 } | 145 } |
57 | 146 |
58 /* | 147 /* |
59 * ":export let Name: type" | 148 * ":export let Name: type" |
60 * ":export const Name: type" | 149 * ":export const Name: type" |
62 * ":export class Name ..." | 151 * ":export class Name ..." |
63 * | 152 * |
64 * ":export {Name, ...}" | 153 * ":export {Name, ...}" |
65 */ | 154 */ |
66 void | 155 void |
67 ex_export(exarg_T *eap UNUSED) | 156 ex_export(exarg_T *eap) |
68 { | 157 { |
69 if (current_sctx.sc_version != SCRIPT_VERSION_VIM9) | 158 if (current_sctx.sc_version != SCRIPT_VERSION_VIM9) |
70 { | 159 { |
71 emsg(_(e_needs_vim9)); | 160 emsg(_(e_needs_vim9)); |
72 return; | 161 return; |