blob: 14586f9b8a06501c1c8897f82014ca102d0c318a [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
16#if defined(FEAT_EVAL) || defined(PROTO)
17
18#include "vim9.h"
19
Bram Moolenaar9721fb42020-06-11 23:10:46 +020020static char e_needs_vim9[] = N_("E1042: export can only be used in vim9script");
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010021
22 int
23in_vim9script(void)
24{
25 // TODO: go up the stack?
26 return current_sctx.sc_version == SCRIPT_VERSION_VIM9;
27}
28
29/*
30 * ":vim9script".
31 */
32 void
33ex_vim9script(exarg_T *eap)
34{
Bram Moolenaar101f4812020-06-16 23:18:51 +020035 scriptitem_T *si;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010036
37 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
38 {
39 emsg(_("E1038: vim9script can only be used in a script"));
40 return;
41 }
Bram Moolenaar101f4812020-06-16 23:18:51 +020042 si = SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010043 if (si->sn_had_command)
44 {
45 emsg(_("E1039: vim9script must be the first command in a script"));
46 return;
47 }
48 current_sctx.sc_version = SCRIPT_VERSION_VIM9;
49 si->sn_version = SCRIPT_VERSION_VIM9;
50 si->sn_had_command = TRUE;
51
52 if (STRCMP(p_cpo, CPO_VIM) != 0)
53 {
54 si->sn_save_cpo = p_cpo;
55 p_cpo = vim_strsave((char_u *)CPO_VIM);
56 }
57}
58
59/*
60 * ":export let Name: type"
61 * ":export const Name: type"
62 * ":export def Name(..."
63 * ":export class Name ..."
64 *
65 * ":export {Name, ...}"
66 */
67 void
Bram Moolenaar09689a02020-05-09 22:50:08 +020068ex_export(exarg_T *eap)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010069{
70 if (current_sctx.sc_version != SCRIPT_VERSION_VIM9)
71 {
72 emsg(_(e_needs_vim9));
73 return;
74 }
75
76 eap->cmd = eap->arg;
77 (void)find_ex_command(eap, NULL, lookup_scriptvar, NULL);
78 switch (eap->cmdidx)
79 {
80 case CMD_let:
81 case CMD_const:
82 case CMD_def:
83 // case CMD_class:
84 is_export = TRUE;
85 do_cmdline(eap->cmd, eap->getline, eap->cookie,
86 DOCMD_VERBOSE + DOCMD_NOWAIT);
87
88 // The command will reset "is_export" when exporting an item.
89 if (is_export)
90 {
91 emsg(_("E1044: export with invalid argument"));
92 is_export = FALSE;
93 }
94 break;
95 default:
96 emsg(_("E1043: Invalid command after :export"));
97 break;
98 }
99}
100
101/*
102 * Add a new imported item entry to the current script.
103 */
104 static imported_T *
105new_imported(garray_T *gap)
106{
107 if (ga_grow(gap, 1) == OK)
108 return ((imported_T *)gap->ga_data + gap->ga_len++);
109 return NULL;
110}
111
112/*
113 * Free all imported items in script "sid".
114 */
115 void
116free_imports(int sid)
117{
Bram Moolenaar21b9e972020-01-26 19:26:46 +0100118 scriptitem_T *si = SCRIPT_ITEM(sid);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100119 int idx;
120
121 for (idx = 0; idx < si->sn_imports.ga_len; ++idx)
122 {
Bram Moolenaar20431c92020-03-20 18:39:46 +0100123 imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100124
125 vim_free(imp->imp_name);
126 }
127 ga_clear(&si->sn_imports);
Bram Moolenaar20431c92020-03-20 18:39:46 +0100128 ga_clear(&si->sn_var_vals);
129 ga_clear(&si->sn_type_list);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100130}
131
132/*
133 * ":import Item from 'filename'"
134 * ":import Item as Alias from 'filename'"
135 * ":import {Item} from 'filename'".
136 * ":import {Item as Alias} from 'filename'"
137 * ":import {Item, Item} from 'filename'"
138 * ":import {Item, Item as Alias} from 'filename'"
139 *
140 * ":import * as Name from 'filename'"
141 */
142 void
143ex_import(exarg_T *eap)
144{
Bram Moolenaar1c991142020-07-04 13:15:31 +0200145 char_u *cmd_end;
146 evalarg_T evalarg;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100147
Bram Moolenaar101f4812020-06-16 23:18:51 +0200148 if (!getline_equal(eap->getline, eap->cookie, getsourceline))
149 {
150 emsg(_("E1094: import can only be used in a script"));
151 return;
152 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200153 fill_evalarg_from_eap(&evalarg, eap, eap->skip);
Bram Moolenaar101f4812020-06-16 23:18:51 +0200154
Bram Moolenaar1c991142020-07-04 13:15:31 +0200155 cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid,
156 &evalarg, NULL);
Bram Moolenaar9721fb42020-06-11 23:10:46 +0200157 if (cmd_end != NULL)
158 eap->nextcmd = check_nextcmd(cmd_end);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200159 clear_evalarg(&evalarg, eap);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100160}
161
162/*
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100163 * Find an exported item in "sid" matching the name at "*argp".
164 * When it is a variable return the index.
165 * When it is a user function return "*ufunc".
166 * When not found returns -1 and "*ufunc" is NULL.
167 */
168 int
169find_exported(
170 int sid,
Bram Moolenaar1c991142020-07-04 13:15:31 +0200171 char_u *name,
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100172 ufunc_T **ufunc,
173 type_T **type)
174{
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100175 int idx = -1;
176 svar_T *sv;
177 scriptitem_T *script = SCRIPT_ITEM(sid);
178
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100179 // find name in "script"
180 // TODO: also find script-local user function
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100181 idx = get_script_item_idx(sid, name, FALSE);
182 if (idx >= 0)
183 {
184 sv = ((svar_T *)script->sn_var_vals.ga_data) + idx;
185 if (!sv->sv_export)
186 {
187 semsg(_("E1049: Item not exported in script: %s"), name);
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100188 return -1;
189 }
190 *type = sv->sv_type;
191 *ufunc = NULL;
192 }
193 else
194 {
195 char_u buffer[200];
196 char_u *funcname;
197
198 // it could be a user function.
199 if (STRLEN(name) < sizeof(buffer) - 10)
200 funcname = buffer;
201 else
202 {
203 funcname = alloc(STRLEN(name) + 10);
204 if (funcname == NULL)
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100205 return -1;
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100206 }
207 funcname[0] = K_SPECIAL;
208 funcname[1] = KS_EXTRA;
209 funcname[2] = (int)KE_SNR;
210 sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name);
Bram Moolenaar4c17ad92020-04-27 22:47:51 +0200211 *ufunc = find_func(funcname, FALSE, NULL);
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100212 if (funcname != buffer)
213 vim_free(funcname);
214
215 if (*ufunc == NULL)
216 {
217 semsg(_("E1048: Item not found in script: %s"), name);
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100218 return -1;
219 }
220 }
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100221
222 return idx;
223}
224
225/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100226 * Handle an ":import" command and add the resulting imported_T to "gap", when
227 * not NULL, or script "import_sid" sn_imports.
228 * Returns a pointer to after the command or NULL in case of failure
229 */
230 char_u *
Bram Moolenaar1c991142020-07-04 13:15:31 +0200231handle_import(
232 char_u *arg_start,
233 garray_T *gap,
234 int import_sid,
235 evalarg_T *evalarg,
236 void *cctx)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100237{
238 char_u *arg = arg_start;
Bram Moolenaar1c991142020-07-04 13:15:31 +0200239 char_u *cmd_end = NULL;
240 char_u *as_name = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100241 int ret = FAIL;
242 typval_T tv;
243 int sid = -1;
244 int res;
Bram Moolenaar1c991142020-07-04 13:15:31 +0200245 garray_T names;
246 static char e_import_syntax[] = N_("E1047: syntax error in import");
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100247
Bram Moolenaar1c991142020-07-04 13:15:31 +0200248 ga_init2(&names, sizeof(char_u *), 10);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100249 if (*arg == '{')
250 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200251 // "import {item, item} from ..."
252 arg = skipwhite_and_linebreak(arg + 1, evalarg);
253 for (;;)
254 {
255 char_u *p = arg;
256 int had_comma = FALSE;
257
258 while (eval_isnamec(*arg))
259 ++arg;
260 if (p == arg)
261 break;
262 if (ga_grow(&names, 1) == FAIL)
263 goto erret;
264 ((char_u **)names.ga_data)[names.ga_len] =
265 vim_strnsave(p, arg - p);
266 ++names.ga_len;
267 if (*arg == ',')
268 {
269 had_comma = TRUE;
270 ++arg;
271 }
272 arg = skipwhite_and_linebreak(arg, evalarg);
273 if (*arg == '}')
274 {
275 arg = skipwhite_and_linebreak(arg + 1, evalarg);
276 break;
277 }
278 if (!had_comma)
279 {
280 emsg(_("E1046: Missing comma in import"));
281 goto erret;
282 }
283 }
284 if (names.ga_len == 0)
285 {
286 emsg(_(e_import_syntax));
287 goto erret;
288 }
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100289 }
290 else
291 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200292 // "import Name from ..."
293 // "import * as Name from ..."
294 // "import item [as Name] from ..."
295 arg = skipwhite_and_linebreak(arg, evalarg);
296 if (arg[0] == '*' && IS_WHITE_OR_NUL(arg[1]))
297 arg = skipwhite_and_linebreak(arg + 1, evalarg);
Bram Moolenaarfa29c8a2020-02-23 22:35:05 +0100298 else if (eval_isnamec1(*arg))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100299 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200300 char_u *p = arg;
301
Bram Moolenaarfa29c8a2020-02-23 22:35:05 +0100302 while (eval_isnamec(*arg))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100303 ++arg;
Bram Moolenaar1c991142020-07-04 13:15:31 +0200304 if (ga_grow(&names, 1) == FAIL)
305 goto erret;
306 ((char_u **)names.ga_data)[names.ga_len] =
307 vim_strnsave(p, arg - p);
308 ++names.ga_len;
309 arg = skipwhite_and_linebreak(arg, evalarg);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100310 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200311 else
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100312 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200313 emsg(_(e_import_syntax));
314 goto erret;
315 }
316
317 if (STRNCMP("as", arg, 2) == 0 && IS_WHITE_OR_NUL(arg[2]))
318 {
319 char_u *p;
320
321 // skip over "as Name "; no line break allowed after "as"
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100322 arg = skipwhite(arg + 2);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200323 p = arg;
Bram Moolenaarfa29c8a2020-02-23 22:35:05 +0100324 if (eval_isnamec1(*arg))
325 while (eval_isnamec(*arg))
326 ++arg;
Bram Moolenaar1c991142020-07-04 13:15:31 +0200327 if (check_defined(p, (int)(arg - p), cctx) == FAIL)
328 goto erret;
329 as_name = vim_strnsave(p, arg - p);
330 arg = skipwhite_and_linebreak(arg, evalarg);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100331 }
332 else if (*arg_start == '*')
333 {
334 emsg(_("E1045: Missing \"as\" after *"));
Bram Moolenaar1c991142020-07-04 13:15:31 +0200335 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100336 }
337 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200338
339 if (STRNCMP("from", arg, 4) != 0 || !IS_WHITE_OR_NUL(arg[4]))
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100340 {
Bram Moolenaarfa29c8a2020-02-23 22:35:05 +0100341 emsg(_("E1070: Missing \"from\""));
Bram Moolenaar1c991142020-07-04 13:15:31 +0200342 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100343 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200344
345 arg = skipwhite_and_linebreak_keep_string(arg + 4, evalarg);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100346 tv.v_type = VAR_UNKNOWN;
347 // TODO: should we accept any expression?
348 if (*arg == '\'')
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +0200349 ret = eval_lit_string(&arg, &tv, TRUE);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100350 else if (*arg == '"')
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +0200351 ret = eval_string(&arg, &tv, TRUE);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100352 if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL)
353 {
Bram Moolenaarfa29c8a2020-02-23 22:35:05 +0100354 emsg(_("E1071: Invalid string after \"from\""));
Bram Moolenaar1c991142020-07-04 13:15:31 +0200355 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100356 }
357 cmd_end = arg;
358
Bram Moolenaar1c991142020-07-04 13:15:31 +0200359 /*
360 * find script file
361 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100362 if (*tv.vval.v_string == '.')
363 {
364 size_t len;
Bram Moolenaar21b9e972020-01-26 19:26:46 +0100365 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100366 char_u *tail = gettail(si->sn_name);
367 char_u *from_name;
368
369 // Relative to current script: "./name.vim", "../../name.vim".
370 len = STRLEN(si->sn_name) - STRLEN(tail) + STRLEN(tv.vval.v_string) + 2;
371 from_name = alloc((int)len);
372 if (from_name == NULL)
373 {
374 clear_tv(&tv);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200375 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100376 }
377 vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
378 add_pathsep(from_name);
379 STRCAT(from_name, tv.vval.v_string);
380 simplify_filename(from_name);
381
382 res = do_source(from_name, FALSE, DOSO_NONE, &sid);
383 vim_free(from_name);
384 }
385 else if (mch_isFullName(tv.vval.v_string))
386 {
387 // Absolute path: "/tmp/name.vim"
388 res = do_source(tv.vval.v_string, FALSE, DOSO_NONE, &sid);
389 }
390 else
391 {
392 size_t len = 7 + STRLEN(tv.vval.v_string) + 1;
393 char_u *from_name;
394
395 // Find file in "import" subdirs in 'runtimepath'.
396 from_name = alloc((int)len);
397 if (from_name == NULL)
398 {
399 clear_tv(&tv);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200400 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100401 }
402 vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string);
403 res = source_in_path(p_rtp, from_name, DIP_NOAFTER, &sid);
404 vim_free(from_name);
405 }
406
407 if (res == FAIL || sid <= 0)
408 {
409 semsg(_("E1053: Could not import \"%s\""), tv.vval.v_string);
410 clear_tv(&tv);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200411 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100412 }
413 clear_tv(&tv);
414
415 if (*arg_start == '*')
416 {
417 imported_T *imported = new_imported(gap != NULL ? gap
Bram Moolenaar21b9e972020-01-26 19:26:46 +0100418 : &SCRIPT_ITEM(import_sid)->sn_imports);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100419
420 if (imported == NULL)
Bram Moolenaar1c991142020-07-04 13:15:31 +0200421 goto erret;
422 imported->imp_name = as_name;
423 as_name = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100424 imported->imp_sid = sid;
425 imported->imp_all = TRUE;
426 }
427 else
428 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200429 int i;
430
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100431 arg = arg_start;
432 if (*arg == '{')
433 arg = skipwhite(arg + 1);
Bram Moolenaar1c991142020-07-04 13:15:31 +0200434 for (i = 0; i < names.ga_len; ++i)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100435 {
Bram Moolenaar1c991142020-07-04 13:15:31 +0200436 char_u *name = ((char_u **)names.ga_data)[i];
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100437 int idx;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100438 imported_T *imported;
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100439 ufunc_T *ufunc = NULL;
440 type_T *type;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100441
Bram Moolenaar1c991142020-07-04 13:15:31 +0200442 idx = find_exported(sid, name, &ufunc, &type);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100443
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100444 if (idx < 0 && ufunc == NULL)
Bram Moolenaar1c991142020-07-04 13:15:31 +0200445 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100446
Bram Moolenaar1c991142020-07-04 13:15:31 +0200447 if (check_defined(name, STRLEN(name), cctx) == FAIL)
448 goto erret;
Bram Moolenaar5269bd22020-03-09 19:25:27 +0100449
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100450 imported = new_imported(gap != NULL ? gap
Bram Moolenaar21b9e972020-01-26 19:26:46 +0100451 : &SCRIPT_ITEM(import_sid)->sn_imports);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100452 if (imported == NULL)
Bram Moolenaar1c991142020-07-04 13:15:31 +0200453 goto erret;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100454
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100455 // TODO: check for "as" following
Bram Moolenaar1c991142020-07-04 13:15:31 +0200456 // imported->imp_name = vim_strsave(as_name);
457 imported->imp_name = name;
458 ((char_u **)names.ga_data)[i] = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100459 imported->imp_sid = sid;
460 if (idx >= 0)
461 {
Bram Moolenaarf2d5c242020-02-23 21:25:54 +0100462 imported->imp_type = type;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100463 imported->imp_var_vals_idx = idx;
464 }
465 else
466 imported->imp_funcname = ufunc->uf_name;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100467 }
468 }
Bram Moolenaar1c991142020-07-04 13:15:31 +0200469erret:
470 ga_clear_strings(&names);
471 vim_free(as_name);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100472 return cmd_end;
473}
474
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200475/*
476 * Declare a script-local variable without init: "let var: type".
477 * "const" is an error since the value is missing.
478 * Returns a pointer to after the type.
479 */
480 char_u *
481vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
482{
483 char_u *p;
484 char_u *name;
485 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
486 type_T *type;
487 int called_emsg_before = called_emsg;
488 typval_T init_tv;
489
490 if (eap->cmdidx == CMD_const)
491 {
492 emsg(_(e_const_req_value));
493 return arg + STRLEN(arg);
494 }
495
496 // Check for valid starting character.
497 if (!eval_isnamec1(*arg))
498 {
499 semsg(_(e_invarg2), arg);
500 return arg + STRLEN(arg);
501 }
502
Bram Moolenaar984dddb2020-06-14 12:50:24 +0200503 for (p = arg + 1; *p != NUL && eval_isnamec(*p); MB_PTR_ADV(p))
Bram Moolenaar3b74b6b2020-06-19 19:01:43 +0200504 if (*p == ':' && (VIM_ISWHITE(p[1]) || p != arg + 1))
Bram Moolenaar984dddb2020-06-14 12:50:24 +0200505 break;
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200506
507 if (*p != ':')
508 {
509 emsg(_(e_type_req));
510 return arg + STRLEN(arg);
511 }
Bram Moolenaar984dddb2020-06-14 12:50:24 +0200512 if (!VIM_ISWHITE(p[1]))
513 {
514 semsg(_(e_white_after), ":");
515 return arg + STRLEN(arg);
516 }
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200517 name = vim_strnsave(arg, p - arg);
518
519 // parse type
520 p = skipwhite(p + 1);
521 type = parse_type(&p, &si->sn_type_list);
522 if (called_emsg != called_emsg_before)
Bram Moolenaarf3decc52020-06-13 19:56:38 +0200523 {
524 vim_free(name);
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200525 return p;
Bram Moolenaarf3decc52020-06-13 19:56:38 +0200526 }
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200527
528 // Create the variable with 0/NULL value.
529 CLEAR_FIELD(init_tv);
530 init_tv.v_type = type->tt_type;
531 set_var_const(name, type, &init_tv, FALSE, 0);
532
533 vim_free(name);
534 return p;
535}
536
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200537/*
538 * Check if the type of script variable "dest" allows assigning "value".
539 */
Bram Moolenaarc785b9a2020-06-19 18:34:15 +0200540 int
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200541check_script_var_type(typval_T *dest, typval_T *value, char_u *name)
542{
543 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
544 int idx;
545
546 // Find the svar_T in sn_var_vals.
547 for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
548 {
549 svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
550
551 if (sv->sv_tv == dest)
552 {
553 if (sv->sv_const)
Bram Moolenaarc785b9a2020-06-19 18:34:15 +0200554 {
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200555 semsg(_(e_readonlyvar), name);
Bram Moolenaarc785b9a2020-06-19 18:34:15 +0200556 return FAIL;
557 }
558 return check_type(sv->sv_type, typval2type(value), TRUE);
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200559 }
560 }
561 iemsg("check_script_var_type(): not found");
Bram Moolenaarc785b9a2020-06-19 18:34:15 +0200562 return OK; // not really
Bram Moolenaar34db91f2020-06-13 19:00:10 +0200563}
Bram Moolenaarc82a5b52020-06-13 18:09:19 +0200564
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100565#endif // FEAT_EVAL