blob: ddbae781c612bc3177c8270fea3f4d1d0246b50f [file] [log] [blame]
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * vim9script.c: :vim9script, :import, :export and friends
12 */
13
14#include "vim.h"
15
Bram Moolenaar9b8d6222020-12-28 18:26:00 +010016#if defined(FEAT_EVAL)
17# include "vim9.h"
18#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010019
Bram Moolenaare535db82021-03-31 21:07:24 +020020/*
21 * Return TRUE when currently using Vim9 script syntax.
22 * Does not go up the stack, a ":function" inside vim9script uses legacy
23 * syntax.
24 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010025 int
26in_vim9script(void)
27{
Bram Moolenaare535db82021-03-31 21:07:24 +020028 // "sc_version" is also set when compiling a ":def" function in legacy
29 // script.
Bram Moolenaar96cf4ba2021-04-24 14:15:41 +020030 return (current_sctx.sc_version == SCRIPT_VERSION_VIM9
31 || (cmdmod.cmod_flags & CMOD_VIM9CMD))
32 && !(cmdmod.cmod_flags & CMOD_LEGACY);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010033}
34
Bram Moolenaarb91d3f82021-04-01 13:17:50 +020035#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010036/*
Bram Moolenaare535db82021-03-31 21:07:24 +020037 * Return TRUE if the current script is Vim9 script.
38 * This also returns TRUE in a legacy function in a Vim9 script.
39 */
40 int
41current_script_is_vim9(void)
42{
43 return SCRIPT_ID_VALID(current_sctx.sc_sid)
44 && SCRIPT_ITEM(current_sctx.sc_sid)->sn_version
45 == SCRIPT_VERSION_VIM9;
46}
Bram Moolenaarb91d3f82021-04-01 13:17:50 +020047#endif
Bram Moolenaare535db82021-03-31 21:07:24 +020048
49/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010050 * ":vim9script".
51 */
52 void
Bram Moolenaar9b8d6222020-12-28 18:26:00 +010053ex_vim9script(exarg_T *eap UNUSED)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010054{
Bram Moolenaar9b8d6222020-12-28 18:26:00 +010055#ifdef FEAT_EVAL
Bram Moolenaar2b327002020-12-26 15:39:31 +010056 int sid = current_sctx.sc_sid;
Bram Moolenaar101f4812020-06-16 23:18:51 +020057 scriptitem_T *si;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010058
59 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
60 {
Bram Moolenaar451c2e32020-08-15 16:33:28 +020061 emsg(_(e_vim9script_can_only_be_used_in_script));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010062 return;
63 }
Bram Moolenaar2b327002020-12-26 15:39:31 +010064
65 si = SCRIPT_ITEM(sid);
66 if (si->sn_state == SN_STATE_HAD_COMMAND)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010067 {
Bram Moolenaar451c2e32020-08-15 16:33:28 +020068 emsg(_(e_vim9script_must_be_first_command_in_script));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010069 return;
70 }
Bram Moolenaar2b327002020-12-26 15:39:31 +010071 if (!IS_WHITE_OR_NUL(*eap->arg) && STRCMP(eap->arg, "noclear") != 0)
72 {
73 semsg(_(e_invarg2), eap->arg);
74 return;
75 }
76 if (si->sn_state == SN_STATE_RELOAD && IS_WHITE_OR_NUL(*eap->arg))
77 {
78 hashtab_T *ht = &SCRIPT_VARS(sid);
79
80 // Reloading a script without the "noclear" argument: clear
81 // script-local variables and functions.
82 hashtab_free_contents(ht);
83 hash_init(ht);
84 delete_script_functions(sid);
85
86 // old imports and script variables are no longer valid
87 free_imports_and_script_vars(sid);
88 }
89 si->sn_state = SN_STATE_HAD_COMMAND;
90
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010091 current_sctx.sc_version = SCRIPT_VERSION_VIM9;
92 si->sn_version = SCRIPT_VERSION_VIM9;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010093
94 if (STRCMP(p_cpo, CPO_VIM) != 0)
95 {
Bram Moolenaar39ca4122020-10-20 14:25:07 +020096 si->sn_save_cpo = vim_strsave(p_cpo);
Bram Moolenaar37294bd2021-03-10 13:40:08 +010097 set_option_value((char_u *)"cpo", 0L, (char_u *)CPO_VIM, OPT_NO_REDRAW);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010098 }
Bram Moolenaar9b8d6222020-12-28 18:26:00 +010099#else
100 // No check for this being the first command, it doesn't matter.
101 current_sctx.sc_version = SCRIPT_VERSION_VIM9;
102#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100103}
104
105/*
Bram Moolenaarae616492020-07-28 20:07:27 +0200106 * When in Vim9 script give an error and return FAIL.
107 */
108 int
109not_in_vim9(exarg_T *eap)
110{
Bram Moolenaar68e30442020-07-28 21:15:07 +0200111 if (in_vim9script())
112 switch (eap->cmdidx)
113 {
Bram Moolenaarada1d872021-02-20 08:16:51 +0100114 case CMD_k:
115 if (eap->addr_count > 0)
116 {
117 emsg(_(e_norange));
118 return FAIL;
119 }
120 // FALLTHROUGH
Bram Moolenaar68e30442020-07-28 21:15:07 +0200121 case CMD_append:
122 case CMD_change:
Bram Moolenaarf5a48012020-08-01 17:00:03 +0200123 case CMD_insert:
Bram Moolenaar65088802021-03-13 21:07:21 +0100124 case CMD_open:
Bram Moolenaarf5a48012020-08-01 17:00:03 +0200125 case CMD_t:
Bram Moolenaar68e30442020-07-28 21:15:07 +0200126 case CMD_xit:
Bram Moolenaar9b8d6222020-12-28 18:26:00 +0100127 semsg(_(e_command_not_supported_in_vim9_script_missing_var_str), eap->cmd);
Bram Moolenaar68e30442020-07-28 21:15:07 +0200128 return FAIL;
129 default: break;
130 }
Bram Moolenaarae616492020-07-28 20:07:27 +0200131 return OK;
132}
133
Bram Moolenaardcc58e02020-12-28 20:53:21 +0100134/*
Bram Moolenaar4b3e1962021-03-18 21:37:55 +0100135 * Give an error message if "p" points at "#{" and return TRUE.
136 * This avoids that using a legacy style #{} dictionary leads to difficult to
137 * understand errors.
138 */
139 int
140vim9_bad_comment(char_u *p)
141{
Bram Moolenaara0399ef2021-03-20 15:00:01 +0100142 if (p[0] == '#' && p[1] == '{' && p[2] != '{')
Bram Moolenaar4b3e1962021-03-18 21:37:55 +0100143 {
144 emsg(_(e_cannot_use_hash_curly_to_start_comment));
145 return TRUE;
146 }
147 return FALSE;
148}
149
150/*
Bram Moolenaara0399ef2021-03-20 15:00:01 +0100151 * Return TRUE if "p" points at a "#" not followed by one '{'.
Bram Moolenaar4b3e1962021-03-18 21:37:55 +0100152 * Does not check for white space.
Bram Moolenaardcc58e02020-12-28 20:53:21 +0100153 */
154 int
155vim9_comment_start(char_u *p)
156{
Bram Moolenaara0399ef2021-03-20 15:00:01 +0100157 return p[0] == '#' && (p[1] != '{' || p[2] == '{');
Bram Moolenaardcc58e02020-12-28 20:53:21 +0100158}
159
Bram Moolenaar9b8d6222020-12-28 18:26:00 +0100160#if defined(FEAT_EVAL) || defined(PROTO)
161
Bram Moolenaarae616492020-07-28 20:07:27 +0200162/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100163 * ":export let Name: type"
164 * ":export const Name: type"
165 * ":export def Name(..."
166 * ":export class Name ..."
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100167 */
168 void
Bram Moolenaar09689a02020-05-09 22:50:08 +0200169ex_export(exarg_T *eap)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100170{
Bram Moolenaareb6880b2020-07-12 17:07:05 +0200171 if (!in_vim9script())
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100172 {
Bram Moolenaar451c2e32020-08-15 16:33:28 +0200173 emsg(_(e_export_can_only_be_used_in_vim9script));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100174 return;
175 }
176
177 eap->cmd = eap->arg;
Bram Moolenaar2e2d7582021-03-03 21:22:41 +0100178 (void)find_ex_command(eap, NULL, lookup_scriptitem, NULL);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100179 switch (eap->cmdidx)
180 {
181 case CMD_let:
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200182 case CMD_var:
183 case CMD_final:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100184 case CMD_const:
185 case CMD_def:
186 // case CMD_class:
187 is_export = TRUE;
188 do_cmdline(eap->cmd, eap->getline, eap->cookie,
189 DOCMD_VERBOSE + DOCMD_NOWAIT);
190
191 // The command will reset "is_export" when exporting an item.
192 if (is_export)
193 {
Bram Moolenaar451c2e32020-08-15 16:33:28 +0200194 emsg(_(e_export_with_invalid_argument));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100195 is_export = FALSE;
196 }
197 break;
198 default:
Bram Moolenaar451c2e32020-08-15 16:33:28 +0200199 emsg(_(e_invalid_command_after_export));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100200 break;
201 }
202}
203
204/*
205 * Add a new imported item entry to the current script.
206 */
207 static imported_T *
208new_imported(garray_T *gap)
209{
210 if (ga_grow(gap, 1) == OK)
211 return ((imported_T *)gap->ga_data + gap->ga_len++);
212 return NULL;
213}
214
215/*
216 * Free all imported items in script "sid".
217 */
218 void
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200219free_imports_and_script_vars(int sid)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100220{
Bram Moolenaar21b9e972020-01-26 19:26:46 +0100221 scriptitem_T *si = SCRIPT_ITEM(sid);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100222 int idx;
223
224 for (idx = 0; idx < si->sn_imports.ga_len; ++idx)
225 {
Bram Moolenaar20431c92020-03-20 18:39:46 +0100226 imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100227
228 vim_free(imp->imp_name);
229 }
230 ga_clear(&si->sn_imports);
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200231
232 free_all_script_vars(si);
233
Bram Moolenaar6110e792020-07-08 19:35:21 +0200234 clear_type_list(&si->sn_type_list);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100235}
236
237/*
Bram Moolenaara6294952020-12-27 13:39:50 +0100238 * Mark all imports as possible to redefine. Used when a script is loaded
239 * again but not cleared.
240 */
241 void
242mark_imports_for_reload(int sid)
243{
244 scriptitem_T *si = SCRIPT_ITEM(sid);
245 int idx;
246
247 for (idx = 0; idx < si->sn_imports.ga_len; ++idx)
248 {
249 imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx;
250
251 imp->imp_flags |= IMP_FLAGS_RELOAD;
252 }
253}
254
255/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100256 * ":import Item from 'filename'"
257 * ":import Item as Alias from 'filename'"
258 * ":import {Item} from 'filename'".
259 * ":import {Item as Alias} from 'filename'"
260 * ":import {Item, Item} from 'filename'"
261 * ":import {Item, Item as Alias} from 'filename'"
262 *
263 * ":import * as Name from 'filename'"
264 */
265 void
266ex_import(exarg_T *eap)
267{
Bram Moolenaar1c991142020-07-04 13:15:31 +0200268 char_u *cmd_end;
269 evalarg_T evalarg;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100270
Bram Moolenaar101f4812020-06-16 23:18:51 +0200271 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
272 {
Bram Moolenaar451c2e32020-08-15 16:33:28 +0200273 emsg(_(e_import_can_only_be_used_in_script));
Bram Moolenaar101f4812020-06-16 23:18:51 +0200274 return;
275 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200276 fill_evalarg_from_eap(&evalarg, eap, eap->skip);
Bram Moolenaar101f4812020-06-16 23:18:51 +0200277
Bram Moolenaar1c991142020-07-04 13:15:31 +0200278 cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid,
279 &evalarg, NULL);
Bram Moolenaar9721fb42020-06-11 23:10:46 +0200280 if (cmd_end != NULL)
281 eap->nextcmd = check_nextcmd(cmd_end);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200282 clear_evalarg(&evalarg, eap);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100283}
284
285/*
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100286 * Find an exported item in "sid" matching the name at "*argp".
287 * When it is a variable return the index.
288 * When it is a user function return "*ufunc".
289 * When not found returns -1 and "*ufunc" is NULL.
290 */
291 int
292find_exported(
293 int sid,
Bram Moolenaar1c991142020-07-04 13:15:31 +0200294 char_u *name,
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100295 ufunc_T **ufunc,
Bram Moolenaarfbbcd002020-10-15 12:46:44 +0200296 type_T **type,
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +0100297 cctx_T *cctx,
298 int verbose)
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100299{
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100300 int idx = -1;
301 svar_T *sv;
302 scriptitem_T *script = SCRIPT_ITEM(sid);
303
Bram Moolenaar529fb5a2021-04-01 12:57:57 +0200304 // Find name in "script".
Bram Moolenaar08251752021-01-11 21:20:18 +0100305 idx = get_script_item_idx(sid, name, 0, cctx);
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100306 if (idx >= 0)
307 {
308 sv = ((svar_T *)script->sn_var_vals.ga_data) + idx;
309 if (!sv->sv_export)
310 {
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +0100311 if (verbose)
312 semsg(_(e_item_not_exported_in_script_str), name);
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100313 return -1;
314 }
315 *type = sv->sv_type;
316 *ufunc = NULL;
317 }
318 else
319 {
320 char_u buffer[200];
321 char_u *funcname;
322
323 // it could be a user function.
Bram Moolenaar5a67c372020-07-23 14:39:47 +0200324 if (STRLEN(name) < sizeof(buffer) - 15)
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100325 funcname = buffer;
326 else
327 {
Bram Moolenaar5a67c372020-07-23 14:39:47 +0200328 funcname = alloc(STRLEN(name) + 15);
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100329 if (funcname == NULL)
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100330 return -1;
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100331 }
332 funcname[0] = K_SPECIAL;
333 funcname[1] = KS_EXTRA;
334 funcname[2] = (int)KE_SNR;
335 sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name);
Bram Moolenaar4c17ad92020-04-27 22:47:51 +0200336 *ufunc = find_func(funcname, FALSE, NULL);
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100337 if (funcname != buffer)
338 vim_free(funcname);
339
340 if (*ufunc == NULL)
341 {
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +0100342 if (verbose)
343 semsg(_(e_item_not_found_in_script_str), name);
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100344 return -1;
345 }
Bram Moolenaar529fb5a2021-04-01 12:57:57 +0200346 else if (((*ufunc)->uf_flags & FC_EXPORT) == 0)
347 {
348 if (verbose)
349 semsg(_(e_item_not_exported_in_script_str), name);
350 *ufunc = NULL;
351 return -1;
352 }
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100353 }
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100354
355 return idx;
356}
357
358/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100359 * Handle an ":import" command and add the resulting imported_T to "gap", when
360 * not NULL, or script "import_sid" sn_imports.
Bram Moolenaarfbbcd002020-10-15 12:46:44 +0200361 * "cctx" is NULL at the script level.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100362 * Returns a pointer to after the command or NULL in case of failure
363 */
364 char_u *
Bram Moolenaar1c991142020-07-04 13:15:31 +0200365handle_import(
366 char_u *arg_start,
367 garray_T *gap,
368 int import_sid,
369 evalarg_T *evalarg,
370 void *cctx)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100371{
372 char_u *arg = arg_start;
Bram Moolenaar1c991142020-07-04 13:15:31 +0200373 char_u *cmd_end = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100374 int ret = FAIL;
375 typval_T tv;
376 int sid = -1;
377 int res;
Bram Moolenaar0a842842021-02-27 22:41:19 +0100378 int mult = FALSE;
Bram Moolenaar1c991142020-07-04 13:15:31 +0200379 garray_T names;
Bram Moolenaar0a842842021-02-27 22:41:19 +0100380 garray_T as_names;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100381
Bram Moolenaar1c991142020-07-04 13:15:31 +0200382 ga_init2(&names, sizeof(char_u *), 10);
Bram Moolenaar0a842842021-02-27 22:41:19 +0100383 ga_init2(&as_names, sizeof(char_u *), 10);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100384 if (*arg == '{')
385 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200386 // "import {item, item} from ..."
Bram Moolenaar0a842842021-02-27 22:41:19 +0100387 mult = TRUE;
Bram Moolenaar1c991142020-07-04 13:15:31 +0200388 arg = skipwhite_and_linebreak(arg + 1, evalarg);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100389 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200390
Bram Moolenaar0a842842021-02-27 22:41:19 +0100391 for (;;)
392 {
393 char_u *p = arg;
394 int had_comma = FALSE;
395 char_u *as_name = NULL;
396
397 // accept "*" or "Name"
398 if (!mult && arg[0] == '*' && IS_WHITE_OR_NUL(arg[1]))
399 ++arg;
400 else
Bram Moolenaarfa29c8a2020-02-23 22:35:05 +0100401 while (eval_isnamec(*arg))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100402 ++arg;
Bram Moolenaar0a842842021-02-27 22:41:19 +0100403 if (p == arg)
404 break;
405 if (ga_grow(&names, 1) == FAIL || ga_grow(&as_names, 1) == FAIL)
Bram Moolenaar1c991142020-07-04 13:15:31 +0200406 goto erret;
Bram Moolenaar0a842842021-02-27 22:41:19 +0100407 ((char_u **)names.ga_data)[names.ga_len] = vim_strnsave(p, arg - p);
408 ++names.ga_len;
Bram Moolenaar1c991142020-07-04 13:15:31 +0200409
Bram Moolenaar0a842842021-02-27 22:41:19 +0100410 arg = skipwhite_and_linebreak(arg, evalarg);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200411 if (STRNCMP("as", arg, 2) == 0 && IS_WHITE_OR_NUL(arg[2]))
412 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200413 // skip over "as Name "; no line break allowed after "as"
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100414 arg = skipwhite(arg + 2);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200415 p = arg;
Bram Moolenaarfa29c8a2020-02-23 22:35:05 +0100416 if (eval_isnamec1(*arg))
417 while (eval_isnamec(*arg))
418 ++arg;
Bram Moolenaar057e84a2021-02-28 16:55:11 +0100419 if (check_defined(p, arg - p, cctx, FALSE) == FAIL)
Bram Moolenaar1c991142020-07-04 13:15:31 +0200420 goto erret;
421 as_name = vim_strnsave(p, arg - p);
422 arg = skipwhite_and_linebreak(arg, evalarg);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100423 }
424 else if (*arg_start == '*')
425 {
Bram Moolenaar451c2e32020-08-15 16:33:28 +0200426 emsg(_(e_missing_as_after_star));
Bram Moolenaar1c991142020-07-04 13:15:31 +0200427 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100428 }
Bram Moolenaar0a842842021-02-27 22:41:19 +0100429 // without "as Name" the as_names entry is NULL
430 ((char_u **)as_names.ga_data)[as_names.ga_len] = as_name;
431 ++as_names.ga_len;
432
433 if (!mult)
434 break;
435 if (*arg == ',')
436 {
437 had_comma = TRUE;
438 ++arg;
439 }
440 arg = skipwhite_and_linebreak(arg, evalarg);
441 if (*arg == '}')
442 {
443 ++arg;
444 break;
445 }
446 if (!had_comma)
447 {
448 emsg(_(e_missing_comma_in_import));
449 goto erret;
450 }
451 }
452 arg = skipwhite_and_linebreak(arg, evalarg);
453
454 if (names.ga_len == 0)
455 {
456 emsg(_(e_syntax_error_in_import));
457 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100458 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200459
460 if (STRNCMP("from", arg, 4) != 0 || !IS_WHITE_OR_NUL(arg[4]))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100461 {
Bram Moolenaar451c2e32020-08-15 16:33:28 +0200462 emsg(_(e_missing_from));
Bram Moolenaar1c991142020-07-04 13:15:31 +0200463 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100464 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200465
Bram Moolenaar962d7212020-07-04 14:15:00 +0200466 arg = skipwhite_and_linebreak(arg + 4, evalarg);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100467 tv.v_type = VAR_UNKNOWN;
468 // TODO: should we accept any expression?
469 if (*arg == '\'')
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +0200470 ret = eval_lit_string(&arg, &tv, TRUE);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100471 else if (*arg == '"')
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +0200472 ret = eval_string(&arg, &tv, TRUE);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100473 if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL)
474 {
Bram Moolenaar451c2e32020-08-15 16:33:28 +0200475 emsg(_(e_invalid_string_after_from));
Bram Moolenaar1c991142020-07-04 13:15:31 +0200476 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100477 }
478 cmd_end = arg;
479
Bram Moolenaar1c991142020-07-04 13:15:31 +0200480 /*
481 * find script file
482 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100483 if (*tv.vval.v_string == '.')
484 {
485 size_t len;
Bram Moolenaar21b9e972020-01-26 19:26:46 +0100486 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100487 char_u *tail = gettail(si->sn_name);
488 char_u *from_name;
489
490 // Relative to current script: "./name.vim", "../../name.vim".
491 len = STRLEN(si->sn_name) - STRLEN(tail) + STRLEN(tv.vval.v_string) + 2;
492 from_name = alloc((int)len);
493 if (from_name == NULL)
494 {
495 clear_tv(&tv);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200496 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100497 }
498 vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
499 add_pathsep(from_name);
500 STRCAT(from_name, tv.vval.v_string);
501 simplify_filename(from_name);
502
503 res = do_source(from_name, FALSE, DOSO_NONE, &sid);
504 vim_free(from_name);
505 }
506 else if (mch_isFullName(tv.vval.v_string))
507 {
508 // Absolute path: "/tmp/name.vim"
509 res = do_source(tv.vval.v_string, FALSE, DOSO_NONE, &sid);
510 }
511 else
512 {
513 size_t len = 7 + STRLEN(tv.vval.v_string) + 1;
514 char_u *from_name;
515
516 // Find file in "import" subdirs in 'runtimepath'.
517 from_name = alloc((int)len);
518 if (from_name == NULL)
519 {
520 clear_tv(&tv);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200521 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100522 }
523 vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string);
524 res = source_in_path(p_rtp, from_name, DIP_NOAFTER, &sid);
525 vim_free(from_name);
526 }
527
528 if (res == FAIL || sid <= 0)
529 {
Bram Moolenaar451c2e32020-08-15 16:33:28 +0200530 semsg(_(e_could_not_import_str), tv.vval.v_string);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100531 clear_tv(&tv);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200532 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100533 }
534 clear_tv(&tv);
535
536 if (*arg_start == '*')
537 {
Bram Moolenaar0a842842021-02-27 22:41:19 +0100538 imported_T *imported;
539 char_u *as_name = ((char_u **)as_names.ga_data)[0];
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100540
Bram Moolenaar0a842842021-02-27 22:41:19 +0100541 // "import * as That"
Bram Moolenaara6294952020-12-27 13:39:50 +0100542 imported = find_imported(as_name, STRLEN(as_name), cctx);
543 if (imported != NULL && imported->imp_sid == sid)
544 {
545 if (imported->imp_flags & IMP_FLAGS_RELOAD)
546 // import already defined on a previous script load
547 imported->imp_flags &= ~IMP_FLAGS_RELOAD;
548 else
549 {
550 semsg(_(e_name_already_defined_str), as_name);
551 goto erret;
552 }
553 }
554
555 imported = new_imported(gap != NULL ? gap
556 : &SCRIPT_ITEM(import_sid)->sn_imports);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100557 if (imported == NULL)
Bram Moolenaar1c991142020-07-04 13:15:31 +0200558 goto erret;
559 imported->imp_name = as_name;
Bram Moolenaar0a842842021-02-27 22:41:19 +0100560 ((char_u **)as_names.ga_data)[0] = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100561 imported->imp_sid = sid;
Bram Moolenaara6294952020-12-27 13:39:50 +0100562 imported->imp_flags = IMP_FLAGS_STAR;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100563 }
564 else
565 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200566 int i;
567
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100568 arg = arg_start;
569 if (*arg == '{')
570 arg = skipwhite(arg + 1);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200571 for (i = 0; i < names.ga_len; ++i)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100572 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200573 char_u *name = ((char_u **)names.ga_data)[i];
Bram Moolenaar0a842842021-02-27 22:41:19 +0100574 char_u *as_name = ((char_u **)as_names.ga_data)[i];
Bram Moolenaara6294952020-12-27 13:39:50 +0100575 size_t len = STRLEN(name);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100576 int idx;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100577 imported_T *imported;
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100578 ufunc_T *ufunc = NULL;
579 type_T *type;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100580
Bram Moolenaarcb4e80f2021-03-13 20:57:19 +0100581 idx = find_exported(sid, name, &ufunc, &type, cctx, TRUE);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100582
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100583 if (idx < 0 && ufunc == NULL)
Bram Moolenaar1c991142020-07-04 13:15:31 +0200584 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100585
Bram Moolenaara6294952020-12-27 13:39:50 +0100586 // If already imported with the same propertis and the
587 // IMP_FLAGS_RELOAD set then we keep that entry. Otherwise create
588 // a new one (and give an error for an existing import).
589 imported = find_imported(name, len, cctx);
590 if (imported != NULL
591 && (imported->imp_flags & IMP_FLAGS_RELOAD)
592 && imported->imp_sid == sid
593 && (idx >= 0
594 ? (equal_type(imported->imp_type, type)
595 && imported->imp_var_vals_idx == idx)
596 : (equal_type(imported->imp_type, ufunc->uf_func_type)
597 && STRCMP(imported->imp_funcname,
598 ufunc->uf_name) == 0)))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100599 {
Bram Moolenaara6294952020-12-27 13:39:50 +0100600 imported->imp_flags &= ~IMP_FLAGS_RELOAD;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100601 }
602 else
Bram Moolenaar40f4f7a2020-07-23 22:41:43 +0200603 {
Bram Moolenaar6c7cc342021-04-17 16:38:50 +0200604 if (as_name == NULL
605 && check_defined(name, len, cctx, FALSE) == FAIL)
Bram Moolenaara6294952020-12-27 13:39:50 +0100606 goto erret;
607
608 imported = new_imported(gap != NULL ? gap
609 : &SCRIPT_ITEM(import_sid)->sn_imports);
610 if (imported == NULL)
611 goto erret;
612
Bram Moolenaar0a842842021-02-27 22:41:19 +0100613 if (as_name == NULL)
614 {
615 imported->imp_name = name;
616 ((char_u **)names.ga_data)[i] = NULL;
Bram Moolenaar057e84a2021-02-28 16:55:11 +0100617 }
Bram Moolenaar0a842842021-02-27 22:41:19 +0100618 else
619 {
620 // "import This as That ..."
621 imported->imp_name = as_name;
622 ((char_u **)as_names.ga_data)[i] = NULL;
623 }
Bram Moolenaara6294952020-12-27 13:39:50 +0100624 imported->imp_sid = sid;
625 if (idx >= 0)
626 {
627 imported->imp_type = type;
628 imported->imp_var_vals_idx = idx;
629 }
630 else
631 {
632 imported->imp_type = ufunc->uf_func_type;
633 imported->imp_funcname = ufunc->uf_name;
634 }
Bram Moolenaar40f4f7a2020-07-23 22:41:43 +0200635 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100636 }
637 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200638erret:
639 ga_clear_strings(&names);
Bram Moolenaar0a842842021-02-27 22:41:19 +0100640 ga_clear_strings(&as_names);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100641 return cmd_end;
642}
643
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200644/*
645 * Declare a script-local variable without init: "let var: type".
646 * "const" is an error since the value is missing.
647 * Returns a pointer to after the type.
648 */
649 char_u *
650vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
651{
652 char_u *p;
653 char_u *name;
654 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
655 type_T *type;
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200656 typval_T init_tv;
657
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200658 if (eap->cmdidx == CMD_final || eap->cmdidx == CMD_const)
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200659 {
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200660 if (eap->cmdidx == CMD_final)
661 emsg(_(e_final_requires_a_value));
662 else
663 emsg(_(e_const_requires_a_value));
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200664 return arg + STRLEN(arg);
665 }
666
667 // Check for valid starting character.
668 if (!eval_isnamec1(*arg))
669 {
670 semsg(_(e_invarg2), arg);
671 return arg + STRLEN(arg);
672 }
673
Bram Moolenaar984dddb2020-06-14 12:50:24 +0200674 for (p = arg + 1; *p != NUL && eval_isnamec(*p); MB_PTR_ADV(p))
Bram Moolenaar3b74b6b2020-06-19 19:01:43 +0200675 if (*p == ':' && (VIM_ISWHITE(p[1]) || p != arg + 1))
Bram Moolenaar984dddb2020-06-14 12:50:24 +0200676 break;
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200677
678 if (*p != ':')
679 {
Bram Moolenaarbc4c5052020-08-13 22:47:35 +0200680 emsg(_(e_type_or_initialization_required));
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200681 return arg + STRLEN(arg);
682 }
Bram Moolenaar984dddb2020-06-14 12:50:24 +0200683 if (!VIM_ISWHITE(p[1]))
684 {
Bram Moolenaarc3fc75d2021-02-07 15:28:09 +0100685 semsg(_(e_white_space_required_after_str_str), ":", p);
Bram Moolenaar984dddb2020-06-14 12:50:24 +0200686 return arg + STRLEN(arg);
687 }
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200688 name = vim_strnsave(arg, p - arg);
689
690 // parse type
691 p = skipwhite(p + 1);
Bram Moolenaar9e68c322020-12-25 12:38:04 +0100692 type = parse_type(&p, &si->sn_type_list, TRUE);
693 if (type == NULL)
Bram Moolenaarf3decc52020-06-13 19:56:38 +0200694 {
695 vim_free(name);
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200696 return p;
Bram Moolenaarf3decc52020-06-13 19:56:38 +0200697 }
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200698
699 // Create the variable with 0/NULL value.
700 CLEAR_FIELD(init_tv);
Bram Moolenaarf0afd9e2020-09-13 18:57:47 +0200701 if (type->tt_type == VAR_ANY)
702 // A variable of type "any" is not possible, just use zero instead
703 init_tv.v_type = VAR_NUMBER;
704 else
705 init_tv.v_type = type->tt_type;
Bram Moolenaarf785aa12021-02-11 21:19:34 +0100706 set_var_const(name, type, &init_tv, FALSE, 0, 0);
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200707
708 vim_free(name);
709 return p;
710}
711
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200712/*
Bram Moolenaar39ca4122020-10-20 14:25:07 +0200713 * Vim9 part of adding a script variable: add it to sn_all_vars (lookup by name
714 * with a hashtable) and sn_var_vals (lookup by index).
Bram Moolenaar07a65d22020-12-26 20:09:15 +0100715 * When "create" is TRUE this is a new variable, otherwise find and update an
716 * existing variable.
Bram Moolenaar08251752021-01-11 21:20:18 +0100717 * "flags" can have ASSIGN_FINAL or ASSIGN_CONST.
Bram Moolenaarf2253962021-04-13 20:53:13 +0200718 * When "*type" is NULL use "tv" for the type and update "*type". If
719 * "do_member" is TRUE also use the member type, otherwise use "any".
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200720 */
721 void
Bram Moolenaar08251752021-01-11 21:20:18 +0100722update_vim9_script_var(
723 int create,
724 dictitem_T *di,
725 int flags,
726 typval_T *tv,
Bram Moolenaarf2253962021-04-13 20:53:13 +0200727 type_T **type,
728 int do_member)
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200729{
Bram Moolenaar07a65d22020-12-26 20:09:15 +0100730 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
731 hashitem_T *hi;
732 svar_T *sv;
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200733
Bram Moolenaar07a65d22020-12-26 20:09:15 +0100734 if (create)
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200735 {
Bram Moolenaar07a65d22020-12-26 20:09:15 +0100736 sallvar_T *newsav;
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200737
Bram Moolenaar07a65d22020-12-26 20:09:15 +0100738 // Store a pointer to the typval_T, so that it can be found by index
739 // instead of using a hastab lookup.
740 if (ga_grow(&si->sn_var_vals, 1) == FAIL)
741 return;
742
743 sv = ((svar_T *)si->sn_var_vals.ga_data) + si->sn_var_vals.ga_len;
744 newsav = (sallvar_T *)alloc_clear(
745 sizeof(sallvar_T) + STRLEN(di->di_key));
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200746 if (newsav == NULL)
747 return;
748
749 sv->sv_tv = &di->di_tv;
Bram Moolenaar08251752021-01-11 21:20:18 +0100750 sv->sv_const = (flags & ASSIGN_FINAL) ? ASSIGN_FINAL
751 : (flags & ASSIGN_CONST) ? ASSIGN_CONST : 0;
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200752 sv->sv_export = is_export;
753 newsav->sav_var_vals_idx = si->sn_var_vals.ga_len;
754 ++si->sn_var_vals.ga_len;
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200755 STRCPY(&newsav->sav_key, di->di_key);
756 sv->sv_name = newsav->sav_key;
757 newsav->sav_di = di;
758 newsav->sav_block_id = si->sn_current_block_id;
759
760 hi = hash_find(&si->sn_all_vars.dv_hashtab, newsav->sav_key);
761 if (!HASHITEM_EMPTY(hi))
762 {
763 sallvar_T *sav = HI2SAV(hi);
764
765 // variable with this name exists in another block
766 while (sav->sav_next != NULL)
767 sav = sav->sav_next;
768 sav->sav_next = newsav;
769 }
770 else
771 // new variable name
772 hash_add(&si->sn_all_vars.dv_hashtab, newsav->sav_key);
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200773 }
Bram Moolenaar07a65d22020-12-26 20:09:15 +0100774 else
775 {
776 sv = find_typval_in_script(&di->di_tv);
777 }
778 if (sv != NULL)
779 {
Bram Moolenaaraa210a32021-01-02 15:41:03 +0100780 if (*type == NULL)
Bram Moolenaarf2253962021-04-13 20:53:13 +0200781 *type = typval2type(tv, get_copyID(), &si->sn_type_list,
782 do_member);
Bram Moolenaaraa210a32021-01-02 15:41:03 +0100783 sv->sv_type = *type;
Bram Moolenaar07a65d22020-12-26 20:09:15 +0100784 }
785
786 // let ex_export() know the export worked.
787 is_export = FALSE;
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200788}
789
Bram Moolenaarfbbcd002020-10-15 12:46:44 +0200790/*
791 * Hide a script variable when leaving a block.
792 * "idx" is de index in sn_var_vals.
Bram Moolenaar39ca4122020-10-20 14:25:07 +0200793 * When "func_defined" is non-zero then a function was defined in this block,
794 * the variable may be accessed by it. Otherwise the variable can be cleared.
Bram Moolenaarfbbcd002020-10-15 12:46:44 +0200795 */
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200796 void
Bram Moolenaar39ca4122020-10-20 14:25:07 +0200797hide_script_var(scriptitem_T *si, int idx, int func_defined)
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200798{
Bram Moolenaarfbbcd002020-10-15 12:46:44 +0200799 svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200800 hashtab_T *script_ht = get_script_local_ht();
801 hashtab_T *all_ht = &si->sn_all_vars.dv_hashtab;
802 hashitem_T *script_hi;
803 hashitem_T *all_hi;
804
805 // Remove a variable declared inside the block, if it still exists.
Bram Moolenaar39ca4122020-10-20 14:25:07 +0200806 // If it was added in a nested block it will already have been removed.
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200807 // The typval is moved into the sallvar_T.
808 script_hi = hash_find(script_ht, sv->sv_name);
809 all_hi = hash_find(all_ht, sv->sv_name);
810 if (!HASHITEM_EMPTY(script_hi) && !HASHITEM_EMPTY(all_hi))
811 {
812 dictitem_T *di = HI2DI(script_hi);
813 sallvar_T *sav = HI2SAV(all_hi);
Bram Moolenaar39ca4122020-10-20 14:25:07 +0200814 sallvar_T *sav_prev = NULL;
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200815
Bram Moolenaarfbbcd002020-10-15 12:46:44 +0200816 // There can be multiple entries with the same name in different
817 // blocks, find the right one.
818 while (sav != NULL && sav->sav_var_vals_idx != idx)
Bram Moolenaar39ca4122020-10-20 14:25:07 +0200819 {
820 sav_prev = sav;
Bram Moolenaarfbbcd002020-10-15 12:46:44 +0200821 sav = sav->sav_next;
Bram Moolenaar39ca4122020-10-20 14:25:07 +0200822 }
Bram Moolenaarfbbcd002020-10-15 12:46:44 +0200823 if (sav != NULL)
824 {
Bram Moolenaar39ca4122020-10-20 14:25:07 +0200825 if (func_defined)
826 {
827 // move the typval from the dictitem to the sallvar
828 sav->sav_tv = di->di_tv;
829 di->di_tv.v_type = VAR_UNKNOWN;
830 sav->sav_flags = di->di_flags;
831 sav->sav_di = NULL;
832 sv->sv_tv = &sav->sav_tv;
833 }
834 else
835 {
836 if (sav_prev == NULL)
837 hash_remove(all_ht, all_hi);
838 else
839 sav_prev->sav_next = sav->sav_next;
840 sv->sv_name = NULL;
841 vim_free(sav);
842 }
Bram Moolenaarfbbcd002020-10-15 12:46:44 +0200843 delete_var(script_ht, script_hi);
Bram Moolenaarfbbcd002020-10-15 12:46:44 +0200844 }
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200845 }
846}
847
848/*
849 * Free the script variables from "sn_all_vars".
850 */
851 void
852free_all_script_vars(scriptitem_T *si)
853{
854 int todo;
855 hashtab_T *ht = &si->sn_all_vars.dv_hashtab;
856 hashitem_T *hi;
857 sallvar_T *sav;
858 sallvar_T *sav_next;
859
860 hash_lock(ht);
861 todo = (int)ht->ht_used;
862 for (hi = ht->ht_array; todo > 0; ++hi)
863 {
864 if (!HASHITEM_EMPTY(hi))
865 {
866 --todo;
867
868 // Free the variable. Don't remove it from the hashtab, ht_array
869 // might change then. hash_clear() takes care of it later.
870 sav = HI2SAV(hi);
871 while (sav != NULL)
872 {
873 sav_next = sav->sav_next;
874 if (sav->sav_di == NULL)
875 clear_tv(&sav->sav_tv);
876 vim_free(sav);
877 sav = sav_next;
878 }
879 }
880 }
881 hash_clear(ht);
882 hash_init(ht);
883
884 ga_clear(&si->sn_var_vals);
Bram Moolenaar2b327002020-12-26 15:39:31 +0100885
886 // existing commands using script variable indexes are no longer valid
887 si->sn_script_seq = current_sctx.sc_seq;
Bram Moolenaar8d739de2020-10-14 19:39:19 +0200888}
889
890/*
Bram Moolenaar10c65862020-10-08 21:16:42 +0200891 * Find the script-local variable that links to "dest".
892 * Returns NULL if not found.
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200893 */
Bram Moolenaar10c65862020-10-08 21:16:42 +0200894 svar_T *
895find_typval_in_script(typval_T *dest)
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200896{
897 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
898 int idx;
899
Bram Moolenaar81e17fb2020-08-21 21:55:43 +0200900 if (si->sn_version != SCRIPT_VERSION_VIM9)
901 // legacy script doesn't store variable types
Bram Moolenaar10c65862020-10-08 21:16:42 +0200902 return NULL;
Bram Moolenaar81e17fb2020-08-21 21:55:43 +0200903
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200904 // Find the svar_T in sn_var_vals.
905 for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
906 {
907 svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
908
Bram Moolenaarc0913d02020-12-05 14:44:37 +0100909 // If "sv_name" is NULL the variable was hidden when leaving a block,
910 // don't check "sv_tv" then, it might be used for another variable now.
911 if (sv->sv_name != NULL && sv->sv_tv == dest)
Bram Moolenaar10c65862020-10-08 21:16:42 +0200912 return sv;
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200913 }
Bram Moolenaarf785aa12021-02-11 21:19:34 +0100914 iemsg("find_typval_in_script(): not found");
Bram Moolenaar10c65862020-10-08 21:16:42 +0200915 return NULL;
916}
917
918/*
919 * Check if the type of script variable "dest" allows assigning "value".
920 * If needed convert "value" to a bool.
921 */
922 int
Bram Moolenaarf785aa12021-02-11 21:19:34 +0100923check_script_var_type(
924 typval_T *dest,
925 typval_T *value,
926 char_u *name,
927 where_T where)
Bram Moolenaar10c65862020-10-08 21:16:42 +0200928{
929 svar_T *sv = find_typval_in_script(dest);
930 int ret;
931
932 if (sv != NULL)
933 {
Bram Moolenaar08251752021-01-11 21:20:18 +0100934 if (sv->sv_const != 0)
Bram Moolenaar10c65862020-10-08 21:16:42 +0200935 {
936 semsg(_(e_readonlyvar), name);
937 return FAIL;
938 }
Bram Moolenaarf785aa12021-02-11 21:19:34 +0100939 ret = check_typval_type(sv->sv_type, value, where);
Bram Moolenaar10c65862020-10-08 21:16:42 +0200940 if (ret == OK && need_convert_to_bool(sv->sv_type, value))
941 {
942 int val = tv2bool(value);
943
944 clear_tv(value);
945 value->v_type = VAR_BOOL;
946 value->v_lock = 0;
947 value->vval.v_number = val ? VVAL_TRUE : VVAL_FALSE;
948 }
949 return ret;
950 }
951
Bram Moolenaarc785b9a2020-06-19 18:34:15 +0200952 return OK; // not really
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200953}
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200954
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100955#endif // FEAT_EVAL